diff options
| author | Maxime Coste <mawww@kakoune.org> | 2021-09-07 08:21:26 +1000 |
|---|---|---|
| committer | Maxime Coste <mawww@kakoune.org> | 2021-09-07 08:21:26 +1000 |
| commit | 3fc8e29d101b4f6eef2538cdbe799bab9859f4b3 (patch) | |
| tree | 27d931e4bed0fb12c8d018f7302c89f634d81350 /src | |
| parent | a6644d3034eba2db1db6cd3832488897ffb78921 (diff) | |
Add support for curly underline and separate underline color
Add support for a third color in face definition that controls
the underline and a 'c' attribute for curly underline (that takes
precedence over 'u' if both are specified)
Allow empty colors to mean default, so that `,,red+u` means the
same as `default,default,red+u`
Fixes #4138
Diffstat (limited to 'src')
| -rw-r--r-- | src/commands.cc | 4 | ||||
| -rw-r--r-- | src/face.hh | 32 | ||||
| -rw-r--r-- | src/face_registry.cc | 20 | ||||
| -rw-r--r-- | src/json_ui.cc | 4 | ||||
| -rw-r--r-- | src/terminal_ui.cc | 20 |
5 files changed, 56 insertions, 24 deletions
diff --git a/src/commands.cc b/src/commands.cc index e6fe6c92..1f5dcf7e 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -2384,8 +2384,8 @@ const CommandDesc set_face_cmd = { "facespec format is <fg color>[,<bg color>][+<attributes>][@<base>]\n" "colors are either a color name, rgb:######, or rgba:######## values.\n" "attributes is a combination of:\n" - " u: underline, i: italic, b: bold, r: reverse,\n" - " s: strikethrough, B: blink, d: dim,\n" + " u: underline, c: curly underline, i: italic, b: bold,\n" + " r: reverse, s: strikethrough, B: blink, d: dim,\n" " f: final foreground, g: final background,\n" " a: final attributes, F: same as +fga\n" "facespec can as well just be the name of another face.\n" diff --git a/src/face.hh b/src/face.hh index 798cd3f3..ce544116 100644 --- a/src/face.hh +++ b/src/face.hh @@ -9,18 +9,19 @@ namespace Kakoune enum class Attribute : int { - Normal = 0, - Underline = 1 << 1, - Reverse = 1 << 2, - Blink = 1 << 3, - Bold = 1 << 4, - Dim = 1 << 5, - Italic = 1 << 6, - Strikethrough = 1 << 7, - FinalFg = 1 << 8, - FinalBg = 1 << 9, - FinalAttr = 1 << 10, - Final = FinalFg | FinalBg | FinalAttr + Normal = 0, + Underline = 1 << 1, + CurlyUnderline = 1 << 2, + Reverse = 1 << 3, + Blink = 1 << 4, + Bold = 1 << 5, + Dim = 1 << 6, + Italic = 1 << 7, + Strikethrough = 1 << 8, + FinalFg = 1 << 9, + FinalBg = 1 << 10, + FinalAttr = 1 << 11, + Final = FinalFg | FinalBg | FinalAttr }; constexpr bool with_bit_ops(Meta::Type<Attribute>) { return true; } @@ -30,11 +31,13 @@ struct Face Color fg = Color::Default; Color bg = Color::Default; Attribute attributes = Attribute::Normal; + Color underline = Color::Default; friend constexpr bool operator==(const Face& lhs, const Face& rhs) { return lhs.fg == rhs.fg and lhs.bg == rhs.bg and + lhs.underline == rhs.underline and lhs.attributes == rhs.attributes; } @@ -45,7 +48,7 @@ struct Face friend constexpr size_t hash_value(const Face& val) { - return hash_values(val.fg, val.bg, val.attributes); + return hash_values(val.fg, val.bg, val.underline, val.attributes); } }; @@ -77,7 +80,8 @@ inline Face merge_faces(const Face& base, const Face& face) choose(&Face::bg, Attribute::FinalBg), face.attributes & Attribute::FinalAttr ? face.attributes : base.attributes & Attribute::FinalAttr ? base.attributes : - face.attributes | base.attributes }; + face.attributes | base.attributes, + choose(&Face::underline, Attribute{0}) }; } } diff --git a/src/face_registry.cc b/src/face_registry.cc index 638059ac..87d638e7 100644 --- a/src/face_registry.cc +++ b/src/face_registry.cc @@ -9,11 +9,12 @@ namespace Kakoune static FaceRegistry::FaceSpec parse_face(StringView facedesc) { - constexpr StringView invalid_face_error = "invalid face description, expected [<fg>][,<bg>][+<attr>][@base] or just [base]"; + constexpr StringView invalid_face_error = "invalid face description, expected [<fg>][,<bg>[,<underline>]][+<attr>][@base] or just [base]"; if (all_of(facedesc, [](char c){ return is_word(c); }) and not is_color_name(facedesc)) return {Face{}, facedesc.str()}; auto bg_it = find(facedesc, ','); + auto underline_it = bg_it == facedesc.end() ? bg_it : std::find(bg_it+1, facedesc.end(), ','); auto attr_it = find(facedesc, '+'); auto base_it = find(facedesc, '@'); if (bg_it != facedesc.end() @@ -25,12 +26,19 @@ static FaceRegistry::FaceSpec parse_face(StringView facedesc) auto colors_end = std::min(attr_it, base_it); + auto parse_color = [](StringView spec) { + return spec.empty() ? Color::Default : str_to_color(spec); + }; + FaceRegistry::FaceSpec spec; auto& face = spec.face; - face.fg = colors_end != facedesc.begin() ? - str_to_color({facedesc.begin(), std::min(bg_it, colors_end)}) : Color::Default; + face.fg = parse_color({facedesc.begin(), std::min(bg_it, colors_end)}); if (bg_it != facedesc.end()) - face.bg = bg_it+1 != attr_it ? str_to_color({bg_it+1, colors_end}) : Color::Default; + { + face.bg = parse_color({bg_it+1, std::min(underline_it, colors_end)}); + if (underline_it != facedesc.end()) + face.underline = parse_color({underline_it+1, colors_end}); + } if (attr_it != facedesc.end()) { for (++attr_it; attr_it != base_it; ++attr_it) @@ -38,6 +46,7 @@ static FaceRegistry::FaceSpec parse_face(StringView facedesc) switch (*attr_it) { case 'u': face.attributes |= Attribute::Underline; break; + case 'c': face.attributes |= Attribute::CurlyUnderline; break; case 'r': face.attributes |= Attribute::Reverse; break; case 'b': face.attributes |= Attribute::Bold; break; case 'B': face.attributes |= Attribute::Blink; break; @@ -65,6 +74,7 @@ String to_string(Attribute attributes) struct Attr { Attribute attr; StringView name; } attrs[] { { Attribute::Underline, "u" }, + { Attribute::CurlyUnderline, "c" }, { Attribute::Reverse, "r" }, { Attribute::Blink, "B" }, { Attribute::Bold, "b" }, @@ -90,7 +100,7 @@ String to_string(Attribute attributes) String to_string(Face face) { - return format("{},{}{}", face.fg, face.bg, face.attributes); + return format("{},{},{}{}", face.fg, face.bg, face.underline, face.attributes); } Face FaceRegistry::operator[](StringView facedesc) const diff --git a/src/json_ui.cc b/src/json_ui.cc index 36c547ef..f5ae1f1f 100644 --- a/src/json_ui.cc +++ b/src/json_ui.cc @@ -57,8 +57,8 @@ String to_json(Attribute attributes) String to_json(Face face) { - return format(R"(\{ "fg": {}, "bg": {}, "attributes": {} })", - to_json(face.fg), to_json(face.bg), to_json(face.attributes)); + return format(R"(\{ "fg": {}, "bg": {}, "underline": {}, "attributes": {} })", + to_json(face.fg), to_json(face.bg), to_json(face.underline), to_json(face.attributes)); } String to_json(const DisplayAtom& atom) diff --git a/src/terminal_ui.cc b/src/terminal_ui.cc index 58d786c9..67b21e7f 100644 --- a/src/terminal_ui.cc +++ b/src/terminal_ui.cc @@ -223,7 +223,8 @@ void TerminalUI::Screen::set_face(const Face& face, Writer& writer) { static constexpr int fg_table[]{ 39, 30, 31, 32, 33, 34, 35, 36, 37, 90, 91, 92, 93, 94, 95, 96, 97 }; static constexpr int bg_table[]{ 49, 40, 41, 42, 43, 44, 45, 46, 47, 100, 101, 102, 103, 104, 105, 106, 107 }; - static constexpr int attr_table[]{ 0, 4, 7, 5, 1, 2, 3, 9 }; + static constexpr int ul_table[]{ 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; + static constexpr const char* attr_table[]{ "0", "4", "4:3", "7", "5", "1", "2", "3", "9" }; auto set_color = [&](bool fg, const Color& color, bool join) { if (join) @@ -255,7 +256,24 @@ void TerminalUI::Screen::set_face(const Face& face, Writer& writer) join = true; } if (m_active_face.bg != face.bg) + { set_color(false, face.bg, join); + join = true; + } + if (m_active_face.underline != face.underline) + { + if (join) + writer.write(";"); + if (face.underline != Color::Default) + { + if (face.underline.isRGB()) + format_with(writer, "58:2::{}:{}:{}", face.underline.r, face.underline.g, face.underline.b); + else + format_with(writer, "58:5:{}", ul_table[(int)(char)face.underline.color]); + } + else + format_with(writer, "59"); + } writer.write("m"); m_active_face = face; |
