Hello Rudy, here's the new patch which includes the change and the new test.
Best Tim --- * lisp/ob-plantuml.el (org-babel-plantuml-make-body): Refactor org-babel-plantuml-make-body to properly parse and preserve content around PlantUML diagram blocks. Previously, the function would apply variable expansion to the entire body content and only check for @start keyword to decide whether to wrap with @startuml/@enduml tags. Changes: - Parse body into 4 components: pre-body, keyword-type (e.g., uml), inner-body, and post-body - Only apply variable expansion to the inner-body, not the entire body - Require exact matching between @start<type> and @end<type> keywords (e.g., @startuml must pair with @enduml, not @endsalt) - If @start<type> exists but no matching @end<type> is found, treat the entire body as diagram content and wrap with default keywords (@startuml ... @enduml) - Preserve any content before the first @start keyword (pre-body) and after the last @end keyword (post-body) without modification (except trimming) This ensures variable substitution only affects the actual diagram content. Examples now supported: - Content before/after diagram blocks - Proper handling of mismatched start/end keyword pairs * testing/lisp/test-ob-plantuml.el (test-ob-plantuml/single-var-on-body-with-start-end-keywords-and-content-outside-the-keywords): Added an additional test for aboves use case (var definition on a BODY with pre-existing @startxxx ... @endxxx keywords and pre-body / post-body content). On 16 Feb 2026, at 10:30, Rudolf Adamkovič wrote: > Tim Hansinger <[email protected]> writes: > >> Hello Rudy, > > Tim, hi! > >> sorry for the long time it took. > > Looks like everyone is busy this winter. Me too! :) > >> I haven't created a patch yet but thought I would just send the code >> [...] Main changes to your code are: [...] > > Great work! Love the use back-references. Smart! > >> I tested it thoroughly and couldn't find any issues with this code. > > I would be great to capture (at least) "the spirit" of the change in > `test-ob-plantuml.el' so we avoid future regressions. > >> Would appreciate your feedback but I believe it is quite clean. > > It looks great. > >> If you like we could of course move the whole (rx ...) part directly >> into the (_ (string-match regex body)) part so we don't define a >> variable regex... but other than that I wouldn't change much. > > Your call. As always, maintainability is the top priority. > > Rudy > -- > "It is no paradox to say that in our most theoretical moods we may be > nearest to our most practical applications." > > --- Alfred North Whitehead, 1861-1947 > > Rudolf Adamkovič <[email protected]> [he/him] > http://adamkovic.org
From e4e51a3426e059c795a1a0673e90af6af5afb268 Mon Sep 17 00:00:00 2001 From: Tim Hansinger <[email protected]> Date: Mon, 23 Feb 2026 20:18:12 +0100 Subject: [PATCH] ob-plantuml.el: Fix body parsing to handle @start/@end keywords * lisp/ob-plantuml.el (org-babel-plantuml-make-body): Refactor org-babel-plantuml-make-body to properly parse and preserve content around PlantUML diagram blocks. Previously, the function would apply variable expansion to the entire body content and only check for @start keyword to decide whether to wrap with @startuml/@enduml tags. Changes: - Parse body into 4 components: pre-body, keyword-type (e.g., uml), inner-body, and post-body - Only apply variable expansion to the inner-body, not the entire body - Require exact matching between @start<type> and @end<type> keywords (e.g., @startuml must pair with @enduml, not @endsalt) - If @start<type> exists but no matching @end<type> is found, treat the entire body as diagram content and wrap with default keywords (@startuml ... @enduml) - Preserve any content before the first @start keyword (pre-body) and after the last @end keyword (post-body) without modification (except trimming) This ensures variable substitution only affects the actual diagram content. Examples now supported: - Content before/after diagram blocks - Proper handling of mismatched start/end keyword pairs * testing/lisp/test-ob-plantuml.el (test-ob-plantuml/single-var-on-body-with-start-end-keywords-and-content-outside-the-keywords): Added an additional test for aboves use case (var definition on a BODY with pre-existing @startxxx ... @endxxx keywords and pre-body / post-body content). Reported-by: "Tim Hansinger" <[email protected]> Link: https://list.orgmode.org/[email protected]/ --- lisp/ob-plantuml.el | 48 +++++++++++++++++++++++++++----- testing/lisp/test-ob-plantuml.el | 30 ++++++++++++++++++++ 2 files changed, 71 insertions(+), 7 deletions(-) diff --git a/lisp/ob-plantuml.el b/lisp/ob-plantuml.el index 93b183b96..1b499d057 100644 --- a/lisp/ob-plantuml.el +++ b/lisp/ob-plantuml.el @@ -102,13 +102,47 @@ of source block parameters. This function relies on the from PARAMS and on the `org-babel-variable-assignments:plantuml' function to convert variables to PlantUML assignments. -If BODY does not contain @startXXX ... @endXXX clauses, @startuml -... @enduml will be added." - (let ((full-body - (org-babel-expand-body:generic - body params (org-babel-variable-assignments:plantuml params)))) - (if (string-prefix-p "@start" body t) full-body - (format "@startuml\n%s\n@enduml" full-body)))) +The function parses BODY to find matching @startXXX ... @endXXX keyword pairs: +- If a matching pair is found (e.g., @startuml/@enduml or @startsalt/@endsalt), + variable expansion is applied only to the content between the keywords, + preserving any content outside the keywords. +- If @startXXX is found but no matching @endXXX, or if no @startXXX is found, + the entire BODY is treated as diagram content and wrapped with + @startuml ... @enduml keywords after variable expansion." + (let* ((regex (rx + (group (zero-or-more anything)) + line-start + (zero-or-more blank) + "@start" + (group (one-or-more (not whitespace))) + (zero-or-more blank) + line-end + (zero-or-one whitespace) + (group (zero-or-more anychar)) + line-start + (zero-or-more blank) + "@end" + (backref 2) + (zero-or-more blank) + line-end + (group (zero-or-more anything)))) + (_ (string-match regex body)) + (pre-body (string-trim (or (match-string 1 body) ""))) + (keyword-type (or (match-string 2 body) "uml")) + (inner-body (string-trim (or (match-string 3 body) body))) + (post-body (string-trim (or (match-string 4 body) "")))) + + (string-join + (remove "" + (list pre-body + (string-join (list "@start" keyword-type)) + (org-babel-expand-body:generic + inner-body + params + (org-babel-variable-assignments:plantuml params)) + (string-join (list "@end" keyword-type)) + post-body)) + "\n"))) (defun org-babel-execute:plantuml (body params) "Execute a block of plantuml code with org-babel. diff --git a/testing/lisp/test-ob-plantuml.el b/testing/lisp/test-ob-plantuml.el index b45d38be6..6e05f8c58 100644 --- a/testing/lisp/test-ob-plantuml.el +++ b/testing/lisp/test-ob-plantuml.el @@ -45,6 +45,36 @@ class CLASSNAME (car src-block-info) (car (cdr src-block-info))))))))) +(ert-deftest test-ob-plantuml/single-var-on-body-with-start-end-keywords-and-content-outside-the-keywords () + "Test file output with input variable on BODY with @startXXX ... @endXXX keywords +and pre-body / post-body content." + (should + (string= + "pre-body content +@startuml +!define CLASSNAME test_class +class CLASSNAME +@enduml +post-body content" + (let ((org-plantuml-jar-path nil)) + (org-test-with-temp-text + "#+name: variable_value +: test_class + +#+header: :file tmp.puml +#+header: :var CLASSNAME=variable_value +#+begin_src plantuml +pre-body content +@startuml +class CLASSNAME +@enduml +post-body content +#+end_src" + (org-babel-next-src-block) + (let ((src-block-info (cdr (org-babel-get-src-block-info)))) + (org-babel-plantuml-make-body + (car src-block-info) + (car (cdr src-block-info))))))))) (ert-deftest test-ob-plantuml/prologue () "Test file output with prologue." -- 2.51.2
