Cambiar sangría de 2 espacios a 4 espacios en vim

93

Tengo algunos códigos copiados de Internet que tienen sangría de 2 espacios y quiero cambiarlos a sangría de 4 espacios. Me pregunto si hay una rutina vim corta para realizar la tarea sin tener que escribir un script vim. Así es como lo estoy haciendo actualmente con un archivo HTML:

  • Grabar una macro
  • Ir al principio de una línea
  • Visual seleccione todos los espacios en blanco hasta la primera aparición de "<"
  • Tira y pega todos los espacios en blanco (básicamente para doblarlos)
  • Reproducir la macro hasta el final del archivo

En breve qa0vt<yp<esc>jq

Escollos:

La macro falla para una línea en blanco o una línea que no comienza con "<". Y no tengo idea de cómo extender esta solución a archivos que no son HTML.

Lim H.
fuente

Respuestas:

175

Una forma general de cambiar la sangría es cambiando el tabstop:

Pegue su archivo en un búfer vacío, luego:

:set ts=2 sts=2 noet
:retab!

Esto cambia cada 2 espacios a un carácter TAB, luego:

:set ts=4 sts=4 et
:retab

Esto cambia cada TAB a 4 espacios.

La ventaja de este método es que también puedes usarlo al revés, para convertir de 4 a 2 espacios por ejemplo.

Daan Bakker
fuente
16
@ XavierT. De hecho, creo que esta respuesta es bastante fácil de entender. Y tal vez será más claro si el nombre del comando corta es reemplazar con su nombre completo: ts: = tabstop, sts: = softtabstopy [no]et: = [no]expandtab.
YaOzI
¿En qué situación sería retabútil el argumento y por qué no podemos usarlo para esta tarea?
joeytwiddle
@joeytwiddle Según tengo entendido, podría usar eso y lograr el mismo efecto que esta respuesta usando :set sts=2 noety, :retab! 2por lo tanto, sería un poco más corto (aunque quizás menos legible) de esa manera.
Daan Bakker
Este método también cambia 2 espacios a 4 espacios dentro de literales de cadena y otros lugares, en lugar de solo el comienzo de la línea.
nacitar sevaht
3
Ponlos todos juntos: :set ts=2 sts=2 noet | retab! | set ts=4 sts=4 et | retab!y luego úsalos @:en diferentes archivos para aplicar rápidamente la misma acción.
L__
59

Puede ser posible con :set shiftwidth=4y gg=G.

perreal
fuente
Tenga en cuenta que si esto no funciona, es posible que tenga un modo habilitado que tenga alguna otra influencia en la sangría.
Dav Clark
1
Aunque la pregunta no se trata de una solución general, tenga en cuenta que esto no siempre funciona, especialmente con el código Python.
0xc0de
5
¿Qué gg=Gsignifica exatly? Entiendo que ggsignifica "mover a 1,1" y Gsignifica "mover a la última línea".
Jonathon Reinhart
5
@JonathonReinhart = hace sangría, por lo que solo significa sangrar de principio a fin del texto
alex
funcionó mejor que %retab, que convirtió incorrectamente espacios incrustados dentro de cadenas literales.
Alnitak
34

Lo que hago es muy similar a los enfoques de esneider y cforbish, pero un poco más rápido de escribir:

:%s/^\s*/&&

Simplemente reemplaza el espacio inicial (espacios o tabulaciones) con el doble de espacio inicial ( &se sustituye por la expresión coincidente).

spro
fuente
2
Esto es útil porque funciona con selección visual (V), simplemente suelte el %.
Trevor Robinson
1
Yo al igual que éste a su vez b / c que no pierde el tiempo con cualquier alineación manual de las tablas que tengo en los comentarios, etc.
stephenmm
@TrevorRobinson Las dos respuestas principales también funcionan en rangos.
Brian McCutchon
Esto tiene también la ventaja añadida de que se puede expandir hacia fuera a usar sedy aplicarlo a todos los archivos en un directorio superuser.com/a/159286/41494
icc97
3

