diff --git a/colors/gruvbox.kak b/colors/gruvbox.kak index 89b9b7a5..fcac50b7 100644 --- a/colors/gruvbox.kak +++ b/colors/gruvbox.kak @@ -71,6 +71,6 @@ evaluate-commands %sh{ face global Prompt ${yellow} face global MatchingChar default+b face global BufferPadding ${bg2},${bg} - face global Whitespace ${bg2} + face global Whitespace ${bg2}+f " } diff --git a/doc/json_ui.asciidoc b/doc/json_ui.asciidoc index 7a93a41d..52ecd17f 100644 --- a/doc/json_ui.asciidoc +++ b/doc/json_ui.asciidoc @@ -14,7 +14,7 @@ Kakoune won't be able to parse named parameters in requests. Here are the data structures used: * Color: a string, either a named color, or #rrggbb, or 'default' -* Attribute: one of {exclusive, underline, reverse, blink, bold, dim, italic} +* Attribute: one of {underline, reverse, blink, bold, dim, italic, final_fg, final_bg, final_attr} * Face { Color fg; Color bg; Array attributes; } * Atom { Face face; String contents; } * Line : Array of Atom diff --git a/doc/pages/changelog.asciidoc b/doc/pages/changelog.asciidoc index e01c41f5..0c360ae8 100644 --- a/doc/pages/changelog.asciidoc +++ b/doc/pages/changelog.asciidoc @@ -8,6 +8,13 @@ released versions. * `remove-hooks` argument is now a regex and removes all hooks whose group matches it. +* `exclusive` face attribute (e) has been replaced with more + granular `final foreground` (f), `final background` (g), and `final + attributes` (a), or the three combined as `final` (F). Semantics + changed slightly as those attributes apply to the existing face as + well (a final face will not get modified by a following face if that + following face does not have the final attribute itself. + == Kakoune 2018.09.04 This version contains a significant overhaul of various Kakoune diff --git a/doc/pages/faces.asciidoc b/doc/pages/faces.asciidoc index c013b7ba..68f8e19c 100644 --- a/doc/pages/faces.asciidoc +++ b/doc/pages/faces.asciidoc @@ -33,9 +33,19 @@ fg_color[,bg_color][+attributes] dim *i*::: italic - *e*::: - exclusive, override previous faces instead of merging - with them + *F*::: + final, override the previous face instead of merging with it + an will only be replaced if another face with the final + attribute is applied + *f*::: + final foreground, as final but only applies to face's + foreground color + *g*::: + final background, as final but only applies to face's + background color + *a*::: + final attributes, as final but only applies to face's + attributes == Builtin faces diff --git a/src/face.hh b/src/face.hh index 098664d7..a240af8b 100644 --- a/src/face.hh +++ b/src/face.hh @@ -10,13 +10,16 @@ namespace Kakoune enum class Attribute : int { Normal = 0, - Exclusive = 1 << 1, - Underline = 1 << 2, - Reverse = 1 << 3, - Blink = 1 << 4, - Bold = 1 << 5, - Dim = 1 << 6, - Italic = 1 << 7, + Underline = 1 << 1, + Reverse = 1 << 2, + Blink = 1 << 3, + Bold = 1 << 4, + Dim = 1 << 5, + Italic = 1 << 6, + FinalFg = 1 << 7, + FinalBg = 1 << 8, + FinalAttr = 1 << 8, + Final = FinalFg | FinalBg | FinalAttr }; constexpr bool with_bit_ops(Meta::Type) { return true; } @@ -49,12 +52,23 @@ constexpr size_t hash_value(const Face& val) return hash_values(val.fg, val.bg, val.attributes); } -constexpr Face merge_faces(const Face& base, const Face& face) +inline Face merge_faces(const Face& base, const Face& face) { - return face.attributes & Attribute::Exclusive ? - face : Face{ face.fg == Color::Default ? base.fg : face.fg, - face.bg == Color::Default ? base.bg : face.bg, - face.attributes | base.attributes }; + auto choose = [&](Color Face::*color, Attribute final_attr) { + if (face.attributes & final_attr) + return face.*color; + if (base.attributes & final_attr) + return base.*color; + if (face.*color == Color::Default) + return base.*color; + return face.*color; + }; + + return Face{ choose(&Face::fg, Attribute::FinalFg), + choose(&Face::bg, Attribute::FinalBg), + face.attributes & Attribute::FinalAttr ? face.attributes : + base.attributes & Attribute::FinalAttr ? base.attributes : + face.attributes | base.attributes }; } } diff --git a/src/face_registry.cc b/src/face_registry.cc index 8b13e439..4f8a6418 100644 --- a/src/face_registry.cc +++ b/src/face_registry.cc @@ -29,13 +29,16 @@ static Face parse_face(StringView facedesc) { switch (*attr_it) { - case 'e': res.attributes |= Attribute::Exclusive; break; case 'u': res.attributes |= Attribute::Underline; break; case 'r': res.attributes |= Attribute::Reverse; break; case 'b': res.attributes |= Attribute::Bold; break; case 'B': res.attributes |= Attribute::Blink; break; case 'd': res.attributes |= Attribute::Dim; break; case 'i': res.attributes |= Attribute::Italic; break; + case 'f': res.attributes |= Attribute::FinalFg; break; + case 'g': res.attributes |= Attribute::FinalBg; break; + case 'a': res.attributes |= Attribute::FinalAttr; break; + case 'F': res.attributes |= Attribute::Final; break; default: throw runtime_error(format("no such face attribute: '{}'", StringView{*attr_it})); } } @@ -50,13 +53,16 @@ String to_string(Attribute attributes) struct Attr { Attribute attr; StringView name; } attrs[] { - { Attribute::Exclusive, "e" }, { Attribute::Underline, "u" }, { Attribute::Reverse, "r" }, { Attribute::Blink, "B" }, { Attribute::Bold, "b" }, { Attribute::Dim, "d" }, { Attribute::Italic, "i" }, + { Attribute::Final, "F" }, + { Attribute::FinalFg, "f" }, + { Attribute::FinalBg, "b" }, + { Attribute::FinalAttr, "a" }, }; auto filteredAttrs = attrs | @@ -150,7 +156,7 @@ FaceRegistry::FaceRegistry() { "Prompt", {Face{ Color::Yellow, Color::Default }} }, { "MatchingChar", {Face{ Color::Default, Color::Default, Attribute::Bold }} }, { "BufferPadding", {Face{ Color::Blue, Color::Default }} }, - { "Whitespace", {Face{ Color::Default, Color::Default }} }, + { "Whitespace", {Face{ Color::Default, Color::Default, Attribute::FinalFg }} }, } {} diff --git a/src/json_ui.cc b/src/json_ui.cc index 3a0bf7d6..32524c3b 100644 --- a/src/json_ui.cc +++ b/src/json_ui.cc @@ -81,13 +81,15 @@ String to_json(Attribute attributes) { struct Attr { Attribute attr; StringView name; } attrs[] { - { Attribute::Exclusive, "exclusive" }, { Attribute::Underline, "underline" }, { Attribute::Reverse, "reverse" }, { Attribute::Blink, "blink" }, { Attribute::Bold, "bold" }, { Attribute::Dim, "dim" }, { Attribute::Italic, "italic" }, + { Attribute::FinalFg, "final_fg" }, + { Attribute::FinalBg, "final_bg" }, + { Attribute::FinalAttr, "final_attr" }, }; return "[" + join(attrs | diff --git a/test/regression/1435-misplaced-cursor-with-show_matching-hl/ui-out b/test/regression/1435-misplaced-cursor-with-show_matching-hl/ui-out index 56262fcc..df245f80 100644 --- a/test/regression/1435-misplaced-cursor-with-show_matching-hl/ui-out +++ b/test/regression/1435-misplaced-cursor-with-show_matching-hl/ui-out @@ -1,11 +1,11 @@ { "jsonrpc": "2.0", "method": "set_ui_options", "params": [{}] } -{ "jsonrpc": "2.0", "method": "draw", "params": [[[{ "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "·" }, { "face": { "fg": "black", "bg": "cyan", "attributes": [] }, "contents": "¬" }], [{ "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "¬" }]], { "fg": "default", "bg": "default", "attributes": [] }, { "fg": "blue", "bg": "default", "attributes": [] }] } +{ "jsonrpc": "2.0", "method": "draw", "params": [[[{ "face": { "fg": "default", "bg": "default", "attributes": ["final_fg"] }, "contents": "·" }, { "face": { "fg": "default", "bg": "cyan", "attributes": ["final_fg"] }, "contents": "¬" }], [{ "face": { "fg": "default", "bg": "default", "attributes": ["final_fg"] }, "contents": "¬" }]], { "fg": "default", "bg": "default", "attributes": [] }, { "fg": "blue", "bg": "default", "attributes": [] }] } { "jsonrpc": "2.0", "method": "menu_hide", "params": [] } { "jsonrpc": "2.0", "method": "info_hide", "params": [] } { "jsonrpc": "2.0", "method": "draw_status", "params": [[], [{ "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "out 1:2 " }, { "face": { "fg": "black", "bg": "yellow", "attributes": [] }, "contents": "[+]" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": " " }, { "face": { "fg": "blue", "bg": "default", "attributes": [] }, "contents": "1 sel" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": " - client0@[kak-tests]" }], { "fg": "cyan", "bg": "default", "attributes": [] }] } { "jsonrpc": "2.0", "method": "set_cursor", "params": ["buffer", { "line": 0, "column": 1 }] } { "jsonrpc": "2.0", "method": "refresh", "params": [true] } -{ "jsonrpc": "2.0", "method": "draw", "params": [[[{ "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "·" }, { "face": { "fg": "black", "bg": "cyan", "attributes": [] }, "contents": "¬" }], [{ "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "¬" }]], { "fg": "default", "bg": "default", "attributes": [] }, { "fg": "blue", "bg": "default", "attributes": [] }] } +{ "jsonrpc": "2.0", "method": "draw", "params": [[[{ "face": { "fg": "default", "bg": "default", "attributes": ["final_fg"] }, "contents": "·" }, { "face": { "fg": "default", "bg": "cyan", "attributes": ["final_fg"] }, "contents": "¬" }], [{ "face": { "fg": "default", "bg": "default", "attributes": ["final_fg"] }, "contents": "¬" }]], { "fg": "default", "bg": "default", "attributes": [] }, { "fg": "blue", "bg": "default", "attributes": [] }] } { "jsonrpc": "2.0", "method": "menu_hide", "params": [] } { "jsonrpc": "2.0", "method": "info_hide", "params": [] } { "jsonrpc": "2.0", "method": "draw_status", "params": [[], [{ "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "out 1:2 " }, { "face": { "fg": "black", "bg": "yellow", "attributes": [] }, "contents": "[+]" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": " " }, { "face": { "fg": "blue", "bg": "default", "attributes": [] }, "contents": "1 sel" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": " - client0@[kak-tests]" }], { "fg": "cyan", "bg": "default", "attributes": [] }] } diff --git a/test/regression/1453-show_whitespaces-highlighter-breaks-tab-alignment/ui-out b/test/regression/1453-show_whitespaces-highlighter-breaks-tab-alignment/ui-out index e8164e2c..3564174e 100644 --- a/test/regression/1453-show_whitespaces-highlighter-breaks-tab-alignment/ui-out +++ b/test/regression/1453-show_whitespaces-highlighter-breaks-tab-alignment/ui-out @@ -1,5 +1,5 @@ { "jsonrpc": "2.0", "method": "set_ui_options", "params": [{}] } -{ "jsonrpc": "2.0", "method": "draw", "params": [[[{ "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "this" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "→ " }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "is" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "→ " }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "a" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "→ " }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "test" }, { "face": { "fg": "black", "bg": "cyan", "attributes": [] }, "contents": "¬" }]], { "fg": "default", "bg": "default", "attributes": [] }, { "fg": "blue", "bg": "default", "attributes": [] }] } +{ "jsonrpc": "2.0", "method": "draw", "params": [[[{ "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "this" }, { "face": { "fg": "default", "bg": "default", "attributes": ["final_fg"] }, "contents": "→ " }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "is" }, { "face": { "fg": "default", "bg": "default", "attributes": ["final_fg"] }, "contents": "→ " }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "a" }, { "face": { "fg": "default", "bg": "default", "attributes": ["final_fg"] }, "contents": "→ " }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "test" }, { "face": { "fg": "default", "bg": "cyan", "attributes": ["final_fg"] }, "contents": "¬" }]], { "fg": "default", "bg": "default", "attributes": [] }, { "fg": "blue", "bg": "default", "attributes": [] }] } { "jsonrpc": "2.0", "method": "menu_hide", "params": [] } { "jsonrpc": "2.0", "method": "info_hide", "params": [] } { "jsonrpc": "2.0", "method": "draw_status", "params": [[], [{ "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": "out 1:15 " }, { "face": { "fg": "black", "bg": "yellow", "attributes": [] }, "contents": "[+]" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": " " }, { "face": { "fg": "blue", "bg": "default", "attributes": [] }, "contents": "1 sel" }, { "face": { "fg": "default", "bg": "default", "attributes": [] }, "contents": " - client0@[kak-tests]" }], { "fg": "cyan", "bg": "default", "attributes": [] }] }