From 0376874c326c85b5e155ad0bed24f5dfb8707608 Mon Sep 17 00:00:00 2001 From: Tommy Allen Date: Wed, 24 Jan 2018 19:19:22 -0500 Subject: [PATCH 1/7] mouse.c: Fix mouse click on lines with multibyte text fixes #5341, #5801 --- src/nvim/mouse.c | 84 +++++++++++++++++++++++++++++------------------- 1 file 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); - - if (col >= vend) { - return col; - } - - int i = wp->w_leftcol; + char_u *line = ml_get(wp->w_cursor.lnum); + char_u *ptr = line; + char_u *ptr_end = line; + char_u *ptr_row_offset = line; + int offset = wp->w_leftcol; if (row > 0) { - i += row * (wp->w_width - win_col_off(wp) - win_col_off2(wp) - - wp->w_leftcol) + wp->w_skipcol; + offset += row * (wp->w_width - win_col_off(wp) - win_col_off2(wp) - + 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 last_matchid; - int bcol = end - (vend - col); + int prev_matchid; + int len = 0; + int prev_len = 0; - while (i < bcol) { - matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, i); +#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; } - From d2ff5d5bb0807be17211b5e3e86da16038d23537 Mon Sep 17 00:00:00 2001 From: Tommy Allen Date: Thu, 25 Jan 2018 10:28:14 -0500 Subject: [PATCH 2/7] Use utfc_ptr2len instead of utf_ptr2len --- src/nvim/mouse.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index e4dc47efde..ea3505aec1 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -634,13 +634,13 @@ static int mouse_adjust_click(win_T *wp, int row, int col) // 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 += utfc_ptr2len(ptr); } ptr_row_offset = ptr; } for (int i = 0; i < col; i++) { - ptr_end += utf_ptr2len(ptr_end); + ptr_end += utfc_ptr2len(ptr_end); } int matchid; @@ -648,12 +648,12 @@ static int mouse_adjust_click(win_T *wp, int row, int col) 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) +#define incr() col++; ptr_end += utfc_ptr2len(ptr_end) +#define decr() col--; ptr_end -= utfc_ptr2len(ptr_end) while (ptr < ptr_end) { prev_len = len; - len = utf_ptr2len(ptr); + len = utfc_ptr2len(ptr); matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, (colnr_T)(ptr - line)); if (matchid != 0) { @@ -682,7 +682,7 @@ static int mouse_adjust_click(win_T *wp, int row, int col) incr(); ptr += len; prev_len = len; - len = utf_ptr2len(ptr); + len = utfc_ptr2len(ptr); matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, (colnr_T)(ptr - line)); } while (prev_matchid == matchid); From 60d035311945c3cf7b87cc3838091f7cd97944f1 Mon Sep 17 00:00:00 2001 From: Tommy Allen Date: Thu, 25 Jan 2018 10:33:44 -0500 Subject: [PATCH 3/7] Don't move cursor to the left if on the first column of wrapped line ref: #7887 --- src/nvim/mouse.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index ea3505aec1..d2b33b03d7 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -646,13 +646,11 @@ static int mouse_adjust_click(win_T *wp, int row, int col) int matchid; int prev_matchid; int len = 0; - int prev_len = 0; #define incr() col++; ptr_end += utfc_ptr2len(ptr_end) #define decr() col--; ptr_end -= utfc_ptr2len(ptr_end) while (ptr < ptr_end) { - prev_len = len; len = utfc_ptr2len(ptr); matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, (colnr_T)(ptr - line)); @@ -660,19 +658,10 @@ static int mouse_adjust_click(win_T *wp, int row, int col) if (wp->w_p_cole == 3) { incr(); } else { - if (row > 0 && ptr == ptr_row_offset) { - // Check if the current concealed character is actually part of - // the previous wrapped row's conceal group. - 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))) { + if (!(row > 0 && ptr == ptr_row_offset) + && (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. decr(); } @@ -681,7 +670,6 @@ static int mouse_adjust_click(win_T *wp, int row, int col) do { incr(); ptr += len; - prev_len = len; len = utfc_ptr2len(ptr); matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, (colnr_T)(ptr - line)); From caf87f597febb90728288865d8df48c35c4a78e3 Mon Sep 17 00:00:00 2001 From: Tommy Allen Date: Fri, 26 Jan 2018 01:39:20 -0500 Subject: [PATCH 4/7] Adjust cursor according to character display widths --- src/nvim/mouse.c | 66 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 18 deletions(-) diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index d2b33b03d7..9bba165299 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -608,8 +608,7 @@ bool mouse_scroll_horiz(int dir) return leftcol_changed(); } -// Adjust the clicked column position if there are concealed characters -// before the current column. +/// 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 @@ -617,43 +616,76 @@ static int mouse_adjust_click(win_T *wp, int row, int col) return col; } - char_u *line = ml_get(wp->w_cursor.lnum); + // `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. + // + // 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; + char_u *line = ml_get(lnum); char_u *ptr = line; char_u *ptr_end = line; - char_u *ptr_row_offset = line; + char_u *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 - 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. - while (offset--) { + vcol = 0; + while (vcol < offset && *ptr != NUL) { + vcol += chartabsize(ptr, vcol); ptr += utfc_ptr2len(ptr); } + ptr_row_offset = ptr; } - for (int i = 0; i < col; i++) { + // Align `ptr_end` with `col` + vcol = offset; + ptr_end = ptr_row_offset; + while (vcol < col && *ptr_end != NUL) { + vcol += chartabsize(ptr_end, vcol); ptr_end += utfc_ptr2len(ptr_end); } int matchid; int prev_matchid; - int len = 0; + int nudge = 0; + int cwidth = 0; -#define incr() col++; ptr_end += utfc_ptr2len(ptr_end) -#define decr() col--; ptr_end -= utfc_ptr2len(ptr_end) + vcol = offset; - while (ptr < ptr_end) { - len = utfc_ptr2len(ptr); - matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, - (colnr_T)(ptr - line)); +#define incr() col++; nudge++; ptr_end += utfc_ptr2len(ptr_end) +#define decr() col--; nudge--; ptr_end -= utfc_ptr2len(ptr_end) + + while (ptr < ptr_end && *ptr != NUL) { + cwidth = chartabsize(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--; + } + } + + matchid = syn_get_concealed_id(wp, lnum, (colnr_T)(ptr - line)); if (matchid != 0) { if (wp->w_p_cole == 3) { incr(); @@ -669,17 +701,15 @@ static int mouse_adjust_click(win_T *wp, int row, int col) prev_matchid = matchid; do { incr(); - ptr += len; - len = utfc_ptr2len(ptr); - matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, - (colnr_T)(ptr - line)); + ptr += utfc_ptr2len(ptr); + matchid = syn_get_concealed_id(wp, lnum, (colnr_T)(ptr - line)); } while (prev_matchid == matchid); continue; } } - ptr += len; + ptr += utfc_ptr2len(ptr); } return col; From be7990bb49d73c56a4aba6c7ce9509d116b77348 Mon Sep 17 00:00:00 2001 From: Tommy Allen Date: Fri, 26 Jan 2018 16:10:16 -0500 Subject: [PATCH 5/7] Use one variable for tracking adjustment instead of two --- src/nvim/mouse.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index 9bba165299..1e1fbe7a4d 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -670,8 +670,8 @@ static int mouse_adjust_click(win_T *wp, int row, int col) vcol = offset; -#define incr() col++; nudge++; ptr_end += utfc_ptr2len(ptr_end) -#define decr() col--; nudge--; ptr_end -= utfc_ptr2len(ptr_end) +#define incr() nudge++; ptr_end += utfc_ptr2len(ptr_end) +#define decr() nudge--; ptr_end -= utfc_ptr2len(ptr_end) while (ptr < ptr_end && *ptr != NUL) { cwidth = chartabsize(ptr, vcol); @@ -712,5 +712,5 @@ static int mouse_adjust_click(win_T *wp, int row, int col) ptr += utfc_ptr2len(ptr); } - return col; + return col + nudge; } From 2eb8dc40acc82231dcb8a6bfd1900a1640a2118a Mon Sep 17 00:00:00 2001 From: Tommy Allen Date: Sat, 27 Jan 2018 00:20:18 -0500 Subject: [PATCH 6/7] Safer loop for skipping consecutive concealed chars --- src/nvim/mouse.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index 1e1fbe7a4d..6f636f643a 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -699,11 +699,12 @@ static int mouse_adjust_click(win_T *wp, int row, int col) } prev_matchid = matchid; - do { + + while (prev_matchid == matchid && *ptr != NUL) { incr(); ptr += utfc_ptr2len(ptr); matchid = syn_get_concealed_id(wp, lnum, (colnr_T)(ptr - line)); - } while (prev_matchid == matchid); + } continue; } From 1813c53e8d5d11dd0584a6f2acc628c5605d92bf Mon Sep 17 00:00:00 2001 From: Tommy Allen Date: Sat, 27 Jan 2018 02:04:32 -0500 Subject: [PATCH 7/7] Updated tests --- test/functional/ui/mouse_spec.lua | 447 +++++++++++++++++++++--------- 1 file changed, 311 insertions(+), 136 deletions(-) diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index 3fdedeb073..13820af3b8 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -750,17 +750,19 @@ describe('ui/mouse/input', function() feed_command('set concealcursor=n') feed_command('set nowrap') - feed_command('syntax match NonText "\\" conceal') - feed_command('syntax match NonText "\\cs\\|g." conceal cchar=X') - feed_command('syntax match NonText "\\%(lo\\|cl\\)." conceal') - feed_command('syntax match NonText "Lo" conceal cchar=Y') + feed_command('set shiftwidth=2 tabstop=4 list listchars=tab:>-') + feed_command('syntax match NonText "\\*" conceal') + feed_command('syntax match NonText "cats" conceal cchar=X') + feed_command('syntax match NonText "x" conceal cchar=>') + -- First column is there to retain the tabs. insert([[ - Lorem ipsum dolor sit amet, consetetur sadipscing elitr. - Stet clita kasd gubergren, no sea takimata sanctus est. + |Section *t1* + | *t2* *t3* *t4* + |x 私は猫が大好き *cats* ✨🐈✨ ]]) - feed('gg') + feed('ggGxgg') end) it('(level 1) click on non-wrapped lines', function() @@ -768,93 +770,138 @@ describe('ui/mouse/input', function() feed('<0,0>') screen:expect([[ - {c:^Y}rem ip{c:X}um do{c: } {c:X}it {c: }, con| - {c:X}tet {c: }ta ka{c:X}d {c:X}ber{c:X}en, no| + ^Section{0:>>--->--->---}{c: }t1{c: } | + {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }| + {c:>} 私は猫が大好き{0:>---}{c: X } {0:>}| | {0:~ }| - {0:~ }| {0:~ }| | ]]) feed('<1,0>') screen:expect([[ - {c:Y}^rem ip{c:X}um do{c: } {c:X}it {c: }, con| - {c:X}tet {c: }ta ka{c:X}d {c:X}ber{c:X}en, no| + S^ection{0:>>--->--->---}{c: }t1{c: } | + {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }| + {c:>} 私は猫が大好き{0:>---}{c: X } {0:>}| | {0:~ }| - {0:~ }| {0:~ }| | ]]) - feed('<15,0>') + feed('<21,0>') screen:expect([[ - {c:Y}rem ip{c:X}um do{c: } {c:^X}it {c: }, con| - {c:X}tet {c: }ta ka{c:X}d {c:X}ber{c:X}en, no| + Section{0:>>--->--->---}{c: }^t1{c: } | + {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }| + {c:>} 私は猫が大好き{0:>---}{c: X } {0:>}| | {0:~ }| - {0:~ }| {0:~ }| | ]]) - feed('<15,1>') + feed('<21,1>') screen:expect([[ - {c:Y}rem ip{c:X}um do{c: } {c:X}it {c: }, con| - {c:X}tet {c: }ta ka{c:X}d {c:X}^ber{c:X}en, no| + Section{0:>>--->--->---}{c: }t1{c: } | + {0:>--->--->---} {c: }t2{c: } {c: }t^3{c: } {c: }| + {c:>} 私は猫が大好き{0:>---}{c: X } {0:>}| | {0:~ }| - {0:~ }| {0:~ }| | ]]) + + feed('<0,2>') + screen:expect([[ + Section{0:>>--->--->---}{c: }t1{c: } | + {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }| + {c:^>} 私は猫が大好き{0:>---}{c: X } {0:>}| + | + {0:~ }| + {0:~ }| + | + ]]) + + feed('<7,2>') + screen:expect([[ + Section{0:>>--->--->---}{c: }t1{c: } | + {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }| + {c:>} 私は^猫が大好き{0:>---}{c: X } {0:>}| + | + {0:~ }| + {0:~ }| + | + ]]) + + feed('<21,2>') + screen:expect([[ + Section{0:>>--->--->---}{c: }t1{c: } | + {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }| + {c:>} 私は猫が大好き{0:>---}{c: ^X } {0:>}| + | + {0:~ }| + {0:~ }| + | + ]]) + end) -- level 1 - non wrapped it('(level 1) click on wrapped lines', function() feed_command('let &conceallevel=1', 'let &wrap=1', 'echo') - feed('<0,0>') + feed('<24,1>') screen:expect([[ - {c:^Y}rem ip{c:X}um do{c: } {c:X}it {c: } | - , con{c:X}etetur {c:X}adip{c:X}cin{c:X} | - elitr. | - {c:X}tet {c: }ta ka{c:X}d {c:X}ber{c:X}en | - , no {c:X}ea takimata {c:X}anctu{c:X}| - e{c:X}t. | + Section{0:>>--->--->---}{c: }t1{c: } | + {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c:^ }| + t4{c: } | + {c:>} 私は猫が大好き{0:>---}{c: X} | + {c: } ✨🐈✨ | + | | ]]) - feed('<6,1>') + feed('<0,2>') screen:expect([[ - {c:Y}rem ip{c:X}um do{c: } {c:X}it {c: } | - , con{c:X}^etetur {c:X}adip{c:X}cin{c:X} | - elitr. | - {c:X}tet {c: }ta ka{c:X}d {c:X}ber{c:X}en | - , no {c:X}ea takimata {c:X}anctu{c:X}| - e{c:X}t. | + Section{0:>>--->--->---}{c: }t1{c: } | + {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }| + ^t4{c: } | + {c:>} 私は猫が大好き{0:>---}{c: X} | + {c: } ✨🐈✨ | + | | ]]) - feed('<15,1>') + feed('<8,3>') screen:expect([[ - {c:Y}rem ip{c:X}um do{c: } {c:X}it {c: } | - , con{c:X}etetur {c:X}a^dip{c:X}cin{c:X} | - elitr. | - {c:X}tet {c: }ta ka{c:X}d {c:X}ber{c:X}en | - , no {c:X}ea takimata {c:X}anctu{c:X}| - e{c:X}t. | + Section{0:>>--->--->---}{c: }t1{c: } | + {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }| + t4{c: } | + {c:>} 私は猫^が大好き{0:>---}{c: X} | + {c: } ✨🐈✨ | + | | ]]) - feed('<15,3>') + feed('<21,3>') screen:expect([[ - {c:Y}rem ip{c:X}um do{c: } {c:X}it {c: } | - , con{c:X}etetur {c:X}adip{c:X}cin{c:X} | - elitr. | - {c:X}tet {c: }ta ka{c:X}d {c:X}^ber{c:X}en | - , no {c:X}ea takimata {c:X}anctu{c:X}| - e{c:X}t. | + Section{0:>>--->--->---}{c: }t1{c: } | + {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }| + t4{c: } | + {c:>} 私は猫が大好き{0:>---}{c: ^X} | + {c: } ✨🐈✨ | + | + | + ]]) + + feed('<4,4>') + screen:expect([[ + Section{0:>>--->--->---}{c: }t1{c: } | + {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }| + t4{c: } | + {c:>} 私は猫が大好き{0:>---}{c: X} | + {c: } ✨^🐈✨ | + | | ]]) end) -- level 1 - wrapped @@ -863,45 +910,67 @@ describe('ui/mouse/input', function() it('(level 2) click on non-wrapped lines', function() feed_command('let &conceallevel=2', 'echo') - feed('<0,0>') + feed('<20,0>') screen:expect([[ - {c:^Y}rem ip{c:X}um do {c:X}it , con{c:X}e| - {c:X}tet ta ka{c:X}d {c:X}ber{c:X}en, no | + Section{0:>>--->--->---}^t1 | + {0:>--->--->---} t2 t3 t4 | + {c:>} 私は猫が大好き{0:>---}{c:X} ✨{0:>}| | {0:~ }| - {0:~ }| {0:~ }| | ]]) - feed('<1,0>') + feed('<14,1>') screen:expect([[ - {c:Y}^rem ip{c:X}um do {c:X}it , con{c:X}e| - {c:X}tet ta ka{c:X}d {c:X}ber{c:X}en, no | + Section{0:>>--->--->---}t1 | + {0:>--->--->---} ^t2 t3 t4 | + {c:>} 私は猫が大好き{0:>---}{c:X} ✨{0:>}| | {0:~ }| - {0:~ }| {0:~ }| | ]]) - feed('<15,0>') + feed('<18,1>') screen:expect([[ - {c:Y}rem ip{c:X}um do {c:X}^it , con{c:X}e| - {c:X}tet ta ka{c:X}d {c:X}ber{c:X}en, no | + Section{0:>>--->--->---}t1 | + {0:>--->--->---} t2 t^3 t4 | + {c:>} 私は猫が大好き{0:>---}{c:X} ✨{0:>}| | {0:~ }| - {0:~ }| {0:~ }| | ]]) - feed('<15,1>') + feed('<0,2>') -- Weirdness screen:expect([[ - {c:Y}rem ip{c:X}um do {c:X}it , con{c:X}e| - {c:X}tet ta ka{c:X}d {c:X}b^er{c:X}en, no | + Section{0:>>--->--->---}t1 | + {0:>--->--->---} t2 t3 t4 | + {c:^>} 私は猫が大好き{0:>---}{c:X} ✨{0:>}| | {0:~ }| + {0:~ }| + | + ]]) + + feed('<8,2>') + screen:expect([[ + Section{0:>>--->--->---}t1 | + {0:>--->--->---} t2 t3 t4 | + {c:>} 私は猫^が大好き{0:>---}{c:X} ✨{0:>}| + | + {0:~ }| + {0:~ }| + | + ]]) + + feed('<20,2>') + screen:expect([[ + Section{0:>>--->--->---}t1 | + {0:>--->--->---} t2 t3 t4 | + {c:>} 私は猫が大好き{0:>---}{c:^X} ✨{0:>}| + | {0:~ }| {0:~ }| | @@ -911,47 +980,108 @@ describe('ui/mouse/input', function() it('(level 2) click on wrapped lines', function() feed_command('let &conceallevel=2', 'let &wrap=1', 'echo') - feed('<0,0>') + feed('<20,0>') screen:expect([[ - {c:^Y}rem ip{c:X}um do {c:X}it | - , con{c:X}etetur {c:X}adip{c:X}cin{c:X} | - elitr. | - {c:X}tet ta ka{c:X}d {c:X}ber{c:X}en | - , no {c:X}ea takimata {c:X}anctu{c:X}| - e{c:X}t. | + Section{0:>>--->--->---}^t1 | + {0:>--->--->---} t2 t3 | + t4 | + {c:>} 私は猫が大好き{0:>---}{c:X} | + ✨🐈✨ | + | | ]]) - feed('<6,1>') + feed('<14,1>') screen:expect([[ - {c:Y}rem ip{c:X}um do {c:X}it | - , con{c:X}^etetur {c:X}adip{c:X}cin{c:X} | - elitr. | - {c:X}tet ta ka{c:X}d {c:X}ber{c:X}en | - , no {c:X}ea takimata {c:X}anctu{c:X}| - e{c:X}t. | + Section{0:>>--->--->---}t1 | + {0:>--->--->---} ^t2 t3 | + t4 | + {c:>} 私は猫が大好き{0:>---}{c:X} | + ✨🐈✨ | + | | ]]) - feed('<15,1>') + feed('<18,1>') screen:expect([[ - {c:Y}rem ip{c:X}um do {c:X}it | - , con{c:X}etetur {c:X}a^dip{c:X}cin{c:X} | - elitr. | - {c:X}tet ta ka{c:X}d {c:X}ber{c:X}en | - , no {c:X}ea takimata {c:X}anctu{c:X}| - e{c:X}t. | + Section{0:>>--->--->---}t1 | + {0:>--->--->---} t2 t^3 | + t4 | + {c:>} 私は猫が大好き{0:>---}{c:X} | + ✨🐈✨ | + | | ]]) - feed('<15,3>') + -- NOTE: The click would ideally be on the 't' in 't4', but wrapping + -- caused the invisible '*' right before 't4' to remain on the previous + -- screen line. This is being treated as expected because fixing this is + -- out of scope for mouse clicks. Should the wrapping behavior of + -- concealed characters change in the future, this case should be + -- reevaluated. + feed('<0,2>') screen:expect([[ - {c:Y}rem ip{c:X}um do {c:X}it | - , con{c:X}etetur {c:X}adip{c:X}cin{c:X} | - elitr. | - {c:X}tet ta ka{c:X}d {c:X}b^er{c:X}en | - , no {c:X}ea takimata {c:X}anctu{c:X}| - e{c:X}t. | + Section{0:>>--->--->---}t1 | + {0:>--->--->---} t2 t3 ^ | + t4 | + {c:>} 私は猫が大好き{0:>---}{c:X} | + ✨🐈✨ | + | + | + ]]) + + feed('<1,2>') + screen:expect([[ + Section{0:>>--->--->---}t1 | + {0:>--->--->---} t2 t3 | + t^4 | + {c:>} 私は猫が大好き{0:>---}{c:X} | + ✨🐈✨ | + | + | + ]]) + + feed('<0,3>') + screen:expect([[ + Section{0:>>--->--->---}t1 | + {0:>--->--->---} t2 t3 | + t4 | + {c:^>} 私は猫が大好き{0:>---}{c:X} | + ✨🐈✨ | + | + | + ]]) + + feed('<20,3>') + screen:expect([[ + Section{0:>>--->--->---}t1 | + {0:>--->--->---} t2 t3 | + t4 | + {c:>} 私は猫が大好き{0:>---}{c:^X} | + ✨🐈✨ | + | + | + ]]) + + feed('<1,4>') + screen:expect([[ + Section{0:>>--->--->---}t1 | + {0:>--->--->---} t2 t3 | + t4 | + {c:>} 私は猫が大好き{0:>---}{c:X} | + ^✨🐈✨ | + | + | + ]]) + + feed('<5,4>') + screen:expect([[ + Section{0:>>--->--->---}t1 | + {0:>--->--->---} t2 t3 | + t4 | + {c:>} 私は猫が大好き{0:>---}{c:X} | + ✨🐈^✨ | + | | ]]) end) -- level 2 - wrapped @@ -960,46 +1090,46 @@ describe('ui/mouse/input', function() it('(level 3) click on non-wrapped lines', function() feed_command('let &conceallevel=3', 'echo') - feed('<0,0>') + feed('<0,2>') screen:expect([[ - ^rem ipum do it , conetetu| - tet ta kad beren, no ea t| + Section{0:>>--->--->---}t1 | + {0:>--->--->---} t2 t3 t4 | + ^ 私は猫が大好き{0:>----} ✨🐈| | {0:~ }| - {0:~ }| {0:~ }| | ]]) - feed('<1,0>') + feed('<1,2>') screen:expect([[ - r^em ipum do it , conetetu| - tet ta kad beren, no ea t| + Section{0:>>--->--->---}t1 | + {0:>--->--->---} t2 t3 t4 | + ^私は猫が大好き{0:>----} ✨🐈| | {0:~ }| - {0:~ }| {0:~ }| | ]]) - feed('<15,0>') + feed('<13,2>') screen:expect([[ - rem ipum do it ^, conetetu| - tet ta kad beren, no ea t| + Section{0:>>--->--->---}t1 | + {0:>--->--->---} t2 t3 t4 | + 私は猫が大好^き{0:>----} ✨🐈| | {0:~ }| - {0:~ }| {0:~ }| | ]]) - feed('<15,1>') + feed('<20,2>') screen:expect([[ - rem ipum do it , conetetu| - tet ta kad bere^n, no ea t| + Section{0:>>--->--->---}t1 | + {0:>--->--->---} t2 t3 t4 | + 私は猫が大好き{0:>----}^ ✨🐈| | {0:~ }| - {0:~ }| {0:~ }| | ]]) @@ -1008,49 +1138,94 @@ describe('ui/mouse/input', function() it('(level 3) click on wrapped lines', function() feed_command('let &conceallevel=3', 'let &wrap=1', 'echo') - feed('<0,0>') + feed('<14,1>') screen:expect([[ - ^rem ipum do it | - , conetetur adipcin | - elitr. | - tet ta kad beren | - , no ea takimata anctu | - et. | + Section{0:>>--->--->---}t1 | + {0:>--->--->---} ^t2 t3 | + t4 | + 私は猫が大好き{0:>----} | + ✨🐈✨ | + | | ]]) - feed('<6,1>') + feed('<18,1>') screen:expect([[ - rem ipum do it | - , cone^tetur adipcin | - elitr. | - tet ta kad beren | - , no ea takimata anctu | - et. | + Section{0:>>--->--->---}t1 | + {0:>--->--->---} t2 t^3 | + t4 | + 私は猫が大好き{0:>----} | + ✨🐈✨ | + | | ]]) - feed('<15,1>') + feed('<1,2>') screen:expect([[ - rem ipum do it | - , conetetur adi^pcin | - elitr. | - tet ta kad beren | - , no ea takimata anctu | - et. | + Section{0:>>--->--->---}t1 | + {0:>--->--->---} t2 t3 | + t^4 | + 私は猫が大好き{0:>----} | + ✨🐈✨ | + | | ]]) - feed('<15,3>') + feed('<0,3>') screen:expect([[ - rem ipum do it | - , conetetur adipcin | - elitr. | - tet ta kad bere^n | - , no ea takimata anctu | - et. | + Section{0:>>--->--->---}t1 | + {0:>--->--->---} t2 t3 | + t4 | + ^ 私は猫が大好き{0:>----} | + ✨🐈✨ | + | | ]]) + + feed('<20,3>') + screen:expect([[ + Section{0:>>--->--->---}t1 | + {0:>--->--->---} t2 t3 | + t4 | + 私は猫が大好き{0:>----}^ | + ✨🐈✨ | + | + | + ]]) + + feed('<1,4>') + screen:expect([[ + Section{0:>>--->--->---}t1 | + {0:>--->--->---} t2 t3 | + t4 | + 私は猫が大好き{0:>----} | + ^✨🐈✨ | + | + | + ]]) + + feed('<3,4>') + screen:expect([[ + Section{0:>>--->--->---}t1 | + {0:>--->--->---} t2 t3 | + t4 | + 私は猫が大好き{0:>----} | + ✨^🐈✨ | + | + | + ]]) + + feed('<5,4>') + screen:expect([[ + Section{0:>>--->--->---}t1 | + {0:>--->--->---} t2 t3 | + t4 | + 私は猫が大好き{0:>----} | + ✨🐈^✨ | + | + | + ]]) + end) -- level 3 - wrapped end) end)