Zaawansowana edycja w vim II

Od ponad 4 lat do edycji wszystkiego co ma litery używam Vim. Dzięki jego niesamowitym możliwościom konfiguracji, mój vimrc nie raz zmieniał się w zależności od zadań jakim musiał sprostać. Od ponad pół roku pracuje jako programista i chyba nie muszę tłumaczyć jak bardzo praca nad własnym małym projektem różni się od rozwijania aplikacji nad którą pracuje paręnaście osób.

Poniższy opis to zbiór "sztuczek" jakie odkryłem i jakich nauczyłem się używać na co dzień, w pracy nad dużą aplikacją.

Wyszukiwanie

Znalezienie odpowiedniego fragmentu kodu, to zazwyczaj połowa sukcesu. Gdyby projekt zawierał się w paru plikach, każdy byłby w stanie szybko wskazać odpowiednią linijkę. Tylko że nigdy nie wiadomo czego tak naprawdę szukamy, aż do momentu znalezienia. A wtedy i tak okazuje się, że kod napisany został przez kogoś innego. Dlatego właśnie potrzebne jest narzędzie, które które rozwiąże ten problem za nas.

grep

Aby nie używać surowego grep i przełączać się między Vim a kolejną konsolą, polecam plugin grep.vim. Z interfejsu jaki udostępnia, najczęściej używam :Rgrep za pomocą którego można przeszukać całe drzewo katalogów. Oprócz wyrażenia i najwyższego katalogu można podać również dopuszczalne rozszerzenie pliku, co dodatkowo przyspiesza proces wyszukiwania.

Exuberant Ctags

Exuberant Ctags to indekser, który początkowo był częścią Vim. Obecnie jest to osobny projekt, używany także przez wiele innych narzędzi.

Osobiście indeksuję jedynie kod Pythona, ale program działa podobno dla co najmniej 41 języków. Aby zaindeksować źródła, używam trochę przekombinowanego polecenia, bo chociaż ctags powinien sam znaleźć odpowiednie pliki to mam wrażenie, że flaga -R nie do końca działa:

cd $HOME/mojprojekt
find . -name "*.py" | xargs ctags -a --language-force=python

Po zakończeniu działania, utworzony zostanie plik tags. Teraz trzeba wykorzystać te informacje w Vim. To jakich indeksów używamy, można sprawdzić wpisując

:echo &tags
./tags,./TAGS,tags,TAGS

Jeśli indeksujemy zewnętrzny kod (na przykład jakąś bibliotekę), można to zrobić w wydzielonym do tego katalogu, poza obecnym projektem. Wtedy trzeba jawnie dołączyć kolejny plik wygenerowany przez ctags:

:set tags=./tags,tags,/home/me/.tags/django.ctags,/home/me/.tags/gtk.ctags

Ponieważ nazwa nie ma znaczenia, wszystkie indeksy bibliotek trzymam w jednym katalogu i zapisuje jako <nazwa biblioteki>.ctags.

Teraz przejść można do najciekawszego, czyli użycia wygenerowanych danych. Załóżmy, że przeglądając kod aplikacji napisanej w django, natrafiłem na użycie klasy UserProfile. Czym jest UserProfile? Jak tego używać? Aby się tego dowiedzieć można zajrzeć do *khe* *khe* dokumentacji. Można też obejrzeć źródła klasy.

W dokumentacji Vim, po wpisaniu :h tagsrch, dostaniemy obszerny opis jak używać indeksu. Oczywiście warto to przeczytać, lecz ja i tak przedstawię te fragmenty manuala, które sam najczęściej wykorzystuję.

Wracając do UserProfile - pierwszą możliwością odnalezienia klasy jest wpisanie polecenia

:tag UserProfile

Jeśli znalezione zostało więcej niż jedno pasujące miejsce, pojawia się stosowna informacja, na przykład "znacznik 1 z 6 lub więcej" i przeniesieni zostajemy w pierwsze pasujące miejsce. Analogicznie, wpisując:

:<N>tag UserProfile

przeniesieni zostajemy do <N>-tego znalezionego wystąpienia UserProfile. W takich przypadkach o wiele wygodniejsze może być więc użycie interaktywnego :tjump UserProfile.

Polecenie :tag jest fajne, jeśli znamy chociażby początek nazwy (użycie <Tab> uzupełniania słowo), ale trochę bez sensu wydaje się wpisywanie wyrazu, na którym właśnie mam ustawiony kursor. W takim przypadku, do dyspozycji mamy skrót g Ctrl-] (:h g_CTRL-]), który jest skrótem dla :tjump.

Śledzenie importów

