Jak mogę utworzyć makro rekurencyjne, aby działało tylko do końca linii?
Lub jak uruchomić rekurencyjne makro tylko do końca linii?
Prawdopodobnie jest to prostsza metoda, ale może wypróbujesz następujące.
Załóżmy, że użyjesz register q
do zarejestrowania swojego rekurencyjnego makra.
Na samym początku nagrania wpisz:
:let a = line('.')
Następnie na samym końcu nagrania, zamiast naciskać, @q
aby makro było rekurencyjne, wpisz następujące polecenie:
:if line('.') == a | exe 'norm @q' | endif
Na koniec zakończ rejestrację makra za pomocą q
.
Ostatnie wpisane polecenie odtworzy makro q
( exe 'norm @q'
), ale tylko jeśli bieżący numer linii ( line('.')
) jest taki sam, jak początkowo przechowywany w zmiennej a
.
:normal
Komenda pozwala wpisać normalnych poleceń (jak @q
) z trybu Ex.
Powodem, dla którego polecenie jest zawinięte w ciąg znaków i wykonane przez polecenie, :execute
jest zapobieganie wykorzystaniu :normal
(wpisaniu) reszty polecenia ( |endif
).
Przykład użycia
Załóżmy, że masz następujący bufor:
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
I chcesz zwiększyć wszystkie liczby z dowolnej linii za pomocą rekurencyjnego makra.
Możesz wpisać, 0
aby przesunąć kursor na początek linii, a następnie rozpocząć rejestrowanie makra:
qqq
qq
:let a=line('.')
<C-a>
w
:if line('.')==a|exe 'norm @q'|endif
q
qqq
usuwa zawartość rejestru q
, aby po wywołaniu go podczas definicji makra nie przeszkadzałqq
rozpoczyna nagrywanie:let a=line('.')
przechowuje bieżący numer linii w zmiennej a
w
przesuwa kursor do następnej liczby:if line('.')==a|exe 'norm @q'|endif
przywołuje makro, ale tylko jeśli numer linii nie zmienił sięq
zatrzymuje nagrywaniePo zdefiniowaniu makra, jeśli umieścisz kursor na trzeciej linii, naciśnij, 0
aby przenieść go na początek linii, a następnie naciśnij, @q
aby odtworzyć makro q
, powinno to wpływać tylko na bieżącą linię, a nie na inne:
1 2 3 4
1 2 3 4
2 3 4 5
1 2 3 4
Zrób makro rekurencyjne po nagraniu
Jeśli chcesz, możesz uczynić makro rekurencyjnym po jego nagraniu, korzystając z faktu, że jest ono przechowywane w ciągu wewnątrz rejestru i że możesz połączyć dwa ciągi z .
operatorem kropki .
Dałoby to kilka korzyści:
@q
zostaną dodane do makra po jego zdefiniowaniu i po nadpisaniu istniejącej zawartościJeśli makro zapisujesz w zwykły sposób (nie rekurencyjnie), możesz później ustawić je jako rekurencyjne za pomocą następującego polecenia:
let @q = @q . "@q"
Lub nawet krócej: let @q .= "@q"
.=
to operator, który pozwala dołączyć ciąg do innego.
To powinno dodać 2 znaki @q
na samym końcu sekwencji naciśnięć klawiszy zapisanych w rejestrze q
. Możesz również zdefiniować niestandardowe polecenie:
command! -register RecursiveMacro let @<reg> .= "@<reg>"
Definiuje polecenie, :RecursiveMacro
które czeka na nazwę rejestru jako argument (ze względu na -register
przekazany atrybut :command
).
To samo polecenie, jak poprzednio, jedyną różnicą jest to zastąpić wszystkie wystąpienia q
z <reg>
. Kiedy polecenie zostanie wykonane, Vim automatycznie rozszerzy każde wystąpienie o <reg>
podaną nazwę rejestru.
Teraz wszystko, co musisz zrobić, to zapisać makro w zwykły sposób (nie rekurencyjnie), a następnie wpisać, :RecursiveMacro q
aby makro przechowywane w rejestrze było q
rekurencyjne.
Możesz zrobić to samo, aby makro było rekurencyjne pod warunkiem, że pozostanie w bieżącym wierszu:
let @q = ":let a=line('.')\r" . @q . ":if line('.')==a|exe 'norm @q'|endif\r"
Jest to dokładnie to samo, co opisano na początku postu, z tym wyjątkiem, że robisz to po nagraniu. Po prostu łączysz dwa ciągi, jeden przed i jeden po dowolnym naciśnięciu klawisza, który q
rejestr zawiera obecnie:
let @q =
redefiniuje zawartość rejestru q
":let a=line('.')\r"
przechowuje bieżący numer wiersza wewnątrz zmiennej, a
zanim makro wykona swoją pracę, \r
konieczne jest, aby powiedzieć Vimowi, aby nacisnął Enter i wykonał polecenie, zobacz :help expr-quote
listę podobnych znaków specjalnych, . @q .
łączy bieżącą zawartość q
rejestru z poprzednim ciągiem i następnym,":if line('.')==a|exe 'norm @q'|endif\r"
przywołuje makro q
pod warunkiem, że linia się nie zmieniłaPonownie, aby zapisać niektóre naciśnięcia klawiszy, możesz zautomatyzować proces, definiując następujące niestandardowe polecenie:
command! -register RecursiveMacroOnLine let @<reg> = ":let a=line('.')\r" . @<reg> . ":if line('.')==a|exe 'norm @<reg>'|endif\r"
I znowu wszystko, co musisz zrobić, to zapisać makro jak zwykle (nie rekurencyjnie), a następnie wpisać, :RecursiveMacroOnLine q
aby makro przechowywane w rejestrze było q
rekurencyjne pod warunkiem, że pozostanie w bieżącej linii.
Scal 2 polecenia
Możesz również dostosować, :RecursiveMacro
aby obejmował 2 przypadki:
Aby to zrobić, możesz przekazać drugi argument do :RecursiveMacro
. Ten ostatni po prostu przetestuje swoją wartość i, w zależności od wartości, wykona jedno z 2 poprzednich poleceń. Dałoby to coś takiego:
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
Lub (używając kontynuacji linii / ukośników odwrotnych, aby była bardziej czytelna):
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
Jest tak samo jak poprzednio, tyle że tym razem musisz podać drugi argument :RecursiveMacro
(z powodu -nargs=1
atrybutu).
Kiedy to nowe polecenie zostanie wykonane, Vim automatycznie rozszerzy się <args>
o podaną wartość.
Jeśli ten drugi argument jest niezerowy / true ( if <args>
), pierwsza wersja polecenia zostanie wykonana (ta, która bezwarunkowo powoduje, że makro rekursywnie), w przeciwnym razie, jeśli jest zero / false, zostanie wykonana druga wersja (ta, która powoduje, że makro rekurencyjne pod warunkiem, że pozostaje w bieżącej linii).
Wracając do poprzedniego przykładu, dałoby to następującą rzecz:
qq
<C-a>
w
q
:RecursiveMacro q 0
3G
0@q
qq
rozpoczyna rejestrowanie makra w rejestrze q
<C-a>
zwiększa liczbę pod kursoremw
przesuwa kursor do następnej liczbyq
kończy nagrywanie:RecursiveMacro q 0
sprawia, że makro przechowywane w rejestrze jest q
rekurencyjne, ale tylko do końca linii (z powodu drugiego argumentu 0
)3G
przesuwa kursor do dowolnej linii (na przykład 3)0@q
odtwarza makro rekurencyjne od początku wierszaPowinien dać taki sam wynik jak poprzednio:
1 2 3 4
1 2 3 4
2 3 4 5
1 2 3 4
Ale tym razem nie musisz wpisywać rozpraszających poleceń podczas rejestrowania makra, możesz po prostu skupić się na stworzeniu działającego.
A podczas kroku 5, jeśli przekazałeś niezerowy argument do polecenia, to znaczy, jeśli wpisałeś :RecursiveMacro q 1
zamiast :RecursiveMacro q 0
, makro q
stałoby się bezwarunkowo rekurencyjne, co dałoby następujący bufor:
1 2 3 4
1 2 3 4
2 3 4 5
2 3 4 5
Tym razem makro nie zatrzymałoby się na końcu 3. linii, ale na końcu bufora.
Aby uzyskać więcej informacji, zobacz:
:help line()
:help :normal
:help :execute
:help :command-nargs
:help :command-register
:lv /\%3l\d/g %<CR>qqqqq<C-a>:lne<CR>@qq@q
Zwiększy wszystkie liczby w wierszu 3. Może istnieje sposób, aby to rozwiązanie było mniej kruche?1 2 3 4 5 6 7 8 9 10
, dostaję2 3 4 5 6 7 8 9 10 12
zamiast2 3 4 5 6 7 8 9 10 11
. Nie wiem dlaczego, może coś pomyliłem. W każdym razie wydaje się bardziej wyrafinowane niż moje proste podejście i wymaga wyrażeń regularnych, aby opisać, gdzie makro powinno przesunąć kursor, a także listę lokalizacji, której nigdy nie widziałem w ten sposób. Bardzo to lubię!\d\+
opisywać wiele cyfr.:lv ...
komendy,:lla
aby przejść do ostatniego dopasowania, a:lp
komendy można użyć, aby przejść do kolejnych meczów w odwrotnej kolejności.Makro rekurencyjne zatrzyma się, gdy tylko napotka polecenie, które się nie powiedzie. Dlatego, aby zatrzymać się na końcu linii, potrzebujesz polecenia, które zawiedzie na końcu linii.
Domyślnie *
l
polecenie jest takim poleceniem, więc możesz go użyć do zatrzymania rekurencyjnego makra. Jeśli kursor nie znajduje się na końcu wiersza, wystarczy przesunąć go z powrotem za pomocą poleceniah
.Tak więc używając tego samego makra przykładowego jak saginaw :
Zepsuty:
qqq
: Wyczyść rejestr q,qq
: Rozpocznij rejestrowanie makra wq
rejestrze,<c-a>
: Zwiększ liczbę pod kursorem,lh
: Jeśli jesteśmy na końcu linii, przerwij makro. W przeciwnym razie nie rób nic.w
: Przejście do następnego słowa w linii.@q
: Recurseq
: Zatrzymaj nagrywanie.Następnie możesz uruchomić makro za pomocą tego samego
0@q
polecenia, które opisano w saginaw.* Ta
'whichwrap'
opcja pozwala określić, które klawisze ruchu będą przewijane do następnej linii, gdy znajdziesz się na początku lub na końcu linii (patrz:help 'whichwrap'
). Jeślil
ustawiłeś tę opcję, spowoduje to uszkodzenie opisanego powyżej rozwiązania.Jednak jest prawdopodobne, że używasz tylko jeden z trzech domyślnych poleceń normalnym trybie na pogłębianie pojedynczy znak (
<Space>
,l
, i<Right>
), więc jeśli maszl
włączone w'whichwrap'
ustawieniach, można usunąć jedno z nich nie korzystać z'whichwrap'
opcja, np. dla<Space>
:Następnie możesz zastąpić
l
polecenie w kroku 4 makra<Space>
poleceniem.źródło
virtualedit=onemore
będzie kolidować z użycieml
do wykrywania końca linii, choć nie tak poważnie jakwhichwrap=l
.'ve'