Satır sonunda yinelemeli bir makroyu nasıl durdurabilirim?


13

Özyinelemeli bir makroyu yalnızca satır sonuna kadar çalışacak şekilde nasıl oluşturabilirim?

Ya da yalnızca satır sonuna kadar özyinelemeli bir makro nasıl çalıştırılır?

Yanıtlar:


11

Muhtemelen daha basit bir yöntem var ama belki aşağıdakileri deneyebilirsiniz.

Diyelim ki qözyinelemeli makronuzu kaydetmek için kayıt kullanacaksınız .

Kaydın en başında şunu yazın:

:let a = line('.')

Ardından, kaydın en sonunda @q, makro özyinelemeli hale getirmek yerine vurmak yerine aşağıdaki komutu yazın:

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

Son olarak makronun kaydını ile bitirin q.

Yazdığınız son komut makrosu q( exe 'norm @q') tekrar oynatır, ancak sadece geçerli satır numarası ( line('.')) değişkente başlangıçta saklananla aynı ise a.

:normalKomutu (gibi normal komutları yazın sağlar @qEx modundan).
Ve komut komutuyla bir dize içine sarılmış ve idam nedeni :executeönlemektir :normal(yazarak) komutu geri kalanı (tüketmesini |endif).


Kullanım örneği.

Diyelim ki şu ara belleğe sahipsiniz:

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

Ve rasgele bir satırdaki tüm sayıları yinelemeli bir makro ile artırmak istiyorsunuz.

0İmlecinizi satırın başına götürmek için yazabilir , ardından makronun kaydını başlatabilirsiniz:

qqq
qq
:let a=line('.')
<C-a>
w
:if line('.')==a|exe 'norm @q'|endif
q
  1. qqqqmakronun tanımı sırasında başlangıçta aradığınızda, karışmayacağı şekilde kayıt içeriğini temizler
  2. qq kaydı başlatır
  3. :let a=line('.') geçerli satır numarasını değişkenin içinde saklar a
  4. Ctrl+ aimlecin altındaki sayıyı artırır
  5. w imleci bir sonraki sayıya taşır
  6. :if line('.')==a|exe 'norm @q'|endif ancak satır numarası değişmediyse makroyu hatırlar
  7. q kaydı durdurur

Makronuzu tanımladıktan sonra, imlecinizi üçüncü satıra konumlandırırsanız, satırın 0başına taşımak için düğmesine @qbasın , ardından makroyu tekrar oynatmak için düğmesine basın q, diğerlerini değil yalnızca geçerli satırı etkilemelidir:

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

Kayıttan sonra makro yinelemeli hale getirme

İsterseniz, bir kaydın içindeki bir dizede saklandığını ve iki dizeyi nokta .işleciyle birleştirebildiğinizi kullanarak, kaydınızdan sonra yinelemeli hale getirebilirsiniz .

Bu size birkaç avantaj sağlar:

  • kayıttan önce kaydı temizlemeye gerek yoktur, çünkü karakterler @qtanımlandıktan sonra ve orada bulunan eski içeriklerin üzerine yazdıktan sonra makroya eklenir
  • kayıt sırasında olağandışı bir şey yazmaya gerek yok, basit, çalışan bir makro yapmaya odaklanabilirsiniz
  • nasıl davrandığını görmek için özyinelemeden önce test etme olasılığı

Makronuzu her zamanki gibi (özyinelemesiz olarak) kaydederseniz, aşağıdaki komutla daha sonra yinelemeli yapabilirsiniz:

let @q = @q . "@q"

Veya daha kısa: let @q .= "@q"
.=bir dizgiyi başka bir dizeye eklemeye izin veren bir operatördür.

Bu, @qyazmaç içinde saklanan tuş vuruşları dizisinin en sonuna 2 karakteri eklemelidir q. Özel bir komut da tanımlayabilirsiniz:

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

:RecursiveMacroBir kaydın adını bekleyen komutu argüman olarak tanımlar ( -registergeçilen öznitelik nedeniyle :command).
Daha önce aynı komutu var, tek fark her geçtiği yerini ise qile <reg>. Komut yürütüldüğünde, Vim girdiğiniz <reg>kayıt adıyla her tekrarlandığında otomatik olarak genişler .

Şimdi, yapmanız gereken tek şey makronuzu her zamanki gibi (özyinelemesiz olarak) kaydetmek, daha sonra :RecursiveMacro qkayıt içinde saklanan makro qözyinelemeli yapmak için yazın .


