Org Mode - Organize Your Life In Plain Text!

原文链接

Table of Contents

Org-mode is a fabulous organizational tool originally built by CarstenDominik that operates on plain text files. Org-mode is part of Emacs.

1 How To Use This Document

This document assumes you've had some exposure to org-mode already soconcepts like the agenda, capture mode, etc. won't be completelyforeign to you. More information about org-mode can be found in theOrg-Mode Manual and on the Worg Site.

I have been using org-mode as my personal information manager foryears now. I started small with just the default TODO and DONEkeywords. I added small changes to my workflow and over time itevolved into what is described by this document.

I still change my workflow and try new things regularly. Thisdocument describes mature workflows in my current org-mode setup. Itend to document changes to my workflow 30 days after implementingthem (assuming they are still around at that point) so that the newworkflow has a chance to mature.

Some of the customized Emacs settings described in this document areset at their default values. This explicitly shows the setting forimportant org-mode variables used in my workflow and to keep myworkflow behaviour stable in the event that the default value changesin the future.

This document is available as an org file which you can load in Emacsand tangle with C-c C-v C-t which will create org-mode.el in thesame directory as the org-mode.org file. This will extract all of theelisp examples in this document into a file you can include in your.emacs file.

2 License

Copyright (C)  2013  Bernt Hansen.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
  
Code in this document 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 3 of the License, or (at your option) any later version.
  
This code 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.

This document http://doc.norang.ca/org-mode.html (either in itsHTML format or in its Org format) is licensed under the GNU FreeDocumentation License version 1.3 or later(http://www.gnu.org/copyleft/fdl.html).

