Ihor Radchenko <yanta...@posteo.net> writes:

> It will be great if you could do it.
> I have other things to work on.

Of course! I'm just a little unfamiliar on how one coordinates active
collaboration via mailing list :-)

Anyways - I did it, and it took less time than I thought

> We should modify it. For example like the following:
>
> 1. We will assume that :any can only occur one time in the exclusive
>    groups. (Otherwise, there is no single definite way to parse header
>    arguments)
> 2. Merge function will treat :any specially - when parameter does not
>    match any of the argument values from all the groups combined, it is
>    considered as :any and replace the previous corresponding values in
>    its exclusive group, if any;
>    In other words, we will need a special match for :any - "anything not
>    equal to other values in all the groups combined".

I've modified the `merge' function within `org-babel-merge-params' so
that the main logic now accumulates a list of potential candidates that
could be the :any keyword, and selects the last added candidate as the
match.

The first two patches are very minor, simply adding
tangle-exclusive-groups using the existing code templates. The last
patch is the merge function rewrite.

It all seems to be passing tests, though I would like to add my toy.org
file to the org testing framework at some point.

Best,
Mehmet

>From eeb3f165498fcc420b862f67fb616b474a14b684 Mon Sep 17 00:00:00 2001
From: MT <mtekma...@gmail.com>
Date: Wed, 10 May 2023 17:38:22 +0200
Subject: [PATCH 1/3] * lisp/ob-core.el
 (org-babel-common-header-args-w-values): Added mutually exclusive tangle
 groups relating to desired tangle sync actions (e.g. :tangle
 (yes|no|<filename>) [(import|export|sync)])

---
 lisp/ob-core.el | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lisp/ob-core.el b/lisp/ob-core.el
index 65fa47ab5..013a37ce5 100644
--- a/lisp/ob-core.el
+++ b/lisp/ob-core.el
@@ -431,7 +431,8 @@ then run `org-babel-switch-to-session'."
     (sep	. :any)
     (session	. :any)
     (shebang	. :any)
