Motivation
OmniFocus1 is a wonderful task management application. It runs on the Mac, iPad and iPhone, and I simply wouldn't be without it.
However, somewhat inexplicably, it's hard to import a list of tasks generated elsewhere into OmniFocus. Happily, the Mac application has a rich AppleScript API, so in principle one could use this to solve the task. In practice though I know very little AppleScript, and when I've tried to write command line scripts with it before, it's always been a pain.
So, I'd rather use a mainstream language with AppleScript bindings. Sadly the Perl interface seems a bit flakey and unloved, perhaps because the cool guys seem to use Ruby's rb_appscript2 for this sort of thing. I've not written much Ruby, but how hard can it be ?
Discussion
Happily there are a number of OmniFocus AppleScript examples floating around the web. Andy Schott's examples3 were helpful, as was browsing the OmniFocus dictionary with the AppleScript Editor application (File | Open Dictionary). The dictionary is particularly handy for details about the properties supported by each task.
The program tries to do as little work as possible. It takes data from a YAML4 file, treats them as simple task properties, and calls the relevant API. In most cases it's just a case of passing strings around, but there are three exceptions:
- Dates need special handling because AppleScript wants a date object not a string.
- The project name should be passed as an object reference, not a string. To find the relevant project I do a global name search: this means that the project name should probably be unique!
- ditto for the Context.
There's one other twist. Incoming fields beginning with an underscore aren't passed to the AppleScript API, rather they're understood as being 'internal' to the import process. Some of these are interpreted by the program:
- _no_dupes : If true, don't import the task if it already exists. Exists here just means that there's already a task with the same name in that project.
Finally you can ask the program to dump a list of all the tasks it actually added.
Sample data
You'll probably generate the YAML with another program, but here's the sort of thing you should get:
---
- context: Administriva
due date: 2010-12-24
name: Blossom 2
note: Cherry 2
project: Auto
- context: Administriva
due date: 2010-12-26
name: Blossom 3
note: Cherry 3
project: Auto
_no_dupes: 1
Practical Matters
You can download the program,5 but you'll then need to copy it to somewhere on your PATH.
To run it, you probably want something like this:
% of-import-yaml --help
...
% of-import-yaml tasks.yml
...
% of-import-yaml --output YAML tasks.yml
Internals
Internally the code is pretty simple. Simplified slightly in the interests of clarity, the basic core is shown below. Feel free to steal it for your own applications.
...
of = app('OmniFocus')
dd = of.default_document
...
add_task(dd, task)
...
def add_task(dd, props)
proj_name = props["project"]
proj = dd.flattened_tasks[proj_name]
ctx_name = props["context"]
ctx = dd.flattened_contexts[ctx_name]
tprops = props.inject({}) do |h, (k, v)|
h[:"#{k}"] = v
h
end
tprops.delete(:project)
tprops[:context] = ctx
t = dd.make(:new => :inbox_task, :with_properties => tprops)
t.assigned_container.set(proj)
return true
end
Disclaimer
I've used this program myself and it appears to work, but you should be aware that I know very little Ruby and even less AppleScript.
Ultimately, the program sends OmniFocus a series of commands asking it to modify your task lists, so it's perfectly possible that things will get trashed!
You should probably backup your OmniFocus data before playing with this.
References
- 1. http://www.omnigroup.com/products/omnifocus/
- 2. http://appscript.sourceforge.net/rb-appscript/index.html
- 3. http://andy.theschotts.net/omnifocus-applescript-integration/
- 4. http://www.yaml.org/
- 5. http://www.mjoldfield.com/atelier/2010/10/of-import-yaml-0.1.tar.gz