Commenter plusieurs lignes de code, spécifiées par des numéros de ligne, à l'aide de vi ou vim

20

J'ai appris de cette question de débordement de pile qu'il est possible d'utiliser vi/ vimde commenter une plage spécifiée de numéros de ligne. Par exemple, supposons que j'ai le script bash suivant:

#!/bin/bash

This
is
my
very
very
great
script

Supposons maintenant que je veux commenter les numéros de ligne 6 à 8 (qui contiennent les mots very, veryet great) en utilisant le #caractère de commentaire. Dans vi/ vim, je peux simplement taper :6,8s/^/#pour obtenir ce qui suit:

#!/bin/bash

This
is
my
#very
#very
#great
script

qui commente les lignes 6 à 8.

Ma question est, est-il possible de taper une doublure similaire qui supprimera le #caractère de commentaire des lignes 6 à 8 (mais pas d'autres lignes commentées dans le fichier)?

Cela dit, je me rends compte qu'il y a un débat quant à savoir si j'utilise réellement viou vim. En pratique, j'ouvre un fichier script.shavec la commande vi script.sh. De plus, lorsque je tape la commande which vi, j'obtiens /usr/bin/vi. Néanmoins, lorsque je tape viet appuie simplement Enter, j'obtiens ceci:

~                              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

qui semble suggérer que j'utilise réellement vim. J'accède à un cluster Ubuntu Linux distant à l'aide de SSH depuis mon PC. Je n'utilise pas d'interface graphique Ubuntu Linux.

Andrew
la source

Réponses:

22

Vous pouvez utiliser:

:6,8s/^#//

Mais il est beaucoup plus facile d'utiliser le mode de sélection Block Visual: allez au début de la ligne 6, appuyez sur Ctrl-v, descendez à la ligne 8 et appuyez sur x.

Il existe également le plugin "The NERD Commenter" .

jofel
la source
2
NERD Commenterest la voie à suivre ici à mon avis! +1 pour cela
user1146332
7

Je sais que votre question précise d'utiliser viouvim mais voici quelques autres options pour le faire sans avoir à ouvrir manuellement le fichier:

  • Perl

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

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

    Cela imprimera le contenu du fichier, vous pouvez soit rediriger vers un autre ( > new_file.sh) ou utiliser ipour modifier le fichier en place:

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

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

    Encore une fois, pour que cela modifie le fichier d'origine en place, utilisez i:

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

    gawk '(NR<=8 && NR>= 6){sub("^ *#","")}{print}' foo.sh
    
  • Pur 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
la source
1
Il ne s'agit pas tant de "devoir ouvrir le fichier manuellement", car généralement vous décidez quelles lignes commenter lors de l'inspection visuelle, lors de l'édition :) Mais bien sûr, c'est une bonne réponse pour être complet.
Paulo Almeida
2
@PauloAlmeida, vous avez bien sûr raison. Je pensais juste que cela pourrait être utile car l'OP connaît déjà les numéros de ligne (à cause de la première commande utilisée pour les commenter) et, en tout cas, les outils que je montre peuvent être appliqués à une variété de problèmes.
terdon
4

viest un lien symbolique vers la vimplupart des distributions GNU / Linux, vous les utilisez donc vimlorsque vous tapez vi.

Pour supprimer les commentaires, vous pouvez taper: :6,8s/^#//ou :6,8s/^\s*#//pour supprimer un espace de début avant le # symbole.

lgeorget
la source
1
Merci beaucoup. Il semble qu'il puisse y avoir des fautes de frappe. Peut-être que ça devrait être :6,8s/^#//et 6,8s/^\s*#//?
Andrew
3

Vous utilisez probablement vim.tiny. Dans tous les cas, vous pouvez supprimer les premiers commentaires avec:

:6,8s/^#//

Bien sûr, si vous les insérez d'une manière différente (par exemple, avec un espace supplémentaire), vous devrez peut-être supprimer tout ce qui s'y trouve. Avec full vim, sélectionner visuellement des colonnes et insérer / supprimer des caractères est un moyen plus simple de faire la même chose.

Paulo Almeida
la source
3

Personnellement, ma façon préférée utilise le mode de blocage visuel

