Thanks Ihor, Phil I updated the patch to address your comments.
>> You are dropping this logic completely in the patch. Without this part >> :tangle no may not work. I restored the logic in the new patch. >> With this change, ONLY-THIS-BLOCK = nil is ignored. This will cause problems. I intended to remove the ONLY-THIS-BLOCK part since it will no longer be used in the official code. However, after searching on GitHub, I realized that org-babel-tangle-single-block is widely used by many users, so I restored it in the new patch. However, in my opinion, it should eventually be abandoned if the patch gets accepted. llcc On Wed, Mar 12, 2025 at 4:38 AM Phil Estival <p...@7d.nz> wrote: > > References: > <caljq+lyfvwgog+ck3p2oel2pdt4gu31xf13x3tgkp9mdj8-...@mail.gmail.com> > <caljq+lyqc7gqvvm7j0ycodinapzpru2rhngz9y08g1k272h...@mail.gmail.com> > User-Agent: mu4e 1.12.8; emacs 30.1 > Date: Tue, 11 Mar 2025 21:38:00 +0100 > > * [2025-03-09 15:12 +0800] Lei Zhe <lzhe...@gmail.com>: > > Hello Lei, > > > It'll make the tangle system more flexible, and I would be glad to > > see it included in the next release. > > I would be glad too. > > > I wanted to check in to see if you’re still planning to complete the > > patch. If not, I am more than happy to take over and finish it. > > Yes, please, do. I don't think I will, I don't intend to at the moment. > Sorry for this late answer. I don't have enough time to properly follow > the list these days (there should only be a little left to provide the > patch to ob-sql in the next weeks, as I'm using it again). > > > This patch is the first step in resolving the feature for tangling > > source blocks to multiple targets. > > I would appreciate any feedback. > > I'll add to Ihor answer that writing a new test suite > (test-ob-n-tangle.el) would be useful. > > -- > Phil
From 99c76cdeaf232115b3d556a17b5a0ebed9151771 Mon Sep 17 00:00:00 2001 From: llcc <lzhes43@gmail.com> Date: Sun, 9 Mar 2025 15:05:35 +0800 Subject: [PATCH] New feature: tangle org source blocks to multiple targets 1. add `:tangle-directory' to specify tangle directory. 2. `:tangle' now accepts symbols that return a path string, or a list of file path, or a single string --- lisp/ob-tangle.el | 79 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 25 deletions(-) diff --git a/lisp/ob-tangle.el b/lisp/ob-tangle.el index 38cad78ab..361ee521d 100644 --- a/lisp/ob-tangle.el +++ b/lisp/ob-tangle.el @@ -500,34 +500,30 @@ code blocks by target file." (org-element-at-point) 'headline t)) 1))) - (if (eq last-heading-pos current-heading-pos) (cl-incf counter) - (setq counter 1) - (setq last-heading-pos current-heading-pos))) + (if (eq last-heading-pos current-heading-pos) (cl-incf counter) + (setq counter 1) + (setq last-heading-pos current-heading-pos))) (unless (or (org-in-commented-heading-p) (org-in-archived-heading-p)) - (let* ((info (org-babel-get-src-block-info 'no-eval)) - (src-lang (nth 0 info)) - (src-tfile (cdr (assq :tangle (nth 2 info))))) - (unless (or (string= src-tfile "no") + (let* ((block (org-babel-tangle-single-block counter t)) + (src-file (car block)) + (src-lang (caar block))) + (unless (or (not src-file) ;; src block without lang - (and (not src-lang) (string= src-tfile "yes")) - (and tangle-file (not (equal tangle-file src-tfile))) + (and (not src-lang) src-file) + (and tangle-file (not (equal tangle-file src-file))) ;; lang-re but either no lang or lang doesn't match - (and lang-re + (and lang-re (or (not src-lang) (not (string-match-p lang-re src-lang))))) - ;; Add the spec for this block to blocks under its tangled - ;; file name. - (let* ((block (org-babel-tangle-single-block counter)) - (src-tfile (cdr (assq :tangle (nth 4 block)))) - (file-name (org-babel-effective-tangled-filename - buffer-fn src-lang src-tfile)) - (by-fn (assoc file-name blocks))) - (if by-fn (setcdr by-fn (cons (cons src-lang block) (cdr by-fn))) - (push (cons file-name (list (cons src-lang block))) blocks))))))) + (setq blocks + (mapcar (lambda (group) + (cons (car group) + (apply #'append (mapcar #'cdr (cdr group))))) + (seq-group-by #'car (append block blocks)))))))) ;; Ensure blocks are in the correct order. (mapcar (lambda (b) (cons (car b) (nreverse (cdr b)))) - (nreverse blocks)))) + (nreverse blocks)))) (defun org-babel-tangle--unbracketed-link (params) "Get a raw link to the src block at point, without brackets. @@ -550,6 +546,39 @@ The PARAMS are the 3rd element of the info for the same src block." bare)))))) (defvar org-outline-regexp) ; defined in lisp/org.el + +(defun org-babel-tangle--concat-targets (buffer-fn info) + "Return a list of tangled files based on the `:tangle' +and `:tangle-directory' in PARAMS." + (let* ((params (nth 2 info)) + (src-lang (nth 0 info)) + (src-tdirectories (cdr (assq :tangle-directory params))) + (src-tfiles (cdr (assq :tangle params))) + (src-tfiles (pcase (type-of src-tfiles) + ('cons src-tfiles) + ('symbol (eval src-tfiles)) + (_ (eval src-tfiles))))) + (unless (or (not src-tdirectories) + (consp src-tdirectories)) + (setq src-tdirectories (list src-tdirectories))) + (unless (consp src-tfiles) + (setq src-tfiles + (list (cond ((string= src-tfiles "yes") + (file-name-nondirectory + (org-babel-effective-tangled-filename buffer-fn src-lang src-tfiles))) + ((string= src-tfiles "no") nil) + (t src-tfiles))))) + (when (and src-tdirectories + (not (equal src-tfiles '(nil)))) + (setq src-tfiles + (apply 'append + (mapcar (lambda (src-tdirectory) + (mapcar (lambda (src-tfile) + (expand-file-name src-tfile src-tdirectory)) + src-tfiles)) + src-tdirectories)))) + src-tfiles)) + (defun org-babel-tangle-single-block (block-counter &optional only-this-block) "Collect the tangled source for current block. Return the list of block attributes needed by @@ -580,7 +609,7 @@ non-nil, return the full association list to be used by ;; Run the tangle-body-hook. (let ((body (if (org-babel-noweb-p params :tangle) (if (string= "strip-tangle" (cdr (assq :noweb (nth 2 info)))) - (replace-regexp-in-string (org-babel-noweb-wrap) "" (nth 1 info)) + (replace-regexp-in-string (org-babel-noweb-wrap) "" (nth 1 info)) (org-babel-expand-noweb-references info)) (nth 1 info)))) (with-temp-buffer @@ -616,7 +645,6 @@ non-nil, return the full association list to be used by (match-end 0) (point-min)))) (point))))) - (src-tfile (cdr (assq :tangle params))) (result (list start-line (if org-babel-tangle-use-relative-file-links @@ -629,9 +657,10 @@ non-nil, return the full association list to be used by (org-trim (org-remove-indentation body))) comment))) (if only-this-block - (let* ((file-name (org-babel-effective-tangled-filename - file src-lang src-tfile))) - (list (cons file-name (list (cons src-lang result))))) + (let* ((file-names (org-babel-tangle--concat-targets file info))) + (mapcar (lambda (file-name) + (cons file-name (list (cons src-lang result)))) + file-names)) result))) (defun org-babel-tangle-comment-links (&optional info) -- 2.37.2.windows.2