From: Jacopo De Simoi <wilderjds@protonmail.com>
To: emacs-orgmode@gnu.org
Subject: [PATCH] Allow tangling to a list of files
Date: Mon, 05 Jul 2021 18:54:14 +0000 [thread overview]
Message-ID: <DZYHT29KLdzymzGwYjsbCYOEOLBOPDZUtIJaKOv0jWoNwzkr1kFcKzX59GJxm214zdfmBVGJQfXIwueTgJw9FbdOBUeqNL0bqUfTifEZ_88=@protonmail.com> (raw)
[-- Attachment #1.1: Type: text/plain, Size: 675 bytes --]
Dear All,
Please find attached a patch (against master) that adds a feature to the tangle framework. Essentially, the following block would now tangle to two files
#+begin_src sh '("filename1" "filename2")
#my script
#+end_src
Usecases
- literate config (e.g. .zshrc) of several machines at once (e.g. tangling via tramp).
- literate similar versions of the same script which differ only in small chunks (I use it for a slightly different latexmkrc for my projects on Dropbox)
The patch also streamlines the tangling routines.
Tests have been checked.
I am of course open to discussions and comments. Looking forward to hear from you.
Thanks for your time
Best
Jacopo
[-- Attachment #1.2: Type: text/html, Size: 758 bytes --]
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-ob-tangle-Accept-lists-of-files-as-tangling-target.patch --]
[-- Type: text/x-diff; name=0001-ob-tangle-Accept-lists-of-files-as-tangling-target.patch, Size: 8030 bytes --]
From 3a04df5e636c11bfcd8e2183e4a3e336daeb46a9 Mon Sep 17 00:00:00 2001
From: Jacopo De Simoi <wilderjds@protonmail.com>
Date: Fri, 2 Jul 2021 18:31:41 -0400
Subject: [PATCH 1/2] ob-tangle: Accept lists of files as tangling target
* lisp/ob-tangle.el (org-babel-tangle): Drop the now
superfluous parameter `only-this-block'.
(org-babel-effective-tangled-filenames): Return a list
of filenames to use as targets for tangling.
(org-babel-tangle-collect-blocks): Adapt to changes to
`org-babel-tangle-single-block', which now returns an
alist.
(org-babel-tangle-single-block): Return an alist to be
used from `org-babel-tangle'. A single block can now
be tangled to several files at once.
This commit correctly parses list of filenames as
arguments of the :tangle parameter. In doing so it
streamlines both `org-babel-tangle-single-block' and
`org-babel-tangle-collect-blocks'. This was inspired
by the solution to the question
[https://emacs.stackexchange.com/questions/39032/tangle-the-same-src-block-to-different-files]
which I asked few years ago.
The suggested solution does not work with recent org-mode,
so I came up with a working rewrite.
---
lisp/ob-tangle.el | 88 ++++++++++++++++++++++++-----------------------
1 file changed, 45 insertions(+), 43 deletions(-)
diff --git a/lisp/ob-tangle.el b/lisp/ob-tangle.el
index 2f60ef9a4..3799da03f 100644
--- a/lisp/ob-tangle.el
+++ b/lisp/ob-tangle.el
@@ -275,7 +275,7 @@ matching a regular expression."
(mapc (lambda (mode) (set-file-modes file-name mode)) modes)
(push file-name path-collector))))))
(if (equal arg '(4))
- (org-babel-tangle-single-block 1 t)
+ (org-babel-tangle-single-block 1)
(org-babel-tangle-collect-blocks lang-re tangle-file)))
(message "Tangled %d code block%s from %s" block-counter
(if (= block-counter 1) "" "s")
@@ -350,22 +350,24 @@ that the appropriate major-mode is set. SPEC has the form:
(org-fill-template
org-babel-tangle-comment-format-end link-data)))))
-(defun org-babel-effective-tangled-filename (buffer-fn src-lang src-tfile)
- "Return effective tangled filename of a source-code block.
+(defun org-babel-effective-tangled-filenames (buffer-fn src-lang src-tfile)
+ "Return a list of effective tangled filename of a source-code block.
BUFFER-FN is the name of the buffer, SRC-LANG the language of the
block and SRC-TFILE is the value of the :tangle header argument,
as computed by `org-babel-tangle-single-block'."
- (let ((base-name (cond
+ (if (consp src-tfile)
+ src-tfile
+ (list (let ((base-name (cond
((string= "yes" src-tfile)
;; Use the buffer name
(file-name-sans-extension buffer-fn))
((string= "no" src-tfile) nil)
((> (length src-tfile) 0) src-tfile)))
(ext (or (cdr (assoc src-lang org-babel-tangle-lang-exts)) src-lang)))
- (when base-name
+ (when base-name
;; decide if we want to add ext to base-name
(if (and ext (string= "yes" src-tfile))
- (concat base-name "." ext) base-name))))
+ (concat base-name "." ext) base-name))))))
(defun org-babel-tangle-collect-blocks (&optional lang-re tangle-file)
"Collect source blocks in the current Org file.
@@ -388,27 +390,26 @@ be used to limit the collected code blocks by target file."
(let* ((info (org-babel-get-src-block-info 'light))
(src-lang (nth 0 info))
(src-tfile (cdr (assq :tangle (nth 2 info)))))
- (unless (or (string= src-tfile "no")
+ (unless (or (and (not (consp src-tfile)) (string= src-tfile "no"))
(and tangle-file (not (equal tangle-file src-tfile)))
(and lang-re (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
- (nth 1 block) 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)))))))
+ (let ((new-blocks (org-babel-tangle-single-block counter)))
+ (dolist (bl new-blocks)
+ (let* ((block (cdr bl))
+ (file-name (car bl))
+ (by-fn (assoc file-name blocks)))
+ (if by-fn (setcdr by-fn (cons (car block) (cdr by-fn)))
+ (push (cons file-name block) blocks)))))))))
;; Ensure blocks are in the correct order.
(mapcar (lambda (b) (cons (car b) (nreverse (cdr b))))
(nreverse blocks))))
-(defun org-babel-tangle-single-block (block-counter &optional only-this-block)
+(defun org-babel-tangle-single-block (block-counter)
"Collect the tangled source for current block.
-Return the list of block attributes needed by
-`org-babel-tangle-collect-blocks'. When ONLY-THIS-BLOCK is
-non-nil, return the full association list to be used by
+Return the association list of blocks needed by
+`org-babel-tangle-collect-blocks' or
`org-babel-tangle' directly."
(let* ((info (org-babel-get-src-block-info))
(start-line
@@ -470,31 +471,32 @@ non-nil, return the full association list to be used by
(match-end 0)
(point-min))))
(point)))))
- (result
- (list start-line
- (if org-babel-tangle-use-relative-file-links
- (file-relative-name file)
- file)
- (if (and org-babel-tangle-use-relative-file-links
- (string-match org-link-types-re link)
- (string= (match-string 1 link) "file"))
- (concat "file:"
- (file-relative-name (substring link (match-end 0))
- (file-name-directory
- (cdr (assq :tangle params)))))
- link)
- source-name
- params
- (if org-src-preserve-indentation
- (org-trim body t)
- (org-trim (org-remove-indentation body)))
- comment)))
- (if only-this-block
- (let* ((src-tfile (cdr (assq :tangle (nth 4 result))))
- (file-name (org-babel-effective-tangled-filename
- (nth 1 result) src-lang src-tfile)))
- (list (cons file-name (list (cons src-lang result)))))
- result)))
+ (src-tfile (cdr (assq :tangle params)))
+ (file-names (org-babel-effective-tangled-filenames
+ (if org-babel-tangle-use-relative-file-links
+ (file-relative-name file)
+ file) src-lang src-tfile)))
+ (mapcar (lambda (file-name)
+ (cons file-name (list (cons src-lang
+ (list start-line
+ (if org-babel-tangle-use-relative-file-links
+ (file-relative-name file)
+ file)
+ (if (and org-babel-tangle-use-relative-file-links
+ (string-match org-link-types-re link)
+ (string= (match-string 1 link) "file"))
+ (concat "file:"
+ (file-relative-name (substring link (match-end 0))
+ (file-name-directory
+ file-name)))
+ link)
+ source-name
+ params
+ (if org-src-preserve-indentation
+ (org-trim body t)
+ (org-trim (org-remove-indentation body)))
+ comment)))))
+ file-names)))
(defun org-babel-tangle-comment-links (&optional info)
"Return a list of begin and end link comments for the code block at point.
--
2.31.1
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0002-org-manual-Update-docs.patch --]
[-- Type: text/x-diff; name=0002-org-manual-Update-docs.patch, Size: 1186 bytes --]
From b7d1e15f5f79bdbec72a36125c700e06d1b33b39 Mon Sep 17 00:00:00 2001
From: Jacopo De Simoi <wilderjds@protonmail.com>
Date: Fri, 2 Jul 2021 18:53:53 -0400
Subject: [PATCH 2/2] org-manual: Update docs
* doc/org-manual.org (Header arguments): document that
lists can be passed as arguments to :tangle
---
doc/org-manual.org | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/doc/org-manual.org b/doc/org-manual.org
index 977ef80b9..eaee9b248 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -17961,6 +17961,14 @@ to source file(s).
file name as being relative to the directory of the Org file's
location. Example: =:tangle FILENAME=.
+- {{{var(FILENAME-LIST)}}} ::
+
+ Export the code block to possibly several source files whose file name is derived from
+ a list of strings passed to the =tangle= header argument. Org derives the
+ file names as being relative to the directory of the Org file's
+ location. Example: =:tangle ’("FILENAME1" "FILENAME2")=.
+
+
#+cindex: @samp{mkdirp}, header argument
The =mkdirp= header argument creates parent directories for tangled
files if the directory does not exist. A =yes= value enables
--
2.31.1
next reply other threads:[~2021-07-05 18:55 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-07-05 18:54 Jacopo De Simoi [this message]
2021-07-06 2:57 ` [PATCH] Allow tangling to a list of files Vladimir Lomov
2021-07-06 4:43 ` Greg Minshall
2021-07-06 5:09 ` Jacopo De Simoi via General discussions about Org-mode.
2021-07-06 6:11 ` Vladimir Lomov
2021-07-06 15:24 ` Jacopo De Simoi via General discussions about Org-mode.
2021-07-07 3:27 ` Vladimir Lomov
2021-07-07 4:09 ` Tim Cross
2021-07-07 5:01 ` Jacopo De Simoi
2021-07-07 6:56 ` Greg Minshall
2021-07-07 11:05 ` Jacopo De Simoi
2021-07-09 12:26 ` Vladimir Lomov
2021-07-09 13:39 ` Jacopo De Simoi
2021-07-09 22:47 ` Tim Cross
2021-07-06 7:30 ` Tim Cross
2021-07-07 23:06 ` Jacopo De Simoi via General discussions about Org-mode.
2021-07-07 23:28 ` Tim Cross
2021-07-08 0:01 ` Jacopo De Simoi
2021-07-08 0:41 ` Tom Gillespie
2021-07-08 16:41 ` Trust me I am a Doctor
2021-07-08 17:42 ` Jacopo De Simoi
[not found] <-0ZoEP_lzUvrnWSq9TwiYHNJ0Spa94xjiTOF0TU8np0pYgHEPx-62_dr5xBMd3VUu7frSRXxiAFje99v2jeaJg==@protonmail.internalid>
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.orgmode.org/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='DZYHT29KLdzymzGwYjsbCYOEOLBOPDZUtIJaKOv0jWoNwzkr1kFcKzX59GJxm214zdfmBVGJQfXIwueTgJw9FbdOBUeqNL0bqUfTifEZ_88=@protonmail.com' \
--to=wilderjds@protonmail.com \
--cc=emacs-orgmode@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).