Thay đổi thụt lề 2 dấu cách thành 4 dấu cách trong vim


93

Tôi đã sao chép một số mã từ Internet có thụt lề 2 dấu cách và tôi muốn thay đổi nó thành thụt lề 4 dấu cách. Tôi tự hỏi nếu có một thói quen vim ngắn để hoàn thành nhiệm vụ mà không cần phải viết kịch bản vim? Đây là cách tôi hiện đang thực hiện với tệp HTML:

  • Ghi lại một macro
  • Đi đến đầu dòng
  • Trực quan chọn tất cả các khoảng trắng cho đến khi xuất hiện đầu tiên của "<"
  • Yank và dán tất cả các khoảng trắng (về cơ bản để nhân đôi chúng)
  • Phát lại macro cho đến cuối tệp

Nói ngắn gọn qa0vt<yp<esc>jq

Cạm bẫy:

Macro không thành công đối với một dòng trống hoặc một dòng không bắt đầu bằng "<". Và tôi không biết làm thế nào để mở rộng giải pháp này cho tệp không phải HTML.

Câu trả lời:


174

Một cách chung để thay đổi thụt lề là thay đổi thanh tab:

Dán tệp của bạn vào bộ đệm trống, sau đó:

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

Điều này thay đổi cứ 2 khoảng trắng thành một ký tự TAB, sau đó:

:set ts=4 sts=4 et
:retab

Điều này thay đổi mọi TAB thành 4 khoảng trắng.

Ưu điểm của phương pháp này là bạn cũng có thể sử dụng nó theo cách khác, để chuyển đổi từ 4 thành 2 khoảng trắng chẳng hạn.


16
@ XavierT.Tôi thực sự nghĩ câu trả lời này khá dễ hiểu. Và có lẽ nó sẽ được rõ ràng hơn nếu tên lệnh ngắn gọn là thay thế với tên đầy đủ của mình: ts: = tabstop, sts= softtabstop[no]et: = [no]expandtab.
YaOzI

Trong tình huống nào retab, lập luận sẽ hữu ích và tại sao chúng ta không thể sử dụng nó cho nhiệm vụ này?
joeytwiddle

@joeytwiddle Theo tôi hiểu, bạn có thể sử dụng câu trả lời đó và đạt được hiệu quả như câu trả lời này bằng cách sử dụng :set sts=2 noet:retab! 2vì vậy nó sẽ ngắn hơn một chút (mặc dù có lẽ ít đọc hơn) theo cách đó.
Daan Bakker

Phương thức này cũng thay đổi 2 dấu cách thành 4 dấu cách trong chuỗi ký tự và các vị trí khác, thay vì chỉ ở đầu dòng.
nacitar sevaht

3
Đặt tất cả chúng lại với nhau: :set ts=2 sts=2 noet | retab! | set ts=4 sts=4 et | retab!và sau đó sử dụng @:trong các tệp khác nhau để nhanh chóng áp dụng cùng một hành động.
L__

59

Nó có thể có thể với :set shiftwidth=4gg=G.


Lưu ý rằng nếu điều này không hiệu quả, bạn có thể đã bật một chế độ có một số ảnh hưởng khác đến việc thụt lề.
Dav Clark

1
Mặc dù câu hỏi không phải về một giải pháp chung, xin lưu ý rằng điều này không phải lúc nào cũng hoạt động, đặc biệt là với mã python.
0xc0de

5
Tinh tế gg=Gnghĩa là gì? Tôi hiểu điều đó ggcó nghĩa là "di chuyển đến 1,1" và Gcó nghĩa là "di chuyển đến dòng cuối cùng".
Jonathon Reinhart.

5
@JonathonReinhart =không thụt, vì vậy nó chỉ có nghĩa là để thụt lề từ đầu đến cuối văn bản
alex

hoạt động tốt hơn %retab, điều này đã chuyển đổi không chính xác không gian được nhúng bên trong các ký tự chuỗi.
Alnitak

34

Những gì tôi làm rất giống với cách tiếp cận của esneider và cforbish, nhưng nhập nhanh hơn một chút:

:%s/^\s*/&&

Chỉ cần thay thế khoảng trắng ở đầu (dấu cách hoặc tab) bằng gấp đôi khoảng trắng ở đầu ( &được thay thế bằng biểu thức đã so khớp).


2
Điều này rất tiện lợi vì nó hoạt động với lựa chọn trực quan (V), chỉ cần thả %.
Trevor Robinson

1
Tôi cũng thích cái này b / c nó không gây rối với bất kỳ căn chỉnh thủ công nào của các bảng mà tôi có trong nhận xét, v.v.
stephenmm

