Commentare più righe di codice, specificate dai numeri di riga, usando vi o vim


20

Ho imparato da questa domanda Stack Overflow che è possibile utilizzare vi/ vimcommentare un intervallo specificato di numeri di riga. Ad esempio, supponiamo che io abbia il seguente script bash:

#!/bin/bash

This
is
my
very
very
great
script

Supponiamo ora che voglio commentare i numeri di riga 6 a 8 (che contengono le parole very, verye great), utilizzando il #carattere di commento. In vi/ vim, posso semplicemente digitare :6,8s/^/#per ottenere quanto segue:

#!/bin/bash

This
is
my
#very
#very
#great
script

che commenta le righe da 6 a 8.

La mia domanda è: è possibile digitare una riga simile che rimuoverà il #carattere di commento dalle righe da 6 a 8 (ma non altre righe commentate nel file)?

Detto questo, mi rendo conto che si sta discutendo se sto effettivamente utilizzando vio vim. In pratica, apro un file script.shcon il comando vi script.sh. Inoltre, quando digito il comando which vi, ottengo /usr/bin/vi. Tuttavia, quando scrivo vie premo semplicemente Enter, ottengo questo:

~                              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

che sembra suggerire che sto effettivamente usando vim. Sto accedendo a un cluster Ubuntu Linux remoto usando SSH dal mio PC. Non sto usando una GUI di Ubuntu Linux.

Risposte:


22

Puoi usare:

:6,8s/^#//

Ma molto più semplice è usare la modalità di selezione Block Visual: vai all'inizio della riga 6, premi Ctrl-v, scendi alla riga 8 e premi x.

C'è anche il plug-in "The NERD Commenter" .


2
NERD Commenterè la strada da percorrere qui secondo me! +1 per quello
user1146332

7

So che la tua domanda specifica l'utilizzo vio, vimma qui ci sono alcune altre opzioni per farlo senza dover aprire manualmente il file:

  • Perl

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

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

    Questo stamperà il contenuto del file, puoi reindirizzare a un altro ( > new_file.sh) o utilizzare iper modificare il file in posizione:

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

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

    Ancora una volta, per rendere questa modifica il file originale in atto, utilizzare i:

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

    gawk '(NR<=8 && NR>= 6){sub("^ *#","")}{print}' foo.sh
    
  • Puro 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
    

1
Non si tratta tanto di "dover aprire manualmente il file", perché di solito decidi quali righe commentare durante l'ispezione visiva, durante la modifica :) Ma certo, è una buona risposta per completezza.
Paulo Almeida,

2
@PauloAlmeida hai ragione ovviamente. Ho pensato che potesse essere utile poiché l'OP conosce già i numeri di riga (a causa del primo comando usato per commentarli) e, in ogni caso, gli strumenti che mostro possono essere applicati a una varietà di problemi.
terdon

4

viè un collegamento simbolico alla vimmaggior parte della distribuzione GNU / Linux, quindi stai effettivamente usando vimquando scrivi vi.

Per rimuovere i commenti, è possibile digitare: :6,8s/^#//o :6,8s/^\s*#//eliminare uno spazio iniziale prima del # simbolo.


1
Grazie mille. Sembra che ci possano essere errori di battitura. Forse dovrebbe essere :6,8s/^#//e 6,8s/^\s*#//?
Andrew,

3

Probabilmente stai usando vim.tiny. In ogni caso, puoi rimuovere i commenti iniziali con:

:6,8s/^#//

Naturalmente, se li inserisci in un modo diverso (ad esempio, con uno spazio aggiuntivo), potrebbe essere necessario rimuovere qualsiasi altra cosa ci sia. Con vim completo, selezionare visivamente le colonne e inserire / eliminare caratteri è un modo più semplice per fare la stessa cosa.


3

Personalmente il mio modo preferito è usare la modalità blocco visivo

ctrl+ vper accedere alla modalità blocco visivo, utilizzare i tasti freccia o hjkl per selezionare le linee e premere xo del.

