Obsah
2. Nastavení proměnných prostředí PATH a GOPATH
4. Otestování nástroje gocode z příkazové řádky
5. Ladicí informace vypisované serverem
6. Výstupní formáty nástroje gocode
7. Doplňování kódu v textovém editoru Vim
9. Instalace pluginu vim-gocode do Vimu
10. Otestování základních vlastností poskytovaných pluginem vim-gocode
11. Konfigurace klávesové zkratky pro vyvolání omni completion
12. Interaktivní smyčka REPL pro kompilovaný programovací jazyk Go?
13. Interaktivní smyčka REPL v různých jazycích a nástrojích
15. Instalace projektu Gore a spuštění interaktivní smyčky REPL
16. Speciální pseudopříkazy používané v REPL projektu Gore
1. Užitečné nástroje pro Go: automatické doplňování kódu, plnohodnotná smyčka REPL a integrace s Vimem
V dnešním pokračování seriálu o programovacím jazyce Go se seznámíme s některými užitečnými nástroji, které mohou dobře posloužit především vývojářům při tvorbě a úpravách zdrojových kódů psaných v Go. V úvodní části článku se budeme věnovat především nástroji pojmenovaném gocode, který umožňuje integraci funkce pro automatické doplňování kódu do textových editorů a samozřejmě i do integrovaných vývojových prostředí. Tato technologie, která se nazývá omni completion, IntelliSense apod. je samozřejmě vývojáři vyhledávaná a prakticky dennodenně používaná, protože mnohdy značným způsobem urychluje jejich práci, redukuje nutnost častého studia dokumentace méně často volaných funkcí a metod, zmenšuje množství triviálních chyb typu chybějící parametr volané funkce/metody, nekompatibilní typ předávaného parametru atd.
Ve druhé části dnešního článku si ukážeme, jakým způsobem se výše zmíněný projekt gocode používá v textovém editoru Vim. Uvidíme, že integrace Vim+gocode je z pohledu uživatelů jednoduchá a přitom uspokojivě funkční. Třetí část dnešního článku je věnována možná poněkud neočekávanému tématu – popisem projektu Gore, který do programovacího jazyka Go implementuje plnohodnotnou interaktivní smyčku REPL (Read-Eval-Print-Loop), což je pro kompilovaný programovací jazyk možná poněkud neobvyklé, ale o to zajímavější řešení. Smyčka REPL totiž mj. umožňuje odlišný způsob vývoje, než jaký známe z klasických vývojových prostředí: namísto neustálých opakování cyklů editace→překlad→spuštění→kontrola chyb je totiž možné interaktivně, tj. doslova příkaz po příkazu, zadávat a sledovat chování programu. To je výhodné například při testování možností cizích knihoven, přípravě jednotkových testů, zkoumání různých parametrů použitých algoritmů atd.
2. Nastavení proměnných prostředí PATH a GOPATH
Jak jsme si již řekli v úvodní kapitole, budeme se v první části dnešního článku zabývat popisem nástroje gocode. Ještě předtím, než budeme moci tento nástroj nainstalovat a plnohodnotně použít, je však nutné správně nastavit proměnné prostředí (environment variables) nazvané PATH a GOPATH. I v případě, že tyto proměnné nejsou nastaveny korektně, je totiž možné jazyk Go (překladač atd.) relativně bez problémů používat, ovšem nástroj gocode by bez nastavení těchto proměnných ve velkém množství případů neposkytoval žádné rozumné výsledky.
Proměnná GOPATH by měla obsahovat cestu či cesty k adresářové struktuře, ve které se nachází zdrojové kódy, balíčky a spustitelné aplikace/nástroje jazyka Go, které ovšem leží mimo ten adresář, do kterého je nainstalován jazyk Go (tento adresář je obsažen v proměnné prostředí GOROOT). Proměnná GOPATH je použita několika nástroji, mj. i nástrojem gocode při hledání kódu pro automatické doplnění.
Proměnná PATH obsahuje cestu či (mnohem častěji) větší množství cest k adresářům se spustitelnými soubory. Do této proměnné je vhodné přidat mj. i podadresář bin obsahující nativní nástroje programovacího jazyka Go a taktéž podadresář, do kterého se ukládají lokálně zkompilované nástroje instalované příkazem go get.
Podívejme se nyní na typické nastavení proměnných GOPATH a PATH. Proměnná GOPATH bude ukazovat na adresář ~/go/, tj. na adresář vytvořený v domácím adresáři aktivně přihlášeného uživatele, v němž je vytvořena následující struktura:
├── bin ├── pkg │ └── linux_amd64 └── src ├── github.com └── golang.org ... ... ...
Do proměnné PATH přidáme dva adresáře. Prvním z nich je adresář s cestou /opt/go/bin, protože právě do /opt/go byl nainstalován jazyk Go se všemi standardními knihovnami a nástroji. Druhým adresářem je ~/go/bin, jelikož právě do tohoto adresáře se instalují spustitelné soubory instalované příkazem go get (mezi tyto soubory patří i dále popsaný nástroj gocode).
Následuje ukázka nastavení obou proměnných prostředí provedených například v souboru .bashrc či .profile:
export GOPATH=~/go/ export PATH=$PATH:~/bin:~/.local/bin/:/opt/go/bin:~/go/bin
Po nastavení těchto proměnných prostředí se můžeme příkazem go env přesvědčit, jaká je aktuální konfigurace jazyka Go, přesněji řečeno, jak proměnné interpretují standardní nástroje Go (dochází zde k expanzi ~ atd. atd.):
$ go env GOARCH="amd64" GOBIN="" GOCACHE="/home/tester/.cache/go-build" GOEXE="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOOS="linux" GOPATH="/home/tester/go/bin" GOPROXY="" GORACE="" GOROOT="/opt/go" GOTMPDIR="" GOTOOLDIR="/opt/go/pkg/tool/linux_amd64" GCCGO="gccgo" CC="gcc" CXX="g++" CGO_ENABLED="1" GOMOD="" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build015606214=/tmp/go-build -gno-record-gcc-switches"
3. Instalace nástroje gocode
Po nastavení konfigurace programovacího jazyka Go se již můžeme zabývat prvním nástrojem, o němž jsme se ve stručnosti zmínili v úvodní kapitole dnešního článku. Tento nástroj se jmenuje gocode a instaluje se naprosto stejným způsobem, jako většina ostatních knihoven, nástrojů a pomocných modulů programovacího jazyka Go – příkazem go get:
$ go get github.com/mdempsky/gocode
Po zadání tohoto příkazu se naklonuje repositář se zdrojovými kódy nástroje gocode, naklonují se i repositáře závislých projektů a následně se provede překlad všech potřebných knihoven i slinkování výsledného spustitelného nativního souboru. Výsledkem překladu a slinkování bude soubor gocode uložený v adresáři ~/$GOPATH/bin/:
$ ls -l $GOPATH/bin total 19872 -rwxr-xr-x 1 tester tester 11995863 čen 26 21:47 gocode -rwxr-xr-x 1 tester tester 8347658 čen 26 14:38 gore
O tom, že byl nástroj gocode přeložen korektně (pro danou architekturu) se prozatím můžeme přesvědčit alespoň pokusem o zobrazení jeho nápovědy:
$ gocode --help Usage: gocode [-s] [-f=<format>] [-in=<path>] [-sock=<type>] [-addr=<addr>] <command> [<args>] Flags: -addr string address for tcp socket (default "127.0.0.1:37373") ... ... ...
4. Otestování nástroje gocode z příkazové řádky
Nyní si již můžeme ukázat základní funkce nabízené nástrojem gocode. Nejdříve tento nástroj spustíme v režimu serveru a přesvědčíme se, že byl skutečně spuštěn na pozadí:
$ gocode $ ps ax |grep gocode 1897 pts/6 Sl 0:00 gocode -s -sock unix -addr 127.0.0.1:37373
Následně vytvoříme následující zdrojový soubor nazvaný 01_counter.go, který ovšem není, jak jste si mohli povšimnout, úplný, takže by ho nebylo možné přeložit. Šipka na šestnáctém řádku není součástí zdrojového kódu, ale pouze ukazuje pozici kurzoru v textovém editoru. Právě na tomto místě budeme požadovat, aby nám nástroj gocode nabídl všechny možné identifikátory, které je možné v daném kontextu doplnit:
package main import ( "fmt" "time" ) func main() { var cnt int = 0 for i := 0; i < 1000; i++ { go func() { cnt++ }() } time.Sleep(1000 * time.M→ fmt.Printf("%d\n", cnt) }
Obrázek 1: S využitím klávesové zkratky G Ctrl+G lze získat přesné informace o pozici kurzoru (ten je zde naznačen modrým obdélníkem, i když skutečný kurzor přeskočil na příkazovou a stavovou řádku).
Pozice naznačená šipkou je od počátku souboru vzdálena o 159 bajtů (a v tomto případě i znaků, protože pro jednoduchost používáme čisté ASCII a nikoli plné Unicode), takže pro zobrazení všech možných identifikátorů, které lze na pozici 159 doplnit použijeme příkaz:
$ gocode -f=json --in 01_counter.go autocomplete 159
Povšimněte si, že je nutné specifikovat výstupní formát, jméno souboru, který se pošle nástroji gocode (přes socket), příkaz pro gocode (autocomplete) a taktéž i pozici kurzoru, na které očekáváme seznam pro doplnění.
Nástroj gocode by měl vrátit JSON obsahující přesné informace o identifikátorech, které je možné na daném místě doplnit:
[1,[{"class":"const","package":"time","name":"March","type":"time.Month"}, {"class":"const","package":"time","name":"May","type":"time.Month"}, {"class":"const","package":"time","name":"Microsecond","type":"time.Duration"}, {"class":"const","package":"time","name":"Millisecond","type":"time.Duration"}, {"class":"const","package":"time","name":"Minute","type":"time.Duration"}, {"class":"const","package":"time","name":"Monday","type":"time.Weekday"}, {"class":"type","package":"time","name":"Month","type":"int"}]]
Můžeme vidět, že se skutečně nabídly pouze ty identifikátory z balíčku time, které začínají znakem „M“. Zajímavé ovšem je, že identifikátory konstant mají rozdílné typy.
V dalším příkladu vyzkoušíme, zda nástroj gocode dokáže doplnit všechny funkce, konstanty a proměnné balíčku fmt. Opět se podívejte, na kterém místě se nyní nachází šipka kurzoru:
package main import ( "fmt" "time" ) func main() { var cnt int = 0 for i := 0; i < 1000; i++ { go func() { cnt++ }() } time.Sleep(1000 * time.Microsecond) fmt.→ }
Nyní se kurzor nachází na offsetu 176, takže si vyžádáme všechny možnosti automatického doplnění na této pozici:
$ gocode -f=json --in 02_counter.go autocomplete 176
Výsledek (ve formátu JSON) pro větší přehlednost upravíme do čitelnější podoby:
[ 0, [ { "class": "func", "package": "fmt", "name": "Errorf", "type": "func(format string, a ...interface{}) error" }, { "class": "func", "package": "fmt", "name": "Fprint", "type": "func(w io.Writer, a ...interface{}) (n int, err error)" }, { "class": "func", "package": "fmt", "name": "Fprintf", "type": "func(w io.Writer, format string, a ...interface{}) (n int, err error)" }, { "class": "func", "package": "fmt", "name": "Fprintln", "type": "func(w io.Writer, a ...interface{}) (n int, err error)" }, ... ... ...
5. Ladicí informace vypisované serverem
Server gocode je možné nastavit i takovým způsobem, aby vypisoval ladicí informace o zdrojových kódech, které mu byly předloženy a o nabídkách automatického doplnění, které provedl. Původní instanci serveru je nejdříve nutné vypnout:
$ gocode exit
A následně znovu nastartovat, tentokrát ovšem s uvedením přepínačů -debug (výpis ladicích informací) a -s (vynucení režimu serveru, nikoli klienta):
$ gocode -debug -s
Nyní serveru znovu předložíme první testovací příklad a budeme požadovat nabídky pro automatické doplnění na offsetu 159:
$ gocode -f=json --in 01_counter.go autocomplete 159
Server vrátí požadovanou informaci, ovšem kromě toho na svůj terminál vypíše i ladicí informace v tomto tvaru:
2019/06/27 20:51:15 Got autocompletion request for '/home/tester/go-root/article_32/01_counter.go' 2019/06/27 20:51:15 Cursor at: 159 2019/06/27 20:51:15 ------------------------------------------------------- package main import ( "fmt" "time" ) func main() { var cnt int = 0 for i := 0; i < 1000; i++ { go func() { cnt++ }() } time.Sleep(1000 * time. # fmt.Printf("%d\n", cnt) } 2019/06/27 20:51:15 ------------------------------------------------------- 2019/06/27 20:51:15 Error parsing input file (outer block): 2019/06/27 20:51:15 /home/tester/go-root/article_32/01_counter.go:17:1: expected selector or type assertion, found ';' 2019/06/27 20:51:15 /home/tester/go-root/article_32/01_counter.go:17:3: missing ',' in argument list 2019/06/27 20:51:15 /home/tester/go-root/article_32/01_counter.go:17:6: expected operand, found '.' 2019/06/27 20:51:15 /home/tester/go-root/article_32/01_counter.go:18:3: expected ')', found 'EOF' 2019/06/27 20:51:15 /home/tester/go-root/article_32/01_counter.go:18:3: expected ';', found 'EOF' 2019/06/27 20:51:15 /home/tester/go-root/article_32/01_counter.go:18:3: expected ';', found 'EOF' 2019/06/27 20:51:15 /home/tester/go-root/article_32/01_counter.go:18:3: expected '}', found 'EOF' 2019/06/27 20:51:15 /home/tester/go-root/article_32/01_counter.go:18:3: missing ',' in argument list 2019/06/27 20:51:15 Error parsing "/home/tester/go-root/article_32/02_counter.go": 2019/06/27 20:51:15 /home/tester/go-root/article_32/02_counter.go:18:1: expected selector or type assertion, found '}' 2019/06/27 20:51:15 Elapsed duration: 8.815436ms 2019/06/27 20:51:15 Offset: 0 2019/06/27 20:51:15 Number of candidates found: 67 2019/06/27 20:51:15 Candidates are: 2019/06/27 20:51:15 const ANSIC untyped string 2019/06/27 20:51:15 const April time.Month 2019/06/27 20:51:15 const August time.Month 2019/06/27 20:51:15 const December time.Month 2019/06/27 20:51:15 const February time.Month ... ... ... 2019/06/27 20:51:15 const Wednesday time.Weekday 2019/06/27 20:51:15 func After(d time.Duration) <-chan time.Time 2019/06/27 20:51:15 func AfterFunc(d time.Duration, f func()) *time.Timer 2019/06/27 20:51:15 func Date(year int, month time.Month, day int, hour int, min int, sec int, nsec int, loc *time.Location) time.Time ... ... ... 2019/06/27 20:51:15 type Time struct 2019/06/27 20:51:15 type Timer struct 2019/06/27 20:51:15 type Weekday int 2019/06/27 20:51:15 var Local *time.Location 2019/06/27 20:51:15 var UTC *time.Location 2019/06/27 20:51:15 =======================================================
Podobně je tomu ve druhém příkladu:
$ gocode -f=json --in 02_counter.go autocomplete 176
S ladicími informacemi:
2019/06/27 20:49:01 Got autocompletion request for '/home/tester/go-root/article_32/02_counter.go' 2019/06/27 20:49:01 Cursor at: 176 2019/06/27 20:49:01 ------------------------------------------------------- package main import ( "fmt" "time" ) func main() { var cnt int = 0 for i := 0; i < 1000; i++ { go func() { cnt++ }() } time.Sleep(1000 * time.Microsecond) fmt.# } 2019/06/27 20:49:01 ------------------------------------------------------- 2019/06/27 20:49:01 Error parsing input file (outer block): 2019/06/27 20:49:01 /home/tester/go-root/article_32/02_counter.go:17:6: expected selector or type assertion, found ';' 2019/06/27 20:49:01 Error parsing "/home/tester/go-root/article_32/01_counter.go": 2019/06/27 20:49:01 /home/tester/go-root/article_32/01_counter.go:17:25: missing ',' before newline in argument list 2019/06/27 20:49:01 /home/tester/go-root/article_32/01_counter.go:18:1: expected operand, found '}' 2019/06/27 20:49:01 Elapsed duration: 8.312908ms 2019/06/27 20:49:01 Offset: 0 2019/06/27 20:49:01 Number of candidates found: 25 2019/06/27 20:49:01 Candidates are: 2019/06/27 20:49:01 func Errorf(format string, a ...interface{}) error 2019/06/27 20:49:01 func Fprint(w io.Writer, a ...interface{}) (n int, err error) 2019/06/27 20:49:01 func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) 2019/06/27 20:49:01 func Fprintln(w io.Writer, a ...interface{}) (n int, err error) 2019/06/27 20:49:01 func Fscan(r io.Reader, a ...interface{}) (n int, err error) 2019/06/27 20:49:01 func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error) 2019/06/27 20:49:01 func Fscanln(r io.Reader, a ...interface{}) (n int, err error) 2019/06/27 20:49:01 func Print(a ...interface{}) (n int, err error) 2019/06/27 20:49:01 func Printf(format string, a ...interface{}) (n int, err error) 2019/06/27 20:49:01 func Println(a ...interface{}) (n int, err error) 2019/06/27 20:49:01 func Scan(a ...interface{}) (n int, err error) 2019/06/27 20:49:01 func Scanf(format string, a ...interface{}) (n int, err error) 2019/06/27 20:49:01 func Scanln(a ...interface{}) (n int, err error) 2019/06/27 20:49:01 func Sprint(a ...interface{}) string 2019/06/27 20:49:01 func Sprintf(format string, a ...interface{}) string 2019/06/27 20:49:01 func Sprintln(a ...interface{}) string 2019/06/27 20:49:01 func Sscan(str string, a ...interface{}) (n int, err error) 2019/06/27 20:49:01 func Sscanf(str string, format string, a ...interface{}) (n int, err error) 2019/06/27 20:49:01 func Sscanln(str string, a ...interface{}) (n int, err error) 2019/06/27 20:49:01 type Formatter interface 2019/06/27 20:49:01 type GoStringer interface 2019/06/27 20:49:01 type ScanState interface 2019/06/27 20:49:01 type Scanner interface 2019/06/27 20:49:01 type State interface 2019/06/27 20:49:01 type Stringer interface 2019/06/27 20:49:01 =======================================================
6. Výstupní formáty nástroje gocode
Nástroj gocode poskytuje informace o kódu, který je možné v daném místě doplnit, v několika různých formátech. S formátem JSON jsme se již setkali v předchozích kapitolách, takže se zde zmiňme o dalších podporovaných formátech:
- CSV
- Formát pro Vim
- Formát pro Emacs
- Takzvaný „nice“ formát
Formát CSV poskytuje informace ve formě jednoduché tabulky zpracovatelné libovolnou knihovnou, která s CSV dokáže pracovat (taková knihovna dnes existuje pro prakticky každý programovací jazyk):
$ gocode -f=csv --in 01_counter.go autocomplete 159 const,,ANSIC,,untyped string,,time const,,April,,time.Month,,time const,,August,,time.Month,,time const,,December,,time.Month,,time const,,February,,time.Month,,time const,,Friday,,time.Weekday,,time const,,Hour,,time.Duration,,time const,,January,,time.Month,,time const,,July,,time.Month,,time ... ... ...
Formát pro Vim odpovídá datovým typům Vim Scriptu, takže je snadno zpracovatelný přímo ve Vimu:
$ gocode -f=vim --in 01_counter.go autocomplete 159 [0, [ {'word': 'ANSIC', 'abbr': 'const ANSIC untyped string', 'info': 'const ANSIC untyped string'}, {'word': 'April', 'abbr': 'const April time.Month', 'info': 'const April time.Month'}, {'word': 'August', 'abbr': 'const August time.Month', 'info': 'const August time.Month'}, {'word': 'December', 'abbr': 'const December time.Month', 'info': 'const Decembe ... ... ...
Formát určený pro Emacs má následující strukturu podobnou struktuře CSV:
$ gocode -f=emacs --in 01_counter.go autocomplete 159 ANSIC,,const untyped string April,,const time.Month August,,const time.Month December,,const time.Month ... ... ...
A konečně „pěkný“ (nice) formát je určen spíše pro čtení uživateli než pro přímé zpracování:
$ gocode -f=nice --in 01_counter.go autocomplete 159 Found 67 candidates: const ANSIC untyped string const April time.Month const August time.Month const December time.Month const February time.Month const Friday time.Weekday const Hour time.Duration
7. Doplňování kódu v textovém editoru Vim
Ve druhé části článku si ukážeme zkombinování textového editoru Vim a nástroje gocode.
Velmi užitečnou vlastností textového editoru Vim, kterou se dnes budeme v souvislosti s pluginem vim-gocode alespoň ve stručnosti zabývat, je technologie nazvaná „omni completion“ (někdy se setkáme i s jednoslovným zápisem „omnicompletion“). Tato technologie, která se ve Vimu objevila až v jeho sedmé verzi, rozšiřuje možnosti automatického doplňování kódu (či obecně textu) o externí nástroje. Připomeňme si, že Vim nabízí ve vkládacím a přepisovacím režimu klávesovou zkratku Ctrl+P (previous) pro nalezení a doplnění slova nacházejícího se před kurzorem a taktéž zkratku Ctrl+N (next), která slouží ke stejnému účelu, ovšem hledá slovo pro doplnění v textu za kurzorem (pokud je k dispozici více možností, zobrazí se všechny nalezené možnosti v kontextovém menu). V praxi tedy postačuje napsat jen začátek slova a stlačit Ctrl+P nebo Ctrl+N. Rozsah vyhledávání se specifikuje volbou complete popsanou zde a samozřejmě i ve vestavěné nápovědě.
Obrázek 2: Doplňování kódu nebo libovolného textu s využitím příkazů CTRL+P a CTRL+N zavolaných v režimu zápisu (insert mode).
Ovšem možnosti automatického doplňování kódu jsou ve skutečnosti daleko větší a textový editor Vim pro ně dokonce nabízí samostatný režim vyvolávaný z vkládacího či přepisovacího režimu klávesovou zkratkou Ctrl+X (právě z tohoto důvodu se tento režim nazývá ^X-mode nebo též CTRL-X mode). Po stlačení této klávesové zkratky se v příkazové řádce editoru objeví jednoduché jednořádkové menu s příkazy platnými pro režim doplňování:
Všechny dostupné příkazy jsou vypsány v tabulce níže:
# | Příkaz | Význam |
---|---|---|
1 | Ctrl+X Ctrl+L | nalezení a doplnění celého (shodného) řádku, užitečné především v případě editace některých typů konfiguračních souborů |
2 | Ctrl+X Ctrl+N | doplnění slova, které se nalézá v aktuálně editovaném souboru |
3 | Ctrl+X Ctrl+K | podobné Ctrl+N, ovšem slova se hledají v souborech specifikovaných pomocí konfiguračního parametru dictionary (jedná se o běžný textový soubor se seznamem slov) |
4 | Ctrl+X Ctrl+T | podobné Ctrl+T, ovšem slova se hledají v souborech specifikovaných pomocí konfiguračního parametru thesaurus |
5 | Ctrl+X Ctrl+I | podobné Ctrl+N, ovšem prohledávají se i všechny vkládané (included) soubory |
6 | Ctrl+X Ctrl+] | vyhledávání v seznamu značek |
7 | Ctrl+X Ctrl+F | doplnění názvu souboru a/nebo cesty, postačuje například zadat text ~/ za nímž následuje klávesová zkratka Ctrl+X Ctrl+F a zobrazí se výpis souborů v domácím adresáři |
8 | Ctrl+X Ctrl+D | vyhledání definice makra a doplnění jména tohoto makra |
9 | Ctrl+X Ctrl+U | zavolání funkce zadané v konfiguračním parametru completefunc, které se předá právě editovaný text |
10 | Ctrl+X Ctrl+O | vyvolání funkce omni completion popsané <a>v následující kapitole (dostupné od Vimu 7) |
Obrázek 3: Doplnění názvu souboru v pracovním adresáři pomocí příkazu CTRL+X CTRL+F.
8. Technologie omnicompletion
V předchozí kapitole jsme si řekli, že s využitím klávesové zkratky Ctrl+X Ctrl+O lze ve vkládacím a přepisovacím režimu zavolat technologii „omni completion“. Tuto technologii lze využít pro (pseudo)inteligentní doplňování textů založeném na analýze zdrojových kódů. Podobnou funkci můžeme najít v nejrůznějších integrovaných vývojových prostředích (Eclipse, Netbeans, Visual Studio, Visual Studio Code, nověji například i v Atomu), v nichž lze doplňovat například jména funkcí a metod, názvy prvků ve strukturách či uniích, atributů objektů, metod objektů či tříd, jmen balíčků atd.
Implicitně tato funkce není specifikována vůbec, o čemž se můžete velmi snadno přesvědčit při spuštění „prázdného“ Vimu:
:set omnifunc? omnifunc=
Naopak při editaci tohoto článku (v HTML) je funkce nastavena, a to konkrétně standardním filetype pluginem html.vim:
:set omnifunc? omnifunc=htmlcomplete#CompleteTags
V případě, že chceme použít možnosti nabízené například pluginem vim-lsp, můžeme omnifunc nastavit globálně (pro celý Vim). To se provede jednoduše příkazem:
:set omnifunc=lsp#complete
Popř. lze stejnou funkci nastavit pouze lokálně pro právě aktivní buffer:
:setlocal omnifunc=lsp#complete
Samozřejmě nemusíme toto nastavení stále provádět ručně po otevření každého zdrojového souboru, ale můžeme do konfiguračního souboru .vimrc přidat příkaz, který se automaticky zavolá při otevření souboru s koncovkou *.py (Python):
augroup __python__ au! au BufRead,BufNewFile *.py setlocal omnifunc=lsp#complete augroup END
9. Instalace pluginu vim-gocode do Vimu
Pro zkombinování možností textového editoru Vim a výše popsaného nástroje gocode slouží plugin (přídavný modul) nazvaný jednoduše a přímočaře vim-gocode. Zdrojové kódy tohoto modulu nalezneme v repositáři dostupném na adrese https://github.com/volgar1×/vim-gocode.
Instalaci modulu vim-gocode je možné provést různými způsoby (například využít různé správce balíčků), ovšem lze zůstat i u konzervativní metody a rozbalit všechny soubory přímo do adresáře ~./vim. V mém případě používám správce balíčků nazvaný Pathogen (viz též Užitečné skripty a pluginy pro textový editor Vim), takže instalace bude ještě jednodušší – celý repositář se jednoduše naklonuje do adresáře ~/.vim/bundle.
V podadresáři ~/.vim by měla být vytvořena následující adresářová struktura (samozřejmě zde můžeme mít uloženy další pluginy, ostatně i já zde mám nainstalovány například slovníky):
. ├── autoload ├── bundle │ ├── calendar-vim │ │ ... │ │ ... │ │ ... │ ├── rainbow_parentheses.vim │ │ ... │ │ ... │ │ ... │ ├── todo.txt-vim │ │ ... │ │ ... │ │ ... │ ├── vim-fugitive │ │ ... │ │ ... │ │ ... │ ├── vim-gocode │ │ ├── autoload │ │ │ └── go │ │ ├── compiler │ │ ├── doc │ │ ├── ftdetect │ │ ├── ftplugin │ │ │ └── go │ │ ├── indent │ │ ├── plugin │ │ └── syntax │ ├── vim-slime │ │ ... │ │ ... │ │ ... │ └── vim-table-mode │ ... │ ... │ ... ├── doc ├── ftdetect ├── plugin ├── spell └── syntax
10. Otestování základních vlastností poskytovaných pluginem vim-gocode
Plugin vim-gocode nabízí uživatelům větší množství důležitých funkcí, které naleznete v integrované nápovědě po zadání příkazu:
:help vim-gocode
Mezi užitečné funkce patří především použití klávesy Tab s automatickým zarovnáváním bloků a s převodem mezer na znaky Tab (což je současnou verzí jazyka Go striktně vyžadováno). Důležitější je ovšem funkce omni completion, která je dostupná pod standardní klávesovou zkratkou Ctrl+X Ctrl+O. Podívejme se nyní na použití této klávesové zkratky na obou demonstračních příkladech, které jsme již viděli v předchozích kapitolách:
Obrázek 4: Nabídka s automaticky nalezenými funkcemi a konstantami. Povšimněte si, že v automaticky vytvořeném okně (nahoře) se zobrazují přesnější informace o doplňovaném symbolu.
Obrázek 5: Nabídka s automaticky nalezenými funkcemi v balíčku fmt.
11. Konfigurace klávesové zkratky pro vyvolání omni completion
Výše uvedená konfigurace sice teoreticky postačuje po prakticky plnohodnotné využití možností pluginu vim-gocode, ovšem skalní uživatelé Vimu pravděpodobně očekávají nějaká vylepšení, která by Vim přiblížila k moderním IDE. Týká se to mj. i klávesové zkratky použité pro vyvolání funkce omni completion, protože Ctrl+X Ctrl+O je spíše „emacsovina“ :-) Řešení samozřejmě existuje několik. Můžeme například použít klávesovou zkratku Ctrl+Tab, pokud se nepoužívá ve správci oken:
:imap <C-Tab> <C-X><C-O>
Alternativně je možné napsat funkci, která bude na začátku řádku klávesu Tab používat pro vkládání mezer a naopak po stisku Tab za písmenem pro zavolání omni completion. Podobné řešení bylo použito v pluginu IndentTab popř. pluginu Smart-Tabs. Další ideu naleznete například na stránce Smart mapping for tab completion
V případě, že používáte GVim nebo KVim, je možné namísto klávesy Tab použít například i klávesovou zkratku Ctrl+Space:
:imap <C-Space> <C-X><C-O>
Na terminálech sice většinou není klávesová zkratka Ctrl+Space korektně rozpoznána, ale můžete se pokusit zjistit, zda terminál namísto Ctrl+Space nerozpozná alespoň Ctrl+@, tj. přesněji řečeno, zda obě klávesové zkratky nejsou rozpoznány jako shodný kód. Pokud tomu tak je, můžete mapování změnit na:
:imap <C-@> <C-X><C-O>
a používat Ctrl+Space i v terminálu.
12. Interaktivní smyčka REPL pro kompilovaný programovací jazyk Go?
Mnozí programátoři, popř. ti uživatelé, kteří programovací jazyk musí používat pro řešení problémů ve své profesi (ovšem vývoj aplikací naopak není jejich hlavní pracovní náplní), mnohdy namísto klasických integrovaných vývojových prostředí preferují dosti odlišný způsob práce, který je v mnohem větší míře založen na přímočaré a prakticky neustálé interakci mezi vývojářem a systémem nebo vznikající (mini)aplikací, jež je mnohdy vysoce jednoúčelová. V takových případech ustupuje správa projektů poněkud do pozadí a naopak se začíná využívat dosti odlišný druh vývojového prostředí založený buď na interaktivní smyčce REPL (Read-Eval-Print-Loop) nebo na konceptu takzvaných diářů (notebooks), které jsou už poměrně dlouho velmi populární především v systémech pro numerickou matematiku, analýzy, statistické výpočty, symbolickou matematiku (manipulace se symboly a výrazy, integrace, derivace, zjednodušování výrazů atd.) a dnes taktéž pro machine learning (ML).
Obrázek 6: Za zjednodušenou formu interaktivní smyčky REPL je možné považovat i takzvaný přímý mód (direct mode) použitý například v klasickém BASICu. Na tomto screenshotu je v přímém módu zapsán příkaz LIST.
Poměrně velkou předností těchto systémů oproti klasickým integrovaným vývojovým prostředím je zejména okamžitá zpětná vazba systému na zadávané definice, deklarace, makra a příkazy. To uživatelům umožňuje se snadněji a taktéž většinou i mnohem rychleji seznámit jak s vlastním programovacím jazykem (nalezení chyby na jediném programovém řádku je určitě snazší, než analýza mnohdy několikastránkového výpisu vytvořeného překladačem), tak i s použitými knihovnami. To je dnes vlastně ještě důležitější, protože mnohdy vývoj spočívá v „lepení“ již existujících komponent či knihoven (se všemi z toho plynoucími důsledky). Aplikace vytvářené v takto koncipovaných prostředích většinou vznikají systémem zdola-nahoru (to se někdy označuje termínem bottom-up programming), tj. postupně se skládají z funkcí a tříd, které mohou být ihned po své deklaraci interaktivně otestovány.
Obrázek 7: Koncept diáře je použit například v nástroji Gorilla REPL, který mohou využít programátoři pracující s jazykem Clojure.
REPL si sice většinou spojujeme s interpretovanými programovacími jazyky, ovšem ve skutečnosti je možné smyčku REPL do určité míry používat i u jazyků kompilovaných či překládaných do bajtkódu (příkladem je programovací jazyk Clojure). Je tomu tak i v případě jazyka Go, který je kompilovaný a REPL pro něj skutečně vznikl. U jazyka Go je to umožněno zejména díky tomu, že překladač Go je velmi rychlý, takže se v REPL může relativně bez problémů používat překlad každé definice či příkazu, a to i na pomalejších počítačích.
13. Interaktivní smyčka REPL v různých jazycích a nástrojích
S principem a použitím interaktivní smyčky REPL jsme se již na stránkách Rootu setkali, a to dokonce mnohokrát. Kromě článků, které se věnovaly klasickým Unixovým shellům typu BASH, tcsh či zsh (a rozhraní shellů není nic jiného, než interaktivní REPL), jsme smyčku REPL použili například při popisu programovacího jazyka Julia či jazyka Clojure. Historií vzniku REPL jsme se zabývali i zde.
Některé smyčky REPL jsou pojaty přísně minimalisticky, což je případ dnes již spíše minimálně používaného jazyka TCL. Tato interaktivní REPL dokonce ani neobsahuje historii příkazů či podporu pro pohyb kurzoru na příkazovém řádku:
%
Další interaktivní REPL alespoň uživatele informují, v jakém prostředí se nachází. To je případ REPL (opět velmi jednoduše pojaté) programovacího jazyka Lua:
Lua 5.2.3 Copyright (C) 1994-2013 Lua.org, PUC-Rio >
REPL projektu LuaJIT vypadá nepatrně odlišně:
LuaJIT 2.1.0-beta3 -- Copyright (C) 2005-2017 Mike Pall. http://luajit.org/ JIT: ON SSE2 SSE3 SSE4.1 BMI2 fold cse dce fwd dse narrow loop abc sink fuse >
Nově se plnohodnotný REPL objevil i v jazyku Clojure; v předchozích verzích se používal dále zmíněný alternativní nREPL:
Clojure 1.9.0 user=>
Podobně vypadá REPL programovacího jazyka Pixie (to vlastně není nijak překvapivé, protože se opět jedná o jednu z v:
user =>
Interaktivní rozhraní projektu GNU Guile, což je jedna z variant programovacího jazyka Scheme:
GNU Guile 2.0.14 Copyright (C) 1995-2016 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. scheme@(guile-user)>
Plnohodnotnou smyčku REPL se všemi vymoženostmi nabízí zejména programovací jazyk Julia, což ostatně není překvapivé, protože se tento jazyk používá právě pro postupnou inkrementální tvorbu aplikací v interaktivním prostředí:
_ _ _ _(_)_ | Documentation: https://docs.julialang.org (_) | (_) (_) | _ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help. | | | | | | |/ _` | | | | |_| | | | (_| | | Version 1.0.0 (2018-08-08) _/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release |__/ | julia>
Podobně je tomu v případě programovacího jazyka Clojure doplněného o nREPL (ten lze spustit například příkazem lein repl):
nREPL server started on port 42733 on host 127.0.0.1 - nrepl://127.0.0.1:42733 REPL-y 0.3.7, nREPL 0.2.12 Clojure 1.8.0 OpenJDK 64-Bit Server VM 1.8.0_171-b10 Docs: (doc function-name-here) (find-doc "part-of-name-here") Source: (source function-name-here) Javadoc: (javadoc java-object-or-class-here) Exit: Control+D or (exit) or (quit) Results: Stored in vars *1, *2, *3, an exception in *e user=>
Samozřejmě nesmíme zapomenout ani na REPL doménově specifického jazyka R:
R version 3.5.3 (2019-03-11) -- "Great Truth" Copyright (C) 2019 The R Foundation for Statistical Computing Platform: x86_64-redhat-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. Natural language support but running in an English locale R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. During startup - Warning messages: 1: Setting LC_TIME failed, using "C" 2: Setting LC_MONETARY failed, using "C" 3: Setting LC_PAPER failed, using "C" 4: Setting LC_MEASUREMENT failed, using "C" gt;
Obrázek 8: Jedna z alternativních REPL určených pro programovací jazyk Python.
14. Projekt Gore
Jak jsme se již zmínili v předchozích kapitolách, implementace interaktivní smyčky REPL vznikla i pro programovací jazyk Go. Jedná se o projekt nazvaný Gore, jehož zdrojové kódy nalezneme na adrese https://github.com/motemen/gore/cmd/gore (existuje i několik forků tohoto projektu). O tomto projektu se v dnešním článku zmiňujeme mj. i proto, že díky kooperaci s projektem gocode nabízí uživatelům i možnost automatického doplňování příkazů, což je velmi užitečné (a mnozí uživatelé si plnohodnotný REPL bez funkce autocomplete ani nedokážou představit).
15. Instalace projektu Gore a spuštění interaktivní smyčky REPL
Instalace projektu Gore se nijak neliší od instalace jakéhokoli jiného balíčku programovacího jazyka Go:
$ go get -u github.com/motemen/gore/cmd/gore
Po (doufejme že úspěšné) instalaci by se měl na PATH objevit i příkaz gore (viz též druhou kapitolu s popisem nastavení cesty).
Samotnou interaktivní smyčku REPL spustíme právě příkazem gore:
$ gore
Následně by se měly objevit základní informace o REPL, verze projektu i takzvaná výzva (prompt):
gore version 0.4.1 :help for help gore>
V tomto okamžiku REPL očekává příkazy, které budou ihned vykonány. Můžeme zadávat i pseudopříkazy, které začínají dvojtečkou. Asi nejlepším příkladem takového pseudopříkazu je nápověda vyvolaná pomocí :help:
gore> :help :import <package> import a package :type <expr> print the type of expression :print print current source :write [<file>] write out current source :clear clear the codes :doc <expr or pkg> show documentation :help show this help :quit quit the session
Do interaktivní smyčky REPL ovšem můžete zadávat i běžné programové konstrukce programovacího jazyka Go. Příkladem může být deklarace proměnné:
gore> i := 42 (int)42 gore> x := "Hello" (string)Hello
Dále si můžeme vyzkoušet vytvořit si programovou smyčku. Povšimněte si, že REPL správně zjistí, kde se používají programové bloky a nevyžaduje stisk Tabu:
gore> for j := 1; j <= 10; j++ { ..... println(j) ..... } 1 2 3 4 5 6 7 8 9 10
V REPL lze vytvářet i funkce:
gore> func Hello() { ..... println("Hello world!") ..... } gore> Hello() Hello world! gore> Hello (func())0x4a9350
Jedna důležitá vlastnost zde ovšem chybí – barevné odlišení příkazů, parametrů, konstant, proměnných a pseudopříkazů.
16. Speciální pseudopříkazy používané v REPL projektu Gore
S takzvanými pseudopříkazy jsme se již setkali v předchozí kapitole. Tyto pseudopříkazy začínají znakem dvojtečky a můžeme je použít například pro získání dokumentace. Následující pseudopříkaz vypíše dokumentaci k zabudované funkci println:
gore> :doc println func println(args ...Type) The println built-in function formats its arguments in an implementation-specific way and writes the result to standard error. Spaces are always added between arguments and a newline is appended. Println is useful for bootstrapping and debugging; it is not guaranteed to stay in the language.
Dalším pseudopříkazem je příkaz :import, který je možné použít kdykoli, nikoli jen na začátku balíčku (pojem balíček je ovšem v rámci REPLu poněkud mlhavý):
gore> :import fmt
Ihned po importu balíčku je možné získat nápovědu k jeho funkcím, konstantám, typům a metodám:
gore> :doc fmt.Println func Println(a ...interface{}) (n int, err error) Println formats using the default formats for its operands and writes to standard output. Spaces are always added between operands and a newline is appended. It returns the number of bytes written and any write error encountered.
Dtto pro balíček time a jeho funkci Sleep:
gore> :import time gore> :doc time.Sleep func Sleep(d Duration) Sleep pauses the current goroutine for at least the duration d. A negative or zero duration causes Sleep to return immediately.
Velmi užitečný je i pseudopříkaz :write jméno_souboru, který zapíše zapsané definice do specifikovaného souboru, který by měl být později přeložitelný překladačem jazyka Go.
17. Odkazy na Internetu
- What is REPL?
https://pythonprogramminglanguage.com/repl/ - What is a REPL?
https://codewith.mu/en/tutorials/1.0/repl - Programming at the REPL: Introduction
https://clojure.org/guides/repl/introduction - What is REPL? (Quora)
https://www.quora.com/What-is-REPL - Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/ - Read-eval-print loop (Wikipedia)
https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop - Vim as a Go (Golang) IDE using LSP and vim-go
https://octetz.com/posts/vim-as-go-ide - gopls
https://github.com/golang/go/wiki/gopls - IDE Integration Guide
https://github.com/stamblerre/gocode/blob/master/docs/IDE_integration.md - How to instrument Go code with custom expvar metrics
https://sysdig.com/blog/golang-expvar-custom-metrics/ - Golang expvar metricset (Metricbeat Reference)
https://www.elastic.co/guide/en/beats/metricbeat/7.x/metricbeat-metricset-golang-expvar.html - Package expvar
https://golang.org/pkg/expvar/#NewInt - Java Platform Debugger Architecture: Overview
https://docs.oracle.com/en/java/javase/11/docs/specs/jpda/jpda.html - The JVM Tool Interface (JVM TI): How VM Agents Work
https://www.oracle.com/technetwork/articles/javase/index-140680.html - JVM Tool Interface Version 11.0
https://docs.oracle.com/en/java/javase/11/docs/specs/jvmti.html - Creating a Debugging and Profiling Agent with JVMTI
http://www.oracle.com/technetwork/articles/javase/jvmti-136367.html - JVM TI (Wikipedia)
http://en.wikipedia.org/wiki/JVM_TI - IBM JVMTI extensions
http://publib.boulder.ibm.com/infocenter/realtime/v2r0/index.jsp?topic=%2Fcom.ibm.softrt.doc%2Fdiag%2Ftools%2Fjvmti_extensions.html - Go & cgo: integrating existing C code with Go
http://akrennmair.github.io/golang-cgo-slides/#1 - Using cgo to call C code from within Go code
https://wenzr.wordpress.com/2018/06/07/using-cgo-to-call-c-code-from-within-go-code/ - Package trace
https://golang.org/pkg/runtime/trace/ - Introducing HTTP Tracing
https://blog.golang.org/http-tracing - Command trace
https://golang.org/cmd/trace/ - A StreamLike, Immutable, Lazy Loading and smart Golang Library to deal with slices
https://github.com/wesovilabs/koazee - Funkce vyššího řádu v knihovně Underscore
https://www.root.cz/clanky/funkce-vyssiho-radu-v-knihovne-underscore/ - Delve: a debugger for the Go programming language.
https://github.com/go-delve/delve - Příkazy debuggeru Delve
https://github.com/go-delve/delve/tree/master/Documentation/cli - Debuggery a jejich nadstavby v Linuxu
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu/ - Debuggery a jejich nadstavby v Linuxu (2. část)
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-2-cast/ - Debuggery a jejich nadstavby v Linuxu (3): Nemiver
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-3-nemiver/ - Debuggery a jejich nadstavby v Linuxu (4): KDbg
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-4-kdbg/ - Debuggery a jejich nadstavby v Linuxu (5): ladění aplikací v editorech Emacs a Vim
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-5-ladeni-aplikaci-v-editorech-emacs-a-vim/ - Debugging Go Code with GDB
https://golang.org/doc/gdb - Debugging Go (golang) programs with gdb
https://thornydev.blogspot.com/2014/01/debugging-go-golang-programs-with-gdb.html - GDB – Dokumentace
http://sourceware.org/gdb/current/onlinedocs/gdb/ - GDB – Supported Languages
http://sourceware.org/gdb/current/onlinedocs/gdb/Supported-Languages.html#Supported-Languages - GNU Debugger (Wikipedia)
https://en.wikipedia.org/wiki/GNU_Debugger - The LLDB Debugger
http://lldb.llvm.org/ - Debugger (Wikipedia)
https://en.wikipedia.org/wiki/Debugger - 13 Linux Debuggers for C++ Reviewed
http://www.drdobbs.com/testing/13-linux-debuggers-for-c-reviewed/240156817 - Go is on a Trajectory to Become the Next Enterprise Programming Language
https://hackernoon.com/go-is-on-a-trajectory-to-become-the-next-enterprise-programming-language-3b75d70544e - Go Proverbs: Simple, Poetic, Pithy
https://go-proverbs.github.io/ - Handling Sparse Files on Linux
https://www.systutorials.com/136652/handling-sparse-files-on-linux/ - Gzip (Wikipedia)
https://en.wikipedia.org/wiki/Gzip - Deflate
https://en.wikipedia.org/wiki/DEFLATE - 10 tools written in Go that every developer needs to know
https://gustavohenrique.net/en/2019/01/10-tools-written-in-go-that-every-dev-needs-to-know/ - Hexadecimální prohlížeče a editory s textovým uživatelským rozhraním
https://www.root.cz/clanky/hexadecimalni-prohlizece-a-editory-s-textovym-uzivatelskym-rozhranim/ - Hex dump
https://en.wikipedia.org/wiki/Hex_dump - Rozhraní io.ByteReader
https://golang.org/pkg/io/#ByteReader - Rozhraní io.RuneReader
https://golang.org/pkg/io/#RuneReader - Rozhraní io.ByteScanner
https://golang.org/pkg/io/#ByteScanner - Rozhraní io.RuneScanner
https://golang.org/pkg/io/#RuneScanner - Rozhraní io.Closer
https://golang.org/pkg/io/#Closer - Rozhraní io.Reader
https://golang.org/pkg/io/#Reader - Rozhraní io.Writer
https://golang.org/pkg/io/#Writer - Typ Strings.Reader
https://golang.org/pkg/strings/#Reader - VACUUM (SQL)
https://www.sqlite.org/lang_vacuum.html - VACUUM (Postgres)
https://www.postgresql.org/docs/8.4/sql-vacuum.html - go-cron
https://github.com/rk/go-cron - gocron
https://github.com/jasonlvhit/gocron - clockwork
https://github.com/whiteShtef/clockwork - clockwerk
https://github.com/onatm/clockwerk - JobRunner
https://github.com/bamzi/jobrunner - Rethinking Cron
https://adam.herokuapp.com/past/2010/4/13/rethinking_cron/ - In the Beginning was the Command Line
https://web.archive.org/web/20180218045352/http://www.cryptonomicon.com/beginning.html - repl.it (REPL pro různé jazyky)
https://repl.it/languages - GOCUI – Go Console User Interface (celé uživatelské prostředí, nejenom input box)
https://github.com/jroimartin/gocui - Read–eval–print loop
https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop - go-prompt
https://github.com/c-bata/go-prompt - readline
https://github.com/chzyer/readline - A pure golang implementation for GNU-Readline kind library
https://golangexample.com/a-pure-golang-implementation-for-gnu-readline-kind-library/ - go-readline
https://github.com/fiorix/go-readline - 4 Python libraries for building great command-line user interfaces
https://opensource.com/article/17/5/4-practical-python-libraries - prompt_toolkit 2.0.3 na PyPi
https://pypi.org/project/prompt_toolkit/ - python-prompt-toolkit na GitHubu
https://github.com/jonathanslenders/python-prompt-toolkit - The GNU Readline Library
https://tiswww.case.edu/php/chet/readline/rltop.html - GNU Readline (Wikipedia)
https://en.wikipedia.org/wiki/GNU_Readline - readline — GNU readline interface (Python 3.x)
https://docs.python.org/3/library/readline.html - readline — GNU readline interface (Python 2.x)
https://docs.python.org/2/library/readline.html - GNU Readline Library – command line editing
https://tiswww.cwru.edu/php/chet/readline/readline.html - gnureadline 6.3.8 na PyPi
https://pypi.org/project/gnureadline/ - Editline Library (libedit)
http://thrysoee.dk/editline/ - Comparing Python Command-Line Parsing Libraries – Argparse, Docopt, and Click
https://realpython.com/comparing-python-command-line-parsing-libraries-argparse-docopt-click/ - libedit or editline
http://www.cs.utah.edu/~bigler/code/libedit.html - WinEditLine
http://mingweditline.sourceforge.net/ - rlcompleter — Completion function for GNU readline
https://docs.python.org/3/library/rlcompleter.html - rlwrap na GitHubu
https://github.com/hanslub42/rlwrap - rlwrap(1) – Linux man page
https://linux.die.net/man/1/rlwrap - readline(3) – Linux man page
https://linux.die.net/man/3/readline - history(3) – Linux man page
https://linux.die.net/man/3/history - Dokumentace k balíčku oglematchers
https://godoc.org/github.com/jacobsa/oglematchers - Balíček oglematchers
https://github.com/jacobsa/oglematchers - Dokumentace k balíčku ogletest
https://godoc.org/github.com/jacobsa/ogletest - Balíček ogletest
https://github.com/jacobsa/ogletest - Dokumentace k balíčku assert
https://godoc.org/github.com/stretchr/testify/assert - Testify – Thou Shalt Write Tests
https://github.com/stretchr/testify/ - package testing
https://golang.org/pkg/testing/ - Golang basics – writing unit tests
https://blog.alexellis.io/golang-writing-unit-tests/ - An Introduction to Programming in Go / Testing
https://www.golang-book.com/books/intro/12 - An Introduction to Testing in Go
https://tutorialedge.net/golang/intro-testing-in-go/ - Advanced Go Testing Tutorial
https://tutorialedge.net/golang/advanced-go-testing-tutorial/ - GoConvey
http://goconvey.co/ - Testing Techniques
https://talks.golang.org/2014/testing.slide - 5 simple tips and tricks for writing unit tests in #golang
https://medium.com/@matryer/5-simple-tips-and-tricks-for-writing-unit-tests-in-golang-619653f90742 - Afinní transformace
https://cs.wikibooks.org/wiki/Geometrie/Afinn%C3%AD_transformace_sou%C5%99adnic - package gg
https://godoc.org/github.com/fogleman/gg - Generate an animated GIF with Golang
http://tech.nitoyon.com/en/blog/2016/01/07/go-animated-gif-gen/ - Generate an image programmatically with Golang
http://tech.nitoyon.com/en/blog/2015/12/31/go-image-gen/ - The Go image package
https://blog.golang.org/go-image-package - Balíček draw2D: 2D rendering for different output (raster, pdf, svg)
https://github.com/llgcode/draw2d - Draw a rectangle in Golang?
https://stackoverflow.com/questions/28992396/draw-a-rectangle-in-golang - YAML
https://yaml.org/ - edn
https://github.com/edn-format/edn - Smile
https://github.com/FasterXML/smile-format-specification - Protocol-Buffers
https://developers.google.com/protocol-buffers/ - Marshalling (computer science)
https://en.wikipedia.org/wiki/Marshalling_(computer_science) - Unmarshalling
https://en.wikipedia.org/wiki/Unmarshalling - Introducing JSON
http://json.org/ - Package json
https://golang.org/pkg/encoding/json/ - The Go Blog: JSON and Go
https://blog.golang.org/json-and-go - Go by Example: JSON
https://gobyexample.com/json - Writing Web Applications
https://golang.org/doc/articles/wiki/ - Golang Web Apps
https://www.reinbach.com/blog/golang-webapps-1/ - Build web application with Golang
https://legacy.gitbook.com/book/astaxie/build-web-application-with-golang/details - Golang Templates – Golang Web Pages
https://www.youtube.com/watch?v=TkNIETmF-RU - Simple Golang HTTPS/TLS Examples
https://github.com/denji/golang-tls - Playing with images in HTTP response in golang
https://www.sanarias.com/blog/1214PlayingwithimagesinHTTPresponseingolang - MIME Types List
https://www.freeformatter.com/mime-types-list.html - Go Mutex Tutorial
https://tutorialedge.net/golang/go-mutex-tutorial/ - Creating A Simple Web Server With Golang
https://tutorialedge.net/golang/creating-simple-web-server-with-golang/ - Building a Web Server in Go
https://thenewstack.io/building-a-web-server-in-go/ - How big is the pipe buffer?
https://unix.stackexchange.com/questions/11946/how-big-is-the-pipe-buffer - How to turn off buffering of stdout in C
https://stackoverflow.com/questions/7876660/how-to-turn-off-buffering-of-stdout-in-c - setbuf(3) – Linux man page
https://linux.die.net/man/3/setbuf - setvbuf(3) – Linux man page (stejný obsah jako předchozí stránka)
https://linux.die.net/man/3/setvbuf - Select waits on a group of channels
https://yourbasic.org/golang/select-explained/ - Rob Pike: Simplicity is Complicated (video)
http://www.golang.to/posts/dotgo-2015-rob-pike-simplicity-is-complicated-youtube-16893 - Algorithms to Go
https://yourbasic.org/ - Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů
https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu/ - Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů: vlastní filtry a lexery
https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu-vlastni-filtry-a-lexery/ - Go Defer Simplified with Practical Visuals
https://blog.learngoprogramming.com/golang-defer-simplified-77d3b2b817ff - 5 More Gotchas of Defer in Go — Part II
https://blog.learngoprogramming.com/5-gotchas-of-defer-in-go-golang-part-ii-cc550f6ad9aa - The Go Blog: Defer, Panic, and Recover
https://blog.golang.org/defer-panic-and-recover - The defer keyword in Swift 2: try/finally done right
https://www.hackingwithswift.com/new-syntax-swift-2-defer - Swift Defer Statement
https://andybargh.com/swift-defer-statement/ - Modulo operation (Wikipedia)
https://en.wikipedia.org/wiki/Modulo_operation - Node.js vs Golang: Battle of the Next-Gen Languages
https://www.hostingadvice.com/blog/nodejs-vs-golang/ - The Go Programming Language (home page)
https://golang.org/ - GoDoc
https://godoc.org/ - Go (programming language), Wikipedia
https://en.wikipedia.org/wiki/Go_(programming_language) - Go Books (kniha o jazyku Go)
https://github.com/dariubs/GoBooks - The Go Programming Language Specification
https://golang.org/ref/spec - Go: the Good, the Bad and the Ugly
https://bluxte.net/musings/2018/04/10/go-good-bad-ugly/ - Package builtin
https://golang.org/pkg/builtin/ - Package fmt
https://golang.org/pkg/fmt/ - The Little Go Book (další kniha)
https://github.com/dariubs/GoBooks - The Go Programming Language by Brian W. Kernighan, Alan A. A. Donovan
https://www.safaribooksonline.com/library/view/the-go-programming/9780134190570/ebook_split010.html - Learning Go
https://www.miek.nl/go/ - Go Bootcamp
http://www.golangbootcamp.com/ - Programming in Go: Creating Applications for the 21st Century (další kniha o jazyku Go)
http://www.informit.com/store/programming-in-go-creating-applications-for-the-21st-9780321774637 - Introducing Go (Build Reliable, Scalable Programs)
http://shop.oreilly.com/product/0636920046516.do - Learning Go Programming
https://www.packtpub.com/application-development/learning-go-programming - The Go Blog
https://blog.golang.org/ - Getting to Go: The Journey of Go's Garbage Collector
https://blog.golang.org/ismmkeynote - Go (programovací jazyk, Wikipedia)
https://cs.wikipedia.org/wiki/Go_(programovac%C3%AD_jazyk) - Rychle, rychleji až úplně nejrychleji s jazykem Go
https://www.root.cz/clanky/rychle-rychleji-az-uplne-nejrychleji-s-jazykem-go/ - Installing Go on the Raspberry Pi
https://dave.cheney.net/2012/09/25/installing-go-on-the-raspberry-pi - How the Go runtime implements maps efficiently (without generics)
https://dave.cheney.net/2018/05/29/how-the-go-runtime-implements-maps-efficiently-without-generics - Niečo málo o Go – Golang (slovensky)
http://golangsk.logdown.com/ - How Many Go Developers Are There?
https://research.swtch.com/gophercount - Most Popular Technologies (Stack Overflow Survery 2018)
https://insights.stackoverflow.com/survey/2018/#most-popular-technologies - Most Popular Technologies (Stack Overflow Survery 2017)
https://insights.stackoverflow.com/survey/2017#technology - JavaScript vs. Golang for IoT: Is Gopher Winning?
https://www.iotforall.com/javascript-vs-golang-iot/ - The Go Programming Language: Release History
https://golang.org/doc/devel/release.html - Go 1.11 Release Notes
https://golang.org/doc/go1.11 - Go 1.10 Release Notes
https://golang.org/doc/go1.10 - Go 1.9 Release Notes (tato verze je stále používána)
https://golang.org/doc/go1.9 - Go 1.8 Release Notes (i tato verze je stále používána)
https://golang.org/doc/go1.8 - Go on Fedora
https://developer.fedoraproject.org/tech/languages/go/go-installation.html - Writing Go programs
https://developer.fedoraproject.org/tech/languages/go/go-programs.html - The GOPATH environment variable
https://tip.golang.org/doc/code.html#GOPATH - Command gofmt
https://tip.golang.org/cmd/gofmt/ - The Go Blog: go fmt your code
https://blog.golang.org/go-fmt-your-code - C? Go? Cgo!
https://blog.golang.org/c-go-cgo - Spaces vs. Tabs: A 20-Year Debate Reignited by Google’s Golang
https://thenewstack.io/spaces-vs-tabs-a-20-year-debate-and-now-this-what-the-hell-is-wrong-with-go/ - 400,000 GitHub repositories, 1 billion files, 14 terabytes of code: Spaces or Tabs?
https://medium.com/@hoffa/400–000-github-repositories-1-billion-files-14-terabytes-of-code-spaces-or-tabs-7cfe0b5dd7fd - Gofmt No Longer Allows Spaces. Tabs Only
https://news.ycombinator.com/item?id=7914523 - Why does Go „go fmt“ uses tabs instead of whitespaces?
https://www.quora.com/Why-does-Go-go-fmt-uses-tabs-instead-of-whitespaces - Interactive: The Top Programming Languages 2018
https://spectrum.ieee.org/static/interactive-the-top-programming-languages-2018 - Go vs. Python
https://www.peterbe.com/plog/govspy - PackageManagementTools
https://github.com/golang/go/wiki/PackageManagementTools - A Tour of Go: Type inference
https://tour.golang.org/basics/14 - Go Slices: usage and internals
https://blog.golang.org/go-slices-usage-and-internals - Go by Example: Slices
https://gobyexample.com/slices - What is the point of slice type in Go?
https://stackoverflow.com/questions/2098874/what-is-the-point-of-slice-type-in-go - The curious case of Golang array and slices
https://medium.com/@hackintoshrao/the-curious-case-of-golang-array-and-slices-2565491d4335 - Introduction to Slices in Golang
https://www.callicoder.com/golang-slices/ - Golang: Understanding ‚null‘ and nil
https://newfivefour.com/golang-null-nil.html - What does nil mean in golang?
https://stackoverflow.com/questions/35983118/what-does-nil-mean-in-golang - nils In Go
https://go101.org/article/nil.html - Go slices are not dynamic arrays
https://appliedgo.net/slices/ - Go-is-no-good (nelze brát doslova)
https://github.com/ksimka/go-is-not-good - Rust vs. Go
https://news.ycombinator.com/item?id=13430108 - Seriál Programovací jazyk Rust
https://www.root.cz/serialy/programovaci-jazyk-rust/ - Modern garbage collection: A look at the Go GC strategy
https://blog.plan99.net/modern-garbage-collection-911ef4f8bd8e - Go GC: Prioritizing low latency and simplicity
https://blog.golang.org/go15gc - Is Golang a good language for embedded systems?
https://www.quora.com/Is-Golang-a-good-language-for-embedded-systems - Running GoLang on an STM32 MCU. A quick tutorial.
https://www.mickmake.com/post/running-golang-on-an-mcu-a-quick-tutorial - Go, Robot, Go! Golang Powered Robotics
https://gobot.io/ - Emgo: Bare metal Go (language for programming embedded systems)
https://github.com/ziutek/emgo - UTF-8 history
https://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt - Less is exponentially more
https://commandcenter.blogspot.com/2012/06/less-is-exponentially-more.html - Should I Rust, or Should I Go
https://codeburst.io/should-i-rust-or-should-i-go-59a298e00ea9 - Setting up and using gccgo
https://golang.org/doc/install/gccgo - Elastic Tabstops
http://nickgravgaard.com/elastic-tabstops/ - Strings, bytes, runes and characters in Go
https://blog.golang.org/strings - Datový typ
https://cs.wikipedia.org/wiki/Datov%C3%BD_typ - Seriál o programovacím jazyku Rust: Základní (primitivní) datové typy
https://www.root.cz/clanky/programovaci-jazyk-rust-nahrada-c-nebo-slepa-cesta/#k09 - Seriál o programovacím jazyku Rust: Vytvoření „řezu“ z pole
https://www.root.cz/clanky/prace-s-poli-v-programovacim-jazyku-rust/#k06 - Seriál o programovacím jazyku Rust: Řezy (slice) vektoru
https://www.root.cz/clanky/prace-s-vektory-v-programovacim-jazyku-rust/#k05 - Printf Format Strings
https://www.cprogramming.com/tutorial/printf-format-strings.html - Java: String.format
https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#format-java.lang.String-java.lang.Object…- - Java: format string syntax
https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html#syntax - Selectors
https://golang.org/ref/spec#Selectors - Calling Go code from Python code
http://savorywatt.com/2015/09/18/calling-go-code-from-python-code/ - Go Data Structures: Interfaces
https://research.swtch.com/interfaces - How to use interfaces in Go
http://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go - Interfaces in Go (part I)
https://medium.com/golangspec/interfaces-in-go-part-i-4ae53a97479c - Part 21: Goroutines
https://golangbot.com/goroutines/ - Part 22: Channels
https://golangbot.com/channels/ - [Go] Lightweight eventbus with async compatibility for Go
https://github.com/asaskevich/EventBus - What about Trait support in Golang?
https://www.reddit.com/r/golang/comments/8mfykl/what_about_trait_support_in_golang/ - Don't Get Bitten by Pointer vs Non-Pointer Method Receivers in Golang
https://nathanleclaire.com/blog/2014/08/09/dont-get-bitten-by-pointer-vs-non-pointer-method-receivers-in-golang/ - Control Flow
https://en.wikipedia.org/wiki/Control_flow - Structured programming
https://en.wikipedia.org/wiki/Structured_programming - Control Structures
https://www.golang-book.com/books/intro/5 - Control structures – Go if else statement
http://golangtutorials.blogspot.com/2011/06/control-structures-if-else-statement.html - Control structures – Go switch case statement
http://golangtutorials.blogspot.com/2011/06/control-structures-go-switch-case.html - Control structures – Go for loop, break, continue, range
http://golangtutorials.blogspot.com/2011/06/control-structures-go-for-loop-break.html - Goroutine IDs
https://blog.sgmansfield.com/2015/12/goroutine-ids/ - Different ways to pass channels as arguments in function in go (golang)
https://stackoverflow.com/questions/24868859/different-ways-to-pass-channels-as-arguments-in-function-in-go-golang - justforfunc #22: using the Go execution tracer
https://www.youtube.com/watch?v=ySy3sR1LFCQ - Single Function Exit Point
http://wiki.c2.com/?SingleFunctionExitPoint - Entry point
https://en.wikipedia.org/wiki/Entry_point - Why does Go have a GOTO statement?!
https://www.reddit.com/r/golang/comments/kag5q/why_does_go_have_a_goto_statement/ - Effective Go
https://golang.org/doc/effective_go.html - GoClipse: an Eclipse IDE for the Go programming language
http://goclipse.github.io/ - GoClipse Installation
https://github.com/GoClipse/goclipse/blob/latest/documentation/Installation.md#installation - The zero value of a slice is not nil
https://stackoverflow.com/questions/30806931/the-zero-value-of-a-slice-is-not-nil - Go-tcha: When nil != nil
https://dev.to/pauljlucas/go-tcha-when-nil–nil-hic - Nils in Go
https://www.doxsey.net/blog/nils-in-go