Créez automatiquement des accolades correspondantes dans vim


17

Comment créer automatiquement des accolades correspondantes dans vim?

Cela devrait fonctionner comme suit: Si j'entre une accolade ouverte, la fermeture devrait apparaître automatiquement et le curseur devrait être placé entre les deux. Pour sauter hors de la paire d'accolades, la combinaison Ctrl-jest utilisée.

Il existe de nombreux plugins permettant l'insertion automatique des accolades. Mais ils

  • soit utiliser une combinaison de touches différente de celle Ctrl-j de sauter hors de la paire d'accolades ou
  • interférer avec les raccourcis clavier UltiSnips .

Les travaux suivants comme prévu

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

Mais avec ces paramètres, les extraits de code UltiSnips ne fonctionnent plus. J'ai donc utilisé UltiSnips pour insérer l'accolade de fermeture:

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

Cela fonctionne presque. L'entretoise correspondante est insérée et je peux sauter celle de fermeture avec Ctrl-j. Cependant, cela ne fonctionne que s'il y a un espace devant l'accolade ouverte.

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

Mes solutions nécessitent soit une liaison de clé différente pour sauter par-dessus l'accolade de fermeture, soit un espace devant l'ouverture. Comment régler ceci?

Remarque: j'ai utilisé des parenthèses comme exemple. Il devrait fonctionner avec des parenthèses, des accolades, des crochets et des signes inférieurs à et ne pas interférer avec le plugin UltiSnips.


1
Avez-vous essayé la fermeture automatique ? Vous pouvez sortir de paires avec ), remapper c-jà cela pourrait fonctionner.
Kevin

Réponses:


4

Comment créer automatiquement des accolades correspondantes dans vim?

