J. Klymak --- Making OSX and Planner play together.

JMK Home

Publications

Curriculum Vitae

Teaching

OtherStuff

Work Calendar

Jody Klymak's 
citations

I'd drifted away from planner because I was using OS X and in particular Mail.app. Gnus had driven me nuts from having too slow a support for Imap, particularly for mutlipart mime attachments. However, I started noting that the productivity apps like OmniFocus were able to handle linking to Mail messages, so why couldn't emacs?

Special emacs code:

OK, so I am terrible at elisp, but this was all I really needed - a way to invoke planner-create-task interactively but still add a custom annotation:

(defun planner-create-task-annote (annote)
  (interactive)
  (let ((boo (planner-read-task)))
        (setq title (car boo))
        (setq boo (cdr boo))
        (setq date (car boo))
        (setq boo (cdr boo))
        (setq plan-page (car boo))
        (setq boo (cdr boo))
        (setq status (car boo))
        (planner-create-task title date annote plan-page status)
        ))

Then all I needed to do was add the message: url to the list of urls that Muse recognizes:

(add-to-list 'muse-url-protocols '("message:" browse-url identity) t)

On the Mac

On the mac, we use applescripts to call emacsclient. You need emacsclient to work on your machine - test on the command line.

The following script is in ~/Library/Scripts/Applications/Mail/

property eclient : "/usr/bin/emacsclient -e "
tell application "Mail"
        tell application "Emacs" to activate
        set _sel to get selection
        set _links to {}
        repeat with _msg in _sel
                set _messageURL to "message://%3c" & _msg's message id & "%3e"
                set _messageSubj to _msg's subject
                set end of _links to _messageURL
        end repeat
        set AppleScript's text item delimiters to return
        set the clipboard to (_links as string)
        do shell script eclient & "'(planner-create-task-annote \"[[" & _links & "][" & _messageSubj & "]]\")'"
        tell application "Emacs" to activate
end tell

It is then invoked using FastScriptsLight. Bound to F5 for a task. When I am in Mail and I have a message selected, pressing F5 takes me to emacs and the normal task entry procedure. Then it creates a link like:

#B _ Respond : [[message://%3c0C848CF8D7D13B4E8348D78C82404F9A11E4A55051@EXCHANGE.uvic.ca%3e][Important Material]] ([[TestPage]])

I've made similar scripts for the Finder and Safari, and for notes:

Calendar integration

OK, I also wanted to see my upcoming appointments in planner mode. There was already planner-diary, but I don't actually keep my appointments in diary mode. Mail.app and iCal interact very well with automatic parsing of mail for appointment dates, times, and if the person who wrote the email writes a decent email, it will even figure out the location. That is very useful.

Fortunately there is icalendar.el, which is part of Emacs. However, all that icalendar.el had was icalendar-import-file which would just take an ics file and create a diary buffer. Not quite what I was after, since ical stores each individual appointment as an ics file.

Has a function icalendar-convert-all that looks in ~/Library/Calendars for a directory with the suffix *.caldav and then looks for calendars inside of that. I suppose I could have hardwired the directory, but it was different on my two machines, which would have been awkward.

Then I call the following every time I want the calendar to be synced.

(defun jmkplan ()
  (interactive)
  (planner-sync-get)
  (icalendar-convert-all)
  (plan))

I also changed the format of the diary entry to include the url and to make the url a clickable link (otherwise the message urls are not possible to click).

(setq icalendar-import-format "%s%d%l%o%u");
(setq icalendar-import-format-url "\n   [[%s][link to appointment]]")
(setq icalendar-import-format-location "\n   *%s*")

Syncing plan pages

In the above, I also synchronize my plan pages with a central store on mymachine.ca. This relies on the following two functions that just call rsync:

(defvar planner-syncloc "mymachine.ca:/Users/jklymak/.planstor/");

(defun planner-sync-put ()
  (interactive)
  (shell-command-to-string (concat "rsync -av " planner-directory " "  planner-syncloc)))

(defun planner-sync-get ()
  (interactive)
  (shell-command-to-string (concat "rsync -av " planner-syncloc "/Plans/ " planner-directory "/" )))


Then I rebind the save keystrokes in planner mode to:


(defun jmk-planner-save-buffers ()
  "Update a note if we are on a note.  Run planner-save-buffers."
  (interactive)
  (save-excursion
    (save-window-excursion
      (planner-update-note)
      (planner-save-buffers)
      (planner-sync-put))))

(define-key planner-mode-map [?\C-x ?\C-s] 'jmk-planner-save-buffers)

This is not a foolproof sync method. If both stores get changed and neither is saved or updated, then the plans will get out of sync. Even worse, it will lose data. However, if you only keep one plan session going at a time all should be good.

Note that you also need to share your public key with the host machine so that ssh doesn't prompt you for a password.


Last Modified: July 31, 2011
Powered by Emacs Muse Jody Klymak - jklymak@uvic.ca