post

Vim ro:Editorul programatorilor

Contents

Introducere

Vim tinde să fie folosit intensiv de către programatori. Facilităţile, uşurinţa în utilizare şi flexibilitatea îl fac o opţiune bună pentru cei care doresc să scrie mult cod. Anu ar trebui să ne surprindă asta întrucât scrierea de cod înseamnă multă editare.

Daţi-mi voie să repet că aptitudinile de tastare sunt critice pentru un programator. Dacă discuţia precedentă nu v-a convins, sper că acest articol de Jeff Atwood despre ‘Suntem întâi dactilografi, apoi programatori’ vă va convinge.

Dacă nu aveţi experienţă de programare, puteţi trece peste acest capitol.

Pentru cei ce adoră programarea, să intrăm puţin în subiect şi să vedem cum vă ajută Vim să scrieţi cod.

Lucruri elementare

Cea mai simplă facilitate din Vim pe care o puteţi folosi ca să vă ajute să scrieţi cod este evidenţierea sintaxei. Aceasta permite vizualizarea codului, ceea ce vă ajută să citiţi şi să scrieţi mai repede, fără greşeli evidente.

Evidenţierea sintaxei

Syntax highlighting.png

Să zicem că editaţi un fişier de sintaxă Vim, rulaţi :set filetype=vim şi vedeţi cum colorează Vim. Similarl, dacă editaţi un fişier Python, rulaţi :set filetype=python.

Pentru a vedea o listă a tipurilor de fişier pentru care sunt disponibile fişiere de sintaxă, parcurgeţi directorul $VIMRUNTIME/syntax/.

Pont
Dacă vreţi să dispuneţi de puterea evidenţierii sintaţei în rezultatul oricărui shell, redirecţionaţi-l prin Vim, de exemplu svn diff | vim -R -. Observaţi cratima la sfârşit, ceea ce face ca Vim să citească textul de la intrarea standard.

Indentarea automată

Codul unui programator experimentat este de obicei indentat corespunzător, ceea ce face codul să arate mai “uniform” şi structura codului este mai evidentă vizual. Vim poate ajuta cu automatizarea indentării, pentru a va putea concentra pe scrierea codului.

Dacă indentaţi o anumită linie şi vreţi să se menţină regula la următoarele linii, puteţi folosi setarea :set autoindent.

Dacă începeţi un nou bloc de declaraţii şi vreţi să setaţi indentarea la nivelul următor, puteţi folosi comanda :set smartindent. De observat că acţiunea acestei setări depinde de limbajul a cărui sintaxă se evidenţiază.

Găsirea acoladei pereche

Dacă limbajul de programare ales foloseşte acolade pentru a delimita blocuri de declaraţii, plasaţi cursorul pe o acoladă şi apăsaţi tasta % pentru a sări la acolada pereche. Această tastă de salt vă permite să treceţi uşor de la începutul la sfârşitul unui bloc de declaraţii şi invers.

Comenzi de consolă

Puteţi rula o comandă de consolă (engl. shell) din Vim folosind comanda :!.

De exemplu, dacă comanda date este disponibilă în sistemul de operare, rulaţi :!date şi veţi vedea afişată data curentă.

Asta este folositoare în situaţii in care vreţi să verificaţi ceva legat de sistemul de fişiere, de exemplu ce fişiere sunt în directorul curent cu :!ls sau :!dir şi altele.

Dacă vreţi acces la un shell în toată regula, rulaţi :sh.

Puteţi folosi această facilitate pentru a rula filtre externe asupra textului de editat. Ca exemplu, dacă aveţi o mulţime de linii care trebuie sortate, puteţi rula :%!sort; aceasta trimite textul curent comenzii sort în shell şi rezultatul acesteia înlocuieşte conţinutul actual al fişierului.

Salturi