Bir makroyu geçerli satırda kalması koşuluyla özyinelemeli yapmak için de aynı işlemi yapabilirsiniz:

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

Bu, kayıttan sonra yaptığınız hariç, yazının başında açıklananla aynı şeydir. Sadece qşu anda kayıtta bulunan tuş vuruşlarından önce ve sonra iki dizeyi birleştirirsiniz :

  1. let @q = kaydın içeriğini yeniden tanımlar q
  2. ":let a=line('.')\r"aMakroyu yapmadan önce geçerli satır numarasını değişkenin içinde saklar,
    \rVim'e Enter tuşuna basmasını ve komutu yürütmesini bildirmek için gereklidir :help expr-quote, benzer özel karakterlerin bir listesine bakın ,
  3. . @q .qkaydın mevcut içeriğini bir önceki dize ve bir sonrakiyle birleştirir ,
  4. ":if line('.')==a|exe 'norm @q'|endif\r"qçizginin değişmemesi şartıyla makroyu hatırlar

Yine, bazı tuş vuruşlarını kaydetmek için, aşağıdaki özel komutu tanımlayarak işlemi otomatikleştirebilirsiniz:

command! -register RecursiveMacroOnLine let @<reg> = ":let a=line('.')\r" . @<reg> . ":if line('.')==a|exe 'norm @<reg>'|endif\r"

Ve yine, tek yapmanız gereken makronuzu her zamanki gibi (özyinelemesiz olarak) kaydetmek, daha sonra :RecursiveMacroOnLine qyazmaç içinde saklanan makroyu qgeçerli satırda kalması koşuluyla yinelemeli hale getirmek için yazın .


2 komutu birleştir

Ayrıca :RecursiveMacro2 vakayı kapsayacak şekilde ince ayar yapabilirsiniz :

  • bir makroyu koşulsuz olarak yinelemeli hale getirmek,
  • geçerli satırda kalması koşuluyla bir makro yinelemeli hale getirme

Bunu yapmak için, ikinci bir argümanı iletebilirsiniz :RecursiveMacro. İkincisi sadece değerini test eder ve değere bağlı olarak önceki 2 komuttan birini yürütür. Böyle bir şey verirdi:

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

Veya (biraz daha okunabilir hale getirmek için çizgi devamlarını / ters eğik çizgileri kullanarak):

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

Öncekiyle aynı, ancak bu kez :RecursiveMacro( -nargs=1nitelik nedeniyle) 2. bir argüman sağlamanız gerekiyor .
Bu yeni komut yürütüldüğünde, Vim <args>verdiğiniz değerle otomatik olarak genişler .
Bu 2. bağımsız değişken sıfır / true ( if <args>) değilse , komutun ilk sürümü (bir makroyu koşulsuz olarak yinelemeli yapan) çalıştırılır, aksi takdirde sıfır / yanlış ise ikinci sürüm yürütülür ( geçerli satırda kalması koşuluyla özyinelemeli bir makro).

Yani bir önceki örneğe geri dönersek, şu şeyi verirdi:

qq
<C-a>
w
q
:RecursiveMacro q 0
3G
0@q
  1. qq yazmaç içindeki bir makro kaydını başlatır q
  2. <C-a> imlecin altındaki sayıyı artırır
  3. w imleci bir sonraki sayıya taşır
  4. q kaydı bitirir
  5. :RecursiveMacro q 0kayıtta saklanan makroyu q yalnızca satır sonuna kadar yinelemeli hale getirir (ikinci bağımsız değişken nedeniyle 0)
  6. 3G imlecinizi rastgele bir satıra taşır (örneğin 3)
  7. 0@q özyinelemeli makroyu satırın başından itibaren yeniden oynatır

Öncekiyle aynı sonucu vermelidir:

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

Ancak bu kez makronuzun kaydı sırasında dikkat dağıtıcı komutları yazmak zorunda kalmadınız, sadece çalışan bir komut yapmaya odaklanabilirsiniz.

Ve adım 5 sırasında, komuta sıfır dışında bir argüman iletmiş olsaydınız , yani :RecursiveMacro q 1bunun yerine :RecursiveMacro q 0yazmış qolsaydınız , makro , koşulsuz olarak özyinelemeli olurdu ve bu da aşağıdaki arabelleği vermiş olurdu:

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

Bu kez makro 3. satırın sonunda değil, ara belleğin sonunda dururdu.


Daha fazla bilgi için bakınız:

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