Li vuoi indietro?

ctrl+ vfai la selezione, quindi I(maiuscola i)#Esc


3

AFAIK, vi è di solito un collegamento simbolico di vim al giorno d'oggi (provare which vio type vie quindi seguire i collegamenti simbolici). Forse, anche /usr/bin/vi-> /etc/alternatives/vi-> /usr/bin/vim.basic.

Personalmente, per rimuovere più righe di commento, preferisco selezionare un blocco verticale CtrlVed eliminarlo. Se è necessario aggiungere un simbolo di commento a più righe, è possibile CtrlVquindi ShiftIdigitare #e Esce un commento verrà aggiunto a più righe.


2

Le risposte sopra, usando

:6,8s/^#//

sono la soluzione perfetta, ma un po 'ingombrante da digitare. Questo può essere semplificato definendo nuovi comandi in ~/.vimrc.

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

E puoi semplicemente digitare

:6,8C
:6,8D

per posizionare / eliminare il comando.

Se ti piace la modalità visiva, puoi definire le mappe

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

Tale che devi solo selezionare un intervallo di linee in modalità visiva e premere F7e F8per inserire e rimuovere rispettivamente i commenti.


1

C'è questo plugin che cambia la vita tpopechiamatovim-commentary

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

Questo plugin fornisce :

  • salute mentale
  • Commenti correttamente rientrati
  • Non commenta le righe vuote / non necessarie

Utilizzo :

  • Installa tramite Vundle (o Pathogen immagino).
  • Evidenzia il tuo testo e premi :quale verrà visualizzato come:<,'>
  • Scrivi qui il commento :<,'>Commentarye premi Invio.
  • Bom. Il tuo amico fatto.

1

Questa risposta è qui per 1) mostrare il codice corretto da incollare in .vimrca vim 7.4+per fare in modo da bloccare i commenti / i commenti, mantenendo il livello di rientro con 1 scorciatoia in modalità visiva e 2) per spiegarlo.

Ecco il codice:

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>

