Hlavní navigace

Vim sedm - druhá část

28. 6. 2005
Doba čtení: 10 minut

Sdílet

V dnešním článku dokončíme popis nejvýznamnějších nových vlastností sedmé verze textového editoru Vim. Podrobně si popíšeme nové vlastnosti skriptovacího jazyka, zejména význam všech nových datových typů a na ně navazujících rozšířených jazykových konstrukcí. Nebude chybět ani zhodnocení paměťových nároků a rychlosti práce nové verze v porovnání s verzí předchozí.

Obsah

1. Rozšíření skriptovacího jazyka Vimu

2. Nové operátory
3. Datový typ LIST (seznam)
    3.1 Vytvoření seznamu
    3.2 Přístup k prvkům seznamu
    3.3 Spojování seznamů
    3.4 Zjednodušený průchod seznamem

4. Datový typ DICTIONARY (slovník)
    4.1 Vytvoření slovníku
    4.2 Přístup k prvkům slovníku
    4.3 Zjednodušený průchod slovníkem
5. Datový typ FUNCREF
6. Další změny a rozšíření oproti starším verzím Vimu

    6.1 Odlišné chování příkazu :helpgrep
    6.2 Nový příkaz :vimgrep
    6.3 Podpora pro prostředí KDE – KVim
    6.4 Podpora interpretačního funkcionálního jazyka MzScheme
7. Paměťové nároky a rychlost nové verze

8. Závěr

1. Rozšíření skriptovacího jazyka Vimu

Skriptovací jazyk Vimu má oproti minulým verzím několik zásadních vylepšení. Tato vylepšení spočívají zejména ve vytvoření nových datových typů, přidání dalších řídicích struktur a funkcí pro práci s novými datovými typy a také v rozšíření repertoáru základních operátorů. Nejprve se podívejme na rozšiřující operátory zabudované ve skriptovacím jazyku.

2. Nové operátory

