Thay đổi tên biến trong Vim


94

Tôi đang cố gắng đọc rất nhiều mã C / Perl thông qua Vim chứa nhiều tên biến ký tự đơn.

Thật tuyệt nếu có một số lệnh có thể giúp tôi thay đổi tên của một biến thành một cái gì đó có ý nghĩa hơn trong khi tôi đang đọc mã để tôi có thể đọc phần còn lại của nó nhanh hơn.

Có lệnh nào trong Vim có thể giúp tôi nhanh chóng thực hiện việc này không?

Tôi không nghĩ regexes sẽ hoạt động vì:

  1. cùng một tên chữ cái có thể có các mục đích khác nhau trong các khối phạm vi khác nhau

  2. sự kết hợp giống nhau của các chữ cái có thể là một phần của tên var khác lớn hơn, hoặc trong một chuỗi hoặc chú thích ... sẽ không muốn sửa đổi chúng

Bất kỳ giải pháp đã biết?

Câu trả lời:


196

Sau đây là cách đổi tên một biến được xác định trong phạm vi hiện tại {} .

Di chuyển con trỏ của bạn đến cách sử dụng biến. Nhấn gd. Có nghĩa là - di chuyển con trỏ đến định nghĩa. Bây giờ Nhấn [{- điều này sẽ đưa bạn đến phạm vi bắt đầu. Nhấn V- sẽ bật lựa chọn Dòng trực quan. Nhấn %- sẽ chuyển sang đối diện }do đó sẽ chọn toàn bộ phạm vi. Nhấn :s/- bắt đầu của lệnh thay thế. <C-R>/- sẽ chèn mẫu phù hợp với tên biến (tên mà bạn đã đặt trước khi nhấn gd). /newname/gc<CR>- sẽ bắt đầu tìm kiếm và thay thế bằng xác nhận vào mỗi trận đấu.

Bây giờ bạn phải ghi macro hoặc thậm chí tốt hơn - ánh xạ một khóa.

Đây là ánh xạ cuối cùng:

" For local replace
nnoremap gr gd[{V%::s/<C-R>///gc<left><left><left>

" For global replace
nnoremap gR gD:%s/<C-R>///gc<left><left><left>

Đặt điều này cho của bạn .vimrchoặc chỉ thực hiện. Sau đó, nhấn grvào biến cục bộ sẽ đưa bạn đến :slệnh mà bạn chỉ cần nhập new_variable_namevà nhấn Enter.


39
+1 để tìm hiểu hơn 5 thủ thuật Vim mới mà tôi nên biết trước đây. Cảm ơn
Kenny Meyer

6
Lưu ý: gd không hoạt động để định vị biến trong phạm vi định nghĩa ngay lập tức ở chế độ Javascript trong macvim. Tôi sẽ đưa tôi đến lần đầu tiên sử dụng tên biến trong một số hàm trong tệp :( Nếu bạn đang ở trong phạm vi nào đó và muốn chọn phạm vi đó, thì "va {" - "visual select around {" - là cách để thực hiện Tôi nghĩ.
Srikumar

3
Một phiên bản được cải thiện đôi chút: gist.github.com/048616a2e3f5d1b5a9ad nhắc nhở người sử dụng, chương trình tên cũ, khôi phục vị trí con trỏ sau khi thay thế
Andy Ray

7
+1 vimgineering rất tốt (Tôi nghĩ tôi vừa đặt ra một thuật ngữ mới). Lưu ý: Tôi thực sự cần nhấn dấu hai chấm ( :) hai lần. Lần đầu tiên tôi ấn vào nó, tôi đã thấy :'<,'>. Nếu tôi chỉ nhập s/từ đó nó không hoạt động; Tôi đã phải gõ một dấu hai chấm khác trước s/.
Kelvin

6
Lưu ý rằng bạn không cần <C-R>trong lệnh thay thế, chỉ cần bỏ qua tìm kiếm sẽ khiến vim sử dụng mẫu được tìm kiếm cuối cùng, trong trường hợp này được tạo từ gdlệnh. Vì vậy, chỉ cần làm là :s//<newname>/gcđủ.
shangxiao

10

AFAIK, không có hỗ trợ tái cấu trúc thực tế trong VIM. Khi thực hiện đổi tên với ý định của một người tái cấu trúc, tôi thường thực hiện các biện pháp phòng ngừa sau:

  1. Giới hạn phạm vi thay đổi của tôi bằng cách sử dụng nhãn hiệu.
  2. Khi nhập regex, hãy đặt tên bằng dấu ngoặc nhọn với \ <và>. Điều này sẽ làm cho nó khớp với toàn bộ một từ, giảm các loại đổi tên sai sẽ xảy ra.
  3. Không thay thế nhiều dòng để giảm cơ hội thay thế kém
  4. Xem kỹ mã khác biệt nếu đó là bất kỳ điều gì khác ngoài một thay đổi nhỏ.

Thay đổi cuối cùng của tôi trông giống như thế này

:'a,'bs/\<foo\>/bar

Tôi rất muốn nhầm là không có công cụ tái cấu trúc cho VIM nhưng tôi chưa thấy nó.


Trong Perl, bạn cũng có thể thêm loại vào mẫu tìm kiếm. tức là $ cho vô hướng, @ cho mảng,% cho băm
Nathan Fellman

@Nathan: thật không may, nó khó hơn một chút trong Perl (5.X), vì dấu hiệu của mảng và hàm băm thay đổi theo cách sử dụng:% hash -> whole hash, $ hash {key} -> single value, @hash { qw / ab /} lát cắt băm.
user55400

9

Tôi biết đó là một câu hỏi cũ và cách của @ mykola-golubyev rõ ràng là câu trả lời tốt nhất cho trường hợp cụ thể trong câu hỏi OP (mà tôi cho rằng đó là đi qua mã bị xáo trộn nơi bạn có thể có nhiều khối có cùng tên var) ; nhưng với tên câu hỏi như vậy, nhiều người đến đây từ tìm kiếm trên google có thể tìm cách đổi tên các biến trong VIM ít tình huống cụ thể hơn - và những cách đó có thể ngắn gọn hơn

Tôi không có ai đề xuất theo cách này:

* :s// TÊN MỚI /gc

Điều *này cũng giống như gn- nó tìm kiếm lần xuất hiện tiếp theo của từ dưới con trỏ VÀ nó trở thành mẫu được tìm kiếm cuối cùng, vì vậy khi bạn bỏ qua mẫu tìm kiếm trong lệnh thay thế, VIM giả định đây là mẫu cần tìm kiếm.

Đối với một lượng nhỏ bản sao var, một bản thậm chí còn nhanh hơn:

* cw NEWNAME <esc> sau đó lặp lại n.cho các lần xuất hiện khác

Tìm kiếm sự xuất hiện, cwlà lệnh cho từ thay đổi , nchuyển đến lần xuất hiện tiếp theo của cụm từ được tìm kiếm cuối cùng và .lặp lại lệnh cuối cùng ( thay đổi từ thành NEWNAME )

(Tín dụng cho tôi khi biết tất cả những điều này được chuyển đến @doomedbunnies trên Reddit )

Một thủ thuật thú vị khác là: ( tín dụng cho @ nobe4 )

* cgn NEWNAME <esc> sau đó lặp lại .cho các lần xuất hiện khác

cgnlà "thay đổi bất cứ điều gì là kết quả của (tìm lần xuất hiện tiếp theo)". Bây giờ đây là lệnh cuối cùng , bạn không cần phải nđi đến lần xuất hiện tiếp theo, do đó, ít nét hơn một lần nữa, và quan trọng hơn, không cần phải thay thế n.. Nhưng, rõ ràng, điều này có nhược điểm là không có cách nào để bỏ qua một lần xuất hiện.

Dưới đây là một số lợi ích:

  • không có ánh xạ, không có .vimrc (hoặc init.vim), vì vậy bạn có thể sử dụng nó trong bất kỳ bản sao VIM nào mà bạn gặp (ví dụ: một tác vụ nhanh trên một số VPS hoặc máy của bạn bè bạn, nơi cấu hình VIM theo cách của bạn sẽ đánh bại mục đích 'nhanh chóng' )
  • sử dụng *hoặc gnđể lựa chọn từ rất nhanh chóng - chỉ một lần nhấn phím (tốt, giả sử 1,5)
  • bằng cách sử dụng *hoặc gnđảm bảo rằng bạn không nhận được bất kỳ kết quả phù hợp nào bên trong các từ khác, giống như :%s/<C-R>//gcvậy. Nhịp đập gõ :%s/\<OLDNAME\>/NEWNAME/gcbằng tay: Cá nhân tôi có xu hướng quên sử dụng những \<thứ để giới hạn kết quả phù hợp với chỉ toàn bộ từ.
  • Không sử dụng phạm vi sẽ chỉ dẫn đến một vài lần đánh thêm nđể bỏ qua các trận đấu không mong muốn - có thể thậm chí còn ít hơn số lần đánh phụ cần thiết để giới hạn phạm vi. Trong các trường hợp giới hạn bình thường, các biến của bạn rất có thể đã được bản địa hóa phần nào vào một khối mã nhất định.

8

Đặt cái này vào .vimrc của bạn

" Function to rename the variable under the cursor
function! Rnvar()
  let word_to_replace = expand("<cword>")
  let replacement = input("new name: ")
  execute '%s/\(\W\)' . word_to_replace . '\(\W\)/\1' . replacement . '\2/gc'
endfunction

Gọi nó bằng :call Rnvar()

expand("<cword>")lấy từ dưới con trỏ. Chuỗi tìm kiếm sử dụng %cho phạm vi tệp và các \(\W\)mẫu tìm kiếm các ký tự không phải là từ ở ranh giới của từ để thay thế và lưu chúng trong các biến \1\2để được chèn lại trong mẫu thay thế.


3

Bạn có thể sử dụng công cụ sửa đổi 'c' trong tìm kiếm chung và thay thế sẽ yêu cầu bạn xác nhận cho mỗi lần thay thế. Sẽ mất nhiều thời gian hơn nhưng nó có thể hoạt động đối với tệp mã không phức tạp:

%s/\$var/\$foo/gc

Chữ c là viết tắt của xác nhận.


Chữ i là viết tắt của trường hợp bỏ qua. Bạn muốn c, xác nhận mọi thay đổi.
Michael Kristofik

rất tiếc .. xin lỗi về điều đó .. Đã sửa câu trả lời
Adnan

Câu trả lời vẫn chưa được sửa hoàn toàn;)
user55400

ý bạn là $ đã trốn thoát? Đó là thứ thuộc về sở thích cá nhân của tôi. $ hoạt động không có lối thoát và cũng với và kể từ trong thế giới regex và trong vi $ có ý nghĩa đặc biệt, tôi muốn thoát khỏi nó chỉ cho rõ ràng.
Adnan

0

Trong c, bạn có thể đạt được một số tiến bộ bằng cách sử dụng cscope. Nó cố gắng hiểu cú pháp, do đó sẽ có cơ hội biết khi nào thì ký tự là một biến.


0

Nếu điều này nằm trên nhiều tệp, bạn có thể cân nhắc xem xét sed. Sử dụng find để lấy các tệp và xargs của bạn cộng với sed để thay thế. Giả sử bạn muốn thay thế a bằng a_better_name trong tất cả các tệp khớp với * .c, bạn có thể làm

tìm thấy . -tên "* .c" | xargs sed -i -e 's / a / a_better_name / g'

Hãy nhớ rằng điều này sẽ thay thế TẤT CẢ các lần xuất hiện của a, vì vậy bạn có thể muốn có một regex mạnh mẽ hơn.

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.