summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2024-03-16 15:03:33 +0100
committerChristian Brabandt <cb@256bit.org>2024-03-16 15:03:33 +0100
commitd0c1b7723f7e73763597af2f97a53d94ab7ed020 (patch)
tree241675d6a8328063a55002fc96a07684320b70b9
parent9e7f1fc2f159d58b2a4cd4b7060bead126fead49 (diff)
patch 9.1.0184: Cursor pos wrong when clicking with conceal and wrapv9.1.0184
Problem: Cursor position wrong when clicking with conceal and wrap. Solution: Use the virtual column of the last char for ScreenCols[] in boguscols. Remove use of MAXCOL in ScreenCols[]. Rename third argument of wlv_screen_line() to "clear_end" as that's clearer what it does (zeertzjq). related: 14192 closes: #14200 Signed-off-by: zeertzjq <zeertzjq@outlook.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
-rw-r--r--src/drawline.c27
-rw-r--r--src/drawscreen.c7
-rw-r--r--src/mouse.c30
-rw-r--r--src/proto/screen.pro2
-rw-r--r--src/screen.c11
-rw-r--r--src/terminal.c5
-rw-r--r--src/testdir/test_conceal.vim180
-rw-r--r--src/version.c2
-rw-r--r--src/vim.h1
9 files changed, 150 insertions, 115 deletions
diff --git a/src/drawline.c b/src/drawline.c
index 9368095485..e73d5b1b63 100644
--- a/src/drawline.c
+++ b/src/drawline.c
@@ -832,9 +832,10 @@ text_prop_position(
* Call screen_line() using values from "wlv".
* Also takes care of putting "<<<" on the first line for 'smoothscroll'
* when 'showbreak' is not set.
+ * When "clear_end" is TRUE clear until the end of the screen line.
*/
static void
-wlv_screen_line(win_T *wp, winlinevars_T *wlv, int negative_width)
+wlv_screen_line(win_T *wp, winlinevars_T *wlv, int clear_end)
{
if (wlv->row == 0 && wp->w_skipcol > 0
#if defined(FEAT_LINEBREAK)
@@ -872,8 +873,8 @@ wlv_screen_line(win_T *wp, winlinevars_T *wlv, int negative_width)
}
screen_line(wp, wlv->screen_row, wp->w_wincol, wlv->col,
- negative_width ? -wp->w_width : wp->w_width,
- wlv->screen_line_flags);
+ clear_end ? wp->w_width : -wp->w_width,
+ wlv->vcol - 1, wlv->screen_line_flags);
}
/*
@@ -939,7 +940,7 @@ draw_screen_line(win_T *wp, winlinevars_T *wlv)
ScreenLines[wlv->off] = ' ';
if (enc_utf8)
ScreenLinesUC[wlv->off] = 0;
- ScreenCols[wlv->off] = MAXCOL;
+ ScreenCols[wlv->off] = wlv->vcol;
++wlv->col;
if (wlv->draw_color_col)
wlv->draw_color_col = advance_color_col(
@@ -969,7 +970,11 @@ draw_screen_line(win_T *wp, winlinevars_T *wlv)
}
#endif
- wlv_screen_line(wp, wlv, FALSE);
+ // Set increasing virtual columns in ScreenCols[] to set correct curswant
+ // (or "coladd" for 'virtualedit') when clicking after end of line.
+ wlv->screen_line_flags |= SLF_INC_VCOL;
+ wlv_screen_line(wp, wlv, TRUE);
+ wlv->screen_line_flags &= ~SLF_INC_VCOL;
++wlv->row;
++wlv->screen_row;
}
@@ -1928,7 +1933,7 @@ win_line(
// stop here.
if (number_only > 0 && wlv.draw_state == WL_NR && wlv.n_extra == 0)
{
- wlv_screen_line(wp, &wlv, TRUE);
+ wlv_screen_line(wp, &wlv, FALSE);
// Need to update more screen lines if:
// - LineNrAbove or LineNrBelow is used, or
// - still drawing filler lines.
@@ -1987,7 +1992,7 @@ win_line(
&& lnum == wp->w_cursor.lnum
&& wlv.vcol >= (long)wp->w_virtcol)
{
- wlv_screen_line(wp, &wlv, TRUE);
+ wlv_screen_line(wp, &wlv, FALSE);
// Pretend we have finished updating the window. Except when
// 'cursorcolumn' is set.
#ifdef FEAT_SYN_HL
@@ -3764,7 +3769,7 @@ win_line(
}
#endif
ScreenAttrs[wlv.off] = wlv.char_attr;
- ScreenCols[wlv.off] = MAXCOL;
+ ScreenCols[wlv.off] = wlv.vcol;
#ifdef FEAT_RIGHTLEFT
if (wp->w_p_rl)
{
@@ -4167,7 +4172,7 @@ win_line(
if (enc_utf8)
ScreenLinesUC[wlv.off] = 0;
ScreenAttrs[wlv.off] = attr;
- ScreenCols[wlv.off] = MAXCOL; // TODO: this is wrong
+ ScreenCols[wlv.off] = wlv.vcol - 1;
# ifdef FEAT_RIGHTLEFT
if (wp->w_p_rl)
{
@@ -4184,12 +4189,12 @@ win_line(
}
}
}
- wlv_screen_line(wp, &wlv, FALSE);
+ wlv_screen_line(wp, &wlv, TRUE);
wlv.col += wlv.boguscols;
wlv.boguscols = 0;
wlv.vcol_off_co = 0;
#else
- wlv_screen_line(wp, &wlv, FALSE);
+ wlv_screen_line(wp, &wlv, TRUE);
#endif
++wlv.row;
++wlv.screen_row;
diff --git a/src/drawscreen.c b/src/drawscreen.c
index 3d6c230c19..f8818ff1aa 100644
--- a/src/drawscreen.c
+++ b/src/drawscreen.c
@@ -1028,7 +1028,8 @@ redraw_win_toolbar(win_T *wp)
}
wp->w_winbar_items[item_idx].wb_menu = NULL; // end marker
- screen_line(wp, wp->w_winrow, wp->w_wincol, wp->w_width, wp->w_width, 0);
+ screen_line(wp, wp->w_winrow, wp->w_wincol, wp->w_width, wp->w_width, -1,
+ 0);
}
#endif
@@ -1363,7 +1364,7 @@ fold_line(
#endif
screen_line(wp, row + W_WINROW(wp), wp->w_wincol,
- wp->w_width, wp->w_width, 0);
+ wp->w_width, wp->w_width, -1, 0);
// Update w_cline_height and w_cline_folded if the cursor line was
// updated (saves a call to plines() later).
@@ -3049,7 +3050,7 @@ redraw_asap(int type)
mch_memmove(ScreenLines2 + off,
screenline2 + r * cols,
(size_t)cols * sizeof(schar_T));
- screen_line(curwin, cmdline_row + r, 0, cols, cols, 0);
+ screen_line(curwin, cmdline_row + r, 0, cols, cols, -1, 0);
}
ret = 4;
}
diff --git a/src/mouse.c b/src/mouse.c
index e5f06874f8..af14af0501 100644
--- a/src/mouse.c
+++ b/src/mouse.c
@@ -2098,35 +2098,7 @@ retnomove:
redraw_cmdline = TRUE; // show visual mode later
}
- if (col_from_screen == MAXCOL)
- {
- // When clicking after end of line, still need to set correct curswant
- int off_l = LineOffset[prev_row] + curwin->w_wincol;
- if (ScreenCols[off_l] < MAXCOL)
- {
- // Binary search to find last char in line
- int off_r = LineOffset[prev_row] + prev_col;
- int off_click = off_r;
- while (off_l < off_r)
- {
- int off_m = (off_l + off_r + 1) / 2;
- if (ScreenCols[off_m] < MAXCOL)
- off_l = off_m;
- else
- off_r = off_m - 1;
- }
- colnr_T eol_vcol = ScreenCols[off_r];
- if (eol_vcol < 0)
- // Empty line or whole line before w_leftcol,
- // with columns before buffer text
- eol_vcol = curwin->w_leftcol - 1;
- col = eol_vcol + (off_click - off_r);
- }
- else
- // Empty line or whole line before w_leftcol
- col = prev_col - curwin->w_wincol + curwin->w_leftcol;
- }
- else if (col_from_screen >= 0)
+ if (col_from_screen >= 0)
{
// Use the virtual column from ScreenCols[], it is accurate also after
// concealed characters.
diff --git a/src/proto/screen.pro b/src/proto/screen.pro
index 53937d3c7f..cf7cd95f46 100644
--- a/src/proto/screen.pro
+++ b/src/proto/screen.pro
@@ -7,7 +7,7 @@ int compute_foldcolumn(win_T *wp, int col);
size_t fill_foldcolumn(char_u *p, win_T *wp, int closed, linenr_T lnum);
int screen_get_current_line_off(void);
void reset_screen_attr(void);
-void screen_line(win_T *wp, int row, int coloff, int endcol, int clear_width, int flags);
+void screen_line(win_T *wp, int row, int coloff, int endcol, int clear_width, colnr_T last_vcol, int flags);
void rl_mirror(char_u *str);
void draw_vsep_win(win_T *wp, int row);
int stl_connected(win_T *wp);
diff --git a/src/screen.c b/src/screen.c
index 208b182541..08b1c018f2 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -452,6 +452,10 @@ skip_for_popup(int row, int col)
* SLF_RIGHTLEFT rightleft window:
* When TRUE and "clear_width" > 0, clear columns 0 to "endcol"
* When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width"
+ * SLF_INC_VCOL:
+ * When FALSE, use "last_vcol" for ScreenCols[] of the columns to clear.
+ * When TRUE, use an increasing sequence starting from "last_vcol + 1" for
+ * ScreenCols[] of the columns to clear.
*/
void
screen_line(
@@ -460,6 +464,7 @@ screen_line(
int coloff,
int endcol,
int clear_width,
+ colnr_T last_vcol,
int flags UNUSED)
{
unsigned off_from;
@@ -775,7 +780,8 @@ screen_line(
&& ScreenAttrs[off_to] == 0
&& (!enc_utf8 || ScreenLinesUC[off_to] == 0))
{
- ScreenCols[off_to] = MAXCOL;
+ ScreenCols[off_to] =
+ (flags & SLF_INC_VCOL) ? ++last_vcol : last_vcol;
++off_to;
++col;
}
@@ -830,7 +836,8 @@ screen_line(
' ', ' ', 0);
while (col < clear_width)
{
- ScreenCols[off_to++] = MAXCOL;
+ ScreenCols[off_to++]
+ = (flags & SLF_INC_VCOL) ? ++last_vcol : last_vcol;
++col;
}
}
diff --git a/src/terminal.c b/src/terminal.c
index a641a850b0..25a6a5dd76 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -3965,7 +3965,8 @@ update_system_term(term_T *term)
else
pos.col = 0;
- screen_line(curwin, term->tl_toprow + pos.row, 0, pos.col, Columns, 0);
+ screen_line(curwin, term->tl_toprow + pos.row, 0, pos.col, Columns, -1,
+ 0);
}
term->tl_dirty_row_start = MAX_ROW;
@@ -4088,7 +4089,7 @@ term_update_window(win_T *wp)
#ifdef FEAT_MENU
+ winbar_height(wp)
#endif
- , wp->w_wincol, pos.col, wp->w_width,
+ , wp->w_wincol, pos.col, wp->w_width, -1,
#ifdef FEAT_PROP_POPUP
popup_is_popup(wp) ? SLF_POPUP :
#endif
diff --git a/src/testdir/test_conceal.vim b/src/testdir/test_conceal.vim
index 1cc08fcf84..9696cdeae8 100644
--- a/src/testdir/test_conceal.vim
+++ b/src/testdir/test_conceal.vim
@@ -389,77 +389,123 @@ func Test_conceal_eol()
endfunc
func Test_conceal_mouse_click()
- enew!
+ call NewWindow(10, 40)
set mouse=a
setlocal conceallevel=2 concealcursor=nc
syn match Concealed "this" conceal
hi link Concealed Search
- call setline(1, 'conceal this click here')
- redraw
- call assert_equal(['conceal click here '], ScreenLines(1, 20))
-
- " click on the space between "this" and "click" puts cursor there
- call test_setmouse(1, 9)
- call feedkeys("\<LeftMouse>", "tx")
- call assert_equal([0, 1, 13, 0, 13], getcurpos())
- " click on 'h' of "here" puts cursor there
- call test_setmouse(1, 16)
- call feedkeys("\<LeftMouse>", "tx")
- call assert_equal([0, 1, 20, 0, 20], getcurpos())
- " click on 'e' of "here" puts cursor there
- call test_setmouse(1, 19)
- call feedkeys("\<LeftMouse>", "tx")
- call assert_equal([0, 1, 23, 0, 23], getcurpos())
- " click after end of line puts cursor on 'e' without 'virtualedit'
- call test_setmouse(1, 20)
- call feedkeys("\<LeftMouse>", "tx")
- call assert_equal([0, 1, 23, 0, 24], getcurpos())
- call test_setmouse(1, 21)
- call feedkeys("\<LeftMouse>", "tx")
- call assert_equal([0, 1, 23, 0, 25], getcurpos())
- call test_setmouse(1, 22)
- call feedkeys("\<LeftMouse>", "tx")
- call assert_equal([0, 1, 23, 0, 26], getcurpos())
- call test_setmouse(1, 31)
- call feedkeys("\<LeftMouse>", "tx")
- call assert_equal([0, 1, 23, 0, 35], getcurpos())
- call test_setmouse(1, 32)
- call feedkeys("\<LeftMouse>", "tx")
- call assert_equal([0, 1, 23, 0, 36], getcurpos())
-
- set virtualedit=all
- redraw
- " click on the space between "this" and "click" puts cursor there
- call test_setmouse(1, 9)
- call feedkeys("\<LeftMouse>", "tx")
- call assert_equal([0, 1, 13, 0, 13], getcurpos())
- " click on 'h' of "here" puts cursor there
- call test_setmouse(1, 16)
- call feedkeys("\<LeftMouse>", "tx")
- call assert_equal([0, 1, 20, 0, 20], getcurpos())
- " click on 'e' of "here" puts cursor there
- call test_setmouse(1, 19)
- call feedkeys("\<LeftMouse>", "tx")
- call assert_equal([0, 1, 23, 0, 23], getcurpos())
- " click after end of line puts cursor there with 'virtualedit'
- call test_setmouse(1, 20)
- call feedkeys("\<LeftMouse>", "tx")
- call assert_equal([0, 1, 24, 0, 24], getcurpos())
- call test_setmouse(1, 21)
- call feedkeys("\<LeftMouse>", "tx")
- call assert_equal([0, 1, 24, 1, 25], getcurpos())
- call test_setmouse(1, 22)
- call feedkeys("\<LeftMouse>", "tx")
- call assert_equal([0, 1, 24, 2, 26], getcurpos())
- call test_setmouse(1, 31)
- call feedkeys("\<LeftMouse>", "tx")
- call assert_equal([0, 1, 24, 11, 35], getcurpos())
- call test_setmouse(1, 32)
- call feedkeys("\<LeftMouse>", "tx")
- call assert_equal([0, 1, 24, 12, 36], getcurpos())
-
- bwipe!
- set mouse& virtualedit&
+
+ " Test with both 'nocursorline' and 'cursorline', as they use two different
+ " code paths to set virtual columns for the cells to clear.
+ for cul in [v:false, v:true]
+ let &l:cursorline = cul
+
+ call setline(1, 'conceal this click here')
+ call assert_equal([
+ \ 'conceal click here ',
+ \ ], ScreenLines(1, 40))
+
+ " Click on the space between "this" and "click" puts cursor there.
+ call test_setmouse(1, 9)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 13, 0, 13], getcurpos())
+ " Click on 'h' of "here" puts cursor there.
+ call test_setmouse(1, 16)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 20, 0, 20], getcurpos())
+ " Click on 'e' of "here" puts cursor there.
+ call test_setmouse(1, 19)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 23, 0, 23], getcurpos())
+ " Click after end of line puts cursor on 'e' without 'virtualedit'.
+ call test_setmouse(1, 20)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 23, 0, 24], getcurpos())
+ call test_setmouse(1, 21)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 23, 0, 25], getcurpos())
+ call test_setmouse(1, 22)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 23, 0, 26], getcurpos())
+ call test_setmouse(1, 31)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 23, 0, 35], getcurpos())
+ call test_setmouse(1, 32)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 23, 0, 36], getcurpos())
+
+ set virtualedit=all
+ redraw
+ " Click on the space between "this" and "click" puts cursor there.
+ call test_setmouse(1, 9)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 13, 0, 13], getcurpos())
+ " Click on 'h' of "here" puts cursor there.
+ call test_setmouse(1, 16)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 20, 0, 20], getcurpos())
+ " Click on 'e' of "here" puts cursor there.
+ call test_setmouse(1, 19)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 23, 0, 23], getcurpos())
+ " Click after end of line puts cursor there with 'virtualedit'.
+ call test_setmouse(1, 20)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 24, 0, 24], getcurpos())
+ call test_setmouse(1, 21)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 24, 1, 25], getcurpos())
+ call test_setmouse(1, 22)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 24, 2, 26], getcurpos())
+ call test_setmouse(1, 31)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 24, 11, 35], getcurpos())
+ call test_setmouse(1, 32)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 24, 12, 36], getcurpos())
+ set virtualedit&
+
+ " Test with a wrapped line.
+ call setline(1, ['conceal this click here']->repeat(3)->join())
+ call assert_equal([
+ \ 'conceal click here conceal cli ',
+ \ 'ck here conceal click here ',
+ \ ], ScreenLines([1, 2], 40))
+ " Click on boguscols puts cursor on the last char of a screen line.
+ for col in range(33, 40)
+ call test_setmouse(1, col)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 40, 0, 40], getcurpos())
+ endfor
+
+ " Also test with the last char of a screen line concealed.
+ setlocal number signcolumn=yes
+ call assert_equal([
+ \ ' 1 conceal click here conceal ',
+ \ ' click here conceal click h ',
+ \ ' ere ',
+ \ ], ScreenLines([1, 3], 40))
+ call test_setmouse(1, 34)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 32, 0, 32], getcurpos())
+ call test_setmouse(2, 7)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 37, 0, 37], getcurpos())
+ " Click on boguscols puts cursor on the last char of a screen line.
+ for col in range(35, 40)
+ call test_setmouse(1, col)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 34, 0, 34], getcurpos())
+ call test_setmouse(2, col)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 68, 0, 68], getcurpos())
+ endfor
+ setlocal number& signcolumn&
+ endfor
+
+ call CloseWindow()
+ set mouse&
endfunc
" Test that cursor is drawn at the correct column when it is after end of the
diff --git a/src/version.c b/src/version.c
index c8037f7928..5d768c178b 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 184,
+/**/
183,
/**/
182,
diff --git a/src/vim.h b/src/vim.h
index 7ef9b00336..85d92d5a9a 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -627,6 +627,7 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring);
// flags for screen_line()
#define SLF_RIGHTLEFT 1
#define SLF_POPUP 2
+#define SLF_INC_VCOL 4
#define MB_FILLER_CHAR '<' // character used when a double-width character
// doesn't fit.