Merge #11211 from jbradaric/vim-8.1.1585

vim-patch:8.1.{1585,1625,1723,1729}
This commit is contained in:
Justin M. Keyes 2019-10-19 15:23:14 -07:00 committed by GitHub
commit 06a6828f01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 631 additions and 458 deletions

View File

@ -9779,27 +9779,37 @@ This does NOT work: >
Like above, but append/add/subtract the value for each
|List| item.
*:let=<<* *:let-heredoc* *E990* *E991*
*:let=<<* *:let-heredoc*
*E990* *E991* *E172* *E221*
: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.
{marker} cannot start with a lower case character.
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.
Without "trim" any white space characters in the lines
of text are preserved. If "trim" is specified before
{marker}, then indentation is stripped so you can do: >
let text =<< trim END
if ok
echo 'done'
endif
END
< Results in: ["if ok", " echo 'done'", "endif"]
The marker must line up with "let" and the indentation
of the first line is removed from all the text lines.
Specifically: all the leading indentation exactly
matching the leading indentation of the first
non-empty text line is stripped from the input lines.
All leading indentation exactly matching the leading
indentation before `let` is stripped from 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

View File

@ -1521,7 +1521,9 @@ heredoc_get(exarg_T *eap, char_u *cmd)
{
char_u *marker;
char_u *p;
int indent_len = 0;
int marker_indent_len = 0;
int text_indent_len = 0;
char_u *text_indent = NULL;
if (eap->getline == NULL) {
EMSG(_("E991: cannot use =<< here"));
@ -1534,17 +1536,19 @@ heredoc_get(exarg_T *eap, char_u *cmd)
&& (cmd[4] == NUL || ascii_iswhite(cmd[4]))) {
cmd = skipwhite(cmd + 4);
// Trim the indentation from all the lines in the here document
// 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.
// the first line after the :let command line. To find the end marker
// the indent of the :let command line is trimmed.
p = *eap->cmdlinep;
while (ascii_iswhite(*p)) {
p++;
indent_len++;
marker_indent_len++;
}
text_indent_len = -1;
}
// The marker is the next word. Default marker is "."
// The marker is the next word.
if (*cmd != NUL && *cmd != '"') {
marker = skipwhite(cmd);
p = skiptowhite(marker);
@ -1553,34 +1557,59 @@ heredoc_get(exarg_T *eap, char_u *cmd)
return NULL;
}
*p = NUL;
if (islower(*marker)) {
EMSG(_("E221: Marker cannot start with lower case letter"));
return NULL;
}
} else {
marker = (char_u *)".";
EMSG(_("E172: Missing marker"));
return NULL;
}
list_T *l = tv_list_alloc(0);
for (;;) {
int i = 0;
int mi = 0;
int ti = 0;
char_u *theline = eap->getline(NUL, eap->cookie, 0, false);
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) {
// with "trim": skip the indent matching the :let line to find the
// marker
if (marker_indent_len > 0
&& STRNCMP(theline, *eap->cmdlinep, marker_indent_len) == 0) {
mi = marker_indent_len;
}
if (STRCMP(marker, theline + mi) == 0) {
xfree(theline);
break;
}
if (text_indent_len == -1 && *theline != NUL) {
// set the text indent from the first line.
p = theline;
text_indent_len = 0;
while (ascii_iswhite(*p)) {
p++;
text_indent_len++;
}
text_indent = vim_strnsave(theline, text_indent_len);
}
// with "trim": skip the indent matching the first line
if (text_indent != NULL) {
for (ti = 0; ti < text_indent_len; ti++) {
if (theline[ti] != text_indent[ti]) {
break;
}
}
}
tv_list_append_string(l, (char *)(theline + i), -1);
tv_list_append_string(l, (char *)(theline + ti), -1);
xfree(theline);
}
xfree(text_indent);
return l;
}
@ -21268,8 +21297,6 @@ void ex_function(exarg_T *eap)
bool overwrite = false;
int indent;
int nesting;
char_u *skip_until = NULL;
char_u *trimmed = NULL;
dictitem_T *v;
funcdict_T fudi;
static int func_nr = 0; /* number for nameless function */
@ -21277,7 +21304,11 @@ void ex_function(exarg_T *eap)
hashtab_T *ht;
int todo;
hashitem_T *hi;
int sourcing_lnum_off;
linenr_T sourcing_lnum_off;
linenr_T sourcing_lnum_top;
bool is_heredoc = false;
char_u *skip_until = NULL;
char_u *heredoc_trimmed = NULL;
bool show_block = false;
bool do_concat = true;
@ -21526,15 +21557,17 @@ void ex_function(exarg_T *eap)
cmdline_row = msg_row;
}
// Save the starting line number.
sourcing_lnum_top = sourcing_lnum;
indent = 2;
nesting = 0;
for (;; ) {
if (KeyTyped) {
msg_scroll = TRUE;
saved_wait_return = FALSE;
msg_scroll = true;
saved_wait_return = false;
}
need_wait_return = FALSE;
sourcing_lnum_off = sourcing_lnum;
need_wait_return = false;
if (line_arg != NULL) {
/* Use eap->arg, split up in parts by line breaks. */
@ -21567,21 +21600,36 @@ void ex_function(exarg_T *eap)
ui_ext_cmdline_block_append((size_t)indent, (const char *)theline);
}
/* Detect line continuation: sourcing_lnum increased more than one. */
if (sourcing_lnum > sourcing_lnum_off + 1)
sourcing_lnum_off = sourcing_lnum - sourcing_lnum_off - 1;
else
// Detect line continuation: sourcing_lnum increased more than one.
sourcing_lnum_off = get_sourced_lnum(eap->getline, eap->cookie);
if (sourcing_lnum < sourcing_lnum_off) {
sourcing_lnum_off -= sourcing_lnum;
} else {
sourcing_lnum_off = 0;
}
if (skip_until != NULL) {
// Between ":append" and "." and between ":python <<EOF" and "EOF"
// don't check for ":endfunc".
if (trimmed == NULL || STRNCMP(theline, trimmed, STRLEN(trimmed)) == 0) {
p = trimmed == NULL ? theline : theline + STRLEN(trimmed);
// Don't check for ":endfunc" between
// * ":append" and "."
// * ":python <<EOF" and "EOF"
// * ":let {var-name} =<< [trim] {marker}" and "{marker}"
if (heredoc_trimmed == NULL
|| (is_heredoc && skipwhite(theline) == theline)
|| STRNCMP(theline, heredoc_trimmed,
STRLEN(heredoc_trimmed)) == 0) {
if (heredoc_trimmed == NULL) {
p = theline;
} else if (is_heredoc) {
p = skipwhite(theline) == theline
? theline : theline + STRLEN(heredoc_trimmed);
} else {
p = theline + STRLEN(heredoc_trimmed);
}
if (STRCMP(p, skip_until) == 0) {
XFREE_CLEAR(skip_until);
XFREE_CLEAR(trimmed);
XFREE_CLEAR(heredoc_trimmed);
do_concat = true;
is_heredoc = false;
}
}
} else {
@ -21689,19 +21737,16 @@ void ex_function(exarg_T *eap)
&& ((p[0] == 'l' && p[1] == 'e'
&& (!ASCII_ISALNUM(p[2])
|| (p[2] == 't' && !ASCII_ISALNUM(p[3])))))) {
// ":let v =<<" continues until a dot
p = skipwhite(arg + 3);
if (STRNCMP(p, "trim", 4) == 0) {
// Ignore leading white space.
p = skipwhite(p + 4);
trimmed = vim_strnsave(theline, (int)(skipwhite(theline) - theline));
heredoc_trimmed = vim_strnsave(theline,
(int)(skipwhite(theline) - theline));
}
if (*p == NUL) {
skip_until = vim_strsave((char_u *)".");
} else {
skip_until = vim_strnsave(p, (int)(skiptowhite(p) - p));
}
do_concat = false;
is_heredoc = true;
}
}
@ -21872,7 +21917,8 @@ void ex_function(exarg_T *eap)
fp->uf_flags = flags;
fp->uf_calls = 0;
fp->uf_script_ctx = current_sctx;
fp->uf_script_ctx.sc_lnum += sourcing_lnum - newlines.ga_len - 1;
fp->uf_script_ctx.sc_lnum += sourcing_lnum_top;
goto ret_free;
erret:

View File

@ -97,6 +97,7 @@ typedef struct sn_prl_S {
struct source_cookie {
FILE *fp; ///< opened file for sourcing
char_u *nextline; ///< if not NULL: line that was read ahead
linenr_T sourcing_lnum; ///< line number of the source file
int finished; ///< ":finish" used
#if defined(USE_CRNL)
int fileformat; ///< EOL_UNKNOWN, EOL_UNIX or EOL_DOS
@ -3124,6 +3125,7 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
#endif
cookie.nextline = NULL;
cookie.sourcing_lnum = 0;
cookie.finished = false;
// Check if this script has a breakpoint.
@ -3375,6 +3377,13 @@ void free_scriptnames(void)
}
# endif
linenr_T get_sourced_lnum(LineGetter fgetline, void *cookie)
{
return fgetline == getsourceline
? ((struct source_cookie *)cookie)->sourcing_lnum
: sourcing_lnum;
}
/// Get one full line from a sourced file.
/// Called by do_cmdline() when it's called from do_source().
@ -3395,6 +3404,8 @@ char_u *getsourceline(int c, void *cookie, int indent, bool do_concat)
if (do_profiling == PROF_YES) {
script_line_end();
}
// Set the current sourcing line number.
sourcing_lnum = sp->sourcing_lnum + 1;
// Get current line. If there is a read-ahead line, use it, otherwise get
// one now.
if (sp->finished) {
@ -3404,7 +3415,7 @@ char_u *getsourceline(int c, void *cookie, int indent, bool do_concat)
} else {
line = sp->nextline;
sp->nextline = NULL;
sourcing_lnum++;
sp->sourcing_lnum++;
}
if (line != NULL && do_profiling == PROF_YES) {
script_line_start();
@ -3414,7 +3425,7 @@ char_u *getsourceline(int c, void *cookie, int indent, bool do_concat)
// contain the 'C' flag.
if (line != NULL && do_concat && (vim_strchr(p_cpo, CPO_CONCAT) == NULL)) {
// compensate for the one line read-ahead
sourcing_lnum--;
sp->sourcing_lnum--;
// Get the next line and concatenate it when it starts with a
// backslash. We always need to read the next line, keep it in
@ -3492,7 +3503,7 @@ static char_u *get_one_sourceline(struct source_cookie *sp)
ga_init(&ga, 1, 250);
// Loop until there is a finished line (or end-of-file).
sourcing_lnum++;
sp->sourcing_lnum++;
for (;; ) {
// make room to read at least 120 (more) characters
ga_grow(&ga, 120);
@ -3559,7 +3570,7 @@ retry:
// len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo
for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--) {}
if ((len & 1) != (c & 1)) { // escaped NL, read more
sourcing_lnum++;
sp->sourcing_lnum++;
continue;
}

View File

@ -96,24 +96,24 @@ func Test_cindent_expr()
call setline(1, testinput)
call cursor(1, 1)
call feedkeys("^\<c-v>j$A;\<esc>", 'tnix')
let expected =<< trim [CODE]
let expected =<< [CODE]
var_a = something();
b = something();
[CODE]
b = something();
[CODE]
call assert_equal(expected, getline(1, '$'))
%d
let testinput =<< trim [CODE]
let testinput =<< [CODE]
var_a = something()
b = something()
[CODE]
[CODE]
call setline(1, testinput)
call cursor(1, 1)
call feedkeys("^\<c-v>j$A;\<esc>", 'tnix')
let expected =<< trim [CODE]
let expected =<< [CODE]
var_a = something();
b = something()
[CODE]
[CODE]
call assert_equal(expected, getline(1, '$'))
bw!
endfunc

View File

@ -26,27 +26,29 @@ func Test_Debugger()
endif
" Create a Vim script with some functions
call writefile([
\ 'func Foo()',
\ ' let var1 = 1',
\ ' let var2 = Bar(var1) + 9',
\ ' return var2',
\ 'endfunc',
\ 'func Bar(var)',
\ ' let var1 = 2 + a:var',
\ ' let var2 = Bazz(var1) + 4',
\ ' return var2',
\ 'endfunc',
\ 'func Bazz(var)',
\ ' try',
\ ' let var1 = 3 + a:var',
\ ' let var3 = "another var"',
\ ' let var3 = "value2"',
\ ' catch',
\ ' let var4 = "exception"',
\ ' endtry',
\ ' return var1',
\ 'endfunc'], 'Xtest.vim')
let lines =<< trim END
func Foo()
let var1 = 1
let var2 = Bar(var1) + 9
return var2
endfunc
func Bar(var)
let var1 = 2 + a:var
let var2 = Bazz(var1) + 4
return var2
endfunc
func Bazz(var)
try
let var1 = 3 + a:var
let var3 = "another var"
let var3 = "value2"
catch
let var4 = "exception"
endtry
return var1
endfunc
END
call writefile(lines, 'Xtest.vim')
" Start Vim in a terminal
let buf = RunVimInTerminal('-S Xtest.vim', {})
@ -294,11 +296,13 @@ func Test_Debugger()
" Tests for :breakadd file and :breakadd here
" Breakpoints should be set before sourcing the file
call writefile([
\ 'let var1 = 10',
\ 'let var2 = 20',
\ 'let var3 = 30',
\ 'let var4 = 40'], 'Xtest.vim')
let lines =<< trim END
let var1 = 10
let var2 = 20
let var3 = 30
let var4 = 40
END
call writefile(lines, 'Xtest.vim')
" Start Vim in a terminal
let buf = RunVimInTerminal('Xtest.vim', {})

View File

@ -153,14 +153,37 @@ func Test_let_heredoc_fails()
call assert_fails('source XheredocFail', 'E126:')
call delete('XheredocFail')
let text =<< trim END
let text =<< trim CodeEnd
func MissingEnd()
let v =<< END
endfunc
END
CodeEnd
call writefile(text, 'XheredocWrong')
call assert_fails('source XheredocWrong', 'E126:')
call delete('XheredocWrong')
let text =<< trim TEXTend
let v =<< " comment
TEXTend
call writefile(text, 'XheredocNoMarker')
call assert_fails('source XheredocNoMarker', 'E172:')
call delete('XheredocNoMarker')
let text =<< trim TEXTend
let v =<< text
TEXTend
call writefile(text, 'XheredocBadMarker')
call assert_fails('source XheredocBadMarker', 'E221:')
call delete('XheredocBadMarker')
endfunc
func Test_let_heredoc_trim_no_indent_marker()
let text =<< trim END
Text
with
indent
END
call assert_equal(['Text', 'with', 'indent'], text)
endfunc
" Test for the setting a variable using the heredoc syntax
@ -173,9 +196,9 @@ END
call assert_equal(["Some sample text", "\tText with indent", " !@#$%^&*()-+_={}|[]\\~`:\";'<>?,./"], var1)
let var2 =<<
let var2 =<< XXX
Editor
.
XXX
call assert_equal(['Editor'], var2)
let var3 =<<END
@ -199,10 +222,18 @@ END
END
call assert_equal(['Line1', ' Line2', "\tLine3", ' END'], var1)
let var1 =<< trim
let var1 =<< trim !!!
Line1
.
call assert_equal([' Line1'], var1)
line2
Line3
!!!
!!!
call assert_equal(['Line1', ' line2', "\tLine3", '!!!',], var1)
let var1 =<< trim XX
Line1
XX
call assert_equal(['Line1'], var1)
" ignore "endfunc"
let var1 =<< END
@ -233,16 +264,16 @@ END
call assert_equal(['something', 'python << xx'], var1)
" ignore "append"
let var1 =<<
let var1 =<< E
something
app
.
E
call assert_equal(['something', 'app'], var1)
" ignore "append" with trim
let var1 =<< trim
let var1 =<< trim END
something
app
.
END
call assert_equal(['something', 'app'], var1)
endfunc

View File

@ -737,11 +737,12 @@ func Test_popup_position()
if !CanRunVimInTerminal()
return
endif
call writefile([
\ '123456789_123456789_123456789_a',
\ '123456789_123456789_123456789_b',
\ ' 123',
\ ], 'Xtest')
let lines =<< trim END
123456789_123456789_123456789_a
123456789_123456789_123456789_b
123
END
call writefile(lines, 'Xtest')
let buf = RunVimInTerminal('Xtest', {})
call term_sendkeys(buf, ":vsplit\<CR>")

View File

@ -814,7 +814,7 @@ func Test_efm1()
call writefile(l, 'Xerrorfile1')
call writefile(l[:-2], 'Xerrorfile2')
let m =<< trim [DATA]
let m =<< [DATA]
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 2
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 3
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 4
@ -836,7 +836,7 @@ func Test_efm1()
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 20
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 21
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 22
[DATA]
[DATA]
call writefile(m, 'Xtestfile')
let save_efm = &efm
@ -1066,7 +1066,7 @@ func Test_efm2()
NEW compiler v1.1
(2,2) warning: variable 'x' not defined
(67,3) warning: 's' already defined
-
--
[DATA]
set efm=%+P[%f]%r,(%l\\,%c)%*[\ ]%t%*[^:]:\ %m,%+Q--%r
" To exercise the push/pop file functionality in quickfix, the test files

View File

@ -1409,6 +1409,76 @@ func Test_compound_assignment_operators()
let @/ = ''
endfunc
func Test_function_defined_line()
if has('gui_running')
" Can't catch the output of gvim.
return
endif
let lines =<< trim [CODE]
" F1
func F1()
" F2
func F2()
"
"
"
return
endfunc
" F3
execute "func F3()\n\n\n\nreturn\nendfunc"
" F4
execute "func F4()\n
\\n
\\n
\\n
\return\n
\endfunc"
endfunc
" F5
execute "func F5()\n\n\n\nreturn\nendfunc"
" F6
execute "func F6()\n
\\n
\\n
\\n
\return\n
\endfunc"
call F1()
verbose func F1
verbose func F2
verbose func F3
verbose func F4
verbose func F5
verbose func F6
qall!
[CODE]
call writefile(lines, 'Xtest.vim')
let res = system(v:progpath .. ' --clean -es -X -S Xtest.vim')
call assert_equal(0, v:shell_error)
let m = matchstr(res, 'function F1()[^[:print:]]*[[:print:]]*')
call assert_match(' line 2$', m)
let m = matchstr(res, 'function F2()[^[:print:]]*[[:print:]]*')
call assert_match(' line 4$', m)
let m = matchstr(res, 'function F3()[^[:print:]]*[[:print:]]*')
call assert_match(' line 11$', m)
let m = matchstr(res, 'function F4()[^[:print:]]*[[:print:]]*')
call assert_match(' line 13$', m)
let m = matchstr(res, 'function F5()[^[:print:]]*[[:print:]]*')
call assert_match(' line 21$', m)
let m = matchstr(res, 'function F6()[^[:print:]]*[[:print:]]*')
call assert_match(' line 23$', m)
call delete('Xtest.vim')
endfunc
"-------------------------------------------------------------------------------
" Modelines {{{1
" vim: ts=8 sw=4 tw=80 fdm=marker