¿Cómo comentar un conjunto de líneas que se seleccionan en modo visual?

35

¿Cómo comento varias líneas seleccionadas en modo visual? ¿Cómo lo hago específico para el idioma?

Por ejemplo, si se seleccionan las primeras 4 líneas:

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

La operación de un comando / macro debería resultar en esto (en python):

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

Respuestas:

31

Si desea comentarios específicos del idioma, necesitará un complemento como nerdcommenter .

Alternativamente, aunque no responde a su pregunta real, puede usar acciones integradas de vim y su conocimiento de los caracteres de comentario de cada idioma ...

Opción # 1: bloques en V

  1. :1 Enter (Ir a la línea 1)
  2. Ctrl-V (modo V-Block)
  3. jjj (Abajo 3 líneas más)
  4. Shift-I (Ingrese al modo de inserción antes del bloque)
  5. # (Inserte un '#')
  6. Esc (Volver al modo normal)

Opción # 2: sustitución

:1,4s/^/#/

Descompostura:

  1. : El comando ex sigue
  2. 1,4 en líneas del 1 al 4
  3. s sustituir
  4. /separador para piezas del comando de sustitución.
    (También puede usar un personaje diferente, por ejemplo :)
  5. ^ comienzo de la línea
  6. / separador
  7. # el personaje de comentario para python
  8. / separador final

