213 lines
4.5 KiB
VimL
213 lines
4.5 KiB
VimL
let s:Combinator = vsnip#parser#combinator#import()
|
|
|
|
"
|
|
" vsnip#snippet#parser#parse.
|
|
" @see https://github.com/Microsoft/language-server-protocol/blob/master/snippetSyntax.md
|
|
"
|
|
function! vsnip#snippet#parser#parse(text) abort
|
|
if strlen(a:text) == 0
|
|
return []
|
|
endif
|
|
|
|
let l:parsed = s:parser.parse(a:text, 0)
|
|
if !l:parsed[0]
|
|
throw json_encode({ 'text': a:text, 'result': l:parsed })
|
|
endif
|
|
return l:parsed[1]
|
|
endfunction
|
|
|
|
let s:skip = s:Combinator.skip
|
|
let s:token = s:Combinator.token
|
|
let s:many = s:Combinator.many
|
|
let s:or = s:Combinator.or
|
|
let s:seq = s:Combinator.seq
|
|
let s:lazy = s:Combinator.lazy
|
|
let s:option = s:Combinator.option
|
|
let s:pattern = s:Combinator.pattern
|
|
let s:map = s:Combinator.map
|
|
|
|
"
|
|
" primitives.
|
|
"
|
|
let s:dollar = s:token('$')
|
|
let s:open = s:token('{')
|
|
let s:close = s:token('}')
|
|
let s:colon = s:token(':')
|
|
let s:slash = s:token('/')
|
|
let s:comma = s:token(',')
|
|
let s:pipe = s:token('|')
|
|
let s:varname = s:pattern('[_[:alpha:]]\w*')
|
|
let s:int = s:map(s:pattern('\d\+'), { value -> str2nr(value[0]) })
|
|
let s:text = { stop, escape -> s:map(
|
|
\ s:skip(stop, escape),
|
|
\ { value -> {
|
|
\ 'type': 'text',
|
|
\ 'raw': value[0],
|
|
\ 'escaped': value[1]
|
|
\ }
|
|
\ }) }
|
|
let s:regex = s:map(s:text(['/'], []), { value -> {
|
|
\ 'type': 'regex',
|
|
\ 'pattern': value.raw
|
|
\ } })
|
|
|
|
"
|
|
" any (without text).
|
|
"
|
|
let s:any = s:or(
|
|
\ s:lazy({ -> s:choice }),
|
|
\ s:lazy({ -> s:variable }),
|
|
\ s:lazy({ -> s:tabstop }),
|
|
\ s:lazy({ -> s:placeholder }),
|
|
\ )
|
|
|
|
"
|
|
" format.
|
|
"
|
|
let s:format1 = s:map(s:seq(s:dollar, s:int), { value -> {
|
|
\ 'type': 'format',
|
|
\ 'id': value[1]
|
|
\ } })
|
|
let s:format2 = s:map(s:seq(s:dollar, s:open, s:int, s:close), { value -> {
|
|
\ 'type': 'format',
|
|
\ 'id': value[2]
|
|
\ } })
|
|
let s:format3 = s:map(
|
|
\ s:seq(
|
|
\ s:dollar,
|
|
\ s:open,
|
|
\ s:int,
|
|
\ s:colon,
|
|
\ s:or(
|
|
\ s:token('/upcase'),
|
|
\ s:token('/downcase'),
|
|
\ s:token('/capitalize'),
|
|
\ s:token('/camelcase'),
|
|
\ s:token('/pascalcase'),
|
|
\ s:token('+if'),
|
|
\ s:token('?if:else'),
|
|
\ s:token('-else'),
|
|
\ s:token('else')
|
|
\ ),
|
|
\ s:close
|
|
\ ), { value -> {
|
|
\ 'type': 'format',
|
|
\ 'id': value[2],
|
|
\ 'modifier': value[4]
|
|
\ } })
|
|
let s:format = s:or(s:format1, s:format2, s:format3)
|
|
|
|
"
|
|
" transform
|
|
"
|
|
let s:transform = s:map(s:seq(
|
|
\ s:slash,
|
|
\ s:regex,
|
|
\ s:slash,
|
|
\ s:many(s:or(s:format, s:text(['/', '$'], []))),
|
|
\ s:slash,
|
|
\ s:option(s:many(s:or(s:token('i'), s:token('g'))))
|
|
\ ), { value -> {
|
|
\ 'type': 'transform',
|
|
\ 'regex': value[1],
|
|
\ 'format': value[3],
|
|
\ 'option': value[5]
|
|
\ } })
|
|
|
|
"
|
|
" variable
|
|
"
|
|
let s:variable1 = s:map(s:seq(s:dollar, s:varname), { value -> {
|
|
\ 'type': 'variable',
|
|
\ 'name': value[1],
|
|
\ 'children': [],
|
|
\ } })
|
|
let s:variable2 = s:map(s:seq(s:dollar, s:open, s:varname, s:close), { value -> {
|
|
\ 'type': 'variable',
|
|
\ 'name': value[2],
|
|
\ 'children': [],
|
|
\ } })
|
|
let s:variable3 = s:map(s:seq(
|
|
\ s:dollar,
|
|
\ s:open,
|
|
\ s:varname,
|
|
\ s:colon,
|
|
\ s:many(s:or(s:any, s:text(['$', '}'], []))),
|
|
\ s:close
|
|
\ ), { value -> {
|
|
\ 'type': 'variable',
|
|
\ 'name': value[2],
|
|
\ 'children': value[4]
|
|
\ } })
|
|
let s:variable4 = s:map(s:seq(s:dollar, s:open, s:varname, s:transform, s:close), { value -> {
|
|
\ 'type': 'variable',
|
|
\ 'name': value[2],
|
|
\ 'transform': value[3],
|
|
\ 'children': [],
|
|
\ } })
|
|
|
|
let s:variable = s:or(s:variable1, s:variable2, s:variable3, s:variable4)
|
|
|
|
"
|
|
" placeholder.
|
|
"
|
|
let s:placeholder = s:map(s:seq(
|
|
\ s:dollar,
|
|
\ s:open,
|
|
\ s:int,
|
|
\ s:colon,
|
|
\ s:many(s:or(s:any, s:text(['$', '}'], []))),
|
|
\ s:close
|
|
\ ), { value -> {
|
|
\ 'type': 'placeholder',
|
|
\ 'id': value[2],
|
|
\ 'children': value[4]
|
|
\ } })
|
|
|
|
"
|
|
" tabstop
|
|
"
|
|
let s:tabstop1 = s:map(s:seq(s:dollar, s:int), { value -> {
|
|
\ 'type': 'placeholder',
|
|
\ 'id': value[1],
|
|
\ 'children': [],
|
|
\ } })
|
|
let s:tabstop2 = s:map(s:seq(s:dollar, s:open, s:int, s:option(s:colon), s:close), { value -> {
|
|
\ 'type': 'placeholder',
|
|
\ 'id': value[2],
|
|
\ 'children': [],
|
|
\ } })
|
|
let s:tabstop3 = s:map(s:seq(s:dollar, s:open, s:int, s:transform, s:close), { value -> {
|
|
\ 'type': 'placeholder',
|
|
\ 'id': value[2],
|
|
\ 'children': [],
|
|
\ 'transform': value[3]
|
|
\ } })
|
|
let s:tabstop = s:or(s:tabstop1, s:tabstop2, s:tabstop3)
|
|
|
|
"
|
|
" choice
|
|
"
|
|
let s:choice = s:map(s:seq(
|
|
\ s:dollar,
|
|
\ s:open,
|
|
\ s:int,
|
|
\ s:pipe,
|
|
\ s:many(
|
|
\ s:map(s:seq(s:text([',', '|'], []), s:option(s:comma)), { value -> value[0] }),
|
|
\ ),
|
|
\ s:pipe,
|
|
\ s:close
|
|
\ ), { value -> {
|
|
\ 'type': 'placeholder',
|
|
\ 'id': value[2],
|
|
\ 'choice': value[4],
|
|
\ 'children': [copy(value[4][0])],
|
|
\ } })
|
|
|
|
"
|
|
" parser.
|
|
"
|
|
let s:parser = s:many(s:or(s:any, s:text(['$'], ['}'])))
|
|
|