Hlavní navigace

Použití Vimu a jeho pluginů pro porovnávání a slučování souborů

Pavel Tišnovský

Ve třetím článku o nástrojích určených pro porovnání a popř. i sloučení textových souborů se budeme zabývat popisem možností nabízených textovým editorem Vim. Popíšeme si i tři velmi užitečné pluginy nazvané DirDiff, DiffChar a Fugitive.

Doba čtení: 27 minut

11. Postup při ruční instalaci přídavného modulu DirDiff

12. Instalace s využitím správce balíčků Pathogen

13. Instalace s využitím správce balíčků Vundle

14. Základní použití přídavného modulu DirDiff

15. Plugin DiffChar

16. Ukázka použití modulu DiffChar

17. Plugin Fugitive

18. Příklad použití pluginu Fugitive

19. Další možnosti pluginu Fugitive, zobrazení rozdílů mezi soubory, slučování verzí

20. Odkazy na Internetu

1. Použití Vimu a jeho pluginů pro porovnávání a slučování souborů

Na dvojici článků, v nichž jsme si popsali různé nástroje a aplikace určené jak pro porovnání dvou textových souborů, tak i složitější nástroje umožňující porovnání tří variant souboru s následným sloučením změn, dnes navážeme. Ovšem již (alespoň ne dnes) se nebude jednat o popis většího množství různých nástrojů, protože se zaměříme pouze na popis možností programátorského textového editoru Vim. Tento editor totiž podporuje takzvaný „režim diff“, který je konfigurovatelný a lze ho tak použít jak pro porovnání dvou verzí souborů, tak i pro porovnání verzí tří, samozřejmě s možností sloučení změn. Kromě toho pro Vim vzniklo hned několik přídavných modulů, které „režim diff“ dále rozšiřují o další užitečné funkce. Jedná se například o moduly DirDiff, DiffChar a v neposlední řadě Fugitive, jež ocení především uživatelé Gitu.

Obrázek 1: Nástroj Meld, který jsme si popsali v předchozím článku.

Poznámka: tento článek nepřímo navazuje na seriály Textový editor Vim jako IDE a Jak si přizpůsobit Vim. To mj. znamená, že se například zde nebudeme podrobněji zabývat popisem přepínání mezi režimy Vimu, použitím oken a tabů atd.

Obrázek 2: Nástroj KDiff3, který byl taktéž popsaný minule.

2. Otestování, zda byl Vim přeložen s podporou technologie pro porovnání bufferů

Ještě předtím, než se pokusíte o použití „režimu diff“ ve Vimu, je vhodné zjistit, jestli varianta Vimu, kterou máte ve svém operačním systému nainstalovanou, vůbec obsahuje subsystém, který vizuální porovnání souborů implementuje. Můžeme se totiž setkat s instalací minimalistické varianty Vimu přeložené takovým způsobem, aby výsledný binární soubor při svém spuštění nevyžadoval příliš mnoho systémových prostředků a tudíž režim „diff“ vůbec neobsahuje.

Příkladem může být Rasbian, kde v adresáři /usr/bin většinou nalezneme hned dvě varianty Vimu:

  1. vim.tiny
  2. vim.basic

I v Mintu (a dalších distribucích založených na Debianu) lze najít hned několik variant Vimu, typicky minimalistický vim.tiny, standardní vim.basic a popř. i vim.gtk přeložený s podporou GUI:

$ ls -1sh /usr/bin/vim.*
 
2,1M /usr/bin/vim.basic
2,5M /usr/bin/vim.gtk
864K /usr/bin/vim.tiny

Obrázek 3: Gvim aneb Vim přeložený s podporou pro GUI.

Na jednu z těchto variant ukazuje symbolický odkaz umístěný v adresáři /etc/alternatives/, takže je nutné si dát pozor na to, která verze se skutečně spouští.

Pro otestování přítomnosti subsystému pro porovnání obsahů dvou či tří bufferů zadejte přímo ve Vimu tento příkaz (dvojtečka značí přepnutí do příkazového režimu z režimu normálního):

:echo has("diff")

Tento příkaz by měl na posledním řádku zobrazit číslo 1. Pokud se však zobrazí 0, nebo se dokonce vypíše chybové hlášení oznamující, že příkaz echo nebyl rozpoznán, znamená to, že je potřeba nainstalovat balíček, který se většinou jmenuje vim-enhanced (jméno se však může na různých distribucích Linuxu lišit). Bližší informace o funkci has získáte přímo z nápovědy Vimu:

:help has

Poznámka: pokud si instalujete Vim ze standardního instalačního balíčku určeného pro systémy Microsoft Windows, bude podpora pro režim „diff“ ve spustitelném souboru dostupná (ve skutečnosti se při překladu této verze povolují prakticky všechny důležité subsystémy).

Dále jen pro jistotu otestujte, jestli se náhodou Vim nenachází v režimu kompatibility s editorem vi:

:set compatible?

Výše uvedený příkaz by měl vypsat hodnotu:

nocompatible

Pokud se vypíše jiná hodnota, zadejte do vašeho konfiguračního souboru .vimrc na začátek řádek:

set nocompatible

V režimu kompatibility totiž přestane pracovat velká část příkazů přidaných jen do Vimu, nikoli už do původního vi.

3. Alternativní způsob zjištění, zda Vim dokáže porovnat dva buffery

Alternativně je možné pro otestování, zda je subsystém pro porovnávání obsahu bufferů součástí vaší varianty Vimu, použít příkaz:

:version

nebo jeho zkrácenou podobu:

:ver

