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