Orgmode Export Process
Table of Contents
1. Overview
The org-mode export process consists of these steps:
- run functions in
org-export-before-processing-hook
- expand
include(#+INCLUDE: ...)
keywords - expend
macro({{{macro}}})
keywords - execute babel code blocks
- run functions in
org-export-before-parsing-hook
- export with specified backend
You can use some of these steps to generate dynamic content during the export process.
2. Use macros to define text snippets
As the manaul page says, you can define text snippets with macro like this:
#+MACRO: use I use $1
then {{{use(Emacs)}}}
will become 'I use Emacs' after export.
Yes, strictly, macro is not such dynamical, but only simple replacement(with arguments).
3. Use babel code blocks to generate content
You must have heard 'literal programming' if you are already an orgmode user: the awesome project Babel allows many different languages work together, we can export both the codes themselves and the output/return-value of them(yeah, by executing the codes). If you are still not very familiar with Babel, you can read the introduction right now, and I will give few simple samples here.
generate table by python code:
#+BEGIN_SRC python :exports results :results table a = (1,2,"string \\vert string") b = (4,5,6) return (a,b) #+END_SRC
will generate the table below:
- generate raw output by elisp:
define a named code block
#+name: test-0 #+BEGIN_SRC elisp :exports none (princ "OUTPUT *STRING* will be captured") #+END_SRC
call the named code block
test-0
, capture the output:#+CALL: test-0[:results output]() :results raw
the output will be considered as raw org source:
OUTPUT STRING will be captured
4. Define named code blocks and macro in a separate file
The include
keywords are expanded before macros expansion and babel
code blocks execution, so you can write all frequently used macros
and code blocks(with a name) in a separate org file, then include it
in other org files, here is an example.
5. Use dynamic block to generate content
Babel code blocks and macros can satisfy our requirements of dynamic content generation in almost all situations, but, today I encounter an exceptional one:
I want to generate include
instruction dynamically, because the
path of the included file is calculated dynamically based on the
path of current org file.
We can't use babel code blocks because these blocks are expanded
after the expansion of the include
keywords, neither can we use
the macro because both of the expansion order and that macro
expansion is only simple replacement.
What should I do? Fortunately we have anthor weapon:
Dynamic Blocks. So I define a dynamic block to generate the
include
instruction dynamically:
(defun org-dblock-write:inc-file (params) (let ((file (plist-get params :file))) (insert (concat "#+INCLUDE: " (get-path-dynamically)))))
and then add org-update-all-blocks
to
org-export-before-processing-hook
:
(add-hook 'org-export-before-processing-hook (lambda (backend) (org-update-all-dblocks)))
Now, I can write:
#+BEGIN: inc-file :file "common.inc.org" #+END:
in my org files, cheers!
6. More samples
I'm using orgmode to build this site, and the source can be found at https://github.com/KDr2/kdr2-on-web, you can find all the tricks I metioned above in this repository.
7. Discuss and Comment
Have few questions or feedback? Feel free to send me(killian.zhuo📧gmail.com) an email!