aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/mouse.c76
-rw-r--r--src/nvim/syntax.c18
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
*/