diff options
-rw-r--r-- | src/nvim/extmark.c | 19 | ||||
-rw-r--r-- | test/functional/ui/inccommand_spec.lua | 72 |
2 files changed, 86 insertions, 5 deletions
diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c index d60723c755..60ff5c3af9 100644 --- a/src/nvim/extmark.c +++ b/src/nvim/extmark.c @@ -699,21 +699,30 @@ void bufhl_add_hl_pos_offset(buf_T *buf, // TODO(bfredl): if decoration had blocky mode, we could avoid this loop for (linenr_T lnum = pos_start.lnum; lnum <= pos_end.lnum; lnum ++) { + int end_off = 0; if (pos_start.lnum < lnum && lnum < pos_end.lnum) { - hl_start = offset-1; - hl_end = MAXCOL; + // TODO(bfredl): This is quite ad-hoc, but the space between |num| and + // text being highlighted is the indication of \n being part of the + // substituted text. But it would be more consistent to highlight + // a space _after_ the previous line instead (like highlight EOL list + // char) + hl_start = MAX(offset-1, 0); + end_off = 1; + hl_end = 0; } else if (lnum == pos_start.lnum && lnum < pos_end.lnum) { hl_start = pos_start.col + offset; - hl_end = MAXCOL; + end_off = 1; + hl_end = 0; } else if (pos_start.lnum < lnum && lnum == pos_end.lnum) { - hl_start = offset-1; + hl_start = MAX(offset-1, 0); hl_end = pos_end.col + offset; } else if (pos_start.lnum == lnum && pos_end.lnum == lnum) { hl_start = pos_start.col + offset; hl_end = pos_end.col + offset; } (void)extmark_add_decoration(buf, (uint64_t)src_id, hl_id, - (int)lnum-1, hl_start, (int)lnum-1, hl_end, + (int)lnum-1, hl_start, + (int)lnum-1+end_off, hl_end, VIRTTEXT_EMPTY); } } diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua index b841574643..afb0c9cfa6 100644 --- a/test/functional/ui/inccommand_spec.lua +++ b/test/functional/ui/inccommand_spec.lua @@ -18,6 +18,7 @@ local wait = helpers.wait local nvim = helpers.nvim local sleep = helpers.sleep local nvim_dir = helpers.nvim_dir +local assert_alive = helpers.assert_alive local default_text = [[ Inc substitution on @@ -84,6 +85,7 @@ local function common_setup(screen, inccommand, text) [14] = {foreground = Screen.colors.White, background = Screen.colors.Red}, [15] = {bold=true, foreground=Screen.colors.Blue}, [16] = {background=Screen.colors.Grey90}, -- cursorline + [17] = {foreground = Screen.colors.Blue1}, vis = {background=Screen.colors.LightGrey} }) end @@ -2291,6 +2293,76 @@ describe(":substitute", function() ]]) end) + it("inccommand=split, contraction of two subsequent NL chars", function() + -- luacheck: push ignore 611 + local text = [[ + AAA AA + + BBB BB + + CCC CC + +]] + -- luacheck: pop + + -- This used to crash, but more than 20 highlight entries are required + -- to reproduce it (so that the marktree has multiple nodes) + common_setup(screen, "split", string.rep(text,10)) + feed(":%s/\\n\\n/<c-v><c-m>/g") + screen:expect{grid=[[ + CCC CC | + AAA AA | + BBB BB | + CCC CC | + | + {11:[No Name] [+] }| + | 1| AAA AA | + | 2|{12: }BBB BB | + | 3|{12: }CCC CC | + | 4|{12: }AAA AA | + | 5|{12: }BBB BB | + | 6|{12: }CCC CC | + | 7|{12: }AAA AA | + {10:[Preview] }| + :%s/\n\n/{17:^M}/g^ | + ]]} + assert_alive() + end) + + it("inccommand=nosplit, contraction of two subsequent NL chars", function() + -- luacheck: push ignore 611 + local text = [[ + AAA AA + + BBB BB + + CCC CC + +]] + -- luacheck: pop + + common_setup(screen, "nosplit", string.rep(text,10)) + feed(":%s/\\n\\n/<c-v><c-m>/g") + screen:expect{grid=[[ + CCC CC | + AAA AA | + BBB BB | + CCC CC | + AAA AA | + BBB BB | + CCC CC | + AAA AA | + BBB BB | + CCC CC | + AAA AA | + BBB BB | + CCC CC | + | + :%s/\n\n/{17:^M}/g^ | + ]]} + assert_alive() + end) + it("inccommand=split, multibyte text", function() common_setup(screen, "split", multibyte_text) feed(":%s/£.*ѫ/X¥¥") |