neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

commit 7432781e71842a595365c351b105971ac3662dff
parent 07d06dd39627ff8fab42985069a26ba54918251f
Author: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Date:   Wed, 16 Apr 2025 03:08:41 -0700

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
Diffstat:
Msrc/nvim/edit.c | 2+-
Msrc/nvim/mouse.c | 14++++++++------
Msrc/nvim/ops.c | 19++++++++++++++-----
3 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/src/nvim/edit.c b/src/nvim/edit.c @@ -3250,7 +3250,7 @@ static void ins_reg(void) do_put(regname, NULL, BACKWARD, 1, (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); need_redraw = true; // remove the '"' } else if (stop_insert_mode) { diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c @@ -503,15 +503,16 @@ bool do_mouse(oparg_T *oap, int c, int dir, int count, bool fixindent) // happens for the GUI). if ((State & MODE_INSERT)) { if (regname == '.') { - insert_reg(regname, true); + insert_reg(regname, NULL, true); } else { if (regname == 0 && eval_has_provider("clipboard", false)) { regname = '*'; } - if ((State & REPLACE_FLAG) && !yank_register_mline(regname)) { - insert_reg(regname, true); + yankreg_T *reg = NULL; + if ((State & REPLACE_FLAG) && !yank_register_mline(regname, &reg)) { + insert_reg(regname, reg, true); } else { - do_put(regname, NULL, BACKWARD, 1, + do_put(regname, reg, BACKWARD, 1, (fixindent ? PUT_FIXINDENT : 0) | PUT_CURSEND); // 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)) { regname = '*'; } - if (yank_register_mline(regname)) { + yankreg_T *reg = NULL; + if (yank_register_mline(regname, &reg)) { if (mouse_past_bottom) { dir = FORWARD; } @@ -855,7 +857,7 @@ bool do_mouse(oparg_T *oap, int c, int dir, int count, bool fixindent) if (restart_edit != 0) { where_paste_started = curwin->w_cursor; } - do_put(regname, NULL, dir, count, + do_put(regname, reg, dir, count, (fixindent ? PUT_FIXINDENT : 0)| PUT_CURSEND); } else if (((mod_mask & MOD_MASK_CTRL) || (mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK) && bt_quickfix(curbuf)) { diff --git a/src/nvim/ops.c b/src/nvim/ops.c @@ -966,16 +966,23 @@ yankreg_T *copy_register(int name) } /// 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)) { return false; } if (regname == '_') { // black hole is always empty return false; } - yankreg_T *reg = get_yank_register(regname, YREG_PASTE); - return reg->y_type == kMTLineWise; + *reg = get_yank_register(regname, YREG_PASTE); + return (*reg)->y_type == kMTLineWise; } /// 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 /// /// @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; bool allocated; @@ -1353,7 +1360,9 @@ int insert_reg(int regname, bool literally_arg) xfree(arg); } } 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) { retval = FAIL; } else {