[elisp]用elisp编译解释当前的buffer
运行当前的buffer,就是说编译或解释当前的buferr。比如在编辑的是python文件”hello.py”,那么运行它的命令就是”python hello.py”,一般的python-mode用”C-c C-c”来处理这个问题,在编辑过程中可以调用这个快捷键来运行。当然你也可以使用”M-!”来打开shell command的mini buffer来输入命令。
诚然,很多语言的mode里面实际上都内置了这一功能,但我觉得,一方面不同的mode可能定义不同快捷键,造成了额外的记忆负担,另一方面并不能要求所有的mode都提供这一功能,在mode不完整的情况下你大概也需要自己定义的能力。
要做这事儿,当然是自定义一个函数。那么最直观的想法,就是在elisp里面写一行调用shell来执行命令的代码。是的,有这种东西,示例如下:
(shell-command "python hello.py")
这一行代码的相当于在终端中执行”python hello.py”。
我们的目的是执行当前buffer,所以下一步要做的是得到当前buffer所对应的文件名。在上一篇blog中介绍过相关方法,就是”buffer-file-name”。
于是代码就变成了这样。
(shell-command (concat "python " (buffer-file-name)))
用concat把”python “和当前buffer的文件名连起来作为要执行的命令。
至此,就完成了.py文件的执行函数,那推广之,需要对不同的文件进行编译/解释时,就需要扩展这个命令。
我们知道对.sh文件要用bash命令执行,对.py要用python,对.htm要调用firefox。现在要做的就是让机器知道这件事。很明显的,我们需要一个map,把它们对应地存下来。
完整的代码和注释如下:
(defun run-current-file ()
(interactive)
(let (ext-map file-name file-ext prog-name cmd-str
(setq ext-map
'(
("py" . "python")
("sh" . "bash")
("htm" . "firefox")
)
);定义命令-文件类型映身表.
(setq file-name (buffer-file-name));得到当前的buffer名
(setq file-ext (file-name-extension file-name));得到后缀
(setq prog-name (cdr (assoc file-ext ext-map)));根据后缀得到执行的命令,通过对ext-map的查找
(setq cmd-str (concat prog-name " " file-name));拼出一个命令
(shell-command cmd-str)));执行
完毕,为这个函数绑定一个键,在编辑相应文件的时候调用,就可以对其进行需要的操作了,不仅限于编译和解释,实际上很容易看出来,只要shell能支持的,你可以玩。当然,要有权限。
Have Fun!
[elisp]针对Emacs中文本编辑的编程简介

