Como posso converter espaços em guias no Vim ou Linux?

189

Eu examinei várias perguntas no Stack Overflow para saber como converter espaços em guias sem encontrar o que eu preciso. Parece haver mais perguntas sobre como converter guias em espaços, mas estou tentando fazer o oposto.

Em VimEu tentei :retabe :retab!sem sorte, mas acredito que esses são realmente para ir de tabulações para espaços de qualquer maneira.

Eu tentei os dois expande unexpandno prompt de comando sem sorte.

Aqui está o arquivo em questão:

http://gdata-python-client.googlecode.com/hg-history/a9ed9edefd61a0ba0e18c43e448472051821003a/samples/docs/docs_v3_example.py

Como converter espaços à esquerda em guias usando Vimo shell ou?

cwd
fonte
No comentário de @ Matt agora excluído, o primeiro exemplo ( sed "s/ +/`echo -e '\t'`/g" < input.py > output.py) parece converter todos os espaços, não apenas espaços iniciais. No segundo exemplo ( sed "s/^ +/`echo -e '\t'`/g" < input.py > output.py), ele substitui apenas o primeiro espaço de cada linha por uma guia e deixa o restante deles.
Cwd
Relacionado ao contrário: como substituir guias por espaços? em Vim SE
kenorb
Não encontrei resposta para todos / muitos arquivos , então escrevi o meu próprio: stackoverflow.com/a/44581474/1115187 . Com find, awke blackjack (muito tempo para deixar nos comentários)
maxkoryukov

Respostas:

313

Usando o Vim para expandir todos os espaços à esquerda (maior que 'tabstop'), você estava certo de usar, retabmas primeiro verifique 'expandtab'se a redefinição ( :verbose set ts? et?é seu amigo). retabtem um intervalo , por isso geralmente especifico %para significar "o arquivo inteiro".

:set tabstop=2      " To match the sample file
:set noexpandtab    " Use tabs, not spaces
:%retab!            " Retabulate the whole file

Antes de fazer algo assim (particularmente com arquivos Python!), Costumo definir 'list', para que eu possa ver o espaço em branco e mudar.

Eu tenho o seguinte mapeamento no meu.vimrc para isso:

nnoremap    <F2> :<C-U>setlocal lcs=tab:>-,trail:-,eol:$ list! list? <CR>
Johnsyweb
fonte
2
Aqui está como eu tenho que trabalhar, não sei o que é necessário eo que não é, e btw eu não sei o que o "%" antes reatab está fazendo: :set noet, :set tabstop=2, :retab!, :%retab!, :set tabstop=1, :retab!,:%retab!
CWD
2
Atualizei minha resposta para incluir uma explicação do motivo pelo qual uso %. O mapeamento F2 é exatamente como foi digitado .
31412 Johnsyweb 1:12
7
Para esse arquivo em particular, eu faria::set noet ts=2 |%retab!
Johnsyweb 02/02
1
@ Johnsyweb para ser justo, eu estava errado: :%retab!ainda funciona. Eu estava confuso com ==, etc, que faz respeitar a configuração preserveindent.
Unk
1
Para converter um arquivo CoffeeScript de espaços para guias I seguido @ resposta de Johnsyweb (incluindo a adição para o arquivo .vimrc) mas em vez com um:set tabstop=4
Mikeumus
38

1 - Se você possui espaços e deseja tabulações.

Primeiro, você precisa decidir quantos espaços terão uma única guia. Dito isto, suponha que você tenha linhas com 4 espaços à esquerda, ou 8 ... Do que você imagina, provavelmente deseja que uma guia tenha 4 espaços. Agora, com essas informações, você faz:

:set ts=4
:set noet
:%retab!

Existe um problema aqui! Essa sequência de comandos procurará todo o seu texto, não apenas espaços no início da linha. Isso significa que uma string como: "Hey,␣this␣␣␣␣is␣4␣spaces"se tornará "Hey,␣this⇥is␣4␣spaces", mas não é! é uma guia!

Para resolver esse pequeno problema, recomendo um search, em vez de retab.

:%s/^\(^I*\)␣␣␣␣/\1^I/g

Essa pesquisa procurará no arquivo inteiro todas as linhas começando com qualquer número de guias, seguido por 4 espaços e substituindo-o pelo número de guias encontradas mais uma.

Infelizmente, isso não será executado de uma vez!

A princípio, o arquivo terá linhas começando com espaços. A pesquisa converterá apenas os 4 primeiros espaços em uma guia e permitirá o seguinte ...

Você precisa repetir o comando. Quantas vezes? Até você receber um pattern not found. Ainda não consigo pensar em uma maneira de automatizar o processo. Mas se você fizer:

`10@:`

Você provavelmente já terminou. Este comando repete a última pesquisa / substituição por 10 vezes. Não é provável que o seu programa tenha tantos recuos. Se tiver, basta repetir novamente @@.

Agora, apenas para completar a resposta. Sei que você pediu o contrário, mas nunca sabe quando precisa desfazer as coisas.

2 - Você tem abas e deseja espaços.

Primeiro, decida a quantos espaços você deseja converter suas guias. Digamos que você queira que cada guia tenha 2 espaços. Você então faz:

:set ts=2
:set et
:%retab!

Isso teria o mesmo problema com as strings. Mas como seu melhor estilo de programação para não usar guias rígidas dentro de strings, você realmente está fazendo uma coisa boa aqui. Se você realmente precisa de uma guia dentro de uma string, use \t.

