Hello Rudy,
sorry for the long time it took.
I haven't created a patch yet but thought I would just send the code so you can
have a look at it.
I have some comments inside which I would remove for the final patch.
I tried to keep it close to what you suggested (using rx, only have a single
match function etc.) but I changed your code to some extend based on heavy
testing and checking again how the plantuml cli converts the code into an image.
Main changes to your code are:
- I also handle code that doesn't contain @start... @end... (we fall back then
to @startuml and @enduml, identical to how plantuml cli would handle the code)
- I changed the regex in some ways (I changed the greedy/non-greedy behavior a
bit so it matches not the first @start... but the last @startuml... just in
case someone has @start multiple times in the code - which of course never
should happen but now we handle it like plantuml cli would handle it)
- I simplified the regex to some extend and use a backref so we assure we match
exactly the same keyword type that has been found in the @start<KEYWORD-TYPE>
regex
I tested it thoroughly and couldn't find any issues with this code.
Would appreciate your feedback but I believe it is quite clean.
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.
Best
Tim
(defun org-babel-plantuml-make-body (body params)
"..."
(let* ((regex (rx
;; 1️⃣ Anything before the block (captured)
(group (zero-or-more anything)) ; 1: pre-body
;; 2️⃣ Start of the line that contains “@start…”
line-start
(zero-or-more blank)
"@start"
(group (one-or-more (not whitespace))) ; 2: start-keyword-type
(zero-or-more blank)
line-end
(zero-or-one whitespace)
;; 3️⃣ The body that follows the @start line (captured)
(group (zero-or-more anychar)) ; 3: inner-body
;; 4️⃣ Start of the line that contains “@end…”
line-start
(zero-or-more blank)
"@end"
(backref 2) ; repeat the tag name
captured in #2
(zero-or-more blank)
line-end
(group (zero-or-more anything)))) ; 4: post-body
(_ (string-match regex body))
(pre-body (string-trim (or (match-string 1 body) "")))
(keyword-type (or (match-string 2 body) "uml")) ; fallback (@startuml
/ @enduml)
(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")))
On 9 Oct 2025, at 12:09, Rudolf Adamkovič wrote:
> Tim Hansinger <[email protected]> writes:
>
>> Hello Rudy,
>
> Tim, hi!
>
>> please find here the latest patch.
>>
>> I tried to implement the changes request. This one is now simplified.
>
> The new patch is *much* simplified, to the point even I can read it. :)
>
> Better and better!
>
>> I think this is very clean. If you have anything to change please
>> provide me with complete alternative code. I hope however this one
>> works for you.
>
> It works but is still tiny bit too complex. :)
>
> Below, I include "complete alternative code" you asked for.
>
> - It matches the regular language of the input body *exactly once*.
> - It contains *exactly one* invocation of `org-babel-expand-body:...'.
> - It contains *exactly one* invocation of
> `org-babel-variable-assignments:...'.
> - It uses `rx' for readability, as I am trying to learn it. :)
>
> Please test it thoroughly; I just tried it once. *ducks*
>
> P.S. We could also extract a `defcustom' for those default "@startuml"
> and "@enduml", e.g. `org-babel-plantuml-default-diagram-type' containing
> the string "uml".
>
> P.P.S. Great work, Tim!
>
> (defun org-babel-plantuml-make-body (body params)
> "..."
> (let ((match (string-match
> (rx (zero-or-more (or whitespace control))
> (group (minimal-match (zero-or-more anything)))
> line-start
> (zero-or-more blank)
> (group "@start" (group (one-or-more (any "a-zA-Z"))))
> (zero-or-more blank)
> line-end
> (group (zero-or-more anything))
> line-start
> (zero-or-more blank)
> (group "@end" (group (one-or-more (any "a-zA-Z"))))
> (zero-or-more blank)
> line-end
> (group (minimal-match (zero-or-more anything)))
> (zero-or-more (or whitespace control)))
> body)))
> (pcase-let ((`(,pre-body
> ,start-keyword
> ,start-keyword-type
> ,inner-body
> ,end-keyword
> ,end-keyword-type
> ,post-body)
> (mapcar (lambda (group)
> (if match (match-string group body)))
> (number-sequence 1 7))))
> (unless (string= start-keyword-type end-keyword-type)
> (user-error "Incompatible PlantUML start/end keywords: %s, %s"
> start-keyword end-keyword))
> (string-join
> (remove "" (list (or pre-body "")
> (or start-keyword "@startuml")
> (org-babel-expand-body:generic
> (or inner-body body)
> params
> (org-babel-variable-assignments:plantuml params))
> (or end-keyword "@enduml")
> (or post-body "")))
> "\n"))))
>
> Rudy
> --
> "All of humanity's problems stem from man's inability to sit quietly in
> a room alone." --- Blaise Pascal, Pensées, 1670
>
> Rudolf Adamkovič <[email protected]> [he/him]
> http://adamkovic.org