mirror of
https://github.com/neovim/neovim.git
synced 2024-12-20 03:05:11 -07:00
mouse.c: Adjust clicked column if chars are concealed (#5087)
syntax.c: Added syn_get_concealed_id() tests: Added tests for mouse clicks on concealed text.
This commit is contained in:
parent
56f178058a
commit
1f7304b846
@ -6,6 +6,7 @@
|
|||||||
#include "nvim/window.h"
|
#include "nvim/window.h"
|
||||||
#include "nvim/strings.h"
|
#include "nvim/strings.h"
|
||||||
#include "nvim/screen.h"
|
#include "nvim/screen.h"
|
||||||
|
#include "nvim/syntax.h"
|
||||||
#include "nvim/ui.h"
|
#include "nvim/ui.h"
|
||||||
#include "nvim/os_unix.h"
|
#include "nvim/os_unix.h"
|
||||||
#include "nvim/fold.h"
|
#include "nvim/fold.h"
|
||||||
@ -303,6 +304,10 @@ retnomove:
|
|||||||
mouse_past_bottom = true;
|
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"
|
// Start Visual mode before coladvance(), for when 'sel' != "old"
|
||||||
if ((flags & MOUSE_MAY_VIS) && !VIsual_active) {
|
if ((flags & MOUSE_MAY_VIS) && !VIsual_active) {
|
||||||
check_visual_highlight();
|
check_visual_highlight();
|
||||||
@ -597,3 +602,74 @@ bool mouse_scroll_horiz(int dir)
|
|||||||
|
|
||||||
return leftcol_changed();
|
return leftcol_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adjust the clicked column position if there are concealed characters
|
||||||
|
// before the current column. But only when it's absolutely necessary.
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (row > 0) {
|
||||||
|
i += row * (wp->w_width - win_col_off(wp) - win_col_off2(wp)
|
||||||
|
- wp->w_leftcol) + wp->w_skipcol;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (matchid != 0) {
|
||||||
|
if (wp->w_p_cole == 3) {
|
||||||
|
bcol++;
|
||||||
|
} else {
|
||||||
|
if (row > 0 && i == start_col) {
|
||||||
|
// 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++;
|
||||||
|
}
|
||||||
|
} 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--;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_matchid = matchid;
|
||||||
|
|
||||||
|
// Adjust for concealed text that spans more than one character.
|
||||||
|
do {
|
||||||
|
i++;
|
||||||
|
bcol++;
|
||||||
|
matchid = syn_get_concealed_id(wp, wp->w_cursor.lnum, i);
|
||||||
|
} while (last_matchid == matchid);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getviscol2(bcol, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -5661,6 +5661,24 @@ int get_syntax_info(int *seqnrp)
|
|||||||
return current_flags;
|
return current_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Get the sequence number of the concealed file position.
|
||||||
|
///
|
||||||
|
/// @return seqnr if the file position is concealed, 0 otherwise.
|
||||||
|
int syn_get_concealed_id(win_T *wp, linenr_T lnum, colnr_T col)
|
||||||
|
{
|
||||||
|
int seqnr;
|
||||||
|
int syntax_flags;
|
||||||
|
|
||||||
|
(void)syn_get_id(wp, lnum, col, false, NULL, false);
|
||||||
|
syntax_flags = get_syntax_info(&seqnr);
|
||||||
|
|
||||||
|
if (syntax_flags & HL_CONCEAL) {
|
||||||
|
return seqnr;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return conceal substitution character
|
* Return conceal substitution character
|
||||||
*/
|
*/
|
||||||
|
@ -462,4 +462,321 @@ describe('Mouse input', function()
|
|||||||
|
|
|
|
||||||
]])
|
]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
describe('on concealed text', function()
|
||||||
|
-- Helpful for reading the test expectations:
|
||||||
|
-- :match Error /\^/
|
||||||
|
local concealed = {
|
||||||
|
c = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray }
|
||||||
|
}
|
||||||
|
|
||||||
|
before_each(function()
|
||||||
|
screen:try_resize(25, 7)
|
||||||
|
feed('ggdG')
|
||||||
|
|
||||||
|
execute('set concealcursor=n')
|
||||||
|
execute('set nowrap')
|
||||||
|
execute('syntax match NonText "\\<amet\\>" conceal')
|
||||||
|
execute('syntax match NonText "\\cs\\|g." conceal cchar=X')
|
||||||
|
execute('syntax match NonText "\\%(lo\\|cl\\)." conceal')
|
||||||
|
execute('syntax match NonText "Lo" conceal cchar=Y')
|
||||||
|
|
||||||
|
insert([[
|
||||||
|
Lorem ipsum dolor sit amet, consetetur sadipscing elitr.
|
||||||
|
Stet clita kasd gubergren, no sea takimata sanctus est.
|
||||||
|
]])
|
||||||
|
|
||||||
|
feed('gg')
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('(level 1) click on non-wrapped lines', function()
|
||||||
|
execute('let &conceallevel=1', 'echo')
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><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|
|
||||||
|
|
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><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|
|
||||||
|
|
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><15,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|
|
||||||
|
|
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><15,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|
|
||||||
|
|
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
end) -- level 1 - non wrapped
|
||||||
|
|
||||||
|
it('(level 1) click on wrapped lines', function()
|
||||||
|
execute('let &conceallevel=1', 'let &wrap=1', 'echo')
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><0,0>')
|
||||||
|
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. |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><6,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. |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><15,1>')
|
||||||
|
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. |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><15,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. |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
end) -- level 1 - wrapped
|
||||||
|
|
||||||
|
|
||||||
|
it('(level 2) click on non-wrapped lines', function()
|
||||||
|
execute('let &conceallevel=2', 'echo')
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><0,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 |
|
||||||
|
|
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><1,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 |
|
||||||
|
|
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><15,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 |
|
||||||
|
|
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><15,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}b^er{c:X}en, no |
|
||||||
|
|
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
end) -- level 2 - non wrapped
|
||||||
|
|
||||||
|
it('(level 2) click on wrapped lines', function()
|
||||||
|
execute('let &conceallevel=2', 'let &wrap=1', 'echo')
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><0,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. |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><6,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. |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><15,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. |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><15,3>')
|
||||||
|
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. |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
end) -- level 2 - wrapped
|
||||||
|
|
||||||
|
|
||||||
|
it('(level 3) click on non-wrapped lines', function()
|
||||||
|
execute('let &conceallevel=3', 'echo')
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><0,0>')
|
||||||
|
screen:expect([[
|
||||||
|
^rem ipum do it , conetetu|
|
||||||
|
tet ta kad beren, no ea t|
|
||||||
|
|
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><1,0>')
|
||||||
|
screen:expect([[
|
||||||
|
r^em ipum do it , conetetu|
|
||||||
|
tet ta kad beren, no ea t|
|
||||||
|
|
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><15,0>')
|
||||||
|
screen:expect([[
|
||||||
|
rem ipum do it ^, conetetu|
|
||||||
|
tet ta kad beren, no ea t|
|
||||||
|
|
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><15,1>')
|
||||||
|
screen:expect([[
|
||||||
|
rem ipum do it , conetetu|
|
||||||
|
tet ta kad bere^n, no ea t|
|
||||||
|
|
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
end) -- level 3 - non wrapped
|
||||||
|
|
||||||
|
it('(level 3) click on wrapped lines', function()
|
||||||
|
execute('let &conceallevel=3', 'let &wrap=1', 'echo')
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><0,0>')
|
||||||
|
screen:expect([[
|
||||||
|
^rem ipum do it |
|
||||||
|
, conetetur adipcin |
|
||||||
|
elitr. |
|
||||||
|
tet ta kad beren |
|
||||||
|
, no ea takimata anctu |
|
||||||
|
et. |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><6,1>')
|
||||||
|
screen:expect([[
|
||||||
|
rem ipum do it |
|
||||||
|
, cone^tetur adipcin |
|
||||||
|
elitr. |
|
||||||
|
tet ta kad beren |
|
||||||
|
, no ea takimata anctu |
|
||||||
|
et. |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><15,1>')
|
||||||
|
screen:expect([[
|
||||||
|
rem ipum do it |
|
||||||
|
, conetetur adi^pcin |
|
||||||
|
elitr. |
|
||||||
|
tet ta kad beren |
|
||||||
|
, no ea takimata anctu |
|
||||||
|
et. |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
|
||||||
|
feed('<esc><LeftMouse><15,3>')
|
||||||
|
screen:expect([[
|
||||||
|
rem ipum do it |
|
||||||
|
, conetetur adipcin |
|
||||||
|
elitr. |
|
||||||
|
tet ta kad bere^n |
|
||||||
|
, no ea takimata anctu |
|
||||||
|
et. |
|
||||||
|
|
|
||||||
|
]], concealed)
|
||||||
|
end) -- level 3 - wrapped
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user