Fügen Sie automatisch eine passende Klammer in Vim ein

77

Ich verbringe viel zu viel Zeit damit, herumzufummeln, weil Vim das Schließen von Klammern nicht wie die meisten IDEs handhabt. Folgendes möchte ich tun:

Geben Sie Folgendes ein:

if( whatever )
{ <CR>

und hol dir das:

if( whatever )
{
  |  
}

Dabei <CR>bedeutet Mittelwert die ENTERTaste und |ist die Position des Cursors. Dies ist, was Eclipse tut. Genau das macht Visual Studio. Und genau das möchte ich von Vim.

Ich habe ein paar Plugins gesehen, ein paar ausprobiert und keines scheint mir dieses Verhalten zu geben. Sicherlich kann ich nicht der erste Programmierer sein, der das will.

Bob
quelle
2
Hinweis: Vim ist ein so leistungsfähiger Texteditor, dass er sich in gewisser Weise wie eine IDE verhalten kann ... aber es ist keine IDE. In diesem Fall handelt es sich um eine Textbearbeitungsfunktion, in der Vim gut ist. Sie sind also golden.
Keith Pinson

Antworten:

43

In VimL können Sie die Aufgaben {genau nach Ihren Wünschen zuordnen :

inoremap { {<CR>}<Esc>ko

Abhängig von Ihrem Autoindent-Setup möchten Sie möglicherweise ein <BS>After hinzufügen <CR>.

Für eine vollständigere Lösung würde ich empfehlen, dass Sie sich die Vim-Plugins von Luc Hermitte ansehen . Sie haben mich bisher noch nie im Stich gelassen.

Michael Foukarakis
quelle
1
ist Mapping {<CR>auch möglich? Ich meine, was ist, wenn ich nur einen Hash {"something":"like this"}in Python, Js oder Ruby eingebe?
Rápli András
4
Ja {<CR>ist möglich Dies ist, was ich in meinem .vimrc{<CR> {<CR>}<Esc>ko
AgmLauncher
Hallo @AgmLauncher, es funktioniert, wenn ich das eingebe, {aber es gibt ein Problem, wenn ich einen Codeblock einfüge, der enthält {, wird }am Ende ein hinzugefügt .
Evan Hu
2
@Evan - Beim Einfügen von Code können viele Dinge schief gehen, insbesondere beim automatischen Einrücken und dergleichen. Versuchen Sie: Paste vor dem Einfügen setzen und dann: Nopaste setzen, wenn Sie fertig sind. Dies schaltet den Einfügemodus um.
Abhinav Gujjar
11

Die Verwendung von AutoClose mit den folgenden Funktionen funktioniert ordnungsgemäß.

inoremap {<CR> {<CR>}<C-o>O

Dies gilt zumindest für mein System (Unix-Terminal unter Mac OS X).

Dmonopol
quelle
7

Folgendes habe ich in meinem vimrc:

let s:pairs={
            \'<': '>',
            \'{': '}',
            \'[': ']',
            \'(': ')',
            \'«': '»',
            \'„': '“',
            \'“': '”',
            \'‘': '’',
        \}
call map(copy(s:pairs), 'extend(s:pairs, {v:val : v:key}, "keep")')
function! InsertPair(left, ...)
    let rlist=reverse(map(split(a:left, '\zs'), 'get(s:pairs, v:val, v:val)'))
    let opts=get(a:000, 0, {})
    let start   = get(opts, 'start',   '')
    let lmiddle = get(opts, 'lmiddle', '')
    let rmiddle = get(opts, 'rmiddle', '')
    let end     = get(opts, 'end',     '')
    let prefix  = get(opts, 'prefix',  '')
    let start.=prefix
    let rmiddle.=prefix
    let left=start.a:left.lmiddle
    let right=rmiddle.join(rlist, '').end
    let moves=repeat("\<Left>", len(split(right, '\zs')))
    return left.right.moves
endfunction
 noremap! <expr> ,f   InsertPair('{')
 noremap! <expr> ,h   InsertPair('[')
 noremap! <expr> ,s   InsertPair('(')
 noremap! <expr> ,u   InsertPair('<')

Und für einige Dateitypen:

inoremap {<CR> {<C-o>o}<C-o>O

// Ich weiß, dass die InsertPair-Funktion trivial ist, aber sie spart Zeit, da ich damit sowohl Befehls- als auch Normalmoduszuordnungen mit einem Befehl definieren kann, ohne viele <Left>s schreiben zu müssen .

ZyX
quelle
6

Fügen Sie Folgendes in Ihre .vimrc-Datei ein:

inoremap { {}<ESC>ha

Jedes Mal, wenn Sie {im Einfügemodus drücken , {}wird generiert und der Cursor befindet sich auf der rechten Klammer, sodass Sie sofort zwischen ihnen tippen können. Indem Sie die geschweiften Klammern nacheinander und nicht in verschiedenen Zeilen platzieren, können Sie }manuell Tabulatoren vorsetzen. Auf diese Weise haben Sie nie die falsche Anzahl von Registerkarten vor sich.

Vielleicht kann jemand herausfinden, wie die Anzahl der Registerkarten gezählt werden soll, auf denen sich der Cursor befindet, und dann eine gleiche Anzahl von Registerkarten vor der }in einer neuen Zeile generieren .

user1534664
quelle
6

Eine Lösung für Klammern, Klammern und Klammern mit dazwischen liegenden Tabulatoren.

" Automatically closing braces
inoremap {<CR> {<CR>}<Esc>ko<tab>
inoremap [<CR> [<CR>]<Esc>ko<tab>
inoremap (<CR> (<CR>)<Esc>ko<tab>

Ergebnis:

function() {
  |
}
Rodrigo Pinto
quelle
4

Ich habe immer so etwas wie erhabenen Text bevorzugt, bei dem die schließende Klammer als nächstes Zeichen angehängt wird. Deshalb habe ich meiner .vimrc Folgendes hinzugefügt:

inoremap (  ()<ESC>hli

Dadurch wird der Cursor zwischen die beiden geschweiften Klammern bewegt.

Aneesh Durg
quelle
Dies ersetzt (zu ()hli. Vim8 auf Mac.
Vitaly Zdanevich
3

Für alle, die wie ich darauf stoßen und nach etwas suchen, das kürzlich aktualisiert wurde als AutoClose: delimitMate Ich habe festgestellt, dass dies nicht nur eine bevorzugte Lösung für AutoClose ist, sondern auch in Bezug auf die aktive Entwicklung. Laut vim.org wurde AutoClose seit 2009 nicht mehr aktualisiert.

Eric H.
quelle
1
Beachten Sie, dass die delmitMateExpandOptionen standardmäßig deaktiviert sind. Sie müssen let delimitMate_expand_cr = 1 zu Ihrem hinzufügen .vimrc.
Sebastian
3

Ich habe verschiedene Plugins ausprobiert, aber ich fand die genauesten und am einfachsten zu verwendenden Auto-Paare . Es ist sehr intuitiv und wenn Sie es installieren, erhalten Sie sofort das, was Sie erwartet haben.

egelev
quelle
1
Es ist fünf Jahre her, seit diese Antwort veröffentlicht wurde. Für den Fall, dass jemand anderes mit einem ähnlichen Problem auftaucht, hat dies für mich funktioniert, zumindest ohne andere Plugins zu beschädigen.
dekarpaulvictor
3

Wie Sie im Wikia-Tipp sehen werden : Es gibt viele Lösungen für diese wiederkehrende Frage (ich habe sogar meine ).

Das ist, wenn Sie sich auf Klammerpaare beschränken. Hier befinden Sie sich im Kontext einer Steueranweisung. Es ist daher wahrscheinlicher, dass Sie Snippet-Systeme finden, die nicht erwarten, dass Sie ") {" eingeben, wenn Sie eine "if" -Anweisung eingeben. Die Vim-Verknüpfung ist in der Regel kürzer als in Ihrer Frage. Auch hier gibt es eine Menge Auswahlmöglichkeiten, wahrscheinlich finden Sie snipmate und möglicherweise meine C & C ++ - Suite .

Luc Hermitte
quelle
Nur zu Ihrer Information: Google gibt eine 404 an, wenn es darum geht, den Vimball lh-cpp-1.0.0.vba zu bekommen. Ich habe den SVN benutzt und noch nie bemerkt.
Michael Foukarakis
Tatsächlich. Mein Fehler. Ich möchte die Dokumentation fertigstellen, bevor ich eine offizielle Veröffentlichung mit Vimball und allem mache.
Luc Hermitte
2

delimitMate hat hierfür eine Einstellung.

Henrik N.
quelle
Weitere Infos bitte. Welche Einstellung?
docwhat
Hm, das ist schon eine Weile her. Ich hätte es vielleicht gemeint delimitMate_expand_cr, obwohl es nicht genau das zu tun scheint, wonach gefragt wird. Scheint, Zeilenumbrüche korrekt einzufügen, aber möglicherweise nicht die Endklammer hinzuzufügen. Die Hilfedatei ist hier: github.com/Raimondi/delimitMate/blob/master/doc/delimitMate.txt Persönlich verwende ich heutzutage nur endwise ( github.com/tpope/vim-endwise ) und stimme ansonsten mit meinen eigenen Klammern überein, da keine Automatisierung erfolgt macht es ganz richtig.
Henrik N
Danke für den Zeiger auf endwise. Ich wusste nicht, was es war, als ich es vorher sah.
docwhat
2

Vim Patch 7.4.849 hat eine Bindung hinzugefügt, um Cursorbewegungen zu ermöglichen, ohne die Rückgängig-Sequenz neu zu starten. Einmal auf> = 7.4.849 aktualisiert, funktioniert so etwas großartig.

inoremap ( ()<C-G>U<Left>

Beachten Sie, dass ich das direkt aus der im Patch enthaltenen Dokumentation entnommen habe. Die bisher beste einfache Lösung für diese Funktion.

John Eikenberry
quelle
Dies ist Fixes '.' funktioniert nicht mit den automatisch angepassten Parens.
John Eikenberry
2
inoremap ( ()<ESC>i
inoremap " ""<ESC>i
inoremap ' ''<ESC>i
inoremap { {<Cr>}<Esc>O
Alvy
quelle
2

Schließlich habe ich herausgefunden, dass kein Plugin erforderlich ist, sondern dass dies perfekt für mich funktioniert:

inoremap { {}<Esc>ha
inoremap ( ()<Esc>ha
inoremap [ []<Esc>ha
inoremap " ""<Esc>ha
inoremap ' ''<Esc>ha
inoremap ` ``<Esc>ha
Nika Tsogiaidze
quelle
1

Installieren und verwenden Sie das Vim-Skript AutoClose, wie im Artikel mit dem Titel " Schließende Zeichen automatisch anhängen" empfohlen .

Derek Mahar
quelle
2
AutoClose macht nicht was ich will. Die schließende Klammer bleibt in derselben Zeile, sodass ich zweimal die Eingabetaste drücke, zum Befehlsmodus zurückkehre, eine Zeile nach oben gehe, den Modus einfüge, eine Registerkarte und schließlich tippe.
Bob
1

Nur eine Notiz an @Bob.

Karl Guertins AutoClose hat eine Funktion namens "Doppelklammer", dh Sie können die geschweifte Klammer wie unten angegeben zweimal eingeben .

int func_name(void) {{ ==> Type `{' twice here.

würde führen zu:

int func_name(void) {
| ==> Cursor here.
}

Anschließend können Sie eine einzelne Registerkarte eingeben, um sie entsprechend Ihrer Einstellung für die Verschiebungsbreite einzurücken, und dann eingeben.

jtuki
quelle
0

Sie benötigen dazu kein spezielles Plugin - dies ist jedoch ein zweistufiger Prozess.

Fügen Sie zunächst Folgendes zu Ihrem hinzu .vimrc, um den auslösenden Charakter zu essen:

" eat characters after abbreviation
function! Eatchar(pat)
    let c = nr2char(getchar(0))
    return (c =~ a:pat) ? '' : c
endfunction

und fügen Sie dann diese Abkürzung zu Ihrem hinzu .vimrc:

inoreabbr <silent> { {
      \<cr><space><space>
      \<cr><esc>0i}<esc>k$i<c-r>=Eatchar('\m\s\<bar>\r')<cr>

Das \am Anfang der Zeilen zwei und drei ist nur ein Zeilenfortsetzungszeichen. Sie hätten dies jedoch alles in einer Zeile tun können, und ich habe es hinzugefügt, damit ich die Abkürzung so verteilen kann, dass sie die gesuchte Ausgabe widerspiegelt - nur damit die Dinge etwas intuitiver sind.

Ricardo
quelle
0

Meine Lösung:

inoremap <expr> <CR> InsertMapForEnter()
function! InsertMapForEnter()
    if pumvisible()
        return "\<C-y>"
    elseif strcharpart(getline('.'),getpos('.')[2]-1,1) == '}'
        return "\<CR>\<Esc>O"
    elseif strcharpart(getline('.'),getpos('.')[2]-1,2) == '</'
        return "\<CR>\<Esc>O"
    else
        return "\<CR>"
    endif
endfunction

Erklärung:

Der obige Code zuerst überprüfen , ob Sie verwenden Entereinen Code - Vervollständigung zu tun bestätigen, wenn nicht es wird der Einzug , {|}wenn Sie eingeben Enter. Außerdem werden HTML-Tags automatisch eingerückt.

Beispiele:

if( whatever ){|}

Drücken EnterSie und Sie werden bekommen

if( whatever )
{
  |  
}

Dies funktioniert auch für HTML-Dateien. Siehe folgendes Beispiel

<html>|<html>

Drücken EnterSie und Sie werden bekommen

<html>
    |
</html>
voldikss
quelle
0

Wenn Sie tippen {}und drücken, befinden altiSie sich im INSERTModus zwischen den geschweiften Klammern (zumindest in einem Terminal). Dann können Sie drücken, ENTERgefolgt von altshifto, um den Zeilenumbruch einzufügen. Sie könnten auch einfach tun {<CR>}und altshifto.

Dies ist möglicherweise nicht vollautomatisch, aber ich halte es für halbautomatisch. Es macht mehr Plugins überflüssig und ist eine nützliche Information für andere Anwendungsfälle. Zum Beispiel benutze ich die altshiftoganze Zeit, um leere Zeilen einzufügen, ohne den INSERTModus explizit verlassen zu müssen , und altium hineinzukommen ()usw.

jdk1.0
quelle