OmniFocus Mac 版售价 258 RMB,内购还需额外的 258 RMB,这个价值 258 RMB 的内购,强就强在它支持 AppleScript,让我们可以很方便地用 OmniFocus 与其他的应用相互联系、相互作用。

最开始的时候,我对“在 OmniFocus 内使用 AppleScript”的理解,还停留在快速设置项目/任务的推迟日期、截止日期、持续时间等,比如我常用的:

  • 推迟到周末;
  • 推迟到下周;
  • 今天内完成;
  • ……

后来在少数派上看到这么一篇文章:

《装了啥丨喜欢效率工具的法官 JannerChang,用 GTD 来处理案件判决》

其中最吸引我的,是利用一个 sh 脚本监视 OmniFocus 的数据库,在项目状态更改时,对与项目相关联的文件夹设置标签。

之后会有一个「sh 脚本」通过监视 OmniFocus 数据库的变化动态的改变 tag ,通过 tag 可以在 Finder 里直观的显示各阶段的案件情况。该脚本设置成随系统启动,实时监视 OmniFocus 的数据库。

我非常喜欢这个功能,去 Github 看了下作者的 sh 脚本,理解了一下,其思路大概是:

  1. 将已完成的任务发布到 Day One;
  2. 通过任务名来判定文件夹、通过上下文(Context)来判定任务状态;
  3. 设置文件夹标签。

这里我发现一个问题,原作者使用上下文(Context)来判断任务状态,也就是说,Context 成为了一个“判断语句”,违背了 Context 的本意:情境。如果给任务设置“判断类型”的 Context,那么就无法为其设置情境类的 Context,在之后的透视、分析、回顾过程中,就无法根据 Context 有效地筛选出目标任务。

举个例子,一个本应该属于情境“办公室”的任务,告诉我当我到达办公室时执行该任务;如果其 Context 被设置为“待完成”,那么在我到达办公室时,就无法根据当时的情境筛选出这项任务。

因此,我根据自己的理解,用 AppleScript 实现了原文中“根据 OmniFocus 内项目/任务状况自动给文件(夹)添加标签(Tags)”的功能。

这里使用了 tag,可以用 brew 来安装:

brew install tag

注:由于 WordPress 不支持 AppleScript 代码高亮,如果觉得看得不舒服的话,可以到 Github 查看源码。

根据任务设置文件标签

场景:

我的写作流程为:

  1. 撰写大纲
  2. 添加内容
  3. 添加题图
  4. 插入图片

在冒出一个写作想法时,我会把想法添加到 OmniFocus,并创建一个大纲文档 Outline,为其添加标签「Startup」;随后,完成「撰写大纲」流程,设置其标签为「Writing」;完成「插入图片」后,设置其标签为「Completed」;假如有带旗标的任务,则给文件添加标签「Flagged」。

实现:

通过一个 Keyboard Maestro 指令把这些流程添加到 OmniFocus 里,如图所示:

