Obsah
1. Pluginy využívající asynchronní volání ve Vimu
2. Podpora pro práci s datovým formátem JSON
5. Časovače: cesta k asynchronnímu kódu
6. Vytvoření a použití několika časovačů
8. Vytvoření kanálu a přenos dat
12. Instalace pluginu asyncrun
18. Okno terminálu (novinka ve Vimu 8.1)
1. Pluginy využívající asynchronní volání ve Vimu
Textový editor Vim, s nímž se na stránkách Rootu setkáváme poměrně pravidelně, je mezi mnoha uživateli oblíbený jak díky svému modálnímu způsobu ovládání, tak i kvůli tomu, že je ho možné nakonfigurovat přesně takovým způsobem, aby plně vyhovoval všem uživatelským požadavkům. Ovšem kromě toho nesmíme zapomenout ani na fakt, že pro Vim existuje velké množství modulů (pluginů), které možnosti tohoto editoru dále rozšiřují. Moduly lze naprogramovat jak v jazyku Vim Script (ten se prakticky objevil až v páté verzi), tak i například v Pythonu, Perlu či v programovacím jazyku Lua.
Obrázek 1: Jedna z prvních verzí Vimu 8.0 (tehdy ještě nebyla zařazena do prakticky žádné stabilní distribuce).
I přesto, že je dnes možné ve Vimu naprogramovat i velmi složité moduly, byly jejich možnosti v porovnání s plnohodnotnými IDE v jedné oblasti omezené – všechny skripty běžely (velmi zjednodušeně řečeno) ve stejném vláknu jako zbytek textového editoru. To v praxi znamenalo, že například při spuštění překladače musel uživatel čekat na dokončení překladu a teprve poté bylo možné pokračovat v editaci, popř. ve zkoumání chyb vypsaných během překladu do tzv. Quickfix window (okno s rychlým náhledem). Podobně tomu bylo i u dalších operací (vyhledávání, volání LSP atd. atd.). Situace se ovšem zásadně změnila právě ve Vimu 8, který přinesl hned několik nových technologií využitelných právě pro tvorbu mnohem lepších pluginů. Dnes se s těmito technologiemi postupně seznámíme a ukážeme si jejich použití na trojici prakticky využitelných pluginů nazvaných asyncrun, agrep a amake.
Obrázek 2: Konfigurační volby, s nimiž byl přeložen Vim 8.0.
2. Podpora pro práci s datovým formátem JSON
Na první pohled sice možná ne příliš výraznou, ale o to důležitější a užitečnější, novinkou je přidání čtyř nových funkcí do skriptovacího engine Vimu. Tyto čtyři funkce slouží pro převod datových struktur Vim Scriptu do formátu JSON a zpět. Proč je vlastně tato novinka tak důležitá? Souvisí totiž s další novou technologií, konkrétně s úlohami (jobs) a kanály (channels). Úlohy umožňují přesně definovaným způsobem vytvářet pluginy (i externí pluginy) s tím, že tyto pluginy mohou běžet asynchronně, tj. částečně nezávisle na samotném Vimu. Důležité je, že pluginy s Vimem komunikují právě přes JSON formát, což je pěkně navržené řešení, protože JSON je dnes podporovaný v prakticky všech relevantních programovacích jazycích, v nichž se externí pluginy většinou píšou (typicky se jedná o Python, ale lze použít i jazyk Lua apod.).
Obrázek 3: Nejdůležitější novinka ve Vimu 8 – příkaz :smile.
Obrázek 4: Příklad použití pluginu vim-lsp.
Skriptovací engine Vimu nabízí programátorům dvě funkce určené pro převod datových struktur do formátu JSON (encode) a dvě funkce určené pro parsování JSON dat do interních struktur Vim Scriptu (decode). Dvě varianty jsou implementovány z toho důvodu, že v některých případech je zapotřebí, aby byly klíče objektů (či slovníků) reprezentovány řetězci, a jinde se může jednat o identifikátory bez uvozovek (záleží na konkrétní situaci):
Funkce | Stručný popis |
---|---|
json_encode(výraz) | převod výrazu do JSON formátu, který se vrátí ve formě řetězce |
json_decode(řetězec) | opak předchozí funkce, parsování řetězce s daty uloženými v JSON formátu do interních datových struktur Vim Scriptu |
js_encode(výraz) | podobné funkci json_encode(), ovšem klíče nejsou umístěny v uvozovkách |
js_decode(řetězec) | podobné funkci json_decode(), ovšem při parsingu se nevyžaduje, aby byly klíče umístěny v uvozovkách |
Obrázek 5: Nápověda k funkcím js_encode a js_decode.
Ve Vim Scriptu existuje celkem deset datových typů, přičemž pět z těchto typů do jisté míry koresponduje s typy používanými ve formátu JSON (Number, Float, String, List a Dictionary) a dva další typy (Boolean, None) lze taktéž do formátu JSON převést, pokud se ovšem dodrží určitá pravidla. Výše zmíněné čtyři funkce json_encode(), json_decode(), js_encode() a js_decode() provádí převody mezi jednotlivými typy (resp. mezi hodnotami různých typů) zcela automaticky, ovšem existuje několik potenciálně problematických výjimek, kterými se budeme zabývat v navazujícím textu.
Obrázek 6: Serializace základních hodnot do JSONu.
V následující tabulce jsou vypsány korespondující datové typy. Povšimněte si, že v JSON formátu se nerozlišuje mezi celými čísly a čísly s plovoucí řádovou čárkou, což do značné míry souvisí s původním návrhem tohoto formátu založeném na JavaScriptu:
Typ ve Vim Scriptu | Převod do JSONu |
---|---|
Number | celé číslo |
Float | číslo s desetinnou čárkou a/nebo exponentem |
String | řetězec umístěný v uvozovkách |
List | pole hodnot |
Dictionary | objekt (asociativní pole) |
Funcref | nelze (teoreticky by se jednalo o serializaci kódu) |
Boolean | True/False |
None | Null |
Job | nelze |
Channel | nelze |
Převody mezi skalárními typy jsou ve většině běžných případů triviální, proto se podívejme, jakým způsobem je možné v JSON formátu reprezentovat složené datové typy Vim Scriptu. Prvním typem, s nímž se setká prakticky každý programátor používající Vim Script, je seznam (list), který je ovšem někdy taktéž nazýván vektorem (vector) či polem (array), což ale není zcela přesné. V následujícím příkladu je do JSON formátu převeden seznam čísel, dále seznam řetězců a dvě matice reprezentované seznamem seznamů. Povšimněte si, že ve Vim Scriptu je nutné při zápisu výrazu či příkazu na více řádků použít zpětné lomítko na začátku (nikoli na konci!) řádku, což je dosti neobvyklé:
let vector1 = [1, 2, 3] echo json_encode(vector1) let vector2 = ["Hello", "world", "!"] echo json_encode(vector2) let matrix1 = [[1,2,3], [4,5,6], [7,8,9]] echo json_encode(matrix1) let matrix2 = [[1,2,3], \ [4,5,6], \ [7,8,9]] echo json_encode(matrix2)
Obrázek 7: Výsledek spuštění předchozího skriptu s funkcí json_encode.
Samozřejmě můžeme namísto funkce json_encode() použít funkci js_encode(), která ovšem vytvoří shodný výsledek (prozatím totiž nepracujeme se slovníky):
let vector1 = [1, 2, 3] echo js_encode(vector1) let vector2 = ["Hello", "world", "!"] echo js_encode(vector2) let matrix1 = [[1,2,3], [4,5,6], [7,8,9]] echo js_encode(matrix1) let matrix2 = [[1,2,3], \ [4,5,6], \ [7,8,9]] echo js_encode(matrix2)
Obrázek 8: Výsledek spuštění předchozího skriptu s funkcí js_encode.
Nejsložitější datovou strukturou, kterou je možné do JSON formátu uložit (serializovat), jsou takzvané slovníky (dictionary, dict), které jsou v jiných programovacích jazycích nazývány hashe či asociativní pole. Právě u slovníků se projeví rozdíl mezi funkcemi json_encode() a js_encode(), a to konkrétně při serializaci klíčů. Rozdíly jsou shrnuty v následující tabulce:
Typ klíče | json_encode() | js_encode() |
---|---|---|
řetězec odpovídající názvu proměnné v JS | klíč je zapsán do uvozovek | klíč je zapsán bez uvozovek |
jiný řetězec (s mezerou, pomlčkou…) | klíč je zapsán do uvozovek | klíč je zapsán do uvozovek |
číslo | klíč je zapsán do uvozovek | klíč je zapsán do uvozovek |
jiný typ (seznam…) | nelze použít | nelze použít |
Název proměnné v JavaScriptu musí začínat písmenem, podtržítkem či znakem dolaru a musí obsahovat čísla, písmena (nikoli jen ASCII, možnosti jsou zde větší), dolary či podtržítka.
V následujícím příkladu je ukázáno, jak je možné do JSON formátu ukládat slovníky, slovníky se seznamy (hodnoty) či naopak seznam slovníků:
let dict1 = {"first": 1, "second" : 2, "third" : 3} echo json_encode(dict1) let dict2 = {1 : "first", 2 : "second", 3 : "third"} echo json_encode(dict2) let dict3 = {"first" : [1,2,3], "second" : [4,5,6]} echo json_encode(dict3) let vectorOfDicts = [ {"first" : 1, "second" : 2}, {"another" : "dictionary"}] echo json_encode(vectorOfDicts)
Obrázek 9: Výsledek spuštění předchozího skriptu s funkcí json_encode.
Pokud budeme shodné datové struktury serializovat funkcí js_encode(), budou se klíče ukládat rozdílným způsobem, ale pouze pro ty řetězce, které odpovídají jménům proměnných v JavaScriptu:
let dict1 = {"first": 1, "second" : 2, "third" : 3} echo js_encode(dict1) let dict2 = {1 : "first", 2 : "second", 3 : "third"} echo js_encode(dict2) let dict3 = {"first" : [1,2,3], "second" : [4,5,6]} echo js_encode(dict3) let vectorOfDicts = [ {"first" : 1, "second" : 2}, {"another" : "dictionary"}] echo js_encode(vectorOfDicts)
Obrázek 10: Výsledek spuštění předchozího skriptu s funkcí js_encode.
3. Anonymní funkce
Poměrně významnou novinkou Vimu 8, kterou nalezneme ve skriptovacím jazyku Vim Script, jsou takzvané anonymní funkce (někdy se setkáme s možná přiléhavějším názvem lambdy, což je označení vycházející z lambda kalkulu). Anonymní funkce je možné použít ve všech místech programového kódu, kde jsou očekávány takzvané reference na funkce (funcrefs, viz další kapitolu). Zápis anonymní funkce se v několika ohledech odlišuje od zápisu běžné funkce. Parametry i samotné tělo funkce jsou totiž umístěny do složených závorek {} a mezi parametry a tělem funkce se zapisuje dvojice znaků → (u parametrů se navíc nemusí používat prefix a:, který je u běžných funkcí vyžadován). Velmi jednoduchou anonymní funkci, která po svém zavolání vrátí součet svých dvou parametrů, lze zapsat takto:
{x,y -> x + y}
Obrázek 11: Nápověda k lambda výrazům (anonymním funkcím).
Volání takové funkce může vypadat například takto:
:echo {x,y -> x + y}(1,2)
nebo (díky přetíženému operátoru +):
:echo {x,y -> x + y}([1,2,3], [4,5,6])
popř: (výsledek vás může překvapit)
:echo {x,y -> x + y}("1", "2")
Obrázek 12: Zavolání anonymní funkce.
Obrázek 13: Výsledek zavolání anonymní funkce.
Alternativně lze anonymní funkci přiřadit do proměnné (a tak ji vlastně pojmenovat):
:let Fce={x,y -> x + y} :echo Fce(1,2) 3
4. Reference na funkce
V předchozí kapitole jsme se – prozatím bez dalšího hlubšího vysvětlení – setkali s termínem „reference na funkci“ což je název běžně zkracovaný na „funcref“. Nejedná se sice o nový koncept zavedený až ve Vimu 8, ale vzhledem k tomu, že se s referencemi na funkce setkáme i v několika dalších demonstračních příkladech, si stručně vysvětlíme, o co se vlastně jedná. Reference na funkci obsahuje, což asi není příliš překvapivé, odkaz na existující funkci (přičemž nás nezajímá, jak konkrétně je tento odkaz reprezentován) a lze ji považovat za plnohodnotný datový typ skriptovacího jazyka Vim Script. To mj. znamená, že reference na funkce lze ukládat do proměnných (globálních i lokálních) či je předávat do jiných funkcí (takzvaných funkcí vyššího řádu). Reference na existující funkci se získá zavoláním function(jméno_funkce), tedy například následujícím způsobem:
function! DoubleValue(index, value) return a:value * 2 endfunction let Funcref = function("DoubleValue")
Obrázek 14: Nápověda k datovému typu reference na funkce.
5. Časovače: cesta k asynchronnímu kódu
S anonymními funkcemi a referencemi na funkce (funcrefy) do jisté míry souvisí i další nová a velmi užitečná vlastnost Vimu 8. Jedná se o takzvané časovače (timers), které umožňují specifikovat, v jakém okamžiku se zavolá nějaká běžná či anonymní funkce. Důležité je, že tyto funkce jsou spouštěny asynchronně, tj. nezávisle na dalším běhu skriptu (a nezávisle na tom, jaké operace provádí uživatel!). Navíc je možné jednoduše specifikovat, kolikrát se má daná funkce zavolat, popř. je možné zajistit, aby se funkce volala periodicky až do ukončení běhu Vimu (to může být velmi užitečné, například u složitějších pluginů). Nový časovač se ve Vim Scriptu vytvoří zavoláním funkce nazvané příhodně timer_start(). Této funkci je nutné předat minimálně dva parametry: časový interval specifikovaný v milisekundách a anonymní funkci či funcref, která se má po uplynutí daného intervalu zavolat:
timer_start(interval, funcref či anonymní funkce)
Taktéž je možné do funkce timer_start() předat třetí nepovinný parametr, kterým je slovník obsahující další upřesnění funkce časovače. V současnosti je podporována jen jediná vlastnost – počet opakování (repeat) popř. specifikace periodického opakování volání funkce:
timer_start(interval, funcref či anonymní funkce, {'repeat':počet_opakování})
Periodické opakování používá magickou konstantu –1:
timer_start(interval, funcref či anonymní funkce, {'repeat':-1})
Funkce timer_start vrátí jednoznačný identifikátor právě vytvořeného časovače.
Příkladem použití může být snaha o zobrazení času na pravítku popř. na stavovém řádku. Pokus o pouhou změnu formátu pravítka ovšem nestačí, protože pravítko bude aktualizováno pouze tehdy, pokud uživatel bude provádět nějakou činnost (zjednodušeně: pokud bude mačkat klávesy):
set laststatus=2 set ruler set rulerformat=%55(%{strftime('%a\ %b\ %e\ %I:%M:%S\ %p')}\ %5l,%-6(%c%V%)\ %P%)
Díky existenci časovače je ovšem změna obsahu pravítka například každou sekundu snadná:
set laststatus=2 set ruler set rulerformat=%55(%{strftime('%a\ %b\ %e\ %I:%M:%S\ %p')}\ %5l,%-6(%c%V%)\ %P%) function! UpdateStatusBar(timer) execute 'let &ro=&ro' endfunction let timer = timer_start(1000, 'UpdateStatusBar',{'repeat':-1})
6. Vytvoření a použití několika časovačů
O tom, že je základní použití časovačů vlastně velmi jednoduché, se lze snadno přesvědčit prozkoumáním následujícího demonstračního příkladu, v němž jsou vytvořeny čtyři časovače volající uživatelskou funkci nazvanou PrintMessage. První časovač zavolá tuto funkci celkem šestkrát s periodou jedné sekundy, druhý časovač jedenkrát po 3,3 sekundách atd. Po spuštění tohoto skriptu sledujte zprávy vypisované do levého spodního rohu editoru:
" --------------------------------------------- " Vim8 example script - timers " " How to use it: " 1) start new Vim session " 2) open this script in it " 3) call :source % " --------------------------------------------- function! PrintMessage(message) echo a:message endfunction call PrintMessage("normal call") let timer1 = timer_start(1000, 'PrintMessage', {'repeat':6}) echo "timer" timer1 "created" let timer2 = timer_start(3300, 'PrintMessage') echo "timer" timer2 "created" let timer3 = timer_start(4400, 'PrintMessage') echo "timer" timer3 "created" let timer4 = timer_start(5500, 'PrintMessage') echo "timer" timer4 "created"
7. Kanály (channels)
Zcela novou technologií, s níž se můžeme setkat ve Vimu 8, je koncept takzvaných kanálů neboli channels. Kanály primárně slouží ke komunikaci mezi Vimem (resp. přesněji řečeno mezi Vim Scriptem) a externími pluginy, které jsou spuštěny v samostatném procesu. Textový editor Vim s těmito pluginy komunikuje buď s využitím socketů nebo roury (pipe). Pro přenos dat se typicky používá výše zmíněný formát JSON a proto jsou tak užitečné ty funkce, které jsme si popsali v předchozích kapitolách. Ve skutečnosti se mohou používat čtyři typy zpráv. Tyto typy jsou pojmenovány RAW, NL, JSON a JS, viz též následující tabulku:
Typ zprávy | Význam |
---|---|
RAW | obecný formát, s nímž Vim nijak speciálně nenakládá, pouze zprávu pošle či přijme |
NL | každá textová zpráva je ukončena znakem pro konec řádku (NL) |
JSON | formát JSON |
JS | formát JSON s klíči odpovídajícími JavaScriptu |
Samotné pluginy mohou pracovat ve čtyřech režimech:
Režim | Typ připojení | Popis |
---|---|---|
démon | socket | proces, ke kterému se může připojit více instancí Vimu |
úloha (job) | socket nebo pipe | proces, ke kterému se připojuje jedna instance Vimu (ten ho typicky i spustí) |
krátká úloha | socket nebo pipe | dtto jako předchozí, typicky však proces neběží po celou dobu existence Vimu |
filtr | pipe | spouští se synchronně, Vim čeká na výsledek operace |
8. Vytvoření kanálu a přenos dat
Nový kanál určený pro komunikaci s démonem či úlohou (viz tabulka uvedené v předchozí kapitole), se vytváří funkcí ch_open(). Například pro démona lokálně běžícího na stejném počítači a poslouchajícího na portu 1234 se použije tento příkaz:
let channel1 = ch_open("localhost:1234")
Jakmile je kanál vytvořen, lze démonu poslat nějaká data, a to konkrétně funkcí ch_evalexpr(kanál, data):
ch_evalexpr(channel1, "Hello daemon")
Pokud démon vrátí nějakou zprávu, je tato zpráva vrácena jako výsledek funkce ch_evalexpr():
let response = ch_evalexpr(channel1, "Hello daemon") echo response
Na konci skriptu je nutné kanál zavřít a uvolnit tak příslušný socket:
ch_close(channel1)
9. Úlohy (jobs)
Pro spuštění pluginů v samostatných procesech se používá nová funkce nazvaná job_start(). Tato funkce má jeden nepovinný parametr, kterým je příkaz pro spuštění (například cesta ke skriptu atd.). Nepovinným parametrem options je možné funkci job_start() předat způsob spuštění úlohy, například zda se mají pro komunikaci použít kanály či roury (pipy), jak dlouho se má čekat na dokončení volání (timeout) atd. Jakmile je úloha spuštěna, lze její stav zjistit zavoláním funkce job_status() vracející řetězec „run“, „fail“ (nepodařil se start) nebo „dead“ (start se podařil, nicméně úloha již skončila). Explicitní ukončení úlohy zajišťuje funkce pojmenovaná jednoduše job_stop(), které lze navíc v Linuxu předat signál pro ukončení: „term“, „hup“, „quit“ apod. A to nejdůležitější na konec: pokud se úloha spustila, je možné získat komunikační kanál funkcí job_channel() a následně použít techniku popsanou v předchozích třech kapitolách.
10. Využití synergie mezi všemi zmíněnými technologiemi: skutečně fungující asynchronně běžící skripty
Nyní již alespoň do určité míry známe všechny nové technologie, které je možné použít při tvorbě pluginů (přídavných modulů), které mají běžet asynchronně, tj. nezávisle na operacích prováděných uživatelem. Typicky si takto fungující pluginy připraví nějaké okno (Quickfix view atd.), do kterého postupně vypíšou informace získané při svém běhu. Asynchronně běžící pluginy bývají spuštěny přes časovač (kterému se předává funcref nebo anonymní funkce), pro komunikaci používají kanál (kanály) a vlastní komunikace typicky probíhá s využitím JSONu (i když to například u dále popsaných pluginů neplatí – ty totiž vykonávají poměrně jednoduché činnosti). Pojďme se tedy seznámit s trojicí praktických pluginů pojmenovaných jednoduše asyncrun, agrep a amake.
Obrázek 15: Nápověda k dále popsanému pluginu agrep.
11. Plugin asyncrun
První plugin, s nímž se v dnešním článku seznámíme, se jmenuje asyncrun. Název pluginu je to skutečně příhodný, protože tento přídavný modul slouží ke spuštění prakticky libovolného externího příkazu, jehož výsledek se následně objeví v quickfix okně. Pokud externí příkaz vypíše nějaké chyby, mohou být automaticky rozpoznány na základě volby errorformat (viz vestavěná nápověda :help errorformat) a bude možné použít standardní příkazy pro skok na předchozí resp. na následující chybu, což jsme si již ukázali v článku Textový editor Vim jako IDE (2.část). Důležité přitom je, že spuštěný externí příkaz může běžet relativně dlouho, ovšem uživatele to nijak neomezuje – ten může prakticky pokračovat v práci s textovým editorem. Po ukončení skriptu může být uživatel informován pípnutím (pokud jste si ovšem tuto možnost nevypnuli).
Obrázek 16: Volba errorformat je samozřejmě opět popsána v nápovědě.
Funkci tohoto pluginu pěkně ukazuje animovaný GIF, který naleznete na adrese https://raw.githubusercontent.com/skywind3000/asyncrun.vim/master/doc/screenshot.gif.
12. Instalace pluginu asyncrun
Před popisem instalace pluginu asyncrun se alespoň krátce zmiňme o další novince, kterou přinesl Vim 8. Jedná se o standardního správce balíčků.
Při instalaci většího množství pluginů prakticky vždy stojíme před závažným problémem – jak tyto pluginy instalovat či odinstalovat bez rozbití konfigurace ostatních pluginů? Jádro problému spočívá v tom, že v předchozích verzích Vimu (konkrétně od Vimu 5.0 do Vimu 7.x) byly cesty nastavené takovým způsobem, že se pluginy musely buď rozbalovat do společných adresářů (všechny nápovědy v jednom adresáři, všechny syntaktické soubory v dalším adresáři, skripty v adresáři třetím atd.) popř. bylo nutné použít některý správce pluginů – typicky Vundle či Pathogen. Ovšem situace, kdy se pro správu pluginů musel používat jiný plugin, byla … suboptimální :-). Z tohoto důvodu je ve Vimu 8 možné použít interního správce a postupně tak odstranit nutnost použití Vundle či Pathogenu. To ale nějaký čas potrvá, protože se musí stávající balíčky s pluginy upravit. Nicméně již dnes můžeme několik nových balíčků kompatibilních s Vimem 8 nalézt, popř. lze zkombinovat standardního správce s Vundlem či Pathogenem.
Obrázek 17: Nápověda ke standardnímu správci balíčků, který je součástí Vimu 8.
Při používání standardního správce balíčků z Vimu 8 je důležité, aby se pluginy po rozbalení umístily do správných adresářů, v nichž je bude Vim po svém spuštění a inicializaci hledat. Nejjednodušší je instalace pluginů pouze pro aktivního uživatele, protože v tomto případě je celá adresářová struktura umístěna v adresáři ~/.vim. V tomto adresáři musí být vytvořen podadresář nazvaný pack a v něm další podadresář s libovolným jménem (já jsem v příkladu použil podadresář nazvaný balicky, ale můžete použít i jiné označení):
[~/.vim]$ tree . └── pack └── balicky
Další dělení je jednoduché – v dalším podadresáři nazvaném opt jsou umístěny ty pluginy, které se mají načítat až na základě žádosti uživatele (optional), zatímco v podadresáři start budou umístěny ty pluginy, které se načtou a inicializují automaticky:
├── pack │ └── balicky │ ├── start │ └── opt
Nyní se tedy konečně dostáváme k tomu, jak nainstalovat balíček asyncrun. Ve Vimu 8 k tomu potřebujeme pouze použít Git a naklonovat si příslušný repositář do adresáře ~/.vim/pack/balicky/start:
cd ~/.vim/pack/balicky/start git clone https://github.com/skywind3000/asyncrun.vim
Výsledek by měl vypadat přibližně následovně:
. ├── autoload ├── doc ├── ftplugin ├── pack │ └── balicky │ └── start │ └── asyncrun.vim │ ├── doc │ │ ├── asyncrun.txt │ │ ├── cooperate_with_fugitive.gif │ │ ├── errormarker.jpg │ │ ├── screenshot.gif │ │ └── simple.png │ ├── LICENSE │ ├── plugin │ │ └── asyncrun.vim │ └── README.md ├── plugin ├── spell │ ├── cs.utf-8.add │ ├── cs.utf-8.add.spl │ ├── cs.utf-8.spl │ ├── en.utf-8.add │ └── en.utf-8.add.spl └── syntax
Po naklonování a restartu Vimu bude balíček připraven k použití.
13. Použití pluginu asyncrun
Praktické použití tohoto pluginu je ve skutečnosti velmi jednoduché. Postačuje totiž kromě standardního příkazu :! libovolný_externí_příkaz argumenty použít volání :Asyncrun libovolný_externí_příkaz argumenty. Zadaný externí příkaz se spustí asynchronně a jeho výstup se postupně přidává do okna quickfix. Aby byl výstup skutečně viditelný, nastavte si globální proměnnou g:asyncrun_open na nenulovou hodnotu – viz též následující screenshot:
Obrázek 18: Nastavení hodnoty globální proměnné g:asyncrun_open.
Chování tohoto pluginu je možné ovlivnit několika globálními proměnnými:
Proměnná | Význam |
---|---|
g:asyncrun_open | výška quickfix okna (zadaná v počtu řádků), do kterého se vypíše výstup skriptu |
g:asyncrun_bell | povolení či zákaz pípnutí po dokončení skriptu |
g:asyncrun_mode | režim spuštění skriptu (synchronní, asynchronní, přes příkaz :shell) |
g:asyncrun_exit | lze specifikovat skript/funkci spuštěnou po dokončení asynchronního skriptu |
g:asyncrun_encs | kódování výstupu asynchronně spuštěného skriptu |
Obrázek 19: Asynchronní spuštění skriptu ./build.sh.
14. Plugin agrep
Druhý plugin, s nímž se dnes ve stručnosti seznámíme, se jmenuje agrep. Opět se jedná o přiléhavý název, protože tento modul do značné míry nahrazuje příkazy :vimgrep a :grep. Navíc tento plugin zobrazuje výsledek vyhledání odlišným způsobem, který může být pro mnoho uživatelů čitelnější. Ostatně se sami podívejte na následující animovaný GIF, v němž jsou některé možnosti tohoto přídavného modulu ukázány. Na animaci je patrné, že vyhledávání skutečně probíhá asynchronně.
Obrázek 20: Nápověda k pluginu agrep.
Instalace pluginu agrep probíhá naprosto stejným způsobem, jako tomu bylo u předchozího pluginu Asyncrun:
cd ~/.vim/pack/balicky/start git clone https://github.com/ramele/agrep
Výsledná struktura adresáře .vim může vypadat následovně:
. ├── autoload ├── doc ├── ftplugin └── pack └── balicky └── start ├── agrep │ ├── doc │ │ └── agrep.txt │ ├── perl │ │ └── agrep.pl │ ├── plugin │ │ └── agrep.vim │ ├── README.md │ └── syntax │ ├── agrep.vim │ └── qf.vim └── asyncrun.vim ├── doc │ ├── asyncrun.txt │ ├── cooperate_with_fugitive.gif │ ├── errormarker.jpg │ ├── screenshot.gif │ └── simple.png ├── LICENSE ├── plugin │ └── asyncrun.vim └── README.md
15. Použití pluginu agrep
Tento plugin nabízí především příkaz Agrep, který akceptuje stejné argumenty, jako standardní grep:
:Agrep přepínače vzorek soubory/cesta
Například:
:Agrep -r requirements.txt .
nebo:
:Agrep -r 'foo.*bar' src/
Na následujícím screenshotu je ukázáno spuštění příkazu :Agrep nad celým domovským adresářem, což je samozřejmě potenciálně poměrně náročná operace. Nicméně nás doba trvání opět nemusí trápit, protože editor může být použitý i předtím, než celá operace doběhne:
Obrázek 21: Spuštění příkazu :Agrep nad celým domovským adresářem.
Vyhledávací proces postupně naplňuje okno s výsledky.
Obrázek 22: Výsledky vyhledání všech souborů „requirements.txt“.
Po vyhledání vzorků je možné použít další příkazy:
Příkaz | Význam |
---|---|
:Aopen | otevře okno s výsledky vyhledání (může se otevřít automaticky) |
:Aclose | opak předchozího; zavře okno s výsledky vyhledání |
:Anext | otevření souboru s dalším nalezeným textem |
:Aprev | otevření souboru s předchozím textem |
:Astop | dokáže zastavit vyhledávání (asynchronní proces) |
Nejjednodušší je ovšem přepnutí do okna s výsledky vyhledávání. Po stisku klávesy Enter se zobrazí ten soubor, na němž se nachází textový kurzor. Okno s výsledky vyhledávání však zůstane stále zobrazeno, takže se k výsledkům můžete kdykoli vrátit.
Obrázek 23: Okno s výsledky vyhledání všech řetězců „test“ v souborech umístěných v domovském adresáři.
16. Plugin amake
Poslední plugin, s nímž se dnes seznámíme, se jmenuje vim-amake, ovšem běžně je jeho jméno zkracováno na amake. Tento modul částečně supluje funkci modulu předchozího, a to z toho důvodu, že uživatelům nabízí dva nové příkazy: :Amake a :Agrep (opět). Tyto příkazy akceptují stejné přepínače, jako standardní příkazy :make a :grep.
Obrázek 24: Minimalisticky pojatá nápověda k pluginu amake.
Instalace tohoto pluginu je snadná a probíhá stejným způsobem, jako tomu bylo u předchozích dvou modulů:
cd ~/.vim/pack/balicky/start git clone https://github.com/edkolev/vim-amake
Nyní by měl celý adresář s pluginy vypadat takto:
. ├── autoload ├── doc ├── ftplugin ├── pack │ └── balicky │ └── start │ ├── agrep │ │ ├── doc │ │ │ └── agrep.txt │ │ ├── perl │ │ │ └── agrep.pl │ │ ├── plugin │ │ │ └── agrep.vim │ │ ├── README.md │ │ └── syntax │ │ ├── agrep.vim │ │ └── qf.vim │ ├── asyncrun.vim │ │ ├── doc │ │ │ ├── asyncrun.txt │ │ │ ├── cooperate_with_fugitive.gif │ │ │ ├── errormarker.jpg │ │ │ ├── screenshot.gif │ │ │ └── simple.png │ │ ├── LICENSE │ │ ├── plugin │ │ │ └── asyncrun.vim │ │ └── README.md │ └── vim-amake │ ├── autoload │ │ └── amake.vim │ ├── plugin │ │ └── amake.vim │ └── README.md ├── plugin ├── spell │ ├── cs.utf-8.add │ ├── cs.utf-8.add.spl │ ├── cs.utf-8.spl │ ├── en.utf-8.add │ └── en.utf-8.add.spl └── syntax
17. Použití pluginu amake
Tento plugin skutečně nabízí pouze dva nové příkazy, a to :Amake a :Agrep. Oba příkazy jsou spuštěny na pozadí, přičemž příkaz :Amake po svém dokončení pouze vypíše „Success: make“ popř. zobrazí standardní chybové okno s informaci o tom, proč se překlad popř. slinkování nepovedlo (podobně pracuje i příkaz :make). Druhý podporovaný příkaz :Agrep používá quickfix okno, podobně jako oba dva pluginy popsané v předchozích kapitolách.
Obrázek 25: Spuštění příkazu :Amake.
Obrázek 26: Dokončení překladu a slinkování projektu.
Obrázek 27: Příkaz :Amake samozřejmě akceptuje i parametry, které jsou předány utilitě make.
18. Okno terminálu (novinka ve Vimu 8.1)
Na tomto místě je vhodné upozornit na to, že do Vimu verze 8.1 byla přidána další velmi užitečná pomůcka, jejíž interní funkcionalita je zajištěna právě schopností nového Vimu spustit asynchronní kód. Jedná se o schopnost Vimu 8.1 přímo na ploše svého okna spustit terminál s prakticky libovolným příkazem, ať již se jedná o neinteraktivní skript (například onen make nebo grep), tak o interaktivní aplikaci. Možnosti terminálu spuštěného uvnitř Vimu asi nejlépe vyniknou na tomto screenshotu, v němž je okno Vimu rozděleno na tři oblasti: terminál s běžícím debuggerem gdb, oblast se spuštěním debuggeru atd. a v pravé části pak editovaný a laděný zdrojový kód. Povšimněte si, že v pravé oblasti je dokonce zobrazen i breakpoint (červená značka) a řádek, který je právě laděn při krokování v debuggeru. Podobně si samozřejmě můžete spustit i další nástroje, například interaktivní merge v Gitu atd. atd.
19. Odkazy na Internetu
- Vim – the editor
http://www.vim.org/ - Vim 8.0 is released
https://laravel-news.com/2016/09/vim-8–0-is-released/ - Vim: So long Pathogen, hello native package loading
https://shapeshed.com/vim-packages/ - Asynchronous grep plugin for Vim
https://github.com/ramele/agrep - Run Async Shell Commands in Vim 8.0 / NeoVim and Output to Quickfix Window
https://github.com/skywind3000/asyncrun.vim - :smile command was not backported! #5116
https://github.com/neovim/neovim/issues/5116 - Run :make and :grep in background jobs (experimental)
https://github.com/edkolev/vim-amake - Favorite vim plugins
http://sherifsoliman.com/2016/05/30/favorite-vim-plugins/ - Makejob
http://www.vim.org/scripts/script.php?script_id=5479 - Články o Vimu na Root.cz:
http://www.root.cz/n/vim/clanky/ - Vim sedm – první část
http://www.root.cz/clanky/vim-sedm-prvni-cast/ - vim (man page)
http://www.linux-tutorial.info/modules.php?name=ManPage&sec=1&manpage=vim - History of the Text Editor
http://vanstee.me/history-of-the-text-editor.html - Interview with Bill Joy
http://web.cecs.pdx.edu/~kirkenda/joy84.html - vi Editor Commands
http://www.cs.rit.edu/~cslab/vi.html#A1.4 - vi Manual
http://www.cs.fsu.edu/general/vimanual.html - Mastering the Vi Editor
http://www.susnet.uk/mastering-the-vi-editor - Vim as a Python IDE, or Python IDE as Vim
http://blog.jetbrains.com/pycharm/2013/06/vim-as-a-python-ide-or-python-ide-as-vim/ - Vi Improved
https://wiki.python.org/moin/Vim - Popis skriptu Vim Pathogen
http://www.vim.org/scripts/script.php?script_id=2332 - Posledníverze skriptu Vim Pathogen
https://tpo.pe/pathogen.vim - Nejlepší pluginy pro Vim
http://vimawesome.com/ - Nejlepší pluginy pro Vim
http://www.vim.org/scripts/script_search_results.php?order_by=rating - Building Vim
http://vim.wikia.com/wiki/Building_Vim - Vim plugins for developers
http://www.linuxtoday.com/upload/vim-plugins-for-developers-140619094010.html - Writing Vim Plugins
http://stevelosh.com/blog/2011/09/writing-vim-plugins/ - how to understand this vim script?
http://stackoverflow.com/questions/12625091/how-to-understand-this-vim-script - Novinky ve VIM 7: Skriptovací jazyk
http://www.root.cz/vim-sedm-druha-cast/ - DirDiff.vim : A plugin to diff and merge two directories recursively.
http://www.vim.org/scripts/script.php?script_id=102 - vim-dirdiff na GitHubu
https://github.com/will133/vim-dirdiff - fakeclip : pseudo clipboard register for non-GUI version of Vim
http://www.vim.org/scripts/script.php?script_id=2098 - vim-fakeclip na GitHubu
https://github.com/kana/vim-fakeclip - vim-fakeclip: Dokumentace
http://kana.github.io/config/vim/fakeclip.html - Vim Multiple Cursors na GitHubu
https://github.com/terryma/vim-multiple-cursors - SLIME (Wikipedia)
http://en.wikipedia.org/wiki/SLIME - vim-slime na GitHubu
https://github.com/jpalardy/vim-slime - The NERD tree: A tree explorer plugin for navigating the filesystem
http://www.vim.org/scripts/script.php?script_id=1658 - JavaBrowser : Shows java file class, package in a tree as in IDEs. Java source browser.
http://www.vim.org/scripts/script.php?script_id=588 - snippetsEmu : An attempt to emulate TextMate's snippet expansion
http://www.vim.org/scripts/script.php?script_id=1318 - c.vim : C/C++ IDE key mappings
http://lug.fh-swf.de/vim/vim-c/c-hotkeys.pdf - Základní základy editoru Vim
http://www.root.cz/clanky/zakladni-zaklady-editoru-vim/ - Jak si přizpůsobit Vim
http://www.root.cz/serialy/jak-si-prizpusobit-vim/ - Taglist (plugin)
http://www.vim.org/scripts/script.php?script_id=273 - Tutorial: Make Vim as Your C/C++ IDE Using c.vim Plugin
http://www.thegeekstuff.com/2009/01/tutorial-make-vim-as-your-cc-ide-using-cvim-plugin/ - c.vim : C/C++ IDE
http://vim.sourceforge.net/scripts/script.php?script_id=213 - The History of Vim
https://jovicailic.org/2014/06/the-history-of-vim/ - Display date-and-time on status line
http://vim.wikia.com/wiki/Display_date-and-time_on_status_line - Vim 8.1 is available!
https://www.vim.org/vim-8.1-released.php