Skip to content

allow leading spaces for heredoc end marker #190

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions autoload/vimlparser.vim
Original file line number Diff line number Diff line change
Expand Up @@ -1509,13 +1509,15 @@ function! s:VimLParser.parse_cmd_call() abort
call self.add_node(node)
endfunction

function! s:VimLParser.parse_heredoc() abort
function! s:VimLParser.parse_heredoc(prefix) abort
let node = s:Node(s:NODE_HEREDOC)
let node.pos = self.ea.cmdpos
let node.op = ''
let node.rlist = []
let node.body = []

" allow prefix to precede heredoc end marker if true
let is_trim = s:FALSE
while s:TRUE
call self.reader.skip_white()
let pos = self.reader.getpos()
Expand All @@ -1531,6 +1533,9 @@ function! s:VimLParser.parse_heredoc() abort
let keynode.pos = pos
let keynode.value = key
call add(node.rlist, keynode)
if key ==# 'trim'
let is_trim = s:TRUE
endif
endif
endwhile
if node.op ==# ''
Expand All @@ -1543,7 +1548,7 @@ function! s:VimLParser.parse_heredoc() abort
endif
let pos = self.reader.getpos()
let line = self.reader.getn(-1)
if line ==# node.op
if line ==# node.op || is_trim && line ==# a:prefix . node.op
return node
endif
let linenode = s:Node(s:NODE_STRING)
Expand Down Expand Up @@ -1600,7 +1605,31 @@ function! s:VimLParser.parse_cmd_let() abort
call self.reader.getn(len(s2))
call self.reader.skip_white()
let node.op = s2
let node.right = self.parse_heredoc()

" compute allowed prefix for heredoc end marker (e.g. EOF)
let pos = self.reader.tell()
while self.reader.tell() > 0
if self.reader.peek() ==# '<EOL>'
call self.reader.seek_cur(1)
break
endif
call self.reader.seek_cur(-1)
endwhile
let prefix = ''
while s:TRUE
let c = self.reader.getn(1)
if c ==# ':'
" any presence of leading ':' disables prefix for heredoc end marker
let prefix = ''
break
elseif !s:iswhite(c)
break
endif
let prefix .= c
endwhile
call self.reader.seek_set(pos)

let node.right = self.parse_heredoc(prefix)
call self.add_node(node)
return
elseif s1 ==# '='
Expand Down
34 changes: 31 additions & 3 deletions js/vimlparser.js
Original file line number Diff line number Diff line change
Expand Up @@ -1805,12 +1805,14 @@ VimLParser.prototype.parse_cmd_call = function() {
this.add_node(node);
}

