Stwierdziłem niedawno, że brakuje mi w Vimie takiego drobiazgu jak wyświetlanie listy funkcji z edytowanego właśnie pliku. Można z jednej strony wykorzystać ctags, ale (pewien nie jestem, nie jestem znawcą tagsów ani ich obsługi w Vimie) po dodaniu funkcji/metody/czegokolwiek innego co można by nazwać tagiem trzeba by od nowa generować listę tagów. Nie jest to problemem takim bardzo dużym, do momentu gdy ciągle pracuje się nad różnymi projektami, z czego sporej części nie mam na dysku (tylko wykorzystując plugin netrw pracuję via ftp). W tym momencie moja znajomość systemu ctags podpowiada mi że robi się ciężko…
Postanowiłem więc napisać sobie prosty skrypt do tego, a że język wewnętrzny Vima mnie nieco odrzuca, postawiłem na Pythona ;) Żeby jakikolwiek skrypt pythona (jak ktoś lubi, można użyć też np perla) mógł zadziałać w Vimie, ten ostatni musi być skompilowany z jego obsługą. W Ubuntu wystarczy zainstalować pakiet vim-full. Łatwo sprawdzić czy Vim ma wkompilowaną obsługę pythona:
vim --version|gi '+python'
Jeśli wyświetliła Ci się podobna linijka:
+python +quickfix +reltime +rightleft +ruby +scrollbind +signs +smartindent
to znaczy że możesz śmiało używać pythona do oskryptowania Vima :)
Skrypty Pythona w Vimie przekazywane są do funkcji Vimowej o zaskakującej, nietypowej nazwie python. Tradycyjne Hello world wyglądałoby tak:
:python print "Hello world"
Interakcję z samym Vimem umożliwia nam moduł o kolejnej zaskakującej nazwie: vim, który powinniśmy zaimportować na początku funkcji/skryptu. Szczegółowa jego dokumentacja jest na stronach Vima: vim.org/htmldoc/if_pyth.html.
Pierwszym krokiem jest wczytanie zawartości całego bufora. Do jego zawartości dostajemy się poprzez obiekt vim.current.buffer:
fc = "\n".join (line for line in vim.current.buffer)
Samo wyszukanie deklaracji funkcji w plikach pythona można by zrobić mniej więcej tak:
re.findall (r'^\s*def\s+(\w+)', fc, re.M)
Jednak nam najwygodniej pobrać będzie jednocześnie z nazwą funkcji, także całą linijkę w której ta została zdefiniowana. Przyda to się przy przechodzeniu do miejsca w kodzie w którym funkcja jest zdefiniowana. Ja końcowo zrobiłem to tak:
re.findall (r'^(\s*def\s+(\w+\s*\(.*?\))\s*:)', fc, re.M)
Teraz, gdy mamy listę funkcji, trzeba je wyświetlić userowi, a następnie pobrać informację do deklaracji jakiej funkcji w kodzie chcemy się przenieść. Najpierw chciałem skorzystać ze standardowego pythonowego raw_input (), ale ta funkcja w Vimie nie działa. Użyłem wobec tego Vimowego input (). Aby skorzystać z funkcji Vimowych, moduł vim udostępnia nam dwie funkcje: vim.eval () i vim.command (). Tutaj odpowiedni będzie vim.eval ():
choice = vim.eval ('input ("Which one: ")')
W tej chwili mamy już praktycznie napisany cały skrypt. Pozostało tylko znalezienie offsetu w jakim się zaczyna deklaracja wybranej przez usera funkcji w buforze, a następnie za pomocą vim.command () przenieść kursor w wybrane miejsce:
vim.command ('goto '+str (pos+1))
Całość w moim wykonaniu jest nieco bardziej rozbudowana (minimalnie), jako że staram się zrobić sobie mały framework do skryptowania Vima. Wycinek realizujący odpowiednią funkcjonalnośc w moim przypadku wygląda tak:
" importy ogólne, przydatne funkcje, etc
python << EOF
import re
import sys
import vim
def MyDevPlugins_GetFileType (default=None):
ft = vim.eval ('synIDattr(synID(line("."), col("."), 1), "name")')
if ft:
m = re.findall (r'^([a-z]+)', ft)
if m:
return m[0]
if not ft:
ft = default
return ft
EOF
" FindSubs - wyszukiwanie funkcji
python << EOF
FindSubs_ftypes = {
'perl': r'^(\s*sub\s+(\w+(?:\s*\(.*?\))?))',
'python': r'^(\s*def\s+(\w+\s*\(.*?\))\s*:)',
'php': r'^(\s*function\s+(\w+\s*\(.*?\)))',
}
FindSubs_ftypes['java'] = FindSubs_ftypes['html'] = FindSubs_ftypes['php']
def FindSubs_Find (ft='perl'):
try:
rxp = FindSubs_ftypes[ft]
except KeyError:
print 'Unknown filetype: "%s"' % ft
return
# read buffer content
fc = "\n".join (line for line in vim.current.buffer)
# find all functions names
m = re.findall (rxp, fc, re.M)
if not m:
print 'Not found'
return
# print them for user
for i, sub in enumerate (m):
print '%d. %s' % (i+1, sub[1])
# ask for function he want to go
choice = vim.eval ('input ("Which one: ")')
try:
choice = int (choice) - 1
except:
print 'Incorrect value'
return
# find file offset
pos = fc.find (m[choice][0].strip ())
if pos < 0:
print >>sys.stderr, "Some error occured."
return
# and go there
vim.command ('goto '+str (pos+1))
def FindSubs_Main ():
FindSubs_Find (MyDevPlugins_GetFileType ())
EOF
function! FindSubs()
python FindSubs_Main()
endfunction
map <F5> :call FindSubs ()<CR>
Ostatnia linijka odpowiada za podmapowanie wywołania funkcji pod klawisz F5.
Natomiast problemy sprawia opcja rozpoznawania typu pliku. Nie doszukałem się nigdzie w dokumentacji lepszego sposobu, a ten czasem zawodzi :( Nic na to chwilowo nie poradzę. Oczywiście przydałoby się rozpoznawanie większej ilości języków, ale to co jest obecnie wystarcza mi w zupełności, w razie czego można sobie dorobić odpowiednie regexpy do słownika FindSubs_ftypes.

Natomiast problemy sprawia opcja rozpoznawania typu pliku. Nie doszukałem się nigdzie w dokumentacji lepszego sposobu, a ten czasem zawodzi
Właśnie trafiłem na tego posta, więc podpowiem ci rozwiązanie – może się przyda:
:py import vim
:py print vim.eval("&ft")
python
ww kod po prostu wyrzuca to, co znajduje się w zmiennej ‘filetype’.
Long live to VIM! :)
Adres bezpośredni: http://urzenia.net/359/skrypty-pythona-w-vimie/#comment-33310
Na ten sposób trafiłem jakiś czas temu, i zacząłem go używać. Niestety, też ma pewne wady: zwraca typ kolorowania dla całego pliku. A co z plikami takimi jak .php, gdzie częściowo można mieć treść HTML, dla której (mówię tu na przykładzie skryptu do zakomentowania linii) zakomentowanie wygląda inaczej niż dla php? Kompletnie nie ma jak tego obejść :(
Adres bezpośredni: http://urzenia.net/359/skrypty-pythona-w-vimie/#comment-33311
Można używać zewnętrznych poleceń powłoki? Jeżeli tak, typ pliku można pobrać przy pomocy polecenia “file”. Analogicznie:
radek@:~ # file www/skrypt.php
www/skrypt.php: PHP script text
radek@:~ # file www/auth.py
www/auth.py: python script text executable
Pozdrawiam.
Adres bezpośredni: http://urzenia.net/359/skrypty-pythona-w-vimie/#comment-33318
@Radek: No tutaj jest ten sam problem co z
&ft: pobiera typ całego pliku. Poza tym wynikfilejest dość ciężko w sumie parsować. Zrobiłem inaczej: dla skryptu który znaduje mi funkcje w pliku sprawdzam najpierw zmienną&ft, jeśli to nic nie da, pobieram rozszerzenie pliku.Dla drugiego skryptu, który komentuje mi linie, sprawdzam kombinacją
synIDattr (synID ()). Jak na razie w większości wypadków działa :)Adres bezpośredni: http://urzenia.net/359/skrypty-pythona-w-vimie/#comment-33319
[...] sobie różne udoskonalenia dla Vima, i piszę je zazwyczaj w Pythonie :) Niedawno opisywałem jak wyświetlić listę funkcji z edytowanego pliku, później zrobiłem sobie wygodne komentowanie kodu (wersje które znalazłem na sieci nie [...]
Adres bezpośredni: http://urzenia.net/359/skrypty-pythona-w-vimie/#comment-33328