mirror of
https://github.com/vim/vim.git
synced 2025-09-26 04:04:07 -04:00
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>
This commit is contained in:
committed by
Christian Brabandt
parent
7ceca3eb00
commit
250739d442
@@ -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;
|
||||
|
@@ -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),
|
||||
|
@@ -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".
|
||||
*/
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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()
|
||||
put! =l
|
||||
call assert_equal(['a', 'b', 'c', ''], getline(1, '$'))
|
||||
bw!
|
||||
endfunc
|
||||
|
||||
func Test_iput_multiline()
|
||||
new
|
||||
setlocal noexpandtab
|
||||
call feedkeys("i\<Tab>foo", 'x')
|
||||
call setreg('0', "bar\n\<Tab>bar2\nbar3", 'l')
|
||||
exe "iput"
|
||||
call assert_equal(["\<Tab>bar", "\<Tab>\<Tab>bar2", "\<Tab>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\<Tab>foo", 'x')
|
||||
call setreg('0', "bar", 'l')
|
||||
exe "iput"
|
||||
call assert_equal(["\<Tab>bar"], getline(2, '$'))
|
||||
call feedkeys("k", 'x')
|
||||
exe "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 feedkeys("i\<Tab>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\<Tab>foo", 'x')
|
||||
call setreg('0', "bar", 'l')
|
||||
exe "iput"
|
||||
call assert_equal("\<Tab>bar", getline(2))
|
||||
exe "put"
|
||||
call assert_equal("bar", getline(3))
|
||||
bw!
|
||||
endfunc
|
||||
|
@@ -1350,6 +1350,59 @@ def Test_put_with_linebreak()
|
||||
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'])
|
||||
|
@@ -704,6 +704,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1213,
|
||||
/**/
|
||||
1212,
|
||||
/**/
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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:
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user