ฉันจะสร้างมาโครแบบเรียกซ้ำเพื่อให้ทำงานเฉพาะจนถึงจุดสิ้นสุดของบรรทัดได้อย่างไร
หรือวิธีการเรียกใช้แมโครแบบเรียกซ้ำจนกระทั่งจบบรรทัดเท่านั้น
ฉันจะสร้างมาโครแบบเรียกซ้ำเพื่อให้ทำงานเฉพาะจนถึงจุดสิ้นสุดของบรรทัดได้อย่างไร
หรือวิธีการเรียกใช้แมโครแบบเรียกซ้ำจนกระทั่งจบบรรทัดเท่านั้น
คำตอบ:
อาจมีวิธีที่ง่ายกว่า แต่คุณอาจลองวิธีต่อไปนี้
สมมติว่าคุณจะใช้ register q
เพื่อบันทึกมาโครแบบเรียกซ้ำ
ที่จุดเริ่มต้นของการบันทึกให้พิมพ์:
:let a = line('.')
จากนั้นในตอนท้ายสุดของการบันทึกแทนที่จะกดปุ่ม@q
เพื่อให้มาโครซ้ำให้พิมพ์คำสั่งต่อไปนี้:
:if line('.') == a | exe 'norm @q' | endif
q
สุดท้ายจบบันทึกแมโครด้วย
คำสั่งสุดท้ายที่คุณพิมพ์จะเล่นมาโครq
( exe 'norm @q'
) แต่ถ้าจำนวนบรรทัดปัจจุบัน ( line('.')
) a
เป็นเช่นเดียวกับหนึ่งที่เก็บไว้ในตัวแปรแรก
:normal
คำสั่งอนุญาตให้คุณพิมพ์คำสั่งปกติ (เช่น@q
) จากโหมด Ex
และเหตุผลที่คำสั่งถูกห่อเป็นสตริงและดำเนินการโดยคำสั่ง:execute
คือการป้องกัน:normal
จากการบริโภค (พิมพ์) ส่วนที่เหลือของคำสั่ง ( |endif
)
ตัวอย่างการใช้งาน
สมมติว่าคุณมีบัฟเฟอร์ต่อไปนี้:
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
และคุณต้องการที่จะเพิ่มจำนวนทั้งหมดจากบรรทัดโดยพลการด้วยมาโครแบบเรียกซ้ำ
คุณสามารถพิมพ์0
เพื่อเลื่อนเคอร์เซอร์ไปที่จุดเริ่มต้นของบรรทัดจากนั้นเริ่มบันทึกแมโคร:
qqq
qq
:let a=line('.')
<C-a>
w
:if line('.')==a|exe 'norm @q'|endif
q
qqq
ล้างเนื้อหาของรีจิสเตอร์q
เพื่อที่เมื่อคุณเริ่มต้นเรียกมันระหว่างนิยามของแมโครมันจะไม่รบกวนqq
เริ่มการบันทึก:let a=line('.')
เก็บหมายเลขบรรทัดปัจจุบันภายในตัวแปร a
w
เลื่อนเคอร์เซอร์ไปที่หมายเลขถัดไป:if line('.')==a|exe 'norm @q'|endif
เรียกคืนแมโคร แต่ถ้าหมายเลขบรรทัดไม่เปลี่ยนแปลงq
หยุดการบันทึกเมื่อคุณกำหนดมาโครของคุณแล้วหากคุณวางเคอร์เซอร์ไว้ที่บรรทัดที่สามให้กด0
เพื่อย้ายไปยังจุดเริ่มต้นของบรรทัดจากนั้นกด@q
เพื่อเล่นแมโครq
อีกครั้งมันจะมีผลกับบรรทัดปัจจุบันเท่านั้น
1 2 3 4
1 2 3 4
2 3 4 5
1 2 3 4
ทำให้แมโครซ้ำหลังจากการบันทึก
หากคุณต้องการคุณสามารถทำให้แมโครของคุณซ้ำหลังจากการบันทึกโดยใช้ความจริงที่ว่ามันถูกเก็บไว้ในสตริงภายในรีจิสเตอร์และคุณสามารถเชื่อมสองสตริงเข้ากับตัว.
ดำเนินการdot
สิ่งนี้จะให้ประโยชน์หลายประการแก่คุณ:
@q
จะถูกเพิ่มในมาโครหลังจากที่มันถูกกำหนดแล้วและหลังจากที่คุณเขียนทับเนื้อหาเก่า ๆหากคุณบันทึกแมโครของคุณตามปกติ (ไม่วนซ้ำ) คุณสามารถทำให้ซ้ำหลังจากนั้นด้วยคำสั่งต่อไปนี้:
let @q = @q . "@q"
หรือสั้นกว่า: let @q .= "@q"
.=
เป็นโอเปอเรเตอร์ที่อนุญาตให้ผนวกสตริงไปยังอีกอันหนึ่งได้
นี้ควรเพิ่ม 2 ตัวอักษรที่ปลายสุดของลำดับของการกดแป้นพิมพ์เก็บไว้ในการลงทะเบียน@q
q
คุณสามารถกำหนดคำสั่งที่กำหนดเอง:
command! -register RecursiveMacro let @<reg> .= "@<reg>"
มันกำหนดคำสั่ง:RecursiveMacro
ที่รอชื่อของการลงทะเบียนเป็นอาร์กิวเมนต์ (เพราะ-register
แอตทริบิวต์ที่ส่งผ่านไป:command
)
มันเป็นคำสั่งเช่นเดียวกับก่อนที่แตกต่างเพียงอย่างเดียวคือคุณเปลี่ยนทุกการเกิดขึ้นของด้วยq
<reg>
เมื่อคำสั่งจะถูกดำเนินการเป็นกลุ่มจะขยายโดยอัตโนมัติทุกครั้งที่<reg>
มีชื่อลงทะเบียนที่คุณให้ไว้
ตอนนี้สิ่งที่คุณต้องทำคือบันทึกแมโครของคุณตามปกติ (ไม่ใช่แบบเรียกซ้ำ) จากนั้นพิมพ์:RecursiveMacro q
เพื่อทำให้แมโครเก็บไว้ใน register q
แบบเรียกซ้ำ
คุณสามารถทำสิ่งเดียวกันเพื่อให้แมโครเรียกซ้ำบนเงื่อนไขที่อยู่ในบรรทัดปัจจุบัน:
let @q = ":let a=line('.')\r" . @q . ":if line('.')==a|exe 'norm @q'|endif\r"
มันเป็นสิ่งเดียวกันที่อธิบายไว้ในตอนต้นของโพสต์ยกเว้นครั้งนี้ที่คุณทำหลังจากการบันทึก คุณเพียงแค่เชื่อมสองสายเข้าด้วยกันหนึ่งรายการก่อนหน้าและหนึ่งรายการหลังจากการกดแป้นใดก็ตามที่q
รีจิสเตอร์ประกอบด้วย:
let @q =
กำหนดเนื้อหาของการลงทะเบียนใหม่ q
":let a=line('.')\r"
เก็บหมายเลขบรรทัดปัจจุบันภายในตัวแปรa
ก่อนที่แมโครจะทำงาน\r
จำเป็นต้องแจ้งให้ Vim กด Enter และเรียกใช้คำสั่งดู:help expr-quote
รายการอักขระพิเศษที่คล้ายกัน . @q .
เชื่อมต่อเนื้อหาปัจจุบันของq
รีจิสเตอร์กับสตริงก่อนหน้าและถัดไป":if line('.')==a|exe 'norm @q'|endif\r"
เรียกคืนแมโครq
โดยมีเงื่อนไขว่าบรรทัดไม่เปลี่ยนแปลงอีกครั้งเพื่อบันทึกการกดแป้นบางอย่างคุณสามารถทำให้กระบวนการโดยอัตโนมัติโดยการกำหนดคำสั่งที่กำหนดเองต่อไปนี้:
command! -register RecursiveMacroOnLine let @<reg> = ":let a=line('.')\r" . @<reg> . ":if line('.')==a|exe 'norm @<reg>'|endif\r"
และอีกครั้งสิ่งที่คุณต้องทำคือบันทึกแมโครของคุณตามปกติ (ไม่ใช่แบบเรียกซ้ำ) จากนั้นพิมพ์:RecursiveMacroOnLine q
เพื่อทำให้แมโครที่เก็บไว้ภายในรีจิสเตอร์q
แบบเรียกซ้ำบนเงื่อนไขที่มันยังคงอยู่ในบรรทัดปัจจุบัน
รวม 2 คำสั่ง
คุณสามารถปรับแต่ง:RecursiveMacro
เพื่อให้ครอบคลุม 2 กรณี:
:RecursiveMacro
การทำเช่นนี้คุณสามารถผ่านอาร์กิวเมนต์ที่สองไป หลังจะทดสอบค่าของมันและขึ้นอยู่กับค่าจะดำเนินการหนึ่งใน 2 คำสั่งก่อนหน้า มันจะให้อะไรเช่นนี้:
command! -register -nargs=1 RecursiveMacro if <args> | let @<reg> .= "@<reg>" | else | let @<reg> = ":let a=line('.')\r" . @<reg> . ":if line('.')==a|exe 'norm @<reg>'|endif\r" | endif
หรือ (ใช้การต่อเนื่อง / แบ็กสแลชเพื่อให้อ่านง่ายขึ้นเล็กน้อย):
command! -register -nargs=1 RecursiveMacro
\ if <args> |
\ let @<reg> .= "@<reg>" |
\ else |
\ let @<reg> = ":let a = line('.')\r" .
\ @<reg> .
\ ":if line('.')==a | exe 'norm @<reg>' | endif\r" |
\ endif
เหมือนกับก่อนหน้านี้ยกเว้นเวลานี้คุณต้องระบุอาร์กิวเมนต์ที่ 2 ให้กับ:RecursiveMacro
(เนื่องจาก-nargs=1
แอตทริบิวต์)
เมื่อคำสั่งใหม่นี้จะถูกดำเนินการเป็นกลุ่มจะขยายโดยอัตโนมัติ<args>
ด้วยค่าที่คุณให้
หากอาร์กิวเมนต์ที่ 2 นี้ไม่ใช่ศูนย์ / จริง ( if <args>
) คำสั่งเวอร์ชันแรกจะถูกดำเนินการ (อันที่ทำให้แมโครเรียกซ้ำโดยไม่มีเงื่อนไข) มิฉะนั้นถ้ามันเป็นศูนย์ / เท็จเวอร์ชันที่สองจะถูกดำเนินการ (อันที่ทำให้ แมโครแบบเรียกซ้ำในเงื่อนไขที่อยู่ในบรรทัดปัจจุบัน)
ดังนั้นกลับไปที่ตัวอย่างก่อนหน้านี้มันจะให้สิ่งต่อไปนี้:
qq
<C-a>
w
q
:RecursiveMacro q 0
3G
0@q
qq
เริ่มการบันทึกแมโครภายในรีจิสเตอร์ q
<C-a>
เพิ่มจำนวนภายใต้เคอร์เซอร์w
เลื่อนเคอร์เซอร์ไปที่หมายเลขถัดไปq
สิ้นสุดการบันทึก:RecursiveMacro q 0
ทำให้แมโครที่เก็บไว้ใน register q
ซ้ำ แต่จนถึงจุดสิ้นสุดของบรรทัด (เนื่องจากอาร์กิวเมนต์ที่สอง0
)3G
เลื่อนเคอร์เซอร์ของคุณไปที่บรรทัดใดก็ได้ (ตัวอย่าง 3)0@q
ไกล่เกลี่ยแมโครซ้ำจากจุดเริ่มต้นของบรรทัดควรให้ผลลัพธ์แบบเดียวกับก่อนหน้านี้:
1 2 3 4
1 2 3 4
2 3 4 5
1 2 3 4
แต่ครั้งนี้คุณไม่จำเป็นต้องพิมพ์คำสั่งที่ทำให้เสียสมาธิระหว่างการบันทึกแมโครของคุณคุณสามารถมุ่งเน้นไปที่การใช้งานได้
และในระหว่างขั้นตอนที่ 5 ถ้าคุณผ่านอาร์กิวเมนต์ที่ไม่เป็นศูนย์ไปยังคำสั่งนั่นคือถ้าคุณพิมพ์:RecursiveMacro q 1
แทน:RecursiveMacro q 0
แมโครq
จะกลายเป็นแบบเรียกซ้ำโดยไม่มีเงื่อนไขซึ่งจะให้บัฟเฟอร์ต่อไปนี้:
1 2 3 4
1 2 3 4
2 3 4 5
2 3 4 5
เวลานี้มาโครจะไม่หยุดที่จุดสิ้นสุดของบรรทัดที่ 3 แต่ท้ายสุดของบัฟเฟอร์
สำหรับข้อมูลเพิ่มเติมดู:
:help line()
:help :normal
:help :execute
:help :command-nargs
:help :command-register
1 2 3 4 5 6 7 8 9 10
ฉันได้รับแทน2 3 4 5 6 7 8 9 10 12
2 3 4 5 6 7 8 9 10 11
ฉันไม่รู้ว่าทำไมบางทีฉันพิมพ์ผิดบางอย่าง อย่างไรก็ตามดูเหมือนว่าจะซับซ้อนกว่าวิธีง่าย ๆ ของฉันและมันเกี่ยวข้องกับ regexes เพื่ออธิบายว่ามาโครควรเลื่อนเคอร์เซอร์ไปที่ใดรวมถึงรายการตำแหน่งที่ฉันไม่เคยเห็นมาก่อนด้วยวิธีนี้ ผมชอบมันมาก!
\d\+
เพื่ออธิบายตัวเลขหลายหลัก
:lv ...
คำสั่งคำ:lla
สั่งสามารถใช้เพื่อข้ามไปยังการแข่งขันครั้งสุดท้ายและ:lp
คำสั่งสามารถใช้เพื่อเลื่อนไปที่การแข่งขันในลำดับย้อนกลับ
แมโครแบบเรียกซ้ำจะหยุดทันทีที่พบคำสั่งที่ล้มเหลว ดังนั้นหากต้องการหยุดที่จุดสิ้นสุดของบรรทัดคุณต้องมีคำสั่งที่จะล้มเหลวเมื่อสิ้นสุดบรรทัด
โดยค่าเริ่มต้น * l
คำสั่งคือคำสั่งดังกล่าวดังนั้นคุณสามารถใช้เพื่อหยุดแมโครแบบเรียกซ้ำ หากเคอร์เซอร์อยู่ไม่ได้h
ในตอนท้ายของบรรทัดแล้วคุณก็จำเป็นต้องย้ายกลับมาหลังจากที่มีคำสั่ง
ดังนั้นการใช้แมโครตัวอย่างเดียวกันกับ saginaw :
qqqqq<c-a>lhw@qq
ทำลายลง:
qqq
: ลบการลงทะเบียน qqq
: เริ่มบันทึกแมโครในq
รีจิสเตอร์<c-a>
: เพิ่มจำนวนภายใต้เคอร์เซอร์lh
: ถ้าเราอยู่ท้ายบรรทัดให้ยกเลิกแมโคร มิฉะนั้นไม่ทำอะไรเลยw
: เลื่อนไปที่คำถัดไปในบรรทัด@q
: ขอเงินคืนq
: หยุดการบันทึกจากนั้นคุณสามารถเรียกใช้แมโครด้วย0@q
คำสั่งเดียวกับที่อธิบายโดย saginaw
* 'whichwrap'
ตัวเลือกช่วยให้คุณกำหนดคีย์การเคลื่อนไหวที่จะล้อมรอบไปยังบรรทัดถัดไปเมื่อคุณอยู่ที่จุดเริ่มต้นหรือจุดสิ้นสุดของบรรทัด (ดู:help 'whichwrap'
) หากคุณl
ตั้งค่าไว้ในตัวเลือกนี้จะทำให้วิธีการแก้ปัญหาที่อธิบายไว้ข้างต้นแตก
แต่ก็เป็นไปได้ว่าคุณจะใช้หนึ่งในคำสั่งโหมดปกติสามเริ่มต้นสำหรับความก้าวหน้าตัวเดียว ( <Space>
, l
และ<Right>
) ดังนั้นหากคุณมีl
รวมอยู่ในของคุณ'whichwrap'
ตั้งค่าคุณสามารถลบหนึ่งที่คุณไม่ได้ใช้จาก'whichwrap'
ตัวเลือกเช่นสำหรับ<Space>
:
:set whichwrap-=s
จากนั้นคุณสามารถแทนที่l
คำสั่งในขั้นตอนที่ 4 ของแมโครด้วย<Space>
คำสั่ง
virtualedit=onemore
จะยุ่งเกี่ยวกับการใช้ในการตรวจสอบการสิ้นสุดของเส้นแม้จะไม่ได้เป็นอย่างรุนแรงl
whichwrap=l
've'
:lv /\%3l\d/g %<CR>qqqqq<C-a>:lne<CR>@qq@q
จะเพิ่มจำนวนทั้งหมดในบรรทัดที่ 3 บางทีอาจมีวิธีที่จะทำให้โซลูชันนี้มีความเปราะบางหรือไม่?