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 <cb@256bit.org>
diff --git a/src/ex_cmdidxs.h b/src/ex_cmdidxs.h
index 0b13a6c..609a81d 100644
--- a/src/ex_cmdidxs.h
+++ b/src/ex_cmdidxs.h
@@ -14,23 +14,23 @@
/* 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 @@
/* 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 @@
/* 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 d217cd9..0659f87 100644
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -761,6 +761,9 @@
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 80ec8a1..341cc38 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -231,6 +231,7 @@
#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 @@
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++;
@@ -8521,6 +8522,25 @@
}
/*
+ * ":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".
*/
static void
diff --git a/src/proto/vim9cmds.pro b/src/proto/vim9cmds.pro
index bd2b5c2..12f0560 100644
--- a/src/proto/vim9cmds.pro
+++ b/src/proto/vim9cmds.pro
@@ -26,7 +26,7 @@
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 3fcf08c..641648f 100644
--- a/src/proto/vim9instr.pro
+++ b/src/proto/vim9instr.pro
@@ -68,7 +68,7 @@
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 94e4f47..51909bf 100644
--- a/src/testdir/test_put.vim
+++ b/src/testdir/test_put.vim
Binary files differ
diff --git a/src/testdir/test_vim9_cmd.vim b/src/testdir/test_vim9_cmd.vim
index 900bf8a..26a3f09 100644
--- a/src/testdir/test_vim9_cmd.vim
+++ b/src/testdir/test_vim9_cmd.vim
@@ -1350,6 +1350,59 @@
bwipe!
enddef
+def Test_iput()
+ new
+ set noexpandtab
+
+ call feedkeys("i\<Tab>foo", 'x')
+
+ @p = "ppp"
+ iput p
+ call assert_equal("\<Tab>ppp", getline(2))
+
+ iput ="below"
+ assert_equal("\<Tab>below", getline(3))
+ iput! ="above"
+ assert_equal("\<Tab>above", getline(3))
+ assert_equal("\<Tab>below", getline(4))
+
+ :2iput =['a', 'b', 'c']
+ assert_equal(["\<Tab>ppp", "\<Tab>a", "\<Tab>b", "\<Tab>c", "\<Tab>above"], getline(2, 6))
+
+ :0iput = "\<Tab>\<Tab>first"
+ assert_equal("\<Tab>first", getline(1))
+ :1iput! ="first again"
+ assert_equal("\<Tab>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\<Tab>foo", 'x')
+ @a = "putting"
+ :0iput a
+ assert_equal("\<Tab>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 2da4952..b69d34d 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1213,
+/**/
1212,
/**/
1211,
diff --git a/src/vim9.h b/src/vim9.h
index 63d7116..7c731fa 100644
--- a/src/vim9.h
+++ b/src/vim9.h
@@ -200,6 +200,7 @@
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 f8ebfb1..aeb742e 100644
--- a/src/vim9cmds.c
+++ b/src/vim9cmds.c
@@ -2161,9 +2161,12 @@
/*
* :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 @@
--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 9d0bf71..cb7b948 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -4595,7 +4595,12 @@
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 4b69dfa..aa0e086 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -3253,6 +3253,57 @@
}
/*
+ * 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 @@
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 @@
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 @@
return OK;
}
-
#endif // FEAT_EVAL
diff --git a/src/vim9instr.c b/src/vim9instr.c
index 86fddd9..4b1de2b 100644
--- a/src/vim9instr.c
+++ b/src/vim9instr.c
@@ -2188,15 +2188,17 @@
}
/*
- * 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;