惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园_首页
F
Full Disclosure
Martin Fowler
Martin Fowler
The GitHub Blog
The GitHub Blog
L
LangChain Blog
T
The Blog of Author Tim Ferriss
D
DataBreaches.Net
GbyAI
GbyAI
Y
Y Combinator Blog
博客园 - Franky
WordPress大学
WordPress大学
Apple Machine Learning Research
Apple Machine Learning Research
A
About on SuperTechFans
Blog — PlanetScale
Blog — PlanetScale
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
G
Google Developers Blog
罗磊的独立博客
Hugging Face - Blog
Hugging Face - Blog
博客园 - 三生石上(FineUI控件)
IT之家
IT之家
Jina AI
Jina AI
N
Netflix TechBlog - Medium
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Recent Announcements
Recent Announcements
酷 壳 – CoolShell
酷 壳 – CoolShell
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 聂微东
腾讯CDC
H
Help Net Security
H
Heimdal Security Blog
J
Java Code Geeks
C
CXSECURITY Database RSS Feed - CXSecurity.com
T
The Exploit Database - CXSecurity.com
The Register - Security
The Register - Security
大猫的无限游戏
大猫的无限游戏
T
Threatpost
B
Blog RSS Feed
T
Threat Research - Cisco Blogs
Microsoft Security Blog
Microsoft Security Blog
S
Securelist
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
B
Blog
量子位
AWS News Blog
AWS News Blog
Project Zero
Project Zero
P
Proofpoint News Feed
Cisco Talos Blog
Cisco Talos Blog
Spread Privacy
Spread Privacy
S
Schneier on Security

少数派

