วิธีเปลี่ยนชื่อตัวแปรใน Vim อย่างรวดเร็ว?


97

ฉันใช้ Vim เพื่ออ่านรหัส C และ Perl จำนวนมากที่มีชื่อตัวแปรอักษรตัวเดียวจำนวนมาก

คงจะดีไม่น้อยหากมีคำสั่งในการเปลี่ยนชื่อตัวแปรให้มีความหมายมากขึ้นในขณะที่ฉันกำลังอ่านโค้ดเพื่อที่ฉันจะได้อ่านส่วนที่เหลือได้เร็วขึ้น

มีคำสั่งบางอย่างใน Vim ที่ช่วยให้ฉันทำสิ่งนี้ได้อย่างรวดเร็วหรือไม่?

ฉันไม่คิดว่า regexes จะใช้ได้ผลเพราะ:

  1. ชื่อตัวอักษรเดี่ยวเดียวกันอาจมีจุดประสงค์ที่แตกต่างกันในบล็อกขอบเขตที่แตกต่างกัน และ

  2. การรวมกันของตัวอักษรอาจเป็นส่วนหนึ่งของชื่อตัวแปรที่ยาวกว่าอื่นสตริงลิเทอรัลหรือข้อคิดเห็น

มีวิธีแก้ไขที่เป็นที่รู้จักหรือไม่?

คำตอบ:


202

{}ต่อไปนี้เป็นวิธีการเปลี่ยนชื่อตัวแปรที่กำหนดไว้ในขอบเขตปัจจุบัน