Mezi základní operátory (známé i z předchozích verzí) patří operátory matematické (+, -, *, / a %), logické (!, &&, ||), relační (==,

!=, >, >=, < a <=) řetězcové (., =~, !~, ==? a

==#) a ternární operátor ? : . K těmto operátorům se v nové verzi Vimu přidávají ještě „zkrácené“ verze některých operátorů, které by původně na své pravé i levé straně měly stejnou proměnnou. Mezi nové operátory, které jsou jistě programátorům v C, C++ a Javě povědomé, patří:

+= – zkrácený operátor nahrazující matematický výraz a=a+b

-= – zkrácený operátor nahrazující matematický výraz a=a-b

= – zkrácený operátor nahrazující matematický výraz a=ab

/= – zkrácený operátor nahrazující matematický výraz a=a/b

.= – zkrácený operátor nahrazující výraz a=a.b, což je konkatenace (spojení) řetězců

Následují příklady použití těchto operátorů:

:let a=10
:let a+=1
:echo a

:let pozdrav="Hello"
:let svet="World"
:let pozdrav.=" ".svet
:echo pozdrav 

(všimněte si, že – alespoň prozatím – neexistují operátory typu ++ a , proto také není možné výraz :let a+=1 zkrátit)

3. Datový typ LIST (seznam)

Nové operátory do vlastního jazyka prakticky nepřinesly žádnou výraznější změnu, pouze zjednodušení zápisu některých výrazů. Naproti tomu nové datové typy skriptovací jazyk Vimu posunují o několik pomyslných příček výše. Pokud by k těmto novým datovým typům byly do jazyka přidány i objekty, byl by skriptovací jazyk Vimu srovnatelný s takovými jazyky, jako jsou například Python či Ruby.

3.1 Vytvoření seznamu (slovník)

Prvním přidaným datovým typem je seznam neboli List. V pojetí Vimu se seznam chová podobně jako v programovacím jazyku Lisp či Scheme, tj. do seznamu lze vkládat buď přímo atomy (tj. základní datové typy včetně řetězců), nebo další seznamy, a vytvářet tak poměrně komplikované hierarchizované datové struktury (v Lispu lze do seznamu zapsat i celý program či funkci, to prozatím ve Vimu není možné). Jednoduchý seznam lze vytvořit například následujícím příkazem (konstruktorem):

:let seznam1=[1, 2, 3]
:echo seznam1 

V seznamu lze samozřejmě kombinovat jednotlivé datové typy Vimu:

:let two=2
:let seznam2=[1, two, "3", "čtyři"]
:echo seznam2 

Seznam složený z jiných seznamů se vytvoří následujícím konstruktorem (opět si všimněte podobnosti s Lispem):

:let seznam3=[[11, 12, 13] , [21, 22, 23], [31, 32, 33]]
:echo seznam3 

3.2 Přístup k prvkům seznamu

K prvkům seznamu se přistupuje pomocí takzvaného selektoru, který se zapisuje jako index v hranatých závorkách, podobně jako pole v C-čku, Pascalu a dalších programovacích jazycích. První prvek seznamu má nulový index, další prvek má index rovný jedničce atd. Pokud je seznam složený z více seznamů (tj. nějaký prvek seznamu je opět tvořen seznamem), používá se indexace pomocí dvou indexů, z nichž každý musí být umístěn v samostatných hranatých závorkách. „Nejlevější“ index přitom ovlivňuje výběr prvku z nejvýše postaveného seznamu v hierarchii. Práce s prvky seznamu tedy může vypadat následovně:

:let prvni=seznam1[0]
:echo prvni

:let seznam2[1]="pokus"
:echo seznam2

:echo seznam3[2][2] 

Pokud nastane při indexaci chyba, tj. indexuje se neexistující prvek (například při průchodu seznamem pomocí smyčky), vypíše Vim chybové hlášení list index out of range a ukončí provádění dalších příkazů. Při psaní skriptů je však výhodnější, aby si skript sám otestoval, zda k seznamu opravdu přistupuje korektním způsobem. K „bezpečnému“ přístupu k prvkům seznamu je možné použít novou funkci get(), která v případě, že se přistoupí k indexu mimo povolený rozsah, vrátí nulovou hodnotu. Prvním parametrem funkce get() je proměnná typu seznam, druhým parametrem je index:

:echo "Indexy v zadaném rozsahu"
:echo get(seznam1, 1)
:echo get(seznam1, 2)

:echo "Indexy mimo rozsah"
:echo get(seznam1,-1)
:echo get(seznam1, 4) 

3.3 Spojování seznamů

Pro spojení dvou seznamů je rozšířena funkce operátoru +. Seznamy jsou spojeny tak, že se zřetězí všechny jejich prvky na nejvyšší úrovni. V případě, že je některým prvkem seznamu další seznam, není spojením ovlivněn. Vyzkoušejte si operaci spojení seznamů na následujících příkladech:

:echo [1,2]+[3,4]
:let seznam1=[1, 2, 3]
:let seznam2=["3", "4", "5"]
:let seznam3=[[11, 12, 13] , [21, 22, 23], [31, 32, 33]]
:let spojeni=seznam1+seznam2+seznam3
:echo spojeni 

3.4 Zjednodušený průchod seznamem

Seznamem je samozřejmě možné procházet pomocí počítané smyčky, například následujícím způsobem:

:let seznam1=[1,2,3,4]
:let i=0
:while i<4
:    echo seznam1[i]
:    let i+=1
:endwhile 

To však není nejlepší řešení, protože se musí složitě (například pomocí globálních proměnných) hlídat počet prvků v seznamu, musí se správně pracovat s čítačem smyčky apod. Vim zde nabízí mnohem lepší řešení, které je používáno i v mnoha dalších vyšších programovacích jazycích. Jedná se o smyčku typu for – endfor, která projde všemi prvky seznamu – význam této smyčky je tedy odlišný od podobně nazvaných C-čkovských smyček. Výše uvedená smyčka while – endwhile se dá přepsat následovně:

:for item in [1,2,3,4]
:    echo item
:endfor 

4. Datový typ DICTIONARY

Pod datovým typem slovník (dictionary) se ve Vimu neskrývá nic jiného než asociativní pole, které je známé i z dalších programovacích jazyků. Malým omezením vimovsky pojatého asociativního pole je skutečnost, že klíčem musí být vždy řetězec, což poněkud komplikuje přístup k jednotlivým prvkům. V následujících podkapitolách si ukážeme, jakým způsobem se dá se slovníky (asociativními poli) ve skriptech manipulovat.

4.1 Vytvoření slovníku

Slovník se jednoduše vytvoří pomocí konstruktoru, který musí splňovat následující schéma, v němž se postupně naplňují jednotlivé hodnoty i se svými klíči (klíč musí být vždycky reprezentován řetězcem, pokud tomu tak při zápisu konstruktoru není, je klíč na řetězec převeden):

{"klíč1":hodnota1, "klíč2":hodnota2} 

Příklad použití:

:let as1={"one":1, "two":2, "three":3}
:echo as1 

4.2 Přístup k prvkům slovníku

Přístup k jednotlivým prvkům uloženým ve slovníku je podobný jako v případě seznamů, pouze se místo číselného indexu použije klíč ve formě řetězce. Kromě toho je podporována i takzvaná tečková notace, kdy se před tečku zapíše jméno slovníku a za tečku klíč bez uvozovek – slovník se potom ve své podstatě chová jako strukturovaný datový typ záznam (record, struct). Příklad použití obou možností přístupu k prvkům slovníku:

:let as1={"one":1, "two":2, "three":3}
:echo as["one"]
:echo as.one

:let id={"jmeno":"Johanka", "prijmeni":"Doležalová"}
:echo id.jmeno
:echo id["prijmeni"] 

Klíč může obsahovat i české znaky, potom však nelze selektor použít ve formě tečkové notace, protože by se tím porušila syntaktická pravidla skriptovacího jazyka.

4.3 Zjednodušený průchod slovníkem

To, že je klíčem ve slovníku řetězec, poněkud zmenšuje možnosti průchodu celým slovníkem, protože nelze jednoduše využít počítané smyčky tak, jak tomu bylo u seznamů. Vim však obsahuje novou funkci keys(), která vrací všechny klíče ve slovníku ve formě seznamu řetězců. Potom je možné smyčku pro průchod slovníkem napsat například následujícím způsobem:

:for key in keys(id)
:    echo id[key]
:endfor 

Jak je z předchozího příkladu patrné, nejprve se převedou všechny klíče na seznam a poté se využije výše popsaná smyčka for – endfor, která slouží k průchodu seznamem.

5. Datový typ FUNCREF

Posledním přidaným datovým typem je reference na funkce. Jeho použití si ukážeme na jednoduché funkci Pocitej(), která může vypadat například následovně:

:function Pocitej()
:    let i=0
:    while i<10
:        let i+=1
:        echo i
:    endwhile
:endfunction 

Tuto funkci je samozřejmě možné zavolat a spustit, například příkazem:

:call Pocitej 

Na tuto funkci je také možné vytvořit referenci pomocí jazykové konstrukce function. Tato jazyková konstrukce vyžaduje, aby jí byl předložen název funkce ve formě řetězce. Vrací se reference na danou funkci. V případě, že funkce s daným jménem neexistuje, je vypsáno chybové hlášení a běh skriptu se ukončí. Reference na funkci může zastupovat jméno funkce, jak je patrné například z následujícího příkladu:

:let Fn=function("Pocitej")
:call Fn() 

Podobně jako názvy funkcí musí i názvy referencí začínat velkým písmenem.

6. Další změny a rozšíření oproti starším verzím Vimu

Kromě integrovaného spelleru popsaného v předchozí části tohoto seriálu a značných rozšíření skriptovacího jazyka má sedmá verze několik dalších rozšíření, která budou stručně popsána v následujících podkapitolách.

6.1 Odlišné chování příkazu :helpgrep

Příkaz :helpgrep slouží k vyhledání řetězce v nápovědě. V šesté verzi Vimu se tento příkaz chová tak, že po nalezení řetězce vypíše text nápovědy do aktivního okna, a dokument, který se v okně nacházel, je tak přesunut do neviditelného bufferu. K zobrazení zdánlivě „ztraceného“ textu je zapotřebí vyvolat příkaz :bnext. Toto chování neodpovídá filozofii nápovědy, která by neměla ovlivňovat editovaný text. Proto se v sedmé verzi Vimu chová příkaz :helpgrep tak, že pro zobrazení svého výstupu si otevře nové okno, stejně jako příkaz :help.

6.2 Nový příkaz :vimgrep

Do sedmé verze Vimu je nově zařazen příkaz :vimgrep, který dělá ve své podstatě to samé jako utilita grep. Rozdíl je v tom, že se :vimgrep vyvolává rychleji a své výsledky může přímo ukládat do rozpracovaného dokumentu. Tento příkaz je také možné použít na systémech, které utilitu grep implicitně neobsahují (například DOS či Microsoft Windows). Při nalezení většího množství výskytů hledaného výrazu je možné se mezi výskyty pohybovat pomocí příkazů :cn a :cp (je velmi vhodné si tyto výrazy namapovat na jednoduššeji zapamatovatelné klávesové zkratky, například na F3 a F4, protože se využijí například i při výpisu chyb při překladu aplikací).

6.3 Podpora pro prostředí KDE – KVim

Některé uživatele jistě potěší informace, že nový Vim nativně podporuje prostředí KDE, tj. uživatelské rozhraní může být alternativně vytvářeno pomocí knihovny Qt. Povolení či zákaz integrace s KDE se provede při překladu Vimu. Alternativně je stále možné používat verzi Vimu pro GTK+, Gnome, Motif nebo pro Athenu.

6.4 Podpora interpretačního funkcionálního jazyka MzScheme

Velmi zajímavým rozšířením Vimu je podpora interpretačního jazyka MzScheme – tímto se totiž Vim začíná přibližovat Emacsu, který je založen na dialektu jazyka Lisp (Emacs je ve skutečnosti s Lispem spjat více než Vim s jakýmkoli skriptovacím jazykem). K dispozici jsou tři možnosti, jak skripty napsané v MzScheme vyvolat. Buď se přímo vyvolá nějaká funkce pomocí příkazu:

:mzscheme funkce 

Druhá možnost, která se dá využít při kombinaci s vimovými skripty, využívá toho, že se dá načítat text až do předem specifikovaného označení konce textu (jde o řetězec). K tomu se používá příkaz:

:mzscheme << endmarker 

Příklad použití výše uvedeného příkazu:

function s:MzStartup()
    if has("mzscheme")
        au BufNew,BufNewFile,BufAdd,BufReadPre * :call s:MzRequire()
        :mz << EOF
        (current-library-collection-paths
            (cons
                (build-path (find-system-path 'addon-dir) (version) "collects")
                (current-library-collection-paths)))
EOF
    endif
endfunction

call s:MzStartup() 

Poslední možností je specifikace souboru, ve kterém se funkce napsané v MzScheme nacházejí. Tato možnost je využitelná zejména při práci s rozsáhlejšími skripty:

:mzfile fileName 

V současné alfa verzi Vimu není MzScheme podporováno, v ostré verzi by však měla být plná podpora již hotova.

7. Paměťové nároky a rychlost nové verze

Pro porovnání paměťových nároků šesté a sedmé verze Vimu jsem použil geniální makro pro generování Mandelbrotovy množiny, které vytvořil Linus Akesson. Toto makro je k dispozici ke stažení. Porovnával jsem běh tohoto makra ve verzi 6.2 a verzi 7.0 (obě přeložené pomocí překladače GCC 3.2). Přitom jsem odstranil (resp. přejmenoval) konfigurační soubor .vimrc, aby nedošlo k ovlivnění měření nastavením mapování, více úrovněmi operace undo atd. Výsledky měření jsou zajímavé a ukazují, že nový Vim sice potřebuje k běhu více paměti, ale zato je nepatrně rychlejší. Níže zveřejněné výsledky je samozřejmě nutné pouze porovnat mezi sebou, absolutní hodnoty samy o sobě žádnou vypovídací schopnost nemají; z téhož důvodu neuvádím ani platformu a konfiguraci HW, na které měření probíhalo. Důležité však je, že se nový Vim vůči starší verzi výrazně nezpomalil ani nemá mnohem vyšší paměťové nároky:

root_podpora

Vim 7
Verze Vimu Paměťové nároky Čas běhu makra M-set
Vim 6.2 3984 kB 11 min 17 sec
Vim 7.0 4580 kB 10 min 14 sec

8. Závěr

V tomto článku jsem uvedl nejzajímavější novinky sedmé verze textového editoru Vim. Plná verze sice ještě není k dispozici, ale dostupná alfa verze je již dostatečně stabilní, a tak ji lze používat i pro běžnou práci (kéž by byly finální verze některých produktů tak stabilní jako alfa verze Vimu :-). Malé problémy však může způsobit fakt, že pro alfa verzi nejsou k dispozici přeložené a připravené balíčky (typu RPM, Windows Installer atd.), uživatel si musí stáhnout zdrojové kódy a sám provést překlad, a to včetně slovníků.

Byl pro vás článek přínosný?

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.