diff options
author | zeertzjq <zeertzjq@outlook.com> | 2025-03-27 09:06:46 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-03-27 01:06:46 +0000 |
commit | 750e1836afb49b860fa11b4336a7ae351720a553 (patch) | |
tree | d46b75c6d0bc947fcfc268e2e103e6fdf1a9547a | |
parent | 8f40ffdb92b6ca25529b470e4a4e2bb7ddbb000a (diff) | |
download | rneovim-750e1836afb49b860fa11b4336a7ae351720a553.tar.gz rneovim-750e1836afb49b860fa11b4336a7ae351720a553.tar.bz2 rneovim-750e1836afb49b860fa11b4336a7ae351720a553.zip |
vim-patch:9.1.1224: cannot :put while keeping indent (#33076)
Problem: cannot :put while keeping indent (Peter Aronoff)
Solution: add the :iput ex command (64-bitman)
fixes: vim/vim#16225
closes: vim/vim#16886
https://github.com/vim/vim/commit/e08f10a55c3f15b0b4af631908551d88ec4fe502
Cherry-pick test_put.vim changes from patch 8.2.1593.
N/A patches:
vim-patch:9.1.1213: cannot :put while keeping indent
vim-patch:9.1.1215: Patch 9.1.1213 has some issues
Co-authored-by: 64-bitman <60551350+64-bitman@users.noreply.github.com>
Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
-rw-r--r-- | runtime/doc/change.txt | 5 | ||||
-rw-r--r-- | runtime/doc/index.txt | 2 | ||||
-rw-r--r-- | runtime/doc/news.txt | 2 | ||||
-rw-r--r-- | src/nvim/api/command.c | 4 | ||||
-rw-r--r-- | src/nvim/ex_cmds.lua | 6 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 23 | ||||
-rw-r--r-- | test/old/testdir/test_put.vim | 94 |
7 files changed, 122 insertions, 14 deletions
diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt index f7cbf7fd36..3d71c3e032 100644 --- a/runtime/doc/change.txt +++ b/runtime/doc/change.txt @@ -1105,6 +1105,11 @@ inside of strings can change! Also see 'softtabstop' option. > :[line]pu[t]! [x] Put the text [from register x] before [line] (default current line). + *:ip* *:iput* +:[line]ip[ut] [x] like |:put|, but adjust indent to the current line + +:[line]ip[ut]! [x] like |:put|!, but adjust indent to the current line + ["x]]p or *]p* *]<MiddleMouse>* ["x]]<MiddleMouse> Like "p", but adjust the indent to the current line. Using the mouse only works when 'mouse' contains 'n' diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt index b814b3be78..4744b24e84 100644 --- a/runtime/doc/index.txt +++ b/runtime/doc/index.txt @@ -1348,6 +1348,8 @@ tag command action ~ |:inoreabbrev| :inorea[bbrev] like ":noreabbrev" but for Insert mode |:inoremenu| :inoreme[nu] like ":noremenu" but for Insert mode |:intro| :int[ro] print the introductory message +|:iput| :ip[ut] like |:put|, but adjust the indent to the + current line |:isearch| :is[earch] list one line where identifier matches |:isplit| :isp[lit] split window and jump to definition of identifier diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 7bdacd73bf..ad1481e304 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -115,7 +115,7 @@ DIAGNOSTICS EDITOR -• todo +• |:iput| works like |:put| but adjusts indent. EVENTS diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index de83ff97f7..4b93f09c61 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -504,7 +504,9 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Arena VALIDATE((regname != '='), "%s", "Cannot use register \"=", { goto end; }); - VALIDATE(valid_yank_reg(regname, ea.cmdidx != CMD_put && !IS_USER_CMDIDX(ea.cmdidx)), + VALIDATE(valid_yank_reg(regname, + (!IS_USER_CMDIDX(ea.cmdidx) + && ea.cmdidx != CMD_put && ea.cmdidx != CMD_iput)), "Invalid register: \"%c", regname, { goto end; }); diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index d68d5a9afa..34723b6102 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -1219,6 +1219,12 @@ M.cmds = { func = 'ex_intro', }, { + command = 'iput', + flags = bit.bor(RANGE, WHOLEFOLD, BANG, REGSTR, TRLBAR, ZEROR, CMDWIN, LOCK_OK, MODIFY), + addr_type = 'ADDR_LINES', + func = 'ex_iput', + }, + { command = 'isearch', flags = bit.bor(BANG, RANGE, DFLALL, WHOLEFOLD, EXTRA, CMDWIN, LOCK_OK), addr_type = 'ADDR_LINES', diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 640c729e3b..6c5cca5d5c 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1393,8 +1393,9 @@ static void parse_register(exarg_T *eap) // Do not allow register = for user commands && (!IS_USER_CMDIDX(eap->cmdidx) || *eap->arg != '=') && !((eap->argt & EX_COUNT) && ascii_isdigit(*eap->arg))) { - if (valid_yank_reg(*eap->arg, (eap->cmdidx != CMD_put - && !IS_USER_CMDIDX(eap->cmdidx)))) { + if (valid_yank_reg(*eap->arg, + (!IS_USER_CMDIDX(eap->cmdidx) + && eap->cmdidx != CMD_put && eap->cmdidx != CMD_iput))) { eap->regname = (uint8_t)(*eap->arg++); // for '=' register: accept the rest of the line as an expression if (eap->arg[-1] == '=' && eap->arg[0] != NUL) { @@ -1752,7 +1753,7 @@ int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview) if (!MODIFIABLE(curbuf) && (eap->argt & EX_MODIFY) // allow :put in terminals - && !(curbuf->terminal && eap->cmdidx == CMD_put)) { + && !(curbuf->terminal && (eap->cmdidx == CMD_put || eap->cmdidx == CMD_iput))) { errormsg = _(e_modifiable); goto end; } @@ -2155,7 +2156,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter } if (!MODIFIABLE(curbuf) && (ea.argt & EX_MODIFY) // allow :put in terminals - && (!curbuf->terminal || ea.cmdidx != CMD_put)) { + && !(curbuf->terminal && (ea.cmdidx == CMD_put || ea.cmdidx == CMD_iput))) { // Command not allowed in non-'modifiable' buffer errormsg = _(e_modifiable); goto doend; @@ -6306,6 +6307,20 @@ static void ex_put(exarg_T *eap) PUT_LINE|PUT_CURSLINE); } +/// ":iput". +static void ex_iput(exarg_T *eap) +{ + // ":0iput" works like ":1iput!". + if (eap->line2 == 0) { + eap->line2 = 1; + eap->forceit = true; + } + curwin->w_cursor.lnum = eap->line2; + check_cursor_col(curwin); + do_put(eap->regname, NULL, eap->forceit ? BACKWARD : FORWARD, 1L, + PUT_LINE|PUT_CURSLINE|PUT_FIXINDENT); +} + /// Handle ":copy" and ":move". static void ex_copymove(exarg_T *eap) { diff --git a/test/old/testdir/test_put.vim b/test/old/testdir/test_put.vim index e0a78c7409..26eb7f0eb4 100644 --- a/test/old/testdir/test_put.vim +++ b/test/old/testdir/test_put.vim @@ -73,16 +73,18 @@ func Test_put_fails_when_nomodifiable() setlocal nomodifiable normal! yy - call assert_fails(':put', 'E21') - call assert_fails(':put!', 'E21') - call assert_fails(':normal! p', 'E21') - call assert_fails(':normal! gp', 'E21') - call assert_fails(':normal! P', 'E21') - call assert_fails(':normal! gP', 'E21') + call assert_fails(':put', 'E21:') + call assert_fails(':put!', 'E21:') + call assert_fails(':iput', 'E21:') + call assert_fails(':iput!', 'E21:') + call assert_fails(':normal! p', 'E21:') + call assert_fails(':normal! gp', 'E21:') + call assert_fails(':normal! P', 'E21:') + call assert_fails(':normal! gP', 'E21:') if has('mouse') set mouse=n - call assert_fails('execute "normal! \<MiddleMouse>"', 'E21') + call assert_fails('execute "normal! \<MiddleMouse>"', 'E21:') set mouse& endif @@ -132,7 +134,7 @@ func Test_put_visual_delete_all_lines() let @r = '' normal! VG"rgp call assert_equal(1, line('$')) - close! + bw! endfunc func Test_gp_with_count_leaves_cursor_at_end() @@ -328,6 +330,82 @@ func Test_put_list() bw! endfunc +func Test_iput_multiline() + new + setlocal noexpandtab + call setline(1, "\<Tab>foo") + call setreg('0', "bar\n\<Tab>bar2\nbar3", 'l') + iput + call assert_equal(["\<Tab>bar", "\<Tab>\<Tab>bar2", "\<Tab>bar3"], getline(2, 4)) + setlocal expandtab tabstop=8 shiftwidth=8 noshiftround + iput + call assert_equal([repeat(' ', 8) . "bar", + \ repeat(' ', 16) . "bar2", + \ repeat(' ', 8) . "bar3"], getline(5, 7)) + bw! +endfunc + +func Test_iput_beforeafter_tab() + new + setlocal noexpandtab + call setline(1, "\<Tab>foo") + call setreg('0', "bar", 'l') + iput + call assert_equal(["\<Tab>bar"], getline(2, '$')) + call feedkeys("k", 'x') + iput! + call assert_equal("\<Tab>bar", getline(1)) + call assert_equal("\<Tab>bar", getline(3)) + bw! +endfunc + +func Test_iput_beforeafter_expandtab() + new + setlocal expandtab tabstop=8 shiftwidth=8 noshiftround + call setline(1, "\<Tab>foo") + call setreg('0', "bar", 'l') + iput + call assert_equal([repeat(' ', 8) . "bar"], getline(2, '$')) + :1iput! + call assert_equal(repeat(' ', 8) . "bar", getline(1)) + bw! +endfunc + +func Test_iput_invalidrange() + new + call setreg('0', "bar", 'l') + call assert_fails(':10iput', 'E16:') + bw! +endfunc + +func Test_iput_zero_range() + new + let _var = [getreg('a'), getregtype('a')] + call setreg('a', 'foobar', 'l') + call setline(1, range(1, 2)) + call cursor(1, 1) + 0iput a + call assert_equal(['foobar', '1', '2'], getline(1, '$')) + %d + call setline(1, range(1, 2)) + call cursor(1, 1) + 0iput! a + call assert_equal(['foobar', '1', '2'], getline(1, '$')) + call setreg('a', _var[0], _var[1]) + bw! +endfunc + +func Test_iput_not_put() + new + call setline(1, "\<Tab>foo") + call setreg('0', "bar", 'l') + iput + call assert_equal("\<Tab>bar", getline(2)) + put + call assert_equal("bar", getline(3)) + bw! +endfunc + " Test pasting the '.' register func Test_put_inserted() new |