Ce problème n'est pas anodin, comme vous le verrez. La réponse simple est: utilisez un plugin, comme autoclose ou smartinput . Le remappage naïf des touches ([.. vous présentera des boîtiers électroniques en quelques lignes, c'est pourquoi ces plugins sont créés et pourquoi ils sont généralement assez complexes (s'ils sont bons).

J'ai donc utilisé UltiSnips pour insérer l'accolade de fermeture

Vous pouvez essayer ceci à la place (ce qui est différent de ma suggestion d'origine):

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

Où UltiSnips divisera la ligne au (lieu de l'inclure maindans le match. Le problème avec l'utilisation d'un plugin d'extrait de code pour cela est qu'ils ne prennent généralement pas en charge l'imbrication, ils oublieront donc toutes les positions de saut lors de l'insertion du prochain extrait de code (imbriqué).

Pour sauter hors de la paire d'accolades, la combinaison Ctrl-jest utilisée.

Vous pouvez remapper Ctrl-jpour UltiSnips ou le plugin en conflit. Si les mappages ne sont pas répertoriés dans la documentation, vous pouvez utiliser :map/imap/nmap <key>pour afficher le mappage. Si vous voulez Ctrl-jchoisir et faire le travail des deux plugins, vous demandez:

  1. quelque chose de beaucoup plus avancé que je pense que vous pourriez penser
  2. quelque chose que je soupçonne que vous ne voulez pas vraiment

Considérez cette boucle bash:

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

Dans ce cas, vous devrez appuyer Ctrl-j5 fois pour accéder au corps de la boucle. L'utilisation des accolades de fermeture pour sauter hors d'une paire correspondante vous donne beaucoup plus de contrôle sur l'endroit où vous souhaitez réellement déplacer le curseur. Vous pouvez implémenter une pile pour garder une trace des paires insérées et utiliser Ctrl-jpour sauter et déplacer, mais vous rencontrerez des problèmes si vous commencez à supprimer manuellement des accolades sans les supprimer de la pile. Vous allez donc commencer à résoudre les problèmes que les plug-ins d'accolade tentent de résoudre. C'est une roue difficile à réinventer.

En développant cela, vous pouvez obtenir ce que vous avez initialement demandé, en utilisant Ctrl-jpour sauter des accolades et des extraits. Si vous utilisez une valeur fictive pour représenter les positions des extraits et les pousser sur la pile en plus des accolades fermantes, avec un remappage dynamique de Ctrl-jpour correspondre à la remise d'extraits ou d'accolades. Mais ensuite, vous devrez implémenter des heuristiques assez avancées pour comprendre ce que la magie devrait se produire, car vous rencontrez essentiellement deux problèmes à la fois, qui sont actuellement résolus séparément par les créateurs de plugins d'insertion d'extraits et de plugins de correspondance d'accolade, et re-résoudre ces problèmes à nouveau, en plus de leurs solutions, pour atteindre la commodité et, bien, la magie.

Cela revient à contrôler vs commodité. Je pense que le contrôle vous servira mieux dans ce cas, ce qui signifie que vous devriez garder ces problèmes et leurs plugins et mappages de clés associés séparés. Si vous voulez toujours la commodité, c'est faisable, mais c'est difficile.


1

Je pense que delimitMate fait ce dont vous avez besoin.

Il ferme automatiquement les parenthèses ou les guillemets et place votre curseur entre les deux. Pour sortir d'une paire de parenthèses (tout en étant en mode insertion), vous feriez Ctrl-g+ gmais vous pouvez remapper cela Ctrl-jen l'ajoutant à votre vimrc:

% Jump out of a block of parentheses (uses delimitMate)
imap <C-j> <C-g>g

Il est préférable de fournir plus de détails ici et d'utiliser le lien comme référence pour une lecture plus approfondie. De cette façon, votre réponse ne perd pas toute sa valeur lorsque le lien devient invalide.
Anthon

1

J'ai trouvé que la fermeture automatique ajoutait un peu de retard et interférait également avec ma configuration (Ultisnips et Supertab), mais j'aime son approche d'émulation d'Eclipse CDT.

J'utilise delimitMate avec les cartes suivantes pour aider à la navigation et à l'indentation, en essayant d'obtenir les mêmes résultats:

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)

Je l'utilise de cette façon: insérez l'ouverture { <CR><CR><C-K>et commencez à écrire dans la ligne intérieure en retrait.


J'ai trouvé que delimitMate ajoutait également un léger décalage
icc97

1

Personnellement, j'utilise smartinput pour l'insertion automatique de crochets et de guillemets. Par exemple, taper {n'importe où produira {}avec votre curseur au milieu. Pour quitter le {groupe de crochets, il vous suffit de taper le }quand à côté de l'inséré }.

Cependant, cela prend en charge votre exigence de tabstops et de sauter à l'extérieur du support. Il ne crée pas non plus de nouveau entre vos crochets, mais vous avez juste besoin d'une clé supplémentaire pour cela de toute façon - <CR>.

Vous pouvez mapper <C-J>pour passer à la ligne suivante:

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

ou si vous vouliez passer au début de la ligne suivante:

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

0

Quelque chose comme ça pourrait fonctionner pour vous.

inoremap {      {}<Left>
inoremap {<CR>  {<CR>}<Esc>O
inoremap {{     {
inoremap {}     {}

Ce que vous proposez est un simple mapping qui ne permet pas de sauter par-dessus l'accolade fermante.
Marco

0

En fait, Ultisnips peut le faire presque parfaitement (cela peut être nouveau). Modifiant légèrement les réponses données ci-dessus, j'ai un bon succès avec

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

Il faut taper ()qui trouve mieux mais qui peut aussi être changé (. Ensuite, les arguments facultatifs supplémentaires à UltiSnips#Anonsont une description et le modificateur iqui permet l'expansion in-word.

Sauter des parenthèses avec des <c-j>œuvres, également imbriquées dans d'autres extraits. Cependant, l'invocation de ()parenthèses imbriquées semble rompre cette fonctionnalité, ce qui n'est pas un gros problème.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.