Eu vou assumir que você usa a matchitversão mais recente do plugin 1.13.3 que eu encontrei no momento no repositório github do Vim.
[%na maioria das vezes pula para function!, ocasionalmente (inconsistentemente dependendo da posição do cursor) pula para ife ignora totalmente (s.
Quando você pressiona [%, a s:MultiMatch()função é invocada. No final deste último, há um whileloop cujo número de iterações é v:count1. Esta variável armazena a contagem para o último comando normal. Aqui deve ser 1, porque você não atingiu nenhum número antes [%. Mas no meio da função, alguns :normalcomandos são executados para salvar a tela e a posição do cursor. Esses comandos normais alteram o valor de v:count1.
Você pode verificar isso assim:
nno cd :<c-u>call Func()<cr>
fu! Func()
echom v:count1
endfu
Origem deste código, e pressione cd, leia suas mensagens ( :messages): você deve ver 1, porque você não atingiu nenhum número antes cd. Agora, forneça este código:
nno cd :<c-u>call Func()<cr>
fu! Func()
norm! 3G
echom v:count1
endfu
E faça o mesmo experimento, pressione cdum arquivo com mais de 3 linhas. Desta vez, nas mensagens, você deve ver 3, não 1.
Por esse motivo, a searchpair()função dentro do loop é invocada muitas vezes, o que, suspeito, explica o comportamento que você descreveu. Pelo menos, ele faz na minha máquina ( 8.0patches Linux, Vim 1-134).
Para corrigir isso, você pode excluir a linha 729 :
let level = v:count1
E mova-o no início da função (antes que outros comandos, incluindo :normalcomandos, tenham a chance de alterar v:count1):
fun! s:MultiMatch(spflag, mode)
if !exists("b:match_words") || b:match_words == ""
return ""
end
let level = v:count1

Eu apenas tentei o matchit do neovim no vim (surpreendentemente é diferente do do vim) e parece funcionar .. estranho
Provavelmente, é por causa da solicitação de recebimento nº 5124 que o neovim foi mesclado há um ano. De acordo com a mensagem de confirmação, seu objetivo era impedir matchita adição de uma entrada indesejada no jumplist. Para resolver isso, a confirmação mudou como as posições da tela e do cursor foram salvas. Ele não usa :normalmais comandos, mas chama a função winsaveview()e winrestview(). Ao se livrar :normal, para uma finalidade diferente, eles também corrigiram o problema que você descreveu anteriormente, porque v:count1não é mais modificado. Embora possa ser no futuro se alguns comandos forem adicionados no meio da função.
]%salta para se )nada mais.
No final da s:MultiMatch()função, linha 722 , o padrão que descreve a parte final de um grupo de tokens é definido assim:
let closepat = substitute(closepat, ',', '\\|', 'g')
O objetivo da substituição é substituir cada vírgula, que separa 2 grupos consecutivos de tokens, por uma barra de escape duplo que será interpretada pelo mecanismo de expressão regular do Vim como uma alternância (separação entre 2 ramificações). Penso que a substituição também deve substituir os dois pontos :que separam os tokens dentro de cada grupo. Então, você pode reescrever a substituição assim:
let closepat = substitute(closepat, '[,:]', '\\|', 'g')
Com essa alteração, ]%mova o cursor nos vários tokens descritos em b:match_wordse &l:matchpairs, não apenas ). Pelo menos, faz na minha máquina.

va%se comporta de maneira idêntica [%neste exemplo e não seleciona nada.
Com as alterações anteriores, em particular a 2ª, va%deve-se selecionar o texto entre os 2 tokens circundantes. Embora, o plug-in pareça tratar a parte do meio de um grupo de tokens (como elseem if|else|endif) como uma parte final (é passada para searchpair()o terceiro argumento, não o segundo). Portanto, o que considera serem os tokens circundantes às vezes pode surpreendê-lo.
No entanto, o neovim va% ((( )))não "expande" após repetido a%. Não tenho certeza se vim já fez, mas eu deveria. assim como a(.
Atualmente, o mapeamento visual a%é definido na linha 71, assim:
vmap a% <Esc>[%v]%
Quando adiciono ono início do {rhs}, para mover o cursor para o início da seleção ( :h v_o), recebo o comportamento que você deseja:
vmap a% o<Esc>[%v]%

Aqui está uma versão do matchitplugin, com as três pequenas alterações descritas até agora.
E aqui está outro onde eu tentei incluir também o PR # 5124 da Neovim.
Se você deseja testar o código em sua máquina, mas não tem o direito de alterar o matchitplug-in padrão (ou não deseja), é possível criar o arquivo ~/.vim/plugin/matchit.vime escrever matchitnele o plug-in experimental .
Como no caminho de execução, ~/.vimvem antes $VIMRUNTIME, o Vim deve originar sua versão personalizada antes da versão padrão. E desde então, o plugin padrão tem a guarda:
if exists("loaded_matchit") || &cp
finish
endif
let loaded_matchit = 1
... apenas sua versão deve ser totalmente originada.
]%, quase nada. Vou ter que dar uma olhada no código.