diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c index 2c64935b64..e9e0e61331 100644 --- a/src/nvim/decoration.c +++ b/src/nvim/decoration.c @@ -865,6 +865,7 @@ static const uint32_t conceal_filter[kMTMetaCount] = {[kMTMetaConcealLines] = kM /// @return whether "row" is concealed bool decor_conceal_line(win_T *wp, int row, bool check_cursor) { + assert(row >= 0); if (wp->w_p_cole < 2 || (!check_cursor && wp == curwin && row + 1 == wp->w_cursor.lnum && !conceal_cursor_line(wp))) { diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 405d699055..2e75d70802 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -2449,10 +2449,10 @@ void cursor_up_inner(win_T *wp, linenr_T n, bool skip_conceal) while (n--) { // move up one line lnum--; - n += skip_conceal && decor_conceal_line(wp, lnum - 1, true); if (lnum <= 1) { break; } + n += skip_conceal && decor_conceal_line(wp, lnum - 1, true); // If we entered a fold, move to the beginning, unless in // Insert mode or when 'foldopen' contains "all": it will open // in a moment. @@ -2506,10 +2506,10 @@ void cursor_down_inner(win_T *wp, int n, bool skip_conceal) } else { lnum++; } - n += skip_conceal && decor_conceal_line(wp, lnum - 1, true); if (lnum >= line_count) { break; } + n += skip_conceal && decor_conceal_line(wp, lnum - 1, true); } lnum = MIN(lnum, line_count); } else { diff --git a/src/nvim/move.c b/src/nvim/move.c index 20850c044e..59e67788fd 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -331,10 +331,10 @@ void update_topline(win_T *wp) // scrolled). n = 0; 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 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; } hasFolding(wp, lnum, NULL, &lnum); @@ -404,23 +404,23 @@ void update_topline(win_T *wp) } } if (check_botline) { - int line_count = 0; + int n = 0; if (win_lines_concealed(wp)) { // Count the number of logical lines between the cursor and // botline - p_so (approximation of how much will be // scrolled). 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 - 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; } hasFolding(wp, lnum, &lnum, NULL); } } 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); } else { scroll_cursor_halfway(wp, false, false); @@ -513,7 +513,7 @@ void check_cursor_moved(win_T *wp) |VALID_CHEIGHT|VALID_CROW|VALID_TOPLINE); // 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_valid_cursor.lnum - 1, true))) { changed_window_setting(wp); diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 69020fa5bb..070c21de9d 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -3524,6 +3524,17 @@ describe('extmark decorations', function() eq(5, n.fn.line('w0')) 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() fn.setline(1, { 'aaa', 'bbb', 'ccc', 'ddd' }) api.nvim_buf_set_extmark(0, ns, 1, 0, { virt_text = { { 'foo' } }, right_gravity = false })