मैं पंक्ति के अंत में एक पुनरावर्ती मैक्रो को कैसे रोकूं?


13

मैं एक पुनरावर्ती मैक्रो कैसे बना सकता हूं ताकि यह केवल पंक्ति के अंत तक चलता रहे?

या केवल पंक्ति के अंत तक एक पुनरावर्ती मैक्रो कैसे चलाएं?

जवाबों:


11

वहाँ शायद एक सरल विधि है, लेकिन हो सकता है कि आप निम्नलिखित की कोशिश कर सकें।

मान लीजिए कि आप qअपने पुनरावर्ती मैक्रो को रिकॉर्ड करने के लिए रजिस्टर का उपयोग करेंगे ।

रिकॉर्डिंग की शुरुआत में, टाइप करें:

:let a = line('.')

फिर, रिकॉर्डिंग के बहुत अंत में, @qमैक्रो को पुनरावर्ती बनाने के लिए मारने के बजाय , निम्न कमांड टाइप करें:

:if line('.') == a | exe 'norm @q' | endif

अंत में मैक्रो की रिकॉर्डिंग को समाप्त करें q

आपके द्वारा टाइप किया गया अंतिम कमांड मैक्रो q( exe 'norm @q') को फिर से करेगा, लेकिन केवल तभी जब वर्तमान लाइन नंबर ( line('.')) वैरिएबल में शुरू में संग्रहीत के समान हो a

:normalआदेश आप (जैसे सामान्य आदेशों टाइप करने के लिए अनुमति देता है @qपूर्व मोड से)।
और यही कारण है कि कमांड को एक स्ट्रिंग में लपेटा गया है और कमांड द्वारा निष्पादित किया गया :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
  1. qqqरजिस्टर की सामग्री को साफ करता है qताकि जब आप शुरू में इसे मैक्रो की परिभाषा के दौरान कहते हैं, तो यह हस्तक्षेप नहीं करेगा
  2. qq रिकॉर्डिंग शुरू करता है
  3. :let a=line('.') चर के अंदर वर्तमान लाइन संख्या को संग्रहीत करता है a
  4. Ctrl+ aकर्सर के तहत संख्या में वृद्धि
  5. w कर्सर को अगले नंबर पर ले जाता है
  6. :if line('.')==a|exe 'norm @q'|endif मैक्रो को याद करता है, लेकिन केवल अगर लाइन नंबर नहीं बदला
  7. q रिकॉर्डिंग बंद कर देता है

एक बार जब आप अपने मैक्रो को परिभाषित कर लेते हैं, यदि आप अपने कर्सर को तीसरी लाइन पर रखते हैं, तो 0इसे लाइन की शुरुआत में ले जाने के लिए हिट करें, फिर @qमैक्रो को फिर से चलाने के लिए हिट करें q, यह केवल वर्तमान लाइन को प्रभावित करना चाहिए, अन्य को नहीं:

1 2 3 4
1 2 3 4
2 3 4 5
1 2 3 4

रिकॉर्डिंग के बाद एक मैक्रो पुनरावर्ती बनाएं

यदि आप चाहें, तो आप अपनी मैक्रो को इस रिकॉर्डिंग के बाद अपनी पुनरावृत्ति कर सकते हैं कि यह एक रजिस्टर के अंदर एक स्ट्रिंग में संग्रहीत है और आप डॉट .ऑपरेटर के साथ दो तारों को जोड़ सकते हैं ।

इससे आपको कई लाभ मिलेंगे:

  • रिकॉर्डिंग से पहले रजिस्टर को साफ करने की कोई आवश्यकता नहीं है, क्योंकि @qइसे परिभाषित किए जाने के बाद पात्रों को मैक्रो में जोड़ दिया जाएगा, और आपके द्वारा पुरानी सामग्री जो भी थी उसे ओवरराइट करने के बाद
  • रिकॉर्डिंग के दौरान कुछ भी असामान्य टाइप करने की आवश्यकता नहीं है, आप एक सरल, कार्यशील मैक्रो बनाने पर ध्यान केंद्रित कर सकते हैं
  • यह कैसे व्यवहार करता है यह देखने के लिए पुनरावर्ती बनाने से पहले इसका परीक्षण करने की संभावना

यदि आप अपने मैक्रो को हमेशा की तरह रिकॉर्ड करते हैं (गैर-पुनरावर्ती), तो आप इसे निम्न कमांड के साथ बाद में पुनरावर्ती बना सकते हैं:

let @q = @q . "@q"

या इससे भी कम: let @q .= "@q"
.=एक ऑपरेटर है जो एक स्ट्रिंग को दूसरे में जोड़ने की अनुमति देता है।

यह @qरजिस्टर के अंदर संग्रहीत कीस्ट्रोक्स के अनुक्रम के बहुत अंत में 2 अक्षरों को जोड़ना चाहिए q। आप एक कस्टम कमांड को भी परिभाषित कर सकते हैं:

command! -register RecursiveMacro let @<reg> .= "@<reg>"

