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:
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, ®)) {
+ 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, ®)) {
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 {