aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/mouse.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/mouse.c')
-rw-r--r--src/nvim/mouse.c148
1 files changed, 139 insertions, 9 deletions
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c
index 2f499e477c..887cbde921 100644
--- a/src/nvim/mouse.c
+++ b/src/nvim/mouse.c
@@ -1,11 +1,16 @@
+// This is an open source non-commercial project. Dear PVS-Studio, please check
+// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+
#include <stdbool.h>
#include "nvim/mouse.h"
#include "nvim/vim.h"
#include "nvim/ascii.h"
#include "nvim/window.h"
+#include "nvim/state.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"
@@ -103,12 +108,14 @@ retnomove:
goto retnomove; // ugly goto...
// Remember the character under the mouse, it might be a '-' or '+' in the
- // fold column.
+ // fold column. NB: only works for ASCII chars!
if (row >= 0 && row < Rows && col >= 0 && col <= Columns
- && ScreenLines != NULL)
- mouse_char = ScreenLines[LineOffset[row] + (unsigned)col];
- else
+ && default_grid.chars != NULL) {
+ mouse_char = default_grid.chars[default_grid.line_offset[row]
+ + (unsigned)col][0];
+ } else {
mouse_char = ' ';
+ }
old_curwin = curwin;
old_cursor = curwin->w_cursor;
@@ -119,6 +126,9 @@ retnomove:
// find the window where the row is in
wp = mouse_find_win(&row, &col);
+ if (wp == NULL) {
+ return IN_UNKNOWN;
+ }
dragwin = NULL;
// winpos and height may change in win_enter()!
if (row >= wp->w_height) { // In (or below) status line
@@ -303,9 +313,12 @@ 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();
VIsual = old_cursor;
VIsual_active = true;
VIsual_reselect = true;
@@ -417,6 +430,7 @@ bool mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump)
// Find the window at screen position "*rowp" and "*colp". The positions are
// updated to become relative to the top-left of the window.
+// Returns NULL when something is wrong.
win_T *mouse_find_win(int *rowp, int *colp)
{
frame_T *fp;
@@ -440,7 +454,14 @@ win_T *mouse_find_win(int *rowp, int *colp)
}
}
}
- return fp->fr_win;
+ // When using a timer that closes a window the window might not actually
+ // exist.
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ if (wp == fp->fr_win) {
+ return wp;
+ }
+ }
+ return NULL;
}
/*
@@ -450,6 +471,7 @@ void setmouse(void)
{
int checkfor;
+ ui_cursor_shape();
/* be quick when mouse is off */
if (*p_mouse == NUL)
@@ -469,9 +491,9 @@ void setmouse(void)
checkfor = MOUSE_NORMAL; /* assume normal mode */
if (mouse_has(checkfor)) {
- ui_mouse_on();
+ ui_call_mouse_on();
} else {
- ui_mouse_off();
+ ui_call_mouse_off();
}
}
@@ -515,7 +537,7 @@ static colnr_T scroll_line_len(linenr_T lnum)
if (*line != NUL) {
for (;;) {
int numchar = chartabsize(line, col);
- mb_ptr_adv(line);
+ MB_PTR_ADV(line);
if (*line == NUL) { // don't count the last character
break;
}
@@ -597,3 +619,111 @@ bool mouse_scroll_horiz(int dir)
return leftcol_changed();
}
+
+/// 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
+ && wp->w_leftcol < curbuf->b_p_smc && conceal_cursor_line(wp))) {
+ return col;
+ }
+
+ // `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;
+ 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.
+ vcol = 0;
+ while (vcol < offset && *ptr != NUL) {
+ vcol += chartabsize(ptr, vcol);
+ ptr += utfc_ptr2len(ptr);
+ }
+
+ ptr_row_offset = ptr;
+ }
+
+ // 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 nudge = 0;
+ int cwidth = 0;
+
+ vcol = offset;
+
+#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);
+ 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();
+ } else {
+ 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();
+ }
+
+ prev_matchid = matchid;
+
+ while (prev_matchid == matchid && *ptr != NUL) {
+ incr();
+ ptr += utfc_ptr2len(ptr);
+ matchid = syn_get_concealed_id(wp, lnum, (colnr_T)(ptr - line));
+ }
+
+ continue;
+ }
+ }
+
+ ptr += utfc_ptr2len(ptr);
+ }
+
+ return col + nudge;
+}