Category Archives: planner

On this page:
  • Contact report
  • Developing a better sense of time
  • Emacs: Show only people whom I haven’t pinged since…
  • More Emacs coolness: List of contacts
  • Sharing the link love
  • TODO lists in Emacs!

Contact report

I started tracking e-mail sent on 2006.09.01 with a
nifty piece of Emacs Lisp code I wrote just for the
purpose. Now I have two months of interesting data which include not
only e-mail but also the occasional in-person contact or phone call
that I remember to note. It’s not complete – e-mail’s the only thing
that gets automatically tracked – but it does give me interesting
information. Here’s the contact report for your amusement:

Contact report

It’s sorted by overall frequency and then by regular frequency.
Warning! Parentheses follow.

(defun sacha/count-matches (regexp string)
  (let ((count 0)
        (start 0))
    (while (string-match regexp string start)
      (setq start (match-end 0)
            count (1+ count)))
    count))

(defun sacha/bbdb-contact-report-as-alist (&rest regexps)
  "Creates a list of (name count-regexp1 count-regexp2 count-regexp3)..."
  (setq regexps (reverse regexps))
  (delq nil
        (mapcar
         (lambda (rec)
           (when (bbdb-record-name (car rec))
             (let ((reg regexps)
                   (notes (bbdb-record-notes (car rec)))
                   list)
               (while reg
                 (setq list (cons (sacha/count-matches (car reg) notes)
                                  list))
                 (setq reg (cdr reg)))
               (cons (sacha/planner-bbdb-annotation-from-bbdb rec)
                     list))))
         bbdb-records)))

(defun sacha/bbdb-alist-sort-by-total (alist)
  "Sort ALIST by total contact."
  (sort alist 'sacha/bbdb-contact-sort-predicate))

(defun sacha/bbdb-contact-sort-predicate (a b)
  (and a b
       (let ((count-a (apply '+ (cdr a)))
             (count-b (apply '+ (cdr b))))
         (or
          (> count-a count-b)
          (and (= count-a count-b)
               ;; If equal, look at the subtotal of the rest
               (sacha/bbdb-contact-sort-predicate (cdr a) (cdr b)))))))

(defun sacha/bbdb-kill-contact-barchart (alist)
  "Kill a barchart with the contact report for ALIST."
  (kill-new
   (mapconcat
    (lambda (entry)
      (concat
       (car entry)
       " | "
       (mapconcat (lambda (count)
                    (if (= count 0)
                        " "
                      (make-string count ?-)))
                  (cdr entry)
                  " | ")))
    alist
    "\n")))

;; Usage: (sacha/bbdb-kill-contact-barchart
;;         (sacha/bbdb-alist-sort-by-total
;;          (sacha/bbdb-contact-report-as-alist "2006.09" "2006.10")))
;; Then yank (paste) this into another buffer

On Technorati: , , , ,

Random Emacs symbol: standard-display-cyrillic-translit – Command: Display a cyrillic buffer using a transliteration.

Developing a better sense of time

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

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)
                   (planner-page-name))
          (jump-to-register sacha/window-register)
        (if (null prefix)
            (message "%s %s"
                     ;; Minutes so far
                     (timeclock-seconds-to-string (timeclock-last-period))
                     planner-timeclock-current-task)
          (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
        (planner-goto-today)
      (message "No current task. HEY!"))))

On Technorati: , , ,

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…)

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

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)
        new-records
        last-match
        omit
        notes)
    (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
              "[0-9][0-9][0-9][0-9]\\.[0-9][0-9]\\.[0-9][0-9]"
              notes
              (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>

On Technorati: , , , , , ,

More Emacs coolness: List of contacts

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!
        (planner-make-link
         (concat "bbdb://"
                 (planner-replace-regexp-in-string
                    " " "." (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."
  (interactive)
  (kill-new
   (mapconcat 'sacha/planner-bbdb-annotation-from-bbdb
              bbdb-records
              ", "))
        (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, Wayne Penney, Simon Rowland, San, Colin Smillie, Solomon, Le Quan Truong, Perry Wong

On Technorati: , , , ,

Sharing the link love

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

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 "/"
                 (planner-gnus-get-message-id)))
        (addresses
         (split-string (planner-gnus-get-address "To") ", *"))
        text)
    (setq text
          (concat
           (planner-make-link mail-link "E-mail to")
           " "
           (mapconcat
            (lambda (address)
              (let (rec)
                ;; Look up record
                (setq addr (mail-extract-address-components address))
                (setq rec (apply 'bbdb-search-simple addr))
                (if rec
                    (planner-make-link
                     (concat "bbdb://"
                             (planner-replace-regexp-in-string
                              " " "."
                              (bbdb-record-name
                               rec)))
                     (bbdb-record-name rec))
                  (or (car address) (cadr address)))))
            addresses
            ",")))
          ;;            ": "
          ;;           (message-fetch-field "Subject"))))
    (save-window-excursion
      (save-excursion
        (planner-goto-today)
        (planner-seek-to-first "E-mail sent")
        (insert " 1. " text "\n"))))
  nil)

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

On Technorati: ,

TODO lists in Emacs!

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.

On Technorati: , ,

E-Mail from Stephen J. Turnbull