-    (tangle	. ((tangle yes no :any)))
+    (tangle	. ((tangle yes no :any)
+                   (import export skip sync)))
     (tangle-mode . ((#o755 #o555 #o444 :any)))
     (var	. :any)
     (wrap       . :any)))
-- 
2.40.1

>From 366a120a394d7783bf1640037ade31f826ef0277 Mon Sep 17 00:00:00 2001
From: MT <mtekma...@gmail.com>
Date: Wed, 10 May 2023 17:41:37 +0200
Subject: [PATCH 2/3] * lisp/ob-core.el (org-babel-merge-params): Tangle header
 with exclusive parameters can now be parsed, following the template of
 :exports and :results

---
 lisp/ob-core.el | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/lisp/ob-core.el b/lisp/ob-core.el
index 013a37ce5..ed31a9de1 100644
--- a/lisp/ob-core.el
+++ b/lisp/ob-core.el
@@ -2803,6 +2803,9 @@ parameters when merging lists."
 	 (exports-exclusive-groups
 	  (mapcar (lambda (group) (mapcar #'symbol-name group))
 		  (cdr (assq 'exports org-babel-common-header-args-w-values))))
+         (tangle-exclusive-groups
+	  (mapcar (lambda (group) (mapcar #'symbol-name group))
+		  (cdr (assq 'tangle org-babel-common-header-args-w-values))))
 	 (merge
 	  (lambda (exclusive-groups &rest result-params)
 	    ;; Maintain exclusivity of mutually exclusive parameters,
@@ -2822,7 +2825,7 @@ parameters when merging lists."
 	 params				;Final parameters list.
 	 ;; Some keywords accept multiple values.  We need to treat
 	 ;; them specially.
-	 vars results exports)
+	 vars results exports tangle)
     (dolist (plist plists)
       (dolist (pair plist)
 	(pcase pair
@@ -2873,6 +2876,12 @@ parameters when merging lists."
                                    (cond ((and value (functionp value)) (funcall value))
                                          (value value)
                                          (t ""))))))
+          (`(:tangle . ,value)
+           (setq tangle (funcall merge
+                                 tangle-exclusive-groups
+                                 tangle
+                                 (split-string
+                                  (or value "")))))
           ((or '(:dir . attach) '(:dir . "'attach"))
            (unless (org-attach-dir nil t)
              (error "No attachment directory for element (add :ID: or :DIR: property)"))
@@ -2898,7 +2907,8 @@ parameters when merging lists."
 			      params)))))
     ;; Handle other special keywords, which accept multiple values.
     (setq params (nconc (list (cons :results (mapconcat #'identity results " "))
-			      (cons :exports (mapconcat #'identity exports " ")))
+			      (cons :exports (mapconcat #'identity exports " "))
+                              (cons :tangle (mapconcat #'identity tangle " ")))
 			params))
     ;; Return merged params.
     (org-babel-eval-headers params)))
-- 
2.40.1

>From 6ce5313b7d3f0ab718072942f082bc259dccbae6 Mon Sep 17 00:00:00 2001
From: MT <mtekma...@gmail.com>
Date: Wed, 10 May 2023 17:44:42 +0200
Subject: [PATCH 3/3] * lisp/ob-core.el (org-babel-merge-params): Major rewrite
 of the `merge' function, which adds the capability to process the :any
 keyword when merging parameters with exclusive groups.

---
 lisp/ob-core.el | 60 +++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 53 insertions(+), 7 deletions(-)

diff --git a/lisp/ob-core.el b/lisp/ob-core.el
index ed31a9de1..3d9000efc 100644
--- a/lisp/ob-core.el
+++ b/lisp/ob-core.el
@@ -2811,15 +2811,61 @@ parameters when merging lists."
 	    ;; Maintain exclusivity of mutually exclusive parameters,
 	    ;; as defined in EXCLUSIVE-GROUPS while merging lists in
 	    ;; RESULT-PARAMS.
-	    (let (output)
+	    (let (output group-any)
 	      (dolist (new-params result-params (delete-dups output))
 		(dolist (new-param new-params)
-		  (dolist (exclusive-group exclusive-groups)
-		    (when (member new-param exclusive-group)
-		      (setq output (cl-remove-if
-				    (lambda (o) (member o exclusive-group))
-				    output))))
-		  (push new-param output))))))
+                  (let (matched-param potential-any-param)
+                    ;; new-param may be an :any value, so we check
+                    ;; across all exclusive-groups.
+                    ;; - If new-param matches one of groups, we
+		    (dolist (exclusive-group exclusive-groups)
+		      (if (member new-param exclusive-group)
+		          (setq output (cl-remove-if
+				        (lambda (o) (member o exclusive-group))
+				        output)
+                                ;; Cancel any potential matches if it's caught
+                                matched-param t
+                                potential-any-param nil)
+                        ;; If not a direct match, flag it as a potential
+                        ;; :any match This can happen multiple times for
+                        ;; each new-param, but only once for each
+                        ;; exclusive-group.
+                        (if (and (not matched-param)
+                                 (member ":any" exclusive-group))
+                            ;; At this point, the new-param has not yet matched
+                            ;; anything in the N exclusive groups
+                            ;; - We also assume that only 1 of these N groups
+                            ;;   has the :any keyword.
+                            ;; - This point in the code can therefore be only
+                            ;;   reached once under this assumption.
+                            ;; - We therefore setq instead of push
+                            (setq potential-any-param (cons new-param
+                                                            exclusive-group)))))
+
+                    ;; At this point we know whether new-param and 1
+                    ;; of the exclusive groups have an :any keyword -
+                    ;; - Due to multiple new-params potentially being
+                    ;;   matches in the same group, we push these to a
+                    ;;   super group of "any" keywords, and process them
+                    ;;   later.
+                    (if potential-any-param
+                        (setq group-any potential-any-param)
+                      ;; If the param isn't :any, add it to the output
+                      ;; as a regular keyword
+		      (push new-param output)))))
+
+              (when group-any
+                ;; Whatever is leftover at this point are :any candidates.
+                ;; - We assume that last added is the most relevant and
+                ;;   that everything else should be ignored
+                ;; - We add the first, and reject everything else in that
+                ;;   exclusion group.
+                (push (car group-any) output)
+                (setq output (cl-remove-if
+			      (lambda (o) (member o (cdr group-any)))
+			      output)))
+              output)))
+
 	 (variable-index 0)		;Handle positional arguments.
 	 clearnames
 	 params				;Final parameters list.
-- 
2.40.1

Reply via email to