mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -04:00
patch 8.0.1598: cannot select text in a terminal with the mouse
Problem: Cannot select text in a terminal with the mouse. Solution: When a job in a terminal is not consuming mouse events, use them for modeless selection. Also stop Insert mode when clicking in a terminal window.
This commit is contained in:
@@ -259,6 +259,19 @@ typedef struct {
|
||||
int (*setlineinfo)(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user);
|
||||
} VTermStateCallbacks;
|
||||
|
||||
typedef struct {
|
||||
VTermPos pos;
|
||||
int buttons;
|
||||
#define MOUSE_BUTTON_LEFT 0x01
|
||||
#define MOUSE_BUTTON_MIDDLE 0x02
|
||||
#define MOUSE_BUTTON_RIGHT 0x04
|
||||
int flags;
|
||||
#define MOUSE_WANT_CLICK 0x01
|
||||
#define MOUSE_WANT_DRAG 0x02
|
||||
#define MOUSE_WANT_MOVE 0x04
|
||||
/* useful to add protocol? */
|
||||
} VTermMouseState;
|
||||
|
||||
VTermState *vterm_obtain_state(VTerm *vt);
|
||||
|
||||
void vterm_state_set_callbacks(VTermState *state, const VTermStateCallbacks *callbacks, void *user);
|
||||
@@ -272,6 +285,7 @@ void *vterm_state_get_unrecognised_fbdata(VTermState *state);
|
||||
void vterm_state_reset(VTermState *state, int hard);
|
||||
|
||||
void vterm_state_get_cursorpos(const VTermState *state, VTermPos *cursorpos);
|
||||
void vterm_state_get_mousestate(const VTermState *state, VTermMouseState *mousestate);
|
||||
void vterm_state_get_default_colors(const VTermState *state, VTermColor *default_fg, VTermColor *default_bg);
|
||||
void vterm_state_get_palette_color(const VTermState *state, int index, VTermColor *col);
|
||||
void vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg);
|
||||
|
@@ -1793,6 +1793,14 @@ void vterm_state_get_cursorpos(const VTermState *state, VTermPos *cursorpos)
|
||||
*cursorpos = state->pos;
|
||||
}
|
||||
|
||||
void vterm_state_get_mousestate(const VTermState *state, VTermMouseState *mousestate)
|
||||
{
|
||||
mousestate->pos.col = state->mouse_col;
|
||||
mousestate->pos.row = state->mouse_row;
|
||||
mousestate->buttons = state->mouse_buttons;
|
||||
mousestate->flags = state->mouse_flags;
|
||||
}
|
||||
|
||||
void vterm_state_set_callbacks(VTermState *state, const VTermStateCallbacks *callbacks, void *user)
|
||||
{
|
||||
if(callbacks) {
|
||||
|
@@ -95,9 +95,6 @@ struct VTermState
|
||||
int mouse_col, mouse_row;
|
||||
int mouse_buttons;
|
||||
int mouse_flags;
|
||||
#define MOUSE_WANT_CLICK 0x01
|
||||
#define MOUSE_WANT_DRAG 0x02
|
||||
#define MOUSE_WANT_MOVE 0x04
|
||||
|
||||
enum { MOUSE_X10, MOUSE_UTF8, MOUSE_SGR, MOUSE_RXVT } mouse_protocol;
|
||||
|
||||
|
@@ -12,6 +12,7 @@ void term_enter_job_mode(void);
|
||||
int send_keys_to_term(term_T *term, int c, int typed);
|
||||
int terminal_is_active(void);
|
||||
cursorentry_T *term_get_cursor_shape(guicolor_T *fg, guicolor_T *bg);
|
||||
void term_win_entered(void);
|
||||
int term_use_loop(void);
|
||||
int terminal_loop(int blocking);
|
||||
void term_job_ended(job_T *job);
|
||||
|
151
src/terminal.c
151
src/terminal.c
@@ -38,8 +38,6 @@
|
||||
* in tl_scrollback are no longer used.
|
||||
*
|
||||
* TODO:
|
||||
* - if the job in the terminal does not support the mouse, we can use the
|
||||
* mouse in the Terminal window for copy/paste and scrolling.
|
||||
* - When using 'termguicolors' still use the 16 ANSI colors as-is. Helps for
|
||||
* - In the GUI use a terminal emulator for :!cmd. Make the height the same as
|
||||
* the window and position it higher up when it gets filled, so it looks like
|
||||
@@ -900,6 +898,105 @@ term_send_mouse(VTerm *vterm, int button, int pressed)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int enter_mouse_col = -1;
|
||||
static int enter_mouse_row = -1;
|
||||
|
||||
/*
|
||||
* Handle a mouse click, drag or release.
|
||||
* Return TRUE when a mouse event is sent to the terminal.
|
||||
*/
|
||||
static int
|
||||
term_mouse_click(VTerm *vterm, int key)
|
||||
{
|
||||
#if defined(FEAT_CLIPBOARD)
|
||||
/* For modeless selection mouse drag and release events are ignored, unless
|
||||
* they are preceded with a mouse down event */
|
||||
static int ignore_drag_release = TRUE;
|
||||
VTermMouseState mouse_state;
|
||||
|
||||
vterm_state_get_mousestate(vterm_obtain_state(vterm), &mouse_state);
|
||||
if (mouse_state.flags == 0)
|
||||
{
|
||||
/* Terminal is not using the mouse, use modeless selection. */
|
||||
switch (key)
|
||||
{
|
||||
case K_LEFTDRAG:
|
||||
case K_LEFTRELEASE:
|
||||
case K_RIGHTDRAG:
|
||||
case K_RIGHTRELEASE:
|
||||
/* Ignore drag and release events when the button-down wasn't
|
||||
* seen before. */
|
||||
if (ignore_drag_release)
|
||||
{
|
||||
int save_mouse_col, save_mouse_row;
|
||||
|
||||
if (enter_mouse_col < 0)
|
||||
break;
|
||||
|
||||
/* mouse click in the window gave us focus, handle that
|
||||
* click now */
|
||||
save_mouse_col = mouse_col;
|
||||
save_mouse_row = mouse_row;
|
||||
mouse_col = enter_mouse_col;
|
||||
mouse_row = enter_mouse_row;
|
||||
clip_modeless(MOUSE_LEFT, TRUE, FALSE);
|
||||
mouse_col = save_mouse_col;
|
||||
mouse_row = save_mouse_row;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case K_LEFTMOUSE:
|
||||
case K_RIGHTMOUSE:
|
||||
if (key == K_LEFTRELEASE || key == K_RIGHTRELEASE)
|
||||
ignore_drag_release = TRUE;
|
||||
else
|
||||
ignore_drag_release = FALSE;
|
||||
/* Should we call mouse_has() here? */
|
||||
if (clip_star.available)
|
||||
{
|
||||
int button, is_click, is_drag;
|
||||
|
||||
button = get_mouse_button(KEY2TERMCAP1(key),
|
||||
&is_click, &is_drag);
|
||||
if (mouse_model_popup() && button == MOUSE_LEFT
|
||||
&& (mod_mask & MOD_MASK_SHIFT))
|
||||
{
|
||||
/* Translate shift-left to right button. */
|
||||
button = MOUSE_RIGHT;
|
||||
mod_mask &= ~MOD_MASK_SHIFT;
|
||||
}
|
||||
clip_modeless(button, is_click, is_drag);
|
||||
}
|
||||
break;
|
||||
|
||||
case K_MIDDLEMOUSE:
|
||||
if (clip_star.available)
|
||||
insert_reg('*', TRUE);
|
||||
break;
|
||||
}
|
||||
enter_mouse_col = -1;
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
enter_mouse_col = -1;
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case K_LEFTMOUSE:
|
||||
case K_LEFTMOUSE_NM: term_send_mouse(vterm, 1, 1); break;
|
||||
case K_LEFTDRAG: term_send_mouse(vterm, 1, 1); break;
|
||||
case K_LEFTRELEASE:
|
||||
case K_LEFTRELEASE_NM: term_send_mouse(vterm, 1, 0); break;
|
||||
case K_MOUSEMOVE: term_send_mouse(vterm, 0, 0); break;
|
||||
case K_MIDDLEMOUSE: term_send_mouse(vterm, 2, 1); break;
|
||||
case K_MIDDLEDRAG: term_send_mouse(vterm, 2, 1); break;
|
||||
case K_MIDDLERELEASE: term_send_mouse(vterm, 2, 0); break;
|
||||
case K_RIGHTMOUSE: term_send_mouse(vterm, 3, 1); break;
|
||||
case K_RIGHTDRAG: term_send_mouse(vterm, 3, 1); break;
|
||||
case K_RIGHTRELEASE: term_send_mouse(vterm, 3, 0); break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert typed key "c" into bytes to send to the job.
|
||||
* Return the number of bytes in "buf".
|
||||
@@ -995,17 +1092,21 @@ term_convert_key(term_T *term, int c, char *buf)
|
||||
case K_MOUSERIGHT: /* TODO */ return 0;
|
||||
|
||||
case K_LEFTMOUSE:
|
||||
case K_LEFTMOUSE_NM: other = term_send_mouse(vterm, 1, 1); break;
|
||||
case K_LEFTDRAG: other = term_send_mouse(vterm, 1, 1); break;
|
||||
case K_LEFTMOUSE_NM:
|
||||
case K_LEFTDRAG:
|
||||
case K_LEFTRELEASE:
|
||||
case K_LEFTRELEASE_NM: other = term_send_mouse(vterm, 1, 0); break;
|
||||
case K_MOUSEMOVE: other = term_send_mouse(vterm, 0, 0); break;
|
||||
case K_MIDDLEMOUSE: other = term_send_mouse(vterm, 2, 1); break;
|
||||
case K_MIDDLEDRAG: other = term_send_mouse(vterm, 2, 1); break;
|
||||
case K_MIDDLERELEASE: other = term_send_mouse(vterm, 2, 0); break;
|
||||
case K_RIGHTMOUSE: other = term_send_mouse(vterm, 3, 1); break;
|
||||
case K_RIGHTDRAG: other = term_send_mouse(vterm, 3, 1); break;
|
||||
case K_RIGHTRELEASE: other = term_send_mouse(vterm, 3, 0); break;
|
||||
case K_LEFTRELEASE_NM:
|
||||
case K_MOUSEMOVE:
|
||||
case K_MIDDLEMOUSE:
|
||||
case K_MIDDLEDRAG:
|
||||
case K_MIDDLERELEASE:
|
||||
case K_RIGHTMOUSE:
|
||||
case K_RIGHTDRAG:
|
||||
case K_RIGHTRELEASE: if (!term_mouse_click(vterm, c))
|
||||
return 0;
|
||||
other = TRUE;
|
||||
break;
|
||||
|
||||
case K_X1MOUSE: /* TODO */ return 0;
|
||||
case K_X1DRAG: /* TODO */ return 0;
|
||||
case K_X1RELEASE: /* TODO */ return 0;
|
||||
@@ -1473,6 +1574,8 @@ term_vgetc()
|
||||
return c;
|
||||
}
|
||||
|
||||
static int mouse_was_outside = FALSE;
|
||||
|
||||
/*
|
||||
* Send keys to terminal.
|
||||
* Return FAIL when the key needs to be handled in Normal mode.
|
||||
@@ -1483,7 +1586,6 @@ send_keys_to_term(term_T *term, int c, int typed)
|
||||
{
|
||||
char msg[KEY_BUF_LEN];
|
||||
size_t len;
|
||||
static int mouse_was_outside = FALSE;
|
||||
int dragging_outside = FALSE;
|
||||
|
||||
/* Catch keys that need to be handled as in Normal mode. */
|
||||
@@ -1731,6 +1833,29 @@ prepare_restore_cursor_props(void)
|
||||
may_output_cursor_props();
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when entering a window with the mouse. If this is a terminal window
|
||||
* we may want to change state.
|
||||
*/
|
||||
void
|
||||
term_win_entered()
|
||||
{
|
||||
term_T *term = curbuf->b_term;
|
||||
|
||||
if (term != NULL)
|
||||
{
|
||||
if (term_use_loop())
|
||||
{
|
||||
reset_VIsual_and_resel();
|
||||
if (State & INSERT)
|
||||
stop_insert_mode = TRUE;
|
||||
}
|
||||
mouse_was_outside = FALSE;
|
||||
enter_mouse_col = mouse_col;
|
||||
enter_mouse_row = mouse_row;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns TRUE if the current window contains a terminal and we are sending
|
||||
* keys to the job.
|
||||
|
9
src/ui.c
9
src/ui.c
@@ -2827,11 +2827,18 @@ retnomove:
|
||||
* (MOUSE_FOCUS was set above if we dragged first). */
|
||||
if (dragwin == NULL || (flags & MOUSE_RELEASED))
|
||||
win_enter(wp, TRUE); /* can make wp invalid! */
|
||||
|
||||
if (curwin != old_curwin)
|
||||
{
|
||||
#ifdef CHECK_DOUBLE_CLICK
|
||||
/* set topline, to be able to check for double click ourselves */
|
||||
if (curwin != old_curwin)
|
||||
set_mouse_topline(curwin);
|
||||
#endif
|
||||
#ifdef FEAT_TERMINAL
|
||||
/* when entering a terminal window may change state */
|
||||
term_win_entered();
|
||||
#endif
|
||||
}
|
||||
if (on_status_line) /* In (or below) status line */
|
||||
{
|
||||
/* Don't use start_arrow() if we're in the same window */
|
||||
|
@@ -766,6 +766,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1598,
|
||||
/**/
|
||||
1597,
|
||||
/**/
|
||||
|
Reference in New Issue
Block a user