Skip to content

Commit 4d7937e

Browse files
committed
Improve syntax command parsing
1 parent be3783d commit 4d7937e

File tree

6 files changed

+219
-26
lines changed

6 files changed

+219
-26
lines changed

autoload/vimlparser.vim

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2122,21 +2122,94 @@ 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+
if self.reader.peek() !=# '='
2179+
continue
2180+
endif
2181+
call self.reader.getn(1)
2182+
let pattern = s:TRUE
2183+
elseif self.reader.peek() ==# '='
2184+
" Read arg value
2185+
call self.reader.getn(1)
2186+
if arg ==# 'cchar'
2187+
call self.reader.getn(1)
2188+
else
2189+
while s:TRUE
2190+
call self.reader.read_alpha()
2191+
let c = self.reader.peek()
2192+
if c ==# ',' || c ==# '@'
2193+
call self.reader.getn(1)
2194+
else
2195+
break
2196+
endif
2197+
endwhile
2198+
endif
2199+
endif
2200+
endif
2201+
2202+
" Read pattern
2203+
if pattern
2204+
let c = self.reader.peek()
2205+
if self.ends_excmds(c) && c !=# '|' && c !=# '"'
2206+
continue
2207+
endif
21302208
call self.reader.getn(1)
21312209
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
21372210
endif
2138-
call self.reader.getn(1)
21392211
endwhile
2212+
21402213
let node = s:Node(s:NODE_EXCMD)
21412214
let node.pos = self.ea.cmdpos
21422215
let node.ea = self.ea

js/vimlparser.js

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2431,22 +2431,82 @@ 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+
if (this.reader.peek() != "=") {
2476+
continue;
2477+
}
2478+
this.reader.getn(1);
2479+
var pattern = TRUE;
2480+
}
2481+
else if (this.reader.peek() == "=") {
2482+
// Read arg value
2483+
this.reader.getn(1);
2484+
if (arg == "cchar") {
2485+
this.reader.getn(1);
2486+
}
2487+
else {
2488+
while (TRUE) {
2489+
this.reader.read_alpha();
2490+
var c = this.reader.peek();
2491+
if (c == "," || c == "@") {
2492+
this.reader.getn(1);
2493+
}
2494+
else {
2495+
break;
2496+
}
2497+
}
2498+
}
2499+
}
2500+
}
2501+
// Read pattern
2502+
if (pattern) {
2503+
var c = this.reader.peek();
2504+
if (this.ends_excmds(c) && c != "|" && c != "\"") {
2505+
continue;
2506+
}
2507+
this.reader.getn(1);
2508+
this.parse_pattern(c);
24482509
}
2449-
this.reader.getn(1);
24502510
}
24512511
var node = Node(NODE_EXCMD);
24522512
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: 53 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,63 @@ 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+
if self.reader.peek() != "=":
2031+
continue
2032+
self.reader.getn(1)
2033+
pattern = TRUE
2034+
elif self.reader.peek() == "=":
2035+
# Read arg value
2036+
self.reader.getn(1)
2037+
if arg == "cchar":
2038+
self.reader.getn(1)
2039+
else:
2040+
while TRUE:
2041+
self.reader.read_alpha()
2042+
c = self.reader.peek()
2043+
if c == "," or c == "@":
2044+
self.reader.getn(1)
2045+
else:
2046+
break
2047+
# Read pattern
2048+
if pattern:
2049+
c = self.reader.peek()
2050+
if self.ends_excmds(c) and c != "|" and c != "\"":
2051+
continue
20012052
self.reader.getn(1)
20022053
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)
20092054
node = Node(NODE_EXCMD)
20102055
node.pos = self.ea.cmdpos
20112056
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)