यह उस कमांड को परिभाषित करता है :RecursiveMacroजो एक तर्क के रूप में एक रजिस्टर के नाम की प्रतीक्षा करता है (क्योंकि -registerपारित विशेषता के कारण :command)।
यह पहले की तरह ही आदेश है, फर्क सिर्फ इतना है कि आप में से हर घटना की जगह है qके साथ <reg>। जब आदेश निष्पादित किया जाएगा, विम <reg>आपके द्वारा प्रदान किए गए रजिस्टर नाम के साथ हर घटना का स्वचालित रूप से विस्तार करेगा ।

अब, आपको बस इतना करना है कि अपने मैक्रो को सामान्य (गैर-पुनरावर्ती) के रूप में रिकॉर्ड करें, फिर :RecursiveMacro qमैक्रो को रजिस्टर के अंदर संग्रहीत करने के लिए टाइप करें q


आप वर्तमान लाइन पर बने रहने की स्थिति पर स्थूल पुनरावर्ती बनाने के लिए एक ही काम कर सकते हैं:

let @q = ":let a=line('.')\r" . @q . ":if line('.')==a|exe 'norm @q'|endif\r"

यह पोस्ट की शुरुआत में वर्णित एक ही बात है, इस समय को छोड़कर जब आप रिकॉर्डिंग के बाद करते हैं। आप बस दो स्ट्रिंग्स को समेटते हैं, एक से पहले और एक के बाद जो कुछ भी कीस्ट्रोक्स qरजिस्टर वर्तमान में होता है:

  1. let @q = रजिस्टर की सामग्री को फिर से परिभाषित करता है q
  2. ":let a=line('.')\r"वैरिएबल के अंदर वर्तमान लाइन नंबर को स्टोर aकरता है इससे पहले कि मैक्रो अपना काम करता
    \rहै वीम को एंटर को दबाने और कमांड को निष्पादित करने के लिए कहना आवश्यक है, :help expr-quoteसमान विशेष वर्णों की सूची देखें ,
  3. . @q .qपिछले स्ट्रिंग और अगले एक के साथ रजिस्टर की वर्तमान सामग्री को साझा करता है ,
  4. ":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

यह पहले की तरह ही है, इस समय को छोड़कर आपको :RecursiveMacro( -nargs=1विशेषता के कारण) 2 तर्क देना होगा ।
जब इस नए आदेश को निष्पादित किया जाएगा, तो विम <args>आपके द्वारा प्रदान किए गए मूल्य के साथ स्वचालित रूप से विस्तार करेगा ।
यदि यह 2 तर्क गैर-शून्य / सत्य है ( if <args>) कमांड के पहले संस्करण को निष्पादित किया जाएगा (एक जो बिना किसी स्थूल पुनरावर्ती बनाता है), अन्यथा यदि यह शून्य / गलत है, तो दूसरा संस्करण निष्पादित किया जाएगा (एक जो बनाता है इस स्थिति पर एक स्थूल पुनरावर्ती वर्तमान रेखा पर रहता है)।

इसलिए पिछले उदाहरण पर वापस जा रहे हैं, यह निम्नलिखित बात देगा:

qq
<C-a>
w
q
:RecursiveMacro q 0
3G
0@q
  1. qq रजिस्टर के अंदर एक मैक्रो की रिकॉर्डिंग शुरू करता है q
  2. <C-a> कर्सर के तहत संख्या में वृद्धि
  3. w कर्सर को अगले नंबर पर ले जाता है
  4. q रिकॉर्डिंग समाप्त करता है
  5. :RecursiveMacro q 0मैक्रो को q पुनरावर्ती के अंदर संग्रहीत किया जाता है, लेकिन केवल पंक्ति के अंत तक (दूसरे तर्क के कारण 0)
  6. 3G अपने कर्सर को एक मनमानी लाइन पर ले जाता है (उदाहरण के लिए 3)
  7. 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

इस बार मैक्रो तीसरी पंक्ति के अंत में नहीं बल्कि बफर के अंत में बंद हो जाएगा।


अधिक जानकारी के लिए देखें:

:help line()
:help :normal
:help :execute
:help :command-nargs
:help :command-register

2
स्थान सूची का उपयोग मैक्रो में खोज मैचों को आगे बढ़ाने के लिए किया जा सकता है, जब तक कि मैक्रो मैचों की स्थिति को नहीं बदलता है, उदाहरण के लिए :lv /\%3l\d/g %<CR>qqqqq<C-a>:lne<CR>@qq@qलाइन पर सभी संख्याओं में वृद्धि होगी 3. शायद इस समाधान को कम नाजुक बनाने का एक तरीका है?
djjcast

