1
0
mirror of https://github.com/amix/vimrc synced 2025-06-16 09:35:01 +08:00

Updated plugins

This commit is contained in:
amix
2016-06-11 15:56:50 +02:00
parent cc0e8a9907
commit 0228ad0e9e
60 changed files with 1341 additions and 784 deletions

View File

@ -14,6 +14,7 @@ additional contributions from:
* [asymmetric](https://github.com/asymmetric)
* [bpugh](https://github.com/bpugh)
* [bruno-](https://github.com/bruno-)
* [CharlesGueunet](https://github.com/CharlesGueunet)
* [darkwise](https://github.com/darkwise)
* [dreviejo](https://github.com/dreviejo)
* [fish-face](https://github.com/fish-face)
@ -40,6 +41,7 @@ additional contributions from:
* [redpill](https://github.com/redpill)
* [rglassett](http://github.com/rglassett)
* [robhudson](https://github.com/robhudson)
* [shinymayhem](https://github.com/shinymayhem)
* [Shraymonks](https://github.com/shraymonks)
* [sickill](https://github.com/sickill)
* [statik](https://github.com/statik)

View File

@ -87,7 +87,7 @@ languages. For this we provide two options: scope aliases and the
`:SnipMateLoadScope` command. Scope aliases simply say "whenever this scope is
loaded, also load this other scope:
let g:snipMate = {}
let g:snipMate = get(g:, 'snipMate', {}) " Allow for vimrc re-sourcing
let g:snipMate.scope_aliases = {}
let g:snipMate.scope_aliases['ruby'] = 'ruby,rails'
@ -98,6 +98,16 @@ does `:SnipMateLoadScope rails` when editing a Rails project for example.
## Release Notes ##
### 0.89 - 2016-05-29 ###
* Various regex updates to legacy parser
* Addition of double bang syntax to completely remove a snippet from lookup
* Group various SnipMate autocommands
* Support setting 'shiftwidth' to 0
* Parser now operates linewise, adding some flexibility
* Mirror substitutions are more literal
* Mirror length is calculated correctly when substitutions occur
### 0.88 - 2015-04-04 ###
* Implement simple caching

View File

@ -28,7 +28,8 @@ function! snipMate#expandSnip(snip, version, col) abort
let [snippet, b:snip_state.stops] = snipmate#parse#snippet(a:snip)
" Build stop/mirror info
let b:snip_state.stop_count = s:build_stops(snippet, b:snip_state.stops, lnum, col, indent)
let snipLines = snipMate#sniplist_str(snippet, b:snip_state.stops)
let snipLines = map(copy(snippet),
\ 'snipMate#sniplist_str(v:val, b:snip_state.stops)')
else
let snippet = snipmate#legacy#process_snippet(a:snip)
let [b:snip_state.stops, b:snip_state.stop_count] = snipmate#legacy#build_stops(snippet, lnum, col - indent, indent)
@ -77,11 +78,11 @@ function! snipMate#expandSnip(snip, version, col) abort
endfunction
function! snipMate#placeholder_str(num, stops) abort
return snipMate#sniplist_str(a:stops[a:num].placeholder, a:stops)[0]
return snipMate#sniplist_str(a:stops[a:num].placeholder, a:stops)
endfunction
function! snipMate#sniplist_str(snippet, stops) abort
let lines = ['']
let str = ''
let pos = 0
let add_to = 1
let seen_stops = []
@ -90,110 +91,82 @@ function! snipMate#sniplist_str(snippet, stops) abort
let item = a:snippet[pos]
if type(item) == type('')
if add_to
let lines[-1] .= item
else
call add(lines, item)
endif
let add_to = 0
let str .= item
elseif type(item) == type([])
let lines[-1] .= snipMate#placeholder_str(item[0], a:stops)
let add_to = 1
let str .= snipMate#placeholder_str(item[0], a:stops)
endif
let pos += 1
unlet item " avoid E706
endwhile
return lines
return str
endfunction
function! s:build_stops(snippet, stops, lnum, col, indent) abort
let stops = a:stops
let line = a:lnum
let lnum = a:lnum
let col = a:col
for [id, dict] in items(stops)
for i in dict.instances
if len(i) > 1 && type(i[1]) != type({})
if !has_key(dict, 'placeholder')
let dict.placeholder = i[1:]
else
unlet i[1:]
endif
endif
endfor
if !has_key(dict, 'placeholder')
let dict.placeholder = []
let j = 0
while len(dict.instances[j]) > 1
let j += 1
endwhile
call add(dict.instances[j], '')
for line in a:snippet
let col = s:build_loc_info(line, stops, lnum, col, [])
if line isnot line[-1]
let lnum += 1
let col = a:indent
endif
unlet dict.instances
endfor
let [line, col] = s:build_loc_info(a:snippet, stops, line, col, a:indent)
" add zero tabstop if it doesn't exist and then link it to the highest stop
" number
let stops[0] = get(stops, 0,
\ { 'placeholder' : [], 'line' : line, 'col' : col })
\ { 'placeholder' : [], 'line' : lnum, 'col' : col })
let stop_count = max(keys(stops)) + 2
let stops[stop_count - 1] = stops[0]
return stop_count
endfunction
function! s:build_loc_info(snippet, stops, line, col, indent) abort
function! s:build_loc_info(snippet, stops, lnum, col, seen_items) abort
let stops = a:stops
let line = a:line
let lnum = a:lnum
let col = a:col
let pos = 0
let in_text = 0
let seen_items = a:seen_items
while pos < len(a:snippet)
let item = a:snippet[pos]
for item in a:snippet
if type(item) == type('')
if in_text
let line += 1
let col = a:indent
endif
let col += len(item)
let in_text = 1
elseif type(item) == type([])
let id = item[0]
if len(item) > 1 && type(item[1]) != type({})
let stops[id].line = line
let stops[id].col = col
let [line, col] = s:build_loc_info(item[1:], stops, line, col, a:indent)
let stub = item[-1]
let stub.line = lnum
let stub.col = col
call s:add_update_objects(stub, seen_items)
if len(item) > 2 && type(item[1]) != type({})
let col = s:build_loc_info(item[1:-2], stops, lnum, col, seen_items)
else
call s:add_mirror(stops, id, line, col, item)
let col += len(snipMate#placeholder_str(id, stops))
endif
let in_text = 0
endif
let pos += 1
unlet item " avoid E706
endwhile
endfor
return [line, col]
return col
endfunction
function! s:add_mirror(stops, id, line, col, item) abort
let stops = a:stops
let item = a:item
let stops[a:id].mirrors = get(stops[a:id], 'mirrors', [])
let mirror = get(a:item, 1, {})
let mirror.line = a:line
let mirror.col = a:col
call add(stops[a:id].mirrors, mirror)
if len(item) == 1
call add(item, mirror)
endif
function! s:add_update_objects(object, targets) abort
let targets = a:targets
for item in targets
let item.update_objects = get(item, 'update_objects', [])
call add(item.update_objects, a:object)
endfor
call add(targets, a:object)
endfunction
" reads a .snippets file

View File

@ -113,7 +113,7 @@ function! s:state_update_changes() dict abort
return self.remove()
endif
call self.update(self.cur_stop, change_len)
call self.update(self.cur_stop, change_len, change_len)
if !empty(self.mirrors)
call self.update_mirrors(change_len)
endif
@ -141,14 +141,37 @@ function! s:state_update_mirrors(change) dict abort
endif
endfor
call self.update(mirror, changeLen)
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)
let update = strpart(theline, 0, mirror.col - 1)
let update .= substitute(newWord, get(mirror, 'pat', ''), get(mirror, 'sub', ''), get(mirror, 'flags', ''))
let update .= strpart(theline, mirror.col + self.end_col - self.start_col - a:change - 1)
" 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
@ -179,17 +202,17 @@ function! s:state_find_update_objects(item) dict abort
return item.update_objects
endfunction
function! s:state_update(item, change_len) dict abort
function! s:state_update(item, change_len, mirror_change) dict abort
let item = a:item
if exists('item.update_objects')
let to_update = item.update_objects
else
let to_update = self.find_update_objects(a:item)
let item.update_objects = to_update
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
let obj.col += a:change_len
" 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

View File

@ -12,8 +12,7 @@ function! snipmate#legacy#process_snippet(snip) abort
else
let visual = ''
endif
let snippet = substitute(snippet, '\n\(\t\+\).\{-\}\zs{VISUAL}',
\ substitute(escape(visual, '%\'), "\n", "\n\\\\1", 'g'), 'g')
let snippet = s:substitute_visual(snippet, visual)
" Evaluate eval (`...`) expressions.
" Backquotes prefixed with a backslash "\" are ignored.
@ -118,6 +117,16 @@ function! snipmate#legacy#build_stops(snip, lnum, col, indent) abort
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

View File

@ -5,6 +5,7 @@ function! s:sfile() abort
endfunction
let s:parser_proto = {}
let s:special_chars = "$`\n"
function! s:new_parser(text) abort
let ret = copy(s:parser_proto)
@ -14,6 +15,7 @@ function! s:new_parser(text) abort
let ret.indent = 0
let ret.value = []
let ret.vars = {}
let ret.stored_lines = []
call ret.advance()
return ret
endfunction
@ -82,35 +84,56 @@ function! s:parser_varend() dict abort
endfunction
function! s:parser_placeholder() dict abort
return self.parse('}')
let ret = self.text('}')
return empty(ret) ? [''] : ret
endfunction
function! s:parser_subst() dict abort
let ret = {}
let ret.pat = join(self.text('/', 1))
let ret.pat = self.pat()
if self.same('/')
let ret.sub = join(self.text('/}'))
let ret.sub = self.pat(1)
endif
if self.same('/')
let ret.flags = join(self.text('}', 1))
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 = join(self.text('`', 1))
let str = self.string('`')
call self.same('`')
return snipmate#util#eval(str)
endfunction
function! s:parser_text(...) dict abort
let res = []
function! s:parser_string(till, ...) dict abort
let val = ''
if a:0 == 2 && a:2
let till = '\V' . escape(a:1, '\')
else
let till = '[`$' . (a:0 ? a:1 : '') . ']'
endif
let till = '\V\[' . escape(a:till, '\') . ']'
while self.pos < self.len
if self.same('\')
@ -120,11 +143,6 @@ function! s:parser_text(...) dict abort
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)
@ -135,55 +153,77 @@ function! s:parser_text(...) dict abort
endif
endwhile
call add(res, val)
return res
return val
endfunction
function! s:parser_parse(...) dict abort
let ret = a:0 ? [] : self.value
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 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])
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 add_to = self.expr()
if !empty(ret) && type(ret[-1]) == type('')
let ret[-1] .= add_to
else
call add(ret, add_to)
endif
let lines = split(self.expr(), "\n", 1)
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)
let lines = [self.string(a:till . s:special_chars)]
endif
if a:0 && self.next == a:1
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
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: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
@ -211,9 +251,59 @@ function! s:visual_placeholder(var, indent) abort
return content
endfunction
function! snipmate#parse#snippet(text) abort
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')

View File

@ -1,7 +1,6 @@
*SnipMate.txt* Plugin for using TextMate-style snippets in Vim.
SnipMate *snippet* *snippets* *SnipMate*
Last Change: December 27, 2009
1. Description |SnipMate-description|
2. Usage |SnipMate-usage|
@ -504,6 +503,15 @@ Perhaps some of these features will be added in a later release.
==============================================================================
CHANGELOG *SnipMate-changelog*
0.89 - 2016-05-29
-----------------
* Various regex updates to legacy parser Addition of double bang syntax to
* completely remove a snippet from lookup Group various SnipMate autocommands
* Support setting 'shiftwidth' to 0 Parser now operates linewise, adding some
* flexibility Mirror substitutions are more literal Mirror length is
* calculated correctly when substitutions occur
0.88 - 2015-04-04
-----------------

View File

@ -2,27 +2,27 @@ describe 'snippet parser'
before
function! Parse(snippet, ...)
let [snip, stops] = snipmate#parse#snippet(a:snippet)
return a:0 ? [snip, stops] : snip
let [snip, stops] = snipmate#parse#snippet(a:snippet, (a:0 ? a:1 : 1))
return (a:0 > 1 && a:2) ? [snip, stops] : snip
endfunction
let b:snipmate_visual = 'testvisual'
end
it 'parses numeric $id and ${id} vars as [id] lists'
let expect = [[1234567890]]
let expect = [[[1234567890]]]
Expect Parse('$1234567890') == expect
Expect Parse('${1234567890}') == expect
end
it 'disregards $ or ${ followed by a non-id'
Expect Parse('$x1') == ['x1']
Expect Parse('${x}1') == ['x}1']
Expect Parse('$VISUA1') == ['VISUA1']
Expect Parse('${VISUA}1') == ['VISUA}1']
Expect Parse('$x1') == [['x1']]
Expect Parse('${x}1') == [['x}1']]
Expect Parse('$VISUA1') == [['VISUA1']]
Expect Parse('${VISUA}1') == [['VISUA}1']]
end
it 'gathers references to each instance of each stop id'
let [snip, b:stops] = Parse('x$1x${2:x$1x}x$1x${1/a/b}x$VISUALx', 1)
let [snip, b:stops] = Parse('x$1x${2:x$1x}x$1x${1/a/b}x$VISUALx', 1, 1)
function! InstanceFound(list)
return !empty(filter(copy(b:stops[a:list[0]].instances),
\ 'v:val is a:list'))
@ -36,87 +36,107 @@ describe 'snippet parser'
unlet item " E732
endfor
endfunction
call CheckList(snip)
call CheckList(snip[0])
end
it 'parses mirror substitutions ${n/pat/sub} as [n, {...}]'
let expect = [[1, { 'pat' : 'abc', 'sub' : 'def' }]]
let expect = [[[1, { 'pat' : 'abc', 'sub' : 'def' }]]]
Expect Parse('${1/abc/def}') == expect
let expect[0][1].flags = ''
let expect[0][0][1].flags = ''
Expect Parse('${1/abc/def/}') == expect
let expect[0][1].flags = 'g'
let expect[0][0][1].flags = 'g'
Expect Parse('${1/abc/def/g}') == expect
end
it 'reads patterns literally except for "\/"'
Expect Parse('${1/\a\/b/\c\/d\}}') == [[[1, { 'pat' : '\a/b', 'sub' : '\c/d}' }]]]
end
it 'parses vars with placeholders as [id, placeholder] lists'
Expect Parse('${1:abc}') == [[1, 'abc']]
Expect Parse('${1:abc}') == [[[1, 'abc']]]
end
it 'evaluates backtick expressions'
Expect Parse('`fnamemodify("x.y", ":r")`') == ['x']
Expect Parse('`fnamemodify("x.y", ":r")`') == [['x']]
end
it 'parses placeholders for vars and other specials'
let text = 'a `fnamemodify("x.y", ":r")` ${2:(${3/a/b})}'
let expect = ['a x ', [2, '(', [3, { 'pat' : 'a', 'sub' : 'b' }], ')']]
Expect Parse(text) == expect
Expect Parse(printf('${1:%s}', text)) == [[1] + expect]
Expect Parse(text) == [expect]
Expect Parse(printf('${1:%s}', text)) == [[[1] + expect]]
end
it 'converts tabs according to &et, &sts, &sw, &ts'
" &noet -> leave tabs alone
setl noet
Expect Parse("abc\tdef\n\t\tghi") == ["abc\tdef", "\t\tghi"]
Expect Parse("abc\tdef\n\t\tghi") == [["abc\tdef"], ["\t\tghi"]]
" &et -> &sts or &sw
setl et sts=2 sw=3
Expect Parse("abc\tdef\n\t\tghi") == ["abc def", " ghi"]
Expect Parse("abc\tdef\n\t\tghi") == [["abc def"], [" ghi"]]
setl et sts=0 sw=3
Expect Parse("abc\tdef\n\t\tghi") == ["abc def", " ghi"]
Expect Parse("abc\tdef\n\t\tghi") == [["abc def"], [" ghi"]]
setl et sts=-1 sw=3
Expect Parse("abc\tdef\n\t\tghi") == ["abc def", " ghi"]
Expect Parse("abc\tdef\n\t\tghi") == [["abc def"], [" ghi"]]
" See #227
if exists('*shiftwidth')
setl et sts=0 sw=0 ts=3
Expect Parse("abc\tdef\n\t\tghi") == ["abc def", " ghi"]
Expect Parse("abc\tdef\n\t\tghi") == [["abc def"], [" ghi"]]
endif
end
it 'parses backslashes as escaping the next character or joining lines'
Expect Parse('x\x') == ['xx']
Expect Parse('x\\x') == ['x\x']
Expect Parse("x\\\nx") == ['xx']
Expect Parse('x\$1') == ['x$1']
Expect Parse('${1:\}}') == [[1, '}']]
Expect Parse('${1/\//\}}') == [[1, { 'pat' : '/', 'sub' : '}' }]]
Expect Parse('`fnamemodify("\`.x", ":r")`') == ['`']
Expect Parse('\`x\`') == ['`x`']
Expect Parse('x\x') == [['xx']]
Expect Parse('x\\x') == [['x\x']]
Expect Parse("x\\\nx") == [['xx']]
Expect Parse('x\$1') == [['x$1']]
Expect Parse('${1:\}}') == [[[1, '}']]]
Expect Parse('`fnamemodify("\`.x", ":r")`') == [['`']]
Expect Parse('\`x\`') == [['`x`']]
end
it 'splits text at newlines'
Expect Parse("x\nx") == ['x', 'x']
Expect Parse("x\nx") == [['x'], ['x']]
end
it 'joins evaluated expressions to surrounding text on the same line'
let g:foo = 'bar'
Expect Parse("x`g:foo`x") == ['xbarx']
Expect Parse("x`g:foo`\nx") == ['xbar', 'x']
Expect Parse("x\n`g:foo`x") == ['x', 'barx']
end
it 'adds empty strings before/after vars if at the start/end of a line'
Expect Parse("x$1\nx") == ['x', [1], '', 'x']
Expect Parse("x\n$1x") == ['x', '', [1], 'x']
Expect Parse("x`g:foo`x") == [['xbarx']]
Expect Parse("x`g:foo`\nx") == [['xbar'], ['x']]
Expect Parse("x\n`g:foo`x") == [['x'], ['barx']]
end
it 'expands $VISUAL placeholders with any indents'
Expect Parse("x$VISUALx") == ['xtestvisualx']
Expect Parse("x$VISUALx") == [['xtestvisualx']]
let b:snipmate_visual = " foo\nbar\n baz"
setl noet
Expect Parse("\tx\n\t$VISUAL\nx") == ["\tx", "\t foo", "\tbar", "\t baz", "x"]
Expect Parse("\tx\n\t$VISUAL\nx") == [["\tx"], ["\t foo"], ["\tbar"],
\ ["\t baz"], ["x"]]
end
it 'determines which var with an id is the stop'
let [snip, stops] = Parse("$1$1$1", 0, 1)
Expect snip == [[[1, "", stops[1]], [1, {}], [1, {}]]]
let [snip, stops] = Parse("$1${1}$1", 0, 1)
Expect snip == [[[1, "", stops[1]], [1, {}], [1, {}]]]
let [snip, stops] = Parse("$1${1:}$1", 0, 1)
Expect snip == [[[1, {}], [1, "", stops[1]], [1, {}]]]
end
it 'picks the first of many possible stops'
let [snip, stops] = Parse("$1${1:foo}${1:bar}", 0, 1)
Expect snip == [[[1, {}], [1, "foo", stops[1]], [1, {}]]]
end
it 'represents empty lines as an empty string'
Expect Parse("foo\n\nbar") == [['foo'], [''], ['bar']]
end
end