1
0
mirror of https://github.com/amix/vimrc synced 2025-07-07 08:45:00 +08:00

Use sources_non_forked folder for pathogen path, with sources_non_forked_fallback folder as fallback.

This commit is contained in:
Wu Tingfeng
2022-11-21 22:56:20 +08:00
parent dddd2e4152
commit d9555d618c
1756 changed files with 4 additions and 250 deletions

View File

@ -1,3 +0,0 @@
doc/tags
*.swp
.DS_Store

View File

@ -1,54 +0,0 @@
# Contributors #
SnipMate was originally authored by Michael Sanders
([Vim](http://www.vim.org/account/profile.php?user_id=16544),
[GitHub](https://github.com/msanders)).
It is currently maintained by [Rok Garbas](rok@garbas.si), [Marc
Weber](marco-oweber@gmx.de), and [Adnan Zafar](https://github.com/ajzafar) with
additional contributions from:
* [907th](https://github.com/907th)
* [adkron](https://github.com/adkron)
* [alderz](https://github.com/alderz)
* [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)
* [henrik](https://github.com/henrik)
* [holizz](https://github.com/holizz)
* [honza](https://github.com/honza)
* [hpesoj](https://github.com/hpesoj)
* [ironcamel](https://github.com/ironcamel)
* [jb55](https://github.com/jb55)
* [jbernard](https://github.com/jbernard)
* [jherdman](https://github.com/jherdman)
* [kozo2](https://github.com/kozo2)
* [lilydjwg](https://github.com/lilydjwg)
* [lpil](https://github.com/lpil)
* [marutanm](https://github.com/marutanm)
* [MicahElliott](https://github.com/MicahElliott)
* [mikeastock](https://github.com/mikeastock)
* [muffinresearch](https://github.com/muffinresearch)
* [munyari](https://github.com/munyari)
* [nickelization](https://github.com/nickelization)
* [pielgrzym](https://github.com/pielgrzym)
* [pose](https://github.com/pose)
* [r00k](https://github.com/r00k)
* [radicalbit](https://github.com/radicalbit)
* [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)
* [steveno](https://github.com/steveno)
* [taq](https://github.com/taq)
* [thisgeek](https://github.com/thisgeek)
* [tomushkin](https://github.com/tomushkin)
* [trusktr](https://github.com/trusktr)
* [Xandaros](https://github.com/Xandaros)

View File

@ -1,187 +0,0 @@
# SnipMate #
SnipMate aims to provide support for textual snippets, similar to TextMate or
other Vim plugins like [UltiSnips][ultisnips]. For
example, in C, typing `for<tab>` could be expanded to
for (i = 0; i < count; i++) {
/* code */
}
with successive presses of tab jumping around the snippet.
Originally authored by [Michael Sanders][msanders], SnipMate was forked in 2011
after a stagnation in development. This fork is currently maintained by [Rok
Garbas][garbas], [Marc Weber][marcweber], and [Adnan Zafar][ajzafar].
## Installing SnipMate ##
We recommend one of the following methods for installing SnipMate and its
dependencies. SnipMate depends on [vim-addon-mw-utils][mw-utils] and
[tlib][tlib].
> **NOTE:** SnipMate does not ship with any snippets out of the box. We suggest
looking at the [vim-snippets][vim-snippets] repository.
* Using [VAM][vam], add `vim-snippets` to the list of packages to be installed.
* Using [Pathogen][pathogen], run the following commands:
% cd ~/.vim/bundle
% git clone https://github.com/tomtom/tlib_vim.git
% git clone https://github.com/MarcWeber/vim-addon-mw-utils.git
% git clone https://github.com/garbas/vim-snipmate.git
# Optional:
% git clone https://github.com/honza/vim-snippets.git
* Using [Vundle][vundle], add the following to your `vimrc` then run
`:PluginInstall`
Plugin 'MarcWeber/vim-addon-mw-utils'
Plugin 'tomtom/tlib_vim'
Plugin 'garbas/vim-snipmate'
" Optional:
Plugin 'honza/vim-snippets'
## Using SnipMate ##
Press <tab> and try :SnipMateOpenSnippetFiles for starting.
Also see doc/SnipMate.txt to learn all SnipMate
## FAQ ##
> SnipMate doesn't work / My snippets aren't triggering
Try all of the following:
* Check that SnipMate is loaded. This can be done by looking for
`<Plug>snipMateTrigger` and similar maps in the output of `:imap`.
Additionally make sure either `<Plug>snipMateTrigger` or
`<Plug>snipMateNextOrTrigger` is mapped to the key you expect.
* Check that the snippets file you mean to use exists, and that it contains the
snippet you're trying to expand.
* Check that your snippets file is located inside a `foo/snippets` directory,
where `foo` is a path listed in your `runtimepath`.
* Check that your snippets file is in scope by either the filetype matching the
path of the snippet file or the scope explicitly loaded.
* Check if any snippets from your snippets file are available. This can be done
with the "show available snips" map, by default bound to `<C-R><Tab>` in
insert mode.
If all of the above check out, please open an issue stating your Vim version,
a sample snippet, and a description of exactly what happens when you try to
trigger a snippet.
> How does SnipMate determine which snippets to load? How can I separate, for
> example, my Rails snippets from my Ruby snippets?
Primarily SnipMate looks at the `'filetype'` and `'syntax'` settings. Taking
"scopes" from these options, it looks in each `snippets/` directory in
`'runtimepath'` for files named `scope.snippets`, `scope/*.snippets`, or
`scope_*.snippets`.
However we understand this may not allow for the flexibility desired by some
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 = get(g:, 'snipMate', {}) " Allow for vimrc re-sourcing
let g:snipMate.scope_aliases = {}
let g:snipMate.scope_aliases['ruby'] = 'ruby,rails'
will load the `ruby-rails` scope whenever the `ruby` scope is active. The
`:SnipMateLoadScope foo` command will always load the foo scope in the current
buffer. The [vim-rails](https://github.com/tpope/vim-rails) plugin automatically
does `:SnipMateLoadScope rails` when editing a Rails project for example.
> What are the snippet parser versions and what's the difference between them?
Originally SnipMate used regex to parse a snippet. Determining where stops were,
what the placeholders were, where mirrors were, etc. were all done with regex.
Needless to say this was a little fragile. When the time came for a rewritten
parser, some incompatibilities were a little necessary. Rather than break
everyone's snippets everywhere, we provided both the new (version 1) and the old
(version 0) and let the user choose between them.
Version 0 is considered legacy and not a lot of effort is going to go into
improving or even maintaining it. Version 1 is the future, and one can expect
new features to only exist for version 1 users. A full list of differences can
be found in the docs at `:h SnipMate-parser-versions`.
## 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
* Remove expansion guards
* Add `:SnipMateLoadScope` command and buffer-local scope aliases
* Load `<scope>_*.snippets` files
* Use CursorMoved autocmd events entirely
* The nested branch has been merged
* A new snippet parser has been added. The g:snipmate.version as well as
version lines in snippet files determines which is used
* The new parser supports tab stops placed within placeholders,
substitutions, non-consecutive stop numbers, and fewer ambiguities
* The stop jumping code has been updated
* Tests have been added for the jumping code and the new parser
* The override branch has been merged
* The g:snipMate.override option is added. When enabled, if two snippets
share the same name, the later-loaded one is kept and the other discarded
* Override behavior can be enabled on a per-snippet basis with a bang (!) in
the snippet file
* Otherwise, SnipMate tries to preserve all snippets loaded
* Fix bug with mirrors in the first column
* Fix bug with tabs in indents ([#143][143])
* Fix bug with mirrors in placeholders
* Fix reading single snippet files
* Fix the use of the visual map at the end of a line
* Fix expansion of stops containing only the zero tab stop
* Remove select mode mappings
* Indent visual placeholder expansions and remove extraneous lines ([#177][177]
and [#178][178])
### 0.87 - 2014-01-04 ###
* Stop indenting empty lines when expanding snippets
* Support extends keyword in .snippets files
* Fix visual placeholder support
* Add zero tabstop support
* Support negative 'softtabstop'
* Add g:snipMate_no_default_aliases option
* Add <Plug>snipMateTrigger for triggering an expansion inside a snippet
* Add snipMate#CanBeTriggered() function
[ultisnips]: https://github.com/sirver/ultisnips
[msanders]: https://github.com/msanders
[garbas]: https://github.com/garbas
[marcweber]: https://github.com/marcweber
[ajzafar]: https://github.com/ajzafar
[mw-utils]: https://github.com/marcweber/vim-addon-mw-utils
[tlib]: https://github.com/tomtom/tlib_vim
[vim-snippets]: https://github.com/honza/vim-snippets
[vam]: https://github.com/marcweber/vim-addon-manager
[pathogen]: https://github.com/tpope/vim-pathogen
[vundle]: https://github.com/gmarik/vundle
[143]: https://github.com/garbas/vim-snipmate/issues/143
[177]: https://github.com/garbas/vim-snipmate/issues/177
[178]: https://github.com/garbas/vim-snipmate/issues/178

View File

@ -1,12 +0,0 @@
{
"name" : "snipMate",
"version" : "dev",
"author" : "Michael Sanders -> original project http://github.com/msanders/snipmate.vim",
"maintainer" : "Rok Garbas / Marc Weber",
"repository" : {"type": "git", "url": "git://github.com/garbas/vim-snipmate.git"},
"dependencies" : {
"vim-addon-mw-utils": {},
"tlib": {}
},
"description" : "snipMate.vim aims to be a concise vim script that implements some of TextMate's snippets features in Vim. See README.md to learn about the features this fork adds"
}

View File

@ -1,46 +0,0 @@
" snipMate maps
" These maps are created here in order to make sure we can reliably create maps
" after SuperTab.
let s:save_cpo = &cpo
set cpo&vim
function! s:map_if_not_mapped(lhs, rhs, mode) abort
let l:unique = s:overwrite ? '' : ' <unique>'
if !hasmapto(a:rhs, a:mode)
silent! exe a:mode . 'map' . l:unique a:lhs a:rhs
endif
endfunction
if !exists('g:snips_no_mappings') || !g:snips_no_mappings
if exists('g:snips_trigger_key')
echom 'g:snips_trigger_key is deprecated. See :h snipMate-mappings'
exec 'imap <unique>' g:snips_trigger_key '<Plug>snipMateTrigger'
exec 'smap <unique>' g:snips_trigger_key '<Plug>snipMateSNext'
exec 'xmap <unique>' g:snips_trigger_key '<Plug>snipMateVisual'
else
" Remove SuperTab map if it exists
let s:overwrite = maparg('<Tab>', 'i') ==? '<Plug>SuperTabForward'
call s:map_if_not_mapped('<Tab>', '<Plug>snipMateNextOrTrigger', 'i')
call s:map_if_not_mapped('<Tab>', '<Plug>snipMateNextOrTrigger', 's')
let s:overwrite = 0
call s:map_if_not_mapped('<Tab>', '<Plug>snipMateVisual', 'x')
endif
if exists('g:snips_trigger_key_backwards')
echom 'g:snips_trigger_key_backwards is deprecated. See :h snipMate-mappings'
exec 'imap <unique>' g:snips_trigger_key_backwards '<Plug>snipMateIBack'
exec 'smap <unique>' g:snips_trigger_key_backwards '<Plug>snipMateSBack'
else
let s:overwrite = maparg('<S-Tab>', 'i') ==? '<Plug>SuperTabBackward'
call s:map_if_not_mapped('<S-Tab>', '<Plug>snipMateBack', 'i')
call s:map_if_not_mapped('<S-Tab>', '<Plug>snipMateBack', 's')
let s:overwrite = 0
endif
call s:map_if_not_mapped('<C-R><Tab>', '<Plug>snipMateShow', 'i')
endif
let &cpo = s:save_cpo
" vim:noet:

View File

@ -1,663 +0,0 @@
" config which can be overridden (shared lines)
if !exists('g:snipMate')
let g:snipMate = {}
endif
try
call tlib#input#List('mi', '', [])
catch /.*/
echoe "tlib is missing. See install instructions at ".expand('<sfile>:h:h').'/README.md'
endtry
fun! Filename(...) abort
let filename = expand('%:t:r')
if filename == '' | return a:0 == 2 ? a:2 : '' | endif
return !a:0 || a:1 == '' ? filename : substitute(a:1, '$1', filename, 'g')
endf
let s:cache = {}
function! snipMate#expandSnip(snip, version, col) abort
let lnum = line('.')
let col = a:col
let line = getline(lnum)
let indent = match(line, '\S\|$') + 1
let b:snip_state = snipmate#jumping#state()
if a:version == 1
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)
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)
endif
" Abort if the snippet is empty
if empty(snippet)
return ''
endif
let col = s:insert_snippet_text(snippet, lnum, col, indent)
" Open any folds snippet expands into
if &foldenable
silent! exec lnum . 'foldopen!'
endif
aug snipmate_changes
au CursorMoved,CursorMovedI <buffer> if exists('b:snip_state') |
\ call b:snip_state.update_changes() |
\ else |
\ silent! au! snipmate_changes * <buffer> |
\ endif
aug END
let b:snip_state.stop_no = 0
return b:snip_state.set_stop(0)
endfunction
function! s:insert_snippet_text(snippet, lnum, col, indent)
let line = getline(a:lnum)
let col = a:col
let snippet = type(a:snippet) == type([]) ? a:snippet : split(a:snippet, "\n", 1)
let lnum = a:lnum
" Keep text after the cursor
let afterCursor = strpart(line, col - 1)
if afterCursor != "\t" && afterCursor != ' '
let line = strpart(line, 0, col - 1)
else
let afterCursor = ''
" For some reason the cursor needs to move one right after this
if line != '' && col == 1 && &ve != 'all' && &ve != 'onemore'
let col += 1
endif
endif
call setline(lnum, '')
call append(lnum, repeat([''], len(snippet) - 1))
for item in snippet
let add = lnum == a:lnum ? line : strpart(line, 0, a:indent - 1)
if !(empty(item) || (type(item) == type([]) && empty(item[0])))
if type(item) == type([])
call setline(lnum, add .
\ snipMate#sniplist_str(item, b:snip_state.stops))
else
call setline(lnum, add .
\ substitute(item, printf('%s\d\+\|%s{\d\+.\{-}}',
\ g:snipmate#legacy#sigil, g:snipmate#legacy#sigil),
\ '', 'g'))
endif
endif
let lnum += 1
endfor
call setline(lnum - 1, getline(lnum - 1) . afterCursor)
return col
endfunction
function! snipMate#placeholder_str(num, stops) abort
return snipMate#sniplist_str(a:stops[a:num].placeholder, a:stops)
endfunction
function! snipMate#sniplist_str(snippet, stops) abort
let str = ''
let pos = 0
let add_to = 1
let seen_stops = []
while pos < len(a:snippet)
let item = a:snippet[pos]
if type(item) == type('')
let str .= item
elseif type(item) == type([])
let placeholder = snipMate#placeholder_str(item[0], a:stops)
if len(item) > 1 && type(item[1]) == type({})
let placeholder = substitute(placeholder,
\ get(item[1], 'pat', ''),
\ get(item[1], 'sub', ''),
\ get(item[1], 'flags', ''))
endif
let str .= placeholder
endif
let pos += 1
unlet item " avoid E706
endwhile
return str
endfunction
function! s:build_stops(snippet, stops, lnum, col, indent) abort
let stops = a:stops
let lnum = a:lnum
let col = a:col
for line in a:snippet
let col = s:build_loc_info(line, stops, lnum, col, [])
if line isnot a:snippet[-1]
let lnum += 1
let col = a:indent
endif
endfor
" 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' : 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, lnum, col, seen_items) abort
let stops = a:stops
let lnum = a:lnum
let col = a:col
let pos = 0
let in_text = 0
let seen_items = a:seen_items
for item in a:snippet
if type(item) == type('')
let col += len(item)
elseif type(item) == type([])
let id = item[0]
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
let col += len(snipMate#placeholder_str(id, stops))
endif
let in_text = 0
endif
unlet item " avoid E706
endfor
return col
endfunction
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
" returns list of
" ['triggername', 'name', 'contents']
" if triggername is not set 'default' is assumed
" TODO: better error checking
fun! snipMate#ReadSnippetsFile(file) abort
let result = []
let new_scopes = []
if !filereadable(a:file) | return [result, new_scopes] | endif
let inSnip = 0
let line_no = 0
let snipversion = get(g:snipMate, 'snippet_version', 0)
for line in readfile(a:file) + ["\n"]
let line_no += 1
if inSnip && (line[0] == "\t" || line == '')
let content .= strpart(line, 1)."\n"
continue
elseif inSnip
call add(result, [trigger, name,
\ content[:-2], bang, snipversion])
let inSnip = 0
endif
if line[:6] == 'snippet'
let inSnip = 1
let bang = (line[7] == '!')
if bang
let bang += line[8] == '!'
endif
let trigger = strpart(line, 8 + bang)
let name = ''
let space = stridx(trigger, ' ') + 1
if space " Process multi snip
let name = strpart(trigger, space)
let trigger = strpart(trigger, 0, space - 1)
endif
let content = ''
if trigger =~ '^\s*$' " discard snippets with empty triggers
echom 'Invalid snippet in' a:file 'near line' line_no
let inSnip = 0
endif
elseif line[:6] == 'extends'
call extend(new_scopes, map(split(strpart(line, 8)),
\ "substitute(v:val, ',*$', '', '')"))
elseif line[:6] == 'version'
let snipversion = +strpart(line, 8)
endif
endfor
return [result, new_scopes]
endf
function! s:GetScopes() abort
let ret = exists('b:snipMate.scope_aliases') ? copy(b:snipMate.scope_aliases) : {}
let global = get(g:snipMate, 'scope_aliases', {})
for alias in keys(global)
if has_key(ret, alias)
let ret[alias] = join(split(ret[alias], ',')
\ + split(global[alias], ','), ',')
else
let ret[alias] = global[alias]
endif
endfor
return ret
endfunction
" adds scope aliases to list.
" returns new list
" the aliases of aliases are added recursively
fun! s:AddScopeAliases(list) abort
let did = {}
let scope_aliases = s:GetScopes()
let new = a:list
let new2 = []
while !empty(new)
for i in new
if !has_key(did, i)
let did[i] = 1
call extend(new2, split(get(scope_aliases,i,''),','))
endif
endfor
let new = new2
let new2 = []
endwhile
return keys(did)
endf
augroup SnipMateSource
au SourceCmd *.snippet,*.snippets call s:source_snippet()
augroup END
function! s:info_from_filename(file) abort
let parts = split(fnamemodify(a:file, ':r'), '/')
let snipidx = len(parts) - index(reverse(copy(parts)), 'snippets') - 1
let rtp_prefix = join(parts[(snipidx -
\ (parts[snipidx - 1] == 'after' ? 3 : 2)):snipidx - 1], '/')
let trigger = get(parts, snipidx + 2, '')
let desc = get(parts, snipidx + 3, get(g:snipMate, 'override', 0) ?
\ '' : fnamemodify(a:file, ':t'))
return [rtp_prefix, trigger, desc]
endfunction
function! s:source_snippet() abort
let file = expand('<afile>:p')
let [rtp_prefix, trigger, desc] = s:info_from_filename(file)
let new_snips = []
if fnamemodify(file, ':e') == 'snippet'
call add(new_snips, [trigger, desc, join(readfile(file), "\n"), 0,
\ get(g:snipMate, 'snippet_version', 0)])
else
let [snippets, extends] = s:CachedSnips(file)
let new_snips = deepcopy(snippets)
call extend(s:lookup_state.extends, extends)
endif
for snip in new_snips
if get(g:snipMate, 'override', 0)
let snip[1] = join([s:lookup_state.scope, snip[1]])
else
let snip[1] = join([s:lookup_state.scope, rtp_prefix,
\ empty(snip[1]) ? desc : snip[1]])
endif
endfor
call extend(s:lookup_state.snips, new_snips)
endfunction
function! s:CachedSnips(file) abort
let mtime = getftime(a:file)
if has_key(s:cache, a:file) && s:cache[a:file].mtime >= mtime
return s:cache[a:file].contents
endif
let s:cache[a:file] = {}
let s:cache[a:file].mtime = mtime
let s:cache[a:file].contents = snipMate#ReadSnippetsFile(a:file)
return s:cache[a:file].contents
endfunction
function! s:snippet_filenames(scope, trigger) abort
let mid = ['', '_*', '/*']
let mid += map(copy(mid), "'/' . a:trigger . '*' . v:val")
call map(mid, "'snippets/' . a:scope . v:val . '.snippet'")
return map(mid[:2], 'v:val . "s"') + mid[3:]
endfunction
function! snipMate#SetByPath(dict, trigger, path, snippet, bang, snipversion) abort
let d = a:dict
if a:bang == 2
unlet! d[a:trigger]
return
elseif !has_key(d, a:trigger) || a:bang == 1
let d[a:trigger] = {}
endif
let d[a:trigger][a:path] = [a:snippet, a:snipversion]
endfunction
if v:version < 704 || has('win32')
function! s:Glob(path, expr)
let res = []
for p in split(a:path, ',')
let h = split(fnamemodify(a:expr, ':h'), '/')[0]
if isdirectory(p . '/' . h)
call extend(res, split(glob(p . '/' . a:expr), "\n"))
endif
endfor
return filter(res, 'filereadable(v:val)')
endfunction
else
function! s:Glob(path, expr)
return split(globpath(a:path, a:expr), "\n")
endfunction
endif
" default triggers based on paths
function! snipMate#DefaultPool(scopes, trigger, result) abort
let scopes = s:AddScopeAliases(a:scopes)
let scopes_done = []
let s:lookup_state = {}
let s:lookup_state.snips = []
while !empty(scopes)
let scope = remove(scopes, 0)
let s:lookup_state.scope = scope
let s:lookup_state.extends = []
for expr in s:snippet_filenames(scope, escape(a:trigger, "*[]?{}`'$|#%"))
for path in s:snippet_dirs()
for file in s:Glob(path, expr)
source `=file`
endfor
endfor
endfor
call add(scopes_done, scope)
call extend(scopes, s:lookup_state.extends)
call filter(scopes, 'index(scopes_done, v:val) == -1')
endwhile
for [trigger, desc, contents, bang, snipversion] in s:lookup_state.snips
if trigger =~ '\V\^' . escape(a:trigger, '\')
call snipMate#SetByPath(a:result, trigger, desc, contents, bang, snipversion)
endif
endfor
endfunction
" return a dict of snippets found in runtimepath matching trigger
" scopes: list of scopes. usually this is the filetype. eg ['c','cpp']
" trigger may contain glob patterns. Thus use '*' to get all triggers
"
fun! snipMate#GetSnippets(scopes, trigger) abort
let result = {}
for F in values(g:snipMateSources)
call funcref#Call(F, [a:scopes, a:trigger, result])
endfor
return result
endf
function! s:snippet_dirs() abort
return get(g:snipMate, 'snippet_dirs', split(&rtp, ','))
endfunction
function! snipMate#OpenSnippetFiles() abort
let files = []
let scopes_done = []
let exists = []
let notexists = []
for scope in s:AddScopeAliases(snipMate#ScopesByFile())
let files += s:snippet_filenames(scope, '')
endfor
call filter(files, "v:val !~# '\\*'")
for path in s:snippet_dirs()
let fullpaths = map(copy(files), 'printf("%s/%s", path, v:val)')
let exists += filter(copy(fullpaths), 'filereadable(v:val)')
let notexists += map(filter(copy(fullpaths),
\ 'v:val =~# "\.snippets" && !filereadable(v:val)'),
\ '"does not exist: " . v:val')
endfor
let all = exists + notexists
let select = tlib#input#List('mi', 'select files to be opened in splits', all)
for idx in select
exec 'sp' all[idx - 1]
endfor
endfunction
fun! snipMate#ScopesByFile() abort
" duplicates are removed in AddScopeAliases
return filter(funcref#Call(g:snipMate.get_scopes), "v:val != ''")
endf
" used by both: completion and insert snippet
fun! snipMate#GetSnippetsForWordBelowCursor(word, exact) abort
" Split non-word characters into their own piece
" so 'foo.bar..baz' becomes ['foo', '.', 'bar', '.', '.', 'baz']
" First split just after a \W and then split each resultant string just
" before a \W
let parts = filter(tlib#list#Flatten(
\ map(split(a:word, '\W\zs'), 'split(v:val, "\\ze\\W")')),
\ '!empty(v:val)')
" Only look at the last few possibilities. Too many can be slow.
if len(parts) > 5
let parts = parts[-5:]
endif
let lookups = [a:word]
let lookup = ''
for w in reverse(parts)
let lookup = w . lookup
if index(lookups, lookup) == -1
call add(lookups, lookup)
endif
endfor
" Remove empty lookup entries, but only if there are other nonempty lookups
if len(lookups) > 1
call filter(lookups, 'v:val != ""')
endif
let matching_snippets = []
let snippet = ''
" prefer longest word
for word in lookups
let g:snipMate.word = word
for [k,snippetD] in items(funcref#Call(g:snipMate['get_snippets'], [snipMate#ScopesByFile(), word]))
" hack: require exact match
if a:exact && k !=# word
continue
endif
call add(matching_snippets, [k, snippetD])
if a:exact
break
endif
endfor
endfor
return matching_snippets
endf
" snippets: dict containing snippets by name
" usually this is just {'default' : snippet_contents }
fun! s:ChooseSnippet(snippets) abort
let snippet = []
let keys = keys(a:snippets)
let i = 1
for snip in keys
let snippet += [i.'. '.snip]
let i += 1
endfor
if len(snippet) == 1 || get(g:snipMate, 'always_choose_first', 0) == 1
" there's only a single snippet, choose it
let idx = 0
else
let idx = tlib#input#List('si','select snippet by name',snippet) -1
if idx == -1
return ''
endif
endif
" if a:snippets[..] is a String Call returns it
" If it's a function or a function string the result is returned
return funcref#Call(a:snippets[keys(a:snippets)[idx]])
endf
fun! snipMate#WordBelowCursor() abort
return matchstr(getline('.'), '\S\+\%' . col('.') . 'c')
endf
fun! snipMate#GetSnippetsForWordBelowCursorForComplete(word) abort
let matches = snipMate#GetSnippetsForWordBelowCursor(a:word, 0)
let snippets = []
for [trigger, dict] in matches
if get(g:snipMate, 'description_in_completion', 0)
call extend(snippets, map(keys(dict),
\ '{ "word" : trigger, "menu" : v:val, "dup" : 1 }'))
else
call add(snippets, { "word" : trigger })
endif
endfor
return filter(snippets,
\ 'v:val.word =~# "\\V\\^' . escape(a:word, '"\') . '"')
endf
fun! snipMate#CanBeTriggered() abort
let word = snipMate#WordBelowCursor()
let matches = snipMate#GetSnippetsForWordBelowCursorForComplete(word)
return len(matches) > 0
endf
fun! snipMate#ShowAvailableSnips() abort
let col = col('.')
let word = snipMate#WordBelowCursor()
let matches = snipMate#GetSnippetsForWordBelowCursorForComplete(word)
" Pretty hacky, but really can't have the tab swallowed!
if len(matches) == 0
call feedkeys(g:snipMate['no_match_completion_feedkeys_chars'], 'n')
return ""
endif
call complete(col - len(word), sort(matches))
return ''
endf
" Pass an argument to force snippet expansion instead of triggering or jumping
function! snipMate#TriggerSnippet(...) abort
if exists('g:SuperTabMappingForward')
if g:SuperTabMappingForward == "<tab>"
let SuperTabPlug = maparg('<Plug>SuperTabForward', 'i')
if SuperTabPlug == ""
let SuperTabKey = "\<c-n>"
else
exec "let SuperTabKey = \"" . escape(SuperTabPlug, '<') . "\""
endif
elseif g:SuperTabMappingBackward == "<tab>"
let SuperTabPlug = maparg('<Plug>SuperTabBackward', 'i')
if SuperTabPlug == ""
let SuperTabKey = "\<c-p>"
else
exec "let SuperTabKey = \"" . escape(SuperTabPlug, '<') . "\""
endif
endif
endif
if pumvisible() " Update snippet if completion is used, or deal with supertab
if exists('SuperTabKey')
call feedkeys(SuperTabKey) | return ''
endif
call feedkeys("\<esc>a", 'n') " Close completion menu
" Once we've dismissed the completion menu, we have to cause this
" function to be executed over again, so that we actually get the
" snippet triggered. (Simply continuing to execute fails because
" we have to finish this function before the results of feedkeys take
" effect and dismiss the completion menu. Recursing also fails for
" similar reasons.)
if a:0 == 0
" Would be nice to have a more robust solution than manually
" branching on the arguments. I tried to do something like:
" call call(function('snipMate#TriggerSnippet'), a:000)
" But I couldn't quite get it working. Maybe somebody else with
" better vimscript skills can find a way to make it work, though?
call feedkeys("\<Plug>snipMateNextOrTrigger") | return ''
else
call feedkeys("\<Plug>snipMateTrigger") | return ''
endif
endif
if exists('b:snip_state') && a:0 == 0 " Jump only if no arguments
let jump = b:snip_state.jump_stop(0)
if type(jump) == 1 " returned a string
return jump
endif
endif
let word = matchstr(getline('.'), '\S\+\%'.col('.').'c')
let list = snipMate#GetSnippetsForWordBelowCursor(word, 1)
if empty(list)
let snippet = ''
else
let [trigger, snippetD] = list[0]
let snippet = s:ChooseSnippet(snippetD)
" Before expanding snippet, create new undo point |i_CTRL-G|
let &undolevels = &undolevels
let col = col('.') - len(trigger)
sil exe 's/\V'.escape(trigger, '/\.').'\%#//'
return snipMate#expandSnip(snippet[0], snippet[1], col)
endif
" should allow other plugins to register hooks instead (duplicate code)
if exists('SuperTabKey')
call feedkeys(SuperTabKey)
return ''
endif
return word == ''
\ ? "\<tab>"
\ : "\<c-r>=snipMate#ShowAvailableSnips()\<cr>"
endfunction
fun! snipMate#BackwardsSnippet() abort
if exists('b:snip_state') | return b:snip_state.jump_stop(1) | endif
if exists('g:SuperTabMappingForward')
if g:SuperTabMappingForward == "<s-tab>"
let SuperTabPlug = maparg('<Plug>SuperTabForward', 'i')
if SuperTabPlug == ""
let SuperTabKey = "\<c-n>"
else
exec "let SuperTabKey = \"" . escape(SuperTabPlug, '<') . "\""
endif
elseif g:SuperTabMappingBackward == "<s-tab>"
let SuperTabPlug = maparg('<Plug>SuperTabBackward', 'i')
if SuperTabPlug == ""
let SuperTabKey = "\<c-p>"
else
exec "let SuperTabKey = \"" . escape(SuperTabPlug, '<') . "\""
endif
endif
endif
" should allow other plugins to register hooks instead (duplicate code)
if exists('SuperTabKey')
call feedkeys(SuperTabKey)
return ''
endif
return "\<s-tab>"
endf
" vim:noet:sw=4:ts=4:ft=vim

View File

@ -1,47 +0,0 @@
" This file demonstrates
" - how to register your own snippet sources (call snipMate_python_demo#Activate() in ftplugin/python.vim)
" - implents a source which creates snippets based on python function
" definitions found in the current file
"
" Example:
"
" def abc(a,b,c=None)
" will create a snippet on the fly which looks like this:
" abc(${1:a}, ${2:b}, ${3:c=None})
fun! snipMate_python_demo#Activate() abort
if !exists('g:snipMateSources')
let g:snipMateSources = {}
endif
let g:snipMateSources['python'] = funcref#Function('snipMate_python_demo#FunctionsFromCurrentFileAndTags')
endf
fun! s:Add(dict, line, source, trigger) abort
let matched = matchlist(a:line,'def\s\+\([^( \t]\+\)[ \t]*(\([^)]*\)')
if len(matched) > 2
let name = matched[1]
" TODO: is this a glob?
if name !~ a:trigger | return | endif
let a:dict[name] = get(a:dict, name, {})
let sd = a:dict[name]
let args = []
let nr=1
for arg in split(matched[2], '\s*,\s*')
call add(args, '${'.nr.':'.arg.'}')
let nr+=1
endfor
let sd[a:source] = name.'('.join(args,', ').')'
endif
endf
fun! snipMate_python_demo#FunctionsFromCurrentFileAndTags(scopes, trigger, result) abort
" getting all might be too much
if a:trigger == '*' | return | endif
if index(a:scopes, 'python') < 0 | return | endif
for t in taglist('^'.a:trigger)
call s:Add(a:result, t.cmd, 'tags-' . t.filename, a:trigger)
endfor
for l in getline(0, line('$'))
call s:Add(a:result, l, 'current-file', a:trigger)
endfor
endf

View File

@ -1,228 +0,0 @@
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

View File

@ -1,139 +0,0 @@
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

View File

@ -1,323 +0,0 @@
" 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 = []
let target = 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)
" Remove trailing newline. See #245
if lines[-1] =~ '^\s*$' && self.next == "\n"
call remove(lines, -1)
endif
elseif var[0] >= 0
call add(target, 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(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
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)
if target isnot ret
call s:join_consecutive_strings(target)
call extend(self.stored_lines, target)
endif
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')

View File

@ -1,30 +0,0 @@
" 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

View File

@ -1,728 +0,0 @@
*SnipMate.txt* Plugin for using TextMate-style snippets in Vim.
SnipMate *snippet* *snippets* *SnipMate*
1. Description |SnipMate-description|
2. Usage |SnipMate-usage|
3. Interface and Settings |SnipMate-interface| |SnipMate-settings|
4. Snippets |SnipMate-snippets|
- Snippet files |SnipMate-snippet-files|
- Snippet syntax |SnipMate-syntax|
5. Snippet sources |SnipMate-snippet-sources|
6. Disadvantages to TextMate |SnipMate-disadvantages|
7. Contact |SnipMate-contact|
8. License |SnipMate-license|
For Vim version 7.0 or later.
This plugin only works if 'compatible' is not set.
{Vi does not have any of these features.}
SnipMate depends on vim-addon-mw-utils and tlib.
==============================================================================
DESCRIPTION *SnipMate-description*
SnipMate implements snippet features in Vim. A snippet is like a template,
reducing repetitive insertion of pieces of text. Snippets can contain
placeholders for modifying the text if necessary or interpolated code for
evaluation. For example, in C, typing "for" then pushing <Tab> could expand
to: >
for (i = 0; i < count; i++) {
/* code */
}
SnipMate is inspired by TextMate's snippet features.
==============================================================================
USAGE *SnipMate-usage*
Every snippet consists of an expansion and a trigger. Typing a trigger into
your buffer and then hitting your trigger key (<Tab> by default, see
|SnipMate-mappings|) will replace the trigger with the expansion text.
The expansion text can optionally include tab stops. When it does, upon
expansion of the snippet, the cursor is placed at the first one, and the user
can jump between each tab stop. Each of these tab stops can be represented by
default placeholder text. If such a placeholder is provided, then the text of
the placeholder can be repeated in the snippet at specified mirrors. Any edits
to the placeholder are instantly updated at every mirror.
SnipMate allows multiple snippets to use the same trigger. When triggered,
a list of all snippets with that trigger is provided and prompts for which
snippet to use.
*SnipMate-scopes*
SnipMate searches for snippets inside a directory named "snippets" inside each
entry in 'runtimepath'. Which files are loaded depends on 'filetype' and
'syntax'; see |SnipMate-syntax| for more information. Snippets are loaded and
refreshed automatically on demand.
Note: SnipMate does not ship with any snippets. In order to use it, the user
must either write their own snippets or obtain some from a repository like
https://github.com/honza/vim-snippets
==============================================================================
INTERFACE AND SETTINGS *SnipMate-interface* *SnipMate-settings*
*SnipMate-commands*
Commands~
*:SnipMateOpenSnippetFiles*
:SnipMateOpenSnippetFiles Opens a list of all valid snippet locations
based on the current scope |SnipMate-scopes|.
Only existing files and non-existing .snippets
files will be shown, with the existing files
shown first.
:SnipMateLoadScope[!] scope [scope ...]
Load snippets from additional scopes. Without
[!] the additional scopes are loaded only in
the current buffer. For example >
:SnipMateLoadScopes rails
< will load all rails.snippets in the current
buffer.
*SnipMate-options*
Options~
g:snips_author A variable used in some snippets in place of
the author's (your) name. Similar to
$TM_FULLNAME in TextMate. For example, >
snippet name
`g:snips_author`
< creates a snippet "name" that expands to your
name.
g:snipMate This |Dictionary| contains other SnipMate
options. In short add >
let g:snipMate = {}
< to your .vimrc before setting other SnipMate
options.
g:snipMate.scope_aliases A |Dictionary| associating certain filetypes
with other scopes |SnipMate-scopes|. The
entries consist of a filetype as the key and
a comma-separated list of aliases as the
value. For example, >
let g:snipMate.scope_aliases = {}
let g:snipMate.scope_aliases['ruby']
\ = 'ruby,ruby-rails'
< tells SnipMate that "ruby-rails" snippets in
addition to "ruby" snippets should be loaded
when editing files with 'filetype' set to
"ruby" or contains "ruby" as an entry in the
case of dotted filetypes. A buffer local
variant b:snipMate_scope_aliases is merged
with the global variant.
g:snipMate_no_default_aliases Note: This has been renamed to the following.
g:snipMate.no_default_aliases
When set to 1, prevents SnipMate from loading
default scope aliases. The defaults are:
Filetype Alias ~
cpp c
cu c
eruby eruby-rails,html
html javascript
mxml actionscript
objc c
php php,html,javascript
ur html,javascript
xhtml html
Individual defaults can be disabled by setting
them to an empty value: >
let g:snipMate.scope_aliases.php = ''
< will disable the default PHP alias.
Note: Setting this option does not disable
scope aliases entirely, only those made by
SnipMate itself. Any scope aliases created by
the user or someone else will still be in
effect.
g:snipMate.snippet_version
The snippet parser version to use. The
possible values are:
0 Use the older parser
1 Use the newer parser
If unset, SnipMate defaults to version 0. The
value of this option is also used for all
.snippet files. See |SnipMate-parser-versions|
for more information.
g:snipMate.override
As detailed below, when two snippets with the
same name and description are loaded, both are
kept and differentiated by the location of the
file they were in. When this option is enabled
(set to 1), the snippet originating in the
last loaded file is kept, similar to how Vim
maps and other settings work. Note: Load order
is determined by 'runtimepath'.
Duplicates are only dropped after reading one
snippet file. If multiple files contain a
snippet see always_choose_first
g:snipMate.always_choose_first
Always choose first snippet if there are
multiple left
g:snipMate.description_in_completion
If set to 1 (default is 0), snippet
descriptions will be included in the popup
menu used for snippet completion, like with
<Plug>snipMateShow.
g:snipMate['no_match_completion_feedkeys_chars']
A string inserted when no match for a trigger
is found. By default a tab is inserted
according to 'expandtab', 'tabstop', and
'softtabstop'. Set it to the empty string to
prevent anything from being inserted.
*SnipMate-mappings*
Mappings~
The mappings SnipMate uses can be customized with the |:map| commands. For
example, to change the key that triggers snippets and moves to the next
tab stop, >
:imap <C-J> <Plug>snipMateNextOrTrigger
:smap <C-J> <Plug>snipMateNextOrTrigger
Note: The noremap variants of the map commands must NOT be used.
The list of possible <Plug> mappings is as follows:
<Plug>snipMateNextOrTrigger Default: <Tab> Mode: Insert, Select
Jumps to the next tab stop or, if none exists,
try to expand a snippet. Use in both insert
and select modes.
<Plug>snipMateTrigger Default: unmapped Mode: Insert
Try to expand a snippet regardless of any
existing snippet expansion. If done within an
expanded snippet, the outer snippet's tab
stops are lost, unless expansion failed.
<Plug>snipMateBack Default: <S-Tab> Mode: Insert, Select
Jump to the previous tab stop, if it exists.
Use in both insert and select modes.
<Plug>snipMateShow Default: <C-R><Tab> Mode: Insert
Show all available snippets (that start with
the previous text, if it exists). Use in
insert mode.
<Plug>snipMateVisual Default: <Tab> Mode: Visual
See |SnipMate-visual|.
Additionally, <CR> is mapped in visual mode in .snippets files for retabbing
snippets.
==============================================================================
SNIPPETS *SnipMate-snippets*
*SnipMate-snippet-files*
Snippet Files ~
Note: SnipMate does not ship with any snippets.
SnipMate looks inside of each entry of 'rtp' (or |SnipMate-snippet-sources|)
for a directory named /snippets/. Based on the 'filetype' and 'syntax'
settings (dotted filetypes are parsed), the following files are read for
snippets: >
.../snippets/<scope>.snippets
.../snippets/<scope>_<name>.snippets
.../snippets/<scope>/<name>.snippets
.../snippets/<scope>/<trigger>.snippet
.../snippets/<scope>/<trigger>/<description>.snippet
where <scope> is a scope or 'filetype' or 'syntax', <name> is an arbitrary
name, <trigger> is the trigger for a snippet, and <description> is
a description used for |SnipMate-multisnip|. Snippets in the `_` scope (for
example `.../snippets/_.snippets`) are loaded for all filetypes.
A .snippet file defines a single snippet with the trigger (and description)
determined by the filename. The entire contents of the file are used as the
snippet expansion text.
Multiple snippets can be defined in *.snippets files. Each snippet definition
looks something like: >
snippet trigger optional description
expanded text
more expanded text
< *SnipMate-multisnip*
The description is optional. If it is left out, the description "default" is
used. When two snippets in the same scope have the same name and the same
description, SnipMate will try to preserve both. The g:snipMate.override
option disables this, in favor of keeping the last-loaded snippet. This can be
overridden on a per-snippet basis by defining the snippet with a bang (!): >
snippet! trigger optional description
expanded text
more expanded text
Two bangs will remove the trigger entirely from SnipMate's lookup. In this
case any snippet text is unused.
Note: Hard tabs in the expansion text are required. When the snippet is
expanded in the text and 'expandtab' is set, each tab will be replaced with
spaces based on 'softtabstop' if nonzero or 'shiftwidth' otherwise.
SnipMate currently provides two versions for the snippet parser. The
differences between them can be found at |SnipMate-parser-versions|. Which
version parser the snippets in a file should be used with can be specified
with a version line, e.g.: >
version 1
Specification of a version applies to the snippets following it. Multiple
version specifications can appear in a single file to intermix version 0 and
version 1 snippets. The default is determined by the
g:snipMate.snippet_version option. |SnipMate-options|
Comments can be made in .snippets files by starting a line with a # character.
However these can't be used inside of snippet definitions: >
# this is a correct comment
snippet trigger
expanded text
snippet another_trigger
# this isn't a comment!
expanded text
This should hopefully be clear with the included syntax highlighting.
*SnipMate-extends*
Borrowing from UltiSnips, .snippets files can also contain an extends
directive, for example: >
extends html, javascript, css
will tell SnipMate to also read html, javascript, and css snippets.
SNIPPET SYNTAX *snippet-syntax* *SnipMate-syntax*
As mentioned above, there are two versions of the snippet parser. They are
selected by the g:snipMate.snippet_version option (|SnipMate-options|) or the
version directive in .snippets files. Differences will be mentioned throughout
with a summary at |SnipMate-parser-versions|.
Anywhere in a snippet, a backslash escapes the character following it,
regardless of whether that character is special or not. That is, '\a' will
always result in an 'a' in the output. A single backslash can be output by
using '\\'.
*SnipMate-tabstops*
Tab stops~
When triggering a snippet, SnipMate will by default jump to the very end of
the snippet text. This can be changed through the use of tab stops: $1, $2,
and so on. After expansion, SnipMate will jump to the first tab stop. From
then on, the <Plug>snipMateNextOrTrigger map will jump to the next higher
numbered tabs top.
In the case of an ambiguity, for example if a stop occurs just before
a literal number, braces may be placed around the stop number to resolve it:
${3}79 is the third tab stop followed by the string "79".
NOTE: In the version 0 snippet parser, the braces are mandatory.
*SnipMate-zero-tabstop*
SnipMate will always stop at the special zero tab stop $0. Once it jumps to
the zero tab stop, snippet expansion is finished. If the zero tab stop is not
present in a definition, it will be put at the end.
For example, to place the cursor first on the id of a <div> tag, then on its
class, and finally end editing its contents: >
snippet div
<div id="$1" class="$2">
$0
</div>
< *SnipMate-placeholders*
In addition to being simply a location, each tab stop contains a placeholder,
or some default text. The placeholder can be specified for every tab stop
(including the zero tab stop) with a colon after the stop ID, as in
${1:default text}. The braces are required only when specifying a placeholder.
Once a tab stop with a placeholder is reached, the placeholder will be
selected in |Select-mode|. For example, >
snippet div
<div id="${1:id}" class="${2:class}">
$0
</div>
Finally, placeholders can contain mirrors and evaluations (detailed below)
and, in version 1 of the snippet parser, even entire other tab stops. If the
placeholder is edited, then these nested tab stops are removed and skipped
entirely.
NOTE: Version 1 of the snippet parser must be used! See
|SnipMate-parser-versions|.
For example, >
snippet div
<div${1: id="${2:id}"}${3: class="${4:class}"}>
$0
</div>
When expanded, this snippet selects the entirety of the id attribute. If this
stop is edited, then the second tab stop is removed and the third tab stop
becomes the next one. If the first tab stop is left unedited, then SnipMate
jumps to the second tab stop. This allows the user to use a single div snippet
that can be used for instances where the id or class attributes are desired
and those where they are not.
*SnipMate-mirrors*
Mirrors~
A mirror is simply a copy of a tab stop's text, updated as the tab stop is
edited. These look like a tab stop without a placeholder; $1 for example. In
the event that no placeholder is specified for a certain tab stop--say $1--the
first instance becomes the tab stop and the rest become mirrors.
Additionally, in version 1 of the parser, substitutions similar to
|:substitute| can be performed. For instance ${1/foo/bar/g} will replace all
instances of "foo" in the $1 mirror with "bar". This uses |substitute()|
behind the scenes.
Note: Just like with tab stops, braces can be used to avoid ambiguities: ${1}2
is a mirror of the first tab stop followed by a 2. Version 0 of the snippet
parser offers no way to resolve such ambiguities. Version 0 also requires that
a tabstop have a placeholder before its mirrors work.
As an example, >
snippet for
for ($1 = ${2:start}; ${1:i} < ${3:end}; $1${4:++}) {
${0:/* code */}
}
< *SnipMate-eval*
Expression Evaluation~
Snippets can contain Vim script expressions that are evaluated as the snippet
is expanded. Expressions are specified inside backticks: >
snippet date
`strftime("%Y-%m-%d")`
If the expression results in any Vim error, the error will be displayed (or
found in :messages) and the result of the expression will be the empty string.
Filename([{expr}] [, {defaultText}]) *SnipMate-Filename()*
Since the current filename is used often in snippets, a default function
has been defined for it in SnipMate.vim, appropriately called Filename().
With no arguments, the default filename without an extension is returned;
the first argument specifies what to place before or after the filename,
and the second argument supplies the default text to be used if the file
has not been named. "$1" in the first argument is replaced with the filename;
if you only want the filename to be returned, the first argument can be left
blank. Examples: >
snippet filename
`Filename()`
snippet filename_with_default
`Filename('', 'name')`
snippet filename_foo
`Filename('$1_foo')`
The first example returns the filename if it the file has been named, and an
empty string if it hasn't. The second returns the filename if it's been named,
and "name" if it hasn't. The third returns the filename followed by "_foo" if
it has been named, and an empty string if it hasn't.
*SnipMate-visual*
The VISUAL Stop~
While tab stops have numeric IDs, a special one exists with the ID 'VISUAL'.
When a snippet is expanded, if any text had been grabbed with the
snipMateVisual mapping (see |SnipMate-mappings|), all instances of the VISUAL
stop will be replaced with it. Both transformations as well as a default
placeholder can be used with the VISUAL stop.
Note: Both $VISUAL and ${VISUAL} are valid in version 1 of the snippet parser.
In version 0, only {VISUAL} is valid (without the $), and neither
transformations nor a default placeholder can be used.
Example: >
snippet div
<div>
${0:${VISUAL:<!-- content -->}}
</div>
<
*SnipMate-parser-versions*
Parser Versions~
SnipMate provides two versions for its snippet parser. Version 0 is the legacy
regex based version and is updated sparingly. Version 1 is the revamped
version with new features. Any newly developed features will likely only be
available to version 1 users.
Which version is used is determined by version directives in snippet files
(|SnipMate-snippet-files|) and by the g:snipMate.snippet_version option
(|SnipMate-options|).
A complete list of current differences is as follows:
- Version 0 does not support nested placeholders such as ${1:"${2:foo}"} at
all.
- Backslash escaping is guaranteed to work in version 1. In certain edge cases
this may not work in version 0.
- Certain syntactic errors, such as a missing closing brace for a tabstop, are
more gracefully handled in version 1. In most cases, the parser will either
discard the error or, as in the previous example, end an item at the end of
line. Version 0 may not be predictable in this regard.
- Braces are not mandatory in version 1. SnipMate will determine which
instance of a stop ID to use based on the presence of a placeholder, or
whichever instance occurs first. Braces can therefore be used to
disambiguate between stop 12, $12, and stop 1 followed by a 2: ${1}2. In
other words, version 0 makes a distinction between a mirror and a stop while
version 1 resolves the differences for you.
- Placeholders are not mandatory to enable mirror support in version 1.
- Version 0 uses the confusing syntax {VISUAL} to refer to visual content.
Version 1 treats it as just another stop ID, so both $VISUAL and ${VISUAL}
work. Plus version 1 allows a default value in case no visual selection has
been made.
- Transformations similar to |:substitute| can be preformed on any mirror,
including visual content.
*SnipMate-deprecate*
Deprecation~
The legacy parser, version 0, is deprecated. It is currently still the default
parser, but that will be changing. NOTE that switching which parser you use
could require changes to your snippets--see the previous section.
To continue using the old parser, set g:snipMate.snippet_version (see
|SnipMate-options|) to 0 in your |vimrc|.
Setting g:snipMate.snippet_version to either 0 or 1 will remove the start up
message. One way this can be done--to use the new parser--is as follows:
>
let g:snipMate = { 'snippet_version' : 1 }
<
==============================================================================
SNIPPET SOURCES *SnipMate-snippet-sources*
SnipMate is configurable.
plugin/SnipMate.vim assigns a couple important keys: >
" default implementation collecting snippets by handlers
let g:SnipMate['get_snippets'] = SnipMate#GetSnippets
" default handler:
let g:SnipMateSources['default'] = SnipMate#DefaultPool
You can override both of those settings.
You can see that the default set of snippets is determined by Vim's 'rtp'.
Example 1:~
autoload/SnipMate_python_demo.vim shows how you can register additional
sources such as creating snippets on the fly representing python function
definitions found in the current file.
Example 2:~
Add to your ~/.vimrc: For each new snippet add a second version ending in _
adding folding markers >
let g:commentChar = {
\ 'vim': '"',
\ 'c': '//',
\ 'cpp': '//',
\ 'sh': '#',
\ 'python': '#'
\ }
" url https://github.com/garbas/vim-snipmate/issues/49
fun! AddFolding(text)
return substitute(a:text,'\n'," ".g:commentChar[&ft]." {{{\n",1)."\n".g:commentChar[&ft]." }}}"
endf
fun! SnippetsWithFolding(scopes, trigger, result)
" hacky: temporarely remove this function to prevent infinite recursion:
call remove(g:SnipMateSources, 'with_folding')
" get list of snippets:
let result = SnipMate#GetSnippets(a:scopes, substitute(a:trigger,'_\(\*\)\?$','\1',''))
let g:SnipMateSources['with_folding'] = funcref#Function('SnippetsWithFolding')
" add folding:
for k in keys(result)
let a:result[k.'_'] = map(result[k],'AddFolding(v:val)')
endfor
endf
" force setting default:
runtime plugin/SnipMate.vim
" add our own source
let g:SnipMateSources['with_folding'] = funcref#Function('SnippetsWithFolding')
See |SnipMate-syntax| for more details about all possible relative locations
to 'rtp' can be found in.
==============================================================================
KNOWN ISSUES *SnipMate-known-issues*
SnipMate.vim currently has the following disadvantages to TextMate's snippets:
- Placeholders cannot span multiple lines.
- Activating snippets in different scopes of the same file is
not possible.
- Vim formatting with fo=t or fo=a can mess up SnipMate.
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
-----------------
* Implement simple caching
* Remove expansion guards
* Add `:SnipMateLoadScope` command and buffer-local scope aliases
* Load `<scope>_*.snippets` files
* Use CursorMoved autocmd events entirely
* The nested branch has been merged
* A new snippet parser has been added. The g:snipmate.version as well as
version lines in snippet files determines which is used
* The new parser supports tab stops placed within placeholders,
substitutions, non-consecutive stop numbers, and fewer ambiguities
* The stop jumping code has been updated
* Tests have been added for the jumping code and the new parser
* The override branch has been merged
* The g:snipMate.override option is added. When enabled, if two snippets
share the same name, the later-loaded one is kept and the other discarded
* Override behavior can be enabled on a per-snippet basis with a bang (!) in
the snippet file
* Otherwise, SnipMate tries to preserve all snippets loaded
* Fix bug with mirrors in the first column
* Fix bug with tabs in indents
<http://github.com/garbas/vim-snipmate/issues/143>
* Fix bug with mirrors in placeholders
* Fix reading single snippet files
* Fix the use of the visual map at the end of a line
* Fix expansion of stops containing only the zero tab stop
* Remove select mode mappings
* Indent visual placeholder expansions and remove extraneous lines
<http://github.com/garbas/vim-snipmate/issues/177>
<http://github.com/garbas/vim-snipmate/issues/178>
0.87 - 2014-01-04
-----------------
* Stop indenting empty lines when expanding snippets
* Support extends keyword in .snippets files
* Fix visual placeholder support
* Add zero tabstop support
* Support negative 'softtabstop'
* Add g:snipMate_no_default_aliases option
* Add <Plug>snipMateTrigger for triggering an expansion inside a snippet
* Add snipMate#CanBeTriggered() function
0.86 - 2013-06-15
-----------------
* Use more idiomatic <Plug> maps
* Remove most select mode mappings
* Fix disappearing variables bug (hpesoj)
* Fix cursor position bug when a variable is on the same line as the stop
* Fix undo point creation causing problems with Supertab
* Fix bug where SnipMate would use a typed trigger as a regular expression
0.85 - 2013-04-03
-----------------
* Allow trigger key customization
* Enable undoing of snippet expansion
* Support backslash escaping in snippets
* Add support for {VISUAL}
* Expand filetype extension with scope_aliases
* Add expansion guards
* Enable per-buffer expansion of snippets
* Fix 'cpo' compatibility
* Update supertab compatibility
* Enable customization of various things through g:SnipMate
* Disable spelling in snippet files
* Highlight trigger names in .snippets files
* Update many snippets
* Separate sample snippets into separate repository
0.84
----
* Unreleased version by Michael Sanders, available on his GitHub,
<https://github.com/msanders/snipmate.vim>
0.83 - 2009-07-13
-----------------
* Last release done by Michael Sanders, available at
<http://www.vim.org/scripts/script.php?script_id=2540>
==============================================================================
CONTACT *SnipMate-contact* *SnipMate-author*
SnipMate is currently maintained by:
- Rok Garbas
- Marc Weber (marco-oweber@gmx.de)
- Adnan Zafar
For bug reports, issues, or questions, check out the Issues page on GitHub:
https://github.com/garbas/vim-snipmate/issues
The original author, Michael Sanders, can be reached at:
msanders42+snipmate <at> gmail <dot> com
==============================================================================
LICENSE *SnipMate-license*
SnipMate is released under the MIT license:
Copyright 2009-2010 Michael Sanders. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The software is provided "as is", without warranty of any kind, express or
implied, including but not limited to the warranties of merchantability,
fitness for a particular purpose and noninfringement. In no event shall the
authors or copyright holders be liable for any claim, damages or other
liability, whether in an action of contract, tort or otherwise, arising from,
out of or in connection with the software or the use or other dealings in the
software.
==============================================================================
vim:tw=78:ts=8:ft=help:norl:

View File

@ -1,10 +0,0 @@
" Helper function for (x)html snippets
if exists('s:did_snip_helper') || &cp || !exists('loaded_snips')
finish
endif
let s:did_snip_helper = 1
" Automatically closes tag if in xhtml
fun! Close() abort
return stridx(&ft, 'xhtml') == -1 ? '' : ' /'
endf

View File

@ -1,20 +0,0 @@
" Vim filetype plugin for SnipMate snippets (.snippets and .snippet files)
if exists("b:did_ftplugin")
finish
endif
let b:did_ftplugin = 1
let b:undo_ftplugin = "setl et< sts< cms< fdm< fde<"
" Use hard tabs
setlocal noexpandtab softtabstop=0
setlocal foldmethod=expr foldexpr=getline(v:lnum)!~'^\\t\\\\|^$'?'>1':1
setlocal commentstring=#\ %s
setlocal nospell
command! -buffer -range=% RetabSnip
\ echom "This command is deprecated. Use :retab and = instead. Doing that now."
\ | <line1>,<line2>retab! | <line1>,<line2>normal =

View File

@ -1,32 +0,0 @@
" Simple indent support for SnipMate snippets files
if exists('b:did_indent')
finish
endif
let b:did_indent = 1
setlocal nosmartindent
setlocal indentkeys=!^F,o,O,=snippet,=version,=extends
setlocal indentexpr=GetSnippetIndent()
if exists("*GetSnippetIndent")
finish
endif
function! GetSnippetIndent()
let line = getline(v:lnum)
let prev_lnum = v:lnum - 1
let prev_line = prev_lnum != 0 ? getline(prev_lnum) : ""
if line =~# '\v^(snippet|extends|version) '
return 0
elseif indent(v:lnum) > 0
return indent(v:lnum)
elseif prev_line =~# '^snippet '
return &sw
elseif indent(prev_lnum) > 0
return indent(prev_lnum)
endif
return 0
endfunction

View File

@ -1,140 +0,0 @@
" File: snipMate.vim
" Description: snipMate.vim implements some of TextMate's snippets features in
" Vim. A snippet is a piece of often-typed text that you can
" insert into your document using a trigger word followed by a "<tab>".
"
" For more help see snipMate.txt; you can do this by using:
" :helptags ~/.vim/doc
" :h SnipMate
if exists('loaded_snips') || &cp || version < 700
finish
endif
let loaded_snips = 1
" Save and reset 'cpo'
let s:save_cpo = &cpo
set cpo&vim
try
call funcref#Function('')
catch /.*/
echoe "you're missing vim-addon-mw-utils. See install instructions at ".expand('<sfile>:h:h').'/README.md'
endtry
if (!exists('g:snipMateSources'))
let g:snipMateSources = {}
" Default source: get snippets based on runtimepath
let g:snipMateSources['default'] = funcref#Function('snipMate#DefaultPool')
endif
augroup SnipMateDetect
au BufRead,BufNewFile *.snippet,*.snippets setlocal filetype=snippets
au FileType snippets if expand('<afile>:e') =~# 'snippet$'
\ | setlocal syntax=snippet
\ | else
\ | setlocal syntax=snippets
\ | endif
augroup END
inoremap <silent> <Plug>snipMateNextOrTrigger <C-R>=snipMate#TriggerSnippet()<CR>
snoremap <silent> <Plug>snipMateNextOrTrigger <Esc>a<C-R>=snipMate#TriggerSnippet()<CR>
inoremap <silent> <Plug>snipMateTrigger <C-R>=snipMate#TriggerSnippet(1)<CR>
inoremap <silent> <Plug>snipMateBack <C-R>=snipMate#BackwardsSnippet()<CR>
snoremap <silent> <Plug>snipMateBack <Esc>a<C-R>=snipMate#BackwardsSnippet()<CR>
inoremap <silent> <Plug>snipMateShow <C-R>=snipMate#ShowAvailableSnips()<CR>
xnoremap <silent> <Plug>snipMateVisual :<C-U>call <SID>grab_visual()<CR>gv"_c
" config variables
if !exists('g:snips_author')
let g:snips_author = 'Me'
endif
if !exists('g:snipMate')
let g:snipMate = {}
endif
" SnipMate inserts this string when no snippet expansion can be done
let g:snipMate['no_match_completion_feedkeys_chars'] =
\ get(g:snipMate, 'no_match_completion_feedkeys_chars', "\t")
if !exists('g:snipMate.snippet_version')
echom 'The legacy SnipMate parser is deprecated. Please see :h SnipMate-deprecate.'
endif
" Add default scope aliases, without overriding user settings
let g:snipMate.scope_aliases = get(g:snipMate, 'scope_aliases', {})
if exists('g:snipMate_no_default_aliases')
echom 'The g:snipMate_no_default_aliases option has been renamed.'
\ 'See :h snipMate-options.'
endif
if (!exists('g:snipMate_no_default_aliases') || !g:snipMate_no_default_aliases)
\ && (!exists('g:snipMate.no_default_aliases')
\ || !g:snipMate.no_default_aliases)
let g:snipMate.scope_aliases.objc =
\ get(g:snipMate.scope_aliases, 'objc', 'c')
let g:snipMate.scope_aliases.cpp =
\ get(g:snipMate.scope_aliases, 'cpp', 'c')
let g:snipMate.scope_aliases.cu =
\ get(g:snipMate.scope_aliases, 'cu', 'c')
let g:snipMate.scope_aliases.xhtml =
\ get(g:snipMate.scope_aliases, 'xhtml', 'html')
let g:snipMate.scope_aliases.html =
\ get(g:snipMate.scope_aliases, 'html', 'javascript')
let g:snipMate.scope_aliases.php =
\ get(g:snipMate.scope_aliases, 'php', 'php,html,javascript')
let g:snipMate.scope_aliases.ur =
\ get(g:snipMate.scope_aliases, 'ur', 'html,javascript')
let g:snipMate.scope_aliases.mxml =
\ get(g:snipMate.scope_aliases, 'mxml', 'actionscript')
let g:snipMate.scope_aliases.eruby =
\ get(g:snipMate.scope_aliases, 'eruby', 'eruby-rails,html')
let g:snipMate.scope_aliases.scss =
\ get(g:snipMate.scope_aliases, 'scss', 'css')
let g:snipMate.scope_aliases.less =
\ get(g:snipMate.scope_aliases, 'less', 'css')
endif
let g:snipMate['get_snippets'] = get(g:snipMate, 'get_snippets', funcref#Function("snipMate#GetSnippets"))
" List of paths where snippets/ dirs are located
if exists('g:snipMate.snippet_dirs') && type(g:snipMate['snippet_dirs']) != type([])
echohl WarningMsg
echom "g:snipMate['snippet_dirs'] must be a List"
echohl None
endif
" _ is default scope added always
"
" &ft honors multiple filetypes and syntax such as in set ft=html.javascript syntax=FOO
let g:snipMate['get_scopes'] = get(g:snipMate, 'get_scopes', funcref#Function('return split(&ft,"\\.")+[&syntax, "_"]'))
" Modified from Luc Hermitte's function on StackOverflow
" <http://stackoverflow.com/a/1534347>
function! s:grab_visual() abort
let a_save = @a
try
normal! gv"ay
let b:snipmate_visual = @a
finally
let @a = a_save
endtry
endfunction
" TODO: Allow specifying an arbitrary snippets file
function! s:load_scopes(bang, ...) abort
let gb = a:bang ? g: : b:
let gb.snipMate = get(gb, 'snipMate', {})
let gb.snipMate.scope_aliases = get(gb.snipMate, 'scope_aliases', {})
let gb.snipMate.scope_aliases['_'] = join(split(get(gb.snipMate.scope_aliases, '_', ''), ',') + a:000, ',')
endfunction
command! -bang -bar -nargs=+ SnipMateLoadScope
\ call s:load_scopes(<bang>0, <f-args>)
" Edit snippet files
command! SnipMateOpenSnippetFiles call snipMate#OpenSnippetFiles()
" restore 'cpo'
let &cpo = s:save_cpo
" vim:noet:sw=4:ts=4:ft=vim

View File

@ -1,11 +0,0 @@
" Syntax highlighting for .snippet files (used for snipMate.vim)
" Hopefully this should make snippets a bit nicer to write!
syn match placeHolder '\${\d\+\(:.\{-}\)\=}' contains=snipCommand
syn match tabStop '\$\d\+'
syn match snipEscape '\\\\\|\\`'
syn match snipCommand '\%(\\\@<!\%(\\\\\)*\)\@<=`.\{-}\%(\\\@<!\%(\\\\\)*\)\@<=`'
hi link placeHolder Special
hi link tabStop Special
hi link snipEscape SpecialChar
hi link snipCommand String

View File

@ -1,23 +0,0 @@
" Syntax highlighting for .snippets files (used for snipMate.vim)
" Hopefully this should make snippets a bit nicer to write!
syn match snipComment '^#.*'
syn match placeHolder '\${\d\+\(:.\{-}\)\=}' contains=snipCommand
syn match tabStop '\$\d\+'
syn match snipEscape '\\\\\|\\`'
syn match snipCommand '\%(\\\@<!\%(\\\\\)*\)\@<=`.\{-}\%(\\\@<!\%(\\\\\)*\)\@<=`'
syn match snippet '^snippet.*' contains=multiSnipText,snipKeyword
syn match snippet '^extends.*' contains=snipKeyword
syn match snippet '^version.*' contains=snipKeyword
syn match multiSnipText '\S\+ \zs.*' contained
syn match snipKeyword '^(snippet|extends|version)'me=s+8 contained
syn match snipError "^[^#vse\t].*$"
hi link snippet Identifier
hi link snipComment Comment
hi link multiSnipText String
hi link snipKeyword Keyword
hi link snipEscape SpecialChar
hi link placeHolder Special
hi link tabStop Special
hi link snipCommand String
hi link snipError Error

View File

@ -1,175 +0,0 @@
function! Setup(snip) abort
return snipMate#expandSnip(join(a:snip, "\n"), 1)
endfunction
function! s:to_be_file(expected) abort
return a:expected == getline(1,'$')
endfunction
function! s:to_be_in(item, list) abort
return !empty(filter(copy(a:list), 'v:val is a:item'))
endfunction
call vspec#customize_matcher('to_be_file', function('s:to_be_file'))
call vspec#customize_matcher('to_be_in', function('s:to_be_in'))
describe 'snippet state'
before
enew
let b:snip_state = snipmate#jumping#state()
end
after
bwipeout!
end
describe '.remove()'
it 'removes the state object'
Expect exists('b:snip_state') to_be_true
call b:snip_state.remove()
Expect exists('b:snip_state') to_be_false
end
it 'removes snippet related autocommands'
function! ReadAutocmds()
redir => autocmds
0verbose au snipmate_changes * <buffer>
redir END
return split(autocmds, "\n")
endfunction
aug snipmate_changes
au CursorMoved,CursorMovedI <buffer> echo 'event'
aug END
Expect len(ReadAutocmds()) > 1
call b:snip_state.remove()
Expect len(ReadAutocmds()) == 1
end
end
describe '.find_next_stop()'
it 'increments/decrements the stop_no'
let b:snip_state.stops = { 1 : {}, 2 : {} }
let b:snip_state.stop_no = 1
let b:snip_state.stop_count = 4
call b:snip_state.find_next_stop(0)
Expect b:snip_state.stop_no == 2
call b:snip_state.find_next_stop(1)
Expect b:snip_state.stop_no == 1
end
it 'continues iterating if the next/previous stop does not exist'
let b:snip_state.stops = { 3 : {} }
let b:snip_state.stop_count = 6
let b:snip_state.stop_no = 1
call b:snip_state.find_next_stop(0)
Expect b:snip_state.stop_no == 3
let b:snip_state.stop_no = 5
call b:snip_state.find_next_stop(1)
Expect b:snip_state.stop_no == 3
end
it 'does something at the ends'
"
end
end
describe '.remove_nested()'
it 'removes nested mirrors and only nested mirrors'
let mirror = { 'line' : 0 }
let b:snip_state.stops = { 1 : { 'placeholder' : [[2, mirror]] },
\ 2 : { 'mirrors' : [mirror, {}] } }
call b:snip_state.remove_nested(1)
Expect len(b:snip_state.stops[2].mirrors) == 1
Expect b:snip_state.stops[2].mirrors[0] isnot mirror
end
it 'removes nested stops'
let stop = [2, 'abc']
let b:snip_state.stops = { 1 : { 'placeholder' : [stop] },
\ 2 : { 'placeholder' : stop[1:1] } }
call b:snip_state.remove_nested(1)
Expect len(b:snip_state.stops) == 1
Expect keys(b:snip_state.stops) == ['1']
end
end
describe '.find_update_objects()'
it 'finds mirrors/stops on the same line and after cur_stop'
let b:snip_state.stops = {
\ 1 : { 'line' : 1, 'col' : 5,
\ 'placeholder' : ['x'] },
\ 2 : { 'line' : 1, 'col' : 7,
\ 'mirrors' : [{ 'line' : 1, 'col' : 7 }] }
\ }
let stop = b:snip_state.stops[1]
call b:snip_state.find_update_objects(stop)
for obj in stop.update_objects
Expect obj to_be_in [ b:snip_state.stops[2],
\ b:snip_state.stops[2].mirrors[0] ]
endfor
end
it 'finds mirrors/stops on the same line and after cur_stop mirrors'
let b:snip_state.stops = {
\ 1 : { 'line' : 1, 'col' : 5,
\ 'mirrors' : [{ 'line' : 2, 'col' : 5 }],
\ 'placeholder' : ['x'] },
\ 2 : { 'line' : 2, 'col' : 7,
\ 'mirrors' : [{ 'line' : 2, 'col' : 7 }] }
\ }
let stop = b:snip_state.stops[1]
call b:snip_state.find_update_objects(stop)
for obj in stop.update_objects
Expect obj to_be_in [ b:snip_state.stops[2],
\ b:snip_state.stops[2].mirrors[0] ]
endfor
end
it 'ignores mirrors/stops on other lines'
let b:snip_state.stops = {
\ 1 : { 'line' : 2, 'col' : 5,
\ 'placeholder' : ['x'] },
\ 2 : { 'line' : 1, 'col' : 7,
\ 'mirrors' : [{ 'line' : 1, 'col' : 7 }] },
\ 3 : { 'line' : 3, 'col' : 7,
\ 'mirrors' : [{ 'line' : 3, 'col' : 7 }] }
\ }
let stop = b:snip_state.stops[1]
call b:snip_state.find_update_objects(stop)
Expect empty(stop.update_objects) to_be_true
end
it 'ignores mirrors/stops on the same line but before cur_stop/mirrors'
let b:snip_state.stops = {
\ 1 : { 'line' : 1, 'col' : 5,
\ 'mirrors' : [{ 'line' : 2, 'col' : 5 }],
\ 'placeholder' : ['x'] },
\ 2 : { 'line' : 1, 'col' : 1,
\ 'mirrors' : [{ 'line' : 2, 'col' : 1 }] },
\ 3 : { 'line' : 2, 'col' : 3,
\ 'mirrors' : [{ 'line' : 1, 'col' : 3 }] },
\ }
let stop = b:snip_state.stops[1]
call b:snip_state.find_update_objects(stop)
Expect empty(stop.update_objects) to_be_true
end
end
end

View File

@ -1,152 +0,0 @@
describe 'snippet parser'
before
function! Parse(snippet, ...)
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]]]
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']]
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, 1)
function! InstanceFound(list)
return !empty(filter(copy(b:stops[a:list[0]].instances),
\ 'v:val is a:list'))
endfunction
function! CheckList(list)
for item in a:list
if type(item) == type([])
Expect InstanceFound(item) to_be_true
call CheckList(item)
endif
unlet item " E732
endfor
endfunction
call CheckList(snip[0])
end
it 'parses mirror substitutions ${n/pat/sub} as [n, {...}]'
let expect = [[[1, { 'pat' : 'abc', 'sub' : 'def' }]]]
Expect Parse('${1/abc/def}') == expect
let expect[0][0][1].flags = ''
Expect Parse('${1/abc/def/}') == expect
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']]]
end
it 'evaluates backtick expressions'
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]]
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"]]
" &et -> &sts or &sw
setl et sts=2 sw=3
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"]]
setl et sts=-1 sw=3
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"]]
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('`fnamemodify("\`.x", ":r")`') == [['`']]
Expect Parse('\`x\`') == [['`x`']]
end
it 'splits text at newlines'
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 'expands $VISUAL placeholders with any indents'
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"]]
end
it 'removes newlines from the end of VISUALs if before an end of line'
let b:snipmate_visual = "1\n2\n"
Expect Parse("x\n$VISUAL\nx") == [['x'], ['1'], ['2'], ['x']]
end
it 'splits the before and after a $VISUAL if it is multiline'
let b:snipmate_visual = "1\n2\n3"
Expect Parse("foo $VISUAL bar") == [['foo 1'], ['2'], ['3 bar']]
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

View File

@ -1,20 +0,0 @@
#!/bin/sh
tmp="$(mktemp || tmpfile)"
vim -Es $tmp <<- EOF
source ~/.vimrc
%delete _
call append(0, split(&rtp, ','))
delete _
wq
EOF
rtp="$(grep -iE 'vspec|snipmate|tlib|mw-utils' < $tmp | grep -v after)"
vspec="$(grep -iE 'vspec' < $tmp | grep -v after)"
test_files="${*:-parser jumping}"
for test in $test_files; do
$vspec/bin/vspec $rtp ${test%%.vim}.vim
done
rm $tmp