To: vim_dev@googlegroups.com Subject: Patch 7.4.1649 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.4.1649 Problem: The matchit plugin needs to be copied to be used. Solution: Put the matchit plugin in an optional package. Files: Filelist, runtime/macros/matchit.vim, runtime/macros/matchit.txt, runtime/macros/README.txt, src/Makefile, runtime/pack/dist/opt/matchit/plugin/matchit.vim, runtime/pack/dist/opt/matchit/doc/matchit.txt, runtime/pack/dist/opt/matchit/doc/tags, runtime/doc/usr_05.txt, runtime/doc/usr_toc.txt *** ../vim-7.4.1648/Filelist 2016-03-19 20:29:08.173621423 +0100 --- Filelist 2016-03-25 16:18:08.205500951 +0100 *************** *** 494,501 **** runtime/macros/less.vim \ runtime/macros/life/click.me \ runtime/macros/life/life.vim \ - runtime/macros/matchit.vim \ - runtime/macros/matchit.txt \ runtime/macros/maze/README.txt \ runtime/macros/maze/[mM]akefile \ runtime/macros/maze/main.aap \ --- 494,499 ---- *************** *** 525,530 **** --- 523,531 ---- runtime/tutor/tutor \ runtime/tutor/tutor.vim \ runtime/vimrc_example.vim \ + runtime/pack/dist/opt/matchit/plugin/matchit.vim \ + runtime/pack/dist/opt/matchit/doc/matchit.txt \ + runtime/pack/dist/opt/matchit/doc/tags \ # runtime files for all distributions without CR-NL translation RT_ALL_BIN = \ *** ../vim-7.4.1648/runtime/macros/matchit.vim 2012-12-12 16:34:11.000000000 +0100 --- runtime/macros/matchit.vim 1970-01-01 01:00:00.000000000 +0100 *************** *** 1,813 **** - " matchit.vim: (global plugin) Extended "%" matching - " Last Change: Fri Jan 25 10:00 AM 2008 EST - " Maintainer: Benji Fisher PhD - " Version: 1.13.2, for Vim 6.3+ - " URL: http://www.vim.org/script.php?script_id=39 - - " Documentation: - " The documentation is in a separate file, matchit.txt . - - " Credits: - " Vim editor by Bram Moolenaar (Thanks, Bram!) - " Original script and design by Raul Segura Acevedo - " Support for comments by Douglas Potts - " Support for back references and other improvements by Benji Fisher - " Support for many languages by Johannes Zellner - " Suggestions for improvement, bug reports, and support for additional - " languages by Jordi-Albert Batalla, Neil Bird, Servatius Brandt, Mark - " Collett, Stephen Wall, Dany St-Amant, Yuheng Xie, and Johannes Zellner. - - " Debugging: - " If you'd like to try the built-in debugging commands... - " :MatchDebug to activate debugging for the current buffer - " This saves the values of several key script variables as buffer-local - " variables. See the MatchDebug() function, below, for details. - - " TODO: I should think about multi-line patterns for b:match_words. - " This would require an option: how many lines to scan (default 1). - " This would be useful for Python, maybe also for *ML. - " TODO: Maybe I should add a menu so that people will actually use some of - " the features that I have implemented. - " TODO: Eliminate the MultiMatch function. Add yet another argument to - " Match_wrapper() instead. - " TODO: Allow :let b:match_words = '\(\(foo\)\(bar\)\):\3\2:end\1' - " TODO: Make backrefs safer by using '\V' (very no-magic). - " TODO: Add a level of indirection, so that custom % scripts can use my - " work but extend it. - - " allow user to prevent loading - " and prevent duplicate loading - if exists("loaded_matchit") || &cp - finish - endif - let loaded_matchit = 1 - let s:last_mps = "" - let s:last_words = ":" - - let s:save_cpo = &cpo - set cpo&vim - - nnoremap % :call Match_wrapper('',1,'n') - nnoremap g% :call Match_wrapper('',0,'n') - vnoremap % :call Match_wrapper('',1,'v') m'gv`` - vnoremap g% :call Match_wrapper('',0,'v') m'gv`` - onoremap % v:call Match_wrapper('',1,'o') - onoremap g% v:call Match_wrapper('',0,'o') - - " Analogues of [{ and ]} using matching patterns: - nnoremap [% :call MultiMatch("bW", "n") - nnoremap ]% :call MultiMatch("W", "n") - vmap [% [%m'gv`` - vmap ]% ]%m'gv`` - " vnoremap [% :call MultiMatch("bW", "v") m'gv`` - " vnoremap ]% :call MultiMatch("W", "v") m'gv`` - onoremap [% v:call MultiMatch("bW", "o") - onoremap ]% v:call MultiMatch("W", "o") - - " text object: - vmap a% [%v]% - - " Auto-complete mappings: (not yet "ready for prime time") - " TODO Read :help write-plugin for the "right" way to let the user - " specify a key binding. - " let g:match_auto = '' - " let g:match_autoCR = '' - " if exists("g:match_auto") - " execute "inoremap " . g:match_auto . ' x"=Autocomplete()Pls' - " endif - " if exists("g:match_autoCR") - " execute "inoremap " . g:match_autoCR . ' =Autocomplete()' - " endif - " if exists("g:match_gthhoh") - " execute "inoremap " . g:match_gthhoh . ' :call Gthhoh()' - " endif " gthhoh = "Get the heck out of here!" - - let s:notslash = '\\\@" - endif - " In s:CleanUp(), we may need to check whether the cursor moved forward. - let startline = line(".") - let startcol = col(".") - " Use default behavior if called with a count. - if v:count - exe "normal! " . v:count . "%" - return s:CleanUp(restore_options, a:mode, startline, startcol) - end - - " First step: if not already done, set the script variables - " s:do_BR flag for whether there are backrefs - " s:pat parsed version of b:match_words - " s:all regexp based on s:pat and the default groups - " - if !exists("b:match_words") || b:match_words == "" - let match_words = "" - " Allow b:match_words = "GetVimMatchWords()" . - elseif b:match_words =~ ":" - let match_words = b:match_words - else - execute "let match_words =" b:match_words - endif - " Thanks to Preben "Peppe" Guldberg and Bram Moolenaar for this suggestion! - if (match_words != s:last_words) || (&mps != s:last_mps) || - \ exists("b:match_debug") - let s:last_words = match_words - let s:last_mps = &mps - " The next several lines were here before - " BF started messing with this script. - " quote the special chars in 'matchpairs', replace [,:] with \| and then - " append the builtin pairs (/*, */, #if, #ifdef, #else, #elif, #endif) - " let default = substitute(escape(&mps, '[$^.*~\\/?]'), '[,:]\+', - " \ '\\|', 'g').'\|\/\*\|\*\/\|#if\>\|#ifdef\>\|#else\>\|#elif\>\|#endif\>' - let default = escape(&mps, '[$^.*~\\/?]') . (strlen(&mps) ? "," : "") . - \ '\/\*:\*\/,#\s*if\%(def\)\=:#\s*else\>:#\s*elif\>:#\s*endif\>' - " s:all = pattern with all the keywords - let match_words = match_words . (strlen(match_words) ? "," : "") . default - if match_words !~ s:notslash . '\\\d' - let s:do_BR = 0 - let s:pat = match_words - else - let s:do_BR = 1 - let s:pat = s:ParseWords(match_words) - endif - let s:all = substitute(s:pat, s:notslash . '\zs[,:]\+', '\\|', 'g') - let s:all = '\%(' . s:all . '\)' - " let s:all = '\%(' . substitute(s:all, '\\\ze[,:]', '', 'g') . '\)' - if exists("b:match_debug") - let b:match_pat = s:pat - endif - endif - - " Second step: set the following local variables: - " matchline = line on which the cursor started - " curcol = number of characters before match - " prefix = regexp for start of line to start of match - " suffix = regexp for end of match to end of line - " Require match to end on or after the cursor and prefer it to - " start on or before the cursor. - let matchline = getline(startline) - if a:word != '' - " word given - if a:word !~ s:all - echohl WarningMsg|echo 'Missing rule for word:"'.a:word.'"'|echohl NONE - return s:CleanUp(restore_options, a:mode, startline, startcol) - endif - let matchline = a:word - let curcol = 0 - let prefix = '^\%(' - let suffix = '\)$' - " Now the case when "word" is not given - else " Find the match that ends on or after the cursor and set curcol. - let regexp = s:Wholematch(matchline, s:all, startcol-1) - let curcol = match(matchline, regexp) - " If there is no match, give up. - if curcol == -1 - return s:CleanUp(restore_options, a:mode, startline, startcol) - endif - let endcol = matchend(matchline, regexp) - let suf = strlen(matchline) - endcol - let prefix = (curcol ? '^.*\%' . (curcol + 1) . 'c\%(' : '^\%(') - let suffix = (suf ? '\)\%' . (endcol + 1) . 'c.*$' : '\)$') - endif - if exists("b:match_debug") - let b:match_match = matchstr(matchline, regexp) - let b:match_col = curcol+1 - endif - - " Third step: Find the group and single word that match, and the original - " (backref) versions of these. Then, resolve the backrefs. - " Set the following local variable: - " group = colon-separated list of patterns, one of which matches - " = ini:mid:fin or ini:fin - " - " Reconstruct the version with unresolved backrefs. - let patBR = substitute(match_words.',', - \ s:notslash.'\zs[,:]*,[,:]*', ',', 'g') - let patBR = substitute(patBR, s:notslash.'\zs:\{2,}', ':', 'g') - " Now, set group and groupBR to the matching group: 'if:endif' or - " 'while:endwhile' or whatever. A bit of a kluge: s:Choose() returns - " group . "," . groupBR, and we pick it apart. - let group = s:Choose(s:pat, matchline, ",", ":", prefix, suffix, patBR) - let i = matchend(group, s:notslash . ",") - let groupBR = strpart(group, i) - let group = strpart(group, 0, i-1) - " Now, matchline =~ prefix . substitute(group,':','\|','g') . suffix - if s:do_BR " Do the hard part: resolve those backrefs! - let group = s:InsertRefs(groupBR, prefix, group, suffix, matchline) - endif - if exists("b:match_debug") - let b:match_wholeBR = groupBR - let i = matchend(groupBR, s:notslash . ":") - let b:match_iniBR = strpart(groupBR, 0, i-1) - endif - - " Fourth step: Set the arguments for searchpair(). - let i = matchend(group, s:notslash . ":") - let j = matchend(group, '.*' . s:notslash . ":") - let ini = strpart(group, 0, i-1) - let mid = substitute(strpart(group, i,j-i-1), s:notslash.'\zs:', '\\|', 'g') - let fin = strpart(group, j) - "Un-escape the remaining , and : characters. - let ini = substitute(ini, s:notslash . '\zs\\\(:\|,\)', '\1', 'g') - let mid = substitute(mid, s:notslash . '\zs\\\(:\|,\)', '\1', 'g') - let fin = substitute(fin, s:notslash . '\zs\\\(:\|,\)', '\1', 'g') - " searchpair() requires that these patterns avoid \(\) groups. - let ini = substitute(ini, s:notslash . '\zs\\(', '\\%(', 'g') - let mid = substitute(mid, s:notslash . '\zs\\(', '\\%(', 'g') - let fin = substitute(fin, s:notslash . '\zs\\(', '\\%(', 'g') - " Set mid. This is optimized for readability, not micro-efficiency! - if a:forward && matchline =~ prefix . fin . suffix - \ || !a:forward && matchline =~ prefix . ini . suffix - let mid = "" - endif - " Set flag. This is optimized for readability, not micro-efficiency! - if a:forward && matchline =~ prefix . fin . suffix - \ || !a:forward && matchline !~ prefix . ini . suffix - let flag = "bW" - else - let flag = "W" - endif - " Set skip. - if exists("b:match_skip") - let skip = b:match_skip - elseif exists("b:match_comment") " backwards compatibility and testing! - let skip = "r:" . b:match_comment - else - let skip = 's:comment\|string' - endif - let skip = s:ParseSkip(skip) - if exists("b:match_debug") - let b:match_ini = ini - let b:match_tail = (strlen(mid) ? mid.'\|' : '') . fin - endif - - " Fifth step: actually start moving the cursor and call searchpair(). - " Later, :execute restore_cursor to get to the original screen. - let restore_cursor = virtcol(".") . "|" - normal! g0 - let restore_cursor = line(".") . "G" . virtcol(".") . "|zs" . restore_cursor - normal! H - let restore_cursor = "normal!" . line(".") . "Gzt" . restore_cursor - execute restore_cursor - call cursor(0, curcol + 1) - " normal! 0 - " if curcol - " execute "normal!" . curcol . "l" - " endif - if skip =~ 'synID' && !(has("syntax") && exists("g:syntax_on")) - let skip = "0" - else - execute "if " . skip . "| let skip = '0' | endif" - endif - let sp_return = searchpair(ini, mid, fin, flag, skip) - let final_position = "call cursor(" . line(".") . "," . col(".") . ")" - " Restore cursor position and original screen. - execute restore_cursor - normal! m' - if sp_return > 0 - execute final_position - endif - return s:CleanUp(restore_options, a:mode, startline, startcol, mid.'\|'.fin) - endfun - - " Restore options and do some special handling for Operator-pending mode. - " The optional argument is the tail of the matching group. - fun! s:CleanUp(options, mode, startline, startcol, ...) - execute "set" a:options - " Open folds, if appropriate. - if a:mode != "o" - if &foldopen =~ "percent" - normal! zv - endif - " In Operator-pending mode, we want to include the whole match - " (for example, d%). - " This is only a problem if we end up moving in the forward direction. - elseif (a:startline < line(".")) || - \ (a:startline == line(".") && a:startcol < col(".")) - if a:0 - " Check whether the match is a single character. If not, move to the - " end of the match. - let matchline = getline(".") - let currcol = col(".") - let regexp = s:Wholematch(matchline, a:1, currcol-1) - let endcol = matchend(matchline, regexp) - if endcol > currcol " This is NOT off by one! - execute "normal!" . (endcol - currcol) . "l" - endif - endif " a:0 - endif " a:mode != "o" && etc. - return 0 - endfun - - " Example (simplified HTML patterns): if - " a:groupBR = '<\(\k\+\)>:' - " a:prefix = '^.\{3}\(' - " a:group = '<\(\k\+\)>:' - " a:suffix = '\).\{2}$' - " a:matchline = "12312" or "12312" - " then extract "tag" from a:matchline and return ":" . - fun! s:InsertRefs(groupBR, prefix, group, suffix, matchline) - if a:matchline !~ a:prefix . - \ substitute(a:group, s:notslash . '\zs:', '\\|', 'g') . a:suffix - return a:group - endif - let i = matchend(a:groupBR, s:notslash . ':') - let ini = strpart(a:groupBR, 0, i-1) - let tailBR = strpart(a:groupBR, i) - let word = s:Choose(a:group, a:matchline, ":", "", a:prefix, a:suffix, - \ a:groupBR) - let i = matchend(word, s:notslash . ":") - let wordBR = strpart(word, i) - let word = strpart(word, 0, i-1) - " Now, a:matchline =~ a:prefix . word . a:suffix - if wordBR != ini - let table = s:Resolve(ini, wordBR, "table") - else - " let table = "----------" - let table = "" - let d = 0 - while d < 10 - if tailBR =~ s:notslash . '\\' . d - " let table[d] = d - let table = table . d - else - let table = table . "-" - endif - let d = d + 1 - endwhile - endif - let d = 9 - while d - if table[d] != "-" - let backref = substitute(a:matchline, a:prefix.word.a:suffix, - \ '\'.table[d], "") - " Are there any other characters that should be escaped? - let backref = escape(backref, '*,:') - execute s:Ref(ini, d, "start", "len") - let ini = strpart(ini, 0, start) . backref . strpart(ini, start+len) - let tailBR = substitute(tailBR, s:notslash . '\zs\\' . d, - \ escape(backref, '\\&'), 'g') - endif - let d = d-1 - endwhile - if exists("b:match_debug") - if s:do_BR - let b:match_table = table - let b:match_word = word - else - let b:match_table = "" - let b:match_word = "" - endif - endif - return ini . ":" . tailBR - endfun - - " Input a comma-separated list of groups with backrefs, such as - " a:groups = '\(foo\):end\1,\(bar\):end\1' - " and return a comma-separated list of groups with backrefs replaced: - " return '\(foo\):end\(foo\),\(bar\):end\(bar\)' - fun! s:ParseWords(groups) - let groups = substitute(a:groups.",", s:notslash.'\zs[,:]*,[,:]*', ',', 'g') - let groups = substitute(groups, s:notslash . '\zs:\{2,}', ':', 'g') - let parsed = "" - while groups =~ '[^,:]' - let i = matchend(groups, s:notslash . ':') - let j = matchend(groups, s:notslash . ',') - let ini = strpart(groups, 0, i-1) - let tail = strpart(groups, i, j-i-1) . ":" - let groups = strpart(groups, j) - let parsed = parsed . ini - let i = matchend(tail, s:notslash . ':') - while i != -1 - " In 'if:else:endif', ini='if' and word='else' and then word='endif'. - let word = strpart(tail, 0, i-1) - let tail = strpart(tail, i) - let i = matchend(tail, s:notslash . ':') - let parsed = parsed . ":" . s:Resolve(ini, word, "word") - endwhile " Now, tail has been used up. - let parsed = parsed . "," - endwhile " groups =~ '[^,:]' - let parsed = substitute(parsed, ',$', '', '') - return parsed - endfun - - " TODO I think this can be simplified and/or made more efficient. - " TODO What should I do if a:start is out of range? - " Return a regexp that matches all of a:string, such that - " matchstr(a:string, regexp) represents the match for a:pat that starts - " as close to a:start as possible, before being preferred to after, and - " ends after a:start . - " Usage: - " let regexp = s:Wholematch(getline("."), 'foo\|bar', col(".")-1) - " let i = match(getline("."), regexp) - " let j = matchend(getline("."), regexp) - " let match = matchstr(getline("."), regexp) - fun! s:Wholematch(string, pat, start) - let group = '\%(' . a:pat . '\)' - let prefix = (a:start ? '\(^.*\%<' . (a:start + 2) . 'c\)\zs' : '^') - let len = strlen(a:string) - let suffix = (a:start+1 < len ? '\(\%>'.(a:start+1).'c.*$\)\@=' : '$') - if a:string !~ prefix . group . suffix - let prefix = '' - endif - return prefix . group . suffix - endfun - - " No extra arguments: s:Ref(string, d) will - " find the d'th occurrence of '\(' and return it, along with everything up - " to and including the matching '\)'. - " One argument: s:Ref(string, d, "start") returns the index of the start - " of the d'th '\(' and any other argument returns the length of the group. - " Two arguments: s:Ref(string, d, "foo", "bar") returns a string to be - " executed, having the effect of - " :let foo = s:Ref(string, d, "start") - " :let bar = s:Ref(string, d, "len") - fun! s:Ref(string, d, ...) - let len = strlen(a:string) - if a:d == 0 - let start = 0 - else - let cnt = a:d - let match = a:string - while cnt - let cnt = cnt - 1 - let index = matchend(match, s:notslash . '\\(') - if index == -1 - return "" - endif - let match = strpart(match, index) - endwhile - let start = len - strlen(match) - if a:0 == 1 && a:1 == "start" - return start - 2 - endif - let cnt = 1 - while cnt - let index = matchend(match, s:notslash . '\\(\|\\)') - 1 - if index == -2 - return "" - endif - " Increment if an open, decrement if a ')': - let cnt = cnt + (match[index]=="(" ? 1 : -1) " ')' - " let cnt = stridx('0(', match[index]) + cnt - let match = strpart(match, index+1) - endwhile - let start = start - 2 - let len = len - start - strlen(match) - endif - if a:0 == 1 - return len - elseif a:0 == 2 - return "let " . a:1 . "=" . start . "| let " . a:2 . "=" . len - else - return strpart(a:string, start, len) - endif - endfun - - " Count the number of disjoint copies of pattern in string. - " If the pattern is a literal string and contains no '0' or '1' characters - " then s:Count(string, pattern, '0', '1') should be faster than - " s:Count(string, pattern). - fun! s:Count(string, pattern, ...) - let pat = escape(a:pattern, '\\') - if a:0 > 1 - let foo = substitute(a:string, '[^'.a:pattern.']', "a:1", "g") - let foo = substitute(a:string, pat, a:2, "g") - let foo = substitute(foo, '[^' . a:2 . ']', "", "g") - return strlen(foo) - endif - let result = 0 - let foo = a:string - let index = matchend(foo, pat) - while index != -1 - let result = result + 1 - let foo = strpart(foo, index) - let index = matchend(foo, pat) - endwhile - return result - endfun - - " s:Resolve('\(a\)\(b\)', '\(c\)\2\1\1\2') should return table.word, where - " word = '\(c\)\(b\)\(a\)\3\2' and table = '-32-------'. That is, the first - " '\1' in target is replaced by '\(a\)' in word, table[1] = 3, and this - " indicates that all other instances of '\1' in target are to be replaced - " by '\3'. The hard part is dealing with nesting... - " Note that ":" is an illegal character for source and target, - " unless it is preceded by "\". - fun! s:Resolve(source, target, output) - let word = a:target - let i = matchend(word, s:notslash . '\\\d') - 1 - let table = "----------" - while i != -2 " There are back references to be replaced. - let d = word[i] - let backref = s:Ref(a:source, d) - " The idea is to replace '\d' with backref. Before we do this, - " replace any \(\) groups in backref with :1, :2, ... if they - " correspond to the first, second, ... group already inserted - " into backref. Later, replace :1 with \1 and so on. The group - " number w+b within backref corresponds to the group number - " s within a:source. - " w = number of '\(' in word before the current one - let w = s:Count( - \ substitute(strpart(word, 0, i-1), '\\\\', '', 'g'), '\(', '1') - let b = 1 " number of the current '\(' in backref - let s = d " number of the current '\(' in a:source - while b <= s:Count(substitute(backref, '\\\\', '', 'g'), '\(', '1') - \ && s < 10 - if table[s] == "-" - if w + b < 10 - " let table[s] = w + b - let table = strpart(table, 0, s) . (w+b) . strpart(table, s+1) - endif - let b = b + 1 - let s = s + 1 - else - execute s:Ref(backref, b, "start", "len") - let ref = strpart(backref, start, len) - let backref = strpart(backref, 0, start) . ":". table[s] - \ . strpart(backref, start+len) - let s = s + s:Count(substitute(ref, '\\\\', '', 'g'), '\(', '1') - endif - endwhile - let word = strpart(word, 0, i-1) . backref . strpart(word, i+1) - let i = matchend(word, s:notslash . '\\\d') - 1 - endwhile - let word = substitute(word, s:notslash . '\zs:', '\\', 'g') - if a:output == "table" - return table - elseif a:output == "word" - return word - else - return table . word - endif - endfun - - " Assume a:comma = ",". Then the format for a:patterns and a:1 is - " a:patterns = ",,..." - " a:1 = ",,..." - " If is the first pattern that matches a:string then return - " if no optional arguments are given; return , if a:1 is given. - fun! s:Choose(patterns, string, comma, branch, prefix, suffix, ...) - let tail = (a:patterns =~ a:comma."$" ? a:patterns : a:patterns . a:comma) - let i = matchend(tail, s:notslash . a:comma) - if a:0 - let alttail = (a:1 =~ a:comma."$" ? a:1 : a:1 . a:comma) - let j = matchend(alttail, s:notslash . a:comma) - endif - let current = strpart(tail, 0, i-1) - if a:branch == "" - let currpat = current - else - let currpat = substitute(current, s:notslash . a:branch, '\\|', 'g') - endif - while a:string !~ a:prefix . currpat . a:suffix - let tail = strpart(tail, i) - let i = matchend(tail, s:notslash . a:comma) - if i == -1 - return -1 - endif - let current = strpart(tail, 0, i-1) - if a:branch == "" - let currpat = current - else - let currpat = substitute(current, s:notslash . a:branch, '\\|', 'g') - endif - if a:0 - let alttail = strpart(alttail, j) - let j = matchend(alttail, s:notslash . a:comma) - endif - endwhile - if a:0 - let current = current . a:comma . strpart(alttail, 0, j-1) - endif - return current - endfun - - " Call this function to turn on debugging information. Every time the main - " script is run, buffer variables will be saved. These can be used directly - " or viewed using the menu items below. - if !exists(":MatchDebug") - command! -nargs=0 MatchDebug call s:Match_debug() - endif - - fun! s:Match_debug() - let b:match_debug = 1 " Save debugging information. - " pat = all of b:match_words with backrefs parsed - amenu &Matchit.&pat :echo b:match_pat - " match = bit of text that is recognized as a match - amenu &Matchit.&match :echo b:match_match - " curcol = cursor column of the start of the matching text - amenu &Matchit.&curcol :echo b:match_col - " wholeBR = matching group, original version - amenu &Matchit.wh&oleBR :echo b:match_wholeBR - " iniBR = 'if' piece, original version - amenu &Matchit.ini&BR :echo b:match_iniBR - " ini = 'if' piece, with all backrefs resolved from match - amenu &Matchit.&ini :echo b:match_ini - " tail = 'else\|endif' piece, with all backrefs resolved from match - amenu &Matchit.&tail :echo b:match_tail - " fin = 'endif' piece, with all backrefs resolved from match - amenu &Matchit.&word :echo b:match_word - " '\'.d in ini refers to the same thing as '\'.table[d] in word. - amenu &Matchit.t&able :echo '0:' . b:match_table . ':9' - endfun - - " Jump to the nearest unmatched "(" or "if" or "" if a:spflag == "bW" - " or the nearest unmatched "" or "endif" or ")" if a:spflag == "W". - " Return a "mark" for the original position, so that - " let m = MultiMatch("bW", "n") ... execute m - " will return to the original position. If there is a problem, do not - " move the cursor and return "", unless a count is given, in which case - " go up or down as many levels as possible and again return "". - " TODO This relies on the same patterns as % matching. It might be a good - " idea to give it its own matching patterns. - fun! s:MultiMatch(spflag, mode) - if !exists("b:match_words") || b:match_words == "" - return "" - end - let restore_options = (&ic ? "" : "no") . "ignorecase" - if exists("b:match_ignorecase") - let &ignorecase = b:match_ignorecase - endif - let startline = line(".") - let startcol = col(".") - - " First step: if not already done, set the script variables - " s:do_BR flag for whether there are backrefs - " s:pat parsed version of b:match_words - " s:all regexp based on s:pat and the default groups - " This part is copied and slightly modified from s:Match_wrapper(). - let default = escape(&mps, '[$^.*~\\/?]') . (strlen(&mps) ? "," : "") . - \ '\/\*:\*\/,#\s*if\%(def\)\=:#\s*else\>:#\s*elif\>:#\s*endif\>' - " Allow b:match_words = "GetVimMatchWords()" . - if b:match_words =~ ":" - let match_words = b:match_words - else - execute "let match_words =" b:match_words - endif - if (match_words != s:last_words) || (&mps != s:last_mps) || - \ exists("b:match_debug") - let s:last_words = match_words - let s:last_mps = &mps - if match_words !~ s:notslash . '\\\d' - let s:do_BR = 0 - let s:pat = match_words - else - let s:do_BR = 1 - let s:pat = s:ParseWords(match_words) - endif - let s:all = '\%(' . substitute(s:pat . (strlen(s:pat)?",":"") . default, - \ '[,:]\+','\\|','g') . '\)' - if exists("b:match_debug") - let b:match_pat = s:pat - endif - endif - - " Second step: figure out the patterns for searchpair() - " and save the screen, cursor position, and 'ignorecase'. - " - TODO: A lot of this is copied from s:Match_wrapper(). - " - maybe even more functionality should be split off - " - into separate functions! - let cdefault = (s:pat =~ '[^,]$' ? "," : "") . default - let open = substitute(s:pat . cdefault, - \ s:notslash . '\zs:.\{-}' . s:notslash . ',', '\\),\\(', 'g') - let open = '\(' . substitute(open, s:notslash . '\zs:.*$', '\\)', '') - let close = substitute(s:pat . cdefault, - \ s:notslash . '\zs,.\{-}' . s:notslash . ':', '\\),\\(', 'g') - let close = substitute(close, '^.\{-}' . s:notslash . ':', '\\(', '') . '\)' - if exists("b:match_skip") - let skip = b:match_skip - elseif exists("b:match_comment") " backwards compatibility and testing! - let skip = "r:" . b:match_comment - else - let skip = 's:comment\|string' - endif - let skip = s:ParseSkip(skip) - " let restore_cursor = line(".") . "G" . virtcol(".") . "|" - " normal! H - " let restore_cursor = "normal!" . line(".") . "Gzt" . restore_cursor - let restore_cursor = virtcol(".") . "|" - normal! g0 - let restore_cursor = line(".") . "G" . virtcol(".") . "|zs" . restore_cursor - normal! H - let restore_cursor = "normal!" . line(".") . "Gzt" . restore_cursor - execute restore_cursor - - " Third step: call searchpair(). - " Replace '\('--but not '\\('--with '\%(' and ',' with '\|'. - let openpat = substitute(open, '\(\\\@" or ... - " and return "endif" or "endwhile" or "" or ... . - " For now, this uses b:match_words and the same script variables - " as s:Match_wrapper() . Later, it may get its own patterns, - " either from a buffer variable or passed as arguments. - " fun! s:Autocomplete() - " echo "autocomplete not yet implemented :-(" - " if !exists("b:match_words") || b:match_words == "" - " return "" - " end - " let startpos = s:MultiMatch("bW") - " - " if startpos == "" - " return "" - " endif - " " - TODO: figure out whether 'if' or '' matched, and construct - " " - the appropriate closing. - " let matchline = getline(".") - " let curcol = col(".") - 1 - " " - TODO: Change the s:all argument if there is a new set of match pats. - " let regexp = s:Wholematch(matchline, s:all, curcol) - " let suf = strlen(matchline) - matchend(matchline, regexp) - " let prefix = (curcol ? '^.\{' . curcol . '}\%(' : '^\%(') - " let suffix = (suf ? '\).\{' . suf . '}$' : '\)$') - " " Reconstruct the version with unresolved backrefs. - " let patBR = substitute(b:match_words.',', '[,:]*,[,:]*', ',', 'g') - " let patBR = substitute(patBR, ':\{2,}', ':', "g") - " " Now, set group and groupBR to the matching group: 'if:endif' or - " " 'while:endwhile' or whatever. - " let group = s:Choose(s:pat, matchline, ",", ":", prefix, suffix, patBR) - " let i = matchend(group, s:notslash . ",") - " let groupBR = strpart(group, i) - " let group = strpart(group, 0, i-1) - " " Now, matchline =~ prefix . substitute(group,':','\|','g') . suffix - " if s:do_BR - " let group = s:InsertRefs(groupBR, prefix, group, suffix, matchline) - " endif - " " let g:group = group - " - " " - TODO: Construct the closing from group. - " let fake = "end" . expand("") - " execute startpos - " return fake - " endfun - - " Close all open structures. "Get the heck out of here!" - " fun! s:Gthhoh() - " let close = s:Autocomplete() - " while strlen(close) - " put=close - " let close = s:Autocomplete() - " endwhile - " endfun - - " Parse special strings as typical skip arguments for searchpair(): - " s:foo becomes (current syntax item) =~ foo - " S:foo becomes (current syntax item) !~ foo - " r:foo becomes (line before cursor) =~ foo - " R:foo becomes (line before cursor) !~ foo - fun! s:ParseSkip(str) - let skip = a:str - if skip[1] == ":" - if skip[0] == "s" - let skip = "synIDattr(synID(line('.'),col('.'),1),'name') =~? '" . - \ strpart(skip,2) . "'" - elseif skip[0] == "S" - let skip = "synIDattr(synID(line('.'),col('.'),1),'name') !~? '" . - \ strpart(skip,2) . "'" - elseif skip[0] == "r" - let skip = "strpart(getline('.'),0,col('.'))=~'" . strpart(skip,2). "'" - elseif skip[0] == "R" - let skip = "strpart(getline('.'),0,col('.'))!~'" . strpart(skip,2). "'" - endif - endif - return skip - endfun - - let &cpo = s:save_cpo - unlet s:save_cpo - - " vim:sts=2:sw=2: --- 0 ---- *** ../vim-7.4.1648/runtime/macros/matchit.txt 2010-05-15 13:04:01.000000000 +0200 --- runtime/macros/matchit.txt 1970-01-01 01:00:00.000000000 +0100 *************** *** 1,406 **** - *matchit.txt* Extended "%" matching - - For instructions on installing this file, type - :help matchit-install - inside Vim. - - For Vim version 6.3. Last change: 2007 Aug 29 - - - VIM REFERENCE MANUAL by Benji Fisher - - *matchit* *matchit.vim* - - 1. Extended matching with "%" |matchit-intro| - 2. Activation |matchit-activate| - 3. Configuration |matchit-configure| - 4. Supporting a New Language |matchit-newlang| - 5. Known Bugs and Limitations |matchit-bugs| - - The functionality mentioned here is a plugin, see |add-plugin|. - This plugin is only available if 'compatible' is not set. - You can avoid loading this plugin by setting the "loaded_matchit" variable - in your |vimrc| file: > - :let loaded_matchit = 1 - - {Vi does not have any of this} - - ============================================================================== - 1. Extended matching with "%" *matchit-intro* - - *matchit-%* - % Cycle forward through matching groups, such as "if", "else", "endif", - as specified by |b:match_words|. - - *g%* *v_g%* *o_g%* - g% Cycle backwards through matching groups, as specified by - |b:match_words|. For example, go from "if" to "endif" to "else". - - *[%* *v_[%* *o_[%* - [% Go to [count] previous unmatched group, as specified by - |b:match_words|. Similar to |[{|. - - *]%* *v_]%* *o_]%* - ]% Go to [count] next unmatched group, as specified by - |b:match_words|. Similar to |]}|. - - *v_a%* - a% In Visual mode, select the matching group, as specified by - |b:match_words|, containing the cursor. Similar to |v_a[|. - A [count] is ignored, and only the first character of the closing - pattern is selected. - - In Vim, as in plain vi, the percent key, |%|, jumps the cursor from a brace, - bracket, or paren to its match. This can be configured with the 'matchpairs' - option. The matchit plugin extends this in several ways: - - You can match whole words, such as "if" and "endif", not just - single characters. You can also specify a |regular-expression|. - You can define groups with more than two words, such as "if", - "else", "endif". Banging on the "%" key will cycle from the "if" to - the first "else", the next "else", ..., the closing "endif", and back - to the opening "if". Nested structures are skipped. Using |g%| goes - in the reverse direction. - By default, words inside comments and strings are ignored, unless - the cursor is inside a comment or string when you type "%". If the - only thing you want to do is modify the behavior of "%" so that it - behaves this way, you do not have to define |b:match_words|, since the - script uses the 'matchpairs' option as well as this variable. - - See |matchit-details| for details on what the script does, and |b:match_words| - for how to specify matching patterns. - - MODES: *matchit-modes* *matchit-v_%* *matchit-o_%* - - Mostly, % and related motions (|g%| and |[%| and |]%|) work just like built-in - |motion| commands in |Operator-pending| and |Visual| modes. However, you - cannot make these motions |linewise| or |characterwise|, since the |:omap|s - that define them start with "v" in order to make the default behavior - inclusive. (See |o_v|.) In other words, "dV%" will not work. The - work-around is to go through Visual mode: "V%d" will work. - - LANGUAGES: *matchit-languages* - - Currently, the following languages are supported: Ada, ASP with VBS, Csh, - DTD, Entity, Essbase, Fortran, HTML, JSP (same as HTML), LaTeX, Lua, Pascal, - SGML, Shell, Tcsh, Vim, XML. Other languages may already have support via - the default |filetype-plugin|s in the standard vim distribution. - - To support a new language, see |matchit-newlang| below. - - DETAILS: *matchit-details* *matchit-parse* - - Here is an outline of what matchit.vim does each time you hit the "%" key. If - there are |backref|s in |b:match_words| then the first step is to produce a - version in which these back references have been eliminated; if there are no - |backref|s then this step is skipped. This step is called parsing. For - example, "\(foo\|bar\):end\1" is parsed to yield - "\(foo\|bar\):end\(foo\|bar\)". This can get tricky, especially if there are - nested groups. If debugging is turned on, the parsed version is saved as - |b:match_pat|. - - *matchit-choose* - Next, the script looks for a word on the current line that matches the pattern - just constructed. It includes the patterns from the 'matchpairs' option. - The goal is to do what you expect, which turns out to be a little complicated. - The script follows these rules: - - Insist on a match that ends on or after the cursor. - Prefer a match that includes the cursor position (that is, one that - starts on or before the cursor). - Prefer a match that starts as close to the cursor as possible. - If more than one pattern in |b:match_words| matches, choose the one - that is listed first. - - Examples: - - Suppose you > - :let b:match_words = '<:>,:' - < and hit "%" with the cursor on or before the "<" in "a is born". - The pattern '<' comes first, so it is preferred over '', which - also matches. If the cursor is on the "t", however, then '' is - preferred, because this matches a bit of text containing the cursor. - If the two groups of patterns were reversed then '<' would never be - preferred. - - Suppose you > - :let b:match_words = 'if:end if' - < (Note the space!) and hit "%" with the cursor at the end of "end if". - Then "if" matches, which is probably not what you want, but if the - cursor starts on the "end " then "end if" is chosen. (You can avoid - this problem by using a more complicated pattern.) - - If there is no match, the cursor does not move. (Before version 1.13 of the - script, it would fall back on the usual behavior of |%|). If debugging is - turned on, the matched bit of text is saved as |b:match_match| and the cursor - column of the start of the match is saved as |b:match_col|. - - Next, the script looks through |b:match_words| (original and parsed versions) - for the group and pattern that match. If debugging is turned on, the group is - saved as |b:match_ini| (the first pattern) and |b:match_tail| (the rest). If - there are |backref|s then, in addition, the matching pattern is saved as - |b:match_word| and a table of translations is saved as |b:match_table|. If - there are |backref|s, these are determined from the matching pattern and - |b:match_match| and substituted into each pattern in the matching group. - - The script decides whether to search forwards or backwards and chooses - arguments for the |searchpair()| function. Then, the cursor is moved to the - start of the match, and |searchpair()| is called. By default, matching - structures inside strings and comments are ignored. This can be changed by - setting |b:match_skip|. - - ============================================================================== - 2. Activation *matchit-activate* - - You can use this script as a plugin, by copying it to your plugin directory. - See |add-global-plugin| for instructions. You can also add a line to your - |vimrc| file, such as > - :source $VIMRUNTIME/macros/matchit.vim - or > - :runtime macros/matchit.vim - Either way, the script should start working the next time you start up Vim. - - (Earlier versions of the script did nothing unless a |buffer-variable| named - |b:match_words| was defined. Even earlier versions contained autocommands - that set this variable for various file types. Now, |b:match_words| is - defined in many of the default |filetype-plugin|s instead.) - - For a new language, you can add autocommands to the script or to your vimrc - file, but the recommended method is to add a line such as > - let b:match_words = '\:\' - to the |filetype-plugin| for your language. See |b:match_words| below for how - this variable is interpreted. - - TROUBLESHOOTING *matchit-troubleshoot* - - The script should work in most installations of Vim. It may not work if Vim - was compiled with a minimal feature set, for example if the |+syntax| option - was not enabled. If your Vim has support for syntax compiled in, but you do - not have |syntax| highlighting turned on, matchit.vim should work, but it may - fail to skip matching groups in comments and strings. If the |filetype| - mechanism is turned off, the |b:match_words| variable will probably not be - defined automatically. - - ============================================================================== - 3. Configuration *matchit-configure* - - There are several variables that govern the behavior of matchit.vim. Note - that these are variables local to the buffer, not options, so use |:let| to - define them, not |:set|. Some of these variables have values that matter; for - others, it only matters whether the variable has been defined. All of these - can be defined in the |filetype-plugin| or autocommand that defines - |b:match_words| or "on the fly." - - The main variable is |b:match_words|. It is described in the section below on - supporting a new language. - - *MatchError* *matchit-hl* *matchit-highlight* - MatchError is the highlight group for error messages from the script. By - default, it is linked to WarningMsg. If you do not want to be bothered by - error messages, you can define this to be something invisible. For example, - if you use the GUI version of Vim and your command line is normally white, you - can do > - :hi MatchError guifg=white guibg=white - < - *b:match_ignorecase* - If you > - :let b:match_ignorecase = 1 - then matchit.vim acts as if 'ignorecase' is set: for example, "end" and "END" - are equivalent. If you > - :let b:match_ignorecase = 0 - then matchit.vim treats "end" and "END" differently. (There will be no - b:match_infercase option unless someone requests it.) - - *b:match_debug* - Define b:match_debug if you want debugging information to be saved. See - |matchit-debug|, below. - - *b:match_skip* - If b:match_skip is defined, it is passed as the skip argument to - |searchpair()|. This controls when matching structures are skipped, or - ignored. By default, they are ignored inside comments and strings, as - determined by the |syntax| mechanism. (If syntax highlighting is turned off, - nothing is skipped.) You can set b:match_skip to a string, which evaluates to - a non-zero, numerical value if the match is to be skipped or zero if the match - should not be skipped. In addition, the following special values are - supported by matchit.vim: - s:foo becomes (current syntax item) =~ foo - S:foo becomes (current syntax item) !~ foo - r:foo becomes (line before cursor) =~ foo - R:foo becomes (line before cursor) !~ foo - (The "s" is meant to suggest "syntax", and the "r" is meant to suggest - "regular expression".) - - Examples: - - You can get the default behavior with > - :let b:match_skip = 's:comment\|string' - < - If you want to skip matching structures unless they are at the start - of the line (ignoring whitespace) then you can > - :let b:match_skip = 'R:^\s*' - < Do not do this if strings or comments can span several lines, since - the normal syntax checking will not be done if you set b:match_skip. - - In LaTeX, since "%" is used as the comment character, you can > - :let b:match_skip = 'r:%' - < Unfortunately, this will skip anything after "\%", an escaped "%". To - allow for this, and also "\\%" (an excaped backslash followed by the - comment character) you can > - :let b:match_skip = 'r:\(^\|[^\\]\)\(\\\\\)*%' - < - See the $VIMRUNTIME/ftplugin/vim.vim for an example that uses both - syntax and a regular expression. - - ============================================================================== - 4. Supporting a New Language *matchit-newlang* - *b:match_words* - In order for matchit.vim to support a new language, you must define a suitable - pattern for |b:match_words|. You may also want to set some of the - |matchit-configure| variables, as described above. If your language has a - complicated syntax, or many keywords, you will need to know something about - Vim's |regular-expression|s. - - The format for |b:match_words| is similar to that of the 'matchpairs' option: - it is a comma (,)-separated list of groups; each group is a colon(:)-separated - list of patterns (regular expressions). Commas and backslashes that are part - of a pattern should be escaped with backslashes ('\:' and '\,'). It is OK to - have only one group; the effect is undefined if a group has only one pattern. - A simple example is > - :let b:match_words = '\:\,' - \ . '\:\:\:\' - (In Vim regular expressions, |\<| and |\>| denote word boundaries. Thus "if" - matches the end of "endif" but "\" does not.) Then banging on the "%" - key will bounce the cursor between "if" and the matching "endif"; and from - "while" to any matching "continue" or "break", then to the matching "endwhile" - and back to the "while". It is almost always easier to use |literal-string|s - (single quotes) as above: '\' rather than "\\" and so on. - - Exception: If the ":" character does not appear in b:match_words, then it is - treated as an expression to be evaluated. For example, > - :let b:match_words = 'GetMatchWords()' - allows you to define a function. This can return a different string depending - on the current syntax, for example. - - Once you have defined the appropriate value of |b:match_words|, you will - probably want to have this set automatically each time you edit the - appropriate file type. The recommended way to do this is by adding the - definition to a |filetype-plugin| file. - - Tips: Be careful that your initial pattern does not match your final pattern. - See the example above for the use of word-boundary expressions. It is usually - better to use ".\{-}" (as many as necessary) instead of ".*" (as many as - possible). See |\{-|. For example, in the string "label", "<.*>" - matches the whole string whereas "<.\{-}>" and "<[^>]*>" match "" and - "". - - *matchit-spaces* *matchit-s:notend* - If "if" is to be paired with "end if" (Note the space!) then word boundaries - are not enough. Instead, define a regular expression s:notend that will match - anything but "end" and use it as follows: > - :let s:notend = '\%(\:\' - < *matchit-s:sol* - This is a simplified version of what is done for Ada. The s:notend is a - |script-variable|. Similarly, you may want to define a start-of-line regular - expression > - :let s:sol = '\%(^\|;\)\s*' - if keywords are only recognized after the start of a line or after a - semicolon (;), with optional white space. - - *matchit-backref* *matchit-\1* - In any group, the expressions |\1|, |\2|, ..., |\9| refer to parts of the - INITIAL pattern enclosed in |\(|escaped parentheses|\)|. These are referred - to as back references, or backrefs. For example, > - :let b:match_words = '\:\(h\)\1\>' - means that "bo" pairs with "ho" and "boo" pairs with "hoo" and so on. Note - that "\1" does not refer to the "\(h\)" in this example. If you have - "\(nested \(parentheses\)\) then "\d" refers to the d-th "\(" and everything - up to and including the matching "\)": in "\(nested\(parentheses\)\)", "\1" - refers to everything and "\2" refers to "\(parentheses\)". If you use a - variable such as |s:notend| or |s:sol| in the previous paragraph then remember - to count any "\(" patterns in this variable. You do not have to count groups - defined by |\%(\)|. - - It should be possible to resolve back references from any pattern in the - group. For example, > - :let b:match_words = '\(foo\)\(bar\):more\1:and\2:end\1\2' - would not work because "\2" cannot be determined from "morefoo" and "\1" - cannot be determined from "andbar". On the other hand, > - :let b:match_words = '\(\(foo\)\(bar\)\):\3\2:end\1' - should work (and have the same effect as "foobar:barfoo:endfoobar"), although - this has not been thoroughly tested. - - You can use |zero-width| patterns such as |\@<=| and |\zs|. (The latter has - not been thouroughly tested in matchit.vim.) For example, if the keyword "if" - must occur at the start of the line, with optional white space, you might use - the pattern "\(^\s*\)\@<=if" so that the cursor will end on the "i" instead of - at the start of the line. For another example, if HTML had only one tag then - one could > - :let b:match_words = '<:>,<\@<=tag>:<\@<=/tag>' - so that "%" can bounce between matching "<" and ">" pairs or (starting on - "tag" or "/tag") between matching tags. Without the |\@<=|, the script would - bounce from "tag" to the "<" in "", and another "%" would not take you - back to where you started. - - DEBUGGING *matchit-debug* *:MatchDebug* - - If you are having trouble figuring out the appropriate definition of - |b:match_words| then you can take advantage of the same information I use when - debugging the script. This is especially true if you are not sure whether - your patterns or my script are at fault! To make this more convenient, I have - made the command :MatchDebug, which defines the variable |b:match_debug| and - creates a Matchit menu. This menu makes it convenient to check the values of - the variables described below. You will probably also want to read - |matchit-details| above. - - Defining the variable |b:match_debug| causes the script to set the following - variables, each time you hit the "%" key. Several of these are only defined - if |b:match_words| includes |backref|s. - - *b:match_pat* - The b:match_pat variable is set to |b:match_words| with |backref|s parsed. - *b:match_match* - The b:match_match variable is set to the bit of text that is recognized as a - match. - *b:match_col* - The b:match_col variable is set to the cursor column of the start of the - matching text. - *b:match_wholeBR* - The b:match_wholeBR variable is set to the comma-separated group of patterns - that matches, with |backref|s unparsed. - *b:match_iniBR* - The b:match_iniBR variable is set to the first pattern in |b:match_wholeBR|. - *b:match_ini* - The b:match_ini variable is set to the first pattern in |b:match_wholeBR|, - with |backref|s resolved from |b:match_match|. - *b:match_tail* - The b:match_tail variable is set to the remaining patterns in - |b:match_wholeBR|, with |backref|s resolved from |b:match_match|. - *b:match_word* - The b:match_word variable is set to the pattern from |b:match_wholeBR| that - matches |b:match_match|. - *b:match_table* - The back reference '\'.d refers to the same thing as '\'.b:match_table[d] in - |b:match_word|. - - ============================================================================== - 5. Known Bugs and Limitations *matchit-bugs* - - Just because I know about a bug does not mean that it is on my todo list. I - try to respond to reports of bugs that cause real problems. If it does not - cause serious problems, or if there is a work-around, a bug may sit there for - a while. Moral: if a bug (known or not) bothers you, let me know. - - The various |:vmap|s defined in the script (%, |g%|, |[%|, |]%|, |a%|) may - have undesired effects in Select mode |Select-mode-mapping|. At least, if you - want to replace the selection with any character in "ag%[]" there will be a - pause of |'updatetime'| first. - - It would be nice if "\0" were recognized as the entire pattern. That is, it - would be nice if "foo:\end\0" had the same effect as "\(foo\):\end\1". I may - try to implement this in a future version. (This is not so easy to arrange as - you might think!) - - ============================================================================== - vim:tw=78:fo=tcq2: --- 0 ---- *** ../vim-7.4.1648/runtime/macros/README.txt 2010-05-15 13:04:01.000000000 +0200 --- runtime/macros/README.txt 2016-03-25 16:12:24.321009194 +0100 *************** *** 15,22 **** justify.vim user function for justifying text - matchit.vim + matchit.txt make % match if-fi, HTML tags, and much more - less.sh + less.vim make Vim work like less (or more) shellmenu.vim menus for editing shell scripts in the GUI version --- 15,20 ---- *************** *** 26,30 **** editexisting.vim when editing a file that is already edited with another Vim instance ! This one is only for Unix. It can be found in the extra archive: file_select.vim macros that make a handy file selector --- 24,32 ---- editexisting.vim when editing a file that is already edited with another Vim instance ! This one is only for Unix. file_select.vim macros that make a handy file selector + + The matchit plugin has been moved to an optional package. To load it put this + line in your vimrc file: + :packadd matchit *** ../vim-7.4.1648/src/Makefile 2016-03-21 22:39:58.621730166 +0100 --- src/Makefile 2016-03-25 16:45:49.580574189 +0100 *************** *** 130,135 **** --- 130,136 ---- # make installlinks only installs the Vim binary links # make installmanlinks only installs the Vim manpage links # make installmacros only installs the Vim macros + # make installpack only installs the packages # make installtutorbin only installs the Vim tutor program # make installtutor only installs the Vim tutor files # make installspell only installs the spell files *************** *** 1008,1013 **** --- 1009,1015 ---- COMPSUBDIR = /compiler KMAPSUBDIR = /keymap MACROSUBDIR = /macros + PACKSUBDIR = /pack TOOLSSUBDIR = /tools TUTORSUBDIR = /tutor SPELLSUBDIR = /spell *************** *** 1029,1034 **** --- 1031,1037 ---- ### COMPSUBLOC location for compiler files ### KMAPSUBLOC location for keymap files ### MACROSUBLOC location for macro files + ### PACKSUBLOC location for packages ### TOOLSSUBLOC location for tools files ### TUTORSUBLOC location for tutor files ### SPELLSUBLOC location for spell files *************** *** 1050,1055 **** --- 1053,1059 ---- COMPSUBLOC = $(VIMRTLOC)$(COMPSUBDIR) KMAPSUBLOC = $(VIMRTLOC)$(KMAPSUBDIR) MACROSUBLOC = $(VIMRTLOC)$(MACROSUBDIR) + PACKSUBLOC = $(VIMRTLOC)$(PACKSUBDIR) TOOLSSUBLOC = $(VIMRTLOC)$(TOOLSSUBDIR) TUTORSUBLOC = $(VIMRTLOC)$(TUTORSUBDIR) SPELLSUBLOC = $(VIMRTLOC)$(SPELLSUBDIR) *************** *** 1155,1160 **** --- 1159,1167 ---- # Where to copy the macro files from MACROSOURCE = ../runtime/macros + # Where to copy the package files from + PACKSOURCE = ../runtime/pack + # Where to copy the tools files from TOOLSSOURCE = ../runtime/tools *************** *** 1430,1435 **** --- 1437,1443 ---- DEST_COMP = $(DESTDIR)$(COMPSUBLOC) DEST_KMAP = $(DESTDIR)$(KMAPSUBLOC) DEST_MACRO = $(DESTDIR)$(MACROSUBLOC) + DEST_PACK = $(DESTDIR)$(PACKSUBLOC) DEST_TOOLS = $(DESTDIR)$(TOOLSSUBLOC) DEST_TUTOR = $(DESTDIR)$(TUTORSUBLOC) DEST_SPELL = $(DESTDIR)$(SPELLSUBLOC) *************** *** 2107,2113 **** $(VIMNAME) $(VIMDIFFNAME) $(EVIMNAME) # Install most of the runtime files ! installruntime: installrtbase installmacros installtutor installspell # install the help files; first adjust the contents for the final location installrtbase: $(HELPSOURCE)/vim.1 $(DEST_VIM) $(DEST_RT) \ --- 2115,2121 ---- $(VIMNAME) $(VIMDIFFNAME) $(EVIMNAME) # Install most of the runtime files ! installruntime: installrtbase installmacros installpack installtutor installspell # install the help files; first adjust the contents for the final location installrtbase: $(HELPSOURCE)/vim.1 $(DEST_VIM) $(DEST_RT) \ *************** *** 2206,2211 **** --- 2214,2224 ---- rm -rf $$cvs; \ fi + installpack: $(DEST_VIM) $(DEST_RT) $(DEST_PACK) + $(INSTALL_DATA_R) $(PACKSOURCE)/* $(DEST_PACK) + chmod $(DIRMOD) `find $(DEST_PACK) -type d -print` + chmod $(FILEMOD) `find $(DEST_PACK) -type f -print` + # install the tutor files installtutorbin: $(DEST_VIM) $(INSTALL_DATA) vimtutor $(DEST_BIN)/$(VIMNAME)tutor *************** *** 2355,2362 **** $(DESTDIR)$(exec_prefix) $(DEST_BIN) \ $(DEST_VIM) $(DEST_RT) $(DEST_HELP) \ $(DEST_PRINT) $(DEST_COL) $(DEST_SYN) $(DEST_IND) $(DEST_FTP) \ ! $(DEST_LANG) $(DEST_KMAP) $(DEST_COMP) \ ! $(DEST_MACRO) $(DEST_TOOLS) $(DEST_TUTOR) $(DEST_SPELL) \ $(DEST_AUTO) $(DEST_AUTO)/xml $(DEST_PLUG): -$(SHELL) ./mkinstalldirs $@ -chmod $(DIRMOD) $@ --- 2368,2375 ---- $(DESTDIR)$(exec_prefix) $(DEST_BIN) \ $(DEST_VIM) $(DEST_RT) $(DEST_HELP) \ $(DEST_PRINT) $(DEST_COL) $(DEST_SYN) $(DEST_IND) $(DEST_FTP) \ ! $(DEST_LANG) $(DEST_KMAP) $(DEST_COMP) $(DEST_MACRO) \ ! $(DEST_PACK) $(DEST_TOOLS) $(DEST_TUTOR) $(DEST_SPELL) \ $(DEST_AUTO) $(DEST_AUTO)/xml $(DEST_PLUG): -$(SHELL) ./mkinstalldirs $@ -chmod $(DIRMOD) $@ *************** *** 2501,2506 **** --- 2514,2520 ---- -rm -f $(DEST_SYN)/*.vim $(DEST_SYN)/README.txt -rm -f $(DEST_IND)/*.vim $(DEST_IND)/README.txt -rm -rf $(DEST_MACRO) + -rm -rf $(DEST_PACK) -rm -rf $(DEST_TUTOR) -rm -rf $(DEST_SPELL) -rm -rf $(DEST_TOOLS) *** ../vim-7.4.1648/runtime/pack/dist/opt/matchit/plugin/matchit.vim 1970-01-01 01:00:00.000000000 +0100 --- runtime/pack/dist/opt/matchit/plugin/matchit.vim 2015-07-23 21:05:08.080740828 +0200 *************** *** 0 **** --- 1,813 ---- + " matchit.vim: (global plugin) Extended "%" matching + " Last Change: Fri Jan 25 10:00 AM 2008 EST + " Maintainer: Benji Fisher PhD + " Version: 1.13.2, for Vim 6.3+ + " URL: http://www.vim.org/script.php?script_id=39 + + " Documentation: + " The documentation is in a separate file, matchit.txt . + + " Credits: + " Vim editor by Bram Moolenaar (Thanks, Bram!) + " Original script and design by Raul Segura Acevedo + " Support for comments by Douglas Potts + " Support for back references and other improvements by Benji Fisher + " Support for many languages by Johannes Zellner + " Suggestions for improvement, bug reports, and support for additional + " languages by Jordi-Albert Batalla, Neil Bird, Servatius Brandt, Mark + " Collett, Stephen Wall, Dany St-Amant, Yuheng Xie, and Johannes Zellner. + + " Debugging: + " If you'd like to try the built-in debugging commands... + " :MatchDebug to activate debugging for the current buffer + " This saves the values of several key script variables as buffer-local + " variables. See the MatchDebug() function, below, for details. + + " TODO: I should think about multi-line patterns for b:match_words. + " This would require an option: how many lines to scan (default 1). + " This would be useful for Python, maybe also for *ML. + " TODO: Maybe I should add a menu so that people will actually use some of + " the features that I have implemented. + " TODO: Eliminate the MultiMatch function. Add yet another argument to + " Match_wrapper() instead. + " TODO: Allow :let b:match_words = '\(\(foo\)\(bar\)\):\3\2:end\1' + " TODO: Make backrefs safer by using '\V' (very no-magic). + " TODO: Add a level of indirection, so that custom % scripts can use my + " work but extend it. + + " allow user to prevent loading + " and prevent duplicate loading + if exists("loaded_matchit") || &cp + finish + endif + let loaded_matchit = 1 + let s:last_mps = "" + let s:last_words = ":" + + let s:save_cpo = &cpo + set cpo&vim + + nnoremap % :call Match_wrapper('',1,'n') + nnoremap g% :call Match_wrapper('',0,'n') + vnoremap % :call Match_wrapper('',1,'v') m'gv`` + vnoremap g% :call Match_wrapper('',0,'v') m'gv`` + onoremap % v:call Match_wrapper('',1,'o') + onoremap g% v:call Match_wrapper('',0,'o') + + " Analogues of [{ and ]} using matching patterns: + nnoremap [% :call MultiMatch("bW", "n") + nnoremap ]% :call MultiMatch("W", "n") + vmap [% [%m'gv`` + vmap ]% ]%m'gv`` + " vnoremap [% :call MultiMatch("bW", "v") m'gv`` + " vnoremap ]% :call MultiMatch("W", "v") m'gv`` + onoremap [% v:call MultiMatch("bW", "o") + onoremap ]% v:call MultiMatch("W", "o") + + " text object: + vmap a% [%v]% + + " Auto-complete mappings: (not yet "ready for prime time") + " TODO Read :help write-plugin for the "right" way to let the user + " specify a key binding. + " let g:match_auto = '' + " let g:match_autoCR = '' + " if exists("g:match_auto") + " execute "inoremap " . g:match_auto . ' x"=Autocomplete()Pls' + " endif + " if exists("g:match_autoCR") + " execute "inoremap " . g:match_autoCR . ' =Autocomplete()' + " endif + " if exists("g:match_gthhoh") + " execute "inoremap " . g:match_gthhoh . ' :call Gthhoh()' + " endif " gthhoh = "Get the heck out of here!" + + let s:notslash = '\\\@" + endif + " In s:CleanUp(), we may need to check whether the cursor moved forward. + let startline = line(".") + let startcol = col(".") + " Use default behavior if called with a count. + if v:count + exe "normal! " . v:count . "%" + return s:CleanUp(restore_options, a:mode, startline, startcol) + end + + " First step: if not already done, set the script variables + " s:do_BR flag for whether there are backrefs + " s:pat parsed version of b:match_words + " s:all regexp based on s:pat and the default groups + " + if !exists("b:match_words") || b:match_words == "" + let match_words = "" + " Allow b:match_words = "GetVimMatchWords()" . + elseif b:match_words =~ ":" + let match_words = b:match_words + else + execute "let match_words =" b:match_words + endif + " Thanks to Preben "Peppe" Guldberg and Bram Moolenaar for this suggestion! + if (match_words != s:last_words) || (&mps != s:last_mps) || + \ exists("b:match_debug") + let s:last_words = match_words + let s:last_mps = &mps + " The next several lines were here before + " BF started messing with this script. + " quote the special chars in 'matchpairs', replace [,:] with \| and then + " append the builtin pairs (/*, */, #if, #ifdef, #else, #elif, #endif) + " let default = substitute(escape(&mps, '[$^.*~\\/?]'), '[,:]\+', + " \ '\\|', 'g').'\|\/\*\|\*\/\|#if\>\|#ifdef\>\|#else\>\|#elif\>\|#endif\>' + let default = escape(&mps, '[$^.*~\\/?]') . (strlen(&mps) ? "," : "") . + \ '\/\*:\*\/,#\s*if\%(def\)\=:#\s*else\>:#\s*elif\>:#\s*endif\>' + " s:all = pattern with all the keywords + let match_words = match_words . (strlen(match_words) ? "," : "") . default + if match_words !~ s:notslash . '\\\d' + let s:do_BR = 0 + let s:pat = match_words + else + let s:do_BR = 1 + let s:pat = s:ParseWords(match_words) + endif + let s:all = substitute(s:pat, s:notslash . '\zs[,:]\+', '\\|', 'g') + let s:all = '\%(' . s:all . '\)' + " let s:all = '\%(' . substitute(s:all, '\\\ze[,:]', '', 'g') . '\)' + if exists("b:match_debug") + let b:match_pat = s:pat + endif + endif + + " Second step: set the following local variables: + " matchline = line on which the cursor started + " curcol = number of characters before match + " prefix = regexp for start of line to start of match + " suffix = regexp for end of match to end of line + " Require match to end on or after the cursor and prefer it to + " start on or before the cursor. + let matchline = getline(startline) + if a:word != '' + " word given + if a:word !~ s:all + echohl WarningMsg|echo 'Missing rule for word:"'.a:word.'"'|echohl NONE + return s:CleanUp(restore_options, a:mode, startline, startcol) + endif + let matchline = a:word + let curcol = 0 + let prefix = '^\%(' + let suffix = '\)$' + " Now the case when "word" is not given + else " Find the match that ends on or after the cursor and set curcol. + let regexp = s:Wholematch(matchline, s:all, startcol-1) + let curcol = match(matchline, regexp) + " If there is no match, give up. + if curcol == -1 + return s:CleanUp(restore_options, a:mode, startline, startcol) + endif + let endcol = matchend(matchline, regexp) + let suf = strlen(matchline) - endcol + let prefix = (curcol ? '^.*\%' . (curcol + 1) . 'c\%(' : '^\%(') + let suffix = (suf ? '\)\%' . (endcol + 1) . 'c.*$' : '\)$') + endif + if exists("b:match_debug") + let b:match_match = matchstr(matchline, regexp) + let b:match_col = curcol+1 + endif + + " Third step: Find the group and single word that match, and the original + " (backref) versions of these. Then, resolve the backrefs. + " Set the following local variable: + " group = colon-separated list of patterns, one of which matches + " = ini:mid:fin or ini:fin + " + " Reconstruct the version with unresolved backrefs. + let patBR = substitute(match_words.',', + \ s:notslash.'\zs[,:]*,[,:]*', ',', 'g') + let patBR = substitute(patBR, s:notslash.'\zs:\{2,}', ':', 'g') + " Now, set group and groupBR to the matching group: 'if:endif' or + " 'while:endwhile' or whatever. A bit of a kluge: s:Choose() returns + " group . "," . groupBR, and we pick it apart. + let group = s:Choose(s:pat, matchline, ",", ":", prefix, suffix, patBR) + let i = matchend(group, s:notslash . ",") + let groupBR = strpart(group, i) + let group = strpart(group, 0, i-1) + " Now, matchline =~ prefix . substitute(group,':','\|','g') . suffix + if s:do_BR " Do the hard part: resolve those backrefs! + let group = s:InsertRefs(groupBR, prefix, group, suffix, matchline) + endif + if exists("b:match_debug") + let b:match_wholeBR = groupBR + let i = matchend(groupBR, s:notslash . ":") + let b:match_iniBR = strpart(groupBR, 0, i-1) + endif + + " Fourth step: Set the arguments for searchpair(). + let i = matchend(group, s:notslash . ":") + let j = matchend(group, '.*' . s:notslash . ":") + let ini = strpart(group, 0, i-1) + let mid = substitute(strpart(group, i,j-i-1), s:notslash.'\zs:', '\\|', 'g') + let fin = strpart(group, j) + "Un-escape the remaining , and : characters. + let ini = substitute(ini, s:notslash . '\zs\\\(:\|,\)', '\1', 'g') + let mid = substitute(mid, s:notslash . '\zs\\\(:\|,\)', '\1', 'g') + let fin = substitute(fin, s:notslash . '\zs\\\(:\|,\)', '\1', 'g') + " searchpair() requires that these patterns avoid \(\) groups. + let ini = substitute(ini, s:notslash . '\zs\\(', '\\%(', 'g') + let mid = substitute(mid, s:notslash . '\zs\\(', '\\%(', 'g') + let fin = substitute(fin, s:notslash . '\zs\\(', '\\%(', 'g') + " Set mid. This is optimized for readability, not micro-efficiency! + if a:forward && matchline =~ prefix . fin . suffix + \ || !a:forward && matchline =~ prefix . ini . suffix + let mid = "" + endif + " Set flag. This is optimized for readability, not micro-efficiency! + if a:forward && matchline =~ prefix . fin . suffix + \ || !a:forward && matchline !~ prefix . ini . suffix + let flag = "bW" + else + let flag = "W" + endif + " Set skip. + if exists("b:match_skip") + let skip = b:match_skip + elseif exists("b:match_comment") " backwards compatibility and testing! + let skip = "r:" . b:match_comment + else + let skip = 's:comment\|string' + endif + let skip = s:ParseSkip(skip) + if exists("b:match_debug") + let b:match_ini = ini + let b:match_tail = (strlen(mid) ? mid.'\|' : '') . fin + endif + + " Fifth step: actually start moving the cursor and call searchpair(). + " Later, :execute restore_cursor to get to the original screen. + let restore_cursor = virtcol(".") . "|" + normal! g0 + let restore_cursor = line(".") . "G" . virtcol(".") . "|zs" . restore_cursor + normal! H + let restore_cursor = "normal!" . line(".") . "Gzt" . restore_cursor + execute restore_cursor + call cursor(0, curcol + 1) + " normal! 0 + " if curcol + " execute "normal!" . curcol . "l" + " endif + if skip =~ 'synID' && !(has("syntax") && exists("g:syntax_on")) + let skip = "0" + else + execute "if " . skip . "| let skip = '0' | endif" + endif + let sp_return = searchpair(ini, mid, fin, flag, skip) + let final_position = "call cursor(" . line(".") . "," . col(".") . ")" + " Restore cursor position and original screen. + execute restore_cursor + normal! m' + if sp_return > 0 + execute final_position + endif + return s:CleanUp(restore_options, a:mode, startline, startcol, mid.'\|'.fin) + endfun + + " Restore options and do some special handling for Operator-pending mode. + " The optional argument is the tail of the matching group. + fun! s:CleanUp(options, mode, startline, startcol, ...) + execute "set" a:options + " Open folds, if appropriate. + if a:mode != "o" + if &foldopen =~ "percent" + normal! zv + endif + " In Operator-pending mode, we want to include the whole match + " (for example, d%). + " This is only a problem if we end up moving in the forward direction. + elseif (a:startline < line(".")) || + \ (a:startline == line(".") && a:startcol < col(".")) + if a:0 + " Check whether the match is a single character. If not, move to the + " end of the match. + let matchline = getline(".") + let currcol = col(".") + let regexp = s:Wholematch(matchline, a:1, currcol-1) + let endcol = matchend(matchline, regexp) + if endcol > currcol " This is NOT off by one! + call cursor(0, endcol) + endif + endif " a:0 + endif " a:mode != "o" && etc. + return 0 + endfun + + " Example (simplified HTML patterns): if + " a:groupBR = '<\(\k\+\)>:' + " a:prefix = '^.\{3}\(' + " a:group = '<\(\k\+\)>:' + " a:suffix = '\).\{2}$' + " a:matchline = "12312" or "12312" + " then extract "tag" from a:matchline and return ":" . + fun! s:InsertRefs(groupBR, prefix, group, suffix, matchline) + if a:matchline !~ a:prefix . + \ substitute(a:group, s:notslash . '\zs:', '\\|', 'g') . a:suffix + return a:group + endif + let i = matchend(a:groupBR, s:notslash . ':') + let ini = strpart(a:groupBR, 0, i-1) + let tailBR = strpart(a:groupBR, i) + let word = s:Choose(a:group, a:matchline, ":", "", a:prefix, a:suffix, + \ a:groupBR) + let i = matchend(word, s:notslash . ":") + let wordBR = strpart(word, i) + let word = strpart(word, 0, i-1) + " Now, a:matchline =~ a:prefix . word . a:suffix + if wordBR != ini + let table = s:Resolve(ini, wordBR, "table") + else + " let table = "----------" + let table = "" + let d = 0 + while d < 10 + if tailBR =~ s:notslash . '\\' . d + " let table[d] = d + let table = table . d + else + let table = table . "-" + endif + let d = d + 1 + endwhile + endif + let d = 9 + while d + if table[d] != "-" + let backref = substitute(a:matchline, a:prefix.word.a:suffix, + \ '\'.table[d], "") + " Are there any other characters that should be escaped? + let backref = escape(backref, '*,:') + execute s:Ref(ini, d, "start", "len") + let ini = strpart(ini, 0, start) . backref . strpart(ini, start+len) + let tailBR = substitute(tailBR, s:notslash . '\zs\\' . d, + \ escape(backref, '\\&'), 'g') + endif + let d = d-1 + endwhile + if exists("b:match_debug") + if s:do_BR + let b:match_table = table + let b:match_word = word + else + let b:match_table = "" + let b:match_word = "" + endif + endif + return ini . ":" . tailBR + endfun + + " Input a comma-separated list of groups with backrefs, such as + " a:groups = '\(foo\):end\1,\(bar\):end\1' + " and return a comma-separated list of groups with backrefs replaced: + " return '\(foo\):end\(foo\),\(bar\):end\(bar\)' + fun! s:ParseWords(groups) + let groups = substitute(a:groups.",", s:notslash.'\zs[,:]*,[,:]*', ',', 'g') + let groups = substitute(groups, s:notslash . '\zs:\{2,}', ':', 'g') + let parsed = "" + while groups =~ '[^,:]' + let i = matchend(groups, s:notslash . ':') + let j = matchend(groups, s:notslash . ',') + let ini = strpart(groups, 0, i-1) + let tail = strpart(groups, i, j-i-1) . ":" + let groups = strpart(groups, j) + let parsed = parsed . ini + let i = matchend(tail, s:notslash . ':') + while i != -1 + " In 'if:else:endif', ini='if' and word='else' and then word='endif'. + let word = strpart(tail, 0, i-1) + let tail = strpart(tail, i) + let i = matchend(tail, s:notslash . ':') + let parsed = parsed . ":" . s:Resolve(ini, word, "word") + endwhile " Now, tail has been used up. + let parsed = parsed . "," + endwhile " groups =~ '[^,:]' + let parsed = substitute(parsed, ',$', '', '') + return parsed + endfun + + " TODO I think this can be simplified and/or made more efficient. + " TODO What should I do if a:start is out of range? + " Return a regexp that matches all of a:string, such that + " matchstr(a:string, regexp) represents the match for a:pat that starts + " as close to a:start as possible, before being preferred to after, and + " ends after a:start . + " Usage: + " let regexp = s:Wholematch(getline("."), 'foo\|bar', col(".")-1) + " let i = match(getline("."), regexp) + " let j = matchend(getline("."), regexp) + " let match = matchstr(getline("."), regexp) + fun! s:Wholematch(string, pat, start) + let group = '\%(' . a:pat . '\)' + let prefix = (a:start ? '\(^.*\%<' . (a:start + 2) . 'c\)\zs' : '^') + let len = strlen(a:string) + let suffix = (a:start+1 < len ? '\(\%>'.(a:start+1).'c.*$\)\@=' : '$') + if a:string !~ prefix . group . suffix + let prefix = '' + endif + return prefix . group . suffix + endfun + + " No extra arguments: s:Ref(string, d) will + " find the d'th occurrence of '\(' and return it, along with everything up + " to and including the matching '\)'. + " One argument: s:Ref(string, d, "start") returns the index of the start + " of the d'th '\(' and any other argument returns the length of the group. + " Two arguments: s:Ref(string, d, "foo", "bar") returns a string to be + " executed, having the effect of + " :let foo = s:Ref(string, d, "start") + " :let bar = s:Ref(string, d, "len") + fun! s:Ref(string, d, ...) + let len = strlen(a:string) + if a:d == 0 + let start = 0 + else + let cnt = a:d + let match = a:string + while cnt + let cnt = cnt - 1 + let index = matchend(match, s:notslash . '\\(') + if index == -1 + return "" + endif + let match = strpart(match, index) + endwhile + let start = len - strlen(match) + if a:0 == 1 && a:1 == "start" + return start - 2 + endif + let cnt = 1 + while cnt + let index = matchend(match, s:notslash . '\\(\|\\)') - 1 + if index == -2 + return "" + endif + " Increment if an open, decrement if a ')': + let cnt = cnt + (match[index]=="(" ? 1 : -1) " ')' + " let cnt = stridx('0(', match[index]) + cnt + let match = strpart(match, index+1) + endwhile + let start = start - 2 + let len = len - start - strlen(match) + endif + if a:0 == 1 + return len + elseif a:0 == 2 + return "let " . a:1 . "=" . start . "| let " . a:2 . "=" . len + else + return strpart(a:string, start, len) + endif + endfun + + " Count the number of disjoint copies of pattern in string. + " If the pattern is a literal string and contains no '0' or '1' characters + " then s:Count(string, pattern, '0', '1') should be faster than + " s:Count(string, pattern). + fun! s:Count(string, pattern, ...) + let pat = escape(a:pattern, '\\') + if a:0 > 1 + let foo = substitute(a:string, '[^'.a:pattern.']', "a:1", "g") + let foo = substitute(a:string, pat, a:2, "g") + let foo = substitute(foo, '[^' . a:2 . ']', "", "g") + return strlen(foo) + endif + let result = 0 + let foo = a:string + let index = matchend(foo, pat) + while index != -1 + let result = result + 1 + let foo = strpart(foo, index) + let index = matchend(foo, pat) + endwhile + return result + endfun + + " s:Resolve('\(a\)\(b\)', '\(c\)\2\1\1\2') should return table.word, where + " word = '\(c\)\(b\)\(a\)\3\2' and table = '-32-------'. That is, the first + " '\1' in target is replaced by '\(a\)' in word, table[1] = 3, and this + " indicates that all other instances of '\1' in target are to be replaced + " by '\3'. The hard part is dealing with nesting... + " Note that ":" is an illegal character for source and target, + " unless it is preceded by "\". + fun! s:Resolve(source, target, output) + let word = a:target + let i = matchend(word, s:notslash . '\\\d') - 1 + let table = "----------" + while i != -2 " There are back references to be replaced. + let d = word[i] + let backref = s:Ref(a:source, d) + " The idea is to replace '\d' with backref. Before we do this, + " replace any \(\) groups in backref with :1, :2, ... if they + " correspond to the first, second, ... group already inserted + " into backref. Later, replace :1 with \1 and so on. The group + " number w+b within backref corresponds to the group number + " s within a:source. + " w = number of '\(' in word before the current one + let w = s:Count( + \ substitute(strpart(word, 0, i-1), '\\\\', '', 'g'), '\(', '1') + let b = 1 " number of the current '\(' in backref + let s = d " number of the current '\(' in a:source + while b <= s:Count(substitute(backref, '\\\\', '', 'g'), '\(', '1') + \ && s < 10 + if table[s] == "-" + if w + b < 10 + " let table[s] = w + b + let table = strpart(table, 0, s) . (w+b) . strpart(table, s+1) + endif + let b = b + 1 + let s = s + 1 + else + execute s:Ref(backref, b, "start", "len") + let ref = strpart(backref, start, len) + let backref = strpart(backref, 0, start) . ":". table[s] + \ . strpart(backref, start+len) + let s = s + s:Count(substitute(ref, '\\\\', '', 'g'), '\(', '1') + endif + endwhile + let word = strpart(word, 0, i-1) . backref . strpart(word, i+1) + let i = matchend(word, s:notslash . '\\\d') - 1 + endwhile + let word = substitute(word, s:notslash . '\zs:', '\\', 'g') + if a:output == "table" + return table + elseif a:output == "word" + return word + else + return table . word + endif + endfun + + " Assume a:comma = ",". Then the format for a:patterns and a:1 is + " a:patterns = ",,..." + " a:1 = ",,..." + " If is the first pattern that matches a:string then return + " if no optional arguments are given; return , if a:1 is given. + fun! s:Choose(patterns, string, comma, branch, prefix, suffix, ...) + let tail = (a:patterns =~ a:comma."$" ? a:patterns : a:patterns . a:comma) + let i = matchend(tail, s:notslash . a:comma) + if a:0 + let alttail = (a:1 =~ a:comma."$" ? a:1 : a:1 . a:comma) + let j = matchend(alttail, s:notslash . a:comma) + endif + let current = strpart(tail, 0, i-1) + if a:branch == "" + let currpat = current + else + let currpat = substitute(current, s:notslash . a:branch, '\\|', 'g') + endif + while a:string !~ a:prefix . currpat . a:suffix + let tail = strpart(tail, i) + let i = matchend(tail, s:notslash . a:comma) + if i == -1 + return -1 + endif + let current = strpart(tail, 0, i-1) + if a:branch == "" + let currpat = current + else + let currpat = substitute(current, s:notslash . a:branch, '\\|', 'g') + endif + if a:0 + let alttail = strpart(alttail, j) + let j = matchend(alttail, s:notslash . a:comma) + endif + endwhile + if a:0 + let current = current . a:comma . strpart(alttail, 0, j-1) + endif + return current + endfun + + " Call this function to turn on debugging information. Every time the main + " script is run, buffer variables will be saved. These can be used directly + " or viewed using the menu items below. + if !exists(":MatchDebug") + command! -nargs=0 MatchDebug call s:Match_debug() + endif + + fun! s:Match_debug() + let b:match_debug = 1 " Save debugging information. + " pat = all of b:match_words with backrefs parsed + amenu &Matchit.&pat :echo b:match_pat + " match = bit of text that is recognized as a match + amenu &Matchit.&match :echo b:match_match + " curcol = cursor column of the start of the matching text + amenu &Matchit.&curcol :echo b:match_col + " wholeBR = matching group, original version + amenu &Matchit.wh&oleBR :echo b:match_wholeBR + " iniBR = 'if' piece, original version + amenu &Matchit.ini&BR :echo b:match_iniBR + " ini = 'if' piece, with all backrefs resolved from match + amenu &Matchit.&ini :echo b:match_ini + " tail = 'else\|endif' piece, with all backrefs resolved from match + amenu &Matchit.&tail :echo b:match_tail + " fin = 'endif' piece, with all backrefs resolved from match + amenu &Matchit.&word :echo b:match_word + " '\'.d in ini refers to the same thing as '\'.table[d] in word. + amenu &Matchit.t&able :echo '0:' . b:match_table . ':9' + endfun + + " Jump to the nearest unmatched "(" or "if" or "" if a:spflag == "bW" + " or the nearest unmatched "" or "endif" or ")" if a:spflag == "W". + " Return a "mark" for the original position, so that + " let m = MultiMatch("bW", "n") ... execute m + " will return to the original position. If there is a problem, do not + " move the cursor and return "", unless a count is given, in which case + " go up or down as many levels as possible and again return "". + " TODO This relies on the same patterns as % matching. It might be a good + " idea to give it its own matching patterns. + fun! s:MultiMatch(spflag, mode) + if !exists("b:match_words") || b:match_words == "" + return "" + end + let restore_options = (&ic ? "" : "no") . "ignorecase" + if exists("b:match_ignorecase") + let &ignorecase = b:match_ignorecase + endif + let startline = line(".") + let startcol = col(".") + + " First step: if not already done, set the script variables + " s:do_BR flag for whether there are backrefs + " s:pat parsed version of b:match_words + " s:all regexp based on s:pat and the default groups + " This part is copied and slightly modified from s:Match_wrapper(). + let default = escape(&mps, '[$^.*~\\/?]') . (strlen(&mps) ? "," : "") . + \ '\/\*:\*\/,#\s*if\%(def\)\=:#\s*else\>:#\s*elif\>:#\s*endif\>' + " Allow b:match_words = "GetVimMatchWords()" . + if b:match_words =~ ":" + let match_words = b:match_words + else + execute "let match_words =" b:match_words + endif + if (match_words != s:last_words) || (&mps != s:last_mps) || + \ exists("b:match_debug") + let s:last_words = match_words + let s:last_mps = &mps + if match_words !~ s:notslash . '\\\d' + let s:do_BR = 0 + let s:pat = match_words + else + let s:do_BR = 1 + let s:pat = s:ParseWords(match_words) + endif + let s:all = '\%(' . substitute(s:pat . (strlen(s:pat)?",":"") . default, + \ '[,:]\+','\\|','g') . '\)' + if exists("b:match_debug") + let b:match_pat = s:pat + endif + endif + + " Second step: figure out the patterns for searchpair() + " and save the screen, cursor position, and 'ignorecase'. + " - TODO: A lot of this is copied from s:Match_wrapper(). + " - maybe even more functionality should be split off + " - into separate functions! + let cdefault = (s:pat =~ '[^,]$' ? "," : "") . default + let open = substitute(s:pat . cdefault, + \ s:notslash . '\zs:.\{-}' . s:notslash . ',', '\\),\\(', 'g') + let open = '\(' . substitute(open, s:notslash . '\zs:.*$', '\\)', '') + let close = substitute(s:pat . cdefault, + \ s:notslash . '\zs,.\{-}' . s:notslash . ':', '\\),\\(', 'g') + let close = substitute(close, '^.\{-}' . s:notslash . ':', '\\(', '') . '\)' + if exists("b:match_skip") + let skip = b:match_skip + elseif exists("b:match_comment") " backwards compatibility and testing! + let skip = "r:" . b:match_comment + else + let skip = 's:comment\|string' + endif + let skip = s:ParseSkip(skip) + " let restore_cursor = line(".") . "G" . virtcol(".") . "|" + " normal! H + " let restore_cursor = "normal!" . line(".") . "Gzt" . restore_cursor + let restore_cursor = virtcol(".") . "|" + normal! g0 + let restore_cursor = line(".") . "G" . virtcol(".") . "|zs" . restore_cursor + normal! H + let restore_cursor = "normal!" . line(".") . "Gzt" . restore_cursor + execute restore_cursor + + " Third step: call searchpair(). + " Replace '\('--but not '\\('--with '\%(' and ',' with '\|'. + let openpat = substitute(open, '\(\\\@" or ... + " and return "endif" or "endwhile" or "" or ... . + " For now, this uses b:match_words and the same script variables + " as s:Match_wrapper() . Later, it may get its own patterns, + " either from a buffer variable or passed as arguments. + " fun! s:Autocomplete() + " echo "autocomplete not yet implemented :-(" + " if !exists("b:match_words") || b:match_words == "" + " return "" + " end + " let startpos = s:MultiMatch("bW") + " + " if startpos == "" + " return "" + " endif + " " - TODO: figure out whether 'if' or '' matched, and construct + " " - the appropriate closing. + " let matchline = getline(".") + " let curcol = col(".") - 1 + " " - TODO: Change the s:all argument if there is a new set of match pats. + " let regexp = s:Wholematch(matchline, s:all, curcol) + " let suf = strlen(matchline) - matchend(matchline, regexp) + " let prefix = (curcol ? '^.\{' . curcol . '}\%(' : '^\%(') + " let suffix = (suf ? '\).\{' . suf . '}$' : '\)$') + " " Reconstruct the version with unresolved backrefs. + " let patBR = substitute(b:match_words.',', '[,:]*,[,:]*', ',', 'g') + " let patBR = substitute(patBR, ':\{2,}', ':', "g") + " " Now, set group and groupBR to the matching group: 'if:endif' or + " " 'while:endwhile' or whatever. + " let group = s:Choose(s:pat, matchline, ",", ":", prefix, suffix, patBR) + " let i = matchend(group, s:notslash . ",") + " let groupBR = strpart(group, i) + " let group = strpart(group, 0, i-1) + " " Now, matchline =~ prefix . substitute(group,':','\|','g') . suffix + " if s:do_BR + " let group = s:InsertRefs(groupBR, prefix, group, suffix, matchline) + " endif + " " let g:group = group + " + " " - TODO: Construct the closing from group. + " let fake = "end" . expand("") + " execute startpos + " return fake + " endfun + + " Close all open structures. "Get the heck out of here!" + " fun! s:Gthhoh() + " let close = s:Autocomplete() + " while strlen(close) + " put=close + " let close = s:Autocomplete() + " endwhile + " endfun + + " Parse special strings as typical skip arguments for searchpair(): + " s:foo becomes (current syntax item) =~ foo + " S:foo becomes (current syntax item) !~ foo + " r:foo becomes (line before cursor) =~ foo + " R:foo becomes (line before cursor) !~ foo + fun! s:ParseSkip(str) + let skip = a:str + if skip[1] == ":" + if skip[0] == "s" + let skip = "synIDattr(synID(line('.'),col('.'),1),'name') =~? '" . + \ strpart(skip,2) . "'" + elseif skip[0] == "S" + let skip = "synIDattr(synID(line('.'),col('.'),1),'name') !~? '" . + \ strpart(skip,2) . "'" + elseif skip[0] == "r" + let skip = "strpart(getline('.'),0,col('.'))=~'" . strpart(skip,2). "'" + elseif skip[0] == "R" + let skip = "strpart(getline('.'),0,col('.'))!~'" . strpart(skip,2). "'" + endif + endif + return skip + endfun + + let &cpo = s:save_cpo + unlet s:save_cpo + + " vim:sts=2:sw=2: *** ../vim-7.4.1648/runtime/pack/dist/opt/matchit/doc/matchit.txt 1970-01-01 01:00:00.000000000 +0100 --- runtime/pack/dist/opt/matchit/doc/matchit.txt 2010-05-15 13:04:01.000000000 +0200 *************** *** 0 **** --- 1,406 ---- + *matchit.txt* Extended "%" matching + + For instructions on installing this file, type + :help matchit-install + inside Vim. + + For Vim version 6.3. Last change: 2007 Aug 29 + + + VIM REFERENCE MANUAL by Benji Fisher + + *matchit* *matchit.vim* + + 1. Extended matching with "%" |matchit-intro| + 2. Activation |matchit-activate| + 3. Configuration |matchit-configure| + 4. Supporting a New Language |matchit-newlang| + 5. Known Bugs and Limitations |matchit-bugs| + + The functionality mentioned here is a plugin, see |add-plugin|. + This plugin is only available if 'compatible' is not set. + You can avoid loading this plugin by setting the "loaded_matchit" variable + in your |vimrc| file: > + :let loaded_matchit = 1 + + {Vi does not have any of this} + + ============================================================================== + 1. Extended matching with "%" *matchit-intro* + + *matchit-%* + % Cycle forward through matching groups, such as "if", "else", "endif", + as specified by |b:match_words|. + + *g%* *v_g%* *o_g%* + g% Cycle backwards through matching groups, as specified by + |b:match_words|. For example, go from "if" to "endif" to "else". + + *[%* *v_[%* *o_[%* + [% Go to [count] previous unmatched group, as specified by + |b:match_words|. Similar to |[{|. + + *]%* *v_]%* *o_]%* + ]% Go to [count] next unmatched group, as specified by + |b:match_words|. Similar to |]}|. + + *v_a%* + a% In Visual mode, select the matching group, as specified by + |b:match_words|, containing the cursor. Similar to |v_a[|. + A [count] is ignored, and only the first character of the closing + pattern is selected. + + In Vim, as in plain vi, the percent key, |%|, jumps the cursor from a brace, + bracket, or paren to its match. This can be configured with the 'matchpairs' + option. The matchit plugin extends this in several ways: + + You can match whole words, such as "if" and "endif", not just + single characters. You can also specify a |regular-expression|. + You can define groups with more than two words, such as "if", + "else", "endif". Banging on the "%" key will cycle from the "if" to + the first "else", the next "else", ..., the closing "endif", and back + to the opening "if". Nested structures are skipped. Using |g%| goes + in the reverse direction. + By default, words inside comments and strings are ignored, unless + the cursor is inside a comment or string when you type "%". If the + only thing you want to do is modify the behavior of "%" so that it + behaves this way, you do not have to define |b:match_words|, since the + script uses the 'matchpairs' option as well as this variable. + + See |matchit-details| for details on what the script does, and |b:match_words| + for how to specify matching patterns. + + MODES: *matchit-modes* *matchit-v_%* *matchit-o_%* + + Mostly, % and related motions (|g%| and |[%| and |]%|) work just like built-in + |motion| commands in |Operator-pending| and |Visual| modes. However, you + cannot make these motions |linewise| or |characterwise|, since the |:omap|s + that define them start with "v" in order to make the default behavior + inclusive. (See |o_v|.) In other words, "dV%" will not work. The + work-around is to go through Visual mode: "V%d" will work. + + LANGUAGES: *matchit-languages* + + Currently, the following languages are supported: Ada, ASP with VBS, Csh, + DTD, Entity, Essbase, Fortran, HTML, JSP (same as HTML), LaTeX, Lua, Pascal, + SGML, Shell, Tcsh, Vim, XML. Other languages may already have support via + the default |filetype-plugin|s in the standard vim distribution. + + To support a new language, see |matchit-newlang| below. + + DETAILS: *matchit-details* *matchit-parse* + + Here is an outline of what matchit.vim does each time you hit the "%" key. If + there are |backref|s in |b:match_words| then the first step is to produce a + version in which these back references have been eliminated; if there are no + |backref|s then this step is skipped. This step is called parsing. For + example, "\(foo\|bar\):end\1" is parsed to yield + "\(foo\|bar\):end\(foo\|bar\)". This can get tricky, especially if there are + nested groups. If debugging is turned on, the parsed version is saved as + |b:match_pat|. + + *matchit-choose* + Next, the script looks for a word on the current line that matches the pattern + just constructed. It includes the patterns from the 'matchpairs' option. + The goal is to do what you expect, which turns out to be a little complicated. + The script follows these rules: + + Insist on a match that ends on or after the cursor. + Prefer a match that includes the cursor position (that is, one that + starts on or before the cursor). + Prefer a match that starts as close to the cursor as possible. + If more than one pattern in |b:match_words| matches, choose the one + that is listed first. + + Examples: + + Suppose you > + :let b:match_words = '<:>,:' + < and hit "%" with the cursor on or before the "<" in "a is born". + The pattern '<' comes first, so it is preferred over '', which + also matches. If the cursor is on the "t", however, then '' is + preferred, because this matches a bit of text containing the cursor. + If the two groups of patterns were reversed then '<' would never be + preferred. + + Suppose you > + :let b:match_words = 'if:end if' + < (Note the space!) and hit "%" with the cursor at the end of "end if". + Then "if" matches, which is probably not what you want, but if the + cursor starts on the "end " then "end if" is chosen. (You can avoid + this problem by using a more complicated pattern.) + + If there is no match, the cursor does not move. (Before version 1.13 of the + script, it would fall back on the usual behavior of |%|). If debugging is + turned on, the matched bit of text is saved as |b:match_match| and the cursor + column of the start of the match is saved as |b:match_col|. + + Next, the script looks through |b:match_words| (original and parsed versions) + for the group and pattern that match. If debugging is turned on, the group is + saved as |b:match_ini| (the first pattern) and |b:match_tail| (the rest). If + there are |backref|s then, in addition, the matching pattern is saved as + |b:match_word| and a table of translations is saved as |b:match_table|. If + there are |backref|s, these are determined from the matching pattern and + |b:match_match| and substituted into each pattern in the matching group. + + The script decides whether to search forwards or backwards and chooses + arguments for the |searchpair()| function. Then, the cursor is moved to the + start of the match, and |searchpair()| is called. By default, matching + structures inside strings and comments are ignored. This can be changed by + setting |b:match_skip|. + + ============================================================================== + 2. Activation *matchit-activate* + + You can use this script as a plugin, by copying it to your plugin directory. + See |add-global-plugin| for instructions. You can also add a line to your + |vimrc| file, such as > + :source $VIMRUNTIME/macros/matchit.vim + or > + :runtime macros/matchit.vim + Either way, the script should start working the next time you start up Vim. + + (Earlier versions of the script did nothing unless a |buffer-variable| named + |b:match_words| was defined. Even earlier versions contained autocommands + that set this variable for various file types. Now, |b:match_words| is + defined in many of the default |filetype-plugin|s instead.) + + For a new language, you can add autocommands to the script or to your vimrc + file, but the recommended method is to add a line such as > + let b:match_words = '\:\' + to the |filetype-plugin| for your language. See |b:match_words| below for how + this variable is interpreted. + + TROUBLESHOOTING *matchit-troubleshoot* + + The script should work in most installations of Vim. It may not work if Vim + was compiled with a minimal feature set, for example if the |+syntax| option + was not enabled. If your Vim has support for syntax compiled in, but you do + not have |syntax| highlighting turned on, matchit.vim should work, but it may + fail to skip matching groups in comments and strings. If the |filetype| + mechanism is turned off, the |b:match_words| variable will probably not be + defined automatically. + + ============================================================================== + 3. Configuration *matchit-configure* + + There are several variables that govern the behavior of matchit.vim. Note + that these are variables local to the buffer, not options, so use |:let| to + define them, not |:set|. Some of these variables have values that matter; for + others, it only matters whether the variable has been defined. All of these + can be defined in the |filetype-plugin| or autocommand that defines + |b:match_words| or "on the fly." + + The main variable is |b:match_words|. It is described in the section below on + supporting a new language. + + *MatchError* *matchit-hl* *matchit-highlight* + MatchError is the highlight group for error messages from the script. By + default, it is linked to WarningMsg. If you do not want to be bothered by + error messages, you can define this to be something invisible. For example, + if you use the GUI version of Vim and your command line is normally white, you + can do > + :hi MatchError guifg=white guibg=white + < + *b:match_ignorecase* + If you > + :let b:match_ignorecase = 1 + then matchit.vim acts as if 'ignorecase' is set: for example, "end" and "END" + are equivalent. If you > + :let b:match_ignorecase = 0 + then matchit.vim treats "end" and "END" differently. (There will be no + b:match_infercase option unless someone requests it.) + + *b:match_debug* + Define b:match_debug if you want debugging information to be saved. See + |matchit-debug|, below. + + *b:match_skip* + If b:match_skip is defined, it is passed as the skip argument to + |searchpair()|. This controls when matching structures are skipped, or + ignored. By default, they are ignored inside comments and strings, as + determined by the |syntax| mechanism. (If syntax highlighting is turned off, + nothing is skipped.) You can set b:match_skip to a string, which evaluates to + a non-zero, numerical value if the match is to be skipped or zero if the match + should not be skipped. In addition, the following special values are + supported by matchit.vim: + s:foo becomes (current syntax item) =~ foo + S:foo becomes (current syntax item) !~ foo + r:foo becomes (line before cursor) =~ foo + R:foo becomes (line before cursor) !~ foo + (The "s" is meant to suggest "syntax", and the "r" is meant to suggest + "regular expression".) + + Examples: + + You can get the default behavior with > + :let b:match_skip = 's:comment\|string' + < + If you want to skip matching structures unless they are at the start + of the line (ignoring whitespace) then you can > + :let b:match_skip = 'R:^\s*' + < Do not do this if strings or comments can span several lines, since + the normal syntax checking will not be done if you set b:match_skip. + + In LaTeX, since "%" is used as the comment character, you can > + :let b:match_skip = 'r:%' + < Unfortunately, this will skip anything after "\%", an escaped "%". To + allow for this, and also "\\%" (an excaped backslash followed by the + comment character) you can > + :let b:match_skip = 'r:\(^\|[^\\]\)\(\\\\\)*%' + < + See the $VIMRUNTIME/ftplugin/vim.vim for an example that uses both + syntax and a regular expression. + + ============================================================================== + 4. Supporting a New Language *matchit-newlang* + *b:match_words* + In order for matchit.vim to support a new language, you must define a suitable + pattern for |b:match_words|. You may also want to set some of the + |matchit-configure| variables, as described above. If your language has a + complicated syntax, or many keywords, you will need to know something about + Vim's |regular-expression|s. + + The format for |b:match_words| is similar to that of the 'matchpairs' option: + it is a comma (,)-separated list of groups; each group is a colon(:)-separated + list of patterns (regular expressions). Commas and backslashes that are part + of a pattern should be escaped with backslashes ('\:' and '\,'). It is OK to + have only one group; the effect is undefined if a group has only one pattern. + A simple example is > + :let b:match_words = '\:\,' + \ . '\:\:\:\' + (In Vim regular expressions, |\<| and |\>| denote word boundaries. Thus "if" + matches the end of "endif" but "\" does not.) Then banging on the "%" + key will bounce the cursor between "if" and the matching "endif"; and from + "while" to any matching "continue" or "break", then to the matching "endwhile" + and back to the "while". It is almost always easier to use |literal-string|s + (single quotes) as above: '\' rather than "\\" and so on. + + Exception: If the ":" character does not appear in b:match_words, then it is + treated as an expression to be evaluated. For example, > + :let b:match_words = 'GetMatchWords()' + allows you to define a function. This can return a different string depending + on the current syntax, for example. + + Once you have defined the appropriate value of |b:match_words|, you will + probably want to have this set automatically each time you edit the + appropriate file type. The recommended way to do this is by adding the + definition to a |filetype-plugin| file. + + Tips: Be careful that your initial pattern does not match your final pattern. + See the example above for the use of word-boundary expressions. It is usually + better to use ".\{-}" (as many as necessary) instead of ".*" (as many as + possible). See |\{-|. For example, in the string "label", "<.*>" + matches the whole string whereas "<.\{-}>" and "<[^>]*>" match "" and + "". + + *matchit-spaces* *matchit-s:notend* + If "if" is to be paired with "end if" (Note the space!) then word boundaries + are not enough. Instead, define a regular expression s:notend that will match + anything but "end" and use it as follows: > + :let s:notend = '\%(\:\' + < *matchit-s:sol* + This is a simplified version of what is done for Ada. The s:notend is a + |script-variable|. Similarly, you may want to define a start-of-line regular + expression > + :let s:sol = '\%(^\|;\)\s*' + if keywords are only recognized after the start of a line or after a + semicolon (;), with optional white space. + + *matchit-backref* *matchit-\1* + In any group, the expressions |\1|, |\2|, ..., |\9| refer to parts of the + INITIAL pattern enclosed in |\(|escaped parentheses|\)|. These are referred + to as back references, or backrefs. For example, > + :let b:match_words = '\:\(h\)\1\>' + means that "bo" pairs with "ho" and "boo" pairs with "hoo" and so on. Note + that "\1" does not refer to the "\(h\)" in this example. If you have + "\(nested \(parentheses\)\) then "\d" refers to the d-th "\(" and everything + up to and including the matching "\)": in "\(nested\(parentheses\)\)", "\1" + refers to everything and "\2" refers to "\(parentheses\)". If you use a + variable such as |s:notend| or |s:sol| in the previous paragraph then remember + to count any "\(" patterns in this variable. You do not have to count groups + defined by |\%(\)|. + + It should be possible to resolve back references from any pattern in the + group. For example, > + :let b:match_words = '\(foo\)\(bar\):more\1:and\2:end\1\2' + would not work because "\2" cannot be determined from "morefoo" and "\1" + cannot be determined from "andbar". On the other hand, > + :let b:match_words = '\(\(foo\)\(bar\)\):\3\2:end\1' + should work (and have the same effect as "foobar:barfoo:endfoobar"), although + this has not been thoroughly tested. + + You can use |zero-width| patterns such as |\@<=| and |\zs|. (The latter has + not been thouroughly tested in matchit.vim.) For example, if the keyword "if" + must occur at the start of the line, with optional white space, you might use + the pattern "\(^\s*\)\@<=if" so that the cursor will end on the "i" instead of + at the start of the line. For another example, if HTML had only one tag then + one could > + :let b:match_words = '<:>,<\@<=tag>:<\@<=/tag>' + so that "%" can bounce between matching "<" and ">" pairs or (starting on + "tag" or "/tag") between matching tags. Without the |\@<=|, the script would + bounce from "tag" to the "<" in "", and another "%" would not take you + back to where you started. + + DEBUGGING *matchit-debug* *:MatchDebug* + + If you are having trouble figuring out the appropriate definition of + |b:match_words| then you can take advantage of the same information I use when + debugging the script. This is especially true if you are not sure whether + your patterns or my script are at fault! To make this more convenient, I have + made the command :MatchDebug, which defines the variable |b:match_debug| and + creates a Matchit menu. This menu makes it convenient to check the values of + the variables described below. You will probably also want to read + |matchit-details| above. + + Defining the variable |b:match_debug| causes the script to set the following + variables, each time you hit the "%" key. Several of these are only defined + if |b:match_words| includes |backref|s. + + *b:match_pat* + The b:match_pat variable is set to |b:match_words| with |backref|s parsed. + *b:match_match* + The b:match_match variable is set to the bit of text that is recognized as a + match. + *b:match_col* + The b:match_col variable is set to the cursor column of the start of the + matching text. + *b:match_wholeBR* + The b:match_wholeBR variable is set to the comma-separated group of patterns + that matches, with |backref|s unparsed. + *b:match_iniBR* + The b:match_iniBR variable is set to the first pattern in |b:match_wholeBR|. + *b:match_ini* + The b:match_ini variable is set to the first pattern in |b:match_wholeBR|, + with |backref|s resolved from |b:match_match|. + *b:match_tail* + The b:match_tail variable is set to the remaining patterns in + |b:match_wholeBR|, with |backref|s resolved from |b:match_match|. + *b:match_word* + The b:match_word variable is set to the pattern from |b:match_wholeBR| that + matches |b:match_match|. + *b:match_table* + The back reference '\'.d refers to the same thing as '\'.b:match_table[d] in + |b:match_word|. + + ============================================================================== + 5. Known Bugs and Limitations *matchit-bugs* + + Just because I know about a bug does not mean that it is on my todo list. I + try to respond to reports of bugs that cause real problems. If it does not + cause serious problems, or if there is a work-around, a bug may sit there for + a while. Moral: if a bug (known or not) bothers you, let me know. + + The various |:vmap|s defined in the script (%, |g%|, |[%|, |]%|, |a%|) may + have undesired effects in Select mode |Select-mode-mapping|. At least, if you + want to replace the selection with any character in "ag%[]" there will be a + pause of |'updatetime'| first. + + It would be nice if "\0" were recognized as the entire pattern. That is, it + would be nice if "foo:\end\0" had the same effect as "\(foo\):\end\1". I may + try to implement this in a future version. (This is not so easy to arrange as + you might think!) + + ============================================================================== + vim:tw=78:fo=tcq2: *** ../vim-7.4.1648/runtime/pack/dist/opt/matchit/doc/tags 1970-01-01 01:00:00.000000000 +0100 --- runtime/pack/dist/opt/matchit/doc/tags 2016-03-25 16:18:18.609394820 +0100 *************** *** 0 **** --- 1,50 ---- + :MatchDebug matchit.txt /*:MatchDebug* + MatchError matchit.txt /*MatchError* + [% matchit.txt /*[%* + ]% matchit.txt /*]%* + b:match_col matchit.txt /*b:match_col* + b:match_debug matchit.txt /*b:match_debug* + b:match_ignorecase matchit.txt /*b:match_ignorecase* + b:match_ini matchit.txt /*b:match_ini* + b:match_iniBR matchit.txt /*b:match_iniBR* + b:match_match matchit.txt /*b:match_match* + b:match_pat matchit.txt /*b:match_pat* + b:match_skip matchit.txt /*b:match_skip* + b:match_table matchit.txt /*b:match_table* + b:match_tail matchit.txt /*b:match_tail* + b:match_wholeBR matchit.txt /*b:match_wholeBR* + b:match_word matchit.txt /*b:match_word* + b:match_words matchit.txt /*b:match_words* + g% matchit.txt /*g%* + matchit matchit.txt /*matchit* + matchit-% matchit.txt /*matchit-%* + matchit-\1 matchit.txt /*matchit-\\1* + matchit-activate matchit.txt /*matchit-activate* + matchit-backref matchit.txt /*matchit-backref* + matchit-bugs matchit.txt /*matchit-bugs* + matchit-choose matchit.txt /*matchit-choose* + matchit-configure matchit.txt /*matchit-configure* + matchit-debug matchit.txt /*matchit-debug* + matchit-details matchit.txt /*matchit-details* + matchit-highlight matchit.txt /*matchit-highlight* + matchit-hl matchit.txt /*matchit-hl* + matchit-intro matchit.txt /*matchit-intro* + matchit-languages matchit.txt /*matchit-languages* + matchit-modes matchit.txt /*matchit-modes* + matchit-newlang matchit.txt /*matchit-newlang* + matchit-o_% matchit.txt /*matchit-o_%* + matchit-parse matchit.txt /*matchit-parse* + matchit-s:notend matchit.txt /*matchit-s:notend* + matchit-s:sol matchit.txt /*matchit-s:sol* + matchit-spaces matchit.txt /*matchit-spaces* + matchit-troubleshoot matchit.txt /*matchit-troubleshoot* + matchit-v_% matchit.txt /*matchit-v_%* + matchit.txt matchit.txt /*matchit.txt* + matchit.vim matchit.txt /*matchit.vim* + o_[% matchit.txt /*o_[%* + o_]% matchit.txt /*o_]%* + o_g% matchit.txt /*o_g%* + v_[% matchit.txt /*v_[%* + v_]% matchit.txt /*v_]%* + v_a% matchit.txt /*v_a%* + v_g% matchit.txt /*v_g%* *** ../vim-7.4.1648/runtime/doc/usr_05.txt 2013-08-10 13:25:03.000000000 +0200 --- runtime/doc/usr_05.txt 2016-03-25 16:56:20.222152601 +0100 *************** *** 1,4 **** ! *usr_05.txt* For Vim version 7.4. Last change: 2012 Nov 20 VIM USER MANUAL - by Bram Moolenaar --- 1,4 ---- ! *usr_05.txt* For Vim version 7.4. Last change: 2016 Mar 25 VIM USER MANUAL - by Bram Moolenaar *************** *** 12,21 **** |05.1| The vimrc file |05.2| The example vimrc file explained |05.3| Simple mappings ! |05.4| Adding a plugin ! |05.5| Adding a help file ! |05.6| The option window ! |05.7| Often used options Next chapter: |usr_06.txt| Using syntax highlighting Previous chapter: |usr_04.txt| Making small changes --- 12,22 ---- |05.1| The vimrc file |05.2| The example vimrc file explained |05.3| Simple mappings ! |05.4| Adding a package ! |05.5| Adding a plugin ! |05.6| Adding a help file ! |05.7| The option window ! |05.8| Often used options Next chapter: |usr_06.txt| Using syntax highlighting Previous chapter: |usr_04.txt| Making small changes *************** *** 263,269 **** least the ones for Normal mode. More about mappings in section |40.1|. ============================================================================== ! *05.4* Adding a plugin *add-plugin* *plugin* Vim's functionality can be extended by adding plugins. A plugin is nothing more than a Vim script file that is loaded automatically when Vim starts. You --- 264,309 ---- least the ones for Normal mode. More about mappings in section |40.1|. ============================================================================== ! *05.4* Adding a package *add-package* *matchit-install* ! ! A package is a set of files that you can add to Vim. There are two kinds of ! packages: optional and automatically loaded on startup. ! ! The Vim distribution comes with a few packages that you can optionally use. ! For example, the matchit plugin. This plugin makes the "%" command jump to ! matching HTML tags, if/else/endif in Vim scripts, etc. Very useful, although ! it's not backwards compatible (that's why it is not enabled by default). ! ! To start using the matchit plugin, add one line to your vimrc file: > ! packadd matchit ! ! That's all! You can also type the command to try it out. Now you can find ! help about this plugin: > ! :help matchit ! ! This works, because when `:packadd` loaded the plugin it also added the ! package directory in 'runtimepath', so that the help file can be found. ! ! You can find packages on the Internet in various places. It usually comes as ! an archive or as a repository. For an archive you can follow these steps: ! 1. create the package directory: > ! mkdir -p ~/.vim/pack/fancy ! < "fancy" can be any name of your liking. Use one that describes the ! package. ! 2. unpack the archive in that directory. This assumes the top ! directory in the archive is "start": > ! cd ~/.vim/pack/fancy ! unzip /tmp/fancy.zip ! < If the archive layout is different make sure that you end up with a ! path like this: ! ~/.vim/pack/fancy/start/fancytext/plugin/fancy.vim ~ ! Here "fancytext" is the name of the package, it can be anything ! else. ! ! More information about packages can be found here: |packages|. ! ! ============================================================================== ! *05.5* Adding a plugin *add-plugin* *plugin* Vim's functionality can be extended by adding plugins. A plugin is nothing more than a Vim script file that is loaded automatically when Vim starts. You *************** *** 415,437 **** |new-filetype| How to detect a new file type. ============================================================================== ! *05.5* Adding a help file *add-local-help* *matchit-install* If you are lucky, the plugin you installed also comes with a help file. We will explain how to install the help file, so that you can easily find help for your new plugin. ! Let us use the "matchit.vim" plugin as an example (it is included with ! Vim). This plugin makes the "%" command jump to matching HTML tags, ! if/else/endif in Vim scripts, etc. Very useful, although it's not backwards ! compatible (that's why it is not enabled by default). ! This plugin comes with documentation: "matchit.txt". Let's first copy the ! plugin to the right directory. This time we will do it from inside Vim, so ! that we can use $VIMRUNTIME. (You may skip some of the "mkdir" commands if ! you already have the directory.) > :!mkdir ~/.vim :!mkdir ~/.vim/plugin ! :!cp $VIMRUNTIME/macros/matchit.vim ~/.vim/plugin The "cp" command is for Unix, on MS-DOS you can use "copy". --- 455,473 ---- |new-filetype| How to detect a new file type. ============================================================================== ! *05.6* Adding a help file *add-local-help* If you are lucky, the plugin you installed also comes with a help file. We will explain how to install the help file, so that you can easily find help for your new plugin. ! Let us use the "doit.vim" plugin as an example. This plugin comes with ! documentation: "doit.txt". Let's first copy the plugin to the right ! directory. This time we will do it from inside Vim. (You may skip some of ! the "mkdir" commands if you already have the directory.) > :!mkdir ~/.vim :!mkdir ~/.vim/plugin ! :!cp /tmp/doit.vim ~/.vim/plugin The "cp" command is for Unix, on MS-DOS you can use "copy". *************** *** 441,447 **** Copy the help file to the "doc" directory. > ! :!cp $VIMRUNTIME/macros/matchit.txt ~/.vim/doc Now comes the trick, which allows you to jump to the subjects in the new help file: Generate the local tags file with the |:helptags| command. > --- 477,483 ---- Copy the help file to the "doc" directory. > ! :!cp /tmp/doit.txt ~/.vim/doc Now comes the trick, which allows you to jump to the subjects in the new help file: Generate the local tags file with the |:helptags| command. > *************** *** 450,459 **** Now you can use the > ! :help g% ! command to find help for "g%" in the help file you just added. You can see an ! entry for the local help file when you do: > :help local-additions --- 486,495 ---- Now you can use the > ! :help doit ! command to find help for "doit" in the help file you just added. You can see ! an entry for the local help file when you do: > :help local-additions *************** *** 464,470 **** For writing a local help file, see |write-local-help|. ============================================================================== ! *05.6* The option window If you are looking for an option that does what you want, you can search in the help files here: |options|. Another way is by using this command: > --- 500,506 ---- For writing a local help file, see |write-local-help|. ============================================================================== ! *05.7* The option window If you are looking for an option that does what you want, you can search in the help files here: |options|. Another way is by using this command: > *************** *** 503,509 **** from the window border where scrolling starts. ============================================================================== ! *05.7* Often used options There are an awful lot of options. Most of them you will hardly ever use. Some of the more useful ones will be mentioned here. Don't forget you can --- 539,545 ---- from the window border where scrolling starts. ============================================================================== ! *05.8* Often used options There are an awful lot of options. Most of them you will hardly ever use. Some of the more useful ones will be mentioned here. Don't forget you can *** ../vim-7.4.1648/runtime/doc/usr_toc.txt 2013-08-10 13:25:06.000000000 +0200 --- runtime/doc/usr_toc.txt 2016-03-25 16:21:31.227430732 +0100 *************** *** 1,4 **** ! *usr_toc.txt* For Vim version 7.4. Last change: 2010 Jul 20 VIM USER MANUAL - by Bram Moolenaar --- 1,4 ---- ! *usr_toc.txt* For Vim version 7.4. Last change: 2016 Mar 25 VIM USER MANUAL - by Bram Moolenaar *************** *** 104,113 **** |05.1| The vimrc file |05.2| The example vimrc file explained |05.3| Simple mappings ! |05.4| Adding a plugin ! |05.5| Adding a help file ! |05.6| The option window ! |05.7| Often used options |usr_06.txt| Using syntax highlighting |06.1| Switching it on --- 104,114 ---- |05.1| The vimrc file |05.2| The example vimrc file explained |05.3| Simple mappings ! |05.4| Adding a package ! |05.5| Adding a plugin ! |05.6| Adding a help file ! |05.7| The option window ! |05.8| Often used options |usr_06.txt| Using syntax highlighting |06.1| Switching it on *** ../vim-7.4.1648/src/version.c 2016-03-25 15:40:45.932372899 +0100 --- src/version.c 2016-03-25 16:48:14.947094023 +0100 *************** *** 750,751 **** --- 750,753 ---- { /* Add new patch number below this line */ + /**/ + 1649, /**/ -- "A clear conscience is usually the sign of a bad memory." -- Steven Wright /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///