派早报:Google 发布 Fitbit Air 等 - 少数派 「新人报到」確認需求,再開始 - 少数派 从 SOLO 独立开发者社区,我看到了越来越多开发者开始做自己的产品 - 少数派 我怎么管理那些"不常做,但总会忘"的生活事项 - 少数派 人形机器人量产元年,数据才是具身智能的“生死线” - 少数派 BuhoLaunchpad 高度还原 Mac 启动台:开发历程与思考 - 少数派 五年陪伴依然不舍,DIY 换壳后让罗技 MX Master 3 继续服役 - 少数派 新玩意 240|少数派的编辑们最近买了啥? - 少数派 一日一技|为什么你应该关闭 iOS 的键盘声音 - 少数派 我做了个插件和 Skills,一键提取任何网站的设计规范 Design.md - 少数派 住在三四线城市的你,该开始录播客了 - 少数派 甘南秘境,大白高国 - 少数派 AI的审美:谁让把我变成川内倫子 - 少数派 返工怎能不烦恼,打工人片单总有一部是你的「嘴替」 - 少数派 为了让「上厕所」更健康,我做了一个小工具 - 少数派 AI + Skill,能够让生成的文章去除 AI 味吗? - 少数派 新玩意|韶音OpenDots ONE 耳夹式耳机 - 少数派 《美满》| 在每一个春天的晚上相爱(362) - 少数派 新玩意|优篮子 PS01 MagSnap 磁吸支架 - 少数派 自我整合手记 | 我开始早睡了:用稳定规则,为自由托底 - 少数派 用龙虾(OpenClaw)两个多月,我最深的12个体会 - 少数派 听歌时间到,12 张你可能错过的 2025 华语乐坛好专辑 - 少数派 承诺能追吗 - 少数派 macOS 26启动台没了? 我做了个不一样的App启动器 - Keboard - 少数派 《四海为家的人》| INTJ对话INTJ(361) - 少数派 你发过的那些黑历史,是时候一次清干净了 - 少数派 新玩意:安安静静玩,越玩越专注:计客密码机 - 少数派 iPad 用户首次体验 Android 平板:vivo Pad6 Pro - 少数派 数据逻辑强 - 少数派 极北行+ | 一路向北,探访日本至北之地 | 001 - 少数派 万字剖析:千问App深度体验报告(2026) - 少数派 在2026年,如何真正防止别人抄袭你的作品 - 少数派 怎么用 50 块搭个 AI 语音助手?我踩了 3 天坑 - 少数派 YeeroAI:让 AI 对话真正成为知识管理的一部分 - 少数派 爬泰山 - 少数派 「旅图显影」 App 更新:这次,我们补上了一点「手感」 - 少数派 假期出门太折磨?我的 23 条经验帮你规划惬意旅行 - 少数派 工作流会变吗 - 少数派 Claude Opus 4.6 怎么用最省钱?我测了 5 种方案 - 少数派 GPT Image 2 让图文并茂不再稀罕 - 少数派 用户侧出发——什么是AI,我要不要学习? - 少数派 找片、转存、整理、播放一条龙!让你的付费网盘值回票价 - 少数派 欢迎试用!日课一问2.0插件 - 少数派 自己做的MDeditor,原本想购买 Typora 试了两次支付不成功,干脆自己做一个 - 少数派 vibe coding了一个 3MB 的小工具,让 ~/Downloads 彻底告别混乱 - 少数派 因为受不了 Mac 的风扇策略,我做了一个风扇控制工具 - 少数派 别只怪模型 - 少数派 Warp 终端的 AI 功能怎么用?我测了一周的体验 - 少数派 AI 写代码老是出 bug?这 5 个配置我后悔没早知道 - 少数派 「新玩意」苹果出相机可能就这样:Sigma BF + 45mm F2.8 DG Contemporary - 少数派 一个面向2030年的AI操作系统是什么样子的:浅谈cola这款有灵魂的Agent - 少数派 别只看写代码 - 少数派 每天解决10个问题,还是一口气攻坚解决400个? - 少数派 AI 交易机器人怎么搭?我用 Claude 跑了一周实盘 - 少数派 Maptoposter Online:把你爱的城市画成艺术海报 - 少数派 Function Calling 怎么用?我测了 3 个模型发现差距真大 - 少数派 Legend Talk:我做了个 AI 圆桌,让 160 位思想家围着你的问题转 - 少数派 如何找到自己的蓝方?在小县城寻找压力测试 - 少数派 语音输入与软件接口|2026年聊AI时,我们都聊些什么(上) - 少数派 混动已经卖爆,纯电又来补刀——钛7闪充版简直“不讲武德” - 少数派 本月玩什么|朋友收藏、识质存在、沙罗周期 - 少数派 为什么要每天坚持输出? - 少数派 Claude API 挂了好几个小时,你的项目有备用方案吗? - 少数派 Function Calling 没你想的复杂——我用它做了个有点用的工具 - 少数派 登录系统立即播放视频或者图片音乐的软件 - 少数派 我为什么创建 FlipHTML5 下载工具 - 少数派 残局没电?多品牌外设电量统一管理软件EasyBluetooth已支持RTSS游戏内显示以及AIDA64 - 少数派 前往通义路的路 - 少数派 太好看了,媲美Sun的个人导航页,NAS部署星云门户 - 少数派 乌黑嘴唇“一键检测”上线了 - 少数派 派早报:Claude AI 接入多个创意软件生态、FILCO 生产方接手品牌等 - 少数派 【更新】BearCLI、Claude 连接器与 MCP 服务器 - 少数派 记了上千条流水,还是看不懂财务?我做了一个让 AI 读懂账本的工作台 - 少数派 MINI R56 升级原厂 Sport 模式 - 少数派 新玩意 | 一棵柠檬树(仿真版) - 少数派 Momenta的“物理AI”野望,需迈过“含摩量”这道关 - 少数派 网页直接投屏控制手机!NAS一键部署PandaScrcpy,流畅丝滑可远程。 - 少数派 众测|邀你一同探索随身 AI 硬件入口 YoooClaw C·ONE - 少数派 2050大会:分享时间是真诚 参会记 - 少数派 iPad 赋能电影创作:国内首部宣纸手绘长片《燃比娃》的幕后故事 - 少数派 AI的审美:我用 8 个大模型给 100 张旅行照片打分 - 少数派 普通人如何破圈?去参加一个本地协会 - 少数派 把极空间的图标全换了,主题DIY全攻略打造你的专属NAS桌面 - 少数派 电子便签墙,帮你实现便签自由 - 少数派 我如何用三个 CLI 工具取代文档创建需求 - 少数派 原来真的有人可以玩一辈子 - 少数派 社区速递 139 | 派友热议三月买了啥、复古单反尼康 Df 体验 - 少数派 06 作品的赏析与评价 - 少数派 TDS REVIEW|索尼 WF-1000XM6 降噪真无线耳机体验 - 少数派 35.98万起售的第二代腾势D9,我看重的不是堆料,而是不凑合 - 少数派 鼠须管 Squirrel 皮肤配置指北 - 少数派 从watch ultra2换到redmi watch6 - 少数派 派早报:阿里巴巴发布视频生成模型 HappyHorse 1.0 等 - 少数派 别迷信1M - 少数派 家人们天塌了!网盘“大封杀”,多个渠道多条路,NAS部署PanHub - 少数派 AI与人勾心斗角!NAS一键部署AI狼人杀,假日休闲必备。 - 少数派 电商必备!Comfyui工作流批量生图插件,一次生成12张!支持Nano banana pro模型 - 少数派 Comfyui工作流配置Gpt-image-2模型教程,0.03/张 - 少数派 OpenClaw第三方APi怎么配置?可使用Gpt-image-2模型 - 少数派 会员社区话题精选 Ep. 103 - 少数派
用 Drafts 实现 OmniFocus 批量添加任务 - 少数派
2017-04-14 · via 少数派

