From 250739d442b51ba76589d6eb67672d95645527ec Mon Sep 17 00:00:00 2001 From: 64-bitman <60551350+64-bitman@users.noreply.github.com> Date: Sun, 16 Mar 2025 21:10:47 +0100 Subject: [PATCH] patch 9.1.1213: cannot :put while keeping indent Problem: cannot :put while keeping indent (Peter Aronoff) Solution: add the :iput ex command (64-bitman) fixes: #16225 closes: #16886 Signed-off-by: 64-bitman <60551350+64-bitman@users.noreply.github.com> Signed-off-by: Christian Brabandt --- runtime/doc/change.txt | 7 ++- runtime/doc/index.txt | 4 +- runtime/doc/tags | 2 + runtime/doc/version9.txt | 6 +- runtime/syntax/vim.vim | 12 ++-- src/ex_cmdidxs.h | 38 ++++++------ src/ex_cmds.h | 3 + src/ex_docmd.c | 22 ++++++- src/proto/vim9cmds.pro | 2 +- src/proto/vim9instr.pro | 2 +- src/testdir/test_put.vim | 61 +++++++++++++++++++ src/testdir/test_vim9_cmd.vim | 53 ++++++++++++++++ src/version.c | 2 + src/vim9.h | 1 + src/vim9cmds.c | 8 ++- src/vim9compile.c | 7 ++- src/vim9execute.c | 111 ++++++++++++++++++++-------------- src/vim9instr.c | 8 ++- 18 files changed, 268 insertions(+), 81 deletions(-) diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt index 301eacee26..6e5279ad8c 100644 --- a/runtime/doc/change.txt +++ b/runtime/doc/change.txt @@ -1,4 +1,4 @@ -*change.txt* For Vim version 9.1. Last change: 2024 Dec 15 +*change.txt* For Vim version 9.1. Last change: 2025 Mar 16 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1149,6 +1149,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* *]* ["x]] 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 06a24e0465..eec49517ff 100644 --- a/runtime/doc/index.txt +++ b/runtime/doc/index.txt @@ -1,4 +1,4 @@ -*index.txt* For Vim version 9.1. Last change: 2025 Jan 03 +*index.txt* For Vim version 9.1. Last change: 2025 Mar 16 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1400,6 +1400,8 @@ tag command action ~ |:inoremenu| :inoreme[nu] like ":noremenu" but for Insert mode |:intro| :int[ro] print the introductory message |:interface| :interface start of an interface declaration +|: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/tags b/runtime/doc/tags index c25effa3a4..eec0336ca1 100644 --- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -2710,6 +2710,8 @@ $quote eval.txt /*$quote* :insert insert.txt /*:insert* :interface vim9class.txt /*:interface* :intro starting.txt /*:intro* +:ip change.txt /*:ip* +:iput change.txt /*:iput* :is tagsrch.txt /*:is* :isearch tagsrch.txt /*:isearch* :isp tagsrch.txt /*:isp* diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt index b27e1245d4..9d46575ed7 100644 --- a/runtime/doc/version9.txt +++ b/runtime/doc/version9.txt @@ -1,4 +1,4 @@ -*version9.txt* For Vim version 9.1. Last change: 2025 Mar 15 +*version9.txt* For Vim version 9.1. Last change: 2025 Mar 16 VIM REFERENCE MANUAL by Bram Moolenaar @@ -41704,6 +41704,10 @@ Highlighting: ~ Commands: ~ |[r| and |]r| to move the cursor to previous/next rare word + +Ex-Commands: ~ + +|:iput| like |:put| but adjust indent |:pbuffer| Edit buffer [N] from the buffer list in the preview window diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim index fbfc8ad7f9..05e8a786cc 100644 --- a/runtime/syntax/vim.vim +++ b/runtime/syntax/vim.vim @@ -2,7 +2,7 @@ " Language: Vim script " Maintainer: Hirohito Higashi " Doug Kearns -" Last Change: 2025 Mar 13 +" Last Change: 2025 Mar 16 " Former Maintainer: Charles E. Campbell " DO NOT CHANGE DIRECTLY. @@ -34,11 +34,11 @@ syn cluster vimCommentGroup contains=vimTodo,@Spell " regular vim commands {{{2 " GEN_SYN_VIM: vimCommand normal, START_STR='syn keyword vimCommand contained', END_STR='nextgroup=vimBang' syn keyword vimCommand contained abo[veleft] al[l] ar[gs] arga[dd] argd[elete] argdo argded[upe] arge[dit] argg[lobal] argl[ocal] argu[ment] as[cii] b[uffer] bN[ext] ba[ll] bad[d] balt bd[elete] bel[owright] bf[irst] bl[ast] bm[odified] bn[ext] bo[tright] bp[revious] br[ewind] brea[k] breaka[dd] breakd[el] breakl[ist] bro[wse] buffers bufd[o] bun[load] bw[ipeout] c[hange] cN[ext] cNf[ile] cabo[ve] cad[dbuffer] cadde[xpr] caddf[ile] caf[ter] cb[uffer] cbe[fore] cbel[ow] cbo[ttom] cc ccl[ose] cd cdo ce[nter] cex[pr] cf[ile] cfd[o] cfir[st] cg[etfile] cgetb[uffer] cgete[xpr] chd[ir] changes che[ckpath] checkt[ime] chi[story] cl[ist] cla[st] clo[se] cle[arjumps] cn[ext] cnew[er] cnf[ile] co[py] col[der] colo[rscheme] com[mand] comc[lear] comp[iler] con[tinue] conf[irm] nextgroup=vimBang -syn keyword vimCommand contained cons[t] cope[n] cp[revious] cpf[ile] cq[uit] cr[ewind] cs[cope] cst[ag] cw[indow] d[elete] delm[arks] deb[ug] defc[ompile] defe[r] delf[unction] di[splay] dif[fupdate] diffg[et] diffo[ff] diffp[atch] diffpu[t] diffs[plit] difft[his] dig[raphs] disa[ssemble] dj[ump] dli[st] dr[op] ds[earch] dsp[lit] e[dit] ea[rlier] el[se] em[enu] en[dif] endfo[r] endt[ry] endw[hile] ene[w] ev[al] ex exi[t] exu[sage] f[ile] files filet[ype] filt[er] fin[d] fina[lly] fini[sh] fir[st] fix[del] fo[ld] foldc[lose] foldd[oopen] folddoc[losed] foldo[pen] g[lobal] go[to] gr[ep] grepa[dd] gu[i] gv[im] h[elp] helpc[lose] helpf[ind] helpg[rep] helpt[ags] ha[rdcopy] hi[ghlight] hid[e] his[tory] hor[izontal] ij[ump] il[ist] imp[ort] int[ro] is[earch] isp[lit] nextgroup=vimBang -syn keyword vimCommand contained j[oin] ju[mps] k kee[pmarks] keepj[umps] keepp[atterns] keepa[lt] l[ist] lN[ext] lNf[ile] la[st] lab[ove] lan[guage] lad[dexpr] laddb[uffer] laddf[ile] laf[ter] lat[er] lb[uffer] lbe[fore] lbel[ow] lbo[ttom] lc[d] lch[dir] lcl[ose] lcs[cope] ld[o] le[ft] lefta[bove] lex[pr] leg[acy] lf[ile] lfd[o] lfir[st] lg[etfile] lgetb[uffer] lgete[xpr] lgr[ep] lgrepa[dd] lh[elpgrep] lhi[story] ll lla[st] lli[st] lmak[e] lne[xt] lnew[er] lnf[ile] lo[adview] loc[kmarks] lockv[ar] lol[der] lop[en] lp[revious] lpf[ile] lr[ewind] lt[ag] lua luad[o] luaf[ile] lv[imgrep] lvimgrepa[dd] lw[indow] ls m[ove] ma[rk] mak[e] marks menut[ranslate] mes[sages] mk[exrc] mks[ession] mksp[ell] mkv[imrc] mkvie[w] mod[e] mz[scheme] mzf[ile] n[ext] nb[key] nbc[lose] nextgroup=vimBang -syn keyword vimCommand contained nbs[tart] noa[utocmd] noh[lsearch] nos[wapfile] nu[mber] o[pen] ol[dfiles] on[ly] opt[ions] ow[nsyntax] p[rint] pa[ckadd] packl[oadall] pb[uffer] pc[lose] pe[rl] perld[o] ped[it] po[p] pp[op] pre[serve] prev[ious] pro[mptfind] promptr[epl] prof[ile] profd[el] ps[earch] pt[ag] ptN[ext] ptf[irst] ptj[ump] ptl[ast] ptn[ext] ptp[revious] ptr[ewind] pts[elect] pu[t] pw[d] py[thon] pyd[o] pyf[ile] py3 py3d[o] python3 py3f[ile] pyx pyxd[o] pythonx pyxf[ile] q[uit] quita[ll] qa[ll] r[ead] rec[over] red[o] redi[r] redr[aw] redraws[tatus] redrawt[abline] reg[isters] res[ize] ret[ab] rew[ind] ri[ght] rightb[elow] ru[ntime] rub[y] rubyd[o] rubyf[ile] rund[o] rv[iminfo] sN[ext] sa[rgument] sal[l] san[dbox] sav[eas] sb[uffer] sbN[ext] sba[ll] nextgroup=vimBang -syn keyword vimCommand contained sbf[irst] sbl[ast] sbm[odified] sbn[ext] sbp[revious] sbr[ewind] scr[iptnames] scripte[ncoding] scriptv[ersion] scs[cope] setf[iletype] sf[ind] sfir[st] sh[ell] sim[alt] sig[n] sil[ent] sla[st] sn[ext] so[urce] sor[t] sp[lit] spe[llgood] spelld[ump] spelli[nfo] spellr[epall] spellra[re] spellu[ndo] spellw[rong] spr[evious] sre[wind] st[op] sta[g] star[tinsert] startg[replace] startr[eplace] stopi[nsert] stj[ump] sts[elect] sun[hide] sus[pend] sv[iew] sw[apname] synti[me] sync[bind] smi[le] t tN[ext] ta[g] tags tab tabc[lose] tabd[o] tabe[dit] tabf[ind] tabfir[st] tabm[ove] tabl[ast] tabn[ext] tabnew tabo[nly] tabp[revious] tabN[ext] tabr[ewind] tabs tc[d] tch[dir] tcl tcld[o] tclf[ile] te[aroff] ter[minal] tf[irst] tj[ump] tl[ast] nextgroup=vimBang -syn keyword vimCommand contained tn[ext] to[pleft] tp[revious] tr[ewind] try ts[elect] u[ndo] undoj[oin] undol[ist] unh[ide] unlo[ckvar] uns[ilent] up[date] v[global] ve[rsion] verb[ose] vert[ical] vi[sual] vie[w] vim[grep] vimgrepa[dd] vim9[cmd] viu[sage] vne[w] vs[plit] w[rite] wN[ext] wa[ll] wi[nsize] winc[md] wind[o] winp[os] wn[ext] wp[revious] wq wqa[ll] wu[ndo] wv[iminfo] x[it] xa[ll] xr[estore] y[ank] z dl dell delel deletl deletel dp dep delp delep deletp deletep a i nextgroup=vimBang +syn keyword vimCommand contained cons[t] cope[n] cp[revious] cpf[ile] cq[uit] cr[ewind] cs[cope] cst[ag] cw[indow] d[elete] delm[arks] deb[ug] defc[ompile] defe[r] delf[unction] di[splay] dif[fupdate] diffg[et] diffo[ff] diffp[atch] diffpu[t] diffs[plit] difft[his] dig[raphs] disa[ssemble] dj[ump] dli[st] dr[op] ds[earch] dsp[lit] e[dit] ea[rlier] el[se] em[enu] en[dif] endfo[r] endt[ry] endw[hile] ene[w] ev[al] ex exi[t] exu[sage] f[ile] files filet[ype] filt[er] fin[d] fina[lly] fini[sh] fir[st] fix[del] fo[ld] foldc[lose] foldd[oopen] folddoc[losed] foldo[pen] g[lobal] go[to] gr[ep] grepa[dd] gu[i] gv[im] h[elp] helpc[lose] helpf[ind] helpg[rep] helpt[ags] ha[rdcopy] hi[ghlight] hid[e] his[tory] hor[izontal] ij[ump] il[ist] imp[ort] int[ro] ip[ut] is[earch] nextgroup=vimBang +syn keyword vimCommand contained isp[lit] j[oin] ju[mps] k kee[pmarks] keepj[umps] keepp[atterns] keepa[lt] l[ist] lN[ext] lNf[ile] la[st] lab[ove] lan[guage] lad[dexpr] laddb[uffer] laddf[ile] laf[ter] lat[er] lb[uffer] lbe[fore] lbel[ow] lbo[ttom] lc[d] lch[dir] lcl[ose] lcs[cope] ld[o] le[ft] lefta[bove] lex[pr] leg[acy] lf[ile] lfd[o] lfir[st] lg[etfile] lgetb[uffer] lgete[xpr] lgr[ep] lgrepa[dd] lh[elpgrep] lhi[story] ll lla[st] lli[st] lmak[e] lne[xt] lnew[er] lnf[ile] lo[adview] loc[kmarks] lockv[ar] lol[der] lop[en] lp[revious] lpf[ile] lr[ewind] lt[ag] lua luad[o] luaf[ile] lv[imgrep] lvimgrepa[dd] lw[indow] ls m[ove] ma[rk] mak[e] marks menut[ranslate] mes[sages] mk[exrc] mks[ession] mksp[ell] mkv[imrc] mkvie[w] mod[e] mz[scheme] mzf[ile] n[ext] nb[key] nextgroup=vimBang +syn keyword vimCommand contained nbc[lose] nbs[tart] noa[utocmd] noh[lsearch] nos[wapfile] nu[mber] o[pen] ol[dfiles] on[ly] opt[ions] ow[nsyntax] p[rint] pa[ckadd] packl[oadall] pb[uffer] pc[lose] pe[rl] perld[o] ped[it] po[p] pp[op] pre[serve] prev[ious] pro[mptfind] promptr[epl] prof[ile] profd[el] ps[earch] pt[ag] ptN[ext] ptf[irst] ptj[ump] ptl[ast] ptn[ext] ptp[revious] ptr[ewind] pts[elect] pu[t] pw[d] py[thon] pyd[o] pyf[ile] py3 py3d[o] python3 py3f[ile] pyx pyxd[o] pythonx pyxf[ile] q[uit] quita[ll] qa[ll] r[ead] rec[over] red[o] redi[r] redr[aw] redraws[tatus] redrawt[abline] reg[isters] res[ize] ret[ab] rew[ind] ri[ght] rightb[elow] ru[ntime] rub[y] rubyd[o] rubyf[ile] rund[o] rv[iminfo] sN[ext] sa[rgument] sal[l] san[dbox] sav[eas] sb[uffer] sbN[ext] nextgroup=vimBang +syn keyword vimCommand contained sba[ll] sbf[irst] sbl[ast] sbm[odified] sbn[ext] sbp[revious] sbr[ewind] scr[iptnames] scripte[ncoding] scriptv[ersion] scs[cope] setf[iletype] sf[ind] sfir[st] sh[ell] sim[alt] sig[n] sil[ent] sla[st] sn[ext] so[urce] sor[t] sp[lit] spe[llgood] spelld[ump] spelli[nfo] spellr[epall] spellra[re] spellu[ndo] spellw[rong] spr[evious] sre[wind] st[op] sta[g] star[tinsert] startg[replace] startr[eplace] stopi[nsert] stj[ump] sts[elect] sun[hide] sus[pend] sv[iew] sw[apname] synti[me] sync[bind] smi[le] t tN[ext] ta[g] tags tab tabc[lose] tabd[o] tabe[dit] tabf[ind] tabfir[st] tabm[ove] tabl[ast] tabn[ext] tabnew tabo[nly] tabp[revious] tabN[ext] tabr[ewind] tabs tc[d] tch[dir] tcl tcld[o] tclf[ile] te[aroff] ter[minal] tf[irst] tj[ump] nextgroup=vimBang +syn keyword vimCommand contained tl[ast] tn[ext] to[pleft] tp[revious] tr[ewind] try ts[elect] u[ndo] undoj[oin] undol[ist] unh[ide] unlo[ckvar] uns[ilent] up[date] v[global] ve[rsion] verb[ose] vert[ical] vi[sual] vie[w] vim[grep] vimgrepa[dd] vim9[cmd] viu[sage] vne[w] vs[plit] w[rite] wN[ext] wa[ll] wi[nsize] winc[md] wind[o] winp[os] wn[ext] wp[revious] wq wqa[ll] wu[ndo] wv[iminfo] x[it] xa[ll] xr[estore] y[ank] z dl dell delel deletl deletel dp dep delp delep deletp deletep a i nextgroup=vimBang " Lower priority for _new_ to distinguish constructors from the command. syn match vimCommand contained "\(\@!" diff --git a/src/ex_cmdidxs.h b/src/ex_cmdidxs.h index 0b13a6c7f6..609a81d398 100644 --- a/src/ex_cmdidxs.h +++ b/src/ex_cmdidxs.h @@ -14,23 +14,23 @@ static const unsigned short cmdidxs1[26] = /* g */ 184, /* h */ 190, /* i */ 200, - /* j */ 220, - /* k */ 222, - /* l */ 227, - /* m */ 290, - /* n */ 308, - /* o */ 328, - /* p */ 340, - /* q */ 381, - /* r */ 384, - /* s */ 404, - /* t */ 474, - /* u */ 521, - /* v */ 532, - /* w */ 553, - /* x */ 567, - /* y */ 577, - /* z */ 578 + /* j */ 221, + /* k */ 223, + /* l */ 228, + /* m */ 291, + /* n */ 309, + /* o */ 329, + /* p */ 341, + /* q */ 382, + /* r */ 385, + /* s */ 405, + /* t */ 475, + /* u */ 522, + /* v */ 533, + /* w */ 554, + /* x */ 568, + /* y */ 578, + /* z */ 579 }; /* @@ -49,7 +49,7 @@ static const unsigned char cmdidxs2[26][26] = /* f */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0 }, /* g */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 4, 5, 0, 0, 0, 0 }, /* h */ { 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* i */ { 1, 0, 0, 0, 0, 3, 0, 0, 0, 4, 0, 5, 6, 0, 0, 0, 0, 0, 15, 0, 17, 0, 0, 0, 0, 0 }, + /* i */ { 1, 0, 0, 0, 0, 3, 0, 0, 0, 4, 0, 5, 6, 0, 0, 15, 0, 0, 16, 0, 18, 0, 0, 0, 0, 0 }, /* j */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, /* k */ { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* l */ { 3, 11, 15, 19, 20, 25, 28, 33, 0, 0, 0, 35, 38, 41, 45, 51, 0, 53, 62, 54, 55, 59, 61, 0, 0, 0 }, @@ -69,4 +69,4 @@ static const unsigned char cmdidxs2[26][26] = /* z */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; -static const int command_count = 595; +static const int command_count = 596; diff --git a/src/ex_cmds.h b/src/ex_cmds.h index d217cd9f7f..0659f87c27 100644 --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -761,6 +761,9 @@ EXCMD(CMD_intro, "intro", ex_intro, EXCMD(CMD_interface, "interface", ex_class, EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE|EX_EXPORT, ADDR_NONE), +EXCMD(CMD_iput, "iput", ex_iput, + EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_REGSTR|EX_TRLBAR|EX_ZEROR|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY, + ADDR_LINES), EXCMD(CMD_isearch, "isearch", ex_findpat, EX_BANG|EX_RANGE|EX_DFLALL|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK, ADDR_LINES), diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 80ec8a1a6f..341cc38895 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -231,6 +231,7 @@ static void ex_winpos(exarg_T *eap); #endif static void ex_operators(exarg_T *eap); static void ex_put(exarg_T *eap); +static void ex_iput(exarg_T *eap); static void ex_copymove(exarg_T *eap); static void ex_submagic(exarg_T *eap); static void ex_join(exarg_T *eap); @@ -2372,7 +2373,7 @@ do_one_cmd( goto doend; } #endif - if (valid_yank_reg(*ea.arg, (ea.cmdidx != CMD_put + if (valid_yank_reg(*ea.arg, ((ea.cmdidx != CMD_put && ea.cmdidx != CMD_iput) && !IS_USER_CMDIDX(ea.cmdidx)))) { ea.regname = *ea.arg++; @@ -8520,6 +8521,25 @@ 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(); + do_put(eap->regname, NULL, eap->forceit ? BACKWARD : FORWARD, 1L, + PUT_LINE|PUT_CURSLINE + |PUT_FIXINDENT); +} + /* * Handle ":copy" and ":move". */ diff --git a/src/proto/vim9cmds.pro b/src/proto/vim9cmds.pro index bd2b5c2487..12f0560ace 100644 --- a/src/proto/vim9cmds.pro +++ b/src/proto/vim9cmds.pro @@ -26,7 +26,7 @@ char_u *compile_eval(char_u *arg, cctx_T *cctx); int get_defer_var_idx(cctx_T *cctx); char_u *compile_defer(char_u *arg_start, cctx_T *cctx); char_u *compile_mult_expr(char_u *arg, int cmdidx, long cmd_count, cctx_T *cctx); -char_u *compile_put(char_u *arg, exarg_T *eap, cctx_T *cctx); +char_u *compile_put(char_u *arg, exarg_T *eap, cctx_T *cctx, int fixindent); char_u *compile_exec(char_u *line_arg, exarg_T *eap, cctx_T *cctx); char_u *compile_script(char_u *line, cctx_T *cctx); char_u *compile_substitute(char_u *arg, exarg_T *eap, cctx_T *cctx); diff --git a/src/proto/vim9instr.pro b/src/proto/vim9instr.pro index 3fcf08c095..641648f4e9 100644 --- a/src/proto/vim9instr.pro +++ b/src/proto/vim9instr.pro @@ -68,7 +68,7 @@ int generate_ECHO(cctx_T *cctx, int with_white, int count); int generate_MULT_EXPR(cctx_T *cctx, isntype_T isn_type, int count); int generate_ECHOWINDOW(cctx_T *cctx, int count, long time); int generate_SOURCE(cctx_T *cctx, int sid); -int generate_PUT(cctx_T *cctx, int regname, linenr_T lnum); +int generate_PUT(cctx_T *cctx, int regname, linenr_T lnum, int fixindent); int generate_LOCKUNLOCK(cctx_T *cctx, char_u *line, int is_arg); int generate_EXEC_copy(cctx_T *cctx, isntype_T isntype, char_u *line); int generate_EXEC(cctx_T *cctx, isntype_T isntype, char_u *str); diff --git a/src/testdir/test_put.vim b/src/testdir/test_put.vim index 94e4f475c0..51909bfc79 100644 --- a/src/testdir/test_put.vim +++ b/src/testdir/test_put.vim @@ -75,6 +75,8 @@ func Test_put_fails_when_nomodifiable() normal! yy 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:') @@ -328,4 +330,63 @@ func Test_put_list() bw! endfunc +func Test_iput_multiline() + new + setlocal noexpandtab + call feedkeys("i\foo", 'x') + call setreg('0', "bar\n\bar2\nbar3", 'l') + exe "iput" + call assert_equal(["\bar", "\\bar2", "\bar3"], getline(2, 4)) + setlocal expandtab tabstop=8 shiftwidth=8 noshiftround + exe "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 feedkeys("i\foo", 'x') + call setreg('0', "bar", 'l') + exe "iput" + call assert_equal(["\bar"], getline(2, '$')) + call feedkeys("k", 'x') + exe "iput!" + call assert_equal("\bar", getline(1)) + call assert_equal("\bar", getline(3)) + bw! +endfunc + +func Test_iput_beforeafter_expandtab() + new + setlocal expandtab tabstop=8 shiftwidth=8 noshiftround + call feedkeys("i\foo", 'x') + call setreg('0', "bar", 'l') + exe "iput" + call assert_equal([repeat(' ', 8) . "bar"], getline(2, '$')) + exe "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_not_put() + new + call feedkeys("i\foo", 'x') + call setreg('0', "bar", 'l') + exe "iput" + call assert_equal("\bar", getline(2)) + exe "put" + call assert_equal("bar", getline(3)) + bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_vim9_cmd.vim b/src/testdir/test_vim9_cmd.vim index 900bf8ae31..26a3f09a13 100644 --- a/src/testdir/test_vim9_cmd.vim +++ b/src/testdir/test_vim9_cmd.vim @@ -1350,6 +1350,59 @@ def Test_put_with_linebreak() bwipe! enddef +def Test_iput() + new + set noexpandtab + + call feedkeys("i\foo", 'x') + + @p = "ppp" + iput p + call assert_equal("\ppp", getline(2)) + + iput ="below" + assert_equal("\below", getline(3)) + iput! ="above" + assert_equal("\above", getline(3)) + assert_equal("\below", getline(4)) + + :2iput =['a', 'b', 'c'] + assert_equal(["\ppp", "\a", "\b", "\c", "\above"], getline(2, 6)) + + :0iput = "\\first" + assert_equal("\first", getline(1)) + :1iput! ="first again" + assert_equal("\first again", getline(1)) + + bw! + v9.CheckDefFailure(['iput =xxx'], 'E1001:') +enddef + +def Test_iput_with_linebreak() + new + var lines =<< trim END + vim9script + ip =split('abc', '\zs') + ->join() + END + v9.CheckScriptSuccess(lines) + getline(2)->assert_equal('a b c') + bwipe! +enddef + +def Test_iput_not_put() + new + call feedkeys("ggS\foo", 'x') + @a = "putting" + :0iput a + assert_equal("\putting", getline(1)) + put a + assert_equal("putting", getline(2)) + iput a + assert_equal("putting", getline(3)) + bwipe! +enddef + def Test_command_star_range() new setline(1, ['xxx foo xxx', 'xxx bar xxx', 'xxx foo xx bar']) diff --git a/src/version.c b/src/version.c index 2da49520a8..b69d34d263 100644 --- a/src/version.c +++ b/src/version.c @@ -704,6 +704,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1213, /**/ 1212, /**/ diff --git a/src/vim9.h b/src/vim9.h index 63d7116fd0..7c731fa604 100644 --- a/src/vim9.h +++ b/src/vim9.h @@ -200,6 +200,7 @@ typedef enum { ISN_USEDICT, // use or clear dict saved by ISN_MEMBER/ISN_STRINGMEMBER ISN_PUT, // ":put", uses isn_arg.put + ISN_IPUT, // ":iput", uses isn_arg.put ISN_CMDMOD, // set cmdmod ISN_CMDMOD_REV, // undo ISN_CMDMOD diff --git a/src/vim9cmds.c b/src/vim9cmds.c index f8ebfb1288..aeb742e570 100644 --- a/src/vim9cmds.c +++ b/src/vim9cmds.c @@ -2161,9 +2161,12 @@ compile_variable_range(exarg_T *eap, cctx_T *cctx) /* * :put r * :put ={expr} + * or if fixindent == TRUE + * :iput r + * :iput ={expr} */ char_u * -compile_put(char_u *arg, exarg_T *eap, cctx_T *cctx) +compile_put(char_u *arg, exarg_T *eap, cctx_T *cctx, int fixindent) { char_u *line = arg; linenr_T lnum; @@ -2202,7 +2205,8 @@ compile_put(char_u *arg, exarg_T *eap, cctx_T *cctx) --lnum; } - generate_PUT(cctx, eap->regname, lnum); + generate_PUT(cctx, eap->regname, lnum, fixindent); + return line; } diff --git a/src/vim9compile.c b/src/vim9compile.c index 9d0bf71def..cb7b948226 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -4595,7 +4595,12 @@ compile_def_function_body( case CMD_put: ea.cmd = cmd; - line = compile_put(p, &ea, cctx); + line = compile_put(p, &ea, cctx, FALSE); + break; + + case CMD_iput: + ea.cmd = cmd; + line = compile_put(p, &ea, cctx, TRUE); break; case CMD_substitute: diff --git a/src/vim9execute.c b/src/vim9execute.c index 4b69dfafa2..aa0e0863ae 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -3252,6 +3252,57 @@ var_any_get_oc_member(class_T *current_class, isn_T *iptr, typval_T *tv) return OK; } +/* + * do ISN_PUT or ISN_IPUT instruction depending on fixindent parameter + */ + static void +isn_put_do (ectx_T *ectx, isn_T *iptr, typval_T *tv, int fixindent) { + int regname = iptr->isn_arg.put.put_regname; + linenr_T lnum = iptr->isn_arg.put.put_lnum; + char_u *expr = NULL; + int dir = FORWARD; + + if (lnum < -2) + { + // line number was put on the stack by ISN_RANGE + tv = STACK_TV_BOT(-1); + curwin->w_cursor.lnum = tv->vval.v_number; + if (lnum == LNUM_VARIABLE_RANGE_ABOVE) + dir = BACKWARD; + --ectx->ec_stack.ga_len; + } + else if (lnum == -2) + // :put! above cursor + dir = BACKWARD; + else if (lnum >= 0) + { + curwin->w_cursor.lnum = lnum; + if (lnum == 0) + // check_cursor() below will move to line 1 + dir = BACKWARD; + } + + if (regname == '=') + { + tv = STACK_TV_BOT(-1); + if (tv->v_type == VAR_STRING) + expr = tv->vval.v_string; + else + { + expr = typval2string(tv, TRUE); // allocates value + clear_tv(tv); + } + --ectx->ec_stack.ga_len; + } + check_cursor(); + + if (fixindent) + do_put(regname, expr, dir, 1L, PUT_LINE|PUT_CURSLINE|PUT_FIXINDENT); + else + do_put(regname, expr, dir, 1L, PUT_LINE|PUT_CURSLINE); + vim_free(expr); +} + /* * Execute instructions in execution context "ectx". * Return OK or FAIL; @@ -5948,48 +5999,10 @@ exec_instructions(ectx_T *ectx) break; case ISN_PUT: - { - int regname = iptr->isn_arg.put.put_regname; - linenr_T lnum = iptr->isn_arg.put.put_lnum; - char_u *expr = NULL; - int dir = FORWARD; - - if (lnum < -2) - { - // line number was put on the stack by ISN_RANGE - tv = STACK_TV_BOT(-1); - curwin->w_cursor.lnum = tv->vval.v_number; - if (lnum == LNUM_VARIABLE_RANGE_ABOVE) - dir = BACKWARD; - --ectx->ec_stack.ga_len; - } - else if (lnum == -2) - // :put! above cursor - dir = BACKWARD; - else if (lnum >= 0) - { - curwin->w_cursor.lnum = lnum; - if (lnum == 0) - // check_cursor() below will move to line 1 - dir = BACKWARD; - } - - if (regname == '=') - { - tv = STACK_TV_BOT(-1); - if (tv->v_type == VAR_STRING) - expr = tv->vval.v_string; - else - { - expr = typval2string(tv, TRUE); // allocates value - clear_tv(tv); - } - --ectx->ec_stack.ga_len; - } - check_cursor(); - do_put(regname, expr, dir, 1L, PUT_LINE|PUT_CURSLINE); - vim_free(expr); - } + isn_put_do(ectx, iptr, tv, FALSE); + break; + case ISN_IPUT: + isn_put_do(ectx, iptr, tv, TRUE); break; case ISN_CMDMOD: @@ -7619,7 +7632,18 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc) iptr->isn_arg.put.put_regname, (long)iptr->isn_arg.put.put_lnum); break; - + case ISN_IPUT: + if (iptr->isn_arg.put.put_lnum == LNUM_VARIABLE_RANGE_ABOVE) + smsg("%s%4d PUT %c above range", + pfx, current, iptr->isn_arg.put.put_regname); + else if (iptr->isn_arg.put.put_lnum == LNUM_VARIABLE_RANGE) + smsg("%s%4d PUT %c range", + pfx, current, iptr->isn_arg.put.put_regname); + else + smsg("%s%4d PUT %c %ld", pfx, current, + iptr->isn_arg.put.put_regname, + (long)iptr->isn_arg.put.put_lnum); + break; case ISN_CMDMOD: { char_u *buf; @@ -7846,5 +7870,4 @@ check_not_string(typval_T *tv) return OK; } - #endif // FEAT_EVAL diff --git a/src/vim9instr.c b/src/vim9instr.c index 86fddd9f64..4b1de2bf9c 100644 --- a/src/vim9instr.c +++ b/src/vim9instr.c @@ -2188,15 +2188,17 @@ generate_SOURCE(cctx_T *cctx, int sid) } /* - * Generate an ISN_PUT instruction. + * Generate an ISN_PUT or ISN_IPUT instruction depending on fixindent. */ int -generate_PUT(cctx_T *cctx, int regname, linenr_T lnum) +generate_PUT(cctx_T *cctx, int regname, linenr_T lnum, int fixindent) { isn_T *isn; RETURN_OK_IF_SKIP(cctx); - if ((isn = generate_instr(cctx, ISN_PUT)) == NULL) + isn = (fixindent) ? generate_instr(cctx, ISN_IPUT) : + generate_instr(cctx, ISN_PUT); + if (isn == NULL) return FAIL; isn->isn_arg.put.put_regname = regname; isn->isn_arg.put.put_lnum = lnum;