mirror of
https://github.com/neovim/neovim.git
synced 2025-10-14 22:06:07 +00:00
fix(folds): cursorline highlight is not always applied on closed folds (#22242)
Problem: The cursorline highlight logic checks for `w_cursor.lnum` which may be different from the line number passed to `win_line()` even when the cursor is actually on that line. Solution: Update cursor line highlight logic to check for the line number of the start of a closed fold if necessary.
This commit is contained in:
@@ -1112,20 +1112,23 @@ struct window_S {
|
|||||||
win_T *w_prev; ///< link to previous window
|
win_T *w_prev; ///< link to previous window
|
||||||
win_T *w_next; ///< link to next window
|
win_T *w_next; ///< link to next window
|
||||||
bool w_closing; ///< window is being closed, don't let
|
bool w_closing; ///< window is being closed, don't let
|
||||||
/// autocommands close it too.
|
///< autocommands close it too.
|
||||||
|
|
||||||
frame_T *w_frame; ///< frame containing this window
|
frame_T *w_frame; ///< frame containing this window
|
||||||
|
|
||||||
pos_T w_cursor; ///< cursor position in buffer
|
pos_T w_cursor; ///< cursor position in buffer
|
||||||
|
|
||||||
colnr_T w_curswant; ///< Column we want to be at. This is
|
colnr_T w_curswant; ///< Column we want to be at. This is
|
||||||
/// used to try to stay in the same column
|
///< used to try to stay in the same column
|
||||||
/// for up/down cursor motions.
|
///< for up/down cursor motions.
|
||||||
|
|
||||||
int w_set_curswant; // If set, then update w_curswant the next
|
int w_set_curswant; // If set, then update w_curswant the next
|
||||||
// time through cursupdate() to the
|
// time through cursupdate() to the
|
||||||
// current virtual column
|
// current virtual column
|
||||||
|
|
||||||
|
linenr_T w_cursorline; ///< Where 'cursorline' should be drawn,
|
||||||
|
///< can be different from w_cursor.lnum
|
||||||
|
///< for closed folds.
|
||||||
linenr_T w_last_cursorline; ///< where last 'cursorline' was drawn
|
linenr_T w_last_cursorline; ///< where last 'cursorline' was drawn
|
||||||
pos_T w_last_cursormoved; ///< for CursorMoved event
|
pos_T w_last_cursormoved; ///< for CursorMoved event
|
||||||
|
|
||||||
|
@@ -303,7 +303,7 @@ static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode,
|
|||||||
static bool use_cursor_line_sign(win_T *wp, linenr_T lnum)
|
static bool use_cursor_line_sign(win_T *wp, linenr_T lnum)
|
||||||
{
|
{
|
||||||
return wp->w_p_cul
|
return wp->w_p_cul
|
||||||
&& lnum == wp->w_cursor.lnum
|
&& lnum == wp->w_cursorline
|
||||||
&& (wp->w_p_culopt_flags & CULOPT_NBR);
|
&& (wp->w_p_culopt_flags & CULOPT_NBR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -517,7 +517,7 @@ static void get_statuscol_display_info(statuscol_T *stcp, LineDrawState *draw_st
|
|||||||
static bool use_cursor_line_nr(win_T *wp, linenr_T lnum, int row, int startrow, int filler_lines)
|
static bool use_cursor_line_nr(win_T *wp, linenr_T lnum, int row, int startrow, int filler_lines)
|
||||||
{
|
{
|
||||||
return wp->w_p_cul
|
return wp->w_p_cul
|
||||||
&& lnum == wp->w_cursor.lnum
|
&& lnum == wp->w_cursorline
|
||||||
&& (wp->w_p_culopt_flags & CULOPT_NBR)
|
&& (wp->w_p_culopt_flags & CULOPT_NBR)
|
||||||
&& (row == startrow + filler_lines
|
&& (row == startrow + filler_lines
|
||||||
|| (row > startrow + filler_lines
|
|| (row > startrow + filler_lines
|
||||||
@@ -547,6 +547,12 @@ static inline void get_line_number_str(win_T *wp, linenr_T lnum, char *buf, size
|
|||||||
|
|
||||||
static int get_line_number_attr(win_T *wp, linenr_T lnum, int row, int startrow, int filler_lines)
|
static int get_line_number_attr(win_T *wp, linenr_T lnum, int row, int startrow, int filler_lines)
|
||||||
{
|
{
|
||||||
|
if (use_cursor_line_nr(wp, lnum, row, startrow, filler_lines)) {
|
||||||
|
// TODO(vim): Can we use CursorLine instead of CursorLineNr
|
||||||
|
// when CursorLineNr isn't set?
|
||||||
|
return win_hl_attr(wp, HLF_CLN);
|
||||||
|
}
|
||||||
|
|
||||||
if (wp->w_p_rnu) {
|
if (wp->w_p_rnu) {
|
||||||
if (lnum < wp->w_cursor.lnum) {
|
if (lnum < wp->w_cursor.lnum) {
|
||||||
// Use LineNrAbove
|
// Use LineNrAbove
|
||||||
@@ -558,12 +564,6 @@ static int get_line_number_attr(win_T *wp, linenr_T lnum, int row, int startrow,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_cursor_line_nr(wp, lnum, row, startrow, filler_lines)) {
|
|
||||||
// TODO(vim): Can we use CursorLine instead of CursorLineNr
|
|
||||||
// when CursorLineNr isn't set?
|
|
||||||
return win_hl_attr(wp, HLF_CLN);
|
|
||||||
}
|
|
||||||
|
|
||||||
return win_hl_attr(wp, HLF_N);
|
return win_hl_attr(wp, HLF_N);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -960,20 +960,17 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
|
|||||||
filler_todo = filler_lines;
|
filler_todo = filler_lines;
|
||||||
|
|
||||||
// Cursor line highlighting for 'cursorline' in the current window.
|
// Cursor line highlighting for 'cursorline' in the current window.
|
||||||
if (lnum == wp->w_cursor.lnum) {
|
if (wp->w_p_cul && wp->w_p_culopt_flags != CULOPT_NBR && lnum == wp->w_cursorline
|
||||||
// Do not show the cursor line in the text when Visual mode is active,
|
// Do not show the cursor line in the text when Visual mode is active,
|
||||||
// because it's not clear what is selected then.
|
// because it's not clear what is selected then.
|
||||||
if (wp->w_p_cul && !(wp == curwin && VIsual_active)
|
&& !(wp == curwin && VIsual_active)) {
|
||||||
&& wp->w_p_culopt_flags != CULOPT_NBR) {
|
cul_screenline = (wp->w_p_wrap && (wp->w_p_culopt_flags & CULOPT_SCRLINE));
|
||||||
cul_screenline = (wp->w_p_wrap
|
if (!cul_screenline) {
|
||||||
&& (wp->w_p_culopt_flags & CULOPT_SCRLINE));
|
apply_cursorline_highlight(wp, lnum, &line_attr, &cul_attr, &line_attr_lowprio);
|
||||||
if (!cul_screenline) {
|
} else {
|
||||||
apply_cursorline_highlight(wp, lnum, &line_attr, &cul_attr, &line_attr_lowprio);
|
margin_columns_win(wp, &left_curline_col, &right_curline_col);
|
||||||
} else {
|
|
||||||
margin_columns_win(wp, &left_curline_col, &right_curline_col);
|
|
||||||
}
|
|
||||||
area_highlighting = true;
|
|
||||||
}
|
}
|
||||||
|
area_highlighting = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
SignTextAttrs sattrs[SIGN_SHOW_MAX]; // sign attributes for the sign column
|
SignTextAttrs sattrs[SIGN_SHOW_MAX]; // sign attributes for the sign column
|
||||||
|
@@ -1552,7 +1552,15 @@ static void win_update(win_T *wp, DecorProviders *providers)
|
|||||||
wp->w_old_visual_col = 0;
|
wp->w_old_visual_col = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cursorline_standout = win_cursorline_standout(wp);
|
foldinfo_T cursorline_fi;
|
||||||
|
wp->w_cursorline = win_cursorline_standout(wp) ? wp->w_cursor.lnum : 0;
|
||||||
|
if (wp->w_p_cul) {
|
||||||
|
// Make sure that the cursorline on a closed fold is redrawn
|
||||||
|
cursorline_fi = fold_info(wp, wp->w_cursor.lnum);
|
||||||
|
if (cursorline_fi.fi_level > 0 && cursorline_fi.fi_lines > 0) {
|
||||||
|
wp->w_cursorline = cursorline_fi.fi_lnum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
win_check_ns_hl(wp);
|
win_check_ns_hl(wp);
|
||||||
|
|
||||||
@@ -1608,7 +1616,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
|
|||||||
// if lines were inserted or deleted
|
// if lines were inserted or deleted
|
||||||
|| (wp->w_match_head != NULL
|
|| (wp->w_match_head != NULL
|
||||||
&& buf->b_mod_xlines != 0)))))
|
&& buf->b_mod_xlines != 0)))))
|
||||||
|| (cursorline_standout && lnum == wp->w_cursor.lnum)
|
|| lnum == wp->w_cursorline
|
||||||
|| lnum == wp->w_last_cursorline) {
|
|| lnum == wp->w_last_cursorline) {
|
||||||
if (lnum == mod_top) {
|
if (lnum == mod_top) {
|
||||||
top_to_mod = false;
|
top_to_mod = false;
|
||||||
@@ -1759,7 +1767,8 @@ static void win_update(win_T *wp, DecorProviders *providers)
|
|||||||
// When lines are folded, display one line for all of them.
|
// When lines are folded, display one line for all of them.
|
||||||
// Otherwise, display normally (can be several display lines when
|
// Otherwise, display normally (can be several display lines when
|
||||||
// 'wrap' is on).
|
// 'wrap' is on).
|
||||||
foldinfo_T foldinfo = fold_info(wp, lnum);
|
foldinfo_T foldinfo = wp->w_p_cul && lnum == wp->w_cursor.lnum ?
|
||||||
|
cursorline_fi : fold_info(wp, lnum);
|
||||||
|
|
||||||
if (foldinfo.fi_lines == 0
|
if (foldinfo.fi_lines == 0
|
||||||
&& idx < wp->w_lines_valid
|
&& idx < wp->w_lines_valid
|
||||||
@@ -1818,7 +1827,8 @@ static void win_update(win_T *wp, DecorProviders *providers)
|
|||||||
if (wp->w_p_rnu && wp->w_last_cursor_lnum_rnu != wp->w_cursor.lnum) {
|
if (wp->w_p_rnu && wp->w_last_cursor_lnum_rnu != wp->w_cursor.lnum) {
|
||||||
// 'relativenumber' set and cursor moved vertically: The
|
// 'relativenumber' set and cursor moved vertically: The
|
||||||
// text doesn't need to be drawn, but the number column does.
|
// text doesn't need to be drawn, but the number column does.
|
||||||
foldinfo_T info = fold_info(wp, lnum);
|
foldinfo_T info = wp->w_p_cul && lnum == wp->w_cursor.lnum ?
|
||||||
|
cursorline_fi : fold_info(wp, lnum);
|
||||||
(void)win_line(wp, lnum, srow, wp->w_grid.rows, true, true,
|
(void)win_line(wp, lnum, srow, wp->w_grid.rows, true, true,
|
||||||
info, &line_providers, &provider_err);
|
info, &line_providers, &provider_err);
|
||||||
}
|
}
|
||||||
@@ -1853,7 +1863,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
|
|||||||
|
|
||||||
// Now that the window has been redrawn with the old and new cursor line,
|
// Now that the window has been redrawn with the old and new cursor line,
|
||||||
// update w_last_cursorline.
|
// update w_last_cursorline.
|
||||||
wp->w_last_cursorline = cursorline_standout ? wp->w_cursor.lnum : 0;
|
wp->w_last_cursorline = wp->w_cursorline;
|
||||||
|
|
||||||
wp->w_last_cursor_lnum_rnu = wp->w_p_rnu ? wp->w_cursor.lnum : 0;
|
wp->w_last_cursor_lnum_rnu = wp->w_p_rnu ? wp->w_cursor.lnum : 0;
|
||||||
|
|
||||||
|
@@ -10,6 +10,7 @@ local meths = helpers.meths
|
|||||||
local exec = helpers.exec
|
local exec = helpers.exec
|
||||||
local exec_lua = helpers.exec_lua
|
local exec_lua = helpers.exec_lua
|
||||||
local assert_alive = helpers.assert_alive
|
local assert_alive = helpers.assert_alive
|
||||||
|
local poke_eventloop = helpers.poke_eventloop
|
||||||
|
|
||||||
|
|
||||||
local content1 = [[
|
local content1 = [[
|
||||||
@@ -90,10 +91,10 @@ describe("folded lines", function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
it("highlights with CursorLineFold when 'cursorline' is set", function()
|
it("highlights with CursorLineFold when 'cursorline' is set", function()
|
||||||
command("set cursorline foldcolumn=2 foldmethod=marker")
|
command("set number cursorline foldcolumn=2")
|
||||||
command("hi link CursorLineFold Search")
|
command("hi link CursorLineFold Search")
|
||||||
insert(content1)
|
insert(content1)
|
||||||
feed("zf3j")
|
feed("ggzf3jj")
|
||||||
if multigrid then
|
if multigrid then
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
## grid 1
|
## grid 1
|
||||||
@@ -106,26 +107,26 @@ describe("folded lines", function()
|
|||||||
[2:---------------------------------------------]|
|
[2:---------------------------------------------]|
|
||||||
[3:---------------------------------------------]|
|
[3:---------------------------------------------]|
|
||||||
## grid 2
|
## grid 2
|
||||||
{7: }This is a |
|
{7:+ }{8: 1 }{5:+-- 4 lines: This is a················}|
|
||||||
{7: }valid English |
|
{6: }{9: 5 }{12:^in his cave. }|
|
||||||
{7: }sentence composed by |
|
{7: }{8: 6 } |
|
||||||
{7: }an exhausted developer |
|
{1:~ }|
|
||||||
{7: }in his cave. |
|
{1:~ }|
|
||||||
{6: }{12:^ }|
|
{1:~ }|
|
||||||
{1:~ }|
|
{1:~ }|
|
||||||
## grid 3
|
## grid 3
|
||||||
|
|
|
|
||||||
]])
|
]])
|
||||||
else
|
else
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
{7: }This is a |
|
{7:+ }{8: 1 }{5:+-- 4 lines: This is a················}|
|
||||||
{7: }valid English |
|
{6: }{9: 5 }{12:^in his cave. }|
|
||||||
{7: }sentence composed by |
|
{7: }{8: 6 } |
|
||||||
{7: }an exhausted developer |
|
{1:~ }|
|
||||||
{7: }in his cave. |
|
{1:~ }|
|
||||||
{6: }{12:^ }|
|
{1:~ }|
|
||||||
{1:~ }|
|
{1:~ }|
|
||||||
|
|
|
|
||||||
]])
|
]])
|
||||||
end
|
end
|
||||||
feed("k")
|
feed("k")
|
||||||
@@ -141,28 +142,36 @@ describe("folded lines", function()
|
|||||||
[2:---------------------------------------------]|
|
[2:---------------------------------------------]|
|
||||||
[3:---------------------------------------------]|
|
[3:---------------------------------------------]|
|
||||||
## grid 2
|
## grid 2
|
||||||
{7: }This is a |
|
{6:+ }{9: 1 }{12:^+-- 4 lines: This is a················}|
|
||||||
{7: }valid English |
|
{7: }{8: 5 }in his cave. |
|
||||||
{7: }sentence composed by |
|
{7: }{8: 6 } |
|
||||||
{7: }an exhausted developer |
|
{1:~ }|
|
||||||
{6: }{12:^in his cave. }|
|
{1:~ }|
|
||||||
{7: } |
|
{1:~ }|
|
||||||
{1:~ }|
|
{1:~ }|
|
||||||
## grid 3
|
## grid 3
|
||||||
|
|
|
|
||||||
]])
|
]])
|
||||||
else
|
else
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
{7: }This is a |
|
{6:+ }{9: 1 }{12:^+-- 4 lines: This is a················}|
|
||||||
{7: }valid English |
|
{7: }{8: 5 }in his cave. |
|
||||||
{7: }sentence composed by |
|
{7: }{8: 6 } |
|
||||||
{7: }an exhausted developer |
|
{1:~ }|
|
||||||
{6: }{12:^in his cave. }|
|
{1:~ }|
|
||||||
{7: } |
|
{1:~ }|
|
||||||
{1:~ }|
|
{1:~ }|
|
||||||
|
|
|
|
||||||
]])
|
]])
|
||||||
end
|
end
|
||||||
|
-- CursorLine is applied correctly with screenrow motions #22232
|
||||||
|
feed("jgk")
|
||||||
|
poke_eventloop()
|
||||||
|
screen:expect_unchanged()
|
||||||
|
-- CursorLine is applied correctly when closing a fold when cursor is not at fold start
|
||||||
|
feed("zo4Gzc")
|
||||||
|
poke_eventloop()
|
||||||
|
screen:expect_unchanged()
|
||||||
command("set cursorlineopt=line")
|
command("set cursorlineopt=line")
|
||||||
if multigrid then
|
if multigrid then
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
@@ -176,26 +185,61 @@ describe("folded lines", function()
|
|||||||
[2:---------------------------------------------]|
|
[2:---------------------------------------------]|
|
||||||
[3:---------------------------------------------]|
|
[3:---------------------------------------------]|
|
||||||
## grid 2
|
## grid 2
|
||||||
{7: }This is a |
|
{7:+ }{8: 1 }{12:^+-- 4 lines: This is a················}|
|
||||||
{7: }valid English |
|
{7: }{8: 5 }in his cave. |
|
||||||
{7: }sentence composed by |
|
{7: }{8: 6 } |
|
||||||
{7: }an exhausted developer |
|
{1:~ }|
|
||||||
{7: }{12:^in his cave. }|
|
{1:~ }|
|
||||||
{7: } |
|
{1:~ }|
|
||||||
{1:~ }|
|
{1:~ }|
|
||||||
## grid 3
|
## grid 3
|
||||||
|
|
|
|
||||||
]])
|
]])
|
||||||
else
|
else
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
{7: }This is a |
|
{7:+ }{8: 1 }{12:^+-- 4 lines: This is a················}|
|
||||||
{7: }valid English |
|
{7: }{8: 5 }in his cave. |
|
||||||
{7: }sentence composed by |
|
{7: }{8: 6 } |
|
||||||
{7: }an exhausted developer |
|
{1:~ }|
|
||||||
{7: }{12:^in his cave. }|
|
{1:~ }|
|
||||||
{7: } |
|
{1:~ }|
|
||||||
{1:~ }|
|
{1:~ }|
|
||||||
|
|
|
|
||||||
|
]])
|
||||||
|
end
|
||||||
|
command("set relativenumber cursorlineopt=number")
|
||||||
|
if multigrid then
|
||||||
|
screen:expect([[
|
||||||
|
## grid 1
|
||||||
|
[2:---------------------------------------------]|
|
||||||
|
[2:---------------------------------------------]|
|
||||||
|
[2:---------------------------------------------]|
|
||||||
|
[2:---------------------------------------------]|
|
||||||
|
[2:---------------------------------------------]|
|
||||||
|
[2:---------------------------------------------]|
|
||||||
|
[2:---------------------------------------------]|
|
||||||
|
[3:---------------------------------------------]|
|
||||||
|
## grid 2
|
||||||
|
{6:+ }{9:1 }{5:^+-- 4 lines: This is a················}|
|
||||||
|
{7: }{8: 1 }in his cave. |
|
||||||
|
{7: }{8: 2 } |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
## grid 3
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
else
|
||||||
|
screen:expect([[
|
||||||
|
{6:+ }{9:1 }{5:^+-- 4 lines: This is a················}|
|
||||||
|
{7: }{8: 1 }in his cave. |
|
||||||
|
{7: }{8: 2 } |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
|
|
||||||
]])
|
]])
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
Reference in New Issue
Block a user