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

lets try again...

This commit is contained in:
amix
2012-08-16 23:41:25 -04:00
parent 85888ddbd3
commit bb9c85e523
306 changed files with 47995 additions and 21 deletions

View File

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

View File

@ -0,0 +1,273 @@
============
snipmate.vim
============
:Author: `Michael Sanders`_
:Maintainer: `Rok Garbas`_
:Homepage: http://www.vim.org/scripts/script.php?script_id=2540
:Contributors: `MarcWeber`_, `lilydjwg`_, `henrik`_, `steveno`_, `asymmetric`_, `jherdman`_, `ironcamel`_, `honza`_, `jb55`_, `robhudson`_, `kozo2`_, `MicahElliott`_, `darkwise`_, `redpill`_, `thisgeek`_, `sickill`_, `pose`_, `marutanm`_, `r00k`_, `jbernard`_, `holizz`_, `muffinresearch`_, `statik`_, `taq`_, `alderz`_, `pielgrzym`_
.. contents::
Changelog
=========
1.0 [Unreleased]
----------------
* Split snippet files into separate git repository (github/honza/snipmate-snippets). [2011-06-20, `honza`_]
See 'Snippets repository' below.
* Adding general snippets to ``css.snippets`` and ``htmldjango.snippets``
[2011-06-10, `pielgrzym`_]
* Adding ``css.snippets`` from `tisho`_
(https://github.com/tisho/css-snippets-snipmate)
[2011-04-17, `garbas`_]
* Lots of updates to snippets.
* Made the trigger key configurable, https://github.com/garbas/vim-snipmate/pull/4.
[2011-04-13, `thenoseman`_]
* Handle single-line or multiline snippets.
[2011-03-22, `johnbintz`_]
* If there is only one snippet choose it directly.
[2011-03-16, `blueyed`_]
* Add snippets file for "diff" filetype and add bang to function
definitons, allowing for reload.
[2011-03-06, `blueyed`_]
* Update snipmate to handle latest supertab version.
[2011-02-09, `ervandew`_]
* Updated README: added contributors, instructions how to install snipMate,
some spellchecking of my wonderful English, added this Changelog
[2011-02-07, `garbas`_]
* Fixed bug: When leaving a placeholder unchanged and trying to jump to the
next placeholder, the text of the first placeholder would get cleared.
[2011-06-16, `jgosmann`_]
* From below mentioned merges I must specially mention `MarcWeber`_'s patch
which brought quite a few functionalities/improvements:
- snippets are loaded lazily.
- snippets are no longer cached. Thus you always get the snippets you
just wrote to a file without reloading anything.
- When visually selecting a snippet in a .snippets file you can press
<cr> to replace spaces by tabs automatically in a smart way.
Big +1 to `MarcWeber`_ for this. Important to note is that we now depend
on `vim-addon-mw-utils`_ and `tlib`_.
[2011-02-02, `garbas`_]
* Merged pull requests of `MarcWeber`_, `lilydjwg`_, `henrik`_, `steveno`_,
`asymmetric`_, `jherdman`_, `ironcamel`_, `honza`_, `jb55`_,
`robhudson`_, `kozo2`_, `MicahElliott`_, `darkwise`_, `redpill`_,
`thisgeek`_, `sickill`_, `pose`_,
[2011-02-02, `garbas`_]
0.83 [2009-07-13]
-----------------
* last release done by `Michael Sanders`_, you can find it here:
http://www.vim.org/scripts/download_script.php?src_id=11006
How to install
==============
Unfortunately there are many ways to how to install vim plugins. If you don't
see your preferred way of installation plugins please consider updating
this section. Basically, installation consists of 2 simple steps:
1. Install vim-snipmate
2. Install snippets
snipmate dependencies
==============
Important to note is that since version 1.0 we depend on this 2 vim plugins:
* `vim-addon-mw-utils`_ providing the implementation for caching parsed
.snippets files.
* `tlib`_ for tlib#input#List which provides the excellent filterable
list selection view (and more).
* the default set of snippets (optional but recommended).
See 'Snippets repository' below.
Using `VAM`_ (recommended)
------------
::
Add snipmate-snippets to the names to be installed. Or use
"github:name/repo" if you want to use a non standard upstream.
The default snippets depend on "snipmate" so VAM will fetch the core along
with its dependencies automatically
Using `pathogen`_
--------------------------------------
::
% cd ~/.vim
% mkdir bundle
% cd bundle
% git clone git://github.com/garbas/vim-snipmate.git
# Install dependencies:
% 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/honza/snipmate-snippets.git
Using `Vundle`_
---------------
::
Install dependencies:
Bundle "MarcWeber/vim-addon-mw-utils"
Bundle "tomtom/tlib_vim"
Bundle "honza/snipmate-snippets"
Install:
Bundle "garbas/vim-snipmate"
And :BundleInstall
Manually (not recommended!)
---------------------------
::
% git clone git://github.com/honza/snipmate-snippets.git
% git clone git://github.com/garbas/vim-snipmate.git
% cd snipmate.vim
% cp -R * ~/.vim
Then in vim::
:helptags ~/.vim/doc/
Then install any dependencies (see above).
Snippets repository
===================
There is now one snippet repo containing almost all snippets. You are
encouraged to submit any fixes and new snippets there.
https://github.com/honza/snipmate-snippets
We also encourage people to maintain sets of snippets for particular use cases.
That all users can benefit from them people can list their snippet repositories here:
* https://github.com/rbonvall/snipmate-snippets-bib (snippets for BibTeX files)
Installation using VAM: "github:rbonvall/snipmate-snippets-bib"
Why forking snipMate?
=====================
::
After several unsuccessful attempts of contacting Michael Sanders, no
commits in last half year and long pull request line on github (none of
pull requests were commented/replied/rejected) I decided to take action,
step up and bring some love to this widely used plugin.
But nothing to worry about. We all get busy, accupied with our daily work
or just lose interest in doing boring maintainance.
While reviewing pull requests on github.com/msanders I found lots of great
improvements and I decided to **friendly** fork it, review and apply patches
that were sent, notify all the patch submitters and decided to maintain
snipmate.vim from now on. Of course if somebody wants to
help, please do not hesitate to write me, I am open to any suggestions.
Maybe I will only maintain it for a while until Michael Sanders takes things
back into his hand or until some other super-hero shows up.
Tnx and happy snipmating, Rok Garbas, 2011-02-02
Known Bugs
=============
* Set one value default as input of another value.
https://github.com/garbas/vim-snipmate/issues/59
[2011-10-18, `bogdan`_]
TODO / Future
=============
* Notify all "forkers" about new home and ask them nicely to review already
merged changes and possibly send their changes.
[2011-02-07, `garbas`_]
* I'd like to investigate whether xptemplate or snipmate has the better
engine. So maybe my vision of the future could be making xptemplate read
snippet files. It is not important enough for me to work on it right now as
snipmate works reasonable well for me.
[2011-02-02, `MarcWeber`_]
* comment without verifying it:
< Silex> MarcWeber: btw, check out ultisnips. Much better than snipmate imho
And before this discussion xptemplate vs snipmate vs ultisnips .. continues
we should create a wiki page comparing them and keep that up to date.
If you volunteer tell me so that I can reference the link.
[2011-02-02, `MarcWeber`_]
.. _`Michael Sanders`: http://www.vim.org/account/profile.php?user_id=16544
.. _`Rok Garbas`: rok@garbas.si
.. _`VAM`: https://github.com/MarcWeber/vim-addon-manager
.. _`pathogen`: http://www.vim.org/scripts/script.php?script_id=2332
.. _`vim-addon-mw-utils`: https://github.com/MarcWeber/vim-addon-mw-utils
.. _`tlib`: https://github.com/tomtom/tlib_vim
.. _`garbas`: https://github.com/garbas
.. _`MarcWeber`: https://github.com/MarcWeber
.. _`lilydjwg`: https://github.com/lilydjwg
.. _`henrik`: https://github.com/henrik
.. _`steveno`: https://github.com/steveno
.. _`asymmetric`: https://github.com/asymmetric
.. _`jherdman`: https://github.com/jherdman
.. _`ironcamel`: https://github.com/ironcamel
.. _`honza`: https://github.com/honza
.. _`jb55`: https://github.com/jb55
.. _`robhudson`: https://github.com/robhudson
.. _`kozo2`: https://github.com/kozo2
.. _`MicahElliott`: https://github.com/MicahElliott
.. _`darkwise`: https://github.com/darkwise
.. _`redpill`: https://github.com/redpill
.. _`thisgeek`: https://github.com/thisgeek
.. _`sickill`: https://github.com/sickill
.. _`pose`: https://github.com/pose
.. _`marutanm`: https://github.com/marutanm
.. _`r00k`: https://github.com/r00k
.. _`jbernard`: https://github.com/jbernard
.. _`holizz`: https://github.com/holizz
.. _`muffinresearch`: https://github.com/muffinresearch
.. _`statik`: https://github.com/statik
.. _`Vundle`: https://github.com/gmarik/vundle
.. _`alderz`: https://github.com/alderz
.. _`johnbintz`: https://github.com/johnbintz
.. _`thenoseman`: https://github.com/thenoseman
.. _`ervandew`: https://github.com/ervandew
.. _`blueyed`: https://github.com/blueyed
.. _`tisho`: https://github.com/tisho
.. _`pielgrzym`: https://github.com/pielgrzym
.. _`jgosmann`: https://github.com/jgosmann
.. _`taq': https://github.com/taq

View File

@ -0,0 +1,12 @@
{
"name" : "snipMate",
"version" : "dev",
"author" : "Michael Sanders -> original project http://github.com/msanders/snipmate.vim",
"maintainer" : "Marc Weber <marco-oweber@gmx.de> (I maintain this fork only)",
"repository" : {"type": "git", "url": "git://github.com/MarcWeber/snipMate.vim.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.markdown to learn about the features this fork adds"
}

View File

@ -0,0 +1,48 @@
" These are the mappings for snipMate.vim. Putting it here ensures that it
" will be mapped after other plugins such as supertab.vim.
if !exists('loaded_snips') || exists('s:did_snips_mappings')
finish
endif
let s:did_snips_mappings = 1
" This is put here in the 'after' directory in order for snipMate to override
" other plugin mappings (e.g., supertab).
"
" To adjust the tirgger key see (:h snipMate-trigger)
"
if !exists('g:snips_trigger_key')
let g:snips_trigger_key = '<tab>'
endif
if !exists('g:snips_trigger_key_backwards')
let g:snips_trigger_key_backwards = '<s-' . substitute(g:snips_trigger_key, '[<>]', '', 'g')
endif
exec 'ino <silent> ' . g:snips_trigger_key . ' <c-g>u<c-r>=snipMate#TriggerSnippet()<cr>'
exec 'snor <silent> ' . g:snips_trigger_key . ' <esc>i<right><c-r>=snipMate#TriggerSnippet()<cr>'
exec 'ino <silent> ' . g:snips_trigger_key_backwards . '> <c-r>=snipMate#BackwardsSnippet()<cr>'
exec 'snor <silent> ' . g:snips_trigger_key_backwards . '> <esc>i<right><c-r>=snipMate#BackwardsSnippet()<cr>'
exec 'ino <silent> <c-r>' . g:snips_trigger_key . ' <c-r>=snipMate#ShowAvailableSnips()<cr>'
" maybe there is a better way without polluting registers ?
exec 'xnoremap ' . g:snips_trigger_key. ' s<c-o>:let<space>g:snipmate_content_visual=getreg('1')<cr>'
" The default mappings for these are annoying & sometimes break snipMate.
" You can change them back if you want, I've put them here for convenience.
snor <bs> b<bs>
snor <right> <esc>a
snor <left> <esc>bi
snor ' b<bs>'
snor ` b<bs>`
snor % b<bs>%
snor U b<bs>U
snor ^ b<bs>^
snor \ b<bs>\
snor <c-x> b<bs><c-x>
" By default load snippets in snippets_dir
if empty(snippets_dir)
finish
endif
" vim:noet:sw=4:ts=4:ft=vim

View File

@ -0,0 +1,935 @@
" config which can be overridden (shared lines)
if !exists('g:snipMate')
let g:snipMate = {}
endif
let s:c = g:snipMate
try
call tlib#input#List('mi', '', [])
catch /.*/
echoe "you're missing tlib. See install instructions at ".expand('<sfile>:h:h').'/README.rst'
endtry
" disable write cache in files
" some people get errors about writing the cache files. Probably there is no
" pay off having slow disks anyway. So disabling the cache by default
let s:c.cache_parsed_snippets_on_disk = get(s:c, 'cache_parsed_snippets_on_disk', 0)
let s:c.read_snippets_cached = get(s:c, 'read_snippets_cached', {'func' : function('snipMate#ReadSnippetsFile'), 'version': 3, 'use_file_cache': s:c.cache_parsed_snippets_on_disk})
" if filetype is objc, cpp, cs or cu also append snippets from scope 'c'
" you can add multiple by separating scopes by ',', see s:AddScopeAliases
" TODO add documentation to doc/*
let s:c.scope_aliases = get(s:c, 'scope_aliases', {})
let s:c.scope_aliases.objc = get(s:c.scope_aliases, 'objc', 'c')
let s:c.scope_aliases.cpp = get(s:c.scope_aliases, 'cpp', 'c')
let s:c.scope_aliases.cu = get(s:c.scope_aliases, 'cu', 'c')
let s:c.scope_aliases.cs = get(s:c.scope_aliases, 'cs','c')
let s:c.scope_aliases.xhtml = get(s:c.scope_aliases, 'xhtml', 'html')
let s:c.scope_aliases.html = get(s:c.scope_aliases, 'html', 'javascript')
let s:c.scope_aliases.php = get(s:c.scope_aliases, 'php', 'php,html,javascript')
let s:c.scope_aliases.ur = get(s:c.scope_aliases, 'ur', 'html,javascript')
let s:c.scope_aliases.mxml = get(s:c.scope_aliases, 'mxml', 'actionscript')
let s:c.scope_aliases.eruby = get(s:c.scope_aliases, 'eruby', 'eruby-rails,html')
" set this to "\<tab>" to make snipmate not swallow tab (make sure to not have
" expandtab set). Remember that you can always enter tabs by <c-v> <tab> then
" you don't need this
let s:c['no_match_completion_feedkeys_chars'] = get(s:c, 'no_match_completion_feedkeys_chars', "\t")
fun! Filename(...)
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
fun! s:RemoveSnippet()
unl! g:snipPos s:curPos s:snipLen s:endCol s:endLine s:prevLen
\ s:lastBuf s:oldWord
if exists('s:update')
unl s:startCol s:origWordLen s:update
if exists('s:oldVars') | unl s:oldVars s:oldEndCol | endif
endif
aug! snipMateAutocmds
endf
fun! snipMate#expandSnip(snip, col)
let lnum = line('.') | let col = a:col
let snippet = s:ProcessSnippet(a:snip)
" Avoid error if eval evaluates to nothing
if snippet == '' | return '' | endif
" Expand snippet onto current position with the tab stops removed
let snipLines = split(substitute(snippet, '$\d\+\|${\d\+.\{-}}', '', 'g'), "\n", 1)
let line = getline(lnum)
let afterCursor = strpart(line, col - 1)
" Keep text after the cursor
if afterCursor != "\t" && afterCursor != ' '
let line = strpart(line, 0, col - 1)
let snipLines[-1] .= afterCursor
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, line.snipLines[0])
" Autoindent snippet according to previous indentation
let indent = matchend(line, '^.\{-}\ze\(\S\|$\)') + 1
call append(lnum, map(snipLines[1:], "'".strpart(line, 0, indent - 1)."'.v:val"))
" Open any folds snippet expands into
if &fen | sil! exe lnum.','.(lnum + len(snipLines) - 1).'foldopen' | endif
let [g:snipPos, s:snipLen] = s:BuildTabStops(snippet, lnum, col - indent, indent)
if s:snipLen
aug snipMateAutocmds
au CursorMovedI * call s:UpdateChangedSnip(0)
au InsertEnter * call s:UpdateChangedSnip(1)
aug END
let s:lastBuf = bufnr(0) " Only expand snippet while in current buffer
let s:curPos = 0
let s:endCol = g:snipPos[s:curPos][1]
let s:endLine = g:snipPos[s:curPos][0]
call cursor(g:snipPos[s:curPos][0], g:snipPos[s:curPos][1])
let s:prevLen = [line('$'), col('$')]
if g:snipPos[s:curPos][2] != -1 | return s:SelectWord() | endif
else
unl g:snipPos s:snipLen
" Place cursor at end of snippet if no tab stop is given
let newlines = len(snipLines) - 1
call cursor(lnum + newlines, indent + len(snipLines[-1]) - len(afterCursor)
\ + (newlines ? 0: col - 1))
endif
return ''
endf
" Prepare snippet to be processed by s:BuildTabStops
fun! s:ProcessSnippet(snip)
let snippet = a:snip
if exists('g:snipmate_content_visual')
let visual = g:snipmate_content_visual | unlet g:snipmate_content_visual
else
let visual = ''
endif
let snippet = substitute(snippet,'{VISUAL}', escape(visual,'%\'), 'g')
" 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, '\%(\\\@<!\%(\\\\\)*\)\@<=`', 1)
let isexp = 0
for i in snip
if isexp
call add(new, substitute(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')
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, '${\d\+:\(.\{-}\)}', '&\1', '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 = 1
while stridx(snippet, '${'.i) != -1
let s = matchstr(snippet, '${'.i.':\zs.\{-}\ze}')
if s != ''
let snippet = substitute(snippet, '$'.i, s.'&', 'g')
endif
let i += 1
endw
if &et " Expand tabs to spaces if 'expandtab' is set.
return substitute(snippet, '\t', repeat(' ', &sts ? &sts : &sw), 'g')
endif
return snippet
endf
" Counts occurences of haystack in needle
fun! s:Count(haystack, needle)
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
endf
" 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). If there is no text, -1 is returned.
" 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.
fun! s:BuildTabStops(snip, lnum, col, indent)
let snipPos = []
let i = 1
let withoutVars = substitute(a:snip, '$\d\+', '', 'g')
while stridx(a:snip, '${'.i) != -1
let beforeTabStop = matchstr(withoutVars, '^.*\ze${'.i.'\D')
let withoutOthers = substitute(withoutVars, '${\('.i.'\D\)\@!\d\+.\{-}}', '', 'g')
let j = i - 1
call add(snipPos, [0, 0, -1])
let snipPos[j][0] = a:lnum + s:Count(beforeTabStop, "\n")
let snipPos[j][1] = a:indent + len(matchstr(withoutOthers, '.*\(\n\|^\)\zs.*\ze${'.i.'\D'))
if snipPos[j][0] == a:lnum | let snipPos[j][1] += a:col | endif
" Get all $# matches in another list, if ${#:name} is given
if stridx(withoutVars, '${'.i.':') != -1
let snipPos[j][2] = len(matchstr(withoutVars, '${'.i.':\zs.\{-}\ze}'))
let dots = repeat('.', snipPos[j][2])
call add(snipPos[j], [])
let withoutOthers = substitute(a:snip, '${\d\+.\{-}}\|$'.i.'\@!\d\+', '', 'g')
while match(withoutOthers, '$'.i.'\(\D\|$\)') != -1
let beforeMark = matchstr(withoutOthers, '^.\{-}\ze'.dots.'$'.i.'\(\D\|$\)')
call add(snipPos[j][3], [0, 0])
let snipPos[j][3][-1][0] = a:lnum + s:Count(beforeMark, "\n")
let snipPos[j][3][-1][1] = a:indent + (snipPos[j][3][-1][0] > a:lnum
\ ? len(matchstr(beforeMark, '.*\n\zs.*'))
\ : a:col + len(beforeMark))
let withoutOthers = substitute(withoutOthers, '$'.i.'\ze\(\D\|$\)', '', '')
endw
endif
let i += 1
endw
return [snipPos, i - 1]
endf
fun! snipMate#jumpTabStop(backwards)
let leftPlaceholder = exists('s:origWordLen')
\ && s:origWordLen != g:snipPos[s:curPos][2]
if leftPlaceholder && exists('s:oldEndCol')
let startPlaceholder = s:oldEndCol + 1
endif
if exists('s:update')
call s:UpdatePlaceholderTabStops()
else
call s:UpdateTabStops()
endif
" Don't reselect placeholder if it has been modified
if leftPlaceholder && g:snipPos[s:curPos][2] != -1
if exists('startPlaceholder')
let g:snipPos[s:curPos][1] = startPlaceholder
else
let g:snipPos[s:curPos][1] = col('.')
let g:snipPos[s:curPos][2] = 0
endif
endif
let s:curPos += a:backwards ? -1 : 1
" Loop over the snippet when going backwards from the beginning
if s:curPos < 0 | let s:curPos = s:snipLen - 1 | endif
if s:curPos == s:snipLen
let sMode = s:endCol == g:snipPos[s:curPos-1][1]+g:snipPos[s:curPos-1][2]
call s:RemoveSnippet()
return sMode ? "\<tab>" : snipMate#TriggerSnippet()
endif
call cursor(g:snipPos[s:curPos][0], g:snipPos[s:curPos][1])
let s:endLine = g:snipPos[s:curPos][0]
let s:endCol = g:snipPos[s:curPos][1]
let s:prevLen = [line('$'), col('$')]
return g:snipPos[s:curPos][2] == -1 ? '' : s:SelectWord()
endf
fun! s:UpdatePlaceholderTabStops()
let changeLen = s:origWordLen - g:snipPos[s:curPos][2]
unl s:startCol s:origWordLen s:update
if !exists('s:oldVars') | return | endif
" Update tab stops in snippet if text has been added via "$#"
" (e.g., in "${1:foo}bar$1${2}").
if changeLen != 0
let curLine = line('.')
for pos in g:snipPos
if pos == g:snipPos[s:curPos] | continue | endif
let changed = pos[0] == curLine && pos[1] > s:oldEndCol
let changedVars = 0
let endPlaceholder = pos[2] - 1 + pos[1]
" Subtract changeLen from each tab stop that was after any of
" the current tab stop's placeholders.
for [lnum, col] in s:oldVars
if lnum > pos[0] | break | endif
if pos[0] == lnum
if pos[1] > col || (pos[2] == -1 && pos[1] == col)
let changed += 1
elseif col < endPlaceholder
let changedVars += 1
endif
endif
endfor
let pos[1] -= changeLen * changed
let pos[2] -= changeLen * changedVars " Parse variables within placeholders
" e.g., "${1:foo} ${2:$1bar}"
if pos[2] == -1 | continue | endif
" Do the same to any placeholders in the other tab stops.
for nPos in pos[3]
let changed = nPos[0] == curLine && nPos[1] > s:oldEndCol
for [lnum, col] in s:oldVars
if lnum > nPos[0] | break | endif
if nPos[0] == lnum && nPos[1] > col
let changed += 1
endif
endfor
let nPos[1] -= changeLen * changed
endfor
endfor
endif
unl s:endCol s:oldVars s:oldEndCol
endf
fun! s:UpdateTabStops()
let changeLine = s:endLine - g:snipPos[s:curPos][0]
let changeCol = s:endCol - g:snipPos[s:curPos][1]
if exists('s:origWordLen')
let changeCol -= s:origWordLen
unl s:origWordLen
endif
let lnum = g:snipPos[s:curPos][0]
let col = g:snipPos[s:curPos][1]
" Update the line number of all proceeding tab stops if <cr> has
" been inserted.
if changeLine != 0
let changeLine -= 1
for pos in g:snipPos
if pos[0] >= lnum
if pos[0] == lnum | let pos[1] += changeCol | endif
let pos[0] += changeLine
endif
if pos[2] == -1 | continue | endif
for nPos in pos[3]
if nPos[0] >= lnum
if nPos[0] == lnum | let nPos[1] += changeCol | endif
let nPos[0] += changeLine
endif
endfor
endfor
elseif changeCol != 0
" Update the column of all proceeding tab stops if text has
" been inserted/deleted in the current line.
for pos in g:snipPos
if pos[1] >= col && pos[0] == lnum
let pos[1] += changeCol
endif
if pos[2] == -1 | continue | endif
for nPos in pos[3]
if nPos[0] > lnum | break | endif
if nPos[0] == lnum && nPos[1] >= col
let nPos[1] += changeCol
endif
endfor
endfor
endif
endf
fun! s:SelectWord()
let s:origWordLen = g:snipPos[s:curPos][2]
let s:oldWord = strpart(getline('.'), g:snipPos[s:curPos][1] - 1,
\ s:origWordLen)
let s:prevLen[1] -= s:origWordLen
if !empty(g:snipPos[s:curPos][3])
let s:update = 1
let s:endCol = -1
let s:startCol = g:snipPos[s:curPos][1] - 1
endif
if !s:origWordLen | return '' | endif
let l = col('.') != 1 ? 'l' : ''
if &sel == 'exclusive'
return "\<esc>".l.'v'.s:origWordLen."l\<c-g>"
endif
return s:origWordLen == 1 ? "\<esc>".l.'gh'
\ : "\<esc>".l.'v'.(s:origWordLen - 1)."l\<c-g>"
endf
" This updates the snippet as you type when text needs to be inserted
" into multiple places (e.g. in "${1:default text}foo$1bar$1",
" "default text" would be highlighted, and if the user types something,
" UpdateChangedSnip() would be called so that the text after "foo" & "bar"
" are updated accordingly)
"
" It also automatically quits the snippet if the cursor is moved out of it
" while in insert mode.
fun! s:UpdateChangedSnip(entering)
if exists('g:snipPos') && bufnr(0) != s:lastBuf
call s:RemoveSnippet()
elseif exists('s:update') " If modifying a placeholder
if !exists('s:oldVars') && s:curPos + 1 < s:snipLen
" Save the old snippet & word length before it's updated
" s:startCol must be saved too, in case text is added
" before the snippet (e.g. in "foo$1${2}bar${1:foo}").
let s:oldEndCol = s:startCol
let s:oldVars = deepcopy(g:snipPos[s:curPos][3])
endif
let col = col('.') - 1
if s:endCol != -1
let changeLen = col('$') - s:prevLen[1]
let s:endCol += changeLen
else " When being updated the first time, after leaving select mode
if a:entering | return | endif
let s:endCol = col - 1
endif
" If the cursor moves outside the snippet, quit it
if line('.') != g:snipPos[s:curPos][0] || col < s:startCol ||
\ col - 1 > s:endCol
unl! s:startCol s:origWordLen s:oldVars s:update
return s:RemoveSnippet()
endif
call s:UpdateVars()
let s:prevLen[1] = col('$')
elseif exists('g:snipPos')
if !a:entering && g:snipPos[s:curPos][2] != -1
let g:snipPos[s:curPos][2] = -2
endif
let col = col('.')
let lnum = line('.')
let changeLine = line('$') - s:prevLen[0]
if lnum == s:endLine
let s:endCol += col('$') - s:prevLen[1]
let s:prevLen = [line('$'), col('$')]
endif
if changeLine != 0
let s:endLine += changeLine
let s:endCol = col
endif
" Delete snippet if cursor moves out of it in insert mode
if (lnum == s:endLine && (col > s:endCol || col < g:snipPos[s:curPos][1]))
\ || lnum > s:endLine || lnum < g:snipPos[s:curPos][0]
call s:RemoveSnippet()
endif
endif
endf
" This updates the variables in a snippet when a placeholder has been edited.
" (e.g., each "$1" in "${1:foo} $1bar $1bar")
fun! s:UpdateVars()
let newWordLen = s:endCol - s:startCol + 1
let newWord = strpart(getline('.'), s:startCol, newWordLen)
if newWord == s:oldWord || empty(g:snipPos[s:curPos][3])
return
endif
let changeLen = g:snipPos[s:curPos][2] - newWordLen
let curLine = line('.')
let startCol = col('.')
let oldStartSnip = s:startCol
let updateTabStops = changeLen != 0
let i = 0
for [lnum, col] in g:snipPos[s:curPos][3]
if updateTabStops
let start = s:startCol
if lnum == curLine && col <= start
let s:startCol -= changeLen
let s:endCol -= changeLen
endif
for nPos in g:snipPos[s:curPos][3][(i):]
" This list is in ascending order, so quit if we've gone too far.
if nPos[0] > lnum | break | endif
if nPos[0] == lnum && nPos[1] > col
let nPos[1] -= changeLen
endif
endfor
if lnum == curLine && col > start
let col -= changeLen
let g:snipPos[s:curPos][3][i][1] = col
endif
let i += 1
endif
" "Very nomagic" is used here to allow special characters.
call setline(lnum, substitute(getline(lnum), '\%'.col.'c\V'.
\ escape(s:oldWord, '\'), escape(newWord, '\&'), ''))
endfor
if oldStartSnip != s:startCol
call cursor(0, startCol + s:startCol - oldStartSnip)
endif
let s:oldWord = newWord
let g:snipPos[s:curPos][2] = newWordLen
endf
" should be moved to utils or such?
fun! snipMate#SetByPath(dict, path, value)
let d = a:dict
for p in a:path[:-2]
if !has_key(d,p) | let d[p] = {} | endif
let d = d[p]
endfor
let d[a:path[-1]] = a:value
endf
" reads a .snippets file
" returns list of
" ['triggername', 'name', 'contents']
" if triggername is not set 'default' is assumed
fun! snipMate#ReadSnippetsFile(file)
let result = []
if !filereadable(a:file) | return result | endif
let r_guard = 'guard\s\+\zs.*'
let inSnip = 0
let guard = 1
for line in readfile(a:file) + ["\n"]
if inSnip == 2 && line =~ r_guard
let guard = matchstr(line, r_guard)
elseif inSnip && (line[0] == "\t" || line == '')
let content .= strpart(line, 1)."\n"
continue
elseif inSnip
call add(result, [trigger, name == '' ? 'default' : name, content[:-2], guard])
let inSnip = 0
let guard = "1"
endif
if inSnip == 2
let inSnip = 1
endif
if line[:6] == 'snippet'
" 2 signals first line
let inSnip = 2
let trigger = strpart(line, 8)
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 = ''
endif
endfor
return result
endf
" adds scope aliases to list.
" returns new list
" the aliases of aliases are added recursively
fun! s:AddScopeAliases(list)
let did = {}
let scope_aliases = get(s:c,'scope_aliases', {})
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
" don't ask me wy searching for trigger { is soo slow.
fun! s:Glob(dir, file)
let f = a:dir.a:file
if a:dir =~ '\*' || isdirectory(a:dir)
return split(glob(escape(f,"{}")),"\n")
else
return filereadable(f) ? [f] : []
endif
endf
" returns dict of
" { path: { 'type': one of 'snippet' 'snippets',
" 'exists': 1 or 0
" " for single snippet files:
" 'name': name of snippet
" 'trigger': trigger of snippet
" }
" }
" use trigger = '*' to match all snippet files
" use mustExist = 1 to return existing files only
"
" mustExist = 0 is used by OpenSnippetFiles
fun! snipMate#GetSnippetFiles(mustExist, scopes, trigger)
let paths = funcref#Call(s:c.snippet_dirs)
let result = {}
let scopes = s:AddScopeAliases(a:scopes)
" collect existing files
for scope in scopes
for r in paths
let rtp_last = fnamemodify(r,':t')
" .snippets files (many snippets per file).
let glob_p = r.'/snippets/'.scope.'.snippets'
for snippetsF in split(glob(glob_p),"\n")
let scope = fnamemodify(snippetsF,':t:r')
let result[snippetsF] = {'exists': 1, 'type': 'snippets', 'name_prefix': rtp_last.' '.scope }
endfor
if !a:mustExist && !has_key(result, glob_p)
" name_prefix not used
let result[glob_p] = {'exists': 0, 'type': 'snippets'}
endif
let glob_p = r.'/snippets/'.scope.'/*.snippets'
for snippetsF in split(glob(glob_p),"\n")
let result[snippetsF] = {'exists': 1, 'type': 'snippets', 'name_prefix' : rtp_last.' '.fnamemodify(snippetsF,':t:r')}
endfor
" == one file per snippet: ==
" without name snippets/<filetype>/<trigger>.snippet
for f in s:Glob(r.'/snippets/'.scope,'/'.a:trigger.'.snippet')
let trigger = fnamemodify(f,':t:r')
let result[f] = {'exists': 1, 'type': 'snippet', 'name': 'default', 'trigger': trigger, 'name_prefix' : rtp_last.' '.scope}
endfor
" add /snippets/trigger/*.snippet files (TODO)
" with name (multi-snip) snippets/<filetype>/<trigger>/<name>.snippet
for f in s:Glob(r.'/snippets/'.scope.'/'.a:trigger,'/*.snippet')
let name = fnamemodify(f,':t:r')
let trigger = fnamemodify(f,':h:t')
let result[f] = {'exists': 1, 'type': 'snippet', 'name': name, 'trigger': trigger, 'name_prefix' : rtp_last.' '.scope}
endfor
endfor
endfor
return result
endf
fun! snipMate#EvalGuard(guard)
" left: everything left of expansion
" word: the expanded word
" are guaranteed to be in scpe
if a:guard == '1' | return 1 | endif
let word = s:c.word
" eval is evil, but backticks are allowed anyway.
let left = getline('.')[:col('.')-3 - len(word)]
exec 'return '.a:guard
endf
" default triggers based on paths
fun! snipMate#DefaultPool(scopes, trigger, result)
let triggerR = substitute(a:trigger,'*','.*','g')
for [f,opts] in items(snipMate#GetSnippetFiles(1, a:scopes, a:trigger))
if opts.type == 'snippets'
for [trigger, name, contents, guard] in cached_file_contents#CachedFileContents(f, s:c.read_snippets_cached, 0)
if trigger !~ triggerR | continue | endif
if snipMate#EvalGuard(guard)
call snipMate#SetByPath(a:result, [trigger, opts.name_prefix.' '.name], contents)
endif
endfor
elseif opts.type == 'snippet'
call snipMate#SetByPath(a:result, [opts.trigger, opts.name_prefix.' '.opts.name], funcref#Function('return readfile('.string(f).')'))
else
throw "unexpected"
endif
endfor
endf
" 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)
let result = {}
let triggerR = escape(substitute(a:trigger,'*','.*','g'), '~') " escape '~' for use as regexp
" let scopes = s:AddScopeAliases(a:scopes)
for F in values(g:snipMateSources)
call funcref#Call(F, [a:scopes, a:trigger, result])
endfor
return result
endf
" adds leading tab
" and replaces leading spaces by tabs
" see ftplugin/snippet.vim
fun! snipMate#RetabSnip() range
let leadingTab = expand('%:e') == 'snippets'
let lines = getline(a:firstline, a:lastline)
" remove leading "\t"
let allIndented = 1
for l in lines
if l[0] != '\t' | let allIndented = 0 | endif
endfor
" retab
if allIndented
call map(lines, 'v:val[1:]')
endif
let leadingSp = filter(map(copy(lines),'matchstr(v:val,"^\\s*") '),'v:val !=""')
if !empty(leadingSp)
" lines containing leading spaces found
let smallestInd = len(sort(leadingSp)[-1])
let ind = input('retab, spaces per tab: ', smallestInd)
for i in range(0, len(lines)-1)
let ml = matchlist(lines[i], '^\(\s*\)\(.*\)')
let lines[i] = repeat("\t", len(ml[1]) / ind)
\ . repeat( " ", len(ml[1]) % ind)
\ . ml[2]
endfor
endif
" readd tab
let tab = leadingTab ? "\t" : ""
for i in range(0,len(lines)-1)
call setline(a:firstline + i, tab.lines[i])
endfor
endf
fun! snipMate#OpenSnippetFiles()
let dict = snipMate#GetSnippetFiles(0, snipMate#ScopesByFile(), '*')
" sort by files wether they exist - put existing files first
let exists = []
let notExists = []
for [file, v] in items(dict)
let v['file'] = file
if v['exists']
call add(exists, v)
else
call add(notExists, v)
endif
endfor
let all = exists + notExists
let show = map(copy(all),'(v:val["exists"] ? "exists:" : "does not exist yet:")." ".v:val["file"]')
let select = tlib#input#List('mi', 'select files to be opened in splits', show)
for idx in select
exec 'sp '.all[idx - 1]['file']
endfor
endf
fun! snipMate#ScopesByFile()
" duplicates are removed in AddScopeAliases
return filter(funcref#Call(s:c.get_scopes), "v:val != ''")
endf
" used by both: completion and insert snippet
fun! snipMate#GetSnippetsForWordBelowCursor(word, suffix, break_on_first_match)
" Setup lookups: '1.2.3' becomes [1.2.3] + [3, 2.3]
let parts = split(a:word, '\W\zs')
if len(parts) > 2
let parts = parts[-2:] " max 2 additional items, this might become a setting
endif
let lookups = [a:word.a:suffix]
let lookup = ''
for w in reverse(parts)
let lookup = w . lookup
if index(lookups, lookup) == -1
call add(lookups, lookup.a:suffix)
endif
endfor
" allow matching '.'
if a:word =~ '\.$'
call add(lookups, '.'.a:suffix)
endif
call filter(lookups, 'v:val != ""')
" echo lookups
let matching_snippets = []
let snippet = ''
" prefer longest word
for word in lookups
let s:c.word = word
" echomsg string(lookups).' current: '.word
for [k,snippetD] in items(funcref#Call(s:c['get_snippets'], [snipMate#ScopesByFile(), word]))
if a:suffix == ''
" hack: require exact match
if k !=# word | continue | endif
endif
call add(matching_snippets, [k, snippetD])
if a:break_on_first_match | 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)
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
" 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#ShowAvailableSnips()
let line = getline('.')
let col = col('.')
let word = matchstr(line, '\S\+\%'.col.'c')
let matchlen = 0
let matches = []
let snippet_triggers = map(snipMate#GetSnippetsForWordBelowCursor(word, '*', 0),'v:val[0]')
for trigger in snippet_triggers
if word == ''
let matches += [trigger] " Show all matches if word is empty
elseif trigger =~ '^'.word
let matches += [trigger]
let len = len(word)
if len > matchlen | let matchlen = len | endif
endif
endfor
" Pretty hacky, but really can't have the tab swallowed!
if len(matches) == 0
call feedkeys(s:c['no_match_completion_feedkeys_chars'], 'n')
return ""
endif
" This is to avoid a bug with Vim when using complete(col - matchlen, matches)
" (Issue#46 on the Google Code snipMate issue tracker).
call setline(line('.'), substitute(line, repeat('.', matchlen).'\%'.col.'c', '', ''))
call complete(col, sort(matches))
return ''
endf
" user interface implementation {{{1
fun! snipMate#TriggerSnippet()
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
call feedkeys("\<tab>") | return ''
endif
if exists('g:snipPos') | return snipMate#jumpTabStop(0) | 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 s = s:ChooseSnippet(snippetD)
if type(s) == type([])
let snippet = join(s, "\n")
else
let snippet = s
end
let &undolevels = &undolevels " create new undo point
let col = col('.') - len(trigger)
sil exe 's/\V'.escape(trigger, '/\.').'\%#//'
return snipMate#expandSnip(snippet, 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>"
endf
fun! snipMate#BackwardsSnippet()
if exists('g:snipPos') | return snipMate#jumpTabStop(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

@ -0,0 +1,47 @@
" 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()
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)
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)
" 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

@ -0,0 +1,458 @@
*snipMate.txt* Plugin for using TextMate-style snippets in Vim.
snipMate *snippet* *snippets* *snipMate*
Last Change: December 27, 2009
|snipMate-installation| Installation
|snipMate-description| Description
|snipMate-related-work| Related work
|snipMate-usage| Usage (GETTING STARTED QUICKLY)
|snipMate-snippet-sources| snippet sources
|snipMate-syntax| Snippet syntax
|snipMate-settings| Settings
|snipMate-features| Features
|snipMate-disadvantages| Disadvantages to TextMate
|snipMate-contact| Contact
|snipMate-license| License
|snipMate-bugs| BUGS
For Vim version 7.0 or later.
This plugin only works if 'compatible' is not set.
{Vi does not have any of these features.}
==============================================================================
INSTALLATION *snipMate-installation*
Of course you can use whatever tool you want.
However some features of snipMate depend on external VimL code:
tlib: tlib#input#List (providing a nice selection list)
vim-addon-mw-utils: (providing all the caching implementation)
Thus i recommend vim-addon-manager to install snipMate because this will also
fetch the dependencies for you.
The complete set of dependencies can be found in snipMate-addon-info.txt
The current VAM-plugin name for this enhanced version of snipMate is "snipMate".
==============================================================================
DESCRIPTION *snipMate-description*
snipMate is an extension to Vim which allows you to store and retrieve text
snippets with placeholders in a very convenient way.
snipMate is inspired by TextMate's snippet features.
==============================================================================
RELATED WORK *snipMate-related-work*
There are some alternatives:
- ultisnips (python based)
- xptemplate which is probably a much more powerful
but also more complex
- (..?)
snipmate is not perfect - however it gets its job done perfectly and gets out
of your way. So if you want to get started fast without reading too much
documentation probably snipmate is for you.
==============================================================================
USAGE (GETTING STARTED QUICKLY) *snipMate-usage*
Adding snippets: >
:SnipMateOpenSnippetFiles
< all valid snippet locations will be shown in a list. Existing files are
shown first. The list depends on Vim's |runtimepath|. Thus snipMate
perfectly integrates with the recommended way of installing each plugin into
its own directory which all newer plugin management solutions (VAM,
Pathogen, Vundle, ..) propagate.
The command will only show non existing .snippets files. See |snipMate-syntax|
to learn about all supported files snipMate can read.
In .snippets files you should use \t as indentation character which will
be replaced by spaces/tabs depending on your Vim indentation settings.
You can retab your snippet text by visually selecting it and pressing <cr>.
Using snippets: ~
<c-r><tab>: shows a list of available snippets
XX<tab> : will either show a list of all snippets starting with the
characters XX or expand the snippet if it matches a snippet name.
associating snippets and filetypes: ~
1) >
g:snipMate.scope_aliases
< defines which snippets types are available when you edit a buffer.
You can override the default in autoload/snipMate.vim in your .vimrc. For
example, to add both ruby.snippets and ruby-rails.snippets for files of
filetype='ruby', add the following to your vimrc: >
let g:snipMate = {}
let g:snipMate.scope_aliases = {}
let g:snipMate.scope_aliases['ruby'] = 'ruby,ruby-rails'
< SnipMate scopes are akin to filetypes. Setting a scope alias as shown above
allows multiple snippets files to be used for one filetype without actually
changing the filetype.
2)
set filetype to a list such as 'html.javascript' or such.
Add this to your .vimrc to not add tabs if there is no match: >
let g:snipMate['no_match_completion_feedkeys_chars'] = ""
<
*snipMate-disambiguation*
What happens if multiple files or filetypes define the same snippet name or if
|multi_snip| is being used? This results in name collisions!
You'll get list of matching snippets and can choose one.
Snippets are loaded and refreshed automatically on demand.
The parsed .snippets files are cached.
in the current buffer to show a list via.
------------------------------------------------------------------------------
SNIPPET SOURCES *snippet-sources*
snipMate is configurable.
plugin/snipMate.vim assigns three important keys:
>
" default implementation collecting snippets by handlers
let g:snipMate['get_snippets'] = snipMate#GetSnippets
" default handler:
let g:snipMateSources['default'] = snipMate#DefaultPool
" default directories containing snippets:
let g:snipMate['snippet_dirs'] = funcref#Function('return split(&runtimepath,",")')
<
You can override all 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 know 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')
<
More details about all possible relative locations to |rtp| can be found in
|snipMate-syntax|
==============================================================================
SYNTAX *snippet-syntax* *snipMate-syntax*
Default snippet sources [1], you can add your own as illustrated in
|snippet-sources|.
trigger: the snippet's name.
|rtp| : Vim's |runtimepath| path list
one snippet per file:
|rtp|/snippets/<filetype>/<trigger>.snippet
many snippets per file, triggers are specified in file, see below:
|rtp|/snippets/<filetype>.snippets (RECOMMENDED)
|rtp|/snippets/<filetype>/*.snippets
See |snipMate-disambiguation| to learn about how name collisions are handled.
Note that dotted
'filetype' syntax is supported -- e.g., you can use >
:set ft=html.eruby syntax=sql
to activate snippets for both HTML, eRuby and sql for the current file.
See g:snipMate['get_scopes'] in plugin/snipMate.vim. However, this is not
recommended, as it can have unwanted side effects (appears to break some forms
of syntax highlighting). Instead, set g:snipMate.scope_aliases.
See|snipMate-usage|.
The syntax for snippets in *.snippets files is the following: >
snippet trigger
guard left_from_cursor='^\s*'
expanded text
more expanded text
Note: the guard condition line is optional. It can be used to make a snippet available
only in some cases. the value should be a viml expression.
(This implementation may change). Only supported in *.snippets files by now.
Multiple snippets having the same name but different triggers exist?
Note that the first hard tab after the snippet trigger is required, and not
expanded in the actual snippet. The syntax for *.snippet files is the same,
only without the trigger declaration and starting indentation.
Also note that indentation within snippets must be defined using hard tabs.
They can be expanded to spaces later if desired (see |snipMate-indenting|).
You can retab a snippet by visually selecting the lines, then press <cr>.
"#" is used as a line-comment character in *.snippets files; however, they can
only be used outside of a snippet declaration. E.g.: >
# this is a correct comment
snippet trigger
expanded text
snippet another_trigger
# this isn't a comment!
expanded text
<
This should hopefully be obvious with the included syntax highlighting.
*snipMate-${#}*
Tab stops ~
By default, the cursor is placed at the end of a snippet. To specify where the
cursor is to be placed next, use "${#}", where the # is the number of the tab
stop. E.g., to place the cursor first on the id of a <div> tag, and then allow
the user to press <tab> to go to the middle of it:
>
snippet div
<div id="${1}">
${2}
</div>
<
*snipMate-placeholders* *snipMate-${#:}* *snipMate-$#*
Placeholders ~
Placeholder text can be supplied using "${#:text}", where # is the number of
the tab stop. This text then can be copied throughout the snippet using "$#",
given # is the same number as used before. So, to make a C for loop: >
snippet for
for (${2:i}; $2 < ${1:count}; $1++) {
${4}
}
This will cause "count" to first be selected and change if the user starts
typing. When <tab> is pressed, the "i" in ${2}'s position will be selected;
all $2 variables will default to "i" and automatically be updated if the user
starts typing.
NOTE: "$#" syntax is used only for variables, not for tab stops as in TextMate.
Variables within variables are also possible. For instance: >
snippet opt
<option value="${1:option}">${2:$1}</option>
Will, as usual, cause "option" to first be selected and update all the $1
variables if the user starts typing. Since one of these variables is inside of
${2}, this text will then be used as a placeholder for the next tab stop,
allowing the user to change it if he wishes.
To copy a value throughout a snippet without supplying default text, simply
use the "${#:}" construct without the text; e.g.: >
snippet foo
${1:}bar$1
< *snipMate-commands*
*snipMate-visual-selection-support*
There is a special placeholder called {VISUAL}. If you visually select text,
then press <tab> Vim switches to insert mode. The next snippet you'll expand
will replace {VISUAL} by the text which was selected previously
Interpolated Vim Script ~
Snippets can also contain Vim script commands that are executed (via |eval()|)
when the snippet is inserted. Commands are given inside backticks (`...`); for
TextMates's functionality, use the |system()| function. E.g.: >
snippet date
`system("date +%Y-%m-%d")`
will insert the current date, assuming you are on a Unix system. Note that you
can also (and should) use |strftime()| for this example.
Filename([{expr}] [, {defaultText}]) *snipMate-filename* *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.
*multi_snip*
To specify that a snippet can have multiple matches in a *.snippets file, use
this syntax: >
snippet trigger A description of snippet #1
expand this text
snippet trigger A description of snippet #2
expand THIS text!
See |snipMate-disambiguation|
==============================================================================
SETTINGS *snipMate-settings* *g:snips_author*
The g:snips_author string (similar to $TM_FULLNAME in TextMate) should be set
to your name; it can then be used in snippets to automatically add it. E.g.: >
let g:snips_author = 'Hubert Farnsworth'
snippet name
`g:snips_author`
<
*snipMate-expandtab* *snipMate-indenting*
If you would like your snippets to be expanded using spaces instead of tabs,
just enable 'expandtab' and set 'softtabstop' to your preferred amount of
spaces. If 'softtabstop' is not set, 'shiftwidth' is used instead.
*snipMate-trigger*
snipMate comes with a setting to configure the key that is used to trigger
snipMate. To configure the key set g:snips_trigger_key to something other than
<tab>,e.g. <c-space> use:
let g:snips_trigger_key='<c-space>'
snipMate will try to automatically configure backwards trigger to prepend shift
key infront, e.g. <s-tab> or <s-c-space>. You can manually configure backward
trigger using:
let g:snips_trigger_key_backwards='<c-space>'
==============================================================================
FEATURES *snipMate-features*
snipMate.vim has the following features among others:
- The syntax of snippets is very similar to TextMate's, allowing
easy conversion.
- The position of the snippet is kept transparently (i.e. it does not use
markers/placeholders written to the buffer), which allows you to escape
out of an incomplete snippet, something particularly useful in Vim.
- Variables in snippets are updated as-you-type.
- Snippets can have multiple matches.
- Snippets can be out of order. For instance, in a do...while loop, the
condition can be added before the code.
- [New] File-based snippets are supported.
- [New] Triggers after non-word delimiters are expanded, e.g. "foo"
in "bar.foo".
- [New] <shift-tab> can now be used to jump tab stops in reverse order.
==============================================================================
DISADVANTAGES *snipMate-disadvantages*
snipMate.vim currently has the following disadvantages to TextMate's snippets:
- There is no $0; the order of tab stops must be explicitly stated.
- Placeholders within placeholders are not possible. E.g.: >
'<div${1: id="${2:some_id}}">${3}</div>'
<
In TextMate this would first highlight ' id="some_id"', and if
you hit delete it would automatically skip ${2} and go to ${3}
on the next <tab>, but if you didn't delete it it would highlight
"some_id" first. You cannot do this in snipMate.vim.
- Regex cannot be performed on variables, such as "${1/.*/\U&}"
- Placeholders cannot span multiple lines.
- Activating snippets in different scopes of the same file is
not possible.
Perhaps some of these features will be added in a later release.
==============================================================================
CONTACT *snipMate-contact* *snipMate-author*
current maintainers:
- garbas
- Marc Weber (marco-oweber@gmx.de)
You should consider creating a github ticket or contacting us because the
original author Michael Sanders did not act upon change requests for long
time. Anyway - he did most of the hard initial work.
To contact the author (Michael Sanders), please email:
msanders42+snipmate <at> gmail <dot> com
==============================================================================
BUGS *snipMate-bugs*
<c-space> does not work: Try gvim. <c-space> is mapped to ctrl-2 or such in
Vim - this is not a snipmate issue.
[1]: I think having so many different ways is too complicated
- Marc Weber
==============================================================================
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

@ -0,0 +1,10 @@
" 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()
return stridx(&ft, 'xhtml') == -1 ? '' : ' /'
endf

View File

@ -0,0 +1,8 @@
command! -buffer -range=% RetabSnip <line1>,<line2>call snipMate#RetabSnip()
vnoremap <buffer> <cr> :RetabSnip<cr>
if !exists('g:nsippet_no_indentation_settings')
setlocal sw=4
setlocal tabstop=4
setlocal noexpandtab
endif

View File

@ -0,0 +1 @@
runtime! ftplugin/snippet.vim

View File

@ -0,0 +1,83 @@
" File: snipMate.vim
" Author: Michael Sanders
" Version: 0.84
" 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.txt
if exists('loaded_snips') || &cp || version < 700
finish
endif
let loaded_snips = 1
if !exists('snips_author') | let snips_author = 'Me' | endif
try
call funcref#Function('')
catch /.*/
echoe "you're missing vim-addon-mw-utils. See install instructions at ".expand('<sfile>:h:h').'/README.rst'
endtry
if (!exists('g:snipMateSources'))
let g:snipMateSources = {}
" default source: get snippets based on runtimepath:
let g:snipMateSources['default'] = funcref#Function('snipMate#DefaultPool')
endif
au BufRead,BufNewFile *.snippet set ft=snippet
au FileType snippet setl noet nospell
au BufRead,BufNewFile *.snippets set ft=snippets
au FileType snippets setl noet nospell fdm=expr fde=getline(v:lnum)!~'^\\t\\\\|^$'?'>1':1
" config which can be overridden (shared lines)
if !exists('g:snipMate')
let g:snipMate = {}
endif
let s:snipMate = g:snipMate
let s:snipMate['get_snippets'] = get(s:snipMate, 'get_snippets', funcref#Function("snipMate#GetSnippets"))
" old snippets_dir: function returning list of paths which is used to read
" snippets. You can replace it with your own implementation. Defaults to all
" directories in &rtp/snippets/*
let s:snipMate['snippet_dirs'] = get(s:snipMate, 'snippet_dirs', funcref#Function('return split(&runtimepath,",")'))
" _ is default scope added always
"
" &ft honors multiple filetypes and syntax such as in set ft=html.javascript syntax=FOO
let s:snipMate['get_scopes'] = get(s:snipMate, 'get_scopes', funcref#Function('return split(&ft,"\\.")+[&syntax, "_"]'))
if !exists('snippets_dir')
let snippets_dir = substitute(globpath(&rtp, 'snippets/'), "\n", ',', 'g')
endif
" Processes a single-snippet file; optionally add the name of the parent
" directory for a snippet with multiple matches.
fun! s:ProcessFile(file, ft, ...)
let keyword = fnamemodify(a:file, ':t:r')
if keyword == '' | return | endif
try
let text = join(readfile(a:file), "\n")
catch /E484/
echom "Error in snipMate.vim: couldn't read file: ".a:file
endtry
return a:0 ? MakeSnip(a:ft, a:1, text, keyword)
\ : MakeSnip(a:ft, keyword, text)
endf
" dummy for compatibility - will be removed
" moving to autoload to improve loading speed and debugging
fun! TriggerSnippet()
echoe "replace TriggerSnippet by snipMate#TriggerSnippet, please!"
return snipMate#TriggerSnippet()
endf
fun! BackwardSnippet()
echoe "replace BackwardSnippet by snipMate#BackwardsSnippet, please!"
return snipMate#BackwardsSnippet()
endf
" vim:noet:sw=4:ts=4:ft=vim

View File

@ -0,0 +1,2 @@
" some useful commands
command! SnipMateOpenSnippetFiles call snipMate#OpenSnippetFiles()

View File

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

@ -0,0 +1,23 @@
" 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 '^guard\s\+.*' contains=multiSnipText,snipKeyword
syn match multiSnipText '\S\+ \zs.*' contained
syn match snipKeyword '^snippet'me=s+8 contained
syn match snipError "^[^#s\t].*$"
hi link snippet Identifier
hi link snipComment Comment
hi link multiSnipText String
hi link snipKeyword Keyword
hi link snipEscape SpecialChar
hi link snipComment Comment
hi link placeHolder Special
hi link tabStop Special
hi link snipCommand String
hi link snipError Error