diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index c1a78cc775..ae3e5698b2 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -21,6 +21,7 @@ #include "nvim/decoration_provider.h" #include "nvim/diff.h" #include "nvim/drawline.h" +#include "nvim/eval.h" #include "nvim/extmark_defs.h" #include "nvim/fold.h" #include "nvim/garray.h" @@ -413,7 +414,7 @@ static void get_statuscol_str(win_T *wp, linenr_T lnum, int row, int startrow, i set_vim_var_nr(VV_VIRTNUM, virtnum); // When called the first time for line "lnum" set num_attr - if (row == startrow) { + if (stcp->num_attr == 0) { stcp->num_attr = sign_num_attr ? sign_num_attr : get_line_number_attr(wp, lnum, row, startrow, filler_lines); } @@ -1203,6 +1204,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } int sign_idx = 0; + int virt_line_index; + int virt_line_offset = -1; // Repeat for the whole displayed line. for (;;) { int has_match_conc = 0; ///< match wants to conceal @@ -1229,9 +1232,22 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } } - // Skip fold, sign and number states if 'statuscolumn' is set. - if (draw_state == WL_FOLD - 1 && n_extra == 0 && statuscol.draw) { - draw_state = WL_STC - 1; + if (draw_state == WL_FOLD - 1 && n_extra == 0) { + if (filler_todo > 0) { + int index = filler_todo - (filler_lines - n_virt_lines); + if (index > 0) { + virt_line_index = (int)kv_size(virt_lines) - index; + assert(virt_line_index >= 0); + virt_line_offset = kv_A(virt_lines, virt_line_index).left_col ? 0 : win_col_off(wp); + } + } + if (!virt_line_offset) { + // Skip the column states if there is a "virt_left_col" line. + draw_state = WL_BRI - 1; + } else if (statuscol.draw) { + // Skip fold, sign and number states if 'statuscolumn' is set. + draw_state = WL_STC - 1; + } } if (draw_state == WL_FOLD - 1 && n_extra == 0) { @@ -2754,15 +2770,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, && !wp->w_p_rl; // Not right-to-left. int draw_col = col - boguscols; - if (filler_todo > 0) { - int index = filler_todo - (filler_lines - n_virt_lines); - if (index > 0) { - int i = (int)kv_size(virt_lines) - index; - assert(i >= 0); - int offset = kv_A(virt_lines, i).left_col ? 0 : win_col_offset; - draw_virt_text_item(buf, offset, kv_A(virt_lines, i).line, - kHlModeReplace, grid->cols, 0); - } + if (virt_line_offset >= 0) { + draw_virt_text_item(buf, virt_line_offset, kv_A(virt_lines, virt_line_index).line, + kHlModeReplace, grid->cols, 0); } else { draw_virt_text(wp, buf, win_col_offset, &draw_col, grid->cols, row); } @@ -2825,13 +2835,15 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (row == startrow + filler_lines + 1 || row == startrow + filler_lines) { // Re-evaluate 'statuscolumn' for the first wrapped row and non filler line statuscol.textp = NULL; - } else { // Otherwise just reset the text/hlrec pointers + } else if (statuscol.textp) { + // Draw the already built 'statuscolumn' on the next wrapped or filler line statuscol.textp = statuscol.text; statuscol.hlrecp = statuscol.hlrec; } // Fall back to default columns if the 'n' flag isn't in 'cpo' statuscol.draw = vim_strchr(p_cpo, CPO_NUMCOL) == NULL; } filler_todo--; + virt_line_offset = -1; // When the filler lines are actually below the last line of the // file, don't draw the line itself, break here. if (filler_todo == 0 && (wp->w_botfill || end_fill)) { diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua index fd57d5dfba..82b91c7788 100644 --- a/test/functional/ui/statuscolumn_spec.lua +++ b/test/functional/ui/statuscolumn_spec.lua @@ -4,7 +4,7 @@ local clear = helpers.clear local command = helpers.command local eq = helpers.eq local eval = helpers.eval -local exec = helpers.exec_lua +local exec_lua = helpers.exec_lua local meths = helpers.meths local pcall_err = helpers.pcall_err @@ -16,8 +16,8 @@ describe('statuscolumn', function() screen:attach() end) - it('fails with invalid \'statuscolumn\'', function() - command('set stc=%{v:relnum?v:relnum:(v:lnum==5?invalid:v:lnum)}\\ ') + it("fails with invalid 'statuscolumn'", function() + command([[set stc=%{v:relnum?v:relnum:(v:lnum==5?invalid:v:lnum)}\ ]]) screen:expect([[ 4 aaaaa | 3 aaaaa | @@ -39,8 +39,8 @@ describe('statuscolumn', function() eq('', eval('&statuscolumn')) end) - it('widens with irregular \'statuscolumn\' width', function() - command('set stc=%{v:relnum?v:relnum:(v:lnum==5?\'bbbbb\':v:lnum)}') + it("widens with irregular 'statuscolumn' width", function() + command([[set stc=%{v:relnum?v:relnum:(v:lnum==5?'bbbbb':v:lnum)}]]) command('norm 5G | redraw!') screen:expect([[ 1 aaaaa | @@ -60,7 +60,7 @@ describe('statuscolumn', function() ]]) end) - it('works with \'statuscolumn\'', function() + it("works with 'statuscolumn'", function() command([[set stc=%{&nu?v:lnum:''}%=%{&rnu?'\ '.v:relnum:''}│]]) screen:expect([[ 4 │aaaaa | @@ -123,7 +123,7 @@ describe('statuscolumn', function() command([[set stc=%{&nu?v:lnum:''}%=%{&rnu?'\ '.v:relnum:''}│]]) end) - it('works with highlighted \'statuscolumn\'', function() + it("works with highlighted 'statuscolumn'", function() command([[set stc=%#NonText#%{&nu?v:lnum:''}]] .. [[%=%{&rnu&&(v:lnum%2)?'\ '.v:relnum:''}]] .. [[%#LineNr#%{&rnu&&!(v:lnum%2)?'\ '.v:relnum:''}│]]) @@ -184,7 +184,7 @@ describe('statuscolumn', function() end) it('works with wrapped lines, signs and folds', function() - command("set stc=%C%s%=%{v:virtnum?'':v:lnum}│\\ ") + command([[set stc=%C%s%=%{v:virtnum?'':v:lnum}│\ ]]) command("call setline(1,repeat([repeat('aaaaa',10)],16))") screen:set_default_attr_ids({ [0] = {bold = true, foreground = Screen.colors.Blue}, @@ -235,7 +235,7 @@ describe('statuscolumn', function() ]]) command('norm zf$') -- Check that alignment works properly with signs after %= - command("set stc=%C%=%{v:virtnum?'':v:lnum}│%s\\ ") + command([[set stc=%C%=%{v:virtnum?'':v:lnum}│%s\ ]]) screen:expect([[ {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| {2: }{1: │}{2: }{1: }aaaaaa | @@ -270,7 +270,7 @@ describe('statuscolumn', function() | ]]) -- v:lnum is the same value on wrapped lines - command("set stc=%C%=%{v:lnum}│%s\\ ") + command([[set stc=%C%=%{v:lnum}│%s\ ]]) screen:expect([[ {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| {2: }{1: 4│}{2: }{1: }aaaaaa | @@ -288,7 +288,7 @@ describe('statuscolumn', function() | ]]) -- v:relnum is the same value on wrapped lines - command("set stc=%C%=\\ %{v:relnum}│%s\\ ") + command([[set stc=%C%=\ %{v:relnum}│%s\ ]]) screen:expect([[ {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| {2: }{1: 4│}{2: }{1: }aaaaaa | @@ -348,14 +348,11 @@ describe('statuscolumn', function() | ]]) -- Status column is re-evaluated for virt_lines, buffer line, and wrapped line - exec([[ + exec_lua([[ local ns = vim.api.nvim_create_namespace("ns") - vim.api.nvim_buf_set_extmark(0, ns, 4, 0, { - virt_lines = {{{"virt_line", ""}}, {{"virt_line", ""}}} - }) vim.api.nvim_buf_set_extmark(0, ns, 5, 0, { - virt_lines_above = true, virt_lines = {{{"virt_line above", ""}}, {{"virt_line above", ""}}} - }) + virt_lines_above = true, virt_lines = {{{"virt_line above", ""}}} }) + vim.api.nvim_buf_set_extmark(0, ns, 4, 0, { virt_lines = {{{"virt_line", ""}}} }) ]]) command('set foldcolumn=0 signcolumn=no') command([[set stc=%{v:virtnum<0?'virtual':(!v:virtnum?'buffer':'wrapped')}%=%{'\ '.v:virtnum.'\ '.v:lnum}]]) @@ -364,20 +361,20 @@ describe('statuscolumn', function() {1:wrapped 1 4}aaaaaaaa | {1:buffer 0 5}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| {1:wrapped 1 5}aaaaaaaa | - {1:virtual-4 5}virt_line | - {1:virtual-4 5}virt_line | - {1:virtual-4 5}virt_line above | - {1:virtual-4 5}virt_line above | + {1:virtual-2 5}virt_line | + {1:virtual-2 5}virt_line above | {1:buffer 0 6}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| {1:wrapped 1 6}aaaaaaaa | {1:buffer 0 7}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| {1:wrapped 1 7}aaaaaaaa | {4:buffer 0 8}{5:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {1:buffer 0 9}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {1:wrapped 1 9}aaaaaaaa | | ]]) end) - it('works with \'statuscolumn\' clicks', function() + it("works with 'statuscolumn' clicks", function() command('set mousemodel=extend') command([[ function! MyClickFunc(minwid, clicks, button, mods) @@ -414,25 +411,36 @@ describe('statuscolumn', function() eq('', eval("g:testvar")) end) - it('fits maximum multibyte foldcolumn #21759', function() - command('set stc=%C fdc=9 fillchars=foldsep:𒀀') + it('works with foldcolumn', function() + -- Fits maximum multibyte foldcolumn #21759 + command([[set stc=%C%=%l\ fdc=9 fillchars=foldsep:𒀀]]) for _ = 0,8 do command('norm zfjzo') end + -- 'statuscolumn' is not drawn for `virt_lines_leftcol` lines + exec_lua([[ + local ns = vim.api.nvim_create_namespace("ns") + vim.api.nvim_buf_set_extmark(0, ns, 6, 0, { + virt_lines_leftcol = true, virt_lines = {{{"virt", ""}}} }) + vim.api.nvim_buf_set_extmark(0, ns, 7, 0, { + virt_lines_leftcol = true, virt_lines = {{{"virt", ""}}} }) + ]]) + helpers.feed('lh') -- force update wcol/row screen:expect([[ - aaaaa | - aaaaa | - aaaaa | - aaaaa | - --------- ^aaaaa | - 𒀀𒀀𒀀𒀀𒀀𒀀𒀀𒀀𒀀 aaaaa | - aaaaa | - aaaaa | - aaaaa | - aaaaa | - aaaaa | - aaaaa | - aaaaa | + 4 aaaaa | + 5 aaaaa | + 6 aaaaa | + 7 aaaaa | + virt | + --------- 8 ^aaaaa | + virt | + 𒀀𒀀𒀀𒀀𒀀𒀀𒀀𒀀𒀀 9 aaaaa | + 10 aaaaa | + 11 aaaaa | + 12 aaaaa | + 13 aaaaa | + 14 aaaaa | | ]]) + command('set stc=') -- also for the default sign column + screen:expect_unchanged() end) - end)