O que [%,]%, a% de matchit.vim faz?


7

Os matchit %/ g%são simples de usar, mas estou tendo problemas para entender os outros mapeamentos, que parecem potencialmente úteis, mas parecem não funcionar de maneira compreensível.

]%  Go to [count] next unmatched group, as specified by
    |b:match_words|.  Similar to |]}|.

Eu esperaria que isso talvez me permitisse pular para endif, endfunctionetc. Pegue o exemplo vimscript a seguir, usando o vim ftplugin interno ( b:match_wordsparece estar definido).

function! SuperTab()
  let l:part = strpart(getline('.'),col('.')-2,1)
  if (l:part=~'^\W\?$')
      return "\<Tab>"
  else
      return "\<C-n>"
  endif
endfunction

[%na maioria das vezes pula para function!, ocasionalmente (inconsistentemente dependendo da posição do cursor) pula para ife ignora totalmente (s. ]%salta para se )nada mais. va%se comporta de maneira idêntica [%neste exemplo e não seleciona nada. Esse comportamento é normal? Existe algum exemplo em que esses mapeamentos fazem sentido?


11
Boa pergunta! Pensei em habilitá-lo e encontrar uma resposta, mas estou tão perplexo quanto você. Tanto quanto eu posso ver ]%, quase nada. Vou ter que dar uma olhada no código.
B Camada

Eu acho que pode ser apenas um buggy. Tanto quanto posso constatar na documentação e nos comentários no código, ele deve funcionar como você sugeriu. Possivelmente alguém (@BLayer? Ou talvez eu!) Dê uma olhada no código real e diga por que / como isso dá errado.
Rich

Vou tentar responder neste fim de semana. Fiz um pouco de cutucada há algum tempo e tenho certeza de que está muito bugado, mas não o depurei profundamente.
B Camada de

Eu apenas tentei o matchit do neovim no vim (surpreendentemente é diferente do do vim) e parece funcionar .. github.com/neovim/neovim/blob/master/runtime/plugin/matchit.vim
Mass

11
No entanto, o neovim va% ((( )))não "expande" após repetido a%. Eu não tenho certeza se o vim já fez, mas eu deveria a(.
Missa

Respostas:


6

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

insira a descrição da imagem aqui


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.

insira a descrição da imagem aqui


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]%

insira a descrição da imagem aqui


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.


abra questões para os vários problemas que você corrigiu em github.com/chrisbra/matchit
Christian Brabandt

@ChristianBrabandt Ok, eu abri 2 questões para discutir os ]%e v_a%mapeamentos que podem ser alteradas um pouco.
user852573

Resposta incrível! Estou um pouco surpreso com o quão aparentemente poucas pessoas usam esses recursos, mas estou feliz que possamos entender o que está acontecendo agora.
Missa
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.