mirror of
https://github.com/vim/vim.git
synced 2025-07-24 10:45:12 -04:00
patch 9.1.0312: heredocs are not supported for :commands
Problem: heredocs are not supported for :commands (@balki) Solution: Add heredoc support (Yegappan Lakshmanan) fixes: #14491 closes: #14528 Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
parent
a1dcd76ce7
commit
e74cad3321
@ -1,4 +1,4 @@
|
||||
*vim9.txt* For Vim version 9.1. Last change: 2024 Jan 12
|
||||
*vim9.txt* For Vim version 9.1. Last change: 2024 Apr 12
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@ -641,6 +641,14 @@ No command can follow the "{", only a comment can be used there.
|
||||
The block can also be used for defining a user command. Inside the block Vim9
|
||||
syntax will be used.
|
||||
|
||||
This is an example of using here-docs: >
|
||||
com SomeCommand {
|
||||
g:someVar =<< trim eval END
|
||||
ccc
|
||||
ddd
|
||||
END
|
||||
}
|
||||
|
||||
If the statements include a dictionary, its closing bracket must not be
|
||||
written at the start of a line. Otherwise, it would be parsed as the end of
|
||||
the block. This does not work: >
|
||||
|
@ -2088,6 +2088,17 @@ skiptowhite(char_u *p)
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* skiptowhite: skip over text until ' ' or '\t' or newline or NUL.
|
||||
*/
|
||||
char_u *
|
||||
skiptowhite_or_nl(char_u *p)
|
||||
{
|
||||
while (*p != ' ' && *p != '\t' && *p != NL && *p != NUL)
|
||||
++p;
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* skiptowhite_esc: Like skiptowhite(), but also skip escaped chars
|
||||
*/
|
||||
|
@ -779,8 +779,10 @@ heredoc_get(exarg_T *eap, char_u *cmd, int script_get, int vim9compile)
|
||||
int eval_failed = FALSE;
|
||||
cctx_T *cctx = vim9compile ? eap->cookie : NULL;
|
||||
int count = 0;
|
||||
int heredoc_in_string = FALSE;
|
||||
char_u *line_arg = NULL;
|
||||
|
||||
if (eap->ea_getline == NULL)
|
||||
if (eap->ea_getline == NULL && vim_strchr(cmd, '\n') == NULL)
|
||||
{
|
||||
emsg(_(e_cannot_use_heredoc_here));
|
||||
return NULL;
|
||||
@ -824,8 +826,14 @@ heredoc_get(exarg_T *eap, char_u *cmd, int script_get, int vim9compile)
|
||||
if (*cmd != NUL && *cmd != comment_char)
|
||||
{
|
||||
marker = skipwhite(cmd);
|
||||
p = skiptowhite(marker);
|
||||
if (*skipwhite(p) != NUL && *skipwhite(p) != comment_char)
|
||||
p = skiptowhite_or_nl(marker);
|
||||
if (*p == NL)
|
||||
{
|
||||
// heredoc in a string
|
||||
line_arg = p + 1;
|
||||
heredoc_in_string = TRUE;
|
||||
}
|
||||
else if (*skipwhite(p) != NUL && *skipwhite(p) != comment_char)
|
||||
{
|
||||
semsg(_(e_trailing_characters_str), p);
|
||||
return NULL;
|
||||
@ -859,12 +867,38 @@ heredoc_get(exarg_T *eap, char_u *cmd, int script_get, int vim9compile)
|
||||
int mi = 0;
|
||||
int ti = 0;
|
||||
|
||||
vim_free(theline);
|
||||
theline = eap->ea_getline(NUL, eap->cookie, 0, FALSE);
|
||||
if (theline == NULL)
|
||||
if (heredoc_in_string)
|
||||
{
|
||||
semsg(_(e_missing_end_marker_str), marker);
|
||||
break;
|
||||
char_u *next_line;
|
||||
|
||||
// heredoc in a string separated by newlines. Get the next line
|
||||
// from the string.
|
||||
|
||||
if (*line_arg == NUL)
|
||||
{
|
||||
semsg(_(e_missing_end_marker_str), marker);
|
||||
break;
|
||||
}
|
||||
|
||||
theline = line_arg;
|
||||
next_line = vim_strchr(theline, '\n');
|
||||
if (next_line == NULL)
|
||||
line_arg += STRLEN(line_arg);
|
||||
else
|
||||
{
|
||||
*next_line = NUL;
|
||||
line_arg = next_line + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vim_free(theline);
|
||||
theline = eap->ea_getline(NUL, eap->cookie, 0, FALSE);
|
||||
if (theline == NULL)
|
||||
{
|
||||
semsg(_(e_missing_end_marker_str), marker);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// with "trim": skip the indent matching the :let line to find the
|
||||
@ -911,6 +945,8 @@ heredoc_get(exarg_T *eap, char_u *cmd, int script_get, int vim9compile)
|
||||
}
|
||||
else
|
||||
{
|
||||
int free_str = FALSE;
|
||||
|
||||
if (evalstr && !eap->skip)
|
||||
{
|
||||
str = eval_all_expr_in_str(str);
|
||||
@ -920,15 +956,20 @@ heredoc_get(exarg_T *eap, char_u *cmd, int script_get, int vim9compile)
|
||||
eval_failed = TRUE;
|
||||
continue;
|
||||
}
|
||||
vim_free(theline);
|
||||
theline = str;
|
||||
free_str = TRUE;
|
||||
}
|
||||
|
||||
if (list_append_string(l, str, -1) == FAIL)
|
||||
break;
|
||||
if (free_str)
|
||||
vim_free(str);
|
||||
}
|
||||
}
|
||||
vim_free(theline);
|
||||
if (heredoc_in_string)
|
||||
// Next command follows the heredoc in the string.
|
||||
eap->nextcmd = line_arg;
|
||||
else
|
||||
vim_free(theline);
|
||||
vim_free(text_indent);
|
||||
|
||||
if (vim9compile && cctx->ctx_skip != SKIP_YES && !eval_failed)
|
||||
|
@ -61,6 +61,7 @@ int vim_isalpha(int c);
|
||||
int vim_toupper(int c);
|
||||
int vim_tolower(int c);
|
||||
char_u *skiptowhite(char_u *p);
|
||||
char_u *skiptowhite_or_nl(char_u *p);
|
||||
char_u *skiptowhite_esc(char_u *p);
|
||||
long getdigits(char_u **pp);
|
||||
long getdigits_quoted(char_u **pp);
|
||||
|
@ -715,6 +715,20 @@ END
|
||||
LINES
|
||||
call v9.CheckScriptFailure(lines, 'E15:')
|
||||
|
||||
" Test for using heredoc in a single string using execute()
|
||||
call assert_equal(["['one', 'two']"],
|
||||
\ execute("let x =<< trim END\n one\n two\nEND\necho x")->split("\n"))
|
||||
call assert_equal(["[' one', ' two']"],
|
||||
\ execute("let x =<< END\n one\n two\nEND\necho x")->split("\n"))
|
||||
let cmd = 'execute("let x =<< END\n one\n two\necho x")'
|
||||
call assert_fails(cmd, "E990: Missing end marker 'END'")
|
||||
let cmd = 'execute("let x =<<\n one\n two\necho x")'
|
||||
call assert_fails(cmd, "E990: Missing end marker ''")
|
||||
let cmd = 'execute("let x =<< trim\n one\n two\necho x")'
|
||||
call assert_fails(cmd, "E221: Marker cannot start with lower case letter")
|
||||
let cmd = 'execute("let x =<< eval END\n one\n two{y}\nEND\necho x")'
|
||||
call assert_fails(cmd, 'E121: Undefined variable: y')
|
||||
|
||||
" skipped heredoc
|
||||
if 0
|
||||
let msg =<< trim eval END
|
||||
|
@ -458,7 +458,7 @@ func s:InvokeSomeCommand()
|
||||
SomeCommand
|
||||
endfunc
|
||||
|
||||
def Test_autocommand_block()
|
||||
def Test_command_block()
|
||||
com SomeCommand {
|
||||
g:someVar = 'some'
|
||||
}
|
||||
@ -469,7 +469,105 @@ def Test_autocommand_block()
|
||||
unlet g:someVar
|
||||
enddef
|
||||
|
||||
def Test_command_block()
|
||||
" Test for using heredoc in a :command command block
|
||||
def Test_command_block_heredoc()
|
||||
var lines =<< trim CODE
|
||||
vim9script
|
||||
com SomeCommand {
|
||||
g:someVar =<< trim END
|
||||
aaa
|
||||
bbb
|
||||
END
|
||||
}
|
||||
SomeCommand
|
||||
assert_equal(['aaa', 'bbb'], g:someVar)
|
||||
def Foo()
|
||||
g:someVar = []
|
||||
SomeCommand
|
||||
assert_equal(['aaa', 'bbb'], g:someVar)
|
||||
enddef
|
||||
Foo()
|
||||
delcommand SomeCommand
|
||||
unlet g:someVar
|
||||
CODE
|
||||
v9.CheckSourceSuccess( lines)
|
||||
|
||||
# Execute a command with heredoc in a block
|
||||
lines =<< trim CODE
|
||||
vim9script
|
||||
com SomeCommand {
|
||||
g:someVar =<< trim END
|
||||
aaa
|
||||
bbb
|
||||
END
|
||||
}
|
||||
execute('SomeCommand')
|
||||
assert_equal(['aaa', 'bbb'], g:someVar)
|
||||
delcommand SomeCommand
|
||||
unlet g:someVar
|
||||
CODE
|
||||
v9.CheckSourceSuccess(lines)
|
||||
|
||||
# heredoc evaluation
|
||||
lines =<< trim CODE
|
||||
vim9script
|
||||
com SomeCommand {
|
||||
var suffix = '---'
|
||||
g:someVar =<< trim eval END
|
||||
ccc{suffix}
|
||||
ddd
|
||||
END
|
||||
}
|
||||
SomeCommand
|
||||
assert_equal(['ccc---', 'ddd'], g:someVar)
|
||||
def Foo()
|
||||
g:someVar = []
|
||||
SomeCommand
|
||||
assert_equal(['ccc---', 'ddd'], g:someVar)
|
||||
enddef
|
||||
Foo()
|
||||
delcommand SomeCommand
|
||||
unlet g:someVar
|
||||
CODE
|
||||
v9.CheckSourceSuccess(lines)
|
||||
|
||||
# command following heredoc
|
||||
lines =<< trim CODE
|
||||
vim9script
|
||||
com SomeCommand {
|
||||
var l =<< trim END
|
||||
eee
|
||||
fff
|
||||
END
|
||||
g:someVar = l
|
||||
}
|
||||
SomeCommand
|
||||
assert_equal(['eee', 'fff'], g:someVar)
|
||||
delcommand SomeCommand
|
||||
unlet g:someVar
|
||||
CODE
|
||||
v9.CheckSourceSuccess(lines)
|
||||
|
||||
# Error in heredoc
|
||||
lines =<< trim CODE
|
||||
vim9script
|
||||
com SomeCommand {
|
||||
g:someVar =<< trim END
|
||||
eee
|
||||
fff
|
||||
}
|
||||
try
|
||||
SomeCommand
|
||||
catch
|
||||
assert_match("E990: Missing end marker 'END'", v:exception)
|
||||
endtry
|
||||
delcommand SomeCommand
|
||||
unlet g:someVar
|
||||
CODE
|
||||
v9.CheckSourceSuccess(lines)
|
||||
enddef
|
||||
|
||||
def Test_autocommand_block()
|
||||
au BufNew *.xml {
|
||||
g:otherVar = 'other'
|
||||
}
|
||||
|
@ -704,6 +704,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
312,
|
||||
/**/
|
||||
311,
|
||||
/**/
|
||||
|
Loading…
x
Reference in New Issue
Block a user