Opción n. ° 3: repetir la aplicación de una macro ( fuente )

  1. :1 Enter (Ir a la línea 1)
  2. qa(Comience a grabar en el registro a)
  3. Shift-I (Ingrese al modo de inserción al comienzo de la línea
  4. # (Agregue un '#' al comienzo de la línea)
  5. Esc (Volver al modo normal)
  6. q (Para de grabar)

  7. :2,4 normal @a(vuelva a ejecutar la macro grabada para registrarse aen líneas entre 2 y 4)

    O

    puede seleccionar las líneas en modo visual y presionar :para llenar automáticamente la línea Ex con :'<,'>(un rango desde el principio hasta el final de la selección visual) y luego escribir normal @ay presionar Enter( fuente ).

Ahora, cuando quiera comentar algunas líneas, simplemente vuelva a ejecutar la macro grabada para registrarse aen esas líneas:

:9,22 normal @a (comment out lines 9-22)
bsmith89
fuente
1
Opción 4: Complemento
Encuesta Cody
No entiendo por qué usas una macro para un solo comando, cuando puedes hacerlo :9,22 normal I#según mi respuesta.
Ben
¿Por qué usarías: 1 <enter> cuando puedes usar gg?
Tanath
@Tanath Los comentarios desde la primera línea fueron específicos de este ejemplo. Si el autor quisiera comentar de las líneas 9 a 22, no podrían usar gg.
bsmith89
@Ben No sabía nada sobre el normalcomando antes de escribir esta respuesta. Tienes razón; :9,22 normal I#funcionará tan bien
bsmith89
26

Usando el modo Visual Block ( CtrlV), seleccione el comienzo de las líneas. Luego presione I#(esa es una letra mayúscula I) para insertar el carácter hash en cada una de esas líneas. Luego presione Escpara regresar del Modo Insertar al Modo Normal.

200_success
fuente
A mi no me funciona. Inserta un comentario solo en la primera línea.
gon1332
¿Estás empujando ctrl? Porque ctrl+ves algo diferente de lo justo v.
Cody Poll
@CodyPoll lo sé. Todo está bien hasta I. Cuando presiono I, el #se colocará solo en frente de la primera línea.
gon1332
@CodyPoll Ok .. Solo estaba internado. No presioné Escdespués del procedimiento descrito.
gon1332
@ gon1332 por lo que sé, debes presionar Escal final.
Gonçalo Ribeiro
18

Si solo necesita una solución rápida para el idioma en el que se encuentra actualmente y ya tiene el texto seleccionado en modo visual, entonces

:norm 0i#

hace el trabajo. (Para cada línea, en modo normal, vaya a la primera columna e inserte #. El uso :norm I#lo insertará antes del primer carácter que no sea un espacio en blanco, lo que puede no ser lo que desea). El uso :norm i#también funcionará, porque :normcomienza al principio del línea, pero es menos explícito y menos claro si no lo sabes.

Por supuesto, si tiene la intención de hacer esto con frecuencia, querrá configurar una asignación o buscar un complemento.

wchargin
fuente
1
0 no es necesario ya que por defecto, el normalcomando se ejecuta con el cursor al comienzo de la línea.
nitishch
1
Por supuesto, los números de línea,%, marcas se pueden prefijar con este comando. Ejemplo:: 1,5norm i # (o): 'a,' bnorm i # (o): 10% norma i #
SibiCoder
9

Hacerlo automáticamente requeriría que agregues algo como lo siguiente a tu vimrcarchivo ( fuente ):

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>

Utilizando ,cpara comentar una región y ,udescomentar una región. Esto establece manualmente los símbolos de comentario para diferentes idiomas.

La segunda opción es usar un complemento como tcomment , vim-commentary o comments.vim . Yo uso tcomment yo mismo. Por favor, lea las instrucciones de uso e instalación en sus páginas, ya que creo que eso va más allá del tema de la pregunta.

Te sugiero que uses un complemento (uno de los enlaces anteriores u otro) ya que es mucho más fácil que mantener un fragmento de código en tu vimrcarchivo.

Editar: eliminé la forma manual ya que la pregunta se modificó y 200_success respondió también la forma correcta.

tokoyami
fuente
Una sugerencia de complemento adicional: NERD Commenter - vim.org/scripts/script.php?script_id=1218
entregado
Nota: esto solo admite comentarios linealmente. Por ejemplo, ANSI C no reconoce //(solo /* */).
wchargin
Si bien me gusta este enfoque, ¿hay alguna manera de hacer que cambie los comentarios?
ideasman42
1
@ ideasman42 Tendría que hacer una función en su lugar y verificar si la línea actual comienza con un comentario y luego, dependiendo de esa llamada, cualquiera de los :scomandos que se muestran en el extracto de la respuesta. El cheque en sí sería algo así getline('.') =~ "^" . escape(b:comment_leader, '\/'). Si es un verdadero comentario, de lo contrario comente. Esto no se ha probado y solo debe servir como ejemplo.
tokoyami
5

Yo uso scrooloose / nerdcommenter para esto.

Con este complemento puede seleccionar visualmente sus líneas y presionar leader+ cpara alternar comentarios. Dependiendo del tipo de archivo, usará diferentes símbolos para comentar.

OrangeTux
fuente
5

Después de haber seleccionado las líneas, simplemente escriba

:norm I#

:se colocará automáticamente '<,'>en su línea de comando, que es un rango desde el comienzo de su selección hasta el final; normejecuta un comando de modo normal y actuará en ese rango; I#es el comando de modo normal que inserta un '#' al comienzo de la línea.

Ben
fuente
4

Soy un gran admirador de TComment por esto; no solo puedo hacer estilos de comentarios específicos de tipo de archivo, sino incluso especificar bloqueo vs por línea para los idiomas que admiten comentarios de bloque.

    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
fuente
¡Gracias por tu respuesta! ¿Podrías quizás expandirlo? Proporcionar respuestas de complementos está bien, pero en este momento es solo un enlace a un complemento. Como mínimo, se espera una descripción básica de lo que hace y cómo usarlo en la respuesta. También vea esta meta publicación .
Martin Tournoij
Parece una tontería copiar / pegar combinaciones de teclas, pero ahí lo tienes; Ya describí lo que hace.
Collin Grady
3

Creo que el complemento vim-commentary es, con mucho, la forma más fácil de hacer esto. Seleccione un rango de líneas, luego simplemente presione gc. Utilizará un carácter de comentario apropiado para el tipo de archivo que haya abierto. Incluso es posible sin ninguna selección visual descomentar líneas comentadas adyacentes con gcuo gcgc.

Andrew Ferrier
fuente
2

Suponiendo que desea agregar un prefijo a 5 líneas al comienzo de la línea, puede usar Buscar y reemplazar :

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

o al final de las líneas:

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

O use el modo visual ( Ctrl+ v) para seleccionar un bloque vertical de texto, luego ingrese al modo de inserción ( I) y escriba algo y presione Escpara confirmar y aplicar los cambios a otras líneas.

Relacionado:

kenorb
fuente
2

Esta respuesta está aquí para 1) mostrar el código correcto para pegar en un .vimrcpara obtenervim 7.4+ hacer el bloque de comentar / descomentar manteniendo nivel de sangría con 1 acceso directo en el modo visual y 2) para explicarlo.

Aquí está el código:

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>

