Wie kann ich eine Reihe von Zeilen auskommentieren, die im visuellen Modus ausgewählt wurden?

35

Wie kann ich mehrere im visuellen Modus ausgewählte Zeilen auskommentieren? Wie mache ich es sprachspezifisch?

Zum Beispiel, wenn die ersten 4 Zeilen ausgewählt sind:

def foo(a,b):
    for each in (a,b):
        print each
    return a+b
print "2"

Die Operation eines Befehls / Makros sollte folgendes ergeben (in Python):

#def foo(a,b):
#    for each in (a,b):
#        print each
#    return a+b
print "2"
John HK
quelle

Antworten:

31

Wenn Sie sprachspezifische Kommentare wünschen, benötigen Sie ein Plugin wie nerdcommenter .

Alternativ können Sie eingebaute vim-Aktionen und Ihre Kenntnisse der Kommentarzeichen jeder Sprache verwenden, obwohl dies Ihre eigentliche Frage nicht beantwortet.

Option 1: V-Blöcke

  1. :1 Enter (Gehe zu Zeile 1)
  2. Ctrl-V (V-Block-Modus)
  3. jjj (3 weitere Zeilen runter)
  4. Shift-I (Einfügemodus vor dem Block aufrufen)
  5. # (Ein '#' einfügen)
  6. Esc (Zurück zum normalen Modus)

Option 2: Substitution

:1,4s/^/#/

Nervenzusammenbruch:

  1. : Es folgt der Ex-Befehl
  2. 1,4 in den Zeilen von 1 bis 4
  3. s Ersatz
  4. /Trennzeichen für Teile des Substitutionsbefehls.
    (Sie können auch ein anderes Zeichen verwenden, z. B. :)
  5. ^ Beginn der Zeile
  6. / Separator
  7. # das Kommentarzeichen für Python
  8. / Endabscheider

