pax_global_header00006660000000000000000000000064145436123740014523gustar00rootroot0000000000000052 comment=c6c68296f8692a2405c318dfa484869f2aab7cdb vim-snipmate-0.90/000077500000000000000000000000001454361237400140645ustar00rootroot00000000000000vim-snipmate-0.90/.gitignore000066400000000000000000000000311454361237400160460ustar00rootroot00000000000000doc/tags *.swp .DS_Store vim-snipmate-0.90/Contributors.md000066400000000000000000000041711454361237400171060ustar00rootroot00000000000000# 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) vim-snipmate-0.90/README.md000066400000000000000000000167321454361237400153540ustar00rootroot00000000000000# 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` 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 ## SnipMate can be installed using a package manager or using Vim's built-in package handling. It does depend on [vim-addon-mw-utils][mw-utils] and [tlib][tlib]. For example, to use Vim's built-in support, % mkdir -p ~/.vim/pack/SnipMate/start % 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/tomtom/tlib_vim.git # Optional: % git clone https://github.com/honza/vim-snippets.git > **NOTE:** SnipMate does not ship with any snippets out of the box. We suggest looking at the [vim-snippets][vim-snippets] repository. ## Using SnipMate ## Install and create some snippets (see `:h SnipMate-snippets`). Then type in the trigger for one in the correct filetype and hit the expansion key (by default bound to ``). ## 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 `snipMateTrigger` and similar maps in the output of `:imap`. Additionally make sure either `snipMateTrigger` or `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 `` 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 ## Some changes listed here were contributed by non-maintainers. A full list can be found at [Contributors.md](Contributors.md). ### 0.90 - 2023-12-29 ### - Remove empty lines at the end of a `${VISUAL}` expansion - Fix code for opening folds when expanding a snippet - Deprecate legacy snippet parser - Fix jumps when `&sel == 'exclusive'` ### 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 `_*.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 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 vim-snipmate-0.90/addon-info.json000066400000000000000000000010131454361237400167700ustar00rootroot00000000000000{ "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" } vim-snipmate-0.90/after/000077500000000000000000000000001454361237400151655ustar00rootroot00000000000000vim-snipmate-0.90/after/plugin/000077500000000000000000000000001454361237400164635ustar00rootroot00000000000000vim-snipmate-0.90/after/plugin/snipMate.vim000066400000000000000000000032321454361237400207600ustar00rootroot00000000000000" 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 ? '' : ' ' 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 ' g:snips_trigger_key 'snipMateTrigger' exec 'smap ' g:snips_trigger_key 'snipMateSNext' exec 'xmap ' g:snips_trigger_key 'snipMateVisual' else " Remove SuperTab map if it exists let s:overwrite = maparg('', 'i') ==? 'SuperTabForward' call s:map_if_not_mapped('', 'snipMateNextOrTrigger', 'i') call s:map_if_not_mapped('', 'snipMateNextOrTrigger', 's') let s:overwrite = 0 call s:map_if_not_mapped('', 'snipMateVisual', 'x') endif if exists('g:snips_trigger_key_backwards') echom 'g:snips_trigger_key_backwards is deprecated. See :h snipMate-mappings' exec 'imap ' g:snips_trigger_key_backwards 'snipMateIBack' exec 'smap ' g:snips_trigger_key_backwards 'snipMateSBack' else let s:overwrite = maparg('', 'i') ==? 'SuperTabBackward' call s:map_if_not_mapped('', 'snipMateBack', 'i') call s:map_if_not_mapped('', 'snipMateBack', 's') let s:overwrite = 0 endif call s:map_if_not_mapped('', 'snipMateShow', 'i') endif let &cpo = s:save_cpo " vim:noet: vim-snipmate-0.90/autoload/000077500000000000000000000000001454361237400156745ustar00rootroot00000000000000vim-snipmate-0.90/autoload/snipMate.vim000066400000000000000000000451411454361237400201760ustar00rootroot00000000000000" 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(':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 if exists('b:snip_state') | \ call b:snip_state.update_changes() | \ else | \ silent! au! snipmate_changes * | \ 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(':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 == "" let SuperTabPlug = maparg('SuperTabForward', 'i') if SuperTabPlug == "" let SuperTabKey = "\" else exec "let SuperTabKey = \"" . escape(SuperTabPlug, '<') . "\"" endif elseif g:SuperTabMappingBackward == "" let SuperTabPlug = maparg('SuperTabBackward', 'i') if SuperTabPlug == "" let SuperTabKey = "\" 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("\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("\snipMateNextOrTrigger") | return '' else call feedkeys("\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 == '' \ ? "\" \ : "\=snipMate#ShowAvailableSnips()\" 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 == "" let SuperTabPlug = maparg('SuperTabForward', 'i') if SuperTabPlug == "" let SuperTabKey = "\" else exec "let SuperTabKey = \"" . escape(SuperTabPlug, '<') . "\"" endif elseif g:SuperTabMappingBackward == "" let SuperTabPlug = maparg('SuperTabBackward', 'i') if SuperTabPlug == "" let SuperTabKey = "\" 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 "\" endf " vim:noet:sw=4:ts=4:ft=vim vim-snipmate-0.90/autoload/snipMate_python_demo.vim000066400000000000000000000030151454361237400225750ustar00rootroot00000000000000" 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 vim-snipmate-0.90/autoload/snipmate/000077500000000000000000000000001454361237400175145ustar00rootroot00000000000000vim-snipmate-0.90/autoload/snipmate/jumping.vim000066400000000000000000000157661454361237400217210ustar00rootroot00000000000000function! s:sfile() abort return expand('') 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 * 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 "\".l.'v'.len."l\" endif return len == 1 ? "\".l.'gh' : "\".l.'v'.(len - 1)."l\" 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('.') " Increase the endpoint by 1 for &sel = exclusive if line('.') != self.cur_stop.line || col < self.start_col \ || col > (self.end_col + (&sel == 'exclusive')) 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 vim-snipmate-0.90/autoload/snipmate/legacy.vim000066400000000000000000000120261454361237400214760ustar00rootroot00000000000000let 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 = '\%(\\\@ 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 vim-snipmate-0.90/autoload/snipmate/parse.vim000066400000000000000000000206001454361237400213410ustar00rootroot00000000000000" Snippet definition parsing code function! s:sfile() abort return expand('') 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') vim-snipmate-0.90/autoload/snipmate/util.vim000066400000000000000000000015071454361237400212110ustar00rootroot00000000000000" The next function was based on s:function and s:add_methods in fugitive " function! snipmate#util#add_methods(sfile, namespace, methods) abort let dict = {} for name in a:methods let dict[name] = function(join([matchstr(a:sfile, '\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 vim-snipmate-0.90/doc/000077500000000000000000000000001454361237400146315ustar00rootroot00000000000000vim-snipmate-0.90/doc/SnipMate.txt000066400000000000000000000773671454361237400171360ustar00rootroot00000000000000*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 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 ( 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 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 snipMateNextOrTrigger :smap snipMateNextOrTrigger Note: The noremap variants of the map commands must NOT be used. The list of possible mappings is as follows: snipMateNextOrTrigger Default: 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. 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. snipMateBack Default: Mode: Insert, Select Jump to the previous tab stop, if it exists. Use in both insert and select modes. snipMateShow Default: Mode: Insert Show all available snippets (that start with the previous text, if it exists). Use in insert mode. snipMateVisual Default: Mode: Visual See |SnipMate-visual|. Additionally, 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/.snippets .../snippets/_.snippets .../snippets//.snippets .../snippets//.snippet .../snippets///.snippet where is a scope or 'filetype' or 'syntax', is an arbitrary name, is the trigger for a snippet, and 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 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
tag, then on its class, and finally end editing its contents: > snippet div
$0
< *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
$0
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 $0
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
${0:${VISUAL:}}
< *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.90 - 2023-12-29 ----------------- - Remove empty lines at the end of a `${VISUAL}` expansion - Fix code for opening folds when expanding a snippet - Deprecate legacy snippet parser - Fix jumps when `&sel == 'exclusive'` 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 `_*.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 * 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 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 snipMateTrigger for triggering an expansion inside a snippet * Add snipMate#CanBeTriggered() function 0.86 - 2013-06-15 ----------------- * Use more idiomatic 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, 0.83 - 2009-07-13 ----------------- * Last release done by Michael Sanders, available at ============================================================================== 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 gmail 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: vim-snipmate-0.90/ftplugin/000077500000000000000000000000001454361237400157145ustar00rootroot00000000000000vim-snipmate-0.90/ftplugin/html_snip_helper.vim000066400000000000000000000003771454361237400217740ustar00rootroot00000000000000" 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 vim-snipmate-0.90/ftplugin/snippets.vim000066400000000000000000000010631454361237400202760ustar00rootroot00000000000000" 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." \ | ,retab! | ,normal = vim-snipmate-0.90/indent/000077500000000000000000000000001454361237400153455ustar00rootroot00000000000000vim-snipmate-0.90/indent/snippets.vim000066400000000000000000000013211454361237400177240ustar00rootroot00000000000000" 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 vim-snipmate-0.90/plugin/000077500000000000000000000000001454361237400153625ustar00rootroot00000000000000vim-snipmate-0.90/plugin/snipMate.vim000066400000000000000000000120251454361237400176570ustar00rootroot00000000000000" 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 "". " " 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(':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(':e') =~# 'snippet$' \ | setlocal syntax=snippet \ | else \ | setlocal syntax=snippets \ | endif augroup END inoremap snipMateNextOrTrigger =snipMate#TriggerSnippet() snoremap snipMateNextOrTrigger a=snipMate#TriggerSnippet() inoremap snipMateTrigger =snipMate#TriggerSnippet(1) inoremap snipMateBack =snipMate#BackwardsSnippet() snoremap snipMateBack a=snipMate#BackwardsSnippet() inoremap snipMateShow =snipMate#ShowAvailableSnips() xnoremap snipMateVisual :call grab_visual()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 " 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(0, ) " Edit snippet files command! SnipMateOpenSnippetFiles call snipMate#OpenSnippetFiles() " restore 'cpo' let &cpo = s:save_cpo " vim:noet:sw=4:ts=4:ft=vim vim-snipmate-0.90/syntax/000077500000000000000000000000001454361237400154125ustar00rootroot00000000000000vim-snipmate-0.90/syntax/snippet.vim000066400000000000000000000007111454361237400176100ustar00rootroot00000000000000" 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 '\%(\\\@ autocmds 0verbose au snipmate_changes * redir END return split(autocmds, "\n") endfunction aug snipmate_changes au CursorMoved,CursorMovedI 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 vim-snipmate-0.90/t/parser.vim000066400000000000000000000123431454361237400163430ustar00rootroot00000000000000describe '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 vim-snipmate-0.90/t/tests.sh000077500000000000000000000006171454361237400160340ustar00rootroot00000000000000#!/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