Există multe căi de a face salturi prin cod.

  • Poziţionaţi cursorul pe un nume de fişier în cod şi tastaţi gf pentru a deschide acel fişier.
  • Poziţionaţi cursorul pe un nume de variabilă şi tastaţi gd pentru a sări la definiţia locală a numelui variabilei. Tastaţi gD pentru definiţia globală, căutată de la începutul fişierului.
  • Folosiţi ]] pentru a vă muta la următoarea { în prima coloană. Există multe mişcări similare – a se citi :help object-motions pentru detalii.
  • A se citi :help 29.3, :help 29.4 şi :help 29.5 pentru mai multe comenzi de acest gen. De exemplu, [I va afişa toate liniile care conţin cuvântul cheie indicat de cursor!

Răsfoirea unor părţi de cod

Sistemul de fişiere

Folosiţi :Vex sau :Sex pentru a răsfoi sistemul de fişiere în Vim şi ca urmare a deschide fişierele căutate.

ctags

Am văzut cum se fac mişcări simple în acelaşi fişier, dar dacă vrem să ne deplasăm în alt fişier şi să avem referinţe încrucişate între fişiere? Atunci vom folosi taguri.

Pentru simpla parcurgere a unui fişier puteţi folosi un plugin taglist.vim.

Taglist in action

  1. Instalaţi programul Exuberant ctags.
  2. Instalaţi pluginul taglist.vim. Citiţi “install details” pe pagina scriptului.
  3. Rulaţi :TlistToggle pentru a deschide fereastra cu lista de taguri. Voila, acum puteţi rasfoi blocuri de fişier precum macrouri, typedefs, variabile şi funcţii.
  4. Puteţi folosi :tag foo pentru a sări la definiţia numelui foo.
  5. Poziţionaţi cursorul pe orice simbol şi apăsaţi ctrl-] pentru a sări la definiţia acelui simbol.
    • Apăsaţi ctrl-t pentru a vă întoarce în locul precedent.
  6. Folosiţi ctrl-w ] pentru a sări la definiţia simbolului întro fereastră divizată.
  7. Folosiţi :tnext, :tprev, :tfirst, :tlast pentru a parcurge listele de identificări ale tagului.

Observaţi că Exuberant Ctags suportă 33 de limbaje de programare la momentul acestei scrieri şi poate fi extins cu uşurinţă pentru alte limbaje.

A se citi :help taglist-intro pentru detalii.

cscope

Pentru a putea sări la definiţii indiferent de fişierul în care se află, avem nevoie de un program ca cscope. Totuşi, aşa cum sugerează chiar numele lui, acesta funcţionează numai pentru limbajul C.

cscope in action

  1. Instalaţi cscope. Citiţi :help cscope-info şi :help cscope-win32 referitor la instalare.
  2. Copiaţi cscope_maps.vim în directorul vostru ~/.vim/plugin/.
  3. Treceţi în directorul vostru de cod sursă şi rulaţi cscope -R -b pentru a construi (engl. ‘b’uild) recursiv (engl. ‘r’ecursively) o bază de date a tuturor subdirectoarelor.
  4. Restartaţi Vim şi deschideţi un fişier de cod sursă.
  5. Rulaţi :cscope show pentru a verifica dacă este creată o conexiune la cscope.
  6. Rulaţi :cscope find symbol foo pentru a găsi simbolul foo. Puteţi scurta comanda până la :cs f s foo.

Puteţi de asemenea:

  • Să găsiţi această definiţie – :cs f g
  • Să găsiţi funcţiile apelate de această funcţie – :cs f d
  • Să găsiţi funcţiile care apelează această funcţie – :cs f c
  • Să găsiţi acest şir – :cs f t
  • Să găsiţi această schemă egrep – :cs f e

A se citi :help cscope-suggestions pentru a afla utilizarea sugerată pentru cscope cu Vim.

Merită studiat şi pluginul Source Code Obedience întrucât acesta oferă scurtături simple pentru cscope/ctags.

Cât timp vorbim despre limbajul C, pluginul c.vim poate fi foarte util.

Compilarea

Am vorbit deja despre asta în capitolul precedent, referitor la :make pentru programele pe care le scriem, aşa că n-o să repetăm.

Scrierea uşoară

Omnicompletare

Una din cele mai solicitate facilităţi adăugate în versiunea Vim 7 este “omnicompletarea” în care textul poate fi completat automat, pe baza contextului curent. De exemplu, dacă folosiţi un nume lung pentru o variabilă în mod repetat, puteţi folosi o scurtătură pe tastatură pentru a cere lui Vim să completeze şi el îşi va da seama de restul.

Vim rezolvă asta folosind pluginuri ft, Mai precis pe acelea numite ftplugin/<language>complete.vim cum ar fi pythoncomplete.vim.

Să începem exemplificarea cu un mic program Python:

def hello():
    print 'hello world'

def helpme():
    print 'help yourself'

Omni-completion in action

După introducerea acestui program, introduceţi o linie nouă în acelaşi fişier, tastaţi ‘he’ şi apăsaţi ctrl-x ctrl-o ceea ce va arăta o listă cu sugestii de autocompletare.

Dacă obţineţi o eroare precum E764: Option 'omnifunc' nu este stabilită, rulaţi :runtime! autoload/pythoncomplete.vim pentru a încărca pluginul de omnicompletare.

