GNU Emacs 一直以來就是一個寫作的利器。從最初的 text-mode, muse-mode,直到今天的 org-mode,Emacs 下的寫作正在變得越來越舒適,越來越具有表現力。尤其是現在的 org-mode,不僅可以 GTD,可以記筆記,甚至已經達到了“只有想不到的,沒有做不到的”的境地。就連 Emacser 的各位童鞋們也都在使用 org-mode 進行寫作。
但是,不管到了什麼時候,懶惰總是一個亙古不變的真理。懶得大發的時候,就會覺得只有把大餅套在脖子上這樣的日子才是最舒服的。所以呢今天就和大家分享幾個使用 org-mode 寫作時候常用的偷懶的方式。
org-mode 的日常操作其實已經足夠方便了。標籤式的書寫方式效率要遠高於菜單式的書寫方式(例如 Word 或者現在的 WPS)。同時由於 Emacs 的強大和靈活,使得 org-mode 在古老的標籤式書寫的方式下,一定程度上實現了所見即所得 (WYSIWYG)的效果。但是,總有一些標籤,由於太長,太常出現,還是難免成為寫作時候的負擔。這種負擔不僅僅 表現在輸入工作量的增加上,由於很多標籤是要成對出現的,配對的缺失和對這些缺失的檢查和修補真可以稱得上是世上最痛苦同時又最沒有價值的負擔。例如引用 代碼、範例的標籤, #+begin_src #+end_src , #+BEGIN_EXAMPLE #+END_EXAMPLE 等等 。特別是在技術類文章裡面,經常需要大量引用範例、代碼等等內容的時候,真的會變成“是可忍孰不可忍”了。
解決這個問題,基本上有兩套解決方案。一個方案是 abbrev + skeleton,一個方案就是 eLisp code 了。這兩種方案無所謂孰優孰劣,只是各自解決不同的問題。指導思想都是一樣的,那就是讓 Emacs 去操心輸入和配對兒的事情。凡事只要不用人去操心了,我們就可以暫時認為這事兒就不存在了。
- 1 skeleton
- 1.1 iexp
- 1.2 isrc
- 1.3 iprop
- 1.4 ihtml
- 2 eLisp
- 2.1 iexp
- 2.2 isrc
- 2.3 ihtml
- 2.4 base function
- 2.5 i=
- 3 後記 Export 中遇到問題
1 skeleton
Skeleton 作為一種 自動輸入 的好方法,主要解決的是白紙一張時候的問題,解決的思路是化繁為簡。通過預先定義好的 Skeleton,將複雜、易錯的配對標籤替換為簡短、易記的 Skeleton 標籤,在輸入的一開始就確保一切都井然有序,包括游標位置都讓它正確定位,當標籤不再需要人工配對的時候,配對就可以認為不再是個問題了。
當然你也可以用 yasnippets 或者其他類似的工具。用 Skeleton 的目的只是因為它簡單、直接。下面讓我們看幾個例子:
1.1 iexp
(define-skeleton 1exp "Input #+BEGIN_EXAMPLE #+END_EXAMPLE in org-mode""""#+BEGIN_EXAMPLE\n" _ "\n" "#+END_EXAMPLE") (define-abbrev org-mode-abbrev-table "iexp" "" '1exp)
這個 Skeleton 解決的是 #+BEGIN_EXAMPLE #+END_EXAMPLE 標籤的問題。通過上面這個 Skeleton,只要在 org-mode 的 buffer 裡面輸入 iexp,就會自動擴充成 org-mode 的範例片段,就像下面這樣,同時把游標自動定位在兩行內容的中間,等待你的進一步輸入。
#+BEGIN_EXAMPLE
#+END_EXAMPLE
1.2 isrc
(define-skeleton 1src "Input #+begin_src #+end_src in org-mode""""#+begin_src lisp \n" _ "\n" "#+end_src") (define-abbrev org-mode-abbrev-table "isrc" "" '1src)
上面這個 skeleton和 iexp 非常類似, 只是擴充出來的是 org-mode 的程式碼片段,使用方式是輸入 isrc, 同樣會把游標定位在兩行的中間,等待使用者輸入代碼。
#+begin_src lisp
#+end_src
1.3 iprop
(define-skeleton 1prop "Input :PROPERTIES: :END: in org-mode""">":PROPERTIES:\n"> _ "\n" >":END:") (define-abbrev org-mode-abbrev-table "iprop" "" '1prop)
:PROPERTIES: 屬性在 GTD 的時候經常會用到。雖然 org-mode 提供了各種按鍵組合來輸入各種 :PROPERTIES: ,但是很多時候,直接輸入 :PROPERTIES: 內容顯然要比記憶那些複雜的按鍵組合要容易的多。
在這裡要注意的是,由於 :PROPERTIES: 經常與 org-mode 的 heading 一起使用,所以需要考慮到縮排的問題。在這個 Skeleton 定義裡面加入的 > 字元,就是為了根據當前使用環境,在擴充的時候進行正確的縮排。使用的時候輸入 iprop,可以得到下面的內容
:PROPERTIES:
:END:
1.4 ihtml
(define-skeleton insert-emacser-code "" "" "#+BEGIN_HTML\n""<pre lang=\"lisp\" line=\"1\">\n"_"\n""</pre>\n""#+END_HTML\n")(define-abbrev org-mode-abbrev-table "ihtml" "" 'insert-emacser-code)
最後這個 Skeleton 看起來有點複雜了,因為這個不是 org-mode 的預設格式。這個是給 Emacser.com 寫稿的時候引用程式碼片段所需的外框。在寫作的時候只要輸入 ihtml,就可以擴充成下面的內容 note 。
#+BEGIN_HTML
<pre lang="lisp" line="1">
</pre>
#+END_HTML
上次發稿的時候由於忘記了這個 Skeleton,所有的代碼、範例全都寫成了 org-mode 預設的標籤,完成之後才想起來,然後又手工刪除並補寫了 Emacser.com 需要的標籤,再然後,相信我不說你們也猜的出來了,慘痛的的教訓啊!!! 以後一定要記得用 Skeleton 啊。
2 eLisp
俗話說,“一張白紙好作畫”。白紙一張的日子畢竟不會是生活的全部。當紙已經變得不白的時候,當那些代碼、範例都已經在那裡了的時候,我們總不能當一切的一切都已經“不可挽回”的時候,我們就需要藉助 eLisp 的處理能力,讓我們在已經選擇的道路上面能夠走得更好。解決思路,面對現實。承認已經存在的現實,把該補的東西補上去就是了。只要這個活兒是 Emacs 幹,不是我們幹,那就不是問題。
2.1 iexp
(defun iexp (St Ed) "Enclose example for org-mode" (interactive "r") (let ((beg St) (end Ed)) (message "%s %s" beg end) (i-babel-quote beg end "#+BEGIN_EXAMPLE" "#+END_EXAMPLE")))
這個函數對應於上面的 iexp Skeleton。使用的時候,選中要處理的範例片段,然後輸入 M-x iexp ,即可在選中的範例兩端加入相應的內容。
例如下面這樣的內容
(require-extensions 'require (list 'tabbar 'switch-window 'thing-edit 'second-sel 'browse-kill-ring+))
通過 M-x iexp 命令,就會變成這樣的內容
#+BEGIN_EXAMPLE(require-extensions 'require (list 'tabbar 'switch-window 'thing-edit 'second-sel 'browse-kill-ring+))#+END_EXAMPLE
2.2 isrc
同樣的道理應用在 isrc 函數上面。 這個函數對應上面的 isrc skeleton。同樣也是選中要處理的範例片段,然後輸入 M-x isrc ,即可在選中的範例兩端加入相應的內容。在這個裡面有一個小小的設計,就是處理完成之後游標會被定位在 #+begin_src 的後面,方便輸入程式設計語言的名稱。
(defun isrc (St Ed) "Enclose code for org-mode" (interactive "r") (let ((beg St) (end Ed)) (message "%s %s" beg end) (i-babel-quote beg end "#+begin_src " "#+end_src")))
2.3 ihtml
這個 ihtml 函數就是上次給 Emacser.com 寫稿的時候用“鮮血”換來的啊。我要是早點兒把這個東西寫出來該有多好啊。每次想到這裡總會想到胖兔子粥粥說到的 和拖拉死磕到底 。其實我真正想說的潛台詞還是——要是早一點兒能夠元旦放假該有多好啊,那樣的話我肯定就把這個函數寫了麼。汗啊。
使用方法同樣是選中要用的代碼,然後輸入 M-x ihtml 命令。由於 Emacser.com 的標籤行數比較多,這裡用了 concat 函數做了處理。
(defun ihtml (St Ed) "Enclose code for Emacser.cn" (interactive "r") (let ((beg St) (end Ed)) (message "%s %s" beg end) (i-babel-quote beg end (concat "#+BEGIN_HTML\n " "<pre lang=\"lisp\" line=\"1\">\n") (concat "</pre>\n" "#+END_HTML\n") )))
2.4 base function
最後還是依照以前的慣例,在介紹完出鏡的美女以後,讓我們來認識一下踏實幹活、默默奉獻的基礎函數吧。所有上面的函數都是通過這個基礎函數完成補全的工作的。讓我們為這個函數鼓掌。
(defun i-babel-quote (beg end str1 str2) (goto-char end) (forward-line 1) (insert str2) (newline) (goto-char beg) (forward-line -1) (newline) (insert str1))
2.5 i=
最後的最後,再饒一個小小的函數。這個函數是處理行內(inline)代碼的。說白了就是在所選文字的首尾加上一組等號。就這麼簡單個事情,如果處理的數量多的時候也是一個不小的負擔。尤其是當文章已經寫好,或者是處理拷貝過來的的內容的時候。
使用方法和上面的函數一樣,選中所需的內容,然後輸入 M-x i= 就一切就都處理完畢了。
(defun i= (St Ed) "" (interactive "r") (let ((beg St) (end Ed)) (goto-char end) (insert "=") (goto-char beg) (insert "=") (goto-char (+ end 2))))
3 後記
這篇文章原創非轉載。首發於 Emacser.com