本文翻译自 http://doc.norang.ca/org-mode.html ,原文作者为Bernt Hansen 由于原文较长,因此会分多篇文章来发布转载请标记出处,我来为大家科普一下关于linux文件管理哲学?下面希望有你要的答案,我们一起来看看吧!

linux文件管理哲学(Org-mode用文本文件管理日常)

linux文件管理哲学

本文翻译自 http://doc.norang.ca/org-mode.html ,原文作者为Bernt Hansen 。由于原文较长,因此会分多篇文章来发布。转载请标记出处。

Org-mode, 用文本文件管理日常(一)

Org-mode, 用文本文件管理日常(二)

Org-mode, 用文本文件管理日常(三)

Org-mode, 用文本文件管理日常(四)

Org-mode, 用文本文件管理日常(五)

Org-mode, 用文本文件管理日常(六)

Org-mode, 用文本文件管理日常(七)

Org-mode, 用文本文件管理日常(八)

Org-mode, 用文本文件管理日常(九)

Org-mode, 用文本文件管理日常(十)

Org-mode, 用文本文件管理日常(十一)

Org-mode, 用文本文件管理日常(十二)

Org-mode, 用文本文件管理日常(十三)

Org-mode, 用文本文件管理日常(十四)

Org-mode, 用文本文件管理日常(十五)

Org-mode, 用文本文件管理日常(十六)

哪些我不再使用功能

下面列了些我知道的功能,但是我不怎么用它们。org-mode 包含大量功能。有很多功能我还不清楚或者说还没有暴露出来,所以这个列表暂时还没有完成。

归档相同层级的子树

这个是个可笑的想法,但是我觉得归档整个子树更合适些。我不介意大量任务被标记DONE (还没有归档)。

处理字符格式

当从其它文件拷贝文本到org-mode文件中,字符中的格式会使得文档可读性很差。通过如下设置,可以移除字符中格式,这样看上去更好点。

(setq org-emphasis-alist (quote (("*" bold "<b>" "</b>") ("/" italic "<i>" "</i>") ("_" underline "<span style=\"text-decoration:underline;\">" "</span>") ("=" org-code "<code>" "</code>" verbatim) ("~" org-verbatim "<code>" "</code>" verbatim))))

下标以及上标

我目前不会写些需要下标以及上标的文档。我通过下面方法禁用 _ 以及 ^ .

(setq org-use-sub-superscripts nil)

Yasnippet

Yasnippet 很棒,但是我不怎么用了。我使用 abbrev-mode以及 skeletons 来替换yasnippet,并且他们默认在emacs中就可用的。

Yasnippet 包含很多代码语言片段。我在 org-mode 中使用少量的babel相关的代码片段。

我下载安装了非绑定的版本的yasnippet,这样我就可以编辑预定义的代码片段。我将yasnippet解压到我的 ~/.emacs.d/plugins 目录,重命名 yasnippet0.5.10 为 yasnippet然后添加进我的 =.emacs=中。

我是这么使用代码片段:

下面是 begin 代码块定义:org-mode Yasnippet: ~/.emacs.d/plugins/yasnippet/snippets/text-mode/org-mode/begin

#name : # begin_...# end_ # -- # begin_$1 $2 $0 # end_$1

我这样创建 # begin_** 代码块

输入 begin 然后按 TAB 然后 begin 文本就会替换成代码段。当输入src TAB emacs-lisp TAB 代码块就完成了。我将这个流程缩减成 elisp TAB因为我经常用。

