vim-patch:8.1.1585: :let-heredoc does not trim enough

Problem:    :let-heredoc does not trim enough.
Solution:   Trim indent from the contents based on the indent of the first
            line.  Use let-heredoc in more tests.
e7eb92708e
This commit is contained in:
Jurica Bradaric
2019-10-12 09:48:48 +02:00
parent 9af0fe529d
commit 6c012b0624
11 changed files with 461 additions and 413 deletions

View File

@@ -9793,13 +9793,24 @@ text...
If {marker} is not supplied, then "." is used as the If {marker} is not supplied, then "." is used as the
default marker. default marker.
Any white space characters in the lines of text are Without "trim" any white space characters in the lines
preserved. If "trim" is specified before {marker}, of text are preserved. If "trim" is specified before
then all the leading indentation exactly matching the {marker}, then indentation is stripped so you can do: >
leading indentation before `let` is stripped from the let text =<< trim END
input lines and the line containing {marker}. Note if ok
that the difference between space and tab matters echo 'done'
here. 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. If {var-name} didn't exist yet, it is created.
Cannot be followed by another command, but can be 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 *marker;
char_u *p; 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) { if (eap->getline == NULL) {
EMSG(_("E991: cannot use =<< here")); EMSG(_("E991: cannot use =<< here"));
@@ -1534,14 +1536,16 @@ heredoc_get(exarg_T *eap, char_u *cmd)
&& (cmd[4] == NUL || ascii_iswhite(cmd[4]))) { && (cmd[4] == NUL || ascii_iswhite(cmd[4]))) {
cmd = skipwhite(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 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; p = *eap->cmdlinep;
while (ascii_iswhite(*p)) { while (ascii_iswhite(*p)) {
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. Default marker is "."
@@ -1559,28 +1563,48 @@ heredoc_get(exarg_T *eap, char_u *cmd)
list_T *l = tv_list_alloc(0); list_T *l = tv_list_alloc(0);
for (;;) { for (;;) {
int i = 0; int mi = 0;
int ti = 0;
char_u *theline = eap->getline(NUL, eap->cookie, 0, false); 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) { if (theline == NULL) {
EMSG2(_("E990: Missing end marker '%s'"), marker); EMSG2(_("E990: Missing end marker '%s'"), marker);
break; 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); xfree(theline);
break; 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(theline);
} }
xfree(text_indent);
return l; return l;
} }

View File

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

View File

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

View File

@@ -199,6 +199,14 @@ END
END END
call assert_equal(['Line1', ' Line2', "\tLine3", ' END'], var1) call assert_equal(['Line1', ' Line2', "\tLine3", ' END'], var1)
let var1 =<< trim !!!
Line1
line2
Line3
!!!
!!!
call assert_equal(['Line1', ' line2', "\tLine3", '!!!',], var1)
let var1 =<< trim let var1 =<< trim
Line1 Line1
. .

View File

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

View File

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