5

I can't seem to get the variable to expand into src block

#+BEGIN_SRC conf :tangle ~/.config/mine.conf :var argument=abcde
setting1 1234
setting2 argument
#+END_SRC

When I export the file for tangling (C-c C-v t), the argument keyword is not expanded into abcde.

I realise that this is because I am not evaluating the block but exporting it.

How do I achieve my desired output in the tangled file?

tinlyx
  • 1,276
  • 1
  • 12
  • 27
Mehmet Tekman
  • 183
  • 1
  • 6
  • 2
    In principle modifying the contents of a source block works with [noweb references](https://orgmode.org/manual/Noweb-reference-syntax.html). But one source block is not tangled for multiple calls with differing arguments. You should write what really want to achieve. This question very much smells like an [XY-problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). – Tobias Apr 23 '19 at 08:40
  • Note also that exporting and tangling are two different things. Exporting produces some export format like HTML or LaTeX from the Org file while tangling writes the source blocks out to files. What do you actually want? Please clarify and correct the tags accordingly. – Tobias Apr 23 '19 at 09:05

1 Answers1

6

Built-in approach

The noweb approach is built in to Org-mode but I believe it is a bit clumsy for your purpose. Therewith you can substitute marked names in source blocks with their result values within a source block. Thereby, the names are themselves names of source blocks that are evaluated to get the results. Applied to your example that could look like the following snippet. In that snippet the noweb reference <<argsubst1()>> is replaced with abcde.

#+NAME: argsubst
#+BEGIN_SRC emacs-lisp :var argument="default value"
argument
#+END_SRC

#+NAME: argsubst1
#+CALL: argsubst("abcde")
#+NAME: conf
#+BEGIN_SRC conf :tangle /tmp/mine.conf :noweb yes
setting1 1234
setting2 <<argsubst1()>>
#+END_SRC

Alternative approach with customized execution of org-blocks

(At first a warning: The code below looks longer than the code above. But it defines also an Elisp function that you can move to your init file if you like it. Furthermore it demonstrates the generation of two conf files with different parametrization.)

An alternative is to use parametrized org source blocks. The org-babel-execute:org function below carries out the parameter substitution at execution of the org source block.

After running the calls to the org source block you can export or tangle the generated conf source blocks.

Org-mode does not have org-babel-execute:org by default. So we can define one which substitutes the values of variables in its contents:

#+BEGIN_SRC emacs-lisp :results none
(defun org-babel-execute:org (body params)
  "Return BODY with variables from PARAMS replaced by their values."
  (let* ((vars (cl-loop for par in params
            if (eq (car par) :var)
            collect (cons (symbol-name (cadr par)) (cddr par))))
     (re (regexp-opt (mapcar #'car vars) 'words))
     (pos 0))
    (while (string-match re body pos)
      (setq body (replace-match
          (format "%s" (cdr (assoc-string (match-string 0 body) vars)))
          nil nil
          body)))
    body))
#+END_SRC

#+NAME: myconfig
#+BEGIN_SRC org :var argument="abcde", configFile="mine.conf" :results raw :tangle no
,#+BEGIN_SRC conf :tangle /tmp/configFile
setting1 1234
setting2 argument
,#+END_SRC
#+END_SRC

#+RESULTS: myconfig
#+BEGIN_SRC conf :tangle /tmp/mine.conf
setting1 1234
setting2 abcde
#+END_SRC

#+CALL: myconfig(argument="fghijk", configFile="yours.conf")

#+RESULTS:
#+BEGIN_SRC conf :tangle /tmp/yours.conf
setting1 1234
setting2 fghijk
#+END_SRC

If you like this approach you can move the function org-babel-execute:org into your init file. In that case you do not need the Elisp source block anymore in your Org file.

If the package authors of Org invent by accident some org-babel-execute:org function that does not what you want you can just derive your own mode from org-mode with define-derived-mode, e.g., myorg-mode and change the name of org-babel-execute:org above appropriately, in the example: org-babel-execute:myorg. In that case you use a myorg source block in place of the org source block above.

Tobias
  • 32,569
  • 1
  • 34
  • 75