└── plugin └── flatfoot.vim /plugin/flatfoot.vim: -------------------------------------------------------------------------------- 1 | " flatfoot.vim - Flatfoot 2 | " Maintainer: Tim Pope 3 | 4 | " Flatfoot helps you to quickly jump to arbitrary predefined short patterns 5 | " within a line. An example might be to jump between the "humps" of a 6 | " camelCaseWord. The interface involves passing f, t, F, or T a control 7 | " character which corresponds to a predefined regexp. The ; and , commands 8 | " will use this regexp as one would expect. 9 | " 10 | " A global variable named flatfoot_1 contains the regexp for CTRL-A, and 11 | " flatfoot_26 CTRL-Z. In other words, the decimal ASCII value of the key 12 | " press becomes the number at the end of the variable. For example, 13 | " 14 | " :let flatfoot_21 = '\u' 15 | " 16 | " sets CTRL-U to find the next uppercase character. CTRL-U comes predefined 17 | " for this, and CTRL-W and CTRL-E comes predefined to handle the beginning and 18 | " ending of camelCase and snake_case words. 19 | " 20 | " If you like the power of this plugin but don't like the awkward use of 21 | " control characters, the following alternate (but discouraged) alternative is 22 | " provided: 23 | " 24 | " nmap u Flatfoot('f','\u') 25 | " xmap u Flatfoot('f','\u') 26 | " omap u Flatfoot('f','\u','o') 27 | " 28 | " The first argument is the kind of search to use (f, t, F, or T), and the 29 | " second is the pattern. The optional third argument indicates the mode. 30 | " Since there is no way to detect operator pending mode, you MUST provide 31 | " both a regular map and an omap, as shown above. 32 | 33 | " Exit quickly when: 34 | " - this plugin was already loaded (or disabled) 35 | " - when 'compatible' is set 36 | " - the version is less than 7.0 37 | if (exists("g:loaded_flatfoot") && g:loaded_flatfoot) || &cp || v:version < 700 38 | finish 39 | endif 40 | let g:loaded_flatfoot = 1 41 | 42 | let s:cpo_save = &cpo 43 | set cpo&vim 44 | 45 | " Defaults {{{1 46 | 47 | if !exists("g:flatfoot_".char2nr("\")) 48 | let flatfoot_{char2nr("\")} = '\u' 49 | endif 50 | if !exists("g:flatfoot_".char2nr("\")) 51 | let flatfoot_{char2nr("\")} = '\C[[:alnum:]]\@")) 54 | let flatfoot_{char2nr("\")} = '\C[[:alnum:]][[:alnum:]]\@!\|[[:lower:][:digit:]][[:upper:]]\@=\|[[:upper:]]\%([[:upper:]][[:lower:]]\)\@=' 55 | endif 56 | 57 | " }}}1 58 | " Code {{{1 59 | 60 | function! s:escapemode(mode) 61 | let mode = a:mode == "" ? mode() : a:mode 62 | let mode = mode == "\" ? "\" . mode : mode 63 | return mode 64 | endfunction 65 | 66 | function! Flatfoot(op,pattern,...) 67 | let mode = s:escapemode(a:0 ? a:1 : mode()) 68 | return ''.":\call FlatfootFindPattern(".string(a:op).",".string(a:pattern).",'".mode."')\" 69 | endfunction 70 | 71 | function! s:findexpr(op,mode,...) 72 | let c = a:0 ? a:1 : getchar() 73 | if !exists("g:flatfoot_".c) && !exists("b:flatfoot_".c) 74 | unlet! s:last_pattern 75 | unlet! s:last_reverse 76 | return a:op.nr2char(c) 77 | endif 78 | let mode = s:escapemode(a:mode) 79 | return ''.":\call FlatfootFindChar('".a:op."',".c.",'".mode."')\" 80 | endfunction 81 | 82 | function! FlatfootFindChar(op,c,mode) 83 | let pat = exists("b:flatfoot_".a:c) ? b:flatfoot_{a:c} : g:flatfoot_{a:c} 84 | return FlatfootFindPattern(a:op,pat,a:mode) 85 | endfunction 86 | 87 | function! FlatfootFindPattern(op,pattern,mode) 88 | let pattern = a:pattern 89 | let reverse = '' 90 | if a:op ==# 't' 91 | let pattern = '.\%(' . pattern . '\)' 92 | elseif a:op ==# 'T' 93 | let pattern = '\%(' . pattern . '\)\zs.' 94 | let reverse = 'b' 95 | elseif a:op ==# 'F' 96 | let reverse = 'b' 97 | endif 98 | let s:last_pattern = pattern 99 | let s:last_reverse = reverse 100 | return s:go(pattern, reverse, v:count1, a:mode) 101 | endfunction 102 | 103 | 104 | function! s:repeatexpr(op,mode) 105 | let mode = s:escapemode(a:mode) 106 | if exists("s:last_pattern") 107 | return ''.":\call FlatfootFindLast('".a:op."','".mode."')\" 108 | else 109 | return a:op 110 | endif 111 | endfunction 112 | 113 | function! FlatfootFindLast(op,mode) 114 | if a:op == "," 115 | let reverse = s:last_reverse ==# 'b' ? '' : 'b' 116 | else 117 | let reverse = s:last_reverse 118 | endif 119 | return s:go(s:last_pattern, reverse, v:count1, a:mode) 120 | endfunction 121 | 122 | function! s:adjustmode(mode) 123 | if a:mode ==? "v" || a:mode == "\" 124 | norm! gv 125 | elseif a:mode == "o" 126 | norm! v 127 | endif 128 | endfunction 129 | 130 | function! s:go(pattern,reverse,count,mode) 131 | call s:adjustmode(a:mode) 132 | "let g:debug = v:count1 . a:pattern . a:reverse . col('.') 133 | let oldcol = virtcol('.') 134 | let i = 0 135 | while i < v:count1 136 | if !search(a:pattern,a:reverse,line('.')) 137 | exe "norm! ".oldcol."|" 138 | " Use escape to beep, but don't cancel visual mode 139 | if a:mode !=? "v" && a:mode != "\" 140 | exe "norm! \" 141 | endif 142 | return 0 143 | endif 144 | let i = i + 1 145 | endwhile 146 | return col('.') 147 | endfunction 148 | 149 | " }}}1 150 | " Maps {{{1 151 | 152 | nnoremap f findexpr('f',mode(),getchar()) 153 | nnoremap F findexpr('F',mode(),getchar()) 154 | nnoremap t findexpr('t',mode(),getchar()) 155 | nnoremap T findexpr('T',mode(),getchar()) 156 | nnoremap ; repeatexpr(';',mode()) 157 | nnoremap , repeatexpr(',',mode()) 158 | xnoremap f findexpr('f',mode(),getchar()) 159 | xnoremap F findexpr('F',mode(),getchar()) 160 | xnoremap t findexpr('t',mode(),getchar()) 161 | xnoremap T findexpr('T',mode(),getchar()) 162 | xnoremap ; repeatexpr(';',mode()) 163 | xnoremap , repeatexpr(',',mode()) 164 | onoremap f findexpr('f','o',getchar()) 165 | onoremap F findexpr('F','o',getchar()) 166 | onoremap t findexpr('t','o',getchar()) 167 | onoremap T findexpr('T','o',getchar()) 168 | onoremap ; repeatexpr(';','o') 169 | onoremap , repeatexpr(',','o') 170 | 171 | nnoremap