This file contains examples of additional org features available when using
org-generate-with-export-as-org
is set to t
. This is by no means complete,
there are endless possibilities.
Some useful features are (links to the org-mode manual):
If enabled it exports target’s heading and its subtree, its parent heading including the content before the first child , and the content before the first heading. This is important so you know which macros and source blocks are available.
Use M-x org-org-export-as-org
while inside the org-capture template buffer to
see what results you will get before running the function. Make sure to add
#+OPTIONS: prop:t
at the top if any properties need to be exported (this is
not needed for the actually export as org-generate
automatically exports the
properties).
- Use a macro to set heading title
- Get user input to set the heading title
- Get user input - avoid multiple evaluations
- Set the :org-generate-root: property with a macro
- Use a property value to set :org-generate-root: with a macro
- Use variables from a emacs lisp list
- Include a file
- Include a file with filename from argument
- Split the template into multiple files with include
- Noweb reference syntax - include results in source block
- Exported source blocks
- Inline source block
- Create root directory if it doesn’t exist
- Use a source block to copy file below root
- Expand a macro with elisp
- Do something after org-generate
Set the title of the heading with a macro:
#+OPTIONS: prop:t
* hugo
#+MACRO: filename page.md
** page
:PROPERTIES:
:org-generate-root: ~/dev/repos/hugo-src/content/blog/
:END:
*** {{{filename}}}
The macro is replaced with:
*** page.md
Set the title of the heading with a macro. To evaluate emacs lisp inside a macro
use eval
:
#+OPTIONS: prop:t
* hugo
#+MACRO: get-directory (eval (format "%s/" (read-string "Directory: ")))
** page
:PROPERTIES:
:org-generate-root: ~/dev/repos/hugo-src/content/blog/
:END:
*** {{{get-directory}}}
You will be prompted for a directory. If you input test
the macro is replaced
with:
*** test/
Each time a macro is expanded any emacs-lisp in it is reevaluated. If you reuse a macro that ask you for an input you probably don’t want it to ask you over and over. To get around use a local variable:
#+NAME: licence
#+BEGIN_SRC emacs-lisp :exports none :results raw :wrap src text
(unless (and (boundp 'my-var-licence) my-var-licence)
(setq-local my-var-licence (completing-read "Licence: " '("mit" "gplv3") nil t)))
(org-export-string-as (concat "#+INCLUDE: \"~/projects/licences/" my-var-licence ".txt\"") 'org t)
#+END_SRC
#+CALL: licence()
#+CALL: licence()
Could use a macro as well with org-sbe
:
#+MACRO: licence (eval (org-sbe "licence"))
{{{licence}}}
{{{licence}}}
To make this work you have to use a macro that sets the whole line.
org-sbe
is used to get the result from the source block named hugo-root
inside the macro. That function is great to combine macros and source blocks.
The macro uses an argument that can be used when calling the macro and inside
the macro as $1
.
#+OPTIONS: prop:t
* hugo
#+NAME: hugo-root
: ~/dev/repos/hugo-src/
#+MACRO: hugo-root (eval (concat ":org-generate-root: " (org-sbe "hugo-root") $1))
** page
:PROPERTIES:
{{{hugo-root(content/blog/)}}}
:END:
The macro line expands to:
:org-generate-root: ~/dev/repos/hugo-src/content/blog/
Uses the value of the inherited property root
:
#+OPTIONS: prop:t
#+MACRO: hugo-root-path (eval (concat ":org-generate-root: " (org-entry-get-with-inheritance "root") $1))
* hugo
:PROPERTIES:
:root: ~/dev/repos/hugo-src/
:END:
** page
:PROPERTIES:
{{{hugo-root-path(content/blog/)}}}
:END:
The macro will be replaced with:
:org-generate-root: ~/dev/repos/hugo-src/content/blog/
This could also be separated into a source block and macro. While the macro is evaluated at the place you use it (each time), the source block is evaluated where it actually is even when calling from a macro. Therefore it needs to be moved below the heading to make it work. This means that it will always use the same root and therefore it is not a good solution for this:
#+OPTIONS: prop:t
* hugo
:PROPERTIES:
:root: ~/dev/repos/hugo-src/
:END:
#+NAME: root
#+BEGIN_SRC emacs-lisp :exports none :results raw :var path=""
(concat ":org-generate-root: " (org-entry-get-with-inheritance "root") (format "%s" path))
#+END_SRC
#+MACRO: hugo-root-path (eval (org-sbe "root" (path $$1)))
** page
:PROPERTIES:
{{{hugo-root-path(content/blog/)}}}
:END:
* another
:PROPERTIES:
:root: ~/another/
:END:
** page
:PROPERTIES:
{{{hugo-root-path(content/blog/)}}}
:END:
In this case both are unexpectedly replaced with:
:org-generate-root: ~/dev/repos/hugo-src/content/blog/
When using a string for a variable with org-sbe
it has to be prefixed with
another $
. Here $$1
or if a string like $"string"
.
Store variables with emacs lisp and a source block and access them with org-sbe
:
#+NAME: variables
#+BEGIN_SRC emacs-lisp
'(:folder "~/.emacs.d"
:license "mit")
#+END_SRC
#+NAME: get-var
#+BEGIN_SRC emacs-lisp :var vars=variables var=""
(plist-get vars (intern-soft var))
#+END_SRC
#+MACRO: emacs-test (eval (org-sbe "get-var" (var $$1)))
{{{emacs-test(:folder)}}}
The macro is expanded into:
~/.emacs.d
Include another file at any place in your template. Make sure it is wrapped in a block if needed.
#+INCLUDE: "~/projects/licences/gplv3.txt" src text
#+INCLUDE: "~/.emacs.d/init.el" src emacs-lisp
#+INCLUDE: "./paper.org::#theory" :only-contents t
Macros in an included file get replaced as well. An include in an included org file works as well.
Found two solutions for this, with org and exporting one just needs to get a bit creative sometimes.
First one uses org-export-string-as
. This function could actually be used for
a lot of other stuff as well.
#+MACRO: include-file (eval (org-export-string-as (concat "#+INCLUDE: \"~/projects/licences/" $1 ".txt\" src text") 'org t))
{{{include-file(gplv3)}}}
The second solution expands the macro to insert the #+INCLUDE: ...
and uses a
macro to trigger the expansion. This is needed as the macros are replaced after
inclusion and therefore the file would never be included.
#+MACRO: include #+INCLUDE: "~/projects/licences/$1.txt" src text
#+MACRO: include-expand (eval (progn (org-export-expand-include-keyword) ""))
{{{include(gplv3)}}}
{{{include-expand}}}
Include files to split the template into multiple files. This example includes
the contents from the heading page
found in hugo.org
inside the directory
where org-generate.org
is placed:
#+OPTIONS: prop:t
* hugo
** page
:PROPERTIES:
:org-generate-root: ~/dev/repos/hugo-src/content/blog/
:END:
#+INCLUDE: hugo.org::*page :only-contents t
The file hugo.org
has the following content:
* page
:PROPERTIES:
:org-generate-root: ~/dev/repos/hugo-src/content/blog/
:END:
** text.txt
#+BEGIN_SRC text
Some text
#+END_SRC
This is exported as:
* hugo
** page
:PROPERTIES:
:org-generate-root: ~/dev/repos/hugo-src/content/blog/
:END:
*** text.txt
#+begin_src text
Some text
#+end_src
Include the code or the result of other source blocks with noweb. Check the the Noweb Reference Syntax in the org manual.
An example with a simple named block and a shell source block:
#+NAME: year
: 2020
#+NAME: whoami
#+BEGIN_SRC sh
whoami
#+END_SRC
#+BEGIN_SRC emacs-lisp :noweb yes
;; by <<whoami()>> in <<year()>>
#+END_SRC
The emacs source block will be exported to:
#+begin_src emacs-lisp
;; by hubisan in 2020
#+end_src
In the header arguments of the source code you can define what will be exported
(:exports code
, :exports result
, :exports both
, :exports none
).
This can for instance be used to insert the results of a source block. In this case to include a file with emacs-lisp.
#+BEGIN_SRC emacs-lisp :exports results :results raw :wrap src text
(org-export-string-as "#+INCLUDE: \"~/projects/licences/gplv3.txt\"" 'org t)
#+END_SRC
The result gets wrapped in a source block (:wrap src text
) and the code is not
exported because of the header arguments :exports: results
.
You can use an inline source block. Only downside is that you can’t get rid of the spaces around it as far as I know.
This is some src_elisp[:results raw]{(concat "inline" "-" "code")}.
After exporting this looks as follows:
This is some inline-code.
This creates the root directory if it doesn’t exist, and if necessary the parent directories.
* Example
#+NAME: create-root
#+BEGIN_SRC emacs-lisp :exports none :results silent :var source="" dest=""
(let* ((copy-root (org-entry-get-with-inheritance "org-generate-root"))
(unless (file-exists-p copy-dir)
(make-directory copy-dir t))
#+END_SRC
** Project
:PROPERTIES:
:org-generate-root: ~/org-generate-test/
:END:
#+CALL: create-root()
*** text.txt
#+BEGIN_SRC text
Some text.
#+END_SRC
Copy in this case an image to the root. The directory is created if it doesn’t exist.
* Example
#+NAME: copy-image
#+BEGIN_SRC emacs-lisp :exports none :results silent :var source="" dest=""
(let* ((copy-root (org-entry-get-with-inheritance "org-generate-root"))
(copy-fname (expand-file-name (concat copy-root dest)))
(copy-dir (file-name-directory copy-fname)))
;; Create the directory if it doesn't exist.
(unless (file-exists-p copy-dir)
(make-directory copy-dir t))
(copy-file source copy-fname t))
#+END_SRC
** Project
:PROPERTIES:
:org-generate-root: ~/org-generate-test/
:END:
#+CALL: copy-image(source="~/image.png", dest="img/image.png")
*** text.txt
#+BEGIN_SRC text
Some text.
#+END_SRC
To expand a macro with elisp you can call org-macro-expand
as follows:
(org-macro-expand '(macro (:key "author" :args nil)) org-macro-templates)
(org-macro-expand '(macro (:key "property" :args ("prop"))) org-macro-templates)
This could be useful for org-sbe
or to use the macro with the noweb reference
syntax in a source block.
org-generate
supports a property to set functions to call before or after.
This examples uses a source block to define the function that will be called
after. Like this you can have everything in the template and you don’t have to
define the function somewhere else.
* Project
** test
:PROPERTIES:
:org-generate-root: ~/example/
:org-generate-after-hook: my-called-after
:END:
#+NAME: after-org-generate
#+BEGIN_SRC emacs-lisp :exports none :results silent
(defun my-called-after ()
(message "called after"))
#+END_SRC
#+CALL: after-org-generate()