Usé esta expresión regular (duplica el número de espacios iniciales):

%s;^\(\s\+\);\=repeat(' ', len(submatch(0))*2);g
cforbish
fuente
no %s/\s\+/&&/hace lo mismo? Por cierto, creo que la gbandera es innecesaria (por un lado, solo habría 1 coincidencia ^patternen cada línea, ¿no?)
doubleDown
Gracias por señalar '&'. Tengo una pequeña corrección en la suya principalmente porque olvidó que el '^' %s/^\s\+/&&/gestá más cerca.
cforbish
1
Esto es similar a la respuesta de spro, pero agradezco la respuesta, ya que le permite modificarlo más fácilmente si necesita hacer algo un poco más complicado.
Stephenmm
3

Esta es una pregunta muy antigua, sin embargo, todas las respuestas son ... incorrectas ... Vim tiene una manera muy fácil de reindentrar todo el archivo. Aprendí esto después de escribir mi propia función para hacerlo, así que estoy en el mismo bote de la ignorancia;)

tipo

gg=G

esto es asumiendo que tiene su tabstop configurado como lo desea, (por lo que para el OP sería ts = 4)

Aprendí esto de http://vim.wikia.com/wiki/Fix_indentation , que menciona

En modo normal, escribir gg = G reindentrará todo el archivo. Este es un caso especial; = es un operador. Al igual que d o y, actuará sobre cualquier texto sobre el que se mueva con un comando de movimiento del cursor. En este caso, gg coloca el cursor en la primera línea, luego = G vuelve a sangrar desde la posición actual del cursor hasta el final del búfer.

Chase Vasic
fuente
2
1. Si se desplaza hacia abajo hasta el final, verá una respuesta que menciona gg = G. 2. No siempre funciona.
Lim H.
1

Similar (pero algo más simple) a la respuesta de cforbish, esta expresión regular duplicará los espacios iniciales

:%s/^\( \+\)/\1\1

O puede usar esta otra expresión regular para transformar 2 espacios en 4 espacios, preservando espacios únicos (y cantidades impares en general)

:%s/^\(\(  \)\+\)/\1\1

Es decir,

  • 1 espacio ⇢ 1 espacio
  • 2 espacios ⇢ 4 espacios
  • 3 espacios ⇢ 5 espacios
  • 4 espacios ⇢ 8 espacios
esneider
fuente
1

Además de la respuesta de @ spro, puse esto en mi .vimrc

command! -range=% Format :<line1>,<line2>s/^\s*/&&

Solo escribe :Format.

Con la selección visual, esto solo formatea las líneas seleccionadas.

Sin selección visual, esto formatea todo el archivo.

Eli
fuente
0

Esta es una variante de las respuestas basadas en expresiones regulares.

Tengo un script bash en mi directorio bin local que duplicará la cantidad de espacios en blanco al comienzo de una línea. La entrada puede ser stdin o un archivo:

$ cat ~/bin/dblsp
#!/bin/bash

file=${1--}

while IFS= read -r line; do
    echo "$line" | sed 's/\s*/&&/'
done < <(cat -- "$file")

Utilizo esto dentro de vim seleccionando visualmente una línea y emitiendo el siguiente comando:

:'<,'>!dblsp

Esto me ahorra la necesidad de escribir (o recordar) la expresión regular.

También lo uso en mapas como el siguiente:

nnoremap <leader>] `[V`]!dblsp<CR>

que lo aplicará a un bloque de texto pegado recientemente. Normalmente uso el siguiente mapa para pegar en lugar de:set paste

nnoremap <leader>p :r !xclip -o<CR>

Mi flujo de trabajo habitual es:

  • seleccione el fragmento de código (por ejemplo, el código de ejemplo en esta página tiene 2 espacios pero quiero 4)
  • pegar fragmento de código (, p)
  • cambiar el espaciado (,])

o simplemente cambiando la sangría en los bloques pegados desde otro búfer.

htaccess
fuente