commit 66dddd8b515af1d195ed0dcea04de5bfc948a954
parent c4e52d604c9ac2fd47ab176ef0d1e4d72015485b
Author: Sean Dewar <6256228+seandewar@users.noreply.github.com>
Date: Sun, 11 May 2025 21:30:04 +0100
fix(folds): adjust filler text drawing for transparent folds
Problem: Search highlighting is applied strangely to the filler text of
transparent folds, and EOL list characters are not shown.
Solution: Don't apply search highlighting to the last column of the window row
if the last text char on the line is highlighted. Display the EOL list char if
needed. Don't highlight the entire filler text when matching EOL, just highlight
the EOL list char or the first filler char.
Diffstat:
2 files changed, 196 insertions(+), 2 deletions(-)
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
@@ -1951,11 +1951,15 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, b
ptr = line + v;
}
- if (draw_folded && wlv.n_extra == 0 && wlv.col < view_width && (has_foldtext || *ptr == NUL)) {
+ // Draw 'fold' fillchar after 'foldtext', or after 'eol' listchar for transparent 'foldtext'.
+ if (draw_folded && wlv.n_extra == 0 && wlv.col < view_width
+ && (has_foldtext || (*ptr == NUL && (!wp->w_p_list || !lcs_eol_todo || lcs_eol == NUL)))) {
// Fill rest of line with 'fold'.
wlv.sc_extra = wp->w_p_fcs_chars.fold;
wlv.sc_final = NUL;
wlv.n_extra = view_width - wlv.col;
+ // Don't continue search highlighting past the first filler char.
+ search_attr = 0;
}
if (draw_folded && wlv.n_extra != 0 && wlv.col >= view_width) {
@@ -2712,7 +2716,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, b
// Add a blank character to highlight.
linebuf_char[wlv.off] = schar_from_ascii(' ');
}
- if (area_attr == 0 && !has_foldtext) {
+ if (area_attr == 0 && !has_fold) {
// Use attributes from match with highest priority among
// 'search_hl' and the match list.
get_search_match_hl(wp,
diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua
@@ -56,6 +56,7 @@ describe('folded lines', function()
[20] = { background = Screen.colors.Red, bold = true, foreground = Screen.colors.Blue },
[21] = { background = Screen.colors.LightGrey, foreground = Screen.colors.Green },
[22] = { background = Screen.colors.Red, foreground = Screen.colors.Green },
+ [23] = { foreground = Screen.colors.Blue1, bold = true, background = Screen.colors.Yellow },
})
end)
@@ -2829,6 +2830,195 @@ describe('folded lines', function()
]])
end
end)
+
+ it('transparent foldtext filler text search highlighting', function()
+ screen:try_resize(30, 7)
+ insert(content1)
+ api.nvim_set_option_value('foldtext', '', {})
+
+ command("3,4fold | let v:hlsearch = 1 | let @/ = '.'")
+ if multigrid then
+ screen:expect({
+ grid = [[
+ ## grid 1
+ [2:------------------------------]|*6
+ [3:------------------------------]|
+ ## grid 2
+ {6:This is a} |
+ {6:valid English} |
+ {19:sentence composed by}{5:··········}|
+ {6:in his cave.} |
+ ^ |
+ {1:~ }|
+ ## grid 3
+ |
+ ]],
+ })
+ else
+ screen:expect([[
+ {6:This is a} |
+ {6:valid English} |
+ {19:sentence composed by}{5:··········}|
+ {6:in his cave.} |
+ ^ |
+ {1:~ }|
+ |
+ ]])
+ end
+
+ command("let @/ = '$'")
+ if multigrid then
+ screen:expect({
+ grid = [[
+ ## grid 1
+ [2:------------------------------]|*6
+ [3:------------------------------]|
+ ## grid 2
+ This is a{6: } |
+ valid English{6: } |
+ {5:sentence composed by}{19:·}{5:·········}|
+ in his cave.{6: } |
+ {6:^ } |
+ {1:~ }|
+ ## grid 3
+ |
+ ]],
+ })
+ else
+ screen:expect([[
+ This is a{6: } |
+ valid English{6: } |
+ {5:sentence composed by}{19:·}{5:·········}|
+ in his cave.{6: } |
+ {6:^ } |
+ {1:~ }|
+ |
+ ]])
+ end
+
+ command("let @/ = '.\\?'")
+ if multigrid then
+ screen:expect({
+ grid = [[
+ ## grid 1
+ [2:------------------------------]|*6
+ [3:------------------------------]|
+ ## grid 2
+ {6:This is a } |
+ {6:valid English } |
+ {19:sentence composed by·}{5:·········}|
+ {6:in his cave. } |
+ {6:^ } |
+ {1:~ }|
+ ## grid 3
+ |
+ ]],
+ })
+ else
+ screen:expect([[
+ {6:This is a } |
+ {6:valid English } |
+ {19:sentence composed by·}{5:·········}|
+ {6:in his cave. } |
+ {6:^ } |
+ {1:~ }|
+ |
+ ]])
+ end
+
+ command('set list')
+ screen:expect_unchanged() -- No "eol" set for &listchars yet.
+
+ command("set listchars+=eol:& | let @/ = '.'")
+ if multigrid then
+ screen:expect({
+ grid = [[
+ ## grid 1
+ [2:------------------------------]|*6
+ [3:------------------------------]|
+ ## grid 2
+ {6:This is a}{1:&} |
+ {6:valid English}{1:&} |
+ {19:sentence composed by}{18:&}{5:·········}|
+ {6:in his cave.}{1:&} |
+ {1:^&} |
+ {1:~ }|
+ ## grid 3
+ |
+ ]],
+ })
+ else
+ screen:expect([[
+ {6:This is a}{1:&} |
+ {6:valid English}{1:&} |
+ {19:sentence composed by}{18:&}{5:·········}|
+ {6:in his cave.}{1:&} |
+ {1:^&} |
+ {1:~ }|
+ |
+ ]])
+ end
+
+ command("let @/ = '$'")
+ if multigrid then
+ screen:expect({
+ grid = [[
+ ## grid 1
+ [2:------------------------------]|*6
+ [3:------------------------------]|
+ ## grid 2
+ This is a{23:&} |
+ valid English{23:&} |
+ {5:sentence composed by}{23:&}{5:·········}|
+ in his cave.{23:&} |
+ {23:^&} |
+ {1:~ }|
+ ## grid 3
+ |
+ ]],
+ })
+ else
+ screen:expect([[
+ This is a{23:&} |
+ valid English{23:&} |
+ {5:sentence composed by}{23:&}{5:·········}|
+ in his cave.{23:&} |
+ {23:^&} |
+ {1:~ }|
+ |
+ ]])
+ end
+
+ command("let @/ = '.\\?'")
+ if multigrid then
+ screen:expect({
+ grid = [[
+ ## grid 1
+ [2:------------------------------]|*6
+ [3:------------------------------]|
+ ## grid 2
+ {6:This is a}{23:&} |
+ {6:valid English}{23:&} |
+ {19:sentence composed by}{23:&}{5:·········}|
+ {6:in his cave.}{23:&} |
+ {23:^&} |
+ {1:~ }|
+ ## grid 3
+ |
+ ]],
+ })
+ else
+ screen:expect([[
+ {6:This is a}{23:&} |
+ {6:valid English}{23:&} |
+ {19:sentence composed by}{23:&}{5:·········}|
+ {6:in his cave.}{23:&} |
+ {23:^&} |
+ {1:~ }|
+ |
+ ]])
+ end
+ end)
end
describe('with ext_multigrid', function()