]> git.madduck.net Git - etc/vim.git/blob - .vim/plugin/snipMate.vim

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

check in snipmate 0.83
[etc/vim.git] / .vim / plugin / snipMate.vim
1 " File:          snipMate.vim
2 " Author:        Michael Sanders
3 " Last Updated:  July 13, 2009
4 " Version:       0.83
5 " Description:   snipMate.vim implements some of TextMate's snippets features in
6 "                Vim. A snippet is a piece of often-typed text that you can
7 "                insert into your document using a trigger word followed by a "<tab>".
8 "
9 "                For more help see snipMate.txt; you can do this by using:
10 "                :helptags ~/.vim/doc
11 "                :h snipMate.txt
12
13 if exists('loaded_snips') || &cp || version < 700
14         finish
15 endif
16 let loaded_snips = 1
17 if !exists('snips_author') | let snips_author = 'Me' | endif
18
19 au BufRead,BufNewFile *.snippets\= set ft=snippet
20 au FileType snippet setl noet fdm=indent
21
22 let s:snippets = {} | let s:multi_snips = {}
23
24 if !exists('snippets_dir')
25         let snippets_dir = substitute(globpath(&rtp, 'snippets/'), "\n", ',', 'g')
26 endif
27
28 fun! MakeSnip(scope, trigger, content, ...)
29         let multisnip = a:0 && a:1 != ''
30         let var = multisnip ? 's:multi_snips' : 's:snippets'
31         if !has_key({var}, a:scope) | let {var}[a:scope] = {} | endif
32         if !has_key({var}[a:scope], a:trigger)
33                 let {var}[a:scope][a:trigger] = multisnip ? [[a:1, a:content]] : a:content
34         elseif multisnip | let {var}[a:scope][a:trigger] += [[a:1, a:content]]
35         else
36                 echom 'Warning in snipMate.vim: Snippet '.a:trigger.' is already defined.'
37                                 \ .' See :h multi_snip for help on snippets with multiple matches.'
38         endif
39 endf
40
41 fun! ExtractSnips(dir, ft)
42         for path in split(globpath(a:dir, '*'), "\n")
43                 if isdirectory(path)
44                         let pathname = fnamemodify(path, ':t')
45                         for snipFile in split(globpath(path, '*.snippet'), "\n")
46                                 call s:ProcessFile(snipFile, a:ft, pathname)
47                         endfor
48                 elseif fnamemodify(path, ':e') == 'snippet'
49                         call s:ProcessFile(path, a:ft)
50                 endif
51         endfor
52 endf
53
54 " Processes a single-snippet file; optionally add the name of the parent
55 " directory for a snippet with multiple matches.
56 fun s:ProcessFile(file, ft, ...)
57         let keyword = fnamemodify(a:file, ':t:r')
58         if keyword  == '' | return | endif
59         try
60                 let text = join(readfile(a:file), "\n")
61         catch /E484/
62                 echom "Error in snipMate.vim: couldn't read file: ".a:file
63         endtry
64         return a:0 ? MakeSnip(a:ft, a:1, text, keyword)
65                         \  : MakeSnip(a:ft, keyword, text)
66 endf
67
68 fun! ExtractSnipsFile(file, ft)
69         if !filereadable(a:file) | return | endif
70         let text = readfile(a:file)
71         let inSnip = 0
72         for line in text + ["\n"]
73                 if inSnip && (line[0] == "\t" || line == '')
74                         let content .= strpart(line, 1)."\n"
75                         continue
76                 elseif inSnip
77                         call MakeSnip(a:ft, trigger, content[:-2], name)
78                         let inSnip = 0
79                 endif
80
81                 if line[:6] == 'snippet'
82                         let inSnip = 1
83                         let trigger = strpart(line, 8)
84                         let name = ''
85                         let space = stridx(trigger, ' ') + 1
86                         if space " Process multi snip
87                                 let name = strpart(trigger, space)
88                                 let trigger = strpart(trigger, 0, space - 1)
89                         endif
90                         let content = ''
91                 endif
92         endfor
93 endf
94
95 fun! ResetSnippets()
96         let s:snippets = {} | let s:multi_snips = {} | let g:did_ft = {}
97 endf
98
99 let g:did_ft = {}
100 fun! GetSnippets(dir, filetypes)
101         for ft in split(a:filetypes, '\.')
102                 if has_key(g:did_ft, ft) | continue | endif
103                 call s:DefineSnips(a:dir, ft, ft)
104                 if ft == 'objc' || ft == 'cpp' || ft == 'cs'
105                         call s:DefineSnips(a:dir, 'c', ft)
106                 elseif ft == 'xhtml'
107                         call s:DefineSnips(a:dir, 'html', 'xhtml')
108                 endif
109                 let g:did_ft[ft] = 1
110         endfor
111 endf
112
113 " Define "aliasft" snippets for the filetype "realft".
114 fun s:DefineSnips(dir, aliasft, realft)
115         for path in split(globpath(a:dir, a:aliasft.'/')."\n".
116                                         \ globpath(a:dir, a:aliasft.'-*/'), "\n")
117                 call ExtractSnips(path, a:realft)
118         endfor
119         for path in split(globpath(a:dir, a:aliasft.'.snippets')."\n".
120                                         \ globpath(a:dir, a:aliasft.'-*.snippets'), "\n")
121                 call ExtractSnipsFile(path, a:realft)
122         endfor
123 endf
124
125 fun! TriggerSnippet()
126         if exists('g:SuperTabMappingForward')
127                 if g:SuperTabMappingForward == "<tab>"
128                         let SuperTabKey = "\<c-n>"
129                 elseif g:SuperTabMappingBackward == "<tab>"
130                         let SuperTabKey = "\<c-p>"
131                 endif
132         endif
133
134         if pumvisible() " Update snippet if completion is used, or deal with supertab
135                 if exists('SuperTabKey')
136                         call feedkeys(SuperTabKey) | return ''
137                 endif
138                 call feedkeys("\<esc>a", 'n') " Close completion menu
139                 call feedkeys("\<tab>") | return ''
140         endif
141
142         if exists('g:snipPos') | return snipMate#jumpTabStop(0) | endif
143
144         let word = matchstr(getline('.'), '\S\+\%'.col('.').'c')
145         for scope in [bufnr('%')] + split(&ft, '\.') + ['_']
146                 let [trigger, snippet] = s:GetSnippet(word, scope)
147                 " If word is a trigger for a snippet, delete the trigger & expand
148                 " the snippet.
149                 if snippet != ''
150                         let col = col('.') - len(trigger)
151                         sil exe 's/\V'.escape(trigger, '/.').'\%#//'
152                         return snipMate#expandSnip(snippet, col)
153                 endif
154         endfor
155
156         if exists('SuperTabKey')
157                 call feedkeys(SuperTabKey)
158                 return ''
159         endif
160         return "\<tab>"
161 endf
162
163 fun! BackwardsSnippet()
164         if exists('g:snipPos') | return snipMate#jumpTabStop(1) | endif
165
166         if exists('g:SuperTabMappingForward')
167                 if g:SuperTabMappingBackward == "<s-tab>"
168                         let SuperTabKey = "\<c-p>"
169                 elseif g:SuperTabMappingForward == "<s-tab>"
170                         let SuperTabKey = "\<c-n>"
171                 endif
172         endif
173         if exists('SuperTabKey')
174                 call feedkeys(SuperTabKey)
175                 return ''
176         endif
177         return "\<s-tab>"
178 endf
179
180 " Check if word under cursor is snippet trigger; if it isn't, try checking if
181 " the text after non-word characters is (e.g. check for "foo" in "bar.foo")
182 fun s:GetSnippet(word, scope)
183         let word = a:word | let snippet = ''
184         while snippet == ''
185                 if exists('s:snippets["'.a:scope.'"]["'.escape(word, '\"').'"]')
186                         let snippet = s:snippets[a:scope][word]
187                 elseif exists('s:multi_snips["'.a:scope.'"]["'.escape(word, '\"').'"]')
188                         let snippet = s:ChooseSnippet(a:scope, word)
189                         if snippet == '' | break | endif
190                 else
191                         if match(word, '\W') == -1 | break | endif
192                         let word = substitute(word, '.\{-}\W', '', '')
193                 endif
194         endw
195         if word == '' && a:word != '.' && stridx(a:word, '.') != -1
196                 let [word, snippet] = s:GetSnippet('.', a:scope)
197         endif
198         return [word, snippet]
199 endf
200
201 fun s:ChooseSnippet(scope, trigger)
202         let snippet = []
203         let i = 1
204         for snip in s:multi_snips[a:scope][a:trigger]
205                 let snippet += [i.'. '.snip[0]]
206                 let i += 1
207         endfor
208         if i == 2 | return s:multi_snips[a:scope][a:trigger][0][1] | endif
209         let num = inputlist(snippet) - 1
210         return num == -1 ? '' : s:multi_snips[a:scope][a:trigger][num][1]
211 endf
212
213 fun! ShowAvailableSnips()
214         let line  = getline('.')
215         let col   = col('.')
216         let word  = matchstr(getline('.'), '\S\+\%'.col.'c')
217         let words = [word]
218         if stridx(word, '.')
219                 let words += split(word, '\.', 1)
220         endif
221         let matchlen = 0
222         let matches = []
223         for scope in [bufnr('%')] + split(&ft, '\.') + ['_']
224                 let triggers = has_key(s:snippets, scope) ? keys(s:snippets[scope]) : []
225                 if has_key(s:multi_snips, scope)
226                         let triggers += keys(s:multi_snips[scope])
227                 endif
228                 for trigger in triggers
229                         for word in words
230                                 if word == ''
231                                         let matches += [trigger] " Show all matches if word is empty
232                                 elseif trigger =~ '^'.word
233                                         let matches += [trigger]
234                                         let len = len(word)
235                                         if len > matchlen | let matchlen = len | endif
236                                 endif
237                         endfor
238                 endfor
239         endfor
240
241         " This is to avoid a bug with Vim when using complete(col - matchlen, matches)
242         " (Issue#46 on the Google Code snipMate issue tracker).
243         call setline(line('.'), substitute(line, repeat('.', matchlen).'\%'.col.'c', '', ''))
244         call complete(col, matches)
245         return ''
246 endf
247 " vim:noet:sw=4:ts=4:ft=vim