February 9, 2018

Creating Lists of Tagged Posts using Emacs Lisp Part 2

I previously implemented some lisp functions to allow me to generate list of posts tagged with a certain topic. I later found a bug in that method (which also affects org-static-blog which I referenced in the last post). To specify the tile of an org document you put #+title: Document Title at the beginning. However for long title, you can break this across multiple #+title: keywords. Both techniques of using regexp and using org-element-parse-buffer fail to parse multiple #+title: lines. However I’ve found org-export-get-environment does, as it is how the org exporters get the title.

In the process of fixing this, I also came across another bug. Org specifies that file-wide tags should be specified like so: #+FILETAGS: :Peter:Boss:Secret: however I was using white space to delimit tags (again because this is how org-static-blog does it).

Here’s the modified functions to show how I used org-export-get-environment to fix these bugs.

elisp code
(defun my-org-get-env-key (post-filename key)
  "Extract the value of `#+title:`, `#+author:`, `#+date:`, or `#+filetags:`
from post-filename."
  (with-temp-buffer (insert-file-contents post-filename)
                    (plist-get (org-export-get-environment) key)))

(defun my-blog-get-tag-tree ()
  "Return an association list of tags to filenames.
e.g. `(('foo' 'file1.org' 'file2.org') ('bar' 'file2.org'))`"
  (let ((tag-tree '()))
    (dolist (post-filename (my-blog-get-post-filenames))
      (let ((tags (my-org-get-env-key post-filename :filetags)))
        (dolist (tag tags)
          (if (assoc-string tag tag-tree t)
              (push post-filename (cdr (assoc-string tag tag-tree t)))
            (push (cons tag (list post-filename)) tag-tree)))))
    tag-tree))

(defun my-blog-posts-to-list (post-filenames)
  (seq-reduce
   (lambda (acc el) (concat acc "\n- " el))
   (seq-map (lambda (fname)
              (concat "/"  (car (my-org-get-env-key fname :date)) "/ "
                      (org-make-link-string
                       (concat "file:" (file-relative-name fname))
                       (org-export-data-with-backend
                        (my-org-get-env-key fname :title) 'org nil))))
            post-filenames)
   ""))

The final bug (hopefully) is fixed by calling org-export-data-with-backend on the title string to convert the string-with-text-properties back into an org-mode formatted string. Otherwise elements with org mode formatting such as for ~code~ won’t appear in our listing of posts.

I found this post on John Kitchin’s blog1 quite useful in solving this along with the org export reference docs.

Footnotes:

1

I can’t believe I went my entire undergrad at CMU without meeting Prof. Kitchin

Email: akira@akirakyle.com
GPG Public Key: 963C 2413 0BD3 BF1B 624C EF4C 8850 284C 20B8 078D