输入 C-c SingleQuote(') 就会插入你需要的emacs-lisp 代码。当进入这个块中,你就可以在一种你知道的格式以及相应着色的emacs lisp 脚本,非常好。 C-c SingleQuote(‘) 退回到org-mode。它可以识别任何emacs编辑模式,所以你只需要输入合适的mode名称即可。

dot

#dot : # begin_src dot ... # end_src # -- # begin_src dot :file $1 :cmdline -Kdot -Tpng $0 # end_src

uml

#uml : # begin_src plantuml ... # end_src # -- # begin_src plantuml :file $1 $0 # end_src

sh

#sh: # begin_src sh ... # end_src # -- # begin_src sh :results output $0 # end_src

elisp

#elisp : # begin_src emacs-lisp ...# end_src emacs-lisp # -- # begin_src emacs-lisp $0 # end_src

节省了非常多时间。

只在奇数行或者偶数行显示标题

这个我已经使用org-indent-mode替换了。

我使用函数 org-convert-to-odd-levels 以及 org-covert-to-oddeven-levels 函数转换成奇数行或者偶数行。我最终会设置为奇偶行,这样可以减少任务上的空格。我不觉得只显示奇数行很好,当然全部显示也不是特别好。

同时设置父任务STARTED状态

我曾经既使用 STARTED 又使用 NEXT 状态。大部分情况来说他俩一个意思,唯一区别就是STARTED 可以表示任务刚开始计时。然后我就会将该任务设置成 NEXT 状态。

下面代码用来将 STARTED 状态同时应用在父任务上,但是目前我不这么用了。当一个任务被标记成 STARTED 状态(不管是手工还是计时器),那么它的父任务如果在 TODO或者 NEXT 时候就会被标记成 STARTED 状态。只要对第一个 NEXT 子任务标记成 STARTED那么父任务也会一样被标记。这能帮我跟踪正在进行的任务。

下面是这个功能的实现:

;; Mark parent tasks as started (defvar bh/mark-parent-tasks-started nil) (defun bh/mark-parent-tasks-started () "Visit each parent task and change TODO states to STARTED" (unless bh/mark-parent-tasks-started (when (equal org-state "STARTED") (let ((bh/mark-parent-tasks-started t)) (save-excursion (while (org-up-heading-safe) (when (member (nth 2 (org-heading-components)) (list "TODO" "NEXT")) (org-todo "STARTED")))))))) (add-hook 'org-after-todo-state-change-hook 'bh/mark-parent-tasks-started 'append)

自动计时任务

我曾经在开源软件BZFlag做贡献。当需要发布时候,我会对测试BZFlag客户端计时。

我有个按键绑定在我的窗口管理器中,当执行该快捷键,就会对测试任务计时,并运行BZFlag客户端,当完成,恢复之前的任务计时。

(defun bh/clock-in-bzflagt-task () (interactive) (bh/clock-in-task-by-id "dcf55180-2a18-460e-8abb-a9f02f0893be"))

该函数通过shell脚本调用:

,#!/bin/sh emacsclient -e '(bh/clock-in-bzflagt-task)' ~/git/bzflag/trunk/bzflag/src/bzflag/bzflag -directory ~/git/bzflag/trunk/bzflag/data $* emacsclient -e '(bh/resume-clock)'

恢复计时函数将计时器应用到之前的计时任务上。

(defun bh/resume-clock () (interactive) (if (marker-buffer org-clock-interrupted-task) (org-with-point-at org-clock-interrupted-task (org-clock-in)) (org-clock-out)))

如果没有任务通过 bh/resume-clock 停止计时。

按键q隐藏agenda视图缓冲区

通过 Sticky Agendas ,q键默认行为就是退出缓冲区,因此这个目前暂时不需要了。

我修改了agenda中 q 按键,替换关闭agenda 缓冲区,取而代之将其放入buffer list最尾端。这样我就可以使用 q 来快速将agenda视图切换回来,或者通过 =f9 f9=重新生成agenda视图。

(add-hook 'org-agenda-mode-hook (lambda () (define-key org-agenda-mode-map "q" 'bury-buffer)) 'append)

任务优先级

我使用agenda来选择下个需要做的任务。通常我不会用优先级来处理,但是在工作中我会从我的经理那边获取有些优先级搞的任务。这种情况我会将这个任务标记成高优先级。这时会让agenda按照优先级来显示任务。

我使用A-E来标记任务优先级,没有明确标记的任务使用最低的E优先级。

# beginsrc emacs-lisp(setq org-enable-priority-commands t)(setq org-default-priority ?E)(setq org-lowest-priority ?E)# endsr

使用git来同步历史,备份以及同步数据

修改org文件中折叠区域非常危险。我的做法是将org文件纳入 git 管理。

我的设置会每个小时保存所有的org文件,并自动创建commit。这方便我及时回退并查看我的org状态,在文档生命周期期间。我使用这种方法来恢复我不小心删除的折叠区域的数据。

自动定时提交

我的emacs设置一小时前1分钟开始保存所有org缓冲区。代码包含在 .emacs 中

(run-at-time "00:59" 3600 'org-save-all-org-buffers)

cron 任务任务每小时通过 org-save-all-org-buffers 保存所有缓冲区。我使用脚本来提交代码,因此我可以按需要提交代码,并当从一台机器移动到另一台机器,方便拉取所有修改。

crontab 细节:

0 * * * * ~/bin/org-git-sync.sh >/dev/null

~/bin/org-git-sync.sh

下面是shell脚本来创建所有的 git 提交。该循环遍历多个仓库,提交所有修改的文件。我有如下几个org-mode仓库。

下面脚本不会创建空commit - git 只会对有修改的才会创建commit.

,#!/bin/sh # Add org file changes to the repository REPOS="org doc.norang.ca www.norang.ca" for REPO in $REPOS do echo "Repository: $REPO" cd ~/git/$REPO # Remove deleted files git ls-files --deleted -z | xargs -0 git rm >/dev/null 2>&1 # Add new files git add . >/dev/null 2>&1 git commit -m "$(date)" done

我使用如下的 .gitignore 文件来在我的 git 仓库中排除自动生成的文件。如果需要导入ditaa或者graphviz我将会将其加到我的repo总。默认情况下所有PNG图像都被忽略(默认情况下我认为他们都是由 ditaa生成)

core core.* *.html *~ .#* \#*\# *.txt *.tex *.aux *.dvi *.log *.out *.ics *.pdf *.xml *.org-source *.png *.toc

Git- 让编辑更加自信

我在我所有目录下都用git,这样我所有的更新都可以通过git来跟踪。

这意味着我可以很自信的修改文件。改文件,破坏文件对我来说也不是问题。通常我也非常方便回退到之前版本,来查看修改了那些东西。当修改配置文件时候,也非常方便(例如 apache webserver,bind9 DNS配置等。)

这非常方便,修改文件可能让破坏文件,但是如果有 git 来跟踪修改,那么你会很方便快速找回之前版本。当然包更新也是可以用git来管理。我将每个修改都保存在我的 git 仓库中。

git仓库同步

我买了台 Eee PC 1000 HE作为我的主要工作电脑来替换我的6年的 Toshiba Tecra S1.我有个LAN服务器作为我所有项目的git仓库。现在唯一的问题是我需要保留5分钟来保证我所有的文档更新到最新,当我把它带出去(没有网络连接)。

为解决这个问题,我在上面建了个bare仓库。它包含我的org-mode仓库以及其他感兴趣的仓库。

当我需要出去,我会通过 git-sync 脚本将我的工作站的bare git仓库更新到我的Eee PC上。对于merge冲突的仓库我先手动解决冲突,然后重新运行git-sync 直到没有报错。这可能会花一到两分钟。然后我就可以带着我的Eee PC离开。当我在路上,我就有所有的历史以及git仓库。

git-sync 脚本替换我之前的脚本,它里边包含所有用到的工具。它能够完成如下工作:

这会使得我电脑上35个仓库自动更新,用最少的干预。我需要人工处理的只剩我在Eee PC以及我的工作站修改冲突– 这样就可以merge了。

下面是我的 git-sync 脚本。

,#!/bin/sh # # Local bare repository name syncrepo=norang reporoot=~/git # Display repository name only once log_repo() { [ "x$lastrepo" == "x$repo" ] || { printf "\nREPO: ${repo}\n" lastrepo="$repo" } } # Log a message for a repository log_msg() { log_repo printf " $1\n" } # fast-forward reference $1 to $syncrepo/$1 fast_forward_ref() { log_msg "fast-forwarding ref $1" current_ref=$(cat .git/HEAD) if [ "x$current_ref" = "xref: refs/heads/$1" ] then # Check for dirty index files=$(git diff-index --name-only HEAD --) git merge refs/remotes/$syncrepo/$1 else git branch -f $1 refs/remotes/$syncrepo/$1 fi } # Push reference $1 to $syncrepo push_ref() { log_msg "Pushing ref $1" if ! git push --tags $syncrepo $1 then exit 1 fi } # Check if a ref can be moved # - fast-forwards if behind the sync repo and is fast-forwardable # - Does nothing if ref is up to date # - Pushes ref to $syncrepo if ref is ahead of syncrepo and fastforwardable # - Fails if ref and $syncrop/ref have diverged check_ref() { revlist1=$(git rev-list refs/remotes/$syncrepo/$1..$1) revlist2=$(git rev-list $1..refs/remotes/$syncrepo/$1) if [ "x$revlist1" = "x" -a "x$revlist2" = "x" ] then # Ref $1 is up to date. : elif [ "x$revlist1" = "x" ] then # Ref $1 is behind $syncrepo/$1 and can be fast-forwarded. fast_forward_ref $1 || exit 1 elif [ "x$revlist2" = "x" ] then # Ref $1 is ahead of $syncrepo/$1 and can be pushed. push_ref $1 || exit 1 else log_msg "Ref $1 and $syncrepo/$1 have diverged." exit 1 fi } # Check all local refs with matching refs in the $syncrepo check_refs () { git for-each-ref refs/heads/* | while read sha1 commit ref do ref=${ref/refs\/heads\//} git for-each-ref refs/remotes/$syncrepo/$ref | while read sha2 commit ref2 do if [ "x$sha2" != "x" -a "x$sha2" != "x" ] then check_ref $ref || exit 1 fi done done } # For all repositories under $reporoot # Check all refs matching $syncrepo and fast-forward, or push as necessary # to synchronize the ref with $syncrepo # Bail out if ref is not fastforwardable so user can fix and rerun time { retval=0 if find $reporoot -type d -name '*.git' | { while read repo do repo=${repo/\/.git/} cd ${repo} upd=$(git remote update $syncrepo 2>&1 || retval=1) [ "x$upd" = "xFetching $syncrepo" ] || { log_repo printf "$upd\n" } check_refs || retval=1 done exit $retval } then printf "\nAll done.\n" else printf "\nFix and redo.\n" fi } exit $retval

,