Post-processing an org-buffer on export

| categories: emacs, orgmode | tags:

In a previous post we examined getting tooltips on emacs keybindings and command syntax in an org-buffer. Someone asked in a comment if we could get that to export to html, or LaTeX. The short answer is not directly, org-mode doesn't recognize our functionalized syntax as an element, and there is no direct way to modify their appearance on export.

There is, however, a hook function that runs before parsing, and we can use that to transform these patterns to what we want. Here, I illustrate how to make the key-bindings and commands bold with a tooltip on them for an html export. Basically, we do an export, and then post-process the html output to put what we want in. I found this easier than pre-processing because the documentation for the command tooltip was too big to fit into an html snippet, and an html block causes carriage returns in the html. I didn't find a more elegant solution to that problem.

Here we replace the key-binding syntax with the actual keybinding in bold, and a tooltip of the command, and the command syntax we replace with bold command and a tooltip for the documentation. It works pretty well. The documentation for helm is pretty extensive, and gets cutoff in the tooltip. Otherwise, this seems pretty satisfactory.

This won't show in the blog post, so you will have to checkout the exported html here: blog.html .

Try \C-x C-f to open a file. You might enjoy using helm too. Or this variable org-agenda-files.

(require 'rx)

(defvar elisp-symbol-keybinding-re
   ;; opening \\[
   (eval "\\[")
   ;; one or more characters that are not ]
   (group (one-or-more (not (any "]"))))
   ;; The closing ]
"Regexp for an elisp command keybinding syntax. \\[some-command]
Regexp group 1 matches src_emacs-lisp[:results html]{(command-html "some-command")}.")

(defun org-process-key-bindings (backend)
  (goto-char (point-min))
  (while (re-search-forward elisp-symbol-keybinding-re nil t)
      ((eq backend 'html)
       (format "<b title=\"The command is %s.\">%s</b>"
               (match-string 1)
               (substitute-command-keys (match-string 0))))))))

(defun org-process-emacs-commands (backend)
  (goto-char (point-min))
  (while (re-search-forward "`\\([^']+\\)'" nil t)
      ((eq backend 'html)
       (format "<b title=\"%s\">%s</b>"
          (if (or (fboundp (intern (match-string 1)))
                  (boundp (intern (match-string 1))))
              (documentation (intern (match-string 1)))
            "No command found.")
          (match-string 1)))))))

(with-current-buffer (org-html-export-as-html)
  (org-process-key-bindings 'html)
  (org-process-emacs-commands 'html)
  (write-file "blog.html")
  (browse-url "blog.html"))

1 Update: A filter approach to exporting

Our patterns are all in org-paragraphs. We can use a filter to modify the paragraph after it is "transcoded". Here is the filter function. It basically does the same thing, through another mechanism.

(defun my-paragraph-filter (data backend info)
   ((eq 'html backend)
    ;; emacs commands
    (setq data (replace-regexp-in-string
                (lambda (x)
                  (string-match "`\\([^']+\\)'" x)
                  (when (match-string 1 x)
                    (format "<b title=\"%s\">%s</b>"
                            (if (or (fboundp (intern (match-string 1 x)))
                                    (boundp (intern (match-string 1 x))))
                                (documentation (intern (match-string 1 x)))
                              "No command found.")
                            (match-string 1 x))))
    ;; keybindings
    (setq data (replace-regexp-in-string
                (lambda (x)
                  (string-match "\\\\\\[\\([^]]+\\)]" x)
                  (when (fboundp  (intern (match-string-no-properties 1 x)))
                    (format "<b title=\"The command is %s.\">%s</b>"
                            (match-string 1 x)
                            (substitute-command-keys (match-string 0 x)))))

(add-to-list 'org-export-filter-paragraph-functions 'my-paragraph-filter)
(browse-url (org-html-export-to-html))
#<process open ./blog.html>

Try the command org-ref to check your document for issues. Insert a citation with org-ref using \M-ESC C.

Now, this should show up in the blog!

Copyright (C) 2015 by John Kitchin. See the License for information about copying.

org-mode source

Org-mode version = 8.2.10

Discuss on Twitter