@TrevorRobinson Hai câu trả lời hàng đầu cũng hoạt động trên phạm vi.
Brian McCutchon

Điều này cũng có thêm lợi ích mà bạn có thể mở rộng nó ra để sử dụng sedvà áp dụng nó cho tất cả các file trong một thư mục superuser.com/a/159286/41494
icc97

3

Tôi đã sử dụng biểu thức chính quy này (nó tăng gấp đôi số khoảng trắng ở đầu):

%s;^\(\s\+\);\=repeat(' ', len(submatch(0))*2);g

không %s/\s\+/&&/làm điều tương tự? Btw, tôi nghĩ gcờ là không cần thiết (đối với một, sẽ chỉ có 1 trận đấu với ^patternmỗi dòng, phải không?)
doubleDown

Cảm ơn vì đã chỉ ra '&'. Tôi có một chút chỉnh sửa cho của bạn chủ yếu là vì bạn quên '^' %s/^\s\+/&&/glà gần hơn.
cforbish

1
Điều này tương tự như câu trả lời của Spit nhưng tôi đánh giá cao câu trả lời vì nó cho phép bạn tweet nó dễ dàng hơn nếu bạn cần làm điều gì đó phức tạp hơn một chút.
stephenmm

3

Đây là một câu hỏi rất cũ, tuy nhiên tất cả các câu trả lời đều ... sai ... Vim có một cách rất dễ dàng để reindent toàn bộ tệp. Tôi đã học được điều này sau khi viết chức năng của riêng mình để làm điều đó, vì vậy tôi đang ở trong cùng một chiếc thuyền ngu dốt;)

kiểu

gg=G

điều này giả sử rằng bạn đã đặt tabstop thành những gì bạn thích, (vì vậy đối với OP, nó sẽ là ts = 4)

Tôi học được điều này từ http://vim.wikia.com/wiki/Fix_indentation , đề cập đến

Ở chế độ bình thường, nhập gg = G sẽ hiển thị toàn bộ tệp. Đây là một trường hợp đặc biệt; = là một toán tử. Cũng giống như d hoặc y, nó sẽ hoạt động trên bất kỳ văn bản nào mà bạn di chuyển qua bằng lệnh chuyển động con trỏ. Trong trường hợp này, gg định vị con trỏ trên dòng đầu tiên, sau đó = G thụt lề lại từ vị trí con trỏ hiện tại đến cuối vùng đệm.


2
1. Nếu bạn cuộn xuống dưới cùng, bạn sẽ thấy câu trả lời đề cập đến gg = G. 2. Nó không phải lúc nào cũng hoạt động.
Lim H.

1

Tương tự (nhưng hơi đơn giản hơn) với câu trả lời của cforbish, regex này sẽ sao chép các khoảng trắng ở đầu

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

Hoặc bạn có thể sử dụng regex khác này để chuyển đổi 2 dấu cách thành 4 dấu cách, bảo toàn các khoảng trắng đơn (và số lượng lẻ nói chung)

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

Đó là,

  • 1 khoảng trắng ⇢ ​​1 khoảng trắng
  • 2 khoảng trắng ⇢ ​​4 khoảng trắng
  • 3 khoảng trắng ⇢ ​​5 khoảng trắng
  • 4 khoảng trắng ⇢ ​​8 khoảng trắng

1

Ngoài câu trả lời của @ ger, tôi đưa câu trả lời này vào .vimrc

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

Chỉ cần gõ :Format.

Với lựa chọn trực quan, điều này chỉ định dạng các dòng đã chọn.

Không có lựa chọn trực quan, điều này sẽ định dạng toàn bộ tệp.


0

Đây là một biến thể của các câu trả lời dựa trên regex.

Tôi có một tập lệnh bash trong thư mục bin cục bộ sẽ tăng gấp đôi lượng khoảng trắng ở đầu dòng. Đầu vào có thể là stdin hoặc tệp:

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

file=${1--}

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

Tôi sử dụng điều này trong vim bằng cách chọn trực quan một dòng và ra lệnh sau:

:'<,'>!dblsp

Điều này giúp tôi không cần phải nhập (hoặc nhớ) regex.

Tôi cũng sử dụng nó trong các bản đồ như sau:

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

sẽ áp dụng nó cho một khối văn bản được dán gần đây. Tôi thường sử dụng bản đồ sau để dán hơn là:set paste

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

Quy trình làm việc thông thường của tôi là:

  • chọn đoạn mã (ví dụ: mã ví dụ trên trang này là 2 khoảng trắng nhưng tôi muốn 4)
  • dán đoạn mã (, p)
  • thay đổi khoảng cách (,])

hoặc đơn giản là thay đổi thụt lề trên các khối bị kéo được dán từ bộ đệm khác.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.