Option 3: Wiederholen der Anwendung eines Makros ( Quelle )

  1. :1 Enter (Gehe zu Zeile 1)
  2. qa(Aufnahme im Register starten a)
  3. Shift-I (Geben Sie den Einfügemodus am Anfang der Zeile ein
  4. # (Fügen Sie am Anfang der Zeile ein '#' hinzu.)
  5. Esc (Zurück zum normalen Modus)
  6. q (Höre auf, aufzunehmen)

  7. :2,4 normal @a(Führen Sie das aufgezeichnete Makro erneut aus, um es ain den Zeilen 2 bis 4 zu registrieren. )

    ODER

    Sie können die Linien im visuellen Modus auswählen und drücken :, um die Ex-Linie automatisch mit :'<,'>(einem Bereich vom Anfang bis zum Ende der visuellen Auswahl) zu füllen. Geben Sie dann ein normal @aund drücken Sie Enter( Quelle ).

Wenn Sie nun einige Zeilen kommentieren möchten, führen Sie einfach das aufgezeichnete Makro erneut aus, um sich ain diesen Zeilen zu registrieren :

:9,22 normal @a (comment out lines 9-22)
bsmith89
quelle
1
Option 4: Plugin
Cody Poll
Ich verstehe nicht, warum Sie ein Makro für einen einzelnen Befehl verwenden, wenn Sie :9,22 normal I#nach meiner Antwort tun können .
Ben
Warum würden Sie verwenden: 1 <enter>, wenn Sie gg verwenden können?
Tanath
@Tanath Das Kommentieren aus der ersten Zeile war spezifisch für dieses Beispiel. Wenn der Autor aus den Zeilen 9 bis 22 einen Kommentar abgeben möchte, kann er gg nicht verwenden.
bsmith89
@Ben Ich wusste nichts über den normalBefehl, bevor ich diese Antwort schrieb. Du hast recht; :9,22 normal I#wird auch funktionieren.
bsmith89
26

Wählen Sie im visuellen Blockmodus ( CtrlV) den Zeilenanfang aus. Drücken Sie dann I#(das ist ein Großbuchstabe I), um das Hash-Zeichen in jede dieser Zeilen einzufügen. Drücken Sie dann Esc, um vom Einfügemodus zum normalen Modus zurückzukehren.

200_erfolg
quelle
Bei mir funktioniert es nicht. Es wird nur in der ersten Zeile ein Kommentar eingefügt.
Gon1332
Drängst du ctrl? Denn ctrl+vist eine andere Sache als nur v.
Cody Poll
@CodyPoll Ich weiß. Alles ist in Ordnung bis zu I. Wenn ich drücke I, #wird das nur vor die erste Zeile gesetzt.
gon1332,
@CodyPoll Ok .. Ich war gerade stationär. Ich habe Escnach dem beschriebenen Verfahren nicht gedrückt.
Gon1332
@gon1332 soweit ich weiß musst du Escam ende drücken .
Gonçalo Ribeiro
18

Wenn Sie für jede Sprache, in der Sie sich gerade befinden, nur eine schnelle Lösung benötigen und den Text bereits im visuellen Modus ausgewählt haben, dann

:norm 0i#

macht den Job. (Wechseln Sie im normalen Modus für jede Zeile in die erste Spalte und fügen Sie sie ein #. Mit :norm I#wird sie vor dem ersten Nicht-Leerzeichen eingefügt. Dies ist möglicherweise nicht das, was Sie möchten.) Mit :norm i#funktioniert auch, da :normam Anfang von beginnt Linie, aber es ist weniger explizit und weniger klar, wenn Sie das nicht wissen.

Wenn Sie dies häufig tun möchten, möchten Sie natürlich ein Mapping einrichten oder nach einem Plugin suchen.

wchargin
quelle
1
0 wird nicht benötigt, da der normalBefehl standardmäßig mit dem Cursor am Zeilenanfang ausgeführt wird.
Nitishch
1
Natürlich können diesem Befehl Zeilennummern,%, Markierungen vorangestellt werden. Beispiel:: 1,5norm i # (oder): 'a', bnorm i # (oder): 10% norm i #
SibiCoder
9

Wenn Sie dies automatisch tun, müssen Sie Ihrer vimrcDatei ( Quelle ) Folgendes hinzufügen :

au FileType haskell,vhdl,ada let b:comment_leader = '-- '
au FileType vim let b:comment_leader = '" '
au FileType c,cpp,java let b:comment_leader = '// '
au FileType sh,make let b:comment_leader = '# '
au FileType tex let b:comment_leader = '% '
noremap <silent> ,c :<C-B>sil <C-E>s/^/<C-R>=escape(b:comment_leader,'\/')<CR>/<CR>:noh<CR>
noremap <silent> ,u :<C-B>sil <C-E>s/^\V<C-R>=escape(b:comment_leader,'\/')<CR>//e<CR>:noh<CR>

Verwenden Sie, ,cum eine Region zu kommentieren und eine Region zu kommentieren ,u. Dadurch werden die Kommentarsymbole für verschiedene Sprachen manuell festgelegt.

Die zweite Möglichkeit ist die Verwendung eines Plugins wie tcomment , vim-commentary oder comments.vim . Ich benutze Tcomment selbst. Bitte lesen Sie die Anweisungen zur Verwendung und Installation auf deren Seiten, da ich glaube, dass dies über das Thema der Frage hinausgeht.

Ich würde vorschlagen, dass Sie ein Plugin (eines der oben genannten oder eines anderen) verwenden, da dies viel einfacher ist, als einen Teil des Codes in Ihrer vimrcDatei zu verwalten.

Bearbeiten: Ich habe den manuellen Weg entfernt, da die Frage geändert wurde und auch der richtige Weg von 200_success beantwortet wurde.

Tokoyami
quelle
Ein zusätzlicher Plugin-Vorschlag: NERD Commenter - vim.org/scripts/script.php?script_id=1218
gab
Hinweis: Dies unterstützt nur zeilenweise Kommentare. Beispielsweise erkennt ANSI C //(nur /* */) nicht.
Wchargin
Während ich diesen Ansatz mag, gibt es eine Möglichkeit, Kommentare umzuschalten?
ideasman42
1
@ ideasman42 Sie müssten stattdessen eine Funktion erstellen und prüfen, ob die aktuelle Zeile mit einem Kommentar beginnt, und dann abhängig von diesem Aufruf einen der :sBefehle aus dem Auszug in der Antwort ausführen. Der Scheck selbst wäre so etwas wie getline('.') =~ "^" . escape(b:comment_leader, '\/'). Wenn es wahr ist, Kommentar, sonst. Dies ist nicht getestet und soll nur als Beispiel dienen.
Tokoyami
5

Ich benutze dafür scrooloose / nerdcommenter .

Mit diesem Plugin können Sie Ihre Zeilen visuell auswählen und mit leader+ cKommentare umschalten. Je nach Dateityp werden unterschiedliche Symbole zum Kommentieren verwendet.

OrangeTux
quelle
5

Nachdem Sie die Zeilen ausgewählt haben, geben Sie einfach ein

:norm I#

:wird automatisch in '<,'>die Befehlszeile eingefügt. Dies ist ein Bereich vom Anfang Ihrer Auswahl bis zum Ende. normFührt einen normalen Modusbefehl aus und handelt in diesem Bereich. I#ist der Normalmodus-Befehl, der am Zeilenanfang ein '#' einfügt.

Ben
quelle
4

Ich bin ein großer Fan von TComment . Ich kann nicht nur Dateityp-spezifische Kommentarstile erstellen, sondern auch für Sprachen, die Blockkommentare unterstützen, Block gegen Zeilen angeben.

    gc{motion}   :: Toggle comments (for small comments within one line 
                    the &filetype_inline style will be used, if 
                    defined)
    gcc          :: Toggle comment for the current line

Explicit commenting/uncommenting:

    g<{motion}   :: Uncomment region
    g<c          :: Uncomment the current line
    g<b          :: Uncomment the current region as block

    g>{motion}   :: Comment region
    g>c          :: Comment the current line
    g>b          :: Comment the current region as block

In visual mode:

    gc           :: Toggle comments
    gC           :: Comment selected text
Collin Grady
quelle
Danke für deine Antwort! Könnten Sie es vielleicht erweitern? Das Bereitstellen von Plugin-Antworten ist in Ordnung, aber im Moment ist es nur ein Link zu einem Plugin. Zumindest wird in der Antwort eine grundlegende Beschreibung dessen, was es tut und wie es verwendet wird, erwartet. siehe auch diese Meta - Post .
Martin Tournoij
Scheint albern, Tastenkombinationen zu kopieren / einzufügen, aber los geht's. Ich habe bereits beschrieben, was es tut.
Collin Grady
3

Ich finde, dass das VIM-Kommentar-Plugin bei weitem der einfachste Weg ist, dies zu tun. Wählen Sie einen Linienbereich aus und drücken Sie einfach gc. Es wird ein entsprechendes Kommentarzeichen für den geöffneten Dateityp verwendet. Es ist sogar ohne visuelle Auswahl möglich, benachbarte kommentierte Zeilen mit gcuoder zu kommentieren gcgc.

Andrew Ferrier
quelle
2

Angenommen, Sie möchten 5 Zeilen am Zeilenanfang mit einem Präfix versehen, dann können Sie Suchen und Ersetzen verwenden :

:.,+5s/^/prefix_/g

oder am Ende der Zeilen:

:.,+5s/$/suffix_/g

Oder verwenden Sie den visuellen Modus (Ctrl + v), um einen vertikalen Textblock auszuwählen. Rufen Sie dann den Einfügemodus ( I) auf, geben Sie etwas ein und drücken Sie Esc, um die Änderungen zu bestätigen und auf andere Zeilen anzuwenden.

Verbunden:

Kenorb
quelle
2

Diese Antwort ist hier, um 1) den richtigen Code zum Einfügen in ein .vimrczu bekommenvim 7.4+ Block zu tun zu kommentieren / uncommenting während Einrückungsebene mit 1 Verknüpfung im visuellen Modus zu halten und 2) es zu erklären.

