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.
_______________________________________________
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