diff options
Diffstat (limited to 'vim/bundle/vim-snipmate/autoload/snipmate')
-rw-r--r-- | vim/bundle/vim-snipmate/autoload/snipmate/jumping.vim | 228 | ||||
-rw-r--r-- | vim/bundle/vim-snipmate/autoload/snipmate/legacy.vim | 139 | ||||
-rw-r--r-- | vim/bundle/vim-snipmate/autoload/snipmate/parse.vim | 309 | ||||
-rw-r--r-- | vim/bundle/vim-snipmate/autoload/snipmate/util.vim | 30 |
4 files changed, 706 insertions, 0 deletions
diff --git a/vim/bundle/vim-snipmate/autoload/snipmate/jumping.vim b/vim/bundle/vim-snipmate/autoload/snipmate/jumping.vim new file mode 100644 index 0000000..aaf65ab --- /dev/null +++ b/vim/bundle/vim-snipmate/autoload/snipmate/jumping.vim @@ -0,0 +1,228 @@ +function! s:sfile() abort + return expand('<sfile>') +endfunction + +let s:state_proto = {} + +function! snipmate#jumping#state() abort + return copy(s:state_proto) +endfunction + +function! s:listize_mirror(mirrors) abort + return map(copy(a:mirrors), '[v:val.line, v:val.col]') +endfunction + +" Removes snippet state info +function! s:state_remove() dict abort + " Remove all autocmds in group snipmate_changes in the current buffer + unlet! b:snip_state + silent! au! snipmate_changes * <buffer> +endfunction + +function! s:state_find_next_stop(backwards) dict abort + let self.stop_no += a:backwards? -1 : 1 + while !has_key(self.stops, self.stop_no) + if self.stop_no == self.stop_count + let self.stop_no = 0 + endif + if self.stop_no <= 0 && a:backwards + let self.stop_no = self.stop_count - 1 + endif + let self.stop_no += a:backwards? -1 : 1 + endwhile +endfunction + +" Update state information to correspond to the given tab stop +function! s:state_set_stop(backwards) dict abort + call self.find_next_stop(a:backwards) + let self.cur_stop = self.stops[self.stop_no] + let self.stop_len = (type(self.cur_stop.placeholder) == type(0)) + \ ? self.cur_stop.placeholder + \ : len(snipMate#placeholder_str(self.stop_no, self.stops)) + let self.start_col = self.cur_stop.col + let self.end_col = self.start_col + self.stop_len + let self.mirrors = get(self.cur_stop, 'mirrors', []) + let self.old_mirrors = deepcopy(self.mirrors) + call cursor(self.cur_stop.line, self.cur_stop.col) + let self.prev_len = col('$') + let self.changed = 0 + let ret = self.select_word() + if (self.stop_no == 0 || self.stop_no == self.stop_count - 1) && !a:backwards + call self.remove() + endif + return ret +endfunction + +" Jump to the next/previous tab stop +function! s:state_jump_stop(backwards) dict abort + " Update changes just in case + " This seems to be only needed because insert completion does not trigger + " the CursorMovedI event + call self.update_changes() + + " Store placeholder/location changes + let self.cur_stop.col = self.start_col + if self.changed + call self.remove_nested() + unlet! self.cur_stop.placeholder " avoid type error for old parsing version + let self.cur_stop.placeholder = [strpart(getline('.'), + \ self.start_col - 1, self.end_col - self.start_col)] + endif + + return self.set_stop(a:backwards) +endfunction + +function! s:state_remove_nested(...) dict abort + let id = a:0 ? a:1 : self.stop_no + if type(self.stops[id].placeholder) == type([]) + for i in self.stops[id].placeholder + if type(i) == type([]) + if type(i[1]) != type({}) + call self.remove_nested(i[0]) + call remove(self.stops, i[0]) + else + call filter(self.stops[i[0]].mirrors, 'v:val isnot i[1]') + endif + endif + unlet i " Avoid E706 + endfor + endif +endfunction + +" Select the placeholder for the current tab stop +function! s:state_select_word() dict abort + let len = self.stop_len + if !len | return '' | endif + let l = col('.') != 1 ? 'l' : '' + if &sel == 'exclusive' + return "\<esc>".l.'v'.len."l\<c-g>" + endif + return len == 1 ? "\<esc>".l.'gh' : "\<esc>".l.'v'.(len - 1)."l\<c-g>" +endfunction + +" Update the snippet as text is typed. The self.update_mirrors() function does +" the actual work. +" If the cursor moves outside of a placeholder, call self.remove() +function! s:state_update_changes() dict abort + let change_len = col('$') - self.prev_len + let self.changed = self.changed || change_len != 0 + let self.end_col += change_len + let col = col('.') + + if line('.') != self.cur_stop.line || col < self.start_col || col > self.end_col + return self.remove() + endif + + call self.update(self.cur_stop, change_len, change_len) + if !empty(self.mirrors) + call self.update_mirrors(change_len) + endif + + let self.prev_len = col('$') +endfunction + +" Actually update the mirrors for any changed text +function! s:state_update_mirrors(change) dict abort + let newWordLen = self.end_col - self.start_col + let newWord = strpart(getline('.'), self.start_col - 1, newWordLen) + let changeLen = a:change + let curLine = line('.') + let curCol = col('.') + let oldStartSnip = self.start_col + let i = 0 + + for mirror in self.mirrors + for stop in values(filter(copy(self.stops), 'v:key != 0')) + if type(stop.placeholder) == type(0) + if mirror.line == stop.line && mirror.col > stop.col + \ && mirror.col < stop.col + stop.placeholder + let stop.placeholder += changeLen + endif + endif + endfor + + if has_key(mirror, 'oldSize') + " recover the old size deduce the endline + let oldSize = mirror.oldSize + else + " first time, we use the intitial size + let oldSize = strlen(newWord) + endif + + " Split the line into three parts: the mirror, what's before it, and + " what's after it. Then combine them using the new mirror string. + " Subtract one to go from column index to byte index + + let theline = getline(mirror.line) + + " part before the current mirror + let beginline = strpart(theline, 0, mirror.col - 1) + + " current mirror transformation, and save size + let wordMirror= substitute(newWord, get(mirror, 'pat', ''), get(mirror, 'sub', ''), get(mirror, 'flags', '')) + let mirror.oldSize = strlen(wordMirror) + + " end of the line, use the oldSize because with the transformation, + " the size of the mirror can be different from those of the snippet + let endline = strpart(theline, mirror.col + oldSize -1) + + " Update other object on the line + call self.update(mirror, changeLen, mirror.oldSize - oldSize) + + " reconstruct the line + let update = beginline.wordMirror.endline + + call setline(mirror.line, update) + endfor + + " Reposition the cursor in case a var updates on the same line but before + " the current tabstop + if oldStartSnip != self.start_col || mode() == 'i' + call cursor(0, curCol + self.start_col - oldStartSnip) + endif +endfunction + +function! s:state_find_update_objects(item) dict abort + let item = a:item + let item.update_objects = [] + + " Filter the zeroth stop because it's duplicated as the last + for stop in values(filter(copy(self.stops), 'v:key != 0')) + if stop.line == item.line && stop.col > item.col + call add(item.update_objects, stop) + endif + + for mirror in get(stop, 'mirrors', []) + if mirror.line == item.line && mirror.col > item.col + call add(item.update_objects, mirror) + endif + endfor + endfor + + return item.update_objects +endfunction + +function! s:state_update(item, change_len, mirror_change) dict abort + let item = a:item + if !exists('item.update_objects') + let item.update_objects = self.find_update_objects(a:item) + endif + let to_update = item.update_objects + + for obj in to_update + " object does not necessarly have the same decalage + " than mirrors if mirrors use regexp + let obj.col += a:mirror_change + if obj is self.cur_stop + let self.start_col += a:change_len + let self.end_col += a:change_len + endif + endfor +endfunction + +call extend(s:state_proto, snipmate#util#add_methods(s:sfile(), 'state', + \ [ 'remove', 'set_stop', 'jump_stop', 'remove_nested', + \ 'select_word', 'update_changes', 'update_mirrors', + \ 'find_next_stop', 'find_update_objects', 'update' ]), 'error') + +" vim:noet:sw=4:ts=4:ft=vim diff --git a/vim/bundle/vim-snipmate/autoload/snipmate/legacy.vim b/vim/bundle/vim-snipmate/autoload/snipmate/legacy.vim new file mode 100644 index 0000000..7ff39cb --- /dev/null +++ b/vim/bundle/vim-snipmate/autoload/snipmate/legacy.vim @@ -0,0 +1,139 @@ +let s:sigil = nr2char(31) +let snipmate#legacy#sigil = s:sigil + +" Prepare snippet to be processed by s:BuildTabStops +function! snipmate#legacy#process_snippet(snip) abort + let snippet = a:snip + let esc_bslash = '\%(\\\@<!\%(\\\\\)*\)\@<=' + + if exists('b:snipmate_visual') + let visual = substitute(b:snipmate_visual, "\n$", '', '') + unlet b:snipmate_visual + else + let visual = '' + endif + let snippet = s:substitute_visual(snippet, visual) + + " Evaluate eval (`...`) expressions. + " Backquotes prefixed with a backslash "\" are ignored. + " And backslash can be escaped by doubling it. + " Using a loop here instead of a regex fixes a bug with nested "\=". + if stridx(snippet, '`') != -1 + let new = [] + let snip = split(snippet, esc_bslash . '`', 1) + let isexp = 0 + for i in snip + if isexp + call add(new, substitute(snipmate#util#eval(i), + \ "\n\\%$", '', '')) + else + call add(new, i) + endif + let isexp = !isexp + endfor + let snippet = join(new, '') + let snippet = substitute(snippet, "\r", "\n", 'g') + let snippet = substitute(snippet, '\\`', "`", 'g') + endif + + " Place all text after a colon in a tab stop after the tab stop + " (e.g. "${#:foo}" becomes "${:foo}foo"). + " This helps tell the position of the tab stops later. + let snippet = substitute(snippet, esc_bslash . '\$\({\d\+:\(.\{-}\)}\|{\d\+}\)', s:sigil . '\1\2', 'g') + let snippet = substitute(snippet, esc_bslash . '\$\(\d\+\)', s:sigil . '\1', 'g') + let snippet = substitute(snippet, esc_bslash . '\\\$', '$', 'g') + let snippet = substitute(snippet, '\\\\', "\\", 'g') + + " Update the a:snip so that all the $# become the text after + " the colon in their associated ${#}. + " (e.g. "${1:foo}" turns all "$1"'s into "foo") + let i = 0 + if snippet !~ s:sigil . '{0' + let snippet .= s:sigil . '{0}' + endif + while snippet =~ s:sigil.'{'.i + let s = matchstr(snippet, s:sigil . '{' . i . ':\zs.\{-}\ze}') + if s != '' + let snippet = substitute(snippet, s:sigil . i, s.'&', 'g') + endif + let i += 1 + endw + + if &et " Expand tabs to spaces if 'expandtab' is set. + return substitute(snippet, '\t', repeat(' ', snipmate#util#tabwidth()), 'g') + endif + return snippet +endfunction + +" Builds a list of a list of each tab stop in the snippet containing: +" 1.) The tab stop's line number. +" 2.) The tab stop's column number +" (by getting the length of the string between the last "\n" and the +" tab stop). +" 3.) The length of the text after the colon for the current tab stop +" (e.g. "${1:foo}" would return 3). +" 4.) If the "${#:}" construct is given, another list containing all +" the matches of "$#", to be replaced with the placeholder. This list is +" composed the same way as the parent; the first item is the line number, +" and the second is the column. +function! snipmate#legacy#build_stops(snip, lnum, col, indent) abort + let stops = {} + let i = 0 + let withoutVars = substitute(a:snip, s:sigil . '\d\+', '', 'g') + while a:snip =~ s:sigil . '{' . i + let beforeTabStop = matchstr(withoutVars, '^.*\ze'.s:sigil .'{'.i.'\D') + let withoutOthers = substitute(withoutVars, ''.s:sigil .'{\('.i.'\D\)\@!\d\+.\{-}}', '', 'g') + + let stops[i] = {} + let stops[i].line = a:lnum + s:count(beforeTabStop, "\n") + let stops[i].col = a:indent + len(matchstr(withoutOthers, '[^\n]\{-}\ze'.s:sigil .'{'.i.'\D')) + let stops[i].placeholder = 0 + let stops[i].mirrors = [] + if stops[i].line == a:lnum + let stops[i].col += a:col + endif + + " Get all $# matches in another list, if ${#:name} is given + if withoutVars =~ printf('%s{%d:', s:sigil, i) + let stops[i].placeholder = len(matchstr(withoutVars, ''.s:sigil .'{'.i.':\zs.\{-}\ze}')) + let withoutOthers = substitute(a:snip, ''.s:sigil .'{\d\+.\{-}}\|'.s:sigil .''.i.'\@!\d\+', '', 'g') + + while match(withoutOthers, ''.s:sigil .''.i.'\(\D\|$\)') != -1 + let stops[i].mirrors = get(stops[i], 'mirrors', []) + let beforeMark = matchstr(withoutOthers, + \ printf('^.\{-}\ze%s%s%d\(\D\|$\)', + \ repeat('.', stops[i].placeholder), s:sigil, i)) + let line = a:lnum + s:count(beforeMark, "\n") + let col = a:indent + (line > a:lnum + \ ? len(matchstr(beforeMark, '.*\n\zs.*')) + \ : a:col + len(beforeMark)) + call add(stops[i].mirrors, { 'line' : line, 'col' : col }) + let withoutOthers = substitute(withoutOthers, ''.s:sigil .''.i.'\ze\(\D\|$\)', '', '') + endw + endif + let i += 1 + endw + let stops[i] = stops[0] + return [stops, i + 1] +endfunction + +function! s:substitute_visual(snippet, visual) abort + let lines = [] + for line in split(a:snippet, "\n") + let indent = matchstr(line, '^\t\+') + call add(lines, substitute(line, '{VISUAL}', + \ substitute(escape(a:visual, '%\'), "\n", "\n" . indent, 'g'), 'g')) + endfor + return join(lines, "\n") +endfunction + +" Counts occurences of haystack in needle +function! s:count(haystack, needle) abort + let counter = 0 + let index = stridx(a:haystack, a:needle) + while index != -1 + let index = stridx(a:haystack, a:needle, index+1) + let counter += 1 + endw + return counter +endfunction diff --git a/vim/bundle/vim-snipmate/autoload/snipmate/parse.vim b/vim/bundle/vim-snipmate/autoload/snipmate/parse.vim new file mode 100644 index 0000000..dd495e9 --- /dev/null +++ b/vim/bundle/vim-snipmate/autoload/snipmate/parse.vim @@ -0,0 +1,309 @@ +" Snippet definition parsing code + +function! s:sfile() abort + return expand('<sfile>') +endfunction + +let s:parser_proto = {} +let s:special_chars = "$`\n" + +function! s:new_parser(text) abort + 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 = {} + let ret.stored_lines = [] + call ret.advance() + return ret +endfunction + +function! s:parser_advance(...) dict abort + let self.pos += a:0 ? a:1 : 1 + let self.next = self.input[self.pos] +endfunction + +function! s:parser_same(tok) dict abort + if self.next == a:tok + call self.advance() + return 1 + else + return 0 + endif +endfunction + +function! s:parser_id() dict abort + 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 + 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 + 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 + 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 abort + let ret = self.text('}') + return empty(ret) ? [''] : ret +endfunction + +function! s:parser_subst() dict abort + let ret = {} + let ret.pat = self.pat() + if self.same('/') + let ret.sub = self.pat(1) + endif + if self.same('/') + let ret.flags = self.pat(1) + endif + return ret +endfunction + +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 + let str = self.string('`') + call self.same('`') + return snipmate#util#eval(str) +endfunction + +function! s:parser_string(till, ...) dict abort + let val = '' + let till = '\V\[' . escape(a:till, '\') . ']' + + 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 + + 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 +endfunction + +function! s:parser_text(till) dict abort + let ret = [] + + while self.pos < self.len + let lines = [] + + if self.same('$') + let var = self.var() + if !empty(var) + if var[0] is# 'VISUAL' + let lines = s:visual_placeholder(var, self.indent) + elseif var[0] >= 0 + call add(ret, var) + call self.add_var(var) + endif + endif + elseif self.same('`') + let lines = split(self.expr(), "\n", 1) + else + let lines = [self.string(a:till . s:special_chars)] + endif + + if !empty(lines) + call add(ret, lines[0]) + call extend(self.stored_lines, lines[1:]) + endif + + " Empty lines are ignored if this is tested at the start of an iteration + if self.next ==# a:till + break + endif + endwhile + + call s:join_consecutive_strings(ret) + return ret +endfunction + +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 + +function! s:indent(count) abort + if &expandtab + let shift = repeat(' ', snipmate#util#tabwidth()) + else + let shift = "\t" + endif + return repeat(shift, a:count) +endfunction + +function! s:visual_placeholder(var, indent) abort + 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! s:parser_create_stubs() dict abort + + for [id, dict] in items(self.vars) + for i in dict.instances + if len(i) > 1 && type(i[1]) != type({}) + if !has_key(dict, 'placeholder') + let dict.placeholder = i[1:] + call add(i, dict) + else + unlet i[1:] + call s:create_mirror_stub(i, dict) + endif + else + call s:create_mirror_stub(i, dict) + endif + endfor + 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 + 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, {}) + call add(mirror, stub) + let dict.mirrors = get(dict, 'mirrors', []) + call add(dict.mirrors, stub) +endfunction + +function! snipmate#parse#snippet(text, ...) abort + let parser = s:new_parser(a:text) + call parser.parse() + if !(a:0 && a:1) + call parser.create_stubs() + endif + unlet! b:snipmate_visual + return [parser.value, parser.vars] +endfunction + +call extend(s:parser_proto, snipmate#util#add_methods(s:sfile(), 'parser', + \ [ 'advance', 'same', 'id', 'add_var', 'var', 'varend', + \ 'line', 'string', 'create_stubs', 'pat', + \ 'placeholder', 'subst', 'expr', 'text', 'parse', + \ ]), 'error') diff --git a/vim/bundle/vim-snipmate/autoload/snipmate/util.vim b/vim/bundle/vim-snipmate/autoload/snipmate/util.vim new file mode 100644 index 0000000..a80d307 --- /dev/null +++ b/vim/bundle/vim-snipmate/autoload/snipmate/util.vim @@ -0,0 +1,30 @@ +" The next function was based on s:function and s:add_methods in fugitive +" <https://github.com/tpope/vim-fugitive/blob/master/plugin/fugitive.vim> +function! snipmate#util#add_methods(sfile, namespace, methods) abort + let dict = {} + for name in a:methods + let dict[name] = function(join([matchstr(a:sfile, '<SNR>\d\+'), + \ a:namespace, name], '_')) + endfor + return dict +endfunction + +function! snipmate#util#eval(arg) + try + let ret = eval(a:arg) + catch + echohl ErrorMsg + echom 'SnipMate:Expression: ' . v:exception + echohl None + let ret = '' + endtry + return type(ret) == type('') ? ret : string(ret) +endfunction + +function! snipmate#util#tabwidth() + if &sts > 0 + return &sts + else + return exists('*shiftwidth') ? shiftwidth() : &sw + endif +endfunction |