將Emacs Org mode用於GTD任務管理


上一篇日志中,我簡要介紹了如何圍繞Emacs Org mode構建個人任務管理系統的基本思路與方法。因為Org mode體系龐大、功能繁雜,本文僅以提綱契領的方式介紹不同環節在Org mode中的操作與實現。更為具體與精密的功能機制和實施細節以查閱Org mode參考手冊為宜。

定義任務狀態關鍵詞

變量org-todo-keywords用於指定可給任務賦予的狀態關鍵詞。該變量的值為一組序列(sequence)構成的列表。每一個序列以符號typesequence開頭,其后則是一組用於定義任務狀態關鍵詞的字符串。若這一組字符串中的某一個為豎線|,則在豎線前的所有字符串代表任務未結束的狀態,之后的則代表任務結束的狀態。若沒有豎線,則僅最后一個字符串代表任務結束的狀態,其之前所有的字符串都代表任務未結束的狀態。這樣的typesequence序列可以定義多個。但是對於一般的任務管理來說,只定義一個就足夠了。

此外,用戶可以在typesequence序列中的每個關鍵詞字符串末尾寫上一對括號,令其中包含一個字母。該字母便是對應關鍵詞的快捷方式。當用戶將光標置於某個任務條目上時,按下C-c C-t后並輸入快捷方式,可將任務直接設為指定的狀態。

我所使用的任務狀態關鍵詞設置如下:

 (setq org-todo-keywords
  '((sequence "TODO(t)" "ONGOING(o)" "MAYBE(m)" "WAIT(w)" "DELEGATED(d)" "|"
  "DONE(f)" "CANCELLED(c)" "STUCK(s)")))

任務組標簽

