feat(editor)!: insert-mode ctrl-r should work like paste #35477

Problem:
insert-mode ctrl-r input is treated like raw user input, which is almost
never useful. This means any newlines in the input are affected by
autoindent, etc., which is:
- slow
- usually breaks the formatting of the input

Solution:
- ctrl-r should be treated like a paste, not user-input.
- does not affect `<c-r>=`, so `<c-r>=@x` can still be used to get the
  old behavior.

Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
This commit is contained in:
Shadman
2025-09-02 10:05:16 +06:00
committed by GitHub
parent b4d21f141c
commit 79bfeecdb4
10 changed files with 70 additions and 21 deletions

View File

@@ -142,13 +142,16 @@ CTRL-R {register} *c_CTRL-R* *c_<C-R>*
typing CTRL-R and the second character '"' will be displayed
to indicate that you are expected to enter the name of a
register.
The text is inserted as if you typed it, but mappings and
abbreviations are not used. Command-line completion through
'wildchar' is not triggered though. And characters that end
the command line are inserted literally (<Esc>, <CR>, <NL>,
<C-C>). A <BS> or CTRL-W could still end the command line
though, and remaining characters will then be interpreted in
another mode, which might not be what you intended.
When used with named or clipboard registers (A-Z,a-z,0-9,+)
text is inserted literally like pasting with "p". For other
registers, the text is inserted as if you typed it, but
mappings and abbreviations are not used. Command-line
completion through 'wildchar' is not triggered though. And
characters that end the command line are inserted literally
(<Esc>, <CR>, <NL>, <C-C>). A <BS> or CTRL-W could still end
the command line though, and remaining characters will then be
interpreted in another mode, which might not be what you
intended.
Special registers:
'"' the unnamed register, containing the text of
the last delete or yank
@@ -176,7 +179,9 @@ CTRL-R {register} *c_CTRL-R* *c_<C-R>*
sure the expression evaluates to an empty
string. E.g.: >
<C-R><C-R>=setcmdpos(2)[-1]<CR>
< See |registers| about registers.
< You can use this to insert a register as
typed with CTRL-R =@reg.
See |registers| about registers.
Implementation detail: When using the |expression| register
and invoking setcmdpos(), this sets the position before
inserting the resulting string. Use CTRL-R CTRL-R to set the

View File

@@ -101,14 +101,17 @@ CTRL-N Find next keyword (see |i_CTRL-N|).
CTRL-P Find previous keyword (see |i_CTRL-P|).
CTRL-R {register} *i_CTRL-R*
Insert the contents of a register. Between typing CTRL-R and
Insert the contents of a register. Between typing CTRL-R and
the second character, '"' will be displayed to indicate that
you are expected to enter the name of a register.
The text is inserted as if you typed it, but mappings and
abbreviations are not used. If you have options like
'textwidth', 'formatoptions', or 'autoindent' set, this will
influence what will be inserted. This is different from what
happens with the "p" command and pasting with the mouse.
you are expected to enter the name of a register. When used
with When used with named or clipboard registers
(A-Z,a-z,0-9,+) text is inserted literally like pasting with
"p". For other registers, the text is inserted as if you typed
it, but mappings and abbreviations are not used. If you have
options like 'textwidth', 'formatoptions', or 'autoindent'
set, this will influence what will be inserted. This is
different from what happens with the "p" command and pasting
with the mouse.
Special registers:
'"' the unnamed register, containing the text of
the last delete or yank
@@ -131,6 +134,8 @@ CTRL-R {register} *i_CTRL-R*
special keys. E.g., you can use this to move
the cursor up:
CTRL-R ="\<Up>"
you can use this to insert a register as
typed with CTRL-R =@reg.
Use CTRL-R CTRL-R to insert text literally.
When the result is a |List| the items are used
as lines. They can have line breaks inside

View File

@@ -68,7 +68,8 @@ DIAGNOSTICS
EDITOR
todo
|i_CTRL-R| inserts named registers (A-Z,a-z,0-9) literally like pasting instead of
as typed. To get the old behavior you can use `<C-R>=@x`.
EVENTS

View File

