Zmień wcięcie z 2 spacjami na 4 spacje w vimie

93

Mam kilka kodów skopiowanych z Internetu, które mają wcięcia 2-spacyjne i chcę to zmienić na wcięcie 4-spacyjne. Zastanawiam się, czy istnieje krótka procedura Vima do wykonania zadania bez konieczności pisania skryptu vim? Oto jak obecnie robię to z plikiem HTML:

  • Zarejestruj makro
  • Idź na początek wiersza
  • Wizualne zaznaczanie wszystkich białych znaków aż do pierwszego wystąpienia „<”
  • Yank i wklej wszystkie białe spacje (w zasadzie aby je podwoić)
  • Powtórz makro do końca pliku

W skrócie qa0vt<yp<esc>jq

Pułapki:

Makro kończy się niepowodzeniem w przypadku pustego wiersza lub wiersza, który nie zaczyna się od „<”. I nie mam pojęcia, jak rozszerzyć to rozwiązanie na plik inny niż HTML.

Lim H.
źródło

Odpowiedzi:

174

Ogólnym sposobem zmiany wcięcia jest zmiana tabulatora:

Wklej plik do pustego bufora, a następnie:

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

Zmienia to co 2 spacje na znak TAB, a następnie:

:set ts=4 sts=4 et
:retab

To zmienia każdą TAB na 4 spacje.

Zaletą tej metody jest to, że można jej użyć również na odwrót, na przykład do konwersji z 4 na 2 spacje.

Daan Bakker
źródło
16
@ XavierT. Właściwie myślę, że ta odpowiedź jest dość łatwa do zrozumienia. A może to będzie bardziej jasne, czy krótka nazwa polecenia jest zastąpienie ich pełną nazwą: ts: = tabstop, sts: = softtabstopi [no]et: = [no]expandtab.
YaOzI
W jakiej sytuacji retabargument byłby przydatny i dlaczego nie możemy go użyć do tego zadania?
joeytwiddle
@joeytwiddle Jak rozumiem, to mógłby wykorzystać to i osiągnąć ten sam efekt, jak przy użyciu tej odpowiedzi :set sts=2 noeti :retab! 2tak byłoby nieco krótszy (choć może mniej czytelny), że sposób.
Daan Bakker
Ta metoda zmienia również 2 spacje na 4 spacje w literałach łańcuchowych i innych miejscach, a nie tylko na początku wiersza.
nacitar sevaht
3
Połącz je wszystkie razem: :set ts=2 sts=2 noet | retab! | set ts=4 sts=4 et | retab!a następnie użyj @:w różnych plikach, aby szybko wykonać tę samą akcję.
L__
59

Może to być możliwe dzięki :set shiftwidth=4i gg=G.

perreal
źródło
Zauważ, że jeśli to nie zadziała, możesz mieć włączony tryb, który ma inny wpływ na wcięcia.
Dav Clark
1
Chociaż pytanie nie dotyczy ogólnego rozwiązania, pamiętaj, że to nie zawsze działa, szczególnie w przypadku kodu Pythona.
0xc0de
5
Co to gg=Gznaczy dokładnie? Rozumiem, że ggoznacza to „przejdź do 1,1” i G„przejdź do ostatniej linii”.
Jonathon Reinhart
5
@JonathonReinhart =wykonuje wcięcia, więc oznacza to po prostu wcięcie od początku do końca tekstu
alex
działało lepiej niż %retab, które nieprawidłowo konwertowało spacje osadzone w literałach ciągów.
Alnitak
34

To, co robię, jest bardzo podobne do podejść esneidera i cforbisha, ale trochę szybciej wpisuję:

:%s/^\s*/&&

Po prostu zastępuje wiodące spacje (spacje lub tabulatory) dwukrotnie większą spacją ( &jest zastępowane dopasowanym wyrażeniem).

spro
źródło
2
Jest to przydatne, ponieważ działa z selekcją wizualną (V), po prostu upuść %.
Trevor Robinson
1
Ten też mi się podoba b / c nie psuje żadnego ręcznego ustawiania tabel, które mam w komentarzach itp.
stephenmm
@TrevorRobinson Dwie najlepsze odpowiedzi również dotyczą zakresów.
Brian McCutchon
Ma to również dodatkową zaletę, że można go rozszerzyć do użycia sedi zastosować do wszystkich plików w katalogu superuser.com/a/159286/41494
icc97
3

