diff options
author | Tommy Allen <tommy@esdf.io> | 2018-01-24 19:19:22 -0500 |
---|---|---|
committer | Tommy Allen <tommy@esdf.io> | 2018-01-28 23:47:11 -0500 |
commit | 0376874c326c85b5e155ad0bed24f5dfb8707608 (patch) | |
tree | bf3a23e9b0aba9c69546cb233b37d8bf9bc30514 | |
parent | 9a36337d32481e0324fe85e2b4886e02f8f74a2c (diff) | |
download | rneovim-0376874c326c85b5e155ad0bed24f5dfb8707608.tar.gz rneovim-0376874c326c85b5e155ad0bed24f5dfb8707608.tar.bz2 rneovim-0376874c326c85b5e155ad0bed24f5dfb8707608.zip |
mouse.c: Fix mouse click on lines with multibyte text
fixes #5341, #5801
-rw-r--r-- | src/nvim/mouse.c | 84 |
1 files changed, 51 insertions, 33 deletions
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index d908a022f1..e4dc47efde 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -609,7 +609,7 @@ bool mouse_scroll_horiz(int dir) } // 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) { 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; } - int end = (colnr_T)STRLEN(ml_get(wp->w_cursor.lnum)); - int vend = getviscol2(end, 0); + char_u *line = ml_get(wp->w_cursor.lnum); + char_u *ptr = line; + char_u *ptr_end = line; + char_u *ptr_row_offset = line; - if (col >= vend) { - return col; + int offset = wp->w_leftcol; + if (row > 0) { + offset += row * (wp->w_width - win_col_off(wp) - win_col_off2(wp) - + wp->w_leftcol + wp->w_skipcol); } - int i = wp->w_leftcol; + 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; + } - if (row > 0) { - i += row * (wp->w_width - win_col_off(wp) - win_col_off2(wp) - - wp->w_leftcol) + wp->w_skipcol; + for (int i = 0; i < col; i++) { + ptr_end += utf_ptr2len(ptr_end); } - int start_col = i; int matchid; - int last_matchid; - int bcol = end - (vend - col); - - while (i < bcol) { - matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, i); - + int prev_matchid; + int len = 0; + int prev_len = 0; + +#define incr() col++; ptr_end += utf_ptr2len(ptr_end) +#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 (wp->w_p_cole == 3) { - bcol++; + incr(); } else { - if (row > 0 && i == start_col) { + if (row > 0 && ptr == ptr_row_offset) { // Check if the current concealed character is actually part of // the previous wrapped row's conceal group. - last_matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, - i - 1); - if (last_matchid == matchid) { - bcol++; + prev_matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, + (colnr_T)((ptr - line) + - prev_len)); + if (prev_matchid == matchid) { + incr(); } } else if (wp->w_p_cole == 1 || (wp->w_p_cole == 2 && (lcs_conceal != NUL || syn_get_sub_char() != NUL))) { // At least one placeholder character will be displayed. - bcol--; + decr(); } - last_matchid = matchid; - - // Adjust for concealed text that spans more than one character. + prev_matchid = matchid; do { - i++; - bcol++; - matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, i); - } while (last_matchid == matchid); + incr(); + ptr += len; + prev_len = len; + len = utf_ptr2len(ptr); + matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, + (colnr_T)(ptr - line)); + } while (prev_matchid == matchid); continue; } } - i++; + ptr += len; } - return getviscol2(bcol, 0); + return col; } - |