Rejestry i rekurencyjne makra w Vim’ie.

Ostatnio wielokrotnie musiałem wykonywać ten sam ciąg operacji na kilkuset linijkach w tym samym formacie. Mógłbym teoretycznie posłużyć się Perl’em który jest idealny do takich rozwiązań, ale moim zdaniem pisanie nawet jednolinijkowego skryptu do takiego banalnego zadania to jak strzelanie z armaty do muchy. Pokażę Wam dzisiaj jak użyć makr w Vim’ie do radzenia sobie z takimi zadaniami w mgnieniu oka.

Żeby dobrze zrozumieć rozwiązanie, musimy zrozumieć jak działają rejestry i makra.

Rejestry

Najpierw kilka słów o rejestrach Vim’a. Używamy ich zawsze gdy usuwamy jakiś tekst, lub coś kopiujemy. Domyślnie komenda y kopiuje do rejestru ""(znak cudzysłowia). Spróbujcie teraz skopoiować jakieś słowo (bvwy) i usunąć trzy różne linijki (dd) ze swojego pliku i wpiszcie komendę :registers. Waszym oczom powinno ukazać się mniej więcej coś takiego:

--- Rejestry --- 
"" trzecia^J 
"0 kopia 
"1 trzecia^J 
"2 druga^J 
"3 pierwsza^J 
etc...

Jak widać powyżej skopiowałem słowo “kopia” i usunąłem po kolei linijki, w których były pojedyńcze słowa “pierwsza”, “druga” i “trzecia”. Jak widzimy, kopiowanie oraz usuwanie napisuje natychmiast nienazwany rejestr """0 zawsze przechowuje ostatnio kopiowaną(y) wartość, a rejestry "1"9 przechowują historię usunięć.

Więcej o celach poszczególnych rejestrów możemy poczytać w helpie (:h "0)

Gdy wydajemy komendy y i p są one równoważne ""y i ""p, czyli domyślnie używają nienazwanego rejestru "". Możemy natomiast sami wybrać sobie nazwany rejestr, do którego ma zostać skopiowana wartość. Na przykład "ayy skopiuje całą obecną linijkę do rejestru a. Od teraz możemy swobodnie wkleić ją komendą "ap.

Makra

Makra używają rejestrów w zupełnie inny sposób. Zamiast przechowywać w nich treść pliku, przechowują nasze komendy. Po naciśnieciu kombinacji qa wyczyścimy rejestr "a i zaczniemy zapisywać w nim wszystkie klawisze które naciskamy. Ponowne naciśnięcie q w trybie normalnym zakończy nagrywanie i od teraz wszyskto co zrobiliśmy możemy jeszcze raz powtórzyć wydając komendę @a. Wywołuje ona wszystkie literki które znajdują się w rejestrze tak jakbyśmy wpisali je własnoręcznie.

Więcej o makrach można przeczytać w :h @

Fuzja

Ponieważ @a bezmyślnie wywołuje rejestr, możemy bez problemu wywołać tekst który właśnie tam skopiowaliśmy.

Notka: W vimie poniższe znaki [esc] powinny wyglądać tak:^[, oraz mieć szare tło. Aby wprowadzić taki znak w trybie wprowadzania, naciśnijcie C-v, [esc].

Dla przykładu, zaznaczcie sobie tekst 3i słowo[esc] i wydajcie polecenie "ay. Teraz polecenie @aspowoduje trzykrotne wpisanie “słowo” z odstępem.

ReReRekurencja

Szybkie pytanie dla bystrych: Jeśli zawartość rejestru "a to A słowo[esc]@a, to co spowoduje komenda @a?

Dokładnie, w nieskończoność będzie dodawać na koniec linii ” słowo”!

Na szczęście Vim jest bardzo dobrze przystosowany do takiego użycia i szybkie C-c (Control+c) skończy nasze makro w miejscu w którym się znajdujemy. Dodam jeszcze że makra te wywołują się bardzo płynnie, więc możemy spokojnie wypatrzeć moment kiedy przerwać rekurencję. Jeśli wywołania rekurencyjne dotrą do końca pliku przerwą się automatycznie.

Zadanie domowe

Zacznę od omówienia szczegółów problemu. Dostaliśmy plik z deklaracjami zmiennych w takim oto formacie:
[typ][*/[]/ ] [nazwa] = [cyfra];
string[] epic = 20; char* epic = 109;
Musimy przerobić go do dziwnego formatu:
[nazwa]() : [typ][*/[]/ ] ~
epic() : string[] ~ epic() : char* ~

Bo akurat tego wymaga nasz framework.

Zadanie dla czytelników:
Pierwsza nadesłana na adres natanek.marcin@gmail.com zawartość rejestru "a która rekurencyjnie przerobi cały plik według powyższego schematu zostanie tutaj opublikowana razem z imieniem/ksywką autora. Przykładowe dane możecie wygenerować używając tego skryptu w Perlu. Przyjmuje on jeden argument: liczbę linii do wygenerowania. Powodzenia!

Autor: 
Rozwiązanie: "a = ---

Dodatkowa lektura dla dociekliwych, aka Bibliografia

  1. http://vim.wikia.com/wiki/Record_a_recursive_macro