#ifndef SYNTAX_EXTRAS_H #define SYNTAX_EXTRAS_H #include "io/knot.h" #include "syntax/decl.h" #include "utils/utils.h" inline static const std::vector> color_map = { {"AliceBlue", 0xF0F8FF}, {"AntiqueWhite", 0xFAEBD7}, {"Aqua", 0x00FFFF}, {"Aquamarine", 0x7FFFD4}, {"Azure", 0xF0FFFF}, {"Beige", 0xF5F5DC}, {"Bisque", 0xFFE4C4}, {"Black", 0x000000}, {"BlanchedAlmond", 0xFFEBCD}, {"Blue", 0x0000FF}, {"BlueViolet", 0x8A2BE2}, {"Brown", 0xA52A2A}, {"BurlyWood", 0xDEB887}, {"CadetBlue", 0x5F9EA0}, {"Chartreuse", 0x7FFF00}, {"Chocolate", 0xD2691E}, {"Coral", 0xFF7F50}, {"CornflowerBlue", 0x6495ED}, {"Cornsilk", 0xFFF8DC}, {"Crimson", 0xDC143C}, {"Cyan", 0x00FFFF}, {"DarkBlue", 0x00008B}, {"DarkCyan", 0x008B8B}, {"DarkGoldenRod", 0xB8860B}, {"DarkGray", 0xA9A9A9}, {"DarkGrey", 0xA9A9A9}, {"DarkGreen", 0x006400}, {"DarkKhaki", 0xBDB76B}, {"DarkMagenta", 0x8B008B}, {"DarkOliveGreen", 0x556B2F}, {"DarkOrange", 0xFF8C00}, {"DarkOrchid", 0x9932CC}, {"DarkRed", 0x8B0000}, {"DarkSalmon", 0xE9967A}, {"DarkSeaGreen", 0x8FBC8F}, {"DarkSlateBlue", 0x483D8B}, {"DarkSlateGray", 0x2F4F4F}, {"DarkSlateGrey", 0x2F4F4F}, {"DarkTurquoise", 0x00CED1}, {"DarkViolet", 0x9400D3}, {"DeepPink", 0xFF1493}, {"DeepSkyBlue", 0x00BFFF}, {"DimGray", 0x696969}, {"DimGrey", 0x696969}, {"DodgerBlue", 0x1E90FF}, {"FireBrick", 0xB22222}, {"FloralWhite", 0xFFFAF0}, {"ForestGreen", 0x228B22}, {"Fuchsia", 0xFF00FF}, {"Gainsboro", 0xDCDCDC}, {"GhostWhite", 0xF8F8FF}, {"Gold", 0xFFD700}, {"GoldenRod", 0xDAA520}, {"Gray", 0x808080}, {"Grey", 0x808080}, {"Green", 0x008000}, {"GreenYellow", 0xADFF2F}, {"HoneyDew", 0xF0FFF0}, {"HotPink", 0xFF69B4}, {"IndianRed", 0xCD5C5C}, {"Indigo", 0x4B0082}, {"Ivory", 0xFFFFF0}, {"Khaki", 0xF0E68C}, {"Lavender", 0xE6E6FA}, {"LavenderBlush", 0xFFF0F5}, {"LawnGreen", 0x7CFC00}, {"LemonChiffon", 0xFFFACD}, {"LightBlue", 0xADD8E6}, {"LightCoral", 0xF08080}, {"LightCyan", 0xE0FFFF}, {"LightGoldenRodYellow", 0xFAFAD2}, {"LightGray", 0xD3D3D3}, {"LightGrey", 0xD3D3D3}, {"LightGreen", 0x90EE90}, {"LightPink", 0xFFB6C1}, {"LightSalmon", 0xFFA07A}, {"LightSeaGreen", 0x20B2AA}, {"LightSkyBlue", 0x87CEFA}, {"LightSlateGray", 0x778899}, {"LightSlateGrey", 0x778899}, {"LightSteelBlue", 0xB0C4DE}, {"LightYellow", 0xFFFFE0}, {"Lime", 0x00FF00}, {"LimeGreen", 0x32CD32}, {"Linen", 0xFAF0E6}, {"Magenta", 0xFF00FF}, {"Maroon", 0x800000}, {"MediumAquaMarine", 0x66CDAA}, {"MediumBlue", 0x0000CD}, {"MediumOrchid", 0xBA55D3}, {"MediumPurple", 0x9370DB}, {"MediumSeaGreen", 0x3CB371}, {"MediumSlateBlue", 0x7B68EE}, {"MediumSpringGreen", 0x00FA9A}, {"MediumTurquoise", 0x48D1CC}, {"MediumVioletRed", 0xC71585}, {"MidnightBlue", 0x191970}, {"MintCream", 0xF5FFFA}, {"MistyRose", 0xFFE4E1}, {"Moccasin", 0xFFE4B5}, {"NavajoWhite", 0xFFDEAD}, {"Navy", 0x000080}, {"OldLace", 0xFDF5E6}, {"Olive", 0x808000}, {"OliveDrab", 0x6B8E23}, {"Orange", 0xFFA500}, {"OrangeRed", 0xFF4500}, {"Orchid", 0xDA70D6}, {"PaleGoldenRod", 0xEEE8AA}, {"PaleGreen", 0x98FB98}, {"PaleTurquoise", 0xAFEEEE}, {"PaleVioletRed", 0xDB7093}, {"PapayaWhip", 0xFFEFD5}, {"PeachPuff", 0xFFDAB9}, {"Peru", 0xCD853F}, {"Pink", 0xFFC0CB}, {"Plum", 0xDDA0DD}, {"PowderBlue", 0xB0E0E6}, {"Purple", 0x800080}, {"RebeccaPurple", 0x663399}, {"Red", 0xFF0000}, {"RosyBrown", 0xBC8F8F}, {"RoyalBlue", 0x4169E1}, {"SaddleBrown", 0x8B4513}, {"Salmon", 0xFA8072}, {"SandyBrown", 0xF4A460}, {"SeaGreen", 0x2E8B57}, {"SeaShell", 0xFFF5EE}, {"Sienna", 0xA0522D}, {"Silver", 0xC0C0C0}, {"SkyBlue", 0x87CEEB}, {"SlateBlue", 0x6A5ACD}, {"SlateGray", 0x708090}, {"SlateGrey", 0x708090}, {"Snow", 0xFFFAFA}, {"SpringGreen", 0x00FF7F}, {"SteelBlue", 0x4682B4}, {"Tan", 0xD2B48C}, {"Teal", 0x008080}, {"Thistle", 0xD8BFD8}, {"Tomato", 0xFF6347}, {"Turquoise", 0x40E0D0}, {"Violet", 0xEE82EE}, {"Wheat", 0xF5DEB3}, {"White", 0xFFFFFF}, {"WhiteSmoke", 0xF5F5F5}, {"Yellow", 0xFFFF00}, {"YellowGreen", 0x9ACD32}, }; // Add word under cursor to this struct ExtraHighlighter { std::vector colors; std::array, 50> lines; Trie css_colors = Trie(); uint32_t start = 0; ExtraHighlighter() { css_colors.build(color_map, false); } void render(Knot *root, uint32_t n_start, std::string word, bool is_css) { start = n_start; for (auto &line : lines) line.clear(); LineIterator *it = begin_l_iter(root, start); if (!it) return; uint32_t idx = 0; uint32_t len; char *line; while (idx < 50 && (line = next_line(it, &len))) { lines[idx].assign(len, UINT32_MAX - 1); uint32_t i = 0; while (i < len) { if (is_css) { std::optional color; uint32_t color_len = css_colors.match( line, i, len, [](char c) { return isalnum(c) || c == '_'; }, &color); if (color) { for (uint32_t j = 0; j < color_len; j++) lines[idx][i + j] = *color; i += color_len; continue; } else if (i + 5 < len && (line[i] == 'r' || line[i] == 'R') && (line[i + 1] == 'g' || line[i + 1] == 'G') && (line[i + 2] == 'b' || line[i + 2] == 'B')) { uint32_t start = i; i += 3; if (line[i] == 'a' || line[i] == 'A') i++; if (line[i] == '(') { i++; bool is_percent = false; std::string r = ""; while (i < len && line[i] >= '0' && line[i] <= '9') r += line[i++]; if (r.empty()) continue; while (i < len && (line[i] == '.' || (line[i] >= '0' && line[i] <= '9'))) i++; if (line[i] == '%') { is_percent = true; i++; } while (i < len && (line[i] == ',' || line[i] == ' ')) i++; std::string g = ""; while (i < len && line[i] >= '0' && line[i] <= '9') g += line[i++]; if (g.empty()) continue; while (i < len && (line[i] == '.' || (line[i] >= '0' && line[i] <= '9'))) i++; while (i < len && (line[i] == ',' || line[i] == ' ' || line[i] == '%')) i++; std::string b = ""; while (i < len && line[i] >= '0' && line[i] <= '9') b += line[i++]; if (b.empty()) continue; while (i < len && (line[i] == ',' || line[i] == ' ' || line[i] == '.' || line[i] == '/' || line[i] == '%' || (line[i] >= '0' && line[i] <= '9'))) i++; if (i < len && line[i] == ')') i++; else continue; uint32_t rr, gg, bb; if (is_percent) { rr = std::stoul(r) * 255 / 100; gg = std::stoul(g) * 255 / 100; bb = std::stoul(b) * 255 / 100; } else { rr = std::stoul(r); gg = std::stoul(g); bb = std::stoul(b); } rr = rr > 255 ? 255 : rr; gg = gg > 255 ? 255 : gg; bb = bb > 255 ? 255 : bb; uint32_t color = (rr << 16) | (gg << 8) | bb; for (uint32_t j = start; j < i; j++) lines[idx][j] = color; } continue; } else if (i + 5 < len && (line[i] == 'h' || line[i] == 'H') && (line[i + 1] == 's' || line[i + 1] == 'S') && (line[i + 2] == 'l' || line[i + 2] == 'L')) { uint32_t start = i; i += 3; if (line[i] == 'a' || line[i] == 'A') i++; if (line[i] == '(') { i++; std::string h = ""; std::string h_unit = ""; enum unit : uint8_t { deg, grad, rad, turn }; unit u = deg; bool negative = false; if (i < len && (line[i] == '-' || line[i] == '+')) { negative = line[i] == '-'; i++; } while (i < len && line[i] >= '0' && line[i] <= '9') h += line[i++]; if (i < len && line[i] == '.') { h += '.'; while (i < len && line[i] >= '0' && line[i] <= '9') h += line[i++]; } if (h.empty()) continue; while (i < len && ((line[i] >= 'a' && line[i] <= 'z') || (line[i] >= 'A' && line[i] <= 'Z'))) h_unit += line[i++]; for (size_t x = 0; x < h_unit.size(); x++) h_unit[x] = tolower(h_unit[x]); if (h_unit.empty()) u = deg; else if (h_unit == "deg") u = deg; else if (h_unit == "grad") u = grad; else if (h_unit == "rad") u = rad; else if (h_unit == "turn") u = turn; else continue; double hue = std::stod(h); if (negative) hue = -hue; switch (u) { case deg: break; case grad: hue = hue * 360.0 / 400.0; break; case rad: hue = hue * 180.0 / M_PI; break; case turn: hue = hue * 360.0; break; } hue = fmod(hue, 360.0); if (hue < 0) hue += 360.0; double h_final = hue / 360.0; while (i < len && (line[i] == ',' || line[i] == ' ')) i++; std::string s = ""; while (i < len && line[i] >= '0' && line[i] <= '9') s += line[i++]; if (s.empty()) continue; if (i < len && line[i] == '%') i++; else continue; while (i < len && (line[i] == ',' || line[i] == ' ')) i++; std::string l = ""; while (i < len && line[i] >= '0' && line[i] <= '9') l += line[i++]; if (l.empty()) continue; if (i < len && line[i] == '%') i++; else continue; while (i < len && (line[i] == ',' || line[i] == ' ' || line[i] == '.' || line[i] == '/' || line[i] == '%' || (line[i] >= '0' && line[i] <= '9'))) i++; if (i < len && line[i] == ')') i++; double s_val = std::stod(s) / 100.0; double l_val = std::stod(l) / 100.0; uint32_t color = hslToRgb(h_final, s_val, l_val); for (uint32_t j = start; j < i; j++) lines[idx][j] = color; } continue; } } if (i + 4 < len && line[i] == '#') { i++; uint32_t start = i; while (i < len && isxdigit(line[i])) i++; uint32_t color = 0; if (is_css && (i - start == 3 || i - start == 4)) { uint32_t r = std::stoul(std::string(line + start, 1), nullptr, 16) * 0x11; uint32_t g = std::stoul(std::string(line + start + 1, 1), nullptr, 16) * 0x11; uint32_t b = std::stoul(std::string(line + start + 2, 1), nullptr, 16) * 0x11; color = (r << 16) | (g << 8) | b; } else if ((is_css && (i - start == 8)) || i - start == 6) { uint32_t r = std::stoul(std::string(line + start, 2), nullptr, 16); uint32_t g = std::stoul(std::string(line + start + 2, 2), nullptr, 16); uint32_t b = std::stoul(std::string(line + start + 4, 2), nullptr, 16); color = (r << 16) | (g << 8) | b; } else { continue; } for (uint32_t j = start - 1; j < i; j++) lines[idx][j] = color; continue; } else if (i + 5 < len && line[i] == '0' && line[i + 1] == 'x') { i += 2; uint32_t start = i; while (i < len && isxdigit(line[i])) i++; uint32_t color = 0; if (i - start == 6) { uint32_t r = std::stoul(std::string(line + start, 2), nullptr, 16); uint32_t g = std::stoul(std::string(line + start + 2, 2), nullptr, 16); uint32_t b = std::stoul(std::string(line + start + 4, 2), nullptr, 16); color = (r << 16) | (g << 8) | b; } else { continue; } if (color) color--; else color++; for (uint32_t j = start - 2; j < i; j++) lines[idx][j] = color; continue; } if (i < len && (isalnum(line[i]) || line[i] == '_')) { uint32_t start = i; uint32_t x = 0; bool found = true; while (i < len && (isalnum(line[i]) || line[i] == '_')) { if (x < word.size() && line[i] == word[x]) { i++; x++; } else { found = false; i++; } } if (found && x == word.size()) for (uint32_t j = start; j < i; j++) lines[idx][j] = UINT32_MAX; } else { i += utf8_codepoint_width(line[i]); } } idx++; } free(it->buffer); free(it); } std::optional> get(Coord pos) { uint32_t val; if (pos.row < start || pos.row >= start + 50 || pos.col >= lines[pos.row - start].size() || (val = lines[pos.row - start][pos.col]) == UINT32_MAX - 1) return std::nullopt; return (std::pair){fg_for_bg(val), val}; } private: uint32_t fg_for_bg(uint32_t color) { uint8_t r = (color >> 16) & 0xFF; uint8_t g = (color >> 8) & 0xFF; uint8_t b = color & 0xFF; double luminance = 0.299 * r + 0.587 * g + 0.114 * b; return (luminance > 128) ? 0x010101 : 0xFFFFFF; } uint32_t hslToRgb(double h, double s, double l) { double r, g, b; if (s == 0.0) { r = g = b = l; } else { auto hue2rgb = [](double p, double q, double t) -> double { if (t < 0) t += 1; if (t > 1) t -= 1; if (t < 1.0 / 6) return p + (q - p) * 6 * t; if (t < 1.0 / 2) return q; if (t < 2.0 / 3) return p + (q - p) * (2.0 / 3 - t) * 6; return p; }; double q = l < 0.5 ? l * (1 + s) : l + s - l * s; double p = 2 * l - q; r = hue2rgb(p, q, h + 1.0 / 3); g = hue2rgb(p, q, h); b = hue2rgb(p, q, h - 1.0 / 3); } uint32_t R = static_cast(std::clamp(r, 0.0, 1.0) * 255); uint32_t G = static_cast(std::clamp(g, 0.0, 1.0) * 255); uint32_t B = static_cast(std::clamp(b, 0.0, 1.0) * 255); return (R << 16) | (G << 8) | B; } }; #endif