diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c index 015c578396..b89d346fbf 100644 --- a/src/nvim/statusline.c +++ b/src/nvim/statusline.c @@ -1031,6 +1031,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n int evaldepth = 0; int curitem = 0; + int foldsignitem = -1; bool prevchar_isflag = true; bool prevchar_isitem = false; @@ -1655,6 +1656,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n if (width == 0) { break; } + foldsignitem = curitem; char *p = NULL; if (fold) { @@ -1664,32 +1666,22 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n p[n] = NUL; } - *buf_tmp = NUL; + size_t buflen = 0; varnumber_T virtnum = get_vim_var_nr(VV_VIRTNUM); - for (int i = 0; i <= width; i++) { - if (i == width) { - if (*buf_tmp == NUL) { - break; - } - stl_items[curitem].minwid = 0; - } else if (!fold) { + for (int i = 0; i < width; i++) { + if (!fold) { SignTextAttrs *sattr = virtnum ? NULL : sign_get_attr(i, stcp->sattrs, wp->w_scwidth); p = sattr && sattr->text ? sattr->text : " "; stl_items[curitem].minwid = -(sattr ? stcp->sign_cul_id ? stcp->sign_cul_id : sattr->hl_id : (stcp->use_cul ? HLF_CLS : HLF_SC) + 1); } - size_t buflen = strlen(buf_tmp); stl_items[curitem].type = Highlight; stl_items[curitem].start = out_p + buflen; + xstrlcpy(buf_tmp + buflen, p, TMPLEN - buflen); + buflen += strlen(p); curitem++; - if (i == width) { - str = buf_tmp; - break; - } - int rc = snprintf(buf_tmp + buflen, sizeof(buf_tmp) - buflen, "%s", p); - (void)rc; // Avoid unused warning on release build - assert(rc > 0); } + str = buf_tmp; break; } @@ -1832,6 +1824,13 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n } } minwid = 0; + // For a 'statuscolumn' sign or fold item, shift the added items + if (foldsignitem >= 0) { + ptrdiff_t offset = out_p - stl_items[foldsignitem].start; + for (int i = foldsignitem; i < curitem; i++) { + stl_items[i].start += offset; + } + } } else { // Note: The negative value denotes a left aligned item. // Here we switch the minimum width back to a positive value. @@ -1851,6 +1850,14 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n } // } + // For a 'statuscolumn' sign or fold item, add an item to reset the highlight group + if (foldsignitem >= 0) { + foldsignitem = -1; + stl_items[curitem].type = Highlight; + stl_items[curitem].start = out_p; + stl_items[curitem].minwid = 0; + } + // For left-aligned items, fill any remaining space with the fillchar for (; l < minwid && out_p < out_end_p; l++) { MB_CHAR2BYTES(fillchar, out_p); diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua index c218bd8fd6..6624fb008d 100644 --- a/test/functional/ui/statuscolumn_spec.lua +++ b/test/functional/ui/statuscolumn_spec.lua @@ -424,6 +424,21 @@ describe('statuscolumn', function() ]]) end) + it('does not corrupt the screen with minwid sign item', function() + screen:try_resize(screen._width, 3) + screen:set_default_attr_ids({ + [0] = {foreground = Screen.colors.Brown}, + [1] = {foreground = Screen.colors.Blue4, background = Screen.colors.Gray}, + }) + command([[set stc=%6s\ %l]]) + exec_lua('vim.api.nvim_buf_set_extmark(0, ns, 7, 0, {sign_text = "ð’€€"})') + screen:expect([[ + {0: ð’€€ 8}^aaaaa | + {0: }{1: }{0: 9}aaaaa | + | + ]]) + end) + for _, model in ipairs(mousemodels) do it("works with 'statuscolumn' clicks with mousemodel=" .. model, function() command('set mousemodel=' .. model)