diff options
Diffstat (limited to 'src/nvim/mouse.c')
-rw-r--r-- | src/nvim/mouse.c | 212 |
1 files changed, 158 insertions, 54 deletions
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index 5d007fb173..a4a521fa80 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -30,6 +30,49 @@ static linenr_T orig_topline = 0; static int orig_topfill = 0; +/// Translate window coordinates to buffer position without any side effects +int get_fpos_of_mouse(pos_T *mpos) +{ + int grid = mouse_grid; + int row = mouse_row; + int col = mouse_col; + + if (row < 0 || col < 0) { // check if it makes sense + return IN_UNKNOWN; + } + + // find the window where the row is in + win_T *wp = mouse_find_win(&grid, &row, &col); + if (wp == NULL) { + return IN_UNKNOWN; + } + + // winpos and height may change in win_enter()! + if (row + wp->w_winbar_height >= wp->w_height) { // In (or below) status line + return IN_STATUS_LINE; + } + if (col >= wp->w_width) { // In vertical separator line + return IN_SEP_LINE; + } + + if (wp != curwin) { + return IN_UNKNOWN; + } + + // compute the position in the buffer line from the posn on the screen + if (mouse_comp_pos(curwin, &row, &col, &mpos->lnum)) { + return IN_STATUS_LINE; // past bottom + } + + mpos->col = vcol2col(wp, mpos->lnum, col); + + if (mpos->col > 0) { + mpos->col--; + } + mpos->coladd = 0; + return IN_BUFFER; +} + /// Return true if "c" is a mouse key. bool is_mouse_key(int c) { @@ -68,12 +111,12 @@ bool is_mouse_key(int c) /// mouse was previously on a status line, then the status line may be dragged. /// /// If flags has MOUSE_MAY_VIS, then VIsual mode will be started before the -/// cursor is moved unless the cursor was on a status line. +/// cursor is moved unless the cursor was on a status line or window bar. /// This function returns one of IN_UNKNOWN, IN_BUFFER, IN_STATUS_LINE or /// IN_SEP_LINE depending on where the cursor was clicked. /// /// If flags has MOUSE_MAY_STOP_VIS, then Visual mode will be stopped, unless -/// the mouse is on the status line of the same window. +/// the mouse is on the status line or window bar of the same window. /// /// If flags has MOUSE_DID_MOVE, nothing is done if the mouse didn't move since /// the last call. @@ -85,8 +128,11 @@ bool is_mouse_key(int c) /// @param which_button MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE int jump_to_mouse(int flags, bool *inclusive, int which_button) { - static int on_status_line = 0; // #lines below bottom of window - static int on_sep_line = 0; // on separator right of window + static int status_line_offset = 0; // #lines offset from status line + static int sep_line_offset = 0; // #cols offset from sep line + static bool on_status_line = false; + static bool on_sep_line = false; + static bool on_winbar = false; static int prev_row = -1; static int prev_col = -1; static win_T *dragwin = NULL; // window being dragged @@ -100,6 +146,7 @@ int jump_to_mouse(int flags, bool *inclusive, int which_button) int col = mouse_col; int grid = mouse_grid; int fdc = 0; + bool keep_focus = flags & MOUSE_FOCUS; mouse_past_bottom = false; mouse_past_eol = false; @@ -120,12 +167,15 @@ int jump_to_mouse(int flags, bool *inclusive, int which_button) retnomove: // before moving the cursor for a left click which is NOT in a status // line, stop Visual mode - if (on_status_line) { + if (status_line_offset) { return IN_STATUS_LINE; } - if (on_sep_line) { + if (sep_line_offset) { return IN_SEP_LINE; } + if (on_winbar) { + return IN_OTHER_WIN | MOUSE_WINBAR; + } if (flags & MOUSE_MAY_STOP_VIS) { end_visual_mode(); redraw_curbuf_later(INVERTED); // delete the inversion @@ -142,47 +192,78 @@ retnomove: old_curwin = curwin; old_cursor = curwin->w_cursor; - if (!(flags & MOUSE_FOCUS)) { - if (row < 0 || col < 0) { // check if it makes sense - return IN_UNKNOWN; + if (row < 0 || col < 0) { // check if it makes sense + return IN_UNKNOWN; + } + + // find the window where the row is in + wp = mouse_find_win(&grid, &row, &col); + if (wp == NULL) { + return IN_UNKNOWN; + } + + on_status_line = (grid == DEFAULT_GRID_HANDLE && row + wp->w_winbar_height >= wp->w_height) + ? row + wp->w_winbar_height - wp->w_height + 1 == 1 + : false; + + on_winbar = (row == -1) + ? wp->w_winbar_height != 0 + : false; + + on_sep_line = grid == DEFAULT_GRID_HANDLE && col >= wp->w_width + ? col - wp->w_width + 1 == 1 + : false; + + // The rightmost character of the status line might be a vertical + // separator character if there is no connecting window to the right. + if (on_status_line && on_sep_line) { + if (stl_connected(wp)) { + on_sep_line = false; + } else { + on_status_line = false; } + } - // find the window where the row is in - wp = mouse_find_win(&grid, &row, &col); - if (wp == NULL) { - return IN_UNKNOWN; + if (keep_focus) { + // If we can't change focus, set the value of row, col and grid back to absolute values + // since the values relative to the window are only used when keep_focus is false + row = mouse_row; + col = mouse_col; + grid = mouse_grid; + } + + if (!keep_focus) { + if (on_winbar) { + return IN_OTHER_WIN | MOUSE_WINBAR; } + fdc = win_fdccol_count(wp); dragwin = NULL; - if (row == -1) { - return IN_OTHER_WIN; - } - // winpos and height may change in win_enter()! - if (grid == DEFAULT_GRID_HANDLE && row >= wp->w_height) { + if (grid == DEFAULT_GRID_HANDLE && row + wp->w_winbar_height >= wp->w_height) { // In (or below) status line - on_status_line = row - wp->w_height + 1; + status_line_offset = row + wp->w_winbar_height - wp->w_height + 1; dragwin = wp; } else { - on_status_line = 0; + status_line_offset = 0; } if (grid == DEFAULT_GRID_HANDLE && col >= wp->w_width) { // In separator line - on_sep_line = col - wp->w_width + 1; + sep_line_offset = col - wp->w_width + 1; dragwin = wp; } else { - on_sep_line = 0; + sep_line_offset = 0; } // The rightmost character of the status line might be a vertical // separator character if there is no connecting window to the right. - if (on_status_line && on_sep_line) { + if (status_line_offset && sep_line_offset) { if (stl_connected(wp)) { - on_sep_line = 0; + sep_line_offset = 0; } else { - on_status_line = 0; + status_line_offset = 0; } } @@ -190,8 +271,8 @@ retnomove: // click, stop Visual mode. if (VIsual_active && (wp->w_buffer != curwin->w_buffer - || (!on_status_line - && !on_sep_line + || (!status_line_offset + && !sep_line_offset && (wp->w_p_rl ? col < wp->w_width_inner - fdc : col >= fdc + (cmdwin_type == 0 && wp == curwin ? 0 : 1)) @@ -202,7 +283,7 @@ retnomove: if (cmdwin_type != 0 && wp != curwin) { // A click outside the command-line window: Use modeless // selection if possible. Allow dragging the status lines. - on_sep_line = 0; + sep_line_offset = 0; row = 0; col += wp->w_wincol; wp = curwin; @@ -217,7 +298,7 @@ retnomove: if (curwin != old_curwin) { set_mouse_topline(curwin); } - if (on_status_line) { // In (or below) status line + if (status_line_offset) { // In (or below) status line // Don't use start_arrow() if we're in the same window if (curwin == old_curwin) { return IN_STATUS_LINE; @@ -225,7 +306,7 @@ retnomove: return IN_STATUS_LINE | CURSOR_MOVED; } } - if (on_sep_line) { // In (or below) status line + if (sep_line_offset) { // In (or below) status line // Don't use start_arrow() if we're in the same window if (curwin == old_curwin) { return IN_SEP_LINE; @@ -235,24 +316,29 @@ retnomove: } curwin->w_cursor.lnum = curwin->w_topline; - } else if (on_status_line && which_button == MOUSE_LEFT) { - if (dragwin != NULL) { + } else if (status_line_offset) { + if (which_button == MOUSE_LEFT && dragwin != NULL) { // Drag the status line count = row - dragwin->w_winrow - dragwin->w_height + 1 - - on_status_line; + - status_line_offset; win_drag_status_line(dragwin, count); did_drag |= count; } return IN_STATUS_LINE; // Cursor didn't move - } else if (on_sep_line && which_button == MOUSE_LEFT) { + } else if (sep_line_offset && which_button == MOUSE_LEFT) { if (dragwin != NULL) { // Drag the separator column count = col - dragwin->w_wincol - dragwin->w_width + 1 - - on_sep_line; + - sep_line_offset; win_drag_vsep_line(dragwin, count); did_drag |= count; } return IN_SEP_LINE; // Cursor didn't move + } else if (on_status_line && which_button == MOUSE_RIGHT) { + return IN_STATUS_LINE; + } else if (on_winbar && which_button == MOUSE_RIGHT) { + // After a click on the window bar don't start Visual mode. + return IN_OTHER_WIN | MOUSE_WINBAR; } else { // keep_window_focus must be true // before moving the cursor for a left click, stop Visual mode @@ -262,8 +348,11 @@ retnomove: } if (grid == 0) { - row -= curwin->w_grid_alloc.comp_row+curwin->w_grid.row_offset; - col -= curwin->w_grid_alloc.comp_col+curwin->w_grid.col_offset; + row -= curwin->w_grid_alloc.comp_row + curwin->w_grid.row_offset; + col -= curwin->w_grid_alloc.comp_col + curwin->w_grid.col_offset; + } else if (grid != DEFAULT_GRID_HANDLE) { + row -= curwin->w_grid.row_offset; + col -= curwin->w_grid.col_offset; } // When clicking beyond the end of the window, scroll the screen. @@ -468,7 +557,6 @@ win_T *mouse_find_win(int *gridp, int *rowp, int *colp) return NULL; } - frame_T *fp; fp = topframe; @@ -497,6 +585,7 @@ win_T *mouse_find_win(int *gridp, int *rowp, int *colp) // exist. FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp == fp->fr_win) { + *rowp -= wp->w_winbar_height; return wp; } } @@ -512,8 +601,8 @@ static win_T *mouse_find_grid_win(int *gridp, int *rowp, int *colp) win_T *wp = get_win_by_grid_handle(*gridp); if (wp && wp->w_grid_alloc.chars && !(wp->w_floating && !wp->w_float_config.focusable)) { - *rowp = MIN(*rowp-wp->w_grid.row_offset, wp->w_grid.Rows-1); - *colp = MIN(*colp-wp->w_grid.col_offset, wp->w_grid.Columns-1); + *rowp = MIN(*rowp - wp->w_grid.row_offset, wp->w_grid.rows - 1); + *colp = MIN(*colp - wp->w_grid.col_offset, wp->w_grid.cols - 1); return wp; } } else if (*gridp == 0) { @@ -523,8 +612,8 @@ static win_T *mouse_find_grid_win(int *gridp, int *rowp, int *colp) continue; } *gridp = grid->handle; - *rowp -= grid->comp_row+wp->w_grid.row_offset; - *colp -= grid->comp_col+wp->w_grid.col_offset; + *rowp -= grid->comp_row + wp->w_grid.row_offset; + *colp -= grid->comp_col + wp->w_grid.col_offset; return wp; } @@ -535,6 +624,22 @@ static win_T *mouse_find_grid_win(int *gridp, int *rowp, int *colp) return NULL; } +/// Convert a virtual (screen) column to a character column. +/// The first column is one. +colnr_T vcol2col(win_T *const wp, const linenr_T lnum, const colnr_T vcol) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +{ + // try to advance to the specified column + char_u *ptr = ml_get_buf(wp->w_buffer, lnum, false); + char_u *const line = ptr; + colnr_T count = 0; + while (count < vcol && *ptr != NUL) { + count += win_lbr_chartabsize(wp, line, ptr, count, NULL); + MB_PTR_ADV(ptr); + } + return (colnr_T)(ptr - line); +} + /// Set UI mouse depending on current mode and 'mouse'. /// /// Emits mouse_on/mouse_off UI event (unless 'mouse' is empty). @@ -544,7 +649,6 @@ void setmouse(void) ui_check_mouse(); } - // Set orig_topline. Used when jumping to another window, so that a double // click still works. void set_mouse_topline(win_T *wp) @@ -618,7 +722,7 @@ bool mouse_scroll_horiz(int dir) return false; } - int step = 6; + int step = (int)p_mousescroll_hor; if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)) { step = curwin->w_width_inner; } @@ -686,7 +790,7 @@ static int mouse_adjust_click(win_T *wp, int row, int col) vcol = 0; while (vcol < offset && *ptr != NUL) { vcol += win_chartabsize(curwin, ptr, vcol); - ptr += utfc_ptr2len(ptr); + ptr += utfc_ptr2len((char *)ptr); } ptr_row_offset = ptr; @@ -697,7 +801,7 @@ static int mouse_adjust_click(win_T *wp, int row, int col) ptr_end = ptr_row_offset; while (vcol < col && *ptr_end != NUL) { vcol += win_chartabsize(curwin, ptr_end, vcol); - ptr_end += utfc_ptr2len(ptr_end); + ptr_end += utfc_ptr2len((char *)ptr_end); } int matchid; @@ -707,8 +811,8 @@ static int mouse_adjust_click(win_T *wp, int row, int col) vcol = offset; -#define INCR() nudge++; ptr_end += utfc_ptr2len(ptr_end) -#define DECR() nudge--; ptr_end -= utfc_ptr2len(ptr_end) +#define INCR() nudge++; ptr_end += utfc_ptr2len((char *)ptr_end) +#define DECR() nudge--; ptr_end -= utfc_ptr2len((char *)ptr_end) while (ptr < ptr_end && *ptr != NUL) { cwidth = win_chartabsize(curwin, ptr, vcol); @@ -739,7 +843,7 @@ static int mouse_adjust_click(win_T *wp, int row, int col) while (prev_matchid == matchid && *ptr != NUL) { INCR(); - ptr += utfc_ptr2len(ptr); + ptr += utfc_ptr2len((char *)ptr); matchid = syn_get_concealed_id(wp, lnum, (colnr_T)(ptr - line)); } @@ -747,7 +851,7 @@ static int mouse_adjust_click(win_T *wp, int row, int col) } } - ptr += utfc_ptr2len(ptr); + ptr += utfc_ptr2len((char *)ptr); } return col + nudge; @@ -768,8 +872,8 @@ int mouse_check_fold(void) wp = mouse_find_win(&click_grid, &click_row, &click_col); if (wp && multigrid) { - max_row = wp->w_grid_alloc.Rows; - max_col = wp->w_grid_alloc.Columns; + max_row = wp->w_grid_alloc.rows; + max_col = wp->w_grid_alloc.cols; } if (wp && mouse_row >= 0 && mouse_row < max_row @@ -782,8 +886,8 @@ int mouse_check_fold(void) // Remember the character under the mouse, might be one of foldclose or // foldopen fillchars in the fold column. if (gp->chars != NULL) { - mouse_char = utf_ptr2char(gp->chars[gp->line_offset[row] - + (unsigned)col]); + mouse_char = utf_ptr2char((char *)gp->chars[gp->line_offset[row] + + (unsigned)col]); } // Check for position outside of the fold column. |