2
Konum listesi, makro eşleşmelerin konumunu değiştirmediği sürece, örneğin :lv /\%3l\d/g %<CR>qqqqq<C-a>:lne<CR>@qq@q3 satırındaki tüm sayıları artıracağı sürece, bir makrodaki arama eşleşmelerinde ilerlemek için kullanılabilir . Belki de bu çözümü daha az kırılgan hale getirmenin bir yolu var mı?
djjcast

@djjcast Cevap olarak gönderebilirsiniz, denedim ve gerçekten harika çalışıyor. Anlamadığım tek bir durum var, makroyu aşağıdaki satırda yürüttüğümde, yerine 1 2 3 4 5 6 7 8 9 10alıyorum . Nedenini bilmiyorum, belki bir şeyler yanlış yazdım. Her neyse, benim basit yaklaşımımdan daha sofistike görünüyor ve makronun imleci nereye taşıyacağını tanımlamak için düzenli ifadeler ve bu şekilde hiç görmediğim bir konum listesi içeriyor. Onu çok severim! 2 3 4 5 6 7 8 9 10 122 3 4 5 6 7 8 9 10 11
saginaw

@djjcast Üzgünüm, anladım, sorun sadece normal ifademden geldi, \d\+birden fazla basamak numarasını tanımlamak için kullanmalıydım .
saginaw

@djjcast Ah, makronun maçların konumunu değiştirmemesi gerektiğini söylediğinizde ne demek istediğinizi anlıyorum. Ancak bu sorunun nasıl çözüleceğini bilmiyorum. Sahip olduğum tek fikir, konum listesini makronun içinden güncellemek olacaktır, ancak konum listesine alışık değilim, bu benim için çok karmaşık, gerçekten üzgünüm.
saginaw

1
@saginaw Maçları ters sırada yineleme, çoğu durumda sorunu çözecek gibi görünüyor çünkü bir makronun önceki maçların pozisyonlarını değiştirmesi daha az olası görünüyor. Bu yüzden :lv ...komuttan sonra, komut :llason eşleşmeye atlamak için kullanılabilir ve :lpkomut eşleşmeleri ters sırayla ilerletmek için kullanılabilir.
djjcast

9

Özyinelemeli bir makro, başarısız olan bir komutla karşılaşır karşılaşmaz duracaktır. Bu nedenle, bir satırın sonunda durmak için, satırın sonunda başarısız olacak bir komuta ihtiyacınız vardır.

Varsayılan olarak *, lkomut böyle bir komuttur, böylece özyinelemeli bir makroyu durdurmak için kullanabilirsiniz. İmleç satırın sonunda değilse , komutla daha sonra geri hareket etmeniz yeterlidir h.

Yani, saginaw ile aynı örnek makrosu kullanmak :

qqqqq<c-a>lhw@qq

Bozuldu:

  1. qqq: Q kaydını temizle,
  2. qq: Kayıt qdefterine bir makro kaydetmeye başlayın ,
  3. <c-a>: İmlecin altındaki sayıyı arttırır,
  4. lh: Satırın sonundaysak makroyu iptal et. Aksi takdirde, hiçbir şey yapmayın.
  5. w: Satırdaki bir sonraki kelimeye ilerleyin.
  6. @q: Eğitim
  7. q: Kaydetmeyi bırak.

Daha sonra makroyu, 0@qsaginaw tarafından açıklanan komutla çalıştırabilirsiniz .


* Bu 'whichwrap'seçenek, bir satırın başında veya sonunda olduğunuzda hangi hareket tuşlarının bir sonraki satıra sarılacağını tanımlamanızı sağlar (Bkz. :help 'whichwrap'). Eğer varsa lbu seçenekte belirtilen, o zaman yukarıda açıklanan çözüm kıracak.

Ancak, yalnızca tek bir karakter ilerletmek üzere üç varsayılan normal mod komutları birini kullanın (olasıdır <Space>, lve <Right>sen gelmiş eğer öyleyse,) lsizin dahil 'whichwrap'belirleme, sen diğerini kaldırın edebilirsiniz yok kullanmak 'whichwrap'seçeneği, örneğin <Space>:

:set whichwrap-=s

Sonra lmakronun 4. adımındaki <Space>komutu bir komutla değiştirebilirsiniz.


1
Ayrıca ayarın hat sonu algılamak virtualedit=onemoreiçin kullanılmaya müdahale edeceğini unutmayın . lwhichwrap=l
Kevin

@Kevin İyi bir nokta! 've'
Zengin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.