@djjcast आप इसे उत्तर के रूप में पोस्ट कर सकते हैं, मैंने इसकी कोशिश की है और यह वास्तव में बहुत अच्छा काम करता है। केवल एक मामला है जो मुझे समझ में नहीं आता है, जब मैं निम्नलिखित लाइन पर मैक्रो निष्पादित करता हूं, तो मुझे इसके बजाय 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। मुझे पता नहीं क्यों, शायद मैंने कुछ गलत किया। वैसे भी यह मेरे सरल दृष्टिकोण की तुलना में अधिक परिष्कृत लगता है, और इसमें यह वर्णन करना शामिल है कि मैक्रो को कर्सर को कहां ले जाना चाहिए, साथ ही एक स्थान सूची भी जिसे मैंने कभी इस तरह से उपयोग नहीं किया है। मुझे बहुत पसंद है!
सागिनॉ

@djjcast क्षमा करें, मैंने अभी-अभी समझा है, समस्या मेरे रीगेक्स से आई है, मुझे \d\+कई अंकों की संख्याओं का वर्णन करना चाहिए था ।
सगिनौ

@ डोजकास्ट आह अब मुझे समझ में आया कि जब आपने कहा था कि मैक्रो को मैचों की स्थिति नहीं बदलनी चाहिए। लेकिन मुझे नहीं पता कि इस मुद्दे को कैसे हल किया जाए। एकमात्र विचार मुझे स्थूल के अंदर से स्थान सूची को अद्यतन करने के लिए होगा, लेकिन मुझे स्थान सूची में उपयोग नहीं किया जाता है, यह मेरे लिए बहुत जटिल है, वास्तव में क्षमा करें।
सागिनेव

1
@saginaw उल्टे क्रम में होने वाले मैचों को देखते हुए ऐसा लगता है कि यह ज्यादातर मामलों में समस्या को हल कर देगा क्योंकि ऐसा लगता है कि पिछले मैचों के पदों को बदलने के लिए मैक्रो के लिए इसकी संभावना कम है। इसलिए :lv ...कमांड के बाद, कमांड का :llaउपयोग अंतिम मैच में कूदने के लिए किया जा सकता है और :lpकमांड का उपयोग रिवर्स ऑर्डर में मैचों को आगे बढ़ाने के लिए किया जा सकता है।
djjcast 14

9

जैसे ही यह विफल होता है एक कमांड का सामना करता है एक पुनरावर्ती मैक्रो बंद हो जाएगा। इसलिए, एक पंक्ति के अंत में रुकने के लिए, आपको एक कमांड की आवश्यकता है जो पंक्ति के अंत में विफल हो जाएगी।

डिफ़ॉल्ट रूप से *, lकमांड एक ऐसा कमांड है, इसलिए आप इसका उपयोग एक रिकर्सिव मैक्रो को रोकने के लिए कर सकते हैं। यदि कर्सर लाइन के अंत में नहीं है , तो आपको बस इसे कमांड के साथ बाद में वापस ले जाने की आवश्यकता है h

तो, saginaw के रूप में एक ही उदाहरण मैक्रो का उपयोग कर :

qqqqq<c-a>lhw@qq

टूटा:

  1. qqq: Q रजिस्टर साफ़ करें,
  2. qq: qरजिस्टर में एक मैक्रो रिकॉर्ड करना शुरू करें ,
  3. <c-a>: कर्सर के नीचे संख्या बढ़ाना,
  4. lh: यदि हम पंक्ति के अंत में हैं, तो मैक्रो को निरस्त करें। नहीं तो कुछ न करें।
  5. w: लाइन पर अगले शब्द के लिए अग्रिम।
  6. @q: पुनर्जीवित
  7. q: रिकॉर्डिंग बंद करें।

तब आप 0@qमैगिन को उसी आदेश के साथ चला सकते हैं जैसा कि saginaw द्वारा वर्णित है।


* 'whichwrap'विकल्प आपको यह परिभाषित करने की अनुमति देता है कि जब आप किसी पंक्ति के आरंभ या अंत में होते हैं तो कौन सी आंदोलन कुंजियाँ अगली पंक्ति में घूमेंगी (देखें :help 'whichwrap')। यदि आपने lइस विकल्प में सेट किया है, तो यह ऊपर वर्णित समाधान को तोड़ देगा।

हालांकि, यह संभावना है कि आप केवल एक ही चरित्र को आगे बढ़ाने के लिए तीन डिफ़ॉल्ट सामान्य मोड से कोई एक आदेश का उपयोग करें (है <Space>, lऔर <Right>), इसलिए यदि आप है lअपने में शामिल 'whichwrap'की स्थापना, आप एक है कि आप निकाल सकते हैं नहीं है से उपयोग करें 'whichwrap'विकल्प, उदाहरण के लिए <Space>:

:set whichwrap-=s

फिर आप lमैक्रो के चरण 4 में कमांड को कमांड से बदल सकते हैं <Space>


1
यह भी ध्यान रखें कि सेटिंग अंत-रेखा का पता लगाने के लिए virtualedit=onemoreहस्तक्षेप करेगी l, भले ही वह उतनी गंभीर न हो whichwrap=l
केविन

@ केविन गुड पॉइंट! मैं उल्लेख करने के लिए अपने उत्तर को अपडेट करूंगा've'
रिच
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.