vimrc/sources_non_forked/vim-snipmate/autoload/snipmate/parse.vim

367 lines
9.6 KiB
VimL
Raw Normal View History

2015-02-04 10:43:54 +00:00
" Snippet definition parsing code
function! s:sfile() abort
2015-02-04 10:43:54 +00:00
return expand('<sfile>')
endfunction
let s:parser_proto = {}
2016-06-11 13:56:50 +00:00
let s:special_chars = "$`\n"
2015-02-04 10:43:54 +00:00
function! s:new_parser(text) abort
2015-02-04 10:43:54 +00:00
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 = {}
2016-06-11 13:56:50 +00:00
let ret.stored_lines = []
2015-02-04 10:43:54 +00:00
call ret.advance()
return ret
endfunction
function! s:parser_advance(...) dict abort
2015-02-04 10:43:54 +00:00
let self.pos += a:0 ? a:1 : 1
let self.next = self.input[self.pos]
endfunction
function! s:parser_same(tok) dict abort
2015-02-04 10:43:54 +00:00
if self.next == a:tok
call self.advance()
return 1
else
return 0
endif
endfunction
function! s:parser_id() dict abort
2015-02-04 10:43:54 +00:00
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 abort
2015-02-04 10:43:54 +00:00
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 abort
2015-02-04 10:43:54 +00:00
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 abort
2015-02-04 10:43:54 +00:00
let ret = []
if self.same(':')
call extend(ret, self.placeholder())
elseif self.same('/')
call add(ret, self.subst())
2024-10-06 08:25:50 +00:00
elseif self.next == '|'
call add(ret, self.select())
2015-02-04 10:43:54 +00:00
endif
call self.same('}')
return ret
endfunction
2024-10-06 08:25:50 +00:00
function! s:parser_select() dict abort
let items = []
while self.same('|')
let str = self.text('|}')
call s:mark_vars_in_select(str)
call add(items, str)
endwhile
return ['select'] + items
endfunction
function! s:mark_vars_in_select(str)
for item in a:str
if type(item) == type([])
call add(item, { 'select' : 1 })
endif
unlet! item " avoid E706
endfor
endfunction
function! s:parser_placeholder() dict abort
2016-06-11 13:56:50 +00:00
let ret = self.text('}')
return empty(ret) ? [''] : ret
2015-02-04 10:43:54 +00:00
endfunction
function! s:parser_subst() dict abort
2015-02-04 10:43:54 +00:00
let ret = {}
2016-06-11 13:56:50 +00:00
let ret.pat = self.pat()
2015-02-04 10:43:54 +00:00
if self.same('/')
2016-06-11 13:56:50 +00:00
let ret.sub = self.pat(1)
2015-02-04 10:43:54 +00:00
endif
if self.same('/')
2016-06-11 13:56:50 +00:00
let ret.flags = self.pat(1)
2015-02-04 10:43:54 +00:00
endif
return ret
endfunction
2016-06-11 13:56:50 +00:00
function! s:parser_pat(...) dict abort
let val = ''
while self.pos < self.len
if self.same('\')
if self.next == '/'
let val .= '/'
call self.advance()
elseif a:0 && self.next == '}'
let val .= '}'
call self.advance()
else
let val .= '\'
endif
elseif self.next == '/' || a:0 && self.next == '}'
break
else
let val .= self.next
call self.advance()
endif
endwhile
return val
endfunction
function! s:parser_expr() dict abort
2016-06-11 13:56:50 +00:00
let str = self.string('`')
2015-02-04 10:43:54 +00:00
call self.same('`')
2015-07-13 10:22:46 +00:00
return snipmate#util#eval(str)
2015-02-04 10:43:54 +00:00
endfunction
2016-06-11 13:56:50 +00:00
function! s:parser_string(till, ...) dict abort
2015-02-04 10:43:54 +00:00
let val = ''
2016-06-11 13:56:50 +00:00
let till = '\V\[' . escape(a:till, '\') . ']'
2015-02-04 10:43:54 +00:00
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 == "\t"
let self.indent += 1
let val .= s:indent(1)
call self.advance()
else
let val .= self.next
call self.advance()
endif
endwhile
2016-06-11 13:56:50 +00:00
return val
endfunction
function! s:join_consecutive_strings(list) abort
let list = a:list
let pos = 0
while pos + 1 < len(list)
if type(list[pos]) == type('') && type(list[pos+1]) == type('')
let list[pos] .= list[pos+1]
call remove(list, pos + 1)
else
let pos += 1
endif
endwhile
2015-02-04 10:43:54 +00:00
endfunction
2016-06-11 13:56:50 +00:00
function! s:parser_text(till) dict abort
let ret = []
2024-10-06 08:25:50 +00:00
let till = '\V\[' . escape(a:till, '\') . ']'
2017-03-14 15:16:07 +00:00
let target = ret
2016-06-11 13:56:50 +00:00
2015-02-04 10:43:54 +00:00
while self.pos < self.len
2016-06-11 13:56:50 +00:00
let lines = []
2015-02-04 10:43:54 +00:00
if self.same('$')
let var = self.var()
if !empty(var)
if var[0] is# 'VISUAL'
2016-06-11 13:56:50 +00:00
let lines = s:visual_placeholder(var, self.indent)
2017-03-14 15:16:07 +00:00
" Remove trailing newline. See #245
2020-04-26 01:56:16 +00:00
if lines[-1] =~ '^\s*$' && self.next == "\n"
2017-03-14 15:16:07 +00:00
call remove(lines, -1)
endif
2015-02-04 10:43:54 +00:00
elseif var[0] >= 0
2017-03-14 15:16:07 +00:00
call add(target, var)
2015-02-04 10:43:54 +00:00
call self.add_var(var)
endif
endif
elseif self.same('`')
2016-06-11 13:56:50 +00:00
let lines = split(self.expr(), "\n", 1)
2015-02-04 10:43:54 +00:00
else
2016-06-11 13:56:50 +00:00
let lines = [self.string(a:till . s:special_chars)]
2015-02-04 10:43:54 +00:00
endif
2016-06-11 13:56:50 +00:00
if !empty(lines)
2017-03-14 15:16:07 +00:00
call add(target, lines[0])
call extend(self.stored_lines, lines[1:-2])
" Don't change targets if there's only one line
if exists("lines[1]")
let target = [lines[-1]]
endif
2016-06-11 13:56:50 +00:00
endif
" Empty lines are ignored if this is tested at the start of an iteration
2024-10-06 08:25:50 +00:00
if self.next =~# till
2015-02-04 10:43:54 +00:00
break
endif
endwhile
2016-06-11 13:56:50 +00:00
call s:join_consecutive_strings(ret)
2017-03-14 15:16:07 +00:00
if target isnot ret
call s:join_consecutive_strings(target)
call extend(self.stored_lines, target)
endif
2015-02-04 10:43:54 +00:00
return ret
endfunction
2016-06-11 13:56:50 +00:00
function! s:parser_line() dict abort
let ret = []
if !empty(self.stored_lines)
call add(ret, remove(self.stored_lines, 0))
else
call extend(ret, self.text("\n"))
call self.same("\n")
endif
let self.indent = 0
return ret
endfunction
function! s:parser_parse() dict abort
while self.pos < self.len || !empty(self.stored_lines)
let line = self.line()
call add(self.value, line)
endwhile
endfunction
2015-02-04 10:43:54 +00:00
function! s:indent(count) abort
2015-02-04 10:43:54 +00:00
if &expandtab
2016-04-12 08:31:09 +00:00
let shift = repeat(' ', snipmate#util#tabwidth())
2015-02-04 10:43:54 +00:00
else
let shift = "\t"
endif
return repeat(shift, a:count)
endfunction
function! s:visual_placeholder(var, indent) abort
2015-02-04 10:43:54 +00:00
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
2016-06-11 13:56:50 +00:00
function! s:parser_create_stubs() dict abort
for [id, dict] in items(self.vars)
2024-10-06 08:25:50 +00:00
" only instance is in a selection, so remove it
if len(dict.instances) == 1 && type(dict.instances[0][-1]) == type({})
\ && dict.instances[0][-1] == { 'select' : 1 }
call remove(self.vars, id)
continue
endif
2016-06-11 13:56:50 +00:00
for i in dict.instances
if len(i) > 1 && type(i[1]) != type({})
if !has_key(dict, 'placeholder')
2024-10-06 08:25:50 +00:00
if type(i[1]) == type([]) && i[1][0] == 'select'
let dict.placeholder = i[1][1]
let dict.items = i[1][1:]
let i[1] = dict.placeholder
call add(i, dict)
else
let dict.placeholder = i[1:]
call add(i, dict)
endif
2016-06-11 13:56:50 +00:00
else
unlet i[1:]
call s:create_mirror_stub(i, dict)
endif
else
call s:create_mirror_stub(i, dict)
endif
endfor
2024-10-06 08:25:50 +00:00
2016-06-11 13:56:50 +00:00
if !has_key(dict, 'placeholder')
let dict.placeholder = []
let j = 0
while len(dict.instances[j]) > 2
let j += 1
endwhile
let oldstub = remove(dict.instances[j], 1, -1)[-1]
call add(dict.instances[j], '')
call add(dict.instances[j], dict)
call filter(dict.mirrors, 'v:val isnot oldstub')
endif
2024-10-06 08:25:50 +00:00
2016-06-11 13:56:50 +00:00
unlet dict.instances
endfor
endfunction
function! s:create_mirror_stub(mirror, dict)
let mirror = a:mirror
let dict = a:dict
let stub = get(mirror, 1, {})
2024-10-06 08:25:50 +00:00
if stub == { 'select' : 1 }
unlet mirror[1:]
else
call add(mirror, stub)
let dict.mirrors = get(dict, 'mirrors', [])
call add(dict.mirrors, stub)
endif
2016-06-11 13:56:50 +00:00
endfunction
function! snipmate#parse#snippet(text, ...) abort
2015-02-04 10:43:54 +00:00
let parser = s:new_parser(a:text)
call parser.parse()
2016-06-11 13:56:50 +00:00
if !(a:0 && a:1)
call parser.create_stubs()
endif
2015-02-04 10:43:54 +00:00
unlet! b:snipmate_visual
return [parser.value, parser.vars]
endfunction
2016-06-11 13:56:50 +00:00
call extend(s:parser_proto, snipmate#util#add_methods(s:sfile(), 'parser',
\ [ 'advance', 'same', 'id', 'add_var', 'var', 'varend',
2024-10-06 08:25:50 +00:00
\ 'line', 'string', 'create_stubs', 'pat', 'select',
2016-06-11 13:56:50 +00:00
\ 'placeholder', 'subst', 'expr', 'text', 'parse',
\ ]), 'error')