Użyłem tego wyrażenia regularnego (podwaja liczbę wiodących spacji):

%s;^\(\s\+\);\=repeat(' ', len(submatch(0))*2);g
cforbish
źródło
nie %s/\s\+/&&/robi tego samego? Btw, myślę, że gflaga jest niepotrzebna (po pierwsze, byłby tylko 1 mecz z ^patternw każdej linii, nie?)
doubleDown
Dzięki za wskazanie „&”. Mam niewielką korektę, głównie dlatego, że zapomniałeś, że „^” %s/^\s\+/&&/gjest bliżej.
cforbish
1
Jest to podobne do odpowiedzi spro, ale doceniam odpowiedź, ponieważ pozwala ona na łatwiejsze dostosowanie, jeśli musisz zrobić coś nieco bardziej skomplikowanego.
stephenmm
3

To jest bardzo stare pytanie, jednak wszystkie odpowiedzi są ... błędne ... Vim ma bardzo łatwy sposób na przywrócenie całego pliku. Nauczyłem się tego po napisaniu własnej funkcji, aby to zrobić, więc jestem na tej samej łodzi ignorancji;)

rodzaj

gg=G

to przy założeniu, że masz ustawioną tabulator na to, co lubisz (więc dla OP będzie to ts = 4)

Dowiedziałem się tego z http://vim.wikia.com/wiki/Fix_indentation , o którym wspomina

W trybie normalnym wpisanie gg = G spowoduje przywrócenie całego pliku. To jest szczególny przypadek; = jest operatorem. Podobnie jak d lub y, będzie działać na każdym tekście, nad którym przesuniesz polecenie ruchu kursora. W tym przypadku gg umieszcza kursor w pierwszym wierszu, a następnie = G przenosi wcięcie od bieżącej pozycji kursora do końca bufora.

Chase Vasic
źródło
2
1. Jeśli przewiniesz w dół do samego końca, zobaczysz odpowiedź, w której jest mowa o gg = G. 2. Nie zawsze działa.
Lim H.
1

Podobne (ale nieco prostsze) do odpowiedzi cforbisha, to wyrażenie regularne powiela początkowe spacje

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

Lub możesz użyć tego innego wyrażenia regularnego, aby przekształcić 2 spacje w 4 spacje, zachowując pojedyncze spacje (i ogólnie nieparzyste ilości)

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

To jest,

  • 1 spacja ⇢ 1 spacja
  • 2 spacje ⇢ 4 spacje
  • 3 spacje ⇢ 5 spacji
  • 4 spacje ⇢ 8 spacji
esneider
źródło
1

Oprócz odpowiedzi @ spro umieściłem to w moim .vimrc

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

Po prostu wpisz :Format.

W przypadku wyboru wizualnego formatuje to tylko wybrane linie.

Bez selekcji wizualnej formatuje to cały plik.

Eli
źródło
0

To jest wariant odpowiedzi opartych na wyrażeniach regularnych.

Mam skrypt bash w moim lokalnym katalogu bin, który podwoi ilość białych znaków na początku wiersza. Wejście może być stdin lub plikiem:

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

file=${1--}

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

Używam tego w Vimie, wizualnie wybierając linię i wydając następujące polecenie:

:'<,'>!dblsp

Oszczędza mi to potrzeby wpisywania (lub zapamiętywania) wyrażenia regularnego.

Używam go również w mapach takich jak:

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

co spowoduje zastosowanie go do bloku ostatnio wklejonego tekstu. Zwykle używam następującej mapy do wklejania zamiast:set paste

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

Mój typowy przepływ pracy to:

  • wybierz fragment kodu (np. przykładowy kod na tej stronie to 2 spacje, ale chcę 4)
  • wklej fragment kodu (, p)
  • zmień odstępy (,])

lub po prostu zmieniając wcięcie na szarpanych blokach wklejonych z innego bufora.

htaccess
źródło