在Org mode中,當光標處於某個任務條目上時,按下快捷鍵C-c C-c,即可為該任務設置標簽。對於任務組,我會為其加上標簽TG予以識別。默認情況下,某一層級條目的標簽會被其所包含的所有子條目繼承。這樣一來,當想要通過搜索標簽TG來查看所有任務組時,具體的細節任務也會一並列出,干擾視線。為此,需要設置變量org-tags-exclude-from-inheritance,對TG標簽禁用繼承。

 (setq org-tags-exclude-from-inheritance '("TG"))

自定義日程視圖

自定義日程視圖簡介

Org mode中的日程視圖(Agenda view)具有強大的模式匹配與搜索能力。通過過濾用戶指定的任務狀態關鍵詞、標簽、時間戳以及自定義條件,可以生成幾乎可以滿足用戶任何需求的視圖。以數學的方式來講,這就相當於將整個復雜的任務體系投影到我們所關注的不同空間中,對任務進行多角度地審視與把握,從而使我們在做任務管理的時候達到理清思路、聚集重點、不放過任何細節的良好效果。

日程視圖的定義需要通過設置變量org-agenda-custom-commands來完成。該變量是一個列表,其中的每一項對應一個視圖設置。這個視圖設置的基本格式為:

 (key desc type match settings files)

各部分的含義如下:

  • key:當用戶執行org-agenda命令時,會彈出*Agenda Commands*緩沖區,其中包含了系統默認和用戶自定義的日程視圖。每個日程視圖均對應一個快捷字母。當用戶按下這個字母時,則可以進入到相應的視圖中查看。這里的key則代表快捷字母。

  • desc:日程視圖的說明。

  • type:日程視圖的類型,即用於定義將哪些類型的任務條目收錄到該視圖中。通常用到的類型有:

    • agenda:基於日或周的日程。

    • todo:包含有特定狀態關鍵詞的任務條目。

    • alltodo:所有處於未結束狀態的任務條目,即,狀態關鍵詞為org-todo-keywords設置中豎線之前的。

    • tags:包含指定標簽的條目。

  • match:用於指定與之前type對應的匹配條件。例如,當typetodo時,match若為"DONE",則匹配狀態關鍵詞為DONE的任務條目。如果沒有匹配條件需要定義,則這一項為空字符串。

  • settings:用於指定匹配時應滿足的一系列選項設置。settings的格式類似用於定義局部變量的let形式,即,

     ((option1 value1) (option2 value2) ...)

    常用的選項有:

    • org-agenda-skip-function:用於設定忽略條件的函數對象。

    • org-agenda-overriding-header:用於設定日程視圖的台頭提示信息。

    • org-agenda-files:這個變量的值是一個字符串列表,用於指定從哪些Org文件中提取信息。默認情況是從所有的Org文件中提取信息。

  • files:用於指定當執行了org-store-agenda-views命令后需要將日程視圖自動導出的文件。可以是HTML格式,也可以是純文本格式。這個功能非常方便:當用戶將所有的視圖都定義好后,可以定期地直接將其全部導出。既可以放在HTTP服務器上統一瀏覽,也可以在審閱后存檔,形成歷史記錄。

隨着日積月累,當用戶定義的日程視圖比較多時,管理起來就會較為混亂,同時可供綁定的字母快捷鍵也開始不夠用。為此,可以將功能、類別相似的視圖歸為一組。這個組視圖在org-agenda-custom-commands中的定義方式為:

 (Group-key . desc)

其中的Group-key為一個字母,指定了組的快捷鍵。

當組定義好了之后,隨后便可以定義組內的各個日程視圖。每個日程視圖的定義與前面所述相同,

 (Group-KeyView-Key desc type match settings files)

只是其key為兩個字母,第一個字母為Group-key,第二個字母View-key為日程視圖自己的快捷捷。當用戶執行org-agenda時,按下Group-key先進入組視圖,再按下View-key則進入到指定的日程視圖中。

有了以上對於Org mode中日程視圖的基本了解,下面便介紹一下我定義的幾種視圖及其配置。

默認日程視圖

該視圖基於Emacs Org默認的Agenda視圖,排除了那些僅包含時間戳但沒有TODO關鍵詞的條目。為此,需要定義一個排除函數tjh/org-agenda-skip-only-timestamp-entries

;; Skip entries which only have timestamp but no TODO keywords.
(defun tjh/org-agenda-skip-only-timestamp-entries ()
  (org-agenda-skip-entry-if 'nottodo 'any))

然后,定義總的默認視圖與各個項目自己的默認視圖。

(setq org-agenda-custom-commands
      '(
        ......
	;; Display general agenda for each project.
        ("A" . "Default agenda view")
        ("Aa" "Agenda for all projects"
         agenda ""
         ((org-agenda-skip-function 'tjh/org-agenda-skip-only-timestamp-entries)
          (org-agenda-overriding-header "Agenda for all projects: "))
         "/agenda/docs/orgs/org-html-exports/Agenda-All.html")
        ("Ab" "CloudSim"
         agenda ""
         ((org-agenda-skip-function 'tjh/org-agenda-skip-only-timestamp-entries)
          (org-agenda-overriding-header "Agenda for CloudSim: ")
          (org-agenda-files '("/agenda/docs/orgs/CloudSim.org")))
         "/agenda/docs/orgs/org-html-exports/Agenda-CloudSim.html")
        ("Ac" "Study"
         agenda ""
         ((org-agenda-skip-function 'tjh/org-agenda-skip-only-timestamp-entries)
          (org-agenda-overriding-header "Agenda for study: ")
          (org-agenda-files '("/agenda/docs/orgs/Math.org"
			      "/agenda/docs/orgs/Computer.org")))
         "/agenda/docs/orgs/org-html-exports/Agenda-Study.html")
        ("Ad" "Personal"
         agenda ""
         ((org-agenda-skip-function 'tjh/org-agenda-skip-only-timestamp-entries)
          (org-agenda-overriding-header "Agenda for personal affairs: ")
          (org-agenda-files '("/agenda/docs/orgs/Personal.org")))
         "/agenda/docs/orgs/org-html-exports/Agenda-Personal.html")
        ("Az" "2019-FOTO"
         agenda ""
         ((org-agenda-skip-function 'tjh/org-agenda-skip-only-timestamp-entries)
          (org-agenda-overriding-header "Agenda for 2019-FOTO: ")
          (org-agenda-files '("/agenda/docs/orgs/2019-FOTO.org")))
         "/agenda/docs/orgs/org-html-exports/Agenda-2019-FOTO.html")
        ("Ay" "Official"
         agenda ""
         ((org-agenda-skip-function 'tjh/org-agenda-skip-only-timestamp-entries)
          (org-agenda-overriding-header "Agenda for official affairs: ")
          (org-agenda-files '("/agenda/docs/orgs/Official.org")))
         "/agenda/docs/orgs/org-html-exports/Agenda-Official.html")
        ......
        ))

截止日期日程視圖

該視圖列出所有加了DEADLINE時間戳的任務。為此,需要事先定義一個函數tjh/org-agenda-skip-not-deadline-entries,用於忽略不包含DEADLINE時間戳的條目。

 ;; Skip entries which are not deadlines.
 (defun tjh/org-agenda-skip-not-deadline-entries ()
   (org-agenda-skip-entry-if 'notdeadline))

然后,定義總的截止日期視圖與各個項目自己的截止日期視圖。

 (setq org-agenda-custom-commands
      '(
         ......
         ;; Display all tasks with deadline.
         ("D" . "Agenda view for deadlines")
         ("Da" "Agenda view for all deadlines"
          agenda ""
          ((org-agenda-skip-function 'tjh/org-agenda-skip-not-deadline-entries)
           (org-agenda-overriding-header "All deadlines: "))
          "/agenda/docs/orgs/org-html-exports/Deadline-All.html")
         ("Dc" "Study"
          agenda ""
          ((org-agenda-skip-function 'tjh/org-agenda-skip-not-deadline-entries)
           (org-agenda-overriding-header "Deadlines for study: ")
           (org-agenda-files '("/agenda/docs/orgs/Math.org"
                       "/agenda/docs/orgs/Computer.org")))
          "/agenda/docs/orgs/org-html-exports/Deadline-Study.html")
         ("Dd" "Personal"
          agenda ""
          ((org-agenda-skip-function 'tjh/org-agenda-skip-not-deadline-entries)
           (org-agenda-overriding-header "Deadlines for personal affairs: ")
           (org-agenda-files '("/agenda/docs/orgs/Personal.org")))
          "/agenda/docs/orgs/org-html-exports/Deadline-Personal.html")
         ("Dy" "Official"
          agenda ""
          ((org-agenda-skip-function 'tjh/org-agenda-skip-not-deadline-entries)
           (org-agenda-overriding-header "Deadlines for official affairs: ")
           (org-agenda-files '("/agenda/docs/orgs/Official.org")))
          "/agenda/docs/orgs/org-html-exports/Deadline-Official.html")
         ......
         ))

已完成任務日程視圖

該視圖列出總的和各個項目的已完成任務視圖。為此,需要定義函數tjh/org-agenda-skip-unfinished-entries,用於忽略所有不包含DONE狀態關鍵詞的任務條目。

 ;; Skip entries which are not finished.
 (defun tjh/org-agenda-skip-unfinished-entries ()
   (org-agenda-skip-entry-if 'nottodo '("DONE")))

變量org-agenda-custom-commands中的對應設置如下:

 (setq org-agenda-custom-commands
      '(
         ......
         ;; Display all finished tasks.
         ("F" . "Agenda view for finished tasks")
         ("Fa" "Agenda view for all finished tasks"
          agenda ""
          ((org-agenda-skip-function 'tjh/org-agenda-skip-unfinished-entries)
           (org-agenda-overriding-header "All finished tasks: "))
          "/agenda/docs/orgs/org-html-exports/Done-All.html")
         ("Fc" "Study"
          agenda ""
          ((org-agenda-skip-function 'tjh/org-agenda-skip-unfinished-entries)
           (org-agenda-overriding-header "Finished tasks for study: ")
           (org-agenda-files '("/agenda/docs/orgs/Math.org"
                       "/agenda/docs/orgs/Computer.org")))
          "/agenda/docs/orgs/org-html-exports/Done-Study.html")
         ("Fd" "Personal"
          agenda ""
          ((org-agenda-skip-function 'tjh/org-agenda-skip-unfinished-entries)
           (org-agenda-overriding-header "Finished tasks for personal affairs: ")
           (org-agenda-files '("/agenda/docs/orgs/Personal.org")))
          "/agenda/docs/orgs/org-html-exports/Done-Personal.html")
         ("Fy" "Official"
          agenda ""
          ((org-agenda-skip-function 'tjh/org-agenda-skip-unfinished-entries)
           (org-agenda-overriding-header "Finished tasks for official affairs: ")
           (org-agenda-files '("/agenda/docs/orgs/Official.org")))
          "/agenda/docs/orgs/org-html-exports/Done-Official.html")
         ......
         ))

GTD流程

收集箱

通過列出所有尚未計划的任務條目,則可以構成GTD流程中的收集箱。為此,需要定義函數tjh/org-agenda-skip-scheduled-entries,用於忽略所有已經加了時間戳、狀態關鍵詞為ONGOINGWAITDELEGATED的任務條目。同時,包含了TG標簽的任務也被排除在外。這是因為任務組只是具體任務的容器,故不參與到實際任務的安排中。

 ;; Skip unscheduled entries.
 (defun tjh/org-agenda-skip-scheduled-entries ()
   (org-agenda-skip-entry-if 'timestamp
    'todo '("ONGOING" "WAIT" "DELEGATED")
    'regexp ":TG:"))

以下配置實現了總的與各個項目的收集箱。

 (setq org-agenda-custom-commands
      '(
         ......
         ;; Inbox for displaying unscheduled tasks.
         ("I" . "Inbox")
         ("Ia" "Inbox for all unfinished TODOs"
          alltodo ""
          ((org-agenda-skip-function 'tjh/org-agenda-skip-scheduled-entries)
           (org-agenda-overriding-header "Inbox items: "))
          "/agenda/docs/orgs/org-html-exports/Inbox-All.html")
         ("Ic" "Study"
          alltodo ""
          ((org-agenda-skip-function 'tjh/org-agenda-skip-scheduled-entries)
           (org-agenda-overriding-header "Inbox items for study: ")
           (org-agenda-files '("/agenda/docs/orgs/Math.org"
                       "/agenda/docs/orgs/Computer.org")))
          "/agenda/docs/orgs/org-html-exports/Inbox-Study.html")
         ("Id" "Personal"
          alltodo ""
          ((org-agenda-skip-function 'tjh/org-agenda-skip-scheduled-entries)
           (org-agenda-overriding-header "Inbox items for personal affairs: ")
           (org-agenda-files '("/agenda/docs/orgs/Personal.org")))
          "/agenda/docs/orgs/org-html-exports/Inbox-Personal.html")
         ("Iy" "Official"
          alltodo ""
          ((org-agenda-skip-function 'tjh/org-agenda-skip-scheduled-entries)
           (org-agenda-overriding-header "Inbox items for official affairs: ")
           (org-agenda-files '("/agenda/docs/orgs/Official.org")))
          "/agenda/docs/orgs/org-html-exports/Inbox-Official.html")
         ......
         ))

規划

Refile

使用org-refile命令(C-c C-w)可以將當前光標所在處的標題及其子樹移動到另一個更高一級的標題下。默認情況下,子樹會添加到這個新標題下的末尾。當然,也可以添加到最開始。這一點由變量org-reverse-note-order來控制。若執行C-u C-c C-w,則僅令光標跳轉到指定的更高一級標題處而不移動子樹。

設定時間戳

  • 使用C-c C-s為任務設置SCHEDULED時間,即,開始着手處理任務的那一天,但對於任務執行具體需要多少時間並不作明確要求。這一點也是符合GTD的基本思想的。

  • 使用C-c C-d為任務設置DEADLINE時間。

執行

估計執行任務所需時間

對於一個任務組及其包含的所有具體任務進行整體上的時間規划時,可以借助Org mode提供的列視圖功能。在任務組標題下定義屬性COLUMNS,用於指定列視圖中各列的內容、標題與寬度。例如,

 * TODO A big task to be handled.     :TG:
  :PROPERTIES:
  :COLUMNS: %75ITEM(Task) %8PRIORITY(Priority) %9TODO(Status) %8EFFORT(Effort){:} %16SCHEDULED %16DEADLINE
  :END:

其中,Effort列后的{:}用於指定對各行子任務的Effort進行求和。

然后,在任務組下定義各個具體任務。

 * TODO A big task to be handled.     :TG:
  :PROPERTIES:
  :COLUMNS: %75ITEM(Task) %8PRIORITY(Priority) %9TODO(Status) %8EFFORT(Effort){:} %16SCHEDULED %16DEADLINE
  :END:
 ** TODO [#A] Task 1
 ** TODO [#C] Task 2
 ** TODO [#B] Task 3

之后,按C-c C-x C-c進入列視圖模式進行規划,如圖1所示。

圖1 在列視圖模式下估計任務的執行時間。

任務列表視圖的保存與導出

C-c C-x C-c得到的列視圖模式只是暫時地顯示於Emacs的緩沖區而無法永久保存。為了保存列視圖並導出,按C-c C-x i執行org-insert-columns-dblock命令。隨后Emacs提示需要為什么范圍的任務節點生成列視圖。對此,有如下模式可供選擇:

  • local:對光標所在節點及子樹生成視圖。
  • global:對整個文件中的標題節點生成視圖。
  • file:FILENAME:對指定文件生成視圖。
  • LABEL:對光標所在節點及子樹中ID屬性值為LABEL的節點生成視圖。

一般來說,使用local選項對指定的任務組生成列視圖就足夠了。

回車確認后,則會在指定位置處插入dynamic block,如下所示:

* TODO [#A] Task planning for official project :TG:
  :PROPERTIES:
  :COLUMNS:  %70ITEM(Task) %8TAGS(Tags) %2PRIORITY(Priority) %9TODO(Status) %8EFFORT(Effort){:} %16SCHEDULED %16DEADLINE
  :END:
** Column view
#+BEGIN: columnview :hlines 1 :id local
| Task                                                  | Tags         | Priority | Status    | SCHEDULED        | DEADLINE         |
|-------------------------------------------------------+--------------+----------+-----------+------------------+------------------|
| Information scouting                                  | :TG:         |          | DONE      |                  |                  |
| Paper survey about segmentation using active contours |              | B        | DONE      | <2019-05-29 Wed> | <2019-05-30 Thu> |
| Theoretical derivation                                | :TG:         |          | TODO      |                  |                  |
| Derivation of existence and uniqueness theorems       |              | A        | TODO      | <2019-06-03 Mon> | <2019-06-04 Tue> |
...
#+END:

注意,由於上述生成的列表視圖包含了時間戳,如果直接將其放在標題節點“Task planning for official project :TG:”下,則會在默認的日程視圖中的相應日期處加入這個條目,而這是我們所不希望的。為此,需要創建一個不包含TODO關鍵詞的子節點,然后將列表視圖的內容放在它的下面。之后,自定義的默認日程視圖會調用函數tjh/org-agenda-skip-only-timestamp-entries將該條目忽略。

之后,如果節點內容有所變動,按C-c C-cC-c C-x C-u執行org-dblock-update更新上述dynamic block。這樣,列視圖就可以隨org文件一起保存下來。

選中上述內容,按C-c C-e則可以將其導出為不同的格式。目前,由於Windows Cygwin下的htmlize功能有問題,我傾向於導出為odt格式。之后,可以將odt文件中的表格拷貝到Calc中,作進一步的格式美化,如圖2所示。

圖2 在LibreOffice Calc中美化任務列表。

統計實際任務執行時間

在開始某項任務時,將光標放到該任務條目上,按快捷鍵C-c C-x C-i執行org-clock-in命令,即可對該任務進行計時。停止工作時,再按C-c C-x C-o執行org-clock-out命令,結束對該任務的計時。為了匯總顯示執行各任務所花費的時間,按C-c C-x C-r執行org-clock-report命令,可對光標當前所在處的任務子樹或者整個Org文件生成時間統計報告。

結語

本文概要地介紹了我在Emacs Org mode中進行GTD任務管理的具體操作與基本配置。然而這只是一個起點,還需要在實際的學習與研究中將這一套方法和流程反復使用、長期練習,才能夠發揮其應有的效力。同時,也需要不斷地積累關於任務管理和Org mode的相關知識,從而能夠對這套方法和流程持續地改進、更新。最后,需要始終牢記的一點是,任務管理的關鍵不在於工具與技術,甚至都不在於管理方法和思想,而在於有效執行和有實質性的產出。這也正是任務管理的最終目的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM