fix(mouse): do not fetch clipboard twice when pasting with middle button #33494

Problem:
When doing paste operation mouse code tries to figure out it it is
dealing with a multi-line register by calling yank_register_mline(),
which fetches register data and checks its type. Later the code calls
either do_put() or insert_reg() which fetch register data again. This is
unnoticeable when working with internal neovim registers, but starts
hurting when dealing with clipboards, especially remote one (forwarded X
or socket tunnel or similar).

Solution:
Change yank_register_mline() to also return pointer to the
register structure prepared for pasting, and insert_reg() to accept
such register pointer and use it if it is supplied. do_put() already
has support for accepting a register structure to be used for pasting.

Fixes #33493

(cherry picked from commit 7432781e71)
This commit is contained in:
Dmitry Torokhov
2025-04-16 03:08:41 -07:00
committed by github-actions[bot]
parent b694131c3b
commit dcd5e4574a
3 changed files with 23 additions and 12 deletions

View File

@ -3244,7 +3244,7 @@ static void ins_reg(void)
do_put(regname, NULL, BACKWARD, 1, do_put(regname, NULL, BACKWARD, 1,
(literally == Ctrl_P ? PUT_FIXINDENT : 0) | PUT_CURSEND); (literally == Ctrl_P ? PUT_FIXINDENT : 0) | PUT_CURSEND);
} else if (insert_reg(regname, literally) == FAIL) { } else if (insert_reg(regname, NULL, literally) == FAIL) {
vim_beep(kOptBoFlagRegister); vim_beep(kOptBoFlagRegister);
need_redraw = true; // remove the '"' need_redraw = true; // remove the '"'
} else if (stop_insert_mode) { } else if (stop_insert_mode) {

View File

@ -503,15 +503,16 @@ bool do_mouse(oparg_T *oap, int c, int dir, int count, bool fixindent)
// happens for the GUI). // happens for the GUI).
if ((State & MODE_INSERT)) { if ((State & MODE_INSERT)) {
if (regname == '.') { if (regname == '.') {
insert_reg(regname, true); insert_reg(regname, NULL, true);
} else { } else {
if (regname == 0 && eval_has_provider("clipboard", false)) { if (regname == 0 && eval_has_provider("clipboard", false)) {
regname = '*'; regname = '*';
} }
if ((State & REPLACE_FLAG) && !yank_register_mline(regname)) { yankreg_T *reg = NULL;
insert_reg(regname, true); if ((State & REPLACE_FLAG) && !yank_register_mline(regname, &reg)) {
insert_reg(regname, reg, true);
} else { } else {
do_put(regname, NULL, BACKWARD, 1, do_put(regname, reg, BACKWARD, 1,
(fixindent ? PUT_FIXINDENT : 0) | PUT_CURSEND); (fixindent ? PUT_FIXINDENT : 0) | PUT_CURSEND);
// Repeat it with CTRL-R CTRL-O r or CTRL-R CTRL-P r // Repeat it with CTRL-R CTRL-O r or CTRL-R CTRL-P r
@ -833,7 +834,8 @@ bool do_mouse(oparg_T *oap, int c, int dir, int count, bool fixindent)
if (regname == 0 && eval_has_provider("clipboard", false)) { if (regname == 0 && eval_has_provider("clipboard", false)) {
regname = '*'; regname = '*';
} }
if (yank_register_mline(regname)) { yankreg_T *reg = NULL;
if (yank_register_mline(regname, &reg)) {
if (mouse_past_bottom) { if (mouse_past_bottom) {
dir = FORWARD; dir = FORWARD;
} }
@ -855,7 +857,7 @@ bool do_mouse(oparg_T *oap, int c, int dir, int count, bool fixindent)
if (restart_edit != 0) { if (restart_edit != 0) {
where_paste_started = curwin->w_cursor; where_paste_started = curwin->w_cursor;
} }
do_put(regname, NULL, dir, count, do_put(regname, reg, dir, count,
(fixindent ? PUT_FIXINDENT : 0)| PUT_CURSEND); (fixindent ? PUT_FIXINDENT : 0)| PUT_CURSEND);
} else if (((mod_mask & MOD_MASK_CTRL) || (mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK) } else if (((mod_mask & MOD_MASK_CTRL) || (mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
&& bt_quickfix(curbuf)) { && bt_quickfix(curbuf)) {

View File

@ -966,16 +966,23 @@ yankreg_T *copy_register(int name)
} }
/// Check if the current yank register has kMTLineWise register type /// Check if the current yank register has kMTLineWise register type
bool yank_register_mline(int regname) /// For valid, non-blackhole registers also provides pointer to the register
/// structure prepared for pasting.
///
/// @param regname The name of the register used or 0 for the unnamed register
/// @param reg Pointer to store yankreg_T* for the requested register. Will be
/// set to NULL for invalid or blackhole registers.
bool yank_register_mline(int regname, yankreg_T **reg)
{ {
*reg = NULL;
if (regname != 0 && !valid_yank_reg(regname, false)) { if (regname != 0 && !valid_yank_reg(regname, false)) {
return false; return false;
} }
if (regname == '_') { // black hole is always empty if (regname == '_') { // black hole is always empty
return false; return false;
} }
yankreg_T *reg = get_yank_register(regname, YREG_PASTE); *reg = get_yank_register(regname, YREG_PASTE);
return reg->y_type == kMTLineWise; return (*reg)->y_type == kMTLineWise;
} }
/// Start or stop recording into a yank register. /// Start or stop recording into a yank register.
@ -1322,7 +1329,7 @@ static int put_in_typebuf(char *s, bool esc, bool colon, int silent)
/// @param literally_arg insert literally, not as if typed /// @param literally_arg insert literally, not as if typed
/// ///
/// @return FAIL for failure, OK otherwise /// @return FAIL for failure, OK otherwise
int insert_reg(int regname, bool literally_arg) int insert_reg(int regname, yankreg_T *reg, bool literally_arg)
{ {
int retval = OK; int retval = OK;
bool allocated; bool allocated;
@ -1353,7 +1360,9 @@ int insert_reg(int regname, bool literally_arg)
xfree(arg); xfree(arg);
} }
} else { // Name or number register. } else { // Name or number register.
yankreg_T *reg = get_yank_register(regname, YREG_PASTE); if (reg == NULL) {
reg = get_yank_register(regname, YREG_PASTE);
}
if (reg->y_array == NULL) { if (reg->y_array == NULL) {
retval = FAIL; retval = FAIL;
} else { } else {