Space plugin.
[profile.git] / .vim / plugin / space.vim
1 " space.vim - Smart Space key
2 " Author:       Henrik Öhman <speeph@gmail.com>
3 " URL:          http://github.com/spiiph/vim-space/tree/master
4 " Version:      1.8
5 " ReleaseDate:  2011 jun 09
6 "
7 " Licensed under the same terms as Vim itself.
8 "
9 " NOTE: Using this script has some problems with 'foldopen', since vim won't
10 "       open folds if a command is part of a mapping. This is possible to
11 "       emulate in Normal mode, and in most cases in Visual mode. Only for
12 "       searches using '/' and '?' have I been unsuccessful in finding a
13 "       solution.
14 " ============================================================================
15 if version < 702
16     finish
17 endif
18
19 " Set this variable to disable space.vim
20 "
21 "   let g:space_loaded = 1
22
23 " Set this variable to disable select mode mappings
24 "
25 "   let g:space_disable_select_mode = 1
26
27 " These variables disables the usage of <Space> for groups of different
28 " movement commands
29 "
30 " Disable <Space> for character movements, e.g. fFtT;,
31 "   let g:space_no_character_movements = 1
32 "
33 " Disable <Space> for searches, e.g. /?#*nN
34 "   let g:space_no_search = 1
35 "
36 " Disable <Space> for jump commands, e.g. Ctrl-O, Ctrl-I, g, and g;
37 "   let g:space_no_jump = 1
38 "
39 " Disable <Space> for diff commands, e.g. [c and ]c
40 "   let g:space_no_diff = 1
41 "
42 " Disable <Space> for brace movement commands, e.g. [(, ]), [{ and ]}
43 "   let g:space_no_brace = 1
44 "
45 " Disable <Space> for method movement commands, e.g. [m, ]m, [M and ]M
46 "   let g:space_no_method = 1
47 "
48 " Disable <Space> for section movement commands, e.g. [[, ]], [] and ][
49 "   let g:space_no_section = 1
50 "
51 " Disable <Space> for fold movement commands, e.g. [z, ]z, zj and zk
52 "   let g:space_no_folds = 1
53 "
54 " Disable <Space> for tag movement commands, e.g. Ctrl-], :tag, etc.
55 "   let g:space_no_tags = 1
56 "
57 " Disable <Space> for quickfix and location list commands, e.g. :cc, :ll, etc.
58 "   let g:space_no_quickfix = 1
59 "
60 " Disable <Space> for undolist movements, e.g. g- and g+
61 "   let g:space_no_undolist = 1
62
63 " It is possible to display the current command assigned to <Space> in the
64 " status line using the GetSpaceMovement() function. Here's an example:
65 "
66 "   function! SlSpace()
67 "       if exists("*GetSpaceMovement")
68 "           return "[" . GetSpaceMovement() . "]"
69 "       else
70 "           return ""
71 "       endif
72 "   endfunc
73 "   set statusline+=%{SlSpace()}
74
75 " TODO: Make the mapping assignments more dynamical, and allow user defined
76 "       commands?
77
78 if exists("g:space_debug")
79     let g:space_no_character_movements = 0
80     let g:space_no_search = 0
81     let g:space_no_jump = 0
82     let g:space_no_diff = 0
83     let g:space_no_brace = 0
84     let g:space_no_method = 0
85     let g:space_no_section = 0
86     let g:space_no_folds = 0
87     let g:space_no_quickfix = 0
88     let g:space_no_undolist = 0
89     let g:space_no_tags = 0
90     echomsg "Running space.vim in debug mode."
91 elseif exists("g:space_loaded")
92     finish
93 endif
94 let g:space_loaded = 1
95
96 " Mapping of <Space>/<S-Space> and possibly <BS>
97 noremap <expr> <silent> <Space>   <SID>do_space(0, "<Space>")
98 noremap <expr> <silent> <S-Space> <SID>do_space(1, "<S-Space>")
99
100 if exists("g:space_disable_select_mode")
101     silent! sunmap <Space>
102     silent! sunmap <S-Space>
103     silent! sunmap <BS>
104 endif
105
106 if mapcheck("<BS>") == "" || !has("gui_running")
107     noremap <expr> <silent> <BS>      <SID>do_space(1, "<BS>")
108     if exists("g:space_disable_select_mode")
109         silent! sunmap <BS>
110     endif
111 endif
112
113
114 " character movement commands
115 if !exists("g:space_no_character_movements") || !g:space_no_character_movements
116     noremap <expr> <silent> f <SID>setup_space("char", "f")
117     noremap <expr> <silent> F <SID>setup_space("char", "F")
118     noremap <expr> <silent> t <SID>setup_space("char", "t")
119     noremap <expr> <silent> T <SID>setup_space("char", "T")
120     noremap <expr> <silent> ; <SID>setup_space("char", ";")
121     noremap <expr> <silent> , <SID>setup_space("char", ",")
122
123     if exists("g:space_disable_select_mode")
124         silent! sunmap f
125         silent! sunmap F
126         silent! sunmap t
127         silent! sunmap T
128         silent! sunmap ;
129         silent! sunmap ,
130     endif
131 endif
132
133 " search commands
134 if !exists("g:space_no_search") || !g:space_no_search
135
136     " do not override visual mappings for * and #
137     " because these are often used for visual search functions
138     if maparg('*', 'v') != ''
139         nnoremap <expr> <silent> *           <SID>setup_space("search", "*")
140         onoremap <expr> <silent> *           <SID>setup_space("search", "*")
141         nnoremap <expr> <silent> <kMultiply> <SID>setup_space("search", "*")
142         onoremap <expr> <silent> <kMultiply> <SID>setup_space("search", "*")
143     else
144         noremap <expr> <silent> *           <SID>setup_space("search", "*")
145         noremap <expr> <silent> <kMultiply> <SID>setup_space("search", "*")
146     endif
147
148     if maparg('#', 'v') != ''
149         nnoremap <expr> <silent> # <SID>setup_space("search", "#")
150         onoremap <expr> <silent> # <SID>setup_space("search", "#")
151     else
152         noremap  <expr> <silent> # <SID>setup_space("search", "#")
153     endif
154
155     noremap <expr> <silent> g* <SID>setup_space("search", "g*")
156     noremap <expr> <silent> g# <SID>setup_space("search", "g#")
157     noremap <expr> <silent> n  <SID>setup_space("search", "n")
158     noremap <expr> <silent> N  <SID>setup_space("search", "N")
159
160     if exists("g:space_disable_select_mode")
161         silent! sunmap *
162         silent! sunmap #
163         silent! sunmap <kMultiply>
164         silent! sunmap g*
165         silent! sunmap g#
166         silent! sunmap n
167         silent! sunmap N
168     endif
169
170     let s:search_mappings = 1
171 else
172     let s:search_mappings = 0
173 endif
174
175 " jump commands
176 " NOTE: Jumps are not motions. They can't be used in Visual mode.
177 if !exists("g:space_no_jump") || !g:space_no_jump
178     nnoremap <expr> <silent> g, <SID>setup_space("cjump", "g,")
179     nnoremap <expr> <silent> g; <SID>setup_space("cjump", "g;")
180     nnoremap <expr> <silent> <C-O> <SID>setup_space("jump", "\<C-o>")
181     nnoremap <expr> <silent> <C-I> <SID>setup_space("jump", "\<C-i>")
182 endif
183
184 " diff next/prev
185 if !exists("g:space_no_diff") || !g:space_no_diff
186     noremap <expr> <silent> ]c <SID>setup_space("diff", "]c")
187     noremap <expr> <silent> [c <SID>setup_space("diff", "[c")
188
189     if exists("g:space_disable_select_mode")
190         silent! sunmap ]c
191         silent! sunmap [c
192     endif
193 endif
194
195 " previous/next unmatched ( or [
196 if !exists("g:space_no_brace") || !g:space_no_brace
197     noremap <expr> <silent> ]) <SID>setup_space("paren", "])")
198     noremap <expr> <silent> [( <SID>setup_space("paren", "[(")
199
200     noremap <expr> <silent> ]} <SID>setup_space("curly", "]}")
201     noremap <expr> <silent> [{ <SID>setup_space("curly", "[{")
202
203     if exists("g:space_disable_select_mode")
204         silent! sunmap ])
205         silent! sunmap [(
206         silent! sunmap ]}
207         silent! sunmap [{
208     endif
209 endif
210
211 " start/end of a method
212 if !exists("g:space_no_method") || !g:space_no_method
213     noremap <expr> <silent> ]m <SID>setup_space("method_start", "]m")
214     noremap <expr> <silent> [m <SID>setup_space("method_start", "[m")
215
216     noremap <expr> <silent> ]M <SID>setup_space("method_end", "]M")
217     noremap <expr> <silent> [M <SID>setup_space("method_end", "[M")
218
219     if exists("g:space_disable_select_mode")
220         silent! sunmap ]m
221         silent! sunmap [m
222         silent! sunmap ]M
223         silent! sunmap [M
224     endif
225 endif
226
227 " previous/next section or '}'/'{' in the first column
228 if !exists("g:space_no_section") || !g:space_no_section
229     noremap <expr> <silent> ]] <SID>setup_space("section_start", "]]")
230     noremap <expr> <silent> [[ <SID>setup_space("section_start", "[[")
231
232     noremap <expr> <silent> ][ <SID>setup_space("section_end", "][")
233     noremap <expr> <silent> [] <SID>setup_space("section_end", "[]")
234
235     if exists("g:space_disable_select_mode")
236         silent! sunmap ]]
237         silent! sunmap [[
238         silent! sunmap ][
239         silent! sunmap []
240     endif
241 endif
242
243 " previous/next fold
244 if !exists("g:space_no_folds") || !g:space_no_folds
245     noremap <expr> <silent> zj <SID>setup_space("fold_next", "zj")
246     noremap <expr> <silent> zk <SID>setup_space("fold_next", "zk")
247
248     noremap <expr> <silent> ]z <SID>setup_space("fold_start", "]z")
249     noremap <expr> <silent> [z <SID>setup_space("fold_start", "[z")
250
251     if exists("g:space_disable_select_mode")
252         silent! sunmap zj
253         silent! sunmap zk
254         silent! sunmap ]z
255         silent! sunmap [z
256     endif
257 endif
258
259 " tag movement
260 if !exists("g:space_no_tags") || !g:space_no_tags
261     noremap <expr> <silent> <C-]> <SID>setup_space("tag", "\<C-]>")
262
263     if exists("g:space_disable_select_mode")
264         silent! sunmap <C-]>
265     endif
266
267     let s:tag_mappings = 1
268 else
269     let s:tag_mappings = 0
270 endif
271
272 " undolist movement
273 if !exists("g:space_no_undolist") || !g:space_no_undolist
274     noremap <expr> <silent> g- <SID>setup_space("undo", "g-")
275     noremap <expr> <silent> g+ <SID>setup_space("undo", "g+")
276
277     if exists("g:space_disable_select_mode")
278         silent! sunmap g-
279         silent! sunmap g+
280     endif
281 endif
282
283 " quickfix and location list commands
284 if !exists("g:space_no_quickfix") || !g:space_no_quickfix
285     cnoremap <expr> <CR> <SID>parse_cmd_line()
286     let s:quickfix_mappings = 1
287 else
288     let s:quickfix_mappings = 0
289 endif
290
291 " TODO: Have all mappings add the remapped sequence to a list, and use that
292 "       list to remove mappings.
293 command! SpaceRemoveMappings call <SID>remove_space_mappings()
294 function! s:remove_space_mappings()
295     silent! unmap <Space>
296     silent! unmap <S-Space>
297     silent! unmap <BS>
298
299     silent! unmap f
300     silent! unmap F
301     silent! unmap t
302     silent! unmap T
303     silent! unmap ;
304     silent! unmap ,
305
306     silent! unmap *
307     silent! unmap #
308     silent! unmap g*
309     silent! unmap g#
310     silent! unmap n
311     silent! unmap N
312
313     silent! nunmap g,
314     silent! nunmap g;
315     silent! nunmap <C-o>
316     silent! nunmap <C-i>
317
318     silent! unmap ]c
319     silent! unmap [c
320
321     silent! unmap [(
322     silent! unmap ])
323     silent! unmap [{
324     silent! unmap ]}
325
326     silent! unmap ]]
327     silent! unmap [[
328     silent! unmap ][
329     silent! unmap []
330
331     silent! unmap ]m
332     silent! unmap [m
333     silent! unmap ]M
334     silent! unmap [M
335
336     silent! unmap zj
337     silent! unmap zk
338     silent! unmap ]z
339     silent! unmap [z
340
341     silent! unmap <C-]>
342
343     silent! unmap g-
344     silent! unmap g+
345
346     silent! cunmap <CR>
347
348     silent! unlet g:space_loaded
349 endfunction
350
351 " TODO: Check if the '\>!\=' part of the pattern fails when 'iskeyword'
352 "       contains '!'
353 " NOTE: Since Vim allows commands like ":'k,'lvim /foo/ *", it's a little
354 "       tedious to write a perfect regexp.
355
356 let s:pre_re = '^\%(' .
357     \   '\%(noa\%[utocmd]\s\+\)\=' .
358     \   '\%(' .
359     \     '\%(' .
360     \       '\%(\d\+\)\|' .
361     \       '\%(''[0-9a-zA-Z><.]\)\|' .
362     \       '\%(\\[/?&]\)\|' .
363     \       '[%$.]' .
364     \     '\)' .
365     \     '\%([-+]\d*\)\=' .
366     \   '\)\=' .
367     \   ',\=' .
368     \   '\%(' .
369     \     '\%(' .
370     \       '\%(\d\+\)\|' .
371     \       '\%(''[0-9a-zA-Z><.]\)\|' .
372     \       '\%(\\[/?&]\)\|' .
373     \       '[%$.]' .
374     \     '\)' .
375     \     '\%([-+]\d*\)\=' .
376     \   '\)\=' .
377     \ '\)\='
378
379 let s:qf_re = '\%(' .
380     \ 'mak\%[e]\|' .
381     \ 'v\%[imgrep]\|' .
382     \ 'gr\%[ep]\|' .
383     \ 'c\%(' .
384     \   'c\|' .
385     \   'p\%[revious]\|' .
386     \   '[nN]\%[ext]\|' .
387     \   '\(fir\|la\)\%[st]\|' .
388     \   'r\%[ewind]\|' .
389     \   '\(f\|nf\|Nf\|pf\)\%[ile]' .
390     \   '\)' .
391     \ '\)\>!\='
392
393 let s:lf_re = 'l\%(' .
394     \ 'mak\%[e]\|' .
395     \ 'v\%[imgrep]\|' .
396     \ 'gr\%[ep]\|' .
397     \ 'l\|' .
398     \ 'p\%[revious]\|' .
399     \ 'ne\%[xt]\|N\%[ext]\|' .
400     \ '\(fir\|la\)\%[st]\|' .
401     \ 'r\%[ewind]\|' .
402     \ '\(f\|nf\|Nf\|pf\)\%[ile]' .
403     \ '\)\>!\='
404
405 let s:ta_re = 't\%(' .
406     \ 'a\%[g]\|' .
407     \ 'n\%[ext]\|' .
408     \ 'p\%[revious]\|' .
409     \ 'N\%[ext]\|' .
410     \ 'r\%[ewind]\|' .
411     \ 'f\%[irst]\|' .
412     \ 'l\%[ast]\|' .
413     \ '\)\>!\='
414
415 function! s:parse_cmd_line()
416     let cmd = getcmdline()
417     let type = getcmdtype()
418
419     if s:search_mappings && (type == '/' || type == '?')
420         return <SID>setup_space("search", cmd)
421     elseif type == ':'
422         if s:quickfix_mappings
423             if cmd =~ s:pre_re . s:lf_re
424                 return <SID>setup_space("lf", cmd)
425             elseif cmd =~ s:pre_re . s:qf_re
426                 return <SID>setup_space("qf", cmd)
427             endif
428         endif
429         if s:tag_mappings && cmd =~ s:pre_re . s:ta_re
430             return <SID>setup_space("tag", cmd)
431         endif
432     end
433     return "\<CR>"
434 endfunc
435
436 function! s:setup_space(type, command)
437     let cmd = a:command
438     let s:cmd_type = "undefined"
439
440     if a:type == "char"
441         let s:space_move = ";"
442         let s:shift_space_move = ","
443         let s:cmd_type = "hor"
444         if cmd =~ "[;,]$"
445             let cmd = <SID>maybe_open_fold(cmd)
446         endif
447     elseif a:type == "diff"
448         let s:space_move = "]c"
449         let s:shift_space_move = "[c"
450     elseif a:type == "method_start"
451         let s:space_move = "]m"
452         let s:shift_space_move = "[m"
453         let s:cmd_type = "block"
454         let cmd = <SID>maybe_open_fold(cmd)
455     elseif a:type == "method_end"
456         let s:space_move = "]M"
457         let s:shift_space_move = "[M"
458         let s:cmd_type = "block"
459         let cmd = <SID>maybe_open_fold(cmd)
460     elseif a:type == "section_start"
461         let s:space_move = "]]"
462         let s:shift_space_move = "[["
463         let s:cmd_type = "block"
464         let cmd = <SID>maybe_open_fold(cmd)
465     elseif a:type == "section_end"
466         let s:space_move = "]["
467         let s:shift_space_move = "[]"
468         let s:cmd_type = "block"
469         let cmd = <SID>maybe_open_fold(cmd)
470     elseif a:type == "paren"
471         let s:space_move = "])"
472         let s:shift_space_move = "[("
473         let s:cmd_type = "block"
474         let cmd = <SID>maybe_open_fold(cmd)
475     elseif a:type == "curly"
476         let s:space_move = "]}"
477         let s:shift_space_move = "[{"
478         let s:cmd_type = "block"
479         let cmd = <SID>maybe_open_fold(cmd)
480     elseif a:type == "fold_next"
481         let s:space_move = "zj"
482         let s:shift_space_move = "zk"
483     elseif a:type == "fold_start"
484         let s:space_move = "]z"
485         let s:shift_space_move = "[z"
486     elseif a:type == "search"
487         let s:space_move = "n"
488         let s:shift_space_move = "N"
489         let s:cmd_type = "search"
490         let cmd = <SID>maybe_open_fold(cmd)
491     elseif a:type == "cjump"
492         let s:space_move = "g,"
493         let s:shift_space_move = "g;"
494         let s:cmd_type = "jump"
495         let cmd = <SID>maybe_open_fold(cmd)
496     elseif a:type == "jump"
497         let s:space_move = "\<C-i>"
498         let s:shift_space_move = "\<C-o>"
499         let s:cmd_type = "jump"
500         let cmd = <SID>maybe_open_fold(cmd)
501     elseif a:type == "tag"
502         let s:space_move = "tn"
503         let s:shift_space_move = "tp"
504         let s:cmd_type = "tag"
505         if getcmdtype() == ':'
506             let cmd = <SID>maybe_open_fold(cmd)
507         endif
508     elseif a:type == "qf"
509         let s:space_move = "cn"
510         let s:shift_space_move = "cN"
511         let s:cmd_type = "quickfix"
512         let cmd = <SID>maybe_open_fold(cmd)
513     elseif a:type == "lf"
514         let s:space_move = "lne"
515         let s:shift_space_move = "lN"
516         let s:cmd_type = "quickfix"
517         let cmd = <SID>maybe_open_fold(cmd)
518     elseif a:type == "undo"
519         let s:space_move = "g-"
520         let s:shift_space_move = "g+"
521         let s:cmd_type = "undo"
522         let cmd = <SID>maybe_open_fold(cmd)
523     endif
524     call <SID>debug_msg("setup_space(type = " . a:type .
525         \ ", command = " . cmd . ")")
526     return cmd
527 endfunc
528
529 function! s:do_space(shift, default)
530     " <Space>
531     if a:shift == 0
532         if exists("s:space_move")
533             let cmd = <SID>maybe_open_fold(s:space_move)
534             call <SID>debug_msg("do_space(cmd = " . cmd . ")")
535         else
536             let cmd = a:default
537         endif
538     " <S-Space> and <BS>
539     else
540         if exists("s:shift_space_move")
541             let cmd = <SID>maybe_open_fold(s:shift_space_move)
542             call <SID>debug_msg("do_space(cmd = " . cmd . ")")
543         else
544             let cmd = a:default
545         endif
546     endif
547     return cmd
548 endfunc
549
550 function! s:maybe_open_fold(cmd)
551     if !exists("g:space_no_foldopen") && &foldopen =~ s:cmd_type && v:operator != "c"
552         " special treatment of :ex commands
553         if s:cmd_type == "quickfix" || s:cmd_type == "tag"
554             if getcmdtype() == ':'
555                 return "\<CR>"
556             else
557                 return ":\<C-u>" . (v:count ? v:count : "") . a:cmd . "\<CR>zv"
558             endif
559         " special treatment of /foo and ?foo commands
560         elseif s:cmd_type == "search" && getcmdtype() =~ "[/?]"
561             return "\<CR>zv"
562         else
563             if mode() =~ "[vV\16]"
564                 " NOTE: That this works is probably a bug in vim.  Let's hope
565                 "       it stays that way. ;)
566                 return ":\<C-u>normal! gv" . (v:count ? v:count : "")
567                     \ . a:cmd . "zv\<CR>"
568                 "return a:cmd . "zv"
569             else
570                 return a:cmd . "zv"
571             endif
572         endif
573     else
574         if s:cmd_type == "quickfix" || s:cmd_type == "tag"
575             if getcmdtype() == ':'
576                 return "\<CR>"
577             else
578                 return ":\<C-u>" . (v:count ? v:count : "") . a:cmd . "\<CR>"
579             endif
580         elseif s:cmd_type == "search" && getcmdtype() =~ "[/?]"
581             return "\<CR>"
582         else
583             return a:cmd
584         endif
585     endif
586 endfunc
587
588 function! s:debug_msg(string)
589     if exists("g:space_debug")
590         echomsg a:string
591     endif
592 endfunc
593
594 function! GetSpaceMovement()
595     if exists("s:space_move")
596         return s:space_move == "\<C-i>" ? "^I" : s:space_move
597     else
598         return ""
599     end
600 endfunc
601
602 " vim: et sts=4 sw=4