aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/drawline.c12
-rw-r--r--src/nvim/grid.c24
-rw-r--r--src/nvim/grid.h1
-rw-r--r--src/nvim/grid_defs.h15
-rw-r--r--src/nvim/mouse.c188
-rw-r--r--test/functional/ui/mouse_spec.lua3
-rw-r--r--test/old/testdir/test_conceal.vim49
-rw-r--r--test/old/testdir/test_normal.vim10
-rw-r--r--test/old/testdir/test_virtualedit.vim6
9 files changed, 162 insertions, 146 deletions
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index d0142c6efa..4c90a562ce 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -2022,6 +2022,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
c = NUL;
} else {
int c0;
+ char *prev_ptr = ptr;
// Get a character from the line itself.
c0 = c = (uint8_t)(*ptr);
@@ -2209,7 +2210,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
v = (ptr - line);
if (spv->spv_has_spell && v >= word_end && v > cur_checked_col) {
spell_attr = 0;
- char *prev_ptr = ptr - mb_l;
// do not calculate cap_col at the end of the line or when
// only white space is following
if (c != 0 && (*skipwhite(prev_ptr) != NUL) && can_spell) {
@@ -2746,6 +2746,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
eol_attr = hl_combine_attr(wlv.cul_attr, eol_attr);
}
linebuf_attr[wlv.off] = eol_attr;
+ linebuf_vcol[wlv.off] = MAXCOL;
if (wp->w_p_rl) {
wlv.col--;
wlv.off--;
@@ -2832,6 +2833,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
while (wp->w_p_rl ? wlv.col >= 0 : wlv.col < grid->cols) {
schar_from_ascii(linebuf_char[wlv.off], ' ');
+ linebuf_vcol[wlv.off] = MAXCOL;
wlv.col += col_stride;
if (draw_color_col) {
draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
@@ -2866,6 +2868,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
while (wlv.col >= 0 && wlv.col < grid->cols) {
schar_from_ascii(linebuf_char[wlv.off], ' ');
linebuf_attr[wlv.off] = wlv.vcol >= TERM_ATTRS_MAX ? 0 : term_attrs[wlv.vcol];
+ linebuf_vcol[wlv.off] = wlv.vcol;
wlv.off += n;
wlv.vcol += n;
wlv.col += n;
@@ -2945,9 +2948,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// Skip characters that are left of the screen for 'nowrap'.
vcol_prev = wlv.vcol;
if (wlv.draw_state < WL_LINE || n_skip <= 0) {
- //
// Store the character.
- //
if (wp->w_p_rl && utf_char2cells(mb_c) > 1) {
// A double-wide character is: put first half in left cell.
wlv.off--;
@@ -2965,6 +2966,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
linebuf_attr[wlv.off] = wlv.char_attr;
}
+ linebuf_vcol[wlv.off] = wlv.vcol;
+
if (utf_char2cells(mb_c) > 1) {
// Need to fill two screen columns.
wlv.off++;
@@ -2980,6 +2983,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
if (wlv.tocol == wlv.vcol) {
wlv.tocol++;
}
+
+ linebuf_vcol[wlv.off] = wlv.vcol;
+
if (wp->w_p_rl) {
// now it's time to backup one cell
wlv.off--;
diff --git a/src/nvim/grid.c b/src/nvim/grid.c
index aef10db414..e25b1b1a73 100644
--- a/src/nvim/grid.c
+++ b/src/nvim/grid.c
@@ -78,6 +78,7 @@ void grid_clear_line(ScreenGrid *grid, size_t off, int width, bool valid)
}
int fill = valid ? 0 : -1;
(void)memset(grid->attrs + off, fill, (size_t)width * sizeof(sattr_T));
+ (void)memset(grid->vcols + off, -1, (size_t)width * sizeof(colnr_T));
}
void grid_invalidate(ScreenGrid *grid)
@@ -196,6 +197,7 @@ void grid_put_schar(ScreenGrid *grid, int row, int col, char *schar, int attr)
// TODO(bfredl): Y U NO DOUBLEWIDTH?
put_dirty_last = MAX(put_dirty_last, col + 1);
}
+ grid->vcols[off] = -1;
}
/// like grid_puts(), but output "text[len]". When "len" is -1 output up to
@@ -324,9 +326,11 @@ int grid_puts_len(ScreenGrid *grid, const char *text, int textlen, int row, int
schar_copy(grid->chars[off], buf);
grid->attrs[off] = attr;
+ grid->vcols[off] = -1;
if (mbyte_cells == 2) {
grid->chars[off + 1][0] = 0;
grid->attrs[off + 1] = attr;
+ grid->vcols[off + 1] = -1;
}
put_dirty_first = MIN(put_dirty_first, col);
put_dirty_last = MAX(put_dirty_last, col + mbyte_cells);
@@ -437,6 +441,7 @@ void grid_fill(ScreenGrid *grid, int start_row, int end_row, int start_col, int
}
dirty_last = col + 1;
}
+ grid->vcols[off] = -1;
if (col == start_col) {
schar_from_char(sc, c2);
}
@@ -620,13 +625,20 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int cle
}
grid->attrs[off_to] = linebuf_attr[off_from];
+ grid->vcols[off_to] = linebuf_vcol[off_from];
// For simplicity set the attributes of second half of a
// double-wide character equal to the first half.
if (char_cells == 2) {
grid->attrs[off_to + 1] = linebuf_attr[off_from];
+ grid->vcols[off_to + 1] = linebuf_vcol[off_from + 1];
}
}
+ grid->vcols[off_to] = linebuf_vcol[off_from];
+ if (char_cells == 2) {
+ grid->vcols[off_to + 1] = linebuf_vcol[off_from];
+ }
+
off_to += (size_t)char_cells;
off_from += (size_t)char_cells;
col += char_cells;
@@ -659,6 +671,7 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int cle
}
clear_end = col + 1;
}
+ grid->vcols[off_to] = MAXCOL;
col++;
off_to++;
}
@@ -690,6 +703,8 @@ void grid_alloc(ScreenGrid *grid, int rows, int columns, bool copy, bool valid)
size_t ncells = (size_t)rows * (size_t)columns;
ngrid.chars = xmalloc(ncells * sizeof(schar_T));
ngrid.attrs = xmalloc(ncells * sizeof(sattr_T));
+ ngrid.vcols = xmalloc(ncells * sizeof(colnr_T));
+ memset(ngrid.vcols, -1, ncells * sizeof(colnr_T));
ngrid.line_offset = xmalloc((size_t)rows * sizeof(*ngrid.line_offset));
ngrid.line_wraps = xmalloc((size_t)rows * sizeof(*ngrid.line_wraps));
@@ -715,6 +730,9 @@ void grid_alloc(ScreenGrid *grid, int rows, int columns, bool copy, bool valid)
memmove(ngrid.attrs + ngrid.line_offset[new_row],
grid->attrs + grid->line_offset[new_row],
(size_t)len * sizeof(sattr_T));
+ memmove(ngrid.vcols + ngrid.line_offset[new_row],
+ grid->vcols + grid->line_offset[new_row],
+ (size_t)len * sizeof(colnr_T));
}
}
}
@@ -726,8 +744,10 @@ void grid_alloc(ScreenGrid *grid, int rows, int columns, bool copy, bool valid)
if (linebuf_size < (size_t)columns) {
xfree(linebuf_char);
xfree(linebuf_attr);
+ xfree(linebuf_vcol);
linebuf_char = xmalloc((size_t)columns * sizeof(schar_T));
linebuf_attr = xmalloc((size_t)columns * sizeof(sattr_T));
+ linebuf_vcol = xmalloc((size_t)columns * sizeof(colnr_T));
linebuf_size = (size_t)columns;
}
}
@@ -736,11 +756,13 @@ void grid_free(ScreenGrid *grid)
{
xfree(grid->chars);
xfree(grid->attrs);
+ xfree(grid->vcols);
xfree(grid->line_offset);
xfree(grid->line_wraps);
grid->chars = NULL;
grid->attrs = NULL;
+ grid->vcols = NULL;
grid->line_offset = NULL;
grid->line_wraps = NULL;
}
@@ -751,6 +773,7 @@ void grid_free_all_mem(void)
grid_free(&default_grid);
xfree(linebuf_char);
xfree(linebuf_attr);
+ xfree(linebuf_vcol);
}
/// (Re)allocates a window grid if size changed while in ext_multigrid mode.
@@ -939,6 +962,7 @@ static void linecopy(ScreenGrid *grid, int to, int from, int col, int width)
memmove(grid->chars + off_to, grid->chars + off_from, (size_t)width * sizeof(schar_T));
memmove(grid->attrs + off_to, grid->attrs + off_from, (size_t)width * sizeof(sattr_T));
+ memmove(grid->vcols + off_to, grid->vcols + off_from, (size_t)width * sizeof(colnr_T));
}
win_T *get_win_by_grid_handle(handle_T handle)
diff --git a/src/nvim/grid.h b/src/nvim/grid.h
index deb3d3785d..0db97345d1 100644
--- a/src/nvim/grid.h
+++ b/src/nvim/grid.h
@@ -27,6 +27,7 @@ EXTERN bool resizing_screen INIT(= 0);
EXTERN schar_T *linebuf_char INIT(= NULL);
EXTERN sattr_T *linebuf_attr INIT(= NULL);
+EXTERN colnr_T *linebuf_vcol INIT(= NULL);
// Low-level functions to manipulate individual character cells on the
// screen grid.
diff --git a/src/nvim/grid_defs.h b/src/nvim/grid_defs.h
index aae61cc719..aeaadea73c 100644
--- a/src/nvim/grid_defs.h
+++ b/src/nvim/grid_defs.h
@@ -5,6 +5,7 @@
#include <stddef.h>
#include <stdint.h>
+#include "nvim/pos.h"
#include "nvim/types.h"
#define MAX_MCO 6 // fixed value for 'maxcombine'
@@ -37,9 +38,14 @@ enum {
/// screen is cleared, the cells should be filled with a single whitespace char.
///
/// attrs[] contains the highlighting attribute for each cell.
-/// line_offset[n] is the offset from chars[] and attrs[] for the
-/// start of line 'n'. These offsets are in general not linear, as full screen
-/// scrolling is implemented by rotating the offsets in the line_offset array.
+///
+/// vcols[] countain the virtual columns in the line. -1 means not available
+/// (below last line), MAXCOL means after the end of the line.
+///
+/// line_offset[n] is the offset from chars[], attrs[] and vcols[] for the start
+/// of line 'n'. These offsets are in general not linear, as full screen scrolling
+/// is implemented by rotating the offsets in the line_offset array.
+///
/// line_wraps[] is an array of boolean flags indicating if the screen line
/// wraps to the next line. It can only be true if a window occupies the entire
/// screen width.
@@ -49,6 +55,7 @@ struct ScreenGrid {
schar_T *chars;
sattr_T *attrs;
+ colnr_T *vcols;
size_t *line_offset;
char *line_wraps;
@@ -106,7 +113,7 @@ struct ScreenGrid {
bool comp_disabled;
};
-#define SCREEN_GRID_INIT { 0, NULL, NULL, NULL, NULL, NULL, 0, 0, false, \
+#define SCREEN_GRID_INIT { 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, false, \
false, 0, 0, NULL, false, true, 0, \
0, 0, 0, 0, 0, false }
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c
index d8341d2b10..0f3405bf0d 100644
--- a/src/nvim/mouse.c
+++ b/src/nvim/mouse.c
@@ -1329,15 +1329,15 @@ retnomove:
}
}
+ colnr_T col_from_screen = -1;
+ int mouse_fold_flags = 0;
+ mouse_check_grid(&col_from_screen, &mouse_fold_flags);
+
// compute the position in the buffer line from the posn on the screen
if (mouse_comp_pos(curwin, &row, &col, &curwin->w_cursor.lnum)) {
mouse_past_bottom = true;
}
- if (!(flags & MOUSE_RELEASED) && which_button == MOUSE_LEFT) {
- col = mouse_adjust_click(curwin, row, col);
- }
-
// Start Visual mode before coladvance(), for when 'sel' != "old"
if ((flags & MOUSE_MAY_VIS) && !VIsual_active) {
VIsual = old_cursor;
@@ -1352,6 +1352,10 @@ retnomove:
}
}
+ if (col_from_screen >= 0) {
+ col = col_from_screen;
+ }
+
curwin->w_curswant = col;
curwin->w_set_curswant = false; // May still have been true
if (coladvance(col) == FAIL) { // Mouse click beyond end of line
@@ -1369,14 +1373,14 @@ retnomove:
count |= CURSOR_MOVED; // Cursor has moved
}
- count |= mouse_check_fold();
+ count |= mouse_fold_flags;
return count;
}
-// Compute the position in the buffer line from the posn on the screen in
-// window "win".
-// Returns true if the position is below the last line.
+/// Compute the position in the buffer line from the posn on the screen in
+/// window "win".
+/// Returns true if the position is below the last line.
bool mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump)
{
int col = *colp;
@@ -1573,9 +1577,7 @@ static void set_mouse_topline(win_T *wp)
orig_topfill = wp->w_topfill;
}
-///
/// Return length of line "lnum" for horizontal scrolling.
-///
static colnr_T scroll_line_len(linenr_T lnum)
{
colnr_T col = 0;
@@ -1663,116 +1665,9 @@ bool mouse_scroll_horiz(int dir)
return set_leftcol(leftcol);
}
-/// Adjusts the clicked column position when 'conceallevel' > 0
-static int mouse_adjust_click(win_T *wp, int row, int col)
-{
- if (!(wp->w_p_cole > 0 && curbuf->b_p_smc > 0
- && wp->w_leftcol < curbuf->b_p_smc && conceal_cursor_line(wp))) {
- return col;
- }
-
- // `col` is the position within the current line that is highlighted by the
- // cursor without consideration for concealed characters. The current line is
- // scanned *up to* `col`, nudging it left or right when concealed characters
- // are encountered.
- //
- // win_chartabsize() is used to keep track of the virtual column position
- // relative to the line's bytes. For example: if col == 9 and the line
- // starts with a tab that's 8 columns wide, we would want the cursor to be
- // highlighting the second byte, not the ninth.
-
- linenr_T lnum = wp->w_cursor.lnum;
- // Make a copy of the line, because syntax matching may free it.
- char *line = xstrdup(ml_get(lnum));
- char *ptr = line;
- char *ptr_end;
- char *ptr_row_offset = line; // Where we begin adjusting `ptr_end`
-
- // Find the offset where scanning should begin.
- int offset = wp->w_leftcol;
- if (row > 0) {
- offset += row * (wp->w_width_inner - win_col_off(wp) - win_col_off2(wp) -
- wp->w_leftcol + wp->w_skipcol);
- }
-
- int vcol;
-
- if (offset) {
- // Skip everything up to an offset since nvim takes care of displaying the
- // correct portion of the line when horizontally scrolling.
- // When 'wrap' is enabled, only the row (of the wrapped line) needs to be
- // checked for concealed characters.
- vcol = 0;
- while (vcol < offset && *ptr != NUL) {
- vcol += win_chartabsize(curwin, ptr, vcol);
- ptr += utfc_ptr2len(ptr);
- }
-
- ptr_row_offset = ptr;
- }
-
- // Align `ptr_end` with `col`
- vcol = offset;
- ptr_end = ptr_row_offset;
- while (vcol < col && *ptr_end != NUL) {
- vcol += win_chartabsize(curwin, ptr_end, vcol);
- ptr_end += utfc_ptr2len(ptr_end);
- }
-
- int prev_matchid;
- int nudge = 0;
-
- vcol = offset;
-
-#define INCR() nudge++; ptr_end += utfc_ptr2len(ptr_end)
-#define DECR() nudge--; ptr_end -= utfc_ptr2len(ptr_end)
-
- while (ptr < ptr_end && *ptr != NUL) {
- int cwidth = win_chartabsize(curwin, ptr, vcol);
- vcol += cwidth;
- if (cwidth > 1 && *ptr == '\t' && nudge > 0) {
- // A tab will "absorb" any previous adjustments.
- cwidth = MIN(cwidth, nudge);
- while (cwidth > 0) {
- DECR();
- cwidth--;
- }
- }
-
- int matchid = syn_get_concealed_id(wp, lnum, (colnr_T)(ptr - line));
- if (matchid != 0) {
- if (wp->w_p_cole == 3) {
- INCR();
- } else {
- if (!(row > 0 && ptr == ptr_row_offset)
- && (wp->w_p_cole == 1 || (wp->w_p_cole == 2
- && (wp->w_p_lcs_chars.conceal != NUL
- || syn_get_sub_char() != NUL)))) {
- // At least one placeholder character will be displayed.
- DECR();
- }
-
- prev_matchid = matchid;
-
- while (prev_matchid == matchid && *ptr != NUL) {
- INCR();
- ptr += utfc_ptr2len(ptr);
- matchid = syn_get_concealed_id(wp, lnum, (colnr_T)(ptr - line));
- }
-
- continue;
- }
- }
-
- ptr += utfc_ptr2len(ptr);
- }
-
- xfree(line);
- return col + nudge;
-}
-
-// Check clicked cell is foldcolumn
-int mouse_check_fold(void)
+/// Check clicked cell on its grid
+static void mouse_check_grid(colnr_T *vcolp, int *flagsp)
+ FUNC_ATTR_NONNULL_ALL
{
int click_grid = mouse_grid;
int click_row = mouse_row;
@@ -1780,7 +1675,8 @@ int mouse_check_fold(void)
int mouse_char = ' ';
int max_row = Rows;
int max_col = Columns;
- int multigrid = ui_has(kUIMultigrid);
+ bool multigrid = ui_has(kUIMultigrid);
+ colnr_T col_from_screen = -1;
win_T *wp = mouse_find_win(&click_grid, &click_row, &click_col);
if (wp && multigrid) {
@@ -1792,14 +1688,46 @@ int mouse_check_fold(void)
&& mouse_col >= 0 && mouse_col < max_col) {
ScreenGrid *gp = multigrid ? &wp->w_grid_alloc : &default_grid;
int fdc = win_fdccol_count(wp);
- int row = multigrid && mouse_grid == 0 ? click_row : mouse_row;
- int col = multigrid && mouse_grid == 0 ? click_col : mouse_col;
+ int use_row = multigrid && mouse_grid == 0 ? click_row : mouse_row;
+ int use_col = multigrid && mouse_grid == 0 ? click_col : mouse_col;
- // Remember the character under the mouse, might be one of foldclose or
- // foldopen fillchars in the fold column.
if (gp->chars != NULL) {
- mouse_char = utf_ptr2char((char *)gp->chars[gp->line_offset[row]
- + (unsigned)col]);
+ const size_t off = gp->line_offset[use_row] + (size_t)use_col;
+
+ // Only use vcols[] after the window was redrawn. Mainly matters
+ // for tests, a user would not click before redrawing.
+ if (wp->w_redr_type == 0) {
+ col_from_screen = gp->vcols[off];
+ }
+
+ if (col_from_screen == MAXCOL) {
+ // When clicking after end of line, still need to set correct curswant
+ size_t off_l = gp->line_offset[use_row];
+ if (gp->vcols[off_l] < MAXCOL) {
+ // Binary search to find last char in line
+ size_t off_r = off;
+ while (off_l < off_r) {
+ size_t off_m = (off_l + off_r + 1) / 2;
+ if (gp->vcols[off_m] < MAXCOL) {
+ off_l = off_m;
+ } else {
+ off_r = off_m - 1;
+ }
+ }
+ *vcolp = gp->vcols[off_r] + (int)(off - off_r);
+ } else {
+ // Shouldn't normally happen
+ *vcolp = MAXCOL;
+ }
+ } else if (col_from_screen >= 0) {
+ // Use the virtual column from vcols[], it is accurate also after
+ // concealed characters.
+ *vcolp = col_from_screen;
+ }
+
+ // Remember the character under the mouse, might be one of foldclose or
+ // foldopen fillchars in the fold column.
+ mouse_char = utf_ptr2char((char *)gp->chars[off]);
}
// Check for position outside of the fold column.
@@ -1810,10 +1738,8 @@ int mouse_check_fold(void)
}
if (wp && mouse_char == wp->w_p_fcs_chars.foldclosed) {
- return MOUSE_FOLD_OPEN;
+ *flagsp |= MOUSE_FOLD_OPEN;
} else if (mouse_char != ' ') {
- return MOUSE_FOLD_CLOSE;
+ *flagsp |= MOUSE_FOLD_CLOSE;
}
-
- return 0;
}
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index d126e27cde..657cc0c325 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -1089,7 +1089,6 @@ describe('ui/mouse/input', function()
command([[setlocal concealcursor=ni nowrap shiftwidth=2 tabstop=4 list listchars=tab:>-]])
command([[syntax region X0 matchgroup=X1 start=/\*/ end=/\*/ concealends contains=X2]])
command([[syntax match X2 /cats/ conceal cchar=X contained]])
- -- No heap-use-after-free with multi-line syntax pattern #24317
command([[syntax match X3 /\n\@<=x/ conceal cchar=>]])
command([[highlight link X0 Normal]])
command([[highlight link X1 NonText]])
@@ -1497,7 +1496,6 @@ describe('ui/mouse/input', function()
]])
end) -- level 2 - wrapped
-
it('(level 3) click on non-wrapped lines', function()
feed_command('let &conceallevel=3', 'echo')
@@ -1535,6 +1533,7 @@ describe('ui/mouse/input', function()
]])
feed('<esc><LeftMouse><20,2>')
+ feed('zH') -- FIXME: unnecessary horizontal scrolling
screen:expect([[
Section{0:>>--->--->---}t1 |
{0:>--->--->---} t2 t3 t4 |
diff --git a/test/old/testdir/test_conceal.vim b/test/old/testdir/test_conceal.vim
index b9541b9e82..0ec171aa2f 100644
--- a/test/old/testdir/test_conceal.vim
+++ b/test/old/testdir/test_conceal.vim
@@ -349,9 +349,56 @@ func Test_conceal_mouse_click()
call Ntest_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 Ntest_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 Ntest_setmouse(1, 20)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 23, 0, 24], getcurpos())
+ call Ntest_setmouse(1, 21)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 23, 0, 25], getcurpos())
+ call Ntest_setmouse(1, 22)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 23, 0, 26], getcurpos())
+ call Ntest_setmouse(1, 31)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 23, 0, 35], getcurpos())
+ call Ntest_setmouse(1, 32)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 23, 0, 36], getcurpos())
+
+ set virtualedit=all
+ redraw " Nvim: redraw_for_cursorcolumn() redraws for conceal
+ " click on 'h' of "here" puts cursor there
+ call Ntest_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 Ntest_setmouse(1, 19)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 23, 0, 23], getcurpos())
+ " click after end of line puts cursor there without 'virtualedit'
+ call Ntest_setmouse(1, 20)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 24, 0, 24], getcurpos())
+ call Ntest_setmouse(1, 21)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 24, 1, 25], getcurpos())
+ call Ntest_setmouse(1, 22)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 24, 2, 26], getcurpos())
+ call Ntest_setmouse(1, 31)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 24, 11, 35], getcurpos())
+ call Ntest_setmouse(1, 32)
+ call feedkeys("\<LeftMouse>", "tx")
+ call assert_equal([0, 1, 24, 12, 36], getcurpos())
bwipe!
- set mouse&
+ set mouse& virtualedit&
endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_normal.vim b/test/old/testdir/test_normal.vim
index 57b68bcbb6..c022133b4f 100644
--- a/test/old/testdir/test_normal.vim
+++ b/test/old/testdir/test_normal.vim
@@ -4062,13 +4062,13 @@ func Test_normal_click_on_ctrl_char()
call assert_equal([0, 1, 1, 0, 1], getcurpos())
call Ntest_setmouse(1, 2)
call feedkeys("\<LeftMouse>", 'xt')
- call assert_equal([0, 1, 2, 0, 8], getcurpos())
+ call assert_equal([0, 1, 2, 0, 2], getcurpos())
call Ntest_setmouse(1, 3)
call feedkeys("\<LeftMouse>", 'xt')
- call assert_equal([0, 1, 2, 0, 8], getcurpos())
+ call assert_equal([0, 1, 2, 0, 3], getcurpos())
call Ntest_setmouse(1, 7)
call feedkeys("\<LeftMouse>", 'xt')
- call assert_equal([0, 1, 2, 0, 8], getcurpos())
+ call assert_equal([0, 1, 2, 0, 7], getcurpos())
call Ntest_setmouse(1, 8)
call feedkeys("\<LeftMouse>", 'xt')
call assert_equal([0, 1, 2, 0, 8], getcurpos())
@@ -4080,13 +4080,13 @@ func Test_normal_click_on_ctrl_char()
call assert_equal([0, 1, 4, 0, 10], getcurpos())
call Ntest_setmouse(1, 11)
call feedkeys("\<LeftMouse>", 'xt')
- call assert_equal([0, 1, 4, 0, 10], getcurpos())
+ call assert_equal([0, 1, 4, 0, 11], getcurpos())
call Ntest_setmouse(1, 12)
call feedkeys("\<LeftMouse>", 'xt')
call assert_equal([0, 1, 5, 0, 12], getcurpos())
call Ntest_setmouse(1, 13)
call feedkeys("\<LeftMouse>", 'xt')
- call assert_equal([0, 1, 5, 0, v:maxcol], getcurpos())
+ call assert_equal([0, 1, 5, 0, 13], getcurpos())
bwipe!
let &mouse = save_mouse
diff --git a/test/old/testdir/test_virtualedit.vim b/test/old/testdir/test_virtualedit.vim
index a2baf276ac..f97b3f987d 100644
--- a/test/old/testdir/test_virtualedit.vim
+++ b/test/old/testdir/test_virtualedit.vim
@@ -586,6 +586,12 @@ func Test_virtualedit_mouse()
call Ntest_setmouse(1, 9)
call feedkeys("\<LeftMouse>", "xt")
call assert_equal([0, 1, 6, 0, 9], getcurpos())
+ call Ntest_setmouse(1, 12)
+ call feedkeys("\<LeftMouse>", "xt")
+ call assert_equal([0, 1, 9, 0, 12], getcurpos())
+ call Ntest_setmouse(1, 13)
+ call feedkeys("\<LeftMouse>", "xt")
+ call assert_equal([0, 1, 10, 0, 13], getcurpos())
call Ntest_setmouse(1, 15)
call feedkeys("\<LeftMouse>", "xt")
call assert_equal([0, 1, 10, 2, 15], getcurpos())