]>
Commit | Line | Data |
---|---|---|
1 | " File: plugin/delimitMate.vim | |
2 | " Version: 2.6 | |
3 | " Modified: 2011-01-14 | |
4 | " Description: This plugin provides auto-completion for quotes, parens, etc. | |
5 | " Maintainer: Israel Chauca F. <israelchauca@gmail.com> | |
6 | " Manual: Read ":help delimitMate". | |
7 | " ============================================================================ | |
8 | ||
9 | " Initialization: {{{ | |
10 | ||
11 | if exists("g:loaded_delimitMate") || &cp | |
12 | " User doesn't want this plugin or compatible is set, let's get out! | |
13 | finish | |
14 | endif | |
15 | let g:loaded_delimitMate = 1 | |
16 | ||
17 | if exists("s:loaded_delimitMate") && !exists("g:delimitMate_testing") | |
18 | " Don't define the functions if they already exist: just do the work | |
19 | " (unless we are testing): | |
20 | call s:DelimitMateDo() | |
21 | finish | |
22 | endif | |
23 | ||
24 | if v:version < 700 | |
25 | echoerr "delimitMate: this plugin requires vim >= 7!" | |
26 | finish | |
27 | endif | |
28 | ||
29 | let s:loaded_delimitMate = 1 | |
30 | let delimitMate_version = "2.6" | |
31 | ||
32 | function! s:option_init(name, default) "{{{ | |
33 | let b = exists("b:delimitMate_" . a:name) | |
34 | let g = exists("g:delimitMate_" . a:name) | |
35 | let prefix = "_l_delimitMate_" | |
36 | ||
37 | if !b && !g | |
38 | let sufix = a:default | |
39 | elseif !b && g | |
40 | exec "let sufix = g:delimitMate_" . a:name | |
41 | else | |
42 | exec "let sufix = b:delimitMate_" . a:name | |
43 | endif | |
44 | if exists("b:" . prefix . a:name) | |
45 | exec "unlockvar! b:" . prefix . a:name | |
46 | endif | |
47 | exec "let b:" . prefix . a:name . " = " . string(sufix) | |
48 | exec "lockvar! b:" . prefix . a:name | |
49 | endfunction "}}} | |
50 | ||
51 | function! s:init() "{{{ | |
52 | " Initialize variables: | |
53 | ||
54 | " autoclose | |
55 | call s:option_init("autoclose", 1) | |
56 | ||
57 | " matchpairs | |
58 | call s:option_init("matchpairs", string(&matchpairs)[1:-2]) | |
59 | call s:option_init("matchpairs_list", split(b:_l_delimitMate_matchpairs, ',')) | |
60 | call s:option_init("left_delims", split(b:_l_delimitMate_matchpairs, ':.,\=')) | |
61 | call s:option_init("right_delims", split(b:_l_delimitMate_matchpairs, ',\=.:')) | |
62 | ||
63 | " quotes | |
64 | call s:option_init("quotes", "\" ' `") | |
65 | call s:option_init("quotes_list", split(b:_l_delimitMate_quotes)) | |
66 | ||
67 | " nesting_quotes | |
68 | call s:option_init("nesting_quotes", []) | |
69 | ||
70 | " excluded_regions | |
71 | call s:option_init("excluded_regions", "Comment") | |
72 | call s:option_init("excluded_regions_list", split(b:_l_delimitMate_excluded_regions, ',\s*')) | |
73 | let enabled = len(b:_l_delimitMate_excluded_regions_list) > 0 | |
74 | call s:option_init("excluded_regions_enabled", enabled) | |
75 | ||
76 | " excluded filetypes | |
77 | call s:option_init("excluded_ft", "") | |
78 | ||
79 | " expand_space | |
80 | if exists("b:delimitMate_expand_space") && type(b:delimitMate_expand_space) == type("") | |
81 | echom "b:delimitMate_expand_space is '".b:delimitMate_expand_space."' but it must be either 1 or 0!" | |
82 | echom "Read :help 'delimitMate_expand_space' for more details." | |
83 | unlet b:delimitMate_expand_space | |
84 | let b:delimitMate_expand_space = 1 | |
85 | endif | |
86 | if exists("g:delimitMate_expand_space") && type(g:delimitMate_expand_space) == type("") | |
87 | echom "delimitMate_expand_space is '".g:delimitMate_expand_space."' but it must be either 1 or 0!" | |
88 | echom "Read :help 'delimitMate_expand_space' for more details." | |
89 | unlet g:delimitMate_expand_space | |
90 | let g:delimitMate_expand_space = 1 | |
91 | endif | |
92 | call s:option_init("expand_space", 0) | |
93 | ||
94 | " expand_cr | |
95 | if exists("b:delimitMate_expand_cr") && type(b:delimitMate_expand_cr) == type("") | |
96 | echom "b:delimitMate_expand_cr is '".b:delimitMate_expand_cr."' but it must be either 1 or 0!" | |
97 | echom "Read :help 'delimitMate_expand_cr' for more details." | |
98 | unlet b:delimitMate_expand_cr | |
99 | let b:delimitMate_expand_cr = 1 | |
100 | endif | |
101 | if exists("g:delimitMate_expand_cr") && type(g:delimitMate_expand_cr) == type("") | |
102 | echom "delimitMate_expand_cr is '".g:delimitMate_expand_cr."' but it must be either 1 or 0!" | |
103 | echom "Read :help 'delimitMate_expand_cr' for more details." | |
104 | unlet g:delimitMate_expand_cr | |
105 | let g:delimitMate_expand_cr = 1 | |
106 | endif | |
107 | if ((&backspace !~ 'eol' || &backspace !~ 'start') && &backspace != 2) && | |
108 | \ ((exists('b:delimitMate_expand_cr') && b:delimitMate_expand_cr == 1) || | |
109 | \ (exists('g:delimitMate_expand_cr') && g:delimitMate_expand_cr == 1)) | |
110 | echom "delimitMate: There seems to be some incompatibility with your settings that may interfer with the expansion of <CR>. See :help 'delimitMate_expand_cr' for details." | |
111 | endif | |
112 | call s:option_init("expand_cr", 0) | |
113 | ||
114 | " smart_matchpairs | |
115 | call s:option_init("smart_matchpairs", '^\%(\w\|\!\|£\|\$\|_\|["'']\s*\S\)') | |
116 | ||
117 | " smart_quotes | |
118 | call s:option_init("smart_quotes", 1) | |
119 | ||
120 | " apostrophes | |
121 | call s:option_init("apostrophes", "") | |
122 | call s:option_init("apostrophes_list", split(b:_l_delimitMate_apostrophes, ":\s*")) | |
123 | ||
124 | " tab2exit | |
125 | call s:option_init("tab2exit", 1) | |
126 | ||
127 | " balance_matchpairs | |
128 | call s:option_init("balance_matchpairs", 0) | |
129 | ||
130 | let b:_l_delimitMate_buffer = [] | |
131 | ||
132 | endfunction "}}} Init() | |
133 | ||
134 | "}}} | |
135 | ||
136 | " Functions: {{{ | |
137 | ||
138 | function! s:Map() "{{{ | |
139 | " Set mappings: | |
140 | try | |
141 | let save_cpo = &cpo | |
142 | let save_keymap = &keymap | |
143 | let save_iminsert = &iminsert | |
144 | let save_imsearch = &imsearch | |
145 | set keymap= | |
146 | set cpo&vim | |
147 | if b:_l_delimitMate_autoclose | |
148 | call s:AutoClose() | |
149 | else | |
150 | call s:NoAutoClose() | |
151 | endif | |
152 | call s:ExtraMappings() | |
153 | finally | |
154 | let &cpo = save_cpo | |
155 | let &keymap = save_keymap | |
156 | let &iminsert = save_iminsert | |
157 | let &imsearch = save_imsearch | |
158 | endtry | |
159 | ||
160 | let b:delimitMate_enabled = 1 | |
161 | ||
162 | endfunction "}}} Map() | |
163 | ||
164 | function! s:Unmap() " {{{ | |
165 | let imaps = | |
166 | \ b:_l_delimitMate_right_delims + | |
167 | \ b:_l_delimitMate_left_delims + | |
168 | \ b:_l_delimitMate_quotes_list + | |
169 | \ b:_l_delimitMate_apostrophes_list + | |
170 | \ ['<BS>', '<S-BS>', '<Del>', '<CR>', '<Space>', '<S-Tab>', '<Esc>'] + | |
171 | \ ['<Up>', '<Down>', '<Left>', '<Right>', '<LeftMouse>', '<RightMouse>'] + | |
172 | \ ['<Home>', '<End>', '<PageUp>', '<PageDown>', '<S-Down>', '<S-Up>', '<C-G>g'] | |
173 | ||
174 | for map in imaps | |
175 | if maparg(map, "i") =~? 'delimitMate' | |
176 | if map == '|' | |
177 | let map = '<Bar>' | |
178 | endif | |
179 | exec 'silent! iunmap <buffer> ' . map | |
180 | endif | |
181 | endfor | |
182 | ||
183 | if !has('gui_running') | |
184 | silent! iunmap <C-[>OC | |
185 | endif | |
186 | ||
187 | let b:delimitMate_enabled = 0 | |
188 | endfunction " }}} s:Unmap() | |
189 | ||
190 | function! s:TestMappingsDo() "{{{ | |
191 | %d | |
192 | if !exists("g:delimitMate_testing") | |
193 | silent call delimitMate#TestMappings() | |
194 | else | |
195 | let temp_varsDM = [b:_l_delimitMate_expand_space, b:_l_delimitMate_expand_cr, b:_l_delimitMate_autoclose] | |
196 | for i in [0,1] | |
197 | let b:delimitMate_expand_space = i | |
198 | let b:delimitMate_expand_cr = i | |
199 | for a in [0,1] | |
200 | let b:delimitMate_autoclose = a | |
201 | call s:init() | |
202 | call s:Unmap() | |
203 | call s:Map() | |
204 | call delimitMate#TestMappings() | |
205 | call append(line('$'),'') | |
206 | endfor | |
207 | endfor | |
208 | let b:delimitMate_expand_space = temp_varsDM[0] | |
209 | let b:delimitMate_expand_cr = temp_varsDM[1] | |
210 | let b:delimitMate_autoclose = temp_varsDM[2] | |
211 | unlet temp_varsDM | |
212 | endif | |
213 | normal gg | |
214 | g/\%^$/d | |
215 | endfunction "}}} | |
216 | ||
217 | function! s:DelimitMateDo(...) "{{{ | |
218 | ||
219 | " First, remove all magic, if needed: | |
220 | if exists("b:delimitMate_enabled") && b:delimitMate_enabled == 1 | |
221 | call s:Unmap() | |
222 | endif | |
223 | ||
224 | " Check if this file type is excluded: | |
225 | if exists("g:delimitMate_excluded_ft") && | |
226 | \ index(split(g:delimitMate_excluded_ft, ','), &filetype, 0, 1) >= 0 | |
227 | ||
228 | " Finish here: | |
229 | return 1 | |
230 | endif | |
231 | ||
232 | " Check if user tried to disable using b:loaded_delimitMate | |
233 | if exists("b:loaded_delimitMate") | |
234 | return 1 | |
235 | endif | |
236 | ||
237 | " Initialize settings: | |
238 | call s:init() | |
239 | ||
240 | " Now, add magic: | |
241 | call s:Map() | |
242 | ||
243 | if a:0 > 0 | |
244 | echo "delimitMate has been reset." | |
245 | endif | |
246 | endfunction "}}} | |
247 | ||
248 | function! s:DelimitMateSwitch() "{{{ | |
249 | if exists("b:delimitMate_enabled") && b:delimitMate_enabled | |
250 | call s:Unmap() | |
251 | echo "delimitMate has been disabled." | |
252 | else | |
253 | call s:Unmap() | |
254 | call s:init() | |
255 | call s:Map() | |
256 | echo "delimitMate has been enabled." | |
257 | endif | |
258 | endfunction "}}} | |
259 | ||
260 | function! s:Finish() " {{{ | |
261 | if exists('g:delimitMate_loaded') | |
262 | return delimitMate#Finish(1) | |
263 | endif | |
264 | return '' | |
265 | endfunction " }}} | |
266 | ||
267 | function! s:FlushBuffer() " {{{ | |
268 | if exists('g:delimitMate_loaded') | |
269 | return delimitMate#FlushBuffer() | |
270 | endif | |
271 | return '' | |
272 | endfunction " }}} | |
273 | ||
274 | "}}} | |
275 | ||
276 | " Mappers: {{{ | |
277 | function! s:NoAutoClose() "{{{ | |
278 | " inoremap <buffer> ) <C-R>=delimitMate#SkipDelim('\)')<CR> | |
279 | for delim in b:_l_delimitMate_right_delims + b:_l_delimitMate_quotes_list | |
280 | if delim == '|' | |
281 | let delim = '<Bar>' | |
282 | endif | |
283 | exec 'inoremap <silent> <Plug>delimitMate' . delim . ' <C-R>=delimitMate#SkipDelim("' . escape(delim,'"') . '")<CR>' | |
284 | exec 'silent! imap <unique> <buffer> '.delim.' <Plug>delimitMate'.delim | |
285 | endfor | |
286 | endfunction "}}} | |
287 | ||
288 | function! s:AutoClose() "{{{ | |
289 | " Add matching pair and jump to the midle: | |
290 | " inoremap <silent> <buffer> ( ()<Left> | |
291 | let i = 0 | |
292 | while i < len(b:_l_delimitMate_matchpairs_list) | |
293 | let ld = b:_l_delimitMate_left_delims[i] == '|' ? '<bar>' : b:_l_delimitMate_left_delims[i] | |
294 | let rd = b:_l_delimitMate_right_delims[i] == '|' ? '<bar>' : b:_l_delimitMate_right_delims[i] | |
295 | exec 'inoremap <silent> <Plug>delimitMate' . ld . ' ' . ld . '<C-R>=delimitMate#ParenDelim("' . escape(rd, '|') . '")<CR>' | |
296 | exec 'silent! imap <unique> <buffer> '.ld.' <Plug>delimitMate'.ld | |
297 | let i += 1 | |
298 | endwhile | |
299 | ||
300 | " Exit from inside the matching pair: | |
301 | for delim in b:_l_delimitMate_right_delims | |
302 | exec 'inoremap <silent> <Plug>delimitMate' . delim . ' <C-R>=delimitMate#JumpOut("\' . delim . '")<CR>' | |
303 | exec 'silent! imap <unique> <buffer> ' . delim . ' <Plug>delimitMate'. delim | |
304 | endfor | |
305 | ||
306 | " Add matching quote and jump to the midle, or exit if inside a pair of matching quotes: | |
307 | " inoremap <silent> <buffer> " <C-R>=delimitMate#QuoteDelim("\"")<CR> | |
308 | for delim in b:_l_delimitMate_quotes_list | |
309 | if delim == '|' | |
310 | let delim = '<Bar>' | |
311 | endif | |
312 | exec 'inoremap <silent> <Plug>delimitMate' . delim . ' <C-R>=delimitMate#QuoteDelim("\' . delim . '")<CR>' | |
313 | exec 'silent! imap <unique> <buffer> ' . delim . ' <Plug>delimitMate' . delim | |
314 | endfor | |
315 | ||
316 | " Try to fix the use of apostrophes (kept for backward compatibility): | |
317 | " inoremap <silent> <buffer> n't n't | |
318 | for map in b:_l_delimitMate_apostrophes_list | |
319 | exec "inoremap <silent> " . map . " " . map | |
320 | exec 'silent! imap <unique> <buffer> ' . map . ' <Plug>delimitMate' . map | |
321 | endfor | |
322 | endfunction "}}} | |
323 | ||
324 | function! s:ExtraMappings() "{{{ | |
325 | " If pair is empty, delete both delimiters: | |
326 | inoremap <silent> <Plug>delimitMateBS <C-R>=delimitMate#BS()<CR> | |
327 | if !hasmapto('<Plug>delimitMateBS','i') | |
328 | silent! imap <unique> <buffer> <BS> <Plug>delimitMateBS | |
329 | endif | |
330 | " If pair is empty, delete closing delimiter: | |
331 | inoremap <silent> <expr> <Plug>delimitMateS-BS delimitMate#WithinEmptyPair() ? "\<C-R>=delimitMate#Del()\<CR>" : "\<S-BS>" | |
332 | if !hasmapto('<Plug>delimitMateS-BS','i') | |
333 | silent! imap <unique> <buffer> <S-BS> <Plug>delimitMateS-BS | |
334 | endif | |
335 | " Expand return if inside an empty pair: | |
336 | inoremap <silent> <Plug>delimitMateCR <C-R>=delimitMate#ExpandReturn()<CR> | |
337 | if b:_l_delimitMate_expand_cr != 0 && !hasmapto('<Plug>delimitMateCR', 'i') | |
338 | silent! imap <unique> <buffer> <CR> <Plug>delimitMateCR | |
339 | endif | |
340 | " Expand space if inside an empty pair: | |
341 | inoremap <silent> <Plug>delimitMateSpace <C-R>=delimitMate#ExpandSpace()<CR> | |
342 | if b:_l_delimitMate_expand_space != 0 && !hasmapto('<Plug>delimitMateSpace', 'i') | |
343 | silent! imap <unique> <buffer> <Space> <Plug>delimitMateSpace | |
344 | endif | |
345 | " Jump over any delimiter: | |
346 | inoremap <silent> <Plug>delimitMateS-Tab <C-R>=delimitMate#JumpAny("\<S-Tab>")<CR> | |
347 | if b:_l_delimitMate_tab2exit && !hasmapto('<Plug>delimitMateS-Tab', 'i') | |
348 | silent! imap <unique> <buffer> <S-Tab> <Plug>delimitMateS-Tab | |
349 | endif | |
350 | " Change char buffer on Del: | |
351 | inoremap <silent> <Plug>delimitMateDel <C-R>=delimitMate#Del()<CR> | |
352 | if !hasmapto('<Plug>delimitMateDel', 'i') | |
353 | silent! imap <unique> <buffer> <Del> <Plug>delimitMateDel | |
354 | endif | |
355 | " Flush the char buffer on movement keystrokes or when leaving insert mode: | |
356 | for map in ['Esc', 'Left', 'Right', 'Home', 'End'] | |
357 | exec 'inoremap <silent> <Plug>delimitMate'.map.' <C-R>=<SID>Finish()<CR><'.map.'>' | |
358 | if !hasmapto('<Plug>delimitMate'.map, 'i') | |
359 | exec 'silent! imap <unique> <buffer> <'.map.'> <Plug>delimitMate'.map | |
360 | endif | |
361 | endfor | |
362 | " Except when pop-up menu is active: | |
363 | for map in ['Up', 'Down', 'PageUp', 'PageDown', 'S-Down', 'S-Up'] | |
364 | exec 'inoremap <silent> <expr> <Plug>delimitMate'.map.' pumvisible() ? "\<'.map.'>" : "\<C-R>=\<SID>Finish()\<CR>\<'.map.'>"' | |
365 | if !hasmapto('<Plug>delimitMate'.map, 'i') | |
366 | exec 'silent! imap <unique> <buffer> <'.map.'> <Plug>delimitMate'.map | |
367 | endif | |
368 | endfor | |
369 | " Avoid ambiguous mappings: | |
370 | for map in ['LeftMouse', 'RightMouse'] | |
371 | exec 'inoremap <silent> <Plug>delimitMateM'.map.' <C-R>=delimitMate#Finish(1)<CR><'.map.'>' | |
372 | if !hasmapto('<Plug>delimitMate'.map, 'i') | |
373 | exec 'silent! imap <unique> <buffer> <'.map.'> <Plug>delimitMateM'.map | |
374 | endif | |
375 | endfor | |
376 | ||
377 | " Jump over next delimiters | |
378 | inoremap <buffer> <Plug>delimitMateJumpMany <C-R>=len(b:_l_delimitMate_buffer) ? delimitMate#Finish(0) : delimitMate#JumpMany()<CR> | |
379 | if !hasmapto('<Plug>delimitMateJumpMany') | |
380 | imap <silent> <buffer> <C-G>g <Plug>delimitMateJumpMany | |
381 | endif | |
382 | ||
383 | " The following simply creates an ambiguous mapping so vim fully processes | |
384 | " the escape sequence for terminal keys, see 'ttimeout' for a rough | |
385 | " explanation, this just forces it to work | |
386 | if !has('gui_running') | |
387 | imap <silent> <C-[>OC <RIGHT> | |
388 | endif | |
389 | endfunction "}}} | |
390 | ||
391 | "}}} | |
392 | ||
393 | " Commands: {{{ | |
394 | ||
395 | call s:DelimitMateDo() | |
396 | ||
397 | " Let me refresh without re-loading the buffer: | |
398 | command! -bar DelimitMateReload call s:DelimitMateDo(1) | |
399 | ||
400 | " Quick test: | |
401 | command! -bar DelimitMateTest silent call s:TestMappingsDo() | |
402 | ||
403 | " Switch On/Off: | |
404 | command! -bar DelimitMateSwitch call s:DelimitMateSwitch() | |
405 | "}}} | |
406 | ||
407 | " Autocommands: {{{ | |
408 | ||
409 | augroup delimitMate | |
410 | au! | |
411 | " Run on file type change. | |
412 | "autocmd VimEnter * autocmd FileType * call <SID>DelimitMateDo() | |
413 | autocmd FileType * call <SID>DelimitMateDo() | |
414 | ||
415 | " Run on new buffers. | |
416 | autocmd BufNewFile,BufRead,BufEnter * | |
417 | \ if !exists('b:delimitMate_was_here') | | |
418 | \ call <SID>DelimitMateDo() | | |
419 | \ let b:delimitMate_was_here = 1 | | |
420 | \ endif | |
421 | ||
422 | " Flush the char buffer: | |
423 | autocmd InsertEnter * call <SID>FlushBuffer() | |
424 | autocmd BufEnter * | |
425 | \ if mode() == 'i' | | |
426 | \ call <SID>FlushBuffer() | | |
427 | \ endif | |
428 | ||
429 | augroup END | |
430 | ||
431 | "}}} | |
432 | ||
433 | " GetLatestVimScripts: 2754 1 :AutoInstall: delimitMate.vim | |
434 | " vim:foldmethod=marker:foldcolumn=4 |