เลื่อนเคอร์เซอร์ไปที่ตัวแปรการใช้งาน gdกด ซึ่งหมายความว่า - เลื่อนเคอร์เซอร์ไปที่คำจำกัดความ Now Press [{- สิ่งนี้จะนำคุณไปสู่ขอบเขตเริ่มต้น กดV- จะเปิดการเลือกเส้นภาพ กด%- จะข้ามไปที่ตรงข้าม}ดังนั้นจะเลือกขอบเขตทั้งหมด กด:s/- เริ่มคำสั่งแทนที่ <C-R>/- จะแทรกรูปแบบที่ตรงกับชื่อตัวแปร (ชื่อที่คุณเคยใช้ก่อนกดgd) /newname/gc<CR>- จะเริ่มการค้นหาและแทนที่ด้วยการยืนยันในทุกนัด

ตอนนี้คุณต้องบันทึกมาโครหรือดีกว่านั้น - แมปคีย์

นี่คือการแมปขั้นสุดท้าย:

" 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>

ใส่สิ่งนี้ให้กับคุณ.vimrcหรือเพียงแค่ดำเนินการ หลังจากนี้กดgrบนตัวแปรท้องถิ่นจะนำคุณไปยัง:sคำสั่งที่คุณก็ควรจะใส่และกดnew_variable_nameEnter


40
+1 เพื่อเรียนรู้เทคนิค Vim ใหม่ ๆ มากกว่า 5 ข้อที่ฉันควรรู้มาก่อน ขอบคุณ
Kenny Meyer

6
หมายเหตุ: gd ไม่ทำงานเพื่อค้นหาตัวแปรในขอบเขตของนิยามในโหมด Javascript ใน macvim ฉันต้องใช้ชื่อตัวแปรเป็นครั้งแรกในบางฟังก์ชันในไฟล์ :( หากคุณอยู่ในขอบเขตและต้องการเลือกขอบเขตนั้น "va {" - "visual select around {" - คือหนทางที่จะไป ฉันคิดว่า
Srikumar

3
รุ่นปรับปรุงเล็กน้อย: gist.github.com/048616a2e3f5d1b5a9adแจ้งให้ผู้ใช้แสดงชื่อเก่าเรียกคืนตำแหน่งเคอร์เซอร์หลังจากแทนที่
Andy Ray

7
+1 vimgineering ที่ดีมาก (ฉันคิดว่าฉันเพิ่งบัญญัติศัพท์ใหม่) หมายเหตุ: จริงๆแล้วฉันต้องกดโคลอน ( :) สองครั้ง :'<,'>ครั้งแรกที่ผมกดมันฉันเห็น ถ้าฉันพิมพ์s/จากตรงนั้นมันไม่ได้ผล ฉันต้องพิมพ์เครื่องหมายจุดคู่ก่อนหน้าไฟล์s/.
Kelvin

7
โปรดทราบว่าคุณไม่จำเป็นต้อง<C-R>ใช้คำสั่งแทนที่การละเว้นการค้นหาจะทำให้กลุ่มใช้รูปแบบการค้นหาล่าสุดซึ่งในกรณีนี้ถูกสร้างขึ้นจากgdคำสั่ง เพียงแค่ทำ:s//<newname>/gcก็เพียงพอแล้ว
shangxiao

15

ฉันรู้ว่ามันเป็นคำถามเก่าและวิธีของ @mykola-golubyev เห็นได้ชัดว่าเป็นคำตอบที่ดีที่สุดสำหรับบางกรณีในคำถาม OP (ซึ่งฉันคิดว่ากำลังใช้รหัสที่สับสนซึ่งคุณน่าจะมีหลายบล็อกที่มีชื่อตัวแปรเดียวกัน) ; แต่ด้วยชื่อคำถามที่หลาย ๆ คนมาที่นี่จากการค้นหาของ Google อาจมองหาวิธีการเปลี่ยนชื่อตัวแปรใน VIM ที่เจาะจงสถานการณ์น้อยลง

ฉันประหลาดใจไม่มีใครแนะนำวิธีนี้:

* :s// NEWNAME /gc

*เป็นเช่นเดียวกับgn- มันค้นหาสำหรับเกิดขึ้นต่อไปของคำภายใต้เคอร์เซอร์และจะกลายเป็นที่ผ่านมารูปแบบการสืบค้นดังนั้นเมื่อคุณไม่ใช้รูปแบบการค้นหาในคำสั่งแทน, VIM ถือว่านี่เป็นรูปแบบในการค้นหา

สำหรับสำเนา var จำนวนน้อยชุดที่เร็วกว่า:

* cw NEWNAME <esc>แล้วทำซ้ำn.สำหรับเหตุการณ์อื่น ๆ

ค้นหาสำหรับการเกิดขึ้น, cwเป็นคำสั่งสำหรับคำว่าการเปลี่ยนแปลง , nไปที่เกิดขึ้นต่อไปของการที่ผ่านมาการค้นหาคำและ.ทำซ้ำคำสั่งสุดท้าย (ซึ่งก็คือการเปลี่ยนแปลงคำ NEWNAME )

(เครดิตสำหรับฉันที่รู้ทั้งหมดนี้ไปที่@doomedbunnies บน Reddit )

เคล็ดลับเด็ดอีกอย่างคือ: ( เครดิตถึง @ nobe4 )

* cgn NEWNAME <esc>แล้วทำซ้ำ.สำหรับเหตุการณ์อื่น ๆ

cgnคือ "เปลี่ยนแปลงสิ่งที่เป็นผลของ (ค้นหาเหตุการณ์ถัดไป)" ตอนนี้ที่นี่เป็นคำสั่งสุดท้ายที่คุณไม่จำเป็นต้องnที่จะไปเกิดขึ้นต่อไปจังหวะเพื่อให้น้อยลงอีกครั้งและที่สำคัญกว่านั้นไม่จำเป็นต้องสำรองและn .แต่เห็นได้ชัดว่าสิ่งนี้มีข้อเสียคือไม่มีทางข้ามเหตุการณ์ได้

นี่คือประโยชน์บางประการ:

  • ไม่มีการแมปไม่มี. vimrc (หรือ init.vim) ดังนั้นคุณสามารถใช้มันในสำเนา VIM ใด ๆ ที่คุณเจอ (เช่นงานด่วนใน VPS หรือเครื่องของเพื่อนคุณซึ่งการกำหนดค่า VIM ในแบบของคุณจะทำให้จุดประสงค์ของ 'ด่วน' )
  • การใช้*หรือgnสำหรับการเลือกคำนั้นรวดเร็วมาก - การกดแป้นพิมพ์เพียงครั้งเดียว (สมมติว่า 1.5)
  • ใช้*หรือgnทำให้แน่ใจว่าคุณไม่ได้ตรงกับคำอื่นเช่นเดียวกับที่:%s/<C-R>//gcทำ Beats พิมพ์:%s/\<OLDNAME\>/NEWNAME/gcด้วยมือ: โดยส่วนตัวแล้วฉันมักจะลืมใช้\<สิ่งต่าง ๆ เพื่อ จำกัด การจับคู่ให้เป็นคำทั้งหมดเท่านั้น
  • การไม่ใช้ขอบเขตจะส่งผลnให้ข้ามการแข่งขันที่ไม่ต้องการเพียงไม่กี่จังหวะ- อาจน้อยกว่าจังหวะพิเศษที่จำเป็นในการ จำกัด ขอบเขตด้วยซ้ำ ภายใต้เงื่อนไขปกติตัวแปรของคุณมักจะถูกแปลเป็นบล็อกโค้ดบางอย่างอยู่แล้ว

10

AFAIK ไม่มีการสนับสนุน refactoring จริงใน VIM เมื่อทำการเปลี่ยนชื่อโดยเจตนาของ refactor ฉันมักจะใช้ข้อควรระวังต่อไปนี้:

  1. จำกัด ขอบเขตของการเปลี่ยนแปลงเครื่องหมายที่ใช้ของฉัน
  2. เมื่อเข้าสู่ regex ให้วงเล็บชื่อด้วย \ <and> สิ่งนี้จะทำให้ตรงกับคำทั้งหมดซึ่งจะช่วยลดประเภทของการเปลี่ยนชื่อที่ไม่ถูกต้องที่จะเกิดขึ้น
  3. อย่าเปลี่ยนหลายสายเพื่อลดโอกาสในการเปลี่ยนที่ไม่ดี
  4. ดูโค้ดที่แตกต่างอย่างระมัดระวังว่ามีอะไรนอกเหนือจากการเปลี่ยนแปลงเล็กน้อย

การเปลี่ยนแปลงในตอนท้ายของฉันมีลักษณะเช่นนี้

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

ฉันชอบที่จะคิดผิดที่ไม่มีเครื่องมือ refactoring สำหรับ VIM แต่ฉันไม่ได้เห็นมัน


ใน Perl คุณสามารถเพิ่มประเภทลงในรูปแบบการค้นหาได้ด้วย เช่น $ สำหรับสเกลาร์, @ สำหรับอาร์เรย์,% สำหรับแฮช
นาธานเฟลล์แมน

@Nathan: น่าเสียดายที่มันยากกว่าเล็กน้อยใน Perl (5.X) เนื่องจาก sigil ของอาร์เรย์และแฮชเปลี่ยนไปตามการใช้งาน:% hash -> whole hash, $ hash {key} -> single value, @hash { ส่วนแฮช qw / ab /}
user55400

9

ใส่สิ่งนี้ใน. vimrc ของคุณ

" 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

โทรหาด้วย :call Rnvar()

expand("<cword>")รับคำใต้เคอร์เซอร์ สตริงการค้นหาใช้%สำหรับขอบเขตไฟล์และ\(\W\)รูปแบบจะค้นหาอักขระที่ไม่ใช่คำที่ขอบเขตของคำที่จะแทนที่และบันทึกไว้ในตัวแปร\1และ\2เพื่อที่จะแทรกเข้าไปใหม่ในรูปแบบการแทนที่


3

คุณสามารถใช้โมดิฟายเออร์ 'c' ในการค้นหาส่วนกลางและแทนที่ซึ่งจะขอให้คุณยืนยันสำหรับการแทนที่แต่ละครั้ง อาจใช้เวลานานกว่านี้ แต่อาจใช้ได้กับไฟล์รหัสที่ไม่ใหญ่โต:

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

c หมายถึงการยืนยัน


ฉันหมายถึงไม่สนใจกรณี คุณต้องการ c ยืนยันทุกการเปลี่ยนแปลง
Michael Kristofik

อ๊ะ .. ขออภัยด้วยนะคะ .. แก้ไขคำตอบ
Adnan

คำตอบยังไม่ได้รับการแก้ไขโดยสมบูรณ์;)
user55400

คุณหมายถึง $ ที่หลบหนีหรือเปล่า นั่นเป็นความชอบส่วนตัวของฉัน $ ใช้งานได้โดยไม่มีการหลบหนีและด้วยและตั้งแต่ในโลก regex และใน vi $ มีความหมายพิเศษฉันชอบที่จะหลบหนีเพื่อความชัดเจน
Adnan

0

ใน c คุณอาจจะก้าวหน้าได้บ้างโดยใช้ cscope มันพยายามทำความเข้าใจไวยากรณ์ดังนั้นจึงมีโอกาสที่จะรู้ว่าตัวอักษรนั้นเป็นตัวแปรเมื่อใด


0

หากเป็นไฟล์หลายไฟล์คุณอาจลองดูที่ sed ใช้ find เพื่อคว้าไฟล์และ xargs บวก sed เพื่อแทนที่ สมมติว่าคุณต้องการแทนที่ a ด้วย a_better_name ในไฟล์ทั้งหมดที่ตรงกับ * .c คุณสามารถทำได้

หา. - ชื่อ "* .c" | xargs sed -i -e 's / a / a_better_name / g'

โปรดทราบว่าสิ่งนี้จะแทนที่การเกิดขึ้นทั้งหมดของ a ดังนั้นคุณอาจต้องการ regex ที่มีประสิทธิภาพมากขึ้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.