ctrl+ vpour entrer en mode de blocage visuel, utilisez les touches fléchées ou hjkl pour sélectionner les lignes et appuyez sur xoudel .

Voulez-vous les récupérer?

ctrl+ vfaire la sélection, puis I(majuscule i)#Esc

exussum
la source
3

AFAIK, vi est généralement un lien symbolique de vim de nos jours (essayez which viou type vipuis suivez les liens symboliques). Peut-être même /usr/bin/vi-> /etc/alternatives/vi-> /usr/bin/vim.basic.

Personnellement, pour supprimer plusieurs lignes de commentaires, je préfère sélectionner un bloc vertical via CtrlVet le supprimer. Si vous devez ajouter un symbole de commentaire à plusieurs lignes, vous pouvez CtrlValors ShiftItaper #et Escet un commentaire sera ajouté à plusieurs lignes.

Boris Burkov
la source
2

Les réponses ci-dessus, en utilisant

:6,8s/^#//

sont une solution parfaite, mais un peu lourde à taper. Cela peut être simplifié en définissant de nouvelles commandes dans ~/.vimrc.

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

Et vous pouvez simplement taper

:6,8C
:6,8D

pour placer / supprimer la commande.

Si vous aimez le mode visuel, vous pouvez définir des cartes

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

De telle sorte que vous n'avez qu'à sélectionner une plage de lignes en mode visuel, puis appuyez sur F7et F8pour mettre et supprimer des commentaires respectivement.

Bernhard
la source
1

Il y a ce plugin qui change la vie par tpopeappelévim-commentary

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

Ce plugin fournit :

  • Santé mentale
  • Commentaires correctement en retrait
  • Ne met pas en commentaire les lignes vides / inutiles

Utilisation :

  • Installez via Vundle (ou Pathogen je suppose).
  • Mettez en surbrillance votre texte et appuyez sur :qui montrera que:<,'>
  • Saisissez Commentaire ici :<,'>Commentaryet appuyez sur Entrée.
  • Bom. Votre bourgeon fini.
Weston Ganger
la source
1

Cette réponse est là pour 1) montrer le code correct à coller dans un .vimrcpour obtenirvim 7.4+ le faire bloc commenter / décommenter tout en gardant le niveau d'indentation avec 1 raccourci en mode visuel et 2) pour l' expliquer.

Voici le 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>

