浏览代码

Fix bulk agenda processing with parents and children in the loop

Bernt Hansen writes:

> Every so often I run into a situation where bulk refiling
> doesn't work anymore.
>
> I currently have 15 items in my refile.org file that I want
> to refile to other locations.  I marked a few of them and
> bulk refiled them just fine.  Then I marked a few more and B
> r fails with "Cannot find entry for marker #<marker at
> 297156 in norang.org>"
>
> I think this happens when I mark multiple tasks in the same
> subtree (i.e. the parent and a sibling) and refile both to
> the same location.  After that it gets confused.
>
> If I have a task like this in refile.org
>
> #+FILETAGS: REFILE
> * Test
> ** Test 2
>
> and run a tags match on REFILE I see both tasks.  Mark both
> with m in the agenda and B r to some other location.  It
> refiles the first (and this moves the sibling too) and then
> it's broken after that.
>
> I get the following backtrace
>
> Debugger entered--Lisp error: (error "Cannot find entry for
> marker #<marker at 297156 in norang.org>")

Indeed the happens because, when a parent gets refiled or
achieved, any entries corresponding to its children are
removed from the agenda.

We address this issue by

- sorting the markers, to make sure parents will be handled
  before children

- No longer throwing an error when a bulk action entry no
  longer is present in the agenda - most likely it was taken
  care of together with its parent.
Carsten Dominik 15 年之前
父节点
当前提交
babd053bd6
共有 2 个文件被更改,包括 31 次插入8 次删除
  1. 5 0
      lisp/ChangeLog
  2. 26 8
      lisp/org-agenda.el

+ 5 - 0
lisp/ChangeLog

@@ -1,5 +1,10 @@
 2009-08-04  Carsten Dominik  <carsten.dominik@gmail.com>
 
+	* org-agenda.el (org-agenda-bulk-action): Make sure parents are
+	handled before children, and do not error if an entry is not
+	found, probably because it hase been remove when the parent was
+	archived or refiled.
+
 	* org.el (org-ido-completing-read): Accept straight lists for
 	completion as well as alists.
 

+ 26 - 8
lisp/org-agenda.el

@@ -6335,7 +6335,7 @@ This will remove the markers, and the overlays."
   (message "Bulk: [r]efile [$]archive [A]rch->sib [t]odo [+/-]tag [s]chedule [d]eadline")
   (let* ((action (read-char-exclusive))
 	 (entries (reverse org-agenda-bulk-marked-entries))
-	 cmd rfloc state e tag (cnt 0))
+	 cmd rfloc state e tag (cnt 0) (cntskip 0))
     (cond
      ((equal action ?$)
       (setq cmd '(org-agenda-archive)))
@@ -6391,17 +6391,35 @@ This will remove the markers, and the overlays."
 			 (fmakunbound 'read-string)))))))
      (t (error "Invalid bulk action")))
 
+    ;; Sort the markers, to make sure that parents are handled before children
+    (setq entries (sort entries
+			(lambda (a b)
+			  (cond
+			   ((equal (marker-buffer a) (marker-buffer b))
+			    (< (marker-position a) (marker-position b)))
+			   (t
+			    (string< (buffer-name (marker-buffer a))
+				     (buffer-name (marker-buffer b))))))))
+
     ;; Now loop over all markers and apply cmd
     (while (setq e (pop entries))
-      (goto-char
-       (or (text-property-any (point-min) (point-max) 'org-hd-marker e)
-	   (error "Cannot find entry for marker %s" e)))
-      (eval cmd)
-      (setq org-agenda-bulk-marked-entries (delete e org-agenda-bulk-marked-entries))
-      (setq cnt (1+ cnt)))
+      (setq pos (text-property-any (point-min) (point-max) 'org-hd-marker e))
+      (if (not pos)
+	  (progn (message "Skipping removed entry at %s" e)
+		 (setq cntskip (1+ cntskip)))
+	(goto-char pos)
+	(eval cmd)
+	(setq org-agenda-bulk-marked-entries
+	      (delete e org-agenda-bulk-marked-entries))
+	(setq cnt (1+ cnt))))
     (setq org-agenda-bulk-marked-entries nil)
     (org-agenda-bulk-remove-all-marks)
-    (message "Acted on %d entries" cnt)))
+    (message "Acted on %d entries%s"
+	     cnt
+	     (if (= cntskip 0)
+		 ""
+	       (format ", skipped %d (disappeared before their turn)"
+		       cntskip)))))
 
 ;;; Appointment reminders