comparison runtime/pack/dist/opt/matchit/autoload/matchit.vim @ 26708:f0d7cb510ce3

Update runtime files Commit: https://github.com/vim/vim/commit/fa3b72348d88343390fbe212cfc230fec1602fc2 Author: Bram Moolenaar <Bram@vim.org> Date: Fri Dec 24 13:18:38 2021 +0000 Update runtime files
author Bram Moolenaar <Bram@vim.org>
date Fri, 24 Dec 2021 14:30:04 +0100
parents d4deb2e50667
children 5825405e4e2c
comparison
equal deleted inserted replaced
26707:d1af15dbf206 26708:f0d7cb510ce3
1 " matchit.vim: (global plugin) Extended "%" matching 1 " matchit.vim: (global plugin) Extended "%" matching
2 " autload script of matchit plugin, see ../plugin/matchit.vim 2 " autload script of matchit plugin, see ../plugin/matchit.vim
3 " Last Change: Mar 01, 2020 3 " Last Change: Jun 10, 2021
4
5 " Neovim does not support scriptversion
6 if has("vimscript-4")
7 scriptversion 4
8 endif
4 9
5 let s:last_mps = "" 10 let s:last_mps = ""
6 let s:last_words = ":" 11 let s:last_words = ":"
7 let s:patBR = "" 12 let s:patBR = ""
8 13
28 33
29 function s:RestoreOptions() 34 function s:RestoreOptions()
30 " In s:CleanUp(), :execute "set" restore_options . 35 " In s:CleanUp(), :execute "set" restore_options .
31 let restore_options = "" 36 let restore_options = ""
32 if get(b:, 'match_ignorecase', &ic) != &ic 37 if get(b:, 'match_ignorecase', &ic) != &ic
33 let restore_options .= (&ic ? " " : " no") . "ignorecase" 38 let restore_options ..= (&ic ? " " : " no") .. "ignorecase"
34 let &ignorecase = b:match_ignorecase 39 let &ignorecase = b:match_ignorecase
35 endif 40 endif
36 if &ve != '' 41 if &ve != ''
37 let restore_options = " ve=" . &ve . restore_options 42 let restore_options = " ve=" .. &ve .. restore_options
38 set ve= 43 set ve=
39 endif 44 endif
40 return restore_options 45 return restore_options
41 endfunction 46 endfunction
42 47
43 function matchit#Match_wrapper(word, forward, mode) range 48 function matchit#Match_wrapper(word, forward, mode) range
44 let restore_options = s:RestoreOptions() 49 let restore_options = s:RestoreOptions()
50 " In s:CleanUp(), we may need to check whether the cursor moved forward.
51 let startpos = [line("."), col(".")]
52 " if a count has been applied, use the default [count]% mode (see :h N%)
53 if v:count
54 exe "normal! " .. v:count .. "%"
55 return s:CleanUp(restore_options, a:mode, startpos)
56 end
57 if a:mode =~# "v" && mode(1) =~# 'ni'
58 exe "norm! gv"
59 elseif a:mode == "o" && mode(1) !~# '[vV]'
60 exe "norm! v"
45 " If this function was called from Visual mode, make sure that the cursor 61 " If this function was called from Visual mode, make sure that the cursor
46 " is at the correct end of the Visual range: 62 " is at the correct end of the Visual range:
47 if a:mode == "v" 63 elseif a:mode == "v"
48 execute "normal! gv\<Esc>" 64 execute "normal! gv\<Esc>"
49 elseif a:mode == "o" && mode(1) !~# '[vV]' 65 let startpos = [line("."), col(".")]
50 exe "norm! v" 66 endif
51 elseif a:mode == "n" && mode(1) =~# 'ni'
52 exe "norm! v"
53 endif
54 " In s:CleanUp(), we may need to check whether the cursor moved forward.
55 let startpos = [line("."), col(".")]
56 " Use default behavior if called with a count.
57 if v:count
58 exe "normal! " . v:count . "%"
59 return s:CleanUp(restore_options, a:mode, startpos)
60 end
61 67
62 " First step: if not already done, set the script variables 68 " First step: if not already done, set the script variables
63 " s:do_BR flag for whether there are backrefs 69 " s:do_BR flag for whether there are backrefs
64 " s:pat parsed version of b:match_words 70 " s:pat parsed version of b:match_words
65 " s:all regexp based on s:pat and the default groups 71 " s:all regexp based on s:pat and the default groups
76 \ || exists("b:match_debug") 82 \ || exists("b:match_debug")
77 let s:last_mps = &mps 83 let s:last_mps = &mps
78 " quote the special chars in 'matchpairs', replace [,:] with \| and then 84 " quote the special chars in 'matchpairs', replace [,:] with \| and then
79 " append the builtin pairs (/*, */, #if, #ifdef, #ifndef, #else, #elif, 85 " append the builtin pairs (/*, */, #if, #ifdef, #ifndef, #else, #elif,
80 " #endif) 86 " #endif)
81 let default = escape(&mps, '[$^.*~\\/?]') . (strlen(&mps) ? "," : "") . 87 let default = escape(&mps, '[$^.*~\\/?]') .. (strlen(&mps) ? "," : "") ..
82 \ '\/\*:\*\/,#\s*if\%(n\=def\)\=:#\s*else\>:#\s*elif\>:#\s*endif\>' 88 \ '\/\*:\*\/,#\s*if\%(n\=def\)\=:#\s*else\>:#\s*elif\>:#\s*endif\>'
83 " s:all = pattern with all the keywords 89 " s:all = pattern with all the keywords
84 let match_words = match_words . (strlen(match_words) ? "," : "") . default 90 let match_words = match_words .. (strlen(match_words) ? "," : "") .. default
85 let s:last_words = match_words 91 let s:last_words = match_words
86 if match_words !~ s:notslash . '\\\d' 92 if match_words !~ s:notslash .. '\\\d'
87 let s:do_BR = 0 93 let s:do_BR = 0
88 let s:pat = match_words 94 let s:pat = match_words
89 else 95 else
90 let s:do_BR = 1 96 let s:do_BR = 1
91 let s:pat = s:ParseWords(match_words) 97 let s:pat = s:ParseWords(match_words)
92 endif 98 endif
93 let s:all = substitute(s:pat, s:notslash . '\zs[,:]\+', '\\|', 'g') 99 let s:all = substitute(s:pat, s:notslash .. '\zs[,:]\+', '\\|', 'g')
94 " Just in case there are too many '\(...)' groups inside the pattern, make 100 " Just in case there are too many '\(...)' groups inside the pattern, make
95 " sure to use \%(...) groups, so that error E872 can be avoided 101 " sure to use \%(...) groups, so that error E872 can be avoided
96 let s:all = substitute(s:all, '\\(', '\\%(', 'g') 102 let s:all = substitute(s:all, '\\(', '\\%(', 'g')
97 let s:all = '\%(' . s:all . '\)' 103 let s:all = '\%(' .. s:all .. '\)'
98 if exists("b:match_debug") 104 if exists("b:match_debug")
99 let b:match_pat = s:pat 105 let b:match_pat = s:pat
100 endif 106 endif
101 " Reconstruct the version with unresolved backrefs. 107 " Reconstruct the version with unresolved backrefs.
102 let s:patBR = substitute(match_words.',', 108 let s:patBR = substitute(match_words .. ',',
103 \ s:notslash.'\zs[,:]*,[,:]*', ',', 'g') 109 \ s:notslash .. '\zs[,:]*,[,:]*', ',', 'g')
104 let s:patBR = substitute(s:patBR, s:notslash.'\zs:\{2,}', ':', 'g') 110 let s:patBR = substitute(s:patBR, s:notslash .. '\zs:\{2,}', ':', 'g')
105 endif 111 endif
106 112
107 " Second step: set the following local variables: 113 " Second step: set the following local variables:
108 " matchline = line on which the cursor started 114 " matchline = line on which the cursor started
109 " curcol = number of characters before match 115 " curcol = number of characters before match
126 else " Find the match that ends on or after the cursor and set curcol. 132 else " Find the match that ends on or after the cursor and set curcol.
127 let regexp = s:Wholematch(matchline, s:all, startpos[1]-1) 133 let regexp = s:Wholematch(matchline, s:all, startpos[1]-1)
128 let curcol = match(matchline, regexp) 134 let curcol = match(matchline, regexp)
129 " If there is no match, give up. 135 " If there is no match, give up.
130 if curcol == -1 136 if curcol == -1
137 " Make sure macros abort properly
138 "exe "norm! \<esc>"
139 call feedkeys("\e", 'tni')
131 return s:CleanUp(restore_options, a:mode, startpos) 140 return s:CleanUp(restore_options, a:mode, startpos)
132 endif 141 endif
133 let endcol = matchend(matchline, regexp) 142 let endcol = matchend(matchline, regexp)
134 let suf = strlen(matchline) - endcol 143 let suf = strlen(matchline) - endcol
135 let prefix = (curcol ? '^.*\%' . (curcol + 1) . 'c\%(' : '^\%(') 144 let prefix = (curcol ? '^.*\%' .. (curcol + 1) .. 'c\%(' : '^\%(')
136 let suffix = (suf ? '\)\%' . (endcol + 1) . 'c.*$' : '\)$') 145 let suffix = (suf ? '\)\%' .. (endcol + 1) .. 'c.*$' : '\)$')
137 endif 146 endif
138 if exists("b:match_debug") 147 if exists("b:match_debug")
139 let b:match_match = matchstr(matchline, regexp) 148 let b:match_match = matchstr(matchline, regexp)
140 let b:match_col = curcol+1 149 let b:match_col = curcol+1
141 endif 150 endif
148 " 157 "
149 " Now, set group and groupBR to the matching group: 'if:endif' or 158 " Now, set group and groupBR to the matching group: 'if:endif' or
150 " 'while:endwhile' or whatever. A bit of a kluge: s:Choose() returns 159 " 'while:endwhile' or whatever. A bit of a kluge: s:Choose() returns
151 " group . "," . groupBR, and we pick it apart. 160 " group . "," . groupBR, and we pick it apart.
152 let group = s:Choose(s:pat, matchline, ",", ":", prefix, suffix, s:patBR) 161 let group = s:Choose(s:pat, matchline, ",", ":", prefix, suffix, s:patBR)
153 let i = matchend(group, s:notslash . ",") 162 let i = matchend(group, s:notslash .. ",")
154 let groupBR = strpart(group, i) 163 let groupBR = strpart(group, i)
155 let group = strpart(group, 0, i-1) 164 let group = strpart(group, 0, i-1)
156 " Now, matchline =~ prefix . substitute(group,':','\|','g') . suffix 165 " Now, matchline =~ prefix . substitute(group,':','\|','g') . suffix
157 if s:do_BR " Do the hard part: resolve those backrefs! 166 if s:do_BR " Do the hard part: resolve those backrefs!
158 let group = s:InsertRefs(groupBR, prefix, group, suffix, matchline) 167 let group = s:InsertRefs(groupBR, prefix, group, suffix, matchline)
159 endif 168 endif
160 if exists("b:match_debug") 169 if exists("b:match_debug")
161 let b:match_wholeBR = groupBR 170 let b:match_wholeBR = groupBR
162 let i = matchend(groupBR, s:notslash . ":") 171 let i = matchend(groupBR, s:notslash .. ":")
163 let b:match_iniBR = strpart(groupBR, 0, i-1) 172 let b:match_iniBR = strpart(groupBR, 0, i-1)
164 endif 173 endif
165 174
166 " Fourth step: Set the arguments for searchpair(). 175 " Fourth step: Set the arguments for searchpair().
167 let i = matchend(group, s:notslash . ":") 176 let i = matchend(group, s:notslash .. ":")
168 let j = matchend(group, '.*' . s:notslash . ":") 177 let j = matchend(group, '.*' .. s:notslash .. ":")
169 let ini = strpart(group, 0, i-1) 178 let ini = strpart(group, 0, i-1)
170 let mid = substitute(strpart(group, i,j-i-1), s:notslash.'\zs:', '\\|', 'g') 179 let mid = substitute(strpart(group, i,j-i-1), s:notslash .. '\zs:', '\\|', 'g')
171 let fin = strpart(group, j) 180 let fin = strpart(group, j)
172 "Un-escape the remaining , and : characters. 181 "Un-escape the remaining , and : characters.
173 let ini = substitute(ini, s:notslash . '\zs\\\(:\|,\)', '\1', 'g') 182 let ini = substitute(ini, s:notslash .. '\zs\\\(:\|,\)', '\1', 'g')
174 let mid = substitute(mid, s:notslash . '\zs\\\(:\|,\)', '\1', 'g') 183 let mid = substitute(mid, s:notslash .. '\zs\\\(:\|,\)', '\1', 'g')
175 let fin = substitute(fin, s:notslash . '\zs\\\(:\|,\)', '\1', 'g') 184 let fin = substitute(fin, s:notslash .. '\zs\\\(:\|,\)', '\1', 'g')
176 " searchpair() requires that these patterns avoid \(\) groups. 185 " searchpair() requires that these patterns avoid \(\) groups.
177 let ini = substitute(ini, s:notslash . '\zs\\(', '\\%(', 'g') 186 let ini = substitute(ini, s:notslash .. '\zs\\(', '\\%(', 'g')
178 let mid = substitute(mid, s:notslash . '\zs\\(', '\\%(', 'g') 187 let mid = substitute(mid, s:notslash .. '\zs\\(', '\\%(', 'g')
179 let fin = substitute(fin, s:notslash . '\zs\\(', '\\%(', 'g') 188 let fin = substitute(fin, s:notslash .. '\zs\\(', '\\%(', 'g')
180 " Set mid. This is optimized for readability, not micro-efficiency! 189 " Set mid. This is optimized for readability, not micro-efficiency!
181 if a:forward && matchline =~ prefix . fin . suffix 190 if a:forward && matchline =~ prefix .. fin .. suffix
182 \ || !a:forward && matchline =~ prefix . ini . suffix 191 \ || !a:forward && matchline =~ prefix .. ini .. suffix
183 let mid = "" 192 let mid = ""
184 endif 193 endif
185 " Set flag. This is optimized for readability, not micro-efficiency! 194 " Set flag. This is optimized for readability, not micro-efficiency!
186 if a:forward && matchline =~ prefix . fin . suffix 195 if a:forward && matchline =~ prefix .. fin .. suffix
187 \ || !a:forward && matchline !~ prefix . ini . suffix 196 \ || !a:forward && matchline !~ prefix .. ini .. suffix
188 let flag = "bW" 197 let flag = "bW"
189 else 198 else
190 let flag = "W" 199 let flag = "W"
191 endif 200 endif
192 " Set skip. 201 " Set skip.
193 if exists("b:match_skip") 202 if exists("b:match_skip")
194 let skip = b:match_skip 203 let skip = b:match_skip
195 elseif exists("b:match_comment") " backwards compatibility and testing! 204 elseif exists("b:match_comment") " backwards compatibility and testing!
196 let skip = "r:" . b:match_comment 205 let skip = "r:" .. b:match_comment
197 else 206 else
198 let skip = 's:comment\|string' 207 let skip = 's:comment\|string'
199 endif 208 endif
200 let skip = s:ParseSkip(skip) 209 let skip = s:ParseSkip(skip)
201 if exists("b:match_debug") 210 if exists("b:match_debug")
202 let b:match_ini = ini 211 let b:match_ini = ini
203 let b:match_tail = (strlen(mid) ? mid.'\|' : '') . fin 212 let b:match_tail = (strlen(mid) ? mid .. '\|' : '') .. fin
204 endif 213 endif
205 214
206 " Fifth step: actually start moving the cursor and call searchpair(). 215 " Fifth step: actually start moving the cursor and call searchpair().
207 " Later, :execute restore_cursor to get to the original screen. 216 " Later, :execute restore_cursor to get to the original screen.
208 let view = winsaveview() 217 let view = winsaveview()
209 call cursor(0, curcol + 1) 218 call cursor(0, curcol + 1)
210 if skip =~ 'synID' && !(has("syntax") && exists("g:syntax_on")) 219 if skip =~ 'synID' && !(has("syntax") && exists("g:syntax_on"))
211 let skip = "0" 220 let skip = "0"
212 else 221 else
213 execute "if " . skip . "| let skip = '0' | endif" 222 execute "if " .. skip .. "| let skip = '0' | endif"
214 endif 223 endif
215 let sp_return = searchpair(ini, mid, fin, flag, skip) 224 let sp_return = searchpair(ini, mid, fin, flag, skip)
216 if &selection isnot# 'inclusive' && a:mode == 'v' 225 if &selection isnot# 'inclusive' && a:mode == 'v'
217 " move cursor one pos to the right, because selection is not inclusive 226 " move cursor one pos to the right, because selection is not inclusive
218 " add virtualedit=onemore, to make it work even when the match ends the " line 227 " add virtualedit=onemore, to make it work even when the match ends the
228 " line
219 if !(col('.') < col('$')-1) 229 if !(col('.') < col('$')-1)
220 set ve=onemore 230 let eolmark=1 " flag to set a mark on eol (since we cannot move there)
221 endif 231 endif
222 norm! l 232 norm! l
223 endif 233 endif
224 let final_position = "call cursor(" . line(".") . "," . col(".") . ")" 234 let final_position = "call cursor(" .. line(".") .. "," .. col(".") .. ")"
225 " Restore cursor position and original screen. 235 " Restore cursor position and original screen.
226 call winrestview(view) 236 call winrestview(view)
227 normal! m' 237 normal! m'
228 if sp_return > 0 238 if sp_return > 0
229 execute final_position 239 execute final_position
230 endif 240 endif
231 return s:CleanUp(restore_options, a:mode, startpos, mid.'\|'.fin) 241 if exists('eolmark') && eolmark
242 call setpos("''", [0, line('.'), col('$'), 0]) " set mark on the eol
243 endif
244 return s:CleanUp(restore_options, a:mode, startpos, mid .. '\|' .. fin)
232 endfun 245 endfun
233 246
234 " Restore options and do some special handling for Operator-pending mode. 247 " Restore options and do some special handling for Operator-pending mode.
235 " The optional argument is the tail of the matching group. 248 " The optional argument is the tail of the matching group.
236 fun! s:CleanUp(options, mode, startpos, ...) 249 fun! s:CleanUp(options, mode, startpos, ...)
268 " a:group = '<\(\k\+\)>:</\(\k\+\)>' 281 " a:group = '<\(\k\+\)>:</\(\k\+\)>'
269 " a:suffix = '\).\{2}$' 282 " a:suffix = '\).\{2}$'
270 " a:matchline = "123<tag>12" or "123</tag>12" 283 " a:matchline = "123<tag>12" or "123</tag>12"
271 " then extract "tag" from a:matchline and return "<tag>:</tag>" . 284 " then extract "tag" from a:matchline and return "<tag>:</tag>" .
272 fun! s:InsertRefs(groupBR, prefix, group, suffix, matchline) 285 fun! s:InsertRefs(groupBR, prefix, group, suffix, matchline)
273 if a:matchline !~ a:prefix . 286 if a:matchline !~ a:prefix ..
274 \ substitute(a:group, s:notslash . '\zs:', '\\|', 'g') . a:suffix 287 \ substitute(a:group, s:notslash .. '\zs:', '\\|', 'g') .. a:suffix
275 return a:group 288 return a:group
276 endif 289 endif
277 let i = matchend(a:groupBR, s:notslash . ':') 290 let i = matchend(a:groupBR, s:notslash .. ':')
278 let ini = strpart(a:groupBR, 0, i-1) 291 let ini = strpart(a:groupBR, 0, i-1)
279 let tailBR = strpart(a:groupBR, i) 292 let tailBR = strpart(a:groupBR, i)
280 let word = s:Choose(a:group, a:matchline, ":", "", a:prefix, a:suffix, 293 let word = s:Choose(a:group, a:matchline, ":", "", a:prefix, a:suffix,
281 \ a:groupBR) 294 \ a:groupBR)
282 let i = matchend(word, s:notslash . ":") 295 let i = matchend(word, s:notslash .. ":")
283 let wordBR = strpart(word, i) 296 let wordBR = strpart(word, i)
284 let word = strpart(word, 0, i-1) 297 let word = strpart(word, 0, i-1)
285 " Now, a:matchline =~ a:prefix . word . a:suffix 298 " Now, a:matchline =~ a:prefix . word . a:suffix
286 if wordBR != ini 299 if wordBR != ini
287 let table = s:Resolve(ini, wordBR, "table") 300 let table = s:Resolve(ini, wordBR, "table")
288 else 301 else
289 let table = "" 302 let table = ""
290 let d = 0 303 let d = 0
291 while d < 10 304 while d < 10
292 if tailBR =~ s:notslash . '\\' . d 305 if tailBR =~ s:notslash .. '\\' .. d
293 let table = table . d 306 let table = table .. d
294 else 307 else
295 let table = table . "-" 308 let table = table .. "-"
296 endif 309 endif
297 let d = d + 1 310 let d = d + 1
298 endwhile 311 endwhile
299 endif 312 endif
300 let d = 9 313 let d = 9
301 while d 314 while d
302 if table[d] != "-" 315 if table[d] != "-"
303 let backref = substitute(a:matchline, a:prefix.word.a:suffix, 316 let backref = substitute(a:matchline, a:prefix .. word .. a:suffix,
304 \ '\'.table[d], "") 317 \ '\' .. table[d], "")
305 " Are there any other characters that should be escaped? 318 " Are there any other characters that should be escaped?
306 let backref = escape(backref, '*,:') 319 let backref = escape(backref, '*,:')
307 execute s:Ref(ini, d, "start", "len") 320 execute s:Ref(ini, d, "start", "len")
308 let ini = strpart(ini, 0, start) . backref . strpart(ini, start+len) 321 let ini = strpart(ini, 0, start) .. backref .. strpart(ini, start+len)
309 let tailBR = substitute(tailBR, s:notslash . '\zs\\' . d, 322 let tailBR = substitute(tailBR, s:notslash .. '\zs\\' .. d,
310 \ escape(backref, '\\&'), 'g') 323 \ escape(backref, '\\&'), 'g')
311 endif 324 endif
312 let d = d-1 325 let d = d-1
313 endwhile 326 endwhile
314 if exists("b:match_debug") 327 if exists("b:match_debug")
318 else 331 else
319 let b:match_table = "" 332 let b:match_table = ""
320 let b:match_word = "" 333 let b:match_word = ""
321 endif 334 endif
322 endif 335 endif
323 return ini . ":" . tailBR 336 return ini .. ":" .. tailBR
324 endfun 337 endfun
325 338
326 " Input a comma-separated list of groups with backrefs, such as 339 " Input a comma-separated list of groups with backrefs, such as
327 " a:groups = '\(foo\):end\1,\(bar\):end\1' 340 " a:groups = '\(foo\):end\1,\(bar\):end\1'
328 " and return a comma-separated list of groups with backrefs replaced: 341 " and return a comma-separated list of groups with backrefs replaced:
329 " return '\(foo\):end\(foo\),\(bar\):end\(bar\)' 342 " return '\(foo\):end\(foo\),\(bar\):end\(bar\)'
330 fun! s:ParseWords(groups) 343 fun! s:ParseWords(groups)
331 let groups = substitute(a:groups.",", s:notslash.'\zs[,:]*,[,:]*', ',', 'g') 344 let groups = substitute(a:groups .. ",", s:notslash .. '\zs[,:]*,[,:]*', ',', 'g')
332 let groups = substitute(groups, s:notslash . '\zs:\{2,}', ':', 'g') 345 let groups = substitute(groups, s:notslash .. '\zs:\{2,}', ':', 'g')
333 let parsed = "" 346 let parsed = ""
334 while groups =~ '[^,:]' 347 while groups =~ '[^,:]'
335 let i = matchend(groups, s:notslash . ':') 348 let i = matchend(groups, s:notslash .. ':')
336 let j = matchend(groups, s:notslash . ',') 349 let j = matchend(groups, s:notslash .. ',')
337 let ini = strpart(groups, 0, i-1) 350 let ini = strpart(groups, 0, i-1)
338 let tail = strpart(groups, i, j-i-1) . ":" 351 let tail = strpart(groups, i, j-i-1) .. ":"
339 let groups = strpart(groups, j) 352 let groups = strpart(groups, j)
340 let parsed = parsed . ini 353 let parsed = parsed .. ini
341 let i = matchend(tail, s:notslash . ':') 354 let i = matchend(tail, s:notslash .. ':')
342 while i != -1 355 while i != -1
343 " In 'if:else:endif', ini='if' and word='else' and then word='endif'. 356 " In 'if:else:endif', ini='if' and word='else' and then word='endif'.
344 let word = strpart(tail, 0, i-1) 357 let word = strpart(tail, 0, i-1)
345 let tail = strpart(tail, i) 358 let tail = strpart(tail, i)
346 let i = matchend(tail, s:notslash . ':') 359 let i = matchend(tail, s:notslash .. ':')
347 let parsed = parsed . ":" . s:Resolve(ini, word, "word") 360 let parsed = parsed .. ":" .. s:Resolve(ini, word, "word")
348 endwhile " Now, tail has been used up. 361 endwhile " Now, tail has been used up.
349 let parsed = parsed . "," 362 let parsed = parsed .. ","
350 endwhile " groups =~ '[^,:]' 363 endwhile " groups =~ '[^,:]'
351 let parsed = substitute(parsed, ',$', '', '') 364 let parsed = substitute(parsed, ',$', '', '')
352 return parsed 365 return parsed
353 endfun 366 endfun
354 367
362 " let regexp = s:Wholematch(getline("."), 'foo\|bar', col(".")-1) 375 " let regexp = s:Wholematch(getline("."), 'foo\|bar', col(".")-1)
363 " let i = match(getline("."), regexp) 376 " let i = match(getline("."), regexp)
364 " let j = matchend(getline("."), regexp) 377 " let j = matchend(getline("."), regexp)
365 " let match = matchstr(getline("."), regexp) 378 " let match = matchstr(getline("."), regexp)
366 fun! s:Wholematch(string, pat, start) 379 fun! s:Wholematch(string, pat, start)
367 let group = '\%(' . a:pat . '\)' 380 let group = '\%(' .. a:pat .. '\)'
368 let prefix = (a:start ? '\(^.*\%<' . (a:start + 2) . 'c\)\zs' : '^') 381 let prefix = (a:start ? '\(^.*\%<' .. (a:start + 2) .. 'c\)\zs' : '^')
369 let len = strlen(a:string) 382 let len = strlen(a:string)
370 let suffix = (a:start+1 < len ? '\(\%>'.(a:start+1).'c.*$\)\@=' : '$') 383 let suffix = (a:start+1 < len ? '\(\%>' .. (a:start+1) .. 'c.*$\)\@=' : '$')
371 if a:string !~ prefix . group . suffix 384 if a:string !~ prefix .. group .. suffix
372 let prefix = '' 385 let prefix = ''
373 endif 386 endif
374 return prefix . group . suffix 387 return prefix .. group .. suffix
375 endfun 388 endfun
376 389
377 " No extra arguments: s:Ref(string, d) will 390 " No extra arguments: s:Ref(string, d) will
378 " find the d'th occurrence of '\(' and return it, along with everything up 391 " find the d'th occurrence of '\(' and return it, along with everything up
379 " to and including the matching '\)'. 392 " to and including the matching '\)'.
390 else 403 else
391 let cnt = a:d 404 let cnt = a:d
392 let match = a:string 405 let match = a:string
393 while cnt 406 while cnt
394 let cnt = cnt - 1 407 let cnt = cnt - 1
395 let index = matchend(match, s:notslash . '\\(') 408 let index = matchend(match, s:notslash .. '\\(')
396 if index == -1 409 if index == -1
397 return "" 410 return ""
398 endif 411 endif
399 let match = strpart(match, index) 412 let match = strpart(match, index)
400 endwhile 413 endwhile
402 if a:0 == 1 && a:1 == "start" 415 if a:0 == 1 && a:1 == "start"
403 return start - 2 416 return start - 2
404 endif 417 endif
405 let cnt = 1 418 let cnt = 1
406 while cnt 419 while cnt
407 let index = matchend(match, s:notslash . '\\(\|\\)') - 1 420 let index = matchend(match, s:notslash .. '\\(\|\\)') - 1
408 if index == -2 421 if index == -2
409 return "" 422 return ""
410 endif 423 endif
411 " Increment if an open, decrement if a ')': 424 " Increment if an open, decrement if a ')':
412 let cnt = cnt + (match[index]=="(" ? 1 : -1) " ')' 425 let cnt = cnt + (match[index]=="(" ? 1 : -1) " ')'
416 let len = len - start - strlen(match) 429 let len = len - start - strlen(match)
417 endif 430 endif
418 if a:0 == 1 431 if a:0 == 1
419 return len 432 return len
420 elseif a:0 == 2 433 elseif a:0 == 2
421 return "let " . a:1 . "=" . start . "| let " . a:2 . "=" . len 434 return "let " .. a:1 .. "=" .. start .. "| let " .. a:2 .. "=" .. len
422 else 435 else
423 return strpart(a:string, start, len) 436 return strpart(a:string, start, len)
424 endif 437 endif
425 endfun 438 endfun
426 439
429 " then s:Count(string, pattern, '0', '1') should be faster than 442 " then s:Count(string, pattern, '0', '1') should be faster than
430 " s:Count(string, pattern). 443 " s:Count(string, pattern).
431 fun! s:Count(string, pattern, ...) 444 fun! s:Count(string, pattern, ...)
432 let pat = escape(a:pattern, '\\') 445 let pat = escape(a:pattern, '\\')
433 if a:0 > 1 446 if a:0 > 1
434 let foo = substitute(a:string, '[^'.a:pattern.']', "a:1", "g") 447 let foo = substitute(a:string, '[^' .. a:pattern .. ']', "a:1", "g")
435 let foo = substitute(a:string, pat, a:2, "g") 448 let foo = substitute(a:string, pat, a:2, "g")
436 let foo = substitute(foo, '[^' . a:2 . ']', "", "g") 449 let foo = substitute(foo, '[^' .. a:2 .. ']', "", "g")
437 return strlen(foo) 450 return strlen(foo)
438 endif 451 endif
439 let result = 0 452 let result = 0
440 let foo = a:string 453 let foo = a:string
441 let index = matchend(foo, pat) 454 let index = matchend(foo, pat)
454 " by '\3'. The hard part is dealing with nesting... 467 " by '\3'. The hard part is dealing with nesting...
455 " Note that ":" is an illegal character for source and target, 468 " Note that ":" is an illegal character for source and target,
456 " unless it is preceded by "\". 469 " unless it is preceded by "\".
457 fun! s:Resolve(source, target, output) 470 fun! s:Resolve(source, target, output)
458 let word = a:target 471 let word = a:target
459 let i = matchend(word, s:notslash . '\\\d') - 1 472 let i = matchend(word, s:notslash .. '\\\d') - 1
460 let table = "----------" 473 let table = "----------"
461 while i != -2 " There are back references to be replaced. 474 while i != -2 " There are back references to be replaced.
462 let d = word[i] 475 let d = word[i]
463 let backref = s:Ref(a:source, d) 476 let backref = s:Ref(a:source, d)
464 " The idea is to replace '\d' with backref. Before we do this, 477 " The idea is to replace '\d' with backref. Before we do this,
475 while b <= s:Count(substitute(backref, '\\\\', '', 'g'), '\(', '1') 488 while b <= s:Count(substitute(backref, '\\\\', '', 'g'), '\(', '1')
476 \ && s < 10 489 \ && s < 10
477 if table[s] == "-" 490 if table[s] == "-"
478 if w + b < 10 491 if w + b < 10
479 " let table[s] = w + b 492 " let table[s] = w + b
480 let table = strpart(table, 0, s) . (w+b) . strpart(table, s+1) 493 let table = strpart(table, 0, s) .. (w+b) .. strpart(table, s+1)
481 endif 494 endif
482 let b = b + 1 495 let b = b + 1
483 let s = s + 1 496 let s = s + 1
484 else 497 else
485 execute s:Ref(backref, b, "start", "len") 498 execute s:Ref(backref, b, "start", "len")
486 let ref = strpart(backref, start, len) 499 let ref = strpart(backref, start, len)
487 let backref = strpart(backref, 0, start) . ":". table[s] 500 let backref = strpart(backref, 0, start) .. ":" .. table[s]
488 \ . strpart(backref, start+len) 501 \ .. strpart(backref, start+len)
489 let s = s + s:Count(substitute(ref, '\\\\', '', 'g'), '\(', '1') 502 let s = s + s:Count(substitute(ref, '\\\\', '', 'g'), '\(', '1')
490 endif 503 endif
491 endwhile 504 endwhile
492 let word = strpart(word, 0, i-1) . backref . strpart(word, i+1) 505 let word = strpart(word, 0, i-1) .. backref .. strpart(word, i+1)
493 let i = matchend(word, s:notslash . '\\\d') - 1 506 let i = matchend(word, s:notslash .. '\\\d') - 1
494 endwhile 507 endwhile
495 let word = substitute(word, s:notslash . '\zs:', '\\', 'g') 508 let word = substitute(word, s:notslash .. '\zs:', '\\', 'g')
496 if a:output == "table" 509 if a:output == "table"
497 return table 510 return table
498 elseif a:output == "word" 511 elseif a:output == "word"
499 return word 512 return word
500 else 513 else
501 return table . word 514 return table .. word
502 endif 515 endif
503 endfun 516 endfun
504 517
505 " Assume a:comma = ",". Then the format for a:patterns and a:1 is 518 " Assume a:comma = ",". Then the format for a:patterns and a:1 is
506 " a:patterns = "<pat1>,<pat2>,..." 519 " a:patterns = "<pat1>,<pat2>,..."
507 " a:1 = "<alt1>,<alt2>,..." 520 " a:1 = "<alt1>,<alt2>,..."
508 " If <patn> is the first pattern that matches a:string then return <patn> 521 " If <patn> is the first pattern that matches a:string then return <patn>
509 " if no optional arguments are given; return <patn>,<altn> if a:1 is given. 522 " if no optional arguments are given; return <patn>,<altn> if a:1 is given.
510 fun! s:Choose(patterns, string, comma, branch, prefix, suffix, ...) 523 fun! s:Choose(patterns, string, comma, branch, prefix, suffix, ...)
511 let tail = (a:patterns =~ a:comma."$" ? a:patterns : a:patterns . a:comma) 524 let tail = (a:patterns =~ a:comma .. "$" ? a:patterns : a:patterns .. a:comma)
512 let i = matchend(tail, s:notslash . a:comma) 525 let i = matchend(tail, s:notslash .. a:comma)
513 if a:0 526 if a:0
514 let alttail = (a:1 =~ a:comma."$" ? a:1 : a:1 . a:comma) 527 let alttail = (a:1 =~ a:comma .. "$" ? a:1 : a:1 .. a:comma)
515 let j = matchend(alttail, s:notslash . a:comma) 528 let j = matchend(alttail, s:notslash .. a:comma)
516 endif 529 endif
517 let current = strpart(tail, 0, i-1) 530 let current = strpart(tail, 0, i-1)
518 if a:branch == "" 531 if a:branch == ""
519 let currpat = current 532 let currpat = current
520 else 533 else
521 let currpat = substitute(current, s:notslash . a:branch, '\\|', 'g') 534 let currpat = substitute(current, s:notslash .. a:branch, '\\|', 'g')
522 endif 535 endif
523 while a:string !~ a:prefix . currpat . a:suffix 536 while a:string !~ a:prefix .. currpat .. a:suffix
524 let tail = strpart(tail, i) 537 let tail = strpart(tail, i)
525 let i = matchend(tail, s:notslash . a:comma) 538 let i = matchend(tail, s:notslash .. a:comma)
526 if i == -1 539 if i == -1
527 return -1 540 return -1
528 endif 541 endif
529 let current = strpart(tail, 0, i-1) 542 let current = strpart(tail, 0, i-1)
530 if a:branch == "" 543 if a:branch == ""
531 let currpat = current 544 let currpat = current
532 else 545 else
533 let currpat = substitute(current, s:notslash . a:branch, '\\|', 'g') 546 let currpat = substitute(current, s:notslash .. a:branch, '\\|', 'g')
534 endif 547 endif
535 if a:0 548 if a:0
536 let alttail = strpart(alttail, j) 549 let alttail = strpart(alttail, j)
537 let j = matchend(alttail, s:notslash . a:comma) 550 let j = matchend(alttail, s:notslash .. a:comma)
538 endif 551 endif
539 endwhile 552 endwhile
540 if a:0 553 if a:0
541 let current = current . a:comma . strpart(alttail, 0, j-1) 554 let current = current .. a:comma .. strpart(alttail, 0, j-1)
542 endif 555 endif
543 return current 556 return current
544 endfun 557 endfun
545 558
546 fun! matchit#Match_debug() 559 fun! matchit#Match_debug()
560 " tail = 'else\|endif' piece, with all backrefs resolved from match 573 " tail = 'else\|endif' piece, with all backrefs resolved from match
561 amenu &Matchit.&tail :echo b:match_tail<CR> 574 amenu &Matchit.&tail :echo b:match_tail<CR>
562 " fin = 'endif' piece, with all backrefs resolved from match 575 " fin = 'endif' piece, with all backrefs resolved from match
563 amenu &Matchit.&word :echo b:match_word<CR> 576 amenu &Matchit.&word :echo b:match_word<CR>
564 " '\'.d in ini refers to the same thing as '\'.table[d] in word. 577 " '\'.d in ini refers to the same thing as '\'.table[d] in word.
565 amenu &Matchit.t&able :echo '0:' . b:match_table . ':9'<CR> 578 amenu &Matchit.t&able :echo '0:' .. b:match_table .. ':9'<CR>
566 endfun 579 endfun
567 580
568 " Jump to the nearest unmatched "(" or "if" or "<tag>" if a:spflag == "bW" 581 " Jump to the nearest unmatched "(" or "if" or "<tag>" if a:spflag == "bW"
569 " or the nearest unmatched "</tag>" or "endif" or ")" if a:spflag == "W". 582 " or the nearest unmatched "</tag>" or "endif" or ")" if a:spflag == "W".
570 " Return a "mark" for the original position, so that 583 " Return a "mark" for the original position, so that
596 else 609 else
597 execute "let match_words =" b:match_words 610 execute "let match_words =" b:match_words
598 endif 611 endif
599 if (match_words != s:last_words) || (&mps != s:last_mps) || 612 if (match_words != s:last_words) || (&mps != s:last_mps) ||
600 \ exists("b:match_debug") 613 \ exists("b:match_debug")
601 let default = escape(&mps, '[$^.*~\\/?]') . (strlen(&mps) ? "," : "") . 614 let default = escape(&mps, '[$^.*~\\/?]') .. (strlen(&mps) ? "," : "") ..
602 \ '\/\*:\*\/,#\s*if\%(n\=def\)\=:#\s*else\>:#\s*elif\>:#\s*endif\>' 615 \ '\/\*:\*\/,#\s*if\%(n\=def\)\=:#\s*else\>:#\s*elif\>:#\s*endif\>'
603 let s:last_mps = &mps 616 let s:last_mps = &mps
604 let match_words = match_words . (strlen(match_words) ? "," : "") . default 617 let match_words = match_words .. (strlen(match_words) ? "," : "") .. default
605 let s:last_words = match_words 618 let s:last_words = match_words
606 if match_words !~ s:notslash . '\\\d' 619 if match_words !~ s:notslash .. '\\\d'
607 let s:do_BR = 0 620 let s:do_BR = 0
608 let s:pat = match_words 621 let s:pat = match_words
609 else 622 else
610 let s:do_BR = 1 623 let s:do_BR = 1
611 let s:pat = s:ParseWords(match_words) 624 let s:pat = s:ParseWords(match_words)
612 endif 625 endif
613 let s:all = '\%(' . substitute(s:pat, '[,:]\+', '\\|', 'g') . '\)' 626 let s:all = '\%(' .. substitute(s:pat, '[,:]\+', '\\|', 'g') .. '\)'
614 if exists("b:match_debug") 627 if exists("b:match_debug")
615 let b:match_pat = s:pat 628 let b:match_pat = s:pat
616 endif 629 endif
617 " Reconstruct the version with unresolved backrefs. 630 " Reconstruct the version with unresolved backrefs.
618 let s:patBR = substitute(match_words.',', 631 let s:patBR = substitute(match_words .. ',',
619 \ s:notslash.'\zs[,:]*,[,:]*', ',', 'g') 632 \ s:notslash .. '\zs[,:]*,[,:]*', ',', 'g')
620 let s:patBR = substitute(s:patBR, s:notslash.'\zs:\{2,}', ':', 'g') 633 let s:patBR = substitute(s:patBR, s:notslash .. '\zs:\{2,}', ':', 'g')
621 endif 634 endif
622 635
623 " Second step: figure out the patterns for searchpair() 636 " Second step: figure out the patterns for searchpair()
624 " and save the screen, cursor position, and 'ignorecase'. 637 " and save the screen, cursor position, and 'ignorecase'.
625 " - TODO: A lot of this is copied from matchit#Match_wrapper(). 638 " - TODO: A lot of this is copied from matchit#Match_wrapper().
626 " - maybe even more functionality should be split off 639 " - maybe even more functionality should be split off
627 " - into separate functions! 640 " - into separate functions!
628 let openlist = split(s:pat . ',', s:notslash . '\zs:.\{-}' . s:notslash . ',') 641 let openlist = split(s:pat .. ',', s:notslash .. '\zs:.\{-}' .. s:notslash .. ',')
629 let midclolist = split(',' . s:pat, s:notslash . '\zs,.\{-}' . s:notslash . ':') 642 let midclolist = split(',' .. s:pat, s:notslash .. '\zs,.\{-}' .. s:notslash .. ':')
630 call map(midclolist, {-> split(v:val, s:notslash . ':')}) 643 call map(midclolist, {-> split(v:val, s:notslash .. ':')})
631 let closelist = [] 644 let closelist = []
632 let middlelist = [] 645 let middlelist = []
633 call map(midclolist, {i,v -> [extend(closelist, v[-1 : -1]), 646 call map(midclolist, {i,v -> [extend(closelist, v[-1 : -1]),
634 \ extend(middlelist, v[0 : -2])]}) 647 \ extend(middlelist, v[0 : -2])]})
635 call map(openlist, {i,v -> v =~# s:notslash . '\\|' ? '\%(' . v . '\)' : v}) 648 call map(openlist, {i,v -> v =~# s:notslash .. '\\|' ? '\%(' .. v .. '\)' : v})
636 call map(middlelist, {i,v -> v =~# s:notslash . '\\|' ? '\%(' . v . '\)' : v}) 649 call map(middlelist, {i,v -> v =~# s:notslash .. '\\|' ? '\%(' .. v .. '\)' : v})
637 call map(closelist, {i,v -> v =~# s:notslash . '\\|' ? '\%(' . v . '\)' : v}) 650 call map(closelist, {i,v -> v =~# s:notslash .. '\\|' ? '\%(' .. v .. '\)' : v})
638 let open = join(openlist, ',') 651 let open = join(openlist, ',')
639 let middle = join(middlelist, ',') 652 let middle = join(middlelist, ',')
640 let close = join(closelist, ',') 653 let close = join(closelist, ',')
641 if exists("b:match_skip") 654 if exists("b:match_skip")
642 let skip = b:match_skip 655 let skip = b:match_skip
643 elseif exists("b:match_comment") " backwards compatibility and testing! 656 elseif exists("b:match_comment") " backwards compatibility and testing!
644 let skip = "r:" . b:match_comment 657 let skip = "r:" .. b:match_comment
645 else 658 else
646 let skip = 's:comment\|string' 659 let skip = 's:comment\|string'
647 endif 660 endif
648 let skip = s:ParseSkip(skip) 661 let skip = s:ParseSkip(skip)
649 let view = winsaveview() 662 let view = winsaveview()
650 663
651 " Third step: call searchpair(). 664 " Third step: call searchpair().
652 " Replace '\('--but not '\\('--with '\%(' and ',' with '\|'. 665 " Replace '\('--but not '\\('--with '\%(' and ',' with '\|'.
653 let openpat = substitute(open, '\%(' . s:notslash . '\)\@<=\\(', '\\%(', 'g') 666 let openpat = substitute(open, '\%(' .. s:notslash .. '\)\@<=\\(', '\\%(', 'g')
654 let openpat = substitute(openpat, ',', '\\|', 'g') 667 let openpat = substitute(openpat, ',', '\\|', 'g')
655 let closepat = substitute(close, '\%(' . s:notslash . '\)\@<=\\(', '\\%(', 'g') 668 let closepat = substitute(close, '\%(' .. s:notslash .. '\)\@<=\\(', '\\%(', 'g')
656 let closepat = substitute(closepat, ',', '\\|', 'g') 669 let closepat = substitute(closepat, ',', '\\|', 'g')
657 let middlepat = substitute(middle, '\%(' . s:notslash . '\)\@<=\\(', '\\%(', 'g') 670 let middlepat = substitute(middle, '\%(' .. s:notslash .. '\)\@<=\\(', '\\%(', 'g')
658 let middlepat = substitute(middlepat, ',', '\\|', 'g') 671 let middlepat = substitute(middlepat, ',', '\\|', 'g')
659 672
660 if skip =~ 'synID' && !(has("syntax") && exists("g:syntax_on")) 673 if skip =~ 'synID' && !(has("syntax") && exists("g:syntax_on"))
661 let skip = '0' 674 let skip = '0'
662 else 675 else
663 try 676 try
664 execute "if " . skip . "| let skip = '0' | endif" 677 execute "if " .. skip .. "| let skip = '0' | endif"
665 catch /^Vim\%((\a\+)\)\=:E363/ 678 catch /^Vim\%((\a\+)\)\=:E363/
666 " We won't find anything, so skip searching, should keep Vim responsive. 679 " We won't find anything, so skip searching, should keep Vim responsive.
667 return {} 680 return {}
668 endtry 681 endtry
669 endif 682 endif
742 " R:foo becomes (line before cursor) !~ foo 755 " R:foo becomes (line before cursor) !~ foo
743 fun! s:ParseSkip(str) 756 fun! s:ParseSkip(str)
744 let skip = a:str 757 let skip = a:str
745 if skip[1] == ":" 758 if skip[1] == ":"
746 if skip[0] == "s" 759 if skip[0] == "s"
747 let skip = "synIDattr(synID(line('.'),col('.'),1),'name') =~? '" . 760 let skip = "synIDattr(synID(line('.'),col('.'),1),'name') =~? '" ..
748 \ strpart(skip,2) . "'" 761 \ strpart(skip,2) .. "'"
749 elseif skip[0] == "S" 762 elseif skip[0] == "S"
750 let skip = "synIDattr(synID(line('.'),col('.'),1),'name') !~? '" . 763 let skip = "synIDattr(synID(line('.'),col('.'),1),'name') !~? '" ..
751 \ strpart(skip,2) . "'" 764 \ strpart(skip,2) .. "'"
752 elseif skip[0] == "r" 765 elseif skip[0] == "r"
753 let skip = "strpart(getline('.'),0,col('.'))=~'" . strpart(skip,2). "'" 766 let skip = "strpart(getline('.'),0,col('.'))=~'" . strpart(skip,2). "'"
754 elseif skip[0] == "R" 767 elseif skip[0] == "R"
755 let skip = "strpart(getline('.'),0,col('.'))!~'" . strpart(skip,2). "'" 768 let skip = "strpart(getline('.'),0,col('.'))!~'" . strpart(skip,2). "'"
756 endif 769 endif