mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #24780 from zeertzjq/vim-9.0.0048
vim-patch:9.0.{0048,0177,1705,1725}: mouse click after concealed text
This commit is contained in:
@@ -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--;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 }
|
||||
|
||||
|
||||
188
src/nvim/mouse.c
188
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;
|
||||
}
|
||||
|
||||
@@ -1073,39 +1073,7 @@ describe('ui/mouse/input', function()
|
||||
]])
|
||||
end)
|
||||
|
||||
describe('on concealed text', function()
|
||||
-- Helpful for reading the test expectations:
|
||||
-- :match Error /\^/
|
||||
|
||||
before_each(function()
|
||||
screen:try_resize(25, 7)
|
||||
screen:set_default_attr_ids({
|
||||
[0] = {bold=true, foreground=Screen.colors.Blue},
|
||||
c = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray },
|
||||
sm = {bold = true},
|
||||
})
|
||||
feed('ggdG')
|
||||
|
||||
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]])
|
||||
command([[highlight link X2 NonText]])
|
||||
command([[highlight link X3 NonText]])
|
||||
|
||||
-- First column is there to retain the tabs.
|
||||
insert([[
|
||||
|Section *t1*
|
||||
| *t2* *t3* *t4*
|
||||
|x 私は猫が大好き *cats* ✨🐈✨
|
||||
]])
|
||||
|
||||
feed('gg<c-v>Gxgg')
|
||||
end)
|
||||
|
||||
local function test_mouse_click_conceal()
|
||||
it('(level 1) click on non-wrapped lines', function()
|
||||
feed_command('let &conceallevel=1', 'echo')
|
||||
|
||||
@@ -1497,7 +1465,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 +1502,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 |
|
||||
@@ -1638,6 +1606,75 @@ describe('ui/mouse/input', function()
|
||||
]])
|
||||
|
||||
end) -- level 3 - wrapped
|
||||
end
|
||||
|
||||
describe('on concealed text', function()
|
||||
-- Helpful for reading the test expectations:
|
||||
-- :match Error /\^/
|
||||
|
||||
before_each(function()
|
||||
screen:try_resize(25, 7)
|
||||
screen:set_default_attr_ids({
|
||||
[0] = { bold = true, foreground = Screen.colors.Blue },
|
||||
c = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray },
|
||||
sm = { bold = true },
|
||||
})
|
||||
feed('ggdG')
|
||||
|
||||
command([[setlocal concealcursor=ni nowrap shiftwidth=2 tabstop=4 list listchars=tab:>-]])
|
||||
command([[highlight link X0 Normal]])
|
||||
command([[highlight link X1 NonText]])
|
||||
command([[highlight link X2 NonText]])
|
||||
command([[highlight link X3 NonText]])
|
||||
|
||||
-- First column is there to retain the tabs.
|
||||
insert([[
|
||||
|Section *t1*
|
||||
| *t2* *t3* *t4*
|
||||
|x 私は猫が大好き *cats* ✨🐈✨
|
||||
]])
|
||||
|
||||
feed('gg<c-v>Gxgg')
|
||||
end)
|
||||
|
||||
describe('(syntax)', function()
|
||||
before_each(function()
|
||||
command([[syntax region X0 matchgroup=X1 start=/\*/ end=/\*/ concealends contains=X2]])
|
||||
command([[syntax match X2 /cats/ conceal cchar=X contained]])
|
||||
command([[syntax match X3 /\n\@<=x/ conceal cchar=>]])
|
||||
end)
|
||||
test_mouse_click_conceal()
|
||||
end)
|
||||
|
||||
describe('(matchadd())', function()
|
||||
before_each(function()
|
||||
funcs.matchadd('Conceal', [[\*]])
|
||||
funcs.matchadd('Conceal', [[cats]], 10, -1, { conceal = 'X' })
|
||||
funcs.matchadd('Conceal', [[\n\@<=x]], 10, -1, { conceal = '>' })
|
||||
end)
|
||||
test_mouse_click_conceal()
|
||||
end)
|
||||
|
||||
-- FIXME: cannot make extmark conceal behave exactly like syntax conceal without cchar
|
||||
pending('(extmarks)', function()
|
||||
before_each(function()
|
||||
local ns = meths.create_namespace('conceal')
|
||||
meths.buf_set_extmark(0, ns, 0, 11, { end_col = 12, conceal = '' })
|
||||
meths.buf_set_extmark(0, ns, 0, 14, { end_col = 15, conceal = '' })
|
||||
meths.buf_set_extmark(0, ns, 1, 5, { end_col = 6, conceal = '' })
|
||||
meths.buf_set_extmark(0, ns, 1, 8, { end_col = 9, conceal = '' })
|
||||
meths.buf_set_extmark(0, ns, 1, 10, { end_col = 11, conceal = '' })
|
||||
meths.buf_set_extmark(0, ns, 1, 13, { end_col = 14, conceal = '' })
|
||||
meths.buf_set_extmark(0, ns, 1, 15, { end_col = 16, conceal = '' })
|
||||
meths.buf_set_extmark(0, ns, 1, 18, { end_col = 19, conceal = '' })
|
||||
meths.buf_set_extmark(0, ns, 2, 24, { end_col = 25, conceal = '' })
|
||||
meths.buf_set_extmark(0, ns, 2, 29, { end_col = 30, conceal = '' })
|
||||
meths.buf_set_extmark(0, ns, 2, 25, { end_col = 29, conceal = 'X' })
|
||||
meths.buf_set_extmark(0, ns, 2, 0, { end_col = 1, conceal = '>' })
|
||||
end)
|
||||
test_mouse_click_conceal()
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
it('getmousepos works correctly', function()
|
||||
|
||||
@@ -4,6 +4,7 @@ source check.vim
|
||||
CheckFeature conceal
|
||||
|
||||
source screendump.vim
|
||||
source view_util.vim
|
||||
|
||||
func Test_conceal_two_windows()
|
||||
CheckScreendump
|
||||
@@ -334,4 +335,70 @@ func Test_conceal_eol()
|
||||
set nolist
|
||||
endfunc
|
||||
|
||||
func Test_conceal_mouse_click()
|
||||
enew!
|
||||
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 '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 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& virtualedit&
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
||||
@@ -4049,4 +4049,47 @@ func Test_normal_r_ctrl_v_cmd()
|
||||
bw!
|
||||
endfunc
|
||||
|
||||
" Test clicking on a TAB or an unprintable character in Normal mode
|
||||
func Test_normal_click_on_ctrl_char()
|
||||
let save_mouse = &mouse
|
||||
set mouse=a
|
||||
new
|
||||
|
||||
call setline(1, "a\<Tab>b\<C-K>c")
|
||||
redraw
|
||||
call Ntest_setmouse(1, 1)
|
||||
call feedkeys("\<LeftMouse>", 'xt')
|
||||
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, 2], getcurpos())
|
||||
call Ntest_setmouse(1, 3)
|
||||
call feedkeys("\<LeftMouse>", 'xt')
|
||||
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, 7], getcurpos())
|
||||
call Ntest_setmouse(1, 8)
|
||||
call feedkeys("\<LeftMouse>", 'xt')
|
||||
call assert_equal([0, 1, 2, 0, 8], getcurpos())
|
||||
call Ntest_setmouse(1, 9)
|
||||
call feedkeys("\<LeftMouse>", 'xt')
|
||||
call assert_equal([0, 1, 3, 0, 9], getcurpos())
|
||||
call Ntest_setmouse(1, 10)
|
||||
call feedkeys("\<LeftMouse>", 'xt')
|
||||
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, 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, 13], getcurpos())
|
||||
|
||||
bwipe!
|
||||
let &mouse = save_mouse
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
||||
@@ -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())
|
||||
|
||||
Reference in New Issue
Block a user