文本化的任务收集

「收集」是 GTD 流程中的第一步,面对头脑中随时一闪而过的各种想法,需要能够将其准确而快速地收集到 Inbox 中。

针对这种需求,主流任务管理 app 大多都提供一种「快速添加」的功能,即在界面上提供一个按钮(如 OmniFocus 中的「Save+」),当用户输入完一条任务信息并点击该按钮时,应用不会回到主界面,而是保存该条任务并清空输入框,让用户可以直接继续输入。

OmniFocus 中的快捷输入功能
OmniFocus 中的快捷输入功能

很明显,这种添加任务的方式只是一种妥协方案,所谓的「快速添加」并没有那么快捷。用户不仅需要手动打开 app、点击添加按钮,而且如果想修改截止日期、备注等具体参数,仍然需要多次点击。

那么,是否存在这样一种方式,能够一步到位地批量收集任务并定义其具体参数呢?

事实上,这样的方法是存在的,那就是用文本来描述任务。

来看下面这段语句:

    - 任务一 @due(+1d 10p)
    - 任务二 @defer(tue)

即便不加说明,读者应该也能很容易猜出它的含义。这段语句描述了两个任务 任务一任务二,其中 任务一 将截止于明天(+1d)晚上 10 点(10p),而 任务二 推迟至周二(tue)开始。

这种描述任务的方式来源于 macOS 上一款基于纯文本的任务管理工具—— Taskpaper

显然,这种基于纯文本的任务描述方法天然地适合批量输入任务,也免去了在各个输入框中来回设置日期、上下文等参数的麻烦——手不离键盘就能完成全部输入过程。和 Omnifocus 原有的添加多任务的方式相比,Taskpaper 语法的优势显得尤为明显。

发送任务到指定项目
发送任务到指定项目

在 OmniFocus 在 2.14 版后,我们就可以用 Taskpaper 的语法,来批量地向 Omnifocus 来添加任务了。操作过程中,只要通过如下 URL Scheme:

    omnifocus:///paste?content=内容

将符合 Taskpaper 格式的文本传送到 OmniFocus,后者即可自动识别其中包含的任务和属性。OmniFocus 目前支持的 Taskpaper 语法如下表所示:

Taskpaper 标签
Taskpaper 标签

不过,用什么工具承担撰写 Taskpaper 语句并发送给 OmniFocus 的职能呢?理论上,只要是能接受输入并运行 URL Scheme 的 app,如常用的 Workflow、Launch Center Pro 等,都可以做到。不过,本文还是首推 Drafts,这不仅是因为其简洁的界面和宽裕的输入空间十分适合任务收集的情境,更是因为其内建的快捷键和脚本支持能进一步提高输入的效率。基于此,下面就以 Drafts 为例演示如何建立和优化这一工作流。

首先建立最基础的动作,将 Drafts 和 OmniFocus 连接起来。我们在 Drafts 中新建一个动作,其中包含一个 URL 步骤,内容为:

    omnifocus:///paste?content=[[draft]]&x-success=drafts4://

并将该动作的「after success」属性改为「Trash」。(你可以点击这里直接导入该动作。)

在 Drafts 中新建动作
在 Drafts 中新建动作

接着,我们在 Drafts 的工具栏中增加一个指向上述动作的快捷按钮。(你可以点击这里直接导入该按钮。)另外,我还为该按钮设置了一个快捷键(Ctrl-Option-O,与 Mac 版 OmniFocus 的 Quick Entry 保持一致),便于使用 iPad 时直接在键盘上完成全过程。

在 Drafts 中新建脚本按钮
在 Drafts 中新建脚本按钮

这样,只要按照 Taskpaper 语法输入需要批量添加的任务,然后点击键盘上方的按钮/按下 Ctrl-Option-O,就能将这些任务批量添加到 OmniFocus 的 Inbox 中、并自动返回到 Drafts,该条 draft 会在动作执行完毕后被自动删除。

此外,为了加快标签的输入,你还可以将下面这些常用标签的快捷键导入 Drafts 中:

它们的效果是点击后在当前位置插入对应标签,并将光标移动到括号之间;如果选中一段文本再点击该按钮,则可以直接将选中文本包括在标签之内。