W śledzeniu przebiegu programu, bardzo pomocny może okazać się skrót gf. Edytując poniższy fragment (znak | oznacza miejsce gdzie znajduje się kursor)

from django.db import models
from userprofile.model|s import UserProfile

po wpisaniu <Esc>gf, rozpoczynam edycję pliku userprofile/models.py. Vim sam znajdzie odpowiedni plik, sprawdzając wszystkie ścieżki ustawione w zmiennej path:

:echo &path
.,/usr/include,,

To samo polecenie nie zadziała więc dla django.db, chyba że dodamy kolejny katalog:

:set path+=/usr/lib/python2.6/site-packages

Należy jednak być świadomym sposobu w jaki używana jest zmienna path oraz tego, że nie jest ona wykorzystywana jedynie do wyszukiwania plików. Ten sam mechanizm może być również stosowany na przykład do uzupełniania kodu, co przy zbyt wielu plikach do sprawdzenia może okazać się niewydajne.

Uzupełnianie kodu

Wielu programistów, za kryterium w wyborze edytora/IDE przyjmuje automatyczne podpowiadanie składni. Osobiście wolę jawnie określić kiedy oczekuje podpowiedzi. supertab.vim chowa pod klawiszem <Tab> wszystkie tradycyjne tryby dopełniania w Vim. Jeśli chcemy zmienić obecny sposób podpowiedzi, wystarczy wpisać :SuperTabHelp i wybrać inny.

Więcej o uzupełnianiu składni można przeczytać w innym wpisie.

Monitorowanie skoków

Używając w dużej ilości poleceń szybkiego przemieszczenia łatwo się pogubić. Parę skoków wystarczy, żeby zapomnieć gdzie byłem jeszcze przed chwilą. Ten problem można rozwiązać używając jump motions. Każdy skok rejestrowany jest przez edytor, a ich lista dostępna jest pod poleceniem :jumps.

Dwa najczęściej używane przeze mnie polecenia to Ctrl-o oraz Ctrl-i, czyli skok wstecz i do przodu.

Bufory

Każdy nowy plik otwierany jest w buforze. Każdy z buforów, o ile nie zostanie jawnie zamknięty, dostępny jest przez cały czas życia Vima. Stan buforów obejrzeć można wydając polecenie :ls:

:ls
  1 #a   "userprofile/models.py"        wiersz 1
  2 %a + "userprofile/forms.py"         wiersz 86
  3  a   "settings.py"                  wiersz 0

Jeśli chcę powrócić do edycji pliku, który kiedyś zamknąłem (ale jego bufor wciąż jest w pamięci), mogę to zrobić używając polecenia :b<numer>. Kursor ustawiony zostanie w tym samym miejscu co przy zamykaniu pliku.

denial

26.10.2009

Też kiedyś bawiłem się vimem, ale skończyłem po jakimś czasie. Jak widze całą stronę opisu konfiguracji podstawowych rzeczy to odechciewa się używania tego edytora. Widziałem Twoją konfigurację, którą udostępniłeś, wszystko ładnie działa, więc widocznie da się poustawiać wszystko. Tylko jak będę chciał coś zmienić to się pewnie znów wkurzę i zmarnuje zbyt dużo czasu. Od niedawna używam eclipse+pydev(od niedawna w pełni opensourcowy)+aptana i muszę powiedzieć, że jestem pod wrażeniem, tak dobrego uzupełniania kodu dawno nie widziałem, świetny debugger, refaktoring i masa innych funkcjonalności, nic więcej nie potrzeba. Wiadomo eclipse zżera troche zasobów, ale trzeba mieć naprawdę starą maszynę, żeby to przeszkadzało. 3/4 ramu i tak siedzi i się marnuje :)

Husio

26.10.2009

Vim, jak każde narzędzie o ogromnych możliwościach, wymaga wielu godzin poświęconych na naukę. Wystarczy znać parę komend, żeby można go było używać jak zwykłego edytora, ale potrzeba wielu miesięcy nauki, żeby używać go efektywnie. Jednak czas poświęcony na zapamiętanie tych pozornie losowych ciągów liter, zwraca się z nawiązką, gdy chce aby mój edytor robił coś, czego nie potrafi żaden inny.

Do tego wzorowa dokumentacja i dobra społeczność - nie wydaje mi się, żeby jakikolwiek inny edytor/IDE mógł z tym konkurować *khe* emacs *khe* ;)

denial

28.10.2009

No właśnie, wiele godzin poświęconych na naukę... Wolę te godziny przeznaczyć na pisanie programów. Ogólnie zauważyłem, że w moim przypadku praca z vimem nie przyśpiesza klepania kodu. Lubię vima jako edytor do konsoli, ale do tworzenia większych projektów już nie :)