Hier ist der Code:

let b:commentChar='//'
autocmd BufNewFile,BufReadPost *.[ch]    let b:commentChar='//'
autocmd BufNewFile,BufReadPost *.cpp    let b:commentChar='//'
autocmd BufNewFile,BufReadPost *.py    let b:commentChar='#'
autocmd BufNewFile,BufReadPost *.*sh    let b:commentChar='#'
function! Docomment ()
  "make comments on all the lines we've grabbed
  execute '''<,''>s/^\s*/&'.escape(b:commentChar, '\/').' /e'
endfunction
function! Uncomment ()
  "uncomment on all our lines
  execute '''<,''>s/\v(^\s*)'.escape(b:commentChar, '\/').'\v\s*/\1/e'
endfunction
function! Comment ()
  "does the first line begin with a comment?
  let l:line=getpos("'<")[1]
  "if there's a match
  if match(getline(l:line), '^\s*'.b:commentChar)>-1
    call Uncomment()
  else
    call Docomment()
  endif
endfunction
vnoremap <silent> <C-r> :<C-u>call Comment()<cr><cr>

Wie es funktioniert:

  • let b:commentChar='//': Dies erstellt eine Variable in vim. Der bhier angegebene Wert bezieht sich auf den Gültigkeitsbereich, der in diesem Fall im Puffer enthalten ist, dh die aktuell geöffnete Datei. Ihre Kommentarzeichen sind Zeichenfolgen und müssen in Anführungszeichen gesetzt werden. Die Anführungszeichen sind nicht Teil dessen, was beim Umschalten von Kommentaren ersetzt wird.

  • autocmd BufNewFile,BufReadPost *...: Autocommands lösen verschiedene Dinge aus. In diesem Fall werden diese ausgelöst, wenn eine neue Datei oder die gelesene Datei mit einer bestimmten Erweiterung endet. Nach dem Auslösen führen Sie den folgenden Befehl aus, mit dem Sie den Befehl ändern könnencommentChar Dateityp können. Es gibt andere Möglichkeiten, dies zu tun, aber sie sind für Anfänger (wie mich) verwirrender.

  • function! Docomment(): Funktionen werden durch Beginnen mit functionund Beenden mit deklariert endfunction. Funktionen müssen mit einem Großbuchstaben beginnen. das !gewährleistet , dass diese Funktion alle vorherigen Funktionen überschreibt definiert als Docomment()mit dieser Version von Docomment(). Ohne !hatte ich Fehler, aber das könnte daran liegen, dass ich neue Funktionen über die vim-Befehlszeile definierte.

  • execute '''<,''>s/^\s*/&'.escape(b:commentChar, '\/').' /e': Execute ruft einen Befehl auf. In diesem Fall wird ausgeführt substitute, was einen Bereich (standardmäßig ist dies die aktuelle Zeile) annehmen kann, z. B. %für den gesamten Puffer oder '<,'>für den hervorgehobenen Abschnitt. ^\s*ist regulär, um mit dem Anfang einer Zeile übereinzustimmen, gefolgt von einer beliebigen Anzahl von Leerzeichen, die dann (aufgrund von &) angehängt werden . Das .hier wird für die Verkettung von Zeichenfolgen verwendet, da escape()es nicht in Anführungszeichen eingeschlossen werden kann. escape()Ermöglicht es Ihnen, Zeichen commentChar, die mit den Argumenten übereinstimmen (in diesem Fall \und /), zu maskieren, indem Sie ihnen ein voranstellen \. Danach verketten wir wieder mit dem Ende unserer substituteZeichenkette, die das hateFlagge. Dieses Flag lässt uns stillschweigend scheitern, was bedeutet, dass wir nicht darüber schreien, wenn wir in einer bestimmten Zeile keine Übereinstimmung finden. Insgesamt können Sie in dieser Zeile ein Kommentarzeichen gefolgt von einem Leerzeichen vor dem ersten Text einfügen, um die Einrückungsstufe beizubehalten.

  • execute '''<,''>s/\v(^\s*)'.escape(b:commentChar, '\/').'\v\s*/\1/e': Dies ist ähnlich wie bei unserem letzten langen Befehl. Einzigartig an diesem haben wir \v, der sicherstellt, dass wir uns nicht entziehen müssen (), und 1der sich auf die Gruppe bezieht, die wir mit unserem gemacht haben (). Grundsätzlich stimmen wir mit einer Zeile überein, die mit einer beliebigen Anzahl von Leerzeichen beginnt, gefolgt von unserem Kommentarzeichen und einer beliebigen Anzahl von Leerzeichen. Wir behalten nur den ersten Satz von Leerzeichen bei. eLassen Sie uns erneut unbemerkt scheitern, wenn in dieser Zeile kein Kommentarzeichen enthalten ist.

  • let l:line=getpos("'<")[1]: dies setzt eine Variable, ähnlich wie wir es mit unserem Kommentarzeichen gemacht haben, lbezieht sich jedoch auf den lokalen Gültigkeitsbereich (lokal für diese Funktion). getpos()erhält in diesem Fall die Position des Beginns unserer Hervorhebung und des[1] bedeutet, dass wir uns nur um die Zeilennummer kümmern, nicht um andere Dinge wie die Spaltennummer.

  • if match(getline(l:line), '^\s*'.b:commentChar)>-1: Sie wissen, wie es iffunktioniert. match()prüft, ob das Erste das Zweite enthält, also greifen wir zu der Zeile, in der wir unsere Hervorhebung begonnen haben, und prüfen, ob sie mit einem Leerzeichen beginnt, gefolgt von unserem Kommentarzeichen. match()Gibt den Index zurück, in dem dies zutrifft und -1wenn keine Übereinstimmungen gefunden wurden. Da ifalle Zahlen ungleich Null als wahr ausgewertet werden, müssen wir unsere Ausgabe vergleichen, um festzustellen, ob sie größer als -1 ist. Der Vergleich in vimgibt 0 zurück, wenn er falsch ist, und 1, wenn er ifrichtig ist.

  • vnoremap <silent> <C-r> :<C-u>call Comment()<cr><cr>: vnoremapbedeutet, den folgenden Befehl im visuellen Modus abzubilden, aber nicht rekursiv abzubilden (dh keine anderen Befehle zu ändern, die auf andere Weise verwendet werden könnten). Grundsätzlich sollten Sie als Anfänger immer noremapdarauf achten, dass Sie nichts kaputt machen. <silent>bedeutet "Ich will nicht deine Worte, nur deine Taten" und weist es an, nichts in die Befehlszeile zu drucken. <C-r>ist das, was wir mappen, was in diesem Fall Strg + R ist (beachten Sie, dass Sie mit diesem Mapping Cr im normalen Modus immer noch normal für "Wiederherstellen" verwenden können). C-uDas ist ein bisschen verwirrend, aber im Grunde stellt es sicher, dass Sie Ihre visuelle Hervorhebung nicht aus den Augen verlieren (laut dieser Antwort beginnt Ihr Befehl mit '<,'>dem, was wir wollen).callHier wird vim lediglich angewiesen, die von uns benannte Funktion auszuführen, und es wird <cr>auf das Drücken derenterTaste. Wir müssen es einmal drücken, um die Funktion tatsächlich aufzurufen (ansonsten haben wir nur call function()die Befehlszeile eingegeben , und wir müssen es erneut drücken, damit unsere Stellvertreter den ganzen Weg durchlaufen (nicht wirklich sicher, warum, aber was auch immer).

Wie auch immer, hoffentlich hilft das. Dies nimmt alles mit v, Voder C-vüberprüft, ob die erste Zeile kommentiert ist. Wenn ja, kommentieren Sie alle markierten Zeilen aus und fügen Sie, falls nicht, jeder Zeile eine zusätzliche Ebene mit Kommentarzeichen hinzu. Das ist mein gewünschtes Verhalten; Ich wollte nicht nur umschalten, ob jede Zeile im Block kommentiert wurde oder nicht, deshalb funktioniert es perfekt für mich, nachdem ich mehrere Fragen zu diesem Thema gestellt habe.

jeremysprofile
quelle