From 64e8a3c4d19eab40888fbac36b96e97bd9d68c42 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 22 Sep 2023 15:36:24 +0800 Subject: [PATCH] fix(ui): handle virtual text with multiple hl in more cases (#25304) --- src/nvim/api/extmark.c | 3 +-- src/nvim/decoration.c | 18 +++++++++++++ src/nvim/drawline.c | 18 ------------- src/nvim/drawscreen.c | 12 +++++---- src/nvim/fold.c | 9 +++++-- test/functional/ui/float_spec.lua | 17 +++++++----- test/functional/ui/fold_spec.lua | 45 +++++++++++++++++-------------- 7 files changed, 69 insertions(+), 53 deletions(-) diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index faab6e593c..1e44c66974 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -1188,8 +1188,7 @@ VirtText parse_virt_text(Array chunks, Error *err, int *width) goto free_exit; } if (j < arr.size - 1) { - kv_push(virt_text, ((VirtTextChunk){ .text = NULL, - .hl_id = hl_id })); + kv_push(virt_text, ((VirtTextChunk){ .text = NULL, .hl_id = hl_id })); } } } else { diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c index b70f070a51..9d391cde8c 100644 --- a/src/nvim/decoration.c +++ b/src/nvim/decoration.c @@ -153,6 +153,24 @@ void clear_virttext(VirtText *text) *text = (VirtText)KV_INITIAL_VALUE; } +/// Get the next chunk of a virtual text item. +/// +/// @param[in] vt The virtual text item +/// @param[in,out] pos Position in the virtual text item +/// @param[in,out] attr Highlight attribute +/// +/// @return The text of the chunk, or NULL if there are no more chunks +char *next_virt_text_chunk(VirtText vt, size_t *pos, int *attr) +{ + char *text = NULL; + for (; text == NULL && *pos < kv_size(vt); (*pos)++) { + text = kv_A(vt, *pos).text; + int hl_id = kv_A(vt, *pos).hl_id; + *attr = hl_combine_attr(*attr, hl_id > 0 ? syn_id2attr(hl_id) : 0); + } + return text; +} + Decoration *decor_find_virttext(buf_T *buf, int row, uint64_t ns_id) { MarkTreeIter itr[1] = { 0 }; diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index a5409dbc98..7d64d9fa3c 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -324,24 +324,6 @@ static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int } } -/// Get the next chunk of a virtual text item. -/// -/// @param[in] vt The virtual text item -/// @param[in,out] pos Position in the virtual text item -/// @param[in,out] attr Highlight attribute -/// -/// @return The text of the chunk, or NULL if there are no more chunks -static char *next_virt_text_chunk(VirtText vt, size_t *pos, int *attr) -{ - char *text = NULL; - for (; text == NULL && *pos < kv_size(vt); (*pos)++) { - text = kv_A(vt, *pos).text; - int hl_id = kv_A(vt, *pos).hl_id; - *attr = hl_combine_attr(*attr, hl_id > 0 ? syn_id2attr(hl_id) : 0); - } - return text; -} - static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode, int max_col, int vcol, bool rl) { diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index 854c8590e4..1d22b67d40 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -709,13 +709,15 @@ void end_search_hl(void) screen_search_hl.rm.regprog = NULL; } -static void win_redr_bordertext(win_T *wp, ScreenGrid *grid, VirtText text_chunks, int row, int col) +static void win_redr_bordertext(win_T *wp, ScreenGrid *grid, VirtText vt, int row, int col) { - for (size_t i = 0; i < text_chunks.size; i++) { - char *text = text_chunks.items[i].text; + for (size_t i = 0; i < kv_size(vt);) { + int attr = 0; + char *text = next_virt_text_chunk(vt, &i, &attr); + if (text == NULL) { + break; + } int cell = (int)mb_string2cells(text); - int hl_id = text_chunks.items[i].hl_id; - int attr = hl_id ? syn_id2attr(hl_id) : 0; grid_puts(grid, text, row, col, attr); col += cell; } diff --git a/src/nvim/fold.c b/src/nvim/fold.c index 1d5ba49301..d874e904d0 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -3344,8 +3344,13 @@ void f_foldtextresult(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } if (kv_size(vt) > 0) { assert(*text == NUL); - for (size_t i = 0; i < kv_size(vt); i++) { - char *new_text = concat_str(text, kv_A(vt, i).text); + for (size_t i = 0; i < kv_size(vt);) { + int attr = 0; + char *new_text = next_virt_text_chunk(vt, &i, &attr); + if (new_text == NULL) { + break; + } + new_text = concat_str(text, new_text); xfree(text); text = new_text; } diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 4fea513249..93ca1aef3f 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -821,7 +821,7 @@ describe('float window', function() [4] = {bold = true, reverse = true}, [5] = {reverse = true}, [6] = {background = Screen.colors.LightMagenta, bold = true, reverse = true}, - [7] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [7] = {foreground = Screen.colors.White, background = Screen.colors.Red}, [8] = {bold = true, foreground = Screen.colors.SeaGreen4}, [9] = {background = Screen.colors.LightGrey, underline = true}, [10] = {background = Screen.colors.LightGrey, underline = true, bold = true, foreground = Screen.colors.Magenta}, @@ -2512,7 +2512,12 @@ describe('float window', function() ]]} end - meths.win_set_config(win, {title= { {"🦄"},{"BB"}},title_pos="right",footer= { {"🦄"},{"BB"}},footer_pos="right"}) + command('hi B0 guibg=Red guifg=Black') + command('hi B1 guifg=White') + meths.win_set_config(win, { + title = {{"🦄"}, {"BB", {"B0", "B1"}}}, title_pos = "right", + footer= {{"🦄"}, {"BB", {"B0", "B1"}}}, footer_pos = "right", + }) if multigrid then screen:expect{grid=[[ ## grid 1 @@ -2533,10 +2538,10 @@ describe('float window', function() ## grid 3 | ## grid 4 - {5:╔═════}🦄BB{5:╗}| + {5:╔═════}🦄{7:BB}{5:╗}| {5:║}{1: halloj! }{5:║}| {5:║}{1: BORDAA }{5:║}| - {5:╚═════}🦄BB{5:╝}| + {5:╚═════}🦄{7:BB}{5:╝}| ]], float_pos={ [4] = { { id = 1001 }, "NW", 1, 2, 5, true } }, win_viewport={ @@ -2547,10 +2552,10 @@ describe('float window', function() screen:expect{grid=[[ ^ | {0:~ }| - {0:~ }{5:╔═════}🦄BB{5:╗}{0: }| + {0:~ }{5:╔═════}🦄{7:BB}{5:╗}{0: }| {0:~ }{5:║}{1: halloj! }{5:║}{0: }| {0:~ }{5:║}{1: BORDAA }{5:║}{0: }| - {0:~ }{5:╚═════}🦄BB{5:╝}{0: }| + {0:~ }{5:╚═════}🦄{7:BB}{5:╝}{0: }| | ]]} end diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua index 5e907f82ba..f42682ba69 100644 --- a/test/functional/ui/fold_spec.lua +++ b/test/functional/ui/fold_spec.lua @@ -33,7 +33,7 @@ describe("folded lines", function() [1] = {bold = true, foreground = Screen.colors.Blue1}, [2] = {reverse = true}, [3] = {bold = true, reverse = true}, - [4] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [4] = {foreground = Screen.colors.White, background = Screen.colors.Red}, [5] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey}, [6] = {background = Screen.colors.Yellow}, [7] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray}, @@ -2938,10 +2938,15 @@ describe("folded lines", function() screen:try_resize(30, 7) insert(content1) command("hi! CursorLine guibg=NONE guifg=Red gui=NONE") + command('hi F0 guibg=Red guifg=Black') + command('hi F1 guifg=White') meths.set_option_value('cursorline', true, {}) meths.set_option_value('foldcolumn', '4', {}) - meths.set_option_value('foldtext', - '[[v:folddashes], ["\t", "Search"], [getline(v:foldstart), "NonText"]]', {}) + meths.set_option_value('foldtext', '[' + .. '["▶", ["F0", "F1"]], ' + .. '[v:folddashes], ' + .. '["\t", "Search"], ' + .. '[getline(v:foldstart), "NonText"]]', {}) command('3,4fold') command('5,6fold') @@ -2958,7 +2963,7 @@ describe("folded lines", function() [3:------------------------------]| ## grid 2 {7: }This is a | - {7:+ }{13:^-}{17: }{18:valid English}{13:·····}| + {7:+ }{4:^▶}{13:-}{17: }{18:valid English}{13:·····}| {1:~ }| {1:~ }| {1:~ }| @@ -2969,7 +2974,7 @@ describe("folded lines", function() else screen:expect([[ {7: }This is a | - {7:+ }{13:^-}{17: }{18:valid English}{13:·····}| + {7:+ }{4:^▶}{13:-}{17: }{18:valid English}{13:·····}| {1:~ }| {1:~ }| {1:~ }| @@ -2977,7 +2982,7 @@ describe("folded lines", function() | ]]) end - eq('-\tvalid English', funcs.foldtextresult(2)) + eq('▶-\tvalid English', funcs.foldtextresult(2)) feed('zo') if multigrid then @@ -2993,8 +2998,8 @@ describe("folded lines", function() ## grid 2 {7: }This is a | {7:- }valid English | - {7:│+ }{5:--}{19: }{18:sentence composed }| - {7:│+ }{13:^--}{17: }{18:in his cave.}{13:······}| + {7:│+ }{4:▶}{5:--}{19: }{18:sentence composed }| + {7:│+ }{4:^▶}{13:--}{17: }{18:in his cave.}{13:······}| {1:~ }| {1:~ }| ## grid 3 @@ -3004,15 +3009,15 @@ describe("folded lines", function() screen:expect([[ {7: }This is a | {7:- }valid English | - {7:│+ }{5:--}{19: }{18:sentence composed }| - {7:│+ }{13:^--}{17: }{18:in his cave.}{13:······}| + {7:│+ }{4:▶}{5:--}{19: }{18:sentence composed }| + {7:│+ }{4:^▶}{13:--}{17: }{18:in his cave.}{13:······}| {1:~ }| {1:~ }| | ]]) end - eq('--\tsentence composed by', funcs.foldtextresult(3)) - eq('--\tin his cave.', funcs.foldtextresult(5)) + eq('▶--\tsentence composed by', funcs.foldtextresult(3)) + eq('▶--\tin his cave.', funcs.foldtextresult(5)) command('hi! Visual guibg=Red') feed('V2k') @@ -3029,8 +3034,8 @@ describe("folded lines", function() ## grid 2 {7: }This is a | {7:- }^v{14:alid English} | - {7:│+ }{15:--}{19: }{20:sentence composed }| - {7:│+ }{15:--}{19: }{20:in his cave.}{15:······}| + {7:│+ }{4:▶}{15:--}{19: }{20:sentence composed }| + {7:│+ }{4:▶}{15:--}{19: }{20:in his cave.}{15:······}| {1:~ }| {1:~ }| ## grid 3 @@ -3040,8 +3045,8 @@ describe("folded lines", function() screen:expect([[ {7: }This is a | {7:- }^v{14:alid English} | - {7:│+ }{15:--}{19: }{20:sentence composed }| - {7:│+ }{15:--}{19: }{20:in his cave.}{15:······}| + {7:│+ }{4:▶}{15:--}{19: }{20:sentence composed }| + {7:│+ }{4:▶}{15:--}{19: }{20:in his cave.}{15:······}| {1:~ }| {1:~ }| {11:-- VISUAL LINE --} | @@ -3062,8 +3067,8 @@ describe("folded lines", function() ## grid 2 a si sihT{7: }| {14:hsilgnE dila}^v{7: -}| - {20: desopmoc ecnetnes}{19: }{15:--}{7: +│}| - {15:······}{20:.evac sih ni}{19: }{15:--}{7: +│}| + {20: desopmoc ecnetnes}{19: }{15:--}{4:▶}{7: +│}| + {15:······}{20:.evac sih ni}{19: }{15:--}{4:▶}{7: +│}| {1: ~}| {1: ~}| ## grid 3 @@ -3073,8 +3078,8 @@ describe("folded lines", function() screen:expect([[ a si sihT{7: }| {14:hsilgnE dila}^v{7: -}| - {20: desopmoc ecnetnes}{19: }{15:--}{7: +│}| - {15:······}{20:.evac sih ni}{19: }{15:--}{7: +│}| + {20: desopmoc ecnetnes}{19: }{15:--}{4:▶}{7: +│}| + {15:······}{20:.evac sih ni}{19: }{15:--}{4:▶}{7: +│}| {1: ~}| {1: ~}| {11:-- VISUAL LINE --} |