Criar automaticamente chaves correspondentes no vim

17

Como crio automaticamente chaves correspondentes no vim?

Ele deve funcionar da seguinte maneira: Se eu inserir uma chave aberta, a chave de fechamento deve aparecer automaticamente e o cursor deve ser colocado no meio. Para pular para fora do par de chaves, a combinação Ctrl-jé usada.

Existem muitos plugins que fornecem a inserção automática de chaves. Mas eles

  • use uma combinação de teclas diferente da que Ctrl-jpular para fora do par de chaves ou
  • interferir nas ligações de teclas do UltiSnips .

O seguinte funciona como esperado

:inoremap ( ()<Esc>:let leavechar=")"<CR>i
:imap <C-j> <Esc>:exec "normal f" . leavechar<CR>a

Mas com essas configurações, os trechos do UltiSnips não funcionam mais. Então, usei o UltiSnips para inserir a chave de fechamento:

inoremap ( (<C-R>=UltiSnips_Anon('($1)$0', '(')<CR>

Isso quase funciona. A chave correspondente é inserida e posso pular a chave de fechamento com Ctrl-j. Isso, no entanto, funciona apenas se houver um espaço na frente da chave aberta.

main () // works, the closing parentheses is added
main(   // fails without a space

Minhas soluções exigem uma ligação de tecla diferente para pular a chave de fechamento ou exigem um espaço na frente da chave aberta. Como consertar isto?

Nota: usei parênteses como exemplo. Ele deve funcionar com parênteses, chaves, colchetes e sinais de menor que e não interferir no plug-in UltiSnips.

Marco
fonte
1
Você já tentou fechar automaticamente ? Você pode pular de pares com ), remapear c-jpara isso pode funcionar.
21712 Kevin

Respostas:

4

Como crio automaticamente chaves correspondentes no vim?

Esse problema não é trivial, como você verá. A resposta simples é: Use um plugin, como autoclose ou smartinput . Apenas remapeando ingenuamente (as teclas [.. apresentarão algumas bordas em algumas linhas, é por isso que esses plugins são feitos e por que eles geralmente são bastante complexos (se são bons).

Então usei o UltiSnips para inserir a chave de fechamento

Você pode tentar fazer isso (que é diferente da minha sugestão original):

inoremap ( ()<CR>=UltiSnips_Anon('$1)$0', ')')<CR>

Onde o UltiSnips dividirá a linha em (vez de incluir mainna partida. O problema com o uso de um plug-in de snippet para isso é que eles (geralmente) não suportam aninhamento; portanto, esquecerão todas as posições de salto quando o próximo snippet (aninhado) for inserido.

Para pular para fora do par de chaves, a combinação Ctrl-jé usada.

Você pode remapear Ctrl-jpara o UltiSnips ou o plugin conflitante. Se os mapeamentos não estiverem listados na documentação, você pode usar :map/imap/nmap <key>para mostrar o mapeamento. Se você deseja Ctrl-jescolher e executar o trabalho de ambos os plugins, está solicitando:

  1. algo muito mais avançado do que eu imagino que você possa pensar
  2. algo que eu suspeito que você realmente não quer

Considere este loop bash:

while (( ${arr1[i]} < ${arr2[i<CURSOR>]} )); do
  [next_snippet_position_marker]
done

Nesse caso, você precisará pressionar Ctrl-j5 vezes para chegar ao corpo do loop. Usar as chaves de fechamento para pular para fora de um par correspondente oferece muito mais controle sobre onde você realmente deseja que o cursor se mova. Você pode implementar uma pilha para acompanhar os pares inseridos e usá Ctrl-j-los para mover e mover, mas depois terá problemas se começar a excluir manualmente os aparelhos sem removê-los da pilha. Então você começará a resolver problemas que os plug-ins estão tentando resolver. É uma roda difícil de reinventar.

Expandindo isso, você pode obter o que solicitou inicialmente, usando Ctrl-jpara pular de chaves e trechos. Se você usar algum valor fictício para representar as posições dos trechos e empurrá-los para a pilha, além das chaves de fechamento, com o remapeamento dinâmico de Ctrl-jpara corresponder à entrega de trechos ou chaves. Mas você precisará implementar algumas heurísticas bastante avançadas para descobrir qual mágica deve acontecer, já que você está enfrentando dois problemas ao mesmo tempo, que estão sendo resolvidos pelos criadores dos plug-ins de inserção de trechos e plug-ins de correspondência separadamente, e resolvendo esses problemas novamente, além de suas soluções, para obter comodidade e, bem, mágica.

Tudo se resume ao controle versus conveniência. Eu acho que o controle irá atendê-lo melhor nesse caso, o que significa que você deve manter esses problemas e seus plugins e chaves associados separados. Se você ainda quer conveniência, é factível, mas é difícil.

aktivb
fonte
1

Eu acho que delimitMate faz o que você precisa.

Fecha automaticamente parênteses ou aspas e coloca o cursor no meio. Para pular de um par de parênteses (enquanto estiver no modo de inserção), você faria Ctrl-g+, gmas poderá remapear isso Ctrl-jadicionando isso ao seu vimrc:

% Jump out of a block of parentheses (uses delimitMate)
imap <C-j> <C-g>g
Matthias Braun
fonte
É melhor fornecer mais detalhes aqui e usar o link como referência para leitura adicional. Dessa forma, sua resposta não perde todo o valor quando o link se torna inválido.
Anthon
1

Eu encontrei o fechamento automático adicionando um pouco de atraso e também interferindo na minha configuração (Ultisnips e Supertab), mas eu gosto da abordagem de emular o Eclipse CDT.

Uso delimitMate com os seguintes mapas para ajudar na navegação e no recuo, tentando obter os mesmos resultados:

imap <C-F> <C-G>g           " To jump out brackets in same line.
inoremap <C-K> <ESC>ki<TAB> " To move and insert an indent on the line before the current cursor (assuming empty line)

Eu o uso desta maneira: insira a abertura { <CR><CR><C-K>e comece a escrever na linha interna recuada.

phcerdan
fonte
Eu encontrei delimitMate para estar adicionando um pequeno atraso também
icc97
1

Pessoalmente, eu uso o smartinput para inserção automática de colchetes e aspas. Por exemplo, digitar em {qualquer lugar produzirá {}com o cursor no meio. Para sair do {grupo de colchetes, basta digitar o }quando ao lado do inserido }.

No entanto, isso suporta sua exigência de tabstops e saltar para fora do suporte. Ele também não cria um novo entre seus colchetes, mas você só precisa de uma chave extra para isso - <CR>.

Você pode mapear <C-J>para ir para a próxima linha abaixo:

:inoremap <C-J> <C-O>j

ou se você quiser passar para o início da próxima linha:

:inoremap <C-J> <C-O>+
Tom Cammann
fonte
0

Algo como isso pode funcionar para você.

inoremap {      {}<Left>
inoremap {<CR>  {<CR>}<Esc>O
inoremap {{     {
inoremap {}     {}
Mark Cohen
fonte
O que você sugere é um mapeamento simples que não permite pular a chave de fechamento.
Marco
0

Na verdade, o Ultisnips pode fazer isso quase perfeitamente (isso pode ser novo). Modificando levemente as respostas dadas acima, tenho um bom sucesso com

inoremap () ()<C-R>=UltiSnips#Anon('($1)$0', '()', 'double parentheses', 'i')<CR>

É preciso digitar ()quais são as melhores, mas que também podem ser alteradas (. Em seguida, os argumentos opcionais adicionais UltiSnips#Anonsão uma descrição e o modificador ique permite a expansão em palavras.

Saltar entre parênteses com <c-j>obras, também aninhadas em outros trechos. No entanto, invocar ()parênteses aninhados parece quebrar esse recurso, o que não é grande coisa.

user3240588
fonte