Komentowanie wielu wierszy kodu, określonych numerami wierszy, za pomocą vi lub vim

20

Nauczyłem się z tego pytania Przepełnienie stosu , że można użyć vi/, vimaby skomentować określony zakres numerów linii. Załóżmy na przykład, że mam następujący skrypt bash:

#!/bin/bash

This
is
my
very
very
great
script

Załóżmy teraz, że chcę wypowiedzieć się numery linii 6 do 8 (które zawierają słowa very, veryi great) przy użyciu #komentarz charakter. W vi/ vim, mogę po prostu wpisać, :6,8s/^/#aby uzyskać następujące informacje:

#!/bin/bash

This
is
my
#very
#very
#great
script

który komentuje linie od 6 do 8.

Moje pytanie brzmi, czy jest możliwe, aby wpisać podobną jedną wkładkę, która będzie usunąć ten #znak komentarz z linii od 6 do 8 (lecz nie innych komentujących linii w pliku)?

Powiedziawszy to, zdaję sobie sprawę, że trwa debata na temat tego, czy faktycznie używam, viczy vim. W praktyce otwieram plik script.shza pomocą polecenia vi script.sh. Po wpisaniu polecenia which viotrzymuję również /usr/bin/vi. Niemniej jednak, po prostu pisząc vii naciskając Enter, uzyskuję to:

~                              VIM - Vi IMproved
~
~                               version 7.2.330
~                           by Bram Moolenaar et al.
~                 Vim is open source and freely distributable
~
~                           Sponsor Vim development!
~                type  :help sponsor<Enter>    for information
~
~                type  :q<Enter>               to exit
~                type  :help<Enter>  or  <F1>  for on-line help
~                type  :help version7<Enter>   for version info

co sugeruje, że faktycznie używam vim. Uzyskuję dostęp do zdalnego klastra Ubuntu Linux za pomocą SSH z mojego komputera. Nie używam graficznego interfejsu użytkownika Ubuntu Linux.

Andrzej
źródło

Odpowiedzi:

22

Możesz użyć:

:6,8s/^#//

Znacznie łatwiej jest jednak użyć trybu wyboru Blokuj wizualnie: Przejdź do początku wiersza 6, naciśnij Ctrl-v, przejdź do wiersza 8 i naciśnij x.

Istnieje również wtyczka „The NERD Commenter” .

Jofel
źródło
2
NERD Commentermoim zdaniem jest to sposób, aby przejść tutaj! +1 za to
1146332
7

Znam twoje Określa zapytania używając vialbo vimale oto kilka innych opcji robi to bez konieczności ręcznego otwierania pliku:

  • Perl

    perl -ne 'if($. <=8 && $. >= 6){s/^\s*#//;}print' foo.sh 
    
  • Wersja Perla> = 5.10

    perl -ne '$. ~~ [6..8] && s/^\s*#//;print' foo.sh 
    

    Spowoduje to wydrukowanie zawartości pliku, możesz przekierować do innej ( > new_file.sh) lub użyć ido edycji pliku w miejscu:

    perl -i -ne '$. ~~ [6..8] && s/^\s*#//;print' foo.sh 
    
  • sed

    sed '6,8 s/^ *#//' foo.sh
    

    Ponownie, aby dokonać edycji oryginalnego pliku na miejscu, użyj i:

    sed -i '6,8 s/^ *#//' foo.sh
    
  • awk/ gawketc:

    gawk '(NR<=8 && NR>= 6){sub("^ *#","")}{print}' foo.sh
    
  • Czysty bash:

    c=1; while read line; do 
      if [ $c -ge 6 ] && [ $c -le 8 ]; then 
         echo "${line/\#/}"
      else 
         echo $line 
      fi
      let c++; done < foo.sh
    
terdon
źródło
1
To nie tyle kwestia „ręcznego otwierania pliku”, ponieważ zazwyczaj decydujesz, które wiersze skomentować podczas kontroli wizualnej podczas edycji :) Ale na pewno jest to dobra odpowiedź na kompletność.
Paulo Almeida
2
@PauloAlmeida masz oczywiście rację. Pomyślałem, że może się przydać, ponieważ OP zna już numery linii (z powodu pierwszego polecenia użytego do ich skomentowania), a w każdym razie pokazane przeze mnie narzędzia można zastosować do różnych problemów.
terdon
4

vijest dowiązaniem symbolicznym do vimwiększości dystrybucji GNU / Linux, więc rzeczywiście używasz go vimpodczas pisania vi.

Aby usunąć komentarze, możesz wpisać: :6,8s/^#//lub :6,8s/^\s*#//odrzucić niektóre spacje wiodące przed # symbolem.

lgeorget
źródło
1
Dzięki wielkie. Wygląda na to, że mogą występować literówki. Może powinno być :6,8s/^#//i 6,8s/^\s*#//?
Andrew
3

Prawdopodobnie używasz vim.tiny. W każdym razie możesz usunąć początkowe komentarze za pomocą:

:6,8s/^#//

Oczywiście, jeśli wstawisz je w inny sposób (na przykład z dodatkową spacją), być może będziesz musiał usunąć cokolwiek innego. Z pełnym vimem wizualny wybór kolumn i wstawianie / usuwanie znaków jest łatwiejszym sposobem na zrobienie tego samego.

Paulo Almeida
źródło
3

Osobiście moim ulubionym sposobem jest korzystanie z trybu blokowania wizualnego

ctrl+, vaby przejść do trybu blokowania wizualnego, użyj klawiszy strzałek lub hjkl, aby wybrać linie i naciśnij xlub del.

Chcesz je z powrotem?

ctrl+ vdokonaj wyboru, a następnie I(wielkie i)#Esc

exussum
źródło
3

AFAIK, vi jest obecnie zwykle dowiązaniem symbolicznym vima (spróbuj which vilub type vipodążaj za dowiązaniami symbolicznymi). Może nawet /usr/bin/vi-> /etc/alternatives/vi-> /usr/bin/vim.basic.

Osobiście, aby usunąć wiele wierszy komentarza, wolę wybrać blok pionowy CtrlVi go usunąć. Jeśli chcesz dodać komentarz symbolu na wielu liniach, można CtrlV, a następnie ShiftIwpisz #a Esc, a komentarz zostanie dodana do wielu linii.

Boris Burkov
źródło
2

Powyższe odpowiedzi za pomocą

:6,8s/^#//

to idealne rozwiązanie, ale trochę kłopotliwe w pisaniu. Można to uprościć, definiując nowe polecenia w ~/.vimrc.

command -range=% C :<line1>,<line2>s/^/#/
command -range=% D :<line1>,<line2>s/^#//

I możesz po prostu pisać

:6,8C
:6,8D

aby wstawić / usunąć polecenie.

Jeśli podoba Ci się tryb wizualny, możesz zdefiniować mapy

map <F7> :s/^/#/<CR>
map <F8> :s/^#//<CR>

Tak, że musisz tylko wybrać zakres linii w trybie wizualnym i odpowiednio nacisnąć F7i, F8aby wstawić i usunąć komentarze.

Bernhard
źródło
1

Istnieje ta wtyczka zmieniająca życie o tpopenazwievim-commentary

https://github.com/tpope/vim-commentary

Ta wtyczka zapewnia :

  • Zdrowie psychiczne
  • Właściwie wcięte komentarze
  • Nie komentuje pustych / niepotrzebnych wierszy

Zastosowanie :

  • Zainstaluj przez Vundle (lub, jak sądzę, Pathogen).
  • Podświetl swój tekst i naciśnij, :który pokaże się jako:<,'>
  • Wpisz tutaj Komentarz :<,'>Commentaryi naciśnij klawisz Enter.
  • Bom. Twoja skończona bud.
Weston Ganger
źródło
1

Ta odpowiedź jest tutaj, aby 1) pokazują prawidłowy kod aby wkleić do .vimrcdostać vim 7.4+zrobić blok komentując / odkomentowanie utrzymując poziom wcięcia z 1 skrót w trybie wizualnym i 2), aby ją wyjaśnić.

Oto kod:

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>

