emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* Feature request and patch - blocked TODO to say BLOCKED
       [not found] <20090101170227.C707734803@mail2.panix.com>
@ 2009-01-01 22:53 ` Tom Breton (Tehom)
  2009-01-09  8:16   ` Carsten Dominik
  0 siblings, 1 reply; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-01-01 22:53 UTC (permalink / raw)
  To: emacs-orgmode


Motivating incident: I had a todo-type item that contained no tasks
itself, directly, but linked to other tasks.  I arranged it this way
in order that those other tasks could be placed neatly in a hierarchy
and not appear as "TODO" in two places.  I used the org-depend.el
BLOCKER code to manage this situation.  BTW, it works nicely.

But when a task is blocked, the heading is left with no "TODO" marking
at all.  That's not so bad for sibling tasks, because there's one
right above it that says "TODO" (or something).  But for distant-link
style tasks, IMO it gives a misleading impression that there is
nothing to do.

I request the following:

 * Object: One TODO workflow keyword set that relates specially to
   "BLOCKER".  It would be something like (sequence "BLOCKED" "|"
   "UNBLOCKED").
 * Behavior: When a C-c C-t change to a heading is blocked, instead of
   doing nothing, mark the heading with the first entry in the
   blockage workflow keyword set.
 * Behavior: Also do so when there is a blocked C-c C-t change to any
   heading whose TODO mark is in a state in the blockage workflow
   keyword set.
 * Behavior: Ordinarily don't offer the blockage workflow keyword set
   for C-c C-t and related commands.

I append a patch which does this.

The change mostly affects org.el, because allowing new TODO keywords
requires org.el to know about them, at least in computing some regular
expressions.  It was also a lot neater to let org-todo react to
blocked transitions than to try to make `org-depend-block-todo' do it,
which also avoided `org-todo' indirectly calling itself.

Summary of changes

Added 3 variables:
 * org-todo-use-blockage-keywords-p :: whether to use this
 * org-todo-blockage-keywords :: configurable keywords
 * org-blockage-keywords-1 :: internal

