diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/mouse.c | 76 | ||||
-rw-r--r-- | src/nvim/syntax.c | 18 |
2 files changed, 94 insertions, 0 deletions
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index 2f499e477c..5efac2623c 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -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); +} + diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 27855184df..3215f7ea14 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -5661,6 +5661,24 @@ int get_syntax_info(int *seqnrp) 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 */ |