From 27e4d7ce487b38428618ed1fb2a6e2a1b59098bc Mon Sep 17 00:00:00 2001 From: Bastien Date: Fri, 14 Feb 2020 10:32:35 +0100 Subject: [PATCH] Prevent infinite loop when showing new time in agenda * lisp/org-agenda.el (org-agenda-dim-blocked-tasks): Don't use an overlay to make the task invisible, use text properties. (org-agenda--mark-blocked-entry): Add text property 'org-filter-type to later use `org-agenda-filter-hide-line' if necessary. (org-agenda-filter-hide-line): Fix docstring. The related bug was first reported in 2013 by Matt Lundin here: https://lists.gnu.org/archive/html/emacs-orgmode/2013-08/msg00072.html Then Andrew Hyatt reported it again, and provided a minimal recipe on how to reproduce it consistently. Thanks a lot to both of them. --- lisp/org-agenda.el | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/lisp/org-agenda.el b/lisp/org-agenda.el index aed1b24ac..ec1271010 100644 --- a/lisp/org-agenda.el +++ b/lisp/org-agenda.el @@ -4003,7 +4003,7 @@ dimming them." (when (called-interactively-p 'interactive) (message "Dim or hide blocked tasks...")) (dolist (o (overlays-in (point-min) (point-max))) - (when (eq (overlay-get o 'org-type) 'org-blocked-todo) + (when (eq (overlay-get o 'face) 'org-agenda-dimmed-todo-face) (delete-overlay o))) (save-excursion (let ((inhibit-read-only t)) @@ -4011,22 +4011,26 @@ dimming them." (while (let ((pos (text-property-not-all (point) (point-max) 'org-todo-blocked nil))) (when pos (goto-char pos))) - (let* ((invisible (eq (org-get-at-bol 'org-todo-blocked) 'invisible)) + (let* ((invisible + (eq (org-get-at-bol 'org-todo-blocked) 'invisible)) + (todo-blocked + (eq (org-get-at-bol 'org-filter-type) 'todo-blocked)) (ov (make-overlay (if invisible (line-end-position 0) (line-beginning-position)) (line-end-position)))) - (if invisible - (overlay-put ov 'invisible t) + (when todo-blocked (overlay-put ov 'face 'org-agenda-dimmed-todo-face)) - (overlay-put ov 'org-type 'org-blocked-todo)) - (forward-line)))) + (when invisible + (org-agenda-filter-hide-line 'todo-blocked))) + (move-beginning-of-line 2)))) (when (called-interactively-p 'interactive) (message "Dim or hide blocked tasks...done"))) (defun org-agenda--mark-blocked-entry (entry) - "For ENTRY a string with the text property `org-hd-marker', if -the header at `org-hd-marker' is blocked according to + "If ENTRY is blocked, mark it for fontification or invisibility. + +If the header at `org-hd-marker' is blocked according to `org-entry-blocked-p', then if `org-agenda-dim-blocked-tasks' is 'invisible and the header is not blocked by checkboxes, set the text property `org-todo-blocked' to `invisible', otherwise set it @@ -4050,7 +4054,9 @@ to t." (put-text-property 0 (length entry) 'org-todo-blocked (if really-invisible 'invisible t) - entry))))))) + entry) + (put-text-property + 0 (length entry) 'org-filter-type 'todo-blocked entry))))))) entry) (defvar org-agenda-skip-function nil @@ -8064,13 +8070,13 @@ tags in the FILTER if any of the tags in FILTER are grouptags." org-agenda-filtered-by-top-headline t)) (defun org-agenda-filter-hide-line (type) - "Hide lines with TYPE in the agenda buffer." + "If current line is TYPE, hide it in the agenda buffer." (let* (buffer-invisibility-spec - (b (max (point-min) (1- (point-at-bol)))) - (e (point-at-eol))) + (beg (max (point-min) (1- (point-at-bol)))) + (end (point-at-eol))) (let ((inhibit-read-only t)) (add-text-properties - b e `(invisible org-filtered org-filter-type ,type))))) + beg end `(invisible org-filtered org-filter-type ,type))))) (defun org-agenda-remove-filter (type) (interactive)