1 " space.vim - Smart Space key
2 " Author: Henrik Öhman <speeph@gmail.com>
3 " URL: http://github.com/spiiph/vim-space/tree/master
5 " ReleaseDate: 2011 jun 09
7 " Licensed under the same terms as Vim itself.
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
14 " ============================================================================
19 " Set this variable to disable space.vim
21 " let g:space_loaded = 1
23 " Set this variable to disable select mode mappings
25 " let g:space_disable_select_mode = 1
27 " These variables disables the usage of <Space> for groups of different
30 " Disable <Space> for character movements, e.g. fFtT;,
31 " let g:space_no_character_movements = 1
33 " Disable <Space> for searches, e.g. /?#*nN
34 " let g:space_no_search = 1
36 " Disable <Space> for jump commands, e.g. Ctrl-O, Ctrl-I, g, and g;
37 " let g:space_no_jump = 1
39 " Disable <Space> for diff commands, e.g. [c and ]c
40 " let g:space_no_diff = 1
42 " Disable <Space> for brace movement commands, e.g. [(, ]), [{ and ]}
43 " let g:space_no_brace = 1
45 " Disable <Space> for method movement commands, e.g. [m, ]m, [M and ]M
46 " let g:space_no_method = 1
48 " Disable <Space> for section movement commands, e.g. [[, ]], [] and ][
49 " let g:space_no_section = 1
51 " Disable <Space> for fold movement commands, e.g. [z, ]z, zj and zk
52 " let g:space_no_folds = 1
54 " Disable <Space> for tag movement commands, e.g. Ctrl-], :tag, etc.
55 " let g:space_no_tags = 1
57 " Disable <Space> for quickfix and location list commands, e.g. :cc, :ll, etc.
58 " let g:space_no_quickfix = 1
60 " Disable <Space> for undolist movements, e.g. g- and g+
61 " let g:space_no_undolist = 1
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:
67 " if exists("*GetSpaceMovement")
68 " return "[" . GetSpaceMovement() . "]"
73 " set statusline+=%{SlSpace()}
75 " TODO: Make the mapping assignments more dynamical, and allow user defined
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")
94 let g:space_loaded = 1
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>")
100 if exists("g:space_disable_select_mode")
101 silent! sunmap <Space>
102 silent! sunmap <S-Space>
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")
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", ",")
123 if exists("g:space_disable_select_mode")
134 if !exists("g:space_no_search") || !g:space_no_search
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", "*")
144 noremap <expr> <silent> * <SID>setup_space("search", "*")
145 noremap <expr> <silent> <kMultiply> <SID>setup_space("search", "*")
148 if maparg('#', 'v') != ''
149 nnoremap <expr> <silent> # <SID>setup_space("search", "#")
150 onoremap <expr> <silent> # <SID>setup_space("search", "#")
152 noremap <expr> <silent> # <SID>setup_space("search", "#")
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")
160 if exists("g:space_disable_select_mode")
163 silent! sunmap <kMultiply>
170 let s:search_mappings = 1
172 let s:search_mappings = 0
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>")
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")
189 if exists("g:space_disable_select_mode")
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", "[(")
200 noremap <expr> <silent> ]} <SID>setup_space("curly", "]}")
201 noremap <expr> <silent> [{ <SID>setup_space("curly", "[{")
203 if exists("g:space_disable_select_mode")
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")
216 noremap <expr> <silent> ]M <SID>setup_space("method_end", "]M")
217 noremap <expr> <silent> [M <SID>setup_space("method_end", "[M")
219 if exists("g:space_disable_select_mode")
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", "[[")
232 noremap <expr> <silent> ][ <SID>setup_space("section_end", "][")
233 noremap <expr> <silent> [] <SID>setup_space("section_end", "[]")
235 if exists("g:space_disable_select_mode")
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")
248 noremap <expr> <silent> ]z <SID>setup_space("fold_start", "]z")
249 noremap <expr> <silent> [z <SID>setup_space("fold_start", "[z")
251 if exists("g:space_disable_select_mode")
260 if !exists("g:space_no_tags") || !g:space_no_tags
261 noremap <expr> <silent> <C-]> <SID>setup_space("tag", "\<C-]>")
263 if exists("g:space_disable_select_mode")
267 let s:tag_mappings = 1
269 let s:tag_mappings = 0
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+")
277 if exists("g:space_disable_select_mode")
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
288 let s:quickfix_mappings = 0
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>
348 silent! unlet g:space_loaded
351 " TODO: Check if the '\>!\=' part of the pattern fails when 'iskeyword'
353 " NOTE: Since Vim allows commands like ":'k,'lvim /foo/ *", it's a little
354 " tedious to write a perfect regexp.
356 let s:pre_re = '^\%(' .
357 \ '\%(noa\%[utocmd]\s\+\)\=' .
361 \ '\%(''[0-9a-zA-Z><.]\)\|' .
371 \ '\%(''[0-9a-zA-Z><.]\)\|' .
379 let s:qf_re = '\%(' .
387 \ '\(fir\|la\)\%[st]\|' .
389 \ '\(f\|nf\|Nf\|pf\)\%[ile]' .
393 let s:lf_re = 'l\%(' .
399 \ 'ne\%[xt]\|N\%[ext]\|' .
400 \ '\(fir\|la\)\%[st]\|' .
402 \ '\(f\|nf\|Nf\|pf\)\%[ile]' .
405 let s:ta_re = 't\%(' .
415 function! s:parse_cmd_line()
416 let cmd = getcmdline()
417 let type = getcmdtype()
419 if s:search_mappings && (type == '/' || type == '?')
420 return <SID>setup_space("search", cmd)
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)
429 if s:tag_mappings && cmd =~ s:pre_re . s:ta_re
430 return <SID>setup_space("tag", cmd)
436 function! s:setup_space(type, command)
438 let s:cmd_type = "undefined"
441 let s:space_move = ";"
442 let s:shift_space_move = ","
443 let s:cmd_type = "hor"
445 let cmd = <SID>maybe_open_fold(cmd)
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)
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)
524 call <SID>debug_msg("setup_space(type = " . a:type .
525 \ ", command = " . cmd . ")")
529 function! s:do_space(shift, default)
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 . ")")
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 . ")")
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() == ':'
557 return ":\<C-u>" . (v:count ? v:count : "") . a:cmd . "\<CR>zv"
559 " special treatment of /foo and ?foo commands
560 elseif s:cmd_type == "search" && getcmdtype() =~ "[/?]"
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>"
574 if s:cmd_type == "quickfix" || s:cmd_type == "tag"
575 if getcmdtype() == ':'
578 return ":\<C-u>" . (v:count ? v:count : "") . a:cmd . "\<CR>"
580 elseif s:cmd_type == "search" && getcmdtype() =~ "[/?]"
588 function! s:debug_msg(string)
589 if exists("g:space_debug")
594 function! GetSpaceMovement()
595 if exists("s:space_move")
596 return s:space_move == "\<C-i>" ? "^I" : s:space_move