Elisp是Emacs下的Lisp方言,而Emacs是一款编辑器。那么针对于Emacs,Lisp要做的很重要一部分工作当然就是对编辑的自动化支持。比如移动鼠标,输入句子,查找替换,代码高亮等等,简单地说,就是为更好更方便地支持文本编辑提供支持。而把这些函数都重合起来,就起成了Emacs mode。如我们常用的C++ mode,python mode。还有之前我一直在介绍的org-mode等,都是由Elisp拼成的。
学习Elisp,可以满足对Emacs进行定制的需求,你可以把想要的功能写在.el文件里面,让Emacs来调用。一方面可以实现一些简单的轻量级的功能,而不需要为此寻找和安装一个完整的mode。另一方面,可以修改现有的mode,使得更符合自己的习惯。这符合开源的作法,不爽即改。
Elisp函数的简单例子
光标位置
;返回当前光标的位置 (point) ;region的头跟尾 (region-beginning) (region-end) ;最大光标位置(即文件尾),elisp还提供最小光标位置(point-min),不过我觉得那应该都是1吧。 (point-max) ;返回buffer结尾的绝对位置,无视narrow-to-region (buffer-end 1) |
移动光标和搜索
;移动光标到392 (goto-char 392) ; 向前/向后移动n字符 (forward-char n) (backward-char n) ; 跳过所有\n\t,即把光标移动第一个不是换行或制表符那里 ; 返回移动的字符数 (skip-chars-forward "\n\t") (skip-chars-backward "\n\t") ;移动光标到myStr后面,向前和向后 ;返回新的光标位置 (search-forward myStr) (search-backward myStr) ; 同上,但是参数是正则表达式,myRegex ; 返回新的光标位置 (re-search-forward myRegex) (re-search-backward myRegex) |
文本编辑
; 删除光标后的九个字符 (delete-char 9) ; 删除选中的两点之前的文本 (delete-region mystartpos myendpos) ; 在当前光标位置插入一字符串 (insert "Forza Inter") ; 从buffer中获得一个字符串并赋给mystr (setq Mystr (buffer-substring mystartpos myendpos)) ; 改变字符大小写 ;这个例子是指当前光标之前的20个字符 (rapitalize-region (- (point) 20) (point)) |
字符串
; 长度 (length "abc") ; returns 3 ; 获取一个子串 (substring myStr startIndex endIndex) ; 替换,以正则方式 (replace-regexp-in-string myRegex myReplacement myStr) |
Buffers
; 当前buffer的名字 (buffer-name) ; 文件名(全路径) (buffer-file-name) ; 设定一个buffer名 (set-buffer myBufferName) ; 保存 (save-buffer) ; 关闭指定的buffer (kill-buffer myBuffName) ; 关闭当前buffer (kill-this-buffer) ; 临时指定一个buffer作为当前buffer (with-current-buffer myBuffer ; do something here ... ) |
Files
; 打开一个文件 (find-file myPath) ; 另存 ; 会关闭当前的buffer,打开另存好的文件 (write-file myPath) ; 把一个文件内容插入到当前位置 (insert-file-contents myPath) ; 将选中的评论文本加到某个文件后面 (append-to-file myStartPos myEndPos myPath) ; 重命名 (rename-file fileName newName) ; 复制 (copy-file oldName newName) ; 删除 (delete-file fileName) ; 获取路径 (file-name-directory myFullPath) ; 获取文件名(不含路径) (file-name-nondirectory myFullPath) ; 得到文件名后缀 (file-name-extension myFileName) ; 获得不含后缀的文件名。 (file-name-sans-extension "abc.htm") |
简单的例子
(defun insert-p-tag () "Insert at cursor point." (interactive) (insert " ") (backward-char 4)) |
在当前光标处插入一个p tag。做法是插放一个串,然后将光标移回4位。
编写一个mode
理论上来讲,知道上面这些东西,你就有能力编写一个mode了。但是,编写mode毕竟是一个复杂的工作,需要编写者对elisp编程具有”hello world”以上很多级的熟练度。
在李杀网,作者有一个系列文章来讨论如何为一个编程语言编写mode。
The End. Have fun!
[elisp]EmacsLisp 基础
李杀网有一枚elisp教程我很喜欢,原因是它不解释太多的名词,而从实际动作方面入手,对我的胃口。
以下是相关的笔记。
运行方式:
作为一个实践的手册,第一件事当然是告诉如果运行一行代码,让你在看指南的过程中可以方便地动手尝试。
- eval-last-sexp
- eval-region
- ielm
输入后把光标移到表达式后面,如“(+ 3 4)”后面,然后输入”Alt+x eval-last-sexp”或者使用快捷键”C-x C-e”,就可以在mini buffer看到这一句的运行结果”7″。
解释选中的区域。
打开一个交互式的elips命令行解释器。
寻找帮助:
可以使用”Alt + x describe-function”(快捷键”C-h f”)来查找一个函数的用法。也可以使用”Alt+x elisp-index-search”在手参考手册中查询。
常用函数
打印
(message "hi") (message "her age is:%d" 16) ;%d 数字 (message "her name is: %s" "Vicky") ;%s 字符串 (message "her min init is: %c" 86) ;%c 字符
注意:你可以在*message* buffer中看到打印出来的结果。
运算函数
(+ 4 5 1 ) ;=10 (- 9 2) ;=7 (* 2 3) ;=6 (* 2 3 4) ;=24 (/ 7 2) ;=3 结果的整数部分 (/ 7 2.0) ;=3.5 (% 7 4) ;=3 余数
注意,如果你的操作数是小数,必须把后面的0带上。就是说你应该写2.0,而不是2.。
(integerp 3.) ;T (floatp 3.) ;nil (floatp 3.0) ;T
以字符p结尾的函数通常意味着它的返回值是True或者False。p意味着”predicate”(判定)。
True和False
在elisp中,标识”nil”代表false,其它的一切都是true,包括0。”nil”是空链表”()”的同义词。所以”()”也是false。
按惯例,标识”t”用来表示true。
(and t nil) ; nil (or t nil) ; t
在elisp中没有布尔型,只需记住”nil”和”()”是false,其它一切都是true。
比较函数
比较数字
(< 3 4) ;小于 (<= 3 4) ;小于等于 (> 3 4) ;大于 (>= 3 4) ;大于等于 (= 3 3) ;等于
比较字符串
(string= "this" "thiS") (string< "a" "b") (string< "B" "b")
在字符串比较中大小写是敏感的。比较依据是字典顺序。
要比较两个sysbols是否有相同的数据类型和值,使用"equal"。
(equal "abc" "abc") ;t (equal 3 3) ;t (equal 3 3.0) ;nil.类型不同 (equal '(3 4 5) '(3 4 5)) ; t (equal '(3 4 5) '(3 4 "5")) ;nil
在Elisp中并没有"!="或者“not-equal”。判断不等,可以在对整个等式取非。
(not (= 3 4)) ;t
全局和局部变量
"setq"用于给变量赋值。格式一般为"setq 变量1 值1 变量2 值2..."
在lisp中,变量不需要声时,并且是全局的。
(setq a 3 b 2 c 7) ;三个变是,a=3 b=2 c=7
定义局部变量,使用let。格式为"(let (变量1 变量2) body)"。"body"代表其它的表达式。其中最后一个表达式的取值是整个语句块的返回值。
(let (a b) (setq a 3) (setq b 4) (+ a b) )
a和b都是这个语句块的局部变量,返值是最后一个表达式"(+ a b)"的取值。
另一种格式是"(let ((变量1 值1)(变量2 值2)) body )"。例如:
(let ((a 3) (b 4)) (+ a b) )
如果你的变量很少,并且值都是已经确定的,可以用这种方法。
表达式块
有时需要把一些表达式括起来。这时可以使用"progn"。
(progn (message "hi"))
它相当于
(message "hi")
"progn"类似于C语言中的"{...}"。它使用于某些需要把语句合并起来的场合,其实这跟C语言中也是一样的。比如:"(if something (progn this that))"。这里,如果把progn去掉,变成"(if somethong this that",在lisp中表示如果something,那么this,否则that。在有progn把this和that括真情 为情况下,表示的是如果something,那么执行this和that。
If then else
格式为"(if test then
(if (< 3 2) (message "yes"))) (if (< 3 2) (message "yes") (message "no")))
迭代循环
使用while。
(setq x 0)
(while (< x 4)
(princ (format "yay %d." x))
(setq x (+ 1 x)))
在elisp中,并没有for语句。
Lists
在lisp中的List是这样的:“'(x y z)”。括号前面那个单引号是很重要的。不需要太在意它的含义,把它当成句法的一部份即可。
(message "%S" '(a b c))
(setq mylist '(a b c)) ;定义
(let ((x 3) (y 4) (z 5))
(message "%S" (list x y z))
)
以下是List的一些函数:
| Function | 目的 |
|---|---|
| (car mylist) | 取第一个元素 |
| (nth n mylist) | 最第n个元素 |
| (car (last mylist)) | 取最后一个元素 |
| (cdr mylist) | 从第二个到最后一个 |
| (nthcdr n mylist) | 从第n个到最后一个元素 |
| (butlast mylist n) | 不包含n到最后一个元素 |
这里所说的n,都是从0开始的。
下列是一些例子。
(car (list "a" "b" "c")) (nth 2 (list "a" "b" "c")) (last (list "a" "b" "c"))
| Function | 目的 |
|---|---|
| (length mylist) | List长度 |
| (cons x mylist) | 把x加到list前面 |
| (append mylist1 mylist2) | 连接两个List |
例如:
(length (list "a" "b" "c"))
| Function | Purpose |
|---|---|
| (pop mylist) | 删除第一个元素并返回 |
| (nbutlast mylist n) | 删除第n个元素,返回删除后的list. |
| (setcar mylist x) | 替换第一个元素,并返回 |
| (setcdr mylist x) | 替换除第一个之外的所有元素 |
遍历运算数组
(mapcar '1+ '(1 2 3 4))
上例的做所是遍历list中的每一个元素,并对它进行"1+"的操作。
当然,也可以用while循环来完成这件事。
定义函数
基本的函数定义方式是"defun
(defun myFunction () "testing" (message "Yay!"))
myFunction是函数名,这个函数无参,函数注释"testing",后面是函数体。
可以在doctsing后面加一个"interactive"来使得函数能跟环境进行交互(在emacs中,就呆以可用"Alt + x"来调用)
interactive的一些常用语法:
- (interactive) 无参
- (interactive "n") 一个数字参数
- (interactive "s") 一个字符串参数
Emacs的orgmode [remember]

Inbox,在GTD的定义里面是收集材料的工具。最好的Inbox工具是纸和笔。而Remember在Orgmode里面算是较好的Inbox工具。它比每次打开org文件来写好非常非常多。它提供的是在emacs启动的情况下,快速的录入工具。如果你的emacs没启动,那用便箋或纸笔会好得多。原因很简单,emacs什么都好,就是启动太龟了。
配置和基本使用
remember.el在emacs23以上版本是自带的,emacs22及以下版本如果发现没有自带,请自行放狗搜。
(setq org-default-notes-file "~/.notes")
在.emacs中作如上设置,表示你希望将remember产生的note存放在~/.notes中,要我说这可一点也不重要,重要的是下面这一行:
(define-key global-map [f12] 'org-remember)
快键键。当然,快捷键从来很重要。不过在remember模式中,它显得尤其重要。因为本身remember是随时需要的东西,用完后又应该随时忘掉。所以调用remember应该越不影响当前的思路又好。一个要键入”M-x org-remember”这么多字符才能调出来的remember又有什么用?
我觉得remeber的用法应该是这样的:
现在我想起来晚上海贼王的汉化应该出新的了,接F12调出remember,输入OP,然后“C-c C-c”保存(C-c C-k是取消),remember buffer自动消失,整个emacs又恢复成写这篇blog的界面。
现在的问题是,我一天可能乱七八糟的出现不少想法,每次都按F12来记录是好的,晚上回家一看,~/.noet里面充满了记录,一条一条分门另类地复制了不同的org文件中。我承认这是重要的工作,无可避免。可是有些想法我在记录的时候就知道它应该是todo还是普通的笔记,能不能让它们自动归位呢?
于是我们应该开始介绍:
模版
模版的配置文件如下:
(setq org-remember-templates
'(("TODO" ?t "* TODO %?\n %x\n %a" "~/doc/org/home.org" "Tasks")
("IDEA" ?i "* IDEA %?\n %i\n %a" "~/doc/org/home.org" "Idea")
))
它的参数是这样的,”TODO”是这个模版的名,”?t”是快捷键,”* TODO %?\n %x\n %a”是整个模版体,然后是该模版要保存的文件,保存后的项目在文件中处于哪个父节点下面(如果没有会自动新建)。
我们以第一个模版为例说一下使用中会发生什么?
当你按下F12(这是我的快捷键)时,会看到buffer被切分成两块,下面出现一个rememeber fuffer。以及一个输入提示,按我们之前的设定,出现两个快捷提示。

这时按下“t”,在remember buffer中,会自动接模版体的格式显示出补好的TODO,第一行是“* TODO”,第二行是%x,%x是你触发remember时kill ring(类似于剪贴板)中的内容。最后一行是%a,一个指向你触发remember的地方的link。
这时如果你按下”C-c C-c”保存,这一条TODO项目将会被送到”~/doc/org/home.org”文件中的”Tasks”条目下面。
模版还有一些好玩的用法,比如说写日记。
关于模版参数的更详细说明,可以在这里找到
参考资料
Emacs的orgmode [tags]
tags
标签(tags)在管理东西方面有很多应用。比如blog,flickr,前阵子还在小众软件上看到用标签管理文件的软件。
本身,我们在做org管理文件的时候就已经把不同的东西放在不同文件里了。比如我们建了home.org,work.org两个文件,把在家的工作做在home.org里,把公司的放在work.org里面。
但这种用文件来分类的方法有不便的地方:其一,如果我想到一个新的分类,那就必须新建一个文件;其二,如果我有一个工作同时属于两个文件,怎么办?
于是,tags来了。
tags只做一件事:标记这个项目是什么?它的展示样式是这样的
TODO 跟特留尼西特握手 :苦差:薪水:逃不掉:
你可以按C-c C-c组合键,这里在mini buffer(就是下面的小框)会出现”Tags:”,等待你输入标签,支持中英文。
就是这么简单。
tags的继承
如前所述,本来我们的想法是用文件来进行不同的分类的,也就是说实际上文件就是一种分类,放在work.org中的项目本来就应该拥有work属性,我不想在每一个项目上添一个:work:的蛇足。
这就得说到tags继承的org特性了。

如图,叶项目“新门”本身有一个属性”苦差”,同时它继续了两个属性,一个来自它的父项目apartment,还有一个来自文件属件work。给一个文件设置属性,需要在文件头加上一行。
更简单的方法
如果有一些常用的标签不想每次都敲。可以使用orgmode的标签快捷键功能.比如你可以用k来代表苦差,用s来代表薪水。跟很多org设置一样,可以在两个地方完成这些设置。
一个是.emacs文件。它的语法是这样的。
(setq org-tag-alist '(("苦差" . ?k)
("薪水" . ?s)))
还有一种做法是在文件的头部加声明。类似这样:
#+FILETAGS: :work:
它们的分别在于,前者对于本机所有的org文件都有效。后者刚只对当前文件有效。
这时再给一个项目加标签就会变成这样

敲相应的快捷键就可以了。
搜索查看tags
使用tags来给项目打标签当然不是为了打打好看而已。我们是要用的。最常用的用法就是用tags来表示context的概念。
江湖传言把事情分类来做能提高工作效率。即是说,如果你有十个电话要打,十个email要回。最好不要打一个电话回一封email再打一个电话再回一封email,比较好的做法是先打十个电话,然后再连回十个email。还有一个秘笈,是威尔史密斯在<当幸福来敲门>里面教给我们的,如果你不把话筒放下来,能节约很多打电话的时间。
这就需要我们能够把十个电话项目都取出来,在文件里面一个一个找:phone:标签?别傻了。敲一个C-c a吧,然后再敲m,下方的mini buffer里出现了几个大字”MATCH:”,这里输入”phone”,回车。你的列表中所有文件里的带有phone标签或者属性的项目就都列出来了。不想要所有项目,只想看TODO?简单,C-c a后不要加m,加个M吧。
输入关键词的时候还可以使用与或非运算,算符如下:phone&work,同时有两个标签的。phone|work,有两个标签之一的。phone-work有phone标签而没有work标签的。
这里,C-c a表示你要求调出agenda view,后面那个命令则指明你想要调出什么样的view。敲后C-c a之后,不要急着敲m,可以看看org都提供了哪些view,我们熟知的有C-c a a,C-c a t等。
不要每次都输关键字
这样看起来,C-a a a也是一种检索,只不过它们是org-mode内置而已,那我也有一些数据视图是经常要用的,有一些是没事就搜一下的。我也要敲三个键就弄出来,不想每次都敲tags。
嘿嘿,改源码把我自己的搜索置进去。倒是不用着急,读代码总是麻烦的。事实上org-mode已经开放了一个自定义view的接口。唤作org-agenda-custom-commands。可以在.emacs文件中设置自己的。
(setq org-agenda-custom-commands
'(("k" "work haha"
((agenda "")
(tags-todo "work")
(tags-todo "支持")))))
这段代码表示您定了一个可以用C-c a k 调出来的view,它的描述是”work haha”,view中包含三段数据。最上面是agenda,就是调C-c a a出来的界面,然后一个分隔行,列出tags为“work”的项目,再一个分隔行,列出tags为支持的项目。

