Since the last time I blogged about org-mode, I’ve been using it much more extensively. I now use it for basically all of my organization, both at home and for work. I try and reflect on my workflow and how it could be improved regularly; what I describe in this entry is just my current one.
My org-mode agenda files are all in the same level. Each one represents either a project or collection of smaller projects - I like to keep the number of agenda files I have down, so for example smaller programming projects are all in ‘technical.org’. These files are generally trees of TODO items, most of which are either scheduled or depend on another item. These scheduled dates are more of a suggestion; they ensure that I see the item at some point in the near future, but I often do them either before or after they are scheduled.
At this point, I’ll start describing my customizations and how I use them. First, I get the latest version of org-mode; the one that comes with Emacs doesn’t have all the features I use.
;;Checkout the latest version of org mode, if I don't already have it.
(unless (file-exists-p "~/.emacs.d/elisp/org-mode/")
(let ((default-directory "~/.emacs.d/elisp/"))
(shell-command "git clone git://repo.or.cz/org-mode.git")
(shell-command "make -C org-mode/")
(add-to-list 'load-path "~/.emacs.d/elisp/org-mode/lisp/")
(add-to-list 'load-path "~/.emacs.d/elisp/org-mode/contrib/lisp/")
I have a few customizations for my general agenda view. I change the color of upcoming deadlines, as the default had the same color as regular items. I have my agenda start on the current day; no point in seeing previous day’s schedules. Items that have deadlines are displayed 10 days in advance, and I don’t display items that are done in my agenda.
(setq org-upcoming-deadline '(:foreground "blue" :weight bold))
(setq org-agenda-start-on-weekday nil)
(setq org-deadline-warning-days 10)
(setq org-agenda-skip-deadline-if-done t)
(setq org-agenda-skip-scheduled-if-done t)
One feature that I’ve started to use more, but often forget about, is org’s clocking mechanism. It will record how much tieme you spend on tasks. The variables I define here will make the clock persist in case you close emacs, and prompt for splitting the time if you leave while clocked in. The function and hook will prompt for an effort estimate when clocking in to a task if it doesn’t already have one; I plan on using both the clocking and estimating to improve my estimation and scheduling skills.
(setq org-clock-idle-time 15)
(setq org-clock-out-remove-zero-time-clocks t)
(setq org-clock-persist 'history)
(defun my-org-mode-ask-effort ()
"Ask for an effort estimate when clocking in."
(unless (org-entry-get (point) "Effort")
(org-entry-get-multivalued-property (point) "Effort"))))
(unless (equal effort "")
(org-set-property "Effort" effort)))))
(add-hook 'org-clock-in-prepare-hook 'my-org-mode-ask-effort)
org-remember is used to take quick notes and store them for later. Many people have a fairly customized version; I personally have a very simple one. When I press C-r, a buffer pops up with a TODO entry begun that I can write into. When I close the buffer, this note is saved into a file that I go through on a weekly basis and move tasks to their correct location. This is helped by refiling, which will prompt for a location and send the region or headline you are on to it. The locations I have set up are my agenda files, and their level-1 headings.
`(("Todo" ?t "* TODO %?\n %i\n " ,(concat org-directory "remember.org") "Tasks")))
(setq org-default-notes-file (concat org-directory "/remember.org"))
(setq org-outline-path-complete-in-steps t)
(setq org-refile-use-outline-path 'file)
(setq org-refile-targets '((org-agenda-files . (:level . 1))))
These are just some general org-mode customizations to make org better. I don’t like org inserting blank lines, and I do like ido. org-insert-heading-respect-content will make new headings appear after the content for the current one, which is usually the behavior I want. Allowing return to follow links makes navigation much easier. org-special-ctrl-a/e will rebind ctrl-a and ctrl-e to make more sense in org mode, going to the beginning and end of the heading instead of the current line. This is actually a bit inaccurate - ctrl-a cycles between beginning of heading and beginning of line, which helps with speed commands. Enabling speed commands will rebind certain one-letter keybindings when the cursor is at the beginning of the row - most notably ‘t’ for org-todo instead of ‘C-c C-t’, a huge increase in efficiency.
Each of my agenda files has a corresponding archive file, where I put completed tasks with org-archive-subtree. Unfortunately, org-archive-subtree doesn’t keep the context of the tree you archive, except in a string; I’ve been meaning to take a look at fixing this, but don’t have the time. If you have a solution, please let me know about it.
(setq org-blank-before-new-entry '((heading . nil) (plain-list-item . nil)))
(setq org-completion-use-ido t)
(setq org-insert-heading-respect-content t)
(setq org-return-follows-link t)
(setq org-special-ctrl-a/e t)
(setq org-use-speed-commands t)
(setq org-speed-commands-user nil)
(setq org-startup-align-all-tables t)
(setq org-treat-S-cursor-todo-selection-as-state-change nil)
(setq org-archive-location (concat org-directory "archive/%s_archive::"))
org-depends is a module that allows you to enforce dependencies of tasks that have the same parent. If you add the following :PROPERTIES: string to a task:
:TRIGGER: chain-siblings-scheduled chain-siblings(TODO)
Once the task is set to DONE, it will automatically schedule the next item in the subtree for the current day and set it to TODO. I would prefer for it to be able to schedule for an offset from the current day, but this in itself is fairly useful.
(when (locate-library "org-depend") (require 'org-depend))
(setq org-enforce-todo-dependencies t)
I also have customized my TODO commands. Instead of the default states of TODO and DONE, I’ve added CANCELED, STALLED, FUTURE, and PENDING, to more accurately represent the state my tasks can be in. I log the time a task is either completed or put into a PENDING, CANCELED, or STALLED state, and setting an item to either CANCELED, STALLED, or PENDING will prompt for a reason and log this reason. Each command has a ’short’ keybinding that can be used to quickly changed the state.
(setq org-log-done 'time)
'((sequence "TODO(t)" "|" "DONE(d!)")
(sequence "|" "CANCELED(c@/!)")
(sequence "|" "STALLED(s@/!)")
(sequence "FUTURE(f)" "|")
(sequence "PENDING(p@/!)" "|" )))
'(("CANCELED" . (:foreground "blue" :weight bold))
("STALLED" . (:foreground "RED" :weight bold))
("FUTURE" . (:foreground "dark green" :weight bold))
("PENDING" . (:foreground "orange" :weight bold))))
I use PENDING to represent tasks that need some input from others, and so I need to periodically review these tasks to see if I have said input. To do this, I created an agenda command which will display every pending task in my agenda files:
(quote (("p" "Pending Tasks" todo "PENDING" ((org-agenda-todo-ignore-scheduled nil)
The following function just adds a timestamp for the current time, making logging easier
(defun bh/insert-inactive-timestamp ()
"Insert a timestamp for the current time at point."
(org-insert-time-stamp nil t t nil nil nil)))
I rebind a few keys for org-mode to make it more efficient. I don’t use the arrow keys to navigate, so I rebind them to promote and demote subtrees, and have a few other convenient keybindings.
(define-key org-mode-map (kbd "<left>") 'org-promote-subtree)
(define-key org-mode-map (kbd "C-t") 'org-todo)
(define-key org-mode-map (kbd "<right>") 'org-demote-subtree)
(global-set-key (kbd "C-c i") 'bh/insert-inactive-timestamp)
(global-set-key "\C-ca" 'org-agenda)
(global-set-key "\C-cl" 'org-store-link)
(define-key global-map "\C-cr" 'org-remember)
Another org feature I use is habit tracking. Add the following :PROPERTIES: drawer to your tree for a repeating task, and in your agenda you will be shown a neat graph of how well you’ve been doing at keeping to the habit. I use it more than I should, since it also hides the item from view until it is scheduled, which I haven’t found a way to do on a per-item basis yet.
:LAST_REPEAT: [2010-02-15 Mon 07:35]
(setq org-habit-graph-column 60)
(add-to-list 'org-modules 'org-habit)
Finally, activate org and ‘C-a a’ will take you to your agenda!