Po spuštění tohoto příkazu se zobrazí přesné informace o verzi Vimu, dále pak všechny subsystémy, které byly zahrnuty do výsledného binárního souboru a nakonec se vypíšou i parametry překladu (ty ovšem v tuto chvíli nejsou tak důležité). Po spuštění příkazu :version může okno s Vimem (dnes již postarší/stabilní verze 7.4) vypadat například takto:

Obrázek 4: První obrazovka se zobrazením voleb použitých při kompilaci Vimu.

Obrázek 5: Druhá obrazovka se zobrazením voleb použitých při kompilaci Vimu. Červeně je označena volba +diff značící, že je „režim diff“ podporován.

Vim verze 8.x zobrazí například následující informace:

Obrázek 6: První obrazovka se zobrazením voleb u Vimu 8.0

Obrázek 7: Druhá obrazovka se zobrazením voleb u Vimu 8.0. Opět je zvýrazněna volba +diff.

vim.tiny se ovšem volba +diff nevyskytuje (přesněji řečeno je vypnutá):

Obrázek 8: Druhá obrazovka se zobrazením voleb u varianty vim.tiny. Povšimněte si, že volba -diff začíná znakem minus.

Podobně i minimalisticky pojatá a dnes již vlastně z doby kamenné pocházející šestá verze Vimu pro DOS (v reálném režimu!) subsystém pro porovnání souborů neobsahuje. Zde to ovšem není příliš překvapivé, protože tato varianta má k dispozici pouze 640 kB RAM:

Obrázek 9: DOSová varianta Vimu pracující v reálném režimu je velmi kompaktní, a to zejména kvůli chybějícím funkcím (16bitový kód nemá tak velký vliv).

Obrázek 10: Jediná obrazovka se zobrazením voleb u DOSové verze Vimu. Opět si povšimněte, že volba -diff začíná znakem minus.

4. Porovnání dvou textových souborů ve Vimu

Podívejme se nyní na způsob porovnání dvou textových souborů ve Vimu. Jedná se o nejjednodušší způsob porovnání, který je možné nastavit několika způsoby. Pokud se tento textový editor spustí s parametrem -d, očekávají se za tímto parametrem jména dvou souborů pro porovnání, popř. jméno souboru a jméno adresáře, v němž se nachází soubor stejného jména:

vim -d test_old.c test_new.c
vim -d test.c ../test-sources/

Popř. při použití Vimu s GUI:

gvim -d test_old.c test_new.c
gvim -d test.c ../test-sources/

Obrázek 11: Nápověda k režimu diff.

Stejného cíle většinou dosáhnete použitím příkazu vimdiff namísto vim -d:

vimdiff test_old.c test_new.c
vimdiff test.c ../test-sources/

Popř. při použití GUI:

gvimdiff test_old.c test_new.c
gvimdiff test.c ../test-sources/

Poznámka: příkaz vimdiff je většinou symbolickým linkem na vim popř. vim-vim. Podobně je příkaz gvimdiff symbolickým linkem na vim.gtk.

Ve všech případech textový editor Vim oba soubory skutečně načte do dvojice bufferů, ovšem režim zobrazení se změní takovým způsobem, že se pomocí různých barev zvýrazní ty části souborů, které jsou odlišné. Navíc je možné delší části, jež jsou v obou souborech stejné, „zabalit“ (klávesová zkratka zc).

Interně dojde k dalším změnám konfigurace:

  1. Pro obě otevřená okna se nastaví volba diff (implicitně je vypnuta, tedy nodiff). Okna, která mají tuto volbu nastavenou, se stávají součástí skupiny, na kterou se vztahují příkazy popsané v navazující kapitole.
  2. Volba foldmethod se nastaví na hodnotu diff. To znamená, že se implicitně skryjí ty části textu, které jsou v obou oknech shodné. I volba foldmethod je lokální a vztažená k oknům.
  3. Pro obě otevřená okna se nastaví volba scrollbind. Povolení této volby zajistí, že vertikální posun textu v oknech bude synchronizován, ovšem jen v těch oknech, kde je tato volba nastavena. To znamená, že pokud si například otevřete další okno s nápovědou příkazem :help, nebude se tohoto okna synchronizace vertikálního posunu nijak týkat.
  4. Pro obě otevřená okna se nastaví volba cursorbind. Tato volba zajišťuje, že pohyb kurzoru v jednom okně se promítne i do druhého okna i když je v daný okamžik viditelný pouze jeden kurzor. Teoreticky je možné nastavit cursorbind a nikoli scrollbind, ovšem při přechodu do druhého okna dojde ke skoku na novou pozici kurzoru, což je matoucí.
  5. Navíc se ještě vypne (zakáže) volba wrap, takže dlouhé řádky nebudou zalomeny na šířku okna.

Poznámka: všech pět výše uvedených voleb je vztaženo k oknům; nejedná se tedy o volby globální. To znamená, že Vim může být v jeden okamžik použit jak pro porovnávání souborů, tak i pro další operace s jinými okny a/nebo taby.

Obrázek 12: Porovnání dvou variant zdrojového kódu psaného v Pythonu, který jsme již použili minule a předminule při popisu dalších nástrojů pro porovnávání souborů.

5. Užitečné klávesové zkratky použitelné v průběhu porovnávání

Barevné zvýraznění změn je sice pěkná a užitečná vlastnost, ovšem to není zdaleka vše, co Vim v „režimu diff“ programátorům nabízí. V tomto režimu jsou totiž k dispozici některé nové příkazy určené pro řízenou synchronizaci mezi soubory. Mezi tyto příkazy patří především:

