mirror of
1
0
Fork 0
ultimate-vim/sources_non_forked/vim-snipmate/autoload/snipmate/parse.vim

221 lines
5.6 KiB
VimL

" Snippet definition parsing code
function! s:sfile()
return expand('<sfile>')
endfunction
let s:parser_proto = {}
function! s:new_parser(text)
let ret = copy(s:parser_proto)
let ret.input = a:text
let ret.len = strlen(ret.input)
let ret.pos = -1
let ret.indent = 0
let ret.value = []
let ret.vars = {}
call ret.advance()
return ret
endfunction
function! s:parser_advance(...) dict
let self.pos += a:0 ? a:1 : 1
let self.next = self.input[self.pos]
endfunction
function! s:parser_same(tok) dict
if self.next == a:tok
call self.advance()
return 1
else
return 0
endif
endfunction
function! s:parser_id() dict
if self.input[(self.pos):(self.pos+5)] == 'VISUAL'
call self.advance(6)
return 'VISUAL'
elseif self.next =~ '\d'
let end = matchend(self.input, '\d\+', self.pos)
let res = strpart(self.input, self.pos, end - self.pos)
call self.advance(end - self.pos)
return +res " force conversion to Number
endif
return -1
endfunction
function! s:parser_add_var(var) dict
let id = a:var[0]
if !has_key(self.vars, id)
let self.vars[id] = { 'instances' : [] }
endif
call add(self.vars[id].instances, a:var)
endfunction
function! s:parser_var() dict
let ret = []
if self.same('{')
let id = self.id()
if id >= 0
call add(ret, id)
call extend(ret, self.varend())
endif
else
let id = self.id()
if id >= 0
call add(ret, id)
endif
endif
return ret
endfunction
function! s:parser_varend() dict
let ret = []
if self.same(':')
call extend(ret, self.placeholder())
elseif self.same('/')
call add(ret, self.subst())
endif
call self.same('}')
return ret
endfunction
function! s:parser_placeholder() dict
return self.parse('}')
endfunction
function! s:parser_subst() dict
let ret = {}
let ret.pat = join(self.text('/', 1))
if self.same('/')
let ret.sub = join(self.text('/}'))
endif
if self.same('/')
let ret.flags = join(self.text('}', 1))
endif
return ret
endfunction
function! s:parser_expr() dict
let str = join(self.text('`', 1))
let ret = eval(str)
call self.same('`')
return type(ret) == type('') ? ret : string(ret)
endfunction
function! s:parser_text(...) dict
let res = []
let val = ''
if a:0 == 2 && a:2
let till = '\V' . escape(a:1, '\')
else
let till = '[`$' . (a:0 ? a:1 : '') . ']'
endif
while self.pos < self.len
if self.same('\')
if self.next != "\n"
let val .= self.next
endif
call self.advance()
elseif self.next =~# till
break
elseif self.next == "\n"
call add(res, val)
let val = ''
let self.indent = 0
call self.advance()
elseif self.next == "\t"
let self.indent += 1
let val .= s:indent(1)
call self.advance()
else
let val .= self.next
call self.advance()
endif
endwhile
call add(res, val)
return res
endfunction
function! s:parser_parse(...) dict
let ret = a:0 ? [] : self.value
while self.pos < self.len
if self.same('$')
let var = self.var()
if !empty(var)
if var[0] is# 'VISUAL'
let add_to = s:visual_placeholder(var, self.indent)
if !empty(ret) && type(ret[-1]) == type('')
let ret[-1] .= add_to[0]
else
call add(ret, add_to[0])
endif
call extend(ret, add_to[1:-1])
elseif var[0] >= 0
call add(ret, var)
call self.add_var(var)
endif
endif
elseif self.same('`')
let add_to = self.expr()
if !empty(ret) && type(ret[-1]) == type('')
let ret[-1] .= add_to
else
call add(ret, add_to)
endif
else
let text = a:0 ? self.text(a:1) : self.text()
if exists('add_to')
let ret[-1] .= text[0]
call remove(text, 0)
unlet add_to
endif
call extend(ret, text)
endif
if a:0 && self.next == a:1
break
endif
endwhile
return ret
endfunction
call extend(s:parser_proto, snipmate#util#add_methods(s:sfile(), 'parser',
\ [ 'advance', 'same', 'id', 'add_var', 'var', 'varend',
\ 'placeholder', 'subst', 'expr', 'text', 'parse' ]), 'error')
function! s:indent(count)
if &expandtab
let shift = repeat(' ', (&sts > 0) ? &sts : &sw)
else
let shift = "\t"
endif
return repeat(shift, a:count)
endfunction
function! s:visual_placeholder(var, indent)
let arg = get(a:var, 1, {})
if type(arg) == type({})
let pat = get(arg, 'pat', '')
let sub = get(arg, 'sub', '')
let flags = get(arg, 'flags', '')
let content = split(substitute(get(b:, 'snipmate_visual', ''), pat, sub, flags), "\n", 1)
else
let content = split(get(b:, 'snipmate_visual', arg), "\n", 1)
endif
let indent = s:indent(a:indent)
call map(content, '(v:key != 0) ? indent . v:val : v:val')
return content
endfunction
function! snipmate#parse#snippet(text)
let parser = s:new_parser(a:text)
call parser.parse()
unlet! b:snipmate_visual
return [parser.value, parser.vars]
endfunction