[15393] | 1 | Index: ../trunk-jpl/externalpackages/vim/addons/vim/plugin/matchit.vim
|
---|
| 2 | ===================================================================
|
---|
| 3 | --- ../trunk-jpl/externalpackages/vim/addons/vim/plugin/matchit.vim (revision 0)
|
---|
| 4 | +++ ../trunk-jpl/externalpackages/vim/addons/vim/plugin/matchit.vim (revision 14737)
|
---|
| 5 | @@ -0,0 +1,812 @@
|
---|
| 6 | +" matchit.vim: (global plugin) Extended "%" matching
|
---|
| 7 | +" Last Change: Fri Jan 25 10:00 AM 2008 EST
|
---|
| 8 | +" Maintainer: Benji Fisher PhD <benji@member.AMS.org>
|
---|
| 9 | +" Version: 1.13.2, for Vim 6.3+
|
---|
| 10 | +" URL: http://www.vim.org/script.php?script_id=39
|
---|
| 11 | +
|
---|
| 12 | +" Documentation:
|
---|
| 13 | +" The documentation is in a separate file, matchit.txt .
|
---|
| 14 | +
|
---|
| 15 | +" Credits:
|
---|
| 16 | +" Vim editor by Bram Moolenaar (Thanks, Bram!)
|
---|
| 17 | +" Original script and design by Raul Segura Acevedo
|
---|
| 18 | +" Support for comments by Douglas Potts
|
---|
| 19 | +" Support for back references and other improvements by Benji Fisher
|
---|
| 20 | +" Support for many languages by Johannes Zellner
|
---|
| 21 | +" Suggestions for improvement, bug reports, and support for additional
|
---|
| 22 | +" languages by Jordi-Albert Batalla, Neil Bird, Servatius Brandt, Mark
|
---|
| 23 | +" Collett, Stephen Wall, Dany St-Amant, Yuheng Xie, and Johannes Zellner.
|
---|
| 24 | +
|
---|
| 25 | +" Debugging:
|
---|
| 26 | +" If you'd like to try the built-in debugging commands...
|
---|
| 27 | +" :MatchDebug to activate debugging for the current buffer
|
---|
| 28 | +" This saves the values of several key script variables as buffer-local
|
---|
| 29 | +" variables. See the MatchDebug() function, below, for details.
|
---|
| 30 | +
|
---|
| 31 | +" TODO: I should think about multi-line patterns for b:match_words.
|
---|
| 32 | +" This would require an option: how many lines to scan (default 1).
|
---|
| 33 | +" This would be useful for Python, maybe also for *ML.
|
---|
| 34 | +" TODO: Maybe I should add a menu so that people will actually use some of
|
---|
| 35 | +" the features that I have implemented.
|
---|
| 36 | +" TODO: Eliminate the MultiMatch function. Add yet another argument to
|
---|
| 37 | +" Match_wrapper() instead.
|
---|
| 38 | +" TODO: Allow :let b:match_words = '\(\(foo\)\(bar\)\):\3\2:end\1'
|
---|
| 39 | +" TODO: Make backrefs safer by using '\V' (very no-magic).
|
---|
| 40 | +" TODO: Add a level of indirection, so that custom % scripts can use my
|
---|
| 41 | +" work but extend it.
|
---|
| 42 | +
|
---|
| 43 | +" allow user to prevent loading
|
---|
| 44 | +" and prevent duplicate loading
|
---|
| 45 | +if exists("loaded_matchit") || &cp
|
---|
| 46 | + finish
|
---|
| 47 | +endif
|
---|
| 48 | +let loaded_matchit = 1
|
---|
| 49 | +let s:last_mps = ""
|
---|
| 50 | +let s:last_words = ":"
|
---|
| 51 | +
|
---|
| 52 | +let s:save_cpo = &cpo
|
---|
| 53 | +set cpo&vim
|
---|
| 54 | +
|
---|
| 55 | +nnoremap <silent> % :<C-U>call <SID>Match_wrapper('',1,'n') <CR>
|
---|
| 56 | +nnoremap <silent> g% :<C-U>call <SID>Match_wrapper('',0,'n') <CR>
|
---|
| 57 | +vnoremap <silent> % :<C-U>call <SID>Match_wrapper('',1,'v') <CR>m'gv``
|
---|
| 58 | +vnoremap <silent> g% :<C-U>call <SID>Match_wrapper('',0,'v') <CR>m'gv``
|
---|
| 59 | +onoremap <silent> % v:<C-U>call <SID>Match_wrapper('',1,'o') <CR>
|
---|
| 60 | +onoremap <silent> g% v:<C-U>call <SID>Match_wrapper('',0,'o') <CR>
|
---|
| 61 | +
|
---|
| 62 | +" Analogues of [{ and ]} using matching patterns:
|
---|
| 63 | +nnoremap <silent> [% :<C-U>call <SID>MultiMatch("bW", "n") <CR>
|
---|
| 64 | +nnoremap <silent> ]% :<C-U>call <SID>MultiMatch("W", "n") <CR>
|
---|
| 65 | +vmap [% <Esc>[%m'gv``
|
---|
| 66 | +vmap ]% <Esc>]%m'gv``
|
---|
| 67 | +" vnoremap <silent> [% :<C-U>call <SID>MultiMatch("bW", "v") <CR>m'gv``
|
---|
| 68 | +" vnoremap <silent> ]% :<C-U>call <SID>MultiMatch("W", "v") <CR>m'gv``
|
---|
| 69 | +onoremap <silent> [% v:<C-U>call <SID>MultiMatch("bW", "o") <CR>
|
---|
| 70 | +onoremap <silent> ]% v:<C-U>call <SID>MultiMatch("W", "o") <CR>
|
---|
| 71 | +
|
---|
| 72 | +" text object:
|
---|
| 73 | +vmap a% <Esc>[%v]%
|
---|
| 74 | +
|
---|
| 75 | +" Auto-complete mappings: (not yet "ready for prime time")
|
---|
| 76 | +" TODO Read :help write-plugin for the "right" way to let the user
|
---|
| 77 | +" specify a key binding.
|
---|
| 78 | +" let g:match_auto = '<C-]>'
|
---|
| 79 | +" let g:match_autoCR = '<C-CR>'
|
---|
| 80 | +" if exists("g:match_auto")
|
---|
| 81 | +" execute "inoremap " . g:match_auto . ' x<Esc>"=<SID>Autocomplete()<CR>Pls'
|
---|
| 82 | +" endif
|
---|
| 83 | +" if exists("g:match_autoCR")
|
---|
| 84 | +" execute "inoremap " . g:match_autoCR . ' <CR><C-R>=<SID>Autocomplete()<CR>'
|
---|
| 85 | +" endif
|
---|
| 86 | +" if exists("g:match_gthhoh")
|
---|
| 87 | +" execute "inoremap " . g:match_gthhoh . ' <C-O>:call <SID>Gthhoh()<CR>'
|
---|
| 88 | +" endif " gthhoh = "Get the heck out of here!"
|
---|
| 89 | +
|
---|
| 90 | +let s:notslash = '\\\@<!\%(\\\\\)*'
|
---|
| 91 | +
|
---|
| 92 | +function! s:Match_wrapper(word, forward, mode) range
|
---|
| 93 | + " In s:CleanUp(), :execute "set" restore_options .
|
---|
| 94 | + let restore_options = (&ic ? " " : " no") . "ignorecase"
|
---|
| 95 | + if exists("b:match_ignorecase")
|
---|
| 96 | + let &ignorecase = b:match_ignorecase
|
---|
| 97 | + endif
|
---|
| 98 | + let restore_options = " ve=" . &ve . restore_options
|
---|
| 99 | + set ve=
|
---|
| 100 | + " If this function was called from Visual mode, make sure that the cursor
|
---|
| 101 | + " is at the correct end of the Visual range:
|
---|
| 102 | + if a:mode == "v"
|
---|
| 103 | + execute "normal! gv\<Esc>"
|
---|
| 104 | + endif
|
---|
| 105 | + " In s:CleanUp(), we may need to check whether the cursor moved forward.
|
---|
| 106 | + let startline = line(".")
|
---|
| 107 | + let startcol = col(".")
|
---|
| 108 | + " Use default behavior if called with a count.
|
---|
| 109 | + if v:count
|
---|
| 110 | + exe "normal! " . v:count . "%"
|
---|
| 111 | + return s:CleanUp(restore_options, a:mode, startline, startcol)
|
---|
| 112 | + end
|
---|
| 113 | +
|
---|
| 114 | + " First step: if not already done, set the script variables
|
---|
| 115 | + " s:do_BR flag for whether there are backrefs
|
---|
| 116 | + " s:pat parsed version of b:match_words
|
---|
| 117 | + " s:all regexp based on s:pat and the default groups
|
---|
| 118 | + "
|
---|
| 119 | + if !exists("b:match_words") || b:match_words == ""
|
---|
| 120 | + let match_words = ""
|
---|
| 121 | + " Allow b:match_words = "GetVimMatchWords()" .
|
---|
| 122 | + elseif b:match_words =~ ":"
|
---|
| 123 | + let match_words = b:match_words
|
---|
| 124 | + else
|
---|
| 125 | + execute "let match_words =" b:match_words
|
---|
| 126 | + endif
|
---|
| 127 | +" Thanks to Preben "Peppe" Guldberg and Bram Moolenaar for this suggestion!
|
---|
| 128 | + if (match_words != s:last_words) || (&mps != s:last_mps) ||
|
---|
| 129 | + \ exists("b:match_debug")
|
---|
| 130 | + let s:last_words = match_words
|
---|
| 131 | + let s:last_mps = &mps
|
---|
| 132 | + " The next several lines were here before
|
---|
| 133 | + " BF started messing with this script.
|
---|
| 134 | + " quote the special chars in 'matchpairs', replace [,:] with \| and then
|
---|
| 135 | + " append the builtin pairs (/*, */, #if, #ifdef, #else, #elif, #endif)
|
---|
| 136 | + " let default = substitute(escape(&mps, '[$^.*~\\/?]'), '[,:]\+',
|
---|
| 137 | + " \ '\\|', 'g').'\|\/\*\|\*\/\|#if\>\|#ifdef\>\|#else\>\|#elif\>\|#endif\>'
|
---|
| 138 | + let default = escape(&mps, '[$^.*~\\/?]') . (strlen(&mps) ? "," : "") .
|
---|
| 139 | + \ '\/\*:\*\/,#if\%(def\)\=:#else\>:#elif\>:#endif\>'
|
---|
| 140 | + " s:all = pattern with all the keywords
|
---|
| 141 | + let match_words = match_words . (strlen(match_words) ? "," : "") . default
|
---|
| 142 | + if match_words !~ s:notslash . '\\\d'
|
---|
| 143 | + let s:do_BR = 0
|
---|
| 144 | + let s:pat = match_words
|
---|
| 145 | + else
|
---|
| 146 | + let s:do_BR = 1
|
---|
| 147 | + let s:pat = s:ParseWords(match_words)
|
---|
| 148 | + endif
|
---|
| 149 | + let s:all = substitute(s:pat, s:notslash . '\zs[,:]\+', '\\|', 'g')
|
---|
| 150 | + let s:all = '\%(' . s:all . '\)'
|
---|
| 151 | + " let s:all = '\%(' . substitute(s:all, '\\\ze[,:]', '', 'g') . '\)'
|
---|
| 152 | + if exists("b:match_debug")
|
---|
| 153 | + let b:match_pat = s:pat
|
---|
| 154 | + endif
|
---|
| 155 | + endif
|
---|
| 156 | +
|
---|
| 157 | + " Second step: set the following local variables:
|
---|
| 158 | + " matchline = line on which the cursor started
|
---|
| 159 | + " curcol = number of characters before match
|
---|
| 160 | + " prefix = regexp for start of line to start of match
|
---|
| 161 | + " suffix = regexp for end of match to end of line
|
---|
| 162 | + " Require match to end on or after the cursor and prefer it to
|
---|
| 163 | + " start on or before the cursor.
|
---|
| 164 | + let matchline = getline(startline)
|
---|
| 165 | + if a:word != ''
|
---|
| 166 | + " word given
|
---|
| 167 | + if a:word !~ s:all
|
---|
| 168 | + echohl WarningMsg|echo 'Missing rule for word:"'.a:word.'"'|echohl NONE
|
---|
| 169 | + return s:CleanUp(restore_options, a:mode, startline, startcol)
|
---|
| 170 | + endif
|
---|
| 171 | + let matchline = a:word
|
---|
| 172 | + let curcol = 0
|
---|
| 173 | + let prefix = '^\%('
|
---|
| 174 | + let suffix = '\)$'
|
---|
| 175 | + " Now the case when "word" is not given
|
---|
| 176 | + else " Find the match that ends on or after the cursor and set curcol.
|
---|
| 177 | + let regexp = s:Wholematch(matchline, s:all, startcol-1)
|
---|
| 178 | + let curcol = match(matchline, regexp)
|
---|
| 179 | + " If there is no match, give up.
|
---|
| 180 | + if curcol == -1
|
---|
| 181 | + return s:CleanUp(restore_options, a:mode, startline, startcol)
|
---|
| 182 | + endif
|
---|
| 183 | + let endcol = matchend(matchline, regexp)
|
---|
| 184 | + let suf = strlen(matchline) - endcol
|
---|
| 185 | + let prefix = (curcol ? '^.*\%' . (curcol + 1) . 'c\%(' : '^\%(')
|
---|
| 186 | + let suffix = (suf ? '\)\%' . (endcol + 1) . 'c.*$' : '\)$')
|
---|
| 187 | + endif
|
---|
| 188 | + if exists("b:match_debug")
|
---|
| 189 | + let b:match_match = matchstr(matchline, regexp)
|
---|
| 190 | + let b:match_col = curcol+1
|
---|
| 191 | + endif
|
---|
| 192 | +
|
---|
| 193 | + " Third step: Find the group and single word that match, and the original
|
---|
| 194 | + " (backref) versions of these. Then, resolve the backrefs.
|
---|
| 195 | + " Set the following local variable:
|
---|
| 196 | + " group = colon-separated list of patterns, one of which matches
|
---|
| 197 | + " = ini:mid:fin or ini:fin
|
---|
| 198 | + "
|
---|
| 199 | + " Reconstruct the version with unresolved backrefs.
|
---|
| 200 | + let patBR = substitute(match_words.',',
|
---|
| 201 | + \ s:notslash.'\zs[,:]*,[,:]*', ',', 'g')
|
---|
| 202 | + let patBR = substitute(patBR, s:notslash.'\zs:\{2,}', ':', 'g')
|
---|
| 203 | + " Now, set group and groupBR to the matching group: 'if:endif' or
|
---|
| 204 | + " 'while:endwhile' or whatever. A bit of a kluge: s:Choose() returns
|
---|
| 205 | + " group . "," . groupBR, and we pick it apart.
|
---|
| 206 | + let group = s:Choose(s:pat, matchline, ",", ":", prefix, suffix, patBR)
|
---|
| 207 | + let i = matchend(group, s:notslash . ",")
|
---|
| 208 | + let groupBR = strpart(group, i)
|
---|
| 209 | + let group = strpart(group, 0, i-1)
|
---|
| 210 | + " Now, matchline =~ prefix . substitute(group,':','\|','g') . suffix
|
---|
| 211 | + if s:do_BR " Do the hard part: resolve those backrefs!
|
---|
| 212 | + let group = s:InsertRefs(groupBR, prefix, group, suffix, matchline)
|
---|
| 213 | + endif
|
---|
| 214 | + if exists("b:match_debug")
|
---|
| 215 | + let b:match_wholeBR = groupBR
|
---|
| 216 | + let i = matchend(groupBR, s:notslash . ":")
|
---|
| 217 | + let b:match_iniBR = strpart(groupBR, 0, i-1)
|
---|
| 218 | + endif
|
---|
| 219 | +
|
---|
| 220 | + " Fourth step: Set the arguments for searchpair().
|
---|
| 221 | + let i = matchend(group, s:notslash . ":")
|
---|
| 222 | + let j = matchend(group, '.*' . s:notslash . ":")
|
---|
| 223 | + let ini = strpart(group, 0, i-1)
|
---|
| 224 | + let mid = substitute(strpart(group, i,j-i-1), s:notslash.'\zs:', '\\|', 'g')
|
---|
| 225 | + let fin = strpart(group, j)
|
---|
| 226 | + "Un-escape the remaining , and : characters.
|
---|
| 227 | + let ini = substitute(ini, s:notslash . '\zs\\\(:\|,\)', '\1', 'g')
|
---|
| 228 | + let mid = substitute(mid, s:notslash . '\zs\\\(:\|,\)', '\1', 'g')
|
---|
| 229 | + let fin = substitute(fin, s:notslash . '\zs\\\(:\|,\)', '\1', 'g')
|
---|
| 230 | + " searchpair() requires that these patterns avoid \(\) groups.
|
---|
| 231 | + let ini = substitute(ini, s:notslash . '\zs\\(', '\\%(', 'g')
|
---|
| 232 | + let mid = substitute(mid, s:notslash . '\zs\\(', '\\%(', 'g')
|
---|
| 233 | + let fin = substitute(fin, s:notslash . '\zs\\(', '\\%(', 'g')
|
---|
| 234 | + " Set mid. This is optimized for readability, not micro-efficiency!
|
---|
| 235 | + if a:forward && matchline =~ prefix . fin . suffix
|
---|
| 236 | + \ || !a:forward && matchline =~ prefix . ini . suffix
|
---|
| 237 | + let mid = ""
|
---|
| 238 | + endif
|
---|
| 239 | + " Set flag. This is optimized for readability, not micro-efficiency!
|
---|
| 240 | + if a:forward && matchline =~ prefix . fin . suffix
|
---|
| 241 | + \ || !a:forward && matchline !~ prefix . ini . suffix
|
---|
| 242 | + let flag = "bW"
|
---|
| 243 | + else
|
---|
| 244 | + let flag = "W"
|
---|
| 245 | + endif
|
---|
| 246 | + " Set skip.
|
---|
| 247 | + if exists("b:match_skip")
|
---|
| 248 | + let skip = b:match_skip
|
---|
| 249 | + elseif exists("b:match_comment") " backwards compatibility and testing!
|
---|
| 250 | + let skip = "r:" . b:match_comment
|
---|
| 251 | + else
|
---|
| 252 | + let skip = 's:comment\|string'
|
---|
| 253 | + endif
|
---|
| 254 | + let skip = s:ParseSkip(skip)
|
---|
| 255 | + if exists("b:match_debug")
|
---|
| 256 | + let b:match_ini = ini
|
---|
| 257 | + let b:match_tail = (strlen(mid) ? mid.'\|' : '') . fin
|
---|
| 258 | + endif
|
---|
| 259 | +
|
---|
| 260 | + " Fifth step: actually start moving the cursor and call searchpair().
|
---|
| 261 | + " Later, :execute restore_cursor to get to the original screen.
|
---|
| 262 | + let restore_cursor = virtcol(".") . "|"
|
---|
| 263 | + normal! g0
|
---|
| 264 | + let restore_cursor = line(".") . "G" . virtcol(".") . "|zs" . restore_cursor
|
---|
| 265 | + normal! H
|
---|
| 266 | + let restore_cursor = "normal!" . line(".") . "Gzt" . restore_cursor
|
---|
| 267 | + execute restore_cursor
|
---|
| 268 | + call cursor(0, curcol + 1)
|
---|
| 269 | + " normal! 0
|
---|
| 270 | + " if curcol
|
---|
| 271 | + " execute "normal!" . curcol . "l"
|
---|
| 272 | + " endif
|
---|
| 273 | + if skip =~ 'synID' && !(has("syntax") && exists("g:syntax_on"))
|
---|
| 274 | + let skip = "0"
|
---|
| 275 | + else
|
---|
| 276 | + execute "if " . skip . "| let skip = '0' | endif"
|
---|
| 277 | + endif
|
---|
| 278 | + let sp_return = searchpair(ini, mid, fin, flag, skip)
|
---|
| 279 | + let final_position = "call cursor(" . line(".") . "," . col(".") . ")"
|
---|
| 280 | + " Restore cursor position and original screen.
|
---|
| 281 | + execute restore_cursor
|
---|
| 282 | + normal! m'
|
---|
| 283 | + if sp_return > 0
|
---|
| 284 | + execute final_position
|
---|
| 285 | + endif
|
---|
| 286 | + return s:CleanUp(restore_options, a:mode, startline, startcol, mid.'\|'.fin)
|
---|
| 287 | +endfun
|
---|
| 288 | +
|
---|
| 289 | +" Restore options and do some special handling for Operator-pending mode.
|
---|
| 290 | +" The optional argument is the tail of the matching group.
|
---|
| 291 | +fun! s:CleanUp(options, mode, startline, startcol, ...)
|
---|
| 292 | + execute "set" a:options
|
---|
| 293 | + " Open folds, if appropriate.
|
---|
| 294 | + if a:mode != "o"
|
---|
| 295 | + if &foldopen =~ "percent"
|
---|
| 296 | + normal! zv
|
---|
| 297 | + endif
|
---|
| 298 | + " In Operator-pending mode, we want to include the whole match
|
---|
| 299 | + " (for example, d%).
|
---|
| 300 | + " This is only a problem if we end up moving in the forward direction.
|
---|
| 301 | + elseif (a:startline < line(".")) ||
|
---|
| 302 | + \ (a:startline == line(".") && a:startcol < col("."))
|
---|
| 303 | + if a:0
|
---|
| 304 | + " Check whether the match is a single character. If not, move to the
|
---|
| 305 | + " end of the match.
|
---|
| 306 | + let matchline = getline(".")
|
---|
| 307 | + let currcol = col(".")
|
---|
| 308 | + let regexp = s:Wholematch(matchline, a:1, currcol-1)
|
---|
| 309 | + let endcol = matchend(matchline, regexp)
|
---|
| 310 | + if endcol > currcol " This is NOT off by one!
|
---|
| 311 | + execute "normal!" . (endcol - currcol) . "l"
|
---|
| 312 | + endif
|
---|
| 313 | + endif " a:0
|
---|
| 314 | + endif " a:mode != "o" && etc.
|
---|
| 315 | + return 0
|
---|
| 316 | +endfun
|
---|
| 317 | +
|
---|
| 318 | +" Example (simplified HTML patterns): if
|
---|
| 319 | +" a:groupBR = '<\(\k\+\)>:</\1>'
|
---|
| 320 | +" a:prefix = '^.\{3}\('
|
---|
| 321 | +" a:group = '<\(\k\+\)>:</\(\k\+\)>'
|
---|
| 322 | +" a:suffix = '\).\{2}$'
|
---|
| 323 | +" a:matchline = "123<tag>12" or "123</tag>12"
|
---|
| 324 | +" then extract "tag" from a:matchline and return "<tag>:</tag>" .
|
---|
| 325 | +fun! s:InsertRefs(groupBR, prefix, group, suffix, matchline)
|
---|
| 326 | + if a:matchline !~ a:prefix .
|
---|
| 327 | + \ substitute(a:group, s:notslash . '\zs:', '\\|', 'g') . a:suffix
|
---|
| 328 | + return a:group
|
---|
| 329 | + endif
|
---|
| 330 | + let i = matchend(a:groupBR, s:notslash . ':')
|
---|
| 331 | + let ini = strpart(a:groupBR, 0, i-1)
|
---|
| 332 | + let tailBR = strpart(a:groupBR, i)
|
---|
| 333 | + let word = s:Choose(a:group, a:matchline, ":", "", a:prefix, a:suffix,
|
---|
| 334 | + \ a:groupBR)
|
---|
| 335 | + let i = matchend(word, s:notslash . ":")
|
---|
| 336 | + let wordBR = strpart(word, i)
|
---|
| 337 | + let word = strpart(word, 0, i-1)
|
---|
| 338 | + " Now, a:matchline =~ a:prefix . word . a:suffix
|
---|
| 339 | + if wordBR != ini
|
---|
| 340 | + let table = s:Resolve(ini, wordBR, "table")
|
---|
| 341 | + else
|
---|
| 342 | + " let table = "----------"
|
---|
| 343 | + let table = ""
|
---|
| 344 | + let d = 0
|
---|
| 345 | + while d < 10
|
---|
| 346 | + if tailBR =~ s:notslash . '\\' . d
|
---|
| 347 | + " let table[d] = d
|
---|
| 348 | + let table = table . d
|
---|
| 349 | + else
|
---|
| 350 | + let table = table . "-"
|
---|
| 351 | + endif
|
---|
| 352 | + let d = d + 1
|
---|
| 353 | + endwhile
|
---|
| 354 | + endif
|
---|
| 355 | + let d = 9
|
---|
| 356 | + while d
|
---|
| 357 | + if table[d] != "-"
|
---|
| 358 | + let backref = substitute(a:matchline, a:prefix.word.a:suffix,
|
---|
| 359 | + \ '\'.table[d], "")
|
---|
| 360 | + " Are there any other characters that should be escaped?
|
---|
| 361 | + let backref = escape(backref, '*,:')
|
---|
| 362 | + execute s:Ref(ini, d, "start", "len")
|
---|
| 363 | + let ini = strpart(ini, 0, start) . backref . strpart(ini, start+len)
|
---|
| 364 | + let tailBR = substitute(tailBR, s:notslash . '\zs\\' . d,
|
---|
| 365 | + \ escape(backref, '\\'), 'g')
|
---|
| 366 | + endif
|
---|
| 367 | + let d = d-1
|
---|
| 368 | + endwhile
|
---|
| 369 | + if exists("b:match_debug")
|
---|
| 370 | + if s:do_BR
|
---|
| 371 | + let b:match_table = table
|
---|
| 372 | + let b:match_word = word
|
---|
| 373 | + else
|
---|
| 374 | + let b:match_table = ""
|
---|
| 375 | + let b:match_word = ""
|
---|
| 376 | + endif
|
---|
| 377 | + endif
|
---|
| 378 | + return ini . ":" . tailBR
|
---|
| 379 | +endfun
|
---|
| 380 | +
|
---|
| 381 | +" Input a comma-separated list of groups with backrefs, such as
|
---|
| 382 | +" a:groups = '\(foo\):end\1,\(bar\):end\1'
|
---|
| 383 | +" and return a comma-separated list of groups with backrefs replaced:
|
---|
| 384 | +" return '\(foo\):end\(foo\),\(bar\):end\(bar\)'
|
---|
| 385 | +fun! s:ParseWords(groups)
|
---|
| 386 | + let groups = substitute(a:groups.",", s:notslash.'\zs[,:]*,[,:]*', ',', 'g')
|
---|
| 387 | + let groups = substitute(groups, s:notslash . '\zs:\{2,}', ':', 'g')
|
---|
| 388 | + let parsed = ""
|
---|
| 389 | + while groups =~ '[^,:]'
|
---|
| 390 | + let i = matchend(groups, s:notslash . ':')
|
---|
| 391 | + let j = matchend(groups, s:notslash . ',')
|
---|
| 392 | + let ini = strpart(groups, 0, i-1)
|
---|
| 393 | + let tail = strpart(groups, i, j-i-1) . ":"
|
---|
| 394 | + let groups = strpart(groups, j)
|
---|
| 395 | + let parsed = parsed . ini
|
---|
| 396 | + let i = matchend(tail, s:notslash . ':')
|
---|
| 397 | + while i != -1
|
---|
| 398 | + " In 'if:else:endif', ini='if' and word='else' and then word='endif'.
|
---|
| 399 | + let word = strpart(tail, 0, i-1)
|
---|
| 400 | + let tail = strpart(tail, i)
|
---|
| 401 | + let i = matchend(tail, s:notslash . ':')
|
---|
| 402 | + let parsed = parsed . ":" . s:Resolve(ini, word, "word")
|
---|
| 403 | + endwhile " Now, tail has been used up.
|
---|
| 404 | + let parsed = parsed . ","
|
---|
| 405 | + endwhile " groups =~ '[^,:]'
|
---|
| 406 | + let parsed = substitute(parsed, ',$', '', '')
|
---|
| 407 | + return parsed
|
---|
| 408 | +endfun
|
---|
| 409 | +
|
---|
| 410 | +" TODO I think this can be simplified and/or made more efficient.
|
---|
| 411 | +" TODO What should I do if a:start is out of range?
|
---|
| 412 | +" Return a regexp that matches all of a:string, such that
|
---|
| 413 | +" matchstr(a:string, regexp) represents the match for a:pat that starts
|
---|
| 414 | +" as close to a:start as possible, before being preferred to after, and
|
---|
| 415 | +" ends after a:start .
|
---|
| 416 | +" Usage:
|
---|
| 417 | +" let regexp = s:Wholematch(getline("."), 'foo\|bar', col(".")-1)
|
---|
| 418 | +" let i = match(getline("."), regexp)
|
---|
| 419 | +" let j = matchend(getline("."), regexp)
|
---|
| 420 | +" let match = matchstr(getline("."), regexp)
|
---|
| 421 | +fun! s:Wholematch(string, pat, start)
|
---|
| 422 | + let group = '\%(' . a:pat . '\)'
|
---|
| 423 | + let prefix = (a:start ? '\(^.*\%<' . (a:start + 2) . 'c\)\zs' : '^')
|
---|
| 424 | + let len = strlen(a:string)
|
---|
| 425 | + let suffix = (a:start+1 < len ? '\(\%>'.(a:start+1).'c.*$\)\@=' : '$')
|
---|
| 426 | + if a:string !~ prefix . group . suffix
|
---|
| 427 | + let prefix = ''
|
---|
| 428 | + endif
|
---|
| 429 | + return prefix . group . suffix
|
---|
| 430 | +endfun
|
---|
| 431 | +
|
---|
| 432 | +" No extra arguments: s:Ref(string, d) will
|
---|
| 433 | +" find the d'th occurrence of '\(' and return it, along with everything up
|
---|
| 434 | +" to and including the matching '\)'.
|
---|
| 435 | +" One argument: s:Ref(string, d, "start") returns the index of the start
|
---|
| 436 | +" of the d'th '\(' and any other argument returns the length of the group.
|
---|
| 437 | +" Two arguments: s:Ref(string, d, "foo", "bar") returns a string to be
|
---|
| 438 | +" executed, having the effect of
|
---|
| 439 | +" :let foo = s:Ref(string, d, "start")
|
---|
| 440 | +" :let bar = s:Ref(string, d, "len")
|
---|
| 441 | +fun! s:Ref(string, d, ...)
|
---|
| 442 | + let len = strlen(a:string)
|
---|
| 443 | + if a:d == 0
|
---|
| 444 | + let start = 0
|
---|
| 445 | + else
|
---|
| 446 | + let cnt = a:d
|
---|
| 447 | + let match = a:string
|
---|
| 448 | + while cnt
|
---|
| 449 | + let cnt = cnt - 1
|
---|
| 450 | + let index = matchend(match, s:notslash . '\\(')
|
---|
| 451 | + if index == -1
|
---|
| 452 | + return ""
|
---|
| 453 | + endif
|
---|
| 454 | + let match = strpart(match, index)
|
---|
| 455 | + endwhile
|
---|
| 456 | + let start = len - strlen(match)
|
---|
| 457 | + if a:0 == 1 && a:1 == "start"
|
---|
| 458 | + return start - 2
|
---|
| 459 | + endif
|
---|
| 460 | + let cnt = 1
|
---|
| 461 | + while cnt
|
---|
| 462 | + let index = matchend(match, s:notslash . '\\(\|\\)') - 1
|
---|
| 463 | + if index == -2
|
---|
| 464 | + return ""
|
---|
| 465 | + endif
|
---|
| 466 | + " Increment if an open, decrement if a ')':
|
---|
| 467 | + let cnt = cnt + (match[index]=="(" ? 1 : -1) " ')'
|
---|
| 468 | + " let cnt = stridx('0(', match[index]) + cnt
|
---|
| 469 | + let match = strpart(match, index+1)
|
---|
| 470 | + endwhile
|
---|
| 471 | + let start = start - 2
|
---|
| 472 | + let len = len - start - strlen(match)
|
---|
| 473 | + endif
|
---|
| 474 | + if a:0 == 1
|
---|
| 475 | + return len
|
---|
| 476 | + elseif a:0 == 2
|
---|
| 477 | + return "let " . a:1 . "=" . start . "| let " . a:2 . "=" . len
|
---|
| 478 | + else
|
---|
| 479 | + return strpart(a:string, start, len)
|
---|
| 480 | + endif
|
---|
| 481 | +endfun
|
---|
| 482 | +
|
---|
| 483 | +" Count the number of disjoint copies of pattern in string.
|
---|
| 484 | +" If the pattern is a literal string and contains no '0' or '1' characters
|
---|
| 485 | +" then s:Count(string, pattern, '0', '1') should be faster than
|
---|
| 486 | +" s:Count(string, pattern).
|
---|
| 487 | +fun! s:Count(string, pattern, ...)
|
---|
| 488 | + let pat = escape(a:pattern, '\\')
|
---|
| 489 | + if a:0 > 1
|
---|
| 490 | + let foo = substitute(a:string, '[^'.a:pattern.']', "a:1", "g")
|
---|
| 491 | + let foo = substitute(a:string, pat, a:2, "g")
|
---|
| 492 | + let foo = substitute(foo, '[^' . a:2 . ']', "", "g")
|
---|
| 493 | + return strlen(foo)
|
---|
| 494 | + endif
|
---|
| 495 | + let result = 0
|
---|
| 496 | + let foo = a:string
|
---|
| 497 | + let index = matchend(foo, pat)
|
---|
| 498 | + while index != -1
|
---|
| 499 | + let result = result + 1
|
---|
| 500 | + let foo = strpart(foo, index)
|
---|
| 501 | + let index = matchend(foo, pat)
|
---|
| 502 | + endwhile
|
---|
| 503 | + return result
|
---|
| 504 | +endfun
|
---|
| 505 | +
|
---|
| 506 | +" s:Resolve('\(a\)\(b\)', '\(c\)\2\1\1\2') should return table.word, where
|
---|
| 507 | +" word = '\(c\)\(b\)\(a\)\3\2' and table = '-32-------'. That is, the first
|
---|
| 508 | +" '\1' in target is replaced by '\(a\)' in word, table[1] = 3, and this
|
---|
| 509 | +" indicates that all other instances of '\1' in target are to be replaced
|
---|
| 510 | +" by '\3'. The hard part is dealing with nesting...
|
---|
| 511 | +" Note that ":" is an illegal character for source and target,
|
---|
| 512 | +" unless it is preceded by "\".
|
---|
| 513 | +fun! s:Resolve(source, target, output)
|
---|
| 514 | + let word = a:target
|
---|
| 515 | + let i = matchend(word, s:notslash . '\\\d') - 1
|
---|
| 516 | + let table = "----------"
|
---|
| 517 | + while i != -2 " There are back references to be replaced.
|
---|
| 518 | + let d = word[i]
|
---|
| 519 | + let backref = s:Ref(a:source, d)
|
---|
| 520 | + " The idea is to replace '\d' with backref. Before we do this,
|
---|
| 521 | + " replace any \(\) groups in backref with :1, :2, ... if they
|
---|
| 522 | + " correspond to the first, second, ... group already inserted
|
---|
| 523 | + " into backref. Later, replace :1 with \1 and so on. The group
|
---|
| 524 | + " number w+b within backref corresponds to the group number
|
---|
| 525 | + " s within a:source.
|
---|
| 526 | + " w = number of '\(' in word before the current one
|
---|
| 527 | + let w = s:Count(
|
---|
| 528 | + \ substitute(strpart(word, 0, i-1), '\\\\', '', 'g'), '\(', '1')
|
---|
| 529 | + let b = 1 " number of the current '\(' in backref
|
---|
| 530 | + let s = d " number of the current '\(' in a:source
|
---|
| 531 | + while b <= s:Count(substitute(backref, '\\\\', '', 'g'), '\(', '1')
|
---|
| 532 | + \ && s < 10
|
---|
| 533 | + if table[s] == "-"
|
---|
| 534 | + if w + b < 10
|
---|
| 535 | + " let table[s] = w + b
|
---|
| 536 | + let table = strpart(table, 0, s) . (w+b) . strpart(table, s+1)
|
---|
| 537 | + endif
|
---|
| 538 | + let b = b + 1
|
---|
| 539 | + let s = s + 1
|
---|
| 540 | + else
|
---|
| 541 | + execute s:Ref(backref, b, "start", "len")
|
---|
| 542 | + let ref = strpart(backref, start, len)
|
---|
| 543 | + let backref = strpart(backref, 0, start) . ":". table[s]
|
---|
| 544 | + \ . strpart(backref, start+len)
|
---|
| 545 | + let s = s + s:Count(substitute(ref, '\\\\', '', 'g'), '\(', '1')
|
---|
| 546 | + endif
|
---|
| 547 | + endwhile
|
---|
| 548 | + let word = strpart(word, 0, i-1) . backref . strpart(word, i+1)
|
---|
| 549 | + let i = matchend(word, s:notslash . '\\\d') - 1
|
---|
| 550 | + endwhile
|
---|
| 551 | + let word = substitute(word, s:notslash . '\zs:', '\\', 'g')
|
---|
| 552 | + if a:output == "table"
|
---|
| 553 | + return table
|
---|
| 554 | + elseif a:output == "word"
|
---|
| 555 | + return word
|
---|
| 556 | + else
|
---|
| 557 | + return table . word
|
---|
| 558 | + endif
|
---|
| 559 | +endfun
|
---|
| 560 | +
|
---|
| 561 | +" Assume a:comma = ",". Then the format for a:patterns and a:1 is
|
---|
| 562 | +" a:patterns = "<pat1>,<pat2>,..."
|
---|
| 563 | +" a:1 = "<alt1>,<alt2>,..."
|
---|
| 564 | +" If <patn> is the first pattern that matches a:string then return <patn>
|
---|
| 565 | +" if no optional arguments are given; return <patn>,<altn> if a:1 is given.
|
---|
| 566 | +fun! s:Choose(patterns, string, comma, branch, prefix, suffix, ...)
|
---|
| 567 | + let tail = (a:patterns =~ a:comma."$" ? a:patterns : a:patterns . a:comma)
|
---|
| 568 | + let i = matchend(tail, s:notslash . a:comma)
|
---|
| 569 | + if a:0
|
---|
| 570 | + let alttail = (a:1 =~ a:comma."$" ? a:1 : a:1 . a:comma)
|
---|
| 571 | + let j = matchend(alttail, s:notslash . a:comma)
|
---|
| 572 | + endif
|
---|
| 573 | + let current = strpart(tail, 0, i-1)
|
---|
| 574 | + if a:branch == ""
|
---|
| 575 | + let currpat = current
|
---|
| 576 | + else
|
---|
| 577 | + let currpat = substitute(current, s:notslash . a:branch, '\\|', 'g')
|
---|
| 578 | + endif
|
---|
| 579 | + while a:string !~ a:prefix . currpat . a:suffix
|
---|
| 580 | + let tail = strpart(tail, i)
|
---|
| 581 | + let i = matchend(tail, s:notslash . a:comma)
|
---|
| 582 | + if i == -1
|
---|
| 583 | + return -1
|
---|
| 584 | + endif
|
---|
| 585 | + let current = strpart(tail, 0, i-1)
|
---|
| 586 | + if a:branch == ""
|
---|
| 587 | + let currpat = current
|
---|
| 588 | + else
|
---|
| 589 | + let currpat = substitute(current, s:notslash . a:branch, '\\|', 'g')
|
---|
| 590 | + endif
|
---|
| 591 | + if a:0
|
---|
| 592 | + let alttail = strpart(alttail, j)
|
---|
| 593 | + let j = matchend(alttail, s:notslash . a:comma)
|
---|
| 594 | + endif
|
---|
| 595 | + endwhile
|
---|
| 596 | + if a:0
|
---|
| 597 | + let current = current . a:comma . strpart(alttail, 0, j-1)
|
---|
| 598 | + endif
|
---|
| 599 | + return current
|
---|
| 600 | +endfun
|
---|
| 601 | +
|
---|
| 602 | +" Call this function to turn on debugging information. Every time the main
|
---|
| 603 | +" script is run, buffer variables will be saved. These can be used directly
|
---|
| 604 | +" or viewed using the menu items below.
|
---|
| 605 | +if !exists(":MatchDebug")
|
---|
| 606 | + command! -nargs=0 MatchDebug call s:Match_debug()
|
---|
| 607 | +endif
|
---|
| 608 | +
|
---|
| 609 | +fun! s:Match_debug()
|
---|
| 610 | + let b:match_debug = 1 " Save debugging information.
|
---|
| 611 | + " pat = all of b:match_words with backrefs parsed
|
---|
| 612 | + amenu &Matchit.&pat :echo b:match_pat<CR>
|
---|
| 613 | + " match = bit of text that is recognized as a match
|
---|
| 614 | + amenu &Matchit.&match :echo b:match_match<CR>
|
---|
| 615 | + " curcol = cursor column of the start of the matching text
|
---|
| 616 | + amenu &Matchit.&curcol :echo b:match_col<CR>
|
---|
| 617 | + " wholeBR = matching group, original version
|
---|
| 618 | + amenu &Matchit.wh&oleBR :echo b:match_wholeBR<CR>
|
---|
| 619 | + " iniBR = 'if' piece, original version
|
---|
| 620 | + amenu &Matchit.ini&BR :echo b:match_iniBR<CR>
|
---|
| 621 | + " ini = 'if' piece, with all backrefs resolved from match
|
---|
| 622 | + amenu &Matchit.&ini :echo b:match_ini<CR>
|
---|
| 623 | + " tail = 'else\|endif' piece, with all backrefs resolved from match
|
---|
| 624 | + amenu &Matchit.&tail :echo b:match_tail<CR>
|
---|
| 625 | + " fin = 'endif' piece, with all backrefs resolved from match
|
---|
| 626 | + amenu &Matchit.&word :echo b:match_word<CR>
|
---|
| 627 | + " '\'.d in ini refers to the same thing as '\'.table[d] in word.
|
---|
| 628 | + amenu &Matchit.t&able :echo '0:' . b:match_table . ':9'<CR>
|
---|
| 629 | +endfun
|
---|
| 630 | +
|
---|
| 631 | +" Jump to the nearest unmatched "(" or "if" or "<tag>" if a:spflag == "bW"
|
---|
| 632 | +" or the nearest unmatched "</tag>" or "endif" or ")" if a:spflag == "W".
|
---|
| 633 | +" Return a "mark" for the original position, so that
|
---|
| 634 | +" let m = MultiMatch("bW", "n") ... execute m
|
---|
| 635 | +" will return to the original position. If there is a problem, do not
|
---|
| 636 | +" move the cursor and return "", unless a count is given, in which case
|
---|
| 637 | +" go up or down as many levels as possible and again return "".
|
---|
| 638 | +" TODO This relies on the same patterns as % matching. It might be a good
|
---|
| 639 | +" idea to give it its own matching patterns.
|
---|
| 640 | +fun! s:MultiMatch(spflag, mode)
|
---|
| 641 | + if !exists("b:match_words") || b:match_words == ""
|
---|
| 642 | + return ""
|
---|
| 643 | + end
|
---|
| 644 | + let restore_options = (&ic ? "" : "no") . "ignorecase"
|
---|
| 645 | + if exists("b:match_ignorecase")
|
---|
| 646 | + let &ignorecase = b:match_ignorecase
|
---|
| 647 | + endif
|
---|
| 648 | + let startline = line(".")
|
---|
| 649 | + let startcol = col(".")
|
---|
| 650 | +
|
---|
| 651 | + " First step: if not already done, set the script variables
|
---|
| 652 | + " s:do_BR flag for whether there are backrefs
|
---|
| 653 | + " s:pat parsed version of b:match_words
|
---|
| 654 | + " s:all regexp based on s:pat and the default groups
|
---|
| 655 | + " This part is copied and slightly modified from s:Match_wrapper().
|
---|
| 656 | + let default = escape(&mps, '[$^.*~\\/?]') . (strlen(&mps) ? "," : "") .
|
---|
| 657 | + \ '\/\*:\*\/,#if\%(def\)\=:#else\>:#elif\>:#endif\>'
|
---|
| 658 | + " Allow b:match_words = "GetVimMatchWords()" .
|
---|
| 659 | + if b:match_words =~ ":"
|
---|
| 660 | + let match_words = b:match_words
|
---|
| 661 | + else
|
---|
| 662 | + execute "let match_words =" b:match_words
|
---|
| 663 | + endif
|
---|
| 664 | + if (match_words != s:last_words) || (&mps != s:last_mps) ||
|
---|
| 665 | + \ exists("b:match_debug")
|
---|
| 666 | + let s:last_words = match_words
|
---|
| 667 | + let s:last_mps = &mps
|
---|
| 668 | + if match_words !~ s:notslash . '\\\d'
|
---|
| 669 | + let s:do_BR = 0
|
---|
| 670 | + let s:pat = match_words
|
---|
| 671 | + else
|
---|
| 672 | + let s:do_BR = 1
|
---|
| 673 | + let s:pat = s:ParseWords(match_words)
|
---|
| 674 | + endif
|
---|
| 675 | + let s:all = '\%(' . substitute(s:pat . (strlen(s:pat)?",":"") . default,
|
---|
| 676 | + \ '[,:]\+','\\|','g') . '\)'
|
---|
| 677 | + if exists("b:match_debug")
|
---|
| 678 | + let b:match_pat = s:pat
|
---|
| 679 | + endif
|
---|
| 680 | + endif
|
---|
| 681 | +
|
---|
| 682 | + " Second step: figure out the patterns for searchpair()
|
---|
| 683 | + " and save the screen, cursor position, and 'ignorecase'.
|
---|
| 684 | + " - TODO: A lot of this is copied from s:Match_wrapper().
|
---|
| 685 | + " - maybe even more functionality should be split off
|
---|
| 686 | + " - into separate functions!
|
---|
| 687 | + let cdefault = (s:pat =~ '[^,]$' ? "," : "") . default
|
---|
| 688 | + let open = substitute(s:pat . cdefault,
|
---|
| 689 | + \ s:notslash . '\zs:.\{-}' . s:notslash . ',', '\\),\\(', 'g')
|
---|
| 690 | + let open = '\(' . substitute(open, s:notslash . '\zs:.*$', '\\)', '')
|
---|
| 691 | + let close = substitute(s:pat . cdefault,
|
---|
| 692 | + \ s:notslash . '\zs,.\{-}' . s:notslash . ':', '\\),\\(', 'g')
|
---|
| 693 | + let close = substitute(close, '^.\{-}' . s:notslash . ':', '\\(', '') . '\)'
|
---|
| 694 | + if exists("b:match_skip")
|
---|
| 695 | + let skip = b:match_skip
|
---|
| 696 | + elseif exists("b:match_comment") " backwards compatibility and testing!
|
---|
| 697 | + let skip = "r:" . b:match_comment
|
---|
| 698 | + else
|
---|
| 699 | + let skip = 's:comment\|string'
|
---|
| 700 | + endif
|
---|
| 701 | + let skip = s:ParseSkip(skip)
|
---|
| 702 | + " let restore_cursor = line(".") . "G" . virtcol(".") . "|"
|
---|
| 703 | + " normal! H
|
---|
| 704 | + " let restore_cursor = "normal!" . line(".") . "Gzt" . restore_cursor
|
---|
| 705 | + let restore_cursor = virtcol(".") . "|"
|
---|
| 706 | + normal! g0
|
---|
| 707 | + let restore_cursor = line(".") . "G" . virtcol(".") . "|zs" . restore_cursor
|
---|
| 708 | + normal! H
|
---|
| 709 | + let restore_cursor = "normal!" . line(".") . "Gzt" . restore_cursor
|
---|
| 710 | + execute restore_cursor
|
---|
| 711 | +
|
---|
| 712 | + " Third step: call searchpair().
|
---|
| 713 | + " Replace '\('--but not '\\('--with '\%(' and ',' with '\|'.
|
---|
| 714 | + let openpat = substitute(open, '\(\\\@<!\(\\\\\)*\)\@<=\\(', '\\%(', 'g')
|
---|
| 715 | + let openpat = substitute(openpat, ',', '\\|', 'g')
|
---|
| 716 | + let closepat = substitute(close, '\(\\\@<!\(\\\\\)*\)\@<=\\(', '\\%(', 'g')
|
---|
| 717 | + let closepat = substitute(closepat, ',', '\\|', 'g')
|
---|
| 718 | + if skip =~ 'synID' && !(has("syntax") && exists("g:syntax_on"))
|
---|
| 719 | + let skip = '0'
|
---|
| 720 | + else
|
---|
| 721 | + execute "if " . skip . "| let skip = '0' | endif"
|
---|
| 722 | + endif
|
---|
| 723 | + mark '
|
---|
| 724 | + let level = v:count1
|
---|
| 725 | + while level
|
---|
| 726 | + if searchpair(openpat, '', closepat, a:spflag, skip) < 1
|
---|
| 727 | + call s:CleanUp(restore_options, a:mode, startline, startcol)
|
---|
| 728 | + return ""
|
---|
| 729 | + endif
|
---|
| 730 | + let level = level - 1
|
---|
| 731 | + endwhile
|
---|
| 732 | +
|
---|
| 733 | + " Restore options and return a string to restore the original position.
|
---|
| 734 | + call s:CleanUp(restore_options, a:mode, startline, startcol)
|
---|
| 735 | + return restore_cursor
|
---|
| 736 | +endfun
|
---|
| 737 | +
|
---|
| 738 | +" Search backwards for "if" or "while" or "<tag>" or ...
|
---|
| 739 | +" and return "endif" or "endwhile" or "</tag>" or ... .
|
---|
| 740 | +" For now, this uses b:match_words and the same script variables
|
---|
| 741 | +" as s:Match_wrapper() . Later, it may get its own patterns,
|
---|
| 742 | +" either from a buffer variable or passed as arguments.
|
---|
| 743 | +" fun! s:Autocomplete()
|
---|
| 744 | +" echo "autocomplete not yet implemented :-("
|
---|
| 745 | +" if !exists("b:match_words") || b:match_words == ""
|
---|
| 746 | +" return ""
|
---|
| 747 | +" end
|
---|
| 748 | +" let startpos = s:MultiMatch("bW")
|
---|
| 749 | +"
|
---|
| 750 | +" if startpos == ""
|
---|
| 751 | +" return ""
|
---|
| 752 | +" endif
|
---|
| 753 | +" " - TODO: figure out whether 'if' or '<tag>' matched, and construct
|
---|
| 754 | +" " - the appropriate closing.
|
---|
| 755 | +" let matchline = getline(".")
|
---|
| 756 | +" let curcol = col(".") - 1
|
---|
| 757 | +" " - TODO: Change the s:all argument if there is a new set of match pats.
|
---|
| 758 | +" let regexp = s:Wholematch(matchline, s:all, curcol)
|
---|
| 759 | +" let suf = strlen(matchline) - matchend(matchline, regexp)
|
---|
| 760 | +" let prefix = (curcol ? '^.\{' . curcol . '}\%(' : '^\%(')
|
---|
| 761 | +" let suffix = (suf ? '\).\{' . suf . '}$' : '\)$')
|
---|
| 762 | +" " Reconstruct the version with unresolved backrefs.
|
---|
| 763 | +" let patBR = substitute(b:match_words.',', '[,:]*,[,:]*', ',', 'g')
|
---|
| 764 | +" let patBR = substitute(patBR, ':\{2,}', ':', "g")
|
---|
| 765 | +" " Now, set group and groupBR to the matching group: 'if:endif' or
|
---|
| 766 | +" " 'while:endwhile' or whatever.
|
---|
| 767 | +" let group = s:Choose(s:pat, matchline, ",", ":", prefix, suffix, patBR)
|
---|
| 768 | +" let i = matchend(group, s:notslash . ",")
|
---|
| 769 | +" let groupBR = strpart(group, i)
|
---|
| 770 | +" let group = strpart(group, 0, i-1)
|
---|
| 771 | +" " Now, matchline =~ prefix . substitute(group,':','\|','g') . suffix
|
---|
| 772 | +" if s:do_BR
|
---|
| 773 | +" let group = s:InsertRefs(groupBR, prefix, group, suffix, matchline)
|
---|
| 774 | +" endif
|
---|
| 775 | +" " let g:group = group
|
---|
| 776 | +"
|
---|
| 777 | +" " - TODO: Construct the closing from group.
|
---|
| 778 | +" let fake = "end" . expand("<cword>")
|
---|
| 779 | +" execute startpos
|
---|
| 780 | +" return fake
|
---|
| 781 | +" endfun
|
---|
| 782 | +
|
---|
| 783 | +" Close all open structures. "Get the heck out of here!"
|
---|
| 784 | +" fun! s:Gthhoh()
|
---|
| 785 | +" let close = s:Autocomplete()
|
---|
| 786 | +" while strlen(close)
|
---|
| 787 | +" put=close
|
---|
| 788 | +" let close = s:Autocomplete()
|
---|
| 789 | +" endwhile
|
---|
| 790 | +" endfun
|
---|
| 791 | +
|
---|
| 792 | +" Parse special strings as typical skip arguments for searchpair():
|
---|
| 793 | +" s:foo becomes (current syntax item) =~ foo
|
---|
| 794 | +" S:foo becomes (current syntax item) !~ foo
|
---|
| 795 | +" r:foo becomes (line before cursor) =~ foo
|
---|
| 796 | +" R:foo becomes (line before cursor) !~ foo
|
---|
| 797 | +fun! s:ParseSkip(str)
|
---|
| 798 | + let skip = a:str
|
---|
| 799 | + if skip[1] == ":"
|
---|
| 800 | + if skip[0] == "s"
|
---|
| 801 | + let skip = "synIDattr(synID(line('.'),col('.'),1),'name') =~? '" .
|
---|
| 802 | + \ strpart(skip,2) . "'"
|
---|
| 803 | + elseif skip[0] == "S"
|
---|
| 804 | + let skip = "synIDattr(synID(line('.'),col('.'),1),'name') !~? '" .
|
---|
| 805 | + \ strpart(skip,2) . "'"
|
---|
| 806 | + elseif skip[0] == "r"
|
---|
| 807 | + let skip = "strpart(getline('.'),0,col('.'))=~'" . strpart(skip,2). "'"
|
---|
| 808 | + elseif skip[0] == "R"
|
---|
| 809 | + let skip = "strpart(getline('.'),0,col('.'))!~'" . strpart(skip,2). "'"
|
---|
| 810 | + endif
|
---|
| 811 | + endif
|
---|
| 812 | + return skip
|
---|
| 813 | +endfun
|
---|
| 814 | +
|
---|
| 815 | +let &cpo = s:save_cpo
|
---|
| 816 | +
|
---|
| 817 | +" vim:sts=2:sw=2:
|
---|
| 818 |
|
---|
| 819 | Property changes on: ../trunk-jpl/externalpackages/vim/addons/vim/plugin/matchit.vim
|
---|
| 820 | ___________________________________________________________________
|
---|
| 821 | Added: svn:executable
|
---|
| 822 | ## -0,0 +1 ##
|
---|
| 823 | +*
|
---|
| 824 | \ No newline at end of property
|
---|