Příkaz Význam
[c skok na začátek předchozího bloku (hunku) se změnami
]c skok na začátek následujícího bloku (hunku) se změnami
   
dp (diff put); pokud se kurzor nachází na řádcích, které se v obou souborech odlišují, je změna z aktuálního souboru přenesena do souboru druhého
do (diff obtain); opak předchozího příkazu – získání změny z druhého souboru a přenesení této změny do souboru aktuálního (tj. do souboru, v němž se nachází textový kurzor)
   
:diffupdate tento příkaz provede nové vyhodnocení rozdílů mezi oběma soubory, vhodné v případech, kdy se oba buffery rozsynchronizují
:diffput obdoba dp, ovšem má i další možnosti popsané dále
:diffget obdoba dg, ovšem má i další možnosti popsané dále

Obrázek 13: Porovnávání dvou souborů při vertikálním rozdělení oken. Toto rozdělení je vhodné použít v případě, že se jedná o zdrojové soubory s krátkými řádky, popř. pokud máte širokoúhlý monitor.

Poznámka: u příkazů [c a ]c dojde k chybě ve chvíli, kdy již neexistuje žádný předchozí či následující blok. To mj. znamená, že se zastaví opakování příkazu (například 100]c) popř. provádění makra. Právě zastavení makra je výhodné, neboť tak nedojde k problémům ve chvíli, kdy má makro například tvar:

]O# TODO check the following lines<esc>

Další příkazy O… (tj. přidání nového řádku před aktivním řádkem) se již neprovedou ve chvíli, kdy už nebyla nalezena další změna. Jinými slovy můžete takové makro opakovat 9999@q a automaticky dojde k jeho zastavení, i když změn bude prakticky vždy méně než 9999.

Příkazy dp a do lze použít i ve chvíli, kdy je vybraný blok textu. V tomto případě se změna aplikuje pouze na vybrané řádky, nikoli na celý blok změn.

Obrázek 14: Porovnávání dvou souborů při horizontálním rozdělení oken, které je vhodné využít v případě, že porovnávané zdrojové kódy (nebo jiné texty) obsahují dlouhé řádky.

6. Aplikace záplaty (patche)

Vim umí na právě editovaný soubor aplikovat záplatu (patch). Jediným omezením je, že záplata musí být připravena pro jeden soubor, nikoli pro více souborů současně. Vraťme se tedy na chvíli k prvnímu článku této série, v němž jsme si připravili záplatu s rozdíly mezi souborem old.py a new.py.

Záplata vypadá následovně:

--- old.py  2018-01-29 21:02:38.906134997 +0100
+++ new.py  2018-02-01 22:41:40.064274389 +0100
@@ -103,6 +103,10 @@
 
     use_token = parse_token_clause(token)
 
