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:
Tommy Allen
2016-07-28 14:14:53 -04:00
committed by Justin M. Keyes
parent 56f178058a
commit 1f7304b846
3 changed files with 411 additions and 0 deletions

View File

@@ -6,6 +6,7 @@
#include "nvim/window.h"
#include "nvim/strings.h"
#include "nvim/screen.h"
#include "nvim/syntax.h"
#include "nvim/ui.h"
#include "nvim/os_unix.h"
#include "nvim/fold.h"
@@ -303,6 +304,10 @@ retnomove:
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) {
check_visual_highlight();
@@ -597,3 +602,74 @@ bool mouse_scroll_horiz(int dir)
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);
}