VimLParser.prototype.parse_heredoc = function() {
VimLParser.prototype.parse_heredoc = function(prefix) {
var node = Node(NODE_HEREDOC);
node.pos = this.ea.cmdpos;
node.op = "";
node.rlist = [];
node.body = [];
// allow prefix to precede heredoc end marker if true
var is_trim = FALSE;
while (TRUE) {
this.reader.skip_white();
var pos = this.reader.getpos();
Expand All @@ -1827,6 +1829,9 @@ VimLParser.prototype.parse_heredoc = function() {
keynode.pos = pos;
keynode.value = key;
viml_add(node.rlist, keynode);
if (key == "trim") {
var is_trim = TRUE;
}
}
}
if (node.op == "") {
Expand All @@ -1839,7 +1844,7 @@ VimLParser.prototype.parse_heredoc = function() {
}
var pos = this.reader.getpos();
var line = this.reader.getn(-1);
if (line == node.op) {
if (line == node.op || is_trim && line == prefix + node.op) {
return node;
}
var linenode = Node(NODE_STRING);
Expand Down Expand Up @@ -1894,7 +1899,30 @@ VimLParser.prototype.parse_cmd_let = function() {
this.reader.getn(viml_len(s2));
this.reader.skip_white();
node.op = s2;
node.right = this.parse_heredoc();
// compute allowed prefix for heredoc end marker (e.g. EOF)
var pos = this.reader.tell();
while (this.reader.tell() > 0) {
if (this.reader.peek() == "<EOL>") {
this.reader.seek_cur(1);
break;
}
this.reader.seek_cur(-1);
}
var prefix = "";
while (TRUE) {
var c = this.reader.getn(1);
if (c == ":") {
// any presence of leading ':' disables prefix for heredoc end marker
var prefix = "";
break;
}
else if (!iswhite(c)) {
break;
}
prefix += c;
}
this.reader.seek_set(pos);
node.right = this.parse_heredoc(prefix);
this.add_node(node);
return;
}
Expand Down
28 changes: 25 additions & 3 deletions py/vimlparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -1483,12 +1483,14 @@ def parse_cmd_call(self):
raise VimLParserException(Err("Not an function call", node.left.pos))
self.add_node(node)

def parse_heredoc(self):
def parse_heredoc(self, prefix):
node = Node(NODE_HEREDOC)
node.pos = self.ea.cmdpos
node.op = ""
node.rlist = []
node.body = []
# allow prefix to precede heredoc end marker if true
is_trim = FALSE
while TRUE:
self.reader.skip_white()
pos = self.reader.getpos()
Expand All @@ -1503,6 +1505,8 @@ def parse_heredoc(self):
keynode.pos = pos
keynode.value = key
viml_add(node.rlist, keynode)
if key == "trim":
is_trim = TRUE
if node.op == "":
raise VimLParserException(Err("E172: Missing marker", self.reader.getpos()))
self.parse_trail()
Expand All @@ -1511,7 +1515,7 @@ def parse_heredoc(self):
break
pos = self.reader.getpos()
line = self.reader.getn(-1)
if line == node.op:
if line == node.op or is_trim and line == prefix + node.op:
return node
linenode = Node(NODE_STRING)
linenode.pos = pos
Expand Down Expand Up @@ -1558,7 +1562,25 @@ def parse_cmd_let(self):
self.reader.getn(viml_len(s2))
self.reader.skip_white()
node.op = s2
node.right = self.parse_heredoc()
# compute allowed prefix for heredoc end marker (e.g. EOF)
pos = self.reader.tell()
while self.reader.tell() > 0:
if self.reader.peek() == "<EOL>":
self.reader.seek_cur(1)
break
self.reader.seek_cur(-1)
prefix = ""
while TRUE:
c = self.reader.getn(1)
if c == ":":
# any presence of leading ':' disables prefix for heredoc end marker
prefix = ""
break
elif not iswhite(c):
break
prefix += c
self.reader.seek_set(pos)
node.right = self.parse_heredoc(prefix)
self.add_node(node)
return
elif s1 == "=":
Expand Down
9 changes: 9 additions & 0 deletions test/test_heredoc.ok
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
(let =<< a (heredoc (list) "EOS" (list "hello" " world")))
(let =<< a (heredoc (list "trim") "EOS" (list "\thello" "world")))
(let =<< a (heredoc (list) "EOS" (list)))
(if v:true
; matching leading indentation is accepted
(let =<< a (heredoc (list "trim") "EOS" (list "\t\thello" "\tworld")))
(let =<< a (heredoc (list "trim") "EOS" (list " hello" " world")))
; but isn't required
(let =<< a (heredoc (list "trim") "EOS" (list " hello" " world"))))
; we don't actually do the trimming for trim heredocs
(let =<< a (heredoc (list "trim") "EOS" (list " hello" " world")))
(let =<< a (heredoc (list "trim") "EOS" (list "\t hello" "\t\tworld")))
25 changes: 25 additions & 0 deletions test/test_heredoc.vim
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,28 @@ world
EOS
let a =<< EOS
EOS
if v:true
" matching leading indentation is accepted
let a =<< trim EOS
hello
world
EOS
let a =<< trim EOS
hello
world
EOS
" but isn't required
let a =<< trim EOS
hello
world
EOS
endif
" we don't actually do the trimming for trim heredocs
let a =<< trim EOS
hello
world
EOS
: let a =<< trim EOS
hello
world
EOS