Pentru a evita lansarea acestei comenzi de fiecare dată, puteţi adăuga următoarea linie în fişierul vostru ~/.vimrc:

autocmd FileType python runtime! autoload/pythoncomplete.vim

Vim foloseşte automat prima sugestie; puteţi trece la următoarea (engl. next) sau precedenta folosind ctrl-n respectiv ctrl-p.

Dacă vreţi să ieşiţi din lista de sugestii fără să selecţionaţi ceva apăsaţi esc.

Pentru a afla ce alte limbaje mai sunt suportate (C, HTML, JavaScript, PHP, Python, Ruby, SQL, XML, …) şi cum să vă creaţi propriile scripturi de autocompletare citiţi :help new-omni-completion.

Notă
Dacă vă convine mai mult să folosiţi tastele săgeţi pentru a parcurge lista de sugestii, citiţi pontul Vim 1228 despre cum se activează asta.

Eu prefer să folosesc un simplu ctrl-space în locul combinaţiei ctrl-x ctrl-o. Pentru asta pun în vimrc:

imap <c-space> <c-x><c-o>

În legătură cu asta, pluginul PySmell poate fi de ajutor utilizatorilor Vim care programează în Python.

Folosirea clişeelor

Clişeele de cod (engl. snippets) sunt mici porţiuni de cod pe care aveţi tendinţa să le scrieţi în mod repetat. Leneşi ca toţi programatorii buni, puteţi folosi un plugin să vă ajute. În cazul nostru, folosim minunatul plugin SnippetsEmu.

  1. Descărcaţi pluginul snippetsEmu.
  2. Creaţi directorul ~/.vim/after/ dacă nu există deja.
  3. Porniţi Vim cu acest plugin dat la linia de comandă. De exemplu, porniţi Vim cu comanda gvim snippy_bundles.vba
  4. Rulaţi :source%. ‘Arhiva Vim’ (engl. ‘vimball’) se va despacheta şi va stoca multiplele fişiere în directoare adecvate.
  5. Repetaţi pentru snippy_plugin.vba

Acum să încercăm să folosim acest plugin.

1. Deschideţi un fişier nou numit, să zicem, test.py.

2. Apăsaţi tastele d, e şi f şi apoi <tab>.

3. Voila! Pluginul snippetsEmu a creat deja o structură pentru funcţie. În fişier este următorul conţinut:

def <{fname}>(<{args}>):
    """
    <{}>
    <{args}>"""
    <{pass}>
    <{}>
Notă
În cazul în care vedeţi def<tab> şi nimic altceva nu se întâmplă, probabil că pluginul de clişee nu este încărcat.

Rulaţi :runtime! ftplugin/python_snippets.vim şi vedeţi dacă ajută.

4. Cursorul este acum poziţionat pe numele funcţiei, adică fname.

5. Introduceţi numele funcţiei, de exemplu test.

6. Apăsaţi <tab> şi cursorul se mută automat la argumente. <tab> din nou pentru a deplasa cursorul la următorul lucru de completat.

7. Acum introduceţi un comentariu: Zi salut!

8. <tab> din nou şi tastaţi print 'Hello World'

9. Apăsaţi <tab>

10. Programul este complet!

Acum ar trebui să aveţi în fişier:

def test():
    """
    Zi salut!
    """
    print 'Hello World'

Partea cea mai frumoasă este că SnippetsEmu pune în acţiune o convenţie standard şi nimeni nu o ‘uită’.

Crearea clişeelor

Hai să creăm propriile noastre clişee.

Să considerăm cazul în care tindem să scriem repetat următorul tip de cod în ActionScript3:

private var _foo:Object;

public function get foo():Object
{
    return _foo;
}

public function set foo(value:Object)
{
    _foo = value;
}

Este o combinaţie simplă pentru a seta/citi folosind o variabilă temporar. Problema este că este prea mult cod banal, de scris de multe ori. Să vedem cum se automatizează asta.

Pluginul de limbaje SnippetsEmu presupune că avem tagul de start st şi tagul de final et – acestea sunt la fel ca simbolurile tip săgeată între care de introducem codul.

Să începem cu un exemplu simplu.

exec "Snippet pubfun public function ".st.et.":".st.et."<CR>{<CR>".st.et."<CR>}<CR>"

Adăugaţi linia de mai sus în fişierul vostru ~/.vim/after/ftplugin/actionscript_snippets.vim.