官方的说法是提供了一个GUI界面,M-x customize-variable RET org-agenda-custom-commands可以打开。界面如下:
![]()
但我个人还是喜欢使用.emacs文件手写配置。不是我装13,而是GUI界面设计得实在太难用了,我到现在也没弄明白它的用法。
emacs代码补完-yasnippet
Email:hamainter(AT)gmail.com
yasnippet是emacs的一款代码补完插件,类似于一个代码模版。基本用法就是“TAB”,输入关键字之后按TAB键,YASnippet根据预先设定的模版来展开代码。很好玩。
YASnippte有两种安装方法,一种是视频中使用的单el文件yasnippet-bundle.el,配置也简单一点,只要在你的.emacs文件中添加以下代码就可以了。
(add-to-list 'load-path
"~/.emacs.d/plugins")
(require 'yasnippet-bundle)
还有一种涉及多个文件,一个是yasnippet.el,还有一个存放模版文件的文件夹,里面按照不同的mode存放模版。相应的,你的配置文件中需要配置el文件的位置和模版文件夹所在的位置。
(add-to-list 'load-path
"~/.emacs.d/plugins/yasnippet-x.y.z")
(require 'yasnippet) ;; not yasnippet-bundle
(yas/initialize)
(yas/load-directory "~/.emacs.d/plugins/yasnippet-x.y.z/snippets")
二者使用起来是一样的。不过很明显的区别在于,单文件模式是指模版也完全整合到yasnippet-bundle.el文件中了,修改起来很麻烦。
而修改模版在我看来是必须的。因为原始的mode模本一般不太可能符合所有人的需要,至少我现在手上的版本来看,质量只能算是一般而已,令人不爽的,需要修改的地方还是很多的。另外,emacs的乐趣不就是完全可定制么?一个调教之前的emacs基本上并不比gedit高明多个,以上是个人意见。
所以我个人推荐多文件的安装方法。安装配置之后进入emacs,看到界面基本上是这样的。

而文件结构基本上是这样
sgml-mode/ |-- body |-- br |-- code |-- code.class |-- div |-- div.class |-- div.id |-- div.id-class |-- dov |-- form |-- head |-- header | |-- h1 | |-- h2 | |-- h3 | |-- h4 | |-- h5 | `-- h6
它与snippet文件夹里的文件成一一对应关系。也就是说,你需要修改哪个模版,只需要在snippet文件夹中找到相应的文件对它进行修改就可以了。
class ${1:ClassName}(${2:object}):
"""$3
"""
def __init__(self,${4:para}):
$0
以上是python中class的模版,不是原始的,我去掉了init中比较复杂的部分。定义了yasnippet这样的行为:
在emacs的python-mode中,你输入了”class”,然后按一下TAB,编辑器将自动给你填出如下代码段。
class ClassName(object):
"""
"""
def __init__(self,para):
并且光标停留在”ClassName”上,因为模版中$1位于这里。你可以对它进行修改。这里提一个模版的简单语法,模版中以$n定义光标定位的位置,从1开始,展开后光标就定位在$1,然后按TAB键在不同的位置间移动,碰到$0时退出模版,开始输入自定义项。
这里有一个限制,就是修改时必须把$1-$n-$0的整个流程走完一遍你才可以写自己想写的东西。所以在$4那里就出了一件我很不爽的事,self后面的逗号,我的__init__是无参的,我可以把para删掉,但是我删不掉逗号,原因是流程还没走完,你不可做流程以外的事情。我必须TAB到$0然后再把光标移上去删除一个逗号。
于是我找到文件所在的地方,修改了__init__的模版,把逗号放到$4当中去,这样我跳过它的时候,逗号也一并消失了。
Just for fun.
装一个不?它们的项目首页是:yasnippet
Emacs的orgmode [归档]
如果你用org-mode来做TODO管理,那么无法避免的是,随着时间的流逝,被DONE的事件会越来越多,那么TODO被会被夹杂在DONE之间,难以查找。同时,由于后期回顾的需要,你也不想简单地将DONE事件删除掉。这个时候,你就需要归档命令了。归档,就是把你不想天天看到的东西,放到你看不到了,或者不怎么影响你的注意力的地方去。org-mode提供了两种归档方式。
内部归档
内部归档是在本文件内部给特定子树打上ACHIVED标签或者移动到名为achived的子树中去并打上标签。
这个被认为是ACIVED的子树,会被移动了本级子树的最末端。
例如有这么一个子树,由三个TODO项目组成。
* blog ** TODO 匈牙利命名法 ** TODO org-mode 归档 ** TODO BillG审查
C-c C-x a
将某一个节点打上ARCHIVE标签。
* blog ** TODO 匈牙利命名法 ** TODO org-mode 归档 :ARCHIVE: ** TODO BillG审查
C-c C-x A
将当前节点归入一个名为Archive的子树中,并且这个子树是位于当前级别子树的最下方。
* blog
** TODO org-mode 归档 :ARCHIVE:
** TODO BillG审查
** Archive :ARCHIVE:
*** TODO 匈牙利命名法
:PROPERTIES:
:ARCHIVE_TIME: 2010-01-02 六 18:14
:END:
外部归档
外部归档是指把子树移动到另一个org文件中去。文件名可以自定义。默认情况下,归档的子树会被移动到名为“当年文件名_archived”的文件中去。
C-c C-x C-s是把当前的节点移到archived文件中去。
我个人还是更喜欢在文件内部做归档。因为它兼具归档的好处和查找的方便。
在任何一个树的子树中,只有一个archive子树,只占文档的一行,当你居然查看以前存档的事件时,只能在这个节点上使用”C-TAB”命令即可打开。
Emacs的org-mode [agenda view]
假设你已经有了一个或多个带有TODO项目的org文件了,里面不少TODO项目还打上了DEADLINE或SCHEDULED时间戳。你打算怎么观赏它?怎么从一大堆项目中找到今天要处理的事情?打开所有的节点搜索?还是创建时按时间顺序排列?
都不需要,用agenda view就够了。这是一种视图,所谓视图,在我看来就是展示数据的方式。
agenda view就是要把你的数据,按时间来排列分割,然后展示给你看的。在你打开Emacs的任何时候,可以用(C-c a a)来打开agenda view。它的效果如图:

以图中23日的日程来看。它的数据展示规则是这样的。
第一部分是一个按时间分割的列表,它并不是每一天都有的,只有你当天的项目除了日期之外还定义了时间的情况下,它才会出现,并以两个时为间隔,将你的项目插入其中。而没有定义具体时间的当天项目,则在之后排队显示。
第二部分,没有具体时间的项目。第一列是TODO项目所在的org文件名,我这里有home,work,linux三个文件。第二列,显示这个项目是被分配在今天,还是在今天到期。Scheduled就是设置在今天的工作项,而Deadline就是指该项目在今天到期。而”In 2 d.”则表示这一项目在两天后到期。之后是描述。如果你的项目有tags的话,它将会在最后一列显示。
agenda view提供四种视图,分别是日(d),周(w),月(v m),年(v y),括号里是切换这四种视图的快捷键。用哪种视图纯属个人喜好,我觉得一方面是看你每天的日程多不多,另一方面可以取决于你在什么样的高度查看你的日程。
tags与情境
情境(context),在时间管理的概念中就是按所处的环境来分割TODO项目。比如说某些事是在网络上做的,某些事是在公司做的,某些事是在家里做的。
当然你可以把不同的情境分别放在不同的文件里。不过如果情境比文件的粒度要小,比如说你在家里有三个情境,”厕上”"床上”"电脑前”,而这些情境都属于“home”,你无须创建三个文件,而可以将它们全部放在home.org中,然后分别打上不同的标签。打标签的命令可以用(C-c C-q)。
之后如果你要做床上的事,可以敲(C-c a m),按提示输入标签,就可以显示所有符合条件的项目。
(C-c a)是打开agenda view的命令,而后面的m a可以看作是参数,用于打开不同的视图。如前所见,(C-c a a)是一种日历式的视图。(C-c a m)是一种可以指定Tags显示的视图。当然还有很多,按(C-c a)之后,界面上会有提示。
要做了以上这些事情,你还需要做一个配置,目的是要让agenda view知道,它应该从哪些个org文件里面取数据。
在你的.emacs文件中,添加:
(setq org-agenda-files (list "~/doc/org/linux.org"
"~/doc/org/work.org"
"~/doc/org/home.org"))
你尽可以在后面添加自己需要的org
Emacs的org-mode [日期与时间]
设定日程或期限
你可以为你的TODO项目设定时间,最普通的是日程,比如说杨威利同学需要在伊谢尔伦新年酒会上致祝酒辞。他可以用S-M-RET创建一个TODO项目。然后按C-c C-s为它设定日期和时间。按完“C-c C-s”之后,会出现一个新的小buffer(emacs的窗口),这时可以用鼠标或Shift+方向键来选取需要的日期。结果大概是这样的。
** TODO 在新年酒会上致辞。
SCHEDULED: <2009-12-31 四>
设定一个TODO项目如“罗马帝国衰亡史”,然后按”C-c C-d”,在出现的buffer中选中需要的日期,保存。结果是这样的。
** TODO 罗马帝国衰亡史
DEADLINE: <2010-01-02 六>
揗环的任务
每个人都会有一些循环的任务,比如说每两天去一次健身房,每周收拾一次房间等等,每月还个信用卡等等……针对这样的需要,只要在TODO项的时间里面,加一个repeater就可以了。
** TODO 还信用卡
DEADLINE: <2010-01-26 二 .+1m>
- CLOSING NOTE [2009-12-26 六 18:22]
:PROPERTIES:
:LAST_REPEAT: [2009-12-26 六 18:21]
:END:
日期后面的.+1m代表这一任务在每月循环一次,当你用C-c C-t改变Item状态之后,这个项目并不会从TODO变成DONE,而是保持TODO状态,同时它的DEADLINE从12-26变成1-26,下面出现一个12-26的CLOSING NOTE,表示这个项目在12月26日被标记为DONE过。
repeater标记分为日(d),周(w),月(m),年(y)四种,同时支持在时间关键字前面添加数字,代表每n个时间周期。比如+3d表示每隔三天,+3w表示每隔三周等。
任务计时
兰迪波许教授在他的最后的讲演之后闻名全球,他还有一个演讲提到了时间的记录time log,就像记账来统计自己的金钱支出一样,时间记录也可以为于了解自己的时间花费,已优化时间的使用。
org-mode提供了一种计算每项任务花了多长时间的能力。
* DONE 艺伎
CLOSED: [2009-12-20 日 20:09]
CLOCK: [2009-12-20 日 19:32]--[2009-12-20 日 20:09] => 0:37
CLOCK: [2009-12-20 日 18:00]--[2009-12-20 日 18:56] =>; 0:56
上面这个记录了我观看BBC记录片<艺伎>的时间花费,org-mode可以记录两段时间的起止,并计算出每段的时间花费。
你需要做的就是在开始时按”C-c C-x C-i”开始计时,在需要结束计时时按”C-c C-x C-o”即可。
页面
Categories
- 92383 (1)
- lonely planet (25)
- Uncategorized (1)
- 一些故事 (3)
- 利其器 (10)
- 善其事 (62)
- 小说翻译 (2)
- 负暄琐话 (74)
laihj



