I am trying to set the default header parameters for org source blocks in plantuml-mode
.
My goal is to generate the result file in the org attachment directory with a generic name by default, and display it as an inline image in the result drawer.
This is my first attempt:
(setq org-babel-default-header-args:plantuml
`((:results . "file link") (:output-dir . ,(org-attach-dir-get-create)) (:file-ext . "png") (:file . "diagram.png") (:exports . "results")))
This works fine the first time, but then, the org-attach-dir
string is prepended to the file
path string at every code block execution.
So for example, if org-attach-dir-get-create
returns "mydir/", the first time I execute the block, the :file
value is mydir/diagram.png
as intended. The second time I execute the block, I get mydir/mydir/diagram.png
, the third time, mydir/mydir/mydir/diagram.png
, and so on.
Please note that I am keeping file-ext
, file
, and output-dir
as separated parameters in the hope of being able to override them individually if needed in specific cases.
I understood from that failure that the header-defaults are set at each block execution, so I tried to pass them all as a function:
(defun my/org-babel-plantuml-header-args ()
"Set dynamic header arguments for PlantUML source blocks."
(let ((output-dir (org-attach-dir-get-create)))
`((:results . "file link")
(:output-dir . ,output-dir)
(:file-ext . "png")
(:file . "diagram.png")
(:exports . "results"))))
(setq org-babel-default-header-args:plantuml
(my/org-babel-plantuml-header-args))
This has exactly the same outcome. It does not make sense to me, but my tests are very stubborn at proving me wrong.
I would appreciate some help in gettng it to work, because I used some of my most advanced Elisp tricks for that one :)
=== EDIT ===
After further testing, I jumped to the wrong conclusion when blaming this buggy behavior on the dynamic setting of the output directory.
I can reproduce it every time I set both output-dir
and file
within the org-babel-default-header-args
variable even with a static string.
Regarding my initial goal, which was to have the diagram files created in the attachment directory, and displayed in the buffer, it is not possible to achieve using the header default arguments.
As @NickD commented, any function used there to set an option is only called once upon setting the org-babel-default-header-args:plantuml
variable. This approach even had other adverse effects as I am using an org config file.
I managed to achieve the same results by using a custom function in a Yasnippet snippet to build the output-dir
string. It works fine, just has a bit of a cluttered header.
Sorry if this thread is a bit all over the place. If future readers are looking to achieve the same kind of thing, I would gladly share the snippet code, and the custom hook function to set the attachment tag to the appropriate org node. I am not posting it because it uses Org-roam which is a niche use case I think, and I think it is off-topic considering how the thread started.
(setq org-bable-default-header-args:plantuml ...)
in the first and second code block: in the first you set it to a manually constructed list, in the second you set it to the result of calling a function, but the function constructs the same list (in the sense ofequal
: they are not the same object, but they look identical and act identically), so the final values are the same in both cases. Does that make sense?org-attach-dir-get-create
function out of the list would prevent it from being called at every block execution. Still in my mind, if the function is called at every block execution, it should always yield the same list, more specifically, the output-dir should not be affected in the same way by repeated block execution. Anyway, I am not set on this approach if it is not te way to go.output-dir
, setting it to a static string produces the same 'bug'. So I guessoutput-dir
andfile
should not both be set or something like that. I have to test and research further...org-attach-dir-get-create
is not called on every block evaluation: either way it is called once when the variable is set. So there is no difference between the methods.