doom_config_settings/ronny/parser.el

109 lines
4.3 KiB
EmacsLisp

;;; ronny/parser.el -*- lexical-binding: t; -*-
;; extract links from HTML
;; take exported HTML like
;; <a href="url1">some text</a>
;; <a href="url2">other text</a>
;;
;; turn it to Lisp data
;; (("url1" . "some text")
;; ("url2" . "other text"))
;;
;; arguments
;; html
;;
;; 1a create a local variable items, initiall empty (nil)
;; 2a create a temporary scratch buffer to search through the HTML text safely
;; 2b put the HTML string into that temporary buffer
;; 2c go to the start of the buffer
;; 3a loop through links
;; 3b search for links of the form
;; <a href="URL">CAPTION</a>
;; 4a store each link and build a pair ("url" . "caption") and push it into 'items'
;; 5a reverse the order because push built the list backwards, so restore original order
(defun ronny-parser--extract-html-links (html)
"Extract (url . caption) pairs from exported HTML links."
(let (items) ;; 1a
(with-temp-buffer ;; 2a
(insert html) ;; 2b
(goto-char (point-min)) ;; 2c
(while (re-search-forward ;; 3a
"<a href=\"\\([^\"]+\\)\">\\([^<]+\\)</a>" ;; 3b
nil t)
(push (cons (match-string 1) (match-string 2)) items))) ;; 4a
(nreverse items))) ;; 5a
;; convert parsed links into final HTML
;;
;; take list data of the form
;; (("url1" . "caption1")
;; ("url2" . "caption2"))
;;
;; and turn it into
;; <div class="image-row">
;; <div class="image-item"><a href="url1"><img src="url1" width="150"><div class="caption">shy cat</div></a></div>
;; <div class="image-item"><a href="url2"><img src="url2" width="150"><div class="caption">happy cat</div></a></div>
;; </div>
;;
;; arguments:
;; items -> list of (url . caption) pairs
;;
;; 1a create the row container leave %s as the place whre all image items go
;;
;; 2a build all items
;; map over each item
;; convert it to a string
;; join them together
;;
;; 2b for each item process one pair at a time
;; 2c split pair into url and caption
;;
;; 2d build image block
;; 2e join with newlines
(defun ronny-parser--build-image-row-html (items)
"Build custom image row HTML from ITEMS."
(format ;; 1a
"<div class=\"image-row\">\n%s\n</div>" ;; 1a
(mapconcat ;; 2a
(lambda (item) ;; 2b
(let ((url (car item)) ;; 2c
(caption (cdr item))) ;; 2c
(format ;; 2d
"<div class=\"image-item\"><a href=\"%s\"><img src=\"%s\" width=\"150\"><div class=\"caption\">%s</div></a></div>"
url url caption)))
items ;; 2e
"\n"))) ;; 2e
;; filter the exported special block
;; this is the function Org calls during export
;; if HTML export, transform it. otherwise leave it alone
;;
;; arguments:
;; text - exported text for the special block
;; backend - export target (html, latex, etc)
;; info - export metadata
;;
;; 1a check backend and only do custom logic for HTML
;; 2a extra links. parse the block's HTML and get (url . caption) list
;; 2b if links found rebuild block as custom image row
;; otherwise return original text
(defun ronny-parser-filter-image-row (text backend info)
"Replace an exported image_row special block with custom HTML."
(if (org-export-derived-backend-p backend 'html) ;; 1a
(let ((items (ronny-parser--extract-html-links text))) ;; 2a
(if items ;; 2b
(ronny-parser--build-image-row-html items) ;; 2b
text)) ;; 2b
text))
;; register the filter with Org
;; after export machinery is loaded use this function for special blocks
;;
;; 1a ox is Org export. prevents errors if export code is not loaded yet
;; 1b add the function to the list of special-block filters
(with-eval-after-load 'ox ;; 1a
(add-to-list 'org-export-filter-special-block-functions ;; 1b
#'ronny-parser-filter-image-row)) ;; 1b