本文翻译自 http://doc.norang.ca/org-mode.html ,原文作者为Bernt Hansen 。由于原文较长,因此会分多篇文章来发布。转载请标记出处。
提高生产力工具
这章主要是一系列我的org-mode中使用的emacs定制化的集合。
Abbrev-mode以及Skeletons
我在Abbrev-mode中使用skeletons,可以快速在我的emacs缓冲区添加预定义代码块。
我需要创建如下一些代码块:
- org-mode中的通用代码块
- org-mode中的plantuml块
- plantuml活动图的代码块
- plantuml序列图的代码块
- org-mode中graphviz dot代码块
- ditta代码块
- org-mode中elisp代码块
我用依然用 < e TAB
或者 < s TAB
创建用例代码块以及shell脚本代码块。
这是我当前org-mode关联的设置。每个相关代码块都定义一个abbrev-mode快捷键,
因此我可以输入 splantuml RET
来创建一个plantuml代码块。同时弹出文件名
来命名生成的图像。
工作中生成代码块的同时也会为其添加 :tangle
头,这样代码块中就可以包含
@startuml
以及 @enduml
。因此我可以使用tangle功能,生成新文件,并分享
给同事。这样,新文件就可以在notepad以及 plantUML
jar单独运行。
我使用 s
快捷键阻止abbrev-mode生效,防止在一个句子中输入plantuml时候被当
做要插入 PlantUML
代码块。
为在活动视图中方便使用方便,我添加了 sif
以及 sfor
用来生成if判断以及for
循环。
;; Enable abbrev-mode
(add-hook 'org-mode-hook (lambda () (abbrev-mode 1)))
;; Skeletons
;;
;; sblk - Generic block #+begin_FOO .. #+end_FOO
(define-skeleton skel-org-block
"Insert an org block, querying for type."
"Type: "
"#+begin_" str "\n"
_ - \n
"#+end_" str "\n")
(define-abbrev org-mode-abbrev-table "sblk" "" 'skel-org-block)
;; splantuml - PlantUML Source block
(define-skeleton skel-org-block-plantuml
"Insert a org plantuml block, querying for filename."
"File (no extension): "
"#+begin_src plantuml :file " str ".png :cache yes\n"
_ - \n
"#+end_src\n")
(define-abbrev org-mode-abbrev-table "splantuml" "" 'skel-org-block-plantuml)
(define-skeleton skel-org-block-plantuml-activity
"Insert a org plantuml block, querying for filename."
"File (no extension): "
"#+begin_src plantuml :file " str "-act.png :cache yes :tangle " str "-act.txt\n"
(bh/plantuml-reset-counters)
"@startuml\n"
"skinparam activity {\n"
"BackgroundColor<<New>> Cyan\n"
"}\n\n"
"title " str " - \n"
"note left: " str "\n"
"(*) --> \"" str "\"\n"
"--> (*)\n"
_ - \n
"@enduml\n"
"#+end_src\n")
(defvar bh/plantuml-if-count 0)
(defun bh/plantuml-if ()
(incf bh/plantuml-if-count)
(number-to-string bh/plantuml-if-count))
(defvar bh/plantuml-loop-count 0)
(defun bh/plantuml-loop ()
(incf bh/plantuml-loop-count)
(number-to-string bh/plantuml-loop-count))
(defun bh/plantuml-reset-counters ()
(setq bh/plantuml-if-count 0
bh/plantuml-loop-count 0)
"")
(define-abbrev org-mode-abbrev-table "sact" "" 'skel-org-block-plantuml-activity)
(define-skeleton skel-org-block-plantuml-activity-if
"Insert a org plantuml block activity if statement"
""
"if \"\" then\n"
" -> [condition] ==IF" (setq ifn (bh/plantuml-if)) "==\n"
" --> ==IF" ifn "M1==\n"
" -left-> ==IF" ifn "M2==\n"
"else\n"
"end if\n"
"--> ==IF" ifn "M2==")
(define-abbrev org-mode-abbrev-table "sif" "" 'skel-org-block-plantuml-activity-if)
(define-skeleton skel-org-block-plantuml-activity-for
"Insert a org plantuml block activity for statement"
"Loop for each: "
"--> ==LOOP" (setq loopn (bh/plantuml-loop)) "==\n"
"note left: Loop" loopn ": For each " str "\n"
"--> ==ENDLOOP" loopn "==\n"
"note left: Loop" loopn ": End for each " str "\n" )
(define-abbrev org-mode-abbrev-table "sfor" "" 'skel-org-block-plantuml-activity-for)
(define-skeleton skel-org-block-plantuml-sequence
"Insert a org plantuml activity diagram block, querying for filename."
"File appends (no extension): "
"#+begin_src plantuml :file " str "-seq.png :cache yes :tangle " str "-seq.txt\n"
"@startuml\n"
"title " str " - \n"
"actor CSR as \"Customer Service Representative\"\n"
"participant CSMO as \"CSM Online\"\n"
"participant CSMU as \"CSM Unix\"\n"
"participant NRIS\n"
"actor Customer"
_ - \n
"@enduml\n"
"#+end_src\n")
(define-abbrev org-mode-abbrev-table "sseq" "" 'skel-org-block-plantuml-sequence)
;; sdot - Graphviz DOT block
(define-skeleton skel-org-block-dot
"Insert a org graphviz dot block, querying for filename."
"File (no extension): "
"#+begin_src dot :file " str ".png :cache yes :cmdline -Kdot -Tpng\n"
"graph G {\n"
_ - \n
"}\n"
"#+end_src\n")
(define-abbrev org-mode-abbrev-table "sdot" "" 'skel-org-block-dot)
;; sditaa - Ditaa source block
(define-skeleton skel-org-block-ditaa
"Insert a org ditaa block, querying for filename."
"File (no extension): "
"#+begin_src ditaa :file " str ".png :cache yes\n"
_ - \n
"#+end_src\n")
(define-abbrev org-mode-abbrev-table "sditaa" "" 'skel-org-block-ditaa)
;; selisp - Emacs Lisp source block
(define-skeleton skel-org-block-elisp
"Insert a org emacs-lisp block"
""
"#+begin_src emacs-lisp\n"
_ - \n
"#+end_src\n")
(define-abbrev org-mode-abbrev-table "selisp" "" 'skel-org-block-elisp)
我在工作中做备忘,依然会使用abbrev-mode。我写了第一个人名后就可以展开成完整的名字。 因此
当我写了 mickey
就会自动展开成 Mickey Mouse
. 为创建缩写,只要输入快捷键
C-x a i l
来创建当前模式的缩写。
你所要做的就是,不要使用通用的单词,来作为你的缩写,因为abbrev-mode会自动扩展所有你写入的。
我发现当我输入 plantuml
就会碰到这个问题,非常讨厌。
我同样在c源代码中使用abbrev-mode。这个非常适合我。
PlantUml 活动图生成示例
当需要创建活动图时,我会用 sif
以及 sfor
添加IF以及FOR代码块,并产生自动唯一的id。
例如: 创建一个包含两个IFs以及两个FOR代码块的活动图。
创建图标: “sact RET test RET”
示例
@startuml
skinparam activity {
BackgroundColor<<New>> Cyan
}
title test -
note left: test
(*) --> "test"
--> (*)
@enduml
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HRrvNC0N-1645013712028)(test-act.png)]
将光标移动到–>(*)然后输入 “sif RET”
示例
@startuml
skinparam activity {
BackgroundColor<<New>> Cyan
}
title test -
note left: test
(*) --> "test"
if "" then
-> [condition] ==IF1==
--> ==IF1M1==
-left-> ==IF1M2==
else
end if
--> ==IF1M2==
--> (*)
@enduml
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DR4F3H4D-1645013712030)(test-act2.png)]
(*)行重复执行
示例
@startuml
skinparam activity {
BackgroundColor<<New>> Cyan
}
title test -
note left: test
(*) --> "test"
if "" then
-> [condition] ==IF1==
--> ==IF1M1==
-left-> ==IF1M2==
else
end if
--> ==IF1M2==
if "" then
-> [condition] ==IF2==
--> ==IF2M1==
-left-> ==IF2M2==
else
end if
--> ==IF2M2==
--> (*)
@enduml
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m0axEdOn-1645013712030)(test-act3.png)]
通过“sfor RET line in file RET”以及"sfor RET address in addressbook RET",添加了两个for循环.
示例
@startuml
skinparam activity {
BackgroundColor<<New>> Cyan
}
title test -
note left: test
(*) --> "test"
if "" then
-> [condition] ==IF1==
--> ==IF1M1==
-left-> ==IF1M2==
else
end if
--> ==IF1M2==
if "" then
-> [condition] ==IF2==
--> ==IF2M1==
-left-> ==IF2M2==
else
end if
--> ==IF2M2==
--> ==LOOP1==
note left: Loop1: For each line in file
--> ==ENDLOOP1==
note left: Loop1: End for each line in file
--> ==LOOP2==
note left: Loop2: For each address in addressbook
--> ==ENDLOOP2==
note left: Loop2: End for each address in addressbook
--> (*)
@enduml
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DNcIzvd2-1645013712031)(test-act4.png)]
当需要调整对齐时候,我会使用列编辑模式来处理。
聚焦当前工作
有多种方式可以达到这个要求,选择合适自己的方式就行。
执行 bh/org-todo
限制子任务树显示
将=f5= 以及 s-f5
分别绑定到限制显示范围以及恢复显示范围功能上。
我就可以这样使用:
- T (任务)C-c / t 在当前缓冲区
- N (限制)只显示该任务子树
- U (向上)显示父任务子树
- P (项目)显示父项目的子任务树
- F (文件)只显示当前文件以及文件限制
但是agenda视图依然保持显示所有缓冲区任务,这方便聚焦我们在做的事情上。
(global-set-key (kbd "<f5>") 'bh/org-todo)
(defun bh/org-todo (arg)
(interactive "p")
(if (equal arg 4)
(save-restriction
(bh/narrow-to-org-subtree)
(org-show-todo-tree nil))
(bh/narrow-to-org-subtree)
(org-show-todo-tree nil)))
(global-set-key (kbd "<S-f5>") 'bh/widen)
(defun bh/widen ()
(interactive)
(if (equal major-mode 'org-agenda-mode)
(progn
(org-agenda-remove-restriction-lock)
(when org-agenda-sticky
(org-agenda-redo)))
(widen)))
(add-hook 'org-agenda-mode-hook
'(lambda () (org-defkey org-agenda-mode-map "W" (lambda () (interactive) (setq bh/hide-scheduled-and-waiting-next-tasks t) (bh/widen))))
'append)
(defun bh/restrict-to-file-or-follow (arg)
"Set agenda restriction to 'file or with argument invoke follow mode.
I don't use follow mode very often but I restrict to file all the time
so change the default 'F' binding in the agenda to allow both"
(interactive "p")
(if (equal arg 4)
(org-agenda-follow-mode)
(widen)
(bh/set-agenda-restriction-lock 4)
(org-agenda-redo)
(beginning-of-buffer)))
(add-hook 'org-agenda-mode-hook
'(lambda () (org-defkey org-agenda-mode-map "F" 'bh/restrict-to-file-or-follow))
'append)
(defun bh/narrow-to-org-subtree ()
(widen)
(org-narrow-to-subtree)
(save-restriction
(org-agenda-set-restriction-lock)))
(defun bh/narrow-to-subtree ()
(interactive)
(if (equal major-mode 'org-agenda-mode)
(progn
(org-with-point-at (org-get-at-bol 'org-hd-marker)
(bh/narrow-to-org-subtree))
(when org-agenda-sticky
(org-agenda-redo)))
(bh/narrow-to-org-subtree)))
(add-hook 'org-agenda-mode-hook
'(lambda () (org-defkey org-agenda-mode-map "N" 'bh/narrow-to-subtree))
'append)
(defun bh/narrow-up-one-org-level ()
(widen)
(save-excursion
(outline-up-heading 1 'invisible-ok)
(bh/narrow-to-org-subtree)))
(defun bh/get-pom-from-agenda-restriction-or-point ()
(or (and (marker-position org-agenda-restrict-begin) org-agenda-restrict-begin)
(org-get-at-bol 'org-hd-marker)
(and (equal major-mode 'org-mode) (point))
org-clock-marker))
(defun bh/narrow-up-one-level ()
(interactive)
(if (equal major-mode 'org-agenda-mode)
(progn
(org-with-point-at (bh/get-pom-from-agenda-restriction-or-point)
(bh/narrow-up-one-org-level))
(org-agenda-redo))
(bh/narrow-up-one-org-level)))
(add-hook 'org-agenda-mode-hook
'(lambda () (org-defkey org-agenda-mode-map "U" 'bh/narrow-up-one-level))
'append)
(defun bh/narrow-to-org-project ()
(widen)
(save-excursion
(bh/find-project-task)
(bh/narrow-to-org-subtree)))
(defun bh/narrow-to-project ()
(interactive)
(if (equal major-mode 'org-agenda-mode)
(progn
(org-with-point-at (bh/get-pom-from-agenda-restriction-or-point)
(bh/narrow-to-org-project)
(save-excursion
(bh/find-project-task)
(org-agenda-set-restriction-lock)))
(org-agenda-redo)
(beginning-of-buffer))
(bh/narrow-to-org-project)
(save-restriction
(org-agenda-set-restriction-lock))))
(add-hook 'org-agenda-mode-hook
'(lambda () (org-defkey org-agenda-mode-map "P" 'bh/narrow-to-project))
'append)
(defvar bh/project-list nil)
(defun bh/view-next-project ()
(interactive)
(let (num-project-left current-project)
(unless (marker-position org-agenda-restrict-begin)
(goto-char (point-min))
; Clear all of the existing markers on the list
(while bh/project-list
(set-marker (pop bh/project-list) nil))
(re-search-forward "Tasks to Refile")
(forward-visible-line 1))
; Build a new project marker list
(unless bh/project-list
(while (< (point) (point-max))
(while (and (< (point) (point-max))
(or (not (org-get-at-bol 'org-hd-marker))
(org-with-point-at (org-get-at-bol 'org-hd-marker)
(or (not (bh/is-project-p))
(bh/is-project-subtree-p)))))
(forward-visible-line 1))
(when (< (point) (point-max))
(add-to-list 'bh/project-list (copy-marker (org-get-at-bol 'org-hd-marker)) 'append))
(forward-visible-line 1)))
; Pop off the first marker on the list and display
(setq current-project (pop bh/project-list))
(when current-project
(org-with-point-at current-project
(setq bh/hide-scheduled-and-waiting-next-tasks nil)
(bh/narrow-to-project))
; Remove the marker
(setq current-project nil)
(org-agenda-redo)
(beginning-of-buffer)
(setq num-projects-left (length bh/project-list))
(if (> num-projects-left 0)
(message "%s projects left to view" num-projects-left)
(beginning-of-buffer)
(setq bh/hide-scheduled-and-waiting-next-tasks t)
(error "All projects viewed.")))))
(add-hook 'org-agenda-mode-hook
'(lambda () (org-defkey org-agenda-mode-map "V" 'bh/view-next-project))
'append)
这些辅助函数,通过限制显示范围,方便临时隐藏org文件中细节。任务通过折叠高亮
等方式显示未完成的任务。
我每天执行很多 f5
(或者 T
快捷键)。它主要做的事情就是 org-narrow-to-subtree
以及
C-c / t
结合保证缓冲区不要显示太多不必要的任务。我使用 S-f5=(或者像 =U
W
F
之类
的快捷键)来切换到正常显示状态。
在agenda限制任务子树显示
C-c C-x <
开启子树agenda限制。这样agenda视图只显示当前子树。但是隐藏任务相关的
警告以及通知设置,在agenda之外依然正常工作。通过快捷键 C-c C-x >
关闭agenda限制
,让agenda正常显示所有任务。
(add-hook 'org-agenda-mode-hook
'(lambda () (org-defkey org-agenda-mode-map "\C-c\C-x<" 'bh/set-agenda-restriction-lock))
'append)
(defun bh/set-agenda-restriction-lock (arg)
"Set restriction lock to current task subtree or file if prefix is specified"
(interactive "p")
(let* ((pom (bh/get-pom-from-agenda-restriction-or-point))
(tags (org-with-point-at pom (org-get-tags-at))))
(let ((restriction-type (if (equal arg 4) 'file 'subtree)))
(save-restriction
(cond
((and (equal major-mode 'org-agenda-mode) pom)
(org-with-point-at pom
(org-agenda-set-restriction-lock restriction-type))
(org-agenda-redo))
((and (equal major-mode 'org-mode) (org-before-first-heading-p))
(org-agenda-set-restriction-lock 'file))
(pom
(org-with-point-at pom
(org-agenda-set-restriction-lock restriction-type))))))))
这允许我从agenda直接限制任务显示,我通常在agenda里边做很多工作,这样就非常方便。
与自动移到项目最上层任务比较 限制任务显示就显得不够惊喜了– 我曾经就是这么做的。
如果当前项目显示有限,需要向上查看,先移动到上面,再做限制。
往往一个项目有很多任务在里边,限制显示一个项目也会有很多要显示的,所以我想限制只
显示其中一个子树。这就是为什么我保留 N
以及 U
来调整显示区域。
我为agenda视图以及org-buffer添加了其他的新的快捷键来控制子树,父任务以及项目任务,当然也
包含相应的取消限制的快捷键。这些快捷键既适合在agenda中也适合在org 文件中使用。
-
N
限制显示当前任务子树
功能和C-c C-x <
一致 -
U
将限制扩展到该子树对应的父任务
该功能对父子树做限制 -
P
限制整个任务所对应的项目
将会向上找到最上层TODO
关键字选择整个子树限制显示 -
W
取消限制,显示原样;; Limit restriction lock highlighting to the headline only
(setq org-agenda-restriction-lock-highlight-subtree nil)
限制agenda只显示一个文件
你也可以只让agenda显示单个文件的视图,当然有多种方法可以做到这点。
可以在第一个标题行前的任意行使用agenda的限制快捷键 C-c C-x <
来限制agenda视图
只显示当前文件视图。这相当于使用前置参数( C-u C-c C-x <
)。这种限制一直有效,
如果需要取消,需要执行 = C-c C-x >=.
同样,在agenda中执行 C-u C-c c-x <
也可以达到这个效果。
另一种方法是通过 F12 < a
在org 文件中启动agenda视图。这就会让agenda只显示
该文件内容。我通常会对非 org-agenda-files
变量定义的文件会通过这种方法查看
agenda视图。
agenda视图开启
有很多定制化agenda视图方法来显示任务细节。这个章节会介绍我的工作流中使用到的
一些定制化。
高亮显示当前agenda行
下面的代码来自我的 .emacs
文件,高亮显示当前的agenda行。这会让该任务高亮显示,
这样就不会选错任务,从而导致对错的任务执行操作。
模式行中计时信息也会反向背景显示。
;; Always hilight the current agenda line
(add-hook 'org-agenda-mode-hook
'(lambda () (hl-line-mode 1))
'append)
;; The following custom-set-faces create the highlights
(custom-set-faces
;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(org-mode-line-clock ((t (:background "grey75" :foreground "red" :box (:line-width -1 :style released-button)))) t))
在全局todo列表中显示时间戳
带(=SCHEDULED:= DEADLINE:
以及其他日期)在agenda中能够合理显示出来。agenda
视图(=F12 a=)只会让任务在一个地方显示(要么在日历中,要么在其他的agenda列表显示)。
我现在很少在org-mode使用全局列表查找(F12 t
, F12 m
)。只有需要找特定任务时候,我才会
这么做。现在该列表包含 所有 , 因此我能够找到我想要的任务。
agenda中不会显示那些截止日期以及计划在将来发生的任务,因此你能够先忽略他们,直到合适
时候他们才会出现在agenda列表中。
;; Keep tasks with dates on the global todo lists
(setq org-agenda-todo-ignore-with-date nil)
;; Keep tasks with deadlines on the global todo lists
(setq org-agenda-todo-ignore-deadlines nil)
;; Keep tasks with scheduled dates on the global todo lists
(setq org-agenda-todo-ignore-scheduled nil)
;; Keep tasks with timestamps on the global todo lists
(setq org-agenda-todo-ignore-timestamp nil)
;; Remove completed deadline tasks from the agenda view
(setq org-agenda-skip-deadline-if-done t)
;; Remove completed scheduled tasks from the agenda view
(setq org-agenda-skip-scheduled-if-done t)
;; Remove completed items from search results
(setq org-agenda-skip-timestamp-if-done t)
使用日记来记录假期以及纪念日
我并不用emacs日记来记录所有事情, 但是我还是希望能在我的agenda中查看到节日信息。
这能方便我在不需要工作时候(节假日),做合适的计划。
(setq org-agenda-include-diary nil)
(setq org-agenda-diary-file "~/git/org/diary.org")
日记文件包含着由capture mode创建的约会模板生成的 时间树
项。我也会用它记录一些突发的
需要计时的任务。
我不用 ~/diary
文件。只保留一个空文件,为了使得emacs能正常工作。我使用org-mode的
日记。在agenda视图中通过 i
来创建一个日期项,并同步到 ~/git/org/diary.org
文件中。
我将日历中的节假日导入我的 todo.org
,文件格式如下:
#+FILETAGS: PERSONAL
* Appointments
:PROPERTIES:
:CATEGORY: Appt
:ARCHIVE: %s_archive::* Appointments
:END:
** Holidays
:PROPERTIES:
:Category: Holiday
:END:
%%(org-calendar-holiday)
** Some other Appointment
...
我使用下面的设置使得agenda可以正常显示日志时间。
(setq org-agenda-insert-diary-extract-time t)
包含归档文件查找
我只用一个归档文件用来归档我所有的org-mode相关的项目文件。这样当我需要查一些信息时,
可以既查看当前文件也可以查看归档文件,方便我从归档文件中找到想要的信息。
这个功能我并不常用,但是有备无患,如果哪天需要,我还是可以立马能使用。
;; Include agenda archive files when searching for things
(setq org-agenda-text-search-extra-files (quote (agenda-archives)))
agenda视图调整
下面列举的是agenda视图需要定制化的地方:
- 显示重复的任务
- 在agenda中显示空日期
- 调整任务排序
- agenda周视图以周日开始
- 显示网格
- 在底部显示习惯
我定制化了排序函数,通过该函数,agenda中任务都是按照重要性来排序的。每日agenda视图
按照如下顺序排序:
- 有时间戳的在前面显示,因此就不会忽略这些任务了
- 今日的任务(带时间戳的活跃任务,但并不包含计划任务或者截止任务)
- 今日截止任务
- 后续截止任务
- 今日计划任务
- 待定的有截止日期的任务(很快可能要处理)
- 后续计划条目
- 习惯
这个排序算法可能并不特比完美,但是能够正常工作。
下面是在我 .emacs
中的相关配置:
;; Show all future entries for repeating tasks
(setq org-agenda-repeating-timestamp-show-all t)
;; Show all agenda dates - even if they are empty
(setq org-agenda-show-all-dates t)
;; Sorting order for tasks on the agenda
(setq org-agenda-sorting-strategy
(quote ((agenda habit-down time-up user-defined-up effort-up category-keep)
(todo category-up effort-up)
(tags category-up effort-up)
(search category-up))))
;; Start the weekly agenda on Monday
(setq org-agenda-start-on-weekday 1)
;; Enable display of the time grid so we can see the marker for the current time
(setq org-agenda-time-grid (quote ((daily today remove-match)
#("----------------" 0 16 (org-heading t))
(0900 1100 1300 1500 1700))))
;; Display tags farther right
(setq org-agenda-tags-column -102)
;;
;; Agenda sorting functions
;;
(setq org-agenda-cmp-user-defined 'bh/agenda-sort)
(defun bh/agenda-sort (a b)
"Sorting strategy for agenda items.
Late deadlines first, then scheduled, then non-late deadlines"
(let (result num-a num-b)
(cond
; time specific items are already sorted first by org-agenda-sorting-strategy
; non-deadline and non-scheduled items next
((bh/agenda-sort-test 'bh/is-not-scheduled-or-deadline a b))
; deadlines for today next
((bh/agenda-sort-test 'bh/is-due-deadline a b))
; late deadlines next
((bh/agenda-sort-test-num 'bh/is-late-deadline '> a b))
; scheduled items for today next
((bh/agenda-sort-test 'bh/is-scheduled-today a b))
; late scheduled items next
((bh/agenda-sort-test-num 'bh/is-scheduled-late '> a b))
; pending deadlines last
((bh/agenda-sort-test-num 'bh/is-pending-deadline '< a b))
; finally default to unsorted
(t (setq result nil)))
result))
(defmacro bh/agenda-sort-test (fn a b)
"Test for agenda sort"
`(cond
; if both match leave them unsorted
((and (apply ,fn (list ,a))
(apply ,fn (list ,b)))
(setq result nil))
; if a matches put a first
((apply ,fn (list ,a))
(setq result -1))
; otherwise if b matches put b first
((apply ,fn (list ,b))
(setq result 1))
; if none match leave them unsorted
(t nil)))
(defmacro bh/agenda-sort-test-num (fn compfn a b)
`(cond
((apply ,fn (list ,a))
(setq num-a (string-to-number (match-string 1 ,a)))
(if (apply ,fn (list ,b))
(progn
(setq num-b (string-to-number (match-string 1 ,b)))
(setq result (if (apply ,compfn (list num-a num-b))
-1
1)))
(setq result -1)))
((apply ,fn (list ,b))
(setq result 1))
(t nil)))
(defun bh/is-not-scheduled-or-deadline (date-str)
(and (not (bh/is-deadline date-str))
(not (bh/is-scheduled date-str))))
(defun bh/is-due-deadline (date-str)
(string-match "Deadline:" date-str))
(defun bh/is-late-deadline (date-str)
(string-match "\\([0-9]*\\) d\. ago:" date-str))
(defun bh/is-pending-deadline (date-str)
(string-match "In \\([^-]*\\)d\.:" date-str))
(defun bh/is-deadline (date-str)
(or (bh/is-due-deadline date-str)
(bh/is-late-deadline date-str)
(bh/is-pending-deadline date-str)))
(defun bh/is-scheduled (date-str)
(or (bh/is-scheduled-today date-str)
(bh/is-scheduled-late date-str)))
(defun bh/is-scheduled-today (date-str)
(string-match "Scheduled:" date-str))
(defun bh/is-scheduled-late (date-str)
(string-match "Sched\.\\(.*\\)x:" date-str))
便利贴式的agenda
便利贴式的agenda允许你同时创建不止一个agenda视图。你可以快速切换到该视图而不需要额外的通过
agenda命令重建agenda视图。如果已经存在,那么就会显示存在视图。快捷键 g
可以强制重新生成
agenda视图。
我通常会使用两个agenda视图(=F12 a= 每日每周视图 F12 SPC
项目视图)。
开启该功能的配置如下:
;; Use sticky agenda's so they persist
(setq org-agenda-sticky t)
清单处理
清单对于那种重复性并包含非常多需要做的事情的任务适用。曾经,当清单任务完成后,我会手动
清除复选框的选择状态,以保证后续能继续执行。但是现在不会这样麻烦了,因为有 rog-checklist
功能,
当重复的任务标记完成时候,清单中复选框就会自动清除选择状态。
在你的.emacs中添加如下脚本来完成上述功能。
(add-to-list 'load-path (expand-file-name "~/git/org-mode/contrib/lisp"))
(require 'org-checklist)
当需要在任务中使用时候,只需要设置 RESET_CHECK_BOXES
为 t
.
像下面一样:
* TODO Invoicing and Archive Tasks [0/7]
DEADLINE: <2009-07-01 Wed +1m -0d>
:PROPERTIES:
:RESET_CHECK_BOXES: t
:END:
- [ ] Do task 1
- [ ] Do task 2
...
- [ ] Do task 7
备份
= 及时备份那些还没有完成的的任务 =
10年前,我曾经因为没有很好的备份手段而丢失掉大量数据。那时我就告诫自己 = 我以后
再也不想丢失任何数据 = 。到现在为止确实没有丢失过了:).
我在备份时候很谨慎。org模式怎么来帮助完成备份的?确实没有花很大力气,并不是我不想
花很多时间来备份–它时刻在发生–这节省我时间,并可以把这些时间花在处理其他更有趣
的事情上。
我备份的原则就是方便恢复数据–但是这条却并不容易实现。也并不需要非常容易/快速从备
份中恢复,因为从备份数据将其恢复也并不经常发生。恢复时候节省时间没什么意义。相反,
我希望备份时候能够快速无痛点,因为我经常做备份。
10年前我就自动化网络备份了,当然现在依然再用。我所用的所有电脑从网络驱动获取
每日备份。每个月收集一次并写入可移动硬盘。
我有个月备份任务,当满一个月,就会提醒我备份当前数据到外部存储中。我很开心
现在备份执行时间变得越来越少。
自从 git
进入我生活, 多主机备份 git
代码仓库就变得更加简单了。当前只要
有修改推送发送远程仓库,就会自动备份该仓库中所有东西。
处理受阻任务
受阻任务是那些包含子任务的任务,并且该任务至少有一个子任务不处于done状态。
受阻任务在agenda视图中以灰色来显示。
可以通过如下脚本,启用受阻任务功能:
(setq org-enforce-todo-dependencies t)
这个设置会阻碍试图将包含未在完成状态子任务的任务,设置为完成状态。除了重复
任务外。这样做非常好。对于重复任务,我通常会在任务下面添加很多=TODO=状态
子任务,并且这些子任务也不一定要这个周期完成,可以在下个周期完成。
当然,可以通过快捷键 C-u C-u C-u C-c C-t
临时修改任务设置,但我记不住
这组快捷键。我在重复任务设置了一个永久属性:
* TODO New Repeating Task
SCHEDULED: <2009-06-16 Tue +1w>
:PROPERTIES:
:NOBLOCKING: t
:END:
...
** TODO Subtask
这可使得 新的重复任务
即使有子任务没有完成,也可以正常对父任务设置完成状态,不会受阻。
通常我会按照一个给定的顺序来完成任务。 org-mode有个 ORDERED
属性来对子
任务做顺序限制。
* TODO Some Task
:PROPERTIES:
:ORDERED: t
:END:
** TODO Step 1
** TODO Step 2
** TODO Step 3
这种情况下,你需要在完成 Step 1
后再去完成 Step 2
。org mode会阻止你去
对一个前面还有不在完成状态的任务,设置完成状态。
org任务结构以及展示
本节主要介绍我处理org文件时,是怎么设置任务显示的大量定制化脚本。
控制标题前置符号显示
对于任务的前置符号(*),org-mode可以定制化其是否显示。也有可能在其它层级中出现标题,
这样前置符号以及标题就可以在子树层对齐。
为使得org 显示前置符号,可以做如下设置
(setq org-hide-leading-stars nil)
我当前使用 org-indent mode来隐藏前置符号(*).
org-indent模式
我最近开始使用org-indent模式。我很喜欢这个模式。它会在org文件中移除这些对齐符号,
但是当编辑缓冲区时,这些对齐就会显示。
org-indent模式当org-odd-level-only 值为true时显示,但是显示效果比我之前的设置更加整洁。
因此我更喜欢它。
我的org-indent模式在emacs启动时自动生效:
(setq org-startup-indented t)
处理空行
空行很邪恶 😃. 他们自动在标题行之间插入,但是当标题行折叠后我并不想看到他们。
当我用 TAB
(循环)折叠标题时,不希望在标题间看到空行。
下列设置保证隐藏空行,这样在标题折叠后,就会更加精炼整洁。
(setq org-cycle-separator-lines 0)
我发现在列表以及大纲显示空行也有点令人讨厌。为了获取list列表后内容,你需要包含
空行–合适缩放内容。我大部分list没有内容,所有我也不希望list后面有空行。
下面设置,防止在创建标题时插入空行,但是允许list兼容空行。
(setq org-blank-before-new-entry (quote ((heading)
(plain-list-item . auto))))
快速添加不含当前任务内容的任务。
为在项目文件中创建一个新标题非常方便,可以通过快捷键 C-RET
, C-S-RET
,
M-RET
, 以及 M-S-RET
. 这将插入一个新标题并包含 TODO
关键字。
通过如下设置:
(setq org-insert-heading-respect-content nil)
org在光标行通过 M-
插入大纲,通过 C-
插入内容。内容设置对于 C-
版本临时开启的,
会添加新标题. 所以可以通过快捷键 C-S-RET
在当前条目上执行后,就会在后面
添加一个新标题。也可以通过 M-S-RET
将一个标题分成两个。
备忘放在任务前部
我通过 C-c C-z
创建一个备忘任务(或者在agenda中执行 z
)。有时候修改任务
状态也会弹出要求输入备忘(e.g. 移动到 WAITING
状态,就会弹出备忘,我会输入
进入等待状态的原因).这些备忘保存在任务最前端,因此当取消折叠任务时,备忘就会显示
最前端。
(setq org-reverse-note-order nil)
查找并显示结果
当需要在你的org文件中查询数据,org-mode的查找能力就起作用了。 C-c / /
会
做正则表达式查找当前文件,并在org文件折叠视图中显示匹配结果。
当使用如下设置,我的org模式就可以显示匹配项的任务,以及邻近的任务(并不是所有相邻任务):
(setq org-show-following-heading t)
(setq org-show-hierarchy-above t)
(setq org-show-siblings (quote ((default))))
这使得查找结果显示更加精简,也能够避免由于使用 C-k
从org文件中剪切太多的数据。剪切折叠
数据(包括…)非常危险,因为它也将那些你看不到的文本内容(包括相邻的子任务)也会
剪切掉。正因为这样,我总是在显示查找结果时,也会显示大纲。
编辑以及特殊按键处理
在处理标题时,org-mode快捷键C-a, C-e以及C-k快捷键都能正常工作。我也会用一些设置
来处理粘贴(yanks)子任务以及根据任务调整子树层级。通过查看帮助文档(C-h v org-yank-adjust- subtrees
), 可以查看详细细节以及如何使用。
我使用 org-special-ctrl-a/e
,能够快速移动光标到标题开始结束位置。 我使用 M-m
或者 C-a C-a
来移动光标到行开始处。 因此,快捷键在org mode依然很好工作,并且通过快捷键 C-a
,
我能够将光标定位到行开始处。
附件
附件可以很方便在你的项目相关org-mode文件之外,添加关联的大量数据。在附件功能出来
之前我会在我的org文件中包含非常多的SQL代码段,来保存项目数据库的修改。这导致我的org
文件非常大。
(setq org-id-method (quote uuidgen))
假如说,你想把 x.sql
添加到当前任务中。在 /tmp/x.sql
中创建文件保存。
通过快捷键 C-c C-a a
,添加附件,并输入文件名: x.sql
.这将为任务生成一个
唯一ID,然后把文件拷贝到附件目录。
* Attachments :ATTACH:
:PROPERTIES:
:Attachments: x.sql
:ID: f1d38e9a-ff70-4cc4-ab50-e8b58b2aaa7b
:END:
附件被保存在 data/f1/d38e9a-ff70-4cc4-ab50-e8b58b2aaa7b/
.它的具体位置对
我来说并不重要–只要它保存下来了并且能够方便取得就可以了。org-mode拷贝原来文件
/tmp/x.sql
到备份目录。
对于有附件的任务,都会添加一个 ATTACH
标签,因此你可以很方便通过tag标签找到这些任务。
通过 C-c C-a o
打开一个带有附件的任务。这个命令会弹出输入要打开文件的提示,按 TAB
就可以自动补全。
ID
对于每个任务都会生成一个唯一的。
当然也可以自己定义附件存储位置,但是我并不需要这么做 – 存在默认位置就行,只要能找到就可以了。
我将我的org文件所有附件,都存储在子目录 data
中。这样就可以通过 git
来管理。
当有附件添加,我就可以直接push到远程仓库中。
截止日以及agenda可视化
截止日在生活必不可少。默认我会在agenda视图中显示30天内的任务。
下面设置可以完成这个目的:
(setq org-deadline-warning-days 30)
这样我就有足够时间在截止日前完成这个任务。
将表格导出成CSV格式
我有时会为任务添加org-mode表格,用来记录一些项目相关数据。我的客户也喜欢这种表格。
当然在org mode中,很方便将表格导出成HTML格式,但是对于希望编辑这种表格的人来说,
就不是特别方便。为解决这个问题,我会将表格导出成逗号分割(CSV)格式然后发给客户
(或者通过表格读取然后发送给可以)
org-mode可以将表格导出成TAB或者逗号分隔的格式。我设置导出默认的CSV格式脚本如下:
(setq org-table-export-default-format "orgtbl-to-csv")
我默认只导出成CSV格式,所有当导出时我只敲击RETURN来完成导出工作。
为导出下面表格,我将光标移动到表格里边然后执行 M-x org-table-export
,然后会提示输入名字以及格式,默认是CSV格式。
这将导出下列格式的数据文件
One,Two,Three
1,1,2
3,6,5
fred,kpe,mary
234.5,432.12,324.3
最小化Emacs Frames
我的org文件中包含各种各样的email链接,网页以及其他文件链接。下面设置控制
org-mode处理链接方法。
(setq org-link-frame-setup (quote ((vm . vm-visit-folder)
(gnus . org-gnus-no-new-news)
(file . find-file))))
; Use the current window for C-c ' source editing
(setq org-src-window-setup 'current-window)
我喜欢所有链接都在一个窗口打开,这样我就不需要在我的窗口中管理多个frame了。通常
我全屏工作,链接都是在这个窗口打开,这样工作方式很适合我。
我如果需要处理多个文件,我会手动通过快捷键 C-x 5 2
创建第二个frame或者用
快捷键 C-x 4 2
或者 C-x 4 3
分割窗口。当需要访问文件时,会将当前窗口内容替换
成新内容。
日志相关的
我大部分日志是通过全局 org-todo-keywords
来控制。
我的日志设置如下:
(setq org-log-done (quote time))
(setq org-log-into-drawer t)
(setq org-log-state-notes-insert-after-drawers nil)
我的 org-todo-keywords
设置如下:
(setq org-todo-keywords
(quote ((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d)")
(sequence "WAITING(w@/!)" "HOLD(h@/!)" "|" "CANCELLED(c@/!)" "PHONE" "MEETING"))))
当任务状态变化发生时, 日志就会被记录下来:
- 达到
DONE
状态或者从DONE
状态退出 - 到
WAITING
状态(包含备忘)或者退出WAITING
状态
= 到 HOLD
状态
- 到
CANCELLED
状态(包含备忘)或者退出CANCELLED
状态。
我将计时信息以及状态信息记录在任务 LOGBOOK
抽屉中,以保持我的任务整洁。如果一个任务在
等待状态,那么在LOGBOOK里,就会显示等待原因,LOGBOOK也会处于展开状态,用来提示信息。
在agenda视图中,只要对任务单击 SPC
就可以取得LOGBOOK信息。
限制任务计时
org-mode新引入一个非常棒的功能,就是一个任务评估时间到的时候会发送通知。我用这个功能来限制
每天某些任务执行时间。
例如,这个文档我已经花了将近2个月时间。我想尽快把它完成但是我没法只做这件事,这样
其他事情就没法做了。我想每天做点,比如限制每天只花1个小时在org-mode文档编写上。
因此我建了下面一个任务:
* NEXT Document my use of org-mode
:LOGBOOK:...
:PROPERTIES:
:CLOCK_MODELINE_TOTAL: today
:Effort: 1:00
:END:
这个任务有一个小时评估时间,当我开始做这个任务时候,mode-line显示如下
--:** org-mode.org 91% (2348,73) Git:master (Org Fly yas Font)-----[0:35/1:00 (Document my use of org-mode)]-------
我今天在这个项目中已经花了35分钟了。
我会设置一个报警声,当评估时间到了的时候就会想起星际迷航声音(是的,我是星际迷)。
(setq org-clock-sound "/usr/local/lib/tngchime.wav")
当一个小时评估时间到了,报警声就会想起,并且会弹出消息提示这个任务应该完成了。如果
我切换到其他任务,又切换回来,每次切换回来报警声都会想起来。这让我不得不做其他工作
😃
你也可以对重复任务做相应设置。默认情况下最后一次时间将会被记录下来。对于重复任务
mode-line时间显示的是最后一次计时。这方便几天后来评估自己花的时间。
习惯跟踪
John Wiegley最近在org-mode中添加了对习惯跟踪的功能支持。
我有很多习惯(有些是不好的习惯),但是我还是希望来改进并建立一些好的习惯。这就是
习惯跟踪做的事。它通过图形形式显示在agenda视图上,显示出你的习惯做的怎么样。
我有如下习惯:
- 手洗碟子
- 30分钟快步走
- 打扫家庭卫生
等等。大部分习惯需要规律性完成,所以有时候需要给点压力才能这么做。为跟踪习惯是否正常
完成,需要记录状态切换日志。
习惯任务与一般的任务很像,除了它设置了特别的 属性
。该属性被设置为习惯,有个
计划
时间项,就像下面这样:
* TODO Update Org Mode Doc
SCHEDULED: <2009-11-21 Sat .+7d/30d>
[2009-11-14 Sat 11:45]
:PROPERTIES:
:STYLE: habit
:END:
这样习惯任务就可以和一般任务有所区别,agenda视图就会把它当做一个习惯任务来显示。
当习惯完成后,并被标记完成后,在agenda视图中就根据计划项,显示下次任务发生时间。
(.+7d
).
SCHEDULED
项特殊地方是,我希望这个任务每天都被执行,或者每两天要执行。如果3天没有
标记习惯完成,那么在agenda视图中它就会显示红色,表示我很久没有执行这个习惯了。
如果习惯被忽略了,那么也不是什么世界末日的大事。你可以通过 K
键来在agenda显示或隐藏习惯
任务。
如下是我的习惯设置:
; Enable habit tracking (and a bunch of other modules)
(setq org-modules (quote (org-bbdb
org-bibtex
org-crypt
org-gnus
org-id
org-info
org-jsinfo
org-habit
org-inlinetask
org-irc
org-mew
org-mhe
org-protocol
org-rmail
org-vm
org-wl
org-w3m)))
; position the habit graph on the agenda to the right of the default
(setq org-habit-graph-column 50)
每日,我会通过 K
在agenda中关闭习惯任务显示。当关闭后,这个设置就会永久保持了,
当我的emacs后台运行几天后,习惯任务也不会自动显示在agenda视图中。为保证我每天早
上都能看到习惯执行情况,我做了如下设置,这样每天早上,习惯任务就能显示在agenda视图中。
(run-at-time "06:00" 86400 '(lambda () (setq org-habit-show-habits t)))
对于习惯只记录完成状态修改
我通常将习惯放在第一层任务 * Habits
中,并且仅当任务完成时候才会记录属性。这样
我就可以在取消一个习惯时候不会记录一个时间戳,从而让这些信息填满习惯任务中.当要
取消一个习惯,只要从agenda中移除。如果习惯没有执行,那么没法重做(例如早上6点起床)
,对于没有遵循的习惯任务,就不能标记成完成。我就会取消每日重复的习惯。
我的习惯任务就像下面一样-我习惯为每个org文件都添加习惯标题。
* Habits
:PROPERTIES:
:LOGGING: DONE(!)
:ARCHIVE: %s_archive::* Habits
:END:
自动复原模式
我使用git在我的笔记本以及我的工作站之间同步org-mode文件。常规执行流程是保存当前修改,
推送到repo中,在其他系统中获取,然后我需要对我的所有org-mode文件执行revert buffer操作,
这样才能够获在buffer中显示更新的文件内容。
曾经我使用 org-revert-all-org-buffers
但是自从我发现 global-auto-revert-mode
之后,我就不再使用原来方法了。使用新的方法,只要缓冲区内容和硬盘中文件内容不一致,
缓冲区就会自动revert buffer。
这个模式对于我这种跨系统使用org-mode文件非常实用。
(global-auto-revert-mode t)
加密处理
我曾经将加密数据,比如说账户密码的保存到单独的GPG加密文件中。现在这些数据都放到
org-mode文件中,并添加特别的标签。这样加密数据就可以保留在org-mode文件中。
org-crypt
允许给任务添加一个特别的 crypt
标签,org-模式就会将这个标题中
的数据加密。当需要查看加密数据你也可以對它解密,但是只要你再次保存文件,org-mode
会重新对它加密。
如下是对加密的一些配置:
(require 'org-crypt)
; Encrypt all entries before saving
(org-crypt-use-before-save-magic)
(setq org-tags-exclude-from-inheritance (quote ("crypt")))
; GPG key to use for encryption
(setq org-crypt-key "F0B66B40")
M-x org-decrypt-entry
会弹出一个提示输入与你加密相关的密码,当正确后就用
明文来替代原来加密的密文。相反,加密并不需要输入密码-只要找到明文数据即可。
我习惯每个org文件都有个加密标题(像 * Passwords
). 我阻止带 crypt
标签的任务
被继承,因为不希望加密数据中包含加密数据。 我发现当执行 M-x org-decrypt-entries
都输入解密密码(每次一个任务项执行一次)不方便。
我会对我的数据项加密直到我想查看他们为止-我根据实际需要选择解密,然后保存文件再次加密。
这样能保证数据明文出现时间尽可能短。
自动保存文件
emacs会临时保存缓冲区的内容到自动保存文件中,当你再编辑你的org缓冲区,并积累足够次数
后进行实际保存。 如果你的缓冲区中有解码的明文并还没有保存,那么这些明文将会写入这些临时自动保存
文件中,有可能会泄露些敏感信息。为防止这种情况,可以禁用自动保存功能。
个人来说,我非常喜欢自动保存功能。 99%情况我的加密项是安全的,因为他们一直都是处于加密
状态。 我通常会解密数据项后,立即通过快捷键 C-x C-s
保存文件,这样明文又会得到加密。
这就可以阻止自动保存文件中存在明文这种情况。
我的org crypt自动保存功能设置如下:
(setq org-crypt-disable-auto-save nil)
加速命令
org-mode有个非常让人兴奋的功能叫做 org-speed-commands
.
加速命令允许在标题行开始处访问经常使用的命令-很像agenda中的1键命令。加速命令
可以自行配置,org-mode提供了些默认的命令。
我在默认基础上有添加了一些如下的加速键。我不怎么使用优先级,因此我重写了1,2,3
键的默认设置。我同样禁用了’c’同时加了’q’用来快速回到agenda视图并更新视图。
(setq org-use-speed-commands t)
(setq org-speed-commands-user (quote (("0" . ignore)
("1" . ignore)
("2" . ignore)
("3" . ignore)
("4" . ignore)
("5" . ignore)
("6" . ignore)
("7" . ignore)
("8" . ignore)
("9" . ignore)
("a" . ignore)
("d" . ignore)
("h" . bh/hide-other)
("i" progn
(forward-char 1)
(call-interactively 'org-insert-heading-respect-content))
("k" . org-kill-note-or-show-branches)
("l" . ignore)
("m" . ignore)
("q" . bh/show-org-agenda)
("r" . ignore)
("s" . org-save-all-org-buffers)
("w" . org-refile)
("x" . ignore)
("y" . ignore)
("z" . org-add-note)
("A" . ignore)
("B" . ignore)
("E" . ignore)
("F" . bh/restrict-to-file-or-follow)
("G" . ignore)
("H" . ignore)
("J" . org-clock-goto)
("K" . ignore)
("L" . ignore)
("M" . ignore)
("N" . bh/narrow-to-org-subtree)
("P" . bh/narrow-to-org-project)
("Q" . ignore)
("R" . ignore)
("S" . ignore)
("T" . bh/org-todo)
("U" . bh/narrow-up-one-org-level)
("V" . ignore)
("W" . bh/widen)
("X" . ignore)
("Y" . ignore)
("Z" . ignore))))
(defun bh/show-org-agenda ()
(interactive)
(if org-agenda-sticky
(switch-to-buffer "*Org Agenda( )*")
(switch-to-buffer "*Org Agenda*"))
(delete-other-windows))
变量 org-speed-commands-default
设置了很多加速键。 我使用最多的键是
I
O
用来计时以及 =t=修改任务状态。
J
跳到当前或者上个计时任务。
c
以及 C
被禁用了,因此当输入这些字符时,字符就会插入进去。我用 TAB
以及 S-TAB=来循环 折叠-所以我不需要 =c
C
. TAB
可以在任何地方工作但是 c
C
只能在标题
行才能执行,有时候我还会误碰。
org 协议
Org protocol方便从其他应用中为org-mode创建捕获的备忘。
我使用这个方法来记录下我在firefox浏览过的网页。
我有个特殊捕获模板用作 org-protocol使用(设置到 w
键)。
我的org-protocol设置非常简单。它能够使用org-protocol并且像Capture Templates描述那样
创建一个捕获模板。
(require 'org-protocol)
另一部分设置是在firefox中,这样在firefox中执行 =C-c c就可以触发org-protocol,捕获我当前
在浏览网页。
保存文件时在文件末尾添加新行
下面的设置主要用在编辑yasnippets, 当我希望在同一行,扩展代码片段时。
我只用这个功能在会议备忘中,替换字符串以及初始化一些人名。我现在使用 abbrev=mode
目前不使用这个设置了。
(setq require-final-newline nil)
当我想在emacs中保存一个文件时,我希望新添加新行-这个对我所工作的项目源码非常有好处。
这些是我的现在设置:
(setq require-final-newline t)
插入不活动的时间戳并排除在导出之外
当我工作在org-mode文件时候,我会插入不活跃的时间戳。
对于记忆任务时间戳,是在记忆模板中的,但是对于正常编辑大纲时候,我希望时间戳能够自行添加。
我定义个可以运行在org-mode的hook,当任务标题创建时,自动插入不活动的时间。
可以用 f9 T
来控制标题时间戳创建开关。
(defvar bh/insert-inactive-timestamp t)
(defun bh/toggle-insert-inactive-timestamp ()
(interactive)
(setq bh/insert-inactive-timestamp (not bh/insert-inactive-timestamp))
(message "Heading timestamps are %s" (if bh/insert-inactive-timestamp "ON" "OFF")))
(defun bh/insert-inactive-timestamp ()
(interactive)
(org-insert-time-stamp nil t t nil nil nil))
(defun bh/insert-heading-inactive-timestamp ()
(save-excursion
(when bh/insert-inactive-timestamp
(org-return)
(org-cycle)
(bh/insert-inactive-timestamp))))
(add-hook 'org-insert-heading-hook 'bh/insert-heading-inactive-timestamp 'append)
每次我通过 M-RET
或者 =M-S-RET=创建标题时,hook调用此函数,然后就会插入不活动的时间戳
* <point here>
[2009-11-22 Sun 18:45]
这个会记录下任务什么时候会被创建,我觉得这个功能非常有用。
我也为这个函数定义了快捷键,因此我就可以按需要插入不活动的时间戳。
(global-set-key (kbd "<f9> t") 'bh/insert-inactive-timestamp)
为阻止时间戳被导出到文档中,我使用下面的设置。
(setq org-export-with-timestamps nil)
链接上回车
下面设置使得 RET
插入新行,而不是打开链接。这个功能我是既爱又恨。当这个功能被
发现时,我首先将其关闭,因为我想在我的链接上插入新行,但是 RET
将会打开链接令人
很烦恼。然后我重新训练自己手指,在上一行结束按回车来创建新行。
(setq org-return-follows-link t)
超时时高亮显示时钟信息
目前计时信息显示在modeline。如果有预估时间,并且我们超时执行了,我让modeline着重
显示红色,通过下面设置:
(custom-set-faces
;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(org-mode-line-clock ((t (:foreground "red" :box (:line-width -1 :style released-button)))) t))
会议备忘
我用org-mode来做会议备忘。我使用org-mode点形式来记录会议会话。如果一个执行项
在会上决定去完成我会用句点好标记出来,并添加TODO:或者DONE:标记。
会议也是一个任务,当会议完成任务也完成。任务内容记录会议上所有细节。如果任务上提到
新任务,我会创建另一个新的TODO任务。
我使用 bh/prepare-meeting-notes
来准备会议备忘,用来发给会议参与者(用固定
宽度字体像“Courier New”). 当会议结束,备忘也就可以发送了–所以不需要花费额外的
时间来重写他们。我也不排斥HTML格式输出–内容比格式更加重要。
* TODO Sample Meeting
- Attendees
- [ ] Joe
- [X] Larry
- [X] Mary
- [X] Fred
- Joe is on vacation this week
- Status Updates
+ Larry
- did this
- and that
- TODO: Needs to follow up on this
+ Mary
- got a promotion for her recent efforts
+ Fred
- completed all his tasks 2 days early
- needs more work
- DONE: everything
* TODO Sample Meeting
- Attendees
- [ ] Joe
- [X] Larry
- [X] Mary
- [X] Fred
- Joe is on vacation this week
- Status Updates
+ Larry
- did this
- and that
>>>>>>>> TODO: Needs to follow up on this
+ Mary
- got a promotion for her recent efforts
+ Fred
- completed all his tasks 2 days early
- needs more work
>>>>>>>> DONE: everything
下面是格式函数。高亮备忘并将TABs转换成空格,高亮todo项。会议纪要同时会保存进删除缓冲区,这样就方便将内容贴到其他应用中。
(defun bh/prepare-meeting-notes ()
"Prepare meeting notes for email
Take selected region and convert tabs to spaces, mark TODOs with leading >>>, and copy to kill ring for pasting"
(interactive)
(let (prefix)
(save-excursion
(save-restriction
(narrow-to-region (region-beginning) (region-end))
(untabify (point-min) (point-max))
(goto-char (point-min))
(while (re-search-forward "^\\( *-\\\) \\(TODO\\|DONE\\): " (point-max) t)
(replace-match (concat (make-string (length (match-string 1)) ?>) " " (match-string 2) ": ")))
(goto-char (point-min))
(kill-ring-save (point-min) (point-max))))))
修改后移除高亮
我发现当我需要在org文件中查找一些细节时候,我会通过快捷键=C-c / /= 使用使用org-occur
查找内容.下面设置保持查找结果高亮,即使内容被修改,依然高亮。这使得我可以直接修改文件而
不丢失高亮,当修改完成后,可以继续下个匹配项。 C-c C-c
移除所有的高亮。
(setq org-remove-highlights-with-change nil)
设置这个参数为t时,当修改缓冲区,高亮将不再。
我已经开始使用当修改缓冲区后自动移除高亮,因为现在使用通用的 M-x occur
在emacs
缓冲区中查找。
获取最新的org-mode帮助文档
我使用git仓库中的org-mode帮助文档,因此我设置emacs从git查找帮助文档,之后才常规查找
(过时)系统版本文档。
(add-to-list 'Info-default-directory-list "~/git/org-mode/doc")
选择将来时间吗?
默认情况下org会选择将来的某个时间。这意味着如果当前时间是5月2号,然后你输入一个
4月30号日期(2天前),org-mode将会跳转到明年的4月30号。我发现这个非常烦,因为
当我需要看看上周五发生什么我必须输入年。现在我训练我的手指,这样,如果需要查看以前
的信息我可以用快捷键 b
,所以这个问题对我来说也不是什么问题了。
自动修改点句
在开会时候我会使用点格式。跟其他的list点句一样,这样当层级超过3行,就会让读取
细节变得更难。
当修改层级时,org-mode可以自动修改list点句。
(setq org-list-demote-modify-bullet (quote (("+" . "-")
("*" . "-")
("1." . "-")
("1)" . "-")
("A)" . "-")
("B)" . "-")
("a)" . "-")
("b)" . "-")
("A." . "-")
("B." . "-")
("a." . "-")
("b." . "-"))))
删除agenda标签视图中的缩进
我不喜欢agenda视图中对匹配的标签子层级缩进显示,当我执行agenda标签查询(=F12 m=),
我只希望看到所有匹配的任务(包含子层级)。
为使得所有匹配的大纲都在agenda显示,可以设置如下变量:
(setq org-tags-match-list-sublevels t)
加固源码显示
我使用babel来在我的文档中包含源码
#+begin_src LANG
,, ...
#+end_src
LANG代表使用的语言(ditaa, dot, sh, emacs-lisp等)这将使得在org-mode中以代码块显示,同样导出文档时也是以
代码块显示。
可以查看这个文档Git Repository synchronization 作为个例子。
持久化agenda过滤器
这是一个伟大功能!持久化agenda过滤器意味着当通过 / TAB SomeTag
查看后agenda
会记住这个过滤条件,直到你修改它。
通过如下参数可以启动持久化过滤器
(setq org-agenda-persistent-filter t)
为标记项添加标记
每个人都会碰到有些非常重要的信息,需要后续能够快速找到。
像这种备忘以及任务我添加了特殊的 :FLAGGED:
标记。这个标记有个快速按键 ?
将会
在agenda中查找标记项。可以查看 Tags了解如何为 FLAGGED
项
设置 org-tag-alist
。
为查找标记项也非常简单,只要执行快捷键 F12 ?
就能获得。
使用compose-mail打开邮件链接
下列设置使得org-mode 可以使用compose-mail打开 mailto:
链接。
(setq org-link-mailto-program (quote (compose-mail "%a" "%s")))
org mode任务来作为邮件内容发送
可以创建基于org-mode子树内容的邮件。我通常使用 C-c M-o
来启动email消息,并从
子树获取内容,作为email邮件内容。我使用这种方式来处理重复的提醒任务,并需要发邮件
给别人。email内容已经包含在org-mode子树中,我只需要对子树执行 C-c M-o
然后
只要在发出前做稍许修改即可。
**使用smex作为 M-x ido-completion后端
:CUSTOMID: SmexAndIdo
我发现smex,并使用它作为IDO-completion 后端,当读取org-mode邮件列表后。我实际上会
执行M-x很多次,因为通过IDO补全方便。
下面是我的设置:
(add-to-list 'load-path (expand-file-name "~/.emacs.d"))
(require 'smex)
(smex-initialize)
(global-set-key (kbd "M-x") 'smex)
(global-set-key (kbd "C-x x") 'smex)
(global-set-key (kbd "M-X") 'smex-major-mode-commands)
使用emacs书签来快速导航
我开始使用emacs书签来保存位置,以方便通过标签自动返回。通常我想回到当前计时任务,这很简单-只要执行 F11
。
当我在查看列表,对任务设置一个书签,就可以快速跳转到该列表处理,当完成后,可以快速回到任务,然后将它的
复选框标记上。
我emacs书签相关设置如下:
;; Bookmark handling
;;
(global-set-key (kbd "<C-f6>") '(lambda () (interactive) (bookmark-set "SAVED")))
(global-set-key (kbd "<f6>") '(lambda () (interactive) (bookmark-jump "SAVED")))
当我想保存当前位置,我只需要执行快捷键 C-f6
,当我想返回,我只需要执行 f6
.我会每次
重写这个标签来设置新位置。
使用org-mime发邮件
我现在正在使用通过mime来发送org相关邮件。我在 org-mode-hook
添加了 C-c M-o
按键绑定来从
org子树生成邮件。
从agenda中移除多个状态切换日志
我在agenda视图中通过如下视图,跳过相同任务项包含多个时间戳这种情况。
(setq org-agenda-skip-additional-timestamps-same-entry t)
这样可以移除多于的状态转换log当多个时间戳存在于一个任务项中。
在表格中舍弃老的引用格式
我通过如下设置,舍弃了表格中老的 A3/B4格式引用。
(setq org-table-use-standard-references (quote from))
使用系统设置来完成file-application选择
为使任务打开方式体验一致,我会像如下方式设置 org-file-apps
.
(setq org-file-apps (quote ((auto-mode . emacs)
("\\.mm\\'" . system)
("\\.x?html?\\'" . system)
("\\.pdf\\'" . system))))
当打开文件文件时,它使用定义在我系统 mailcap
中的项目设置,这使得我,在通过 C-c C-o
打开一些HTML链接时候有一致体验。
复制时删除ID
(setq org-clone-delete-id t)
折叠文本列表
org mode能够折叠(展开)文本列表。
(setq org-cycle-include-plain-lists t)
我发现当我的重复任务包含很多复选框子列表时,这个功能非常有用。我可以折叠起完成项,并只关注那些还没有完成的。
代码块语法高亮
在org-mode中可以显示native形式的源码。这可以高亮 C以及shell脚本源码。当我要
标记源码,我使用 =C-c '=(control-c单引号)会打开源码窗口,源码也会高亮。这个
设置也会将org-mode缓冲区的语法高亮。
插入代码块模板
在org-mode中有一些快捷键用来快速插入代码块模板。
我在org中使用example以及代码块非常多
我添加了一个代码模板块用来从MS outlook中拷贝内容到我的org-mode任务。
下面的lisp在org-mode中将默认将字符转化成小写。
(setq org-structure-template-alist
(quote (("s" "#+begin_src ?\n\n#+end_src" "<src lang=\"?\">\n\n</src>")
("e" "#+begin_example\n?\n#+end_example" "<example>\n?\n</example>")
("q" "#+begin_quote\n?\n#+end_quote" "<quote>\n?\n</quote>")
("v" "#+begin_verse\n?\n#+end_verse" "<verse>\n?\n</verse>")
("c" "#+begin_center\n?\n#+end_center" "<center>\n?\n</center>")
("l" "#+begin_latex\n?\n#+end_latex" "<literal style=\"latex\">\n?\n</literal>")
("L" "#+latex: " "<literal style=\"latex\">?</literal>")
("h" "#+begin_html\n?\n#+end_html" "<literal style=\"html\">\n?\n</literal>")
("H" "#+html: " "<literal style=\"html\">?</literal>")
("a" "#+begin_ascii\n?\n#+end_ascii")
("A" "#+ascii: ")
("i" "#+index: ?" "#+index: ?")
("I" "#+include %file ?" "<include file=%file markup=\"?\">"))))
NEXT状态只适用于任务
NEXT
任务只适用 tasks 并不适用 projects 。我写了个函数来处理状态改变,以及当子任务
状态变成 NEXT
,会将父任务从 NEXT
转换成 TODO
,因为父任务是项目,并不是任务。
默认折叠模式显示
启动时显示折叠模式
(setq org-startup-folded t)
我以前使用内容模式,因此可以在归档前查看子树内容,但是我的归档流程已经修改了,
因此我不需要这步了。
只允许字符类表项
下列设置添加如下的字符列表
a. item one
b. item two
(setq org-alphabetical-lists t)
为使得能正常工作,这个需要在exporter之前设置。
使用orgstruct 发邮件
orgstruct++-mode
在 Gnus
消息缓冲区开启,用以创建结构化邮件消息。
(add-hook 'message-mode-hook 'orgstruct++-mode 'append)
(add-hook 'message-mode-hook 'turn-on-auto-fill 'append)
(add-hook 'message-mode-hook 'bbdb-define-all-aliases 'append)
(add-hook 'message-mode-hook 'orgtbl-mode 'append)
(add-hook 'message-mode-hook 'turn-on-flyspell 'append)
(add-hook 'message-mode-hook
'(lambda () (setq fill-column 72))
'append)
使用flyspell mode减少拼写错误
flyspell-mode
默认在任何模式都开启,用来检查文档中包含拼写错误。
;; flyspell mode for spell checking everywhere
(add-hook 'org-mode-hook 'turn-on-flyspell 'append)
;; Disable keys in org-mode
;; C-c [
;; C-c ]
;; C-c ;
;; C-c C-x C-q cancelling the clock (we never want this)
(add-hook 'org-mode-hook
'(lambda ()
;; Undefine C-c [ and C-c ] since this breaks my
;; org-agenda files when directories are include It
;; expands the files in the directories individually
(org-defkey org-mode-map "\C-c[" 'undefined)
(org-defkey org-mode-map "\C-c]" 'undefined)
(org-defkey org-mode-map "\C-c;" 'undefined)
(org-defkey org-mode-map "\C-c\C-x\C-q" 'undefined))
'append)
(add-hook 'org-mode-hook
(lambda ()
(local-set-key (kbd "C-c M-o") 'bh/mail-subtree))
'append)
(defun bh/mail-subtree ()
(interactive)
(org-mark-subtree)
(org-mime-subtree))
维持源码块对齐
我不会在源码块中维持对齐,因为这样看起来不是很好。唯一一个我觉得需要保留对齐是在文件中
的TABs需要保留(例如 Makefiles)。我不怎么在org-mode编辑这种文件,所以我默认将对齐关闭。
我修改了默认代码块对齐方式,这样就不会从文本开始对齐。这允许立即编辑源码而不需要执行
C-c '
,因此代码看上去就正确了。
(setq org-src-preserve-indentation nil)
(setq org-edit-src-content-indentation 0)
阻止修改不可见文档
当光标在折叠去,下面设置阻止不小心修改隐藏文档。这种情况会发生在当光标在标题体内,然后通过
执行 S-TAB
折叠org文件。
我发现不可见编辑(撤销)很难处理,因此现在我禁止编辑不可见文本。 C-c C-r
(org-reveal) 将会
显示光标,当光标折叠在不可见区域时,这样就可以编辑了。
(setq org-catch-invisible-edits 'error)
使用utf-8作为默认文字编码
我对我所有的org文件使用 utf-8
作为默认编码格式。
(setq org-export-coding-system 'utf-8)
(prefer-coding-system 'utf-8)
(set-charset-priority 'unicode)
(setq default-process-coding-system '(utf-8-unix . utf-8-unix))
使用小时来计时
默认计时时长变成以24小时每日计时。工作中我通常认为一天有6小时来工作(其它时间用在
开会以及其他事情上)所以以日计时对我来说没有什么意义。
下列设置修改计时为以小时以及分钟来计时(C-c C-x C-d
)
(setq org-time-clocksum-format
'(:hours "%d" :require-hours t :minutes ":%02d" :require-minutes t))
创建唯一ID为任务做链接
当设置下面设置后,使用 C-c l
, 就会为标题在 PROPERTY
属性抽屉中,创建唯一ID.
当有了唯一ID,我即使将任务在文档中移动,链接到该任务的链接依然有效。
(setq org-id-link-to-org-use-id 'create-if-interactive-and-no-custom-id)