Skip to content

Latest commit

 

History

History
472 lines (362 loc) · 13.3 KB

with-export-examples.org

File metadata and controls

472 lines (362 loc) · 13.3 KB

Examples for org-generate-with-export

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).

Table of Contents

Use a macro to set heading title

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

Get user input to set the heading title

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/

Get user input - avoid multiple evaluations

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}}}

Set the :org-generate-root: property with a macro

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/

Use a property value to set :org-generate-root: with a macro

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".

Use variables from a emacs lisp list

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 a file

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.

Include a file with filename from argument

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}}}

Split the template into multiple files with include

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

Noweb reference syntax - include results in source block

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

Exported source blocks

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.

Inline source block

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.

Create root directory if it doesn’t exist

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

Use a source block to copy file below root

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

Expand a macro with elisp

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.

Do something after org-generate

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()