+    # three new lines
+    # three new lines
+    # three new lines
+
     url = component_analysis_url(context, ecosystem, component, version)
 
     for _ in range(timeout // sleep_amount):
@@ -115,22 +119,19 @@
         elif status_code != 404:
             raise Exception('Bad HTTP status code {c}'.format(c=status_code))
         time.sleep(sleep_amount)
-        # TODO: delete these three lines
-        # TODO: delete these three lines
-        # TODO: delete these three lines
     else:
         raise Exception('Timeout waiting for the component analysis results')
 
 
-@then('I should see 0 components')
 @then('I should see {num:d} components ({components}), all from {ecosystem} ecosystem')
-def check_components(context, num=0, components='', ecosystem=''):
+def check_components(context, num, components='', ecosystem=''):
     """Check that the specified number of components can be found."""
     components = split_comma_separated_list(components)
 
     json_data = context.response.json()
+    assert json_data is not None
 
-    search_results = json_data['result']
+    search_results=json_data['analysis']
     assert len(search_results) == num
     for search_result in search_results:
         assert search_result['ecosystem'] == ecosystem

Nejprve otevřeme původní verzi souboru old.py ve Vimu, a to naprosto běžným způsobem:

Obrázek 15: Původní soubor old.py běžným způsobem otevřený ve Vimu.

Následně je nutné použít příkaz:

:diffpatch old2new.patch

kde old2new.patch je jméno souboru s patchem:

Obrázek 16: Zadání příkazu :diffpatch.

Pokud se aplikace záplaty podaří, vytvoří se nový soubor a Vim se automaticky přepne do „režimu diff“, aby se zvýraznily změny vůči souboru původnímu:

Obrázek 17: Výsledný soubor se zobrazením změn provedených vůči původní variantě.

7. Porovnání tří verzí textového souboru ve Vimu

Jak jsme mohli vidět v předchozích kapitolách, je porovnání dvou verzí souborů poměrně snadné a většinou zde nenarazíme na vážnější problémy (snad jen na nutnost občasné synchronizace). Zajímavější a také poněkud složitější je postup, který se používá při porovnání tří verzí textového souboru a následně pro provedení třícestného sloučení změn (three-way merge). Víme již, že nutnost třícestného sloučení vznikne ve chvíli, kdy byla původní verze souboru modifikována jak lokálním autorem, tak i někým jiným. Naším úkolem je tedy zpracovat obě nezávisle na sobě vzniklé varianty a sloučit je do nové verze:

Vim je v tomto případě nutné spustit následujícím způsobem:

vim -d newest.py new.py old.py other.py

V tomto případě se zobrazí tři sloupcová okna, v nichž jsou všechny tři varianty souboru zobrazeny:

Obrázek 18: Zobrazení tří variant téhož souboru v režimu diff.

8. Provedení třícestného sloučení (merge)

Ve skutečnosti je však praktičtější si otevřít čtyři okna, přičemž první tři okna budou obsahovat historické varianty a budou v režimu read only, aby se omylem nepřepsal obsah jejich bufferů. Čtvrté okno bude naopak obsahovat výsledek příkazu diff3 -m new.py old.py other.py. Toto okno je vhodné zobrazit pod tři zmíněná okna, a to následujícím způsobem, který zajistí jak umístění čtvrtého okna, tak i nastavení režimu read only pro první tři okna:

vim -d newest.py new.py old.py other.py -c "wincmd J" -c "set modifiable" -c "set write"

Výsledek by měl vypadat takto:

Obrázek 19: Zobrazení tří variant téhož souboru; spodní okno slouží pro třícestný merge.

Poznámka: vytvořte si v .bashrc pomocnou funkci nazvanou například vimdiff3.

Příkazy pro pohyb na následující a předcházející změny budou stále pracovat v pořádku, ovšem u příkazů :diffget a :diffput dojde k chybě, protože Vim nebude vědět, kterých dvou oken ze čtyř se tyto příkazy týkají:

Obrázek 20: Příkazy :diffget a :diffput vyžadují číslo bufferu.

Z tohoto důvodu si nejdříve zjistěte čísla bufferů tímto příkazem:

:ls

Obrázek 21: Čísla bufferů, která se použijí společně s příkazy :diffget a :diffput.

Jakmile znáte čísla bufferů, je již možné jednotlivé změny postupně akceptovat ve výsledné variantě newest.py. Ve skutečnosti bude většina změn již aplikována korektně nástrojem diff3, takže bude jen nutné vyřešit případné konflikty (většinou částečně ručně odmazáním jedné z variant).

Obrázek 22: Výsledek příkazu :diffget 2.

Můžete si taktéž upravit .gitconfig, aby GIT volal Vim při provádění merge:

[merge]
    tool = vimdiff
    conflictstyle = diff3
 
[mergetool]
prompt = false
keepBackup = false

9. Přídavné moduly pro Vim, které zjednodušují porovnávání a slučování souborů

V navazujících kapitolách se zaměříme na popis některých užitečných pluginů, kterými je možné rozšířit základní (a nutno říci, že už tak velmi rozsáhlou) funkcionalitu Vimu při porovnávání a slučování souborů. Jedná se o tyto pluginy:

  1. DirDiff
  2. DiffChar
  3. Fugitive

Poznámka: vzhledem k tomu, že přídavné moduly je možné instalovat různými způsoby, ukážeme si u prvního pluginu (konkrétně u modulu pojmenovaného DirDiff) ruční instalaci (bez použití správce balíčků), dále instalaci za předpokladu, že pro správu balíčků používáte manažer Pathogen a samozřejmě nezapomeneme ani na ty uživatele, kteří dávají přednost použití správce balíčků Vundle. U dalších popisovaných pluginů se již nebudeme instalací do takovýchto podrobností zabývat, neboť se jedná stále o stejnou činnost.

10. Plugin DirDiff

První plugin naprogramovaný pro textový editor Vim, s nímž se v dnešním článku podrobněji seznámíme, je přídavný modul pojmenovaný DirDiff. Stránku s podrobnějšími informacemi o tomto modulu naleznete na adrese http://www.vim.org/scripts/scrip­t.php?script_id=102. Jméno pluginu DirDiff poměrně přesně vystihuje jeho hlavní činnost, neboť se skutečně jedná o modul, jenž je možné použít pro porovnání obsahu dvou vybraných adresářů, přesněji řečeno souborů uložených v těchto adresářích. Důležitý a užitečný je především fakt, že se porovnání provádí rekurzivně, tj. zpracovány jsou i případné podadresáře.

To se může hodit v mnoha situacích, například ve chvíli, kdy má uživatel na disku uložen pracovní adresář s nějakým projektem a na jiném médiu zálohu tohoto adresáře a potřebuje zjistit, které soubory se od poslední zálohy změnily (lze kombinovat například i s velmi užitečným příkazem rsync, to však již přesahuje téma tohoto článku). Pokud se nějaké soubory změnily, lze si prohlédnout jednotlivé rozdíly, podobně jako při explicitním volání vim -d soubor1 soubor2 nebo vimdiff soubor1 soubor2 a navíc má uživatel k dispozici několik příkazů určených pro synchronizaci souborů v obou porovnávaných adresářích (ty si popíšeme za chvíli).

11. Postup při ruční instalaci přídavného modulu DirDiff

Ruční instalaci pluginu DirDiff je nutné použít ve chvíli, kdy nepoužíváte žádný správce balíčků, což je sice možné, ovšem už při současné instalaci dvou a více pluginů se správce balíčků (Pathogen nebo Vundle) začíná vyplácet. Nicméně se i přesto podívejme, jak lze instalaci provést i bez správce balíčků. Do libovolného pracovního adresáře si nejdříve naklonujte repositář s obsahem pluginu:

$ git clone https://github.com/will133/vim-dirdiff

Následně je nutné ručně zkopírovat soubor dirdiff.txt do adresáře ~/.vim/doc a soubor dirdiff.vim do adresáře ~/.vim/plugin. Výsledek může vypadat například následovně (jedná se o strom souborů, který momentálně používám na Raspberry Pi, bez správce balíčků):

.vim
├── colors
│   └── vo_dark.vim
├── diffchar.vim
├── doc
│   ├── bufexplorer.txt
│   ├── dirdiff.txt
│   ├── help.vim
│   ├── NERD_tree.txt
│   └── tags
├── ftdetect
│   └── vo_base.vim
├── ftplugin
│   ├── vo_base.vim
│   ├── vo_checkbox.vim
│   └── vo_hoist.vim
├── indent
├── plugin
│   ├── bufexplorer.vim
│   ├── dirdiff.vim
│   └── NERD_tree.vim
├── spell
│   ├── cs.utf-8.add
│   └── cs.utf-8.add.spl
└── syntax
    ├── asciidoc.vim
    ├── clojure.vim
    ├── nerdtree.vim
    └── vo_base.vim

Při dalším spuštění Vimu bude plugin aktivní.

12. Instalace s využitím správce balíčků Pathogen

Nyní si ukažme častěji používaný postup při instalaci přídavného modulu DirDiff, a to konkrétně s využitím některého ze správců balíčků (Vim8 má navíc vlastního správce). V případě, že se pro konfiguraci, instalaci a inicializaci pluginů používá správce balíčků Pathogen, je instalace velmi jednoduchá, protože pouze stačí přejít do adresáře ~/.vim/bundle a v něm naklonovat repositář obsahující všechny důležité souboru pluginu DirDiff:

$ cd ~/.vim/bundle
 
$ git clone https://github.com/will133/vim-dirdiff
Cloning into 'vim-dirdiff'...
remote: Counting objects: 72, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 72 (delta 0), reused 0 (delta 0), pack-reused 67
Unpacking objects: 100% (72/72), done.
Checking connectivity... done.

Struktura adresáře ~/.vim může vypadat například následovně. Pro nás je v tuto chvíli důležitý zejména obsah podadresáře bundle s naklonovaným repositářem:

~/.vim
├── after
│   └── syntax
├── autoload
│   ├── help.vim
│   └── pathogen.vim
├── bundle
│   └── vim-dirdiff
│       ├── doc
│       │   └── dirdiff.txt
│       ├── plugin
│       │   └── dirdiff.vim
│       ├── README.md
│       └── screenshot.png
├── doc
│   └──
├── ftdetect
├── indent
├── macros
├── plugin
│   └── calendar.vim
├── spell
│   ├── cs.utf-8.add
│   ├── cs.utf-8.add.spl
│   ├── cs.utf-8.spl
│   ├── en.utf-8.add
│   └── en.utf-8.add.spl
└── syntax
    └── otl.vim

Po dalším spuštění Vimu by mělo dojít k automatickému načtení všech nainstalovaných pluginů, samozřejmě včetně pluginu DirDiff.

13. Instalace s využitím správce balíčků Vundle

V případě, že namísto správce balíčků Pathogen používáte Vundle, je instalace nového pluginu DirDiff poněkud odlišná. Celý postup si ukážeme na čtveřici screenshotů. Po instalaci samotného Vundle a spuštění příkazu :PluginInstall by se mělo vedle původního okna s dokumentem objevit další okno reprezentující ovládací panel správce balíčků Vundle:

Obrázek 23: Správce balíčků Vundle ve stavu ihned po své instalaci.

Příkazem search se zahájí hledání vhodného pluginu na základě části jeho jména. Pokud jméno specifikujete přesně (tedy „DirDiff“), vyhledá se jen jediný dostupný plugin:

Obrázek 24: Výsledek příkazu „search DirDiff“.

Příkazem innstall lze plugin nainstalovat, tj. stáhnout jeho zdrojové kódy. Následně je však nutné provést ruční úpravu souboru .vimrc, a to následujícím způsobem:

Obrázek 25: Povolení pluginu DirDiff v souboru .vimrc.

Po restartu Vimu a opětovném použití příkazu :PluginList se již nově nainstalovaný plugin objeví ve výpisu a lze ho ihned použít:

Obrázek 26: Po restartu Vimu již vidíme oba balíčky.

14. Základní použití přídavného modulu DirDiff

Použití přídavného modulu DirDiff je ve skutečnosti velmi jednoduché. Po spuštění textového editoru Vim stačí v normálním režimu použít příkaz:

:DirDiff cesta_k_prvnímu_adresáři cesta_ke_druhému_adresáři

Obrázek 27: Nápověda k pluginu DirDiff.

Po spuštění tohoto příkazu se okno textového editoru Vim rozdělí na několik částí (předpokládáme přitom, že původně byl v okně zobrazen jen jediný buffer). V části spodní je zobrazen seznam porovnávaných souborů a v části horní pak výsledky porovnání (vim diff) vybraného souboru ve verzi získané z prvního adresáře i z adresáře druhého. Navíc je v tomto speciálním režimu přepsán význam některých klávesových zkratek, zejména:

# Zkratka Význam
1 Enter zobrazí se rozdíl pro vybraný soubor (na němž se v daný okamžik nachází kurzor)
2 o má stejný význam jako předchozí zkratka (mnemotechnická pomůcka – o=open)
3 s provedení synchronizace s výběrem vhodné metody (kopie z prvního adresáře atd.)
4 u má stejný význam jako příkaz :diffupdate zadaný v příkazovém režimu
5 q ukončení režimu DirDiff a návrat do normálního režimu (normal mode)

Při synchronizaci klávesovou zkratkou s se zobrazí dotaz, jakým způsobem se má vlastně synchronizace provést. Pokud je Vim spuštěn v terminálu, je dotaz zobrazen samozřejmě taktéž v terminálu, ovšem v případě použití GVimu nebo KVimu se zobrazí plnohodnotný dialog.

Obrázek 28: Ukázka použití pluginu DirDiff. V dolním okně je zobrazen seznam souborů, v okně horním pak rozdíly mezi oběma variantami.

15. Plugin DiffChar

V mnoha případech je způsob zobrazení změn nabízený režimem diff poněkud nepřehledný, a to z toho důvodu, že se sice správně zobrazí změny provedené na jednom řádku, ovšem již se nezvýrazní, jakých znaků se tyto změny týkají. Tato užitečná funkcionalita, kterou jsme již mohli vidět minule u nástrojů vybavených grafickým uživatelským rozhraním, je implementována v přídavném modulu nazvaném jednoduše DiffChar. Zdrojové kódy tohoto pluginu naleznete na GitHubu, konkrétně na adrese https://github.com/rickho­we/diffchar.vim. Instalace se provádí stejně, jako tomu bylo u předchozího pluginu – modul je možné nainstalovat ručně, lze použít správce balíčků Pathogen popř. správce balíčků Vundle.

Obrázek 29: Klasický „režim diff“ ve chvíli, kdy se na řádku objevilo několik změn.

Obrázek 30: „Režim diff“ upravený pluginem DiffChar. Jednotlivé změny jsou zvýrazněny červeným a modrým pozadím.

16. Ukázka použití modulu DiffChar

Pokud instalace proběhla bez chyby, měl by být plugin po opětovném spuštění Vimu korektně inicializován a použit ve chvíli, kdy přejdeme do režimu diff. Plugin DiffChar, pokud je povolen, definuje některé nové klávesové zkratky, které jsou vypsány v následující tabulce:

Režim Zkratka Význam klávesové zkratky
normal F7 zapne nebo naopak vypne zvýraznění rozdílů pro všechny řádky
normal F8 zapne nebo naopak vypne zvýraznění rozdílů pro řádek, na kterém se nachází kurzor
visual F7 zapne nebo naopak vypne zvýraznění rozdílů pro vybrané řádky
visual F8 zapne nebo naopak vypne zvýraznění rozdílů pro vybrané řádky
normal [b skok na předchozí detekovanou změnu
normal ]b skok na následující detekovanou změnu
normal [e skok na konec předchozí detekované změny
normal ]e skok na konec následující detekované změny
normal <Leader>g synchronizace změny operací „get“ (tj. změna se získá ze druhého/neaktivního bufferu)
normal <Leader>p synchronizace změny operací „put“

Použití znaků [ a ] pro příkazy určené pro přesun kurzoru by nemělo být překvapivé, protože se tyto příkazy používají i ve standardním Vimu pro přesuny kurzoru po textových objektech (například na předchozí či následující metodu v Javě atd.).

Poznámka: za <Leader> si v předchozí tabulce doplňte klávesu nastavenou příkazem:

let mapleader=...

Typicky se mapleader nastavuje v souboru .vimrc. Výchozí klávesa je \, někteří uživatelé však používají čárku nebo dokonce mezerník (což vlastně není až tak špatný nápad).

Kromě klávesových zkratek je možné použít i nové příkazy, před nimiž je možné uvést rozsah (od, do, %, vizuální výběr bloku atd.):

Příkaz Význam příkazu
:[rozsah]SDChar zobrazení změn (Show/Set Diff Char)
:[rozsah]RDChar vypnutí zobrazení změn (Reset Diff Char)
:[rozsah]TDChar přepnutí mezi stavem zobrazení změn (zapnuto/vypnuto) (Toggle…)
:[rozsah]EDChar výpis změn na výstup, tj. do terminálu Vimu (Echo…)

Obrázek 31: Klasický „režim diff“ u našich ukázkových zdrojových kódů.

Jen pro úplnost si ukažme možnosti nastavení pluginu DiffChar:

Volba (globální) Volba (pro tab) Stručný popis volby
g:DiffUnit t:DiffUnit specifikace, jaké jednotky se mají porovnávat (slova, jednotlivé znaky…)
g:DiffColors t:DiffColors konfigurace barev, lze zvolit 4, 8, 16 barev nebo dokonce náhodný výběr
g:DiffPairVisible t:DiffPairVisible způsob zobrazení změn ve druhém okně ve chvíli, kdy se na změně nachází textový kurzor
g:DiffUpdate t:DiffUpdate povolení automatické synchronizace souborů v průběhu editace (viz :help diffupdate)
g:DiffSplitTime t:DiffSplitTime timeout pro interní algoritmus pro detekci změn (ten může být někdy pomalý)
g:DiffExpr   určuje, zda se má použít volba diffexpr (ve výchozím stavu povoleno)

Povšimněte si, že většinu voleb je možné nastavit buď globálně nebo pro aktivní tab. To je užitečné, protože je například možné na každém tabu použít odlišný algoritmus atd.

Obrázek 32: Použití pluginu DirDiff u změn provedených ve zdrojových kódech.

17. Plugin Fugitive

Druhým dnes popisovaným rozšiřujícím modulem určeným pro textový editor Vim je plugin nazvaný Fugitive. Tento rozšiřující modul slouží pro usnadnění práce s Gitem, resp. přesněji řečeno k práci se soubory uloženými v naklonovaných Git repositářích. A vzhledem k tomu, že se při spolupráci většího množství autorů nevyhneme konfliktům ve verzích souborů, kooperuje Fugitive s režimem diff. Plugin Fugitive je dostupný na adrese http://www.vim.org/scripts/scrip­t.php?script_id=2975, jeho vlastní Git repositář pak naleznete na adrese https://github.com/tpope/vim-fugitive.

Obrázek 33: Nápověda k pluginu Fugitive.

Instalace při použití správce balíčků Pathogen je triviální:

$ cd ~/.vim/bundle
 
$ $ git clone https://github.com/tpope/vim-fugitive
Cloning into 'vim-fugitive'...
remote: Counting objects: 2501, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 2501 (delta 0), reused 2 (delta 0), pack-reused 2496
Receiving objects: 100% (2501/2501), 897.06 KiB | 400.00 KiB/s, done.
Resolving deltas: 100% (969/969), done.
Checking connectivity... done.

Obrázek 34: Zobrazení historie posledních změn příkazem :Gdiff.

Po instalaci tohoto pluginu by měla struktura adresáře ~/.vim vypadat přibližně následovně (samozřejmě je možné, že již budete mít nainstalovány nějaké další pluginy, například ty popsané v předchozích kapitolách):

~/.vim
├── after
│   └── syntax
├── autoload
│   ├── help.vim
│   └── pathogen.vim
├── bundle
│   ├── vim-dirdiff
│   │   ├── doc
│   │   │   └── dirdiff.txt
│   │   ├── plugin
│   │   │   └── dirdiff.vim
│   │   ├── README.md
│   │   └── screenshot.png
│   └── vim-fugitive
│       ├── CONTRIBUTING.markdown
│       ├── doc
│       │   └── fugitive.txt
│       ├── plugin
│       │   └── fugitive.vim
│       └── README.markdown
├── doc
│   └──
├── ftdetect
├── indent
├── macros
├── plugin
│   └── calendar.vim
├── spell
│   ├── cs.utf-8.add
│   ├── cs.utf-8.add.spl
│   ├── cs.utf-8.spl
│   ├── en.utf-8.add
│   └── en.utf-8.add.spl
└── syntax
    └── otl.vim

Po instalaci pluginu Fugitive a po spuštění nové instance Vimu je pro každý buffer, který je součástí naklonovaného Git repositáře, k dispozici několik nových příkazů popsaných v navazujících dvou kapitolách. Důležité přitom je, že tyto příkazy jsou skutečně aktivní pouze pro buffery odpovídající souborům uloženým v Git repositáři.

Obrázek 35: I commit změn lze provést bez opuštění Vimu.

18. Příklad použití pluginu Fugitive

Otestování funkčnosti rozšiřujícího modulu Fugitive lze provést jednoduše. Nejprve je nutné přejít do adresáře, v němž se nachází soubory naklonované z Git repositáře; může se klidně jednat přímo o adresář s naklonovaným pluginem Fugitive. Následně se spustí Vim, GVim či KVim a otevře se buffer obsahující nějaký soubor, který je již součástí repositáře:

vim libovolny_soubor_z_gitu

Nyní by uživatel textového editoru Vim měl mít k dispozici velké množství nových příkazů, které všechny začínají na písmeno G (jedná se skutečně o velké G). Jak je však možné si tyto příkazy vypsat? Postačuje nepatrně změnit nastavení Vimu následujícím způsobem:

set wildmenu
set wildmode=list:longest,full

Posléze se všechny příkazy začínající na písmeno G zobrazí takto:

:G<Tab>

Obrázek 36: V závislosti na nastavení Vimu je možné si jednoduše vypsat všechny příkazy začínající na písmeno G s využitím :G[Tab].

Základní čtyři příkazy poskytované pluginem Fugitive jsou uvedeny v následující tabulce:

# Příkaz Význam
1 :Gpull zavolá příkaz git pull
2 :Gpush zavolá příkaz git push, případné chyby se vypisují do speciálního okna nazvaného quick window (stejně jako chyby při překladu atd.)
3 :Gcommit zavolá příkaz git commit (pokud došlo ke změnám) popř. git status (pokud nedošlo k žádným změnám). Při commitu se otevře nové okno pro zadání zprávy.
4 :Gmerge zavolá příkaz git merge, chyby se vypisují do speciálního okna nazvaného quick window (stejně jako chyby při překladu atd.)

Předností využití těchto příkazů oproti jejich ekvivalentům zadávaným z příkazové řádky je fakt, že se veškeré zprávy budou vypisovat přímo do bufferů/oken textového editoru Vim, při commitu se navíc zadání zprávy (commit message) provede v novém okně – to vše bez nutnosti opuštění prostředí Vimu. Pokud dojde k chybě, což se samozřejmě může stát, zejména v případě příkazu :Gmerge, jsou tyto chyby zobrazeny v okně quick window a navíc uloženy v paměti Vimu takovým způsobem, že je lze zpracovat tzv.quickfix příkazy, například:

Příkaz Stručný popis příkazu
:cc zobrazení chyby
:cn zobrazení další chyby
:cp zobrazení předchozí chyby

Obrázek 37: Takto vypadá výsledek příkazu :Glog.

19. Další možnosti pluginu Fugitive, zobrazení rozdílů mezi soubory, slučování verzí

Přídavný modul Fugitive ve skutečnosti uživatelům nabízí i poměrně velké množství dalších příkazů, které v menší či větší míře využívají faktu, že jsou spuštěny přímo v prostředí Vimu a nikoli na příkazové řádce. Pojďme si některé tyto příkazy alespoň ve stručnosti popsat:

# Příkaz Stručný popis příkazu
1 :Glog do takzvaného quickfix listu uloží informace o všech revizích aktuálně editovaného souboru. Mezi revizemi se lze přepínat například s využitím příkazů :cn a :cp, vypsat změny přes :clist
2 :Gllog podobný příkaz jako :Glog, ale používá seznam lokací, zde se používají příkazy :lprev a :lnext pro procházení revizemi
3 :Gstatus zobrazí aktuální stav Git repositáře, odpovídá git status
4 :Gblame aktuální okno se vertikálně rozdělí a v levém (novém) okně se pro každý řádek zobrazí autor poslední změny
5 :Gfetch odpovídá příkazu git fetch, opět se zapamatováním chybových zpráv
6 :Gdiff aktuální okno se rozdělí a zobrazí se změny v bufferu (používá se přitom režim vimdiff, takže dochází k synchronizaci při skrolování rozděleného okna atd.)
7 :Gsdiff stejné jako předchozí příkaz, ale okno je vždy rozděleno horizontálně
8 :Gvdiff stejné jako předchozí příkaz, ale okno je vždy rozděleno vertikálně (užitečnější, zejména na moderních širokoúhlých monitorech)
9 :Gread umožňuje do aktuálního bufferu načíst libovolnou revizi souboru

Pozor: některé výše popsané příkazy nefungují korektně, pokud máte ve .vimrc nastaveno :set shellpipe=2>. Bližší informace o této volbě naleznete v nápovědě Vimu:

:help 'shellpipe'

nebo v tomto případě (nedochází kolizi s názvem příkazu) jen:

:help shellpipe

Obrázek 38: Pomocí příkazu :Gcommit lze provést commit, a to bez nutnosti opuštění Vimu.

Velmi užitečný je v mnoha případech příkaz :Gread, který částečně odpovídá chování externího příkazu git checkout, ovšem provedeného jen pro aktuálně editovaný soubor/buffer (ve skutečnosti jsou možnosti :Gread mnohem větší, více je uvedeno v nápovědě). Tento příkaz se volá následovně:

:Gread revize

Po provedení tohoto příkazu se obsah bufferu změní takovým způsobem, že odpovídá zadané revizi. Revizi lze zadat mnoha způsoby, například:

Revize Význam
^ předchozí commit
~1 dtto
~2 verze před dvěma commity
~3 verze před třemi commity

Obrázek 39: Užitečný je taktéž příkaz :Gblame.

20. Odkazy na Internetu

  1. Plugin Diffchar
    https://github.com/vim-scripts/diffchar.vim
  2. DirDiff.vim : A plugin to diff and merge two directories recursively.
    http://www.vim.org/scripts/scrip­t.php?script_id=102
  3. vim-dirdiff na GitHubu
    https://github.com/will133/vim-dirdiff
  4. Vim-fugitive na GitHubu
    https://github.com/tpope/vim-fugitive
  5. Vim-fugitive na www.vim.org
    http://www.vim.org/scripts/scrip­t.php?script_id=2975
  6. vimdiff, nástroj drsňáků
    http://www.sw-samuraj.cz/2017/11/vimdiff-nastroj-drsnaku.html
  7. Comparing and Merging Files
    https://www.gnu.org/softwa­re/diffutils/manual/diffu­tils.html
  8. Three-way merge
    https://en.wikipedia.org/wi­ki/Merge_(version_control)#Three-way_merge
  9. diff (1) – Linux Man Pages
    https://www.systutorials.com/doc­s/linux/man/1-diff/
  10. diff utility (Wikipedia)
    https://en.wikipedia.org/wi­ki/Diff_utility
  11. GNU Wdiff
    https://www.gnu.org/software/wdiff/
  12. GNU wdiff Manual
    https://www.gnu.org/softwa­re/wdiff/manual/
  13. wdiff (1) – Linux Man Pages
    https://www.systutorials.com/doc­s/linux/man/1-wdiff/
  14. diff3 (1) – Linux Man Pages
    https://www.systutorials.com/doc­s/linux/man/1-diff3/
  15. sdiff (1) – Linux Man Pages
    https://www.systutorials.com/doc­s/linux/man/1-sdiff/
  16. Stránky nástroje Meld
    http://meldmerge.org/
  17. Meld na stránkách GNOME
    https://wiki.gnome.org/Apps/Meld
  18. Stránky nástroje TkDiff
    https://sourceforge.net/pro­jects/tkdiff/
  19. Zdrojové kódy TkDiffu
    https://sourceforge.net/pro­jects/tkdiff/files/tkdiff/4­.2/
  20. Poslední verze nástroje TkDiff
    https://sourceforge.net/pro­jects/tkdiff/files/latest/dow­nload
  21. Manuálová stránka k nástroji TkDiff
    http://linux.math.tifr.res­.in/manuals/man/tkdiff.html
  22. diffh: Make your diff easier to see
    https://inconsolation.wor­dpress.com/2013/10/07/dif­fh-make-your-diff-easier-to-see/
  23. Stránky projektu diffh
    https://sourceforge.net/pro­jects/diffh/
  24. Pretty Diff (implementovaný v JavaScriptu)
    http://prettydiff.com/
  25. Nástroje pro diff textů
    https://en.wikipedia.org/wiki/Diff-Text
  26. Pretty Diff (implementovaný v JavaScriptu)
    https://en.wikipedia.org/wi­ki/Pretty_Diff
  27. Stránky projektu colordiff
    https://www.colordiff.org/
  28. Skript idiff
    http://www.pixelbeat.org/scrip­ts/idiff
  29. Three way git merging with Meld
    https://lukas.zapletalovi­.com/2012/09/three-way-git-merging-with-meld.html
  30. xxdiff na serveru SourceForge
    https://sourceforge.net/pro­jects/xxdiff/
  31. Stránka nástroje KDiff3
    http://kdiff3.sourceforge.net/
  32. Seriál o programovacím jazyku TCL a GUI knihovně Tk
    https://www.root.cz/seria­ly/programovaci-jazyk-tcl/
  33. ActiveTcl
    https://www.activestate.com/activetcl
  34. Tiobe: žebříček popularity programovacích jazyků
    https://www.tiobe.com/tiobe-index/
Našli jste v článku chybu?