这样一来,我们就实现了用 Taskpaper 语法批量收集任务到 OmniFocus 的流程。下面的动画演示了在 iPad 上使用快捷键操作的过程:

发送 Taskpaper 语句到 OmniFocus
发送 Taskpaper 语句到 OmniFocus

需要注意的是,目前 OmniFocus 尚未支持指定任务所在的文件夹或项目。好在,得益于 Drafts 强大的脚本功能,我们可以「自力更生」,间接实现指定文件夹/项目的功能;事实上,上文中提供的动作已经增加了对 @project@folder 两种标签的支持。只要在输入时添加 @project(项目名)@folder(文件夹名) 之一,再运行该动作,即可实现发送到指定项目或文件夹的效果。

例如,下面的输入:

    - 任务一 @project(项目一)
    - 任务二

会在名为「项目一」的项目中新建两个任务「任务一」和「任务二」。

需要注意的是:

  1. 输入的项目名或文件夹名无须完全正确,因为 OmniFocus 对输入有一定的模糊识别能力;
  2. 由于实现机制本身的限制,每次输入中只能指定一个项目或文件夹,而不能单独指定。如果输入中出现多个 @project@folder 标签,所有输入都会被发送到第一个标签指定的项目或文件夹。但反过来说,要给输入的任务/项目指定目的地,只要写一次 @project@folder 即可,无须每条任务指定一次。

你可以导入这两个标签的快捷输入按钮:

来看一下最终的实现效果:

发送任务到指定项目
发送任务到指定项目

细节探究

经过上文的配置,我们已经实现了借助 Taskpaper 语法,用纯文本的形式批量快速收集任务到 OmniFocus。那么,这些功能是怎样实现的?如何修改这些功能使其更加符合自己的偏好?为此,下文就来具体说明上面导入的动作和按钮是如何通过 Drafts 内建的 JavaScript 和正则表达式支持实现其功能的

需要说明的是,Drafts 支持全部的基础 JavaScript 语法及正则表达式,且有较为详尽的官方文档。因此,下文目的并不在于详细介绍语法或翻译文档,而重在对于代码中的一些关键思路和所用到的 Drafts 独有的函数/属性进行介绍。

1. 快捷输入标签的实现机制

Drafts 中的快捷按钮功能相当多样,不仅可以输入特定字符、执行某个动作,还可以运行一段 JavaScript 脚本。以上文中提供的用于输入 @context 标签的按钮为例,点击该按钮执行的代码是:

    var sel = getSelectedText();
    var selRange = getSelectedRange();
    if (!sel || sel.length == 0) {
      setSelectedText("@context()");
      setSelectedRange(selRange[0]+9,0);
    }
    else {
      setSelectedText("@context("+sel+")");
      setSelectedRange(selRange[0]+selRange[1]+10,0);
    }

这段脚本主要使用了与文本选择有关的几个函数:

  • getSelectedText() 获得的是当前选中的文本
  • getSelectedRange() 将返回两个值,分别是当前光标所在位置选中文本的长度
  • 在上述代码中,这两个值被一起传递给了 selRange
  • 因此后面用 selRange[0]selRange[1]

代码的第三行对选中的文本长度进行了判断,如果长度为 0,就直接插入「@context()」这段文本。之后的 setSelectedRange() 函数用于选中文本,它需要输入两个值:光标的起始位置和选中文本的长度,当后一个值为 0 时,就相当于将光标置于前一个值指定的位置。我们希望将光标放在@context 后的括号中间,更精确地说是,放在@ 算起第 9 个字符的位置,这就是这些代码里总会出现数字 9 的原因的来源。以此类推,如果我们需要输入 @due() 并移动光标,则应相应改为 (selRange[0]+5,0)