@@ -316,6 +316,8 @@ Commands:
Editor:
- |prompt-buffer| supports multiline input/paste, undo/redo, and o/O normal
commands.
- |i_CTRL-R| inserts named registers (A-Z,a-z,0-9) literally like pasting instead of
as typed. To get the old behavior you can use `<C-R>=@x`.
Events (autocommands):
- Fixed inconsistent behavior in execution of nested autocommands #23368

View File

@@ -2854,6 +2854,8 @@ static void ins_reg(void)
vim_beep(kOptBoFlagRegister);
need_redraw = true; // remove the '"'
} else {
yankreg_T *reg = get_yank_register(regname, YREG_PASTE);
if (literally == Ctrl_O || literally == Ctrl_P) {
// Append the command to the redo buffer.
AppendCharToRedobuff(Ctrl_R);
@@ -2862,7 +2864,11 @@ static void ins_reg(void)
do_put(regname, NULL, BACKWARD, 1,
(literally == Ctrl_P ? PUT_FIXINDENT : 0) | PUT_CURSEND);
} else if (insert_reg(regname, NULL, literally) == FAIL) {
} else if (reg->y_size > 1 && is_literal_register(regname)) {
AppendCharToRedobuff(Ctrl_R);
AppendCharToRedobuff(regname);
do_put(regname, NULL, BACKWARD, 1, PUT_CURSEND);
} else if (insert_reg(regname, NULL, !!literally) == FAIL) {
vim_beep(kOptBoFlagRegister);
need_redraw = true; // remove the '"'
} else if (stop_insert_mode) {

View File

@@ -152,7 +152,7 @@ static inline int op_reg_index(const int regname)
static inline bool is_literal_register(const int regname)
FUNC_ATTR_CONST
{
return regname == '*' || regname == '+';
return regname == '*' || regname == '+' || ASCII_ISALNUM(regname);
}
EXTERN LuaRef repeat_luaref INIT( = LUA_NOREF); ///< LuaRef for "."

View File

@@ -83,6 +83,36 @@ describe('insert-mode', function()
{5:-- INSERT --} |
]])
end)
it('inserts named registers literally', function()
local screen = Screen.new(50, 6)
-- regular text without special charecter command
command('let @a = "test"')
feed('i<C-R>a<ESC>')
screen:expect([[
tes^t |
{1:~ }|*4
|
]])
-- text with backspace character gets written literally by default
command('let @a = "test\\<C-H>"')
feed('cc<C-R>a<ESC>')
screen:expect([[
test{18:^^H} |
{1:~ }|*4
|
]])
-- =@reg<CR> can be used to get effect of keypress
command('let @a = "test\\<C-H>"')
feed('cc<C-R>=@a<CR><ESC>')
screen:expect([[
te^s |
{1:~ }|*4
|
]])
end)
end)
describe('Ctrl-O', function()

View File

@@ -2090,7 +2090,7 @@ func Test_Cmdline()
let g:log = []
let @r = 'abc'
call feedkeys(":0\<C-R>r1\<C-R>\<C-O>r2\<C-R>\<C-R>r3\<Esc>", 'xt')
call feedkeys(":0\<C-R>=@r\<CR>1\<C-R>\<C-O>r2\<C-R>\<C-R>r3\<Esc>", 'xt')
call assert_equal([
\ '0',
\ '0a',

View File

@@ -905,7 +905,7 @@ func Test_cmdline_paste()
" Test for pasting register containing CTRL-H using CTRL-R and CTRL-R CTRL-R
let @a = "xy\<C-H>z"
call feedkeys(":\"\<C-R>a\<CR>", 'xt')
call feedkeys(":\"\<C-R>=@a\<CR>\<CR>", 'xt')
call assert_equal('"xz', @:)
call feedkeys(":\"\<C-R>\<C-R>a\<CR>", 'xt')
call assert_equal("\"xy\<C-H>z", @:)

View File

@@ -1523,7 +1523,7 @@ func Test_complete_reginsert()
exe "normal Goa\<C-P>\<C-R>=\"\\<C-P>\"\<CR>"
call assert_equal('a123', getline(5))
let @r = "\<C-P>\<C-P>"
exe "normal GCa\<C-P>\<C-R>r"
exe "normal GCa\<C-P>\<C-R>=@r\<CR>"
call assert_equal('a12', getline(5))
exe "normal GCa\<C-P>\<C-R>=\"x\"\<CR>"
call assert_equal('a1234x', getline(5))