Erstellen Sie automatisch passende Klammern in vim


17

Wie erstelle ich automatisch passende Klammern in vim?

Es sollte wie folgt funktionieren: Wenn ich eine offene Klammer eingebe, sollte die schließende automatisch erscheinen und der Cursor dazwischen stehen. Zum Herausspringen aus dem Zahnspangenpaar wird die Kombination Ctrl-jverwendet.

Es gibt viele Plugins, die das automatische Einfügen von Klammern ermöglichen. Aber sie

  • Verwenden Sie entweder eine andere Tastenkombination als Ctrl-j, um aus dem Klammerpaar zu springen, oder
  • stören die UltiSnips- Tastenkombinationen.

Das Folgende funktioniert wie erwartet

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

Aber mit diesen Einstellungen funktionieren die UltiSnips-Snippets nicht mehr. Also habe ich UltiSnips verwendet, um die schließende Klammer einzufügen:

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

Das funktioniert fast. Die passende Klammer wird eingefügt und ich kann die schließende mit überspringen Ctrl-j. Dies funktioniert jedoch nur, wenn vor der geöffneten Klammer ein Leerzeichen vorhanden ist.

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

Meine Lösungen erfordern entweder eine andere Schlüsselbindung, um über die schließende Klammer zu springen, oder erfordern ein Leerzeichen vor der offenen. Wie kann man das beheben?

Hinweis: Als Beispiel habe ich Klammern verwendet. Es sollte mit Klammern, Klammern, Klammern und Kleinbuchstaben funktionieren und das UltiSnips-Plugin nicht beeinträchtigen.


1
Haben Sie versucht, automatisch zu schließen ? Sie können mit aus Paaren springen ), eine Neuzuordnung c-jkönnte funktionieren.
Kevin

Antworten:


4

Wie erstelle ich automatisch passende Klammern in vim?

