My aim is to write dynamic reports which will be generated using a base skeleton file and snippets that correspond to and parametrise the particular issues. These issues are all content-wise similar and can be represented using exactly the same logical structure. The Emacs' org-mode
seemed like a perfect solution given the power which comes with org-babel
. My question is if there exist an Org Mode Way (tm) to deal with this problem. I will lay out my current approach below, but I hope someone has a less cumbersome solution.
The structure of my org dynamic report as follows,
skeleton.org:
- include1.org
- include2.org
- ...
body
where include org files (plugged in using #+INCLUDE:
) mostly contain #+MACRO macroname macro
definitions and :PROPERTY:
blocks.
I was originally intending to use {{{macroname}}}
substitutions and to read in the parameters into the skeleton and generate the report. However, while #+MACRO:
definitions work within many elements of org-mode
, their major drawback is that one cannot substitute them into :var varname=value
#+HEADER
declarations, or #+CALL
source block calls. This is why :PROPERTY:
blocks seemed like a right way to go. A property value can be read into a :var
with a simple elisp-to-var assignment :var=(org-get-entry nil "prop-name" t)
.
Unfortunately, as i found out, org-get-entry
function works only for properties local to the file and current heading (and its sub-elements with third argument non-nil). This means it will not scan the files I have #+INCLUDE
-ed.
My solution to this limitation was to write an elisp function to open a file, search the property entries under a particular heading and return what was found:
(defun tk-org-get-prop (heading prop)
"Finds a property somewhere under a heading in the current buffer."
(car (org-map-entries `(org-entry-get nil ,prop t)
heading)))
(defun tk-org-get-prop-file (filename heading prop)
"Finds a property somewhere under a heading in the file."
(with-current-buffer (find-file-noselect filename)
(tk-org-get-prop heading prop)))
I can now assign property values under a specific heading in a specific file with :var somevar=(tk-org-get-prop-file "input1.org" ".*property_heading.*" "property_name")
.
The aforementioned approach allows me to extract parameters from various input files and substitute them into the skeleton, but it feels hacky and it seems like there has to be a more elegant way to do that.
Ideally, I would like something like dynamic blocks (#+BEGIN :par1 val1 :par2 val2 ... #+END
syntax), but generating org code instead of returning a value of some custom-written elisp writer function.
:session
property, you may not need to use org mode properties to do this. In my use-case, based onR
andbash
source blocks, I set the session values for the file with a#+PROPERTY
line at the top, then set specific parameters in the first source block for each language, right at the top of the file. The rest of the source blocks reference these variables, so they don't need to change.