Vim: (dávkové) spouštění ex příkazů
Publikováno: 28.3.2020
Text vyšel původně na autorově webu.
Co jsem řešil?
Když jsem před časem zmigroval web na Hugo, bylo to celkem jednoduché — tehdejší verze Hugo bez problémů požrala HTML čurbes z Bloggeru a tak s tím nebylo moc starostí.
Bohužel, od verze v0.60.0 změnil Hugo Markdown knihovnu — z Blackfriday na Goldmark a mě se přestaly renderovat všechny nevyčištěné stránky (tedy ty, nepřevedené na čistý Markdown).
Rozhodl jsem se na to jít z gruntu a všechen HTML balast odstranit. To je hodně práce. A protože píšu ve Vimu, tak jsem čistil… ve Vimu.
Okno s historií příkazů
Přítelem každého Vim-uchyláka je bravurní znalost (Vim-flavored) regexů. A když vás po čase přestane bavit je psát zpaměti, začnete je hledat v historii.
Knížce Practical Vim vděčím mimo jiné za to, že vím, k čemu je ten příkaz, který mě vždycky přiváděl k šílenství, když jsem chtěl zavřít buffer, a omylem jsem se překlepl, takže jsem místo :q
napsal q:
Příkazy q:
, q/
a q?
totiž otevřou command-line window s načtenou historií :
, či /
příkazů. Výhodou je, že se v tom okně můžete chovat jako ve Vimu. Můžete v něm vyhledávat, kopírovat, editovat… A znovu spouštět dané příkazy.
Spuštění příkazů ze souboru
Vyhledání a spuštění nějakého složitější příkazu je sice fajn, ale jsou tu dva problémy:
- Jednak jde o historii a ta má nějaký limit (třeba já mám defaultní
history=200
), takže po čase může příkaz zmizet. - Pokud zpracovávám více souborů, je to repetitivní a chtělo by to nějak naskriptovat.
Ke slovu tak přichází příkaz source, který načte sadu příkazů ze souboru a postupně je provede.
Pro potřeby čištění blogu jsem si vytvořil následující sadu příkazů:
" -------------------
" Generic markdownify
" -------------------
" Put every tag to new line
%s/></>\r</g
" Separate paragraphs by one line
%s/<br \/>\n*<br \/>/\r\r/
%s/\n\n\{2,}/\r\r/
" Markdownify links
%s/<a href="https\?:\(.\{-}\)">\(.\{-}\)<\/a>/[\2](\1)/g
" Markdownify bold, cursiva & strikethrough
%s/<i>\(.\{-}\)<\/i>/_\1_/g
%s/<b>\(.\{-}\)<\/b>/**\1**/g
%s/<strike>\(.\{-}\)<\/strike>/\~\~\1\~\~/g
" Markdownify headers
%s/<h2.\{-}>\(.\{-}\)<\/h2>/## \1\r\r/g
%s/<h3.\{-}>\(.\{-}\)<\/h3>/### \1\r\r/g
%s/<h4.\{-}>\(.\{-}\)<\/h4>/#### \1\r\r/g
" Markdownify monospace
%s/<span.\{-}monospace.\{-}>\(.\{-}\)<\/span>/`\1`/g
" Markdownify items
%s/<li>\n\?\(.\{-}\)\n\?<\/li>/* \1/
" Replace a non-breaking-space with a space
%s/ / /g
" Markdownify dashes
%s/ - / --- /g
" Markdownify blockquotes
%s/<blockquote.\{-}>\n\?\(.\+\)\n\?<\/blockquote>/> \1\r\r/g
" -------------------------
" External sites shortcodes
" -------------------------
" Markdownify gists
%s/<script .\{-}\(gist\)\.github\.com\/\(.\{-}\)\/\(.\{-}\)\.js">\n\?<\/script>\s*\(<br \/>\)\?/{{< \1 \2 \3 >}}\r\r/g
" ---------------------------
" sw-samuraj.cz & clojure.cz specific changes
" ---------------------------
" Remove following prefix from links, plus .html suffix:
" * //sw-samuraj.cz
" * //www.sw-samuraj.cz
" * http://sw-samuraj.cz
" * https://sw-samuraj.cz
" * http://www.sw-samuraj.cz
" * https://www.sw-samuraj.cz
%s/(\(https\?:\)\?\/\/\(w\{3}\.\)\?sw-samuraj\.cz\(\/.\{-}\)\.html)/(\3\/)/cg
" Remove following prefix from links, plus .html suffix:
" * //clojure.cz
" * //www.clojure.cz
" * http://clojure.cz
" * https://clojure.cz
" * http://www.clojure.cz
" * https://www.clojure.cz
%s/(\(https\?:\)\?\/\/\(w\{3}\.\)\?clojure\.cz\(\/.\{-}\)\.html)/(\3\/)/cg
Teď stačí zadat v editoru tenhle příkaz a mám vyčištěno!
:source srcipts/html-to-markdown.vim
Fakt je to tak jednoduchý?
Jasně, je. Pořeší se tím všechno, co se dá zvládnout regulárním výrazy. Samozřejmě, my, co jsme měli na škole dva semestry předmětu Regulární a bezkontextové jazyky a není nám neznámá Chomského hierarchie jazyků víme, že některé problémy se regexem vyřešit nedají. Ale na čištění HTML to bohatě stačí… (tak z 95 %).
Happy sourcing!