Categories: geek » emacs » planner

RSS - Atom - Subscribe via email

Developing a better sense of time

| emacs, planner, productivity

One of the things I want to do is develop a good sense of how long it
takes me to do something. Better time estimates lead to better
scheduling, better sense of what I can commit to, and ultimately less
stress and more happiness. =)

Fortunately, Planner makes it easy for me to do really detailed
time-tracking. When I mark a task as in progress, the clock starts
ticking. When I postpone or close a task, the system clocks out

I find that my attention occasionally strays. Sometime ago, I wrote a
function to help me keep track of what I’m supposed to be doing.
Today, I’ve decided to try estimating task completion times for more
of the tasks on my list. I modified my old function to tell me how
much time has elapsed since I started the task. This doesn’t take into
account previous clock-in/clock-outs, but it will do for now.

We’ll see how well it works. =)

;; I've bound sacha/planner-what-am-i-supposed-to-be-doing to F9 F11. I
;; start out by clocking into the task (use planner-timeclock.el and
;; C-c TAB to mark a task as in progress). Then, when I find myself
;; getting distracted, I hit F9 F9 to see my current task in the
;; minibuffer. C-u F9 F9 jumps back to the task so that I can either
;; mark it as postponed. M-x planner-task-pending (bound to C-c C-p in
;; my local config) and M-x planner-task-done (C-c C-x) both clock out
;; of the task. If I want to jump back to the previous window
;; configuration from that planner page, I can just hit F9 F9 again.

(defvar sacha/window-register "w"
  "Register for jumping back and forth between planner and wherever I am.")
(defvar sacha/planner-current-task nil
  "Current task info.")
(defadvice planner-task-in-progress (after sacha activate)
  "Keep track of the task info."
  (setq sacha/planner-current-task (planner-current-task-info)))

