Comment commenter un ensemble de lignes sélectionnées en mode visuel?

35

Comment commenter plusieurs lignes sélectionnées en mode visuel? Comment puis-je le rendre spécifique à la langue?

Par exemple, si les 4 premières lignes sont sélectionnées:

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

L'opération d'une commande / macro devrait avoir pour résultat (en python):

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

Réponses:

31

Si vous souhaitez commenter une langue spécifique, vous aurez besoin d'un plugin tel que nerdcommenter .

Sinon, bien que cela ne réponde pas à votre question, vous pouvez utiliser les actions vim intégrées et votre connaissance des caractères de commentaire de chaque langue ...

Option n ° 1: V-blocks

  1. :1 Enter (Aller à la ligne 1)
  2. Ctrl-V (mode V-Block)
  3. jjj (3 lignes plus bas)
  4. Shift-I (entrer en mode insertion avant le bloc)
  5. # (Insérer un '#')
  6. Esc (Retour au mode normal)

Option n ° 2: substitution

:1,4s/^/#/

Panne:

  1. : La commande Ex suit
  2. 1,4 sur les lignes 1 à 4
  3. s remplacer
  4. /séparateur pour les éléments de la commande de substitution.
    (Vous pouvez également utiliser un caractère différent, par exemple :)
  5. ^ début de la ligne
  6. / séparateur
  7. # le caractère de commentaire pour python
  8. / séparateur final