Cómo funciona:

  • let b:commentChar='//': Esto crea una variable en vim. el baquí se refiere al alcance, que en este caso está contenido en el búfer, es decir, el archivo abierto actualmente. Sus caracteres de comentario son cadenas y deben estar entre comillas, las comillas no son parte de lo que se sustituirá al alternar comentarios.

  • autocmd BufNewFile,BufReadPost *...: Los comandos automáticos se disparan en diferentes cosas, en este caso, se disparan cuando un nuevo archivo o el archivo de lectura termina con una cierta extensión. Una vez activado, ejecute el siguiente comando, que nos permite cambiar elcommentChar de archivo dependiendo. Hay otras formas de hacer esto, pero son más confusas para los novatos (como yo).

  • function! Docomment(): Las funciones se declaran comenzando functiony terminando con endfunction. Las funciones deben comenzar con una capital. los !asegura que esta función sobrescribe los anteriores funciones definidas como Docomment()con esta versión de Docomment(). Sin el !, tuve errores, pero eso podría deberse a que estaba definiendo nuevas funciones a través de la línea de comando vim.

  • execute '''<,''>s/^\s*/&'.escape(b:commentChar, '\/').' /e': Ejecutar llama a un comando. En este caso, estamos ejecutando substitute, que puede tomar un rango (por defecto, esta es la línea actual), como %para todo el búfer o '<,'>para la sección resaltada. ^\s*es regex para que coincida con el inicio de una línea seguida de cualquier cantidad de espacio en blanco, que luego se agrega a (debido a &). El .que aquí se utiliza para la concatenación de cadenas, ya que escape()no se puede ajustar entre comillas. escape()le permite escapar del personaje commentCharque coincide con los argumentos (en este caso, \y/ ) al anteponerlos con un \. Después de esto, volvemos a concatenar con el final de nuestra substitutecadena, que tiene elebandera. Esta bandera nos permite fallar en silencio, lo que significa que si no encontramos una coincidencia en una línea determinada, no gritaremos al respecto. En general, esta línea nos permite poner un carácter de comentario seguido de un espacio justo antes del primer texto, lo que significa que mantenemos nuestro nivel de sangría.

  • execute '''<,''>s/\v(^\s*)'.escape(b:commentChar, '\/').'\v\s*/\1/e': Esto es similar a nuestro último gran comando largo. Único a este, tenemos \v, lo que asegura que no tenemos que escapar de nuestro (), y 1, que se refiere al grupo que hicimos con nuestro (). Básicamente, estamos haciendo coincidir una línea que comienza con cualquier cantidad de espacio en blanco y luego nuestro carácter de comentario seguido de cualquier cantidad de espacio en blanco, y solo mantenemos el primer conjunto de espacios en blanco. Nuevamente, edejemos de fallar en silencio si no tenemos un carácter de comentario en esa línea.

  • let l:line=getpos("'<")[1]: establece una variable muy similar a lo que hicimos con nuestro carácter de comentario, pero se lrefiere al ámbito local (local para esta función). getpos()obtiene la posición de, en este caso, el inicio de nuestro resaltado, y el[1] significa que solo nos importa el número de línea, no otras cosas como el número de columna.

  • if match(getline(l:line), '^\s*'.b:commentChar)>-1: ya sabes cómo iffunciona. match()verifica si lo primero contiene lo segundo, por lo que tomamos la línea en la que comenzamos a resaltar y verificamos si comienza con un espacio en blanco seguido de nuestro carácter de comentario. match()devuelve el índice donde esto es cierto, y -1si no se encontraron coincidencias. Como ifevalúa todos los números distintos de cero para que sean verdaderos, tenemos que comparar nuestra salida para ver si es mayor que -1. La comparación en vimdevuelve 0 si es falso y 1 si es verdadero, que es lo que ifquiere ver para evaluar correctamente.

  • vnoremap <silent> <C-r> :<C-u>call Comment()<cr><cr>: vnoremapsignifica asignar el siguiente comando en modo visual, pero no asignarlo de forma recursiva (es decir, no cambiar ningún otro comando que pueda usarse de otras maneras). Básicamente, si eres un novato vim, siempre úsalo noremappara asegurarte de no romper cosas. <silent>significa "No quiero tus palabras, solo tus acciones" y le dice que no imprima nada en la línea de comando. <C-r>es lo que estamos asignando, que es ctrl + r en este caso (tenga en cuenta que todavía puede usar Cr normalmente para "rehacer" en modo normal con esta asignación). C-ues un poco confuso, pero básicamente se asegura de que no pierdas el rastro de tu resaltado visual (según esta respuesta , tu comando comienza con '<,'>lo que queremos).callaquí solo le dice a vim que ejecute la función que nombramos, y se <cr>refiere a enterpresionar el botón. Tenemos que presionarlo una vez para llamar realmente a la función (de lo contrario, simplemente escribimos call function()en la línea de comando, y debemos presionarlo nuevamente para que nuestros sustitutos pasen por todo el camino (no estoy seguro de por qué, pero lo que sea).

De todos modos, espero que esto ayude. Esto tomará todo lo resaltado con v, Vo C-v, verifique si la primera línea está comentada, en caso afirmativo, intente descomentar todas las líneas resaltadas, y si no, agregue una capa adicional de caracteres de comentario a cada línea. Este es mi comportamiento deseado; No solo quería que cambiara si cada línea en el bloque estaba comentada o no, por lo que funciona perfectamente para mí después de hacer múltiples preguntas sobre el tema.

jeremysprofile
fuente