forsooth!

By necessity, by proclivity, and by delight, we all quote.

Custom TODOs in org-mode


Setup

It’s easy to add your own TODO keywords to your org-mode configuration, you can cycle through them with S-<left> and S-<right> or select them with t, if you use evil bindings.

(setq org-todo-keywords
      '((sequence "TODO(t!)" "WAIT(w!)" "|" "DONE(d)" "CANCELLED(c)")
        (sequence "GOAL(g)" "|" "ACCOMPLISHED(a)")
        (sequence "READ(r)" "|" "DONE(d)")
        (sequence "WATCH(W)" "|" "DONE(d)")
        ))

All stated before a vertical bar | are states that still require some action, all states after it indicate the item no longer requires action, i.e. they are “done” states.

The letters in parentheses are the shortcuts you can use to select them after pressing t, and the ! adds a log entry whenever that state is entered. For example, the task below was set to WAIT and a bit later it became a TODO again. Certainly not needed for every state change, but I like it for those two, because a task might go through these states several times.

* TODO Do something
- State "TODO"       from "WAIT"       [2017-10-08 Sun 13:53]
- State "WAIT"       from "TODO"       [2017-10-08 Sun 13:31]

Configure style

By default all active TODOs are displayed in the same style as TODO itself, all inactive ones are displayed in the style of DONE. If you want some visual clews to make it more obvious at a quick glance at your todo list, then you can configure each keyword to your heart’s content.

(setq org-todo-keyword-faces
      '(("WAIT" . org-warning)
        ("CANCELLED" . (:foreground "#657700" :weight bold))))

Here I simply used the org-warning face for WAIT, because it works well. For CANCELLED I wanted something very like DONE, but somewhat faded to set it apart from DONE tasks.

Define clock-stopping states

Changing to DONE (or any other closing state) while clocked into a TODOs heading will automatically clock out of that heading. However, some states might not close the TODO and still should result in a clock out. For instance, in my setup that’s the state WAIT. Luckily this sort of thing is supported as well, you can provide a list of states that end a clock:

(setq org-clock-out-when-done '("DONE" "WAIT"))

Avoid certain states as default

Using the appropriate shortcut (e.g. T in evil-org-mode) on a TODO headline will create another TODO headline below it, and it’ll default to the same TODO state the current headline has.

This isn’t desirable for states like WAIT, as it is an unlikely starting point for a new TODO. The following code shows how to control the keyword for that situation.

(defun pick-default-todo-keyword-instead-of-wait (new-mark old-mark)
  (if (and
        (eq old-mark nil)
        (string= new-mark "WAIT")) "TODO" nil))
(setq org-todo-get-default-hook '(pick-default-todo-keyword-instead-of-wait))
#+TITLE: Custom TODOs in org-mode
#+DATE: <2017-10-08 Sun>
#+AUTHOR: @or
#+CATEGORY: tech
#+SUMMARY: Configuring cycles of TODO keywords
#+SLUG: org-mode-custom-todos
#+TAGS: org, spacemacs

** Setup
It's easy to add your own =TODO= keywords to your =org-mode= configuration, you
can cycle through them with =S-<left>= and =S-<right>= or select them with =t=,
if you use =evil= bindings.

#+begin_src emacs-lisp
(setq org-todo-keywords
      '((sequence "TODO(t!)" "WAIT(w!)" "|" "DONE(d)" "CANCELLED(c)")
        (sequence "GOAL(g)" "|" "ACCOMPLISHED(a)")
        (sequence "READ(r)" "|" "DONE(d)")
        (sequence "WATCH(W)" "|" "DONE(d)")
        ))
#+end_src

All stated before a vertical bar =|= are states that still require some action,
all states after it indicate the item no longer requires action, i.e. they are
"done" states.

The letters in parentheses are the shortcuts you can use to select them after
pressing =t=, and the =!= adds a log entry whenever that state is entered. For
example, the task below was set to =WAIT= and a bit later it became a =TODO=
again. Certainly not needed for every state change, but I like it for those two,
because a task might go through these states several times.

#+begin_src org
,* TODO Do something
- State "TODO"       from "WAIT"       [2017-10-08 Sun 13:53]
- State "WAIT"       from "TODO"       [2017-10-08 Sun 13:31]
#+end_src

** Configure style
By default all active =TODOs= are displayed in the same style as =TODO= itself,
all inactive ones are displayed in the style of =DONE=. If you want some visual
clews to make it more obvious at a quick glance at your todo list, then you can
configure each keyword to your heart's content.

#+begin_src emacs-lisp
(setq org-todo-keyword-faces
      '(("WAIT" . org-warning)
        ("CANCELLED" . (:foreground "#657700" :weight bold))))
#+end_src

Here I simply used the =org-warning= face for =WAIT=, because it works well. For
=CANCELLED= I wanted something very like =DONE=, but somewhat faded to set it
apart from =DONE= tasks.

** Define clock-stopping states
Changing to =DONE= (or any other closing state) while clocked into a =TODO='s
heading will automatically clock out of that heading. However, some states might
not close the =TODO= and still should result in a clock out. For instance, in my
setup that's the state =WAIT=. Luckily this sort of thing is supported as well,
you can provide a list of states that end a clock:

#+begin_src emacs-lisp
(setq org-clock-out-when-done '("DONE" "WAIT"))
#+end_src

** Avoid certain states as default
Using the appropriate shortcut (e.g. =T= in =evil-org-mode=) on a =TODO=
headline will create another =TODO= headline below it, and it'll default to the
same =TODO= state the current headline has.

This isn't desirable for states like =WAIT=, as it is an unlikely starting point
for a new =TODO=. The following code shows how to control the keyword for that
situation.
#+begin_src emacs-lisp
(defun pick-default-todo-keyword-instead-of-wait (new-mark old-mark)
  (if (and
        (eq old-mark nil)
        (string= new-mark "WAIT")) "TODO" nil))
(setq org-todo-get-default-hook '(pick-default-todo-keyword-instead-of-wait))
#+end_src