fix(conceal): check for concealed lines on invalid row (#36084)

Problem:  May check for concealed lines on invalid line numbers.
Solution: Move checks after line number validation.
This commit is contained in:
luukvbaal
2025-10-09 15:44:11 +02:00
committed by GitHub
parent 645206e87f
commit ad8bce6674
4 changed files with 22 additions and 10 deletions

View File

@@ -865,6 +865,7 @@ static const uint32_t conceal_filter[kMTMetaCount] = {[kMTMetaConcealLines] = kM
/// @return whether "row" is concealed /// @return whether "row" is concealed
bool decor_conceal_line(win_T *wp, int row, bool check_cursor) bool decor_conceal_line(win_T *wp, int row, bool check_cursor)
{ {
assert(row >= 0);
if (wp->w_p_cole < 2 if (wp->w_p_cole < 2
|| (!check_cursor && wp == curwin && row + 1 == wp->w_cursor.lnum || (!check_cursor && wp == curwin && row + 1 == wp->w_cursor.lnum
&& !conceal_cursor_line(wp))) { && !conceal_cursor_line(wp))) {

View File

@@ -2449,10 +2449,10 @@ void cursor_up_inner(win_T *wp, linenr_T n, bool skip_conceal)
while (n--) { while (n--) {
// move up one line // move up one line
lnum--; lnum--;
n += skip_conceal && decor_conceal_line(wp, lnum - 1, true);
if (lnum <= 1) { if (lnum <= 1) {
break; break;
} }
n += skip_conceal && decor_conceal_line(wp, lnum - 1, true);
// If we entered a fold, move to the beginning, unless in // If we entered a fold, move to the beginning, unless in
// Insert mode or when 'foldopen' contains "all": it will open // Insert mode or when 'foldopen' contains "all": it will open
// in a moment. // in a moment.
@@ -2506,10 +2506,10 @@ void cursor_down_inner(win_T *wp, int n, bool skip_conceal)
} else { } else {
lnum++; lnum++;
} }
n += skip_conceal && decor_conceal_line(wp, lnum - 1, true);
if (lnum >= line_count) { if (lnum >= line_count) {
break; break;
} }
n += skip_conceal && decor_conceal_line(wp, lnum - 1, true);
} }
lnum = MIN(lnum, line_count); lnum = MIN(lnum, line_count);
} else { } else {

View File

@@ -331,10 +331,10 @@ void update_topline(win_T *wp)
// scrolled). // scrolled).
n = 0; n = 0;
for (linenr_T lnum = wp->w_cursor.lnum; lnum < wp->w_topline + *so_ptr; lnum++) { for (linenr_T lnum = wp->w_cursor.lnum; lnum < wp->w_topline + *so_ptr; lnum++) {
n += !decor_conceal_line(wp, lnum, false);
// stop at end of file or when we know we are far off // stop at end of file or when we know we are far off
assert(wp->w_buffer != 0); assert(wp->w_buffer != 0);
if (lnum >= wp->w_buffer->b_ml.ml_line_count || n >= halfheight) { if (lnum >= wp->w_buffer->b_ml.ml_line_count
|| (n += !decor_conceal_line(wp, lnum, false)) >= halfheight) {
break; break;
} }
hasFolding(wp, lnum, NULL, &lnum); hasFolding(wp, lnum, NULL, &lnum);
@@ -404,23 +404,23 @@ void update_topline(win_T *wp)
} }
} }
if (check_botline) { if (check_botline) {
int line_count = 0; int n = 0;
if (win_lines_concealed(wp)) { if (win_lines_concealed(wp)) {
// Count the number of logical lines between the cursor and // Count the number of logical lines between the cursor and
// botline - p_so (approximation of how much will be // botline - p_so (approximation of how much will be
// scrolled). // scrolled).
for (linenr_T lnum = wp->w_cursor.lnum; lnum >= wp->w_botline - *so_ptr; lnum--) { for (linenr_T lnum = wp->w_cursor.lnum; lnum >= wp->w_botline - *so_ptr; lnum--) {
line_count += !decor_conceal_line(wp, lnum - 1, false);
// stop at end of file or when we know we are far off // stop at end of file or when we know we are far off
if (lnum <= 0 || line_count > wp->w_view_height + 1) { if (lnum <= 0
|| (n += !decor_conceal_line(wp, lnum - 1, false)) > wp->w_view_height + 1) {
break; break;
} }
hasFolding(wp, lnum, &lnum, NULL); hasFolding(wp, lnum, &lnum, NULL);
} }
} else { } else {
line_count = wp->w_cursor.lnum - wp->w_botline + 1 + (int)(*so_ptr); n = wp->w_cursor.lnum - wp->w_botline + 1 + (int)(*so_ptr);
} }
if (line_count <= wp->w_view_height + 1) { if (n <= wp->w_view_height + 1) {
scroll_cursor_bot(wp, scrolljump_value(wp), false); scroll_cursor_bot(wp, scrolljump_value(wp), false);
} else { } else {
scroll_cursor_halfway(wp, false, false); scroll_cursor_halfway(wp, false, false);
@@ -513,7 +513,7 @@ void check_cursor_moved(win_T *wp)
|VALID_CHEIGHT|VALID_CROW|VALID_TOPLINE); |VALID_CHEIGHT|VALID_CROW|VALID_TOPLINE);
// Concealed line visibility toggled. // Concealed line visibility toggled.
if (wp->w_p_cole >= 2 && !conceal_cursor_line(wp) if (wp->w_valid_cursor.lnum > 0 && wp->w_p_cole >= 2 && !conceal_cursor_line(wp)
&& (decor_conceal_line(wp, wp->w_cursor.lnum - 1, true) && (decor_conceal_line(wp, wp->w_cursor.lnum - 1, true)
|| decor_conceal_line(wp, wp->w_valid_cursor.lnum - 1, true))) { || decor_conceal_line(wp, wp->w_valid_cursor.lnum - 1, true))) {
changed_window_setting(wp); changed_window_setting(wp);

View File

@@ -3524,6 +3524,17 @@ describe('extmark decorations', function()
eq(5, n.fn.line('w0')) eq(5, n.fn.line('w0'))
end) end)
it('conceal_lines not checking on invalid row #36057', function()
exec_lua(function()
vim.fn.setline(1, { 'foo', 'bar', 'baz' })
vim.api.nvim_command('set conceallevel=3 scrolloff=3')
vim.api.nvim_open_win(0, true, { width = 1, height = 1, relative = 'editor', row = 0, col = 0 })
vim.api.nvim_buf_set_extmark(0, ns, 1, 0, { conceal_lines = '' })
vim.api.nvim__redraw({ flush = true })
end)
n.assert_alive()
end)
it('redraws the line from which a left gravity mark has moved #27369', function() it('redraws the line from which a left gravity mark has moved #27369', function()
fn.setline(1, { 'aaa', 'bbb', 'ccc', 'ddd' }) fn.setline(1, { 'aaa', 'bbb', 'ccc', 'ddd' })
api.nvim_buf_set_extmark(0, ns, 1, 0, { virt_text = { { 'foo' } }, right_gravity = false }) api.nvim_buf_set_extmark(0, ns, 1, 0, { virt_text = { { 'foo' } }, right_gravity = false })