The code examples and CSS stylesheets are licensed under the GNUGeneral Public License v3 or later(http://www.gnu.org/licenses/gpl.html).

3 Change History - What's new

This is version 2015.06-5-gf5bb of this document. Thisdocument is created using the publishing features of org-mode gitversion release_8.2.10-42-g2e1bc42.

The source for this document can be found as a plain text org file. Itry to update this document about once a month.

The change history for this document can be found atgit://git.norang.ca/org-mode-doc.git.

4 Getting Started

Getting started with org-mode is really easy. You only need a few lines in youremacs startup to use the latest version of org-mode from the git repository.

4.1 Getting org-mode with Git

I keep a copy of the org-mode git repository in ~/git/org-mode/. This clonewas created with

cd ~/git
git clone git://orgmode.org/org-mode.git

To update and get new commits from the org-mode developers you can use

cd ~/git/org-mode
git pull
make uncompiled

I run uncompiled source files in my setup so the uncompiled make target is all you need.

I normally track the master branch in the org-mode repository.

4.2 Org-Mode Setup

The following setup in my .emacs enables org-mode for most buffers.org-mode is the default mode for .org, .org_archive, and .txtfiles.

;;;
;;; Org Mode
;;;
(add-to-list 'load-path (expand-file-name "~/git/org-mode/lisp"))
(add-to-list 'auto-mode-alist '("\\.\\(org\\|org_archive\\|txt\\)$" . org-mode))
(require 'org)
;;
;; Standard key bindings
(global-set-key "\C-cl" 'org-store-link)
(global-set-key "\C-ca" 'org-agenda)
(global-set-key "\C-cb" 'org-iswitchb)

That's all you need to get started using headlines and lists in org-mode.

The rest of this document describes customizations I use in my setup,how I structure org-mode files, and other changes to fit the way Iwant org-mode to work.

4.3 Organizing Your Life Into Org Files

Tasks are separated into logical groupings or projects. Use separate org files for large task groupings and subdirectories for collections of files for multipleprojects that belong together.

Here are sample files that I use.

The following org files collect non-work related tasks:

FilenameDescription
todo.orgPersonal tasks and things to keep track of
gsoc2009.orgGoogle Summer of Code stuff for 2009
farm.orgFarm related tasks
mark.orgTasks related to my son Mark
org.orgOrg-mode related tasks
git.orgGit related tasks

The following org-file collects org capture notes and tasks:

FilenameDescription
refile.orgCapture task bucket

The following work-related org-files keep my business notes (usingfictitious client names)

FilenameDescription
norang.orgNorang tasks and notes
XYZ.orgXYZ Corp tasks and notes
ABC.orgABC Ltd tasks
ABC-DEF.orgABC Ltd tasks for their client DEF Corp
ABC-KKK.orgABC Ltd tasks for their client KKK Inc
YYY.orgYYY Inc tasks

Org-mode is great for dealing with multiple clients and clientprojects. An org file becomes the collection of projects, notes,etc. for a single client or client-project.

Client ABC Ltd. has multiple customer systems that I work on.Separating the tasks for each client-customer into separate org fileshelps keep things logically grouped and since clients come and go thisallows entire org files to be added or dropped from my agenda to keeponly what is important visible in agenda views.

Other org files are used for publishing only and do not contribute to the agenda.See Publishing and Exporting for more details.

4.4 Agenda Setup

Here is my current org-agenda-files setup.

(setq org-agenda-files (quote ("~/git/org"
                               "~/git/org/client1"
                               "~/git/client2")))

org-mode manages the org-agenda-files variable automatically usingC-c [ and C-c ] to add and remove files respectively. However,this replaces my directory list with a list of explicit filenamesinstead and is not what I want. If this occurs then adding a new orgfile to any of the above directories will not contribute to my agendaand I will probably miss something important.

I have disabled the C-c [ and C-c ] keys in org-mode-hook toprevent messing up my list of directories in the org-agenda-filesvariable. I just add and remove directories manually in my .emacsfile. Changing the list of directories in org-agenda-files happensvery rarely since new files in existing directories are automaticallypicked up.

I also disable the comment function C-c ; since I never use those.I kept accidentally hitting this key sequence when doing C-csinglequote for editing source blocks.

In the example above I have ~/git/client2 in a separate gitrepository from ~/git/org. This gives me the flexibility of leavingconfidential information at the client site and having all of mypersonal information available everywhere I use org-mode. Isynchronize my personal repositories on multiple machines and skip theconfidential info on the non-client laptop I travel with.org-agenda-files on this laptop does not include the ~/git/client2directory.

4.5 Org File Structure

Most of my org files are set up with level 1 headings as maincategories only. Tasks and projects normally start as level 2.

Here are some examples of my level 1 headings in

todo.org:

  • Special Dates

    Includes level 2 headings for

    • Birthdays
    • Anniversaries
    • Holidays
  • Finances
  • Health and Recreation
  • House Maintenance
  • Lawn and Garden Maintenance
  • Notes
  • Tasks
  • Vehicle Maintenance
  • Passwords

norang.org:

  • System Maintenance
  • Payroll
  • Accounting
  • Finances
  • Hardware Maintenance
  • Tasks
  • Research and Development
  • Notes
  • Purchase Order Tracking
  • Passwords

Each of these level 1 tasks normally has a property drawerspecifying the category for any tasks in that tree. Level 1 headingsare set up like this:

* Health and Recreation
  :PROPERTIES:
  :CATEGORY: Health
  :END:
  ...
* House Maintenance
  :PROPERTIES:
  :CATEGORY: House
  :END:

4.6 Key bindings

I live in the agenda. To make getting to the agenda faster I mappedF12 to the sequence C-c a since I'm using it hundreds of times aday.

I have the following custom key bindings set up for my emacs (sorted by frequency).

KeyForUsed
F12Agenda (1 key less than C-c a)Very Often
C-c bSwitch to org fileVery Often
F11Goto currently clocked itemVery Often
C-c cCapture a taskVery Often
C-F11Clock in a task (show menu with prefix)Often
f9 gGnus - I check mail regularlyOften
f5Show todo items for this subtreeOften
S-f5WidenOften
f9 bQuick access to bbdb dataOften
f9 cCalendar accessOften
C-S-f12Save buffers and publish current projectOften
C-c lStore a link for retrieval with C-c C-lOften
f8Go to next org file in org-agenda-filesSometimes
f9 rBoxquote selected regionSometimes
f9 tInsert inactive timestampSometimes
f9 vToggle visible mode (for showing/editing links)Sometimes
C-f9Previous bufferSometimes
C-f10Next bufferSometimes
C-x n rNarrow to regionSometimes
f9 fBoxquote insert a fileSometimes
f9 iInfo manualSometimes
f9 IPunch Clock InSometimes
f9 OPunch Clock OutSometimes
f9 oSwitch to org scratch bufferSometimes
f9 sSwitch to scratch bufferSometimes
f9 hHide other tasksRare
f7Toggle line truncation/wrapRare
f9 TToggle insert inactive timestampRare
C-c aEnter Agenda (minimal emacs testing)Rare

Here is the keybinding setup in lisp:

;; Custom Key Bindings
(global-set-key (kbd "<f12>") 'org-agenda)
(global-set-key (kbd "<f5>") 'bh/org-todo)
(global-set-key (kbd "<S-f5>") 'bh/widen)
(global-set-key (kbd "<f7>") 'bh/set-truncate-lines)
(global-set-key (kbd "<f8>") 'org-cycle-agenda-files)
(global-set-key (kbd "<f9> <f9>") 'bh/show-org-agenda)
(global-set-key (kbd "<f9> b") 'bbdb)
(global-set-key (kbd "<f9> c") 'calendar)
(global-set-key (kbd "<f9> f") 'boxquote-insert-file)
(global-set-key (kbd "<f9> g") 'gnus)
(global-set-key (kbd "<f9> h") 'bh/hide-other)
(global-set-key (kbd "<f9> n") 'bh/toggle-next-task-display)

(global-set-key (kbd "<f9> I") 'bh/punch-in)
(global-set-key (kbd "<f9> O") 'bh/punch-out)

(global-set-key (kbd "<f9> o") 'bh/make-org-scratch)

(global-set-key (kbd "<f9> r") 'boxquote-region)
(global-set-key (kbd "<f9> s") 'bh/switch-to-scratch)

(global-set-key (kbd "<f9> t") 'bh/insert-inactive-timestamp)
(global-set-key (kbd "<f9> T") 'bh/toggle-insert-inactive-timestamp)

(global-set-key (kbd "<f9> v") 'visible-mode)
(global-set-key (kbd "<f9> l") 'org-toggle-link-display)
(global-set-key (kbd "<f9> SPC") 'bh/clock-in-last-task)
(global-set-key (kbd "C-<f9>") 'previous-buffer)
(global-set-key (kbd "M-<f9>") 'org-toggle-inline-images)
(global-set-key (kbd "C-x n r") 'narrow-to-region)
(global-set-key (kbd "C-<f10>") 'next-buffer)
(global-set-key (kbd "<f11>") 'org-clock-goto)
(global-set-key (kbd "C-<f11>") 'org-clock-in)
(global-set-key (kbd "C-s-<f12>") 'bh/save-then-publish)
(global-set-key (kbd "C-c c") 'org-capture)

(defun bh/hide-other ()
  (interactive)
  (save-excursion
    (org-back-to-heading 'invisible-ok)
    (hide-other)
    (org-cycle)
    (org-cycle)
    (org-cycle)))

(defun bh/set-truncate-lines ()
  "Toggle value of truncate-lines and refresh window display."
  (interactive)
  (setq truncate-lines (not truncate-lines))
  ;; now refresh window display (an idiom from simple.el):
  (save-excursion
    (set-window-start (selected-window)
                      (window-start (selected-window)))))

(defun bh/make-org-scratch ()
  (interactive)
  (find-file "/tmp/publish/scratch.org")
  (gnus-make-directory "/tmp/publish"))

(defun bh/switch-to-scratch ()
  (interactive)
  (switch-to-buffer "*scratch*"))

The main reason I have special key bindings (like F11, and F12) isso that the keys work in any mode. If I'm in the Gnus summary bufferthen C-u C-c C-x C-i doesn't work, but the C-F11 key combinationdoes and this saves me time since I don't have to visit an org-modebuffer first just to clock in a recent task.

5 Tasks and States

I use one set of TODO keywords for all of my org files. Org-mode letsyou define TODO keywords per file but I find it's easier to have astandard set of TODO keywords globally so I can use the same setup inany org file I'm working with.

The only exception to this is this document :) since I don't wantorg-mode hiding the TODO keyword when it appears in headlines.I've set up a dummy #+SEQ_TODO: FIXME FIXED entry at the top of thisfile just to leave my TODO keyword untouched in this document.

5.1 TODO keywords

I use a light colour theme in emacs. I find this easier to read on bright sunny days.

Here are my TODO state keywords and colour settings:

(setq org-todo-keywords
      (quote ((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d)")
              (sequence "WAITING(w@/!)" "HOLD(h@/!)" "|" "CANCELLED(c@/!)" "PHONE" "MEETING"))))

(setq org-todo-keyword-faces
      (quote (("TODO" :foreground "red" :weight bold)
              ("NEXT" :foreground "blue" :weight bold)
              ("DONE" :foreground "forest green" :weight bold)
              ("WAITING" :foreground "orange" :weight bold)
              ("HOLD" :foreground "magenta" :weight bold)
              ("CANCELLED" :foreground "forest green" :weight bold)
              ("MEETING" :foreground "forest green" :weight bold)
              ("PHONE" :foreground "forest green" :weight bold))))
5.1.1 Task States

Tasks go through the sequence TODO -> DONE.

The following diagram shows the possible state transitions for a task.

normal_task_states.png

5.1.2 Project Task States

I use a lazy project definition. I don't like to bother with manuallystating 'this is a project' and 'that is not a project'. For me a projectdefinition is really simple. If a task has subtasks with a todo keywordthen it's a project. That's it.

Projects can be defined at any level - just create a task with a todostate keyword that has at least one subtask also with a todo statekeyword and you have a project. Projects use the same todo keywordsas regular tasks. One subtask of a project needs to be marked NEXTso the project is not on the stuck projects list.

5.1.3 Phone Calls

Telephone calls are special. They are created in a done state by a capture task.The time of the call is recorded for as long as the capture task is active. If I need to look up other details and want to close the capture task early I can just C-c C-c to close the capture task (stopping the clock) and then f9 SPC to resumethe clock in the phone call while I do other things.

phone_states.png

5.1.4 Meetings

Meetings are special. They are created in a done state by a capturetask. I use the MEETING capture template when someone interrupts whatI'm doing with a question or discussion. This is handled similarly tophone calls where I clock the amount of time spent with whomever it isand record some notes of what was discussed (either during or afterthe meeting) depending on content, length, and complexity of thediscussion.

The time of the meeting is recorded for as long as the capture task isactive. If I need to look up other details and want to close thecapture task early I can just C-c C-c to close the capture task(stopping the clock) and then f9 SPC to resume the clock in themeeting task while I do other things.

meeting_states.png

5.2 Fast Todo Selection

Fast todo selection allows changing from any task todo state to anyother state directly by selecting the appropriate key from the fasttodo selection key menu. This is a great feature!

(setq org-use-fast-todo-selection t)

Changing a task state is done with C-c C-t KEY

where KEY is the appropriate fast todo state selection key as defined in org-todo-keywords.

The setting

(setq org-treat-S-cursor-todo-selection-as-state-change nil)

allows changing todo states with S-left and S-right skipping all ofthe normal processing when entering or leaving a todo state. Thiscycles through the todo states but skips setting timestamps andentering notes which is very convenient when all you want to do is fixup the status of an entry.

5.3 TODO state triggers

I have a few triggers that automatically assign tags to tasks based onstate changes. If a task moves to CANCELLED state then it gets aCANCELLED tag. Moving a CANCELLED task back to TODO removes theCANCELLED tag. These are used for filtering tasks in agenda viewswhich I'll talk about later.

The triggers break down to the following rules:

  • Moving a task to CANCELLED adds a CANCELLED tag
  • Moving a task to WAITING adds a WAITING tag
  • Moving a task to HOLD adds WAITING and HOLD tags
  • Moving a task to a done state removes WAITING and HOLD tags
  • Moving a task to TODO removes WAITING, CANCELLED, and HOLD tags
  • Moving a task to NEXT removes WAITING, CANCELLED, and HOLD tags
  • Moving a task to DONE removes WAITING, CANCELLED, and HOLD tags

The tags are used to filter tasks in the agenda views conveniently.

(setq org-todo-state-tags-triggers
      (quote (("CANCELLED" ("CANCELLED" . t))
              ("WAITING" ("WAITING" . t))
              ("HOLD" ("WAITING") ("HOLD" . t))
              (done ("WAITING") ("HOLD"))
              ("TODO" ("WAITING") ("CANCELLED") ("HOLD"))
              ("NEXT" ("WAITING") ("CANCELLED") ("HOLD"))
              ("DONE" ("WAITING") ("CANCELLED") ("HOLD")))))

6 Adding New Tasks Quickly with Org Capture

Org Capture mode replaces remember mode for capturing tasks and notes.

To add new tasks efficiently I use a minimal number of capturetemplates. I used to have lots of capture templates, one for eachorg-file. I'd start org-capture with C-c c and then pick a templatethat filed the task under * Tasks in the appropriate file.

I found I still needed to refile these capture tasks again to thecorrect location within the org-file so all of these different capturetemplates weren't really helping at all. Since then I've changed myworkflow to use a minimal number of capture templates – I create thenew task quickly and refile it once. This also saves me frommaintaining my org-capture templates when I add a new org file.

6.1 Capture Templates

When a new task needs to be added I categorize it into one of a fewthings:

  • A phone call (p)
  • A meeting (m)
  • An email I need to respond to (r)
  • A new task (t)
  • A new note (n)
  • An interruption (j)
  • A new habit (h)

and pick the appropriate capture task.

Here is my setup for org-capture

(setq org-directory "~/git/org")
(setq org-default-notes-file "~/git/org/refile.org")

;; I use C-c c to start capture mode
(global-set-key (kbd "C-c c") 'org-capture)

;; Capture templates for: TODO tasks, Notes, appointments, phone calls, meetings, and org-protocol
(setq org-capture-templates
      (quote (("t" "todo" entry (file "~/git/org/refile.org")
               "* TODO %?\n%U\n%a\n" :clock-in t :clock-resume t)
              ("r" "respond" entry (file "~/git/org/refile.org")
               "* NEXT Respond to %:from on %:subject\nSCHEDULED: %t\n%U\n%a\n" :clock-in t :clock-resume t :immediate-finish t)
              ("n" "note" entry (file "~/git/org/refile.org")
               "* %? :NOTE:\n%U\n%a\n" :clock-in t :clock-resume t)
              ("j" "Journal" entry (file+datetree "~/git/org/diary.org")
               "* %?\n%U\n" :clock-in t :clock-resume t)
              ("w" "org-protocol" entry (file "~/git/org/refile.org")
               "* TODO Review %c\n%U\n" :immediate-finish t)
              ("m" "Meeting" entry (file "~/git/org/refile.org")
               "* MEETING with %? :MEETING:\n%U" :clock-in t :clock-resume t)
              ("p" "Phone call" entry (file "~/git/org/refile.org")
               "* PHONE %? :PHONE:\n%U" :clock-in t :clock-resume t)
              ("h" "Habit" entry (file "~/git/org/refile.org")
               "* NEXT %?\n%U\n%a\nSCHEDULED: %(format-time-string \"%<<%Y-%m-%d %a .+1d/3d>>\")\n:PROPERTIES:\n:STYLE: habit\n:REPEAT_TO_STATE: NEXT\n:END:\n"))))

Capture mode now handles automatically clocking in and out of acapture task. This all works out of the box now without special hooks.When I start a capture mode task the task is clocked in as specifiedby :clock-in t and when the task is filed with C-c C-c the clock resumes on the original clocking task.

The quick clocking in and out of capture mode tasks (often it takesless than a minute to capture some new task details) can leaveempty clock drawers in my tasks which aren't really useful. Since Iremove clocking lines with 0:00 length I end up with a clock drawerlike this:

* TODO New Capture Task
  :LOGBOOK:
  :END:
  [2010-05-08 Sat 13:53]

I have the following setup to remove these empty LOGBOOK drawers ifthey occur.

;; Remove empty LOGBOOK drawers on clock out
(defun bh/remove-empty-drawer-on-clock-out ()
  (interactive)
  (save-excursion
    (beginning-of-line 0)
    (org-remove-empty-drawer-at "LOGBOOK" (point))))

(add-hook 'org-clock-out-hook 'bh/remove-empty-drawer-on-clock-out 'append)

6.2 Separate file for Capture Tasks

I have a single org file which is the target for my capture templates.

I store notes, tasks, phone calls, and org-protocol tasks inrefile.org. I used to use multiple files but found that didn'treally have any advantage over a single file.

Normally this file is empty except for a single line at the top whichcreates a REFILE tag for anything in the file.

The file has a single permanent line at the top like this

#+FILETAGS: REFILE

6.3 Capture Tasks is all about being FAST

Okay I'm in the middle of something and oh yeah - I have to rememberto do that. I don't stop what I'm doing. I'm probably clocking aproject I'm working on and I don't want to lose my focus on that but Ican't afford to forget this little thing that just came up.

So what do I do? Hit C-c c to start capture mode and select tsince it's a new task and I get a buffer like this:

* TODO 
  [2010-08-05 Thu 21:06]

  Capture Tasks is all about being FAST

Enter the details of the TODO item and C-c C-c to file it away inrefile.org and go right back to what I'm really working on secure inthe knowledge that that item isn't going to get lost and I don't haveto think about it anymore at all now.

The amount of time I spend entering the captured note is clocked. Thecapture templates are set to automatically clock in and out of thecapture task. This is great for interruptions and telephone callstoo.

7 Refiling Tasks

Refiling tasks is easy. After collecting a bunch of new tasks in myrefile.org file using capture mode I need to move these to thecorrect org file and topic. All of my active org-files are in myorg-agenda-files variable and contribute to the agenda.

I collect capture tasks in refile.org for up to a week. These nowstand out daily on my block agenda and I usually refile them duringthe day. I like to keep my refile task list empty.

7.1 Refile Setup

To refile tasks in org you need to tell it where you want to refile things.

In my setup I let any file in org-agenda-files and the current filecontribute to the list of valid refile targets.

I've recently moved to using IDO to complete targets directly. I findthis to be faster than my previous complete in steps setup. At firstI didn't like IDO but after reviewing the documentation again andlearning about C-SPC to limit target searches I find it is muchbetter than my previous complete-in-steps setup. Now when I want torefile something I do C-c C-w to start the refile process, then typesomething to get some matching targets, then C-SPC to restrict thematches to the current list, then continue searching with some othertext to find the target I need. C-j also selects the currentcompletion as the final target. I like this a lot. I show fulloutline paths in the targets so I can have the same heading inmultiple subtrees or projects and still tell them apart whilerefiling.

I now exclude DONE state tasks as valid refile targets. This helps to keep therefile target list to a reasonable size.

Here is my refile configuration:

; Targets include this file and any file contributing to the agenda - up to 9 levels deep
(setq org-refile-targets (quote ((nil :maxlevel . 9)
                                 (org-agenda-files :maxlevel . 9))))

; Use full outline paths for refile targets - we file directly with IDO
(setq org-refile-use-outline-path t)

; Targets complete directly with IDO
(setq org-outline-path-complete-in-steps nil)

; Allow refile to create parent tasks with confirmation
(setq org-refile-allow-creating-parent-nodes (quote confirm))

; Use IDO for both buffer and file completion and ido-everywhere to t
(setq org-completion-use-ido t)
(setq ido-everywhere t)
(setq ido-max-directory-size 100000)
(ido-mode (quote both))
; Use the current window when visiting files and buffers with ido
(setq ido-default-file-method 'selected-window)
(setq ido-default-buffer-method 'selected-window)
; Use the current window for indirect buffer display
(setq org-indirect-buffer-display 'current-window)

;;;; Refile settings
; Exclude DONE state tasks from refile targets
(defun bh/verify-refile-target ()
  "Exclude todo keywords with a done state from refile targets"
  (not (member (nth 2 (org-heading-components)) org-done-keywords)))

(setq org-refile-target-verify-function 'bh/verify-refile-target)

To refile a task to my norang.org file under System Maintenance Ijust put the cursor on the task and hit C-c C-w and enter nor C-SPCsys RET and it's done. IDO completion makes locating targets a snap.

7.2 Refiling Tasks

Tasks to refile are in their own section of the block agenda. To findtasks to refile I run my agenda view with F12 SPC and scroll down tosecond section of the block agenda: Tasks to Refile. This viewshows all tasks (even ones marked in a done state).

Bulk refiling in the agenda works very well for multiple tasks goingto the same place. Just mark the tasks with m and then B r torefile all of them to a new location. Occasionally I'll also refiletasks as subtasks of the current clocking task using C-2 C-c C-wfrom the refile.org file.

Refiling all of my tasks tends to take less than a minute so Inormally do this a couple of times a day.

7.3 Refiling Notes

I keep a * Notes headline in most of my org-mode files. Notes havea NOTE tag which is created by the capture template for notes. Thisallows finding notes across multiple files easily using the agendasearch functions.

Notes created by capture tasks go first to refile.org and are laterrefiled to the appropriate project file. Some notes that are projectrelated get filed to the appropriate project instead of under thecatchall * NOTES task. Generally these types of notes are specificto the project and not generally useful – so removing them from thenotes list when the project is archived makes sense.

7.4 Refiling Phone Calls and Meetings

Phone calls and meetings are handled using capture mode. I time mycalls and meetings using the capture mode template settings to clockin and out the capture task while the phone call or meeting is inprogress.

Phone call and meeting tasks collect in refile.org and are laterrefiled to the appropriate location. Some phone calls are billableand we want these tracked in the appropriate category. I refile myphone call and meeting tasks under the appropriate project so timetracking and reports are as accurate as possible.

8 Custom agenda views

I now have one block agenda view that has everything on it. I alsokeep separate single view agenda commands for use on my slower EeePC - since it takes prohibitively long to generate my block agenda onthat slow machine. I'm striving to simplify my layout with everythingat my fingertips in a single agenda on my workstation which is where Ispend the bulk of my time.

Most of my old custom agenda views were rendered obsolete whenfiltering functionality was added to the agenda in newer versions oforg-mode and now with block agenda functionality I can combineeverything into a single view.

Custom agenda views are used for:

  • Single block agenda shows the following
    • overview of today
    • Finding tasks to be refiled
    • Finding stuck projects
    • Finding NEXT tasks to work on
    • Show all related tasks
    • Reviewing projects
    • Finding tasks waiting on something
    • Findings tasks to be archived
  • Finding notes
  • Viewing habits

If I want just today's calendar view then F12 a is still faster thangenerating the block agenda - especially if I want to view a week ormonth's worth of information, or check my clocking data. In that casethe extra detail on the block agenda view is never really needed and Idon't want to spend time waiting for it to be generated.

8.1 Setup

;; Do not dim blocked tasks
(setq org-agenda-dim-blocked-tasks nil)

;; Compact the block agenda view
(setq org-agenda-compact-blocks t)

;; Custom agenda command definitions
(setq org-agenda-custom-commands
      (quote (("N" "Notes" tags "NOTE"
               ((org-agenda-overriding-header "Notes")
                (org-tags-match-list-sublevels t)))
              ("h" "Habits" tags-todo "STYLE=\"habit\""
               ((org-agenda-overriding-header "Habits")
                (org-agenda-sorting-strategy
                 '(todo-state-down effort-up category-keep))))
              (" " "Agenda"
               ((agenda "" nil)
                (tags "REFILE"
                      ((org-agenda-overriding-header "Tasks to Refile")
                       (org-tags-match-list-sublevels nil)))
                (tags-todo "-CANCELLED/!"
                           ((org-agenda-overriding-header "Stuck Projects")
                            (org-agenda-skip-function 'bh/skip-non-stuck-projects)
                            (org-agenda-sorting-strategy
                             '(category-keep))))
                (tags-todo "-HOLD-CANCELLED/!"
                           ((org-agenda-overriding-header "Projects")
                            (org-agenda-skip-function 'bh/skip-non-projects)
                            (org-tags-match-list-sublevels 'indented)
                            (org-agenda-sorting-strategy
                             '(category-keep))))
                (tags-todo "-CANCELLED/!NEXT"
                           ((org-agenda-overriding-header (concat "Project Next Tasks"
                                                                  (if bh/hide-scheduled-and-waiting-next-tasks
                                                                      ""
                                                                    " (including WAITING and SCHEDULED tasks)")))
                            (org-agenda-skip-function 'bh/skip-projects-and-habits-and-single-tasks)
                            (org-tags-match-list-sublevels t)
                            (org-agenda-todo-ignore-scheduled bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-todo-ignore-deadlines bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-todo-ignore-with-date bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-sorting-strategy
                             '(todo-state-down effort-up category-keep))))
                (tags-todo "-REFILE-CANCELLED-WAITING-HOLD/!"
                           ((org-agenda-overriding-header (concat "Project Subtasks"
                                                                  (if bh/hide-scheduled-and-waiting-next-tasks
                                                                      ""
                                                                    " (including WAITING and SCHEDULED tasks)")))
                            (org-agenda-skip-function 'bh/skip-non-project-tasks)
                            (org-agenda-todo-ignore-scheduled bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-todo-ignore-deadlines bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-todo-ignore-with-date bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-sorting-strategy
                             '(category-keep))))
                (tags-todo "-REFILE-CANCELLED-WAITING-HOLD/!"
                           ((org-agenda-overriding-header (concat "Standalone Tasks"
                                                                  (if bh/hide-scheduled-and-waiting-next-tasks
                                                                      ""
                                                                    " (including WAITING and SCHEDULED tasks)")))
                            (org-agenda-skip-function 'bh/skip-project-tasks)
                            (org-agenda-todo-ignore-scheduled bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-todo-ignore-deadlines bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-todo-ignore-with-date bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-sorting-strategy
                             '(category-keep))))
                (tags-todo "-CANCELLED+WAITING|HOLD/!"
                           ((org-agenda-overriding-header (concat "Waiting and Postponed Tasks"
                                                                  (if bh/hide-scheduled-and-waiting-next-tasks
                                                                      ""
                                                                    " (including WAITING and SCHEDULED tasks)")))
                            (org-agenda-skip-function 'bh/skip-non-tasks)
                            (org-tags-match-list-sublevels nil)
                            (org-agenda-todo-ignore-scheduled bh/hide-scheduled-and-waiting-next-tasks)
                            (org-agenda-todo-ignore-deadlines bh/hide-scheduled-and-waiting-next-tasks)))
                (tags "-REFILE/"
                      ((org-agenda-overriding-header "Tasks to Archive")
                       (org-agenda-skip-function 'bh/skip-non-archivable-tasks)
                       (org-tags-match-list-sublevels nil))))
               nil))))

My block agenda view looks like this when not narrowed to a project.This shows top-level projects and NEXT tasks but hides the project details sincewe are not focused on any particular project.

NOTE: This agenda screen shot is out of date and does not currently match the agenda setup in this document.This will be fixed soon.

block-agenda-nonproject.png

After selecting a project (with P on any task in the agenda) the block agenda changes to show the project andany subprojects in the Projects section. Tasks show project-related tasks that are hidden when notnarrowed to a project.

This makes it easy to focus on the task at hand.

NOTE: This agenda screen shot is out of date and does not currently match the agenda setup in this document.This will be fixed soon.

block-agenda-project.png

I generally work top-down on the agenda. Things with deadlines andscheduled dates (planned to work on today or earlier) show up in theagenda at the top.

My day goes generally like this:

  • Punch in (this starts the clock on the default task)
  • Look at the agenda and make a mental note of anything important to deal with today
  • Read email and news
    • create notes, and tasks for things that need responses with org-capture
  • Check refile tasks and respond to emails
  • Look at my agenda and work on important tasks for today
    • Clock it in
    • Work on it until it is DONE or it gets interrupted
  • Work on tasks
  • Make journal entries (C-c c j) for interruptions
  • Punch out for lunch and punch back in after lunch
  • work on more tasks
  • Refile tasks to empty the list
    • Tag tasks to be refiled with m collecting all tasks for the same target
    • Bulk refile the tasks to the target location with B r
    • Repeat (or refile individually with C-c C-w) until all refile tasks are gone
  • Mark habits done today as DONE
  • Punch out at the end of the work day

8.2 What do I work on next?

Start with deadlines and tasks scheduled today or earlier from thedaily agenda view. Then move on to tasks in the Next Tasks list inthe block agenda view. I tend to schedule current projects to 'today'when I start work on them and they sit on my daily agenda reminding methat they need to be completed. I normally only schedule one or twoprojects to the daily agenda and unschedule things that are no longerimportant and don't deserve my attention today.

When I look for a new task to work on I generally hit F12 SPC to getthe block agenda and follow this order:

  • Pick something off today's agenda
    • deadline for today (do this first - it's not late yet)
    • deadline in the past (it's already late)
    • a scheduled task for today (it's supposed to be done today)
    • a scheduled task that is still on the agenda
    • deadline that is coming up soon
  • pick a NEXT task
  • If you run out of items to work on look for a NEXT task in the current contextpick a task from the Tasks list of the current project.
8.2.1 Why keep it all on the NEXT list?

I've moved to a more GTD way of doing things. Now I just use a NEXTlist. Only projects get tasks with NEXT keywords since stuck projectsinitiate the need for marking or creating NEXT tasks. A NEXT taskis something that is available to work on now, it is the nextlogical step in some project.

I used to have a special keyword ONGOING for things that I do a lotand want to clock but never really start/end. I had a special agendaview for ONGOING tasks that I would pull up to easily find the thingI want to clock.

Since then I've moved away from using the ONGOING todo keyword.Having an agenda view that shows NEXT tasks makes it easy to pickthe thing to clock - and I don't have to remember if I need to look inthe ONGOING list or the NEXT list when looking for the task toclock-in. The NEXT list is basically 'what is current' - any taskthat moves a project forward. I want to find the thing to work on asfast as I can and actually do work on it - not spend time huntingthrough my org files for the task that needs to be clocked-in.

To drop a task off the NEXT list simply move it back to the TODOstate.

8.3 Reading email, newsgroups, and conversations on IRC

When reading email, newsgroups, and conversations on IRC I just letthe default task (normally ** Organization) clock the time I spend onthese tasks. To read email I go to Gnus and read everything in myinboxes. If there are emails that require a response I useorg-capture to create a new task with a heading of 'Respond to <user>'for each one. This automatically links to the email in the task andmakes it easy to find later. Some emails are quick to respond to andsome take research and a significant amount of time to complete. Iclock each one in it's own task just in case I need that clocked timelater. The capture template for Repond To tasks is now scheduled fortoday so I can refile the task to the appropriate org file withoutlosing the task for a week.

Next, I go to my newly created tasks to be refiled from the blockagenda with F12 a and clock in an email task and deal with it.Repeat this until all of the 'Respond to <user>' tasks are markedDONE.

I read email and newgroups in Gnus so I don't separate clocked timefor quickly looking at things. If an article has a useful piece ofinformation I want to remember I create a note for it with C-c c nand enter the topic and file it. This takes practically no time atall and I know the note is safely filed for later retrieval. The timeI spend in the capture buffer is clocked with that capture note.

8.4 Filtering

So many tasks, so little time. I have hundreds of tasks at any giventime (373 right now). There is so much stuff to look at it can bedaunting. This is where agenda filtering saves the day.

It's 11:53AM and I'm in work mode just before lunch. I don't want tosee tasks that are not work related right now. I also don't want towork on a big project just before lunch… so I need to find smalltasks that I can knock off the list.

How do we do this? Get a list of NEXT tasks from the block agenda andthen narrow it down with filtering. Tasks are ordered in the NEXTagenda view by estimated effort so the short tasks are first – juststart at the top and work your way down. I can limit the displayedagenda tasks to those estimates of 10 minutes or less with / + 1 andI can pick something that fits the minutes I have left before I takeoff for lunch.

8.4.1 Automatically removing context based tasks with / RET

/ RET in the agenda is really useful. This awesome feature wasadded to org-mode by John Wiegley. It removes tasks automatically byfiltering based on a user-provided function.

At work I have projects I'm working on which are assigned by mymanager. Sometimes priorities changes and projects are delayed tosometime in the future. This means I need to stop working on theseimmediately. I put the project task on HOLD and work on somethingelse. The / RET filter removes HOLD tasks and subtasks (becauseof tag inheritance).

At home I have some tasks tagged with farm since these need to beperformed when I am physically at our family farm. Since I am thereinfrequently I have added farm to the list of auto-excluded tags onmy system. I can always explicitly filter to just farm tasks with/ TAB farm RET when I am physically there.

I have the following setup to allow / RET to filter tasks based onthe description above.

(defun bh/org-auto-exclude-function (tag)
  "Automatic task exclusion in the agenda with / RET"
  (and (cond
        ((string= tag "hold")
         t)
        ((string= tag "farm")
         t))
       (concat "-" tag)))

(setq org-agenda-auto-exclude-function 'bh/org-auto-exclude-function)

This lets me filter tasks with just / RET on the agenda which removes tasks I'm notsupposed to be working on now from the list of returned results.

This helps to keep my agenda clutter-free.

9 Time Clocking

Okay, I admit it. I'm a clocking fanatic.

I clock everything at work. Org-mode makes this really easy. I'drather clock too much stuff than not enough so I find it's easier toget in the habit of clocking everything.

This makes it possible to look back at the day and see where I'mspending too much time, or not enough time on specific projects. Thisalso helps a lot when you need to estimate how long something is goingto take to do – you can use your clocking data from similar tasks tohelp tune your estimates so they are more accurate.

Without clocking data it's hard to tell how long something took to doafter the fact.

I now use the concept of punching in and punching out at the startand end of my work day. I punch in when I arrive at work, punch outfor lunch, punch in after lunch, and punch out at the end of the day.Every minute is clocked between punch-in and punch-out times.

Punching in defines a default task to clock time on whenever the clockwould normally stop. I found that with the default org-mode setup Iwould lose clocked minutes during the day, a minute here, a minutethere, and that all adds up. This is especially true if you writenotes when moving to a DONE state - in this case the clock normallystops before you have composed the note – and good notes take a fewminutes to write.

My clocking setup basically works like this:

  • Punch in (start the clock)
    • This clocks in a predefined task by org-id that is the defaulttask to clock in whenever the clock normally stops
  • Clock in tasks normally, and let moving to a DONE state clock out
    • clocking out automatically clocks time on a parent task or movesback to the predefined default task if no parent exists.
  • Continue clocking whatever tasks you work on
  • Punch out (stop the clock)

I'm free to change the default task multiple times during the day but with the clock moving up the project tree on clock out I no longer need to do this. I simply have a single task that gets clocked inwhen I punch-in.

If I punch-in with a prefix on a task in Project X then that taskautomatically becomes the default task and all clocked time goes onthat project until I either punch out or punch in some other task.

My org files look like this:

todo.org:

#+FILETAGS: PERSONAL
...
* Tasks
** Organization
   :PROPERTIES:
   :CLOCK_MODELINE_TOTAL: today
   :ID:       eb155a82-92b2-4f25-a3c6-0304591af2f9
   :END:
   ...

If I am working on some task, then I simply clock in on the task.Clocking out moves the clock up to a parent task with a todo keyword(if any) which keeps the clock time in the same subtree. If thereis no parent task with a todo keyword then the clock moves back tothe default clocking task until I punch out or clock in some othertask. When an interruption occurs I start a capture task whichkeeps clocked time on the interruption task until I close it withC-c C-c.

This works really well for me.

For example, consider the following org file:

* TODO Project A
** NEXT TASK 1
** TODO TASK 2
** TODO TASK 3
* Tasks
** TODO Some miscellaneous task

I'll work on this file in the following sequence:

  1. I punch in with F9-I at the start of my day

    That clocks in the Organization task by id in my todo.org file.

  2. F12-SPC to review my block agenda

    Pick 'TODO Some miscellaneous task' to work on next and clock that in with IThe clock is now on 'TODO Some miscellaneous task'

  3. I complete that task and mark it done with C-c C-t d

    This stops the clock and moves it back to the Organization task.

  4. Now I want to work on Project A so I clock in Task 1

    I work on Task 1 and mark it DONE. This clocks out Task 1 and movesthe clock to Project A. Now I work on Task 2 and clock that in.

The entire time I'm working on and clocking some subtask of Project Aall of the clock time in the interval is applied somewhere to the Project Atree. When I eventually mark Project A done then the clock will moveback to the default organization task.

9.1 Clock Setup

To get started we need to punch in which clocks in the defaulttask and keeps the clock running. This is now simply a matter ofpunching in the clock with F9 I. You can do this anywhere.Clocking out will now clock in the parent task (if there is onewith a todo keyword) or clock in the default task if not parentexists.

Keeping the clock running when moving a subtask to a DONE statemeans clocking continues to apply to the project task. I can pick thenext task from the parent and clock that in without losing a minute ortwo while I'm deciding what to work on next.

I keep clock times, state changes, and other notes in the :LOGBOOK:drawer.

I have the following org-mode settings for clocking:

;;
;; Resume clocking task when emacs is restarted
(org-clock-persistence-insinuate)
;;
;; Show lot of clocking history so it's easy to pick items off the C-F11 list
(setq org-clock-history-length 23)
;; Resume clocking task on clock-in if the clock is open
(setq org-clock-in-resume t)
;; Change tasks to NEXT when clocking in
(setq org-clock-in-switch-to-state 'bh/clock-in-to-next)
;; Separate drawers for clocking and logs
(setq org-drawers (quote ("PROPERTIES" "LOGBOOK")))
;; Save clock data and state changes and notes in the LOGBOOK drawer
(setq org-clock-into-drawer t)
;; Sometimes I change tasks I'm clocking quickly - this removes clocked tasks with 0:00 duration
(setq org-clock-out-remove-zero-time-clocks t)
;; Clock out when moving task to a done state
(setq org-clock-out-when-done t)
;; Save the running clock and all clock history when exiting Emacs, load it on startup
(setq org-clock-persist t)
;; Do not prompt to resume an active clock
(setq org-clock-persist-query-resume nil)
;; Enable auto clock resolution for finding open clocks
(setq org-clock-auto-clock-resolution (quote when-no-clock-is-running))
;; Include current clocking task in clock reports
(setq org-clock-report-include-clocking-task t)

(setq bh/keep-clock-running nil)

(defun bh/clock-in-to-next (kw)
  "Switch a task from TODO to NEXT when clocking in.
Skips capture tasks, projects, and subprojects.
Switch projects and subprojects from NEXT back to TODO"
  (when (not (and (boundp 'org-capture-mode) org-capture-mode))
    (cond
     ((and (member (org-get-todo-state) (list "TODO"))
           (bh/is-task-p))
      "NEXT")
     ((and (member (org-get-todo-state) (list "NEXT"))
           (bh/is-project-p))
      "TODO"))))

(defun bh/find-project-task ()
  "Move point to the parent (project) task if any"
  (save-restriction
    (widen)
    (let ((parent-task (save-excursion (org-back-to-heading 'invisible-ok) (point))))
      (while (org-up-heading-safe)
        (when (member (nth 2 (org-heading-components)) org-todo-keywords-1)
          (setq parent-task (point))))
      (goto-char parent-task)
      parent-task)))

(defun bh/punch-in (arg)
  "Start continuous clocking and set the default task to the
selected task.  If no task is selected set the Organization task
as the default task."
  (interactive "p")
  (setq bh/keep-clock-running t)
  (if (equal major-mode 'org-agenda-mode)
      ;;
      ;; We're in the agenda
      ;;
      (let* ((marker (org-get-at-bol 'org-hd-marker))
             (tags (org-with-point-at marker (org-get-tags-at))))
        (if (and (eq arg 4) tags)
            (org-agenda-clock-in '(16))
          (bh/clock-in-organization-task-as-default)))
    ;;
    ;; We are not in the agenda
    ;;
    (save-restriction
      (widen)
      ; Find the tags on the current task
      (if (and (equal major-mode 'org-mode) (not (org-before-first-heading-p)) (eq arg 4))
          (org-clock-in '(16))
        (bh/clock-in-organization-task-as-default)))))

(defun bh/punch-out ()
  (interactive)
  (setq bh/keep-clock-running nil)
  (when (org-clock-is-active)
    (org-clock-out))
  (org-agenda-remove-restriction-lock))

(defun bh/clock-in-default-task ()
  (save-excursion
    (org-with-point-at org-clock-default-task
      (org-clock-in))))

(defun bh/clock-in-parent-task ()
  "Move point to the parent (project) task if any and clock in"
  (let ((parent-task))
    (save-excursion
      (save-restriction
        (widen)
        (while (and (not parent-task) (org-up-heading-safe))
          (when (member (nth 2 (org-heading-components)) org-todo-keywords-1)
            (setq parent-task (point))))
        (if parent-task
            (org-with-point-at parent-task
              (org-clock-in))
          (when bh/keep-clock-running
            (bh/clock-in-default-task)))))))

(defvar bh/organization-task-id "eb155a82-92b2-4f25-a3c6-0304591af2f9")

(defun bh/clock-in-organization-task-as-default ()
  (interactive)
  (org-with-point-at (org-id-find bh/organization-task-id 'marker)
    (org-clock-in '(16))))

(defun bh/clock-out-maybe ()
  (when (and bh/keep-clock-running
             (not org-clock-clocking-in)
             (marker-buffer org-clock-default-task)
             (not org-clock-resolving-clocks-due-to-idleness))
    (bh/clock-in-parent-task)))

(add-hook 'org-clock-out-hook 'bh/clock-out-maybe 'append)

I used to clock in tasks by ID using the following function but withthe new punch-in and punch-out I don't need these as much anymore.f9-SPC calls bh/clock-in-last-task which switches the clock backto the previously clocked task.

(require 'org-id)
(defun bh/clock-in-task-by-id (id)
  "Clock in a task by id"
  (org-with-point-at (org-id-find id 'marker)
    (org-clock-in nil)))

(defun bh/clock-in-last-task (arg)
  "Clock in the interrupted task if there is one
Skip the default task and get the next one.
A prefix arg forces clock in of the default task."
  (interactive "p")
  (let ((clock-in-to-task
         (cond
          ((eq arg 4) org-clock-default-task)
          ((and (org-clock-is-active)
                (equal org-clock-default-task (cadr org-clock-history)))
           (caddr org-clock-history))
          ((org-clock-is-active) (cadr org-clock-history))
          ((equal org-clock-default-task (car org-clock-history)) (cadr org-clock-history))
          (t (car org-clock-history)))))
    (widen)
    (org-with-point-at clock-in-to-task
      (org-clock-in nil))))

9.2 Clocking in

When I start or continue working on a task I clock it in with any of the following:

  • C-c C-x C-i
  • I in the agenda
  • I speed key on the first character of the heading line
  • f9 I while on the task in the agenda
  • f9 I while in the task in an org file
9.2.1 Setting a default clock task

I have a default ** Organization task in my todo.org file thatI tend to put miscellaneous clock time on. This is the task Iclock in on when I punch in at the start of my work day withF9-I. While reorganizing my org-files, reading email,clearing my inbox, and doing other planning work that isn't fora specific project I'll clock in this task. Punching-inanywhere clocks in this Organization task as the default task.

If I want to change the default clocking task I just visit thenew task in any org buffer and clock it in with C-u C-u C-c C-xC-i. Now this new task that collects miscellaneous clockminutes when the clock would normally stop.

You can quickly clock in the default clocking task with C-u C-cC-x C-i d. Another option is to repeatedly clock out so theclock moves up the project tree until you clock out thetop-level task and the clock moves to the default task.

9.2.2 Using the clock history to clock in old tasks

You can use the clock history to restart clocks on old tasks you'veclocked or to jump directly to a task you have clocked previously. Iuse this mainly to clock in whatever got interrupted by something.

Consider the following scenario:

  • You are working on and clocking Task A (Organization)
  • You get interrupted and switch to Task B (Document my use of org-mode)
  • You complete Task B (Document my use of org-mode)
  • Now you want to go back to Task A (Organization) again to continue

This is easy to deal with.

  1. Clock in Task A, work on it
  2. Go to Task B (or create a new task) and clock it in
  3. When you are finished with Task B hit C-u C-c C-x C-i i

This displays a clock history selection window like the following andselects the interrupted [i] entry.

Clock history selection buffer for C-u C-c C-x C-i

Default Task
[d] norang          Organization                          <-- Task B
The task interrupted by starting the last one
[i] norang          Organization                          <-- Task B
Current Clocking Task
[c] org             NEXT Document my use of org-mode      <-- Task A
Recent Tasks
[1] org             NEXT Document my use of org-mode      <-- Task A
[2] norang          Organization                          <-- Task B
...
[Z] org             DONE Fix default section links        <-- 35 clock task entries ago

9.3 Clock Everything - Create New Tasks

In order to clock everything you need a task for everything. That'sfine for planned projects but interruptions inevitably occur and youneed some place to record whatever time you spend on thatinterruption.

To deal with this we create a new capture task to record the thing weare about to do. The workflow goes something like this:

  • You are clocking some task and an interruption occurs
  • Create a quick capture task journal entry C-c c j
  • Type the heading
  • go do that thing (eat lunch, whatever)
  • file it C-c C-c, this restores the clock back to the previous clocking task
  • clock something else in or continue with the current clocking task

This means you can ignore the details like where this task reallybelongs in your org file layout and just get on with completing thething. Refiling a bunch of tasks later in a group when it isconvenient to refile the tasks saves time in the long run.

If it's a one-shot uninteresting task (like a coffee break) I createa capture journal entry for it that goes to the diary.org date tree.If it's a task that actually needs to be tracked and marked done, and applied to some project then I create a capture task instead which files it in refile.org.

9.4 Finding tasks to clock in

To find a task to work on I use one of the following options(generally listed most frequently used first)

  • Use the clock history C-u C-c C-x C-iGo back to something I was clocking that is not finished
  • Pick something off today's block agendaSCHEDULED or DEADLINE items that need to be done soon
  • Pick something off the NEXT tasks agenda viewWork on some unfinished task to move to completion
  • Pick something off the other task list
  • Use an agenda view with filtering to pick something to work on

Punching in on the task you select will restrict the agenda view to that projectso you can focus on just that thing for some period of time.

9.5 Editing clock entries

Sometimes it is necessary to edit clock entries so they reflectreality. I find I do this for maybe 2-3 entries in a week.

Occassionally I cannot clock in a task on time because I'm away frommy computer. In this case the previous clocked task is still runningand counts time for both tasks which is wrong.

I make a note of the time and then when I get back to my computer Iclock in the right task and edit the start and end times to correctthe clock history.

To visit the clock line for an entry quickly use the agenda log mode.F12 a l shows all clock lines for today. I use this to navigate tothe appropriate clock lines quickly. F11 goes to the current clockedtask but the agenda log mode is better for finding and visiting olderclock entries.

Use F12 a l to open the agenda in log mode and show only loggedclock times. Move the cursor down to the clock line you need to editand hit TAB and you're there.

To edit a clock entry just put the cursor on the part of the date youwant to edit (use the keyboard not the mouse - since the clicking onthe timestamp with the mouse goes back to the agenda for that day) andhit the S-<up arrow> or S-<down arrow> keys to change the time.

The following setting makes time editing use discrete minute intervals (no rounding)increments:

(setq org-time-stamp-rounding-minutes (quote (1 1)))

Editing the time with the shift arrow combination also updates thetotal for the clock line which is a nice convenience.

I always check that I haven't created task overlaps when fixing timeclock entries by viewing them with log mode on in the agenda. Thereis a new view in the agenda for this – just hit v c in the daily agenda and clock gaps and overlaps are identified.

I want my clock entries to be as accurate as possible.

The following setting shows 1 minute clocking gaps.

(setq org-agenda-clock-consistency-checks
      (quote (:max-duration "4:00"
              :min-duration 0
              :max-gap 0
              :gap-ok-around ("4:00"))))

10 Time reporting and tracking

10.1 Billing clients based on clocked time

At the beginning of the month I invoice my clients for work done lastmonth. This is where I review my clocking data for correctness beforebilling for the clocked time.

Billing for clocked time basically boils down to the following steps:

  1. Verify that the clock data is complete and correct
  2. Use clock reports to summarize time spent
  3. Create an invoice based on the clock data

    I currently create invoices in an external software packagebased on the org-mode clock data.

  4. Archive complete tasks so they are out of the way.

    See Archiving for more details.

10.1.1 Verify that the clock data is complete and correct

Since I change tasks often (sometimes more than once in a minute) Iuse the following setting to remove clock entries with a zeroduration.

;; Sometimes I change tasks I'm clocking quickly - this removes clocked tasks with 0:00 duration
(setq org-clock-out-remove-zero-time-clocks t)

This setting just keeps my clocked log entries clean - only keepingclock entries that contribute to the clock report.

Before invoicing for clocked time it is important to make sure yourclocked time data is correct. If you have a clocked time with anentry that is not closed (ie. it has no end time) then that is a holein your clocked day and it gets counted as zero (0) for time spent onthe task when generating clock reports. Counting it as zero is almostcertainly wrong.

To check for unclosed clock times I use the agenda-view clock check(v c in the agenda). This view shows clocking gaps and overlaps inthe agenda.

To check the last month's clock data I use F12 a v m b v cwhich shows a full month in the agenda, moves to the previousmonth, and shows the clocked times only. It's important toremove any agenda restriction locks and filters when checkingthe logs for gaps and overlaps.

The clocked-time only display in the agenda makes it easy to quicklyscan down the list to see if an entry is missing an end time. If anentry is not closed you can manually fix the clock entry based onother clock info around that time.

10.1.2 Using clock reports to summarize time spent

Billable time for clients are kept in separate org files.

To get a report of time spent on tasks for XYZ.org you simply visitthe XYZ.org file and run an agenda clock report for the last monthwith F12 < a v m b R. This limits the agenda to this one file,shows the agenda for a full month, moves to last month, and generatesa clock report.

My agenda org clock report settings show 5 levels of detail with linksto the tasks. I like wider reports than the default compact settingso I override the :narrow value.

;; Agenda clock report parameters
(setq org-agenda-clockreport-parameter-plist
      (quote (:link t :maxlevel 5 :fileskip0 t :compact t :narrow 80)))

I used to have a monthly clock report dynamic block in each projectorg file and manually updated them at the end of my billing cycle. Iused this as the basis for billing my clients for time spent on theirprojects. I found updating the dynamic blocks fairly tedious when youhave more than a couple of files for the month.

I have since moved to using agenda clock reports shortly after thatfeature was added. I find this much more convenient. The data isn'tnormally for consumption by anyone else so the format of the agendaclock report format is great for my use-case.

10.2 Task Estimates and column view

Estimating how long tasks take to complete is a difficult skill tomaster. Org-mode makes it easy to practice creating estimates fortasks and then clock the actual time it takes to complete.

By repeatedly estimating tasks and reviewing how your estimate relatesto the actual time clocked you can tune your estimating skills.

10.2.1 Creating a task estimate with column mode

I use properties and column view to do project estimates.

I set up column view globally with the following headlines

; Set default column view headings: Task Effort Clock_Summary
(setq org-columns-default-format "%80ITEM(Task) %10Effort(Effort){:} %10CLOCKSUM")

This makes column view show estimated task effort and clocked timesside-by-side which is great for reviewing your project estimates.

A property called Effort records the estimated amount of time agiven task will take to complete. The estimate times I use are oneof:

  • 10 minutes
  • 30 minutes
  • 1 hour
  • 2 hours
  • 3 hours
  • 4 hours
  • 5 hours
  • 6 hours
  • 7 hours
  • 8 hours

These are stored for easy use in column mode in the global propertyEffort_ALL.

; global Effort estimate values
; global STYLE property values for completion
(setq org-global-properties (quote (("Effort_ALL" . "0:15 0:30 0:45 1:00 2:00 3:00 4:00 5:00 6:00 0:00")
                                    ("STYLE_ALL" . "habit"))))

To create an estimate for a task or subtree start column mode withC-c C-x C-c and collapse the tree with c. This shows a tableoverlayed on top of the headlines with the task name, effort estimate,and clocked time in columns.

With the cursor in the Effort column for a task you can easily setthe estimated effort value with the quick keys 1 through 9.

After setting the effort values exit column mode with q.

10.2.2 Saving your estimate

For fixed price jobs where you provide your estimate to a client, thenwork to complete the project it is useful to save the originalestimate that is provided to the client.

Save your original estimate by creating a dynamic clock report tableat the top of your estimated project subtree. Entering C-c C-x iRET inserts a clock table report with your estimated values and anyclocked time to date.

Original Estimate
#+BEGIN: columnview :hlines 1 :id local
| Task                        | Estimated Effort | CLOCKSUM |
|-----------------------------+------------------+----------|
| ** TODO Project to estimate |             5:40 |          |
| *** TODO Step 1             |             0:10 |          |
| *** TODO Step 2             |             0:10 |          |
| *** TODO Step 3             |             5:10 |          |
| **** TODO Step 3.1          |             2:00 |          |
| **** TODO Step 3.2          |             3:00 |          |
| **** TODO Step 3.3          |             0:10 |          |
| *** TODO Step 4             |             0:10 |          |
#+END:

I normally delete the #+BEGIN: and #+END: lines from the originaltable after providing the estimate to the client to ensure I don'taccidentally update the table by hitting C-c C-c on the #+BEGIN:line.

Saving the original estimate data makes it possible to refine theproject tasks into subtasks as you work on the project without losingthe original estimate data.

10.2.3 Reviewing your estimate

Column view is great for reviewing your estimate. This shows yourestimated time value and the total clock time for the projectside-by-side.

Creating a dynamic clock table with C-c C-x i RET is a great way tosave this project review if you need to make it available to otherapplications.

C-c C-x C-d also provides a quick summary of clocked time for thecurrent org file.

10.3 Providing progress reports to others

When someone wants details of what I've done recently I simple generate alog report in the agenda with tasks I've completed and state changes combinedwith a clock report for the appropriate time period.

The following setting shows closed tasks and state changes in theagenda. Combined with the agenda clock report ('R') I can quicklygenerate all of the details required.

;; Agenda log mode items to display (closed and state changes by default)
(setq org-agenda-log-mode-items (quote (closed state)))

To generate the report I pull up the agenda for the appropriate time frame(today, yesterday, this week, or last week) and hit the key sequencel R to add the log report (without clocking data lines) and the agenda clockreport at the end.

Then it's simply a matter of exporting the resulting agenda in some useful formatto provide to other people. C-x C-w /tmp/agenda.html RET exports to HTMLand C-x C-w /tmp/agenda.txt RET exports to plain text. Other formats are available but I use these two the most.

Combining this export with tag filters and C-u R can limit thereport to exactly the tags that people are interested in.

11 Tags

Tasks can have any number of arbitrary tags. Tags are used for:

  • filtering todo lists and agenda views
  • providing context for tasks
  • tagging notes
  • tagging phone calls
  • tagging meetings
  • tagging tasks to be refiled
  • tagging tasks in a WAITING state because a parent task is WAITING
  • tagging cancelled tasks because a parent task is CANCELLED
  • preventing export of some subtrees when publishing

I use tags mostly for filtering in the agenda. This means you canfind tasks with a specific tag easily across your large number oforg-mode files.

Some tags are mutually exclusive. These are defined in a group sothat only one of the tags can be applied to a task at a time(disregarding tag inheritance). I use these types for tags forapplying context to a task. (Work tasks have an @office tag, andare done at the office, Farm tasks have an @farm tag and are done atthe farm – I can't change the oil on the tractor if I'm not at thefarm… so I hide these and other tasks by filtering my agenda view toonly @office tasks when I'm at the office.)

Tasks are grouped together in org-files and a #+FILETAGS: entryapplies a tag to all tasks in the file. I use this to apply a tag toall tasks in the file. My norang.org file creates a NORANG file tagso I can filter tasks in the agenda in the norang.org file easily.

11.1 Tags

Here are my tag definitions with associated keys for filtering in theagenda views.

The startgroup - endgroup (@XXX) tags are mutually exclusive -selecting one removes a similar tag already on the task. These arethe context tags - you can't be in two places at once so if a task ismarked with @farm and you add @office then the @farm tag is removedautomagically.

The other tags WAITING .. FLAGGED are not mutually exclusive andmultiple tags can appear on a single task. Some of those tags arecreated by todo state change triggers. The shortcut key is used toadd or remove the tag using C-c C-q or to apply the task forfiltering on the agenda.

I have both FARM and @farm tags. FARM is set by a FILETAGSentry and just gives me a way to filter anything farm related. The@farm tag signifies that the task as to be done at the farm. If Ihave to call someone about something that would have a FARM tag butI can do that at home on my lunch break. I don't physically have tobe at the farm to make the call.

; Tags with fast selection keys
(setq org-tag-alist (quote ((:startgroup)
                            ("@errand" . ?e)
                            ("@office" . ?o)
                            ("@home" . ?H)
                            ("@farm" . ?f)
                            (:endgroup)
                            ("WAITING" . ?w)
                            ("HOLD" . ?h)
                            ("PERSONAL" . ?P)
                            ("WORK" . ?W)
                            ("FARM" . ?F)
                            ("ORG" . ?O)
                            ("NORANG" . ?N)
                            ("crypt" . ?E)
                            ("NOTE" . ?n)
                            ("CANCELLED" . ?c)
                            ("FLAGGED" . ??))))

; Allow setting single tags without the menu
(setq org-fast-tag-selection-single-key (quote expert))

; For tag searches ignore tasks with scheduled and deadline dates
(setq org-agenda-tags-todo-honor-ignore-options t)

11.2 Filetags

Filetags are a convenient way to apply one or more tags to all of theheadings in a file.

Filetags look like this:

#+FILETAGS: NORANG @office

I have the following #+FILETAGS: entries in my org-mode files:

11.2.1 Non-work related org-mode files
FileTags
todo.orgPERSONAL
gsoc2009.orgGSOC PERSONAL
git.orgGIT WORK
org.orgORG WORK
mark.orgMARK PERSONAL
farm.orgFARM PERSONAL
11.2.2 Work related org-mode files
FileTags
norang.orgNORANG @office
ABC.orgABC @office
XYZ.orgXYZ @office
ABC-DEF.orgABC DEF @office
ABC-KKK.orgABC KKK @office
YYY.orgYYY @office
11.2.3 Refile tasks
FileTags
refile.orgREFILE

11.3 State Trigger Tags

The following tags are automatically added or removed by todo statetriggers described previously in ToDo state triggers

  • WAITING
  • CANCELLED

12 Handling Notes

Notes are little gems of knowledge that you come across during yourday. They are just like tasks except there is nothing to do (exceptlearn and memorize the gem of knowledge). Unfortunately there are waytoo many gems to remember and my head explodes just thinking about it.

org-mode to the rescue!

Often I'll find some cool feature or thing I want to remember whilereading the org-mode and git mailing lists in Gnus. To create a noteI use my note capture template C-c c n, type a heading for the noteand C-c C-c to save it. The only other thing to do is to refile it(later) to the appropriate project file.

I have an agenda view just to find notes. Notes are refiled to anappropriate project file and task. If there is no specific task itbelongs to it goes to the catchall * Notes task. I generally have acatchall notes task in every project file. Notes are created with aNOTE tag already applied by the capture template so I'm free torefile the note anywhere. As long as the note is in a project filethat contributes to my agenda (ie. in org-agenda-files) then I canfind the note back easily with my notes agenda view by hitting the keycombination F12 N. I'm free to limit the agenda view of notes usingstandard agenda tag filtering.

Short notes with a meaningful headline are a great way to remembertechnical details without the need to actually remember anything -other than how to find them back when you need them using F12 N.

Notes that are project related and not generally useful can bearchived with the project and removed from the agenda when the projectis removed.

So my org notes go in org.org and my git notes go in git.org bothunder the * Notes task. I'll forever be able to find those. A noteabout some work project detail I want to remember with the project isfiled to the project task under the appropriate work org-mode file andeventually gets removed from the agenda when the project is completeand archived.

13 Handling Phone Calls

Phone calls are interruptions and I use capture mode to deal withthese (like all interruptions). Most of the heavy lifting for phonecalls is done by capture mode. I use a special capture template forphone calls combined with a custom function that replaces text withinformation from my bbdb addressbook database.

C-c c p starts a capture task normally and I'm free to enter notesfrom the call in the template immediately. The cursor starts in thetemplate normally where the name of the caller would be inserted. Ican use a bbdb lookup function to insert the name with f9-p or Ican just type in whatever is appropriate. If a bbdb entry needs tobe created for the caller I can do that and replace the caller detailswith f9-p anytime that is convenient for me. I found thatautomatically calling the bbdb lookup function would interrupt myworkflow during the call in cases where the information about thecaller was not readily available. Sometimes I want to make notes first and get the caller details later during the call.

The phone call capture template starts the clock as soon as the phonerings and I'm free to lookup and replace the caller in bbdb anytimeduring or after the call. Capture mode starts the clock using the:clock-in t setting in the template.

When the phone call ends I simple do C-c C-c to close the capturebuffer and stop the clock. If I have to close it early and look upother information during the call I just do C-c C-c F9-SPC to closethe capture buffer (which stops the clock) and then immediately switchback to the last clocked item to continue the clock in the phone calltask. When the phone call ends I clock out which normally clocks inmy default task again (if any).

Here is my set up for phone calls. I would like to thank Gregory

  1. Grubbs for the original bbdb lookup functions which this version

is based on.

Below is the partial capture template showing the phone call templatefollowed by the phone-call related lookup functions.

;; Capture templates for: TODO tasks, Notes, appointments, phone calls, and org-protocol
(setq org-capture-templates
      (quote (...
              ("p" "Phone call" entry (file "~/git/org/refile.org")
               "* PHONE %? :PHONE:\n%U" :clock-in t :clock-resume t)
              ...)))
(require 'bbdb)
(require 'bbdb-com)

(global-set-key (kbd "<f9> p") 'bh/phone-call)

;;
;; Phone capture template handling with BBDB lookup
;; Adapted from code by Gregory J. Grubbs
(defun bh/phone-call ()
  "Return name and company info for caller from bbdb lookup"
  (interactive)
  (let* (name rec caller)
    (setq name (completing-read "Who is calling? "
                                (bbdb-hashtable)
                                'bbdb-completion-predicate
                                'confirm))
    (when (> (length name) 0)
      ; Something was supplied - look it up in bbdb
      (setq rec
            (or (first
                 (or (bbdb-search (bbdb-records) name nil nil)
                     (bbdb-search (bbdb-records) nil name nil)))
                name)))

    ; Build the bbdb link if we have a bbdb record, otherwise just return the name
    (setq caller (cond ((and rec (vectorp rec))
                        (let ((name (bbdb-record-name rec))
                              (company (bbdb-record-company rec)))
                          (concat "[[bbdb:"
                                  name "]["
                                  name "]]"
                                  (when company
                                    (concat " - " company)))))
                       (rec)
                       (t "NameOfCaller")))
    (insert caller)))

14 GTD stuff

Most of my day is deadline/schedule driven.I work off of the agenda first and then pick items from the todo lists asoutlined in What do I work on next?

14.1 Weekly Review Process

The first day of the week (usually Monday) I do my weekly review. I keep a list like this one to remind me what needs to be done.

To keep the agenda fast I set

(setq org-agenda-span 'day)

so only today's date is shown by default. I only need the weeklyview during my weekly review and this keeps my agenda generationfast.

I have a recurring task which keeps my weekly review checklisthandy. This pops up as a reminder on Monday's. This week I'mdoing my weekly review on Tuesday since Monday was a holiday.

* NEXT Weekly Review [0/6]
  SCHEDULED: <2009-05-18 Mon ++1w> 
  :LOGBOOK:...
  :PROPERTIES:...

  What to review:

   - [ ] Check follow-up folder
   - [ ] Review weekly agenda =F12 a w //=
   - [ ] Check clocking data for past week =v c=
   - [ ] Review clock report for past week =R=
     - Check where we spent time (too much or too little) and rectify this week
   - [ ] Look at entire agenda for today  =F12 SPC=
   - [ ] Review projects =F12 SPC //= and =V= repeatedly to view each project

   - start work
     - daily agenda first - knock off items
     - then work on NEXT tasks

The first item [ ] Check follow-up folder makes me pull out the paperfile I dump stuff into all week long - things I need to take care ofbut are in no particular hurry to deal with. Stuff I get in the mailetc. that I don't want to deal with now. I just toss it in myFollow-Up folder in the filing cabinet and forget about it until theweekly review.

I go through the folder and weed out anything that needs to be dealtwith. After that everything else is in org-mode. I tend toschedule tasks onto the agenda for the coming week so that I don'tspend lots of time trying to find what needs to be worked on next.

This works for me. Your mileage may vary ;)

14.2 Project definition and finding stuck projects

I'm using a new lazy project definition to mark tasks as projects.This requires zero effort from me. Any task with a subtask using atodo keyword is a project. Period.

Projects are 'stuck' if they have no subtask with a NEXT todokeyword task defined.

The org-mode stuck projects agenda view lists projects that have noNEXT task defined. Stuck projects show up on my block agenda and Itend to assign a NEXT task so the list remains empty. This helps tokeep projects moving forward.

I disable the default org-mode stuck projects agenda view with thefollowing setting.

(setq org-stuck-projects (quote ("" nil nil "")))

This prevents org-mode from trying to show incorrect data if I selectthe default stuck project view with F12 # from the agenda menu. Mycustomized stuck projects view is part of my block agenda displayedwith F12 SPC.

Projects can have subprojects - and these subprojects can also be stuck.Any project that is stuck shows up on the stuck projects list so I canindicate or create a NEXT task to move that project forward.

In the following example Stuck Project A is stuck because it has nosubtask which is NEXT. Project C is not stuck because it hasNEXT tasks SubTask G and Task I. Stuck Sub Project D is stuckbecause SubTask E is not NEXT and there are no other tasksavailable in this project.

* Category
** TODO Stuck Project A
*** TODO Task B
** TODO Project C
*** TODO Stuck Sub Project D
**** TODO SubTask E
*** TODO Sub Project F
**** NEXT SubTask G
**** TODO SubTask H
*** NEXT Task I
*** TODO Task J

All of the stuck projects and subprojects show up in the stuckprojects list and that is my indication to assign or create NEXTtasks until the stuck projects list is empty. Occasionally somesubtask is WAITING for something and the project is stuck until thatcondition is satisfied. In this case I leave it on the stuck projectlist and just work on something else. This stuck project 'bugs' meregularly when I see it on the block agenda and this prompts me tofollow up on the thing that I'm waiting for.

I have the following helper functions defined for projects which areused by agenda views.

(defun bh/is-project-p ()
  "Any task with a todo keyword subtask"
  (save-restriction
    (widen)
    (let ((has-subtask)
          (subtree-end (save-excursion (org-end-of-subtree t)))
          (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1)))
      (save-excursion
        (forward-line 1)
        (while (and (not has-subtask)
                    (< (point) subtree-end)
                    (re-search-forward "^\*+ " subtree-end t))
          (when (member (org-get-todo-state) org-todo-keywords-1)
            (setq has-subtask t))))
      (and is-a-task has-subtask))))

(defun bh/is-project-subtree-p ()
  "Any task with a todo keyword that is in a project subtree.
Callers of this function already widen the buffer view."
  (let ((task (save-excursion (org-back-to-heading 'invisible-ok)
                              (point))))
    (save-excursion
      (bh/find-project-task)
      (if (equal (point) task)
          nil
        t))))

(defun bh/is-task-p ()
  "Any task with a todo keyword and no subtask"
  (save-restriction
    (widen)
    (let ((has-subtask)
          (subtree-end (save-excursion (org-end-of-subtree t)))
          (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1)))
      (save-excursion
        (forward-line 1)
        (while (and (not has-subtask)
                    (< (point) subtree-end)
                    (re-search-forward "^\*+ " subtree-end t))
          (when (member (org-get-todo-state) org-todo-keywords-1)
            (setq has-subtask t))))
      (and is-a-task (not has-subtask)))))

(defun bh/is-subproject-p ()
  "Any task which is a subtask of another project"
  (let ((is-subproject)
        (is-a-task (member (nth 2 (org-heading-components)) org-todo-keywords-1)))
    (save-excursion
      (while (and (not is-subproject) (org-up-heading-safe))
        (when (member (nth 2 (org-heading-components)) org-todo-keywords-1)
          (setq is-subproject t))))
    (and is-a-task is-subproject)))

(defun bh/list-sublevels-for-projects-indented ()
  "Set org-tags-match-list-sublevels so when restricted to a subtree we list all subtasks.
  This is normally used by skipping functions where this variable is already local to the agenda."
  (if (marker-buffer org-agenda-restrict-begin)
      (setq org-tags-match-list-sublevels 'indented)
    (setq org-tags-match-list-sublevels nil))
  nil)

(defun bh/list-sublevels-for-projects ()
  "Set org-tags-match-list-sublevels so when restricted to a subtree we list all subtasks.
  This is normally used by skipping functions where this variable is already local to the agenda."
  (if (marker-buffer org-agenda-restrict-begin)
      (setq org-tags-match-list-sublevels t)
    (setq org-tags-match-list-sublevels nil))
  nil)

(defvar bh/hide-scheduled-and-waiting-next-tasks t)

(defun bh/toggle-next-task-display ()
  (interactive)
  (setq bh/hide-scheduled-and-waiting-next-tasks (not bh/hide-scheduled-and-waiting-next-tasks))
  (when  (equal major-mode 'org-agenda-mode)
    (org-agenda-redo))
  (message "%s WAITING and SCHEDULED NEXT Tasks" (if bh/hide-scheduled-and-waiting-next-tasks "Hide" "Show")))

(defun bh/skip-stuck-projects ()
  "Skip trees that are not stuck projects"
  (save-restriction
    (widen)
    (let ((next-headline (save-excursion (or (outline-next-heading) (point-max)))))
      (if (bh/is-project-p)
          (let* ((subtree-end (save-excursion (org-end-of-subtree t)))
                 (has-next ))
            (save-excursion
              (forward-line 1)
              (while (and (not has-next) (< (point) subtree-end) (re-search-forward "^\\*+ NEXT " subtree-end t))
                (unless (member "WAITING" (org-get-tags-at))
                  (setq has-next t))))
            (if has-next
                nil
              next-headline)) ; a stuck project, has subtasks but no next task
        nil))))

(defun bh/skip-non-stuck-projects ()
  "Skip trees that are not stuck projects"
  ;; (bh/list-sublevels-for-projects-indented)
  (save-restriction
    (widen)
    (let ((next-headline (save-excursion (or (outline-next-heading) (point-max)))))
      (if (bh/is-project-p)
          (let* ((subtree-end (save-excursion (org-end-of-subtree t)))
                 (has-next ))
            (save-excursion
              (forward-line 1)
              (while (and (not has-next) (< (point) subtree-end) (re-search-forward "^\\*+ NEXT " subtree-end t))
                (unless (member "WAITING" (org-get-tags-at))
                  (setq has-next t))))
            (if has-next
                next-headline
              nil)) ; a stuck project, has subtasks but no next task
        next-headline))))

(defun bh/skip-non-projects ()
  "Skip trees that are not projects"
  ;; (bh/list-sublevels-for-projects-indented)
  (if (save-excursion (bh/skip-non-stuck-projects))
      (save-restriction
        (widen)
        (let ((subtree-end (save-excursion (org-end-of-subtree t))))
          (cond
           ((bh/is-project-p)
            nil)
           ((and (bh/is-project-subtree-p) (not (bh/is-task-p)))
            nil)
           (t
            subtree-end))))
    (save-excursion (org-end-of-subtree t))))

(defun bh/skip-non-tasks ()
  "Show non-project tasks.
Skip project and sub-project tasks, habits, and project related tasks."
  (save-restriction
    (widen)
    (let ((next-headline (save-excursion (or (outline-next-heading) (point-max)))))
      (cond
       ((bh/is-task-p)
        nil)
       (t
        next-headline)))))

(defun bh/skip-project-trees-and-habits ()
  "Skip trees that are projects"
  (save-restriction
    (widen)
    (let ((subtree-end (save-excursion (org-end-of-subtree t))))
      (cond
       ((bh/is-project-p)
        subtree-end)
       ((org-is-habit-p)
        subtree-end)
       (t
        nil)))))

(defun bh/skip-projects-and-habits-and-single-tasks ()
  "Skip trees that are projects, tasks that are habits, single non-project tasks"
  (save-restriction
    (widen)
    (let ((next-headline (save-excursion (or (outline-next-heading) (point-max)))))
      (cond
       ((org-is-habit-p)
        next-headline)
       ((and bh/hide-scheduled-and-waiting-next-tasks
             (member "WAITING" (org-get-tags-at)))
        next-headline)
       ((bh/is-project-p)
        next-headline)
       ((and (bh/is-task-p) (not (bh/is-project-subtree-p)))
        next-headline)
       (t
        nil)))))

(defun bh/skip-project-tasks-maybe ()
  "Show tasks related to the current restriction.
When restricted to a project, skip project and sub project tasks, habits, NEXT tasks, and loose tasks.
When not restricted, skip project and sub-project tasks, habits, and project related tasks."
  (save-restriction
    (widen)
    (let* ((subtree-end (save-excursion (org-end-of-subtree t)))
           (next-headline (save-excursion (or (outline-next-heading) (point-max))))
           (limit-to-project (marker-buffer org-agenda-restrict-begin)))
      (cond
       ((bh/is-project-p)
        next-headline)
       ((org-is-habit-p)
        subtree-end)
       ((and (not limit-to-project)
             (bh/is-project-subtree-p))
        subtree-end)
       ((and limit-to-project
             (bh/is-project-subtree-p)
             (member (org-get-todo-state) (list "NEXT")))
        subtree-end)
       (t
        nil)))))

(defun bh/skip-project-tasks ()
  "Show non-project tasks.
Skip project and sub-project tasks, habits, and project related tasks."
  (save-restriction
    (widen)
    (let* ((subtree-end (save-excursion (org-end-of-subtree t))))
      (cond
       ((bh/is-project-p)
        subtree-end)
       ((org-is-habit-p)
        subtree-end)
       ((bh/is-project-subtree-p)
        subtree-end)
       (t
        nil)))))

(defun bh/skip-non-project-tasks ()
  "Show project tasks.
Skip project and sub-project tasks, habits, and loose non-project tasks."
  (save-restriction
    (widen)
    (let* ((subtree-end (save-excursion (org-end-of-subtree t)))
           (next-headline (save-excursion (or (outline-next-heading) (point-max)))))
      (cond
       ((bh/is-project-p)
        next-headline)
       ((org-is-habit-p)
        subtree-end)
       ((and (bh/is-project-subtree-p)
             (member (org-get-todo-state) (list "NEXT")))
        subtree-end)
       ((not (bh/is-project-subtree-p))
        subtree-end)
       (t
        nil)))))

(defun bh/skip-projects-and-habits ()
  "Skip trees that are projects and tasks that are habits"
  (save-restriction
    (widen)
    (let ((subtree-end (save-excursion (org-end-of-subtree t))))
      (cond
       ((bh/is-project-p)
        subtree-end)
       ((org-is-habit-p)
        subtree-end)
       (t
        nil)))))

(defun bh/skip-non-subprojects ()
  "Skip trees that are not projects"
  (let ((next-headline (save-excursion (outline-next-heading))))
    (if (bh/is-subproject-p)
        nil
      next-headline)))

15 Archiving

15.1 Archiving Subtrees

My archiving procedure has changed. I used to move entire subtrees toa separate archive file for the project. Task subtrees in FILE.orgget archived to FILE.org_archive using the a y command in theagenda.

I still archive to the same archive file as before but now I archiveany done state todo task that is old enough to archive. Tasks toarchive are listed automatically at the end of my block agenda andthese are guaranteed to be old enough that I've already billed anytime associated with these tasks. This cleans up my project trees andremoves the old tasks that are no longer interesting. The archivedtasks get extra property data created during the archive procedure sothat it is possible to reconstruct exactly where the archived entrycame from in the rare case where you want to unarchive something.

My archive files are huge but so far I haven't found a need to splitthem by year (or decade) :)

Archivable tasks show up in the last section of my block agenda when anew month starts. Any tasks that are done but have no timestamps thismonth or last month (ie. they are over 30 days old) are available toarchive. Timestamps include closed dates, notes, clock data, etc - anyactive or inactive timestamp in the task.

Archiving is trivial. Just mark all of the entries in the block agendausing the m key and then archive them all to the appropriate placewith B $. This normally takes less than 5 minutes once a month.

15.2 Archive Setup

I no longer use an ARCHIVE property in my subtrees. Tasks can justarchive normally to the Archived Tasks heading in the archive file.

The following setting ensures that task states are untouched when theyare archived. This makes it possible to archive tasks that are notmarked DONE. By default tasks are archived under the heading *Archived Tasks in the archive file.

This archiving function does not keep your project trees intact. Itarchives done state tasks after they are old enough to they areremoved from the main org file. It should be possible to reconstructthe original tree from the archive detail properties but I've neverneeded to do this yet. The archived detail is very useful the fewtimes a year I actually need to look for some archived data but mostof the time I just move it out of the way and keep it for historicalpurposes.

(setq org-archive-mark-done nil)
(setq org-archive-location "%s_archive::* Archived Tasks")
(defun bh/skip-non-archivable-tasks ()
  "Skip trees that are not available for archiving"
  (save-restriction
    (widen)
    ;; Consider only tasks with done todo headings as archivable candidates
    (let ((next-headline (save-excursion (or (outline-next-heading) (point-max))))
          (subtree-end (save-excursion (org-end-of-subtree t))))
      (if (member (org-get-todo-state) org-todo-keywords-1)
          (if (member (org-get-todo-state) org-done-keywords)
              (let* ((daynr (string-to-int (format-time-string "%d" (current-time))))
                     (a-month-ago (* 60 60 24 (+ daynr 1)))
                     (last-month (format-time-string "%Y-%m-" (time-subtract (current-time) (seconds-to-time a-month-ago))))
                     (this-month (format-time-string "%Y-%m-" (current-time)))
                     (subtree-is-current (save-excursion
                                           (forward-line 1)
                                           (and (< (point) subtree-end)
                                                (re-search-forward (concat last-month "\\|" this-month) subtree-end t)))))
                (if subtree-is-current
                    subtree-end ; Has a date in this month or last month, skip it
                  nil))  ; available to archive
            (or subtree-end (point-max)))
        next-headline))))

15.3 Archive Tag - Hiding Information

The only time I set the ARCHIVE tag on a task is to prevent it fromopening by default because it has tons of information I don't reallyneed to look at on a regular basis. I can open the task with C-TAB ifI need to see the gory details (like a huge table of data related tothe task) but normally I don't need that information displayed.

15.4 When to Archive

Archiving monthly works well for me. I keep completed tasks aroundfor at least 30 days before archiving them. This keeps currentclocking information for the last 30 days out of the archives. Thiskeeps my files that contribute to the agenda fairly current (thismonth, and last month, and anything that is unfinished). I onlyrarely visit tasks in the archive when I need to pull up ancienthistory for something.

Archiving keeps my main working files clutter-free. If I ever needthe detail for the archived tasks they are available in theappropriate archive file.

16 Publishing and Exporting

I don't do a lot of publishing for other people but I do keep a set ofprivate client system documentation online. Most of thisdocumentation is a collection of notes exported to HTML.

Everything at http://doc.norang.ca/ is generated by publishingorg-files. This includes the index pages on this site.

Org-mode can export to a variety of publishing formats including (but not limited to)

  • ASCII(plain text - but not the original org-mode file)
  • HTML
  • LaTeX
  • Docbookwhich enables getting to lots of other formats like ODF, XML, etc
  • PDFvia LaTeX or Docbook
  • iCal

I haven't begun the scratch the surface of what org-mode is capable ofdoing. My main use case for org-mode publishing is just to createHTML documents for viewing online conveniently. Someday I'll get timeto try out the other formats when I need them for something.

16.1 New Exporter Setup

The new exporter created by Nicolas Goaziou was introduced in org 8.0.

I have the following setup for the exporters I use.

Alphabetical listing options need to be set before the exporters areloaded for filling to work correctly.

(setq org-alphabetical-lists t)

;; Explicitly load required exporters
(require 'ox-html)
(require 'ox-latex)
(require 'ox-ascii)
16.1.1 Conversion from the old exporter to the new exporter

Here is the list of changes I made to move from the old exporter (preorg 8.0) to the new exporter.

  • Explicitly require exporters
    • Add ox-html
    • Add ox-latex
    • Add ox-ascii
  • Rename variables
    • org-export-html-style-extra to org-html-head-extra
    • org-export-html-validation-link to org-html-validation-link
    • org-export-html-inline-images to org-html-inline-images
    • org-export-html-style-include-default to org-html-head-include-default-style
    • org-export-html-xml-declaration to org-html-xml-declaration
    • org-export-latex-listings to org-latex-listings
    • org-export-html-style-include-scripts to org-html-head-include-scripts
  • Publishing changes
    • Rename :publishing-function
      • org-publish-org-to-html to org-html-publish-to-html
      • org-publish-org-to-org to org-org-publish-to-org
    • Change :style to :html-head
  • Change bh/is-late-deadline to handle modified deadline string in agenda
  • Reverse agenda sorting for late deadlines

    These are no longer reported with negative values on the agenda

  • Add a blank line after my inactive timestamps following headings toprevent them from being exported.

16.2 Org-babel Setup

Org-babel makes it easy to generate decent graphics using externalpackages like ditaa, graphviz, PlantUML, and others.

The setup is really easy. ditaa is provided with the org-modesource. You'll have to install the graphviz and PlantUML packageson your system.

(setq org-ditaa-jar-path "~/git/org-mode/contrib/scripts/ditaa.jar")
(setq org-plantuml-jar-path "~/java/plantuml.jar")

(add-hook 'org-babel-after-execute-hook 'bh/display-inline-images 'append)

; Make babel results blocks lowercase
(setq org-babel-results-keyword "results")

(defun bh/display-inline-images ()
  (condition-case nil
      (org-display-inline-images)
    (error nil)))

(org-babel-do-load-languages
 (quote org-babel-load-languages)
 (quote ((emacs-lisp . t)
         (dot . t)
         (ditaa . t)
         (R . t)
         (python . t)
         (ruby . t)
         (gnuplot . t)
         (clojure . t)
         (sh . t)
         (ledger . t)
         (org . t)
         (plantuml . t)
         (latex . t))))

; Do not prompt to confirm evaluation
; This may be dangerous - make sure you understand the consequences
; of setting this -- see the docstring for details
(setq org-confirm-babel-evaluate nil)

; Use fundamental mode when editing plantuml blocks with C-c '
(add-to-list 'org-src-lang-modes (quote ("plantuml" . fundamental)))

Now you just create a begin-src block for the appropriate tool, editthe text, and build the pictures with C-c C-c. After evaluating theblock results are displayed. You can toggle display of inline imageswith C-c C-x C-v

I disable startup with inline images because when I access myorg-files from an SSH session without X this breaks (say from myAndroid phone) it fails when trying to display the images on a non-Xsession. It's much more important for me to be able to access my org files from my Android phone remotely than it is to see images onstartup.

;; Don't enable this because it breaks access to emacs from my Android phone
(setq org-startup-with-inline-images nil)

16.3 Playing with ditaa

ditaa is a great tool for quickly generating graphics to convey ideasand ditaa is distributed with org-mode! All of the graphics in thisdocument are automatically generated by org-mode using plain textsource.

Artist mode makes it easy to create boxes and lines for ditaagraphics.

The source for a ditaa graphic looks like this in org-mode:

#+begin_src ditaa :file some_filename.png :cmdline -r -s 0.8
  <context of ditaa source goes here>
#+end_src

Here's an example without the #+begin_src and #+end_src lines.

    +-----------+        +---------+  
    |    PLC    |        |         |                
    |  Network  +<------>+   PLC   +<---=---------+ 
    |    cRED   |        |  c707   |              | 
    +-----------+        +----+----+              | 
                              ^                   | 
                              |                   | 
                              |  +----------------|-----------------+
                              |  |                |                 |
                              v  v                v                 v
      +----------+       +----+--+--+      +-------+---+      +-----+-----+       Windows clients
      |          |       |          |      |           |      |           |      +----+      +----+
      | Database +<----->+  Shared  +<---->+ Executive +<-=-->+ Operator  +<---->|cYEL| . . .|cYEL|
      |   c707   |       |  Memory  |      |   c707    |      | Server    |      |    |      |    |
      +--+----+--+       |{d} cGRE  |      +------+----+      |   c707    |      +----+      +----+
         ^    ^          +----------+             ^           +-------+---+
         |    |                                   |                        
         |    +--------=--------------------------+                    
         v                                                             
+--------+--------+                                                         
|                 |                                                         
| Millwide System |            -------- Data ---------                      
| cBLU            |            --=----- Signals ---=--                      
+-----------------+

communication.png

16.4 Playing with graphviz

Graphviz is another great tool for creating graphics in your documents.

The source for a graphviz graphic looks like this in org-mode:

#+begin_src dot :file some_filename.png :cmdline -Kdot -Tpng
  <context of graphviz source goes here>
#+end_src
digraph G {
  size="8,6"
  ratio=expand
  edge [dir=both]
  plcnet [shape=box, label="PLC Network"]
  subgraph cluster_wrapline {
    label="Wrapline Control System"
    color=purple
    subgraph {
    rank=same
    exec
    sharedmem [style=filled, fillcolor=lightgrey, shape=box]
    }
    edge[style=dotted, dir=none]
    exec -> opserver
    exec -> db
    plc -> exec
    edge [style=line, dir=both]
    exec -> sharedmem
    sharedmem -> db
    plc -> sharedmem
    sharedmem -> opserver
  }
  plcnet -> plc [constraint=false]
  millwide [shape=box, label="Millwide System"]
  db -> millwide

  subgraph cluster_opclients {
    color=blue
    label="Operator Clients"
    rankdir=LR
    labelloc=b
    node[label=client]
    opserver -> client1
    opserver -> client2
    opserver -> client3
  }
}

gv01.png

The -Kdot is optional (defaults to dot) but you can substitute other graphviztypes instead here (ie. twopi, neato, circo, etc).

16.5 Playing with PlantUML

I have just started using PlantUML which is built on top of Graphviz.I'm still experimenting with this but so far I like it a lot. Thetodo state change diagrams in this document are created with PlantUML.

The source for a PlantUML graphic looks like this in org-mode:

#+begin_src plantuml :file somefile.png
  <context of PlantUML source goes here>
#+end_src
16.5.1 Sequence Diagram

title Example Sequence Diagram
activate Client
Client -> Server: Session Initiation
note right: Client requests new session
activate Server
Client <-- Server: Authorization Request
note left: Server requires authentication
Client -> Server: Authorization Response
note right: Client provides authentication details
Server --> Client: Session Token
note left: Session established
deactivate Server
Client -> Client: Saves token
deactivate Client

sequence.png

16.5.2 Activity Diagram

title Example Activity Diagram
note right: Example Function
(*)--> "Step 1"
--> "Step 2"
-> "Step 3"
--> "Step 4"
--> === STARTLOOP ===
note top: For each element in the array
if "Are we done?" then
  -> [no] "Do this"
  -> "Do that"
  note bottom: Important note\ngoes here
  -up-> "Increment counters"
  --> === STARTLOOP ===
else
  --> [yes] === ENDLOOP ===
endif
--> "Last Step"
--> (*)

activity.png

16.5.3 Usecase Diagram
LabUser --> (Runs Simulation)
LabUser --> (Analyses Results)

usecase.png

16.5.4 Object Diagram
Object1 <|-- Object2
Object1: someVar
Object1: execute()
Object2: getState()
Object2: setState()
Object2: state

object.png

16.5.5 State Diagram
[*] --> Start
Start -> State2
State2 -> State3
note right of State3: Notes can be\nattached to states
State2 --> State4
State4 -> Finish
State3 --> Finish
Finish --> [*]

plantuml_example_states.png

16.6 Publishing Single Files

Org-mode exports the current file to one of the standard formats byinvoking an export function. The standard key binding for this isC-c C-e followed by the key for the type of export you want.

This works great for single files or parts of files – if you narrowthe buffer to only part of the org-mode file then you only get thenarrowed detail in the export.

16.7 Publishing Projects

I mainly use publishing for publishing multiple files or projects. Idon't want to remember where the created export file needs to move toand org-mode projects are a great solution to this.

The http://doc.norang.ca website (and a bunch of other files that arenot publicly available) are all created by editing org-mode files andpublishing the project the file is contained in. This is great forpeople like me who want to figure out the details once and forgetabout it. I love stuff that Just Works(tm).

I have 5 main projects I use org-mode publishing for currently:

  • norang (website)
  • doc.norang.ca (website, published documents)
  • doc.norang.ca/private (website, non-published documents)
  • www.norang.ca/tmp (temporary publishing site for testing org-mode stuff)
  • org files (which are selectively included by other websites)

Here's my publishing setup:

; experimenting with docbook exports - not finished
(setq org-export-docbook-xsl-fo-proc-command "fop %s %s")
(setq org-export-docbook-xslt-proc-command "xsltproc --output %s /usr/share/xml/docbook/stylesheet/nwalsh/fo/docbook.xsl %s")
;
; Inline images in HTML instead of producting links to the image
(setq org-html-inline-images t)
; Do not use sub or superscripts - I currently don't need this functionality in my documents
(setq org-export-with-sub-superscripts nil)
; Use org.css from the norang website for export document stylesheets
(setq org-html-head-extra "<link rel=\"stylesheet\" href=\"http://doc.norang.ca/org.css\" type=\"text/css\" />")
(setq org-html-head-include-default-style nil)
; Do not generate internal css formatting for HTML exports
(setq org-export-htmlize-output-type (quote css))
; Export with LaTeX fragments
(setq org-export-with-LaTeX-fragments t)
; Increase default number of headings to export
(setq org-export-headline-levels 6)

; List of projects
; norang       - http://www.norang.ca/
; doc          - http://doc.norang.ca/
; org-mode-doc - http://doc.norang.ca/org-mode.html and associated files
; org          - miscellaneous todo lists for publishing
(setq org-publish-project-alist
      ;
      ; http://www.norang.ca/  (norang website)
      ; norang-org are the org-files that generate the content
      ; norang-extra are images and css files that need to be included
      ; norang is the top-level project that gets published
      (quote (("norang-org"
               :base-directory "~/git/www.norang.ca"
               :publishing-directory "/ssh:www-data@www:~/www.norang.ca/htdocs"
               :recursive t
               :table-of-contents nil
               :base-extension "org"
               :publishing-function org-html-publish-to-html
               :style-include-default nil
               :section-numbers nil
               :table-of-contents nil
               :html-head "<link rel=\"stylesheet\" href=\"norang.css\" type=\"text/css\" />"
               :author-info nil
               :creator-info nil)
              ("norang-extra"
               :base-directory "~/git/www.norang.ca/"
               :publishing-directory "/ssh:www-data@www:~/www.norang.ca/htdocs"
               :base-extension "css\\|pdf\\|png\\|jpg\\|gif"
               :publishing-function org-publish-attachment
               :recursive t
               :author nil)
              ("norang"
               :components ("norang-org" "norang-extra"))
              ;
              ; http://doc.norang.ca/  (norang website)
              ; doc-org are the org-files that generate the content
              ; doc-extra are images and css files that need to be included
              ; doc is the top-level project that gets published
              ("doc-org"
               :base-directory "~/git/doc.norang.ca/"
               :publishing-directory "/ssh:www-data@www:~/doc.norang.ca/htdocs"
               :recursive nil
               :section-numbers nil
               :table-of-contents nil
               :base-extension "org"
               :publishing-function (org-html-publish-to-html org-org-publish-to-org)
               :style-include-default nil
               :html-head "<link rel=\"stylesheet\" href=\"/org.css\" type=\"text/css\" />"
               :author-info nil
               :creator-info nil)
              ("doc-extra"
               :base-directory "~/git/doc.norang.ca/"
               :publishing-directory "/ssh:www-data@www:~/doc.norang.ca/htdocs"
               :base-extension "css\\|pdf\\|png\\|jpg\\|gif"
               :publishing-function org-publish-attachment
               :recursive nil
               :author nil)
              ("doc"
               :components ("doc-org" "doc-extra"))
              ("doc-private-org"
               :base-directory "~/git/doc.norang.ca/private"
               :publishing-directory "/ssh:www-data@www:~/doc.norang.ca/htdocs/private"
               :recursive nil
               :section-numbers nil
               :table-of-contents nil
               :base-extension "org"
               :publishing-function (org-html-publish-to-html org-org-publish-to-org)
               :style-include-default nil
               :html-head "<link rel=\"stylesheet\" href=\"/org.css\" type=\"text/css\" />"
               :auto-sitemap t
               :sitemap-filename "index.html"
               :sitemap-title "Norang Private Documents"
               :sitemap-style "tree"
               :author-info nil
               :creator-info nil)
              ("doc-private-extra"
               :base-directory "~/git/doc.norang.ca/private"
               :publishing-directory "/ssh:www-data@www:~/doc.norang.ca/htdocs/private"
               :base-extension "css\\|pdf\\|png\\|jpg\\|gif"
               :publishing-function org-publish-attachment
               :recursive nil
               :author nil)
              ("doc-private"
               :components ("doc-private-org" "doc-private-extra"))
              ;
              ; Miscellaneous pages for other websites
              ; org are the org-files that generate the content
              ("org-org"
               :base-directory "~/git/org/"
               :publishing-directory "/ssh:www-data@www:~/org"
               :recursive t
               :section-numbers nil
               :table-of-contents nil
               :base-extension "org"
               :publishing-function org-html-publish-to-html
               :style-include-default nil
               :html-head "<link rel=\"stylesheet\" href=\"/org.css\" type=\"text/css\" />"
               :author-info nil
               :creator-info nil)
              ;
              ; http://doc.norang.ca/  (norang website)
              ; org-mode-doc-org this document
              ; org-mode-doc-extra are images and css files that need to be included
              ; org-mode-doc is the top-level project that gets published
              ; This uses the same target directory as the 'doc' project
              ("org-mode-doc-org"
               :base-directory "~/git/org-mode-doc/"
               :publishing-directory "/ssh:www-data@www:~/doc.norang.ca/htdocs"
               :recursive t
               :section-numbers nil
               :table-of-contents nil
               :base-extension "org"
               :publishing-function (org-html-publish-to-html)
               :plain-source t
               :htmlized-source t
               :style-include-default nil
               :html-head "<link rel=\"stylesheet\" href=\"/org.css\" type=\"text/css\" />"
               :author-info nil
               :creator-info nil)
              ("org-mode-doc-extra"
               :base-directory "~/git/org-mode-doc/"
               :publishing-directory "/ssh:www-data@www:~/doc.norang.ca/htdocs"
               :base-extension "css\\|pdf\\|png\\|jpg\\|gif\\|org"
               :publishing-function org-publish-attachment
               :recursive t
               :author nil)
              ("org-mode-doc"
               :components ("org-mode-doc-org" "org-mode-doc-extra"))
              ;
              ; http://doc.norang.ca/  (norang website)
              ; org-mode-doc-org this document
              ; org-mode-doc-extra are images and css files that need to be included
              ; org-mode-doc is the top-level project that gets published
              ; This uses the same target directory as the 'doc' project
              ("tmp-org"
               :base-directory "/tmp/publish/"
               :publishing-directory "/ssh:www-data@www:~/www.norang.ca/htdocs/tmp"
               :recursive t
               :section-numbers nil
               :table-of-contents nil
               :base-extension "org"
               :publishing-function (org-html-publish-to-html org-org-publish-to-org)
               :html-head "<link rel=\"stylesheet\" href=\"http://doc.norang.ca/org.css\" type=\"text/css\" />"
               :plain-source t
               :htmlized-source t
               :style-include-default nil
               :auto-sitemap t
               :sitemap-filename "index.html"
               :sitemap-title "Test Publishing Area"
               :sitemap-style "tree"
               :author-info t
               :creator-info t)
              ("tmp-extra"
               :base-directory "/tmp/publish/"
               :publishing-directory "/ssh:www-data@www:~/www.norang.ca/htdocs/tmp"
               :base-extension "css\\|pdf\\|png\\|jpg\\|gif"
               :publishing-function org-publish-attachment
               :recursive t
               :author nil)
              ("tmp"
               :components ("tmp-org" "tmp-extra")))))

; I'm lazy and don't want to remember the name of the project to publish when I modify
; a file that is part of a project.  So this function saves the file, and publishes
; the project that includes this file
;
; It's bound to C-S-F12 so I just edit and hit C-S-F12 when I'm done and move on to the next thing
(defun bh/save-then-publish (&optional force)
  (interactive "P")
  (save-buffer)
  (org-save-all-org-buffers)
  (let ((org-html-head-extra)
        (org-html-validation-link "<a href=\"http://validator.w3.org/check?uri=referer\">Validate XHTML 1.0</a>"))
    (org-publish-current-project force)))

(global-set-key (kbd "C-s-<f12>") 'bh/save-then-publish)

The main projects are norang, doc, doc-private, org-mode-doc,and tmp. These projects publish directly to the webserver directoryon a remote web server that serves the site. Publishing one of theseprojects exports all modified pages, generates images, and copies theresulting files to the webserver so that they are immediatelyavailable for viewing.

The http://doc.norang.ca/ site contains subdirectories with client andprivate documentation that are restricted by using Apache Basicauthentication. I don't create links to these sites from the publiclyviewable pages. http://doc.norang.ca/someclient/ would show the indexfor any org files under ~/git/doc.norang.ca/someclient/ if that isset up as a viewable website. I use most of the information myselfbut give access to clients if they are interested in theinformation/notes that I keep about their systems.

This works great for me - I know where my notes are and I can accessthem from anywhere on the internet. I'm also free to share notes withother people by simply giving them the link to the appropriate site.

All I need to remember to do is edit the appropriate org file andpublish it with C-S-F12 – not exactly hard :)

I added a temporary publishing site for testing exports andvalidation. This is the tmp site which takes files from/tmp/publish and exports those files to a website publishingdirectory. This makes it easy to try new throw-away things on a liveserver.

16.8 Miscellaneous Export Settings

This is a collection of export and publishing related settings that Iuse.

16.8.1 Fontify Latex listings for source blocks

For export to latex I use the following setting to get fontifiedlistings from source blocks:

(setq org-latex-listings t)
16.8.2 Export HTML without XML header

I use the following setting to remove the xml header line for HTMLexports. This xml line was confusing Open Office when opening theHTML to convert to ODT.

(setq org-html-xml-declaration (quote (("html" . "")
                                       ("was-html" . "<?xml version=\"1.0\" encoding=\"%s\"?>")
                                       ("php" . "<?php echo \"<?xml version=\\\"1.0\\\" encoding=\\\"%s\\\" ?>\"; ?>"))))
16.8.3 Allow binding variables on export without confirmation

The following setting allows #+BIND: variables to be set on exportwithout confirmation. In rare situations where I want to overridesome org-mode variable for export this allows exporting the documentwithout a prompt.

(setq org-export-allow-BIND t)

17 Reminders

I use appt for reminders. It's simple and unobtrusive – puttingpending appointments in the status bar and beeping as 12, 9, 6, 3,and 0 minutes before the appointment is due.

Everytime the agenda is displayed (and that's lots for me) theappointment list is erased and rebuilt from the current agendadetails for today. This means everytime I reschedule something, addor remove tasks that are time related the appointment list isautomatically updated the next time I look at the agenda.

17.1 Reminder Setup

; Erase all reminders and rebuilt reminders for today from the agenda
(defun bh/org-agenda-to-appt ()
  (interactive)
  (setq appt-time-msg-list nil)
  (org-agenda-to-appt))

; Rebuild the reminders everytime the agenda is displayed
(add-hook 'org-finalize-agenda-hook 'bh/org-agenda-to-appt 'append)

; This is at the end of my .emacs - so appointments are set up when Emacs starts
(bh/org-agenda-to-appt)

; Activate appointments so we get notifications
(appt-activate t)

; If we leave Emacs running overnight - reset the appointments one minute after midnight
(run-at-time "24:01" nil 'bh/org-agenda-to-appt)

18 Productivity Tools

This section is a miscellaneous collection of Emacs customizations that I usewith org-mode so that it Works-For-Me(tm).

18.1 Abbrev-mode and Skeletons

I use skeletons with abbrev-mode to quickly add preconfigured blocks to my Emacs edit buffers.

I have blocks for creating:

  • generic blocks in org-mode
  • plantuml blocks in org-mode
    • plantuml activity diagram block in org-mode
    • plantuml sequence diagram block in org-mode
  • graphviz dot blocks in org-mode
  • ditaa blocks in org-mode
  • elisp source blocks in org-mode

I still use < e TAB and < s TAB for creating example blocks andsimple shell script blocks that need no further parameters.

Here's my current setup for org-mode related skeletons. Each onedefines an abbrev-mode shortcut so I can type splantumlRET to createa Plantuml block. This prompts for the filename (without extension) forthe generated image file.

At work I add a :tangle header to the skeleton and explicitlyinclude the @startuml and @enduml marker lines in the skeleton soI can tangle the source file and share it with my colleagues. Thismakes the tangled source useable in Notepad and the PlantUML jarfile running standalone.

I have put the s (src) prefix on the shortcuts to preventabbrev-mode from trying to expand PlantUML when I'm typing it in asentence.

For convenience in activity diagrams I added sif and sfor and justchange the labels for the synchronization bars.

;; Enable abbrev-mode
(add-hook 'org-mode-hook (lambda () (abbrev-mode 1)))

;; Skeletons
;;
;; sblk - Generic block #+begin_FOO .. #+end_FOO
(define-skeleton skel-org-block
  "Insert an org block, querying for type."
  "Type: "
  "#+begin_" str "\n"
  _ - \n
  "#+end_" str "\n")

(define-abbrev org-mode-abbrev-table "sblk" "" 'skel-org-block)

;; splantuml - PlantUML Source block
(define-skeleton skel-org-block-plantuml
  "Insert a org plantuml block, querying for filename."
  "File (no extension): "
  "#+begin_src plantuml :file " str ".png :cache yes\n"
  _ - \n
  "#+end_src\n")

(define-abbrev org-mode-abbrev-table "splantuml" "" 'skel-org-block-plantuml)

(define-skeleton skel-org-block-plantuml-activity
  "Insert a org plantuml block, querying for filename."
  "File (no extension): "
  "#+begin_src plantuml :file " str "-act.png :cache yes :tangle " str "-act.txt\n"
  (bh/plantuml-reset-counters)
  "@startuml\n"
  "skinparam activity {\n"
  "BackgroundColor<<New>> Cyan\n"
  "}\n\n"
  "title " str " - \n"
  "note left: " str "\n"
  "(*) --> \"" str "\"\n"
  "--> (*)\n"
  _ - \n
  "@enduml\n"
  "#+end_src\n")

(defvar bh/plantuml-if-count 0)

(defun bh/plantuml-if () 
  (incf bh/plantuml-if-count)
  (number-to-string bh/plantuml-if-count))

(defvar bh/plantuml-loop-count 0)

(defun bh/plantuml-loop () 
  (incf bh/plantuml-loop-count)
  (number-to-string bh/plantuml-loop-count))

(defun bh/plantuml-reset-counters ()
  (setq bh/plantuml-if-count 0
        bh/plantuml-loop-count 0)
  "")

(define-abbrev org-mode-abbrev-table "sact" "" 'skel-org-block-plantuml-activity)

(define-skeleton skel-org-block-plantuml-activity-if
  "Insert a org plantuml block activity if statement"
  "" 
  "if \"\" then\n"
  "  -> [condition] ==IF" (setq ifn (bh/plantuml-if)) "==\n"
  "  --> ==IF" ifn "M1==\n"
  "  -left-> ==IF" ifn "M2==\n"
  "else\n"
  "end if\n"
  "--> ==IF" ifn "M2==")

(define-abbrev org-mode-abbrev-table "sif" "" 'skel-org-block-plantuml-activity-if)

(define-skeleton skel-org-block-plantuml-activity-for
  "Insert a org plantuml block activity for statement"
  "Loop for each: " 
  "--> ==LOOP" (setq loopn (bh/plantuml-loop)) "==\n"
  "note left: Loop" loopn ": For each " str "\n"
  "--> ==ENDLOOP" loopn "==\n"
  "note left: Loop" loopn ": End for each " str "\n" )

(define-abbrev org-mode-abbrev-table "sfor" "" 'skel-org-block-plantuml-activity-for)

(define-skeleton skel-org-block-plantuml-sequence
  "Insert a org plantuml activity diagram block, querying for filename."
  "File appends (no extension): "
  "#+begin_src plantuml :file " str "-seq.png :cache yes :tangle " str "-seq.txt\n"
  "@startuml\n"
  "title " str " - \n"
  "actor CSR as \"Customer Service Representative\"\n"
  "participant CSMO as \"CSM Online\"\n"
  "participant CSMU as \"CSM Unix\"\n"
  "participant NRIS\n"
  "actor Customer"
  _ - \n
  "@enduml\n"
  "#+end_src\n")

(define-abbrev org-mode-abbrev-table "sseq" "" 'skel-org-block-plantuml-sequence)

;; sdot - Graphviz DOT block
(define-skeleton skel-org-block-dot
  "Insert a org graphviz dot block, querying for filename."
  "File (no extension): "
  "#+begin_src dot :file " str ".png :cache yes :cmdline -Kdot -Tpng\n"
  "graph G {\n"
  _ - \n
  "}\n"
  "#+end_src\n")

(define-abbrev org-mode-abbrev-table "sdot" "" 'skel-org-block-dot)

;; sditaa - Ditaa source block
(define-skeleton skel-org-block-ditaa
  "Insert a org ditaa block, querying for filename."
  "File (no extension): "
  "#+begin_src ditaa :file " str ".png :cache yes\n"
  _ - \n
  "#+end_src\n")

(define-abbrev org-mode-abbrev-table "sditaa" "" 'skel-org-block-ditaa)

;; selisp - Emacs Lisp source block
(define-skeleton skel-org-block-elisp
  "Insert a org emacs-lisp block"
  ""
  "#+begin_src emacs-lisp\n"
  _ - \n
  "#+end_src\n")

(define-abbrev org-mode-abbrev-table "selisp" "" 'skel-org-block-elisp)

I also use abbrev-mode when taking notes at work. I tend to writefirst names for people which get expanded to their complete name in mynotes. So if I write mickey it gets automatically expanded toMickey Mouse as I type. To create an abbreviation just type in theshort form followed by C-x a i l to create an abbreviation for thecurrent mode I'm in.

The only thing you have to be careful with is not to use a common word for yourabbreviation since abbrev-mode will try to expand it everytime you enter it.I found this annoying when I used plantuml as one of my abbreviations.

I also use skeletons and abbrev-mode for C source files at work.This works really well for me.

18.1.1 Example PlantUml Activity Diagram Generation

When creating activity diagrams I can use 'sif' and 'sfor' to add IF and FOR blocks to the diagram with unique numbering automaticallygenerated.

Example: Create a new diagram and enter 2 IFs and 2 FOR blocks

Create diagram: "sact RET test RET"

gives

@startuml
skinparam activity {
BackgroundColor<<New>> Cyan
}

title test - 
note left: test
(*) --> "test"
--> (*)

@enduml

test-act.png

Put cursor on –> (*) and enter "sif RET"

gives

@startuml
skinparam activity {
BackgroundColor<<New>> Cyan
}

title test - 
note left: test
(*) --> "test"
if "" then
  -> [condition] ==IF1==
  --> ==IF1M1==
  -left-> ==IF1M2==
else
end if
--> ==IF1M2==
--> (*)

@enduml

test-act2.png

repeat on –> (*) line

gives

@startuml
skinparam activity {
BackgroundColor<<New>> Cyan
}

title test - 
note left: test
(*) --> "test"
if "" then
  -> [condition] ==IF1==
  --> ==IF1M1==
  -left-> ==IF1M2==
else
end if
--> ==IF1M2==
if "" then
  -> [condition] ==IF2==
  --> ==IF2M1==
  -left-> ==IF2M2==
else
end if
--> ==IF2M2==
--> (*)

@enduml

test-act3.png

and add two for loops at the end with "sfor RET line in file RET" and"sfor RET address in addressbook RET"

gives

@startuml
skinparam activity {
BackgroundColor<<New>> Cyan
}

title test - 
note left: test
(*) --> "test"
if "" then
  -> [condition] ==IF1==
  --> ==IF1M1==
  -left-> ==IF1M2==
else
end if
--> ==IF1M2==
if "" then
  -> [condition] ==IF2==
  --> ==IF2M1==
  -left-> ==IF2M2==
else
end if
--> ==IF2M2==
--> ==LOOP1==
note left: Loop1: For each line in file
--> ==ENDLOOP1==
note left: Loop1: End for each line in file
--> ==LOOP2==
note left: Loop2: For each address in addressbook
--> ==ENDLOOP2==
note left: Loop2: End for each address in addressbook

--> (*)

@enduml

test-act4.png

I use rectangular cut and paste if I need to indent generated blocks.

18.2 Focus On Current Work

There is more than one way to do this. Use what works for you.

18.2.1 Narrowing to a subtree with bh/org-todo

f5 and S-f5 are bound the functions for narrowing and widening theemacs buffer as defined below.

We now use:

  • T (tasks) for C-c / t on the current buffer
  • N (narrow) narrows to this task subtree
  • U (up) narrows to the immediate parent task subtree without moving
  • P (project) narrows to the parent project subtree without moving
  • F (file) narrows to the current file or file of the existing restriction

The agenda keeps widening the org buffer so this gives a convenientway to focus on what we are doing.

(global-set-key (kbd "<f5>") 'bh/org-todo)

(defun bh/org-todo (arg)
  (interactive "p")
  (if (equal arg 4)
      (save-restriction
        (bh/narrow-to-org-subtree)
        (org-show-todo-tree nil))
    (bh/narrow-to-org-subtree)
    (org-show-todo-tree nil)))

(global-set-key (kbd "<S-f5>") 'bh/widen)

(defun bh/widen ()
  (interactive)
  (if (equal major-mode 'org-agenda-mode)
      (progn
        (org-agenda-remove-restriction-lock)
        (when org-agenda-sticky
          (org-agenda-redo)))
    (widen)))

(add-hook 'org-agenda-mode-hook
          '(lambda () (org-defkey org-agenda-mode-map "W" (lambda () (interactive) (setq bh/hide-scheduled-and-waiting-next-tasks t) (bh/widen))))
          'append)

(defun bh/restrict-to-file-or-follow (arg)
  "Set agenda restriction to 'file or with argument invoke follow mode.
I don't use follow mode very often but I restrict to file all the time
so change the default 'F' binding in the agenda to allow both"
  (interactive "p")
  (if (equal arg 4)
      (org-agenda-follow-mode)
    (widen)
    (bh/set-agenda-restriction-lock 4)
    (org-agenda-redo)
    (beginning-of-buffer)))

(add-hook 'org-agenda-mode-hook
          '(lambda () (org-defkey org-agenda-mode-map "F" 'bh/restrict-to-file-or-follow))
          'append)

(defun bh/narrow-to-org-subtree ()
  (widen)
  (org-narrow-to-subtree)
  (save-restriction
    (org-agenda-set-restriction-lock)))

(defun bh/narrow-to-subtree ()
  (interactive)
  (if (equal major-mode 'org-agenda-mode)
      (progn
        (org-with-point-at (org-get-at-bol 'org-hd-marker)
          (bh/narrow-to-org-subtree))
        (when org-agenda-sticky
          (org-agenda-redo)))
    (bh/narrow-to-org-subtree)))

(add-hook 'org-agenda-mode-hook
          '(lambda () (org-defkey org-agenda-mode-map "N" 'bh/narrow-to-subtree))
          'append)

(defun bh/narrow-up-one-org-level ()
  (widen)
  (save-excursion
    (outline-up-heading 1 'invisible-ok)
    (bh/narrow-to-org-subtree)))

(defun bh/get-pom-from-agenda-restriction-or-point ()
  (or (and (marker-position org-agenda-restrict-begin) org-agenda-restrict-begin)
      (org-get-at-bol 'org-hd-marker)
      (and (equal major-mode 'org-mode) (point))
      org-clock-marker))

(defun bh/narrow-up-one-level ()
  (interactive)
  (if (equal major-mode 'org-agenda-mode)
      (progn
        (org-with-point-at (bh/get-pom-from-agenda-restriction-or-point)
          (bh/narrow-up-one-org-level))
        (org-agenda-redo))
    (bh/narrow-up-one-org-level)))

(add-hook 'org-agenda-mode-hook
          '(lambda () (org-defkey org-agenda-mode-map "U" 'bh/narrow-up-one-level))
          'append)

(defun bh/narrow-to-org-project ()
  (widen)
  (save-excursion
    (bh/find-project-task)
    (bh/narrow-to-org-subtree)))

(defun bh/narrow-to-project ()
  (interactive)
  (if (equal major-mode 'org-agenda-mode)
      (progn
        (org-with-point-at (bh/get-pom-from-agenda-restriction-or-point)
          (bh/narrow-to-org-project)
          (save-excursion
            (bh/find-project-task)
            (org-agenda-set-restriction-lock)))
        (org-agenda-redo)
        (beginning-of-buffer))
    (bh/narrow-to-org-project)
    (save-restriction
      (org-agenda-set-restriction-lock))))

(add-hook 'org-agenda-mode-hook
          '(lambda () (org-defkey org-agenda-mode-map "P" 'bh/narrow-to-project))
          'append)

(defvar bh/project-list nil)

(defun bh/view-next-project ()
  (interactive)
  (let (num-project-left current-project)
    (unless (marker-position org-agenda-restrict-begin)
      (goto-char (point-min))
      ; Clear all of the existing markers on the list
      (while bh/project-list
        (set-marker (pop bh/project-list) nil))
      (re-search-forward "Tasks to Refile")
      (forward-visible-line 1))

    ; Build a new project marker list
    (unless bh/project-list
      (while (< (point) (point-max))
        (while (and (< (point) (point-max))
                    (or (not (org-get-at-bol 'org-hd-marker))
                        (org-with-point-at (org-get-at-bol 'org-hd-marker)
                          (or (not (bh/is-project-p))
                              (bh/is-project-subtree-p)))))
          (forward-visible-line 1))
        (when (< (point) (point-max))
          (add-to-list 'bh/project-list (copy-marker (org-get-at-bol 'org-hd-marker)) 'append))
        (forward-visible-line 1)))

    ; Pop off the first marker on the list and display
    (setq current-project (pop bh/project-list))
    (when current-project
      (org-with-point-at current-project
        (setq bh/hide-scheduled-and-waiting-next-tasks nil)
        (bh/narrow-to-project))
      ; Remove the marker
      (setq current-project nil)
      (org-agenda-redo)
      (beginning-of-buffer)
      (setq num-projects-left (length bh/project-list))
      (if (> num-projects-left 0)
          (message "%s projects left to view" num-projects-left)
        (beginning-of-buffer)
        (setq bh/hide-scheduled-and-waiting-next-tasks t)
        (error "All projects viewed.")))))

(add-hook 'org-agenda-mode-hook
          '(lambda () (org-defkey org-agenda-mode-map "V" 'bh/view-next-project))
          'append)

This makes it easy to hide all of the other details in your org-filetemporarily by limiting your view to this task subtree. Tasks arefolded and hilighted so that only tasks which are incomplete areshown.

I hit f5 (or the T speed key) a lot. This basically does aorg-narrow-to-subtree and C-c / t combination leaving the bufferin a narrowed state. I use S-f5 (or some other widening speed keylike U, W, F) to widen back to the normal view.

I also have the following setting to force showing the next headline.

(setq org-show-entry-below (quote ((default))))

This prevents too many headlines from being folded together when I'mworking with collapsed trees.

18.2.2 Limiting the agenda to a subtree

C-c C-x < turns on the agenda restriction lock for the currentsubtree. This keeps your agenda focused on only this subtree. Alarmsand notifications are still active outside the agenda restriction.C-c C-x > turns off the agenda restriction lock returning youragenda view back to normal.

I have added key bindings for the agenda to allow using C-c C-x < inthe agenda to set the restriction lock to the current task directly.The following elisp accomplishes this.

(add-hook 'org-agenda-mode-hook
          '(lambda () (org-defkey org-agenda-mode-map "\C-c\C-x<" 'bh/set-agenda-restriction-lock))
          'append)

(defun bh/set-agenda-restriction-lock (arg)
  "Set restriction lock to current task subtree or file if prefix is specified"
  (interactive "p")
  (let* ((pom (bh/get-pom-from-agenda-restriction-or-point))
         (tags (org-with-point-at pom (org-get-tags-at))))
    (let ((restriction-type (if (equal arg 4) 'file 'subtree)))
      (save-restriction
        (cond
         ((and (equal major-mode 'org-agenda-mode) pom)
          (org-with-point-at pom
            (org-agenda-set-restriction-lock restriction-type))
          (org-agenda-redo))
         ((and (equal major-mode 'org-mode) (org-before-first-heading-p))
          (org-agenda-set-restriction-lock 'file))
         (pom
          (org-with-point-at pom
            (org-agenda-set-restriction-lock restriction-type))))))))

This allows me to set the restriction lock from agenda to task directly.I work from the agenda a lot and I find this very convenient.

Setting the restriction directly to the task is less surprising thanautomatically moving up the tree to the project level task – which iswhat I was doing before. If the select task is too restrictive it'seasy to move the restriction lock up a level by visiting the task inthe org file and going up and resetting the lock - in case you want tosee move of the project.

Selecting the entire project sometimes has too many tasks in it and Iwant to limit the view to part of the subtree. This is why I keep the N andU key bindings for adjusting the narrowed region.

I've added new convenience keys for restricting the agenda and org-buffer tosubtree, parent task, and project task, as well as removing the restriction.These keys work both in the agenda and as speed commands on a headline in theorg-file.

  • N narrows to the current task subtree

    This is the same as same as C-c C-x <

  • U narrows to the parent subtree of this task

    This goes up one level and narrows to that subtree.

  • P narrows to the entire project containing this task

    This goes up the tree to the top-level TODO keyword and selectsthat as the subtree to narrow to

  • W removes the restriction, widening the buffer

I like the highlighting for a restriction to only affect the headlineand not the entire body of the agenda restriction. I use thefollowing setting to keep the highlight on the heading only (as wasthe case for pre-8.0 versions of org-mode)

;; Limit restriction lock highlighting to the headline only
(setq org-agenda-restriction-lock-highlight-subtree nil)
18.2.3 Limiting the agenda to a file

You can limit the agenda view to a single file in multiple ways.

You can use the agenda restriction lock C-c C-x < on the anyline before the first heading to set the agenda restriction lockto this file only. This is equivalent using a prefix argumment(C-u C-c C-x <) anywhere in the file. This lock stays ineffect until you remove it with C-c C-x >.

This also works in the agenda with my C-u C-c c-x < key binding.

Another way is to invoke the agenda with F12 < a while visiting anorg-mode file. This limits the agenda view to just this file. Ioccasionally use this to view a file not in my org-agenda-files inthe agenda.

18.3 Tuning the Agenda Views

Various customizations affect how the agenda views show task details.This section shows each of the customizations I use in my workflow.

18.3.1 Highlight the current agenda line

The following code in my .emacs file keeps the current agenda linehighlighted. This makes it obvious what task will be affected bycommands issued in the agenda. No more acting on the wrong task bymistake!

The clock modeline time is also shown with a reverse background.

;; Always hilight the current agenda line
(add-hook 'org-agenda-mode-hook
          '(lambda () (hl-line-mode 1))
          'append)
;; The following custom-set-faces create the highlights
(custom-set-faces
  ;; custom-set-faces was added by Custom.
  ;; If you edit it by hand, you could mess it up, so be careful.
  ;; Your init file should contain only one such instance.
  ;; If there is more than one, they won't work right.
 '(org-mode-line-clock ((t (:background "grey75" :foreground "red" :box (:line-width -1 :style released-button)))) t))
18.3.2 Keep tasks with timestamps visible on the global todo lists

Tasks with dates (SCHEDULED:, DEADLINE:, or active dates) show upin the agenda when appropriate. The block agenda view (F12 a) triesto keep tasks showing up only in one location (either in the calendaror other todo lists in later sections of the block agenda.) I nowrarely use the global todo list search in org-mode (F12 t, F12 m)and when I do I'm trying to find a specific task quickly. These listsnow include everything so I can just search for the item I want andmove on.

The block agenda prevents display of tasks with deadlines or scheduleddates in the future so you can safely ignore these until theappropriate time.

;; Keep tasks with dates on the global todo lists
(setq org-agenda-todo-ignore-with-date nil)

;; Keep tasks with deadlines on the global todo lists
(setq org-agenda-todo-ignore-deadlines nil)

;; Keep tasks with scheduled dates on the global todo lists
(setq org-agenda-todo-ignore-scheduled nil)

;; Keep tasks with timestamps on the global todo lists
(setq org-agenda-todo-ignore-timestamp nil)

;; Remove completed deadline tasks from the agenda view
(setq org-agenda-skip-deadline-if-done t)

;; Remove completed scheduled tasks from the agenda view
(setq org-agenda-skip-scheduled-if-done t)

;; Remove completed items from search results
(setq org-agenda-skip-timestamp-if-done t)
18.3.3 Use the Diary for Holidays and Appointments

I don't use the emacs Diary for anything but I like seeing theholidays on my agenda. This helps with planning for those days whenyou're not supposed to be working.

(setq org-agenda-include-diary nil)
(setq org-agenda-diary-file "~/git/org/diary.org")

The diary file keeps date-tree entries created by the capture mode'appointment' template. I use this also for miscellaneous tasks Iwant to clock during interruptions.

I don't use a ~/diary file anymore. That is just there as azero-length file to keep Emacs happy. I use org-mode's diaryfunctions instead. Inserting entries with i in the emacs agendacreates date entries in the ~/git/org/diary.org file.

I include holidays from the calendar in my todo.org file as follows:

#+FILETAGS: PERSONAL
* Appointments
  :PROPERTIES:
  :CATEGORY: Appt
  :ARCHIVE:  %s_archive::* Appointments
  :END:      
** Holidays
   :PROPERTIES:
   :Category: Holiday
   :END:
   %%(org-calendar-holiday)
** Some other Appointment
   ...

I use the following setting so any time strings in the heading areshown in the agenda.

(setq org-agenda-insert-diary-extract-time t)
18.3.4 Searches include archive files

I keep a single archive file for each of my org-mode project files.This allows me to search the current file and the archive when I needto dig up old information from the archives.

I don't need this often but it sure is handy on the occasions thatI do need it.

;; Include agenda archive files when searching for things
(setq org-agenda-text-search-extra-files (quote (agenda-archives)))
18.3.5 Agenda view tweaks

The following agenda customizations control

  • display of repeating tasks
  • display of empty dates on the agenda
  • task sort order
  • start the agenda weekly view with Sunday
  • display of the grid
  • habits at the bottom

I use a custom sorting function so that my daily agenda lists tasks inorder of importance. Tasks on the daily agenda are listed in thefollowing order:

  1. tasks with times at the top so they are hard to miss
  2. entries for today (active timestamp headlines that are not scheduled or deadline tasks)
  3. deadlines due today
  4. late deadline tasks
  5. scheduled items for today
  6. pending deadlines (due soon)
  7. late scheduled items
  8. habits

The lisp for this isn't particularly pretty but it works.

Here are the .emacs settings:

;; Show all future entries for repeating tasks
(setq org-agenda-repeating-timestamp-show-all t)

;; Show all agenda dates - even if they are empty
(setq org-agenda-show-all-dates t)

;; Sorting order for tasks on the agenda
(setq org-agenda-sorting-strategy
      (quote ((agenda habit-down time-up user-defined-up effort-up category-keep)
              (todo category-up effort-up)
              (tags category-up effort-up)
              (search category-up))))

;; Start the weekly agenda on Monday
(setq org-agenda-start-on-weekday 1)

;; Enable display of the time grid so we can see the marker for the current time
(setq org-agenda-time-grid (quote ((daily today remove-match)
                                   #("----------------" 0 16 (org-heading t))
                                   (0900 1100 1300 1500 1700))))

;; Display tags farther right
(setq org-agenda-tags-column -102)

;;
;; Agenda sorting functions
;;
(setq org-agenda-cmp-user-defined 'bh/agenda-sort)

(defun bh/agenda-sort (a b)
  "Sorting strategy for agenda items.
Late deadlines first, then scheduled, then non-late deadlines"
  (let (result num-a num-b)
    (cond
     ; time specific items are already sorted first by org-agenda-sorting-strategy

     ; non-deadline and non-scheduled items next
     ((bh/agenda-sort-test 'bh/is-not-scheduled-or-deadline a b))

     ; deadlines for today next
     ((bh/agenda-sort-test 'bh/is-due-deadline a b))

     ; late deadlines next
     ((bh/agenda-sort-test-num 'bh/is-late-deadline '> a b))

     ; scheduled items for today next
     ((bh/agenda-sort-test 'bh/is-scheduled-today a b))

     ; late scheduled items next
     ((bh/agenda-sort-test-num 'bh/is-scheduled-late '> a b))

     ; pending deadlines last
     ((bh/agenda-sort-test-num 'bh/is-pending-deadline '< a b))

     ; finally default to unsorted
     (t (setq result nil)))
    result))

(defmacro bh/agenda-sort-test (fn a b)
  "Test for agenda sort"
  `(cond
    ; if both match leave them unsorted
    ((and (apply ,fn (list ,a))
          (apply ,fn (list ,b)))
     (setq result nil))
    ; if a matches put a first
    ((apply ,fn (list ,a))
     (setq result -1))
    ; otherwise if b matches put b first
    ((apply ,fn (list ,b))
     (setq result 1))
    ; if none match leave them unsorted
    (t nil)))

(defmacro bh/agenda-sort-test-num (fn compfn a b)
  `(cond
    ((apply ,fn (list ,a))
     (setq num-a (string-to-number (match-string 1 ,a)))
     (if (apply ,fn (list ,b))
         (progn
           (setq num-b (string-to-number (match-string 1 ,b)))
           (setq result (if (apply ,compfn (list num-a num-b))
                            -1
                          1)))
       (setq result -1)))
    ((apply ,fn (list ,b))
     (setq result 1))
    (t nil)))

(defun bh/is-not-scheduled-or-deadline (date-str)
  (and (not (bh/is-deadline date-str))
       (not (bh/is-scheduled date-str))))

(defun bh/is-due-deadline (date-str)
  (string-match "Deadline:" date-str))

(defun bh/is-late-deadline (date-str)
  (string-match "\\([0-9]*\\) d\. ago:" date-str))

(defun bh/is-pending-deadline (date-str)
  (string-match "In \\([^-]*\\)d\.:" date-str))

(defun bh/is-deadline (date-str)
  (or (bh/is-due-deadline date-str)
      (bh/is-late-deadline date-str)
      (bh/is-pending-deadline date-str)))

(defun bh/is-scheduled (date-str)
  (or (bh/is-scheduled-today date-str)
      (bh/is-scheduled-late date-str)))

(defun bh/is-scheduled-today (date-str)
  (string-match "Scheduled:" date-str))

(defun bh/is-scheduled-late (date-str)
  (string-match "Sched\.\\(.*\\)x:" date-str))
18.3.6 Sticky Agendas

Sticky agendas allow you to have more than one agenda view created simultaneously.You can quickly switch to the view without incurring an agenda rebuild by invokingthe agenda custom command key that normally generates the agenda. If it already exists it will display the existing view. g forces regeneration of the agenda view.

I normally have two views displayed (F12 a for the daily/weeklyagenda and F12 SPC for my project management view)

;; Use sticky agenda's so they persist
(setq org-agenda-sticky t)

18.4 Checklist handling

Checklists are great for repeated tasks with lots of things that needto be done. For a long time I was manually resetting the check boxesto unchecked when marking the repeated task DONE but no more!There's a contributed org-checklist that can uncheck the boxesautomagically when the task is marked done.

Add the following to your .emacs

(add-to-list 'load-path (expand-file-name "~/git/org-mode/contrib/lisp"))

(require 'org-checklist)

and then to use it in a task you simply set the property RESET_CHECK_BOXES to t like this

* TODO Invoicing and Archive Tasks [0/7]
  DEADLINE: <2009-07-01 Wed +1m -0d> 
  :PROPERTIES:
  :RESET_CHECK_BOXES: t
  :END:

  - [ ] Do task 1
  - [ ] Do task 2
  ...
  - [ ] Do task 7

18.5 Backups

Backups that you have to work hard at don't get done.

I lost a bunch of data over 10 years ago due to not having a workingbackup solution. At the time I said I'm not going to lose anyimportant data ever again. So far so good :)

My backups get done religiously. What does this have to do withorg-mode? Not much really, other than I don't spend time doingbackups – they just happen – which saves me time for other moreinteresting things.

My backup philosophy is to make it possible to recover your data –not necessarily easy. It doesn't have to be easy/fast to do therecovery because I'll rarely have to recover data from the backups.Saving time for recovery doesn't make sense to me. I want the backupto be fast and painless since I do those all the time.

I set up an automated network backup over 10 years ago that is stillserving me well today. All of my systems gets daily backups to anetwork drive. These are collected monthly and written to an externalremovable USB disk.

Once a month my task for backups prompts me to move the currentcollection of montly backups to the USB drive for external storage.Backups take minimal effort currently and I'm really happy about that.

Since then git came into my life, so backups of git repositoriesthat are on multiple machines is much less critical than it used tobe. There is an automatic backup of everything pushed to the remoterepository.

18.6 Handling blocked tasks

Blocked tasks are tasks that have subtasks which are not in a donetodo state. Blocked tasks show up in a grayed font by default in theagenda.

To enable task blocking set the following variable:

(setq org-enforce-todo-dependencies t)

This setting prevents tasks from changing to DONE if any subtasksare still open. This works pretty well except for repeating tasks. Ifind I'm regularly adding TODO tasks under repeating tasks and notall of the subtasks need to be complete before the next repeat cycle.

You can override the setting temporarily by changing the task withC-u C-u C-u C-c C-t but I never remember that. I set a permanentproperty on the repeated tasks as follows:

* TODO New Repeating Task
  SCHEDULED: <2009-06-16 Tue +1w>
  :PROPERTIES:
  :NOBLOCKING: t
  :END:
  ...
** TODO Subtask

This prevents the New Repeating Task from being blocked if some ofthe items under it are not complete.

Occassionally I need to complete tasks in a given order. Org-mode hasa property ORDERED that enforces this for subtasks.

* TODO Some Task
  :PROPERTIES:
  :ORDERED: t
  :END:
** TODO Step 1
** TODO Step 2
** TODO Step 3

In this case you need to complete Step 1 before you can completeStep 2, etc. and org-mode prevents the state change to a done taskuntil the preceding tasks are complete.

18.7 Org Task structure and presentation

This section describes various org-mode settings I use to control howtasks are displayed while I work on my org mode files.

18.7.1 Controlling display of leading stars on headlines

Org-mode has the ability to show or hide the leading stars on taskheadlines. It's also possible to have headlines at odd levels only sothat the stars and heading task names line up in sublevels.

To make org show leading stars use

(setq org-hide-leading-stars nil)

I now use org-indent mode which hides leading stars.

18.7.2 org-indent mode

I recently started using org-indent mode. I like this setting a lot.It removes the indentation in the org-file but displays it as if itwas indented while you are working on the org file buffer.

org-indent mode displays as if org-odd-levels-only is true but it hasa really clean look that I prefer over my old setup.

I have org-indent mode on by default at startup with the followingsetting:

(setq org-startup-indented t)
18.7.3 Handling blank lines

Blank lines are evil :). They keep getting inserted in betweenheadlines and I don't want to see them in collapsed (contents) views.When I use TAB to fold (cycle) tasks I don't want to see any blanklines between headings.

The following setting hides blank lines between headings which keepsfolded view nice and compact.

(setq org-cycle-separator-lines 0)

I find extra blank lines in lists and headings a bit of a nuisance.To get a body after a list you need to include a blank line betweenthe list entry and the body – and indent the body appropriately.Most of my lists have no body detail so I like the look of collapsedlists with no blank lines better.

The following setting prevents creating blank lines before headingsbut allows list items to adapt to existing blank lines around the items:

(setq org-blank-before-new-entry (quote ((heading)
                                         (plain-list-item . auto))))
18.7.4 Adding new tasks quickly without disturbing the current task content

To create new headings in a project file it is really convenient touse C-RET, C-S-RET, M-RET, and M-S-RET. This inserts a new headlinepossibly with a TODO keyword. With the following setting

(setq org-insert-heading-respect-content nil)

org inserts the heading at point for the M- versions and respectscontent for the C- versions. The respect content setting istemporarily turned on for the C- versions which adds the new headingafter the content of the current item. This lets you hit C-S-RET inthe middle of an entry and the new heading is added after the body ofthe current entry but still allow you to split an entry in the middlewith M-S-RET.

18.7.5 Notes at the top

I enter notes for tasks with C-c C-z (or just z in the agenda).Changing tasks states also sometimes prompt for a note (e.g. moving toWAITING prompts for a note and I enter a reason for why it iswaiting). These notes are saved at the top of the task so unfoldingthe task shows the note first.

(setq org-reverse-note-order nil)
18.7.6 Searching and showing results

Org-mode's searching capabilities are really effective at finding datain your org files. C-c / / does a regular expression search on thecurrent file and shows matching results in a collapsed view of theorg-file.

I have org-mode show the hierarchy of tasks above the matched entriesand also the immediately following sibling task (but not all siblings)with the following settings:

(setq org-show-following-heading t)
(setq org-show-hierarchy-above t)
(setq org-show-siblings (quote ((default))))

This keeps the results of the search relatively compact and mitigatesaccidental errors by cutting too much data from your org file withC-k. Cutting folded data (including the …) can be reallydangerous since it cuts text (including following subtrees) which youcan't see. For this reason I always show the following headline whendisplaying search results.

18.7.7 Editing and Special key handling

Org-mode allows special handling of the C-a, C-e, and C-k keys whileediting headlines. I also use the setting that pastes (yanks)subtrees and adjusts the levels to match the task I am pasting to.See the docstring (C-h v org-yank-adjust-subtrees) for more detailson each variable and what it does.

I have org-special-ctrl-a/e set to enable easy access to thebeginning and end of headlines. I use M-m or C-a C-a to get to thebeginning of the line so the speed commands work and C-a to giveeasy access to the beginning of the heading text when I need that.

(setq org-special-ctrl-a/e t)
(setq org-special-ctrl-k t)
(setq org-yank-adjusted-subtrees t)

18.8 Attachments

Attachments are great for getting large amounts of data related toyour project out of your org-mode files. Before attachments camealong I was including huge blocks of SQL code in my org files to keeptrack of changes I made to project databases. This bloated my orgfile sizes badly.

Now I can create the data in a separate file and attach it to myproject task so it's easily located again in the future.

I set up org-mode to generate unique attachment IDs withorg-id-method as follows:

(setq org-id-method (quote uuidgen))

Say you want to attach a file x.sql to your current task. Createthe file data in /tmp/x.sql and save it.

Attach the file with C-c C-a a and enter the filename: x.sql.This generates a unique ID for the task and adds the file in theattachment directory.

* Attachments                                                        :ATTACH:
  :PROPERTIES:
  :Attachments: x.sql
  :ID:       f1d38e9a-ff70-4cc4-ab50-e8b58b2aaa7b
  :END:

The attached file is saved indata/f1/d38e9a-ff70-4cc4-ab50-e8b58b2aaa7b/. Where it goes exactlyisn't important for me – as long as it is saved and retrievableeasily. Org-mode copies the original file /tmp/x.sql into theappropriate attachment directory.

Tasks with attachments automatically get an ATTACH tag so you caneasily find tasks with attachments with a tag search.

To open the attachment for a task use C-c C-a o. This prompts forthe attachment to open and TAB completion works here.

The ID changes for every task header when a new ID is generated.

It's possible to use named directories for attachments but I haven'tneeded this functionality yet – it's there if you need it.

I store my org-mode attachments with my org files in a subdirectorydata. These are automatically added to my git repository alongwith any other org-mode changes I've made.

18.9 Deadlines and Agenda Visibility

Deadlines and due dates are a fact or life. By default I want to seedeadlines in the agenda 30 days before the due date.

The following setting accomplishes this:

(setq org-deadline-warning-days 30)

This gives me plenty of time to deal with the task so that it iscompleted on or before the due date.

I also use deadlines for repeating tasks. If the task repeats moreoften than once per month it would be always bugging me on the agendaview. For these types of tasks I set an explicit deadline warningdate as follows:

* TODO Pay Wages
  DEADLINE: <2009-07-01 Wed +1m -0d>

This example repeats monthly and shows up in the agenda on the day itis due (with no prior warning). You can set any number of lead daysyou want on DEADLINES using -Nd where N is the number of days inadvance the task should show up in the agenda. If no value isspecified the default org-deadline-warning-days is used.

18.10 Exporting Tables to CSV

I generate org-mode tables with details of task specifications andrecord structures for some of my projects. My clients like to usespreadsheets for this type of detail.

It's easy to share the details of the org-mode table by exporting inHTML but that isn't easy for anyone else to work with if they need toedit data.

To solve this problem I export my table as comma delimited values(CSV) and then send that to the client (or read it into a spreadsheetand email the resulting spreadsheet file).

Org-mode can export tables as TAB or comma delimited formats. I setthe default format to CSV with:

(setq org-table-export-default-format "orgtbl-to-csv")

Exporting to CSV format is the only one I use and this provides thedefault so I can just hit RETURN when prompted for the format.

To export the following table I put the cursor inside the table andhit M-x org-table-export which prompts for a filename and the formatwhich defaults to orgtbl-to-csv from the setting above.

OneTwoThree
112
365
fredkpemary
234.5432.12324.3

This creates the file with the following data

One,Two,Three
1,1,2
3,6,5
fred,kpe,mary
234.5,432.12,324.3

18.11 Minimize Emacs Frames

Links to emails, web pages, and other files are sprinkled all over myorg files. The following setting control how org-mode handles openingthe link.

(setq org-link-frame-setup (quote ((vm . vm-visit-folder)
                                   (gnus . org-gnus-no-new-news)
                                   (file . find-file))))

; Use the current window for C-c ' source editing
(setq org-src-window-setup 'current-window)

I like to keep links in the same window so that I don't end up with aton of frames in my window manager. I normally work in a full-screenwindow and having links open in the same window just works better forme.

If I need to work in multiple files I'll manually create the secondframe with C-x 5 2 or split the window with C-x 4 2 or C-X 4 3.When I visit files in Emacs I normally want to replace the currentwindow with the new content.

18.12 Logging stuff

Most of my logging is controlled by the global org-todo-keywords

My logging settings are set as follows:

(setq org-log-done (quote time))
(setq org-log-into-drawer t)
(setq org-log-state-notes-insert-after-drawers nil)

My org-todo-keywords are set as follows:

(setq org-todo-keywords
      (quote ((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d)")
              (sequence "WAITING(w@/!)" "HOLD(h@/!)" "|" "CANCELLED(c@/!)" "PHONE" "MEETING"))))

This adds a log entry whenever a task moves to any of the following states:

  • to or out of DONE status
  • to WAITING status (with a note) or out of WAITING status
  • to HOLD status
  • to CANCELLED status (with a note) or out of CANCELLED status

I keep clock times and states in the LOGBOOK drawer to keep my tasksuncluttered. If a task is WAITING then the reason for why it iswaiting is near the top of the LOGBOOK and unfolding the LOGBOOKdrawer provides that information. From the agenda simply hittingSPC on the task will reveal the LOGBOOK drawer.

18.13 Limiting time spent on tasks

Org-mode has this great new feature for signalling alarms when theestimated time for a task is reached. I use this to limit the amountof time I spend on a task during the day.

As an example, I've been working on this document for over two monthsnow. I want to get it finished but I can't just work on it solelyuntil it's done because then nothing else gets done. I want to do alittle bit every day but limit the total amount of time I spenddocumenting org-mode to an hour a day.

To this end I have a task

* NEXT Document my use of org-mode
  :LOGBOOK:...
  :PROPERTIES:
  :CLOCK_MODELINE_TOTAL: today
  :Effort:   1:00
  :END:

The task has an estimated effort of 1 hour and when I clock in thetask it gives me a total in the mode-line like this

--:**  org-mode.org   91% (2348,73) Git:master  (Org Fly yas Font)-----[0:35/1:00 (Document my use of org-mode)]-------

I've spent 35 minutes of my 1 hour so far today on this document andother help on IRC.

I set up an alarm so the Star Trek door chime goes off when thetotal estimated time is hit. (Yes I'm a Trekkie :) )

(setq org-clock-sound "/usr/local/lib/tngchime.wav")

When the one hour time limit is hit the alarm sound goes off and amessage states that I should be done working on this task. If Iswitch tasks and try to clock in this task again I get the sound eachand every time I clock in the task. This nags me to go work onsomething else :)

You can use similar setups for repeated tasks. By default the lastrepeat time is recorded as a property when a repeating task is markeddone. For repeating tasks the mode-line clock total counts since thelast repeat time by default. This lets you accumulate time overmultiple days and counts towards your estimated effort limit.

18.14 Habit Tracking

John Wiegley recently added support for Habit tracking to org-mode.

I have lots of habits (some bad) but I'd still like to improve andbuild new good habits. This is what habit tracking is for. It showsa graph on the agenda of how well you have been doing on developingyour habits.

I have habits like:

  • Hand wash the dishes
  • 30 minute brisk walk
  • Clean the house

etc. and most of these need a push to get done regularly. Logging ofthe done state needs to be enabled for habit tracking to work.

A habit is just like a regular task except it has a special PROPERTYvalue setting and a special SCHEDULED date entry like this:

* TODO Update Org Mode Doc
  SCHEDULED: <2009-11-21 Sat .+7d/30d>
  [2009-11-14 Sat 11:45]
  :PROPERTIES:
  :STYLE: habit
  :END:

This marks the task as a habit and separates it from the regular taskdisplay on the agenda. When you mark a habit done it shows up on yourdaily agenda the next time based on the first interval in theSCHEDULED entry (.+7d)

The special SCHEDULED entry states that I want to do this every daybut at least every 2 days. If I go 3 days without marking it DONE itshows up RED on the agenda indicating that I have been neglecting thishabit.

The world isn't going to end if you neglect your habits. You can hideand display habits quickly using the K key on the agenda.

These are my settings for habit tracking.

; Enable habit tracking (and a bunch of other modules)
(setq org-modules (quote (org-bbdb
                          org-bibtex
                          org-crypt
                          org-gnus
                          org-id
                          org-info
                          org-jsinfo
                          org-habit
                          org-inlinetask
                          org-irc
                          org-mew
                          org-mhe
                          org-protocol
                          org-rmail
                          org-vm
                          org-wl
                          org-w3m)))

; position the habit graph on the agenda to the right of the default
(setq org-habit-graph-column 50)

During the day I'll turn off the habit display in the agenda with K.This is a persistent setting and since I leave my Emacs running fordays at a time my habit display doesn't come back. To make sure Ilook at the habits daily I have the following settings to redisplaythe habits in the agenda each day. This turns the habit display onagain at 6AM each morning.

(run-at-time "06:00" 86400 '(lambda () (setq org-habit-show-habits t)))

18.15 Habits only log DONE state changes

I tend to keep habits under a level 1 task * Habits with a speciallogging property that only logs changes to the DONE state. Thisallows me to cancel a habit and not record a timestamp for it sincethat messes up the habit graph. Cancelling a habit just to get it offmy agenda because it's undoable (like get up before 6AM) should notmark the habit as done today. I only cancel habits that repeat everyday.

My habit tasks look as follows - and I tend to have one in every orgfile that can have habits defined

* Habits
  :PROPERTIES:
  :LOGGING:  DONE(!)
  :ARCHIVE:  %s_archive::* Habits
  :END:

18.16 Auto revert mode

I use git to synchronize my org-mode files between my laptop and myworkstation. This normally requires saving all the current changes,pushing to a bare repo, and fetching on the other system. After thatI need to revert all of my org-mode files to get the updatedinformation.

I used to use org-revert-all-org-buffers but have since discoveredglobal-auto-revert-mode. With this setting any files that change ondisk where there are no changes in the buffer automatically revert tothe on-disk version.

This is perfect for synchronizing my org-mode files between systems.

(global-auto-revert-mode t)

18.17 Handling Encryption

I used to keep my encrypted data like account passwords in a separateGPG encrypted file. Now I keep them in my org-mode files with aspecial tag instead. Encrypted data is kept in the org-mode file thatit is associated with.

org-crypt allows you to tag headings with a special tag crypt andorg-mode can keep data in these headings encrypted when saved to disk.You decrypt the heading temporarily when you need access to the dataand org-mode re-encrypts the heading as soon as you save the file.

I use the following setup for encryption:

(require 'org-crypt)
; Encrypt all entries before saving
(org-crypt-use-before-save-magic)
(setq org-tags-exclude-from-inheritance (quote ("crypt")))
; GPG key to use for encryption
(setq org-crypt-key "F0B66B40")

M-x org-decrypt-entry will prompt for the passphrase associated withyour encryption key and replace the encrypted data where the point iswith the plaintext details for your encrypted entry. As soon as yousave the file the data is re-encrypted for your key. Encrypting doesnot require prompting for the passphrase - that's only for looking atthe plain text version of the data.

I tend to have a single level 1 encrypted entry per file (like *Passwords). I prevent the crypt tag from using inheritance so thatI don't have encrypted data inside encrypted data. I found M-xorg-decrypt-entries prompting for the passphrase to decrypt data overand over again (once per entry to decrypt) too inconvenient.

I leave my entries encrypted unless I have to look up data - I decrypton demand and then save the file again to re-encrypt the data. Thiskeeps the data in plain text as short as possible.

18.17.1 Auto Save Files

Emacs temporarily saves your buffer in an autosave file while you areediting your org buffer and a sufficient number of changes haveaccumulated. If you have decrypted subtrees in your buffer these willbe written to disk in plain text which possibly leaks sensitive information.To combat this org-mode now asks if you want to disable the autosave functionality in this buffer.

Personally I really like the autosave feature. 99% of the time my encryptedentries are perfectly safe to write to the autosave file since they arestill encrypted. I tend to decrypt an entry, read the details for whatI need to look up and then immediately save the file again with C-x C-swhich re-encrypts the entry immediately. This pretty much guarantees that my autosave files never have decrypted data stored in them.

I disable the default org crypt auto-save setting as follows:

(setq org-crypt-disable-auto-save nil)

18.18 Speed Commands

There's an exciting feature called org-speed-commands in theorg-mode.

Speed commands allow access to frequently used commands when on thebeginning of a headline - similar to one-key agenda commands. Speedcommands are user configurable and org-mode provides a good set ofdefault commands.

I have the following speed commands set up in addition to thedefaults. I don't use priorities so I override the default settingsfor the 1, 2, and 3 keys. I also disable cycling with 'c' and add 'q'as a quick way to get back to the agenda and update the current view.

(setq org-use-speed-commands t)
(setq org-speed-commands-user (quote (("0" . ignore)
                                      ("1" . ignore)
                                      ("2" . ignore)
                                      ("3" . ignore)
                                      ("4" . ignore)
                                      ("5" . ignore)
                                      ("6" . ignore)
                                      ("7" . ignore)
                                      ("8" . ignore)
                                      ("9" . ignore)

                                      ("a" . ignore)
                                      ("d" . ignore)
                                      ("h" . bh/hide-other)
                                      ("i" progn
                                       (forward-char 1)
                                       (call-interactively 'org-insert-heading-respect-content))
                                      ("k" . org-kill-note-or-show-branches)
                                      ("l" . ignore)
                                      ("m" . ignore)
                                      ("q" . bh/show-org-agenda)
                                      ("r" . ignore)
                                      ("s" . org-save-all-org-buffers)
                                      ("w" . org-refile)
                                      ("x" . ignore)
                                      ("y" . ignore)
                                      ("z" . org-add-note)

                                      ("A" . ignore)
                                      ("B" . ignore)
                                      ("E" . ignore)
                                      ("F" . bh/restrict-to-file-or-follow)
                                      ("G" . ignore)
                                      ("H" . ignore)
                                      ("J" . org-clock-goto)
                                      ("K" . ignore)
                                      ("L" . ignore)
                                      ("M" . ignore)
                                      ("N" . bh/narrow-to-org-subtree)
                                      ("P" . bh/narrow-to-org-project)
                                      ("Q" . ignore)
                                      ("R" . ignore)
                                      ("S" . ignore)
                                      ("T" . bh/org-todo)
                                      ("U" . bh/narrow-up-one-org-level)
                                      ("V" . ignore)
                                      ("W" . bh/widen)
                                      ("X" . ignore)
                                      ("Y" . ignore)
                                      ("Z" . ignore))))

(defun bh/show-org-agenda ()
  (interactive)
  (if org-agenda-sticky
      (switch-to-buffer "*Org Agenda( )*")
    (switch-to-buffer "*Org Agenda*"))
  (delete-other-windows))

The variable org-speed-commands-default sets a lot of usefuldefaults for speed command keys. The default keys I use the most areI and O for clocking in and out and t to change todo state.

J jumps to the current or last clocking task.

c and C are disabled so they self insert. I use TAB and S-TABfor cycling - I don't need c and C as well. TAB workseverywhere while c and C only works on the headline and sometimesI accidentally cycle when I don't intend to.

18.19 Org Protocol

Org protocol is a great way to create capture notes in org-mode fromother applications. I use this to create tasks to review interestingweb pages I visit in Firefox.

I have a special capture template set up for org-protocol to use (setup with the w key).

My org-mode setup for org-protocol is really simple. It enablesorg-protocol and creates a single org-protocol capture template asdescribed in Capture Templates.

(require 'org-protocol)

The bulk of the setup is in the Firefox application so that C-c c on apage in Firefox will trigger the org-protocol capture template withdetails of the page I'm currently viewing in firefox.

I set up org-protocol in firefox as described in Keybindings for Firefox.

18.20 Require a final newline when saving files

The following setting was mainly for editing yasnippets where I want tobe able to expand a snippet but stay on the same line. I used thismainly for replacing short strings or initials with full names forpeople during meeting notes. I now use abbrev-mode- for this andno longer need this setting.

(setq require-final-newline nil)

When I save a file in Emacs I want a final newline - this fits betterwith the source code projects I work on. This is the setting I use now:

(setq require-final-newline t)

18.21 Insert inactive timestamps and exclude from export

I insert inactive timestamps when working on org-mode files.

For remember tasks the timestamp is in the remember template but for regularstructure editing I want the timestamp automatically added when I create the headline.

I have a function that is run by an org-mode hook to automatically insert the inactivetimestamp whenever a headline is created.

Adding the timestamp can be controlled by f9 T which toggles thecreation of the timestamp on and off for new headlines.

(defvar bh/insert-inactive-timestamp t)

(defun bh/toggle-insert-inactive-timestamp ()
  (interactive)
  (setq bh/insert-inactive-timestamp (not bh/insert-inactive-timestamp))
  (message "Heading timestamps are %s" (if bh/insert-inactive-timestamp "ON" "OFF")))

(defun bh/insert-inactive-timestamp ()
  (interactive)
  (org-insert-time-stamp nil t t nil nil nil))

(defun bh/insert-heading-inactive-timestamp ()
  (save-excursion
    (when bh/insert-inactive-timestamp
      (org-return)
      (org-cycle)
      (bh/insert-inactive-timestamp))))

(add-hook 'org-insert-heading-hook 'bh/insert-heading-inactive-timestamp 'append)

Everytime I create a heading with M-RET or M-S-RET the hook invokes the functionand it inserts an inactive timestamp like this

* <point here>
  [2009-11-22 Sun 18:45]

This keeps an automatic record of when tasks are created which I find very useful.

I also have a short cut key defined to invoke this function on demand so that I can insert the inactive timestamp anywhere on demand.

(global-set-key (kbd "<f9> t") 'bh/insert-inactive-timestamp)

To prevent the timestamps from being exported in documents I use the following setting

(setq org-export-with-timestamps nil)

18.23 Highlight clock when running overtime

The current clocking task is displayed on the modeline. If this hasan estimated time and we run over the limit I make this stand out onthe modeline by changing the background to red as follows

(custom-set-faces
  ;; custom-set-faces was added by Custom.
  ;; If you edit it by hand, you could mess it up, so be careful.
  ;; Your init file should contain only one such instance.
  ;; If there is more than one, they won't work right.
 '(org-mode-line-clock ((t (:foreground "red" :box (:line-width -1 :style released-button)))) t))

18.24 Meeting Notes

I take meeting notes with org-mode. I record meeting conversations inpoint-form using org-mode lists. If action items are decided on inthe meeting I'll denote them with a bullet and a TODO: or DONE: flag.

A meeting is a task and it is complete when the meeting is over. Thebody of the task records all of the interesting meeting details. IfTODO items are created in the meeting I make separate TODO tasks fromthose.

I use the function bh/prepare-meeting-notes to prepare the meetingnotes for emailing to the participants (in a fixed-width font like"Courier New"). As soon as the meeting is over the notes arebasically ready for distribution – there's not need to waste lots oftime rewriting the minutes before they go out. I haven't botheredwith fancy HTML output – the content is more important than thestyle.

* TODO Sample Meeting
  - Attendees
    - [ ] Joe
    - [X] Larry
    - [X] Mary
    - [X] Fred
  - Joe is on vacation this week
  - Status Updates
    + Larry
      - did this
      - and that
      - TODO: Needs to follow up on this
    + Mary
      - got a promotion for her recent efforts
    + Fred
      - completed all his tasks 2 days early
      - needs more work
      - DONE: everything
* TODO Sample Meeting
   - Attendees
     - [ ] Joe
     - [X] Larry
     - [X] Mary
     - [X] Fred
   - Joe is on vacation this week
   - Status Updates
     + Larry
       - did this
       - and that
>>>>>>>> TODO: Needs to follow up on this
     + Mary
       - got a promotion for her recent efforts
     + Fred
       - completed all his tasks 2 days early
       - needs more work
>>>>>>>> DONE: everything

Here is the formatting function. Just highlight the region for thenotes and it turns tabs into spaces, and highlights todo items. Theresulting notes are in the kill buffer ready to paste to anotherapplication.

(defun bh/prepare-meeting-notes ()
  "Prepare meeting notes for email
   Take selected region and convert tabs to spaces, mark TODOs with leading >>>, and copy to kill ring for pasting"
  (interactive)
  (let (prefix)
    (save-excursion
      (save-restriction
        (narrow-to-region (region-beginning) (region-end))
        (untabify (point-min) (point-max))
        (goto-char (point-min))
        (while (re-search-forward "^\\( *-\\\) \\(TODO\\|DONE\\): " (point-max) t)
          (replace-match (concat (make-string (length (match-string 1)) ?>) " " (match-string 2) ": ")))
        (goto-char (point-min))
        (kill-ring-save (point-min) (point-max))))))

18.25 Remove Highlights after changes

I'm finding I use org-occur C-c / / a lot when trying to finddetails in my org-files. The following setting keeps the highlightedresults of the search even after modifying the text. This allows meto edit the file without having to reissue the org-occur command tofind the other matches in my file. C-c C-c removes the highlights.

(setq org-remove-highlights-with-change nil)

Setting this variable to t will automatically remove the yellowhighlights as soon as the buffer is modified.

I've gone back to automatically removing the highlights with changewhich is the default setting. I've been using regular M-x occur alot more lately to find things in any Emacs buffer.

(setq org-remove-highlights-with-change t)

18.26 Getting up to date org-mode info documentation

I use the org-mode info documentation from the git repository so I setup emacs to find the info files from git before the regular (out ofdate) system versions.

(add-to-list 'Info-default-directory-list "~/git/org-mode/doc")

18.27 Prefer future dates or not?

By default org-mode prefers dates in the future. This means that iftoday's date is May 2 and you enter a date for April 30th (2 days ago)org-mode will jump to April 30th of next year. I used to find thisannoying when I wanted to look at what happened last Friday since I haveto specify the year. Now I've trained my fingers to go back relativelyin the agenda with b so this isn't really an issue for me anymore.

To make org-mode prefer the current year when entering dates setthe following variable

(setq org-read-date-prefer-future nil)

I now have this variable set to ='time= so times before now (with nodate specified) will default to tomorrow..

(setq org-read-date-prefer-future 'time)

18.28 Automatically change list bullets

I take point-form notes during meetings. Having the same list bulletfor every list level makes it hard to read the details when lists areindented more than 3 levels.

Org-mode has a way to automatically change the list bullets when youchange list levels.

Current List BulletNext indented list bullet
+-
*-
1.-
1)-
A)-
B)-
a)-
b)-
A.-
B.-
a.-
b.-
(setq org-list-demote-modify-bullet (quote (("+" . "-")
                                            ("*" . "-")
                                            ("1." . "-")
                                            ("1)" . "-")
                                            ("A)" . "-")
                                            ("B)" . "-")
                                            ("a)" . "-")
                                            ("b)" . "-")
                                            ("A." . "-")
                                            ("B." . "-")
                                            ("a." . "-")
                                            ("b." . "-"))))

18.29 Remove indentation on agenda tags view

I don't like the indented view for sublevels on a tags match in theagenda but I want to see all matching tasks (including sublevels) whenI do a agenda tag search (F12 m).

To make all of the matched headings for a tag show at the same levelin the agenda set the following variable:

(setq org-tags-match-list-sublevels t)

18.30 Fontify source blocks natively

I use babel for including source blocks in my documents with

#+begin_src LANG
,  ...
#+end_src

where LANG specifies the language to use (ditaa, dot, sh, emacs-lisp,etc) This displays the language contents fontified in both theorg-mode source buffer and the exported document.

See this Git Repository synchronization in this document for an example..

18.31 Agenda persistent filters

This is a great feature! Persistent agenda filters means if you limita search with / TAB SomeTag the agenda remembers this filter untilyou change it.

Enable persistent filters with the following variable

(setq org-agenda-persistent-filter t)

The current filter is displayed in the modeline as {+SomeTag} so youcan easily see what filter currently applies to your agenda view.

I use this with FILETAGS to limit the displayed results to a singleclient or context.

18.32 Add tags for flagged entries

Everyone so often something will come along that is really importantand you know you want to be able to find it back fast sometime in thefuture.

For these types of notes and tasks I add a special :FLAGGED: tag.This tag gets a special fast-key ? which matches the search key inthe agenda for flagged items. See Tags for the setup oforg-tag-alist for the FLAGGED entry.

Finding flagged entries is then simple - just F12 ? and you get them all.

18.33 Mail links open compose-mail

The following setting makes org-mode open mailto: linksusing compose-mail.

(setq org-link-mailto-program (quote (compose-mail "%a" "%s")))

18.34 Composing mail from org mode subtrees

It's possible to create mail from an org-mode subtree. I use C-cM-o to start an email message with the details filled in from thecurrent subtree. I use this for repeating reminder tasks where I needto send an email to someone else. The email contents are alreadycontained in the org-mode subtree and all I need to do is C-c M-oand any minor edits before sending it off.

18.35 Use smex for M-x ido-completion

I discovered smex for IDO-completion for M-x commands after reading apost of the org-mode mailing list. I actually use M-x a lot nowbecause IDO completion is so easy.

Here's the smex setup I use

(add-to-list 'load-path (expand-file-name "~/.emacs.d"))
(require 'smex)
(smex-initialize)

(global-set-key (kbd "M-x") 'smex)
(global-set-key (kbd "C-x x") 'smex)
(global-set-key (kbd "M-X") 'smex-major-mode-commands)

18.36 Use Emacs bookmarks for fast navigation

I've started using emacs bookmarks to save a location and return to it easily.Normally I want to get back to my currently clocking task and that's easy - just hit F11.When I'm working down a long checklist I find it convenient to set a bookmark on the nextitem to check, then go away and work on it, and return to the checkbox to mark it done.

I use Emacs bookmarks for this setup as follows:

;; Bookmark handling
;;
(global-set-key (kbd "<C-f6>") '(lambda () (interactive) (bookmark-set "SAVED")))
(global-set-key (kbd "<f6>") '(lambda () (interactive) (bookmark-jump "SAVED")))

When I want to save the current location I just hit C-f6 and then Ican return to it with f6 anytime. I overwrite the same bookmarkeach time I set a new position.

18.37 Using org-mime to email

I'm experimenting with sending mime mail from org. I've added C-c M=o key bindings in the org-mode-hook to generate mail from an org-mode subtree.

(require 'org-mime)

18.38 Remove multiple state change log details from the agenda

I skip multiple timestamps for the same entry in the agenda view with the following setting.

(setq org-agenda-skip-additional-timestamps-same-entry t)

This removes the clutter of extra state change log details when multiple timestampsexist in a single entry.

18.39 Drop old style references in tables

I drop the old A3/B4 style references from tables when editing with thefollowing setting.

(setq org-table-use-standard-references (quote from))

18.40 Use system settings for file-application selection

To get consistent applications for opening tasks I set the org-file-apps variable as follows:

(setq org-file-apps (quote ((auto-mode . emacs)
                            ("\\.mm\\'" . system)
                            ("\\.x?html?\\'" . system)
                            ("\\.pdf\\'" . system))))

This uses the entries defined in my system mailcap settings whenopening file extensions. This gives me consistent behaviour whenopening an link to some HTML file with C-c C-o or when previewing an export.

18.41 Use the current window for the agenda

; Overwrite the current window with the agenda
(setq org-agenda-window-setup 'current-window)

18.42 Delete IDs when cloning

(setq org-clone-delete-id t)

18.43 Cycling plain lists

Org mode can fold (cycle) plain lists.

(setq org-cycle-include-plain-lists t)

I find this setting useful when I have repeating tasks with lots of sublists withcheckboxes. I can fold the completed list entries and focus on what is remaining easily.

18.44 Showing source block syntax highlighting

It is possible to display org-mode source blocks fontified in theirnative mode. This allows colourization of keywords for C and shellscript source etc. If I edit the source I use =C-c '= (control-c singlequote) to bring up the source window which is then rendered withsyntax highlighting in the native mode. This setting also shows thesyntax highlighting when viewing in the org-mode buffer.

(setq org-src-fontify-natively t)

18.45 Inserting Structure Template Blocks

There is a shortcut key sequence in org-mode to insert structure templatesquickly into your org files.

I use example and source blocks often in my org files.

Key SequenceExpands to
< s TAB#+begin_src … #+end_src
< e TAB#+begin_example … #+end_example

I've added a block for saving email text which I copy from MS Outlook at work so I have contextassociated with my org-mode tasks.

The following lisp makes the blocks lowercase instead of the default upper case inorg-mode.

(setq org-structure-template-alist
      (quote (("s" "#+begin_src ?\n\n#+end_src" "<src lang=\"?\">\n\n</src>")
              ("e" "#+begin_example\n?\n#+end_example" "<example>\n?\n</example>")
              ("q" "#+begin_quote\n?\n#+end_quote" "<quote>\n?\n</quote>")
              ("v" "#+begin_verse\n?\n#+end_verse" "<verse>\n?\n</verse>")
              ("c" "#+begin_center\n?\n#+end_center" "<center>\n?\n</center>")
              ("l" "#+begin_latex\n?\n#+end_latex" "<literal style=\"latex\">\n?\n</literal>")
              ("L" "#+latex: " "<literal style=\"latex\">?</literal>")
              ("h" "#+begin_html\n?\n#+end_html" "<literal style=\"html\">\n?\n</literal>")
              ("H" "#+html: " "<literal style=\"html\">?</literal>")
              ("a" "#+begin_ascii\n?\n#+end_ascii")
              ("A" "#+ascii: ")
              ("i" "#+index: ?" "#+index: ?")
              ("I" "#+include %file ?" "<include file=%file markup=\"?\">"))))

18.46 NEXT is for tasks

NEXT keywords are for tasks and not projects. I've added afunction to the todo state change hook and clock in hook so that anyparent tasks marked NEXT automagically change from NEXT to TODOsince they are now projects and not tasks.

(defun bh/mark-next-parent-tasks-todo ()
  "Visit each parent task and change NEXT states to TODO"
  (let ((mystate (or (and (fboundp 'org-state)
                          state)
                     (nth 2 (org-heading-components)))))
    (when mystate
      (save-excursion
        (while (org-up-heading-safe)
          (when (member (nth 2 (org-heading-components)) (list "NEXT"))
            (org-todo "TODO")))))))

(add-hook 'org-after-todo-state-change-hook 'bh/mark-next-parent-tasks-todo 'append)
(add-hook 'org-clock-in-hook 'bh/mark-next-parent-tasks-todo 'append)

18.47 Startup in folded view

Startup in folded view.

(setq org-startup-folded t)

I used to use content view by default so I could review org subtreesbefore archiving but my archiving workflow has changed so I no longerneed this manual step.

18.48 Allow alphabetical list entries

The following setting adds alphabetical lists like

a. item one
b. item two
(setq org-alphabetical-lists t)

In order for filling to work correctly this needs to be set before theexporters are loaded.

18.49 Using orgstruct mode for mail

orgstruct++-mode is enabled in Gnus message buffers to aid increating structured email messages.

(add-hook 'message-mode-hook 'orgstruct++-mode 'append)
(add-hook 'message-mode-hook 'turn-on-auto-fill 'append)
(add-hook 'message-mode-hook 'bbdb-define-all-aliases 'append)
(add-hook 'message-mode-hook 'orgtbl-mode 'append)
(add-hook 'message-mode-hook 'turn-on-flyspell 'append)
(add-hook 'message-mode-hook
          '(lambda () (setq fill-column 72))
          'append)

18.50 Using flyspell mode to reduce spelling errors

flyspell-mode is enabled for almost everything to help preventcreating documents with spelling errors.

;; flyspell mode for spell checking everywhere
(add-hook 'org-mode-hook 'turn-on-flyspell 'append)

;; Disable keys in org-mode
;;    C-c [ 
;;    C-c ]
;;    C-c ;
;;    C-c C-x C-q  cancelling the clock (we never want this)
(add-hook 'org-mode-hook
          '(lambda ()
             ;; Undefine C-c [ and C-c ] since this breaks my
             ;; org-agenda files when directories are include It
             ;; expands the files in the directories individually
             (org-defkey org-mode-map "\C-c[" 'undefined)
             (org-defkey org-mode-map "\C-c]" 'undefined)
             (org-defkey org-mode-map "\C-c;" 'undefined)
             (org-defkey org-mode-map "\C-c\C-x\C-q" 'undefined))
          'append)

(add-hook 'org-mode-hook
          (lambda ()
            (local-set-key (kbd "C-c M-o") 'bh/mail-subtree))
          'append)

(defun bh/mail-subtree ()
  (interactive)
  (org-mark-subtree)
  (org-mime-subtree))

18.51 Preserving source block indentation

I do not preserve indentation for source blocks mainly because this doesn't looknice with indented org-files. The only reason I've found to preserve indentation iswhen TABs in files need to be preserved (e.g. Makefiles). I don't normally editthese files in org-mode so I leave this setting turned off.

I've changed the default block indentation so that it is not indentedfrom the text in the org file. This allows editing source blocks in place without requiring use of =C-c '= so that code lines up correctly.

(setq org-src-preserve-indentation nil)
(setq org-edit-src-content-indentation 0)

18.52 Prevent editing invisible text

The following setting prevents accidentally editing hidden text when the point is inside a folded region.This can happen if you are in the body of a heading and globally fold the org-file with S-TAB

I find invisible edits (and undo's) hard to deal with so now I can't edit invisible text. C-c C-r (org-reveal) will display where the point is if it is buried in invisible textto allow editing again.

(setq org-catch-invisible-edits 'error)

18.53 Use utf-8 as default coding system

I use utf-8 as the default coding system for all of my org files.

(setq org-export-coding-system 'utf-8)
(prefer-coding-system 'utf-8)
(set-charset-priority 'unicode)
(setq default-process-coding-system '(utf-8-unix . utf-8-unix))

18.54 Keep clock durations in hours

The default for clock durations has changed to include days which is24 hours. At work I like to think of a day as 6 hours of work (therest of the time is lost in meetings and other overhead on average) sodisplaying clock durations in days doesn't make sense to me.

The following setting displays clock durations (from C-c C-x C-d inhours and minutes.

(setq org-time-clocksum-format
      '(:hours "%d" :require-hours t :minutes ":%02d" :require-minutes t))

18.55 Create unique IDs for tasks when linking

The following setting creates a unique task ID for the heading in thePROPERTY drawer when I use C-c l. This allows me to move the taskaround arbitrarily in my org files and the link to it still works.

(setq org-id-link-to-org-use-id 'create-if-interactive-and-no-custom-id)

19 Things I Don't Use (Anymore)

This is a partial list of things I know about but do not use.org-mode is huge with tons of features. There are features outthere that I don't know about yet or haven't explored so this list isnot going to be complete.

19.1 Archive Sibling

This was a cute idea but I find archiving entire complete subtreesbetter. I don't mind having a bunch of tasks marked DONE (but notarchived)

19.2 Strike-through emphasis

Strike-through emphasis is just unreadable and tends to only show upwhen pasting data from other files into org-mode. This just removesthe strike-through completely which I find a lot nicer.

(setq org-emphasis-alist (quote (("*" bold "<b>" "</b>")
                                 ("/" italic "<i>" "</i>")
                                 ("_" underline "<span style=\"text-decoration:underline;\">" "</span>")
                                 ("=" org-code "<code>" "</code>" verbatim)
                                 ("~" org-verbatim "<code>" "</code>" verbatim))))

19.3 Subscripts and Superscripts

I don't currently write documents that need subscripts and superscriptsupport. I disable handling of _ and ^ for subscript andsuperscripts with

(setq org-use-sub-superscripts nil)

19.4 Yasnippet

Yasnippet is cool but I don't use this anymore. I've replacedyasnippet with a combination of abbrev-mode and skeletons whichare available by default in Emacs.

The following description applies to yasnippet version 0.5.10. The setuprequirements may have changed with newer versions.

You type the snippet name and TAB and yasnippet expands the namewith the contents of the snippet text - substituting snippet variablesas appropriate.

Yasnippet comes with lots of snippets for programming languages. Iused a few babel related snippets with org-mode.

I downloaded and installed the unbundled version of yasnippet so thatI can edit the predefined snippets. I unpacked the yasnippet softwarein my ~/.emacs.d/plugins directory, renamed yasnippet0.5.10 toyasnippet and added the following setup in my .emacs:

(add-to-list 'load-path (expand-file-name "~/.emacs.d/plugins"))

(require 'yasnippet)
(yas/initialize)
(yas/load-directory "~/.emacs.d/plugins/yasnippet/snippets")

;; Make TAB the yas trigger key in the org-mode-hook and enable flyspell mode and autofill
(add-hook 'org-mode-hook
          (lambda ()
            ;; yasnippet
            (make-variable-buffer-local 'yas/trigger-key)
            (org-set-local 'yas/trigger-key [tab])
            (define-key yas/keymap [tab] 'yas/next-field-group)
            ;; flyspell mode for spell checking everywhere
            (flyspell-mode 1)
            ;; auto-fill mode on
            (auto-fill-mode 1)))

I used snippets for the following:

  • begin for generic #+begin_ blocks
  • dot for graphviz
  • uml for PlantUML graphics
  • sh for bash shell scripts
  • elisp for emacs lisp code
  • initials of a person converts to their full nameI used this while taking meeting notes

Here is the definition for the begin snippet:

org-mode Yasnippet: ~/.emacs.d/plugins/yasnippet/snippets/text-mode/org-mode/begin

#name : #+begin_...#+end_
# --     
#+begin_$1 $2
$0
#+end_$1

I used this to create #+begin_* blocks like

  • #+begin_example
  • #+begin_src
  • etc.

Simply type begin and then TAB it replaces the begin text withthe snippet contents. Then type src TAB emacs-lisp TAB and yoursnippet block is done. I've shortened this specific sequence to justelisp TAB since I use it fairly often.

Hit C-c SingeQuote(') and insert whatever emacs-lisp code you need.While in this block you're in a mode that knows how to format andcolourize emacs lisp code as you enter it which is really nice. C-cSingleQuote(') exits back to org-mode. This recognizes any emacsediting mode so all you have to do is enter the appropriate mode namefor the block.

dot

#dot : #+begin_src dot ... #+end_src
# --
#+begin_src dot :file $1 :cmdline -Kdot -Tpng
$0
#+end_src

uml

#uml : #+begin_src plantuml ... #+end_src
# --
#+begin_src plantuml :file $1
$0
#+end_src

sh

#sh: #+begin_src sh ... #+end_src
# --
#+begin_src sh :results output
$0
#+end_src

elisp

#elisp : #+begin_src emacs-lisp ...#+end_src emacs-lisp
# --
#+begin_src emacs-lisp
$0
#+end_src

This is a great time saver.

19.5 Show headings at odd levels only or odd-even levels

This has been replaced by org-indent-mode

I've converted my files between odd-levels-only and odd-even using thefunctions org-convert-to-odd-levels andorg-convert-to-oddeven-levels functions a number of times. I endedup going back to odd-even levels to reduce the amount of leadingwhitespace on tasks. I didn't find that lining up the headlines andtasks in odd-levels-only to be all that helpful.

(setq org-odd-levels-only nil)

19.6 Propagate STARTED to parent tasks

I used to have a STARTED and NEXT task state. These werebasically the same except STARTED indicated that I've clocked sometime on the task. Since then I've just moved to using NEXT forthis.

The following code used to propagate the STARTED task up the projecttree but I don't use this anymore.

When a task is marked STARTED (either manually or by clocking it in) the STARTEDstate propagates up the tree to any parent tasks of this task that are TODO or NEXT.As soon as I work on the first NEXT task in a tree the project is also marked STARTED.This helps me keep track of things that are in progress.

Here's the setup I use to propagate STARTED to parent tasks:

;; Mark parent tasks as started
(defvar bh/mark-parent-tasks-started nil)

(defun bh/mark-parent-tasks-started ()
  "Visit each parent task and change TODO states to STARTED"
  (unless bh/mark-parent-tasks-started
    (when (equal org-state "STARTED")
      (let ((bh/mark-parent-tasks-started t))
        (save-excursion
          (while (org-up-heading-safe)
            (when (member (nth 2 (org-heading-components)) (list "TODO" "NEXT"))
              (org-todo "STARTED"))))))))

(add-hook 'org-after-todo-state-change-hook 'bh/mark-parent-tasks-started 'append)

19.7 Automatically clocking tasks

I used to spend time on an open source project called BZFlag. Duringwork for releases I want to clock the time I spend testing the newBZFlag client. I have a key binding in my window manager that runs ascript which starts the clock on my testing task, runs the BZFlagclient, and on exit resumes the clock on the previous clocking task.

The testing task has an ID property ofdcf55180-2a18-460e-8abb-a9f02f0893be and the following elisp codestarts the clock on this task.

(defun bh/clock-in-bzflagt-task ()
  (interactive)
  (bh/clock-in-task-by-id "dcf55180-2a18-460e-8abb-a9f02f0893be"))

This is invoked by a bash shell script as follows:

#!/bin/sh
emacsclient -e '(bh/clock-in-bzflagt-task)'
~/git/bzflag/trunk/bzflag/src/bzflag/bzflag -directory ~/git/bzflag/trunk/bzflag/data $*
emacsclient -e '(bh/resume-clock)'

The resume clock function just returns the clock to the previous clocking task

(defun bh/resume-clock ()
  (interactive)
  (if (marker-buffer org-clock-interrupted-task)
      (org-with-point-at org-clock-interrupted-task
        (org-clock-in))
    (org-clock-out)))

If no task was clocking bh/resume-clock just stops the clock.

19.8 q buries the agenda view buffer

With Sticky Agendas burying the buffer is the default behaviour forthe q key so this is not needed anymore.

I change the q key in the agenda so instead of killing the agenda bufferit merely buries it to the end of the buffer list. This allows me to pull it back up quickly with the q speed key or f9 f9 and regeneratethe results with g.

(add-hook 'org-agenda-mode-hook
          (lambda ()
            (define-key org-agenda-mode-map "q" 'bury-buffer))
          'append)

19.9 Task Priorities

I use the agenda to figure out what to do work on next. I don't usepriorities at all normally but at work I occasionally get prioritiesfrom my manager. In this case I mark my tasks with the prioritiesfrom the external source just to track the values and force the agendato display tasks in the priority order.

I use priorities A-E where tasks without a specific priority are lowest priority E.

(setq org-enable-priority-commands t)
(setq org-default-priority ?E)
(setq org-lowest-priority ?E)

20 Using Git for Automatic History, Backups, and Synchronization

Editing folded regions of your org-mode file can be hazardous to yourdata. My method for dealing with this is to put my org files in aGit source repository.

My setup saves all of my org-files every hour and creates a commitwith my changes automatically. This lets me go back in time and viewthe state of my org files for any given hour over the lifetime of thedocument. I've used this once or twice to recover data I accidentallyremoved while editing folded regions.

20.1 Automatic Hourly Commits

My Emacs setup saves all org buffers at 1 minute before the hour usingthe following code in my .emacs

(run-at-time "00:59" 3600 'org-save-all-org-buffers)

A cron job runs at the top of the hour to commit any changes justsaved by the call to org-save-all-org-buffers above. I use a scriptto create the commits so that I can run it on demand to easily commitall modified work when moving from one machine to another.

crontab details:

0 * * * * ~/bin/org-git-sync.sh >/dev/null
20.1.1 ~/bin/org-git-sync.sh

Here is the shell script I use to create a git commit for each of myorg-repositories. This loops through multiple repositories andcommits any modified files. I have the following org-moderepositories:

This script does not create empty commits - git only creates a commitif something was modified.

#!/bin/sh
# Add org file changes to the repository
REPOS="org doc.norang.ca www.norang.ca"

for REPO in $REPOS
do
    echo "Repository: $REPO"
    cd ~/git/$REPO
    # Remove deleted files
    git ls-files --deleted -z | xargs -0 git rm >/dev/null 2>&1
    # Add new files
    git add . >/dev/null 2>&1
    git commit -m "$(date)"
done

I use the following .gitignore file in my org-mode gitrepositories to keep export generated files out of my gitrepositories. If I include a graphic from some other source thanditaa or graphviz then I'll add it to the repository manually. Bydefault all PNG graphic files are ignored (since I assume they areproduced by ditaa during export)

core
core.*
*.html
*~
.#*
\#*\#
*.txt
*.tex
*.aux
*.dvi
*.log
*.out
*.ics
*.pdf
*.xml
*.org-source
*.png
*.toc

20.2 Git - Edit files with confidence

I use git in all of my directories where editing a file should betracked.

This means I can edit files with confidence. I'm free to change stuffand break things because it won't matter. It's easy to go back to aprevious working version or to see exactly what changed since the lastcommit. This is great when editing configuration files (such asapache webserver, bind9 DNS configurations, etc.)

I find this extremely useful where your edits might break things andhaving git tracking the changes means if you break it you can justgo back to the previous working version easily. This is also true forpackage upgrades for software where the upgrade modifies theconfiguration files.

I have every version of my edits in a local git repository.

20.3 Git Repository synchronization

I acquired a Eee PC 1000 HE which now serves as my main road-warriorlaptop replacing my 6 year old Toshiba Tecra S1.

I have a server on my LAN that hosts bare git repositories for all ofmy projects. The problem I was facing is I have to leave in 5 minutesand want to make sure I have up-to-date copies of everything I work onwhen I take it on the road (without Internet access).

To solve this I use a server with bare git repositories on it. Thisincludes my org-mode repositories as well as any other gitrepositories I'm interested in.

Just before I leave I run the git-sync script on my workstation toupdate the bare git repositories and then I run it again on my Eee PCto update all my local repositories on the laptop. For anyrepositories that give errors due to non-fast-forward merges Imanually merge as required and rerun git-sync until it reports noerrors. This normally takes a minute or two to do. Then I grab myEee PC and leave. When I'm on the road I have full up-to-date historyof all my git repositories.

The git-sync script replaces my previous scripts with an all-in-onetool that basically does this:

  • for each repository on the current system
    • fetch objects from the remote
    • for each branch that tracks a remote branch
      • Check if the ref can be moved
        • fast-forwards if behind the remote repository and is fast-forwardable
        • Does nothing if ref is up to date
        • Pushes ref to remote repository if ref is ahead of remote repository and fast-forwardable
        • Fails if ref and remote have diverged

This automatically advances changes on my 35+ git repositories withminimal manual intervention. The only time I need to manually dosomething in a repository is when I make changes on my Eee PC and myworkstation at the same time - so that a merge is required.

Here is the git-sync script

#!/bin/sh
#

# Local bare repository name
syncrepo=norang
reporoot=~/git

# Display repository name only once
log_repo() {
  [ "x$lastrepo" == "x$repo" ] || {
    printf "\nREPO: ${repo}\n"
    lastrepo="$repo"
  }
}

# Log a message for a repository
log_msg() {
  log_repo
  printf "  $1\n"
}

# fast-forward reference $1 to $syncrepo/$1
fast_forward_ref() {
  log_msg "fast-forwarding ref $1"
  current_ref=$(cat .git/HEAD)
  if [ "x$current_ref" = "xref: refs/heads/$1" ]
  then
    # Check for dirty index
    files=$(git diff-index --name-only HEAD --)
    git merge refs/remotes/$syncrepo/$1
  else
    git branch -f $1 refs/remotes/$syncrepo/$1
  fi
}

# Push reference $1 to $syncrepo
push_ref() {
  log_msg "Pushing ref $1"
  if ! git push --tags $syncrepo $1
  then
    exit 1
  fi
}

# Check if a ref can be moved
#   - fast-forwards if behind the sync repo and is fast-forwardable
#   - Does nothing if ref is up to date
#   - Pushes ref to $syncrepo if ref is ahead of syncrepo and fastforwardable
#   - Fails if ref and $syncrop/ref have diverged
check_ref() {
  revlist1=$(git rev-list refs/remotes/$syncrepo/$1..$1)
  revlist2=$(git rev-list $1..refs/remotes/$syncrepo/$1)
  if [ "x$revlist1" = "x" -a "x$revlist2" = "x" ]
  then
    # Ref $1 is up to date.
    :
  elif [ "x$revlist1" = "x" ]
  then
    # Ref $1 is behind $syncrepo/$1 and can be fast-forwarded.
    fast_forward_ref $1 || exit 1
  elif [ "x$revlist2" = "x" ]
  then
    # Ref $1 is ahead of $syncrepo/$1 and can be pushed.
    push_ref $1 || exit 1
  else
    log_msg "Ref $1 and $syncrepo/$1 have diverged."
    exit 1
  fi
}

# Check all local refs with matching refs in the $syncrepo
check_refs () {
  git for-each-ref refs/heads/* | while read sha1 commit ref
  do
    ref=${ref/refs\/heads\//}
    git for-each-ref refs/remotes/$syncrepo/$ref | while read sha2 commit ref2
    do
      if [ "x$sha2" != "x" -a "x$sha2" != "x" ]
      then
        check_ref $ref || exit 1
      fi
    done
  done
}

# For all repositories under $reporoot
#   Check all refs matching $syncrepo and fast-forward, or push as necessary
#   to synchronize the ref with $syncrepo
#   Bail out if ref is not fastforwardable so user can fix and rerun
time {
  retval=0
  if find $reporoot -type d -name '*.git' | { 
      while read repo
      do
        repo=${repo/\/.git/}
        cd ${repo}
        upd=$(git remote update $syncrepo 2>&1 || retval=1)
        [ "x$upd" = "xFetching $syncrepo" ] || {
          log_repo
          printf "$upd\n"
        }
        check_refs || retval=1
      done
      exit $retval
    }
  then
    printf "\nAll done.\n"
  else
    printf "\nFix and redo.\n"
  fi
}

exit $retval

Author: Bernt Hansen (IRC: BerntH on freenode)

Created: 2015-07-23 Thu 22:36

Emacs 23.2.1 (Org mode 8.2.10)

Validate XHTML 1.0

### 回答1: eslint-plugin-organize-imports是一个用于ESLint的插件,它可以帮助我们自动整理和优化我们的导入语句。 在编写JavaScript代码时,我们通常需要引入其他模块或库的功能。在大型项目中,可能会有许多导入语句,而这些语句的顺序和组织方式可能会导致代码的可读性和维护性下降。 eslint-plugin-organize-imports提供了一种自动化的方式来整理和优化导入语句。通过在代码中添加特定的注释指令,我们可以告诉该插件如何组织我们的导入语句。例如,我们可以使用注释指令`/* organize-imports */`来启用导入语句的整理功能。 一旦启用了eslint-plugin-organize-imports,它将扫描我们的代码并分析我们的导入语句。然后,它会根据一些配置规则和选项,对导入语句进行排序、分组和优化。 这个插件可以处理各种类型的导入语句,包括默认导入、命名导入和命名空间导入。它可以将相似的导入语句合并到同一个组中,删除不需要的导入语句,并根据规则对它们进行排序。这样,我们就可以更清楚地看到我们的模块依赖,并提高代码的可读性。 总结起来,eslint-plugin-organize-imports是一个帮助我们自动整理和优化导入语句的ESLint插件。它可以根据我们的配置规则对导入语句进行排序、分组和优化,从而提高代码的可读性和维护性。 ### 回答2: eslint-plugin-organize-imports是一个ESLint插件,用于自动整理和规范化import语句。它可以帮助开发者在代码中保持一致的import风格和结构,提高代码的可读性和维护性。 该插件提供了一系列规则,用于检测和修复import语句的错误和风格问题。它可以自动排序和格式化import语句,使其按照一定的顺序和规范排列。例如,可以按照字母顺序对import语句进行排序,将默认导出放在非默认导出之前,将外部模块的导入语句放在内部模块之前等等。通过使用该插件,可以确保在不同的文件和团队成员之间保持一致的import风格,减少代码冲突和维护难度。 除了排序和格式化import语句,eslint-plugin-organize-imports还提供了其他的规则,如删除未使用的导入、合并重复的导入、使用正确的导入别名等。这些规则可以帮助开发者减少无用的导入语句和重复的代码,提高代码质量和执行效率。 总之,eslint-plugin-organize-imports是一个功能强大的ESLint插件,可以帮助开发者自动整理和规范化import语句。它可以提高代码的可读性和维护性,减少冲突和错误的发生,是一个非常实用的工具。 ### 回答3: eslint-plugin-organize-imports 是一个 ESLint 插件,用于帮助开发者组织和管理 JavaScript 代码文件的 import 语句。 在 JavaScript 开发中,我们经常需要引入其他模块或库,以便使用它们提供的功能。代码中的 import 语句就是用来实现这一功能的。 eslint-plugin-organize-imports 通过对 import 语句的静态分析,提供了一些自动化的代码组织和规范化功能,以保持代码的整洁性和一致性。 该插件可以帮助我们实现以下功能: 1. 自动按照字母顺序对 import 语句进行排序。这样做可以提高代码可读性,减少重复的 import 语句,避免遗漏某些模块。 2. 自动移除未使用的 import 语句。当项目逐渐变大时,可能会出现一些无用的 import 语句,通过该插件可以自动删除这些未使用的 import 语句,提高代码的执行效率。 3. 自动分组 import 语句。当引入的模块来自不同的来源时,可以将它们按照不同的分组进行组织,以提高代码的可读性和维护性。 4. 自定义配置选项。该插件提供了丰富的配置选项,可以根据项目的需求,对不同的组织规则进行灵活配置。 借助 eslint-plugin-organize-imports,我们可以轻松地优化 JavaScript 代码的 import 语句,使其更加整齐规范,提高代码的可读性和可维护性。这对于大型项目和团队合作开发尤其重要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值