>From 6315be9e7a83cd9837807c2eb87ed7b3c6b70997 Mon Sep 17 00:00:00 2001 From: Kyle Meyer Date: Fri, 26 Jun 2015 21:33:34 -0400 Subject: [PATCH] org-add-planning-info: Improve deletion handling * lisp/org.el (org-add-planning-info): Reset point before each planning entry search. Clean up extra spaces. * testing/lisp/test-org.el (test-org/add-planning-info): Add tests. - Reposition save-excursion call to reset point every dolist iteration. Otherwise, the order of the entries to be removed matters, and a call like (org-add-planning-info nil nil 'scheduled 'deadline) on DEADLINE: <2015-06-26 Fri> SCHEDULED: <2015-06-26 Fri> will fail to remove the deadline entry. - Delete leading white space even when at the beginning of the line so that, when org-adapt-indentation is nil, a space is not inserted when removing the leading planning info entry. This prevents headings with repeating entries like SCHEDULED: <2015-06-26 Fri +1w> from being closed and recycled with an extra space in front of SCHEDULED. - Add leading white space to the planning info entry regexp to prevent leftover white space when removing entries other than the first entry. --- lisp/org.el | 35 ++++++----- testing/lisp/test-org.el | 159 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 178 insertions(+), 16 deletions(-) diff --git a/lisp/org.el b/lisp/org.el index 02f5c22..5a7d6d3 100755 --- a/lisp/org.el +++ b/lisp/org.el @@ -13478,23 +13478,26 @@ (defun org-add-planning-info (what &optional time &rest remove) (skip-chars-forward " \t") ;; Check if we have to remove something. (dolist (type (if what (cons what remove) remove)) - (when (save-excursion - (re-search-forward - (case type - (closed org-closed-time-regexp) - (deadline org-deadline-time-regexp) - (scheduled org-scheduled-time-regexp) - (otherwise (error "Invalid planning type: %s" type))) - (line-end-position) t)) - (replace-match "") - (when (looking-at "--+<[^>]+>") (replace-match "")) - (when (and (not what) (eq type 'closed)) - (save-excursion - (beginning-of-line) - (if (looking-at "[ \t]*$") - (delete-region (point) (1+ (point-at-eol))))))) + (save-excursion + (when (re-search-forward + (concat + " *" + (case type + (closed org-closed-time-regexp) + (deadline org-deadline-time-regexp) + (scheduled org-scheduled-time-regexp) + (otherwise + (error "Invalid planning type: %s" type)))) + (line-end-position) t) + (replace-match "") + (when (looking-at "--+<[^>]+>") (replace-match "")) + (when (and (not what) (eq type 'closed)) + (save-excursion + (beginning-of-line) + (if (looking-at "[ \t]*$") + (delete-region (point) (1+ (point-at-eol)))))))) ;; Remove leading white spaces. - (when (and (not (bolp)) (looking-at "[ \t]+")) (replace-match "")))) + (when (looking-at "[ \t]+") (replace-match "")))) ((not what) (throw 'exit nil)) ; Nothing to do. (t (insert-before-markers "\n") (backward-char 1) diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el index 35905d3..437b594 100644 --- a/testing/lisp/test-org.el +++ b/testing/lisp/test-org.el @@ -2858,6 +2858,165 @@ (ert-deftest test-org/at-planning-p () "* Headline\n*** Inlinetask\n*** END\nDEADLINE: <2014-03-04 tue.>" (let ((org-inlinetask-min-level 3)) (org-at-planning-p)))))) +(ert-deftest test-org/add-planning-info () + "Test `org-add-planning-info'." + ;; Create deadline when `org-adapt-indentation' is non-nil. + (should + (equal "* H\n DEADLINE: <2015-06-25>\nParagraph" + (org-test-with-temp-text "* H\nParagraph" + (let ((org-adapt-indentation t)) + (org-add-planning-info 'deadline "<2015-06-25 Thu>")) + (replace-regexp-in-string + "\\( [.A-Za-z]+\\)>" "" (buffer-string) + nil nil 1)))) + ;; Create deadline when `org-adapt-indentation' is nil. + (should + (equal "* H\nDEADLINE: <2015-06-25>\nParagraph" + (org-test-with-temp-text "* H\nParagraph" + (let ((org-adapt-indentation nil)) + (org-add-planning-info 'deadline "<2015-06-25 Thu>")) + (replace-regexp-in-string + "\\( [.A-Za-z]+\\)>" "" (buffer-string) + nil nil 1)))) + ;; Update deadline when `org-adapt-indentation' is non-nil. + (should + (equal "* H\n DEADLINE: <2015-06-25>\nParagraph" + (org-test-with-temp-text "\ +* H + DEADLINE: <2015-06-24 Wed> +Paragraph" + (let ((org-adapt-indentation t)) + (org-add-planning-info 'deadline "<2015-06-25 Thu>")) + (replace-regexp-in-string + "\\( [.A-Za-z]+\\)>" "" (buffer-string) + nil nil 1)))) + ;; Update deadline when `org-adapt-indentation' is nil. + (should + (equal "* H\nDEADLINE: <2015-06-25>\nParagraph" + (org-test-with-temp-text "\ +* H +DEADLINE: <2015-06-24 Wed> +Paragraph" + (let ((org-adapt-indentation nil)) + (org-add-planning-info 'deadline "<2015-06-25 Thu>")) + (replace-regexp-in-string + "\\( [.A-Za-z]+\\)>" "" (buffer-string) + nil nil 1)))) + ;; Schedule when `org-adapt-indentation' is non-nil. + (should + (equal "* H\n SCHEDULED: <2015-06-25>\nParagraph" + (org-test-with-temp-text "* H\nParagraph" + (let ((org-adapt-indentation t)) + (org-add-planning-info 'scheduled "<2015-06-25 Thu>")) + (replace-regexp-in-string + "\\( [.A-Za-z]+\\)>" "" (buffer-string) + nil nil 1)))) + ;; Schedule when `org-adapt-indentation' is nil. + (should + (equal "* H\nSCHEDULED: <2015-06-25>\nParagraph" + (org-test-with-temp-text "* H\nParagraph" + (let ((org-adapt-indentation nil)) + (org-add-planning-info 'scheduled "<2015-06-25 Thu>")) + (replace-regexp-in-string + "\\( [.A-Za-z]+\\)>" "" (buffer-string) + nil nil 1)))) + ;; Add deadline when scheduled. + (should + (equal "\ +* H + DEADLINE: <2015-06-25> SCHEDULED: <2015-06-24> +Paragraph" + (org-test-with-temp-text "\ +* H + SCHEDULED: <2015-06-24 Wed> +Paragraph" + (let ((org-adapt-indentation t)) + (org-add-planning-info 'deadline "<2015-06-25 Thu>")) + (replace-regexp-in-string + "\\( [.A-Za-z]+\\)>" "" (buffer-string) + nil nil 1)))) + ;; Remove middle entry. + (should + (equal "\ +* H + CLOSED: [2015-06-24] SCHEDULED: <2015-06-24> +Paragraph" + (org-test-with-temp-text "\ +* H + CLOSED: [2015-06-24 Wed] DEADLINE: <2015-06-25 Thu> SCHEDULED: <2015-06-24 Wed> +Paragraph" + (let ((org-adapt-indentation t)) + (org-add-planning-info nil nil 'deadline)) + (replace-regexp-in-string + "\\( [.A-Za-z]+\\)[]>]" "" (buffer-string) + nil nil 1)))) + ;; Remove last entry and then middle entry (order should not + ;; matter). + (should + (equal "\ +* H + CLOSED: [2015-06-24] +Paragraph" + (org-test-with-temp-text "\ +* H + CLOSED: [2015-06-24 Wed] DEADLINE: <2015-06-25 Thu> SCHEDULED: <2015-06-24 Wed> +Paragraph" + (let ((org-adapt-indentation t)) + (org-add-planning-info nil nil 'scheduled 'deadline)) + (replace-regexp-in-string + "\\( [.A-Za-z]+\\)[]>]" "" (buffer-string) + nil nil 1)))) + ;; Remove closed when `org-adapt-indentation' is non-nil. + (should + (equal "* H\n DEADLINE: <2015-06-25>\nParagraph" + (org-test-with-temp-text "\ +* H + CLOSED: [2015-06-25 Thu] DEADLINE: <2015-06-25 Thu> +Paragraph" + (let ((org-adapt-indentation t)) + (org-add-planning-info nil nil 'closed)) + (replace-regexp-in-string + "\\( [.A-Za-z]+\\)>" "" (buffer-string) + nil nil 1)))) + ;; Remove closed when `org-adapt-indentation' is nil. + (should + (equal "* H\nDEADLINE: <2015-06-25>\nParagraph" + (org-test-with-temp-text "\ +* H +CLOSED: [2015-06-25 Thu] DEADLINE: <2015-06-25 Thu> +Paragraph" + (let ((org-adapt-indentation nil)) + (org-add-planning-info nil nil 'closed)) + (replace-regexp-in-string + "\\( [.A-Za-z]+\\)>" "" (buffer-string) + nil nil 1)))) + ;; Remove closed entry and delete empty line. + (should + (equal "\ +* H +Paragraph" + (org-test-with-temp-text "\ +* H + CLOSED: [2015-06-24 Wed] +Paragraph" + (let ((org-adapt-indentation t)) + (org-add-planning-info nil nil 'closed)) + (replace-regexp-in-string + "\\( [.A-Za-z]+\\)>" "" (buffer-string) + nil nil 1)))) + ;; Remove one entry and update another. + (should + (equal "* H\n DEADLINE: <2015-06-25>\nParagraph" + (org-test-with-temp-text "\ +* H + SCHEDULED: <2015-06-23 Tue> DEADLINE: <2015-06-24 Wed> +Paragraph" + (let ((org-adapt-indentation t)) + (org-add-planning-info 'deadline "<2015-06-25 Thu>" 'scheduled)) + (replace-regexp-in-string + "\\( [.A-Za-z]+\\)>" "" (buffer-string) + nil nil 1))))) + ;;; Property API -- 2.4.4