mirror of
https://github.com/neovim/neovim.git
synced 2025-09-20 10:18:18 +00:00
vim-patch:8.0.1558: no right-click menu in a terminal
Problem: No right-click menu in a terminal.
Solution: Implement the right click menu for the terminal.
aef8c3da2b
This commit is contained in:
@@ -11,6 +11,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "nvim/ascii.h"
|
#include "nvim/ascii.h"
|
||||||
|
#include "nvim/autocmd.h"
|
||||||
#include "nvim/charset.h"
|
#include "nvim/charset.h"
|
||||||
#include "nvim/cursor.h"
|
#include "nvim/cursor.h"
|
||||||
#include "nvim/eval.h"
|
#include "nvim/eval.h"
|
||||||
@@ -22,6 +23,7 @@
|
|||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
#include "nvim/menu.h"
|
#include "nvim/menu.h"
|
||||||
#include "nvim/message.h"
|
#include "nvim/message.h"
|
||||||
|
#include "nvim/popupmnu.h"
|
||||||
#include "nvim/screen.h"
|
#include "nvim/screen.h"
|
||||||
#include "nvim/state.h"
|
#include "nvim/state.h"
|
||||||
#include "nvim/strings.h"
|
#include "nvim/strings.h"
|
||||||
@@ -1355,9 +1357,64 @@ static int menu_is_hidden(char *name)
|
|||||||
|| (menu_is_popup(name) && name[5] != NUL);
|
|| (menu_is_popup(name) && name[5] != NUL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int get_menu_mode(void)
|
||||||
|
{
|
||||||
|
if (VIsual_active) {
|
||||||
|
if (VIsual_select)
|
||||||
|
return MENU_INDEX_SELECT;
|
||||||
|
return MENU_INDEX_VISUAL;
|
||||||
|
}
|
||||||
|
if (State & MODE_INSERT) {
|
||||||
|
return MENU_INDEX_INSERT;
|
||||||
|
}
|
||||||
|
if ((State & MODE_CMDLINE) || State == MODE_ASKMORE || State == MODE_HITRETURN) {
|
||||||
|
return MENU_INDEX_CMDLINE;
|
||||||
|
}
|
||||||
|
if (finish_op) {
|
||||||
|
return MENU_INDEX_OP_PENDING;
|
||||||
|
}
|
||||||
|
if (State & MODE_NORMAL) {
|
||||||
|
return MENU_INDEX_NORMAL;
|
||||||
|
}
|
||||||
|
if (State & MODE_LANGMAP) { // must be a "r" command, like Insert mode
|
||||||
|
return MENU_INDEX_INSERT;
|
||||||
|
}
|
||||||
|
return MENU_INDEX_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Display the Special "PopUp" menu as a pop-up at the current mouse
|
||||||
|
/// position. The "PopUpn" menu is for Normal mode, "PopUpi" for Insert mode,
|
||||||
|
/// etc.
|
||||||
|
void show_popupmenu(void)
|
||||||
|
{
|
||||||
|
int mode = get_menu_mode();
|
||||||
|
if (mode == MENU_INDEX_INVALID) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mode = menu_mode_chars[mode];
|
||||||
|
|
||||||
|
char ename[2];
|
||||||
|
ename[0] = (char)mode;
|
||||||
|
ename[1] = NUL;
|
||||||
|
apply_autocmds(EVENT_MENUPOPUP, ename, NULL, false, curbuf);
|
||||||
|
|
||||||
|
vimmenu_T *menu;
|
||||||
|
|
||||||
|
for (menu = root_menu; menu != NULL; menu = menu->next) {
|
||||||
|
if (STRNCMP("PopUp", menu->name, 5) == 0 && menu->name[5] == mode) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only show a popup when it is defined and has entries
|
||||||
|
if (menu != NULL && menu->children != NULL) {
|
||||||
|
pum_show_popupmenu(menu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Execute "menu". Use by ":emenu" and the window toolbar.
|
// Execute "menu". Use by ":emenu" and the window toolbar.
|
||||||
// "eap" is NULL for the window toolbar.
|
// "eap" is NULL for the window toolbar.
|
||||||
static void execute_menu(const exarg_T *eap, vimmenu_T *menu)
|
void execute_menu(const exarg_T *eap, vimmenu_T *menu)
|
||||||
FUNC_ATTR_NONNULL_ARG(2)
|
FUNC_ATTR_NONNULL_ARG(2)
|
||||||
{
|
{
|
||||||
int idx = -1;
|
int idx = -1;
|
||||||
|
@@ -30,6 +30,49 @@
|
|||||||
static linenr_T orig_topline = 0;
|
static linenr_T orig_topline = 0;
|
||||||
static int orig_topfill = 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.
|
/// Return true if "c" is a mouse key.
|
||||||
bool is_mouse_key(int c)
|
bool is_mouse_key(int c)
|
||||||
{
|
{
|
||||||
|
@@ -1493,12 +1493,12 @@ static void call_click_def_func(StlClickDefinition *click_defs, int col, int whi
|
|||||||
/// Do the appropriate action for the current mouse click in the current mode.
|
/// Do the appropriate action for the current mouse click in the current mode.
|
||||||
/// Not used for Command-line mode.
|
/// Not used for Command-line mode.
|
||||||
///
|
///
|
||||||
/// Normal Mode:
|
/// Normal and Visual Mode:
|
||||||
/// event modi- position visual change action
|
/// event modi- position visual change action
|
||||||
/// fier cursor window
|
/// fier cursor window
|
||||||
/// left press - yes end yes
|
/// left press - yes end yes
|
||||||
/// left press C yes end yes "^]" (2)
|
/// left press C yes end yes "^]" (2)
|
||||||
/// left press S yes end yes "*" (2)
|
/// left press S yes end (popup: extend) yes "*" (2)
|
||||||
/// left drag - yes start if moved no
|
/// left drag - yes start if moved no
|
||||||
/// left relse - yes start if moved no
|
/// left relse - yes start if moved no
|
||||||
/// middle press - yes if not active no put register
|
/// middle press - yes if not active no put register
|
||||||
@@ -1787,9 +1787,52 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent)
|
|||||||
if (mouse_model_popup()) {
|
if (mouse_model_popup()) {
|
||||||
if (which_button == MOUSE_RIGHT
|
if (which_button == MOUSE_RIGHT
|
||||||
&& !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))) {
|
&& !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))) {
|
||||||
// NOTE: Ignore right button down and drag mouse events. Windows only
|
if (!is_click) {
|
||||||
// shows the popup menu on the button up event.
|
// Ignore right button release events, only shows the popup
|
||||||
return false;
|
// menu on the button down event.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
jump_flags = 0;
|
||||||
|
if (STRCMP(p_mousem, "popup_setpos") == 0) {
|
||||||
|
// First set the cursor position before showing the popup
|
||||||
|
// menu.
|
||||||
|
if (VIsual_active) {
|
||||||
|
pos_T m_pos;
|
||||||
|
// set MOUSE_MAY_STOP_VIS if we are outside the
|
||||||
|
// selection or the current window (might have false
|
||||||
|
// negative here)
|
||||||
|
if (mouse_row < curwin->w_winrow
|
||||||
|
|| mouse_row > (curwin->w_winrow + curwin->w_height)) {
|
||||||
|
jump_flags = MOUSE_MAY_STOP_VIS;
|
||||||
|
} else if (get_fpos_of_mouse(&m_pos) != IN_BUFFER) {
|
||||||
|
jump_flags = MOUSE_MAY_STOP_VIS;
|
||||||
|
} else {
|
||||||
|
if ((lt(curwin->w_cursor, VIsual)
|
||||||
|
&& (lt(m_pos, curwin->w_cursor) || lt(VIsual, m_pos)))
|
||||||
|
|| (lt(VIsual, curwin->w_cursor)
|
||||||
|
&& (lt(m_pos, VIsual) || lt(curwin->w_cursor, m_pos)))) {
|
||||||
|
jump_flags = MOUSE_MAY_STOP_VIS;
|
||||||
|
} else if (VIsual_mode == Ctrl_V) {
|
||||||
|
getvcols(curwin, &curwin->w_cursor, &VIsual, &leftcol, &rightcol);
|
||||||
|
getvcol(curwin, &m_pos, NULL, &m_pos.col, NULL);
|
||||||
|
if (m_pos.col < leftcol || m_pos.col > rightcol) {
|
||||||
|
jump_flags = MOUSE_MAY_STOP_VIS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
jump_flags = MOUSE_MAY_STOP_VIS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (jump_flags) {
|
||||||
|
jump_flags = jump_to_mouse(jump_flags, NULL, which_button);
|
||||||
|
update_curbuf(VIsual_active ? INVERTED : VALID);
|
||||||
|
setcursor();
|
||||||
|
ui_flush(); // Update before showing popup menu
|
||||||
|
}
|
||||||
|
show_popupmenu();
|
||||||
|
got_click = false; // ignore release events
|
||||||
|
return (jump_flags & CURSOR_MOVED) != 0;
|
||||||
}
|
}
|
||||||
if (which_button == MOUSE_LEFT
|
if (which_button == MOUSE_LEFT
|
||||||
&& (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_ALT))) {
|
&& (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_ALT))) {
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
#include "nvim/ex_cmds.h"
|
#include "nvim/ex_cmds.h"
|
||||||
#include "nvim/memline.h"
|
#include "nvim/memline.h"
|
||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
|
#include "nvim/menu.h"
|
||||||
#include "nvim/move.h"
|
#include "nvim/move.h"
|
||||||
#include "nvim/option.h"
|
#include "nvim/option.h"
|
||||||
#include "nvim/popupmnu.h"
|
#include "nvim/popupmnu.h"
|
||||||
@@ -512,9 +513,13 @@ void pum_redraw(void)
|
|||||||
char_u *st;
|
char_u *st;
|
||||||
char_u saved = *p;
|
char_u saved = *p;
|
||||||
|
|
||||||
*p = NUL;
|
if (saved != NUL) {
|
||||||
|
*p = NUL;
|
||||||
|
}
|
||||||
st = (char_u *)transstr((const char *)s, true);
|
st = (char_u *)transstr((const char *)s, true);
|
||||||
*p = saved;
|
if (saved != NUL) {
|
||||||
|
*p = saved;
|
||||||
|
}
|
||||||
|
|
||||||
if (pum_rl) {
|
if (pum_rl) {
|
||||||
char *rt = (char *)reverse_text(st);
|
char *rt = (char *)reverse_text(st);
|
||||||
@@ -932,3 +937,145 @@ void pum_set_event_info(dict_T *dict)
|
|||||||
(void)tv_dict_add_bool(dict, S_LEN("scrollbar"),
|
(void)tv_dict_add_bool(dict, S_LEN("scrollbar"),
|
||||||
pum_scrollbar ? kBoolVarTrue : kBoolVarFalse);
|
pum_scrollbar ? kBoolVarTrue : kBoolVarFalse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pum_position_at_mouse(int min_width)
|
||||||
|
{
|
||||||
|
if (Rows - mouse_row > pum_size) {
|
||||||
|
// Enough space below the mouse row.
|
||||||
|
pum_row = mouse_row + 1;
|
||||||
|
if (pum_height > Rows - pum_row) {
|
||||||
|
pum_height = Rows - pum_row;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Show above the mouse row, reduce height if it does not fit.
|
||||||
|
pum_row = mouse_row - pum_size;
|
||||||
|
if (pum_row < 0) {
|
||||||
|
pum_height += pum_row;
|
||||||
|
pum_row = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Columns - mouse_col >= pum_base_width || Columns - mouse_col > min_width) {
|
||||||
|
// Enough space to show at mouse column.
|
||||||
|
pum_col = mouse_col;
|
||||||
|
} else {
|
||||||
|
// Not enough space, right align with window.
|
||||||
|
pum_col = Columns - (pum_base_width > min_width ? min_width : pum_base_width);
|
||||||
|
}
|
||||||
|
|
||||||
|
pum_width = Columns - pum_col;
|
||||||
|
if (pum_width > pum_base_width + 1) {
|
||||||
|
pum_width = pum_base_width + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Select the pum entry at the mouse position.
|
||||||
|
static void pum_select_mouse_pos(void)
|
||||||
|
{
|
||||||
|
int idx = mouse_row - pum_row;
|
||||||
|
|
||||||
|
if (idx < 0 || idx >= pum_size) {
|
||||||
|
pum_selected = -1;
|
||||||
|
} else if (*pum_array[idx].pum_text != NUL) {
|
||||||
|
pum_selected = idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Execute the currently selected popup menu item.
|
||||||
|
static void pum_execute_menu(vimmenu_T *menu)
|
||||||
|
{
|
||||||
|
int idx = 0;
|
||||||
|
exarg_T ea;
|
||||||
|
|
||||||
|
for (vimmenu_T *mp = menu->children; mp != NULL; mp = mp->next) {
|
||||||
|
if (idx++ == pum_selected) {
|
||||||
|
memset(&ea, 0, sizeof(ea));
|
||||||
|
execute_menu(&ea, mp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Open the terminal version of the popup menu and don't return until it is closed.
|
||||||
|
void pum_show_popupmenu(vimmenu_T *menu)
|
||||||
|
{
|
||||||
|
pum_undisplay(true);
|
||||||
|
pum_size = 0;
|
||||||
|
|
||||||
|
for (vimmenu_T *mp = menu->children; mp != NULL; mp = mp->next) {
|
||||||
|
pum_size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
pumitem_T *array = (pumitem_T *)xcalloc((size_t)pum_size, sizeof(pumitem_T));
|
||||||
|
|
||||||
|
for (vimmenu_T *mp = menu->children; mp != NULL; mp = mp->next) {
|
||||||
|
if (menu_is_separator(mp->dname)) {
|
||||||
|
array[idx++].pum_text = (char_u *)"";
|
||||||
|
} else {
|
||||||
|
array[idx++].pum_text = (char_u *)mp->dname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pum_array = array;
|
||||||
|
pum_compute_size();
|
||||||
|
pum_scrollbar = 0;
|
||||||
|
pum_height = pum_size;
|
||||||
|
pum_position_at_mouse(20);
|
||||||
|
|
||||||
|
pum_selected = -1;
|
||||||
|
pum_first = 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
pum_is_visible = true;
|
||||||
|
pum_is_drawn = true;
|
||||||
|
pum_redraw();
|
||||||
|
setcursor();
|
||||||
|
ui_flush();
|
||||||
|
|
||||||
|
int c = vgetc();
|
||||||
|
if (c == ESC) {
|
||||||
|
break;
|
||||||
|
} else if (c == CAR || c == NL) {
|
||||||
|
// enter: select current item, if any, and close
|
||||||
|
pum_execute_menu(menu);
|
||||||
|
break;
|
||||||
|
} else if (c == 'k' || c == K_UP || c == K_MOUSEUP) {
|
||||||
|
// cursor up: select previous item
|
||||||
|
while (pum_selected > 0) {
|
||||||
|
pum_selected--;
|
||||||
|
if (*array[pum_selected].pum_text != NUL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (c == 'j' || c == K_DOWN || c == K_MOUSEDOWN) {
|
||||||
|
// cursor down: select next item
|
||||||
|
while (pum_selected < pum_size - 1) {
|
||||||
|
pum_selected++;
|
||||||
|
if (*array[pum_selected].pum_text != NUL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (c == K_RIGHTMOUSE) {
|
||||||
|
// Right mouse down: reposition the menu.
|
||||||
|
vungetc(c);
|
||||||
|
break;
|
||||||
|
} else if (c == K_LEFTDRAG || c == K_RIGHTDRAG || c == K_MOUSEMOVE) {
|
||||||
|
// mouse moved: select item in the mouse row
|
||||||
|
pum_select_mouse_pos();
|
||||||
|
} else if (c == K_LEFTMOUSE || c == K_LEFTMOUSE_NM || c == K_RIGHTRELEASE) {
|
||||||
|
// left mouse click: select clicked item, if any, and close;
|
||||||
|
// right mouse release: select clicked item, close if any
|
||||||
|
pum_select_mouse_pos();
|
||||||
|
if (pum_selected >= 0) {
|
||||||
|
pum_execute_menu(menu);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c == K_LEFTMOUSE || c == K_LEFTMOUSE_NM) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xfree(array);
|
||||||
|
pum_undisplay(true);
|
||||||
|
}
|
||||||
|
@@ -298,6 +298,13 @@ void redraw_win_signcol(win_T *wp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update all windows that are editing the current buffer.
|
||||||
|
void update_curbuf(int type)
|
||||||
|
{
|
||||||
|
redraw_curbuf_later(type);
|
||||||
|
update_screen(type);
|
||||||
|
}
|
||||||
|
|
||||||
/// Redraw the parts of the screen that is marked for redraw.
|
/// Redraw the parts of the screen that is marked for redraw.
|
||||||
///
|
///
|
||||||
/// Most code shouldn't call this directly, rather use redraw_later() and
|
/// Most code shouldn't call this directly, rather use redraw_later() and
|
||||||
|
Reference in New Issue
Block a user