vim-patch:8.1.1354: getting a list of text lines is clumsy
Problem: Getting a list of text lines is clumsy.
Solution: Add the =<< assignment. (Yegappan Lakshmanan, closes vim/vim#4386)
f5842c5a53
This commit is contained in:
parent
dfed0e60d7
commit
b1ada8ec21
|
@ -9779,6 +9779,44 @@ This does NOT work: >
|
|||
Like above, but append/add/subtract the value for each
|
||||
|List| item.
|
||||
|
||||
*:let=<<* *:let-heredoc* *E990* *E991*
|
||||
:let {var-name} =<< [trim] {marker}
|
||||
text...
|
||||
text...
|
||||
{marker}
|
||||
Set internal variable {var-name} to a List containing
|
||||
the lines of text bounded by the string {marker}.
|
||||
{marker} must not contain white space.
|
||||
The last line should end only with the {marker} string
|
||||
without any other character. Watch out for white
|
||||
space after {marker}!
|
||||
If {marker} is not supplied, then "." is used as the
|
||||
default marker.
|
||||
|
||||
Any white space characters in the lines of text are
|
||||
preserved. If "trim" is specified before {marker},
|
||||
then all the leading indentation exactly matching the
|
||||
leading indentation before `let` is stripped from the
|
||||
input lines and the line containing {marker}. Note
|
||||
that the difference between space and tab matters
|
||||
here.
|
||||
|
||||
If {var-name} didn't exist yet, it is created.
|
||||
Cannot be followed by another command, but can be
|
||||
followed by a comment.
|
||||
|
||||
Examples: >
|
||||
let var1 =<< END
|
||||
Sample text 1
|
||||
Sample text 2
|
||||
Sample text 3
|
||||
END
|
||||
|
||||
let data =<< trim DATA
|
||||
1 2 3 4
|
||||
5 6 7 8
|
||||
DATA
|
||||
<
|
||||
*E121*
|
||||
:let {var-name} .. List the value of variable {var-name}. Multiple
|
||||
variable names may be given. Special names recognized
|
||||
|
|
|
@ -1504,6 +1504,87 @@ void ex_const(exarg_T *eap)
|
|||
ex_let_const(eap, true);
|
||||
}
|
||||
|
||||
// Get a list of lines from a HERE document. The here document is a list of
|
||||
// lines surrounded by a marker.
|
||||
// cmd << {marker}
|
||||
// {line1}
|
||||
// {line2}
|
||||
// ....
|
||||
// {marker}
|
||||
//
|
||||
// The {marker} is a string. If the optional 'trim' word is supplied before the
|
||||
// marker, then the leading indentation before the lines (matching the
|
||||
// indentation in the 'cmd' line) is stripped.
|
||||
// Returns a List with {lines} or NULL.
|
||||
static list_T *
|
||||
heredoc_get(exarg_T *eap, char_u *cmd)
|
||||
{
|
||||
char_u *marker;
|
||||
char_u *p;
|
||||
int indent_len = 0;
|
||||
|
||||
if (eap->getline == NULL) {
|
||||
EMSG(_("E991: cannot use =<< here"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Check for the optional 'trim' word before the marker
|
||||
cmd = skipwhite(cmd);
|
||||
if (STRNCMP(cmd, "trim", 4) == 0
|
||||
&& (cmd[4] == NUL || ascii_iswhite(cmd[4]))) {
|
||||
cmd = skipwhite(cmd + 4);
|
||||
|
||||
// Trim the indentation from all the lines in the here document
|
||||
// The amount of indentation trimmed is the same as the indentation of
|
||||
// the :let command line.
|
||||
p = *eap->cmdlinep;
|
||||
while (ascii_iswhite(*p)) {
|
||||
p++;
|
||||
indent_len++;
|
||||
}
|
||||
}
|
||||
|
||||
// The marker is the next word. Default marker is "."
|
||||
if (*cmd != NUL && *cmd != '"') {
|
||||
marker = skipwhite(cmd);
|
||||
p = skiptowhite(marker);
|
||||
if (*skipwhite(p) != NUL && *skipwhite(p) != '"') {
|
||||
EMSG(_(e_trailing));
|
||||
return NULL;
|
||||
}
|
||||
*p = NUL;
|
||||
} else {
|
||||
marker = (char_u *)".";
|
||||
}
|
||||
|
||||
list_T *l = tv_list_alloc(0);
|
||||
for (;;) {
|
||||
int i = 0;
|
||||
|
||||
char_u *theline = eap->getline(NUL, eap->cookie, 0);
|
||||
if (theline != NULL && indent_len > 0) {
|
||||
// trim the indent matching the first line
|
||||
if (STRNCMP(theline, *eap->cmdlinep, indent_len) == 0) {
|
||||
i = indent_len;
|
||||
}
|
||||
}
|
||||
|
||||
if (theline == NULL) {
|
||||
EMSG2(_("E990: Missing end marker '%s'"), marker);
|
||||
break;
|
||||
}
|
||||
if (STRCMP(marker, theline + i) == 0) {
|
||||
xfree(theline);
|
||||
break;
|
||||
}
|
||||
|
||||
tv_list_append_string(l, (char *)(theline + i), -1);
|
||||
xfree(theline);
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
// ":let" list all variable values
|
||||
// ":let var1 var2" list variable values
|
||||
// ":let var = expr" assignment command.
|
||||
|
@ -1560,6 +1641,17 @@ static void ex_let_const(exarg_T *eap, const bool is_const)
|
|||
list_vim_vars(&first);
|
||||
}
|
||||
eap->nextcmd = check_nextcmd(arg);
|
||||
} else if (expr[0] == '=' && expr[1] == '<' && expr[2] == '<') {
|
||||
// HERE document
|
||||
list_T *l = heredoc_get(eap, expr + 3);
|
||||
if (l != NULL) {
|
||||
tv_list_set_ret(&rettv, l);
|
||||
op[0] = '=';
|
||||
op[1] = NUL;
|
||||
(void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count,
|
||||
is_const, op);
|
||||
tv_clear(&rettv);
|
||||
}
|
||||
} else {
|
||||
op[0] = '=';
|
||||
op[1] = NUL;
|
||||
|
|
|
@ -140,3 +140,58 @@ func Test_let_varg_fail()
|
|||
call assert_fails('call s:set_varg7(1)', 'E742:')
|
||||
call s:set_varg8([0])
|
||||
endfunction
|
||||
|
||||
|
||||
" Test for the setting a variable using the heredoc syntax
|
||||
func Test_let_heredoc()
|
||||
let var1 =<< END
|
||||
Some sample text
|
||||
Text with indent
|
||||
!@#$%^&*()-+_={}|[]\~`:";'<>?,./
|
||||
END
|
||||
|
||||
call assert_equal(["Some sample text", "\tText with indent", " !@#$%^&*()-+_={}|[]\\~`:\";'<>?,./"], var1)
|
||||
|
||||
let var2 =<<
|
||||
Editor
|
||||
.
|
||||
call assert_equal(['Editor'], var2)
|
||||
|
||||
let var3 =<<END
|
||||
END
|
||||
call assert_equal([], var3)
|
||||
|
||||
let var3 =<<END
|
||||
vim
|
||||
|
||||
end
|
||||
END
|
||||
END
|
||||
END
|
||||
call assert_equal(['vim', '', 'end', ' END', 'END '], var3)
|
||||
|
||||
let var1 =<< trim END
|
||||
Line1
|
||||
Line2
|
||||
Line3
|
||||
END
|
||||
END
|
||||
call assert_equal(['Line1', ' Line2', "\tLine3", ' END'], var1)
|
||||
|
||||
let var1 =<< trim
|
||||
Line1
|
||||
.
|
||||
call assert_equal([' Line1'], var1)
|
||||
|
||||
call assert_fails('let v =<< marker', 'E991:')
|
||||
call assert_fails('call WrongSyntax()', 'E488:')
|
||||
call assert_fails('call MissingEnd()', 'E990:')
|
||||
endfunc
|
||||
|
||||
func WrongSyntax()
|
||||
let fail =<< that there
|
||||
endfunc
|
||||
|
||||
func MissingEnd()
|
||||
let fail =<< END
|
||||
endfunc
|
||||
|
|
Loading…
Reference in New Issue