diff options
author | Stephen Berman <stephen.berman@gmx.net> | 2017-07-07 17:37:46 +0200 |
---|---|---|
committer | Stephen Berman <stephen.berman@gmx.net> | 2017-07-07 17:37:46 +0200 |
commit | 1cf6b1579976227346284033c3e333e53226a350 (patch) | |
tree | dec78bfc13f142f148e87fbd41f9a12eae481fda /lisp/calendar | |
parent | 579a9ee22e0decf7bed8aff1751c5b3d147b921f (diff) | |
download | emacs-1cf6b1579976227346284033c3e333e53226a350.tar.gz |
Fix several todo-mode bugs found while debugging bug#27609
* lisp/calendar/todo-mode.el (todo-toggle-mark-item): Calculate
current category only once.
(todo-mark-category): Update number of marked items to avoid
spurious duplication in todo-categories-with-marks alist and
corruption of the todo-categories alist. Handle empty line
when there are no todo items and done items are shown.
(todo-set-item-priority): Make noop if called from
todo-raise-item-priority or todo-lower-item-priority when
point is on a done todo item or an empty line.
(todo-move-item): Use markers instead of integer positions to
correctly handle deleting the now moved items from the source
category (without markers an infinite loop arises when moving
marked item to a preceding category).
(todo-unarchive-items): Put point on the (first) restored done
item, instead of leaving it at the end of the done items
separator string.
(todo-revert-buffer): Ensure buffer remains read-only after
reverting.
Diffstat (limited to 'lisp/calendar')
-rw-r--r-- | lisp/calendar/todo-mode.el | 95 |
1 files changed, 54 insertions, 41 deletions
diff --git a/lisp/calendar/todo-mode.el b/lisp/calendar/todo-mode.el index 7b27e7049d1..eb8d3d65eb5 100644 --- a/lisp/calendar/todo-mode.el +++ b/lisp/calendar/todo-mode.el @@ -1731,46 +1731,49 @@ done items sections are visible, the sequence of N items can consist of the the last todo items and the first done items." (interactive "p") (when (todo-item-string) - (unless (> n 1) (setq n 1)) - (catch 'end - (dotimes (i n) - (let* ((cat (todo-current-category)) - (marks (assoc cat todo-categories-with-marks)) - (ov (progn - (unless (looking-at todo-item-start) - (todo-item-start)) - (todo-get-overlay 'prefix))) - (pref (overlay-get ov 'before-string))) - (if (todo-marked-item-p) - (progn - (overlay-put ov 'before-string (substring pref 1)) - (if (= (cdr marks) 1) ; Deleted last mark in this category. - (setq todo-categories-with-marks - (assq-delete-all cat todo-categories-with-marks)) - (setcdr marks (1- (cdr marks))))) - (overlay-put ov 'before-string (concat todo-item-mark pref)) - (if marks - (setcdr marks (1+ (cdr marks))) - (push (cons cat 1) todo-categories-with-marks)))) - (todo-forward-item) - ;; Don't try to mark the empty lines at the end of the todo - ;; and done items sections. - (when (looking-at "^$") - (if (eobp) - (throw 'end nil) - (todo-forward-item))))))) + (let ((cat (todo-current-category))) + (unless (> n 1) (setq n 1)) + (catch 'end + (dotimes (i n) + (let* ((marks (assoc cat todo-categories-with-marks)) + (ov (progn + (unless (looking-at todo-item-start) + (todo-item-start)) + (todo-get-overlay 'prefix))) + (pref (overlay-get ov 'before-string))) + (if (todo-marked-item-p) + (progn + (overlay-put ov 'before-string (substring pref 1)) + (if (= (cdr marks) 1) ; Deleted last mark in this category. + (setq todo-categories-with-marks + (assq-delete-all cat todo-categories-with-marks)) + (setcdr marks (1- (cdr marks))))) + (overlay-put ov 'before-string (concat todo-item-mark pref)) + (if marks + (setcdr marks (1+ (cdr marks))) + (push (cons cat 1) todo-categories-with-marks)))) + (todo-forward-item) + ;; Don't try to mark the empty lines at the end of the todo + ;; and done items sections. + (when (looking-at "^$") + (if (eobp) + (throw 'end nil) + (todo-forward-item)))))))) (defun todo-mark-category () "Mark all visible items in this category with `todo-item-mark'." (interactive) - (let* ((cat (todo-current-category)) - (marks (assoc cat todo-categories-with-marks))) + (let ((cat (todo-current-category))) (save-excursion (goto-char (point-min)) (while (not (eobp)) - (let* ((ov (todo-get-overlay 'prefix)) - (pref (overlay-get ov 'before-string))) - (unless (todo-marked-item-p) + (let* ((marks (assoc cat todo-categories-with-marks)) + (ov (todo-get-overlay 'prefix)) + ;; When done items are shown and there are no todo items, the + ;; loop starts on the empty line in the todo items sections, + ;; which has no overlay, so don't try to get it. + (pref (when ov (overlay-get ov 'before-string)))) + (unless (or (todo-marked-item-p) (not ov)) (overlay-put ov 'before-string (concat todo-item-mark pref)) (if marks (setcdr marks (1+ (cdr marks))) @@ -1791,7 +1794,7 @@ consist of the the last todo items and the first done items." (goto-char (point-min)) (while (not (eobp)) (let* ((ov (todo-get-overlay 'prefix)) - ;; No overlay on empty line between todo and done items. + ;; See comment above in `todo-mark-category'. (pref (when ov (overlay-get ov 'before-string)))) (when (todo-marked-item-p) (overlay-put ov 'before-string (substring pref 1))) @@ -2513,7 +2516,7 @@ numerical prefix argument, or noninteractively by argument ARG, whose value can be either of the symbols `raise' or `lower', meaning to raise or lower the item's priority by one." (interactive) - (unless (and (called-interactively-p 'any) + (unless (and (or (called-interactively-p 'any) (memq arg '(raise lower))) (or (todo-done-item-p) (looking-at "^$"))) (let* ((item (or item (todo-item-string))) (marked (todo-marked-item-p)) @@ -2530,7 +2533,7 @@ meaning to raise or lower the item's priority by one." (re-search-forward regexp1 nil t) (match-string-no-properties 1))))))) curnum - (todo (cond ((or (eq arg 'raise) (eq arg 'lower) + (todo (cond ((or (memq arg '(raise lower)) (eq major-mode 'todo-filtered-items-mode)) (save-excursion (let ((curstart (todo-item-start)) @@ -2761,10 +2764,13 @@ section in the category moved to." (forward-line) (setq beg (point)) (setq end (if (re-search-forward - (concat "^" (regexp-quote - todo-category-beg)) nil t) - (match-beginning 0) - (point-max))) + (concat "^" + (regexp-quote todo-category-beg)) + nil t) + (progn + (goto-char (match-beginning 0)) + (point-marker)) + (point-max-marker))) (goto-char beg) (while (< (point) end) (if (todo-marked-item-p) @@ -3263,6 +3269,10 @@ the only category in the archive, the archive file is deleted." (set-buffer (find-file-noselect tfile))) (todo-category-number cat) (todo-category-select) + ;; Selecting the category leaves point at the end of the done + ;; items separator string, so move it to the (first) restored + ;; done item. + (forward-line) (message "Items unarchived."))))) (defun todo-jump-to-archive-category (&optional file) @@ -5221,7 +5231,10 @@ Also preserve category display, if applicable." (let ((revert-buffer-function nil)) (revert-buffer ignore-auto noconfirm 'preserve-modes) (when (memq major-mode '(todo-mode todo-archive-mode)) - (todo-category-select)))) + (save-excursion (todo-category-select)) + ;; revert-buffer--default calls after-find-file, which makes + ;; buffer writable. + (setq buffer-read-only t)))) (defun todo-desktop-save-buffer (_dir) `((catnum . ,(todo-category-number (todo-current-category))))) |