在上一篇文章中，我们简单介绍了 gtd 的一些理念，并且也通过org capture 完成了 gtd 中收集的操作。gtd分为收集任务、整理、执行、回顾。本篇我想通过org todo 来聚焦整理和执行这两个步骤整理上一篇文章中，我们通过org capture 收集到了一些任务，针对这些任务我们还需要给每个任务安排优先级并且根据优先级来确定开始执行的时间。显示待办事项我们在前面的模板中，待办任务前面都是以 TODO 开头，这里的TODO就是org 中待办事项的一个标识。我们可以通过 org-agenda 来查看相关的任务。打开该页面之后，它列举出了所有的支持的一些快捷键。例如使用 t 显示所有的待办事项，使用 m 来根据 PROP、TODO、TAGS 来查找任务。但是第一次使用时会发现自己兴冲冲的咔咔一顿添加任务，结果到头来通过 org-ageda 的 t 来列举之前添加的待办任务毛都没看到，顿时好奇兴奋的心情一下跌倒谷底。别着急这是因为我们没有告诉 org-agenda 该去哪里找这些待办事项。我们可以通过 org-agenda-files 来告诉org-agenda 这个信息就像名称显示的那样 org-agenda-files 是一个列表成员，我们指定它去这些文件中查找待办事项； (use-package org-agenda :ensure nil :custom (org-agenda-files (list "~/org/reading.org" "~/org/blog.org" "~/org/working.org")))这里我设置了三个 org 文档，这三个文档分别记录待读书目、需要完成的博客以及工作任务。需要注意的是我们需要这几个文件真实存在否则就会报错。设置好了这个变量之后效果如下:设定优先级列举出所有任务之后，针对每个任务我们可以考虑如何安排这些任务，首先需要的就是考虑给它从那四个维度安排一个优先级。上面说到我们可以使用A、B、C、D 做一个标识，这里我规定优先级的顺序是:A > B > C > D为了达到这个需求，首先我们要解决的是优先级的定义问题，因为Emacs默认只支持A/B/C这三种优先级，我需要它能支持4种。Emacs种有两个变量分别控制优先级最大值和优先级最小值，它们是 org-highest-priority 和 org-lowest-priority。另外还有一个变量可以设置默认的优先级 org-default-priority。理论上它可以设置优先级从A到Z，但是过多的优先级并不适合。我们可以在上面的 :custom 下使用下列的语句进行设置 (org-highest-priority ?A) (org-lowest-priority ?D) (org-default-priority ?D)设置完成之后可以使用 S-UP (Shift + 上箭头)或者 S-Down(Shift+下箭头)来调整优先级设置计划执行时间和结束时间安排好了优先级，我们就需要为每个任务安排时间了，这里可以安排计划开始时间和结束时间。开始时间和结束时间在 org agenda 中分别是命令 org-agenda-schedule 和 org-agenda-deadline。它们被绑定到了快捷键 C-c C-s 和 C-c C-d上面。当我们通过快捷键或者 M-x 调用这两个命令的时候，Emacs会弹出日历菜单供我们选择日期，默认提供了三个月的日期可供选择。如果不够的化，日历下方两个各有一个箭头可以向上或者向下再显示一个月。另外可以在下方 mini-buffer 处输入 +1d 这样的字符表示在当前时间的1天以后，根据这个规律我们可以输入 + 后面跟任意的数字，然后后面加 d/w/m/y 来表示天、周、月、年。设置任务属性和标签有些任务，特别是工作中的任务我们自己可能无法单独完成，例如某个bug需要前端或者后端一起完成又或者这个bug不光前端要改后端也需要改，这个时候我们修改完了自己的部分，这个时候可以显示我们将任务派发给了其他同事。又或者这个bug牵扯到其他bug，又或者有时候需要开会或者整理需求文档，这个时候我们需要记录该任务的场地例如对于会议可以记录一下在 D-01 会议室。这些可以通过设置属性和标签来描述这些信息。我个人认为它们二者在记录任务的额外信息时没有什么大的区别。主要区别在显示方面，标签一般于TODO 信息展示在一行，而属性默认是被折叠起来的，所以对于一些简要的信息，例如任务目前是谁在处理、开会的地点这类信息我习惯放置到标签上、而属性放置一些不那么重要的信息。对于标签，我们可以在设置任务时，在任务后面使用 :TAG1:TAG2: 这种方式添加多个标签。在前面介绍 org-capture 的文章中我给出了一个创建工作任务的模板 * TODO %^{任务描述} :%^{任务类型|dev|bugfix|env|doc|meeting}:\n SCHEDULED: %^t\n PRIORITY: %^{优先级|A|B|C|D}\n %?\n %i"。任务类型部分就是一个标签,这里我只设置了一个标签。我们可以事先使用 org-tag-alist 来规定一组标签以及打上这个标签所需要的快捷键。这个变量是一个列表类型，每个列表包含一个cell，cell的第一个元素是一个标签的名称，第二个元素是对应的快捷键。同时它也可以通过 :groupstart 和 :groupend 来定义一组互斥的标签项。例如针对任务我们可以定义如下的标签 (org-tag-alist `((:startgroup) ("dev" . ?d) ("bugfix" . ?B) ("env" . ?E) ("doc" . ?D) ("meeting" . ?M) ("reading" . ?R) (:endgroup) ("Sendto Tom" . ?T) ("Sendto Jerry" . ?J) ))需要注意这里标签过多的话，我们需要避免出现快捷键重复的情况。设置了标签，我们可以使用 C-c C-q属性是放到 :PROPERTIES: 下的一组键值对，默认情况下是被折叠的。属性相对于标签来说更加灵活，能显示的信息也更加多样化。我们可以使用 C-c C-x p 来设置属性设置子任务有时候一个大的任务分为几个小任务，例如某个bug可能包含几个方面的问题甚至需要不同组的开发人员进行协调。这个时候我们可以将一个任务分解为几个子任务org mode 中对于子任务的表现比较简单。子任务就是任务下的一个次级的 headline。我们可以在主任务后面加上 [/] 或者 [%] 来根据子任务的完成情况自动更新主任务的完成进度从上面的截图上看，关于子任务还有两个问题没有解决，首先在将任务状态由TODO 切换到DONE时，checkbox的状态应该是勾选的。第二个问题就是当所有的子任务都完成之后应该将主任务的状态改为done。这些我暂时没有找到好的解决方案，所以不展开说明了。任务状态切换上面我们看到可以通过 C-c C-t 来切换状态，但是我们只能在TODO|DONE之间进行切换。以我个人的习惯来说，我还需要几个关键字:WAIT: 等待，一般是任务完成需要等待其他人的配合，例如bug的产生可能是多个模块共同作用，需要等待其他人修改完ABORT：终止DOING: 正在执行这里我说的是关键字，但是它并不代表org todo 中任务实际的状态。事实上org todo中只有两种状态，TODO和DONE表示未完成和终结，我们无法在中间插入新的状态，能做的也只有在两种状态之间插入一些新的关键字。插入新的关键字可以通过设置变量 org-todo-keywords。根据Emacs的文档显示，org-todo-keywords 原始的值为 ((sequence "TODO" "DONE"))。因为这里需要一个有序列表，也就是说Emacs会保证状态切换时按照我们定义的顺序进行切换，并且切换到最后一个关键字时会认定任务已经处于终止状态，后续可以针对这个终止状态来进行一些操作。所以这里需要通过 sequence 函数来保证设置的是一个有序的列表这里我们针对终止状态设置了两个关键字DONE和ABORT，我们可以通过在中间插入 | 的方式告知Emacs，| 之前的关键字是未完成的状态，| 之后的是终止的状态。我们可以在 :custom 下加入 (org-todo-keywords '( (sequence "TODO(t)" "DOING(i)" "WAIT(w@/!)" "|" "DONE(d!)" "ABORT(a@)") ))) 这里后面括号中的字母表示可以在 C-c C-t 之后按字母快捷键快速选择状态，@表示需要由用户填写理由，例如针对等待的任务可以写明需要等待某个子模块修改完成。而后面的 !表示会插入一条包括时间戳的记录。至于 / 则是中间的一个分隔符现在它的效果如下:接入番茄工作法前面介绍了关于任务的定义和关键字的切换，现在我们的流程可能就变成了:通过 org-capture 收集任务将分析任务确定任务的优先级以及计划执行和结束时间通过org-agenda 查看当天需要执行的任务执行任务任务完成之后切换状态在执行任务的过程中我们可以采用番茄工作法来保证时间的高效利用。Emacs中可以嵌入有关番茄工作法的插件来做到。这里推荐使用 org-pomodoro 插件(use-package org-pomodoro :ensure t :custom (org-prmodoro-length 25) ;每个番茄钟25分钟 (org-pomodoro-short-break-length 5) ;; 短休5分钟 (org-pomodoro-long-break-length) ;; 长休15分钟 (每4个番茄钟之后) (org-pomodoro-play-sounds-t) ;; 启用提示音 )在使用时我们可以将鼠标放置到需要执行的任务上，然后执行命令 org-pomodoro。如果出现打扰的情况，例如有同事突然找到你，希望你提供帮助或者外卖电话到了要去拿外卖这个时候可以通过再次执行 org-pomodoro 停止计时。我们可以看到在番茄钟启动之后下方的 minibuffer 中有番茄钟的倒计时。到此为止，我们现在自建的任务管理系统已经可以到执行这步了，这个系统后续只剩下如何进行进行归档与回顾了。关于这部分将在下篇文章中给出我的一些实践，谢谢各位读者的关注
在日常的工作生活中有各种各样的琐事，如果不及时记录下来很可能后面就忘了。或者在日常软件开发中有很多想法想要实现但是时间一长自己就忘了。这种情况下我们需要一个系统来记录收集想法并且后续需要追踪甚至回顾。我们需要一套适合的管理系统让大脑摆脱待办事项的纠缠，让大脑专注于当前要做的事物。目前我采取的方式是GTD+ 番茄工作法。GTD 简介GTD（Getting Things Done），是由戴维·艾伦于2002年提出的时间管理方法。其核心在于通过收集、整理、组织、回顾、执行五个步骤，将任务从大脑中移出，减轻心理压力以提升效率，强调两分钟内可完成事项立即处理的原则。用我的理解，我们需要事先准备几个速记的笔记本，一旦脑海中出现了想法就将它记录下来，这步叫做收集。在一天中的空闲时间例如下班前或者睡觉前打开看看之前记录的内容，将内容按照一定的规则重新组织例如分为工作、生活、学习之类的想法，将它们转化成可以执行的任务。并且为每个事项定一个紧急程度，这个就是整理、组织。在每天开始的时候或者结束的时候可以根据上面的分类安排一下当前或者明天的任务，这个是执行任务。在每周或者每天的时候回忆一下当前的任务看看哪些完成了、哪些未完成、从任务中有何感想，有哪些可以记录下来作为重要的日志或者日后博客的灵感来源，这个就是最后的回顾总结过程。番茄工作法再完美的系统，如果不执行或者不认真执行也是白搭的。对我来说GTD主要解决的是要做哪些事，如何安排时间的问题。至于如何高效的执行任务专注到任务上，我采用的番茄工作法。番茄工作法的简单理解就是将任务的时间拆分成几个不可分割的最小单元，在这个时间片单元内一心一意、专心到任务上。一旦分心就需要终止当前番茄钟，并记录分心的原因，如果是有新来的新任务就需要采用记录的方式记录，如果是紧急且重要的任务可能还要修改当前的任务计划。当然番茄工作法有一整套的收集、整理、执行、归纳总结的流程，但是对我来说我喜欢GTD的流程和番茄工作法的时间管理方式，所以我采用的是它们二者的结合。但是主要用在工作中，日常生活中的场景都是一些简单的琐事，例如收拾卫生、做饭、对我来说不合适这种形式。org capture目前来说市面上没有完全符合我心目中最佳时间管理理论的工具，但是Emacs中的org 是十分强大的，完全可以稍加改造成符合自己心意的时间管理系统。首先要解决的就是如何收集想法的问题。这个功能可以使用 org-capture，顾名思义它就是使用org的格式来快速记录当前的想法。我们使用 org-capture 命令可以看到下面的界面下方提示我们可以使用前面的字母符号来选择一个模板，默认只提供了一个名为 Task 的模板。我们可以使用 org-capture 中 来实现GTD中的分类记录的功能。在我们选定需要使用的模板之后，Emacs会调用 org-capture-select-template 函数来选中模板并且根据模板来创建默认的org 模板。默认的Task 模板如下：("t" "Task" entry (file+headline "" "Tasks") "* TODO %?\n %u\n %a")它们的含义如下t 标识选择模板时的快捷键。Task 模板的描述，让用户了解当前模板作用的说明文字。后面一个部分就是新增的内容新增的内容比较复杂，我们一个个的说。第一个部分是新增模板的type。type 可以是下面的内容type描述entry带有 headline 的一个 Org mode 节点item一个列表项checkitem一个 checkbox 列表项table-line一个表格行plain普通文本type 的不同，后面跟的内容也不一样。例如如果当前是 entry 的话，后面需要添加 "* headline" 作为标题行的形式，如果是 item 后面需要跟上 - item 作为一个项。如果是 checkitem 需要跟 [ ] item 作为一个checkbox项。如果使用 table-line，需要跟 | colum 1 | colum 2 | colum3 | 作为一个表格项目。如果是 plain 则没有特殊要求。接下来看看 (file+headline "" "Tasks") 中各个部分的含义，前面的 file+headline 表示将记录的内容保存到哪个位置。除了这两个标识还有其他的一些常用标识标识含义file文件id某个特定id的headlinefile+headline某个文件中的某个headlinefile+olp文件中某个headline的路径file+regexp文件以及被正则匹配的headlinefile+datetree文件中当日所在的datetreefile+datetree+prompt文件中的datetree 会弹出日期选择file+weektree文件中当日所属的 weektreefile+weektree+prompt文件中 weektree 会弹出日期选择file+function文件中被函数匹配的headlineclock当前正在计时中的任务所在位置function自定义函数的所定义的位置后面两个参数根据前面的内容来决定，例如如果使用 file+headline 的话，第二个参数就是文件路径，第三个参数就是具体的 headline 的名称。如果文件名参数为空的话，那么会使用 org-default-notes-file 所对应的文件路径为 ~/.notes 这些内容如果觉得有些比较难以理解的，可以查看 org-capture-tempetes 变量的详细说明"* TODO %?\n %u\n %a" 部分都是一些格式字符串和占位符，在选中模板之后会自动生成我们想要的模板文字。这里的占位符如果写过代码应该很容易理解，首先占位符都是 以%开头，后面根据不同的字符表示不同的含义时间相关的占位符占位符含义%<>表示自定义时间的时间戳，两个<>之间可以使用字符表示不同的时间格式，例如 %<%Y-%m-%d> 表示年月日的格式，年是4位字符的形式%t当前仅包含日期的时间戳%T当前包含日期时间的时间戳%u包含当前未激活的时间戳%U表示当前未激活的包含日期时间的时间戳%^t类似于 %t，但是会弹出日历供用户选择%^T类似于%T，但是会弹出日期和时间供用户选择%^u与上面的类似%^U与上面类似这里所谓的激活，在Emacs的文档中使用的词是 interactive 我不知道翻译为激活是否准确。未激活的时间戳日后不会出现在 org-agenda 中，至于什么是 org-agenda 请继续往下看剪切板相关的占位符占位符含义%c当前 kill ring 中的第一条内容%x当前系统剪贴板中的内容%^C交互式地选择 kill ring 或剪贴板中的内容%^L类似 %^C，但是将选中的内容作为链接插入后面还有更多更复杂的占位符，但是目前来说我用不到那么多，也就不一一列举了，各位读者如果感兴趣可以查看 org-capture-templetes 来查阅更多类型的占位符，至于 %?它什么也不往文件里面添加，它会在模板文本添加成功后将光标移动到它所在位置，方便用于自己输入内容除此以外，它还支持自定义函数的形式来插入内容，它的形式为 %(sexp) 括号中间就是lisp函数，假设我们有一个 custom-placeholder 那么这里就可以写成 %(custom-placeholder) 有了这些内容我们就可以定义自己的各种任务的模板个人日常任务模板对我个人来说，日常任务主要有：阅读清单、博客计划、工作任务。下面我希望通过这三大类任务来定制一些模板阅读清单首先是阅读清单，阅读清单主要记录一些我通过各种渠道了解到的并计划在后续需要读的书。根据我之前读的《如何有效阅读一本书：超实用笔记读书法》 的说法，记录要读的书，可以记录下面几个内容:书名作者出版社其他(可以是ISBN号)如果只根据书名可能会有书名重复的现象，所以根据这几条信息就可以唯一确认一本书因为Emacs提供的默认模板我不太喜欢，所以这里我先使用 (setq org-capture-templates nil) 来清空模板，后续由我自己实现各种模板(use-package org-capture :ensure nil :custom (org-capture-templates nil) (org-capture-templates '(("r" "Reading List" entry (file+olp "~/org/reading.org" "Reading" "Book") "*** TODO 《%^{书名}》\n作者:%^{作者}\n出版社:%^{出版社}:\n备注:%^{备注}\n添加时间:%U\n" :clock-int t :clock-resume t))))我们按照之前分析的模板中各个部分的组成来看看它是什么意思。首先第一个部分，我们定义通过快捷键 r 来选中并生成这个模板，Reading List 表示在模板展示时显示的内容。后面的entry 表示我需要添加一个带有 headline 的 org mode 节点，它后面跟着的子列表里面使用 file+olp 表示我需要在文件中的某个headline 下添加这条记录作为它的子内容部分。后面跟的就是文件路径、以及需要插入到当前文件下Reading 里面的 Book 下，作为子节点。最后定义的就是具体的内容了, 因为Reading 作为一级标题，它下面的 Book 作为二级标题，所以这里添加的阅读清单记录就是三级标题，所以我在它前面加了一个 *** 作为三级标题。前面的TODO是关键词，表示待做。后面就是输入的常规的内容了，包括出版社、作者等信息。它的运行效果如下:新建博客文章org-mode实际上是支持转换成markdown并通过hugo之类的静态网站生成程序来生成博客的。对于hugo 来说如果希望将markdown格式的内容转化成博客，我们需要在markdown文件头位置加入这些内容title: "Test" date: categories: blog tags: blog draft: true根据这些信息我们可以很容易的搭建基础的模板。针对这种场景，我希望它能在固定的位置生成一个以时间命名的 .md文档，这个位置一般位于hugo安装目录下的 posts 目录下。我们可以写下这样的配置 (add-to-list 'org-capture-templates `("b" "Blog" plain (file ,(concat "~/org/" (format-time-string "%Y-%m-%d.md"))) ,(concat "---\n" "tile: %^{标题}\n" "date: %U\n" "categories: %^{分类}\n" "tags: %^{标签}\n" "draft: %^{草稿|true|false}\n" "---\n" "%?")))它的效果如下:最终在我们保存之后它会在~/org 目录下生成一个以时间命名的markdown文件这种模式我个人不太喜欢，因为对我而言org-capture 仅仅只是一个收集的动作，我们应该快速记录想要写的博客以及博客的主要论点，而不应该开始编写具体的内容。至于如何使用org-mode来写博客，后面我想单独写一篇博客来介绍创建工作计划作为一个程序员来说，日常工作总会与程序打交道，比如开发新功能、写接口文档、修改bug、搭建开发测试环境、开会等等。有时候需要一个人负责多个多个项目。对于工作任务我们还需要分一个轻重缓急，我一般习惯于将它们分为：重要且紧急、重要但不紧急、紧急但不重要、不重要不紧急。那么对于工作任务的需求就很明确了。首先任务可以归属到不同的项目中，日后可以根据任务进行筛选任务可以细分为开发新功能、修复bug、搭建环境、写文档、开会等等任务可以划分轻重缓急日后通过todolist可以看到任务的轻重缓急，目前使用重要且紧急、重要但不紧急、不重要但紧急、不紧急不重要我们采用下面的代码 (add-to-list 'org-capture-templates `("w" "Work Task" entry (file+headline "~/org/working.org" "Work") "* TODO %^{任务描述} :%^{任务类型|dev|bugfix|env|doc|meeting}:\n SCHEDULED: %^t\n PRIORITY: %^{优先级|A|B|C|D}\n %?\n %i")))它的效果如下:到目前为止，介绍了关于org capture的相关内容，并演示了如何利用capture 实现一个任务的捕捉功能。gtd 后面的流程还有任务的分配、执行、记录等等功能，这些内容将在后面介绍。感谢各位读者的支持