Ubah indentasi 2 spasi menjadi 4 spasi dalam vim

93

Saya telah menyalin beberapa kode dari Internet yang memiliki indentasi 2 spasi dan saya ingin mengubahnya menjadi indentasi 4 spasi. Saya ingin tahu apakah ada rutinitas vim singkat untuk menyelesaikan tugas tanpa harus menulis skrip vim? Berikut adalah cara saya melakukannya dengan file HTML:

  • Rekam makro
  • Pergi ke awal baris
  • Visual pilih semua spasi hingga kemunculan pertama "<"
  • Tarik dan tempel semua spasi (pada dasarnya untuk menggandakannya)
  • Putar ulang makro hingga akhir file

Pendeknya qa0vt<yp<esc>jq

Jebakan:

Makro gagal untuk baris kosong atau baris yang tidak dimulai dengan "<". Dan saya tidak tahu bagaimana memperluas solusi ini ke file non-HTML.

Lim H.
sumber

Jawaban:

175

Cara umum untuk mengubah indentasi adalah dengan mengubah tabstop:

Tempel file Anda ke buffer kosong, lalu:

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

Ini mengubah setiap 2 spasi menjadi karakter TAB, lalu:

:set ts=4 sts=4 et
:retab

Ini mengubah setiap TAB menjadi 4 spasi.

Keuntungan dari metode ini adalah Anda juga dapat menggunakannya sebaliknya, untuk mengonversi dari 4 menjadi 2 spasi misalnya.

Daan Bakker
sumber
16
@ XavierT. Saya pikir jawaban ini cukup mudah dimengerti. Dan mungkin itu akan lebih jelas jika nama perintah pendek adalah mengganti dengan nama lengkap mereka: ts: = tabstop, sts: = softtabstopdan [no]et: = [no]expandtab.
YaOzI
Dalam situasi apa retabargumen akan berguna, dan mengapa kita tidak bisa menggunakannya untuk tugas ini?
joeytwiddle
@joeytwiddle Seperti yang saya pahami, Anda dapat menggunakannya dan mencapai efek yang sama seperti jawaban ini dengan menggunakan :set sts=2 noetdan :retab! 2karenanya akan menjadi sedikit lebih pendek (meskipun mungkin kurang terbaca) seperti itu.
Daan Bakker
Metode ini juga mengubah 2 spasi menjadi 4 spasi dalam literal string dan tempat lain, bukan hanya awal baris.
nacitar sevaht
3
Gabungkan semuanya: :set ts=2 sts=2 noet | retab! | set ts=4 sts=4 et | retab!lalu gunakan @:di file yang berbeda untuk menerapkan tindakan yang sama dengan cepat.
L__
59

Ini dimungkinkan dengan :set shiftwidth=4dan gg=G.

nyata
sumber
Perhatikan bahwa jika ini tidak berhasil, Anda mungkin mengaktifkan mode yang memiliki pengaruh lain pada indentasi.
Dav Clark
1
Meskipun pertanyaannya bukan tentang solusi umum, harap dicatat bahwa ini tidak selalu berfungsi, khususnya dengan kode python.
0xc0de
5
Apa gg=Gartinya dengan exatly? Saya mengerti itu ggartinya "pindah ke 1,1", dan Gberarti "pindah ke baris terakhir".
Jonathon Reinhart
5
@JonathonReinhart =melakukan indentasi, jadi itu hanya berarti membuat indentasi dari awal hingga akhir teks
alex
bekerja lebih baik daripada %retab, yang salah mengonversi ruang yang tertanam di dalam literal string.
Alnitak
34

Apa yang saya lakukan sangat mirip dengan pendekatan esneider dan cforbish, tetapi sedikit lebih cepat untuk mengetik:

:%s/^\s*/&&

Cukup ganti spasi utama (spasi atau tab) dengan spasi utama dua kali lebih banyak ( &diganti dengan ekspresi yang cocok).

tunas
sumber
2
Ini berguna karena bekerja dengan pemilihan visual (V), cukup jatuhkan %.
Trevor Robinson
1
Saya suka yang ini juga karena tidak mengacaukan penyelarasan manual tabel yang saya miliki di komentar, dll.
stephenmm
@TrevorRobinson Dua jawaban teratas juga bekerja pada rentang.
Brian McCutchon
Ini juga memiliki keuntungan tambahan yaitu Anda dapat mengembangkannya untuk digunakan seddan diterapkan ke semua file dalam direktori superuser.com/a/159286/41494
icc97
3