Jak to działa:

  • let b:commentChar='//': To tworzy zmienną w vimie. btutaj odnosi się do zakresu, w tym przypadku jest zawarte w buforze, co oznacza, że obecnie otwarty plik. Znaki komentarza są ciągami znaków i muszą być zawinięte w cytaty, cytaty nie są częścią tego, co zostanie zastąpione podczas przełączania komentarzy.

  • autocmd BufNewFile,BufReadPost *...: Komendy automatyczne uruchamiają różne rzeczy, w tym przypadku są one uruchamiane, gdy nowy plik lub plik odczytu kończy się określonym rozszerzeniem. Po uruchomieniu wykonaj następujące polecenie, które pozwala nam zmienićcommentChar zależnie od rodzaju pliku. Są na to inne sposoby, ale są bardziej mylące dla nowicjuszy (takich jak ja).

  • function! Docomment(): Funkcje są deklarowane, zaczynając od functioni kończąc na endfunction. Funkcje muszą zaczynać się od dużej. to !gwarantuje, że funkcja ta zastępuje wszystkie poprzednie funkcje zdefiniowane jak Docomment()z tą wersją Docomment(). Bez! miałem błędy, ale mogło to wynikać z tego, że definiowałem nowe funkcje za pomocą wiersza poleceń vim.

  • execute '''<,''>s/^\s*/&'.escape(b:commentChar, '\/').' /e': Wykonaj wywołuje polecenie. W tym przypadku wykonujemy substitute, który może przyjmować zakres (domyślnie jest to bieżący wiersz), na przykład %dla całego bufora lub '<,'>podświetlonej sekcji. ^\s*jest wyrażeniem regularnym pasującym do początku linii, po której następuje dowolna ilość białych znaków, które są następnie dodawane do (z powodu &). .Tutaj służy do łańcuchów znaków, gdyż escape()nie może być owinięty w cudzysłowach. escape()pozwala na ucieczkę znaku, commentCharktóry pasuje do argumentów (w tym przypadku \i /), poprzedzając je znakiem \. Następnie ponownie łączymy się z końcem naszego substitutełańcucha, który maeflaga. Ta flaga pozwala nam po cichu zawieść, co oznacza, że ​​jeśli nie znajdziemy dopasowania w danej linii, nie będziemy o tym krzyczeć. Jako całość, ten wiersz pozwala nam wstawić znak komentarza, po którym następuje spacja tuż przed pierwszym tekstem, co oznacza, że ​​utrzymujemy poziom wcięcia.

  • execute '''<,''>s/\v(^\s*)'.escape(b:commentChar, '\/').'\v\s*/\1/e': Jest to podobne do naszego ostatniego wielkiego długiego polecenia. Unikatowe dla tego, co mamy \v, zapewnia, że ​​nie musimy uciekać przed naszym (), i 1które odnosi się do grupy, którą stworzyliśmy z naszą (). Zasadniczo dopasowujemy linię zaczynającą się od dowolnej ilości białych znaków, a następnie nasz znak komentarza, po którym następuje dowolna ilość białych znaków, i zachowujemy tylko pierwszy zestaw białych znaków. Ponownie, epo cichu zawiedźmy, jeśli nie mamy znaku komentarza w tym wierszu.

  • let l:line=getpos("'<")[1]: ustawia zmienną podobnie jak w przypadku naszego znaku komentarza, ale lodnosi się do zasięgu lokalnego (lokalnego dla tej funkcji). getpos()otrzymuje pozycję, w tym przypadku, początku naszego wyróżnienia i [1]oznacza, że ​​dbamy tylko o numer linii, a nie o inne rzeczy, takie jak numer kolumny.

  • if match(getline(l:line), '^\s*'.b:commentChar)>-1: wiesz jak ifdziała. match()sprawdza, czy pierwsza rzecz zawiera drugą rzecz, więc chwytamy linię, od której zaczęliśmy wyróżnianie, i sprawdzamy, czy zaczyna się od białych znaków, po których następuje znak komentarza. match()zwraca indeks, w którym jest to prawda, i -1jeśli nie znaleziono żadnych dopasowań. Ponieważ ifocenia, że ​​wszystkie niezerowe liczby są prawdziwe, musimy porównać nasze dane wyjściowe, aby zobaczyć, czy są większe niż -1. Porównanie vimzwraca 0, jeśli jest fałszem, i 1, jeśli jest prawdą, co ifchce zobaczyć, aby poprawnie ocenić.

  • vnoremap <silent> <C-r> :<C-u>call Comment()<cr><cr>: vnoremapoznacza odwzoruj następujące polecenie w trybie wizualnym, ale nie mapuj go rekurencyjnie (co oznacza, że ​​nie zmieniaj żadnych innych poleceń, które mogłyby być użyte w inny sposób). Zasadniczo, jeśli jesteś początkującym vimem, zawsze używaj, noremapaby upewnić się, że nie psujesz rzeczy. <silent>oznacza „Nie chcę twoich słów, tylko twoje działania” i mówi, aby nie drukował niczego w wierszu poleceń. <C-r>to jest to, co mapujemy, czyli ctrl + r w tym przypadku (zwróć uwagę, że nadal możesz używać Cr normalnie do „ponawiania” w trybie normalnym z tym mapowaniem). C-ujest trochę mylące, ale zasadniczo zapewnia, że ​​nie stracisz kontroli nad wizualnym podświetlaniem (zgodnie z tą odpowiedzią powoduje, że twoje polecenie zaczyna od '<,'>tego, czego chcemy).call tutaj po prostu każe vimowi wykonać funkcję, którą wymieniliśmy, i <cr>odnosi się do naciśnięciaenterprzycisk. Musimy go nacisnąć raz, aby faktycznie wywołać tę funkcję (w przeciwnym razie właśnie wpisaliśmy call function()wiersz poleceń i musimy go nacisnąć ponownie, aby nasze substytuty przeszły przez całą drogę (nie do końca pewni dlaczego, ale cokolwiek).

W każdym razie, mam nadzieję, że to pomaga. Spowoduje to, że wszystko wyróżnione za pomocą v, Vlub C-vsprawdzi, czy pierwszy wiersz jest skomentowany, jeśli tak, spróbuj odkomentować wszystkie podświetlone wiersze, a jeśli nie, dodaj dodatkową warstwę znaków komentarza do każdego wiersza. To jest moje pożądane zachowanie; Nie chciałem tylko, aby przełączało się, czy każda linia w bloku była komentowana, czy nie, więc działa to idealnie dla mnie po zadaniu wielu pytań na ten temat.

jeremysprofile
źródło