(defun sacha/planner-what-am-i-supposed-to-be-doing (&optional prefix)
  "Make it easy to keep track of what I'm supposed to be working on.
If PREFIX is non-nil, jump to the current task, else display it
in a message. If called from the plan page, jump back to whatever
I was looking at."
  (interactive "P")
  (if planner-timeclock-current-task
      (if (string= (planner-task-page sacha/planner-current-task)
          (jump-to-register sacha/window-register)
        (if (null prefix)
            (message "%s %s"
                     ;; Minutes so far
                     (timeclock-seconds-to-string (timeclock-last-period))
          (frame-configuration-to-register sacha/window-register)
          (planner-find-file (planner-task-page sacha/planner-current-task))
          (planner-find-task sacha/planner-current-task)))
    (if prefix
      (message "No current task. HEY!"))))

Random Emacs symbol: cal-tex-mouse-filofax-week – Command: Two page Filofax calendar for week indicated by cursor. (Hey, I didn’t know we could print Filofax calendars from Emacs cal…)

View or add comments

Emacs: Show only people whom I haven’t pinged since…

| bbdb, connecting, emacs, planner

One of the things I want in a contact management system is a quick way
to find out who I haven’t pinged in a while. The following code
filters currently-displayed contacts to show who I might want to get
back in touch with. Call it from a *BBDB* window and specify the date
(could be 2006.01.01 for annual, -7 for the last seven days, etc.).
This works incredibly well with the following hacks:

I should write a small book about how to build a contact management
system with Emacs. ;) It’s insanely powerful, you know.

(require 'planner)
(require 'bbdb)
(defun sacha/bbdb-show-only-no-contact-since (date)
  "Show only people who haven't been pinged since DATE or at all."
  (interactive (list (planner-read-date)))
  (let ((records bbdb-records)
    (while records
      ;; Find the latest date mentioned in the entry
      (setq notes (or (bbdb-record-notes (caar records)) ""))
      (setq last-match nil omit nil)
      (while (string-match
              (or last-match 0))
        (unless (string> date (match-string 0 notes))
          (setq omit t)
          (setq last-match (length notes)))
        (setq last-match (match-end 0)))
      (unless (and last-match omit)
        (add-to-list 'new-records (caar records) t))
      (setq records (cdr records)))
    (bbdb-display-records new-records)))

One of the other things I’d like to smooth over is keeping track of
who owes whom e-mail… <laugh>

View or add comments

More Emacs coolness: List of contacts

| bbdb, emacs, planner

This bit of Emacs Lisp code produces a Planner-ready list of the contacts displayed in the BBDB window.

(defun sacha/planner-bbdb-annotation-from-bbdb (&optional record)
  "If called from a bbdb buffer, return an annotation.
Suitable for use in `planner-annotation-functions'."
  (when (or record (eq major-mode 'bbdb-mode))
    (setq record (if record (car record) (bbdb-current-record)))
    (or (bbdb-record-getprop record 'plan)
        ;; From a BBDB entry with a plan page; use that. Yay!
         (concat "bbdb://"
                    " " "." (bbdb-record-name record)))
         (bbdb-record-name record)))))
(defalias 'planner-bbdb-annotation-from-bbdb 'sacha/planner-bbdb-annotation-from-bbdb)

(defun sacha/yank-planner-bbdb-list ()
  "Copy the list of people displayed in the buffer."
   (mapconcat 'sacha/planner-bbdb-annotation-from-bbdb
              ", "))
        (sacha/planner-bbdb-annotation-from-bbdb rec))

It allows me to say, for example, that I met 23 people yesterday:
Bruce, Daniel Charles, Shane D’Costa, Emily, Greg A. Fitz, Clara Fong, Jay Goldman, Harvey, Kai Fai Ho, Iris, KC, Charles McCulloch, Jamie McQuay, Joshua Meles, Naomi, Helen Overland, W- Penney, Simon Rowland, San, Colin Smillie, Solomon, Le Quan Truong, Perry Wong

View or add comments

Sharing the link love

Posted: - Modified: | emacs, planner

People who visit my blog instead of reading
it on an RSS aggregator get a couple of nifty extras, including my
task list and a list of e-mail messages sent. It’s a personal
experiment I’ve been running for a while now with unexpectedly
positive results. People have helped me with things on my task list,
and my sent mail list resulted in reminders from two people who
noticed that they hadn’t received some messages listed as sent—the
messages had gotten stuck in my mail queue.

These things are easy for me to track because I use
Planner, an
insanely customizable personal information manager for the Emacs text
editor. Today I realized that my list of sent e-mail is a good way to
share the link love and direct you to the websites of the people I
talk to, so I added a bit of code to my config.

On my computer, “E-mail to” is hyperlinked to the actual e-mail, and
names are hyperlinked to their contact records. On the Web, “E-mail
to” is not a hyperlink, and names are hyperlinked to people’s blogs or

It’s a little tweak, but who knows what it’ll lead to? If you end up
discovering an interesting person through this, way cool. And hey, it
gives people whom I write extra Google juice… =)

I might do the same for the tasks, although that requires a teensy bit
more coding. Hmm.

I’m thinking of listing the subject header again. It’ll give people
more of an idea of what other people talk to me about.
Dan Howard was concerned about privacy. I
occasionally delete subjects if I think they’re sensitive. Do you
think I might get away with a mostly opt-out system?

Anyway, check out my actual blog every now and then! =)

Emacs Lisp code:

(defun sacha/planner-gnus-track-sent ()
  "Add this to `message-sent-hook' to keep track of messages sent on your daily page.
Result: Adds it to * E-mail sent."
  ;; Grab the header
  (let ((mail-link
         (concat "gnus://" gnus-newsgroup-name "/"
         (split-string (planner-gnus-get-address "To") ", *"))
    (setq text
           (planner-make-link mail-link "E-mail to")
           " "
            (lambda (address)
              (let (rec)
                ;; Look up record
                (setq addr (mail-extract-address-components address))
                (setq rec (apply 'bbdb-search-simple addr))
                (if rec
                     (concat "bbdb://"
                              " " "."
                     (bbdb-record-name rec))
                  (or (car address) (cadr address)))))
          ;;            ": "
          ;;           (message-fetch-field "Subject"))))
        (planner-seek-to-first "E-mail sent")
        (insert " 1. " text "\n"))))

(add-hook 'message-mode-hook
          (lambda ()
            (add-hook 'message-sent-hook 'sacha/planner-gnus-track-sent)))
View or add comments

TODO lists in Emacs!

| emacs, goodkarma, planner

E-mail addresses removed. But it’s the real Stephen J. Turnbull… =)

From: "Stephen J. Turnbull"
Subject: Re: TODO extension for source code and Emacs
To: tlug (Tokyo Linux Users Group)
Date: Wed Jan 18 14:17:40 2006 +0800

>>>>> "Ian" == Ian Wells (ijw) writes:

    Ian> Actually I was hoping for something that understood
    Ian> todo-lists (i.e. allowed you to tick stuff off and add
    Ian> unrelated items) but I think I may be fantasising.

(a) [the helpful answer] Find Sacha Chua (TLUG denizen), this is up
her alley.

Will write a good reply on the plane.

E-Mail from Stephen J. Turnbull

View or add comments

Blast from the past

Posted: - Modified: | emacs, planner

If you want to know what I’ve been up to all this while, check out
2004, 2003, 2002,
2001. <laugh> planner-notes-index.el does all the magic.

View or add comments

Really funky Planner sorting

| emacs, planner

The following code sorts completed tasks in reverse-chronological
order and incomplete tasks in chronological order. This makes it
easier to see the next action (top of list) and the last action (first
completed task).

(defun sacha/planner-sort-tasks-by-date ()
  "Sort tasks by date, status and priority."
  (skip-chars-forward "#ABC")
  (let ((ch (char-before))
    (skip-chars-forward "0123456789 ")
    (setq status (char-after))
    (goto-char (line-end-position))
    (skip-chars-backward "]) ")
    (format "%1c%1c%10s"
             ((= status ?o) ?1)
             ((= status ?X) ?3)
             ((= status ?C) ?4)
             (t ?2))
            (let ((date (or (planner-task-date (planner-current-task-info))
              (if (or (= status ?X)
                      (= status ?C))
                  (sacha/planner-invert-date date)

(defun sacha/planner-invert-date (date)
  "Reverse the date in the sorting order."
  (mapconcat (lambda (ch)
               (if (string= ch ".")
                  (- 9 (string-to-number ch)))))
             (split-string date "" t) ""))


View or add comments