Saya menggunakan ekspresi reguler ini (ini menggandakan jumlah spasi di depan):

%s;^\(\s\+\);\=repeat(' ', len(submatch(0))*2);g
cforbish
sumber
tidak %s/\s\+/&&/melakukan hal yang sama? Btw, saya pikir gbendera itu tidak perlu (untuk satu, hanya akan ada 1 pertandingan ^patterndi setiap baris, bukan?)
doubleDown
Terima kasih telah menunjukkan '&'. Saya memiliki sedikit koreksi pada Anda terutama karena Anda lupa '^' %s/^\s\+/&&/glebih dekat.
cforbish
1
Ini mirip dengan jawaban spro tetapi saya menghargai jawabannya karena memungkinkan Anda untuk mengubah lebih mudah jika Anda perlu melakukan sesuatu yang sedikit lebih rumit.
stephenmm
3

Ini adalah pertanyaan yang sangat lama, namun semua jawabannya ... salah ... Vim memiliki cara yang sangat mudah untuk mengindentifikasi kembali seluruh file. Saya belajar ini setelah menulis fungsi saya sendiri untuk melakukannya, jadi saya berada dalam perahu ketidaktahuan yang sama;)

Tipe

gg=G

ini mengasumsikan bahwa Anda mengatur tabstop sesuai keinginan Anda, (jadi untuk OP itu akan menjadi ts = 4)

Saya mempelajari ini dari http://vim.wikia.com/wiki/Fix_indentation , yang menyebutkan

Dalam mode normal, mengetik gg = G akan mengindentasi kembali seluruh file. Ini adalah kasus khusus; = adalah operator. Sama seperti d atau y, ini akan bekerja pada teks apa pun yang Anda pindahkan dengan perintah gerakan kursor. Dalam hal ini, gg memposisikan kursor pada baris pertama, kemudian = G mengindentasi ulang dari posisi kursor saat ini ke ujung buffer.

Chase Vasic
sumber
2
1. Jika Anda menggulir ke bawah sampai ke bawah, Anda akan melihat jawaban yang menyebutkan gg = G. 2. Itu tidak selalu berhasil.
Lim H.
1

Mirip (tetapi lebih sederhana) dengan jawaban cforbish, ekspresi reguler ini akan menduplikasi spasi di depan

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

Atau Anda dapat menggunakan regex lain ini untuk mengubah 2 spasi menjadi 4 spasi, mempertahankan satu spasi (dan jumlah ganjil pada umumnya)

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

Itu adalah,

  • 1 spasi ⇢ 1 spasi
  • 2 spasi ⇢ 4 spasi
  • 3 spasi ⇢ 5 spasi
  • 4 spasi ⇢ 8 spasi
esneider
sumber
1

Selain jawaban @ spro, saya memasukkan ini ke dalam file .vimrc

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

Ketik saja :Format.

Dengan pemilihan visual, ini hanya memformat garis yang dipilih.

Tanpa seleksi visual, ini memformat seluruh file.

Eli
sumber
0

Ini adalah varian dari jawaban berbasis ekspresi reguler.

Saya memiliki skrip bash di direktori bin lokal saya yang akan menggandakan jumlah spasi putih di awal baris. Input dapat berupa stdin atau file:

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

file=${1--}

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

Saya menggunakan ini dalam vim dengan memilih baris secara visual dan mengeluarkan perintah berikut:

:'<,'>!dblsp

Ini membuat saya tidak perlu mengetik (atau mengingat) regex.

Saya juga menggunakannya di peta seperti berikut:

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

yang akan menerapkannya ke blok teks yang baru saja ditempel. Saya biasanya menggunakan peta berikut untuk menempelkan:set paste

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

Alur kerja saya yang biasa adalah:

  • pilih cuplikan kode (mis. kode contoh di halaman ini adalah 2 spasi tetapi saya ingin 4)
  • tempel potongan kode (, p)
  • ubah spasi (,])

atau hanya mengubah indentasi pada blok yang ditarik yang ditempelkan dari buffer lain.

htaccess
sumber