commit 9ca69488cf08d78609ad4baef50bbcbbc937a9b7
parent 1b83b00fff40e13ecea06246ca33c2f41256a968
Author: zeertzjq <zeertzjq@outlook.com>
Date: Fri, 9 Jan 2026 09:37:43 +0800
vim-patch:e80a4ed: runtime(matchit): Update to Release 1.21
closes: vim/vim#19109
https://github.com/vim/vim/commit/e80a4ed845a76ab2d57cb154d9cd10df605c0971
Co-authored-by: Christian Brabandt <cb@256bit.org>
Diffstat:
3 files changed, 88 insertions(+), 21 deletions(-)
diff --git a/runtime/pack/dist/opt/matchit/autoload/matchit.vim b/runtime/pack/dist/opt/matchit/autoload/matchit.vim
@@ -1,6 +1,6 @@
" matchit.vim: (global plugin) Extended "%" matching
" autload script of matchit plugin, see ../plugin/matchit.vim
-" Last Change: May 20, 2024
+" Last Change: Jan 06, 2025
" Neovim does not support scriptversion
if has("vimscript-4")
@@ -69,6 +69,26 @@ function matchit#Match_wrapper(word, forward, mode) range
let startpos = [line("."), col(".")]
endif
+ " Check for custom match function hook
+ if exists("b:match_function")
+ let MatchFunc = b:match_function
+ try
+ let result = call(MatchFunc, [a:forward])
+ if !empty(result)
+ call cursor(result)
+ return s:CleanUp(restore_options, a:mode, startpos)
+ endif
+ catch /.*/
+ if exists("b:match_debug")
+ echohl WarningMsg
+ echom 'matchit: b:match_function error: ' .. v:exception
+ echohl NONE
+ endif
+ return s:CleanUp(restore_options, a:mode, startpos)
+ endtry
+ " Empty result: fall through to regular matching
+ endif
+
" 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
@@ -91,7 +111,7 @@ function matchit#Match_wrapper(word, forward, mode) range
let default = escape(&mps, '[$^.*~\\/?]') .. (strlen(&mps) ? "," : "") ..
\ '\/\*:\*\/,#\s*if\%(n\=def\)\=:#\s*else\>:#\s*elif\%(n\=def\)\=\>:#\s*endif\>'
" s:all = pattern with all the keywords
- let match_words = match_words .. (strlen(match_words) ? "," : "") .. default
+ let match_words = s:Append(match_words, default)
let s:last_words = match_words
if match_words !~ s:notslash .. '\\\d'
let s:do_BR = 0
@@ -101,8 +121,8 @@ function matchit#Match_wrapper(word, forward, mode) range
let s:pat = s:ParseWords(match_words)
endif
let s:all = substitute(s:pat, s:notslash .. '\zs[,:]\+', '\\|', 'g')
- " un-escape \, to ,
- let s:all = substitute(s:all, '\\,', ',', 'g')
+ " un-escape \, and \: to , and :
+ let s:all = substitute(s:all, s:notslash .. '\zs\\\(:\|,\)', '\1', 'g')
" Just in case there are too many '\(...)' groups inside the pattern, make
" sure to use \%(...) groups, so that error E872 can be avoided
let s:all = substitute(s:all, '\\(', '\\%(', 'g')
@@ -342,6 +362,18 @@ fun! s:InsertRefs(groupBR, prefix, group, suffix, matchline)
return ini .. ":" .. tailBR
endfun
+" String append item2 to item and add ',' in between items
+fun! s:Append(item, item2)
+ if a:item == ''
+ return a:item2
+ endif
+ " there is already a trailing comma, don't add another one
+ if a:item[-1:] == ','
+ return a:item .. a:item2
+ endif
+ return a:item .. ',' .. a:item2
+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:
@@ -539,8 +571,8 @@ fun! s:Choose(patterns, string, comma, branch, prefix, suffix, ...)
else
let currpat = substitute(current, s:notslash .. a:branch, '\\|', 'g')
endif
- " un-escape \, to ,
- let currpat = substitute(currpat, '\\,', ',', 'g')
+ " un-escape \, and \: to , and :
+ let currpat = substitute(currpat, s:notslash .. '\zs\\\(:\|,\)', '\1', 'g')
while a:string !~ a:prefix .. currpat .. a:suffix
let tail = strpart(tail, i)
let i = matchend(tail, s:notslash .. a:comma)
@@ -553,6 +585,8 @@ fun! s:Choose(patterns, string, comma, branch, prefix, suffix, ...)
else
let currpat = substitute(current, s:notslash .. a:branch, '\\|', 'g')
endif
+ " un-escape \, and \: to , and :
+ let currpat = substitute(currpat, s:notslash .. '\zs\\\(:\|,\)', '\1', 'g')
if a:0
let alttail = strpart(alttail, j)
let j = matchend(alttail, s:notslash .. a:comma)
@@ -622,7 +656,7 @@ fun! matchit#MultiMatch(spflag, mode)
let default = escape(&mps, '[$^.*~\\/?]') .. (strlen(&mps) ? "," : "") ..
\ '\/\*:\*\/,#\s*if\%(n\=def\)\=:#\s*else\>:#\s*elif\>:#\s*endif\>'
let s:last_mps = &mps
- let match_words = match_words .. (strlen(match_words) ? "," : "") .. default
+ let match_words = s:Append(match_words, default)
let s:last_words = match_words
if match_words !~ s:notslash .. '\\\d'
let s:do_BR = 0
diff --git a/runtime/pack/dist/opt/matchit/doc/matchit.txt b/runtime/pack/dist/opt/matchit/doc/matchit.txt
@@ -1,13 +1,7 @@
-*matchit.txt* Extended |%| matching
+*matchit.txt* Extended |%| matching Last change: 2026 Jan 06
-For instructions on installing this file, type
- `:help matchit-install`
-inside Vim.
+ VIM REFERENCE MANUAL by Benji Fisher et al
-For Vim version 9.1. Last change: 2024 May 20
-
-
- VIM REFERENCE MANUAL by Benji Fisher et al
*matchit* *matchit.vim*
@@ -176,7 +170,7 @@ defined automatically.
2.1 Temporarily disable the matchit plugin *matchit-disable* *:MatchDisable*
-To temporarily disable the matchit plugin, after it hat been loaded,
+To temporarily disable the matchit plugin, after it has been loaded,
execute this command: >
:MatchDisable
@@ -263,6 +257,45 @@ Examples:
See the $VIMRUNTIME/ftplugin/vim.vim for an example that uses both
syntax and a regular expression.
+ *b:match_function*
+If b:match_function is defined, matchit.vim will first call this function to
+perform matching. This is useful for languages with an indentation-based block
+structure (such as Python) or other complex matching requirements that cannot
+be expressed with regular expression patterns.
+
+The function should accept one argument:
+ forward - 1 for forward search (% command)
+ 0 for backward search (g% command)
+
+The function should return a list with one of these values:
+ [line, col] - Match found at the specified position
+ [] - No match found; fall through to regular matching
+ (|b:match_words|, matchpairs, etc.)
+
+The cursor position is not changed by the function; matchit handles cursor
+movement based on the returned position.
+
+If the function throws an error, matchit gives up and doesn't continue.
+Enable |b:match_debug| to see error messages from custom match functions.
+
+Python example (simplified): >
+ let s:keywords = {'if': 'elif\|else', 'elif': 'elif\|else'}
+
+ function! s:PythonMatch(forward) abort
+ let keyword = matchstr(getline('.'), '^\s*\zs\w\+')
+ let pattern = get(s:keywords, keyword, '')
+ if empty(pattern) | return [] | endif
+
+ let flags = a:forward ? 'nW' : 'nbW'
+ let [lnum, col] = searchpos('^\s*\%(' . pattern . '\)\>', flags, 0, 0,
+ \ 'indent(".") != ' . indent('.'))
+ return lnum > 0 ? [lnum, col] : []
+ endfunction
+
+ let b:match_function = function('s:PythonMatch')
+<
+See |matchit-newlang| below for more details on supporting new languages.
+
==============================================================================
4. Supporting a New Language *matchit-newlang*
*b:match_words*
@@ -274,9 +307,9 @@ 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.
+list of patterns (regular expressions). Commas and colons 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 = '\<if\>:\<endif\>,'
\ . '\<while\>:\<continue\>:\<break\>:\<endwhile\>'
@@ -319,7 +352,7 @@ expression >
if keywords are only recognized after the start of a line or after a
semicolon (;), with optional white space.
- *matchit-backref* *matchit-\1*
+ *matchit-backref*
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, >
diff --git a/runtime/pack/dist/opt/matchit/plugin/matchit.vim b/runtime/pack/dist/opt/matchit/plugin/matchit.vim
@@ -1,6 +1,6 @@
" matchit.vim: (global plugin) Extended "%" matching
" Maintainer: Christian Brabandt
-" Version: 1.20
+" Version: 1.21
" Last Change: 2024 May 20
" Repository: https://github.com/chrisbra/matchit
" Previous URL:http://www.vim.org/script.php?script_id=39