如果选中文本的长度不为 0,代表我们希望将一段已经输入的文本转化为标签,因此,我们用加号 (+)@context、一个左括号、选中的内容和一个右括号依次连接起来,交给 setSelectedText() 函数。另外,在这种情况下,我们希望光标被放在括号之外,因此交给 setSelectedRange() 的光标起始位置应该是原来的后推@context() 的长度(10 个字符)、再加上选中文本的长度(selRange[1],故完整的表达就是 (selRange[0]+selRange[1]+10,0)。类似地,如果这里是要将选中文本转化为 @due() 标签,则应改为 (selRange[0]+selRange[1]+6,0)

2. 指定文件夹或项目的实现机制

如上所述,OmniFocus 没有提供对 @project@folder 标签的原生支持。但是,在其 URL Scheme 中,paste 动作可以附加一个 target 参数,用于指定发送到的具体位置。例如:

    omnifocus:///paste?target=/task/general

会将当前的剪贴板内容创建为 General 项目下的任务。[^1]

而下列 URL:

    omnifocus:///paste?target=/folder/personal

会将当前的剪贴板内容创建为 Personal 文件夹下的项目。

这就为我们自行创建对 @project@folder 标签的支持提供了可能:只要用正则表达式提取 draft 中出现的相应标签内容,将其填入上述 URL Scheme 并执行即可。事实上,上文提供的动作就用下列 JavaScript 脚本对输入进行了处理:

    var text = draft.content;
    var folderTag = text.match(/@folder\(.+?\)/g);
    if (folderTag != null) {
    var target = '/folder/' + folderTag[0].slice(8,-1);
    } else {
        var projectTag = text.match(/@project\(.+?\)/g);
        if (projectTag != null) {
            var target = '/task/' + projectTag[0].slice(9,-1);
        } else {
            var target = 'inbox';
            }
    }
    draft.defineTag('target',target);

该段代码用到了 Drafts 中特有的 draft 对象及其属性和函数。在 Drafts 中,draft 是一个预先定义的对象,指当前这条 draft。该对象有多种属性:

  • content:文本内容
  • createdDate:创建日期
  • archived:是否被归档,布尔值
  • uuid:该条 draft 的唯一代码

上述代码的第一行即将 text 变量定义为当前 draft 的内容(draft.content)。

接着,代码用正则表达式 /@folder\(.+?\)/g 查找文本中的 @folder 标签,其中 .+ 匹配的是不限数量的、换行符以外的任意字符。而将表达式夹在 //g 之间则代表搜索所有的结果。匹配结果被传给了 folderTag。然后,将第一个匹配到的结果(folderTag[0])进行切割,去掉开头的「@folder(」(8 个字符)和结尾的「)」(1 个字符),只留标签括号中的部分(slice(8,-1)),拼成 /folder/文件夹名的形式,赋给 target 变量。

如果没有搜索到 @folder 标签,代码将继续搜索 @project 标签,方法类似。如果仍然没有搜索到,说明没有指定项目或文件夹,则将 inbox 赋给 target 变量,即发送到 Inbox。最后,将 target 变量的值定义为一个 Drafts 标签[^2] [[target]],以便在之后的步骤中引用。事实上,它将在下一步中,通过 URL Scheme:

    omnifocus:///paste?content=[[draft]]&target=[[target]]&x-success=drafts4://

发送给 OmniFocus。

3. 语法细则

OmniFocus 支持大部分的 Taskpaper 语法,但也存在一些变通,下文列举的是两者的主要差异。

关于短横线

在 Taskpaper 中,任务必须以一个短横线(-)开头,但 OmniFocus 无此要求。因此,单独添加任务时,「- 任务一」和「任务一」这两种写法都可以。

关于备注

在 Taskpaper 语法中,紧跟一条任务之后、不以短横线开头的一行,被认为是该条任务的备注(Notes),例如:

    - 任务一
    备注内容

OmniFocus 同样能识别该语法。在这种场合,任务前的横线不能被省略。例如,不能写成:

    任务一
    备注内容

否则,备注将被识别为另一条任务。

关于子任务

在 Taskpaper 语法中,任务间的隶属关系通过缩进来体现,你可以通过输入一个制表符(Tab 键)将一个任务标记为其上一行的子任务,例如:

    - 任务
    - 子任务一
    - 子任务二

这种情况下,任务名前的横线可以省略。而且你还可以通过 @parallel 标签指定子任务是平行的(@parallel(1))还是顺序的(@parallel(0)),如不指定,默认为平行。

最后,根据 Taskpaper 原本的规则,可以用项目名:的格式来新建一个项目。但 OmniFocus 并未接受这一设定。因此,即使输入:

项目一:
    - 任务一
    - 任务二

也不能创建一个名为 Task 1 的项目。对于 OmniFocus,该输入与上个例子是等价的。如果想将任务发送到一个既有的项目,你应该如前文所述,使用我们自行定义的 @project 标签。


[^1]: 注意,target 参数的值须经 URL 编码。但为易读性起见,本段中的 URL 没有做此处理。实际执行中,该 URL 会被 Drafts 自动编码为 omnifocus:///paste?target=%2Ftask%2Fgeneral
[^2]: 标签(Tags)是 Drafts 另一项重要功能,类似于 Workflow 中的变量。Drafts 提供了一些默认标签,但用户也可以自行定义新的标签。与步骤内部执行的 JavaScript 脚本中的变量相比,标签的优势在于可以在步骤之间传递数据。