Skip to content

Commit 72bf9fa

Browse files
committed
Improve syntax command parsing
1 parent be3783d commit 72bf9fa

File tree

6 files changed

+222
-26
lines changed

6 files changed

+222
-26
lines changed

autoload/vimlparser.vim

Lines changed: 82 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2122,21 +2122,95 @@ endfunction
21222122

21232123
" FIXME: validate argument
21242124
function! s:VimLParser.parse_cmd_syntax() abort
2125-
let end = self.reader.getpos()
2125+
let subcmd = self.reader.read_alpha()
2126+
2127+
" Read name
2128+
if subcmd ==# 'region' || subcmd ==# 'match'
2129+
call self.reader.read_white()
2130+
call self.reader.read_alpha()
2131+
endif
2132+
2133+
let match_pattern = subcmd !=# 'match'
2134+
21262135
while s:TRUE
21272136
let end = self.reader.getpos()
2137+
let pattern = s:FALSE
2138+
2139+
" Read non-alpha
21282140
let c = self.reader.peek()
2129-
if c ==# '/' || c ==# "'" || c ==# '"'
2141+
if self.ends_excmds(c)
2142+
if !match_pattern && (c ==# '|' || c ==# '"')
2143+
let pattern = s:TRUE
2144+
let match_pattern = s:TRUE
2145+
else
2146+
break
2147+
endif
2148+
elseif !s:isalpha(c)
2149+
if !match_pattern && !s:iswhite(c)
2150+
let pattern = s:TRUE
2151+
let match_pattern = s:TRUE
2152+
else
2153+
call self.reader.getn(1)
2154+
continue
2155+
endif
2156+
endif
2157+
2158+
" Read arg
2159+
if !pattern
2160+
let arg_pos = self.reader.tell()
2161+
let arg = self.reader.read_alpha()
2162+
2163+
if !match_pattern
2164+
\ && arg !=# 'keepend'
2165+
\ && arg !=# 'conceal'
2166+
\ && arg !=# 'cchar'
2167+
\ && arg !=# 'contained'
2168+
\ && arg !=# 'containedin'
2169+
\ && arg !=# 'nextgroup'
2170+
\ && arg !=# 'transparent'
2171+
\ && arg !=# 'skipwhite'
2172+
\ && arg !=# 'skipnl'
2173+
\ && arg !=# 'skipempty'
2174+
let match_pattern = s:TRUE
2175+
let pattern = s:TRUE
2176+
call self.reader.seek_set(arg_pos)
2177+
elseif subcmd ==# 'region' && (arg ==# 'start' || arg ==# 'skip' || arg ==# 'end')
2178+
let c = self.reader.peek()
2179+
if c !=# '='
2180+
continue
2181+
endif
2182+
call self.reader.getn(1)
2183+
let pattern = s:TRUE
2184+
elseif self.reader.peek() ==# '='
2185+
" Read arg value
2186+
call self.reader.getn(1)
2187+
if arg ==# 'cchar'
2188+
call self.reader.getn(1)
2189+
else
2190+
while s:TRUE
2191+
call self.reader.read_alpha()
2192+
let c = self.reader.peek()
2193+
if c ==# ',' || c ==# '@'
2194+
call self.reader.getn(1)
2195+
else
2196+
break
2197+
endif
2198+
endwhile
2199+
endif
2200+
endif
2201+
endif
2202+
2203+
" Read pattern
2204+
if pattern
2205+
let c = self.reader.peek()
2206+
if c ==# '' || c ==# '<EOF>' || c ==# '<EOL>'
2207+
continue
2208+
endif
21302209
call self.reader.getn(1)
21312210
call self.parse_pattern(c)
2132-
elseif c ==# '='
2133-
call self.reader.getn(1)
2134-
call self.parse_pattern(' ')
2135-
elseif self.ends_excmds(c)
2136-
break
21372211
endif
2138-
call self.reader.getn(1)
21392212
endwhile
2213+
21402214
let node = s:Node(s:NODE_EXCMD)
21412215
let node.pos = self.ea.cmdpos
21422216
let node.ea = self.ea

js/vimlparser.js

Lines changed: 71 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2431,22 +2431,83 @@ VimLParser.prototype.parse_wincmd = function() {
24312431

24322432
// FIXME: validate argument
24332433
VimLParser.prototype.parse_cmd_syntax = function() {
2434-
var end = this.reader.getpos();
2434+
var subcmd = this.reader.read_alpha();
2435+
// Read name
2436+
if (subcmd == "region" || subcmd == "match") {
2437+
this.reader.read_white();
2438+
this.reader.read_alpha();
2439+
}
2440+
var match_pattern = subcmd != "match";
24352441
while (TRUE) {
24362442
var end = this.reader.getpos();
2443+
var pattern = FALSE;
2444+
// Read non-alpha
24372445
var c = this.reader.peek();
2438-
if (c == "/" || c == "'" || c == "\"") {
2439-
this.reader.getn(1);
2440-
this.parse_pattern(c);
2446+
if (this.ends_excmds(c)) {
2447+
if (!match_pattern && (c == "|" || c == "\"")) {
2448+
var pattern = TRUE;
2449+
var match_pattern = TRUE;
2450+
}
2451+
else {
2452+
break;
2453+
}
24412454
}
2442-
else if (c == "=") {
2443-
this.reader.getn(1);
2444-
this.parse_pattern(" ");
2455+
else if (!isalpha(c)) {
2456+
if (!match_pattern && !iswhite(c)) {
2457+
var pattern = TRUE;
2458+
var match_pattern = TRUE;
2459+
}
2460+
else {
2461+
this.reader.getn(1);
2462+
continue;
2463+
}
24452464
}
2446-
else if (this.ends_excmds(c)) {
2447-
break;
2465+
// Read arg
2466+
if (!pattern) {
2467+
var arg_pos = this.reader.tell();
2468+
var arg = this.reader.read_alpha();
2469+
if (!match_pattern && arg != "keepend" && arg != "conceal" && arg != "cchar" && arg != "contained" && arg != "containedin" && arg != "nextgroup" && arg != "transparent" && arg != "skipwhite" && arg != "skipnl" && arg != "skipempty") {
2470+
var match_pattern = TRUE;
2471+
var pattern = TRUE;
2472+
this.reader.seek_set(arg_pos);
2473+
}
2474+
else if (subcmd == "region" && (arg == "start" || arg == "skip" || arg == "end")) {
2475+
var c = this.reader.peek();
2476+
if (c != "=") {
2477+
continue;
2478+
}
2479+
this.reader.getn(1);
2480+
var pattern = TRUE;
2481+
}
2482+
else if (this.reader.peek() == "=") {
2483+
// Read arg value
2484+
this.reader.getn(1);
2485+
if (arg == "cchar") {
2486+
this.reader.getn(1);
2487+
}
2488+
else {
2489+
while (TRUE) {
2490+
this.reader.read_alpha();
2491+
var c = this.reader.peek();
2492+
if (c == "," || c == "@") {
2493+
this.reader.getn(1);
2494+
}
2495+
else {
2496+
break;
2497+
}
2498+
}
2499+
}
2500+
}
2501+
}
2502+
// Read pattern
2503+
if (pattern) {
2504+
var c = this.reader.peek();
2505+
if (c == "" || c == "<EOF>" || c == "<EOL>") {
2506+
continue;
2507+
}
2508+
this.reader.getn(1);
2509+
this.parse_pattern(c);
24482510
}
2449-
this.reader.getn(1);
24502511
}
24512512
var node = Node(NODE_EXCMD);
24522513
node.pos = this.ea.cmdpos;

py/vimlfunc.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class AttributeDict(dict):
3232
pat_vim2py = {
3333
"[0-9a-zA-Z]": "[0-9a-zA-Z]",
3434
"[@*!=><&~#]": "[@*!=><&~#]",
35+
'[=,@]': '[=,@]',
3536
"\\<ARGOPT\\>": "\\bARGOPT\\b",
3637
"\\<BANG\\>": "\\bBANG\\b",
3738
"\\<EDITCMD\\>": "\\bEDITCMD\\b",

py/vimlparser.py

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class AttributeDict(dict):
3232
pat_vim2py = {
3333
"[0-9a-zA-Z]": "[0-9a-zA-Z]",
3434
"[@*!=><&~#]": "[@*!=><&~#]",
35+
'[=,@]': '[=,@]',
3536
"\\<ARGOPT\\>": "\\bARGOPT\\b",
3637
"\\<BANG\\>": "\\bBANG\\b",
3738
"\\<EDITCMD\\>": "\\bEDITCMD\\b",
@@ -1993,19 +1994,64 @@ def parse_wincmd(self):
19931994

19941995
# FIXME: validate argument
19951996
def parse_cmd_syntax(self):
1996-
end = self.reader.getpos()
1997+
subcmd = self.reader.read_alpha()
1998+
# Read name
1999+
if subcmd == "region" or subcmd == "match":
2000+
self.reader.read_white()
2001+
self.reader.read_alpha()
2002+
match_pattern = subcmd != "match"
19972003
while TRUE:
19982004
end = self.reader.getpos()
2005+
pattern = FALSE
2006+
# Read non-alpha
19992007
c = self.reader.peek()
2000-
if c == "/" or c == "'" or c == "\"":
2008+
if self.ends_excmds(c):
2009+
if not match_pattern and (c == "|" or c == "\""):
2010+
pattern = TRUE
2011+
match_pattern = TRUE
2012+
else:
2013+
break
2014+
elif not isalpha(c):
2015+
if not match_pattern and not iswhite(c):
2016+
pattern = TRUE
2017+
match_pattern = TRUE
2018+
else:
2019+
self.reader.getn(1)
2020+
continue
2021+
# Read arg
2022+
if not pattern:
2023+
arg_pos = self.reader.tell()
2024+
arg = self.reader.read_alpha()
2025+
if not match_pattern and arg != "keepend" and arg != "conceal" and arg != "cchar" and arg != "contained" and arg != "containedin" and arg != "nextgroup" and arg != "transparent" and arg != "skipwhite" and arg != "skipnl" and arg != "skipempty":
2026+
match_pattern = TRUE
2027+
pattern = TRUE
2028+
self.reader.seek_set(arg_pos)
2029+
elif subcmd == "region" and (arg == "start" or arg == "skip" or arg == "end"):
2030+
c = self.reader.peek()
2031+
if c != "=":
2032+
continue
2033+
self.reader.getn(1)
2034+
pattern = TRUE
2035+
elif self.reader.peek() == "=":
2036+
# Read arg value
2037+
self.reader.getn(1)
2038+
if arg == "cchar":
2039+
self.reader.getn(1)
2040+
else:
2041+
while TRUE:
2042+
self.reader.read_alpha()
2043+
c = self.reader.peek()
2044+
if c == "," or c == "@":
2045+
self.reader.getn(1)
2046+
else:
2047+
break
2048+
# Read pattern
2049+
if pattern:
2050+
c = self.reader.peek()
2051+
if c == "" or c == "<EOF>" or c == "<EOL>":
2052+
continue
20012053
self.reader.getn(1)
20022054
self.parse_pattern(c)
2003-
elif c == "=":
2004-
self.reader.getn(1)
2005-
self.parse_pattern(" ")
2006-
elif self.ends_excmds(c):
2007-
break
2008-
self.reader.getn(1)
20092055
node = Node(NODE_EXCMD)
20102056
node.pos = self.ea.cmdpos
20112057
node.ea = self.ea

test/test_syncmd.ok

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,10 @@
66
(excmd "syn match pythonError \"[&|]\\{2,}\" display")
77
(excmd "syntax match qfFileName /^\\zs\\S[^|]\\+\\/\\ze[^|\\/]\\+\\/[^|\\/]\\+|/ conceal cchar=+")
88
(excmd "syntax region jsString start=+\"+ skip=+\\\\\\(\"\\|$\\)+ end=+\"\\|$+ contains=jsSpecial,@Spell extend")
9+
(excmd "syntax match testCchar conceal cchar=/ /pattern/")
10+
(excmd "syntax match testArgValue contained containedin=parentGroup /pattern/")
11+
(excmd "syntax match testArgsAfterPattern /pattern/ contained containedin=parentGroup")
12+
(excmd "syntax match testPatternDelim contained +pattern+")
13+
(excmd "syntax match testAlphaPatternDelim contained ApatternA")
14+
(excmd "syntax match testPipePatternDelim contained |pattern|")
15+
(excmd "syntax match testQuotePatternDelim contained \"pattern\"")

test/test_syncmd.vim

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,10 @@ syntax list GroupName
55
syn match pythonError "[&|]\{2,}" display
66
syntax match qfFileName /^\zs\S[^|]\+\/\ze[^|\/]\+\/[^|\/]\+|/ conceal cchar=+
77
syntax region jsString start=+"+ skip=+\\\("\|$\)+ end=+"\|$+ contains=jsSpecial,@Spell extend
8+
syntax match testCchar conceal cchar=/ /pattern/
9+
syntax match testArgValue contained containedin=parentGroup /pattern/
10+
syntax match testArgsAfterPattern /pattern/ contained containedin=parentGroup
11+
syntax match testPatternDelim contained +pattern+
12+
syntax match testAlphaPatternDelim contained ApatternA
13+
syntax match testPipePatternDelim contained |pattern|
14+
syntax match testQuotePatternDelim contained "pattern"

0 commit comments

Comments
 (0)