branch: externals/org
commit dea0804e63c8aff44436d9821bcdb2f03a620bed
Author: Derek Chen-Becker <o...@chen-becker.org>
Commit: Ihor Radchenko <yanta...@posteo.net>

    ob-tangle: Fix tangling within an indirect/capture buffer
    
    * lisp/org-macs.el (org-base-buffer-file-name): Add a function to properly
    resolve the filename for both direct and indirect buffers.
    * lisp/ob-tangle.el (org-babel-tangle): Update to utilize the new
    `org-base-buffer-file-name' function.
    * testing/lisp/test-ob-tangle.el (ob-tangle/tangle-from-capture-buffer): Add
    a unit test to cover the use case of tangling within a capture buffer.
    * testing/lisp/test-org-macs.el (test-org-base-buffer-file-name): Add a
    unit test to exercise the behavior of the new `org-base-buffer-file-name'
    function, particulary around handling base vis indirect buffers.
    
    The previous use of `buffer-file-name' would fail inside of a capture buffer
    because it is indirect and does not have an associated filename.  This
    appears to be a common pitfall across Org, so I've added a helper function
    to resolve the filename for both indirect and direct buffers so that it can
    be used in other places within the codebase.
    
    Reported-by: Dilip <id...@protonmail.com>
    Link: https://list.orgmode.org/87msfxd81c.fsf@localhost/T/#t
---
 lisp/ob-tangle.el              |  2 +-
 lisp/org-macs.el               |  9 +++++++++
 testing/lisp/test-ob-tangle.el | 23 +++++++++++++++++++++++
 testing/lisp/test-org-macs.el  | 29 +++++++++++++++++++++++++++++
 4 files changed, 62 insertions(+), 1 deletion(-)

diff --git a/lisp/ob-tangle.el b/lisp/ob-tangle.el
index 38cad78ab5..64bdced84f 100644
--- a/lisp/ob-tangle.el
+++ b/lisp/ob-tangle.el
@@ -269,7 +269,7 @@ matching a regular expression."
               (or (cdr (assq :tangle (nth 2 (org-babel-get-src-block-info 
'no-eval))))
                   (user-error "Point is not in a source code block"))))
            path-collector
-            (source-file buffer-file-name))
+            (source-file (org-base-buffer-file-name)))
        (mapc ;; map over file-names
         (lambda (by-fn)
           (let ((file-name (car by-fn)))
diff --git a/lisp/org-macs.el b/lisp/org-macs.el
index 152f19a817..292dfff03a 100644
--- a/lisp/org-macs.el
+++ b/lisp/org-macs.el
@@ -1824,6 +1824,15 @@ indirectly called by the latter."
                    (eq (window-frame) (window-frame window))))
       (window--display-buffer buffer window 'reuse alist))))
 
+(defun org-base-buffer-file-name (&optional buffer)
+  "Resolve the base file name for the provided BUFFER.
+If BUFFER is not provided, default to the current buffer.  If
+BUFFER does not have a file name associated with it (e.g. a
+transient buffer) then return nil."
+  (if-let* ((base-buffer (buffer-base-buffer buffer)))
+      (buffer-file-name base-buffer)
+    (buffer-file-name buffer)))
+
 (provide 'org-macs)
 
 ;; Local variables:
diff --git a/testing/lisp/test-ob-tangle.el b/testing/lisp/test-ob-tangle.el
index 4c953b15d0..cd68763701 100644
--- a/testing/lisp/test-ob-tangle.el
+++ b/testing/lisp/test-ob-tangle.el
@@ -741,6 +741,29 @@ another block
                              bib))))
       (delete-file file))))
 
+;; See https://list.orgmode.org/87msfxd81c.fsf@localhost/T/#t
+(ert-deftest ob-tangle/tangle-from-capture-buffer ()
+  "Test tangling of source blocks from within a capture buffer.
+This is to ensure that we properly resolve the buffer name."
+  (org-test-with-temp-text-in-file
+   "* Header\n\nCapture after this point:\n<point>"
+   (let ((tangle-filename (format "%s.el" (buffer-file-name))))
+      (unwind-protect
+          (progn
+            (let ((org-capture-templates '(("t" "Test" entry (here) "* Test 
Header\n\n"))))
+              (org-capture nil "t")
+              (goto-char (point-max))
+              (insert
+               (format "
+#+begin_src elisp :tangle \"%s\" :comments org
+  (message \"FOO\")
+#+end_src" tangle-filename))
+              (search-backward "message")
+              ;; Confirm that we tangled to the right file
+              (should (equal (org-babel-tangle) (list tangle-filename)))))
+        ;; Clean up the tangled file with the filename from 
org-test-with-temp-text-in-file
+        (delete-file tangle-filename)))))
+
 (provide 'test-ob-tangle)
 
 ;;; test-ob-tangle.el ends here
diff --git a/testing/lisp/test-org-macs.el b/testing/lisp/test-org-macs.el
index 93f00a4c51..dde1dccff5 100644
--- a/testing/lisp/test-org-macs.el
+++ b/testing/lisp/test-org-macs.el
@@ -145,5 +145,34 @@
                      (butlast (decode-time (org-matcher-time "<+14h>"))
                               3))))))
 
+
+;;; Buffers
+
+(ert-deftest test-org-base-buffer-file-name ()
+  "Test `org-base-buffer-file-name'."
+  ;; Test direct buffer resolution
+  (org-test-with-temp-text-in-file
+   "File"
+   (let ((base-filename (buffer-file-name)))
+     ;; Confirm that we get the same answer whether we provide the buffer or 
use the default
+     (should (equal base-filename (org-base-buffer-file-name)))
+     (should (equal base-filename (org-base-buffer-file-name 
(current-buffer))))))
+  ;; Test indirect buffer resolution
+  (org-test-with-temp-text-in-file
+   "File with indirect buffer"
+   (let ((base-filename (buffer-file-name))
+         (base-buffer (current-buffer))
+         (indirect-test-buffer (make-indirect-buffer (current-buffer) "test")))
+     (set-buffer indirect-test-buffer)
+     ;; Confirm that we get the same answer for the default, the indirect 
buffer, and the base buffer
+     (should (equal base-filename (org-base-buffer-file-name)))
+     (should (equal base-filename (org-base-buffer-file-name base-buffer)))
+     (should (equal base-filename (org-base-buffer-file-name 
indirect-test-buffer)))
+     (kill-buffer indirect-test-buffer)))
+  ;; Test for a buffer with no associated file
+  (org-test-with-temp-text
+   "Buffer without file"
+   (should-not (org-base-buffer-file-name))))
+
 (provide 'test-org-macs)
 ;;; test-org-macs.el ends here

Reply via email to