Power of Two

Something that does matter, technically.

A Quicksilver Action to Create New Reminders

| Comments

I recently switched to Reminder.app as my ToDo management tool, after upgrading to Mountain Lion. The only thing I missed is a hotkey window to create a new reminder instantly. As always, I turn to Quicksilver for this kind of things.

So, I wrote a Quicksilver action (in Ruby). The following is the screenshot of how it works.

And here is the source code. Just drop it under ~/Library/Application Support/Quicksilver/Actions and make it executable by using chmod 755 NewReminder.rb in terminal (thanks to Luke for pointing it out), then restart Quicksilver.

(NewReminder.rb) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#!/usr/bin/ruby
# as of 0.7.0, chronic has problem with ruby 1.9.3. So use system ruby
require "rubygems"
require "chronic"

AS_GET_LIST = <<-EOF
on run argv
  set listStr to ""
  tell application "Reminders"
    repeat with listIndex from 1 to (count of list)
        set oneList to list listIndex
        if listStr is equal to "" then
            set listStr to (name of oneList)
        else
            set listStr to listStr & "|" & (name of oneList)
        end if
    end repeat
  end tell
  return listStr
end run
EOF

AS_MAKE_REMINDER = <<-EOF
on run argv
  set theList to item 1 of argv
  set theName to item 2 of argv
  if item 3 of argv equal to "" then
    set theDate to ""
  else
    set theDate to date(item 3 of argv)
  end if

  tell application "Reminders"
    tell list theList
      if theDate equal to "" then
        make new reminder with properties {name:theName, body:""}
      else
        make new reminder with properties {name:theName, body:"", due date:theDate}
      end if
    end tell
  end tell
end run
EOF

lists = `osascript -e '#{AS_GET_LIST}'`
lists = lists.strip.split("|") # strip \n, and get ["Life", "Work", ...]

line = ARGV[0].strip
return 1 if !line

parts = line.split("^")
body = parts[0]
date_str = parts.length > 1 ? parts[1] : nil
due_date = Chronic.parse date_str
due_date_str = due_date ? due_date.strftime("%m/%d/%Y %I:%M%p") : ""

words = body.strip.split(" ")

list = words.find {|w| w.start_with? "@"}
words.delete list

list = lists.find {|l| list.gsub(/^@/, "").upcase.eql? l.upcase} if list
list = lists[0] if !list

`osascript -e '#{AS_MAKE_REMINDER}' #{list} "#{words.join(' ')}" "#{due_date_str}"`

if $?.to_i == 0
  `terminal-notifier -message "#{words.join(' ')}" -title "#{"Reminder @" + list + " " + (due_date ? date_str : "")}" -group new_reminder -activate "com.apple.Reminders"`
else
  `terminal-notifier -message "Oops... Something was wrong" -title "New Reminder" -group new_reminder -activate "com.apple.Reminders"`
end

Some notes about this script:

  • The script is written in Ruby, and it uses 2 gems: chronic for parsing human readable date string and terminal-notifier for send notification using Notification Center. As chronic cannot work well with Ruby 1.9.3 as of this writing, I forced the script to be executed using system ruby (/usr/bin/ruby) which is of version 1.8.7 in OS X 10.8. Anyway, you need to install those 2 gems using gem install chronic and gem install terminal-notifier.

  • As it uses Notification Center, it should only work on OS X 10.8+. But it is easy to be tweaked to drop notification or use other notification services like Growl.

  • Some AppleScript code is embedded and executed by osascript to interact with Reminder.app. This script could be written entirely in AppleScript, but I chose Ruby + AppleScript way as it is much easier to write most part of the logic in Ruby.

  • The usage of this action: assuming it is correctly installed, launch QS, hit “.” to enter text mode, write your reminder message, hit tab key to focus on the 2nd pane, and choose “NewReminder” action. Your reminder should be created.

  • You can set list and/or due date in your message. The list name should be prefixed with @. The due date string can be any human readable format understandable by chronic. Due date must be prefixed with ^ and be the last part of the message. For example, call my mom @life ^tomorrow 6pm will create a reminder call my mom in the life list and set due date to 6pm of tomorrow.

Comments