mouse.c: Fix mouse click on lines with multibyte text

fixes #5341, #5801
This commit is contained in:
Tommy Allen 2018-01-24 19:19:22 -05:00
parent 9a36337d32
commit 0376874c32

View File

@ -609,7 +609,7 @@ bool mouse_scroll_horiz(int dir)
} }
// Adjust the clicked column position if there are concealed characters // Adjust the clicked column position if there are concealed characters
// before the current column. But only when it's absolutely necessary. // before the current column.
static int mouse_adjust_click(win_T *wp, int row, int col) static int mouse_adjust_click(win_T *wp, int row, int col)
{ {
if (!(wp->w_p_cole > 0 && curbuf->b_p_smc > 0 if (!(wp->w_p_cole > 0 && curbuf->b_p_smc > 0
@ -617,64 +617,82 @@ static int mouse_adjust_click(win_T *wp, int row, int col)
return col; return col;
} }
int end = (colnr_T)STRLEN(ml_get(wp->w_cursor.lnum)); char_u *line = ml_get(wp->w_cursor.lnum);
int vend = getviscol2(end, 0); char_u *ptr = line;
char_u *ptr_end = line;
if (col >= vend) { char_u *ptr_row_offset = line;
return col;
}
int i = wp->w_leftcol;
int offset = wp->w_leftcol;
if (row > 0) { if (row > 0) {
i += row * (wp->w_width - win_col_off(wp) - win_col_off2(wp) offset += row * (wp->w_width - win_col_off(wp) - win_col_off2(wp) -
- wp->w_leftcol) + wp->w_skipcol; wp->w_leftcol + wp->w_skipcol);
}
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.
while (offset--) {
ptr += utf_ptr2len(ptr);
}
ptr_row_offset = ptr;
}
for (int i = 0; i < col; i++) {
ptr_end += utf_ptr2len(ptr_end);
} }
int start_col = i;
int matchid; int matchid;
int last_matchid; int prev_matchid;
int bcol = end - (vend - col); int len = 0;
int prev_len = 0;
while (i < bcol) { #define incr() col++; ptr_end += utf_ptr2len(ptr_end)
matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, i); #define decr() col--; ptr_end -= utf_ptr2len(ptr_end)
while (ptr < ptr_end) {
prev_len = len;
len = utf_ptr2len(ptr);
matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum,
(colnr_T)(ptr - line));
if (matchid != 0) { if (matchid != 0) {
if (wp->w_p_cole == 3) { if (wp->w_p_cole == 3) {
bcol++; incr();
} else { } else {
if (row > 0 && i == start_col) { if (row > 0 && ptr == ptr_row_offset) {
// Check if the current concealed character is actually part of // Check if the current concealed character is actually part of
// the previous wrapped row's conceal group. // the previous wrapped row's conceal group.
last_matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, prev_matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum,
i - 1); (colnr_T)((ptr - line)
if (last_matchid == matchid) { - prev_len));
bcol++; if (prev_matchid == matchid) {
incr();
} }
} else if (wp->w_p_cole == 1 } else if (wp->w_p_cole == 1
|| (wp->w_p_cole == 2 || (wp->w_p_cole == 2
&& (lcs_conceal != NUL && (lcs_conceal != NUL
|| syn_get_sub_char() != NUL))) { || syn_get_sub_char() != NUL))) {
// At least one placeholder character will be displayed. // At least one placeholder character will be displayed.
bcol--; decr();
} }
last_matchid = matchid; prev_matchid = matchid;
// Adjust for concealed text that spans more than one character.
do { do {
i++; incr();
bcol++; ptr += len;
matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, i); prev_len = len;
} while (last_matchid == matchid); len = utf_ptr2len(ptr);
matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum,
(colnr_T)(ptr - line));
} while (prev_matchid == matchid);
continue; continue;
} }
} }
i++; ptr += len;
} }
return getviscol2(bcol, 0); return col;
} }