Dr. Beco
fonte
Parece uma condição de corrida extremamente rara. De qualquer forma, crie uma função que aceite a seleção do intervalo visual e repita a função de pesquisa até que nenhuma correspondência seja encontrada, acho que seria uma resposta mais inteligente e útil.
Albfan
Sim, ou aquilo. Se você deseja uma solução mais definitiva, pode usar uma função. De qualquer forma, é sempre bom saber como fazer no ex command, porque isso seria o que está dentro da função. E não, não é raro. Você só precisa ter strings com espaços para ter uma bagunça. Não é raro. Eu estou lá. Obrigado por comentar.
Dr Beco
Explique por que / g não é suficiente para converter todos os grupos de 4 em cada linha de espaços consecutivos em guias, em vez de ter que executar a pesquisa várias vezes.
Bjartur Thorlacius
Olá, @BjarturThorlacius, o problema é que, se você remover o ^símbolo, para iniciar a pesquisa a partir do início da linha, corre o risco de mudar de espaço dentro das strings. Com a ^garantia, você está alterando apenas espaços e tabulações desde o início da linha e, portanto, recuo. Além disso, se você tiver certeza de que está tudo bem em ^executar de uma só vez , remova-o e execute-o apenas uma vez com::%s/\(^I*\)␣␣␣␣/\1^I/g
Dr. Beco
14
:%s/\(^\s*\)\@<=    /\t/g

Conversão: pesquise todas as instâncias de 4 espaços consecutivos (após o caractere =), mas apenas se a linha inteira até esse ponto for em branco (isso usa a asserção look-behind de largura zero \@<=). Substitua cada instância encontrada por um caractere de tabulação.

Simon Zuckerbraun
fonte
1
A única solução que funcionou para expandir 1 espaço para 1 guia , mas cuidado com o unicode na resposta, eu apenas usei :%s/\(^\s*\)\@<= /\t/g- coloque o número apropriado de espaços (para converter 4 espaços em 1 guia, coloque 4 espaços) logo após o<=
Orwellophile
5

Altera todos os espaços para a guia:% s / \ s / \ t / g

murat budak
fonte
Isto é precisamente o que eu precisava. Obrigado. A única alteração que tive que fazer foi substituir a cada 4 espaços por uma guia, em vez de fazer todos os espaços.
Pessoa anônima
3

Linux: com unexpand(e expand)

Aqui está uma solução muito boa: https://stackoverflow.com/a/11094620/1115187 , principalmente porque usa * nix-utilities:

  1. inexpandir - espaços -> guias
  2. expandir - guias -> espaços

Linux: script customizado

Minha resposta original

Snippet de festança para substituir o recuo de 4 espaços (existem dois {4}no script) por guias em todos os .pyarquivos da ./apppasta (recursivamente):

find ./app -iname '*.py' -type f \
    -exec awk -i inplace \
    '{ match($0, /^(( {4})*)(.*?)$/, arr); gsub(/ {4}/, "\t", arr[1]) }; { print arr[1] arr[3] }' {} \; 

Não modifica 4 espaços no meio ou no final.

Foi testado no Ubuntu 16.0xe Linux Mint 18

maxkoryukov
fonte
0

No meu caso, eu tinha vários espaços (os campos foram separados por um ou mais espaços) que eu queria substituir por uma guia. O seguinte foi feito:

:% s/\s\+/\t/g
zee
fonte
0

Se você coreutils GNU instalado, considere %!unexpand --first-onlyou para guias 4-espaciais, considere %!unexpand -t 4 --first-only( --first-onlyestá presente apenas no caso de você foram acidentalmente invocando unexpandcom --all).

Observe que isso substituirá apenas os espaços que precedem as paradas prescritas da guia, não os espaços que os seguem; você não verá nenhuma diferença visual no vim, a menos que exiba as guias mais literalmente; por exemplo, meu ~/.vimrccontém set list listchars=tab:▸┈(suspeito que seja por isso que você pensou unexpandque não funcionou).

Adam Katz
fonte
0

Para usar o Vim para redefinir novamente um conjunto de arquivos (por exemplo, todos os arquivos * .ts em uma hierarquia de diretórios) de 2 espaços para 4 espaços, tente isso na linha de comando:

find . -name '*.ts' -print0 | xargs -0 -n1 vim -e '+set ts=2 noet | retab! | set ts=4 et | retab | wq'

O que isto está fazendo é usar findpara passar todos os arquivos correspondentes para xargs(a opção -print0 em find funciona com a opção -0 para xargs para manipular arquivos com espaços no nome).

O xargs executa o vim no modo ex ( -e) em cada arquivo que executa o comando ex fornecido, que na verdade são vários comandos, para alterar os espaços iniciais existentes para guias, redefinindo a parada de tabulação e alterando as guias de volta para espaços e, finalmente, salvando e saindo.

A execução no modo ex impede isso: Vim: Warning: Input is not from a terminalpara cada arquivo.

Mike Lippert
fonte
-1

Script Python simples:

import os

SOURCE_ROOT = "ROOT DIRECTORY - WILL CONVERT ALL UNDERNEATH"

for root, dirs, files in os.walk(SOURCE_ROOT):
    for f in files:
        fpath = os.path.join(root,f)
        assert os.path.exists(fpath)
        data = open(fpath, "r").read()
        data = data.replace("    ", "\t")
        outfile = open(fpath, "w")
        outfile.write(data)
        outfile.close()
Michael W.
fonte
Um enorme problema: esse trecho substitui todos os 4-espaços, não só recuo (no início da linha)
maxkoryukov
eo segundo: file-filtro não está implementada
maxkoryukov