Acum deschideţi un fişier nou, să zicem test.as scrieţi în el pubfun şi apăsaţi <tab>; o să vedeţi cum se schimbă în:

public function <{}>:<{}>
{

}

Cursorul va fi poziţionat pe numele funcţiei; <tab> pentru a introduce tipul valorii returnate de funcţie, <tab> din nou pentru a scrie corpul funcţiei.

Întorcându-ne la problema iniţială, eu am găsit:

exec "Snippet getset private var _".st."name".et.";<CR><CR>public function get ".st."name".et."():".st."type".et."<CR>{<CR><tab>return _".st."name".et.";<CR>}<CR><CR>public function set ".st."name".et."(value:".st."type".et.")<CR>{<CR><tab>_".st."name".et." = value;<CR>}<CR>"
Notă
Toate clişeele pentru acest plugin trebuie introduse pe o singură linie. Este o limitare tehnică.

Urmaţi aceeaşi procedură ca mai sus pentru a folosi acest nou clişeu:

1. Adăugaţi linia aceasta în fişierul ~/.vim/after/ftplugin/actionscript_snippets.vim.

2. Deschideţi un fişier nou precum test.as.

3. Introduceţi getset şi apăsaţi <tab>; veţi vedea următoarele:

private var _<{name}>;

public function get <{name}>():<{type}>
{
        return _<{name}>;
}

public function set <{name}>(value:<{type}>)
{
        _<{name}> = value;
}

4. Tastaţi color şi apăsaţi <tab>. Observaţi că numele variabilei color este înlocuit peste tot.

5. Tastaţi Number şi tastaţi <tab>. Codul arată acum astfel:

private var _color;

public function get color():Number
{
        return _color;
}

public function set color(value:Number)
{
        _color = value;
}

Observaţi cât de mult s-a redus numărul de caractere tastate! Am înlocuit scrierea a 11 rânduri de cod banal cu o singură linie de script Vim.

Putem continua să adăugăm clişee pentru a face codarea mai uşoară pentru leneşi, ca să ne permită să ne concentrăm pe adevărata muncă de software.

A se citi :help snippets_emu.txt pentru mai multe detalii (acest fişier help va fi disponibil numai după instalarea pluginului).

IDE

Vim poate fi folosit ca IDE cu ajutorul câtorva pluginuri.

Pluginul project

Pluginul project este folosit pentru a crea un mod de a folosi Vim ca manager de proiect.

  1. Descărcaţi pluginul project.
  2. Dezarhivaţi-l în directorul vostru ~/.vim/.
  3. Rulaţi :helptags ~/.vim/doc/.
  4. Descărcaţi codul sursă Vim de la http://www.vim.org/subversion.php
  5. Rulaţi :Project. O bară laterală (engl. sidebar) se va deschide în stânga şi va funcţiona ca o fereastră ‘project’.
  6. Rulaţi \c (backslash urmat de ‘c’)
  7. Daţi răspunsuri pentru opţiunile următoare
    • Name of entry (rom. denumire), să zicem ‘vim7_src’
    • Director, să zicem C:\repo\vim7\src\
    • Opţiunea CD, la fel ca directorul de mai sus
    • Opţiunea de filtrare, să zicem *.h *.c
  8. Veţi vedea sidebarul umplut cu lista fişierelor din directorul specificat care trec prin filtrul specificat.
  9. Folosiţi tastele săgeţi sau tastele j/k pentru a parcurge lisra de fişiere, iar pentru a deschide fişierul curent apăsaţi tasta enter.

Astfel obţineţi un fel de interfaţă familiară, de tip IDE, partea bună este că nu există fişiere de configurare cu fiţe sau setări de cale rigide care apar mereu în IDE-uri. Funcţionalitatea pluginului project este simplă şi directă.

Puteţi folosi comenzile standard de pliere pentru a închide/deschide proiectele şi detaliile lor.

De ademenea puteţi rula scripturi la începerea şi încheierea utilizării unui proiect; astfel se simplifică setarea adecvată a variabilei PATH sau opţiunile de compilare, etc.

A se vedea :help project.txt pentru mai multe detalii.

Runlarea de cod din text

Puteţi rula cod direct din Vim folosind pluginuri precum EvalSelection.vim sau mai simple, precum inc-python.vim.

Integrarea cu SCM

Dacă începeţi să editaţi un fişier, puteţi să faceţi asta cu verificare automată din Perforce folosind pluginul perforce. Similar, există un plugin de integrare cu CVS/SVN/SVK/Git.

Plus

Pentru a explora mai multe pluginuri care implementează un mediu tip IDE în Vim, citiţi:

Există multe pluginuri de limbaj care vă permit să faceţi chestii mişto. De exemplu, pentru Python, pot fi utile următoarele pluginuri:

  • SuperTab vă permite să activaţi omni-completarea apăsând pur şi simplu tab, apoi să alegeţi opţiunile folosind tastele săgeţi.
  • python_calltips vă arată o fereastră în partea de jos în care aveţi o listă de completări posibile. Frumuseţea acestui mod de lucru faţă de omni-completarea standard este că puteţi vedea documentaţia pentru fiecare din aceste posibilităţi.
  • VimPdb vă ajută să depanaţi programe Python în Vim.

Scrierea propriilor pluginuri

Vă puteţi scrie propriile pluginuri pentru a extinde Vim în ce direcţie vreţi. De exemplu, puteţi considera următoarea sarcină:

Scrieţi un plugin Vim care ia cuvântul curent şi deschide o fereastră de browser cu documentaţia pentru un anumit cuvânt(care poate fi numele unei funcţii sau clase, etc.).

Dacă chiar nu puteţi găsi o abordare a acestei probleme, aruncaţi o privire la pontul “Online documentation for word under cursor” din wikiul Vim Tips.

Am extins acelaşi tip şi l-am făcut mai generic:

" Adăugaţi următoarele linii la ~/.vimrc pentru a activa  documentaţia online
" Inspiraţie: 
" http://vim.wikia.com/wiki/Online_documentation_for_word_under_cursor

function Browser()
    if has("win32") || has("win64")
        let s:browser = "C:\Program Files\Mozilla Firefox\firefox.exe -new-tab"
    elseif has("win32unix") " Cygwin
        let s:browser = "'/cygdrive/c/Program Files/Mozilla Firefox/firefox.exe' -new-tab"
    elseif has("mac") || has("macunix") || has("unix")
        let s:browser = "firefox -new-tab"
    endif

    return s:browser
endfunction

function Run(command)
    if has("win32") || has("win64")
        let s:startCommand = "!start"
        let s:endCommand = ""
    elseif has("mac") || has("macunix") " TODO Untested on Mac
        let s:startCommand = "!open -a"
        let s:endCommand = ""
    elseif has("unix") || has("win32unix")
        let s:startCommand = "!"
        let s:endCommand = "&"
    else
        echo "Don't know how to handle this OS!"
        finish
    endif

    let s:cmd = "silent " . s:startCommand . " " . a:command . " " . s:endCommand
    " echo s:cmd
    execute s:cmd
endfunction

function OnlineDoc()
    if &filetype == "viki"
        " Dictionary
        let s:urlTemplate = "http://dictionary.reference.com/browse/<name>"
    elseif &filetype == "perl"
        let s:urlTemplate = "http://perldoc.perl.org/functions/<name>.html"
    elseif &filetype == "python"
        let s:urlTemplate = "http://www.google.com/search?q=<name>&domains=docs.python.org&sitesearch=docs.python.org"
    elseif &filetype == "ruby"
        let s:urlTemplate = "http://www.ruby-doc.org/core/classes/<name>.html"
    elseif &filetype == "vim"
        let s:urlTemplate = "http://vimdoc.sourceforge.net/search.php?search=<name>&docs=help"
    endif

    let s:wordUnderCursor = expand("<cword>")
    let s:url = substitute(s:urlTemplate, '<name>', s:wordUnderCursor, 'g')

    call Run(Browser() . " " . s:url)
endfunction

noremap <silent> <M-d> :call OnlineDoc()<CR>
inoremap <silent> <M-d> <Esc>:call OnlineDoc()<CR>a

Accesarea bazelor de date

Puteţi chiar să comunicaţi cu vreo 10 baze de date diferite, de la Oracle la MySQL şi PostgreSQL sau Sybase şi SQLite, toate din Vim, folosind pluginul dbext.vim. Ce e mai minunat despre asta este că vă ajută să editaţi SQL scris în PHP, Perl, Java, etc. şi puteţi chiar să executaţi interogările SQL deşi sunt implantate în alt limbaj de programare şi chiar vă poate cere valorile pentru variabile.

Rezumat

Am învăţat cum poate fi folosit Vim pentru programare cu ajutorul unor setări şi pluginuri. Dacă avem nevoie de o facilitate, se poate rezolva prin scrierea unor pluginuri (aşa cum am discutat în capitolulScriptare).

O sursă bună de discuţii pe acest subiect se poate găsi la Stack Overflow şi pe blogul lui Peteris Krumins.


Advertisements