Alterar recuo de 2 espaços para 4 espaços no vim

91

Copiei alguns códigos da Internet que têm recuo de 2 espaços e quero transformá-los em recuo de 4 espaços. Eu me pergunto se existe uma rotina curta do vim para realizar a tarefa sem ter que escrever o script do vim? Aqui está como estou fazendo isso com um arquivo HTML:

  • Grave uma macro
  • Vá para o início de uma linha
  • Selecione visualmente todos os espaços em branco até a primeira ocorrência de "<"
  • Puxe e cole todos os espaços em branco (basicamente para duplicá-los)
  • Repete a macro até o final do arquivo

Em resumo qa0vt<yp<esc>jq

Armadilhas:

A macro falha para uma linha em branco ou uma linha que não começa com "<". E não tenho ideia de como estender essa solução para um arquivo não HTML.

Lim H.
fonte

Respostas:

170

Uma maneira geral de alterar o recuo é alterando o tabstop:

Cole seu arquivo em um buffer vazio e:

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

Isso muda a cada 2 espaços para um caractere TAB, então:

:set ts=4 sts=4 et
:retab

Isso muda cada TAB para 4 espaços.

A vantagem deste método é que você também pode usá-lo ao contrário, para converter de 4 para 2 espaços, por exemplo.

Daan Bakker
fonte
16
@ XavierT. Na verdade, acho que essa resposta é muito fácil de entender. E talvez será mais claro se o nome do comando curta é substituir com o seu nome completo: ts: = tabstop, sts: = softtabstope [no]et: = [no]expandtab.
YaOzI 01 de
Em que situação retabo argumento seria útil e por que não podemos usá-lo para essa tarefa?
joeytwiddle
@joeytwiddle Pelo que entendi, você poderia usar isso e obter o mesmo efeito que esta resposta usando :set sts=2 noete, :retab! 2portanto, seria um pouco mais curto (embora talvez menos legível) dessa forma.
Daan Bakker
Este método também altera 2 espaços para 4 espaços em literais de string e outros lugares, em vez de apenas o início da linha.
nacitar sevaht
2
Junte-os todos: :set ts=2 sts=2 noet | retab! | set ts=4 sts=4 et | retab!e use-os @:em arquivos diferentes para aplicar rapidamente a mesma ação.
L__
58

Pode ser possível com :set shiftwidth=4e gg=G.

perreal
fonte
Observe que se isso não funcionar, você pode ter um modo ativado que tem alguma outra influência no recuo.
Dav Clark
1
Embora a questão não seja sobre uma solução geral, observe que isso nem sempre funciona, especialmente com código python.
0xc0de
5
O que gg=Gsignifica exatamente? Eu entendo que ggsignifica "mover para 1,1" e Gsignifica "mover para a última linha".
Jonathon Reinhart de
5
@JonathonReinhart =faz recuo, então significa apenas recuar do início ao fim do texto
alex
funcionou melhor do que %retab, que converteu incorretamente espaços incorporados em literais de string.
Alnitak
33

O que eu faço é muito semelhante às abordagens de esneider e cforbish, mas um pouco mais rápido de digitar:

:%s/^\s*/&&

Simplesmente substitui o espaço inicial (espaços ou tabulações) pelo dobro do espaço inicial ( &é substituído pela expressão correspondente).

spro
fonte
2
Isso é útil porque funciona com seleção visual (V), basta soltar o %.
Trevor Robinson
1
Eu gosto deste também b / c não mexe com nenhum alinhamento manual de tabelas que tenho nos comentários etc.
stephenmm
@TrevorRobinson As duas respostas principais também funcionam em intervalos.
Brian McCutchon
Isso também tem o benefício adicional de que você pode expandi-lo para usar sede aplicá-lo a todos os arquivos em um diretório superuser.com/a/159286/41494
icc97
3

Esta é uma pergunta muito antiga, porém todas as respostas estão ... erradas ... O Vim tem uma maneira muito fácil de reindentar o arquivo inteiro. Aprendi isso depois de escrever minha própria função para fazê-lo, então estou no mesmo barco da ignorância;)

tipo

gg=G

isso pressupõe que você tenha seu tabstop configurado para o que você gosta, (então para o OP seria ts = 4)

Aprendi isso em http://vim.wikia.com/wiki/Fix_indentation , que menciona

No modo normal, digitar gg = G reindentará o arquivo inteiro. Este é um caso especial; = é um operador. Assim como d ou y, ele atuará em qualquer texto que você mover com um comando de movimento do cursor. Neste caso, gg posiciona o cursor na primeira linha, então = G re-indenta da posição atual do cursor até o final do buffer.

Chase Vasic
fonte
2
1. Se você rolar para baixo até o fim, verá uma resposta mencionando gg = G. 2. Nem sempre funciona.
Lim H.
2

Eu usei esta expressão regular (ela dobra o número de espaços à esquerda):

%s;^\(\s\+\);\=repeat(' ', len(submatch(0))*2);g
cforbish
fonte
não %s/\s\+/&&/faz a mesma coisa? A propósito, acho que o gsinalizador é desnecessário (por exemplo, haveria apenas 1 correspondência com ^patternem cada linha, não?)
doubleDown
Obrigado por apontar '&'. Tenho uma pequena correção no seu, principalmente porque você se esqueceu de que o '^' %s/^\s\+/&&/gestá mais próximo.
cforbish
Isso é semelhante à resposta do spro, mas agradeço a resposta, pois permite que você faça ajustes mais facilmente se precisar fazer algo um pouco mais complicado.
stephenmm
1

Semelhante (mas um pouco mais simples) à resposta de cforbish, este regex irá duplicar os espaços iniciais

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

Ou você pode usar este outro regex para transformar 2 espaços em 4 espaços, preservando espaços únicos (e quantidades ímpares em geral)

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

Isso é,

  • 1 espaço ⇢ 1 espaço
  • 2 espaços ⇢ 4 espaços
  • 3 espaços ⇢ 5 espaços
  • 4 espaços ⇢ 8 espaços
Esneider
fonte
0

Esta é uma variante das respostas baseadas em regex.

Eu tenho um script bash em meu diretório bin local que dobrará a quantidade de espaços em branco no início de uma linha. A entrada pode ser stdin ou um arquivo:

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

file=${1--}

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

Eu uso isso no vim selecionando visualmente uma linha e emitindo o seguinte comando:

:'<,'>!dblsp

Isso me livra da necessidade de digitar (ou lembrar) o regex.

Eu também o uso em mapas como o seguinte:

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

que o aplicará a um bloco de texto recentemente colado. Eu geralmente uso o seguinte mapa para colar em vez de:set paste

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

Meu fluxo de trabalho normal é:

  • selecione o snippet de código (por exemplo, o código de exemplo nesta página tem 2 espaços, mas eu quero 4)
  • colar snippet de código (, p)
  • alterar o espaçamento (,])

ou simplesmente alterando o recuo em blocos arrancados colados de outro buffer.

htaccess
fonte
0

Além da resposta de @ spro, coloquei isso em meu .vimrc

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

Basta digitar :Format.

Com a seleção visual, isso apenas formata as linhas selecionadas.

Sem seleção visual, isso formata todo o arquivo.

Eli
fonte