Export org file embedded with code snippets

  |   Source

CREATED: <2014-11-20 Thu>

UPDATED: <2015-06-06 Sat>

1 problem

I use Org-mode to record all my notes.

As a developer, I place code snippets from many programming languages into one org file.

The issue is when exporting the org file, major mode for each language will be loaded to render the code snippet.

It means the hooks of the major modes will be executed. Since I put lots of heavy weight setup things in those hooks, my exporting is extremely slow.

My hooks are also dependent on third party tools. So if anyone else uses my setup without those tools, his/her exporting will fail.

2 Solution

2.1 Setup

In order to solve the issue, I write a small function which will be called at the beginning of each major mode hook.

The function basically check whether the `(buffer-file-name)` is the temporary file created by Org-mode or the output HTML converted from org file. If answer is "YES", then code in major mode hook will not be executed.

(defvar load-user-customized-major-mode-hook t)
(defvar cached-normal-file-full-path nil)
(defun is-buffer-file-temp ()
  (interactive)
  "If (buffer-file-name) is nil or a temp file or HTML file converted from org file"
  (let ((f (buffer-file-name))
        org
        (rlt t))
    (cond
     ((not load-user-customized-major-mode-hook) t)
     ((not f)
      ;; file does not exist at all
      (setq rlt t))
     ((string= f cached-normal-file-full-path)
      (setq rlt nil))
     ((string-match (concat "^" temporary-file-directory) f)
      ;; file is create from temp directory
      (setq rlt t))
     ((and (string-match "\.html$" f)
           (file-exists-p (setq org (replace-regexp-in-string "\.html$" ".org" f))))
      ;; file is a html file exported from org-mode
      (setq rlt t))
     (t
      ;; avoid calling to file-exists-p too often for performance reason
      (setq cached-normal-file-full-path f)
      (setq rlt nil)))
    rlt))

2.2 Usage

I use python-mode-hook setup as an example:

(add-hook 'python-mode-hook
          '(lambda ()
             (unless (is-buffer-file-temp)
               (anaconda-mode)
               (eldoc-mode)
               (if (executable-find "pyflakes")
                   (flymake-python-pyflakes-load))
               (setq electric-indent-chars (delq ?: electric-indent-chars))
               )))

3 Tips

3.1 Export shell code

Exporting shell code will fail if `sh-mode` is loaded. So I use "bash" instead. Since there is no "bash-mode", exporting will be fine.

3.2 Yasnippet setup

To avoid loading yasnippets when exporting, I have to "use yas-minor-mode on a per-buffer basis".

3.3 Manually turn off the major-mode hook

It's controlled by global flag `load-user-customized-major-mode-hook`, as you can see from the "Setup" section.

Say I want to turn off the major mode hooks when `M-x org-publish`, here is the setup:

(defadvice org-publish (around org-publish-advice activate)
  "Stop running major-mode hook when org-publish"
  (let ((old load-user-customized-major-mode-hook))
    (setq load-user-customized-major-mode-hook nil)
    ad-do-it
    (setq load-user-customized-major-mode-hook old)))

3.4 after-save-hook

`after-save-hook` is the "Normal hook that is run after a buffer is saved to its file". You may also need tweak it up because it will be called when exporting org files

Comments powered by Disqus