From 7d7c38c6b1255a3a1ddd03f32849232bf86200e3 Mon Sep 17 00:00:00 2001 From: Nicolas Goaziou Date: Sun, 19 Feb 2017 15:27:09 +0100 Subject: [PATCH] org-capture: Fix `org-capture-refile' * lisp/org-capture.el (org-capture-refile): Preserve location of point when refiling. * testing/lisp/test-org-capture.el (test-org-capture/refile): New test. Reported-by: Liu Hui --- lisp/org-capture.el | 34 ++++++++++++++++++++------------ testing/lisp/test-org-capture.el | 34 +++++++++++++++++++++++++------- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/lisp/org-capture.el b/lisp/org-capture.el index ae5ee50c9..71aff0dea 100644 --- a/lisp/org-capture.el +++ b/lisp/org-capture.el @@ -820,20 +820,28 @@ Refiling is done from the base buffer, because the indirect buffer is then already gone. Any prefix argument will be passed to the refile command." (interactive) (unless (eq (org-capture-get :type 'local) 'entry) - (error - "Refiling from a capture buffer makes only sense for `entry'-type templates")) - (let ((pos (point)) - (base (buffer-base-buffer (current-buffer))) - (org-capture-is-refiling t) - (kill-buffer (org-capture-get :kill-buffer 'local))) + (user-error "Refiling from a capture buffer makes only sense \ +for `entry'-type templates")) + (let* ((base (or (buffer-base-buffer) (current-buffer))) + (pos (make-marker)) + (org-capture-is-refiling t) + (kill-buffer (org-capture-get :kill-buffer 'local))) + ;; Since `org-capture-finalize' may alter buffer contents (e.g., + ;; empty lines) around entry, use a marker to refer to the + ;; headline to be refiled. Place the marker in the base buffer, + ;; as the current indirect one is going to be killed. + (set-marker pos (save-excursion (org-back-to-heading t)) base) (org-capture-put :kill-buffer nil) - (org-capture-finalize) - (save-window-excursion - (with-current-buffer (or base (current-buffer)) - (org-with-wide-buffer - (goto-char pos) - (call-interactively 'org-refile)))) - (when kill-buffer (kill-buffer base)))) + (unwind-protect + (progn + (org-capture-finalize) + (save-window-excursion + (with-current-buffer base + (org-with-wide-buffer + (goto-char pos) + (call-interactively 'org-refile)))) + (when kill-buffer (kill-buffer base))) + (set-marker pos nil)))) (defun org-capture-kill () "Abort the current capture process." diff --git a/testing/lisp/test-org-capture.el b/testing/lisp/test-org-capture.el index 6b8641030..3f477b2c9 100644 --- a/testing/lisp/test-org-capture.el +++ b/testing/lisp/test-org-capture.el @@ -87,14 +87,34 @@ ;; %(sexp) placeholder with an input containing the traps %, " and ) ;; all at once which is complicated to parse. (should - (equal - "5 % Less (See Item \"3)\" Somewhere)\n" - (let ((org-store-link-plist nil)) - (org-capture-fill-template - "%(capitalize \"%i\")" - "5 % less (see item \"3)\" somewhere)"))))) - + (equal "5 % Less (See Item \"3)\" Somewhere)\n" + (let ((org-store-link-plist nil)) + (org-capture-fill-template + "%(capitalize \"%i\")" + "5 % less (see item \"3)\" somewhere)"))))) +(ert-deftest test-org-capture/refile () + "Test `org-capture-refile' specifications." + ;; When refiling, make sure the headline being refiled is the one + ;; being captured. In particular, empty lines after the entry may + ;; be removed, and we don't want to shift onto the next heading. + (should + (string-prefix-p + "** H1" + (org-test-with-temp-text-in-file "* A\n* B\n" + (let* ((file (buffer-file-name)) + (org-capture-templates + `(("t" "Todo" entry (file+headline ,file "A") "** H1 %?")))) + (org-capture nil "t") + (insert "\n") + (cl-letf (((symbol-function 'org-refile) + (lambda () + (interactive) + (throw :return + (buffer-substring-no-properties + (line-beginning-position) + (line-end-position)))))) + (catch :return (org-capture-refile)))))))) (provide 'test-org-capture)