Comment ça fonctionne:

  • let b:commentChar='//': Cela crée une variable dans vim. le bfait référence ici à la portée, qui dans ce cas est contenu dans la mémoire tampon, ce qui signifie le fichier actuellement ouvert. Vos caractères de commentaire sont des chaînes et doivent être placés entre guillemets, les guillemets ne font pas partie de ce qui sera remplacé lors du basculement des commentaires.

  • autocmd BufNewFile,BufReadPost *...: Les commandes automatiques se déclenchent sur différentes choses, dans ce cas, elles se déclenchent lorsqu'un nouveau fichier ou le fichier lu se termine avec une certaine extension. Une fois déclenchée, exécutez la commande suivante, qui nous permet de changer le type commentCharde fichier en fonction. Il existe d'autres façons de le faire, mais elles sont plus déroutantes pour les novices (comme moi).

  • function! Docomment(): Les fonctions sont déclarées en commençant par functionet en terminant par endfunction. Les fonctions doivent commencer par un capital. le !garantit que cette fonction écrase toutes les fonctions précédentes définies comme Docomment()avec cette version de Docomment(). Sans le !, j'ai eu des erreurs, mais c'est peut-être parce que je définissais de nouvelles fonctions via la ligne de commande vim.

  • execute '''<,''>s/^\s*/&'.escape(b:commentChar, '\/').' /e': Exécuter appelle une commande. Dans ce cas, nous exécutons substitute, ce qui peut prendre une plage (par défaut, c'est la ligne actuelle) comme %pour tout le tampon ou '<,'>pour la section en surbrillance. ^\s*est regex pour correspondre au début d'une ligne suivie par n'importe quelle quantité d'espace, qui est ensuite ajoutée à (en raison de &). L' .ici est utilisé pour la concaténation de chaînes, car escape()il ne peut pas être placé entre guillemets. escape()vous permet d'échapper le caractère commentCharqui correspond aux arguments (dans ce cas, \et /) en les ajoutant au début par un \. Après cela, nous concaténons à nouveau avec la fin de notre substitutechaîne, qui a leedrapeau. Ce drapeau nous permet d'échouer en silence, ce qui signifie que si nous ne trouvons pas de correspondance sur une ligne donnée, nous ne crierons pas à ce sujet. Dans l'ensemble, cette ligne nous permet de mettre un caractère de commentaire suivi d'un espace juste avant le premier texte, ce qui signifie que nous conservons notre niveau d'indentation.

  • execute '''<,''>s/\v(^\s*)'.escape(b:commentChar, '\/').'\v\s*/\1/e': Ceci est similaire à notre dernière énorme commande longue. Unique à celui-ci, nous l'avons \v, ce qui garantit que nous n'avons pas à échapper à notre (), et 1, qui fait référence au groupe que nous avons fait avec notre (). Fondamentalement, nous faisons correspondre une ligne qui commence par n'importe quelle quantité d'espace, puis notre caractère de commentaire suivi par n'importe quelle quantité d'espace, et nous ne conservons que le premier ensemble d'espaces. Encore une fois, elaissez-nous échouer en silence si nous n'avons pas de caractère de commentaire sur cette ligne.

  • let l:line=getpos("'<")[1]: cela définit une variable un peu comme nous l'avons fait avec notre caractère de commentaire, mais lfait référence à la portée locale (locale à cette fonction). getpos()obtient la position, dans ce cas, le début de notre surbrillance, et les [1]moyens que nous nous soucions uniquement du numéro de ligne, pas d'autres choses comme le numéro de colonne.

  • if match(getline(l:line), '^\s*'.b:commentChar)>-1: vous savez comment ça ifmarche. match()vérifie si la première chose contient la deuxième chose, nous prenons donc la ligne sur laquelle nous avons commencé notre surbrillance, et vérifions si elle commence par un espace suivi de notre caractère de commentaire. match()renvoie l'index où cela est vrai et -1si aucune correspondance n'a été trouvée. Étant donné que iftous les nombres non nuls sont vrais, nous devons comparer notre sortie pour voir si elle est supérieure à -1. La comparaison en vimretourne 0 si faux et 1 si vrai, c'est ce ifque l' on veut voir pour évaluer correctement.

  • vnoremap <silent> <C-r> :<C-u>call Comment()<cr><cr>: vnoremapsignifie mapper la commande suivante en mode visuel, mais ne la mappez pas récursivement (c'est-à-dire ne modifiez aucune autre commande qui pourrait être utilisée d'une autre manière). Fondamentalement, si vous êtes un novice vim, utilisez toujours noremappour vous assurer de ne pas casser les choses. <silent>signifie "Je ne veux pas de vos mots, juste de vos actions" et lui dit de ne rien imprimer sur la ligne de commande. <C-r>est la chose que nous mappons, qui est ctrl + r dans ce cas (notez que vous pouvez toujours utiliser Cr normalement pour "refaire" en mode normal avec ce mappage). C-uest un peu déroutant, mais fondamentalement, il garantit que vous ne perdez pas la trace de votre mise en évidence visuelle (selon cette réponse, cela fait démarrer votre commande avec '<,'>ce que nous voulons).call ici juste dit à vim d'exécuter la fonction que nous avons nommée, et<cr> fait référence à la frappeenterbouton. Nous devons le frapper une fois pour appeler la fonction (sinon nous venons de taper call function()sur la ligne de commande, et nous devons le frapper à nouveau pour que nos remplaçants passent au travers (pas vraiment pourquoi, mais peu importe).

Quoi qu'il en soit, j'espère que cela aide. Cela prendra quoi que ce soit mis en évidence avec v, VouC-v , vérifiez si la première ligne est commentée, si oui, essayez de décommenter toutes les lignes en surbrillance, et sinon, ajoutez une couche supplémentaire de caractères de commentaire à chaque ligne. C'est mon comportement souhaité; Je ne voulais pas simplement qu'il permute si chaque ligne du bloc était commentée ou non, donc cela fonctionne parfaitement pour moi après avoir posé plusieurs questions sur le sujet.

jeremysprofile
la source