(每个流程后面都会跟着该任务的具体名称,例如上图的「1. 撰写大纲丨OmniFocus」

在 Keyboard Maestro 指令中,包含两部分 AppleScript:

首先是为选中的任务设置持续时间,我设置的是 2 小时,以便在「番茄钟」透视中显示:

tell application "OmniFocus"
tell front document
tell content of document window 1
set SelectedTasks to value of every selected tree
if ((count of SelectedTasks) < 1) then
display alert "You must first select an item to complete." as warning
return
end if
repeat with anItem in SelectedTasks
set estimated minutes of anItem to 120
end repeat
end tell
end tell
end tell

其次是为该任务在指定文件夹创建与任务同名的 Outline 文件:

tell front document of application "OmniFocus"
tell content of document window 1
set ofitems to value of every selected tree
repeat with theitem in ofitems
set filename to name of theitem

tell application "Finder"
set filepath to alias "HD:Users:User:Documents:Outline"
make new file at filepath with properties {name:filename & ".oeoutline"}
end tell

end repeat
end tell
end tell

通过一个 Hazel 脚本为空白的 Outline 文件添加「Startup」标签:

(至于为什么要用 Hazel 而不是直接在 AppleScript 里设置标签,是因为有时候会直接绕过 OmniFocus 添加文件,因此用 Hazel 更合适。)

当然,添加文本容易,设置首个标签也容易,但是如何根据任务完成情况来设置其他的标签呢?

由于我的写作流程是模板化的四个步骤,每个步骤都包含特定的前缀,例如「撰写大纲」、「添加内容」,因此我的想法是利用“前缀”的方法来判断任务状态。

例如:如果「1. 撰写大纲丨OmniFocus」出现在完成列表中,那么就判断「OmniFocus」这个任务的 Outline 已经完成了,应该给相关文件设置「Writing」标签。同理,如果「4. 插入图片丨OmniFocus」出现在完成列表中,则应该给相关文件设置「Completed」标签。

那么,首先我们要抓出这些满足条件的任务的名称(状态:已完成;上下文:写作):

set startDate to (current date) - 20 * minutes
tell application "OmniFocus"
tell front document
set theContext to first flattened context where its name = "context"
set theTask to name of every flattened task where its context = theContext and completed = true and completion date is greater than startDate
set flaggedTask to name of every flattened task where its flagged is true and its completed is not true and its modification date is greater than startDate
end tell
end tell

其中,为了加快运行速度(其实影响并不是很大),我还添加了一个筛选条件:20 分钟内修改过的任务,这样一些早期完成的任务就不会被索引了。

只有在筛选出的任务数量大于 0 时,AppleScript 才会继续运行;如果 20 分钟内没有符合条件的任务,那这个 AppleScript 就不执行了:

if number of theTask is greater than 0 then

接着,就是要拿 Finder 里的文件,和 OmniFocus 中的任务进行比对,说是比对,其实只是取一个文件名用作变量而已。

set filepath to alias "HD:Users:User:Documents:Outline"
tell application "Finder"
set filename to name of every file in filepath whose label index is not 6

其中,那些已经被标记为「Completed」的文件可以直接排除掉,因此通过 label index 来判断,0 代表绿色(标签)。

这里,获取完文件的名称,由于是带扩展名的,例如(OmniFocus.oeoutline),因此要把扩展名去掉:

repeat with theFile in filename
set t to text 1 thru -11 of theFile

判断任务里是否包含「1. 撰写大纲丨OmniFocus」

if theTask contains “1. 撰写大纲” & t then

如果包含,那么就为文件设置标签「Writing」,值得注意的是,由于要执行 Shell Script,因此空格前都要加转义符号 \

set newString to {}
repeat with i in theFile
if (i as string) is " " then
set end of newString to "\\ "
else
set end of newString to (i as string)
end if
end repeat

set n to newString as string

然后就是执行 Shell 命令:

do shell script "/usr/local/bin/tag -s Writing ~/Documents/" & n
end if

同理,判断任务里是否包含<strong>「4. 插入图片丨OmniFocus」</strong>,给 Outline 文件设置「Completed」标签:

if theTask contains t then

set newString to {}
repeat with i in theFile
if (i as string) is " " then
set end of newString to "\\ "
else
set end of newString to (i as string)
end if
end repeat

set n to newString as string

do shell script "/usr/local/bin/tag -s Complete ~/Documents/" & n
end if

end repeat
end tell

end if

同样的思路,我们判断是否有带旗标的任务,添加「Flagged」标签,注意,在这里是“添加”标签,而不是“设置”标签,添加「Flagged」标签后,文件将会共存两个标签,一个原标签,一个「Flagged」标签:

if number of flaggedTask is greater than 0 then

tell application "Finder"
set filename to name of every file in filepath whose label index is not 6
repeat with theFile in filename
set t to text 1 thru -11 of theFile

if flaggedTask contains t then

set newString to {}
repeat with i in theFile
if (i as string) is " " then
set end of newString to "\\ "
else
set end of newString to (i as string)
end if
end repeat

set n to newString as string

do shell script "/usr/local/bin/tag -a Flagged ~/Documents/" & n
end if

end repeat
end tell

end if

根据项目设置文件夹标签

场景:

我在 OmniFocus 设置了一个「工作」文件夹,其中包含有工作中的各个项目;在 Finder 中有一个「工作」文件夹,每个工作项目是其中一个独立的文件夹,包含项目中的相关文件。OmniFocus 中的项目与 Finder 中对应的文件夹同名。

  1. 根据 OmniFocus 中项目的状态(活跃、暂停、已完成、已丢弃),为对应的文件夹设置标签;
  2. 假如项目附带旗标,则添加「Flagged」标签;
  3. 在 OmniFocus 中新建项目时,自动在 Finder 中创建同名文件夹。

实现:

首先,先实现第三点需求「在 OmniFocus 中新建项目时,自动在 Finder 中创建同名文件夹」。思路是,将 Finder 中的文件夹与 OmniFocus 中的项目进行比对,如果 Finder 文件夹不包含 OmniFocus 项目,则新建以这个项目命名的文件夹。

set startDate to (current date) - 20 * minutes
set filepath to alias "HD:Users:User:Documents:Work"

tell application "OmniFocus"
tell front document
set theFolder to first flattened folder where its name = "Folder"
set subFolder to every folder of theFolder
repeat with f in subFolder
set theProject to (name of every project of f where its modification date is greater than startDate)
if number of theProject is greater than 0 then
repeat with p0 in theProject

tell application "Finder"
set foldername0 to name of every folder in filepath
if foldername0 does not contain p0 then
tell application "Finder" to make new folder at filepath with properties {name:p0}
end if
end tell

end repeat
end if
end repeat

end tell
end tell

「根据 OmniFocus 中项目的状态(活跃、暂停、已完成、已丢弃),为对应的文件夹设置标签」,思路和「根据任务设置文件标签」差不多,只不过把任务(Task)换成项目(Project)。

最后,把 Finder 设置为按照 Tags 排列:

对这两个 AppleScript 感兴趣的,可以从 Github 下载源码:

https://github.com/Boyux/OFAppleScript

发表评论

Fill in your details below or click an icon to log in:

WordPress.com 徽标

您正在使用您的 WordPress.com 账号评论。 注销 /  更改 )

Twitter picture

您正在使用您的 Twitter 账号评论。 注销 /  更改 )

Facebook photo

您正在使用您的 Facebook 账号评论。 注销 /  更改 )

Connecting to %s