Dieses Problem ist nicht trivial, wie Sie sehen werden. Die einfache Antwort lautet: Verwenden Sie ein Plugin wie Autoclose oder Smartinput . Durch einfaches Neuzuordnen der Tasten ([..] erhalten Sie Edgecases in mehreren Zeilen. Deshalb werden diese Plugins erstellt und sind normalerweise recht komplex (wenn sie gut sind).

Also habe ich UltiSnips verwendet, um die schließende Klammer einzufügen

Sie könnten dies stattdessen versuchen (was sich von meinem ursprünglichen Vorschlag unterscheidet):

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

Wobei UltiSnips die Linie aufteilt, (anstatt sie mainin das Match einzubeziehen . Das Problem bei der Verwendung eines Snippet-Plugins besteht darin, dass es (normalerweise) kein Verschachteln unterstützt, sodass Sprungpositionen beim Einfügen des nächsten (verschachtelten) Snippets vergessen werden.

Zum Herausspringen aus dem Zahnspangenpaar wird die Kombination Ctrl-jverwendet.

Sie können entweder Ctrl-jfür UltiSnips oder das in Konflikt stehende Plugin eine Neuzuordnung vornehmen. Wenn die Zuordnungen nicht in der Dokumentation aufgeführt sind, können Sie sie :map/imap/nmap <key>anzeigen. Wenn Sie Ctrl-jbeide Plugins auswählen und ausführen möchten , fragen Sie nach:

  1. Etwas viel Fortgeschritteneres, als ich vermute
  2. etwas, von dem ich vermute, dass du es nicht wirklich willst

Betrachten Sie diese Bash-Schleife:

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

In diesem Fall müssen Sie Ctrl-jfünfmal drücken , um zum Loop-Body zu gelangen. Wenn Sie die schließenden Klammern verwenden, um aus einem entsprechenden Paar zu springen, können Sie viel besser steuern, wo sich der Cursor tatsächlich bewegen soll. Sie könnten einen Stapel implementieren, um eingefügte Paare zu verfolgen und Ctrl-jzum Platzieren und Verschieben zu verwenden, aber dann treten Probleme auf, wenn Sie beginnen, Klammern manuell zu löschen, ohne sie aus dem Stapel zu entfernen. Also werden Sie anfangen, Probleme zu lösen, die die Klammer-Plugins zu lösen versuchen. Das Rad ist schwer neu zu erfinden.

Wenn Sie dies erweitern, können Sie das bekommen, wonach Sie ursprünglich gefragt haben, indem Sie Ctrl-jaus geschweiften Klammern und Auszügen springen . Wenn Sie einen Dummy-Wert verwenden, um die Schnipselpositionen darzustellen, und diese zusätzlich zu den schließenden Klammern auf den Stapel schieben, wobei die dynamische Neuzuordnung der Ctrl-jÜbergabe von Schnipsel oder Klammern entspricht. Dann müssen Sie jedoch einige recht fortgeschrittene Heuristiken implementieren, um herauszufinden, was mit Magie geschehen soll, da Sie im Wesentlichen zwei Probleme gleichzeitig angehen, die derzeit von den Entwicklern der Plugins zum Einfügen von Snippets und zum Anpassen von Klammern separat gelöst werden Lösen Sie diese Probleme erneut, zusätzlich zu ihren Lösungen, um Bequemlichkeit und Magie zu erreichen.

Es kommt auf die Kontrolle gegen die Bequemlichkeit an. Ich denke, die Steuerung wird Ihnen in diesem Fall bessere Dienste leisten. Das bedeutet, Sie sollten diese Probleme und die zugehörigen Plugins und Tastenzuordnungen voneinander trennen. Wenn Sie noch Bequemlichkeit wünschen, ist es machbar, aber es ist schwer.


1

Ich denke, delimitMate macht das, was Sie brauchen.

Es schließt automatisch Klammern oder Anführungszeichen und setzt den Cursor dazwischen. Springen aus einem Klammerpaar (während im Einfügemodus ist) würden Sie tun Ctrl-g+ , gaber Sie können diese neu zuordnen sein , Ctrl-jindem Sie diese in Ihrem vimrc:

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

Es ist besser, hier weitere Details anzugeben und den Link als Referenz für die weitere Lektüre zu verwenden. Auf diese Weise verliert Ihre Antwort nicht den gesamten Wert, wenn der Link ungültig wird.
Anthon

1

Ich habe festgestellt, dass Autoclose ein wenig Verzögerung hinzufügt und auch mein Setup stört (Ultisnips und Supertab), aber ich mag seinen Ansatz, Eclipse CDT zu emulieren.

Ich verwende delimitMate mit den folgenden Karten, um die Navigation und das Einrücken zu erleichtern, und versuche, die gleichen Ergebnisse zu erzielen :

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)

Ich benutze es so: Füge die Öffnung ein { <CR><CR><C-K>und beginne, in die eingerückte innere Zeile zu schreiben.


Ich fand, dass delimitMate auch eine leichte Verzögerung hinzufügt
icc97

1

Persönlich benutze ich smartinput zum automatischen Einfügen von Klammern und Anführungszeichen. Wenn Sie beispielsweise {irgendwo tippen , wird {}der Cursor in der Mitte angezeigt. Um die {Klammergruppe zu verlassen , geben Sie einfach den }Zeitpunkt neben dem eingefügten ein }.

Dies unterstützt jedoch Ihre Anforderungen an Tabstopps und das Springen nach außerhalb der Klammer. Es wird auch kein neuer zwischen Ihren Klammern erstellt, aber Sie benötigen dafür nur einen zusätzlichen Schlüssel - <CR>.

Sie können eine Karte <C-J>erstellen, um zur nächsten Zeile nach unten zu springen:

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

oder wenn Sie zum Anfang der nächsten Zeile springen wollten:

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

0

So etwas könnte für Sie funktionieren.

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

Was Sie vorschlagen, ist eine einfache Zuordnung, die es nicht ermöglicht, über die schließende Klammer zu springen.
Marco

0

Eigentlich kann Ultisnips das fast perfekt (dies könnte neu sein). Die oben gegebenen Antworten leicht modifizierend, habe ich guten Erfolg damit

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

Man muss eingeben, ()was man besser findet, aber das kann man auch ändern (. Dann sind die zusätzlichen optionalen Argumente UltiSnips#Anoneine Beschreibung und der Modifikator, ider die In-Word-Erweiterung ermöglicht.

Mit <c-j>Werken aus den Klammern springen , auch verschachtelt in anderen Ausschnitten. Das Aufrufen verschachtelter ()Klammern scheint diese Funktion jedoch zu beeinträchtigen, was keine große Sache ist.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.