Encapsulated part of `org-set-regexps-and-options' as
`org-set-todo-constants'.  I had to because it needed to be called
twice, once for normal keywords and once with a flag for blockage
keywords.  I used encap-sexp to do it automatically (it's on my site,
http://panix.com/~tehom/my-code/), so no code changed, and I kept that
comment aligned with the regexp.

Made `org-set-regexps-and-options' also process
`org-todo-blockage-keywords'.

Changed the behavior of org-todo and org-depend-block-todo as described
above.

Tom Breton (Tehom)

*** org-depend.el	2008-12-18 18:26:05.000000000 -0500
--- new-org-depend.el	2009-01-01 17:13:13.000000000 -0500
***************
*** 196,204 ****
        (unless (eq type 'todo-state-change)
  	;; We are not handling this kind of change
  	(throw 'return t))
!       (unless (and (not from) (member to org-not-done-keywords))
! 	;; This is not a change from nothing to TODO, ignore it
! 	(throw 'return t))

        ;; OK, the plan is to switch from nothing to TODO
        ;; Lets see if we will allow it.  Find the BLOCKER property
--- 196,210 ----
        (unless (eq type 'todo-state-change)
  	;; We are not handling this kind of change
  	(throw 'return t))
!        ;;Act on only the right types of TODO-change:
!        (unless
! 	  (or
! 	     ;;A change from a member of the blockage set
! 	     (member from org-todo-blockage-keywords)
! 	     ;;A change from nothing to TODO
! 	     (and (not from) (member to org-not-done-keywords)))
! 	  ;; Otherwise ignore it
! 	  (throw 'return t))

        ;; OK, the plan is to switch from nothing to TODO
        ;; Lets see if we will allow it.  Find the BLOCKER property
*** old-org.el	2008-12-18 18:26:05.000000000 -0500
--- org.el	2009-01-01 17:25:32.000000000 -0500
***************
*** 1458,1464 ****
  		    (const :tag "Type     (cycling directly to DONE)" type))
  		   (repeat
  		    (string :tag "Keyword"))))))
-
  (defvar org-todo-keywords-1 nil
    "All TODO and DONE keywords active in a buffer.")
  (make-variable-buffer-local 'org-todo-keywords-1)
--- 1458,1463 ----
***************
*** 1483,1488 ****
--- 1482,1494 ----
  (make-variable-buffer-local 'org-todo-key-alist)
  (defvar org-todo-key-trigger nil)
  (make-variable-buffer-local 'org-todo-key-trigger)
+ (defvar org-todo-use-blockage-keywords-p t)
+ (defvar org-todo-blockage-keywords
+    '(sequence "BLOCKED" "|" "UNBLOCKED")
+    "Keywords of the blocking workflow keyword set." )
+ (defvar org-blockage-keywords-1 nil
+    "All blockage keywords active in a buffer" )
+ (make-variable-buffer-local 'org-blockage-keywords-1)

  (defcustom org-todo-interpretation 'sequence
    "Controls how TODO keywords are interpreted.
***************
*** 2997,3002 ****
--- 3003,3079 ----
  set this variable to if the option is found.  An optional forth element
PUSH
  means to push this value onto the list in the variable.")

+ (defun org-set-todo-constants (kwds block)
+    ""
+    (let
+       (inter kws kw)
+       (while
+ 	 (setq kws (pop kwds))
+ 	 (setq
+ 	    inter (pop kws)
+ 	    sep (member "|" kws)
+ 	    kws0 (delete "|"
+ 		    (copy-sequence kws))
+ 	    kwsa nil
+ 	    kws1
+ 	    (mapcar
+ 	       (lambda
+ 		  (x)
+ 		  (if
+ 		     ;;                 1              2
+ 		     (string-match "^\\(.*?\\)\\(?:(\\([^!@/]\\)?.*?)\\)?$" x)
+ 		     (progn
+ 			(setq kw
+ 			   (match-string 1 x)
+ 			   key
+ 			   (and
+ 			      (match-end 2)
+ 			      (match-string 2 x))
+ 			   log
+ 			   (org-extract-log-state-settings x))
+ 			(push
+ 			   (cons kw
+ 			      (and key
+ 				 (string-to-char key)))
+ 			   kwsa)
+ 			(and log
+ 			   (push log org-todo-log-states))
+ 			kw)
+ 		     (error "Invalid TODO keyword %s" x)))
+ 	       kws0)
+ 	    kwsa
+ 	    (if kwsa
+ 	       (append
+ 		  '((:startgroup))
+ 		  (nreverse kwsa)
+ 		  '((:endgroup))))
+ 	    hw (car kws1)
+ 	    dws (if sep
+ 		   (org-remove-keyword-keys
+ 		      (cdr sep))
+ 		   (last kws1))
+ 	    tail (list inter hw
+ 		    (car dws)
+ 		    (org-last dws)))
+ 	 (add-to-list 'org-todo-heads hw 'append)
+ 	 (push kws1 org-todo-sets)
+ 	 (setq org-done-keywords
+ 	    (append org-done-keywords dws nil))
+ 	 (setq org-todo-key-alist
+ 	    (append org-todo-key-alist kwsa))
+ 	 (mapc
+ 	    (lambda
+ 	       (x)
+ 	       (push
+ 		  (cons x tail)
+ 		  org-todo-kwd-alist))
+ 	    kws1)
+ 	 (if block
+ 	    (setq org-blockage-keywords-1
+ 	       (append org-blockage-keywords-1 kws1 nil)))
+ 	 (setq org-todo-keywords-1
+ 	    (append org-todo-keywords-1 kws1 nil)))))
+
  (defun org-set-regexps-and-options ()
    "Precompute regular expressions for current buffer."
    (when (org-mode-p)
***************
*** 3116,3156 ****
  	    (setq kwds (list (cons org-todo-interpretation
  				   (default-value 'org-todo-keywords)))))
  	(setq kwds (reverse kwds)))
!       (setq kwds (nreverse kwds))
!       (let (inter kws kw)
! 	(while (setq kws (pop kwds))
! 	  (setq inter (pop kws) sep (member "|" kws)
! 		kws0 (delete "|" (copy-sequence kws))
! 		kwsa nil
! 		kws1 (mapcar
! 		      (lambda (x)
! 			;;                     1              2
! 			(if (string-match "^\\(.*?\\)\\(?:(\\([^!@/]\\)?.*?)\\)?$" x)
! 			    (progn
! 			      (setq kw (match-string 1 x)
! 				    key (and (match-end 2) (match-string 2 x))
! 				    log (org-extract-log-state-settings x))
! 			      (push (cons kw (and key (string-to-char key))) kwsa)
! 			      (and log (push log org-todo-log-states))
! 			      kw)
! 			  (error "Invalid TODO keyword %s" x)))
! 		      kws0)
! 		kwsa (if kwsa (append '((:startgroup))
! 				      (nreverse kwsa)
! 				      '((:endgroup))))
! 		hw (car kws1)
! 		dws (if sep (org-remove-keyword-keys (cdr sep)) (last kws1))
! 		tail (list inter hw (car dws) (org-last dws)))
! 	  (add-to-list 'org-todo-heads hw 'append)
! 	  (push kws1 org-todo-sets)
! 	  (setq org-done-keywords (append org-done-keywords dws nil))
! 	  (setq org-todo-key-alist (append org-todo-key-alist kwsa))
! 	  (mapc (lambda (x) (push (cons x tail) org-todo-kwd-alist)) kws1)
! 	  (setq org-todo-keywords-1 (append org-todo-keywords-1 kws1 nil)))
! 	(setq org-todo-sets (nreverse org-todo-sets)
! 	      org-todo-kwd-alist (nreverse org-todo-kwd-alist)
! 	      org-todo-key-trigger (delq nil (mapcar 'cdr org-todo-key-alist))
! 	      org-todo-key-alist (org-assign-fast-keys org-todo-key-alist)))
        ;; Process the constants
        (when const
  	(let (e cst)
--- 3193,3209 ----
  	    (setq kwds (list (cons org-todo-interpretation
  				   (default-value 'org-todo-keywords)))))
  	(setq kwds (reverse kwds)))
!       ;;(setq kwds (append (nreverse kwds) (list
org-todo-blockage-keywords)))
!       (org-set-todo-constants (nreverse kwds) nil)
!        (when org-todo-use-blockage-keywords-p
! 	  (org-set-todo-constants (list org-todo-blockage-keywords) t))
!       (setq
! 	 org-todo-sets (nreverse org-todo-sets)
! 	 org-todo-kwd-alist (nreverse org-todo-kwd-alist)
! 	 org-todo-key-trigger (delq nil
! 				 (mapcar 'cdr org-todo-key-alist))
! 	 org-todo-key-alist (org-assign-fast-keys org-todo-key-alist))
!
        ;; Process the constants
        (when const
  	(let (e cst)
***************
*** 8222,8232 ****
  		    (save-match-data
  		      (run-hook-with-args-until-failure
  		       'org-blocker-hook change-plist)))
! 	    (if (interactive-p)
! 		(error "TODO state change from %s to %s blocked" this state)
! 	      ;; fail silently
! 	      (message "TODO state change from %s to %s blocked" this state)
! 	      (throw 'exit nil))))
  	(store-match-data match-data)
  	(replace-match next t t)
  	(unless (pos-visible-in-window-p hl-pos)
--- 8275,8294 ----
  		    (save-match-data
  		      (run-hook-with-args-until-failure
  		       'org-blocker-hook change-plist)))
! 	     (if
! 		org-todo-use-blockage-keywords-p
! 		(let
! 		   ((blocked-state (car org-blockage-keywords-1)))
! 		   (setq arg 'none)
! 		   (setq next (concat " " blocked-state " "))
! 		   (unless
! 		      (string= state blocked-state)
! 		      (message "TODO state change from %s to %s blocked" this state)))
! 		(if (interactive-p)
! 		   (error "TODO state change from %s to %s blocked" this state)
! 		   ;; fail silently
! 		   (message "TODO state change from %s to %s blocked" this state)
! 		   (throw 'exit nil)))))
  	(store-match-data match-data)
  	(replace-match next t t)
  	(unless (pos-visible-in-window-p hl-pos)

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Feature request and patch - blocked TODO to say BLOCKED
  2009-01-01 22:53 ` Feature request and patch - blocked TODO to say BLOCKED Tom Breton (Tehom)
@ 2009-01-09  8:16   ` Carsten Dominik
  2009-01-15  2:34     ` Tom Breton (Tehom)
  2009-01-19  3:33     ` Advice sought on managing decision alternatives Tom Breton (Tehom)
  0 siblings, 2 replies; 56+ messages in thread
From: Carsten Dominik @ 2009-01-09  8:16 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode

Hi Tom,

I am hesitant to apply this relatively complex patch which
I have not had the time to study closely enough.
I am wondering:  Instead of setting a TODO keyword,
would it not be simpler and equally effective to set a
special tag when an entry is blocked?

You could use a bright font to mark this tag, in order to
make it obvious.  And you could use a custom query to look
for blocked items, to see what can be done about them....

- Carsten

On Jan 1, 2009, at 11:53 PM, Tom Breton (Tehom) wrote:

>
> Motivating incident: I had a todo-type item that contained no tasks
> itself, directly, but linked to other tasks.  I arranged it this way
> in order that those other tasks could be placed neatly in a hierarchy
> and not appear as "TODO" in two places.  I used the org-depend.el
> BLOCKER code to manage this situation.  BTW, it works nicely.
>
> But when a task is blocked, the heading is left with no "TODO" marking
> at all.  That's not so bad for sibling tasks, because there's one
> right above it that says "TODO" (or something).  But for distant-link
> style tasks, IMO it gives a misleading impression that there is
> nothing to do.
>
> I request the following:
>
> * Object: One TODO workflow keyword set that relates specially to
>   "BLOCKER".  It would be something like (sequence "BLOCKED" "|"
>   "UNBLOCKED").
> * Behavior: When a C-c C-t change to a heading is blocked, instead of
>   doing nothing, mark the heading with the first entry in the
>   blockage workflow keyword set.
> * Behavior: Also do so when there is a blocked C-c C-t change to any
>   heading whose TODO mark is in a state in the blockage workflow
>   keyword set.
> * Behavior: Ordinarily don't offer the blockage workflow keyword set
>   for C-c C-t and related commands.
>
> I append a patch which does this.
>
> The change mostly affects org.el, because allowing new TODO keywords
> requires org.el to know about them, at least in computing some regular
> expressions.  It was also a lot neater to let org-todo react to
> blocked transitions than to try to make `org-depend-block-todo' do it,
> which also avoided `org-todo' indirectly calling itself.
>
> Summary of changes
>
> Added 3 variables:
> * org-todo-use-blockage-keywords-p :: whether to use this
> * org-todo-blockage-keywords :: configurable keywords
> * org-blockage-keywords-1 :: internal
>
> Encapsulated part of `org-set-regexps-and-options' as
> `org-set-todo-constants'.  I had to because it needed to be called
> twice, once for normal keywords and once with a flag for blockage
> keywords.  I used encap-sexp to do it automatically (it's on my site,
> http://panix.com/~tehom/my-code/), so no code changed, and I kept that
> comment aligned with the regexp.
>
> Made `org-set-regexps-and-options' also process
> `org-todo-blockage-keywords'.
>
> Changed the behavior of org-todo and org-depend-block-todo as  
> described
> above.
>
> Tom Breton (Tehom)
>
> *** org-depend.el	2008-12-18 18:26:05.000000000 -0500
> --- new-org-depend.el	2009-01-01 17:13:13.000000000 -0500
> ***************
> *** 196,204 ****
>        (unless (eq type 'todo-state-change)
>  	;; We are not handling this kind of change
>  	(throw 'return t))
> !       (unless (and (not from) (member to org-not-done-keywords))
> ! 	;; This is not a change from nothing to TODO, ignore it
> ! 	(throw 'return t))
>
>        ;; OK, the plan is to switch from nothing to TODO
>        ;; Lets see if we will allow it.  Find the BLOCKER property
> --- 196,210 ----
>        (unless (eq type 'todo-state-change)
>  	;; We are not handling this kind of change
>  	(throw 'return t))
> !        ;;Act on only the right types of TODO-change:
> !        (unless
> ! 	  (or
> ! 	     ;;A change from a member of the blockage set
> ! 	     (member from org-todo-blockage-keywords)
> ! 	     ;;A change from nothing to TODO
> ! 	     (and (not from) (member to org-not-done-keywords)))
> ! 	  ;; Otherwise ignore it
> ! 	  (throw 'return t))
>
>        ;; OK, the plan is to switch from nothing to TODO
>        ;; Lets see if we will allow it.  Find the BLOCKER property
> *** old-org.el	2008-12-18 18:26:05.000000000 -0500
> --- org.el	2009-01-01 17:25:32.000000000 -0500
> ***************
> *** 1458,1464 ****
>  		    (const :tag "Type     (cycling directly to DONE)" type))
>  		   (repeat
>  		    (string :tag "Keyword"))))))
> -
>  (defvar org-todo-keywords-1 nil
>    "All TODO and DONE keywords active in a buffer.")
>  (make-variable-buffer-local 'org-todo-keywords-1)
> --- 1458,1463 ----
> ***************
> *** 1483,1488 ****
> --- 1482,1494 ----
>  (make-variable-buffer-local 'org-todo-key-alist)
>  (defvar org-todo-key-trigger nil)
>  (make-variable-buffer-local 'org-todo-key-trigger)
> + (defvar org-todo-use-blockage-keywords-p t)
> + (defvar org-todo-blockage-keywords
> +    '(sequence "BLOCKED" "|" "UNBLOCKED")
> +    "Keywords of the blocking workflow keyword set." )
> + (defvar org-blockage-keywords-1 nil
> +    "All blockage keywords active in a buffer" )
> + (make-variable-buffer-local 'org-blockage-keywords-1)
>
>  (defcustom org-todo-interpretation 'sequence
>    "Controls how TODO keywords are interpreted.
> ***************
> *** 2997,3002 ****
> --- 3003,3079 ----
>  set this variable to if the option is found.  An optional forth  
> element
> PUSH
>  means to push this value onto the list in the variable.")
>
> + (defun org-set-todo-constants (kwds block)
> +    ""
> +    (let
> +       (inter kws kw)
> +       (while
> + 	 (setq kws (pop kwds))
> + 	 (setq
> + 	    inter (pop kws)
> + 	    sep (member "|" kws)
> + 	    kws0 (delete "|"
> + 		    (copy-sequence kws))
> + 	    kwsa nil
> + 	    kws1
> + 	    (mapcar
> + 	       (lambda
> + 		  (x)
> + 		  (if
> + 		     ;;                 1              2
> + 		     (string-match "^\\(.*?\\)\\(?:(\\([^!@/]\\)?.*?)\\)?$" x)
> + 		     (progn
> + 			(setq kw
> + 			   (match-string 1 x)
> + 			   key
> + 			   (and
> + 			      (match-end 2)
> + 			      (match-string 2 x))
> + 			   log
> + 			   (org-extract-log-state-settings x))
> + 			(push
> + 			   (cons kw
> + 			      (and key
> + 				 (string-to-char key)))
> + 			   kwsa)
> + 			(and log
> + 			   (push log org-todo-log-states))
> + 			kw)
> + 		     (error "Invalid TODO keyword %s" x)))
> + 	       kws0)
> + 	    kwsa
> + 	    (if kwsa
> + 	       (append
> + 		  '((:startgroup))
> + 		  (nreverse kwsa)
> + 		  '((:endgroup))))
> + 	    hw (car kws1)
> + 	    dws (if sep
> + 		   (org-remove-keyword-keys
> + 		      (cdr sep))
> + 		   (last kws1))
> + 	    tail (list inter hw
> + 		    (car dws)
> + 		    (org-last dws)))
> + 	 (add-to-list 'org-todo-heads hw 'append)
> + 	 (push kws1 org-todo-sets)
> + 	 (setq org-done-keywords
> + 	    (append org-done-keywords dws nil))
> + 	 (setq org-todo-key-alist
> + 	    (append org-todo-key-alist kwsa))
> + 	 (mapc
> + 	    (lambda
> + 	       (x)
> + 	       (push
> + 		  (cons x tail)
> + 		  org-todo-kwd-alist))
> + 	    kws1)
> + 	 (if block
> + 	    (setq org-blockage-keywords-1
> + 	       (append org-blockage-keywords-1 kws1 nil)))
> + 	 (setq org-todo-keywords-1
> + 	    (append org-todo-keywords-1 kws1 nil)))))
> +
>  (defun org-set-regexps-and-options ()
>    "Precompute regular expressions for current buffer."
>    (when (org-mode-p)
> ***************
> *** 3116,3156 ****
>  	    (setq kwds (list (cons org-todo-interpretation
>  				   (default-value 'org-todo-keywords)))))
>  	(setq kwds (reverse kwds)))
> !       (setq kwds (nreverse kwds))
> !       (let (inter kws kw)
> ! 	(while (setq kws (pop kwds))
> ! 	  (setq inter (pop kws) sep (member "|" kws)
> ! 		kws0 (delete "|" (copy-sequence kws))
> ! 		kwsa nil
> ! 		kws1 (mapcar
> ! 		      (lambda (x)
> ! 			;;                     1              2
> ! 			(if (string-match "^\\(.*?\\)\\(?:(\\([^!@/]\\)?.*?)\\)?$" x)
> ! 			    (progn
> ! 			      (setq kw (match-string 1 x)
> ! 				    key (and (match-end 2) (match-string 2 x))
> ! 				    log (org-extract-log-state-settings x))
> ! 			      (push (cons kw (and key (string-to-char key))) kwsa)
> ! 			      (and log (push log org-todo-log-states))
> ! 			      kw)
> ! 			  (error "Invalid TODO keyword %s" x)))
> ! 		      kws0)
> ! 		kwsa (if kwsa (append '((:startgroup))
> ! 				      (nreverse kwsa)
> ! 				      '((:endgroup))))
> ! 		hw (car kws1)
> ! 		dws (if sep (org-remove-keyword-keys (cdr sep)) (last kws1))
> ! 		tail (list inter hw (car dws) (org-last dws)))
> ! 	  (add-to-list 'org-todo-heads hw 'append)
> ! 	  (push kws1 org-todo-sets)
> ! 	  (setq org-done-keywords (append org-done-keywords dws nil))
> ! 	  (setq org-todo-key-alist (append org-todo-key-alist kwsa))
> ! 	  (mapc (lambda (x) (push (cons x tail) org-todo-kwd-alist)) kws1)
> ! 	  (setq org-todo-keywords-1 (append org-todo-keywords-1 kws1 nil)))
> ! 	(setq org-todo-sets (nreverse org-todo-sets)
> ! 	      org-todo-kwd-alist (nreverse org-todo-kwd-alist)
> ! 	      org-todo-key-trigger (delq nil (mapcar 'cdr org-todo-key- 
> alist))
> ! 	      org-todo-key-alist (org-assign-fast-keys org-todo-key- 
> alist)))
>        ;; Process the constants
>        (when const
>  	(let (e cst)
> --- 3193,3209 ----
>  	    (setq kwds (list (cons org-todo-interpretation
>  				   (default-value 'org-todo-keywords)))))
>  	(setq kwds (reverse kwds)))
> !       ;;(setq kwds (append (nreverse kwds) (list
> org-todo-blockage-keywords)))
> !       (org-set-todo-constants (nreverse kwds) nil)
> !        (when org-todo-use-blockage-keywords-p
> ! 	  (org-set-todo-constants (list org-todo-blockage-keywords) t))
> !       (setq
> ! 	 org-todo-sets (nreverse org-todo-sets)
> ! 	 org-todo-kwd-alist (nreverse org-todo-kwd-alist)
> ! 	 org-todo-key-trigger (delq nil
> ! 				 (mapcar 'cdr org-todo-key-alist))
> ! 	 org-todo-key-alist (org-assign-fast-keys org-todo-key-alist))
> !
>        ;; Process the constants
>        (when const
>  	(let (e cst)
> ***************
> *** 8222,8232 ****
>  		    (save-match-data
>  		      (run-hook-with-args-until-failure
>  		       'org-blocker-hook change-plist)))
> ! 	    (if (interactive-p)
> ! 		(error "TODO state change from %s to %s blocked" this state)
> ! 	      ;; fail silently
> ! 	      (message "TODO state change from %s to %s blocked" this  
> state)
> ! 	      (throw 'exit nil))))
>  	(store-match-data match-data)
>  	(replace-match next t t)
>  	(unless (pos-visible-in-window-p hl-pos)
> --- 8275,8294 ----
>  		    (save-match-data
>  		      (run-hook-with-args-until-failure
>  		       'org-blocker-hook change-plist)))
> ! 	     (if
> ! 		org-todo-use-blockage-keywords-p
> ! 		(let
> ! 		   ((blocked-state (car org-blockage-keywords-1)))
> ! 		   (setq arg 'none)
> ! 		   (setq next (concat " " blocked-state " "))
> ! 		   (unless
> ! 		      (string= state blocked-state)
> ! 		      (message "TODO state change from %s to %s blocked" this  
> state)))
> ! 		(if (interactive-p)
> ! 		   (error "TODO state change from %s to %s blocked" this state)
> ! 		   ;; fail silently
> ! 		   (message "TODO state change from %s to %s blocked" this state)
> ! 		   (throw 'exit nil)))))
>  	(store-match-data match-data)
>  	(replace-match next t t)
>  	(unless (pos-visible-in-window-p hl-pos)
>
>
>
>
> _______________________________________________
> Emacs-orgmode mailing list
> Remember: use `Reply All' to send replies to the list.
> Emacs-orgmode@gnu.org
> http://lists.gnu.org/mailman/listinfo/emacs-orgmode

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Feature request and patch - blocked TODO to say BLOCKED
  2009-01-09  8:16   ` Carsten Dominik
@ 2009-01-15  2:34     ` Tom Breton (Tehom)
  2009-01-17  8:01       ` Carsten Dominik
  2009-01-19  3:33     ` Advice sought on managing decision alternatives Tom Breton (Tehom)
  1 sibling, 1 reply; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-01-15  2:34 UTC (permalink / raw)
  To: Carsten Dominik; +Cc: emacs-orgmode

> Hi Tom,
>
> I am hesitant to apply this relatively complex patch which
> I have not had the time to study closely enough.
> I am wondering:  Instead of setting a TODO keyword,
> would it not be simpler and equally effective to set a
> special tag when an entry is blocked?

That is a much better solution.  I have coded that and tested it against
an example file, and it works.

I've attached a patch.  One note: I used diff flag -b to ignore whitespace
because most of the change is that the big `catch' statement isn't
directly returned but assigned to proceed-p.  So most of it got indented
further but no change other than whitespace.  I can diff it without -b if
you prefer.

> You could use a bright font to mark this tag, in order to
> make it obvious.  And you could use a custom query to look
> for blocked items, to see what can be done about them....

Tom Breton (Tehom)

[example-file.org]

* Header
** TODO Blocking item
** Item that gets blocked
    :PROPERTIES:
   :BLOCKER:  previous-sibling
   :END:
[end]

[begin patch]
*** old-org-depend.el	2009-01-04 03:01:50.000000000 -0500
--- ord-depend.el	2009-01-14 21:15:47.000000000 -0500
***************
*** 112,117 ****
--- 112,121 ----
  ;;

  (require 'org)
+ (defcustom org-tag-blocked-depends t
+   "Whether to indicate blocked TODO items by a special tag."
+   :group 'org
+   :type 'bool)

  (defun org-depend-trigger-todo (change-plist)
    "Trigger new TODO entries after the current is switched to DONE.
***************
*** 191,197 ****
  	 (from (plist-get change-plist :from))
  	 (to (plist-get change-plist :to))
  	 (org-log-done nil) ; IMPROTANT!: no logging during automatic trigger
! 	 blocker blockers bl p1)
      (catch 'return
        (unless (eq type 'todo-state-change)
  	;; We are not handling this kind of change
--- 195,202 ----
  	 (from (plist-get change-plist :from))
  	 (to (plist-get change-plist :to))
  	 (org-log-done nil) ; IMPROTANT!: no logging during automatic trigger
! 	 blocker blockers bl p1
! 	   (proceed-p
  	      (catch 'return
  		 (unless (eq type 'todo-state-change)
  		    ;; We are not handling this kind of change
***************
*** 234,239 ****
--- 239,251 ----
  				(throw 'return nil))))))
  		 t     ; return t to indicate that we are not blocking
  		 )))
+      (when org-tag-blocked-depends
+ 	(org-toggle-tag "blocked"
+ 	   (if proceed-p 'off 'on)))
+
+      proceed-p))
+
+

  (add-hook 'org-trigger-hook 'org-depend-trigger-todo)
  (add-hook 'org-blocker-hook 'org-depend-block-todo)

[end patch]

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Feature request and patch - blocked TODO to say BLOCKED
  2009-01-15  2:34     ` Tom Breton (Tehom)
@ 2009-01-17  8:01       ` Carsten Dominik
  0 siblings, 0 replies; 56+ messages in thread
From: Carsten Dominik @ 2009-01-17  8:01 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode

Hi Tom,

thanks for the patch, I have applied it, with one change:
The variable is now called `org-depend-tag-blocked'.

Thanks!

- Carsten


On Jan 15, 2009, at 3:34 AM, Tom Breton (Tehom) wrote:

>> Hi Tom,
>>
>> I am hesitant to apply this relatively complex patch which
>> I have not had the time to study closely enough.
>> I am wondering:  Instead of setting a TODO keyword,
>> would it not be simpler and equally effective to set a
>> special tag when an entry is blocked?
>
> That is a much better solution.  I have coded that and tested it  
> against
> an example file, and it works.
>
> I've attached a patch.  One note: I used diff flag -b to ignore  
> whitespace
> because most of the change is that the big `catch' statement isn't
> directly returned but assigned to proceed-p.  So most of it got  
> indented
> further but no change other than whitespace.  I can diff it without - 
> b if
> you prefer.
>
>> You could use a bright font to mark this tag, in order to
>> make it obvious.  And you could use a custom query to look
>> for blocked items, to see what can be done about them....
>
> Tom Breton (Tehom)
>
> [example-file.org]
>
> * Header
> ** TODO Blocking item
> ** Item that gets blocked
>    :PROPERTIES:
>   :BLOCKER:  previous-sibling
>   :END:
> [end]
>
> [begin patch]
> *** old-org-depend.el	2009-01-04 03:01:50.000000000 -0500
> --- ord-depend.el	2009-01-14 21:15:47.000000000 -0500
> ***************
> *** 112,117 ****
> --- 112,121 ----
>  ;;
>
>  (require 'org)
> + (defcustom org-tag-blocked-depends t
> +   "Whether to indicate blocked TODO items by a special tag."
> +   :group 'org
> +   :type 'bool)
>
>  (defun org-depend-trigger-todo (change-plist)
>    "Trigger new TODO entries after the current is switched to DONE.
> ***************
> *** 191,197 ****
>  	 (from (plist-get change-plist :from))
>  	 (to (plist-get change-plist :to))
>  	 (org-log-done nil) ; IMPROTANT!: no logging during automatic  
> trigger
> ! 	 blocker blockers bl p1)
>      (catch 'return
>        (unless (eq type 'todo-state-change)
>  	;; We are not handling this kind of change
> --- 195,202 ----
>  	 (from (plist-get change-plist :from))
>  	 (to (plist-get change-plist :to))
>  	 (org-log-done nil) ; IMPROTANT!: no logging during automatic  
> trigger
> ! 	 blocker blockers bl p1
> ! 	   (proceed-p
>  	      (catch 'return
>  		 (unless (eq type 'todo-state-change)
>  		    ;; We are not handling this kind of change
> ***************
> *** 234,239 ****
> --- 239,251 ----
>  				(throw 'return nil))))))
>  		 t     ; return t to indicate that we are not blocking
>  		 )))
> +      (when org-tag-blocked-depends
> + 	(org-toggle-tag "blocked"
> + 	   (if proceed-p 'off 'on)))
> +
> +      proceed-p))
> +
> +
>
>  (add-hook 'org-trigger-hook 'org-depend-trigger-todo)
>  (add-hook 'org-blocker-hook 'org-depend-block-todo)
>
> [end patch]
>
>

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Advice sought on managing decision alternatives.
  2009-01-09  8:16   ` Carsten Dominik
  2009-01-15  2:34     ` Tom Breton (Tehom)
@ 2009-01-19  3:33     ` Tom Breton (Tehom)
  2009-01-22 11:15       ` Carsten Dominik
  1 sibling, 1 reply; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-01-19  3:33 UTC (permalink / raw)
  To: Carsten Dominik; +Cc: emacs-orgmode

On my last two requests, Carsten had better ideas and my proposal
really benefitted from them.  So I'm asking for advice on the design.

****** Rationale

When I make a decision, in org-mode, I write down the set of
reasonable alternatives that I see, each one as an item.  Then I make
notes about each one and then choose.

Often the process is messy.  I sometimes:

 * add a new alternative later
 * realize an alternative is fatally flawed and permanently reject it.
 * choose one but come to regret it.  Then I need to unchoose it and
   then choose another.
 * Realize that what I thought was an alternative is really a distinct
   yes/no choice.
 * Add a related yes/no choice to the group - I could make a new
   subtree for each new related choice, but usually once I find one
   related choice, I soon find many, so that's a lot of restructuring
   for little benefit.

****** The overall idea:

So I want a way of keeping track of alternatives and their state of
decision.  Where possible, I'd like this to automatically stay in a
sensible state.  Eg, if one alternative is chosen, no other is.

****** A detailed example

******* Item markings

For example, each item could be marked from this set of markings:

 * CHOSEN
   * Invariant :: The other items are marked NOT CHOSEN or lower
   * Reaction :: If another item becomes CHOSEN, this item becomes NOT
                 CHOSEN
   * Reaction :: If another item becomes LEANING TOWARDS, this item
                 becomes MAYBE.

 * LEANING TOWARDS
   * Invariant :: The other items are marked MAYBE or lower.
   * Reaction :: If another item becomes LEANING TOWARDS, this item
                 becomes MAYBE.
 * MAYBE
   * The default marking.  New items in the group get this marking
     unless some item is marked CHOSEN, in which case new items get
     NOT CHOSEN.
   * Reaction :: If another item becomes CHOSEN, MAYBE becomes NOT
                 CHOSEN.
 * NOT CHOSEN
   * Reaction :: If it becomes the case that no item is CHOSEN, NOT
                 CHOSEN items become MAYBE.
   * If marks are to be changed by moving up and down this "scale", an
     item could become "NOT CHOSEN" in the course of becoming
     "REJECTED".  This requirement keeps me from adding an invariant
     that if any item is NOT CHOSEN, exactly one item should be
     CHOSEN.

 * REJECTED
   * Remains marked REJECTED regardless what happens to other items.


Notice the symmetry in the constraints:

| If any   |   | then the other |   |
| item is: |   | items can't be |   |
|          |   | higher than:   |   |
|----------+---+----------------+---|
| CHOSEN   | 1 | NOT CHOSEN     | 4 |
| FAVORED  | 2 | MAYBE          | 3 |
|----------+---+----------------+---|

So there are 2 ranges of marks relating to each other in mirror image
fashion.  If some item is marked in the "CHOSEN" range, other items
can't be marked higher than the mirror-corresponding entry in the "NOT
CHOSEN" range.  I believe that will keep the items collectively in a
sensible state.

******* Item grouping

A group of items represent alternatives in a decision just if:

 * they are siblings
 * they all have a mark from that set.

There's plenty of room to expand to other means of grouping items.

****** The plan

My tentative plan is this:

 * Use the TODO position to carry chosenness information
   * Is that a bad idea?  Is there ever a case when an item should be
     both an alternative in a choice and a normal TODO item?
 * Re-use the usual TODO manipulation commands to manipulate these
   marks.
 * Add a new class of TODO-like mark interpretation
   * This interpretation is "chosenness" instead of "type" or
     "sequence".
   * The spec for it can indicate
     * The mark that is given to new items by default
     * The upper range (as above)
     * The lower range (as above)
   * Indications
     * "0" indicates the default mark
     * "-" indicates the lowest automatically managed mark.
       * If a low auto mark is not present, no automatic handling is
         wanted.
     * "+" indicates the counterpart of the low auto mark, to help
       indicate the upper range.
       * Defaults to the last item.
   * How these marks indicate ranges
     * the lower range is from the low auto mark to the default mark,
       inclusive
     * the upper range is from the mark above the default mark to the
       high auto mark, inclusive.
     * EXCEPT that the ranges must be the same length, so truncate the
       longer one.  Truncate it at the default end of it.
     * If there's no low auto mark, there are no ranges and no automatic
       handling.
   * Examples:
     * (chosenness "REJECTED" "-" "NOT_CHOSEN" "0" "MAYBE"
       "LEANING_TOWARDS" "+" "CHOSEN")
     * (chosenness "NO" "0" "MAYBE" "YES")
 * Set up the regular expressions etc to accept these marks in TODO
   position.  Same thing org-set-regexps-and-options does now, except:
   * Accept chosenness too.
   * Don't place chosenness marks in org-done-keywords and
     org-not-done-keywords
   * Place chosenness ranges in appropriate buffer-local variables.
 * In order to keep the marks consistent (as described above), use
   org-trigger-hook. When some item becomes marked with a mark in the
   upper range, demote the other items to the mark that occupies the
   mirror position in the lower range.
   * Eg, using the first example of marks, when an item is made
     CHOSEN, demote its siblings to NOT_CHOSEN.
   * Eg, using the first example of marks, when an item is made
     LEANING_TOWARDS, demote its siblings to MAYBE.
 * In order to find the correct default for such an item, add another
   hook.
   * It is called just if a default mark is wanted
   * It (each function on it) returns `nil' or a string.
   * For chosenness, it acts when
     * the old mark is `nil' or is from another TODO keyword set
     * A chosenness keyword set is to be used.


****** Impact on code

 * Most of this would go in a contrib module to hold the changes.
   * Name it "org-decisions.el"
   * This would define and manage the range variables described above.
   * When it loaded, it would add appropriately to the new variables
     below.
 * In org.el
   * Affecting customizations:
     * The org-todo-keywords customize would add an interpretation
       "chosenness" as alternative to "type" and "sequence".
   * Affecting org-todo
     * I'd add a hook.
       * Name it org-todo-get-default-hook
     * That hook would be called to find a default item.
   * Affecting org-set-regexps-and-options:
     * I'd add an alist that associates type to a handler that sets up
       the various todo variables.
       * Name it org-set-todo-handlers-alist.
     * org-set-regexps-and-options would use that list to find a
       handler where now it processes "type" and "sequence".
     * The "type" and "sequence" handlers would be the same code that
       is used now in `org-set-regexps-and-options', excerpted.
     * Alternatively, I could leave "type" and "sequence" handling
       where it is as special cases.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Advice sought on managing decision alternatives.
  2009-01-19  3:33     ` Advice sought on managing decision alternatives Tom Breton (Tehom)
@ 2009-01-22 11:15       ` Carsten Dominik
  2009-01-31  4:21         ` Tom Breton (Tehom)
  0 siblings, 1 reply; 56+ messages in thread
From: Carsten Dominik @ 2009-01-22 11:15 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode

Hi Tom,

I went through your draft and I think this is interesting functionality
which would be really nice to have.

I also see that you have thought carefully on how to implement it
and minimize impact on the core code, which I appreciate.

I would be happy to to make/accept the following changes
to org.el:

In addition to SEQ_TODO and TYP_TODO, I could look for similar
words.  We could even do this in a general way, looking for

#+XYZFOOBAR_TODO:

and making this call a special function org-todo-setup-xyzfoobar, which
could then be defined in add-on packages.

As you want to re-use the internal functions Org uses
to change states, I would like to change this code as
little as possible, even going beyond what you already proposed:
My proposal would be:

Your add-on defines a setup function which is actually a *filter*  
function.
It gets passed the list of words resulting from parsing the
"#+CHOOSE_TODO:" line, or equivalently such a list found in
org-todo-keywords.

For example:

#+CHOOSE_TODO: REJECTED - NOT_CHOSEN 0 MAYBE LEANING_TOWARDS + CHOSEN

or

#+CHOOSE_TODO: REJECTED(r){-} NOT_CHOSEN(n){0} MAYBE(m)  
LEANING_TOWARDS(l){+} CHOSEN(c)

The format would be entirely up to you, as long as you do the following:

The filter function must return a list as it is *normally*
expected for TODO keywords, with flags for fast selection
and note taking, maybe a "|" entry to separate "DONE" entries
from the rest, but any other special stuff of your interface
removed, for example:

  (choseness "REJECTED(r)" "NOT_CHOSEN(n)" "MAYBE(m)"  
"LEANING_TOWARDS(l)" "|" CHOSEN(c))

Org will then process this return list appropriately, set up
keys for fast selection, arranges for notes and time stamps
to be recorded etc.

The interaction type does very little indeed inside Org, it
only decides if a cycling command should go to the next
step (sequence) or jump to the first DONE state (type).
I think we should treat any other interaction types like
"sequence" in this respect.

This would be all as far as Org is concerned.  No need to
change any code at all.

I will then add hooks wherever you need them, they will
be called whenever a TODO keyword changes and your code
can react to it.

One important precaution would be to make sure that one does
not end up in infinite loops, so maybe when the hook is called,
bind it dynamically to a nil value while you mess around with
with the status of the siblings.  Maybe do the same thing with
the variables that trigger time stamp and note recording.

What do you think?

- Carsten

P.S. What is you copyright status with the FSF?


On Jan 19, 2009, at 4:33 AM, Tom Breton (Tehom) wrote:

> On my last two requests, Carsten had better ideas and my proposal
> really benefitted from them.  So I'm asking for advice on the design.
>
> ****** Rationale
>
> When I make a decision, in org-mode, I write down the set of
> reasonable alternatives that I see, each one as an item.  Then I make
> notes about each one and then choose.
>
> Often the process is messy.  I sometimes:
>
> * add a new alternative later
> * realize an alternative is fatally flawed and permanently reject it.
> * choose one but come to regret it.  Then I need to unchoose it and
>   then choose another.
> * Realize that what I thought was an alternative is really a distinct
>   yes/no choice.
> * Add a related yes/no choice to the group - I could make a new
>   subtree for each new related choice, but usually once I find one
>   related choice, I soon find many, so that's a lot of restructuring
>   for little benefit.
>
> ****** The overall idea:
>
> So I want a way of keeping track of alternatives and their state of
> decision.  Where possible, I'd like this to automatically stay in a
> sensible state.  Eg, if one alternative is chosen, no other is.
>
> ****** A detailed example
>
> ******* Item markings
>
> For example, each item could be marked from this set of markings:
>
> * CHOSEN
>   * Invariant :: The other items are marked NOT CHOSEN or lower
>   * Reaction :: If another item becomes CHOSEN, this item becomes NOT
>                 CHOSEN
>   * Reaction :: If another item becomes LEANING TOWARDS, this item
>                 becomes MAYBE.
>
> * LEANING TOWARDS
>   * Invariant :: The other items are marked MAYBE or lower.
>   * Reaction :: If another item becomes LEANING TOWARDS, this item
>                 becomes MAYBE.
> * MAYBE
>   * The default marking.  New items in the group get this marking
>     unless some item is marked CHOSEN, in which case new items get
>     NOT CHOSEN.
>   * Reaction :: If another item becomes CHOSEN, MAYBE becomes NOT
>                 CHOSEN.
> * NOT CHOSEN
>   * Reaction :: If it becomes the case that no item is CHOSEN, NOT
>                 CHOSEN items become MAYBE.
>   * If marks are to be changed by moving up and down this "scale", an
>     item could become "NOT CHOSEN" in the course of becoming
>     "REJECTED".  This requirement keeps me from adding an invariant
>     that if any item is NOT CHOSEN, exactly one item should be
>     CHOSEN.
>
> * REJECTED
>   * Remains marked REJECTED regardless what happens to other items.
>
>
> Notice the symmetry in the constraints:
>
> | If any   |   | then the other |   |
> | item is: |   | items can't be |   |
> |          |   | higher than:   |   |
> |----------+---+----------------+---|
> | CHOSEN   | 1 | NOT CHOSEN     | 4 |
> | FAVORED  | 2 | MAYBE          | 3 |
> |----------+---+----------------+---|
>
> So there are 2 ranges of marks relating to each other in mirror image
> fashion.  If some item is marked in the "CHOSEN" range, other items
> can't be marked higher than the mirror-corresponding entry in the "NOT
> CHOSEN" range.  I believe that will keep the items collectively in a
> sensible state.
>
> ******* Item grouping
>
> A group of items represent alternatives in a decision just if:
>
> * they are siblings
> * they all have a mark from that set.
>
> There's plenty of room to expand to other means of grouping items.
>
> ****** The plan
>
> My tentative plan is this:
>
> * Use the TODO position to carry chosenness information
>   * Is that a bad idea?  Is there ever a case when an item should be
>     both an alternative in a choice and a normal TODO item?
> * Re-use the usual TODO manipulation commands to manipulate these
>   marks.
> * Add a new class of TODO-like mark interpretation
>   * This interpretation is "chosenness" instead of "type" or
>     "sequence".
>   * The spec for it can indicate
>     * The mark that is given to new items by default
>     * The upper range (as above)
>     * The lower range (as above)
>   * Indications
>     * "0" indicates the default mark
>     * "-" indicates the lowest automatically managed mark.
>       * If a low auto mark is not present, no automatic handling is
>         wanted.
>     * "+" indicates the counterpart of the low auto mark, to help
>       indicate the upper range.
>       * Defaults to the last item.
>   * How these marks indicate ranges
>     * the lower range is from the low auto mark to the default mark,
>       inclusive
>     * the upper range is from the mark above the default mark to the
>       high auto mark, inclusive.
>     * EXCEPT that the ranges must be the same length, so truncate the
>       longer one.  Truncate it at the default end of it.
>     * If there's no low auto mark, there are no ranges and no  
> automatic
>       handling.
>   * Examples:
>     * (chosenness "REJECTED" "-" "NOT_CHOSEN" "0" "MAYBE"
>       "LEANING_TOWARDS" "+" "CHOSEN")
>     * (chosenness "NO" "0" "MAYBE" "YES")
> * Set up the regular expressions etc to accept these marks in TODO
>   position.  Same thing org-set-regexps-and-options does now, except:
>   * Accept chosenness too.
>   * Don't place chosenness marks in org-done-keywords and
>     org-not-done-keywords
>   * Place chosenness ranges in appropriate buffer-local variables.
> * In order to keep the marks consistent (as described above), use
>   org-trigger-hook. When some item becomes marked with a mark in the
>   upper range, demote the other items to the mark that occupies the
>   mirror position in the lower range.
>   * Eg, using the first example of marks, when an item is made
>     CHOSEN, demote its siblings to NOT_CHOSEN.
>   * Eg, using the first example of marks, when an item is made
>     LEANING_TOWARDS, demote its siblings to MAYBE.
> * In order to find the correct default for such an item, add another
>   hook.
>   * It is called just if a default mark is wanted
>   * It (each function on it) returns `nil' or a string.
>   * For chosenness, it acts when
>     * the old mark is `nil' or is from another TODO keyword set
>     * A chosenness keyword set is to be used.
>
>
> ****** Impact on code
>
> * Most of this would go in a contrib module to hold the changes.
>   * Name it "org-decisions.el"
>   * This would define and manage the range variables described above.
>   * When it loaded, it would add appropriately to the new variables
>     below.
> * In org.el
>   * Affecting customizations:
>     * The org-todo-keywords customize would add an interpretation
>       "chosenness" as alternative to "type" and "sequence".
>   * Affecting org-todo
>     * I'd add a hook.
>       * Name it org-todo-get-default-hook
>     * That hook would be called to find a default item.
>   * Affecting org-set-regexps-and-options:
>     * I'd add an alist that associates type to a handler that sets up
>       the various todo variables.
>       * Name it org-set-todo-handlers-alist.
>     * org-set-regexps-and-options would use that list to find a
>       handler where now it processes "type" and "sequence".
>     * The "type" and "sequence" handlers would be the same code that
>       is used now in `org-set-regexps-and-options', excerpted.
>     * Alternatively, I could leave "type" and "sequence" handling
>       where it is as special cases.
>
>
>

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Advice sought on managing decision alternatives.
       [not found] <20090122112819.B30E12940C@mail1.panix.com>
@ 2009-01-22 22:11 ` Tom Breton (Tehom)
  0 siblings, 0 replies; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-01-22 22:11 UTC (permalink / raw)
  To: emacs-orgmode

> P.S. What is you copyright status with the FSF?

I believe I'm already good to go.  A few years back when I contributed
some code to emacs' lread.c, RMS had me sign and send the letter that
legally enabled FSF to include it.  IIUC, that step only has to be
done once for any code contributor.


> Your add-on defines a setup function which is actually a *filter*
> function.

OK, sounds good.  And makes it a bit easier to test.

> The interaction type does very little indeed inside Org, it
> only decides if a cycling command should go to the next
> step (sequence) or jump to the first DONE state (type).
> I think we should treat any other interaction types like
> "sequence" in this respect.

Here it would also distinguish chosenness from the other
interpretations, but that would be entirely inside org-decisions.el.

> I will then add hooks wherever you need them, they will
> be called whenever a TODO keyword changes and your code
> can react to it.

OK.

> One important precaution would be to make sure that one does
> not end up in infinite loops, so maybe when the hook is called,
> bind it dynamically to a nil value while you mess around with
> with the status of the siblings.  Maybe do the same thing with
> the variables that trigger time stamp and note recording.

Right.  I had already planned to let the hooks to nil; I will do the
same for the time stamp and note recording variables.

Thanks for the advice.  I will code it up and send it.

Tom Breton (Tehom)

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Advice sought on managing decision alternatives.
  2009-01-22 11:15       ` Carsten Dominik
@ 2009-01-31  4:21         ` Tom Breton (Tehom)
  2009-01-31  5:41           ` Carsten Dominik
  2009-02-06 13:08           ` Carsten Dominik
  0 siblings, 2 replies; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-01-31  4:21 UTC (permalink / raw)
  Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 947 bytes --]

Here is org-decisions.  "All 68 tests ran successfully".  I hope it is
satisfactory.  If it's not, please let me know.

Please find attached:
 * org-decisions.el
 * diffs to org.el
 * test-org-decisions.el.
 * 6 example files in testing

A few notes:

****** Test files

I included 6 example files that I used in testing, and my test file
test-org-decisions.el.

test-org-decisions.el uses my tester rtest, which is unfortunately in
flux at the moment.  Still, I felt it would be best to make it
publicly available.

****** Use of cl

I used cl in org-decisions.el.  I hope that's not a problem, but if it
is I can rewrite the parts that use cl.

 * pushnew
 * position
 * destructuring-bind
 * defstruct

****** Use of allout

org-decisions.el and test-org-decisions.el use allout for structuring.
I removed the "mode: allout" line so that they can be read without
allout present.

        Tom Breton (Tehom)

[-- Attachment #2: org-decisions.el --]
[-- Type: application/octet-stream, Size: 12642 bytes --]

;;;_ org-decisions.el --- decision management for org-mode

;;;_. Headers
;;;_ , License
;; Copyright (C) 2009  Tom Breton (Tehom)

;; Author: Tom Breton (Tehom)
;; Keywords: 

;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;;;_ , Commentary:

;; 


;;;_ , Requires

(require 'org)
(eval-when-compile
   (require 'cl))

;;;_. Body
;;;_ , The variables

(defstruct (org-decisions-mark-data. (:type list))
   "The format of an entry in org-decisions-mark-data.
Indexes are 0-based or `nil'.
"
   keyword
   bot-lower-range
   top-upper-range
   range-length
   static-default
   all-keywords)

(defvar org-decisions-mark-data 
   ()
   "Alist of information for chosenness marks.

Each entry is an `org-decisions-mark-data.'" )
(make-variable-buffer-local 'org-decisions-mark-data)
;;;_ , For setup
;;;_  . org-decisions-filter-one

(defun org-decisions-filter-one (i)
   "Return a list of
 * a canonized version of the string
 * optionally one symbol"

   (if
      (not
	 (string-match "(.*)" i))
      (list i i)
      (let* 
	 (
	    (end-text (match-beginning 0))
	    (vanilla-text (substring i 0 end-text))
	    ;;Get the parenthesized part.
	    (match (match-string 0 i))
	    ;;Remove the parentheses.
	    (args (substring match 1 -1))
	    ;;Split it
	    (arglist
	       (let
		  ((arglist-x (split-string args ",")))
		  ;;When string starts with "," `split-string' doesn't
		  ;;make a first arg, so in that case make one
		  ;;manually.
		  (if 
		     (string-match "^," args)
		     (cons nil arglist-x)
		     arglist-x)))
	    (decision-arg (second arglist))
	    (type
	       (cond
		  ((string= decision-arg "0")
		     'default-mark)
		  ((string= decision-arg "+")
		     'top-upper-range)
		  ((string= decision-arg "-")
		     'bot-lower-range)
		  (t nil)))
	    (vanilla-arg (first arglist))
	    (vanilla-mark
	       (if vanilla-arg
		  (concat vanilla-text "("vanilla-arg")")
		  vanilla-text)))
	 (if type
	    (list vanilla-text vanilla-mark type)
	    (list vanilla-text vanilla-mark)))))

;;;_  . org-decisions-setup-vars
(defun org-decisions-setup-vars (bot-lower-range top-upper-range
				   static-default num-items all-mark-texts)
   "Add to org-decisions-mark-data according to arguments"

   (let*
      (
	 (tail
	    ;;If there's no bot-lower-range or no default, we don't
	    ;;have ranges.
	    (cdr
	       (if (and static-default bot-lower-range)
		  (let*
		     (
			;;If there's no top-upper-range, use the last
			;;item.
			(top-upper-range
			   (or top-upper-range (1- num-items)))
			(lower-range-length 
			   (1+ (- static-default bot-lower-range)))
			(upper-range-length 
			   (- top-upper-range static-default))
			(range-length 
			   (min upper-range-length lower-range-length)))


		     (make-org-decisions-mark-data.
			:keyword nil
			:bot-lower-range bot-lower-range
			:top-upper-range top-upper-range
			:range-length    range-length
			:static-default static-default
			:all-keywords all-mark-texts))

		  (make-org-decisions-mark-data.
		     :keyword nil
		     :bot-lower-range nil
		     :top-upper-range nil
		     :range-length    nil
		     :static-default (or static-default 0)
		     :all-keywords all-mark-texts)))))

      (dolist (text all-mark-texts)
	 (pushnew (cons text tail)
	    org-decisions-mark-data
	    :test
	    #'(lambda (a b)
		 (equal (car a) (car b)))))))




;;;_  . org-decisions-filter-tail
(defun org-decisions-filter-tail (raw)
   "Return a translation of RAW to vanilla and set appropriate
buffer-local variables. 

RAW is a list of strings representing the input text of a chosenness
interpretation."
   (let
      ((vanilla-list nil)
	 (all-mark-texts nil)
	 (index 0)
	 bot-lower-range top-upper-range range-length static-default)
      (dolist (i raw)
	 (destructuring-bind
	    (vanilla-text vanilla-mark &optional type)
	    (org-decisions-filter-one i)
	    (cond
	       ((eq type 'bot-lower-range)
		  (setq bot-lower-range index))
	       ((eq type 'top-upper-range)
		  (setq top-upper-range index))
	       ((eq type 'default-mark)
		  (setq static-default index)))
	    (incf index)
	    (push vanilla-text all-mark-texts)
	    (push vanilla-mark vanilla-list)))

      (org-decisions-setup-vars bot-lower-range top-upper-range
	 static-default index (reverse all-mark-texts)) 
      (nreverse vanilla-list)))

;;;_  . org-decisions-setup-filter

(defun org-decisions-setup-filter (raw)
   "A setup filter for chosenness interpretations."
   (when (eq (car raw) 'chosenness)
      (cons
	 'chosenness
	 (org-decisions-filter-tail (cdr raw)))))

;;;_  . org-decisions-conform-after-promotion
(defun org-decisions-conform-after-promotion (entry-pos keywords highest-ok-ix)
   ""
   
   (unless
      ;;Skip the entry that triggered this by skipping any entry with
      ;;the same starting position.  Both map and plist use the start
      ;;of the header line as the position, so we can just compare
      ;;them with `='
      (= (point) entry-pos)
      (let
	 ((ix
	     (org-decisions-get-entry-index keywords)))
	 ;;If the index of the entry exceeds the highest allowable
	 ;;index, change it to that.
	 (when (and ix 
		  (> ix highest-ok-ix))
	    (org-todo 
	       (nth highest-ok-ix keywords))))))
;;;_  . org-decisions-conform-after-demotion
(defun org-decisions-conform-after-demotion (entry-pos keywords
					       raise-to-ix
					       old-highest-ok-ix) 
   ""
   (unless
      ;;Skip the entry that triggered this.
      (= (point) entry-pos)
      (let
	 ((ix
	     (org-decisions-get-entry-index keywords)))
	 ;;If the index of the entry was at or above the old allowable
	 ;;position, change it to the new mirror position if there is
	 ;;one.
	 (when (and 
		  ix 
		  raise-to-ix
		  (>= ix old-highest-ok-ix))
	    (org-todo 
	       (nth raise-to-ix keywords))))))

;;;_ , org-decisions-keep-sensible (the trigger-hook function)
(defun org-decisions-keep-sensible (change-plist)
   ""

   (let*
      (  (from (plist-get change-plist :from))
	 (to (plist-get change-plist :to))
	 (entry-pos 
	    (set-marker
	       (make-marker)
	       (plist-get change-plist :position)))
	 (kwd-data
	    (assoc to org-todo-kwd-alist)))
      (when
	 (eq (nth 1 kwd-data) 'chosenness)
	 (let*
	    (
	       (data
		  (assoc to org-decisions-mark-data))
	       (keywords
		  (org-decisions-mark-data.-all-keywords data))
	       (old-index
		  (org-decisions-get-index-in-keywords
		     from 
		     keywords))
	       (new-index
		  (org-decisions-get-index-in-keywords
		     to 
		     keywords))
	       (highest-ok-ix
		  (org-decisions-highest-other-ok
		     new-index
		     data))
	       (funcdata
		  (cond
		     ;;The entry doesn't participate in conformance,
		     ;;so give `nil' which does nothing.
		     ((not highest-ok-ix) nil)
		     ;;The entry was created or promoted
		     ((or
			 (not old-index)
			 (> new-index old-index))
			(list
			   #'org-decisions-conform-after-promotion
			   entry-pos keywords 
			   highest-ok-ix))
		     (t	;;Otherwise the entry was demoted.
			(let
			   (
			      (raise-to-ix
				 (min
				    highest-ok-ix
				    (org-decisions-mark-data.-static-default
				       data)))
			      (old-highest-ok-ix
				 (org-decisions-highest-other-ok
				    old-index
				    data)))
			   
			   (list
			      #'org-decisions-conform-after-demotion 
			      entry-pos 
			      keywords
			      raise-to-ix
			      old-highest-ok-ix))))))
	    
	    (if funcdata
	       ;;The funny-looking names are to make variable capture
	       ;;unlikely.  (Poor-man's lexical bindings).
	       (destructuring-bind (func-d473 . args-46k) funcdata
		  (let
		     ((map-over-entries
			 (org-decisions-get-fn-map-group))
			;;We may call `org-todo', so let various hooks
			;;`nil' so we don't cause loops.
			org-after-todo-state-change-hook
			org-trigger-hook 
			org-blocker-hook 
			org-todo-get-default-hook
			;;Also let this alist `nil' so we don't log
			;;secondary transitions.
			org-todo-log-states)
		     ;;Map over group
		     (funcall map-over-entries
			#'(lambda ()
			     (apply func-d473 args-46k))))))))
      
      ;;Remove the marker
      (set-marker entry-pos nil)))



;;;_ , Getting the default mark
;;;_  . org-decisions-get-index-in-keywords
(defun org-decisions-get-index-in-keywords (ix all-keywords)
   "Return index of current entry."
   (if ix
      (position ix all-keywords
	 :test #'equal)))

;;;_  . org-decisions-get-entry-index
(defun org-decisions-get-entry-index (all-keywords)
   "Return index of current entry."

   (let*
      ((state (org-entry-get (point) "TODO")))
      (org-decisions-get-index-in-keywords state all-keywords)))

;;;_  . org-decisions-get-fn-map-group

(defun org-decisions-get-fn-map-group ()
   "Return a function to map over the group"
   
   #'(lambda (fn)
	(save-excursion
	   (outline-up-heading-all 1)
	   (save-restriction
	      (org-map-entries fn nil 'tree)))))

;;;_  . org-decisions-get-highest-mark-index

(defun org-decisions-get-highest-mark-index (keywords)
   "Get the index of the highest current mark in the group.
If there is none, return 0"

   (let*
      (
	 ;;Func maps over applicable entries.
	 (map-over-entries
	    (org-decisions-get-fn-map-group))
	 
	 (indexes-list
	    (remove nil
	       (funcall map-over-entries 
		  #'(lambda ()
		       (org-decisions-get-entry-index keywords))))))
      (if
	 indexes-list
	 (apply #'max indexes-list)
	 0)))


;;;_  . org-decisions-highest-ok

(defun org-decisions-highest-other-ok (ix data)
   ""

   (let
      (		
	 (bot-lower-range
	    (org-decisions-mark-data.-bot-lower-range data))
	 (top-upper-range
	    (org-decisions-mark-data.-top-upper-range data))
	 (range-length
	    (org-decisions-mark-data.-range-length data)))
      (when (and ix bot-lower-range)
	 (let*
	    ((delta
		(- top-upper-range ix)))
	    (unless
	       (< range-length delta)
	       (+ bot-lower-range delta))))))

;;;_  . org-decisions-get-default-mark-index

(defun org-decisions-get-default-mark-index (data) 
   "Get the index of the default mark in a chosenness interpretation.

Args are in the same order as the fields of
`org-decisions-mark-data.' and have the same meaning."

   (or
      (let
	 ((highest-mark-index
	     (org-decisions-get-highest-mark-index
		(org-decisions-mark-data.-all-keywords data))))
	 (org-decisions-highest-other-ok
	    highest-mark-index data))
      (org-decisions-mark-data.-static-default data)))



;;;_  . org-decisions-get-mark-N
(defun org-decisions-get-mark-N (n data)
   "Get the text of the nth mark in a chosenness interpretation."
   
   (let*
      ((l (org-decisions-mark-data.-all-keywords data)))
      (nth n l)))

;;;_  . org-decisions-get-default-mark

(defun org-decisions-get-default-mark (new-mark old-mark)
   "Get the default mark IFF in a chosenness interpretation.
NEW-MARK and OLD-MARK are the text of the new and old marks."

   (let*
      (
	 (old-kwd-data
	    (assoc old-mark org-todo-kwd-alist))
	 (new-kwd-data
	    (assoc new-mark org-todo-kwd-alist))
	 (becomes-chosenness
	    (and
	       (or
		  (not old-kwd-data)
		  (not
		     (eq (nth 1 old-kwd-data) 'chosenness)))
	       (eq (nth 1 new-kwd-data) 'chosenness))))
      (when
	 becomes-chosenness
	 (let
	    ((new-mark-data
		(assoc new-mark org-decisions-mark-data)))
	    (if
	       new-mark
	       (org-decisions-get-mark-N
		  (org-decisions-get-default-mark-index
		     new-mark-data)
		  new-mark-data)
	       (error "Somehow got an unrecognizable mark"))))))

;;;_ , Setting it all up

(eval-after-load 'org
   (progn
      (add-to-list 'org-todo-setup-filter-hook
	 #'org-decisions-setup-filter) 
      (add-to-list 'org-todo-get-default-hook
	 #'org-decisions-get-default-mark) 
      (add-to-list 'org-trigger-hook
	 #'org-decisions-keep-sensible)))

;;;_. Footers
;;;_ , Provides

(provide 'org-decisions)

;;;_ * Local emacs vars.
;;;_  + Local variables:
;;;_  + End:

;;;_ , End
;;; org-decisions.el ends here

[-- Attachment #3: org.el.diff --]
[-- Type: application/octet-stream, Size: 5799 bytes --]

*** old-org.el	2009-01-04 03:01:50.000000000 -0500
--- org.el	2009-01-29 21:09:17.000000000 -0500
***************
*** 1459,1465 ****
  		   (choice
  		    :tag "Interpretation"
  		    (const :tag "Sequence (cycling hits every state)" sequence)
! 		    (const :tag "Type     (cycling directly to DONE)" type))
  		   (repeat
  		    (string :tag "Keyword"))))))
  
--- 1459,1467 ----
  		   (choice
  		    :tag "Interpretation"
  		    (const :tag "Sequence (cycling hits every state)" sequence)
! 		    (const :tag "Type     (cycling directly to DONE)" type)
! 		    (const :tag "Chosenness    (to record decisions)" 
! 		       chosenness))
  		   (repeat
  		    (string :tag "Keyword"))))))
  
***************
*** 3025,3031 ****
      (org-set-local 'org-file-properties nil)
      (org-set-local 'org-file-tags nil)
      (let ((re (org-make-options-regexp
! 	       '("CATEGORY" "SEQ_TODO" "TYP_TODO" "TODO" "COLUMNS"
  		 "STARTUP" "ARCHIVE" "FILETAGS" "TAGS" "LINK" "PRIORITIES"
  		 "CONSTANTS" "PROPERTY" "DRAWERS" "SETUPFILE")))
  	  (splitre "[ \t]+")
--- 3027,3033 ----
      (org-set-local 'org-file-properties nil)
      (org-set-local 'org-file-tags nil)
      (let ((re (org-make-options-regexp
! 	       '("CATEGORY" "SEQ_TODO" "TYP_TODO" "TODO" "CHOOSE_TODO" "COLUMNS"
  		 "STARTUP" "ARCHIVE" "FILETAGS" "TAGS" "LINK" "PRIORITIES"
  		 "CONSTANTS" "PROPERTY" "DRAWERS" "SETUPFILE")))
  	  (splitre "[ \t]+")
***************
*** 3052,3057 ****
--- 3054,3061 ----
  	      (push (cons 'sequence (org-split-string value splitre)) kwds))
  	     ((equal key "TYP_TODO")
  	      (push (cons 'type (org-split-string value splitre)) kwds))
+ 	     ((equal key "CHOOSE_TODO")
+ 	      (push (cons 'chosenness (org-split-string value splitre)) kwds))
  	     ((equal key "TAGS")
  	      (setq tags (append tags (org-split-string value splitre))))
  	     ((equal key "COLUMNS")
***************
*** 3133,3138 ****
--- 3137,3148 ----
        (setq kwds (nreverse kwds))
        (let (inter kws kw)
  	(while (setq kws (pop kwds))
+ 	  (let
+ 	     ((kws
+ 		 (or
+ 		    (run-hook-with-args-until-success
+ 		       'org-todo-setup-filter-hook kws) 
+ 		    kws)))
  	     (setq inter (pop kws) sep (member "|" kws)
  		kws0 (delete "|" (copy-sequence kws))
  		kwsa nil
***************
*** 3154,3160 ****
  				      '((:endgroup))))
  		hw (car kws1)
  		dws (if sep (org-remove-keyword-keys (cdr sep)) (last kws1))
! 		tail (list inter hw (car dws) (org-last dws)))
  	  (add-to-list 'org-todo-heads hw 'append)
  	  (push kws1 org-todo-sets)
  	  (setq org-done-keywords (append org-done-keywords dws nil))
--- 3164,3170 ----
  				 '((:endgroup))))
  		hw (car kws1)
  		dws (if sep (org-remove-keyword-keys (cdr sep)) (last kws1))
! 		tail (list inter hw (car dws) (org-last dws))))
  	  (add-to-list 'org-todo-heads hw 'append)
  	  (push kws1 org-todo-sets)
  	  (setq org-done-keywords (append org-done-keywords dws nil))
***************
*** 4934,4944 ****
        (org-back-to-heading)
        (outline-previous-heading)
        (looking-at org-todo-line-regexp))
      (if (or arg
  	    (not (match-beginning 2))
  	    (member (match-string 2) org-done-keywords))
! 	(insert (car org-todo-keywords-1) " ")
!       (insert (match-string 2) " "))
      (when org-provide-todo-statistics
        (org-update-parent-todo-statistics))))
  
--- 4944,4963 ----
        (org-back-to-heading)
        (outline-previous-heading)
        (looking-at org-todo-line-regexp))
+     (let*
+        ((new-mark-x
  	   (if (or arg
  		  (not (match-beginning 2))
  		  (member (match-string 2) org-done-keywords))
! 	      (car org-todo-keywords-1)
! 	      (match-string 2)))
! 	  (new-mark
! 	     (or
! 		(run-hook-with-args-until-success
! 		   'org-todo-get-default-hook new-mark-x nil)
! 		new-mark-x)))
!        (insert new-mark " "))
!      
      (when org-provide-todo-statistics
        (org-update-parent-todo-statistics))))
  
***************
*** 8190,8195 ****
--- 8209,8226 ----
  :from  previous state (keyword as a string), or nil
  :to    new state (keyword as a string), or nil")
  
+ (defvar org-todo-setup-filter-hook nil 
+    "Hook for functions that pre-filter todo specs.
+ 
+ Each function takes a todo spec and returns either `nil' or the spec
+ transformed into canonical form." )
+ 
+ (defvar org-todo-get-default-hook nil
+    "Hook for functions that get a default item for todo.
+ 
+ Each function takes arguments (NEW-MARK OLD-MARK) and returns either
+ `nil' or a string to be used for the todo mark." )
+ 
  (defvar org-agenda-headline-snapshot-before-repeat)
  (defun org-todo (&optional arg)
    "Change the TODO state of an item.
***************
*** 8285,8291 ****
  		     ((null member) (or head (car org-todo-keywords-1)))
  		     ((equal this final-done-word) nil) ;; -> make empty
  		     ((null tail) nil) ;; -> first entry
! 		     ((eq interpret 'sequence)
  		      (car tail))
  		     ((memq interpret '(type priority))
  		      (if (eq this-command last-command)
--- 8316,8322 ----
  		     ((null member) (or head (car org-todo-keywords-1)))
  		     ((equal this final-done-word) nil) ;; -> make empty
  		     ((null tail) nil) ;; -> first entry
! 		     ((memq interpret '(sequence chosenness))
  		      (car tail))
  		     ((memq interpret '(type priority))
  		      (if (eq this-command last-command)
***************
*** 8294,8299 ****
--- 8325,8334 ----
  			    (or done-word (car org-done-keywords))
  			  nil)))
  		     (t nil)))
+ 	     (state (or 
+ 		       (run-hook-with-args-until-success
+ 			  'org-todo-get-default-hook state last-state) 
+ 		       state))
  	     (next (if state (concat " " state " ") " "))
  	     (change-plist (list :type 'todo-state-change :from this :to state
  				 :position startpos))

[-- Attachment #4: test-org-decisions.el --]
[-- Type: application/octet-stream, Size: 47226 bytes --]

;;;_ test-org-decisions.el --- Test code for org-decisions

;;;_. Headers
;;;_ , License
;; Copyright (C) 2009  Tom Breton (Tehom)

;; Author: Tom Breton (Tehom) <tehom@localhost.localdomain>
;; Keywords: lisp

;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;;;_ , Commentary:

;; 


;;;_ , Requires

(require 'rtest-define)
(require 'mockbuf)
(require 'el-mock)
(require 'org)
(require 'org-id)
(require 'org-decisions)


;;;_. Body
;;;_ , Example files
(defconst test-org-decisions:th:examples-dir
   (rtest:expand-filename-by-load-file "examples") 
   "Directory where examples are" )

(rtest:defexample test-org-decisions:thd:file-simple
   (expand-file-name "simple.org" 
      test-org-decisions:th:examples-dir))
(rtest:defexample test-org-decisions:thd:file-w-1-chosen
   (expand-file-name "w-1-chosen.org" 
      test-org-decisions:th:examples-dir))
(rtest:defexample test-org-decisions:thd:file-nonautomatic
   (expand-file-name "nonautomatic.org" 
      test-org-decisions:th:examples-dir))
(rtest:defexample test-org-decisions:thd:file-w-2-types
   (expand-file-name "w-2-types.org" 
      test-org-decisions:th:examples-dir))
(rtest:defexample test-org-decisions:thd:file-w-some-nils
   (expand-file-name "w-some-nils.org" 
      test-org-decisions:th:examples-dir))
(rtest:defexample test-org-decisions:thd:file-nosibs
   (expand-file-name "no-sibs.org" 
      test-org-decisions:th:examples-dir))

(rtest:defexample test-org-decisions:thd:nofile-1-list-o-marks
   '("REJECTED" "NOT_CHOSEN" "MAYBE" "LEANING_TOWARDS" "CHOSEN"))

(rtest:defexample test-org-decisions:thd:nofile-1-raw-marks
   '(chosenness "REJECTED" "NOT_CHOSEN" "MAYBE" "LEANING_TOWARDS" "CHOSEN")
   "Raw marks")

(rtest:defexample test-org-decisions:thd:nofile-1-output-marks
   '(chosenness "REJECTED" "NOT_CHOSEN" "MAYBE" "LEANING_TOWARDS" "CHOSEN")
   "Output marks")

(rtest:defexample test-org-decisions:thd:nofile-1-setup-args
   (list nil nil nil 5 test-org-decisions:thd:nofile-1-list-o-marks)
   "Arguments given to org-decisions-setup-vars"
   )

(rtest:defexample test-org-decisions:thd:nofile-1-mark-data
   (mapcar 
      #'(lambda (x)
	   (make-org-decisions-mark-data.
	      :keyword x
	      :bot-lower-range nil
	      :top-upper-range nil
	      :range-length    nil
	      :static-default 0
	      :all-keywords test-org-decisions:thd:nofile-1-list-o-marks))
      
      test-org-decisions:thd:nofile-1-list-o-marks)
   
   "The mark data corresponding to nofile-1")

(rtest:defexample test-org-decisions:thd:nofile-2-list-o-marks
   '("ZERO" "ONE" "TWO" "THREE" "FOUR" "FIVE" "SIX"))

(rtest:defexample test-org-decisions:thd:nofile-2-raw-marks
   '(chosenness "ZERO" "ONE" "TWO(b)" "THREE(c,-)" "FOUR(d,0)" 
       "FIVE(e,+)" "SIX(,)")
   "Raw marks")


(rtest:defexample test-org-decisions:thd:nofile-2-output-marks
   '(chosenness "ZERO" "ONE" "TWO(b)" "THREE(c)" "FOUR(d)" 
       "FIVE(e)" "SIX")
   "Output marks")
(rtest:defexample test-org-decisions:thd:nofile-2-setup-args
   (list 3 5 4 7 test-org-decisions:thd:nofile-2-list-o-marks)
   "Arguments given to org-decisions-setup-vars"
   )

(rtest:defexample test-org-decisions:thd:nofile-2-mark-data
   (mapcar 
      #'(lambda (x)
	   (make-org-decisions-mark-data.
	      :keyword x
	      :bot-lower-range 3
	      :top-upper-range 5
	      :range-length    1
	      :static-default    4
	      :all-keywords
	      test-org-decisions:thd:nofile-2-list-o-marks))
      
      test-org-decisions:thd:nofile-2-list-o-marks)
   
   "The mark data corresponding to nofile example 2")

;;An example of one that's not automatically managed
(rtest:defexample test-org-decisions:thd:nofile-3-raw-marks
   '(sequence "ZERO" "ONE" "TWO(b)" "THREE(c)" "FOUR(d)" 
       "FIVE(e)" "SIX")
   "Input marks")

(rtest:defexample test-org-decisions:thd:nofile-3-output-marks
   nil
   "Output marks")


;;An example where the top of the range is implicit
(rtest:defexample test-org-decisions:thd:nofile-4-list-o-marks
   '("ZERO" "ONE" "TWO" "THREE" "FOUR" "FIVE" "SIX"))

(rtest:defexample test-org-decisions:thd:nofile-4-raw-marks
   '(chosenness "ZERO" "ONE" "TWO(b)" "THREE(c,-)" "FOUR(d,0)" 
       "FIVE(e)" "SIX")
   "Input marks")

(rtest:defexample test-org-decisions:thd:nofile-4-setup-args
   (list 3 nil 4 7 test-org-decisions:thd:nofile-4-list-o-marks)
   "Arguments given to org-decisions-setup-vars")

(rtest:defexample test-org-decisions:thd:nofile-4-mark-data
   (mapcar 
      #'(lambda (x)
	   (make-org-decisions-mark-data.
	      :keyword x
	      :bot-lower-range 3
	      :top-upper-range 6
	      :range-length    2
	      :static-default    4
	      :all-keywords
	      test-org-decisions:thd:nofile-4-list-o-marks))
      test-org-decisions:thd:nofile-4-list-o-marks)
   
   "The mark data corresponding to nofile example 2")

(rtest:defexample test-org-decisions:thd:nofile-4-kwd-alist
   (mapcar 
      #'(lambda (x)
	   ;;(KEY interpretation head done-word final-done-word)
	   (list x 'chosenness "ZERO" "SIX" "SIX"))
      test-org-decisions:thd:nofile-4-list-o-marks))


(rtest:defexample test-org-decisions:thd:file-simple-list-o-marks
   '("REJECTED" "NOT_CHOSEN" "MAYBE" "LEANING_TOWARDS" "CHOSEN"))
(rtest:defexample test-org-decisions:thd:file-simple-setup-args
   (list 1 4 2 5 test-org-decisions:thd:file-simple-list-o-marks)
   "Arguments given to org-decisions-setup-vars"
   )

(rtest:defexample test-org-decisions:thd:file-simple-mark-data
   (mapcar 
      #'(lambda (x)
	   (make-org-decisions-mark-data.
	      :keyword x
	      :bot-lower-range 1
	      :top-upper-range 4
	      :range-length    2
	      :static-default    2
	      :all-keywords
	      test-org-decisions:thd:file-simple-list-o-marks))
      
      test-org-decisions:thd:file-simple-list-o-marks)
   
   "The mark data corresponding to file1")
(rtest:defexample test-org-decisions:thd:file-simple-high-ix
   3)

(rtest:defexample test-org-decisions:thd:file-simple-sib-maybe-id
   "67a7cbba-c78b-47fe-886a-08a80f67e4ab"
   "ID of a sibling")
(rtest:defexample test-org-decisions:thd:file-simple-sib-maybe-ix
   2
   "Mark index of that sibling")

(rtest:defexample test-org-decisions:thd:file-simple-sib-rejected-id
   "953d4524-f15e-4198-ab33-5769732f51ad"
   "ID of another sibling")

(rtest:defexample test-org-decisions:thd:file-simple-sib-leaning-id
   "be01f611-6175-4e40-a3b5-525a9c1e3b4d"
   "ID of another sibling")
(rtest:defexample test-org-decisions:thd:file-simple-sib-not-chosen-id
   "b7760ac9-e0bf-41a0-9661-720d42670432"
   "ID of another sibling")

(rtest:defexample test-org-decisions:thd:file-simple-parent-id
   "a13a4b6f-02d6-445c-a38e-7e51b9ba29d4"
   "ID of the parent of those nodes")
(rtest:defexample test-org-decisions:thd:file-simple-original-marks
   '("MAYBE""REJECTED""LEANING_TOWARDS""NOT_CHOSEN"))



(rtest:defexample test-org-decisions:thd:file-w-1-chosen-mark-data
   test-org-decisions:thd:file-simple-mark-data)
(rtest:defexample test-org-decisions:thd:file-w-1-chosen-high-ix
   4)
(rtest:defexample test-org-decisions:thd:file-w-1-chosen-sib-not-chosen-a-id
   "b390f9b1-57d0-4a17-9811-47b49fee196f"
   "ID of a not-chosen sibling")
(rtest:defexample test-org-decisions:thd:file-w-1-chosen-sib-maybe-id
   "5a449704-494c-412f-b21d-8ffe07b8092c"
   "ID of another not-chosen sibling")
(rtest:defexample test-org-decisions:thd:file-w-1-chosen-sib-chosen-id
   "c0958364-1f99-4dfc-a671-f21bb5f708bb"
   "ID of the chosen sibling")
(rtest:defexample test-org-decisions:thd:file-w-1-chosen-parent-id
   "b2a6f78c-6199-461b-9850-18980b85b1ab")
(rtest:defexample test-org-decisions:thd:file-w-1-chosen-list-o-marks
   test-org-decisions:thd:file-simple-list-o-marks)

(rtest:defexample test-org-decisions:thd:file-w-1-chosen-original-marks
   '("NOT_CHOSEN" "REJECTED" "CHOSEN " "MAYBE"))

(rtest:defexample test-org-decisions:thd:file-nonautomatic-list-o-marks
   '("NO" "MAYBE_YN" "YES"))
(rtest:defexample test-org-decisions:thd:file-nonautomatic-raw-marks
   '(chosenness "NO" "MAYBE_YN(,0)" "YES"))

(rtest:defexample test-org-decisions:thd:file-nonautomatic-setup-args
   (list nil nil 1 3 test-org-decisions:thd:file-nonautomatic-list-o-marks)
   "Arguments given to org-decisions-setup-vars")
(rtest:defexample test-org-decisions:thd:file-nonautomatic-high-ix
   2)

(rtest:defexample test-org-decisions:thd:file-nonautomatic-sib-yes-id
   "6a27cc97-6e65-4c4e-9014-7fbcf27f52fa")

(rtest:defexample test-org-decisions:thd:file-nonautomatic-mark-data
   (mapcar 
      #'(lambda (x)
	   (make-org-decisions-mark-data.
	      :keyword x
	      :bot-lower-range nil
	      :top-upper-range nil
	      :range-length    nil
	      :static-default    1
	      :all-keywords
	      test-org-decisions:thd:file-nonautomatic-list-o-marks)
	   )
      test-org-decisions:thd:file-nonautomatic-list-o-marks)
   
   "The mark data corresponding to file3")

(rtest:defexample test-org-decisions:thd:context:kwd-alist-normal-todo
   (mapcar 
      #'(lambda (x)
	   ;;(KEY interpretation head done-word final-done-word)
	   (list x 'sequence "TODO" "DONE" "DONE"))
      '("TODO" "DONE"))

   "A kwd-alist that includes only the 2 normal TODO marks.
NB, this is context.  It is not *produced* by any test code, it is
used to control what marks are understood."
   )


(rtest:defexample test-org-decisions:thd:context:kwd-alist
   (append
      test-org-decisions:thd:context:kwd-alist-normal-todo
      (mapcar 
      #'(lambda (x)
       ;;(KEY interpretation head done-word final-done-word)
	   (list x 'chosenness  "NO" "YES" "YES"))
	 test-org-decisions:thd:file-nonautomatic-list-o-marks))
   
   "A kwd-alist to combines 2 normal TODO marks and the
file-nonautomatic marks.
NB, this is not *produced* by any test code, it is used to control
what marks are understood."
   )

(rtest:defexample test-org-decisions:thd:context:kwd-alist-simple

   (append
      test-org-decisions:thd:context:kwd-alist-normal-todo
      (mapcar 
	 #'(lambda (x)
	      ;;(KEY interpretation head done-word final-done-word)
	      (list x 'chosenness "REJECTED" "CHOSEN" "CHOSEN"))
	 test-org-decisions:thd:file-simple-list-o-marks))

   "A kwd-alist that includes the marks in simple.org plus 2 normal TODO marks.
NB, this is context.  It is not *produced* by any test code, it is
used to control what marks are understood."
   )


(rtest:defexample test-org-decisions:thd:file-w-2-types-mark-data
   (append
      test-org-decisions:thd:file-simple-mark-data
      test-org-decisions:thd:file-nonautomatic-mark-data))

(rtest:defexample test-org-decisions:thd:file-w-2-types-t1-high-ix
   3)

(rtest:defexample test-org-decisions:thd:file-w-2-types-t1-leaning-id
   "c8e7d7af-15a2-4650-a604-50ade52bd06c")
(rtest:defexample test-org-decisions:thd:file-w-2-types-t1-list-o-marks
   '("REJECTED" "NOT_CHOSEN" "MAYBE" "LEANING_TOWARDS" "CHOSEN"))

(rtest:defexample test-org-decisions:thd:file-w-2-types-t2-high-ix
   2)

(rtest:defexample test-org-decisions:thd:file-w-2-types-t2-yes-id
   "02e917f5-ac3d-477f-baf5-7eb7c8961683")
(rtest:defexample test-org-decisions:thd:file-w-2-types-t2-list-o-marks
   '("YES" "MAYBE_YN" "NO"))

(rtest:defexample test-org-decisions:thd:file-w-some-nils-high-ix
   4)

(rtest:defexample test-org-decisions:thd:file-w-some-nils-sib-marked-id
   "a4e52131-1145-49f5-8b4b-dc4264900a05")

(rtest:defexample test-org-decisions:thd:file-w-some-nils-sib-nil-id
   "d9729468-db22-4870-8969-9500da63d560")
(rtest:defexample test-org-decisions:thd:file-w-some-nils-list-o-marks
   '("REJECTED" "NOT_CHOSEN" "MAYBE" "LEANING_TOWARDS" "CHOSEN"))

(rtest:defexample test-org-decisions:thd:file-nosibs-sib
   "78fb63fa-4fad-4c7f-aa4a-954ee3431754")
(rtest:defexample test-org-decisions:thd:file-nosibs-high-ix
   0)

;;;_ , Tests of org-decisions-filter-one

(rtest:defexample test-org-decisions:thd:singlemark-1-input-output
   '("ONE(,0)" ("ONE" "ONE" default-mark))
   "Pairs of single marks: Input and output"
   )


(rtest:defexample test-org-decisions:thd:singlemark-2-input-output
   '("TWO" ("TWO" "TWO"))
   "Pairs of single marks: Input and output"
   )


(rtest:defexample test-org-decisions:thd:singlemark-3-input-output
   '("THREE(b)" ("THREE" "THREE(b)"))
   "Pairs of single marks: Input and output")


(rtest:defexample test-org-decisions:thd:singlemark-4-input-output
   '("FOUR(c,0)" ("FOUR" "FOUR(c)" default-mark))
   "Pairs of single marks: Input and output")

(rtest:defexample test-org-decisions:thd:singlemark-5-input-output
   '("FIVE(d,+)" ("FIVE" "FIVE(d)" top-upper-range))
   "Pairs of single marks: Input and output")

(rtest:defexample test-org-decisions:thd:singlemark-6-input-output
   '("SIX(e,-)" ("SIX" "SIX(e)" bot-lower-range))
   "Pairs of single marks: Input and output")

(rtest:defexample test-org-decisions:thd:singlemark-7-input-output
   '("SEVEN(,)" ("SEVEN" "SEVEN"))
   "Pairs of single marks: Input and output")

(rtest:defexample test-org-decisions:thd:singlemark-8-input-output
   '("EIGHT(x!/@,)" ("EIGHT" "EIGHT(x!/@)"))
   "Pairs of single marks: Input and output")

(rtest:deftest org-decisions-filter-one

   (  "Does the examples correctly."
      (equal
	 (org-decisions-filter-one 
	    (car test-org-decisions:thd:singlemark-1-input-output))
	 (second
	    test-org-decisions:thd:singlemark-1-input-output)))
   
   (  "Does the examples correctly."
      (equal
	 (org-decisions-filter-one 
	    (car test-org-decisions:thd:singlemark-2-input-output))
	 (second
	    test-org-decisions:thd:singlemark-2-input-output)))
   
   (  "Does the examples correctly."
      (equal
	 (org-decisions-filter-one 
	    (car test-org-decisions:thd:singlemark-3-input-output))
	 (second
	    test-org-decisions:thd:singlemark-3-input-output)))
   (  "Does the examples correctly."
      (equal
	 (org-decisions-filter-one 
	    (car test-org-decisions:thd:singlemark-4-input-output))
	 (second
	    test-org-decisions:thd:singlemark-4-input-output)))
   (  "Does the examples correctly."
      (equal
	 (org-decisions-filter-one 
	    (car test-org-decisions:thd:singlemark-5-input-output))
	 (second
	    test-org-decisions:thd:singlemark-5-input-output)))
   (  "Does the examples correctly."
      (equal
	 (org-decisions-filter-one 
	    (car test-org-decisions:thd:singlemark-6-input-output))
	 (second
	    test-org-decisions:thd:singlemark-6-input-output)))
   (  "Does the examples correctly."
      (equal
	 (org-decisions-filter-one 
	    (car test-org-decisions:thd:singlemark-7-input-output))
	 (second
	    test-org-decisions:thd:singlemark-7-input-output)))
      (  "Does the examples correctly."
	 (equal
	    (org-decisions-filter-one 
	       (car test-org-decisions:thd:singlemark-8-input-output))
	    (second
	       test-org-decisions:thd:singlemark-8-input-output)))
   )
;;;_ , Tests of org-decisions-setup-vars

(rtest:deftest org-decisions-setup-vars

   (  "The `*-setup-args' examples are proper args to
`org-decisions-setup-vars'.  It sets org-decisions-mark-data
correspondingly."
      (with-temp-buffer
	 (apply #'org-decisions-setup-vars
	    test-org-decisions:thd:nofile-1-setup-args)
	 
	 (rtest:sets=
	    org-decisions-mark-data
	    test-org-decisions:thd:nofile-1-mark-data)))

   (  "The `*-setup-args' examples are proper args to
`org-decisions-setup-vars'.  It sets org-decisions-mark-data
correspondingly."
      (with-temp-buffer
	 (apply #'org-decisions-setup-vars
	    test-org-decisions:thd:nofile-2-setup-args)
	 
	 (rtest:sets=
	    org-decisions-mark-data
	    test-org-decisions:thd:nofile-2-mark-data)))

   (  "The `*-setup-args' examples are proper args to
`org-decisions-setup-vars'.  It sets org-decisions-mark-data
correspondingly."
      (with-temp-buffer
	 (apply #'org-decisions-setup-vars
	    test-org-decisions:thd:nofile-4-setup-args)
	 
	 (rtest:sets=
	    org-decisions-mark-data
	    test-org-decisions:thd:nofile-4-mark-data)))

   (  "The `*-setup-args' examples are proper args to
`org-decisions-setup-vars'.  It sets org-decisions-mark-data
correspondingly."
      (with-temp-buffer
	 (apply #'org-decisions-setup-vars
	    test-org-decisions:thd:file-simple-setup-args)
	 
	 (rtest:sets=
	    org-decisions-mark-data
	    test-org-decisions:thd:file-simple-mark-data)))      
   (  "The `*-setup-args' examples are proper args to
`org-decisions-setup-vars'.  It sets org-decisions-mark-data
correspondingly."
      (with-temp-buffer
	 (apply #'org-decisions-setup-vars
	    test-org-decisions:thd:file-nonautomatic-setup-args)
	 
	 (rtest:sets=
	    org-decisions-mark-data
	    test-org-decisions:thd:file-nonautomatic-mark-data)))   
   )

;;;_ , Tests of the setup filter

(rtest:deftest org-decisions-setup-filter

   ;;I'd like to have also tested that output is conformant.  But
   ;;AFAICT no existing predicate reports that, so I'll only test that
   ;;output matches what's expected, which I'll eyeball.

   (  "Situation: Called manually, passed data with another interpretation.
Response: Return value is `nil'."
      (equal
	 (with-temp-buffer
	    (org-decisions-setup-filter
	       test-org-decisions:thd:nofile-3-raw-marks))
	 test-org-decisions:thd:nofile-3-output-marks))

   (  "Situation: Called manually, passed known data.
Response: Return value is as expected."
      (equal
	 (with-temp-buffer
	    (org-decisions-setup-filter
	       test-org-decisions:thd:nofile-1-raw-marks))
	 test-org-decisions:thd:nofile-1-output-marks))

   (  "Situation: Called manually, passed known data.
Response: Return value is as expected."
      (equal
	 (with-temp-buffer
	    (org-decisions-setup-filter
	       test-org-decisions:thd:nofile-2-raw-marks))
	 test-org-decisions:thd:nofile-2-output-marks))


   (  "Situation: Called manually, passed known data.
Response: Variables have been set up as expected."

      (with-temp-buffer
	 (org-decisions-setup-filter
	    test-org-decisions:thd:nofile-1-raw-marks)
	 (rtest:sets=
	    org-decisions-mark-data
	    test-org-decisions:thd:nofile-1-mark-data)))

   (  "Situation: Called manually, passed known data.
Response: Variables have been set up as expected."

      (with-temp-buffer
	 (org-decisions-setup-filter
	    test-org-decisions:thd:nofile-2-raw-marks)
	 (rtest:sets=
	    org-decisions-mark-data
	    test-org-decisions:thd:nofile-2-mark-data)))

   (  "Situation: Called manually, passed known data.
Response: Variables have been set up as expected."

      (with-temp-buffer
	 (org-decisions-setup-filter
	    test-org-decisions:thd:nofile-4-raw-marks)
	 (rtest:sets=
	    org-decisions-mark-data
	    test-org-decisions:thd:nofile-4-mark-data)))

   (  "Situation: In temp buffer, given the same marks as for file 3.
Response: `org-decisions-mark-data' have been set up as expected."
      (with-temp-buffer
	 (org-decisions-setup-filter
	    test-org-decisions:thd:file-nonautomatic-raw-marks)
	 (rtest:sets=
	    org-decisions-mark-data
	    test-org-decisions:thd:file-nonautomatic-mark-data)))

   (  "Situation: `org-decisions-mark-data' has already been set with
marks from this set
Response: `org-decisions-mark-data' gets the expected value and
nothing extra."
      (with-temp-buffer
	 (let
	    ((org-decisions-mark-data
		test-org-decisions:thd:file-nonautomatic-mark-data))
	    (org-decisions-setup-filter
	       test-org-decisions:thd:file-nonautomatic-raw-marks)
	    (rtest:sets=
	       org-decisions-mark-data
	       test-org-decisions:thd:file-nonautomatic-mark-data))))
   
   (  "Situation: `org-decisions-mark-data' has already been set with
marks from another set
Response: `org-decisions-mark-data' gets the new marks and keeps the
marks from the other set."
      (with-temp-buffer
	 (let
	    ((org-decisions-mark-data
		test-org-decisions:thd:file-simple-mark-data))
	    (org-decisions-setup-filter
	       test-org-decisions:thd:file-nonautomatic-raw-marks)
	    (rtest:sets=
	       org-decisions-mark-data
	       (append
		  test-org-decisions:thd:file-simple-mark-data
		  test-org-decisions:thd:file-nonautomatic-mark-data)))))
   
   ;;Insinuated tests, so that setup filter is called automatically by
   ;;setup.

   (  "Situation: In example file 1.
Response: `org-decisions-mark-data' gets the expected value."
      (with-buffer-containing-object (:file test-org-decisions:thd:file-simple)
	 (rtest:sets=
	    org-decisions-mark-data
	    test-org-decisions:thd:file-simple-mark-data)))
   
   (  "Situation: In example file 2.
Response: `org-decisions-mark-data' gets the expected value."
      (with-buffer-containing-object (:file test-org-decisions:thd:file-w-1-chosen)
	 (rtest:sets=
	    org-decisions-mark-data
	    test-org-decisions:thd:file-w-1-chosen-mark-data)))

   (  "Situation: In example file 3.
Response: `org-decisions-mark-data' gets the expected value."
      (with-buffer-containing-object (:file test-org-decisions:thd:file-nonautomatic)

	 (rtest:sets=
	    org-decisions-mark-data
	    test-org-decisions:thd:file-nonautomatic-mark-data)))

   (  "Situation: In example file 4.
Response: `org-decisions-mark-data' gets the expected value."
      (with-buffer-containing-object (:file test-org-decisions:thd:file-w-2-types)

	 (rtest:sets=
	    org-decisions-mark-data
	    test-org-decisions:thd:file-w-2-types-mark-data))))


;;;_ , Tests of the function to get default
;;;_  . Test helper

;;;_    . org-decisions:th:in-buffer-at

(defmacro* org-decisions:th:in-buffer-at ((&key file id) &rest body)
   ""
   
   `(with-buffer-containing-object
       (:file ,file)
       ;;Have to show entries otherwise we might fail to go to them.
       (show-all)
       ;;Go to one of the entries.  Use `org-find-entry-with-id' so we
       ;;can't accidentally leave this file, as we could with
       ;;`org-id-find'.
       (goto-char
	  (org-find-entry-with-id ,id)) 
       ,@body))

;;;_     , Tests

(put 'org-decisions:th:in-buffer-at 'rtest:test-thru
   'org-decisions-get-entry-index)

;;;_  . org-decisions-get-entry-index
(rtest:deftest org-decisions-get-entry-index
   ;;These tests are tests after insinuation.
   (  "Situation: Point is in a marked entry.
Response: Return the index of that entry."
      (org-decisions:th:in-buffer-at
	 (:file test-org-decisions:thd:file-simple 
	    :id test-org-decisions:thd:file-simple-sib-maybe-id)
	 
	 (equal
	    (org-decisions-get-entry-index 
	       test-org-decisions:thd:file-simple-list-o-marks)
	    test-org-decisions:thd:file-simple-sib-maybe-ix)))
   
   
   (  "Situation: Point is in a unmarked entry (nil).
Response: Return nil."
      (org-decisions:th:in-buffer-at
	 (:file test-org-decisions:thd:file-w-some-nils
	    :id test-org-decisions:thd:file-w-some-nils-sib-nil-id)
	 
	 (equal
	    (org-decisions-get-entry-index 
	       test-org-decisions:thd:file-w-some-nils-list-o-marks)
	    nil)))
   
   (  "Situation: Point is in an entry with a mark from a different set.
Response: Return nil."
      (org-decisions:th:in-buffer-at 
	 (:file test-org-decisions:thd:file-w-2-types
	    :id test-org-decisions:thd:file-w-2-types-t2-yes-id)
	 
	 (equal
	    (org-decisions-get-entry-index 
	       test-org-decisions:thd:file-w-2-types-t1-list-o-marks)
	    nil)))
      
   )
;;;_  . org-decisions-get-highest-mark-index
(rtest:deftest org-decisions-get-highest-mark-index

   (  "Situation: Point is in one of the sibling entries
Response: Returns the highest index."
      (org-decisions:th:in-buffer-at 
	 (:file test-org-decisions:thd:file-simple
	    :id test-org-decisions:thd:file-simple-sib-maybe-id)
	 (equal
	    (org-decisions-get-highest-mark-index
	       test-org-decisions:thd:file-simple-list-o-marks)
	    test-org-decisions:thd:file-simple-high-ix)))
   
   (  "Situation: Point is in a different one of the sibling entries
Response: Returns the highest index."
      (org-decisions:th:in-buffer-at 
	 (:file test-org-decisions:thd:file-simple
	    :id test-org-decisions:thd:file-simple-sib-rejected-id)
	 (equal
	    (org-decisions-get-highest-mark-index
	       test-org-decisions:thd:file-simple-list-o-marks)
	    test-org-decisions:thd:file-simple-high-ix)))

   (  "Situation: Point is in one of the sibling entries
Response: Returns the highest index."
      (org-decisions:th:in-buffer-at 
	 (:file test-org-decisions:thd:file-w-1-chosen
	    :id test-org-decisions:thd:file-w-1-chosen-sib-not-chosen-a-id)
	 (equal
	    (org-decisions-get-highest-mark-index
	       test-org-decisions:thd:file-w-1-chosen-list-o-marks)
	    test-org-decisions:thd:file-w-1-chosen-high-ix)))
   
   (  "Situation: Point is in one of the sibling entries
Response: Returns the highest index."
      (org-decisions:th:in-buffer-at 
	 (:file test-org-decisions:thd:file-nonautomatic
	    :id test-org-decisions:thd:file-nonautomatic-sib-yes-id)
	 (equal
	    (org-decisions-get-highest-mark-index
	       test-org-decisions:thd:file-nonautomatic-list-o-marks)
	    test-org-decisions:thd:file-nonautomatic-high-ix)))


   (  "Situation: Point is in one of the sibling entries of one type.
Response: Returns the highest index of siblings of that type, ignoring
the others."
      (org-decisions:th:in-buffer-at 
	 (:file test-org-decisions:thd:file-w-2-types
	    :id test-org-decisions:thd:file-w-2-types-t1-leaning-id)
	 (equal
	    (org-decisions-get-highest-mark-index
	       test-org-decisions:thd:file-w-2-types-t1-list-o-marks)
	    test-org-decisions:thd:file-w-2-types-t1-high-ix)))
   

   (  "Situation: Point is in one of the sibling entries of one type,
in a sibling group that has 2 types.
Response: Returns the highest index of siblings of that type, ignoring
the others."
      (org-decisions:th:in-buffer-at 
	 (:file test-org-decisions:thd:file-w-2-types
	    :id test-org-decisions:thd:file-w-2-types-t2-yes-id)
	 (equal
	    (org-decisions-get-highest-mark-index
	       test-org-decisions:thd:file-w-2-types-t2-list-o-marks)
	    test-org-decisions:thd:file-w-2-types-t2-high-ix)))


   (  "Situation: Point is in one of the sibling entries.  Some
entries are nil. 
Response: Returns the highest index, ignoring the `nil's."
      (org-decisions:th:in-buffer-at 
	 (:file test-org-decisions:thd:file-w-some-nils
	    :id test-org-decisions:thd:file-w-some-nils-sib-marked-id)
	 (equal
	    (org-decisions-get-highest-mark-index
	       test-org-decisions:thd:file-w-some-nils-list-o-marks)
	    test-org-decisions:thd:file-w-some-nils-high-ix)))

   ( "Situation: There are no entries of chosenness type.
Response: Return 0"
      (org-decisions:th:in-buffer-at 
	 (:file test-org-decisions:thd:file-nosibs
	    :id test-org-decisions:thd:file-nosibs-sib)
	 (equal
	    (org-decisions-get-highest-mark-index
	       test-org-decisions:thd:file-simple-list-o-marks)
	    0)))
   
   )

;;;_  . org-decisions-get-default-mark-index
(put 'org-decisions-get-default-mark-index 'rtest:test-thru
   'org-decisions-get-default-mark)
;;;_  . org-decisions-get-mark-N
(rtest:deftest org-decisions-get-mark-N
   
   (  "Behavior: Gets the corresponding mark from the set."
      (let
	 ((org-decisions-mark-data 
	     test-org-decisions:thd:nofile-4-mark-data))
	 (equal
	    (org-decisions-get-mark-N 0
	       (assoc "ONE" org-decisions-mark-data))
	    "ZERO")))

   (  "Behavior: Gets the corresponding mark from the set."
      (let
	 ((org-decisions-mark-data 
	     test-org-decisions:thd:nofile-4-mark-data))
	 (equal
	    (org-decisions-get-mark-N 4
	       (assoc "THREE" org-decisions-mark-data))
	    "FOUR")))
   )

;;;_  . org-decisions-get-default-mark

;;;_   , Test helpers
(defun org-decisions-get-default-mark-index:th (new-mark mark-data)
   "Test helper"

   (org-decisions-get-default-mark-index
      (assoc new-mark mark-data)))
(defun org-decisions:th:collect-childrens-todo-marks (parent-id)
   ""
   
   (save-excursion
      (show-all) ;;In case anything got hidden
      (goto-char
	 (org-find-entry-with-id
	    parent-id))
      (save-restriction
	 (org-map-entries 
	    #'(lambda ()
		 (org-entry-get (point) "TODO"))
	    nil 'tree))))
;;;_    . Tests of org-decisions:th:collect-childrens-todo-marks
(rtest:deftest org-decisions:th:collect-childrens-todo-marks
   ("Situation: In a known file.
Param: The id of the parent entry.
Response: Returns the TODO marks of the children."
      (with-buffer-containing-object 
	 (:file test-org-decisions:thd:file-simple)
	 (equal
	    (org-decisions:th:collect-childrens-todo-marks
	       test-org-decisions:thd:file-simple-parent-id)
	    test-org-decisions:thd:file-simple-original-marks))))


;;;_   , Tests

(rtest:deftest org-decisions-get-default-mark

   (  "Situation: we're not going into a chosenness type
Response: Return nil, signalling to use the mark we were going to."
      (let
	 ((org-todo-kwd-alist
	     test-org-decisions:thd:context:kwd-alist))
	 (equal
	    (org-decisions-get-default-mark nil "DONE")
	    nil)))

   (  "Situation: We were already in a chosenness type.
Response: Return nil, signalling to use the mark we were going to."
      (let
	 ((org-todo-kwd-alist
	     test-org-decisions:thd:context:kwd-alist))
	 (equal
	    (org-decisions-get-default-mark "YES" "MAYBE_YN")
	    nil)))

   
   ;;These tests test the index return for
   ;;`org-decisions-get-default-mark-index' and also test the string
   ;;return for `org-decisions-get-default-mark'.  Combining the tests
   ;;under `and' is not good style but I don't want to write each
   ;;setup twice.

   (  "Situation: there are no ranges.
Response: return the static default."
      (let
	 ((org-decisions-mark-data 
	     test-org-decisions:thd:file-nonautomatic-mark-data)
	    (org-todo-kwd-alist
	       test-org-decisions:thd:context:kwd-alist))
	 
	 (with-mock
	    (stub org-decisions-get-highest-mark-index => nil)
	    (and
	       (equal 
		  (org-decisions-get-default-mark-index:th "NO"
		     test-org-decisions:thd:file-nonautomatic-mark-data)
		  1)
 	       (equal
 		  (org-decisions-get-default-mark "NO" nil)
 		  "MAYBE_YN")))))
   
   ( "Situation: no current mark is in the upper range.
Response: return the static default."
      (let
	 ((org-decisions-mark-data 
	     test-org-decisions:thd:nofile-4-mark-data)
	    (org-todo-kwd-alist
	       test-org-decisions:thd:nofile-4-kwd-alist))
	 (with-mock
	    (stub org-decisions-get-highest-mark-index => 2)
	    (and
	       (equal 
		  (org-decisions-get-default-mark-index:th 
		     "ONE"
		     test-org-decisions:thd:nofile-4-mark-data)
		  4)
 	       (equal
 		  (org-decisions-get-default-mark "ONE" nil)
 		  "FOUR")
	       ))))


   ;;Because the static default is at or above the top of lower range,
   ;;any mirror-wise constraint is a stronger constraint than it.  So
   ;;no additional test is needed for the interaction between those
   ;;two constraints.

   ( "Situation: a current mark is in the upper range.
Response: return an accordingly lower index.."
      (let
	 ((org-decisions-mark-data 
	     test-org-decisions:thd:nofile-4-mark-data)
	    (org-todo-kwd-alist
	       test-org-decisions:thd:nofile-4-kwd-alist))
	 (with-mock
	    (stub org-decisions-get-highest-mark-index => 6)
	    (and
	       (equal 
		  (org-decisions-get-default-mark-index:th 
		     "ONE"
		     test-org-decisions:thd:nofile-4-mark-data)
		  3)
 	       (equal
 		  (org-decisions-get-default-mark "ONE" nil)
 		  "THREE")))))


   ("Situation: Point is on a heading.  
The only type of TODO in this buffer is a chosenness type.
The default type is MAYBE.
No sibling mark is higher than LEANING_TOWARDS.
Operation: Add a new todo heading.
Result: It then has the mark MAYBE."

      (org-decisions:th:in-buffer-at
	 (:file test-org-decisions:thd:file-simple
	    :id test-org-decisions:thd:file-simple-sib-maybe-id)
	 (org-insert-todo-heading 1)

	 (equal
	    (org-entry-get (point) "TODO")
	    "MAYBE")))
   
   ("Situation: Point is on a heading with no mark.
The only type of TODO in this buffer is a chosenness type.
The default type is MAYBE.
No sibling mark is higher than LEANING_TOWARDS.
Operation: Add a todo mark to the heading.
Result: It then has the mark MAYBE."

      (org-decisions:th:in-buffer-at
	 (:file test-org-decisions:thd:file-simple
	    :id test-org-decisions:thd:file-simple-sib-maybe-id) 
	 (org-insert-heading)

	 
	 (org-todo)
	 
	 (equal
	    (org-entry-get (point) "TODO")
	    "MAYBE")))
   
   
   ("Situation: Point is on a heading.  
The only type of TODO in this buffer is a chosenness type.
The default type is MAYBE.
A sibling mark is CHOSEN
The mark NOT_CHOSEN mirrors the mark CHOSEN.
Operation: Add a todo mark to the heading.
Result: It then has the mark NOT_CHOSEN."

      (org-decisions:th:in-buffer-at
	 (:file test-org-decisions:thd:file-w-1-chosen
	    :id test-org-decisions:thd:file-w-1-chosen-sib-not-chosen-a-id) 
	 (org-insert-heading)

	 (org-todo)

	 (equal
	    (org-entry-get (point) "TODO")
	    "NOT_CHOSEN"))))


;;;_ , Tests of the trigger function

;;;_  . org-decisions-conform-after-promotion

;;;_   , Test helper

(defun* org-decisions-conform-after-promotion:th (&key file id
						    mark-data 
						    other-was
						    other-changed-to
						    expect
						    demoted)
   ""
   (org-decisions:th:in-buffer-at
      (:file file :id id) 
      (let*
	 (
	    (data
	       (or
		  (assoc other-changed-to mark-data)
		  (error
		     "Mark-data should contain the entry being changed to")))
	    
	    (keywords
	       (org-decisions-mark-data.-all-keywords data))
	    
	    (index
	       (org-decisions-get-index-in-keywords
		  other-changed-to keywords))
	    (old-index
	       (when other-was
		  (org-decisions-get-index-in-keywords
		     other-was keywords))))
	 
	 (if demoted
	    (org-decisions-conform-after-demotion
	       0 ;;Fake position that matches nothing
	       keywords
	       (let
		  ((new-highest 
		      (org-decisions-highest-other-ok index data))
		     (static-default
			(org-decisions-mark-data.-static-default data)))
		  (if new-highest
		     (min new-highest static-default)
		     static-default))
	       (org-decisions-highest-other-ok old-index data))
	    
	    (org-decisions-conform-after-promotion 
	       0 ;;Fake position that matches nothing
	       keywords
	       (org-decisions-highest-other-ok index data))))

      (equal
	 (org-entry-get (point) "TODO")
	 expect)))


;;;_   , Tests
(rtest:deftest org-decisions-conform-after-promotion

   (  "Situation: Entry's mark is from some other workflow state.
Response: Do nothing."
      (org-decisions-conform-after-promotion:th 
	 :file test-org-decisions:thd:file-w-2-types
	 :id test-org-decisions:thd:file-w-2-types-t2-yes-id
	 :mark-data test-org-decisions:thd:file-w-2-types-mark-data
	 :other-changed-to "CHOSEN"
	 :expect "YES"))

   (  "Situation: Entry's mark is already lower than the highest allowed index.
Response: No change."
      (org-decisions-conform-after-promotion:th 
	 :file test-org-decisions:thd:file-simple
	 :id test-org-decisions:thd:file-simple-sib-rejected-id
	 :mark-data test-org-decisions:thd:file-simple-mark-data
	 :other-changed-to "CHOSEN"
	 :expect "REJECTED"))


   (  "Situation: Entry's mark is higher than the highest allowed index.
Response: Demote it."
      (org-decisions-conform-after-promotion:th 
	 :file test-org-decisions:thd:file-simple
	 :id test-org-decisions:thd:file-simple-sib-leaning-id
	 :mark-data test-org-decisions:thd:file-simple-mark-data
	 :other-changed-to "LEANING_TOWARDS"
	 :expect "MAYBE"))
   )
;;;_  . org-decisions-conform-after-demotion

;;;_   , Tests
(rtest:deftest org-decisions-conform-after-demotion

   (  "Situation: The other entry was not keeping this node below the default.
Response: This node is unchanged."
      (org-decisions-conform-after-promotion:th 
	 :file test-org-decisions:thd:file-simple
	 :id test-org-decisions:thd:file-simple-sib-maybe-id
	 :mark-data test-org-decisions:thd:file-simple-mark-data
	 :other-was "LEANING_TOWARDS"
	 :other-changed-to "MAYBE"
	 :demoted t
	 :expect "MAYBE"))
   
   (  "Situation: The other entry was keeping this node below the default.
Response: This node is promoted."
      (org-decisions-conform-after-promotion:th 
	 :file test-org-decisions:thd:file-simple
	 :id test-org-decisions:thd:file-simple-sib-maybe-id
	 :mark-data test-org-decisions:thd:file-simple-mark-data
	 :other-was "LEANING_TOWARDS"
	 :other-changed-to "CHOSEN"
	 :demoted t
	 :expect "NOT_CHOSEN"))
   
   (  "Situation: The other entry was keeping this node below the
default.  It was just demoted quite low.
Response: This node is promoted only to the default."
      (org-decisions-conform-after-promotion:th 
	 :file test-org-decisions:thd:file-simple
	 :id test-org-decisions:thd:file-simple-sib-not-chosen-id
	 :mark-data test-org-decisions:thd:file-simple-mark-data
	 :other-was "CHOSEN"
	 :other-changed-to "REJECTED"
	 :demoted t
	 :expect "MAYBE"))

   )


;;;_  . org-decisions-keep-sensible
;;;_   , Helper
(defun* org-decisions-keep-sensible:th:manual (&key from to)
   ""
   
   (let
      (org-blocker-hook)
      (org-todo to)
      (org-decisions-keep-sensible
	 (list
	    :from from
	    :to to
	    :position (point-at-bol)))))

;;;_   , Tests

(rtest:deftest org-decisions-keep-sensible

   ;;Non-insinuated tests, `org-decisions-keep-sensible' is just
   ;;called manually.
   (  "Operation: An entry's todo mark is changed into a TODO from
some other workflow state. 
Response: No change to our entries."
      (org-decisions:th:in-buffer-at
	 (:file test-org-decisions:thd:file-simple
	    :id test-org-decisions:thd:file-simple-sib-rejected-id) 
	 (let
	    ((org-todo-kwd-alist
		test-org-decisions:thd:context:kwd-alist-simple))
	    (org-decisions-keep-sensible:th:manual 
	       :from "RESPONSE:" :to "NOT_CHOSEN"))	 
	 
	 (equal
	    (org-decisions:th:collect-childrens-todo-marks
	       test-org-decisions:thd:file-simple-parent-id)
	    '("MAYBE""NOT_CHOSEN""LEANING_TOWARDS""NOT_CHOSEN"))))
   

   (  "Operation: An entry is promoted, but not high enough to cause
inconsistent state.
Response: It gets promoted.  Other nodes keep their values"
      (org-decisions:th:in-buffer-at
	 (:file test-org-decisions:thd:file-simple
	    :id test-org-decisions:thd:file-simple-sib-rejected-id) 

	 (org-decisions-keep-sensible:th:manual 
	    :from "RESPONSE:" :to "NOT_CHOSEN")	 
	 
	 (equal
	    (org-decisions:th:collect-childrens-todo-marks
	       test-org-decisions:thd:file-simple-parent-id)
	    '("MAYBE""NOT_CHOSEN""LEANING_TOWARDS""NOT_CHOSEN"))))
   

   (  "Operation: An entry is promoted high enough to cause
inconsistent state.  Leaning_towards becomes Chosen.
Response: It gets promoted.  Other nodes are demoted just enough to
keep the state consistent."
      (org-decisions:th:in-buffer-at
	 (:file test-org-decisions:thd:file-simple
	    :id test-org-decisions:thd:file-simple-sib-leaning-id) 

	 
	 (org-decisions-keep-sensible:th:manual 
	    :from "LEANING_TOWARDS" :to "CHOSEN")
	 
	 (equal
	    (org-decisions:th:collect-childrens-todo-marks
	       test-org-decisions:thd:file-simple-parent-id)
	    '("NOT_CHOSEN""REJECTED""CHOSEN""NOT_CHOSEN"))))


   (  "Operation: An entry is promoted high enough to cause
inconsistent state.  Rejected becomes Leaning_towards.
Response: It gets promoted.  Other nodes are demoted just enough to
keep the state consistent."
      (org-decisions:th:in-buffer-at
	 (:file test-org-decisions:thd:file-simple
	    :id test-org-decisions:thd:file-simple-sib-rejected-id) 
	 
	 (org-decisions-keep-sensible:th:manual 
	    :from "REJECTED" :to "LEANING_TOWARDS")
	 
	 (equal
	    (org-decisions:th:collect-childrens-todo-marks
	       test-org-decisions:thd:file-simple-parent-id)
	    '("MAYBE""LEANING_TOWARDS""MAYBE""NOT_CHOSEN"))))
   

   (  "Situation: An entry was medium-high-marked; it's not high
enough to be keeping other nodes down below the default.
Operation: That entry is demoted one place.  LEANING_TOWARDS becomes MAYBE.
Response: It gets demoted.  Other nodes are unchanged."
      (org-decisions:th:in-buffer-at
	 (:file test-org-decisions:thd:file-simple
	    :id test-org-decisions:thd:file-simple-sib-leaning-id) 
	 
	 (org-decisions-keep-sensible:th:manual 
	    :from "LEANING_TOWARDS" :to "MAYBE")
	 
	 (equal
	    (org-decisions:th:collect-childrens-todo-marks
	       test-org-decisions:thd:file-simple-parent-id)
	    '("MAYBE""REJECTED""MAYBE""NOT_CHOSEN"))))
   
   (  "Situation: An entry was high-marked, holding other nodes below
the top of the low range. 
Operation: That entry is demoted one place.  CHOSEN becomes LEANING_TOWARDS.
Response: It gets demoted.  Nodes that it was holding down are
promoted. NOT_CHOSEN becomes MAYBE."
      (org-decisions:th:in-buffer-at
	 (:file test-org-decisions:thd:file-w-1-chosen
	    :id test-org-decisions:thd:file-w-1-chosen-sib-chosen-id) 
	 
	 (org-decisions-keep-sensible:th:manual 
	    :from "CHOSEN" :to "LEANING_TOWARDS")
	 
	 (equal
	    (org-decisions:th:collect-childrens-todo-marks
	       test-org-decisions:thd:file-w-1-chosen-parent-id)
	    '( "MAYBE" "REJECTED" "LEANING_TOWARDS" "MAYBE"))))
   

   (  "Situation: An entry was high-marked, holding other nodes below
the top of the low range. 
Operation: That entry is demoted two places.  CHOSEN becomes MAYBE.
Response: It gets demoted.  Nodes that it was holding down are
promoted as if by two one-place operations.
NOT_CHOSEN becomes MAYBE."
      (org-decisions:th:in-buffer-at
	 (:file test-org-decisions:thd:file-w-1-chosen
	    :id test-org-decisions:thd:file-w-1-chosen-sib-chosen-id) 
	 
	 (org-decisions-keep-sensible:th:manual 
	    :from "CHOSEN" :to "MAYBE")
	 
	 (equal
	    (org-decisions:th:collect-childrens-todo-marks
	       test-org-decisions:thd:file-w-1-chosen-parent-id)
	    '("MAYBE" "REJECTED" "MAYBE" "MAYBE"))))

   ;;No tests for the situation where a node is demoted to the middle
   ;;of the upper range and should both potentially raise some others
   ;;and lower some others.  It's unlikely to be an important
   ;;situation.  YAGNI.


   ;;Tests of org-decisions after having been insinuated

   ;;Implicit operations of `org-todo'
   (  "Operation: An entry is implicitly promoted.
Response: It gets promoted to the next value."
      (org-decisions:th:in-buffer-at
	 (:file test-org-decisions:thd:file-simple
	    :id test-org-decisions:thd:file-simple-sib-rejected-id) 
	 
	 (org-todo)
	 (equal
	    (org-entry-get (point) "TODO")
	    "NOT_CHOSEN")))

   (  "Operation: An entry is implicitly promoted, but not high enough to cause
inconsistent state.
Response: It gets promoted.  Other nodes keep their values"
      (org-decisions:th:in-buffer-at
	 (:file test-org-decisions:thd:file-simple
	    :id test-org-decisions:thd:file-simple-sib-rejected-id) 
	 
	 (org-todo)
	 (equal
	    (org-decisions:th:collect-childrens-todo-marks
	       test-org-decisions:thd:file-simple-parent-id)
	    '("MAYBE""NOT_CHOSEN""LEANING_TOWARDS""NOT_CHOSEN"))))

   ;;Tests that operations still behave after insinuation the same as
   ;;they did manually.
   (  "Operation: An entry is explicitly promoted, but not high enough to cause
inconsistent state.
Response: It gets promoted.  Other nodes keep their values"
      (org-decisions:th:in-buffer-at
	 (:file test-org-decisions:thd:file-simple
	    :id test-org-decisions:thd:file-simple-sib-rejected-id) 
	 
	 (org-todo "NOT_CHOSEN")
	 
	 (equal
	    (org-decisions:th:collect-childrens-todo-marks
	       test-org-decisions:thd:file-simple-parent-id)
	    '("MAYBE""NOT_CHOSEN""LEANING_TOWARDS""NOT_CHOSEN"))))
   

   (  "Operation: An entry is promoted high enough to cause
inconsistent state.  Leaning_towards becomes Chosen.
Response: It gets promoted.  Other nodes are demoted just enough to
keep the state consistent."
      (org-decisions:th:in-buffer-at
	 (:file test-org-decisions:thd:file-simple
	    :id test-org-decisions:thd:file-simple-sib-leaning-id) 
	 
	 (org-todo "CHOSEN")
	 
	 (equal
	    (org-decisions:th:collect-childrens-todo-marks
	       test-org-decisions:thd:file-simple-parent-id)
	    '("NOT_CHOSEN""REJECTED""CHOSEN""NOT_CHOSEN"))))

   (  "Operation: An entry is promoted high enough to cause
inconsistent state.  Rejected becomes Leaning_towards.
Response: It gets promoted.  Other nodes are demoted just enough to
keep the state consistent."
      (org-decisions:th:in-buffer-at
	 (:file test-org-decisions:thd:file-simple
	    :id test-org-decisions:thd:file-simple-sib-rejected-id) 
	 
	 (org-todo "LEANING_TOWARDS")
	 
	 (equal
	    (org-decisions:th:collect-childrens-todo-marks
	       test-org-decisions:thd:file-simple-parent-id)
	    '("MAYBE""LEANING_TOWARDS""MAYBE""NOT_CHOSEN"))))
   

   (  "Situation: An entry was medium-high-marked; it's not high
enough to be keeping other nodes down below the default.
Operation: That entry is demoted one place.  LEANING_TOWARDS becomes MAYBE.
Response: It gets demoted."
      (org-decisions:th:in-buffer-at
	 (:file test-org-decisions:thd:file-simple
	    :id test-org-decisions:thd:file-simple-sib-leaning-id) 
	 
	 (org-todo "MAYBE")
	 
	 (equal
	    (org-decisions:th:collect-childrens-todo-marks
	       test-org-decisions:thd:file-simple-parent-id)
	    '("MAYBE""REJECTED""MAYBE""NOT_CHOSEN"))))
   
   (  "Situation: An entry was high-marked, holding other nodes below
the top of the low range. 
Operation: That entry is demoted one place.  CHOSEN becomes LEANING_TOWARDS.
Response: It gets demoted.  Nodes that it was holding down are
promoted. NOT_CHOSEN becomes MAYBE."
      (org-decisions:th:in-buffer-at
	 (:file test-org-decisions:thd:file-w-1-chosen
	    :id test-org-decisions:thd:file-w-1-chosen-sib-chosen-id) 
	 
	 (org-todo "LEANING_TOWARDS")
	 
	 (equal
	    (org-decisions:th:collect-childrens-todo-marks
	       test-org-decisions:thd:file-w-1-chosen-parent-id)
	    '( "MAYBE" "REJECTED" "LEANING_TOWARDS" "MAYBE"))))
   

   (  "Situation: An entry was high-marked, holding other nodes below
the top of the low range. 
Operation: That entry is demoted two places.  CHOSEN becomes MAYBE.
Response: It gets demoted.  Nodes that it was holding down are
promoted as if by two one-place operations.
NOT_CHOSEN becomes MAYBE."
      (org-decisions:th:in-buffer-at
	 (:file test-org-decisions:thd:file-w-1-chosen
	    :id test-org-decisions:thd:file-w-1-chosen-sib-chosen-id) 
	 
	 (org-todo "MAYBE")
	 
	 (equal
	    (org-decisions:th:collect-childrens-todo-marks
	       test-org-decisions:thd:file-w-1-chosen-parent-id)
	    '("MAYBE" "REJECTED" "MAYBE" "MAYBE"))))
   )




;;;_. Footers
;;;_ , Provides

(provide 'test-org-decisions)

;;;_ * Local emacs vars.
;;;_  + Local variables:
;;;_  + End:

;;;_ , End
;;; test-org-decisions.el ends here

[-- Attachment #5: simple.org --]
[-- Type: application/octet-stream, Size: 575 bytes --]

#+CHOOSE_TODO: REJECTED(r) NOT_CHOSEN(n,-) MAYBE(,0) LEANING_TOWARDS(l) CHOSEN(c,+)
* Parent
  :PROPERTIES:
  :ID:       a13a4b6f-02d6-445c-a38e-7e51b9ba29d4
  :END:
** MAYBE Sib maybe
   :PROPERTIES:
   :ID:       67a7cbba-c78b-47fe-886a-08a80f67e4ab
   :END:
** REJECTED Sib rejected
   :PROPERTIES:
   :ID:       953d4524-f15e-4198-ab33-5769732f51ad
   :END:

** LEANING_TOWARDS Sib leaning
   :PROPERTIES:
   :ID:       be01f611-6175-4e40-a3b5-525a9c1e3b4d
   :END:
** NOT_CHOSEN Sib not-chosen
   :PROPERTIES:
   :ID:       b7760ac9-e0bf-41a0-9661-720d42670432
   :END:

[-- Attachment #6: w-1-chosen.org --]
[-- Type: application/octet-stream, Size: 485 bytes --]

#+CHOOSE_TODO: REJECTED(r) NOT_CHOSEN(n,-) MAYBE(,0) LEANING_TOWARDS(l) CHOSEN(c,+)

* Parent
  :PROPERTIES:
  :ID:       b2a6f78c-6199-461b-9850-18980b85b1ab
  :END:
** NOT_CHOSEN sib-not-chosen-a
   :PROPERTIES:
   :ID:       b390f9b1-57d0-4a17-9811-47b49fee196f
   :END:
** REJECTED sib 2
** CHOSEN sib-chosen
   :PROPERTIES:
   :ID:       c0958364-1f99-4dfc-a671-f21bb5f708bb
   :END:
** MAYBE sib-maybe
   :PROPERTIES:
   :ID:       5a449704-494c-412f-b21d-8ffe07b8092c
   :END:


[-- Attachment #7: w-2-types.org --]
[-- Type: application/octet-stream, Size: 359 bytes --]

#+CHOOSE_TODO: REJECTED(r) NOT_CHOSEN(n,-) MAYBE(,0) LEANING_TOWARDS(l) CHOSEN(c,+)
#+CHOOSE_TODO: NO MAYBE_YN(,0) YES

* Header line
** LEANING_TOWARDS
   :PROPERTIES:
   :ID:       c8e7d7af-15a2-4650-a604-50ade52bd06c
   :END:
** REJECTED
** YES
   :PROPERTIES:
   :ID:       02e917f5-ac3d-477f-baf5-7eb7c8961683
   :END:
** MAYBE_YN
** MAYBE
** NO
** YES


[-- Attachment #8: nonautomatic.org --]
[-- Type: application/octet-stream, Size: 183 bytes --]

#+CHOOSE_TODO:  NO MAYBE_YN(,0) YES

* Using a non-automatic set of marks
** MAYBE_YN
** YES
   :PROPERTIES:
   :ID:       6a27cc97-6e65-4c4e-9014-7fbcf27f52fa
   :END:
** YES
** NO


[-- Attachment #9: no-sibs.org --]
[-- Type: application/octet-stream, Size: 193 bytes --]

#+CHOOSE_TODO: REJECTED(r) NOT_CHOSEN(n,-) MAYBE(,0) LEANING_TOWARDS(l) CHOSEN(c,+)
* Header lines
** The sole entry
   :PROPERTIES:
   :ID:       78fb63fa-4fad-4c7f-aa4a-954ee3431754
   :END:

[-- Attachment #10: w-some-nils.org --]
[-- Type: application/octet-stream, Size: 320 bytes --]

#+CHOOSE_TODO: REJECTED(r) NOT_CHOSEN(n,-) MAYBE(,0) LEANING_TOWARDS(l) CHOSEN(c,+)

* Header line
** CHOSEN entry
   :PROPERTIES:
   :ID:       a4e52131-1145-49f5-8b4b-dc4264900a05
   :END:
** No mark here
   :PROPERTIES:
   :ID:       d9729468-db22-4870-8969-9500da63d560
   :END:
** NOT_CHOSEN
** No mark here either

[-- Attachment #11: Type: text/plain, Size: 204 bytes --]

_______________________________________________
Emacs-orgmode mailing list
Remember: use `Reply All' to send replies to the list.
Emacs-orgmode@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-orgmode

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Advice sought on managing decision alternatives.
  2009-01-31  4:21         ` Tom Breton (Tehom)
@ 2009-01-31  5:41           ` Carsten Dominik
  2009-01-31 18:36             ` Tom Breton (Tehom)
  2009-02-06 13:08           ` Carsten Dominik
  1 sibling, 1 reply; 56+ messages in thread
From: Carsten Dominik @ 2009-01-31  5:41 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode

Hi Tom,

this looks awesome.

Right now I am stabilizing everything to make my final release
for Emacs 23.1, so it may be a week or two before I get to
integrate this.

Also, I am interested in the testing environment, and what
you made here may end up to be enough to establish a testing
framework for Org-mode.

If it turns out to be like this, maybe you can make a tutorial
on test creation and put that up on Worg?  I would be willing
to put the code needed for the testing environment into the
contrib directory.

- Carsten

On Jan 31, 2009, at 5:21 AM, Tom Breton (Tehom) wrote:

> Here is org-decisions.  "All 68 tests ran successfully".  I hope it is
> satisfactory.  If it's not, please let me know.
>
> Please find attached:
> * org-decisions.el
> * diffs to org.el
> * test-org-decisions.el.
> * 6 example files in testing
>
> A few notes:
>
> ****** Test files
>
> I included 6 example files that I used in testing, and my test file
> test-org-decisions.el.
>
> test-org-decisions.el uses my tester rtest, which is unfortunately in
> flux at the moment.  Still, I felt it would be best to make it
> publicly available.
>
> ****** Use of cl
>
> I used cl in org-decisions.el.  I hope that's not a problem, but if it
> is I can rewrite the parts that use cl.
>
> * pushnew
> * position
> * destructuring-bind
> * defstruct
>
> ****** Use of allout
>
> org-decisions.el and test-org-decisions.el use allout for structuring.
> I removed the "mode: allout" line so that they can be read without
> allout present.
>
>        Tom Breton (Tehom)
> <org-decisions.el><org.el.diff><test-org- 
> decisions.el><simple.org><w-1-chosen.org><w-2- 
> types.org><nonautomatic.org><no-sibs.org><w-some-nils.org>

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Advice sought on managing decision alternatives.
  2009-01-31  5:41           ` Carsten Dominik
@ 2009-01-31 18:36             ` Tom Breton (Tehom)
  2009-02-01 15:54               ` James TD Smith
  0 siblings, 1 reply; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-01-31 18:36 UTC (permalink / raw)
  Cc: emacs-orgmode

> Hi Tom,
>
> this looks awesome.
>
> Right now I am stabilizing everything to make my final release
> for Emacs 23.1, so it may be a week or two before I get to
> integrate this.

Understood.

> Also, I am interested in the testing environment, and what
> you made here may end up to be enough to establish a testing
> framework for Org-mode.

> If it turns out to be like this, maybe you can make a tutorial
> on test creation and put that up on Worg?  I would be willing
> to put the code needed for the testing environment into the
> contrib directory.

Certainly.  One thing, once my testing package rtest is in a stable state,
I plan to release it on its own, possibly as a sourceforge project.  But I
have no objection to you also putting in the org contrib directory.

Tom Breton (Tehom)

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Re: Advice sought on managing decision alternatives.
  2009-01-31 18:36             ` Tom Breton (Tehom)
@ 2009-02-01 15:54               ` James TD Smith
  0 siblings, 0 replies; 56+ messages in thread
From: James TD Smith @ 2009-02-01 15:54 UTC (permalink / raw)
  To: emacs-orgmode

Hi Tom,

On 2009-01-31 13:36:20(-0500), Tom Breton (Tehom) wrote:
> > Also, I am interested in the testing environment, and what
> > you made here may end up to be enough to establish a testing
> > framework for Org-mode.
>
> > If it turns out to be like this, maybe you can make a tutorial
> > on test creation and put that up on Worg?  I would be willing
> > to put the code needed for the testing environment into the
> > contrib directory.
>
> Certainly.  One thing, once my testing package rtest is in a stable state,
> I plan to release it on its own, possibly as a sourceforge project.  But I
> have no objection to you also putting in the org contrib directory.

As part of the rewrite of org-remember I am working on I have been adding tests
using ert (at the time I started it you suggested not to use rtest as it was
undergoing a lot of changes[1]). I haven't run into any problems with ert so
far, but I would be willing to switch to another testing package if it becomes
the standard for org-mode.

I'd like to take a look at rtest, but the only version of I can find on the web
is at http://www.panix.com/~tehom/my-code/rtest-3-0.tar.gz, which appears to be
from 2001. Is there a more recent version available?

James

[1] http://article.gmane.org/gmane.emacs.orgmode/8817

--
|-<James TD Smith>-<email/ahktenzero@mohorovi.cc>-|

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Advice sought on managing decision alternatives.
  2009-01-31  4:21         ` Tom Breton (Tehom)
  2009-01-31  5:41           ` Carsten Dominik
@ 2009-02-06 13:08           ` Carsten Dominik
  2009-02-06 16:16             ` William Henney
  2009-02-06 20:07             ` Tom Breton (Tehom)
  1 sibling, 2 replies; 56+ messages in thread
From: Carsten Dominik @ 2009-02-06 13:08 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode

Hi Tom,

I am now looking at org-decision and start to integrate it.

There is one point I'd like to discuss.

My preferred way to do the integration is opening a new hacking door
which will not require changes to org.el for other people doing  
similar stuff.

So my idea would be to search for

"^#\\+\\(\\([a-zA-Z]+\\)_\\)?TODO"

when scanning the buffer, i.e. that any keyword could precede TODO in  
such a line.

I would then like to call the filter hook, using that keyword as  
interpretation.

WIth you patch, we have right now

CHOOSE    as the prefix
choseness as the interpretation
org-decision as the name of the module.

My request would be to maybe use `choose' also as the
interpretation symbol, or, alternatively, CHOSENESS
as the prefix.

For customizing org-todo-keywords, instead of explicitly
offering `choseness', maybe we can use a symbol field
where people can type into.

That would turn your patch into a generally useful system
of hooks where other ideas could be implemented as well.

What do you think?

- Carsten

On Jan 31, 2009, at 5:21 AM, Tom Breton (Tehom) wrote:

> Here is org-decisions.  "All 68 tests ran successfully".  I hope it is
> satisfactory.  If it's not, please let me know.
>
> Please find attached:
> * org-decisions.el
> * diffs to org.el
> * test-org-decisions.el.
> * 6 example files in testing
>
> A few notes:
>
> ****** Test files
>
> I included 6 example files that I used in testing, and my test file
> test-org-decisions.el.
>
> test-org-decisions.el uses my tester rtest, which is unfortunately in
> flux at the moment.  Still, I felt it would be best to make it
> publicly available.
>
> ****** Use of cl
>
> I used cl in org-decisions.el.  I hope that's not a problem, but if it
> is I can rewrite the parts that use cl.
>
> * pushnew
> * position
> * destructuring-bind
> * defstruct
>
> ****** Use of allout
>
> org-decisions.el and test-org-decisions.el use allout for structuring.
> I removed the "mode: allout" line so that they can be read without
> allout present.
>
>        Tom Breton (Tehom)
> <org-decisions.el><org.el.diff><test-org- 
> decisions.el><simple.org><w-1-chosen.org><w-2- 
> types.org><nonautomatic.org><no-sibs.org><w-some-nils.org>

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Re: Advice sought on managing decision alternatives.
  2009-02-06 13:08           ` Carsten Dominik
@ 2009-02-06 16:16             ` William Henney
  2009-02-06 20:07             ` Tom Breton (Tehom)
  1 sibling, 0 replies; 56+ messages in thread
From: William Henney @ 2009-02-06 16:16 UTC (permalink / raw)
  To: Carsten Dominik; +Cc: emacs-orgmode, Tehom Tom Breton

On Fri, Feb 6, 2009 at 7:08 AM, Carsten Dominik <dominik@science.uva.nl> wrote:
> CHOOSE    as the prefix
> choseness as the interpretation
> org-decision as the name of the module.
>
> My request would be to maybe use `choose' also as the
> interpretation symbol, or, alternatively, CHOSENESS
> as the prefix.
>

I believe the standard spelling is "chosenness", although it is a very
rare word in English outside of Judaism :)

Cheers

Will



-- 

  Dr William Henney, Centro de Radioastronomía y Astrofísica,
  Universidad Nacional Autónoma de México, Campus Morelia

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Advice sought on managing decision alternatives.
  2009-02-06 13:08           ` Carsten Dominik
  2009-02-06 16:16             ` William Henney
@ 2009-02-06 20:07             ` Tom Breton (Tehom)
  2009-02-07  0:18               ` Carsten Dominik
  1 sibling, 1 reply; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-02-06 20:07 UTC (permalink / raw)
  Cc: emacs-orgmode

> Hi Tom,
> [...]

> WIth you patch, we have right now
>
> CHOOSE    as the prefix
> choseness as the interpretation
> org-decision as the name of the module.
>
> My request would be to maybe use `choose' also as the
> interpretation symbol, or, alternatively, CHOSENESS
> as the prefix.

Yes.  I think "choose" is best; the ambiguity between "chosenness" and
"choseness" just invited difficulties.

Always feel free to suggest alternatives to my naming.  Sometimes my
initial ideas go in a funny direction.  Eg, my initial thinking, which I
now abandon, was:

 * org-DECISIONS.el because it supports decisions.
 * CHOSENNESS because it's the property the item has of being chosen or not.
   As William observed, it's grammatically correct but rare.
 * CHOOSE because I saw that CHOSENNESS has problems.

So "choose" it is.  I'd like to rename the file org-choose.el as well, now
that I think about the naming.

Do you want a patch for it?

> For customizing org-todo-keywords, instead of explicitly
> offering `choseness', maybe we can use a symbol field
> where people can type into.

It's more flexible but offers less support to the user.  Maybe we can have
the best of both worlds by restricting the choice to interpretations that
available modules support.  Ie, something like this:

 * Object: a variable that holds the names of the interpretation symbols,
or of the ones that aren't built in.
 * Behavior: interested modules add their interpretation symbol to the list
 * Behavior: When customizing org-todo-keywords, offer the symbols from
   that list as choices for interpretation symbols.

The primary difficulty would be getting widgets to understand that.


> That would turn your patch into a generally useful system
> of hooks where other ideas could be implemented as well.
>
> What do you think?

Sounds good to me.

Tom Breton (Tehom)

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Advice sought on managing decision alternatives.
  2009-02-06 20:07             ` Tom Breton (Tehom)
@ 2009-02-07  0:18               ` Carsten Dominik
  2009-02-07 20:46                 ` Tom Breton (Tehom)
  0 siblings, 1 reply; 56+ messages in thread
From: Carsten Dominik @ 2009-02-07  0:18 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode

Hi Tom,

On Feb 6, 2009, at 9:07 PM, Tom Breton (Tehom) wrote:

>> Hi Tom,
>> [...]
>
>> WIth you patch, we have right now
>>
>> CHOOSE    as the prefix
>> choseness as the interpretation
>> org-decision as the name of the module.
>>
>> My request would be to maybe use `choose' also as the
>> interpretation symbol, or, alternatively, CHOSENESS
>> as the prefix.
>
> Yes.  I think "choose" is best; the ambiguity between "chosenness" and
> "choseness" just invited difficulties.
>
> Always feel free to suggest alternatives to my naming.  Sometimes my
> initial ideas go in a funny direction.  Eg, my initial thinking,  
> which I
> now abandon, was:
>
> * org-DECISIONS.el because it supports decisions.
> * CHOSENNESS because it's the property the item has of being chosen  
> or not.
>   As William observed, it's grammatically correct but rare.
> * CHOOSE because I saw that CHOSENNESS has problems.
>
> So "choose" it is.  I'd like to rename the file org-choose.el as  
> well, now
> that I think about the naming.

Good.

>
>
> Do you want a patch for it?


Yes, against current org.el, please, if you do not mind,
because I have not yet applied your earlier patch.

>
>
>> For customizing org-todo-keywords, instead of explicitly
>> offering `choseness', maybe we can use a symbol field
>> where people can type into.
>
> It's more flexible but offers less support to the user.  Maybe we  
> can have
> the best of both worlds by restricting the choice to interpretations  
> that
> available modules support.  Ie, something like this:
>
> * Object: a variable that holds the names of the interpretation  
> symbols,
> or of the ones that aren't built in.
> * Behavior: interested modules add their interpretation symbol to  
> the list
> * Behavior: When customizing org-todo-keywords, offer the symbols from
>   that list as choices for interpretation symbols.

This sounds perfect.

> The primary difficulty would be getting widgets to understand that.

Yes.  Right now, I do not know how to do this, therefore
my more primitive proposal. Yours is better, if you can
make the widget work...

- Carsten

>
>
>
>> That would turn your patch into a generally useful system
>> of hooks where other ideas could be implemented as well.
>>
>> What do you think?
>
> Sounds good to me.
>
> Tom Breton (Tehom)
>
>
>
>

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Advice sought on managing decision alternatives.
  2009-02-07  0:18               ` Carsten Dominik
@ 2009-02-07 20:46                 ` Tom Breton (Tehom)
  2009-02-08 13:06                   ` Carsten Dominik
  0 siblings, 1 reply; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-02-07 20:46 UTC (permalink / raw)
  Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 1678 bytes --]


Hi, Carsten.  Here is the new patch to org.el and the new
org-choose.el

A couple of notes:

 * As we talked about, "decisions" and "chosenness" are now called
   "choose" everywhere.
 * I was able to add the library-aware customization we talked about.
 * I also added new variable `org-todo-normal-interpretations' - see
   explanation below.
 * New test file.  Essentially the same, with name replacement.
 * Didn't append the example files; they are all unchanged from before.

******* About `org-todo-normal-interpretations'

You said your idea was to make a generally useful system.  I noticed
that one thing was still hard-coded.  It's the part of org-todo that
finds the next entry:

	(memq interpret '(sequence choose))
	...
	(memq interpret '(type priority))

If I understand your intentions correctly, new TODO modules should
always behave like `sequence' in this respect.  So the first line now
looks at a variable list.

I saw two possible approaches to get this list:
 * Extract the symbol from `org-todo-interpretations'.  It's in there,
   but:
   * Con: Of the two obvious ways to extract it, neither is good
     1. Parse the widget form the way that wid-edit does, which is
        hairy
     2. Have a policy that every module that adds to it has to put the
        symbol first, which changes the appearance of widgets and
        invites mistakes.
 * Add yet another variable to contain all the "normal" interpretation
   symbols.

I have tentatively chosen the second and coded it.  I named the
variable `org-todo-normal-interpretations' (as always, feel free to
suggest a better name).


Tom Breton (Tehom)

[-- Attachment #2: org.el.diff --]
[-- Type: application/octet-stream, Size: 6650 bytes --]

*** old-org.el	2009-01-04 03:01:50.000000000 -0500
--- org.el	2009-02-07 15:13:57.000000000 -0500
***************
*** 1409,1414 ****
--- 1409,1426 ----
    :tag "Org Progress"
    :group 'org-time)
  
+ (defvar org-todo-interpretation-widgets
+    '(
+        (:tag "Sequence (cycling hits every state)" sequence)
+        (:tag "Type     (cycling directly to DONE)" type))
+    
+    "The available interpretation symbols for customizing
+ `org-todo-keywords'.
+ Interested libraries should add to this list." )
+ (defvar org-todo-normal-interpretations 
+    '(sequence)
+    "" )
+ 
  (defcustom org-todo-keywords '((sequence "TODO" "DONE"))
    "List of TODO entry keyword sequences and their interpretation.
  \\<org-mode-map>This is a list of sequences.
***************
*** 1458,1465 ****
  		  (cons
  		   (choice
  		    :tag "Interpretation"
! 		    (const :tag "Sequence (cycling hits every state)" sequence)
! 		    (const :tag "Type     (cycling directly to DONE)" type))
  		   (repeat
  		    (string :tag "Keyword"))))))
  
--- 1470,1487 ----
  		  (cons
  		   (choice
  		    :tag "Interpretation"
! 		      ;;Quick and dirty way to see
! 		      ;;`org-todo-interpretations'.  This takes the
! 		      ;;place of item arguments
! 		      :convert-widget
! 		      (lambda (widget)
! 			 (widget-put widget 
! 			    :args (mapcar 
! 				     #'(lambda (x)
! 					  (widget-convert 
! 					     (cons 'const x)))
! 				     org-todo-interpretation-widgets))
! 			 widget))
  		   (repeat
  		    (string :tag "Keyword"))))))
  
***************
*** 3025,3031 ****
      (org-set-local 'org-file-properties nil)
      (org-set-local 'org-file-tags nil)
      (let ((re (org-make-options-regexp
! 	       '("CATEGORY" "SEQ_TODO" "TYP_TODO" "TODO" "COLUMNS"
  		 "STARTUP" "ARCHIVE" "FILETAGS" "TAGS" "LINK" "PRIORITIES"
  		 "CONSTANTS" "PROPERTY" "DRAWERS" "SETUPFILE")))
  	  (splitre "[ \t]+")
--- 3047,3053 ----
      (org-set-local 'org-file-properties nil)
      (org-set-local 'org-file-tags nil)
      (let ((re (org-make-options-regexp
! 	       '("CATEGORY" "SEQ_TODO" "TYP_TODO" "TODO" "CHOOSE_TODO" "COLUMNS"
  		 "STARTUP" "ARCHIVE" "FILETAGS" "TAGS" "LINK" "PRIORITIES"
  		 "CONSTANTS" "PROPERTY" "DRAWERS" "SETUPFILE")))
  	  (splitre "[ \t]+")
***************
*** 3052,3057 ****
--- 3074,3081 ----
  	      (push (cons 'sequence (org-split-string value splitre)) kwds))
  	     ((equal key "TYP_TODO")
  	      (push (cons 'type (org-split-string value splitre)) kwds))
+ 	     ((equal key "CHOOSE_TODO")
+ 	      (push (cons 'choose (org-split-string value splitre)) kwds))
  	     ((equal key "TAGS")
  	      (setq tags (append tags (org-split-string value splitre))))
  	     ((equal key "COLUMNS")
***************
*** 3133,3138 ****
--- 3157,3168 ----
        (setq kwds (nreverse kwds))
        (let (inter kws kw)
  	(while (setq kws (pop kwds))
+ 	  (let
+ 	     ((kws
+ 		 (or
+ 		    (run-hook-with-args-until-success
+ 		       'org-todo-setup-filter-hook kws) 
+ 		    kws)))
  	     (setq inter (pop kws) sep (member "|" kws)
  		kws0 (delete "|" (copy-sequence kws))
  		kwsa nil
***************
*** 3154,3160 ****
  				      '((:endgroup))))
  		hw (car kws1)
  		dws (if sep (org-remove-keyword-keys (cdr sep)) (last kws1))
! 		tail (list inter hw (car dws) (org-last dws)))
  	  (add-to-list 'org-todo-heads hw 'append)
  	  (push kws1 org-todo-sets)
  	  (setq org-done-keywords (append org-done-keywords dws nil))
--- 3184,3190 ----
  				 '((:endgroup))))
  		hw (car kws1)
  		dws (if sep (org-remove-keyword-keys (cdr sep)) (last kws1))
! 		tail (list inter hw (car dws) (org-last dws))))
  	  (add-to-list 'org-todo-heads hw 'append)
  	  (push kws1 org-todo-sets)
  	  (setq org-done-keywords (append org-done-keywords dws nil))
***************
*** 4934,4944 ****
        (org-back-to-heading)
        (outline-previous-heading)
        (looking-at org-todo-line-regexp))
      (if (or arg
  	    (not (match-beginning 2))
  	    (member (match-string 2) org-done-keywords))
! 	(insert (car org-todo-keywords-1) " ")
!       (insert (match-string 2) " "))
      (when org-provide-todo-statistics
        (org-update-parent-todo-statistics))))
  
--- 4964,4983 ----
        (org-back-to-heading)
        (outline-previous-heading)
        (looking-at org-todo-line-regexp))
+     (let*
+        ((new-mark-x
  	   (if (or arg
  		  (not (match-beginning 2))
  		  (member (match-string 2) org-done-keywords))
! 	      (car org-todo-keywords-1)
! 	      (match-string 2)))
! 	  (new-mark
! 	     (or
! 		(run-hook-with-args-until-success
! 		   'org-todo-get-default-hook new-mark-x nil)
! 		new-mark-x)))
!        (insert new-mark " "))
!      
      (when org-provide-todo-statistics
        (org-update-parent-todo-statistics))))
  
***************
*** 8190,8195 ****
--- 8229,8246 ----
  :from  previous state (keyword as a string), or nil
  :to    new state (keyword as a string), or nil")
  
+ (defvar org-todo-setup-filter-hook nil 
+    "Hook for functions that pre-filter todo specs.
+ 
+ Each function takes a todo spec and returns either `nil' or the spec
+ transformed into canonical form." )
+ 
+ (defvar org-todo-get-default-hook nil
+    "Hook for functions that get a default item for todo.
+ 
+ Each function takes arguments (NEW-MARK OLD-MARK) and returns either
+ `nil' or a string to be used for the todo mark." )
+ 
  (defvar org-agenda-headline-snapshot-before-repeat)
  (defun org-todo (&optional arg)
    "Change the TODO state of an item.
***************
*** 8285,8291 ****
  		     ((null member) (or head (car org-todo-keywords-1)))
  		     ((equal this final-done-word) nil) ;; -> make empty
  		     ((null tail) nil) ;; -> first entry
! 		     ((eq interpret 'sequence)
  		      (car tail))
  		     ((memq interpret '(type priority))
  		      (if (eq this-command last-command)
--- 8336,8342 ----
  		     ((null member) (or head (car org-todo-keywords-1)))
  		     ((equal this final-done-word) nil) ;; -> make empty
  		     ((null tail) nil) ;; -> first entry
! 		     ((memq interpret org-todo-normal-interpretations)
  		      (car tail))
  		     ((memq interpret '(type priority))
  		      (if (eq this-command last-command)
***************
*** 8294,8299 ****
--- 8345,8354 ----
  			    (or done-word (car org-done-keywords))
  			  nil)))
  		     (t nil)))
+ 	     (state (or 
+ 		       (run-hook-with-args-until-success
+ 			  'org-todo-get-default-hook state last-state) 
+ 		       state))
  	     (next (if state (concat " " state " ") " "))
  	     (change-plist (list :type 'todo-state-change :from this :to state
  				 :position startpos))

[-- Attachment #3: org-choose.el --]
[-- Type: application/octet-stream, Size: 12531 bytes --]

;;;_ org-choose.el --- decision management for org-mode

;;;_. Headers
;;;_ , License
;; Copyright (C) 2009  Tom Breton (Tehom)

;; Author: Tom Breton (Tehom)
;; Keywords: 

;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;;;_ , Commentary:

;; 


;;;_ , Requires

(require 'org)
(eval-when-compile
   (require 'cl))

;;;_. Body
;;;_ , The variables

(defstruct (org-choose-mark-data. (:type list))
   "The format of an entry in org-choose-mark-data.
Indexes are 0-based or `nil'.
"
   keyword
   bot-lower-range
   top-upper-range
   range-length
   static-default
   all-keywords)

(defvar org-choose-mark-data 
   ()
   "Alist of information for choose marks.

Each entry is an `org-choose-mark-data.'" )
(make-variable-buffer-local 'org-choose-mark-data)
;;;_ , For setup
;;;_  . org-choose-filter-one

(defun org-choose-filter-one (i)
   "Return a list of
 * a canonized version of the string
 * optionally one symbol"

   (if
      (not
	 (string-match "(.*)" i))
      (list i i)
      (let* 
	 (
	    (end-text (match-beginning 0))
	    (vanilla-text (substring i 0 end-text))
	    ;;Get the parenthesized part.
	    (match (match-string 0 i))
	    ;;Remove the parentheses.
	    (args (substring match 1 -1))
	    ;;Split it
	    (arglist
	       (let
		  ((arglist-x (split-string args ",")))
		  ;;When string starts with "," `split-string' doesn't
		  ;;make a first arg, so in that case make one
		  ;;manually.
		  (if 
		     (string-match "^," args)
		     (cons nil arglist-x)
		     arglist-x)))
	    (decision-arg (second arglist))
	    (type
	       (cond
		  ((string= decision-arg "0")
		     'default-mark)
		  ((string= decision-arg "+")
		     'top-upper-range)
		  ((string= decision-arg "-")
		     'bot-lower-range)
		  (t nil)))
	    (vanilla-arg (first arglist))
	    (vanilla-mark
	       (if vanilla-arg
		  (concat vanilla-text "("vanilla-arg")")
		  vanilla-text)))
	 (if type
	    (list vanilla-text vanilla-mark type)
	    (list vanilla-text vanilla-mark)))))

;;;_  . org-choose-setup-vars
(defun org-choose-setup-vars (bot-lower-range top-upper-range
				   static-default num-items all-mark-texts)
   "Add to org-choose-mark-data according to arguments"

   (let*
      (
	 (tail
	    ;;If there's no bot-lower-range or no default, we don't
	    ;;have ranges.
	    (cdr
	       (if (and static-default bot-lower-range)
		  (let*
		     (
			;;If there's no top-upper-range, use the last
			;;item.
			(top-upper-range
			   (or top-upper-range (1- num-items)))
			(lower-range-length 
			   (1+ (- static-default bot-lower-range)))
			(upper-range-length 
			   (- top-upper-range static-default))
			(range-length 
			   (min upper-range-length lower-range-length)))


		     (make-org-choose-mark-data.
			:keyword nil
			:bot-lower-range bot-lower-range
			:top-upper-range top-upper-range
			:range-length    range-length
			:static-default static-default
			:all-keywords all-mark-texts))

		  (make-org-choose-mark-data.
		     :keyword nil
		     :bot-lower-range nil
		     :top-upper-range nil
		     :range-length    nil
		     :static-default (or static-default 0)
		     :all-keywords all-mark-texts)))))

      (dolist (text all-mark-texts)
	 (pushnew (cons text tail)
	    org-choose-mark-data
	    :test
	    #'(lambda (a b)
		 (equal (car a) (car b)))))))




;;;_  . org-choose-filter-tail
(defun org-choose-filter-tail (raw)
   "Return a translation of RAW to vanilla and set appropriate
buffer-local variables. 

RAW is a list of strings representing the input text of a choose
interpretation."
   (let
      ((vanilla-list nil)
	 (all-mark-texts nil)
	 (index 0)
	 bot-lower-range top-upper-range range-length static-default)
      (dolist (i raw)
	 (destructuring-bind
	    (vanilla-text vanilla-mark &optional type)
	    (org-choose-filter-one i)
	    (cond
	       ((eq type 'bot-lower-range)
		  (setq bot-lower-range index))
	       ((eq type 'top-upper-range)
		  (setq top-upper-range index))
	       ((eq type 'default-mark)
		  (setq static-default index)))
	    (incf index)
	    (push vanilla-text all-mark-texts)
	    (push vanilla-mark vanilla-list)))

      (org-choose-setup-vars bot-lower-range top-upper-range
	 static-default index (reverse all-mark-texts)) 
      (nreverse vanilla-list)))

;;;_  . org-choose-setup-filter

(defun org-choose-setup-filter (raw)
   "A setup filter for choose interpretations."
   (when (eq (car raw) 'choose)
      (cons
	 'choose
	 (org-choose-filter-tail (cdr raw)))))

;;;_  . org-choose-conform-after-promotion
(defun org-choose-conform-after-promotion (entry-pos keywords highest-ok-ix)
   ""
   
   (unless
      ;;Skip the entry that triggered this by skipping any entry with
      ;;the same starting position.  Both map and plist use the start
      ;;of the header line as the position, so we can just compare
      ;;them with `='
      (= (point) entry-pos)
      (let
	 ((ix
	     (org-choose-get-entry-index keywords)))
	 ;;If the index of the entry exceeds the highest allowable
	 ;;index, change it to that.
	 (when (and ix 
		  (> ix highest-ok-ix))
	    (org-todo 
	       (nth highest-ok-ix keywords))))))
;;;_  . org-choose-conform-after-demotion
(defun org-choose-conform-after-demotion (entry-pos keywords
					       raise-to-ix
					       old-highest-ok-ix) 
   ""
   (unless
      ;;Skip the entry that triggered this.
      (= (point) entry-pos)
      (let
	 ((ix
	     (org-choose-get-entry-index keywords)))
	 ;;If the index of the entry was at or above the old allowable
	 ;;position, change it to the new mirror position if there is
	 ;;one.
	 (when (and 
		  ix 
		  raise-to-ix
		  (>= ix old-highest-ok-ix))
	    (org-todo 
	       (nth raise-to-ix keywords))))))

;;;_ , org-choose-keep-sensible (the trigger-hook function)
(defun org-choose-keep-sensible (change-plist)
   ""

   (let*
      (  (from (plist-get change-plist :from))
	 (to (plist-get change-plist :to))
	 (entry-pos 
	    (set-marker
	       (make-marker)
	       (plist-get change-plist :position)))
	 (kwd-data
	    (assoc to org-todo-kwd-alist)))
      (when
	 (eq (nth 1 kwd-data) 'choose)
	 (let*
	    (
	       (data
		  (assoc to org-choose-mark-data))
	       (keywords
		  (org-choose-mark-data.-all-keywords data))
	       (old-index
		  (org-choose-get-index-in-keywords
		     from 
		     keywords))
	       (new-index
		  (org-choose-get-index-in-keywords
		     to 
		     keywords))
	       (highest-ok-ix
		  (org-choose-highest-other-ok
		     new-index
		     data))
	       (funcdata
		  (cond
		     ;;The entry doesn't participate in conformance,
		     ;;so give `nil' which does nothing.
		     ((not highest-ok-ix) nil)
		     ;;The entry was created or promoted
		     ((or
			 (not old-index)
			 (> new-index old-index))
			(list
			   #'org-choose-conform-after-promotion
			   entry-pos keywords 
			   highest-ok-ix))
		     (t	;;Otherwise the entry was demoted.
			(let
			   (
			      (raise-to-ix
				 (min
				    highest-ok-ix
				    (org-choose-mark-data.-static-default
				       data)))
			      (old-highest-ok-ix
				 (org-choose-highest-other-ok
				    old-index
				    data)))
			   
			   (list
			      #'org-choose-conform-after-demotion 
			      entry-pos 
			      keywords
			      raise-to-ix
			      old-highest-ok-ix))))))
	    
	    (if funcdata
	       ;;The funny-looking names are to make variable capture
	       ;;unlikely.  (Poor-man's lexical bindings).
	       (destructuring-bind (func-d473 . args-46k) funcdata
		  (let
		     ((map-over-entries
			 (org-choose-get-fn-map-group))
			;;We may call `org-todo', so let various hooks
			;;`nil' so we don't cause loops.
			org-after-todo-state-change-hook
			org-trigger-hook 
			org-blocker-hook 
			org-todo-get-default-hook
			;;Also let this alist `nil' so we don't log
			;;secondary transitions.
			org-todo-log-states)
		     ;;Map over group
		     (funcall map-over-entries
			#'(lambda ()
			     (apply func-d473 args-46k))))))))
      
      ;;Remove the marker
      (set-marker entry-pos nil)))



;;;_ , Getting the default mark
;;;_  . org-choose-get-index-in-keywords
(defun org-choose-get-index-in-keywords (ix all-keywords)
   "Return index of current entry."
   (if ix
      (position ix all-keywords
	 :test #'equal)))

;;;_  . org-choose-get-entry-index
(defun org-choose-get-entry-index (all-keywords)
   "Return index of current entry."

   (let*
      ((state (org-entry-get (point) "TODO")))
      (org-choose-get-index-in-keywords state all-keywords)))

;;;_  . org-choose-get-fn-map-group

(defun org-choose-get-fn-map-group ()
   "Return a function to map over the group"
   
   #'(lambda (fn)
	(save-excursion
	   (outline-up-heading-all 1)
	   (save-restriction
	      (org-map-entries fn nil 'tree)))))

;;;_  . org-choose-get-highest-mark-index

(defun org-choose-get-highest-mark-index (keywords)
   "Get the index of the highest current mark in the group.
If there is none, return 0"

   (let*
      (
	 ;;Func maps over applicable entries.
	 (map-over-entries
	    (org-choose-get-fn-map-group))
	 
	 (indexes-list
	    (remove nil
	       (funcall map-over-entries 
		  #'(lambda ()
		       (org-choose-get-entry-index keywords))))))
      (if
	 indexes-list
	 (apply #'max indexes-list)
	 0)))


;;;_  . org-choose-highest-ok

(defun org-choose-highest-other-ok (ix data)
   ""

   (let
      (		
	 (bot-lower-range
	    (org-choose-mark-data.-bot-lower-range data))
	 (top-upper-range
	    (org-choose-mark-data.-top-upper-range data))
	 (range-length
	    (org-choose-mark-data.-range-length data)))
      (when (and ix bot-lower-range)
	 (let*
	    ((delta
		(- top-upper-range ix)))
	    (unless
	       (< range-length delta)
	       (+ bot-lower-range delta))))))

;;;_  . org-choose-get-default-mark-index

(defun org-choose-get-default-mark-index (data) 
   "Get the index of the default mark in a choose interpretation.

Args are in the same order as the fields of
`org-choose-mark-data.' and have the same meaning."

   (or
      (let
	 ((highest-mark-index
	     (org-choose-get-highest-mark-index
		(org-choose-mark-data.-all-keywords data))))
	 (org-choose-highest-other-ok
	    highest-mark-index data))
      (org-choose-mark-data.-static-default data)))



;;;_  . org-choose-get-mark-N
(defun org-choose-get-mark-N (n data)
   "Get the text of the nth mark in a choose interpretation."
   
   (let*
      ((l (org-choose-mark-data.-all-keywords data)))
      (nth n l)))

;;;_  . org-choose-get-default-mark

(defun org-choose-get-default-mark (new-mark old-mark)
   "Get the default mark IFF in a choose interpretation.
NEW-MARK and OLD-MARK are the text of the new and old marks."

   (let*
      (
	 (old-kwd-data
	    (assoc old-mark org-todo-kwd-alist))
	 (new-kwd-data
	    (assoc new-mark org-todo-kwd-alist))
	 (becomes-choose
	    (and
	       (or
		  (not old-kwd-data)
		  (not
		     (eq (nth 1 old-kwd-data) 'choose)))
	       (eq (nth 1 new-kwd-data) 'choose))))
      (when
	 becomes-choose
	 (let
	    ((new-mark-data
		(assoc new-mark org-choose-mark-data)))
	    (if
	       new-mark
	       (org-choose-get-mark-N
		  (org-choose-get-default-mark-index
		     new-mark-data)
		  new-mark-data)
	       (error "Somehow got an unrecognizable mark"))))))

;;;_ , Setting it all up

(eval-after-load 'org
   (progn
      (add-to-list 'org-todo-setup-filter-hook
	 #'org-choose-setup-filter) 
      (add-to-list 'org-todo-get-default-hook
	 #'org-choose-get-default-mark) 
      (add-to-list 'org-trigger-hook
	 #'org-choose-keep-sensible)
      (add-to-list 'org-todo-interpretation-widgets
	 '(:tag "Choose   (to record decisions)" choose))
      (add-to-list 'org-todo-normal-interpretations 'choose)))



;;;_. Footers
;;;_ , Provides

(provide 'org-choose)

;;;_ * Local emacs vars.
;;;_  + Local variables:
;;;_  + End:

;;;_ , End
;;; org-choose.el ends here

[-- Attachment #4: test-org-choose.el --]
[-- Type: application/octet-stream, Size: 45687 bytes --]

;;;_ test-org-choose.el --- Test code for org-choose

;;;_. Headers
;;;_ , License
;; Copyright (C) 2009  Tom Breton (Tehom)

;; Author: Tom Breton (Tehom) <tehom@localhost.localdomain>
;; Keywords: lisp

;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;;;_ , Commentary:

;; 


;;;_ , Requires

(require 'rtest-define)
(require 'mockbuf)
(require 'el-mock)
(require 'org)
(require 'org-id)
(require 'org-choose)


;;;_. Body
;;;_ , Example files
(defconst test-org-choose:th:examples-dir
   (rtest:expand-filename-by-load-file "examples") 
   "Directory where examples are" )

(rtest:defexample test-org-choose:thd:file-simple
   (expand-file-name "simple.org" 
      test-org-choose:th:examples-dir))
(rtest:defexample test-org-choose:thd:file-w-1-chosen
   (expand-file-name "w-1-chosen.org" 
      test-org-choose:th:examples-dir))
(rtest:defexample test-org-choose:thd:file-nonautomatic
   (expand-file-name "nonautomatic.org" 
      test-org-choose:th:examples-dir))
(rtest:defexample test-org-choose:thd:file-w-2-types
   (expand-file-name "w-2-types.org" 
      test-org-choose:th:examples-dir))
(rtest:defexample test-org-choose:thd:file-w-some-nils
   (expand-file-name "w-some-nils.org" 
      test-org-choose:th:examples-dir))
(rtest:defexample test-org-choose:thd:file-nosibs
   (expand-file-name "no-sibs.org" 
      test-org-choose:th:examples-dir))

(rtest:defexample test-org-choose:thd:nofile-1-list-o-marks
   '("REJECTED" "NOT_CHOSEN" "MAYBE" "LEANING_TOWARDS" "CHOSEN"))

(rtest:defexample test-org-choose:thd:nofile-1-raw-marks
   '(choose "REJECTED" "NOT_CHOSEN" "MAYBE" "LEANING_TOWARDS" "CHOSEN")
   "Raw marks")

(rtest:defexample test-org-choose:thd:nofile-1-output-marks
   '(choose "REJECTED" "NOT_CHOSEN" "MAYBE" "LEANING_TOWARDS" "CHOSEN")
   "Output marks")

(rtest:defexample test-org-choose:thd:nofile-1-setup-args
   (list nil nil nil 5 test-org-choose:thd:nofile-1-list-o-marks)
   "Arguments given to org-choose-setup-vars"
   )

(rtest:defexample test-org-choose:thd:nofile-1-mark-data
   (mapcar 
      #'(lambda (x)
	   (make-org-choose-mark-data.
	      :keyword x
	      :bot-lower-range nil
	      :top-upper-range nil
	      :range-length    nil
	      :static-default 0
	      :all-keywords test-org-choose:thd:nofile-1-list-o-marks))
      
      test-org-choose:thd:nofile-1-list-o-marks)
   
   "The mark data corresponding to nofile-1")

(rtest:defexample test-org-choose:thd:nofile-2-list-o-marks
   '("ZERO" "ONE" "TWO" "THREE" "FOUR" "FIVE" "SIX"))

(rtest:defexample test-org-choose:thd:nofile-2-raw-marks
   '(choose "ZERO" "ONE" "TWO(b)" "THREE(c,-)" "FOUR(d,0)" 
       "FIVE(e,+)" "SIX(,)")
   "Raw marks")


(rtest:defexample test-org-choose:thd:nofile-2-output-marks
   '(choose "ZERO" "ONE" "TWO(b)" "THREE(c)" "FOUR(d)" 
       "FIVE(e)" "SIX")
   "Output marks")
(rtest:defexample test-org-choose:thd:nofile-2-setup-args
   (list 3 5 4 7 test-org-choose:thd:nofile-2-list-o-marks)
   "Arguments given to org-choose-setup-vars"
   )

(rtest:defexample test-org-choose:thd:nofile-2-mark-data
   (mapcar 
      #'(lambda (x)
	   (make-org-choose-mark-data.
	      :keyword x
	      :bot-lower-range 3
	      :top-upper-range 5
	      :range-length    1
	      :static-default    4
	      :all-keywords
	      test-org-choose:thd:nofile-2-list-o-marks))
      
      test-org-choose:thd:nofile-2-list-o-marks)
   
   "The mark data corresponding to nofile example 2")

;;An example of one that's not automatically managed
(rtest:defexample test-org-choose:thd:nofile-3-raw-marks
   '(sequence "ZERO" "ONE" "TWO(b)" "THREE(c)" "FOUR(d)" 
       "FIVE(e)" "SIX")
   "Input marks")

(rtest:defexample test-org-choose:thd:nofile-3-output-marks
   nil
   "Output marks")


;;An example where the top of the range is implicit
(rtest:defexample test-org-choose:thd:nofile-4-list-o-marks
   '("ZERO" "ONE" "TWO" "THREE" "FOUR" "FIVE" "SIX"))

(rtest:defexample test-org-choose:thd:nofile-4-raw-marks
   '(choose "ZERO" "ONE" "TWO(b)" "THREE(c,-)" "FOUR(d,0)" 
       "FIVE(e)" "SIX")
   "Input marks")

(rtest:defexample test-org-choose:thd:nofile-4-setup-args
   (list 3 nil 4 7 test-org-choose:thd:nofile-4-list-o-marks)
   "Arguments given to org-choose-setup-vars")

(rtest:defexample test-org-choose:thd:nofile-4-mark-data
   (mapcar 
      #'(lambda (x)
	   (make-org-choose-mark-data.
	      :keyword x
	      :bot-lower-range 3
	      :top-upper-range 6
	      :range-length    2
	      :static-default    4
	      :all-keywords
	      test-org-choose:thd:nofile-4-list-o-marks))
      test-org-choose:thd:nofile-4-list-o-marks)
   
   "The mark data corresponding to nofile example 2")

(rtest:defexample test-org-choose:thd:nofile-4-kwd-alist
   (mapcar 
      #'(lambda (x)
	   ;;(KEY interpretation head done-word final-done-word)
	   (list x 'choose "ZERO" "SIX" "SIX"))
      test-org-choose:thd:nofile-4-list-o-marks))


(rtest:defexample test-org-choose:thd:file-simple-list-o-marks
   '("REJECTED" "NOT_CHOSEN" "MAYBE" "LEANING_TOWARDS" "CHOSEN"))
(rtest:defexample test-org-choose:thd:file-simple-setup-args
   (list 1 4 2 5 test-org-choose:thd:file-simple-list-o-marks)
   "Arguments given to org-choose-setup-vars"
   )

(rtest:defexample test-org-choose:thd:file-simple-mark-data
   (mapcar 
      #'(lambda (x)
	   (make-org-choose-mark-data.
	      :keyword x
	      :bot-lower-range 1
	      :top-upper-range 4
	      :range-length    2
	      :static-default    2
	      :all-keywords
	      test-org-choose:thd:file-simple-list-o-marks))
      
      test-org-choose:thd:file-simple-list-o-marks)
   
   "The mark data corresponding to file1")
(rtest:defexample test-org-choose:thd:file-simple-high-ix
   3)

(rtest:defexample test-org-choose:thd:file-simple-sib-maybe-id
   "67a7cbba-c78b-47fe-886a-08a80f67e4ab"
   "ID of a sibling")
(rtest:defexample test-org-choose:thd:file-simple-sib-maybe-ix
   2
   "Mark index of that sibling")

(rtest:defexample test-org-choose:thd:file-simple-sib-rejected-id
   "953d4524-f15e-4198-ab33-5769732f51ad"
   "ID of another sibling")

(rtest:defexample test-org-choose:thd:file-simple-sib-leaning-id
   "be01f611-6175-4e40-a3b5-525a9c1e3b4d"
   "ID of another sibling")
(rtest:defexample test-org-choose:thd:file-simple-sib-not-chosen-id
   "b7760ac9-e0bf-41a0-9661-720d42670432"
   "ID of another sibling")

(rtest:defexample test-org-choose:thd:file-simple-parent-id
   "a13a4b6f-02d6-445c-a38e-7e51b9ba29d4"
   "ID of the parent of those nodes")
(rtest:defexample test-org-choose:thd:file-simple-original-marks
   '("MAYBE""REJECTED""LEANING_TOWARDS""NOT_CHOSEN"))



(rtest:defexample test-org-choose:thd:file-w-1-chosen-mark-data
   test-org-choose:thd:file-simple-mark-data)
(rtest:defexample test-org-choose:thd:file-w-1-chosen-high-ix
   4)
(rtest:defexample test-org-choose:thd:file-w-1-chosen-sib-not-chosen-a-id
   "b390f9b1-57d0-4a17-9811-47b49fee196f"
   "ID of a not-chosen sibling")
(rtest:defexample test-org-choose:thd:file-w-1-chosen-sib-maybe-id
   "5a449704-494c-412f-b21d-8ffe07b8092c"
   "ID of another not-chosen sibling")
(rtest:defexample test-org-choose:thd:file-w-1-chosen-sib-chosen-id
   "c0958364-1f99-4dfc-a671-f21bb5f708bb"
   "ID of the chosen sibling")
(rtest:defexample test-org-choose:thd:file-w-1-chosen-parent-id
   "b2a6f78c-6199-461b-9850-18980b85b1ab")
(rtest:defexample test-org-choose:thd:file-w-1-chosen-list-o-marks
   test-org-choose:thd:file-simple-list-o-marks)

(rtest:defexample test-org-choose:thd:file-w-1-chosen-original-marks
   '("NOT_CHOSEN" "REJECTED" "CHOSEN " "MAYBE"))

(rtest:defexample test-org-choose:thd:file-nonautomatic-list-o-marks
   '("NO" "MAYBE_YN" "YES"))
(rtest:defexample test-org-choose:thd:file-nonautomatic-raw-marks
   '(choose "NO" "MAYBE_YN(,0)" "YES"))

(rtest:defexample test-org-choose:thd:file-nonautomatic-setup-args
   (list nil nil 1 3 test-org-choose:thd:file-nonautomatic-list-o-marks)
   "Arguments given to org-choose-setup-vars")
(rtest:defexample test-org-choose:thd:file-nonautomatic-high-ix
   2)

(rtest:defexample test-org-choose:thd:file-nonautomatic-sib-yes-id
   "6a27cc97-6e65-4c4e-9014-7fbcf27f52fa")

(rtest:defexample test-org-choose:thd:file-nonautomatic-mark-data
   (mapcar 
      #'(lambda (x)
	   (make-org-choose-mark-data.
	      :keyword x
	      :bot-lower-range nil
	      :top-upper-range nil
	      :range-length    nil
	      :static-default    1
	      :all-keywords
	      test-org-choose:thd:file-nonautomatic-list-o-marks)
	   )
      test-org-choose:thd:file-nonautomatic-list-o-marks)
   
   "The mark data corresponding to file3")

(rtest:defexample test-org-choose:thd:context:kwd-alist-normal-todo
   (mapcar 
      #'(lambda (x)
	   ;;(KEY interpretation head done-word final-done-word)
	   (list x 'sequence "TODO" "DONE" "DONE"))
      '("TODO" "DONE"))

   "A kwd-alist that includes only the 2 normal TODO marks.
NB, this is context.  It is not *produced* by any test code, it is
used to control what marks are understood."
   )


(rtest:defexample test-org-choose:thd:context:kwd-alist
   (append
      test-org-choose:thd:context:kwd-alist-normal-todo
      (mapcar 
      #'(lambda (x)
       ;;(KEY interpretation head done-word final-done-word)
	   (list x 'choose  "NO" "YES" "YES"))
	 test-org-choose:thd:file-nonautomatic-list-o-marks))
   
   "A kwd-alist to combines 2 normal TODO marks and the
file-nonautomatic marks.
NB, this is not *produced* by any test code, it is used to control
what marks are understood."
   )

(rtest:defexample test-org-choose:thd:context:kwd-alist-simple

   (append
      test-org-choose:thd:context:kwd-alist-normal-todo
      (mapcar 
	 #'(lambda (x)
	      ;;(KEY interpretation head done-word final-done-word)
	      (list x 'choose "REJECTED" "CHOSEN" "CHOSEN"))
	 test-org-choose:thd:file-simple-list-o-marks))

   "A kwd-alist that includes the marks in simple.org plus 2 normal TODO marks.
NB, this is context.  It is not *produced* by any test code, it is
used to control what marks are understood."
   )


(rtest:defexample test-org-choose:thd:file-w-2-types-mark-data
   (append
      test-org-choose:thd:file-simple-mark-data
      test-org-choose:thd:file-nonautomatic-mark-data))

(rtest:defexample test-org-choose:thd:file-w-2-types-t1-high-ix
   3)

(rtest:defexample test-org-choose:thd:file-w-2-types-t1-leaning-id
   "c8e7d7af-15a2-4650-a604-50ade52bd06c")
(rtest:defexample test-org-choose:thd:file-w-2-types-t1-list-o-marks
   '("REJECTED" "NOT_CHOSEN" "MAYBE" "LEANING_TOWARDS" "CHOSEN"))

(rtest:defexample test-org-choose:thd:file-w-2-types-t2-high-ix
   2)

(rtest:defexample test-org-choose:thd:file-w-2-types-t2-yes-id
   "02e917f5-ac3d-477f-baf5-7eb7c8961683")
(rtest:defexample test-org-choose:thd:file-w-2-types-t2-list-o-marks
   '("YES" "MAYBE_YN" "NO"))

(rtest:defexample test-org-choose:thd:file-w-some-nils-high-ix
   4)

(rtest:defexample test-org-choose:thd:file-w-some-nils-sib-marked-id
   "a4e52131-1145-49f5-8b4b-dc4264900a05")

(rtest:defexample test-org-choose:thd:file-w-some-nils-sib-nil-id
   "d9729468-db22-4870-8969-9500da63d560")
(rtest:defexample test-org-choose:thd:file-w-some-nils-list-o-marks
   '("REJECTED" "NOT_CHOSEN" "MAYBE" "LEANING_TOWARDS" "CHOSEN"))

(rtest:defexample test-org-choose:thd:file-nosibs-sib
   "78fb63fa-4fad-4c7f-aa4a-954ee3431754")
(rtest:defexample test-org-choose:thd:file-nosibs-high-ix
   0)

;;;_ , Tests of org-choose-filter-one

(rtest:defexample test-org-choose:thd:singlemark-1-input-output
   '("ONE(,0)" ("ONE" "ONE" default-mark))
   "Pairs of single marks: Input and output"
   )


(rtest:defexample test-org-choose:thd:singlemark-2-input-output
   '("TWO" ("TWO" "TWO"))
   "Pairs of single marks: Input and output"
   )


(rtest:defexample test-org-choose:thd:singlemark-3-input-output
   '("THREE(b)" ("THREE" "THREE(b)"))
   "Pairs of single marks: Input and output")


(rtest:defexample test-org-choose:thd:singlemark-4-input-output
   '("FOUR(c,0)" ("FOUR" "FOUR(c)" default-mark))
   "Pairs of single marks: Input and output")

(rtest:defexample test-org-choose:thd:singlemark-5-input-output
   '("FIVE(d,+)" ("FIVE" "FIVE(d)" top-upper-range))
   "Pairs of single marks: Input and output")

(rtest:defexample test-org-choose:thd:singlemark-6-input-output
   '("SIX(e,-)" ("SIX" "SIX(e)" bot-lower-range))
   "Pairs of single marks: Input and output")

(rtest:defexample test-org-choose:thd:singlemark-7-input-output
   '("SEVEN(,)" ("SEVEN" "SEVEN"))
   "Pairs of single marks: Input and output")

(rtest:defexample test-org-choose:thd:singlemark-8-input-output
   '("EIGHT(x!/@,)" ("EIGHT" "EIGHT(x!/@)"))
   "Pairs of single marks: Input and output")

(rtest:deftest org-choose-filter-one

   (  "Does the examples correctly."
      (equal
	 (org-choose-filter-one 
	    (car test-org-choose:thd:singlemark-1-input-output))
	 (second
	    test-org-choose:thd:singlemark-1-input-output)))
   
   (  "Does the examples correctly."
      (equal
	 (org-choose-filter-one 
	    (car test-org-choose:thd:singlemark-2-input-output))
	 (second
	    test-org-choose:thd:singlemark-2-input-output)))
   
   (  "Does the examples correctly."
      (equal
	 (org-choose-filter-one 
	    (car test-org-choose:thd:singlemark-3-input-output))
	 (second
	    test-org-choose:thd:singlemark-3-input-output)))
   (  "Does the examples correctly."
      (equal
	 (org-choose-filter-one 
	    (car test-org-choose:thd:singlemark-4-input-output))
	 (second
	    test-org-choose:thd:singlemark-4-input-output)))
   (  "Does the examples correctly."
      (equal
	 (org-choose-filter-one 
	    (car test-org-choose:thd:singlemark-5-input-output))
	 (second
	    test-org-choose:thd:singlemark-5-input-output)))
   (  "Does the examples correctly."
      (equal
	 (org-choose-filter-one 
	    (car test-org-choose:thd:singlemark-6-input-output))
	 (second
	    test-org-choose:thd:singlemark-6-input-output)))
   (  "Does the examples correctly."
      (equal
	 (org-choose-filter-one 
	    (car test-org-choose:thd:singlemark-7-input-output))
	 (second
	    test-org-choose:thd:singlemark-7-input-output)))
      (  "Does the examples correctly."
	 (equal
	    (org-choose-filter-one 
	       (car test-org-choose:thd:singlemark-8-input-output))
	    (second
	       test-org-choose:thd:singlemark-8-input-output)))
   )
;;;_ , Tests of org-choose-setup-vars

(rtest:deftest org-choose-setup-vars

   (  "The `*-setup-args' examples are proper args to
`org-choose-setup-vars'.  It sets org-choose-mark-data
correspondingly."
      (with-temp-buffer
	 (apply #'org-choose-setup-vars
	    test-org-choose:thd:nofile-1-setup-args)
	 
	 (rtest:sets=
	    org-choose-mark-data
	    test-org-choose:thd:nofile-1-mark-data)))

   (  "The `*-setup-args' examples are proper args to
`org-choose-setup-vars'.  It sets org-choose-mark-data
correspondingly."
      (with-temp-buffer
	 (apply #'org-choose-setup-vars
	    test-org-choose:thd:nofile-2-setup-args)
	 
	 (rtest:sets=
	    org-choose-mark-data
	    test-org-choose:thd:nofile-2-mark-data)))

   (  "The `*-setup-args' examples are proper args to
`org-choose-setup-vars'.  It sets org-choose-mark-data
correspondingly."
      (with-temp-buffer
	 (apply #'org-choose-setup-vars
	    test-org-choose:thd:nofile-4-setup-args)
	 
	 (rtest:sets=
	    org-choose-mark-data
	    test-org-choose:thd:nofile-4-mark-data)))

   (  "The `*-setup-args' examples are proper args to
`org-choose-setup-vars'.  It sets org-choose-mark-data
correspondingly."
      (with-temp-buffer
	 (apply #'org-choose-setup-vars
	    test-org-choose:thd:file-simple-setup-args)
	 
	 (rtest:sets=
	    org-choose-mark-data
	    test-org-choose:thd:file-simple-mark-data)))      
   (  "The `*-setup-args' examples are proper args to
`org-choose-setup-vars'.  It sets org-choose-mark-data
correspondingly."
      (with-temp-buffer
	 (apply #'org-choose-setup-vars
	    test-org-choose:thd:file-nonautomatic-setup-args)
	 
	 (rtest:sets=
	    org-choose-mark-data
	    test-org-choose:thd:file-nonautomatic-mark-data)))   
   )

;;;_ , Tests of the setup filter

(rtest:deftest org-choose-setup-filter

   ;;I'd like to have also tested that output is conformant.  But
   ;;AFAICT no existing predicate reports that, so I'll only test that
   ;;output matches what's expected, which I'll eyeball.

   (  "Situation: Called manually, passed data with another interpretation.
Response: Return value is `nil'."
      (equal
	 (with-temp-buffer
	    (org-choose-setup-filter
	       test-org-choose:thd:nofile-3-raw-marks))
	 test-org-choose:thd:nofile-3-output-marks))

   (  "Situation: Called manually, passed known data.
Response: Return value is as expected."
      (equal
	 (with-temp-buffer
	    (org-choose-setup-filter
	       test-org-choose:thd:nofile-1-raw-marks))
	 test-org-choose:thd:nofile-1-output-marks))

   (  "Situation: Called manually, passed known data.
Response: Return value is as expected."
      (equal
	 (with-temp-buffer
	    (org-choose-setup-filter
	       test-org-choose:thd:nofile-2-raw-marks))
	 test-org-choose:thd:nofile-2-output-marks))


   (  "Situation: Called manually, passed known data.
Response: Variables have been set up as expected."

      (with-temp-buffer
	 (org-choose-setup-filter
	    test-org-choose:thd:nofile-1-raw-marks)
	 (rtest:sets=
	    org-choose-mark-data
	    test-org-choose:thd:nofile-1-mark-data)))

   (  "Situation: Called manually, passed known data.
Response: Variables have been set up as expected."

      (with-temp-buffer
	 (org-choose-setup-filter
	    test-org-choose:thd:nofile-2-raw-marks)
	 (rtest:sets=
	    org-choose-mark-data
	    test-org-choose:thd:nofile-2-mark-data)))

   (  "Situation: Called manually, passed known data.
Response: Variables have been set up as expected."

      (with-temp-buffer
	 (org-choose-setup-filter
	    test-org-choose:thd:nofile-4-raw-marks)
	 (rtest:sets=
	    org-choose-mark-data
	    test-org-choose:thd:nofile-4-mark-data)))

   (  "Situation: In temp buffer, given the same marks as for file 3.
Response: `org-choose-mark-data' have been set up as expected."
      (with-temp-buffer
	 (org-choose-setup-filter
	    test-org-choose:thd:file-nonautomatic-raw-marks)
	 (rtest:sets=
	    org-choose-mark-data
	    test-org-choose:thd:file-nonautomatic-mark-data)))

   (  "Situation: `org-choose-mark-data' has already been set with
marks from this set
Response: `org-choose-mark-data' gets the expected value and
nothing extra."
      (with-temp-buffer
	 (let
	    ((org-choose-mark-data
		test-org-choose:thd:file-nonautomatic-mark-data))
	    (org-choose-setup-filter
	       test-org-choose:thd:file-nonautomatic-raw-marks)
	    (rtest:sets=
	       org-choose-mark-data
	       test-org-choose:thd:file-nonautomatic-mark-data))))
   
   (  "Situation: `org-choose-mark-data' has already been set with
marks from another set
Response: `org-choose-mark-data' gets the new marks and keeps the
marks from the other set."
      (with-temp-buffer
	 (let
	    ((org-choose-mark-data
		test-org-choose:thd:file-simple-mark-data))
	    (org-choose-setup-filter
	       test-org-choose:thd:file-nonautomatic-raw-marks)
	    (rtest:sets=
	       org-choose-mark-data
	       (append
		  test-org-choose:thd:file-simple-mark-data
		  test-org-choose:thd:file-nonautomatic-mark-data)))))
   
   ;;Insinuated tests, so that setup filter is called automatically by
   ;;setup.

   (  "Situation: In example file 1.
Response: `org-choose-mark-data' gets the expected value."
      (with-buffer-containing-object (:file test-org-choose:thd:file-simple)
	 (rtest:sets=
	    org-choose-mark-data
	    test-org-choose:thd:file-simple-mark-data)))
   
   (  "Situation: In example file 2.
Response: `org-choose-mark-data' gets the expected value."
      (with-buffer-containing-object (:file test-org-choose:thd:file-w-1-chosen)
	 (rtest:sets=
	    org-choose-mark-data
	    test-org-choose:thd:file-w-1-chosen-mark-data)))

   (  "Situation: In example file 3.
Response: `org-choose-mark-data' gets the expected value."
      (with-buffer-containing-object (:file test-org-choose:thd:file-nonautomatic)

	 (rtest:sets=
	    org-choose-mark-data
	    test-org-choose:thd:file-nonautomatic-mark-data)))

   (  "Situation: In example file 4.
Response: `org-choose-mark-data' gets the expected value."
      (with-buffer-containing-object (:file test-org-choose:thd:file-w-2-types)

	 (rtest:sets=
	    org-choose-mark-data
	    test-org-choose:thd:file-w-2-types-mark-data))))


;;;_ , Tests of the function to get default
;;;_  . Test helper

;;;_    . org-choose:th:in-buffer-at

(defmacro* org-choose:th:in-buffer-at ((&key file id) &rest body)
   ""
   
   `(with-buffer-containing-object
       (:file ,file)
       ;;Have to show entries otherwise we might fail to go to them.
       (show-all)
       ;;Go to one of the entries.  Use `org-find-entry-with-id' so we
       ;;can't accidentally leave this file, as we could with
       ;;`org-id-find'.
       (goto-char
	  (org-find-entry-with-id ,id)) 
       ,@body))

;;;_     , Tests

(put 'org-choose:th:in-buffer-at 'rtest:test-thru
   'org-choose-get-entry-index)

;;;_  . org-choose-get-entry-index
(rtest:deftest org-choose-get-entry-index
   ;;These tests are tests after insinuation.
   (  "Situation: Point is in a marked entry.
Response: Return the index of that entry."
      (org-choose:th:in-buffer-at
	 (:file test-org-choose:thd:file-simple 
	    :id test-org-choose:thd:file-simple-sib-maybe-id)
	 
	 (equal
	    (org-choose-get-entry-index 
	       test-org-choose:thd:file-simple-list-o-marks)
	    test-org-choose:thd:file-simple-sib-maybe-ix)))
   
   
   (  "Situation: Point is in a unmarked entry (nil).
Response: Return nil."
      (org-choose:th:in-buffer-at
	 (:file test-org-choose:thd:file-w-some-nils
	    :id test-org-choose:thd:file-w-some-nils-sib-nil-id)
	 
	 (equal
	    (org-choose-get-entry-index 
	       test-org-choose:thd:file-w-some-nils-list-o-marks)
	    nil)))
   
   (  "Situation: Point is in an entry with a mark from a different set.
Response: Return nil."
      (org-choose:th:in-buffer-at 
	 (:file test-org-choose:thd:file-w-2-types
	    :id test-org-choose:thd:file-w-2-types-t2-yes-id)
	 
	 (equal
	    (org-choose-get-entry-index 
	       test-org-choose:thd:file-w-2-types-t1-list-o-marks)
	    nil)))
      
   )
;;;_  . org-choose-get-highest-mark-index
(rtest:deftest org-choose-get-highest-mark-index

   (  "Situation: Point is in one of the sibling entries
Response: Returns the highest index."
      (org-choose:th:in-buffer-at 
	 (:file test-org-choose:thd:file-simple
	    :id test-org-choose:thd:file-simple-sib-maybe-id)
	 (equal
	    (org-choose-get-highest-mark-index
	       test-org-choose:thd:file-simple-list-o-marks)
	    test-org-choose:thd:file-simple-high-ix)))
   
   (  "Situation: Point is in a different one of the sibling entries
Response: Returns the highest index."
      (org-choose:th:in-buffer-at 
	 (:file test-org-choose:thd:file-simple
	    :id test-org-choose:thd:file-simple-sib-rejected-id)
	 (equal
	    (org-choose-get-highest-mark-index
	       test-org-choose:thd:file-simple-list-o-marks)
	    test-org-choose:thd:file-simple-high-ix)))

   (  "Situation: Point is in one of the sibling entries
Response: Returns the highest index."
      (org-choose:th:in-buffer-at 
	 (:file test-org-choose:thd:file-w-1-chosen
	    :id test-org-choose:thd:file-w-1-chosen-sib-not-chosen-a-id)
	 (equal
	    (org-choose-get-highest-mark-index
	       test-org-choose:thd:file-w-1-chosen-list-o-marks)
	    test-org-choose:thd:file-w-1-chosen-high-ix)))
   
   (  "Situation: Point is in one of the sibling entries
Response: Returns the highest index."
      (org-choose:th:in-buffer-at 
	 (:file test-org-choose:thd:file-nonautomatic
	    :id test-org-choose:thd:file-nonautomatic-sib-yes-id)
	 (equal
	    (org-choose-get-highest-mark-index
	       test-org-choose:thd:file-nonautomatic-list-o-marks)
	    test-org-choose:thd:file-nonautomatic-high-ix)))


   (  "Situation: Point is in one of the sibling entries of one type.
Response: Returns the highest index of siblings of that type, ignoring
the others."
      (org-choose:th:in-buffer-at 
	 (:file test-org-choose:thd:file-w-2-types
	    :id test-org-choose:thd:file-w-2-types-t1-leaning-id)
	 (equal
	    (org-choose-get-highest-mark-index
	       test-org-choose:thd:file-w-2-types-t1-list-o-marks)
	    test-org-choose:thd:file-w-2-types-t1-high-ix)))
   

   (  "Situation: Point is in one of the sibling entries of one type,
in a sibling group that has 2 types.
Response: Returns the highest index of siblings of that type, ignoring
the others."
      (org-choose:th:in-buffer-at 
	 (:file test-org-choose:thd:file-w-2-types
	    :id test-org-choose:thd:file-w-2-types-t2-yes-id)
	 (equal
	    (org-choose-get-highest-mark-index
	       test-org-choose:thd:file-w-2-types-t2-list-o-marks)
	    test-org-choose:thd:file-w-2-types-t2-high-ix)))


   (  "Situation: Point is in one of the sibling entries.  Some
entries are nil. 
Response: Returns the highest index, ignoring the `nil's."
      (org-choose:th:in-buffer-at 
	 (:file test-org-choose:thd:file-w-some-nils
	    :id test-org-choose:thd:file-w-some-nils-sib-marked-id)
	 (equal
	    (org-choose-get-highest-mark-index
	       test-org-choose:thd:file-w-some-nils-list-o-marks)
	    test-org-choose:thd:file-w-some-nils-high-ix)))

   ( "Situation: There are no entries of choose type.
Response: Return 0"
      (org-choose:th:in-buffer-at 
	 (:file test-org-choose:thd:file-nosibs
	    :id test-org-choose:thd:file-nosibs-sib)
	 (equal
	    (org-choose-get-highest-mark-index
	       test-org-choose:thd:file-simple-list-o-marks)
	    0)))
   
   )

;;;_  . org-choose-get-default-mark-index
(put 'org-choose-get-default-mark-index 'rtest:test-thru
   'org-choose-get-default-mark)
;;;_  . org-choose-get-mark-N
(rtest:deftest org-choose-get-mark-N
   
   (  "Behavior: Gets the corresponding mark from the set."
      (let
	 ((org-choose-mark-data 
	     test-org-choose:thd:nofile-4-mark-data))
	 (equal
	    (org-choose-get-mark-N 0
	       (assoc "ONE" org-choose-mark-data))
	    "ZERO")))

   (  "Behavior: Gets the corresponding mark from the set."
      (let
	 ((org-choose-mark-data 
	     test-org-choose:thd:nofile-4-mark-data))
	 (equal
	    (org-choose-get-mark-N 4
	       (assoc "THREE" org-choose-mark-data))
	    "FOUR")))
   )

;;;_  . org-choose-get-default-mark

;;;_   , Test helpers
(defun org-choose-get-default-mark-index:th (new-mark mark-data)
   "Test helper"

   (org-choose-get-default-mark-index
      (assoc new-mark mark-data)))
(defun org-choose:th:collect-childrens-todo-marks (parent-id)
   ""
   
   (save-excursion
      (show-all) ;;In case anything got hidden
      (goto-char
	 (org-find-entry-with-id
	    parent-id))
      (save-restriction
	 (org-map-entries 
	    #'(lambda ()
		 (org-entry-get (point) "TODO"))
	    nil 'tree))))
;;;_    . Tests of org-choose:th:collect-childrens-todo-marks
(rtest:deftest org-choose:th:collect-childrens-todo-marks
   ("Situation: In a known file.
Param: The id of the parent entry.
Response: Returns the TODO marks of the children."
      (with-buffer-containing-object 
	 (:file test-org-choose:thd:file-simple)
	 (equal
	    (org-choose:th:collect-childrens-todo-marks
	       test-org-choose:thd:file-simple-parent-id)
	    test-org-choose:thd:file-simple-original-marks))))


;;;_   , Tests

(rtest:deftest org-choose-get-default-mark

   (  "Situation: we're not going into a choose type
Response: Return nil, signalling to use the mark we were going to."
      (let
	 ((org-todo-kwd-alist
	     test-org-choose:thd:context:kwd-alist))
	 (equal
	    (org-choose-get-default-mark nil "DONE")
	    nil)))

   (  "Situation: We were already in a choose type.
Response: Return nil, signalling to use the mark we were going to."
      (let
	 ((org-todo-kwd-alist
	     test-org-choose:thd:context:kwd-alist))
	 (equal
	    (org-choose-get-default-mark "YES" "MAYBE_YN")
	    nil)))

   
   ;;These tests test the index return for
   ;;`org-choose-get-default-mark-index' and also test the string
   ;;return for `org-choose-get-default-mark'.  Combining the tests
   ;;under `and' is not good style but I don't want to write each
   ;;setup twice.

   (  "Situation: there are no ranges.
Response: return the static default."
      (let
	 ((org-choose-mark-data 
	     test-org-choose:thd:file-nonautomatic-mark-data)
	    (org-todo-kwd-alist
	       test-org-choose:thd:context:kwd-alist))
	 
	 (with-mock
	    (stub org-choose-get-highest-mark-index => nil)
	    (and
	       (equal 
		  (org-choose-get-default-mark-index:th "NO"
		     test-org-choose:thd:file-nonautomatic-mark-data)
		  1)
 	       (equal
 		  (org-choose-get-default-mark "NO" nil)
 		  "MAYBE_YN")))))
   
   ( "Situation: no current mark is in the upper range.
Response: return the static default."
      (let
	 ((org-choose-mark-data 
	     test-org-choose:thd:nofile-4-mark-data)
	    (org-todo-kwd-alist
	       test-org-choose:thd:nofile-4-kwd-alist))
	 (with-mock
	    (stub org-choose-get-highest-mark-index => 2)
	    (and
	       (equal 
		  (org-choose-get-default-mark-index:th 
		     "ONE"
		     test-org-choose:thd:nofile-4-mark-data)
		  4)
 	       (equal
 		  (org-choose-get-default-mark "ONE" nil)
 		  "FOUR")
	       ))))


   ;;Because the static default is at or above the top of lower range,
   ;;any mirror-wise constraint is a stronger constraint than it.  So
   ;;no additional test is needed for the interaction between those
   ;;two constraints.

   ( "Situation: a current mark is in the upper range.
Response: return an accordingly lower index.."
      (let
	 ((org-choose-mark-data 
	     test-org-choose:thd:nofile-4-mark-data)
	    (org-todo-kwd-alist
	       test-org-choose:thd:nofile-4-kwd-alist))
	 (with-mock
	    (stub org-choose-get-highest-mark-index => 6)
	    (and
	       (equal 
		  (org-choose-get-default-mark-index:th 
		     "ONE"
		     test-org-choose:thd:nofile-4-mark-data)
		  3)
 	       (equal
 		  (org-choose-get-default-mark "ONE" nil)
 		  "THREE")))))


   ("Situation: Point is on a heading.  
The only type of TODO in this buffer is a choose type.
The default type is MAYBE.
No sibling mark is higher than LEANING_TOWARDS.
Operation: Add a new todo heading.
Result: It then has the mark MAYBE."

      (org-choose:th:in-buffer-at
	 (:file test-org-choose:thd:file-simple
	    :id test-org-choose:thd:file-simple-sib-maybe-id)
	 (org-insert-todo-heading 1)

	 (equal
	    (org-entry-get (point) "TODO")
	    "MAYBE")))
   
   ("Situation: Point is on a heading with no mark.
The only type of TODO in this buffer is a choose type.
The default type is MAYBE.
No sibling mark is higher than LEANING_TOWARDS.
Operation: Add a todo mark to the heading.
Result: It then has the mark MAYBE."

      (org-choose:th:in-buffer-at
	 (:file test-org-choose:thd:file-simple
	    :id test-org-choose:thd:file-simple-sib-maybe-id) 
	 (org-insert-heading)

	 
	 (org-todo)
	 
	 (equal
	    (org-entry-get (point) "TODO")
	    "MAYBE")))
   
   
   ("Situation: Point is on a heading.  
The only type of TODO in this buffer is a choose type.
The default type is MAYBE.
A sibling mark is CHOSEN
The mark NOT_CHOSEN mirrors the mark CHOSEN.
Operation: Add a todo mark to the heading.
Result: It then has the mark NOT_CHOSEN."

      (org-choose:th:in-buffer-at
	 (:file test-org-choose:thd:file-w-1-chosen
	    :id test-org-choose:thd:file-w-1-chosen-sib-not-chosen-a-id) 
	 (org-insert-heading)

	 (org-todo)

	 (equal
	    (org-entry-get (point) "TODO")
	    "NOT_CHOSEN"))))


;;;_ , Tests of the trigger function

;;;_  . org-choose-conform-after-promotion

;;;_   , Test helper

(defun* org-choose-conform-after-promotion:th (&key file id
						    mark-data 
						    other-was
						    other-changed-to
						    expect
						    demoted)
   ""
   (org-choose:th:in-buffer-at
      (:file file :id id) 
      (let*
	 (
	    (data
	       (or
		  (assoc other-changed-to mark-data)
		  (error
		     "Mark-data should contain the entry being changed to")))
	    
	    (keywords
	       (org-choose-mark-data.-all-keywords data))
	    
	    (index
	       (org-choose-get-index-in-keywords
		  other-changed-to keywords))
	    (old-index
	       (when other-was
		  (org-choose-get-index-in-keywords
		     other-was keywords))))
	 
	 (if demoted
	    (org-choose-conform-after-demotion
	       0 ;;Fake position that matches nothing
	       keywords
	       (let
		  ((new-highest 
		      (org-choose-highest-other-ok index data))
		     (static-default
			(org-choose-mark-data.-static-default data)))
		  (if new-highest
		     (min new-highest static-default)
		     static-default))
	       (org-choose-highest-other-ok old-index data))
	    
	    (org-choose-conform-after-promotion 
	       0 ;;Fake position that matches nothing
	       keywords
	       (org-choose-highest-other-ok index data))))

      (equal
	 (org-entry-get (point) "TODO")
	 expect)))


;;;_   , Tests
(rtest:deftest org-choose-conform-after-promotion

   (  "Situation: Entry's mark is from some other workflow state.
Response: Do nothing."
      (org-choose-conform-after-promotion:th 
	 :file test-org-choose:thd:file-w-2-types
	 :id test-org-choose:thd:file-w-2-types-t2-yes-id
	 :mark-data test-org-choose:thd:file-w-2-types-mark-data
	 :other-changed-to "CHOSEN"
	 :expect "YES"))

   (  "Situation: Entry's mark is already lower than the highest allowed index.
Response: No change."
      (org-choose-conform-after-promotion:th 
	 :file test-org-choose:thd:file-simple
	 :id test-org-choose:thd:file-simple-sib-rejected-id
	 :mark-data test-org-choose:thd:file-simple-mark-data
	 :other-changed-to "CHOSEN"
	 :expect "REJECTED"))


   (  "Situation: Entry's mark is higher than the highest allowed index.
Response: Demote it."
      (org-choose-conform-after-promotion:th 
	 :file test-org-choose:thd:file-simple
	 :id test-org-choose:thd:file-simple-sib-leaning-id
	 :mark-data test-org-choose:thd:file-simple-mark-data
	 :other-changed-to "LEANING_TOWARDS"
	 :expect "MAYBE"))
   )
;;;_  . org-choose-conform-after-demotion

;;;_   , Tests
(rtest:deftest org-choose-conform-after-demotion

   (  "Situation: The other entry was not keeping this node below the default.
Response: This node is unchanged."
      (org-choose-conform-after-promotion:th 
	 :file test-org-choose:thd:file-simple
	 :id test-org-choose:thd:file-simple-sib-maybe-id
	 :mark-data test-org-choose:thd:file-simple-mark-data
	 :other-was "LEANING_TOWARDS"
	 :other-changed-to "MAYBE"
	 :demoted t
	 :expect "MAYBE"))
   
   (  "Situation: The other entry was keeping this node below the default.
Response: This node is promoted."
      (org-choose-conform-after-promotion:th 
	 :file test-org-choose:thd:file-simple
	 :id test-org-choose:thd:file-simple-sib-maybe-id
	 :mark-data test-org-choose:thd:file-simple-mark-data
	 :other-was "LEANING_TOWARDS"
	 :other-changed-to "CHOSEN"
	 :demoted t
	 :expect "NOT_CHOSEN"))
   
   (  "Situation: The other entry was keeping this node below the
default.  It was just demoted quite low.
Response: This node is promoted only to the default."
      (org-choose-conform-after-promotion:th 
	 :file test-org-choose:thd:file-simple
	 :id test-org-choose:thd:file-simple-sib-not-chosen-id
	 :mark-data test-org-choose:thd:file-simple-mark-data
	 :other-was "CHOSEN"
	 :other-changed-to "REJECTED"
	 :demoted t
	 :expect "MAYBE"))

   )


;;;_  . org-choose-keep-sensible
;;;_   , Helper
(defun* org-choose-keep-sensible:th:manual (&key from to)
   ""
   
   (let
      (org-blocker-hook)
      (org-todo to)
      (org-choose-keep-sensible
	 (list
	    :from from
	    :to to
	    :position (point-at-bol)))))

;;;_   , Tests

(rtest:deftest org-choose-keep-sensible

   ;;Non-insinuated tests, `org-choose-keep-sensible' is just
   ;;called manually.
   (  "Operation: An entry's todo mark is changed into a TODO from
some other workflow state. 
Response: No change to our entries."
      (org-choose:th:in-buffer-at
	 (:file test-org-choose:thd:file-simple
	    :id test-org-choose:thd:file-simple-sib-rejected-id) 
	 (let
	    ((org-todo-kwd-alist
		test-org-choose:thd:context:kwd-alist-simple))
	    (org-choose-keep-sensible:th:manual 
	       :from "RESPONSE:" :to "NOT_CHOSEN"))	 
	 
	 (equal
	    (org-choose:th:collect-childrens-todo-marks
	       test-org-choose:thd:file-simple-parent-id)
	    '("MAYBE""NOT_CHOSEN""LEANING_TOWARDS""NOT_CHOSEN"))))
   

   (  "Operation: An entry is promoted, but not high enough to cause
inconsistent state.
Response: It gets promoted.  Other nodes keep their values"
      (org-choose:th:in-buffer-at
	 (:file test-org-choose:thd:file-simple
	    :id test-org-choose:thd:file-simple-sib-rejected-id) 

	 (org-choose-keep-sensible:th:manual 
	    :from "RESPONSE:" :to "NOT_CHOSEN")	 
	 
	 (equal
	    (org-choose:th:collect-childrens-todo-marks
	       test-org-choose:thd:file-simple-parent-id)
	    '("MAYBE""NOT_CHOSEN""LEANING_TOWARDS""NOT_CHOSEN"))))
   

   (  "Operation: An entry is promoted high enough to cause
inconsistent state.  Leaning_towards becomes Chosen.
Response: It gets promoted.  Other nodes are demoted just enough to
keep the state consistent."
      (org-choose:th:in-buffer-at
	 (:file test-org-choose:thd:file-simple
	    :id test-org-choose:thd:file-simple-sib-leaning-id) 

	 
	 (org-choose-keep-sensible:th:manual 
	    :from "LEANING_TOWARDS" :to "CHOSEN")
	 
	 (equal
	    (org-choose:th:collect-childrens-todo-marks
	       test-org-choose:thd:file-simple-parent-id)
	    '("NOT_CHOSEN""REJECTED""CHOSEN""NOT_CHOSEN"))))


   (  "Operation: An entry is promoted high enough to cause
inconsistent state.  Rejected becomes Leaning_towards.
Response: It gets promoted.  Other nodes are demoted just enough to
keep the state consistent."
      (org-choose:th:in-buffer-at
	 (:file test-org-choose:thd:file-simple
	    :id test-org-choose:thd:file-simple-sib-rejected-id) 
	 
	 (org-choose-keep-sensible:th:manual 
	    :from "REJECTED" :to "LEANING_TOWARDS")
	 
	 (equal
	    (org-choose:th:collect-childrens-todo-marks
	       test-org-choose:thd:file-simple-parent-id)
	    '("MAYBE""LEANING_TOWARDS""MAYBE""NOT_CHOSEN"))))
   

   (  "Situation: An entry was medium-high-marked; it's not high
enough to be keeping other nodes down below the default.
Operation: That entry is demoted one place.  LEANING_TOWARDS becomes MAYBE.
Response: It gets demoted.  Other nodes are unchanged."
      (org-choose:th:in-buffer-at
	 (:file test-org-choose:thd:file-simple
	    :id test-org-choose:thd:file-simple-sib-leaning-id) 
	 
	 (org-choose-keep-sensible:th:manual 
	    :from "LEANING_TOWARDS" :to "MAYBE")
	 
	 (equal
	    (org-choose:th:collect-childrens-todo-marks
	       test-org-choose:thd:file-simple-parent-id)
	    '("MAYBE""REJECTED""MAYBE""NOT_CHOSEN"))))
   
   (  "Situation: An entry was high-marked, holding other nodes below
the top of the low range. 
Operation: That entry is demoted one place.  CHOSEN becomes LEANING_TOWARDS.
Response: It gets demoted.  Nodes that it was holding down are
promoted. NOT_CHOSEN becomes MAYBE."
      (org-choose:th:in-buffer-at
	 (:file test-org-choose:thd:file-w-1-chosen
	    :id test-org-choose:thd:file-w-1-chosen-sib-chosen-id) 
	 
	 (org-choose-keep-sensible:th:manual 
	    :from "CHOSEN" :to "LEANING_TOWARDS")
	 
	 (equal
	    (org-choose:th:collect-childrens-todo-marks
	       test-org-choose:thd:file-w-1-chosen-parent-id)
	    '( "MAYBE" "REJECTED" "LEANING_TOWARDS" "MAYBE"))))
   

   (  "Situation: An entry was high-marked, holding other nodes below
the top of the low range. 
Operation: That entry is demoted two places.  CHOSEN becomes MAYBE.
Response: It gets demoted.  Nodes that it was holding down are
promoted as if by two one-place operations.
NOT_CHOSEN becomes MAYBE."
      (org-choose:th:in-buffer-at
	 (:file test-org-choose:thd:file-w-1-chosen
	    :id test-org-choose:thd:file-w-1-chosen-sib-chosen-id) 
	 
	 (org-choose-keep-sensible:th:manual 
	    :from "CHOSEN" :to "MAYBE")
	 
	 (equal
	    (org-choose:th:collect-childrens-todo-marks
	       test-org-choose:thd:file-w-1-chosen-parent-id)
	    '("MAYBE" "REJECTED" "MAYBE" "MAYBE"))))

   ;;No tests for the situation where a node is demoted to the middle
   ;;of the upper range and should both potentially raise some others
   ;;and lower some others.  It's unlikely to be an important
   ;;situation.  YAGNI.


   ;;Tests of org-choose after having been insinuated

   ;;Implicit operations of `org-todo'
   (  "Operation: An entry is implicitly promoted.
Response: It gets promoted to the next value."
      (org-choose:th:in-buffer-at
	 (:file test-org-choose:thd:file-simple
	    :id test-org-choose:thd:file-simple-sib-rejected-id) 
	 
	 (org-todo)
	 (equal
	    (org-entry-get (point) "TODO")
	    "NOT_CHOSEN")))

   (  "Operation: An entry is implicitly promoted, but not high enough to cause
inconsistent state.
Response: It gets promoted.  Other nodes keep their values"
      (org-choose:th:in-buffer-at
	 (:file test-org-choose:thd:file-simple
	    :id test-org-choose:thd:file-simple-sib-rejected-id) 
	 
	 (org-todo)
	 (equal
	    (org-choose:th:collect-childrens-todo-marks
	       test-org-choose:thd:file-simple-parent-id)
	    '("MAYBE""NOT_CHOSEN""LEANING_TOWARDS""NOT_CHOSEN"))))

   ;;Tests that operations still behave after insinuation the same as
   ;;they did manually.
   (  "Operation: An entry is explicitly promoted, but not high enough to cause
inconsistent state.
Response: It gets promoted.  Other nodes keep their values"
      (org-choose:th:in-buffer-at
	 (:file test-org-choose:thd:file-simple
	    :id test-org-choose:thd:file-simple-sib-rejected-id) 
	 
	 (org-todo "NOT_CHOSEN")
	 
	 (equal
	    (org-choose:th:collect-childrens-todo-marks
	       test-org-choose:thd:file-simple-parent-id)
	    '("MAYBE""NOT_CHOSEN""LEANING_TOWARDS""NOT_CHOSEN"))))
   

   (  "Operation: An entry is promoted high enough to cause
inconsistent state.  Leaning_towards becomes Chosen.
Response: It gets promoted.  Other nodes are demoted just enough to
keep the state consistent."
      (org-choose:th:in-buffer-at
	 (:file test-org-choose:thd:file-simple
	    :id test-org-choose:thd:file-simple-sib-leaning-id) 
	 
	 (org-todo "CHOSEN")
	 
	 (equal
	    (org-choose:th:collect-childrens-todo-marks
	       test-org-choose:thd:file-simple-parent-id)
	    '("NOT_CHOSEN""REJECTED""CHOSEN""NOT_CHOSEN"))))

   (  "Operation: An entry is promoted high enough to cause
inconsistent state.  Rejected becomes Leaning_towards.
Response: It gets promoted.  Other nodes are demoted just enough to
keep the state consistent."
      (org-choose:th:in-buffer-at
	 (:file test-org-choose:thd:file-simple
	    :id test-org-choose:thd:file-simple-sib-rejected-id) 
	 
	 (org-todo "LEANING_TOWARDS")
	 
	 (equal
	    (org-choose:th:collect-childrens-todo-marks
	       test-org-choose:thd:file-simple-parent-id)
	    '("MAYBE""LEANING_TOWARDS""MAYBE""NOT_CHOSEN"))))
   

   (  "Situation: An entry was medium-high-marked; it's not high
enough to be keeping other nodes down below the default.
Operation: That entry is demoted one place.  LEANING_TOWARDS becomes MAYBE.
Response: It gets demoted."
      (org-choose:th:in-buffer-at
	 (:file test-org-choose:thd:file-simple
	    :id test-org-choose:thd:file-simple-sib-leaning-id) 
	 
	 (org-todo "MAYBE")
	 
	 (equal
	    (org-choose:th:collect-childrens-todo-marks
	       test-org-choose:thd:file-simple-parent-id)
	    '("MAYBE""REJECTED""MAYBE""NOT_CHOSEN"))))
   
   (  "Situation: An entry was high-marked, holding other nodes below
the top of the low range. 
Operation: That entry is demoted one place.  CHOSEN becomes LEANING_TOWARDS.
Response: It gets demoted.  Nodes that it was holding down are
promoted. NOT_CHOSEN becomes MAYBE."
      (org-choose:th:in-buffer-at
	 (:file test-org-choose:thd:file-w-1-chosen
	    :id test-org-choose:thd:file-w-1-chosen-sib-chosen-id) 
	 
	 (org-todo "LEANING_TOWARDS")
	 
	 (equal
	    (org-choose:th:collect-childrens-todo-marks
	       test-org-choose:thd:file-w-1-chosen-parent-id)
	    '( "MAYBE" "REJECTED" "LEANING_TOWARDS" "MAYBE"))))
   

   (  "Situation: An entry was high-marked, holding other nodes below
the top of the low range. 
Operation: That entry is demoted two places.  CHOSEN becomes MAYBE.
Response: It gets demoted.  Nodes that it was holding down are
promoted as if by two one-place operations.
NOT_CHOSEN becomes MAYBE."
      (org-choose:th:in-buffer-at
	 (:file test-org-choose:thd:file-w-1-chosen
	    :id test-org-choose:thd:file-w-1-chosen-sib-chosen-id) 
	 
	 (org-todo "MAYBE")
	 
	 (equal
	    (org-choose:th:collect-childrens-todo-marks
	       test-org-choose:thd:file-w-1-chosen-parent-id)
	    '("MAYBE" "REJECTED" "MAYBE" "MAYBE"))))
   )




;;;_. Footers
;;;_ , Provides

(provide 'test-org-choose)

;;;_ * Local emacs vars.
;;;_  + Local variables:
;;;_  + End:

;;;_ , End
;;; test-org-choose.el ends here

[-- Attachment #5: Type: text/plain, Size: 204 bytes --]

_______________________________________________
Emacs-orgmode mailing list
Remember: use `Reply All' to send replies to the list.
Emacs-orgmode@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-orgmode

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Advice sought on managing decision alternatives.
  2009-02-07 20:46                 ` Tom Breton (Tehom)
@ 2009-02-08 13:06                   ` Carsten Dominik
  2009-02-08 20:25                     ` Tom Breton (Tehom)
  0 siblings, 1 reply; 56+ messages in thread
From: Carsten Dominik @ 2009-02-08 13:06 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode

Hi Tom,

I have now added org-choose.el, it is part of the current git status.

A few comments:

On Feb 7, 2009, at 9:46 PM, Tom Breton (Tehom) wrote:

>
> Hi, Carsten.  Here is the new patch to org.el and the new
> org-choose.el
>
> A couple of notes:
>
> * As we talked about, "decisions" and "chosenness" are now called
>   "choose" everywhere.

Great.

>
> * I was able to add the library-aware customization we talked about.

This is nice, I earned something new! :convert-widget.....

>
> * I also added new variable `org-todo-normal-interpretations' - see
>   explanation below.

See my comments below

>
> * New test file.  Essentially the same, with name replacement.

I have not run the tests myself yet.

>
> * Didn't append the example files; they are all unchanged from before.
>
> ******* About `org-todo-normal-interpretations'
>
> You said your idea was to make a generally useful system.  I noticed
> that one thing was still hard-coded.  It's the part of org-todo that
> finds the next entry:
>
> 	(memq interpret '(sequence choose))
> 	...
> 	(memq interpret '(type priority))

Yes, this is correct.  I appreciate you noticing this additional
point where changes have to be made.
However, for now I have opted for a different solution:  I made the
sequence interpretation the last test in the cond chain, so that
all interpretations that are not `type' will fall back to this  
mechanism.
I envision that we can add another hook if someone wants an additional
way of handling this.  I would like to minimize the number of variables
where an add-on has to insert itself.

I have commented the corresponding line which tries to add to the
non-existing variable org-todo-normal-interpretations' in org-choose.el

I hope you agree with this solution, if not let me know.

I think what is missing now is documentation.  It seems to me that
there should be some minimal documentation in org-choose.el,
and it would be great to get a tutorial on Worg which describes
this in more detail.

Thanks a lot for this contribution, and for your precision and
attention to detail.

- Carsten

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Advice sought on managing decision alternatives.
  2009-02-08 13:06                   ` Carsten Dominik
@ 2009-02-08 20:25                     ` Tom Breton (Tehom)
  2009-02-09  6:42                       ` Carsten Dominik
  0 siblings, 1 reply; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-02-08 20:25 UTC (permalink / raw)
  To: Carsten Dominik; +Cc: emacs-orgmode, Tom Breton

> Hi Tom,
>
> I have now added org-choose.el, it is part of the current git status.
>
> A few comments:
>
[...]
> Yes, this is correct.  I appreciate you noticing this additional
> point where changes have to be made.
> However, for now I have opted for a different solution:  I made the
> sequence interpretation the last test in the cond chain, so that
> all interpretations that are not `type' will fall back to this
> mechanism.

Great, that's better than my solution.




>
> I think what is missing now is documentation.  It seems to me that
> there should be some minimal documentation in org-choose.el,
> and it would be great to get a tutorial on Worg which describes
> this in more detail.

What sort of format are you looking for?


[From other email]
> I also changed the call to add to the interpretation types
> for the widget so that it appends its value to the list,
> rather than adding to the front.  Hope you agree,
> I made this change right in contrib/lisp/org-choose.el

Good.  It occurred to me shortly after I sent the file that it would be
better to append.

Tom Breton (Tehom)

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Advice sought on managing decision alternatives.
  2009-02-08 20:25                     ` Tom Breton (Tehom)
@ 2009-02-09  6:42                       ` Carsten Dominik
  2009-02-10  3:14                         ` Docs submitted (Was Re: Advice sought on managing decision alternatives.) Tom Breton (Tehom)
  0 siblings, 1 reply; 56+ messages in thread
From: Carsten Dominik @ 2009-02-09  6:42 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode

Hi Tom,

On Feb 8, 2009, at 9:25 PM, Tom Breton (Tehom) wrote:
>>
>> I think what is missing now is documentation.  It seems to me that
>> there should be some minimal documentation in org-choose.el,
>> and it would be great to get a tutorial on Worg which describes
>> this in more detail.
>
> What sort of format are you looking for?

Well, some ASCII documentation could be inserted into org-choose.el
as a file commentary.  If you use a standard header with keywords
for the finder (M-x finder-commentary and friends), that would be  
useful.

Tutorials on Worg are usually written in Org, but you can upload
any format you like (or send it it me) and we wil publish it there.

- Carsten

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Docs submitted (Was Re: Advice sought on managing decision alternatives.)
  2009-02-09  6:42                       ` Carsten Dominik
@ 2009-02-10  3:14                         ` Tom Breton (Tehom)
  2009-02-10  7:55                           ` Carsten Dominik
  2009-02-10  8:46                           ` Docs submitted (Was Re: Advice sought on managing decision alternatives.) Manish
  0 siblings, 2 replies; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-02-10  3:14 UTC (permalink / raw)
  Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 534 bytes --]

Hi, Carsten.

> Well, some ASCII documentation could be inserted into org-choose.el
> as a file commentary.  If you use a standard header with keywords
> for the finder (M-x finder-commentary and friends), that would be
> useful.
>
> Tutorials on Worg are usually written in Org, but you can upload
> any format you like (or send it it me) and we wil publish it there.

OK, I've add comments, keywords, and some docstrings I forgot to
org-choose.el, and I wrote a standalone doc.  Both are attached.

Tom Breton (Tehom)

[-- Attachment #2: docs.org-choose.el.diff --]
[-- Type: application/octet-stream, Size: 5874 bytes --]

*** old-org-choose.el	2009-02-09 18:25:51.000000000 -0500
--- org-choose.el	2009-02-09 20:47:47.000000000 -0500
***************
*** 5,11 ****
  ;; Copyright (C) 2009  Tom Breton (Tehom)
  
  ;; Author: Tom Breton (Tehom)
! ;; Keywords: 
  
  ;; This file is free software; you can redistribute it and/or modify
  ;; it under the terms of the GNU General Public License as published by
--- 5,11 ----
  ;; Copyright (C) 2009  Tom Breton (Tehom)
  
  ;; Author: Tom Breton (Tehom)
! ;; Keywords: outlines, convenience
  
  ;; This file is free software; you can redistribute it and/or modify
  ;; it under the terms of the GNU General Public License as published by
***************
*** 24,29 ****
--- 24,64 ----
  
  ;;;_ , Commentary:
  
+ ;; This is code to support decision management.  It lets you treat a
+ ;; group of sibling items in org-mode as alternatives in a decision.
+ 
+ ;; There are no user commands in this file.  You use it by:
+ ;;   * Loading it (manually or by M-x customize-apropos org-modules)
+ 
+ ;;   * Setting up at least one set of TODO keywords with the
+ ;;     interpretation "choose" by either:
+ 
+ ;;     * Using the file directive #+CHOOSE_TODO:
+ 
+ ;;       * For instance, "#+CHOOSE_TODO: NO(,-) MAYBE(,0) YES"
+ 
+ ;;     * Or by M-x customize-apropos org-todo-keywords
+ 
+ ;;   * Operating on single items with the TODO commands.
+ 
+ ;;     * Use C-S-right to change the keyword set.  Use this to change to
+ ;;       the "choose" keyword set that you just defined.
+ 
+ ;;     * Use S-right to advance the TODO mark to the next setting.  
+ 
+ ;;       For "choose", that means you like this alternative more than
+ ;;       before.  Other alternatives will be automatically demoted to
+ ;;       keep your settings consistent.
+ 
+ ;;     * Use S-left to demote TODO to the previous setting.  
+ 
+ ;;       For "choose", that means you don't like this alternative as much
+ ;;       as before.  Other alternatives will be automatically promoted,
+ ;;       if this item was all that was keeping them down.
+ 
+ ;;     * All the other TODO commands are available and behave essentially
+ ;;       the normal way.
+ 
  ;;;_ , Requires
  
  (require 'org)
***************
*** 194,200 ****
  
  ;;;_  . org-choose-conform-after-promotion
  (defun org-choose-conform-after-promotion (entry-pos keywords highest-ok-ix)
!    ""
     
     (unless
        ;;Skip the entry that triggered this by skipping any entry with
--- 229,235 ----
  
  ;;;_  . org-choose-conform-after-promotion
  (defun org-choose-conform-after-promotion (entry-pos keywords highest-ok-ix)
!    "Conform the current item after another item was promoted"
     
     (unless
        ;;Skip the entry that triggered this by skipping any entry with
***************
*** 215,221 ****
  (defun org-choose-conform-after-demotion (entry-pos keywords
  					       raise-to-ix
  					       old-highest-ok-ix) 
!    ""
     (unless
        ;;Skip the entry that triggered this.
        (= (point) entry-pos)
--- 250,256 ----
  (defun org-choose-conform-after-demotion (entry-pos keywords
  					       raise-to-ix
  					       old-highest-ok-ix) 
!    "Conform the current item after another item was demoted"
     (unless
        ;;Skip the entry that triggered this.
        (= (point) entry-pos)
***************
*** 232,240 ****
  	    (org-todo 
  	       (nth raise-to-ix keywords))))))
  
! ;;;_ , org-choose-keep-sensible (the trigger-hook function)
  (defun org-choose-keep-sensible (change-plist)
!    ""
  
     (let*
        (  (from (plist-get change-plist :from))
--- 267,276 ----
  	    (org-todo 
  	       (nth raise-to-ix keywords))))))
  
! ;;;_ , org-choose-keep-sensible (the org-trigger-hook function)
  (defun org-choose-keep-sensible (change-plist)
!    "Bring the other items back into a sensible state after an item's
! setting was changed."
  
     (let*
        (  (from (plist-get change-plist :from))
***************
*** 327,340 ****
  ;;;_ , Getting the default mark
  ;;;_  . org-choose-get-index-in-keywords
  (defun org-choose-get-index-in-keywords (ix all-keywords)
!    "Return index of current entry."
     (if ix
        (position ix all-keywords
  	 :test #'equal)))
  
  ;;;_  . org-choose-get-entry-index
  (defun org-choose-get-entry-index (all-keywords)
!    "Return index of current entry."
  
     (let*
        ((state (org-entry-get (point) "TODO")))
--- 363,376 ----
  ;;;_ , Getting the default mark
  ;;;_  . org-choose-get-index-in-keywords
  (defun org-choose-get-index-in-keywords (ix all-keywords)
!    "Return the index of IX in ALL-KEYWORDS."
     (if ix
        (position ix all-keywords
  	 :test #'equal)))
  
  ;;;_  . org-choose-get-entry-index
  (defun org-choose-get-entry-index (all-keywords)
!    "Return the index of the current entry."
  
     (let*
        ((state (org-entry-get (point) "TODO")))
***************
*** 377,383 ****
  ;;;_  . org-choose-highest-ok
  
  (defun org-choose-highest-other-ok (ix data)
!    ""
  
     (let
        (		
--- 413,421 ----
  ;;;_  . org-choose-highest-ok
  
  (defun org-choose-highest-other-ok (ix data)
!    "Return the highest index that any choose mark can sensibly have,
! given that another mark has index IX.
! DATA must be a `org-choose-mark-data.'."
  
     (let
        (		
***************
*** 398,407 ****
  ;;;_  . org-choose-get-default-mark-index
  
  (defun org-choose-get-default-mark-index (data) 
!    "Get the index of the default mark in a choose interpretation.
  
! Args are in the same order as the fields of
! `org-choose-mark-data.' and have the same meaning."
  
     (or
        (let
--- 436,444 ----
  ;;;_  . org-choose-get-default-mark-index
  
  (defun org-choose-get-default-mark-index (data) 
!    "Return the index of the default mark in a choose interpretation.
  
! DATA must be a `org-choose-mark-data.'."
  
     (or
        (let

[-- Attachment #3: docs.org-choose-docs.org --]
[-- Type: application/octet-stream, Size: 4966 bytes --]

* Org-choose

Org-choose supports decision management.

** General 

org-choose operates on a group of sibling items in org-mode.  It
treats them as potential choices in some decision.

The items have marks such as "CHOSEN", "MAYBE", or "REJECTED".  You
can configure the set of marks.  The marks behave similarly to TODO
marks.  org-choose keeps the marks in a consistent overall state.

A sibling item that has no mark is assumed to not represent an
alternative; so is an item with a mark from another keyword set.

** How to use it

*** Overview of use

org-choose contains no user commands.  You use it by:

  * Loading it

  * Setting up at least one set of TODO keywords with the
    interpretation "choose".

  * Operating on single items with the TODO commands.

*** Loading it (No surprises here)

The easiest way is by 

	M-x customize-apropos org-modules

Scroll down to "External packages" at the end of the list.  Insert a
new one, and fill in "org-choose".  This will cause it to be loaded
every time you start org-mode.

You'll still have to load it manually the first time.

Of course, you can also just try it out by loading it manually.

*** Setting up a keyword set

To use org-choose, you need to set up at least one set of TODO
keywords with the interpretation "choose".  There are two basic ways.
Both are essentially the same as for other TODO marks.

    * By using the file directive #+CHOOSE_TODO: 

    * By M-x customize-apropos org-todo-keywords

**** The markings

The format of marks is essentially that of ordinary TODO marks.  The
marks can have parenthesized arguments that indicate key bindings and
similar shortcuts.

In addition, they can optionally have a second argument.  The
arguments are separated by a comma.  The second argument can have one
of 3 values:

 * 0 :: The mark with this argument is the default mark.  New items
        will have that mark, if they are from this TODO keyword set.

 * - :: This mark with this argument is at the bottom of the "NOT
        CHOSEN" range (See [[id:3698439c-93d5-4242-b566-96e760f64108][About consistent state]]).  It should be
        lower than the default mark (0). If this is omitted,
        org-choose will not try to keep marks in consistent state.

 * + :: This mark with this argument is at the top of the "CHOSEN"
        range.  It should be higher than the default mark (0). If this
        is omitted, org-choose will use the highest mark instead.

No value should be given twice.

This works even if there is no first argument; just give an empty
string as the first argument.

***** Examples of marks

 * REJECTED :: Makes a mark whose text is "REJECTED".
 * MAYBE(,0) :: Makes a mark whose text is "MAYBE".  It is the default
                mark.
 * CHOSEN(c,+) :: Makes a mark whose text is "CHOSEN".  It is the top
                  of the high range.  The key "c" will select it,
                  exactly as the usual TODO hotkey behavior.

**** Examples of mark specs

 * #+CHOOSE_TODO: NO(,-) MAYBE(,0) YES
 * #+CHOOSE_TODO: REJECTED(r) NOT_CHOSEN(n,-) MAYBE(,0) LEANING_TOWARDS(l) CHOSEN(c,+)

*** Operating on items

You can operate on single items with the usual TODO commands.

    * Use C-S-right to change the keyword set.  Use this to change to
      the "choose" keyword set that you just defined.

    * Use S-right to advance the TODO mark to the next setting.  

      For "choose", that means you like this alternative more than
      before.  Other alternatives will be automatically demoted to
      keep your settings consistent.

    * Use S-left to demote TODO to the previous setting.  

      For "choose", that means you don't like this alternative as much
      as before.  Other alternatives will be automatically promoted,
      if this item was all that was keeping them down.

    * All the other TODO commands are available and behave essentially
      the normal way.



** About consistent state
   :PROPERTIES:
   :ID:       3698439c-93d5-4242-b566-96e760f64108
   :END:

org-choose tries to keep each group of items in a consistent state.

It knows about 2 ranges of marks that relate to each other in mirror
image fashion.  We can call them the "CHOSEN" range and the "NOT
CHOSEN" range.

If some item is marked in the "CHOSEN" range, other items can't be
marked higher than the mirror-corresponding entry in the "NOT CHOSEN"
range.

*** An example

For this example, assume we're using the marks from the second example
spec,

	"REJECTED(r) NOT_CHOSEN(n,-) MAYBE(,0) LEANING_TOWARDS(l)
	CHOSEN(c,+)"

Then org-choose enforces the following constraints:

| If any   |   | then the other |   |
| item is: |   | items can't be |   |
|          |   | higher than:   |   |
|----------+---+----------------+---|
| CHOSEN   | 1 | NOT CHOSEN     | 4 |
| FAVORED  | 2 | MAYBE          | 3 |
|----------+---+----------------+---|


** Credits

org-choose was written by Tom Breton, with much-appreciated advice
from Carsten Dominik.


[-- Attachment #4: Type: text/plain, Size: 204 bytes --]

_______________________________________________
Emacs-orgmode mailing list
Remember: use `Reply All' to send replies to the list.
Emacs-orgmode@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-orgmode

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing decision alternatives.)
  2009-02-10  3:14                         ` Docs submitted (Was Re: Advice sought on managing decision alternatives.) Tom Breton (Tehom)
@ 2009-02-10  7:55                           ` Carsten Dominik
  2009-02-24  0:51                             ` org-choose bugfix Tom Breton (Tehom)
  2009-02-10  8:46                           ` Docs submitted (Was Re: Advice sought on managing decision alternatives.) Manish
  1 sibling, 1 reply; 56+ messages in thread
From: Carsten Dominik @ 2009-02-10  7:55 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode

Hi Tom,

it looks like efficiency is *not* one of your problems.
Thanks a lot for getting this done so quickly.

I have just released Org-mode 6.22 which included org-choose.el.

As for the documentation, I have made some minor layout
changes (turned the level-1 heading into a title,
and promoted the level-2 headings).  I also modified
the "Loading it" section to reflect the fact that org-module
now has a checkbox for this package.

The resulting file is up on Worg at

http://orgmode.org/worg/org-contrib/org-choose.php

If you ever want to change anything in that document, just do
it yourself, in Worg.

Thanks for your contribution!

- Carsten



On Feb 10, 2009, at 4:14 AM, Tom Breton (Tehom) wrote:

> Hi, Carsten.
>
>> Well, some ASCII documentation could be inserted into org-choose.el
>> as a file commentary.  If you use a standard header with keywords
>> for the finder (M-x finder-commentary and friends), that would be
>> useful.
>>
>> Tutorials on Worg are usually written in Org, but you can upload
>> any format you like (or send it it me) and we wil publish it there.
>
> OK, I've add comments, keywords, and some docstrings I forgot to
> org-choose.el, and I wrote a standalone doc.  Both are attached.
>
> Tom Breton (Tehom)
> <docs.org-choose.el.diff><docs.org-choose-docs.org>

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing decision alternatives.)
  2009-02-10  3:14                         ` Docs submitted (Was Re: Advice sought on managing decision alternatives.) Tom Breton (Tehom)
  2009-02-10  7:55                           ` Carsten Dominik
@ 2009-02-10  8:46                           ` Manish
  2009-02-10  9:12                             ` Carsten Dominik
  2009-02-10 22:45                             ` Tom Breton (Tehom)
  1 sibling, 2 replies; 56+ messages in thread
From: Manish @ 2009-02-10  8:46 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode

On Tue, Feb 10, 2009 at 8:44 AM, Tom Breton (Tehom) wrote:
[...]
> OK, I've add comments, keywords, and some docstrings I forgot to
> org-choose.el, and I wrote a standalone doc. Both are attached.

This is very intriguing functionality.  I tried to follow your and Casten's
earlier exchanges but could understand only a little.  So I tried to follow
your tutorial but I am getting stuck at switching the `choosenness' of items.
I get following error when I try to switch to any state from "no state".  Once
I assign a state by typing it out manually (as opposed to using state
switching commands), I can then switch between states but the error repeats
when I try to switch to "MAYBE" state.

,----
| save-excursion: Symbol's function definition is void: outline-up-heading-all
`----

And the test file:

--8<---------------cut here---------------start------------->8---
#+CHOOSE_TODO: NO(n,-) MAYBE(m,0) YES(y,+)

* Which bike to buy?
*** Ducati
*** Honda
*** Kawasaki
--8<---------------cut here---------------end--------------->8---

So far, my understaning is that only one item can be in "YES" state.  If I try
to switch another item to "YES" then the existing "YES" will be demoted
to "MAYBE".  So for a two-state choosenness only one item can be in CHOOSE
state while all others will switch to NOT_CHOOSEN state.. is that
understanding correct?

Thanks again.
-- 
Manish

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing decision alternatives.)
  2009-02-10  8:46                           ` Docs submitted (Was Re: Advice sought on managing decision alternatives.) Manish
@ 2009-02-10  9:12                             ` Carsten Dominik
  2009-02-10 10:26                               ` Manish
  2009-02-10 23:19                               ` Docs submitted (Was Re: Advice sought on managing decision alternatives.) Tom Breton (Tehom)
  2009-02-10 22:45                             ` Tom Breton (Tehom)
  1 sibling, 2 replies; 56+ messages in thread
From: Carsten Dominik @ 2009-02-10  9:12 UTC (permalink / raw)
  To: Manish; +Cc: emacs-orgmode, Tom Breton (Tehom)


On Feb 10, 2009, at 9:46 AM, Manish wrote:

> On Tue, Feb 10, 2009 at 8:44 AM, Tom Breton (Tehom) wrote:
> [...]
>> OK, I've add comments, keywords, and some docstrings I forgot to
>> org-choose.el, and I wrote a standalone doc. Both are attached.
>
> This is very intriguing functionality.  I tried to follow your and  
> Casten's
> earlier exchanges but could understand only a little.  So I tried to  
> follow
> your tutorial but I am getting stuck at switching the `choosenness'  
> of items.
> I get following error when I try to switch to any state from "no  
> state".  Once
> I assign a state by typing it out manually (as opposed to using state
> switching commands), I can then switch between states but the error  
> repeats
> when I try to switch to "MAYBE" state.
>
> ,----
> | save-excursion: Symbol's function definition is void: outline-up- 
> heading-all
> `----

Hmm, not sure if I messed up there - so I fixed this bug.  Tom,
please check if I did this right.

- Carsten

>
>
> And the test file:
>
> --8<---------------cut here---------------start------------->8---
> #+CHOOSE_TODO: NO(n,-) MAYBE(m,0) YES(y,+)
>
> * Which bike to buy?
> *** Ducati
> *** Honda
> *** Kawasaki
> --8<---------------cut here---------------end--------------->8---
>
> So far, my understaning is that only one item can be in "YES"  
> state.  If I try
> to switch another item to "YES" then the existing "YES" will be  
> demoted
> to "MAYBE".  So for a two-state choosenness only one item can be in  
> CHOOSE
> state while all others will switch to NOT_CHOOSEN state.. is that
> understanding correct?
>
> Thanks again.
> -- 
> Manish
>
>
> _______________________________________________
> Emacs-orgmode mailing list
> Remember: use `Reply All' to send replies to the list.
> Emacs-orgmode@gnu.org
> http://lists.gnu.org/mailman/listinfo/emacs-orgmode

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing decision alternatives.)
  2009-02-10  9:12                             ` Carsten Dominik
@ 2009-02-10 10:26                               ` Manish
  2009-02-10 22:48                                 ` Tom Breton (Tehom)
                                                   ` (2 more replies)
  2009-02-10 23:19                               ` Docs submitted (Was Re: Advice sought on managing decision alternatives.) Tom Breton (Tehom)
  1 sibling, 3 replies; 56+ messages in thread
From: Manish @ 2009-02-10 10:26 UTC (permalink / raw)
  To: Carsten Dominik; +Cc: emacs-orgmode, Tom Breton (Tehom)

On Tue, Feb 10, 2009 at 2:42 PM, Carsten Dominik wrote:
>
> On Feb 10, 2009, at 9:46 AM, Manish wrote:
>
>> On Tue, Feb 10, 2009 at 8:44 AM, Tom Breton (Tehom) wrote:
>> [...]
>>>
>>> OK, I've add comments, keywords, and some docstrings I forgot to
>>> org-choose.el, and I wrote a standalone doc. Both are attached.
>>
>> This is very intriguing functionality. I tried to follow your and
>> Casten's
>> earlier exchanges but could understand only a little. So I tried to
>> follow
>> your tutorial but I am getting stuck at switching the `choosenness' of
>> items.
>> I get following error when I try to switch to any state from "no state".
>> Once
>> I assign a state by typing it out manually (as opposed to using state
>> switching commands), I can then switch between states but the error
>> repeats
>> when I try to switch to "MAYBE" state.
>>
>> ,----
>> | save-excursion: Symbol's function definition is void:
>> outline-up-heading-all
>> `----
>
> Hmm, not sure if I messed up there - so I fixed this bug. Tom,
> please check if I did this right.

This issue is gone for me.  Thanks.

>> So far, my understaning is that only one item can be in "YES" state. If I
>> try
>> to switch another item to "YES" then the existing "YES" will be demoted
>> to "MAYBE". So for a two-state choosenness only one item can be in CHOOSE
>> state while all others will switch to NOT_CHOOSEN state.. is that
>> understanding correct?

With three choices for choosenness, it works as I expected (only one item in
CHOSEN state at a time) but for more choices like:

#+CHOOSE_TODO: REJECTED(r) NOT_CHOSEN(n,-) MAYBE(,0)
LEANING_TOWARDS(l) CHOSEN(c,+)

it allows multiple items to be in CHOSEN state.  How do we interpret that?

-- 
Manish

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing   decision alternatives.)
  2009-02-10  8:46                           ` Docs submitted (Was Re: Advice sought on managing decision alternatives.) Manish
  2009-02-10  9:12                             ` Carsten Dominik
@ 2009-02-10 22:45                             ` Tom Breton (Tehom)
  1 sibling, 0 replies; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-02-10 22:45 UTC (permalink / raw)
  To: Manish; +Cc: emacs-orgmode

> On Tue, Feb 10, 2009 at 8:44 AM, Tom Breton (Tehom) wrote:
> [...]
>> OK, I've add comments, keywords, and some docstrings I forgot to
>> org-choose.el, and I wrote a standalone doc. Both are attached.
>
> This is very intriguing functionality.  I tried to follow your and
> Casten's
> earlier exchanges but could understand only a little.  So I tried to
> follow
> your tutorial but I am getting stuck at switching the `choosenness' of
> items.
> I get following error when I try to switch to any state from "no state".
> Once
> I assign a state by typing it out manually (as opposed to using state
> switching commands), I can then switch between states but the error
> repeats
> when I try to switch to "MAYBE" state.
>
> ,----
> | save-excursion: Symbol's function definition is void:
> outline-up-heading-all
> `----

I couldn't reproduce this bug with your test file.

It seemed to have to do with loading, so I restarted emacs without
pre-loading org (ie, I commented it out of my .emacs).  I only found a
dependency on org-agenda, and once that was loaded, no more error.  So I
couldn't reproduce it.


> So far, my understaning is that only one item can be in "YES" state.  If I
> try
> to switch another item to "YES" then the existing "YES" will be demoted
> to "MAYBE".

Right.

> So for a two-state choosenness only one item can be in CHOOSE
> state while all others will switch to NOT_CHOOSEN state.. is that
> understanding correct?

Hm, I didn't look at sets with just two states.  Now that I look at it,
yes, that works but not in the best way it could.  Because I never
contemplated "0" and "-" being properties of the same mark, it has to be
speced as something like:

        #+CHOOSE_TODO: NO(n,-) YES(y,0)

Tom Breton (Tehom)

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing   decision alternatives.)
  2009-02-10 10:26                               ` Manish
@ 2009-02-10 22:48                                 ` Tom Breton (Tehom)
  2009-02-12 12:50                                   ` Manish
  2009-02-11  1:08                                 ` Tom Breton (Tehom)
  2009-02-11  1:45                                 ` Slight fix to update-org.sh Tom Breton (Tehom)
  2 siblings, 1 reply; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-02-10 22:48 UTC (permalink / raw)
  To: Manish; +Cc: emacs-orgmode, Tom Breton

> With three choices for choosenness, it works as I expected (only one item
> in
> CHOSEN state at a time) but for more choices like:
>
> #+CHOOSE_TODO: REJECTED(r) NOT_CHOSEN(n,-) MAYBE(,0)
> LEANING_TOWARDS(l) CHOSEN(c,+)
>
> it allows multiple items to be in CHOSEN state.  How do we interpret that?

I couldn't reproduce this.  Is this on the same test file as before?

Tom Breton (Tehom)

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing   decision alternatives.)
  2009-02-10  9:12                             ` Carsten Dominik
  2009-02-10 10:26                               ` Manish
@ 2009-02-10 23:19                               ` Tom Breton (Tehom)
  2009-02-11 10:34                                 ` Carsten Dominik
  1 sibling, 1 reply; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-02-10 23:19 UTC (permalink / raw)
  To: Carsten Dominik; +Cc: emacs-orgmode


>
> Hmm, not sure if I messed up there - so I fixed this bug.  Tom,
> please check if I did this right.
>
> - Carsten


Hi, Carsten.  I just looked at org-6.22b

You caught a problem, but I think it's a different bug.  I think there
are these different things:

 * What you saw, that it doesn't work at top level.  Good catch.  My
   code finds the groups of siblings via their parent.  If they have
   no parent, it doesn't work.  Doing that already generated an error
   deep in the guts of outline, but your way is better.  Let's keep
   your fix.
 * What Manish saw.  I can't reproduce this.  I suspect that it
   relates to outline somehow not being loaded, but org-choose
   requires org which requires outline.  I find a dependency on
   org-agenda from `org-map-entries' in org.el, and once I load that,
   it all works.

Tom Breton (Tehom)

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing   decision alternatives.)
  2009-02-10 10:26                               ` Manish
  2009-02-10 22:48                                 ` Tom Breton (Tehom)
@ 2009-02-11  1:08                                 ` Tom Breton (Tehom)
  2009-02-11 10:34                                   ` Carsten Dominik
  2009-02-11 12:29                                   ` Carsten Dominik
  2009-02-11  1:45                                 ` Slight fix to update-org.sh Tom Breton (Tehom)
  2 siblings, 2 replies; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-02-11  1:08 UTC (permalink / raw)
  To: Manish; +Cc: emacs-orgmode

> On Tue, Feb 10, 2009 at 2:42 PM, Carsten Dominik wrote:
>>
>> On Feb 10, 2009, at 9:46 AM, Manish wrote:
>>
>>> On Tue, Feb 10, 2009 at 8:44 AM, Tom Breton (Tehom) wrote:
>>> [...]
>>>>
>>>> OK, I've add comments, keywords, and some docstrings I forgot to
>>>> org-choose.el, and I wrote a standalone doc. Both are attached.
>>>
>>> This is very intriguing functionality. I tried to follow your and
>>> Casten's
>>> earlier exchanges but could understand only a little. So I tried to
>>> follow
>>> your tutorial but I am getting stuck at switching the `choosenness' of
>>> items.
>>> I get following error when I try to switch to any state from "no
>>> state".
>>> Once
>>> I assign a state by typing it out manually (as opposed to using state
>>> switching commands), I can then switch between states but the error
>>> repeats
>>> when I try to switch to "MAYBE" state.
>>>
>>> ,----
>>> | save-excursion: Symbol's function definition is void:
>>> outline-up-heading-all
>>> `----
>>
>> Hmm, not sure if I messed up there - so I fixed this bug. Tom,
>> please check if I did this right.
>
> This issue is gone for me.  Thanks.
>
>>> So far, my understaning is that only one item can be in "YES" state. If
>>> I
>>> try
>>> to switch another item to "YES" then the existing "YES" will be demoted
>>> to "MAYBE". So for a two-state choosenness only one item can be in
>>> CHOOSE
>>> state while all others will switch to NOT_CHOOSEN state.. is that
>>> understanding correct?
>
> With three choices for choosenness, it works as I expected (only one item
> in
> CHOSEN state at a time) but for more choices like:
>
> #+CHOOSE_TODO: REJECTED(r) NOT_CHOSEN(n,-) MAYBE(,0)
> LEANING_TOWARDS(l) CHOSEN(c,+)
>
> it allows multiple items to be in CHOSEN state.  How do we interpret that?

Having fetched and set up 6.22b, I can now reproduce it.

This bug is simple.  In "Setting it all up" at the end of org-choose.el,
in 6.22b a quote got introduced before progn.  That's all.  With that
quote, it "evaluated" a quoted form and did nothing.  I'd send a patch,
but ISTM it's easier to just press backspace once.  It's here:

(eval-after-load 'org
  '(progn
;;^--HERE.
     (add-to-list 'org-todo-setup-filter-hook
		  #'org-choose-setup-filter)
     (add-to-list 'org-todo-get-default-hook
		  #'org-choose-get-default-mark)
     (add-to-list 'org-trigger-hook
		  #'org-choose-keep-sensible)
     (add-to-list 'org-todo-interpretation-widgets
		  '(:tag "Choose   (to record decisions)" choose)
		  'append)
   ))





Tom Breton (Tehom)

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Slight fix to update-org.sh
  2009-02-10 10:26                               ` Manish
  2009-02-10 22:48                                 ` Tom Breton (Tehom)
  2009-02-11  1:08                                 ` Tom Breton (Tehom)
@ 2009-02-11  1:45                                 ` Tom Breton (Tehom)
  2 siblings, 0 replies; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-02-11  1:45 UTC (permalink / raw)
  Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 422 bytes --]

While updating to 6.22b, I remembered this:

I like pete's update-org.sh.  It's convenient when you haven't got git
(I'll get around to getting git someday, but it's not high priority)

It had a bit of a problem because my org directory wasn't a subdirectory
of my build directory.  I made some minor changes to make it do that and
to gunzip the archive.  I've attached it to this message.

Tom Breton (Tehom)


[-- Attachment #2: update-org.sh --]
[-- Type: application/x-sh, Size: 2007 bytes --]

[-- Attachment #3: Type: text/plain, Size: 204 bytes --]

_______________________________________________
Emacs-orgmode mailing list
Remember: use `Reply All' to send replies to the list.
Emacs-orgmode@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-orgmode

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing decision alternatives.)
  2009-02-11  1:08                                 ` Tom Breton (Tehom)
@ 2009-02-11 10:34                                   ` Carsten Dominik
  2009-02-11 21:41                                     ` Tom Breton (Tehom)
  2009-02-11 12:29                                   ` Carsten Dominik
  1 sibling, 1 reply; 56+ messages in thread
From: Carsten Dominik @ 2009-02-11 10:34 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode


[-- Attachment #1.1: Type: text/plain, Size: 2881 bytes --]


On Feb 11, 2009, at 2:08 AM, Tom Breton (Tehom) wrote:

>> On Tue, Feb 10, 2009 at 2:42 PM, Carsten Dominik wrote:
>>>
>>> On Feb 10, 2009, at 9:46 AM, Manish wrote:
>>>
>>>> On Tue, Feb 10, 2009 at 8:44 AM, Tom Breton (Tehom) wrote:
>>>> [...]
>>>>>
>>>>> OK, I've add comments, keywords, and some docstrings I forgot to
>>>>> org-choose.el, and I wrote a standalone doc. Both are attached.
>>>>
>>>> This is very intriguing functionality. I tried to follow your and
>>>> Casten's
>>>> earlier exchanges but could understand only a little. So I tried to
>>>> follow
>>>> your tutorial but I am getting stuck at switching the  
>>>> `choosenness' of
>>>> items.
>>>> I get following error when I try to switch to any state from "no
>>>> state".
>>>> Once
>>>> I assign a state by typing it out manually (as opposed to using  
>>>> state
>>>> switching commands), I can then switch between states but the error
>>>> repeats
>>>> when I try to switch to "MAYBE" state.
>>>>
>>>> ,----
>>>> | save-excursion: Symbol's function definition is void:
>>>> outline-up-heading-all
>>>> `----
>>>
>>> Hmm, not sure if I messed up there - so I fixed this bug. Tom,
>>> please check if I did this right.
>>
>> This issue is gone for me.  Thanks.
>>
>>>> So far, my understaning is that only one item can be in "YES"  
>>>> state. If
>>>> I
>>>> try
>>>> to switch another item to "YES" then the existing "YES" will be  
>>>> demoted
>>>> to "MAYBE". So for a two-state choosenness only one item can be in
>>>> CHOOSE
>>>> state while all others will switch to NOT_CHOOSEN state.. is that
>>>> understanding correct?
>>
>> With three choices for choosenness, it works as I expected (only  
>> one item
>> in
>> CHOSEN state at a time) but for more choices like:
>>
>> #+CHOOSE_TODO: REJECTED(r) NOT_CHOSEN(n,-) MAYBE(,0)
>> LEANING_TOWARDS(l) CHOSEN(c,+)
>>
>> it allows multiple items to be in CHOSEN state.  How do we  
>> interpret that?
>
> Having fetched and set up 6.22b, I can now reproduce it.
>
> This bug is simple.  In "Setting it all up" at the end of org- 
> choose.el,
> in 6.22b a quote got introduced before progn.  That's all.  With that
> quote, it "evaluated" a quoted form and did nothing.  I'd send a  
> patch,
> but ISTM it's easier to just press backspace once.  It's here:
>
> (eval-after-load 'org
>  '(progn
> ;;^--HERE.
>     (add-to-list 'org-todo-setup-filter-hook
> 		  #'org-choose-setup-filter)
>     (add-to-list 'org-todo-get-default-hook
> 		  #'org-choose-get-default-mark)
>     (add-to-list 'org-trigger-hook
> 		  #'org-choose-keep-sensible)
>     (add-to-list 'org-todo-interpretation-widgets
> 		  '(:tag "Choose   (to record decisions)" choose)
> 		  'append)
>   ))

Hi Tom,

I added the quote because without it, evaluating org-chose.el did error.
It was my understanding that such a form has to be quoted.  Am
I missing something here?


- Carsten

[-- Attachment #1.2: Type: text/html, Size: 8485 bytes --]

[-- Attachment #2: Type: text/plain, Size: 204 bytes --]

_______________________________________________
Emacs-orgmode mailing list
Remember: use `Reply All' to send replies to the list.
Emacs-orgmode@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-orgmode

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing decision alternatives.)
  2009-02-10 23:19                               ` Docs submitted (Was Re: Advice sought on managing decision alternatives.) Tom Breton (Tehom)
@ 2009-02-11 10:34                                 ` Carsten Dominik
  0 siblings, 0 replies; 56+ messages in thread
From: Carsten Dominik @ 2009-02-11 10:34 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode


On Feb 11, 2009, at 12:19 AM, Tom Breton (Tehom) wrote:

>
>>
>> Hmm, not sure if I messed up there - so I fixed this bug.  Tom,
>> please check if I did this right.
>>
>> - Carsten
>
>
> Hi, Carsten.  I just looked at org-6.22b
>
> You caught a problem, but I think it's a different bug.  I think there
> are these different things:
>
> * What you saw, that it doesn't work at top level.  Good catch.  My
>   code finds the groups of siblings via their parent.  If they have
>   no parent, it doesn't work.  Doing that already generated an error
>   deep in the guts of outline, but your way is better.  Let's keep
>   your fix.

OK

>
> * What Manish saw.  I can't reproduce this.


I could.  Your code was calling outline-up-heading-all, which
does not exist in the outline.el I have.  I replaced it
with org-up-heading-all, then the code did work.

- Carsten

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing decision alternatives.)
  2009-02-11  1:08                                 ` Tom Breton (Tehom)
  2009-02-11 10:34                                   ` Carsten Dominik
@ 2009-02-11 12:29                                   ` Carsten Dominik
  2009-02-11 14:58                                     ` Docs submitted Bernt Hansen
                                                       ` (2 more replies)
  1 sibling, 3 replies; 56+ messages in thread
From: Carsten Dominik @ 2009-02-11 12:29 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode


On Feb 11, 2009, at 2:08 AM, Tom Breton (Tehom) wrote:

>> On Tue, Feb 10, 2009 at 2:42 PM, Carsten Dominik wrote:
>>>
>>> On Feb 10, 2009, at 9:46 AM, Manish wrote:
>>>
>>>> On Tue, Feb 10, 2009 at 8:44 AM, Tom Breton (Tehom) wrote:
>>>> [...]
>>>>>
>>>>> OK, I've add comments, keywords, and some docstrings I forgot to
>>>>> org-choose.el, and I wrote a standalone doc. Both are attached.
>>>>
>>>> This is very intriguing functionality. I tried to follow your and
>>>> Casten's
>>>> earlier exchanges but could understand only a little. So I tried to
>>>> follow
>>>> your tutorial but I am getting stuck at switching the  
>>>> `choosenness' of
>>>> items.
>>>> I get following error when I try to switch to any state from "no
>>>> state".
>>>> Once
>>>> I assign a state by typing it out manually (as opposed to using  
>>>> state
>>>> switching commands), I can then switch between states but the error
>>>> repeats
>>>> when I try to switch to "MAYBE" state.
>>>>
>>>> ,----
>>>> | save-excursion: Symbol's function definition is void:
>>>> outline-up-heading-all
>>>> `----
>>>
>>> Hmm, not sure if I messed up there - so I fixed this bug. Tom,
>>> please check if I did this right.
>>
>> This issue is gone for me.  Thanks.
>>
>>>> So far, my understaning is that only one item can be in "YES"  
>>>> state. If
>>>> I
>>>> try
>>>> to switch another item to "YES" then the existing "YES" will be  
>>>> demoted
>>>> to "MAYBE". So for a two-state choosenness only one item can be in
>>>> CHOOSE
>>>> state while all others will switch to NOT_CHOOSEN state.. is that
>>>> understanding correct?
>>
>> With three choices for choosenness, it works as I expected (only  
>> one item
>> in
>> CHOSEN state at a time) but for more choices like:
>>
>> #+CHOOSE_TODO: REJECTED(r) NOT_CHOSEN(n,-) MAYBE(,0)
>> LEANING_TOWARDS(l) CHOSEN(c,+)
>>
>> it allows multiple items to be in CHOSEN state.  How do we  
>> interpret that?
>
> Having fetched and set up 6.22b, I can now reproduce it.
>
> This bug is simple.  In "Setting it all up" at the end of org- 
> choose.el,
> in 6.22b a quote got introduced before progn.  That's all.  With that
> quote, it "evaluated" a quoted form and did nothing.  I'd send a  
> patch,
> but ISTM it's easier to just press backspace once.  It's here:
>
> (eval-after-load 'org
>  '(progn
> ;;^--HERE.
>     (add-to-list 'org-todo-setup-filter-hook
> 		  #'org-choose-setup-filter)
>     (add-to-list 'org-todo-get-default-hook
> 		  #'org-choose-get-default-mark)
>     (add-to-list 'org-trigger-hook
> 		  #'org-choose-keep-sensible)
>     (add-to-list 'org-todo-interpretation-widgets
> 		  '(:tag "Choose   (to record decisions)" choose)
> 		  'append)
>   ))
>

Hi Tom,

maybe you can educate me:  I have never understood what the "#" does
in code like the one you have here.  You are using it, so maybe you  
know?

- Carsten

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted
  2009-02-11 12:29                                   ` Carsten Dominik
@ 2009-02-11 14:58                                     ` Bernt Hansen
  2009-02-11 17:33                                       ` Samuel Wales
  2009-02-11 15:38                                     ` Docs submitted (Was Re: Advice sought on managing decision alternatives.) Daniel Clemente
  2009-02-11 20:02                                     ` Tom Breton (Tehom)
  2 siblings, 1 reply; 56+ messages in thread
From: Bernt Hansen @ 2009-02-11 14:58 UTC (permalink / raw)
  To: Carsten Dominik; +Cc: emacs-orgmode, Tom Breton (Tehom)

Carsten Dominik <dominik@science.uva.nl> writes:

> On Feb 11, 2009, at 2:08 AM, Tom Breton (Tehom) wrote:
>
>> (eval-after-load 'org
>>  '(progn
>> ;;^--HERE.
>>     (add-to-list 'org-todo-setup-filter-hook
>> 		  #'org-choose-setup-filter)
>>     (add-to-list 'org-todo-get-default-hook
>> 		  #'org-choose-get-default-mark)
>>     (add-to-list 'org-trigger-hook
>> 		  #'org-choose-keep-sensible)
>>     (add-to-list 'org-todo-interpretation-widgets
>> 		  '(:tag "Choose   (to record decisions)" choose)
>> 		  'append)
>>   ))
>>
>
> Hi Tom,
>
> maybe you can educate me:  I have never understood what the "#" does
> in code like the one you have here.  You are using it, so maybe you
> know?

As I understand it (from my book on Common Lisp) #'some-function is used
to quote function names.  'some-function quotes a variable.

It means "Get me the function with the following name" - without the #',
Lisp would treat some-function as the name of a variable and look up the
value of the variable, not the function.

-Bernt

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing decision alternatives.)
  2009-02-11 12:29                                   ` Carsten Dominik
  2009-02-11 14:58                                     ` Docs submitted Bernt Hansen
@ 2009-02-11 15:38                                     ` Daniel Clemente
  2009-02-11 15:41                                       ` Carsten Dominik
  2009-02-11 20:02                                     ` Tom Breton (Tehom)
  2 siblings, 1 reply; 56+ messages in thread
From: Daniel Clemente @ 2009-02-11 15:38 UTC (permalink / raw)
  To: Carsten Dominik; +Cc: emacs-orgmode, Tom Breton (Tehom)


Carsten Dominik <dominik@science.uva.nl> writes:
> Hi Tom,
>
> maybe you can educate me:  I have never understood what the "#" does
> in code like the one you have here.  You are using it, so maybe you know?
>

  Since I am always having questions like that, I keep writing here each new notation I find :-)
http://www.emacswiki.org/emacs/CategoryGlossary#toc1

-- Daniel

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing decision alternatives.)
  2009-02-11 15:38                                     ` Docs submitted (Was Re: Advice sought on managing decision alternatives.) Daniel Clemente
@ 2009-02-11 15:41                                       ` Carsten Dominik
  0 siblings, 0 replies; 56+ messages in thread
From: Carsten Dominik @ 2009-02-11 15:41 UTC (permalink / raw)
  To: Daniel Clemente; +Cc: Tom Breton (Tehom), emacs-orgmode

Useful resource!

Thanks.

- Carsten

On Feb 11, 2009, at 4:38 PM, Daniel Clemente wrote:

>
> Carsten Dominik <dominik@science.uva.nl> writes:
>> Hi Tom,
>>
>> maybe you can educate me:  I have never understood what the "#" does
>> in code like the one you have here.  You are using it, so maybe you  
>> know?
>>
>
>  Since I am always having questions like that, I keep writing here  
> each new notation I find :-)
> http://www.emacswiki.org/emacs/CategoryGlossary#toc1
>
> -- Daniel
>

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Re: Docs submitted
  2009-02-11 14:58                                     ` Docs submitted Bernt Hansen
@ 2009-02-11 17:33                                       ` Samuel Wales
  0 siblings, 0 replies; 56+ messages in thread
From: Samuel Wales @ 2009-02-11 17:33 UTC (permalink / raw)
  To: Bernt Hansen; +Cc: Tom Breton (Tehom), emacs-orgmode

The CL spec is online: http://www.lispworks.com/documentation/HyperSpec/Front/

In emacs lisp:

function is a special form in `C source code'.
(function arg)

Like `quote', but preferred for objects which are functions.
In byte compilation, `function' causes its argument to be compiled.
`quote' cannot do that.

[back]
--

-- 
Myalgic encephalomyelitis denialists are causing massive suffering and
25-years-early death by grossly corrupting science.
http://www.meactionuk.org.uk/What_Is_ME_What_Is_CFS.htm

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing    decision alternatives.)
  2009-02-11 12:29                                   ` Carsten Dominik
  2009-02-11 14:58                                     ` Docs submitted Bernt Hansen
  2009-02-11 15:38                                     ` Docs submitted (Was Re: Advice sought on managing decision alternatives.) Daniel Clemente
@ 2009-02-11 20:02                                     ` Tom Breton (Tehom)
  2009-02-11 23:45                                       ` Carsten Dominik
  2 siblings, 1 reply; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-02-11 20:02 UTC (permalink / raw)
  To: Carsten Dominik; +Cc: emacs-orgmode

>
> Hi Tom,
>
> maybe you can educate me:  I have never understood what the "#" does
> in code like the one you have here.  You are using it, so maybe you
> know?
>
> - Carsten
>
>

Here, it's   #'   that it of interest, not  #  alone.

At the most direct level, it quotes the symbol with `function' instead of
`quote'.  For example:

(format "%s" ' 'foo)  => "(quote foo)"
(format "%s" ' #'foo) => "(function foo)"

What it accomplishes:
 * In some contexts, it is needed to get a symbol's function binding
instead of its value binding.
 * It alerts the byte-compiler that it's seeing a function, so it can
perform certain optimizations (I don't know offhand exactly what).
 * Stylistically, it alerts the reader.

It's an imitation of Common Lisp's reader macro  #'  which does sort of
the same thing.

At the syntax level, it's really a combination of   #   which signals a
reader macro - though in emacs, it's all hard-coded and inextensible - and
 '  which stands for the function-quote reader macro.

FWIW, what I added to lread.c was an extension of the reader macro
facility at RMS' request, so you definitely asked the right guy.

Tom Breton (Tehom)

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing    decision alternatives.)
  2009-02-11 10:34                                   ` Carsten Dominik
@ 2009-02-11 21:41                                     ` Tom Breton (Tehom)
  2009-02-11 23:38                                       ` Nick Dokos
  2009-02-11 23:44                                       ` Carsten Dominik
  0 siblings, 2 replies; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-02-11 21:41 UTC (permalink / raw)
  To: Carsten Dominik; +Cc: emacs-orgmode

>
> On Feb 11, 2009, at 2:08 AM, Tom Breton (Tehom) wrote:
>

>> This bug is simple.  In "Setting it all up" at the end of org-
>> choose.el,
>> in 6.22b a quote got introduced before progn.  That's all.  With that
>> quote, it "evaluated" a quoted form and did nothing.  I'd send a
>> patch,
>> but ISTM it's easier to just press backspace once.  It's here:
>>
>> (eval-after-load 'org
>>  '(progn
>> ;;^--HERE.
>>     (add-to-list 'org-todo-setup-filter-hook
>> 		  #'org-choose-setup-filter)
>>     (add-to-list 'org-todo-get-default-hook
>> 		  #'org-choose-get-default-mark)
>>     (add-to-list 'org-trigger-hook
>> 		  #'org-choose-keep-sensible)
>>     (add-to-list 'org-todo-interpretation-widgets
>> 		  '(:tag "Choose   (to record decisions)" choose)
>> 		  'append)
>>   ))
>
> Hi Tom,
>
> I added the quote because without it, evaluating org-chose.el did error.
> It was my understanding that such a form has to be quoted.  Am
> I missing something here?

What error did it give?  I didn't get one here.

Definitely the form should not be quoted.  Quoted, it does nothing.
Demonstration (with libary `simple' which is fairly basic in emacs so
probably loaded for everyone):

(let*
   ((x 1))
   (eval-after-load 'simple (setq x 2))
   x)

=> 2



(let*
   ((x 1))
   (eval-after-load 'simple '(setq x 2))
   x)

=> 1



Tom Breton (Tehom)

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing decision alternatives.)
  2009-02-11 21:41                                     ` Tom Breton (Tehom)
@ 2009-02-11 23:38                                       ` Nick Dokos
  2009-02-12  4:17                                         ` Tom Breton (Tehom)
  2009-02-11 23:44                                       ` Carsten Dominik
  1 sibling, 1 reply; 56+ messages in thread
From: Nick Dokos @ 2009-02-11 23:38 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode

Tom Breton (Tehom) <tehom@panix.com> wrote:

> >
> > On Feb 11, 2009, at 2:08 AM, Tom Breton (Tehom) wrote:
> >
> 
> >> This bug is simple.  In "Setting it all up" at the end of org-
> >> choose.el,
> >> in 6.22b a quote got introduced before progn.  That's all.  With that
> >> quote, it "evaluated" a quoted form and did nothing.  I'd send a
> >> patch,
> >> but ISTM it's easier to just press backspace once.  It's here:
> >>
> >> (eval-after-load 'org
> >>  '(progn
> >> ;;^--HERE.
> >>     (add-to-list 'org-todo-setup-filter-hook
> >> 		  #'org-choose-setup-filter)
> >>     (add-to-list 'org-todo-get-default-hook
> >> 		  #'org-choose-get-default-mark)
> >>     (add-to-list 'org-trigger-hook
> >> 		  #'org-choose-keep-sensible)
> >>     (add-to-list 'org-todo-interpretation-widgets
> >> 		  '(:tag "Choose   (to record decisions)" choose)
> >> 		  'append)
> >>   ))
> >
> > Hi Tom,
> >
> > I added the quote because without it, evaluating org-chose.el did error=
> .
> > It was my understanding that such a form has to be quoted.  Am
> > I missing something here?
> 
> What error did it give?  I didn't get one here.
> 
> Definitely the form should not be quoted.  Quoted, it does nothing.
> Demonstration (with libary `simple' which is fairly basic in emacs so
> probably loaded for everyone):
> 
> (let*
>    ((x 1))
>    (eval-after-load 'simple (setq x 2))
>    x)
> 
> =3D> 2
> 
> 
> 
> (let*
>    ((x 1))
>    (eval-after-load 'simple '(setq x 2))
>    x)
> 
> =3D> 1


Are you sure about this? My understanding of this differs from
yours:

eval-after-load is an ordinary function (not a special form), and
function evaluation in most LISPs (elisp in particular) evaluates
arguments before the function is called on them. So if you give it an
unquoted form, the form will be evaluated *before* eval-after-load gets
its hands on it. That seems to me to defeat the purpose. I'd think that
the thing to do is to give the quoted form as argument, then function
evaluation evaluates the argument (i.e. unquotes the quoted form,
giving back the form) which is then passed to eval-after-load for
action. The semantics of eval-after-load imply that (depending on
whether the library is already loaded or not) the form may be evaluated
once. It is then squirrelled away and if the library is ever loaded
again, it is evaluated (perhaps for the first time, perhaps for the
nth), *after* the library is loaded.

And I think your demonstration is misleading: after doing the
eval-after-load, you need to reload "simple" to trigger the "after-load"
evaluation, otherwise eval-after-load reduces to just plain eval (in
this  particular case, since simple is, as you point out, already loaded -
things would be different if you had chosen some obscure library that
is not already loaded):

(let*
    ((x 1))
    (eval-after-load 'simple (setq x 2))
    (load-library "simple")
    x)
2

(let*
    ((x 1))
    (eval-after-load 'simple '(setq x 2))
    (load-library "simple")
    x)
2

In the first case, (setq x 2) was evaluated, x was set to 2 and 2 was
passed into eval-after-load. Assuming that simple is already loaded, the
2 is evaluated: the result is 2 and it is just thrown away. After the
library is loaded again, 2 is evaluated again and the result is 2 and it
just thrown away. Since x was set to 2 before, the value of x is 2.

In the second case, (quote (setq x 2)) is evaluated, so the form (setq x
2) is passed to eval-after-load. Assuming that simple is already loaded,
the form is evaluated, setting x to 2 and giving a result of 2 (which is
thrown away). After the library is loaded, (setq x 2) is eval'led again,
setting x to 2 again, and giving a result of 2 (which is thrown away).

In both cases, the value of x (and therefore the value the let* form
returns) is 2. But it seems to me that the second case is the useful
one. 

Perhaps the most telling evidence that the quote should be there however
is the following: if you look at eval-after-load instances in the emacs
lisp directory, you'll see that the second argument in all of them is
quoted or at least (when partial evaluation is required) backquoted --
although I guess one could argue that they all originated by copying a
badly constructed precursor - the programming version of original sin!-)

Regards,
Nick

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing decision alternatives.)
  2009-02-11 21:41                                     ` Tom Breton (Tehom)
  2009-02-11 23:38                                       ` Nick Dokos
@ 2009-02-11 23:44                                       ` Carsten Dominik
  2009-02-12  4:27                                         ` Tom Breton (Tehom)
  1 sibling, 1 reply; 56+ messages in thread
From: Carsten Dominik @ 2009-02-11 23:44 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode


On Feb 11, 2009, at 10:41 PM, Tom Breton (Tehom) wrote:

>>
>> On Feb 11, 2009, at 2:08 AM, Tom Breton (Tehom) wrote:
>>
>
>>> This bug is simple.  In "Setting it all up" at the end of org-
>>> choose.el,
>>> in 6.22b a quote got introduced before progn.  That's all.  With  
>>> that
>>> quote, it "evaluated" a quoted form and did nothing.  I'd send a
>>> patch,
>>> but ISTM it's easier to just press backspace once.  It's here:
>>>
>>> (eval-after-load 'org
>>> '(progn
>>> ;;^--HERE.
>>>    (add-to-list 'org-todo-setup-filter-hook
>>> 		  #'org-choose-setup-filter)
>>>    (add-to-list 'org-todo-get-default-hook
>>> 		  #'org-choose-get-default-mark)
>>>    (add-to-list 'org-trigger-hook
>>> 		  #'org-choose-keep-sensible)
>>>    (add-to-list 'org-todo-interpretation-widgets
>>> 		  '(:tag "Choose   (to record decisions)" choose)
>>> 		  'append)
>>>  ))
>>
>> Hi Tom,
>>
>> I added the quote because without it, evaluating org-chose.el did  
>> error.
>> It was my understanding that such a form has to be quoted.  Am
>> I missing something here?
>
> What error did it give?  I didn't get one here.

eval: Invalid function: (:tag "Sequence (cycling hits every state)"  
sequence)

I don't understand it either.

>
>
> Definitely the form should not be quoted.  Quoted, it does nothing.
> Demonstration (with libary `simple' which is fairly basic in emacs so
> probably loaded for everyone):
>
> (let*
>   ((x 1))
>   (eval-after-load 'simple (setq x 2))
>   x)
>
> => 2
>
>
>
> (let*
>   ((x 1))
>   (eval-after-load 'simple '(setq x 2))
>   x)
>
> => 1

In fact, I am getting 2 in both cases!!!!!???????
Do you really get 1 for the second???

eval-after-load is a function, not a macro, so FORM will
be evaluated *before* being passed to the function.  But the
idea, IIUC is, that the form will be added to after-load-alist,
and evaluated whenever appropriate.

I have a number of eval-after-loads in org.el, each time the
form is quotes and does the right thing.

- Carsten



>
>
>
>
> Tom Breton (Tehom)
>
>
>

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing decision alternatives.)
  2009-02-11 20:02                                     ` Tom Breton (Tehom)
@ 2009-02-11 23:45                                       ` Carsten Dominik
  0 siblings, 0 replies; 56+ messages in thread
From: Carsten Dominik @ 2009-02-11 23:45 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode


On Feb 11, 2009, at 9:02 PM, Tom Breton (Tehom) wrote:

>>
>> Hi Tom,
>>
>> maybe you can educate me:  I have never understood what the "#" does
>> in code like the one you have here.  You are using it, so maybe you
>> know?
>>
>> - Carsten
>>
>>
>
> Here, it's   #'   that it of interest, not  #  alone.
>
> At the most direct level, it quotes the symbol with `function'  
> instead of
> `quote'.  For example:
>
> (format "%s" ' 'foo)  => "(quote foo)"
> (format "%s" ' #'foo) => "(function foo)"
>
> What it accomplishes:
> * In some contexts, it is needed to get a symbol's function binding
> instead of its value binding.
> * It alerts the byte-compiler that it's seeing a function, so it can
> perform certain optimizations (I don't know offhand exactly what).
> * Stylistically, it alerts the reader.

OK, thanks a lot!

>
>
> It's an imitation of Common Lisp's reader macro  #'  which does sort  
> of
> the same thing.
>
> At the syntax level, it's really a combination of   #   which  
> signals a
> reader macro - though in emacs, it's all hard-coded and inextensible  
> - and
> '  which stands for the function-quote reader macro.
>
> FWIW, what I added to lread.c was an extension of the reader macro
> facility at RMS' request, so you definitely asked the right guy.


:-)  Thanks for the explanations.

>
>
> Tom Breton (Tehom)
>
>

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing decision alternatives.)
  2009-02-11 23:38                                       ` Nick Dokos
@ 2009-02-12  4:17                                         ` Tom Breton (Tehom)
  0 siblings, 0 replies; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-02-12  4:17 UTC (permalink / raw)
  To: nicholas.dokos; +Cc: emacs-orgmode

nicholas.dokos@hp.com wrote:
> Tom Breton (Tehom) <tehom@panix.com> wrote:

>> (let*
>>    ((x 1))
>>    (eval-after-load 'simple (setq x 2))
>>    x)
>>
>> =3D> 2
>>
>>
>>
>> (let*
>>    ((x 1))
>>    (eval-after-load 'simple '(setq x 2))
>>    x)
>>
>> =3D> 1
>
>
> Are you sure about this? My understanding of this differs from
> yours:

This is definitely a "Boy is my face red" moment.  You are completely
correct.  I had misunderstood `eval-after-load' as a macro.  Upon looking
at subr.el, it is obvious that you are right and I am wrong.

Thank you for pointing all that out.

> eval-after-load is an ordinary function (not a special form), and
> function evaluation in most LISPs (elisp in particular) evaluates
> arguments before the function is called on them. So if you give it an
> unquoted form, the form will be evaluated *before* eval-after-load gets
> its hands on it. That seems to me to defeat the purpose. I'd think that
> the thing to do is to give the quoted form as argument, then function
> evaluation evaluates the argument (i.e. unquotes the quoted form,
> giving back the form) which is then passed to eval-after-load for
> action. The semantics of eval-after-load imply that (depending on
> whether the library is already loaded or not) the form may be evaluated
> once. It is then squirrelled away and if the library is ever loaded
> again, it is evaluated (perhaps for the first time, perhaps for the
> nth), *after* the library is loaded.
>
> And I think your demonstration is misleading: after doing the
> eval-after-load, you need to reload "simple" to trigger the "after-load"
> evaluation, otherwise eval-after-load reduces to just plain eval (in
> this  particular case, since simple is, as you point out, already loaded -
> things would be different if you had chosen some obscure library that
> is not already loaded):
>
> (let*
>     ((x 1))
>     (eval-after-load 'simple (setq x 2))
>     (load-library "simple")
>     x)
> 2
>
> (let*
>     ((x 1))
>     (eval-after-load 'simple '(setq x 2))
>     (load-library "simple")
>     x)
> 2
>
> In the first case, (setq x 2) was evaluated, x was set to 2 and 2 was
> passed into eval-after-load. Assuming that simple is already loaded, the
> 2 is evaluated: the result is 2 and it is just thrown away. After the
> library is loaded again, 2 is evaluated again and the result is 2 and it
> just thrown away. Since x was set to 2 before, the value of x is 2.
>
> In the second case, (quote (setq x 2)) is evaluated, so the form (setq x
> 2) is passed to eval-after-load. Assuming that simple is already loaded,
> the form is evaluated, setting x to 2 and giving a result of 2 (which is
> thrown away). After the library is loaded, (setq x 2) is eval'led again,
> setting x to 2 again, and giving a result of 2 (which is thrown away).
>
> In both cases, the value of x (and therefore the value the let* form
> returns) is 2. But it seems to me that the second case is the useful
> one.
>
> Perhaps the most telling evidence that the quote should be there however
> is the following: if you look at eval-after-load instances in the emacs
> lisp directory, you'll see that the second argument in all of them is
> quoted or at least (when partial evaluation is required) backquoted --
> although I guess one could argue that they all originated by copying a
> badly constructed precursor - the programming version of original sin!-)
>
> Regards,
> Nick
>
>

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing     decision alternatives.)
  2009-02-11 23:44                                       ` Carsten Dominik
@ 2009-02-12  4:27                                         ` Tom Breton (Tehom)
  2009-02-12 15:49                                           ` Nick Dokos
  0 siblings, 1 reply; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-02-12  4:27 UTC (permalink / raw)
  Cc: emacs-orgmode


>>> On Feb 11, 2009, at 2:08 AM, Tom Breton (Tehom) wrote:
>>>
>>
>> (let*
>>   ((x 1))
>>   (eval-after-load 'simple (setq x 2))
>>   x)
>>
>> => 2
>>
>>
>>
>> (let*
>>   ((x 1))
>>   (eval-after-load 'simple '(setq x 2))
>>   x)
>>
>> => 1
>
> In fact, I am getting 2 in both cases!!!!!???????
> Do you really get 1 for the second???

Yes I do, but it's clear now that I was mistaken about why.  On closer
inspection, it has to do with emacs not recognizing 'simple because it
wants to see "simple" instead (string instead of symbol).

;;As symbol
(let*
   ((x 1))
   (eval-after-load 'simple '(setq x 2))
   x)

=> 1


;;As string
(let*
   ((x 1))
   (eval-after-load "simple" '(setq x 2))
   x)

=> 2


Not sure why it's different for you.  I suspect it may have to do with a
difference between the emacs version I use and later versions.

> eval-after-load is a function, not a macro, so FORM will
> be evaluated *before* being passed to the function.  []

Yes, I see that now.

Tom Breton (Tehom)

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing decision alternatives.)
  2009-02-10 22:48                                 ` Tom Breton (Tehom)
@ 2009-02-12 12:50                                   ` Manish
  2009-02-12 20:13                                     ` Tom Breton (Tehom)
  2009-02-12 20:55                                     ` Patch " Tom Breton (Tehom)
  0 siblings, 2 replies; 56+ messages in thread
From: Manish @ 2009-02-12 12:50 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode

On Wed, Feb 11, 2009 at 4:18 AM, Tom Breton (Tehom) wrote:
>> With three choices for choosenness, it works as I expected (only one
>> item in CHOSEN state at a time) but for more choices like:
>>
>> #+CHOOSE_TODO: REJECTED(r) NOT_CHOSEN(n,-) MAYBE(,0)
>> LEANING_TOWARDS(l) CHOSEN(c,+)
>>
>> it allows multiple items to be in CHOSEN state. How do we interpret
>> that?
>
> I couldn't reproduce this. Is this on the same test file as before?

Sorry for the delay in reply, Tom.  I reproduce the situation below:

First the test file.

--8<---------------cut here---------------start------------->8---
#+CHOOSE_TODO: REJECTED(r) NOT_CHOSEN(n,-) MAYBE(,0)
LEANING_TOWARDS(l) CHOSEN(c,+)

* Which editor to use?
*** LEANING_TOWARDS Emacs
*** LEANING_TOWARDS Vim
*** LEANING_TOWARDS Textmate
*** REJECTED Gedit
*** REJECTED Textpad
--8<---------------cut here---------------end--------------->8---

0. I have latest org-choose loaded, org-mode restarted, and local
   setup refreshed.
1. S-right on the second item to switch it to CHOSEN state.  It works.
2. Now S-right on the first item to switch it to CHOSEN state.  Also
   works.

Both entries stay at CHOSEN state whereas I expected the second entry
to switch to a NON-CHOSEN state (possibly switching just one state
backwards not all the way back to REJECTED, but then I do not yet
understand it fully.)

Is this the right behaviour?  If yes, please help me understand this a
little.  Or could I be doing or have something wrong in my setup?

Regards,
-- 
Manish

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing decision alternatives.)
  2009-02-12  4:27                                         ` Tom Breton (Tehom)
@ 2009-02-12 15:49                                           ` Nick Dokos
  2009-02-12 20:32                                             ` Tom Breton (Tehom)
  0 siblings, 1 reply; 56+ messages in thread
From: Nick Dokos @ 2009-02-12 15:49 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode

Tom Breton (Tehom) <tehom@panix.com> wrote:

> 
> >>> On Feb 11, 2009, at 2:08 AM, Tom Breton (Tehom) wrote:
> >>>
> >>
> >> (let*
> >>   ((x 1))
> >>   (eval-after-load 'simple (setq x 2))
> >>   x)
> >>
> >> =3D> 2
> >>
> >>
> >>
> >> (let*
> >>   ((x 1))
> >>   (eval-after-load 'simple '(setq x 2))
> >>   x)
> >>
> >> =3D> 1
> >
> > In fact, I am getting 2 in both cases!!!!!???????
> > Do you really get 1 for the second???
> 
> Yes I do, but it's clear now that I was mistaken about why.  On closer
> inspection, it has to do with emacs not recognizing 'simple because it
> wants to see "simple" instead (string instead of symbol).
> 

That's not correct: eval-after-load will happily accept a symbol instead
of a string, as long as the symbol is a feature provided by the library.
simple.el does that - the last form in it is

(provide 'simple)

Regards,
Nick

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing   decision alternatives.)
  2009-02-12 12:50                                   ` Manish
@ 2009-02-12 20:13                                     ` Tom Breton (Tehom)
  2009-02-13  4:23                                       ` Manish
  2009-02-12 20:55                                     ` Patch " Tom Breton (Tehom)
  1 sibling, 1 reply; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-02-12 20:13 UTC (permalink / raw)
  To: Manish; +Cc: emacs-orgmode

> On Wed, Feb 11, 2009 at 4:18 AM, Tom Breton (Tehom) wrote:
>> [...]
>> I couldn't reproduce this. Is this on the same test file as before?
>
> Sorry for the delay in reply, Tom.  I reproduce the situation below:
>
> First the test file.
>
> --8<---------------cut here---------------start------------->8---
> #+CHOOSE_TODO: REJECTED(r) NOT_CHOSEN(n,-) MAYBE(,0)
> LEANING_TOWARDS(l) CHOSEN(c,+)
>
> * Which editor to use?
> *** LEANING_TOWARDS Emacs
> *** LEANING_TOWARDS Vim
> *** LEANING_TOWARDS Textmate
> *** REJECTED Gedit
> *** REJECTED Textpad
> --8<---------------cut here---------------end--------------->8---
>
> 0. I have latest org-choose loaded, org-mode restarted, and local
>    setup refreshed.
> 1. S-right on the second item to switch it to CHOSEN state.  It works.
> 2. Now S-right on the first item to switch it to CHOSEN state.  Also
>    works.
>
> Both entries stay at CHOSEN state whereas I expected the second entry
> to switch to a NON-CHOSEN state (possibly switching just one state
> backwards not all the way back to REJECTED, but then I do not yet
> understand it fully.)
>
> Is this the right behaviour?  If yes, please help me understand this a
> little.  Or could I be doing or have something wrong in my setup?

That's not right the behavior, but again I can't seem to reproduce this. 
Using your test file and following your instructions, I get the correct
behavior.  Specifically, after S-right on second item:
[begin]
* Which editor to use?
*** NOT_CHOSEN Emacs
*** CHOSEN Vim
*** NOT_CHOSEN Textmate
*** REJECTED Gedit
*** REJECTED Textpad
[end]
Then after S-right on the first item, again correctly:
[begin]
* Which editor to use?
*** MAYBE Emacs
*** LEANING_TOWARDS Vim
*** NOT_CHOSEN Textmate
*** REJECTED Gedit
*** REJECTED Textpad
[end]

Now there's clearly something different between my setup and yours that it
causing a bug, but it's very difficult to diagnose and fix at a distance.

I have a theory that it's caused by an unloaded library whose absence makes
`org-map-entries' abort.

What I'm going to try is to add a require for org-agenda.  Will you try it
and tell me whether it fixes the bug?  Because I just can't see the bug in
my setup.

Tom Breton (Tehom)

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing decision alternatives.)
  2009-02-12 15:49                                           ` Nick Dokos
@ 2009-02-12 20:32                                             ` Tom Breton (Tehom)
  2009-02-12 21:25                                               ` Nick Dokos
  0 siblings, 1 reply; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-02-12 20:32 UTC (permalink / raw)
  To: nicholas.dokos; +Cc: emacs-orgmode

> Tom Breton (Tehom) <tehom@panix.com> wrote:
>
>>
>> >>> On Feb 11, 2009, at 2:08 AM, Tom Breton (Tehom) wrote:
>> >>>
>> >>
>> >> (let*
>> >>   ((x 1))
>> >>   (eval-after-load 'simple (setq x 2))
>> >>   x)
>> >>
>> >> =3D> 2
>> >>
>> >>
>> >>
>> >> (let*
>> >>   ((x 1))
>> >>   (eval-after-load 'simple '(setq x 2))
>> >>   x)
>> >>
>> >> =3D> 1
>> >
>> > In fact, I am getting 2 in both cases!!!!!???????
>> > Do you really get 1 for the second???
>>
>> Yes I do, but it's clear now that I was mistaken about why.  On closer
>> inspection, it has to do with emacs not recognizing 'simple because it
>> wants to see "simple" instead (string instead of symbol).
>>
>
> That's not correct: eval-after-load will happily accept a symbol instead
> of a string, as long as the symbol is a feature provided by the library.
> simple.el does that - the last form in it is
>
> (provide 'simple)

What version is this?  Because that's clearly not what it does on emacs
21.3.1. Here simple.el does not have (provide 'simple) in it.

I see no provision for accepting a symbol in eval-after-load.  The test it
uses is just:

        (assoc file load-history)

The cars of load-history are all strings, so I can't see how it would find
a symbol among them.  And it continues to stubbornly return a 1 for that
example when I use 'simple.

Clearly something has changed across versions.

Tom Breton (Tehom)

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Patch Re: Docs submitted (Was Re: Advice sought on managing  decision alternatives.)
  2009-02-12 12:50                                   ` Manish
  2009-02-12 20:13                                     ` Tom Breton (Tehom)
@ 2009-02-12 20:55                                     ` Tom Breton (Tehom)
  2009-02-13  4:38                                       ` Manish
  1 sibling, 1 reply; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-02-12 20:55 UTC (permalink / raw)
  To: Manish; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 394 bytes --]

Here is a patch that I hope will solve the problems people are having with
org-choose.el.  It contains two intended fixes:

 * `eval-after-load' gets a string argument.  Apparently some emacsen can
accept a symbol, but older ones can't.
 * "org-agenda" is required before `org-map-entries' is called.  This is  
 admittedly a quick and dirty fix, if it even works.

Tom Breton (Tehom)

[-- Attachment #2: org-choose.el.diff --]
[-- Type: application/octet-stream, Size: 795 bytes --]

*** old-org-choose.el	2009-02-10 14:23:13.000000000 -0500
--- org-choose.el	2009-02-12 15:26:51.000000000 -0500
***************
*** 385,390 ****
--- 385,391 ----
     "Return a function to map over the group"
     
     #'(lambda (fn)
+ 	(require 'org-agenda)  ;;`org-map-entries' seems to need it.
  	(save-excursion
  	  (unless (org-up-heading-safe)
  	    (error "Chosing is only supported between siblings in a tree, not on top level"))
***************
*** 499,505 ****
  
  ;;;_ , Setting it all up
  
! (eval-after-load 'org
    '(progn
       (add-to-list 'org-todo-setup-filter-hook
  		  #'org-choose-setup-filter) 
--- 500,506 ----
  
  ;;;_ , Setting it all up
  
! (eval-after-load "org"
    '(progn
       (add-to-list 'org-todo-setup-filter-hook
  		  #'org-choose-setup-filter) 

[-- Attachment #3: Type: text/plain, Size: 204 bytes --]

_______________________________________________
Emacs-orgmode mailing list
Remember: use `Reply All' to send replies to the list.
Emacs-orgmode@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-orgmode

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing decision alternatives.)
  2009-02-12 20:32                                             ` Tom Breton (Tehom)
@ 2009-02-12 21:25                                               ` Nick Dokos
  0 siblings, 0 replies; 56+ messages in thread
From: Nick Dokos @ 2009-02-12 21:25 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode

Tom Breton (Tehom) <tehom@panix.com> wrote:

> What version is this?  Because that's clearly not what it does on emacs
> 21.3.1. Here simple.el does not have (provide 'simple) in it.
> 
> I see no provision for accepting a symbol in eval-after-load.  The test it
> uses is just:
> 
>         (assoc file load-history)
> 
> The cars of load-history are all strings, so I can't see how it would find
> a symbol among them.  And it continues to stubbornly return a 1 for that
> example when I use 'simple.

23.0.60, but I also checked 22.1 and that contains both the feature
and the "smarter" eval-after-load.

> 
> Clearly something has changed across versions.
> 

Clearly, but 21.3.1 is ancient: it was released March 24, 2003 (and the
emacs page also indicates that 21.4 was released to fix a security hole,
so one way or another, you should upgrade.)

Regards,
Nick

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Docs submitted (Was Re: Advice sought on managing decision alternatives.)
  2009-02-12 20:13                                     ` Tom Breton (Tehom)
@ 2009-02-13  4:23                                       ` Manish
  0 siblings, 0 replies; 56+ messages in thread
From: Manish @ 2009-02-13  4:23 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode

On Fri, Feb 13, 2009 at 1:43 AM, Tom Breton (Tehom) wrote:
>> On Wed, Feb 11, 2009 at 4:18 AM, Tom Breton (Tehom) wrote:
>>> [...]
>>> I couldn't reproduce this. Is this on the same test file as before?
>>
>> Sorry for the delay in reply, Tom. I reproduce the situation below:
>>
>> First the test file.
>>
>> --8<---------------cut here---------------start------------->8---
>> #+CHOOSE_TODO: REJECTED(r) NOT_CHOSEN(n,-) MAYBE(,0)
>> LEANING_TOWARDS(l) CHOSEN(c,+)
>>
>> * Which editor to use?
>> *** LEANING_TOWARDS Emacs
>> *** LEANING_TOWARDS Vim
>> *** LEANING_TOWARDS Textmate
>> *** REJECTED Gedit
>> *** REJECTED Textpad
>> --8<---------------cut here---------------end--------------->8---
>>
>> 0. I have latest org-choose loaded, org-mode restarted, and local
>>  setup refreshed.
>> 1. S-right on the second item to switch it to CHOSEN state. It works.
>> 2. Now S-right on the first item to switch it to CHOSEN state. Also
>>  works.
>>
>> Both entries stay at CHOSEN state whereas I expected the second entry
>> to switch to a NON-CHOSEN state (possibly switching just one state
>> backwards not all the way back to REJECTED, but then I do not yet
>> understand it fully.)
>>
>> Is this the right behaviour? If yes, please help me understand this a
>> little. Or could I be doing or have something wrong in my setup?
>
> That's not right the behavior, but again I can't seem to reproduce this.
> Using your test file and following your instructions, I get the correct
> behavior. Specifically, after S-right on second item:
> [begin]
> * Which editor to use?
> *** NOT_CHOSEN Emacs
> *** CHOSEN Vim
> *** NOT_CHOSEN Textmate
> *** REJECTED Gedit
> *** REJECTED Textpad
> [end]
> Then after S-right on the first item, again correctly:
> [begin]
> * Which editor to use?
> *** MAYBE Emacs
> *** LEANING_TOWARDS Vim
> *** NOT_CHOSEN Textmate
> *** REJECTED Gedit
> *** REJECTED Textpad
> [end]
>
> Now there's clearly something different between my setup and yours that it
> causing a bug, but it's very difficult to diagnose and fix at a distance.
>
> I have a theory that it's caused by an unloaded library whose absence makes
> `org-map-entries' abort.
>
> What I'm going to try is to add a require for org-agenda. Will you try it
> and tell me whether it fixes the bug? Because I just can't see the bug in
> my setup.

I didn't know if you meant to send me a patch or try something myself.
I do not know any elisp but I interpreted your statement to mean
something like the following patch and tried but without success.  This
is with "GNU Emacs 22.3.1 (i386-mingw-nt5.1.2600) of 2008-09-06 on
SOFT-MJASON" and latest Org-mode compiled from git with uncompiled
org-choose.el.

--8<---------------cut here---------------start------------->8---
diff --git a/contrib/lisp/org-choose.el b/contrib/lisp/org-choose.el
index a5e8a19..1f54df6 100644
--- a/contrib/lisp/org-choose.el
+++ b/contrib/lisp/org-choose.el
@@ -65,6 +65,7 @@
 (require 'org)
 (eval-when-compile
    (require 'cl))
+(require 'org-agenda)

 ;;;_. Body
 ;;;_ , The variables
--8<---------------cut here---------------end--------------->8---

I am sure you meant something more intelligent. :-/

Thanks for looking into it.
-- 
Manish

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* Re: Patch Re: Docs submitted (Was Re: Advice sought on managing decision alternatives.)
  2009-02-12 20:55                                     ` Patch " Tom Breton (Tehom)
@ 2009-02-13  4:38                                       ` Manish
  0 siblings, 0 replies; 56+ messages in thread
From: Manish @ 2009-02-13  4:38 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode

On Fri, Feb 13, 2009 at 2:25 AM, Tom Breton (Tehom) wrote:
> Here is a patch that I hope will solve the problems people are having with
> org-choose.el. It contains two intended fixes:
>
> * `eval-after-load' gets a string argument. Apparently some emacsen can
> accept a symbol, but older ones can't.
> * "org-agenda" is required before `org-map-entries' is called. This is
> admittedly a quick and dirty fix, if it even works.

I saw this email just a moment after responding to the other thread.

No, it did not work.  I restarted Emacs and loaded org-choose.el both
using load-library and load-file (in case that makes a difference.)

Thanks
-- 
Manish

^ permalink raw reply	[flat|nested] 56+ messages in thread

* org-choose bugfix
  2009-02-10  7:55                           ` Carsten Dominik
@ 2009-02-24  0:51                             ` Tom Breton (Tehom)
  2009-02-24  3:05                               ` Manish
  2009-02-24  5:51                               ` Carsten Dominik
  0 siblings, 2 replies; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-02-24  0:51 UTC (permalink / raw)
  Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 242 bytes --]

Here is a bugfix for org-choose that I've been meaning to post.

The bug was this:

  When looking for alternatives, it looks at the whole tree, not just
  the immediate children.

Now fixed.  Patch is attached.

Tom Breton (Tehom)

[-- Attachment #2: org-choose.el.diff --]
[-- Type: application/octet-stream, Size: 778 bytes --]

*** old-org-choose.el	2009-02-13 14:18:01.000000000 -0500
--- org-choose.el	2009-02-14 21:29:46.000000000 -0500
***************
*** 388,395 ****
  	(save-excursion
  	  (unless (org-up-heading-safe)
  	    (error "Chosing is only supported between siblings in a tree, not on top level"))
! 	  (save-restriction
! 	    (org-map-entries fn nil 'tree)))))
  
  ;;;_  . org-choose-get-highest-mark-index
  
--- 388,400 ----
  	(save-excursion
  	  (unless (org-up-heading-safe)
  	    (error "Chosing is only supported between siblings in a tree, not on top level"))
! 	   (let
! 	      ((level (org-outline-level)))
! 	      (save-restriction
! 		 (org-map-entries 
! 		    fn
! 		    (format "LEVEL=%d" level)
! 		    'tree))))))
  
  ;;;_  . org-choose-get-highest-mark-index
  

[-- Attachment #3: Type: text/plain, Size: 204 bytes --]

_______________________________________________
Emacs-orgmode mailing list
Remember: use `Reply All' to send replies to the list.
Emacs-orgmode@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-orgmode

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: org-choose bugfix
  2009-02-24  0:51                             ` org-choose bugfix Tom Breton (Tehom)
@ 2009-02-24  3:05                               ` Manish
  2009-04-07  0:13                                 ` Tom Breton (Tehom)
  2009-02-24  5:51                               ` Carsten Dominik
  1 sibling, 1 reply; 56+ messages in thread
From: Manish @ 2009-02-24  3:05 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode

On Tue, Feb 24, 2009 at 6:21 AM, Tom Breton (Tehom) wrote:
> Here is a bugfix for org-choose that I've been meaning to post.
>
> The bug was this:
>
> When looking for alternatives, it looks at the whole tree, not just
> the immediate children.
>
> Now fixed. Patch is attached.

This seems to be already in the latest git.  And my test file now works!

Thanks.
-- 
Manish

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: org-choose bugfix
  2009-02-24  0:51                             ` org-choose bugfix Tom Breton (Tehom)
  2009-02-24  3:05                               ` Manish
@ 2009-02-24  5:51                               ` Carsten Dominik
  1 sibling, 0 replies; 56+ messages in thread
From: Carsten Dominik @ 2009-02-24  5:51 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode

Applied, thanks.

I added a call to `org-reduced-level' which it needed for
people who use `org-odd-levels-only'.

- Carsten

On Feb 24, 2009, at 1:51 AM, Tom Breton (Tehom) wrote:

> Here is a bugfix for org-choose that I've been meaning to post.
>
> The bug was this:
>
>  When looking for alternatives, it looks at the whole tree, not just
>  the immediate children.
>
> Now fixed.  Patch is attached.
>
> Tom Breton (Tehom)
> <org-choose.el.diff>

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: org-choose bugfix
  2009-02-24  3:05                               ` Manish
@ 2009-04-07  0:13                                 ` Tom Breton (Tehom)
  2009-04-08 13:13                                   ` Carsten Dominik
  0 siblings, 1 reply; 56+ messages in thread
From: Tom Breton (Tehom) @ 2009-04-07  0:13 UTC (permalink / raw)
  Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 473 bytes --]

I don't know how this slipped by me before, and I was sure that I had run
the test suite and validated the previous fix, but I just noticed a
serious bug, and patched it.

The bug is that org-choose uses the wrong number for "LEVEL", resulting in
no keep-sensible checking.  I attach a patch for it.  Also patched a doc
typo.  (6.25 is the OLD half of the patch - I fixed it and then realized I
had no old one to diff it to so I fetched the newest org-mode)

Tom

[-- Attachment #2: org-choose.el.diff --]
[-- Type: application/octet-stream, Size: 1223 bytes --]

cd /home/tehom/emacs-site-lisp/built/org-6.24c/contrib/lisp/
diff -c /home/tehom/emacs-site-lisp/built/org-6.25d/contrib/lisp/org-choose.el /home/tehom/emacs-site-lisp/built/org-6.24c/contrib/lisp/org-choose.el
*** /home/tehom/emacs-site-lisp/built/org-6.25d/contrib/lisp/org-choose.el	2009-04-05 09:30:47.000000000 -0400
--- /home/tehom/emacs-site-lisp/built/org-6.24c/contrib/lisp/org-choose.el	2009-04-06 16:11:42.000000000 -0400
***************
*** 388,396 ****
         (require 'org-agenda) ;; `org-map-entries' seems to need it.
  	(save-excursion
  	  (unless (org-up-heading-safe)
! 	    (error "Chosing is only supported between siblings in a tree, not on top level"))
  	  (let
!  	      ((level (org-reduced-level (org-outline-level))))
  	    (save-restriction
  	      (org-map-entries 
  	       fn
--- 388,396 ----
         (require 'org-agenda) ;; `org-map-entries' seems to need it.
  	(save-excursion
  	  (unless (org-up-heading-safe)
! 	    (error "Choosing is only supported between siblings in a tree, not on top level"))
  	  (let
!  	      ((level (1+ (org-reduced-level (org-outline-level)))))
  	    (save-restriction
  	      (org-map-entries 
  	       fn

Diff finished at Mon Apr  6 20:06:52

[-- Attachment #3: Type: text/plain, Size: 204 bytes --]

_______________________________________________
Emacs-orgmode mailing list
Remember: use `Reply All' to send replies to the list.
Emacs-orgmode@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-orgmode

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: org-choose bugfix
  2009-04-07  0:13                                 ` Tom Breton (Tehom)
@ 2009-04-08 13:13                                   ` Carsten Dominik
  0 siblings, 0 replies; 56+ messages in thread
From: Carsten Dominik @ 2009-04-08 13:13 UTC (permalink / raw)
  To: Tom Breton (Tehom); +Cc: emacs-orgmode

Applied, thanks.

- Carsten

On Apr 7, 2009, at 2:13 AM, Tom Breton (Tehom) wrote:

> I don't know how this slipped by me before, and I was sure that I  
> had run
> the test suite and validated the previous fix, but I just noticed a
> serious bug, and patched it.
>
> The bug is that org-choose uses the wrong number for "LEVEL",  
> resulting in
> no keep-sensible checking.  I attach a patch for it.  Also patched a  
> doc
> typo.  (6.25 is the OLD half of the patch - I fixed it and then  
> realized I
> had no old one to diff it to so I fetched the newest org-mode)
>
> Tom
> <org-choose.el.diff>_______________________________________________
> Emacs-orgmode mailing list
> Remember: use `Reply All' to send replies to the list.
> Emacs-orgmode@gnu.org
> http://lists.gnu.org/mailman/listinfo/emacs-orgmode

^ permalink raw reply	[flat|nested] 56+ messages in thread

end of thread, other threads:[~2009-04-08 13:13 UTC | newest]

Thread overview: 56+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20090101170227.C707734803@mail2.panix.com>
2009-01-01 22:53 ` Feature request and patch - blocked TODO to say BLOCKED Tom Breton (Tehom)
2009-01-09  8:16   ` Carsten Dominik
2009-01-15  2:34     ` Tom Breton (Tehom)
2009-01-17  8:01       ` Carsten Dominik
2009-01-19  3:33     ` Advice sought on managing decision alternatives Tom Breton (Tehom)
2009-01-22 11:15       ` Carsten Dominik
2009-01-31  4:21         ` Tom Breton (Tehom)
2009-01-31  5:41           ` Carsten Dominik
2009-01-31 18:36             ` Tom Breton (Tehom)
2009-02-01 15:54               ` James TD Smith
2009-02-06 13:08           ` Carsten Dominik
2009-02-06 16:16             ` William Henney
2009-02-06 20:07             ` Tom Breton (Tehom)
2009-02-07  0:18               ` Carsten Dominik
2009-02-07 20:46                 ` Tom Breton (Tehom)
2009-02-08 13:06                   ` Carsten Dominik
2009-02-08 20:25                     ` Tom Breton (Tehom)
2009-02-09  6:42                       ` Carsten Dominik
2009-02-10  3:14                         ` Docs submitted (Was Re: Advice sought on managing decision alternatives.) Tom Breton (Tehom)
2009-02-10  7:55                           ` Carsten Dominik
2009-02-24  0:51                             ` org-choose bugfix Tom Breton (Tehom)
2009-02-24  3:05                               ` Manish
2009-04-07  0:13                                 ` Tom Breton (Tehom)
2009-04-08 13:13                                   ` Carsten Dominik
2009-02-24  5:51                               ` Carsten Dominik
2009-02-10  8:46                           ` Docs submitted (Was Re: Advice sought on managing decision alternatives.) Manish
2009-02-10  9:12                             ` Carsten Dominik
2009-02-10 10:26                               ` Manish
2009-02-10 22:48                                 ` Tom Breton (Tehom)
2009-02-12 12:50                                   ` Manish
2009-02-12 20:13                                     ` Tom Breton (Tehom)
2009-02-13  4:23                                       ` Manish
2009-02-12 20:55                                     ` Patch " Tom Breton (Tehom)
2009-02-13  4:38                                       ` Manish
2009-02-11  1:08                                 ` Tom Breton (Tehom)
2009-02-11 10:34                                   ` Carsten Dominik
2009-02-11 21:41                                     ` Tom Breton (Tehom)
2009-02-11 23:38                                       ` Nick Dokos
2009-02-12  4:17                                         ` Tom Breton (Tehom)
2009-02-11 23:44                                       ` Carsten Dominik
2009-02-12  4:27                                         ` Tom Breton (Tehom)
2009-02-12 15:49                                           ` Nick Dokos
2009-02-12 20:32                                             ` Tom Breton (Tehom)
2009-02-12 21:25                                               ` Nick Dokos
2009-02-11 12:29                                   ` Carsten Dominik
2009-02-11 14:58                                     ` Docs submitted Bernt Hansen
2009-02-11 17:33                                       ` Samuel Wales
2009-02-11 15:38                                     ` Docs submitted (Was Re: Advice sought on managing decision alternatives.) Daniel Clemente
2009-02-11 15:41                                       ` Carsten Dominik
2009-02-11 20:02                                     ` Tom Breton (Tehom)
2009-02-11 23:45                                       ` Carsten Dominik
2009-02-11  1:45                                 ` Slight fix to update-org.sh Tom Breton (Tehom)
2009-02-10 23:19                               ` Docs submitted (Was Re: Advice sought on managing decision alternatives.) Tom Breton (Tehom)
2009-02-11 10:34                                 ` Carsten Dominik
2009-02-10 22:45                             ` Tom Breton (Tehom)
     [not found] <20090122112819.B30E12940C@mail1.panix.com>
2009-01-22 22:11 ` Advice sought on managing decision alternatives Tom Breton (Tehom)

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).