Option n ° 3: Répéter l'application d'une macro ( source )

  1. :1 Enter (Aller à la ligne 1)
  2. qa(Démarrer l'enregistrement sur le registre a)
  3. Shift-I (Entrée en mode insertion au début de la ligne
  4. # (Ajoutez un '#' au début de la ligne)
  5. Esc (Retour au mode normal)
  6. q (Arrête d'enregistrer)

  7. :2,4 normal @a(relancez la macro enregistrée pour vous inscrire asur les lignes 2 à 4)

    OU

    vous pouvez sélectionner les lignes en mode visuel et appuyer :pour remplir automatiquement la ligne Ex :'<,'>(une plage allant du début à la fin de la sélection visuelle), puis taper normal @aet frapper Enter( source ).

Maintenant, chaque fois que vous souhaitez commenter certaines lignes, il suffit de réexécuter la macro enregistrée pour s’enregistrer asur ces lignes:

:9,22 normal @a (comment out lines 9-22)
bsmith89
la source
1
Option 4: Plugin
Cody Poll
Je ne comprends pas pourquoi vous utilisez une macro pour une commande unique, alors que vous pouvez le faire :9,22 normal I#conformément à ma réponse.
Ben
Pourquoi voudriez-vous utiliser: 1 <entrée> quand vous pouvez utiliser gg?
Tanath
@Tanath Les commentaires de la première ligne étaient spécifiques à cet exemple. Si l'auteur souhaitait commenter des lignes 9 à 22, il ne pourrait pas utiliser gg.
bsmith89
@ Ben, je ne connaissais rien à la normalcommande avant d'écrire cette réponse. Tu as raison; :9,22 normal I#fonctionnera aussi bien.
bsmith89
26

En utilisant le mode Visual Block ( CtrlV), sélectionnez le début des lignes. Appuyez ensuite I#(c'est une lettre majuscule I) pour insérer le caractère de hachage sur chacune de ces lignes. Appuyez ensuite sur Escpour revenir du mode insertion au mode normal.

200_success
la source
Ca ne marche pas pour moi Il insère un commentaire uniquement dans la première ligne.
gon1332
Est-ce que vous poussez ctrl? Parce que ctrl+vc'est différent de juste v.
Cody Poll
@CodyPoll je sais. Tout va bien jusqu'à I. Lorsque j'appuie sur I, le #sera placé uniquement devant la première ligne.
gon1332
@CodyPoll Ok .. j'étais juste hospitalisé. Je n'ai pas appuyé Escaprès la procédure décrite.
gon1332
@ Gon1332 pour autant que je sache, vous devez appuyer Escà la fin.
Gonçalo Ribeiro
18

Si vous avez juste besoin d’une solution rapide pour la langue dans laquelle vous êtes actuellement et que le texte est déjà sélectionné en mode visuel, alors

:norm 0i#

Fait le travail. (Pour chaque ligne, en mode normal, accédez à la première colonne et insérez-la #. Utilisation :norm I#sera insérée avant le premier caractère non-blanc, ce qui peut ne pas être ce que vous voulez.) Utiliser :norm i#fonctionnera également, car :normcommence au début de la ligne, mais il est moins explicite et moins clair si vous ne le savez pas.

Bien sûr, si vous avez l’intention de le faire fréquemment, vous devrez configurer un mappage ou rechercher un plugin.

wchargin
la source
1
0 n'est pas nécessaire car, par défaut, la normalcommande est exécutée avec le curseur au début de la ligne.
Nitishch
1
Bien sûr, les numéros de ligne,%, marques peuvent être préfixés avec cette commande. Exemple:: 1,5norm i # (ou): 'a,' bnorm i # (ou): 10% de la norme i #
SibiCoder
9

Faire cela automatiquement vous obligerait à ajouter quelque chose comme ceci dans votre vimrcfichier ( source ):

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>

Utiliser ,cpour commenter une région et ,udécommenter une région. Ceci définit manuellement les symboles de commentaire pour différentes langues.

La deuxième option consiste à utiliser un plugin tel que tcomment , vim-commentary ou comments.vim . J'utilise tcomment moi-même. S'il vous plaît, lisez les instructions d'utilisation et d'installation sur leurs pages car je pense que cela dépasse le sujet de la question.

Je suggérerais que vous utilisiez un plugin (l'un des liens ci-dessus ou un autre), ce qui est beaucoup plus facile que de conserver un morceau de code dans votre vimrcfichier.

Edit: J'ai supprimé le mode manuel car la question a été modifiée et le mode correct a été répondu par 200_success.

tokoyami
la source
Une suggestion de plugin supplémentaire: commentateur NERD - vim.org/scripts/script.php?script_id=1218
donnée le
Remarque: cela ne prend en charge que les commentaires ligne par ligne. Par exemple, ANSI C ne reconnaît pas //(uniquement /* */).
wchargin
Bien que cette approche me plaise, existe-t-il un moyen de la faire basculer dans les commentaires?
ideasman42
1
@ ideasman42 Vous devez plutôt créer une fonction et vérifier si la ligne actuelle commence par un commentaire, puis en fonction de cet appel, l'une des :scommandes indiquées dans l'extrait de la réponse. Le chèque lui-même serait quelque chose comme getline('.') =~ "^" . escape(b:comment_leader, '\/'). Si c'est vrai, commentez, sinon. Ceci n’a pas été testé et ne devrait servir qu’à titre d’exemple.
tokoyami
5

J'utilise scrooloose / nerdcommenter pour cela.

Avec ce plugin, vous pouvez sélectionner visuellement vos lignes et appuyer sur leader+ cpour faire basculer les commentaires. Selon le type de fichier, il utilisera différents symboles pour les commentaires.

OrangeTux
la source
5

Après avoir sélectionné les lignes, tapez simplement

:norm I#

:sera automatiquement mis '<,'>sur votre ligne de commande, qui va du début à la fin de votre sélection; normexécute une commande en mode normal et agira sur cette plage; I#est la commande de mode normal qui insère un '#' au début de la ligne.

Ben
la source
4

Je suis un grand fan de TComment pour ça; non seulement je peux créer des styles de commentaires spécifiques à un type de fichier, mais je peux même spécifier bloc par ligne pour les langues qui prennent en charge les commentaires de bloc.

    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
la source
Merci pour votre réponse! Pourriez-vous peut-être l'agrandir? Fournir des réponses de plug-in est correct, mais pour le moment, il s'agit simplement d'un lien vers un plug-in. À tout le moins, une réponse de base sur ce qu'il fait et comment l'utiliser est attendue dans la réponse. voir aussi ce meta post .
Martin Tournoij
Cela semble idiot de copier / coller des keybinds, mais voilà; J'ai déjà décrit ce que ça fait.
Collin Grady
3

Je trouve que le plugin vim-commentary est de loin le moyen le plus simple de le faire. Sélectionnez une plage de lignes, puis appuyez simplement sur gc. Il utilisera un caractère de commentaire approprié pour le type de fichier que vous avez ouvert. Il est même possible sans sélection visuelle de décommenter les lignes commentées adjacentes avec gcuou gcgc.

Andrew Ferrier
la source
2

En supposant que vous souhaitiez ajouter un préfixe à 5 lignes au début de la ligne, vous pouvez utiliser Rechercher et remplacer :

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

ou au bout des lignes:

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

Ou utilisez le mode visuel ( Ctrl+ v) pour sélectionner un bloc de texte vertical, puis entrez en mode insertion ( I), tapez quelque chose et appuyez sur Escpour confirmer et appliquer les modifications aux autres lignes.

En relation:

Kenorb
la source
2

Cette réponse est ici pour 1) montrer le code correct à coller dans un .vimrcpour pouvoir vim 7.4+faire un bloc en commentant / décommentant tout en maintenant 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 marche:

  • let b:commentChar='//': Ceci crée une variable dans vim. le bfait ici référence à la portée, qui dans ce cas est contenue dans le tampon, ce qui signifie le fichier actuellement ouvert. Les caractères de vos commentaires sont des chaînes et doivent être entourés de guillemets. Les guillemets ne font pas partie de ce qui sera substitué 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é, exécutez la commande suivante, ce qui nous permet de changer le type commentCharde fichier en fonction. Il y a d'autres moyens de le faire, mais ils sont plus déroutants pour les novices (comme moi).

  • function! Docomment(): Les fonctions sont déclarées en commençant par functionet se terminant par endfunction. Les fonctions doivent commencer par une capitale. les !assure que cette fonction écrase toutes les fonctions précédentes définis comme Docomment()avec cette version de Docomment(). Sans cela !, j'avais 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': Execute appelle une commande. Dans ce cas, nous sommes en train de nous exécuter substitute, ce qui peut prendre une plage (par défaut, il s’agit de la ligne courante), par exemple %pour l’ensemble du tampon ou '<,'>pour la section en surbrillance. ^\s*est regex pour correspondre au début d'une ligne suivi de n'importe quelle quantité d'espaces, qui est ensuite ajoutée à (due à &). Le .here est utilisé pour la concaténation de chaînes, car escape()il ne peut pas être placé entre guillemets. escape()vous permet d'échapper au caractère commentCharqui correspond aux arguments (dans ce cas, \et /) en les préfixant avec un \. Après cela, nous concaténons à nouveau avec la fin de notre substitutechaîne, qui a laedrapeau. Cet indicateur nous laisse échouer en silence, ce qui signifie que si nous ne trouvons pas de correspondance sur une ligne donnée, nous ne crierons pas dessus. 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 commande longue et énorme. Nous avons un système unique en son genre \v, qui garantit que nous n’avons pas à échapper à notre groupe (), et 1qui fait référence au groupe que nous avons créé avec notre groupe (). Fondamentalement, nous faisons correspondre une ligne qui commence par n'importe quelle quantité d’espace, suivie de notre caractère de commentaire suivi de toute quantité d’espace, et nous ne conservons que le premier ensemble d’espace. 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 de, dans ce cas, le début de notre surbrillance, et les [1]moyens pour nous ne nous soucions que 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, alors nous prenons 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. Etant donné que iftous les nombres non nuls sont vrais, nous devons comparer notre sortie pour voir si elle est supérieure à -1. La comparaison dans vimrenvoie 0 si faux et 1 si vrai, qui est ce que ifveut 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 mappe pas de manière récursive (autrement dit, ne modifiez aucune autre commande pouvant être utilisée d'une autre manière). En gros, si vous êtes un novice de Vim, noremapveillez toujours à ne pas casser des 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 ce que nous mappons, ctrl + r dans ce cas (notez que vous pouvez toujours utiliser Cr normalement pour "rétablir" en mode normal avec ce mappage). C-uC'est un peu déroutant, mais en gros, cela garantit que vous ne perdez pas la trace de votre surbrillance visuelle (selon cette réponse , votre commande commencera par '<,'>ce que nous voulons).callIci, il indique simplement à vim d'exécuter la fonction que nous avons nommée, et <cr>fait référence à l'appui sur le enterbouton. Nous devons appuyer une fois pour appeler la fonction (sinon, nous tapons call function()sur la ligne de commande et nous devons appuyer à nouveau pour que nos remplaçants passent au travers (sans trop savoir pourquoi, mais peu importe).

Quoi qu'il en soit, j'espère que cela aide. Cela prend tout ce qui est en surbrillance avec v, Vou C-v, vérifiez si la première ligne est commentée, si oui, essayez de supprimer le commentaire de toutes les lignes en surbrillance et, dans le cas contraire, ajoutez une couche supplémentaire de caractères de commentaire à chaque ligne. C'est mon comportement souhaité. Je ne voulais pas seulement que chaque ligne du bloc soit commentée ou non. Cela fonctionne donc parfaitement pour moi après avoir posé plusieurs questions sur le sujet.

jeremysprofile
la source