Come funziona:

  • let b:commentChar='//': Questo crea una variabile in vim. il bqui si riferisce al campo di applicazione, che in questo caso è contenuto al buffer, cioè il file aperto. I caratteri del tuo commento sono stringhe e devono essere racchiusi tra virgolette, le virgolette non fanno parte di ciò che verrà sostituito quando si alternano i commenti.

  • autocmd BufNewFile,BufReadPost *...: I comandi automatici si attivano su cose diverse, in questo caso si attivano quando un nuovo file o il file letto termina con una determinata estensione. Una volta attivato, esegui il seguente comando, che ci consente di modificare il commentCharsecondo tipo di file. Ci sono altri modi per farlo, ma sono più confusi per i principianti (come me).

  • function! Docomment(): Le funzioni vengono dichiarate iniziando con functione terminando con endfunction. Le funzioni devono iniziare con un capitale. le !assicura che questa funzione sovrascrive qualsiasi precedenti funzioni definite Docomment()con questa versione di Docomment(). Senza il !, ho avuto degli errori, ma ciò potrebbe essere dovuto al fatto che stavo definendo nuove funzioni tramite la riga di comando di vim.

  • execute '''<,''>s/^\s*/&'.escape(b:commentChar, '\/').' /e': Esegui chiama un comando. In questo caso, stiamo eseguendo substitute, che può assumere un intervallo (per impostazione predefinita questa è la riga corrente) come %per l'intero buffer o '<,'>per la sezione evidenziata. ^\s*è regex in modo che corrisponda all'inizio di una riga seguita da qualsiasi quantità di spazio bianco, che viene quindi aggiunto (a causa di &). Il .qui è usato per la concatenazione di stringhe, poiché escape()non può essere racchiuso tra virgolette. escape()ti permette di sfuggire al carattere commentCharche corrisponde agli argomenti (in questo caso \e /) anteponendoli con a \. Dopo questo, ci concateniamo di nuovo con la fine della nostra substitutestringa, che ha ilebandiera. Questa bandiera ci consente di fallire silenziosamente, il che significa che se non troviamo una corrispondenza su una determinata linea, non urleremo al riguardo. Nel complesso, questa riga ci consente di inserire un carattere di commento seguito da uno spazio appena prima del primo testo, il che significa che manteniamo il nostro livello di rientro.

  • execute '''<,''>s/\v(^\s*)'.escape(b:commentChar, '\/').'\v\s*/\1/e': Questo è simile al nostro ultimo enorme comando lungo. Unico a questo, abbiamo \v, il che ci assicura che non dobbiamo sfuggire al nostro (), e 1che si riferisce al gruppo che abbiamo fatto con il nostro (). Fondamentalmente, stiamo abbinando una linea che inizia con qualsiasi quantità di spazio bianco e quindi il nostro carattere di commento seguito da qualsiasi quantità di spazio bianco, e stiamo solo mantenendo il primo set di spazi bianchi. Ancora una volta, epossiamo fallire silenziosamente se non abbiamo un carattere di commento su quella riga.

  • let l:line=getpos("'<")[1]: imposta una variabile come abbiamo fatto con il nostro carattere di commento, ma si lriferisce all'ambito locale (locale a questa funzione). getpos()ottiene la posizione, in questo caso, l'inizio della nostra evidenziazione e i [1]mezzi che ci interessano solo del numero di riga, non di altre cose come il numero di colonna.

  • if match(getline(l:line), '^\s*'.b:commentChar)>-1: sai come iffunziona. match()controlla se la prima cosa contiene la seconda cosa, quindi prendiamo la linea su cui abbiamo iniziato la nostra evidenziazione e controlliamo se inizia con uno spazio bianco seguito dal nostro carattere di commento. match()restituisce l'indice dove questo è vero e -1se non sono state trovate corrispondenze. Poiché ifvaluta che tutti i numeri diversi da zero sono veri, dobbiamo confrontare il nostro output per vedere se è maggiore di -1. Il confronto tra vimrestituisce 0 se falso e 1 se vero, che è ciò che ifvuole vedere per valutare correttamente.

  • vnoremap <silent> <C-r> :<C-u>call Comment()<cr><cr>: vnoremapsignifica mappare il seguente comando in modalità visiva, ma non mapparlo in modo ricorsivo (il che significa che non cambia altri comandi che potrebbero essere utilizzati in altri modi). Fondamentalmente, se sei un principiante, usa sempre noremapper assicurarti di non rompere le cose. <silent>significa "Non voglio le tue parole, solo le tue azioni" e gli dice di non stampare nulla sulla riga di comando. <C-r>è la cosa che stiamo mappando, che in questo caso è ctrl + r (nota che puoi sempre usare Cr normalmente per "ripetere" in modalità normale con questa mappatura). C-uè un po 'confuso, ma fondamentalmente si assicura che non si perda traccia dell'evidenziazione visiva (in base a questa risposta fa iniziare il comando con '<,'>quale è quello che vogliamo).callqui dice solo a Vim di eseguire la funzione che abbiamo nominato e si <cr>riferisce a enterpremere il pulsante. Dobbiamo premerlo una volta per chiamare effettivamente la funzione (altrimenti abbiamo appena digitato call function()sulla riga di comando e dobbiamo premerlo di nuovo per fare in modo che i nostri sostituti procedano fino in fondo (non sono sicuro del perché, ma qualunque cosa).

Comunque, si spera che questo aiuti. Ciò richiederà qualsiasi cosa evidenziata con v, Vo C-v, controlla se la prima riga è commentata, in caso affermativo, prova a rimuovere il commento da tutte le linee evidenziate e, in caso contrario, aggiungi un ulteriore livello di caratteri di commento a ciascuna riga. Questo è il mio comportamento desiderato; Non volevo solo cambiare se ogni riga del blocco è stata commentata o meno, quindi funziona perfettamente per me dopo aver fatto più domande sull'argomento.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.