博客 / 詳情

返回

Emacs 是他們的,也是我的

上一篇:讓 Emacs 略帶感性

Emacs 用了一段時間後,只要你一時沒忍住,安裝了幾個插件,就會發現 init.el 文件實屬兵家必爭之地。

你親力親為所作的那部分配置,與一堆陌生的配置混在一起,一旦出現某些衝突,通常很難快速確定問題出在何處。我們有必要對 init.el 中的配置盡力予以隔離。至少,我們真正清楚的那部分配置,可隔離出來,單獨存放於一份 .el 文件中,然後在 init.el 文件裏將其載入。一方面可以控制 init.el 的複雜度,另一方面也便於問題排查。

Emacs 提供了一個列表類型的全局變量 load-path。假設我們將自己清楚的那部分配置代碼從 init.el 中移除,將其單獨存放在 ~/.my-emacs 目錄裏的 my-config.el 文件,然後只需將該目錄添加到 load-path,之後便可在 init.el 裏用 load 載入 my-config.el 文件了。

現在,為 init.el 添加以下代碼

(setq load-path (cons "~/.my-emacs" load-path))
(load "my-config.el")

之後每次打開 Emacs,它都會自動從 ~/.my-emacs 加載 my-config.el 文件,從而使得我們的配置代碼生效。

上述代碼所用的 cons,我在講述關聯列表時提起過它一次,當時是用它構造鍵值對,實際上,它也能用於構造列表。至於 load,只需知道它能從 load-path 列表中目錄搜索給定名字的文件並載入,除此之外,它也沒有更多用途了。

conscar 以及 cdr 是所有 Lisp 語言最為基礎的函數。在早期的 Lisp 機上,它們甚至是 CPU 可直接執行的指令。我們之所以一直沒有像那些 Lisp 教科書,從一開始就介紹它們的作用和意義,原因是 Emacs 已經基於它們實現了許多高級功能,以至於我們幾乎不需要使用它們,就已經能夠編寫許多有用的程序了,但作為 Lisp 語言之根本,不掌握它們,近乎數典忘祖。

首先回顧一下,這三個基礎函數在鍵值對或二元組方面的用法:

(let ((x (cons 1 2)))  ;; x 為 (1 . 2)
  (car x)  ;; 結果為 1
  (cdr x))  ;; 結果為 2

現在,用 cons 構造列表,例如

(cons 1 nil)

(cons 1 '())

上述兩個表達式是等效的,它們的求值結果都是 (1) 即只含有單個元素的列表,且元素為 1。另外,你應當明白了,在 Elisp 語言裏,nil'(),反之亦然。'() 即空列表,故而 nil 也是空列表,你可以試着對以下表達式求值,以確認這個事實。

(equal nil '())

equal 是 Elisp 語言裏最為通用的相等測試函數,它不僅要比較兩個值是否相等,也要比較它們的類型是否相同。上述表達式求值結果為 t,足以證明 nil'()

再看以下示例:

(let ((x (cons 1 nil)))
  (car x)  ;; 結果為 1
  (cdr x)) ;; 結果為 nil

再看以下示例:

(let ((x (cons 1 nil)))
  (setq x (cons 0 x)) ;; 結果為 (0 1)
  (car x)  ;; 結果為 0
  (cdr x)) ;; 結果為 (1)

你會發現,上述代碼中的 cdr 表達式的求值結果是一個列表。現在,你應該能認識到,若 x 是一個列表,則 (car x) 可以獲取 x 的首元素,而 (cdr x) 獲取的是 x 首元素之後的元素構成的列表,亦即 carcdr 可讓一個列表身首異處。至於 cons,它用於向列表首部追加一個元素,所以現在你應該清楚以下代碼的含義了!

(setq load-path (cons "~/.my-emacs" load-path))

函數 length,之前我們曾用它獲取過字符串的長度。實際上,它也可以用於獲取列表長度。例如

(length load-path)

在我的機器上,求值結果為 36,表示 load-path 已記錄了 36 個目錄。倘若你想查看它們,可以用 dolist 遍歷它,並逐一輸出目錄的路徑:

(dolist (dir load-path)
  (message "%s" dir))

練習:編寫一個遞歸函數 reverse-list,讓它可將列表 (0 1 2 3 4 5) 逆轉,結果為 (5 4 3 2 1 0),然後將其定義修改為 while 表達式的形式。

Emacs 提供了 push 函數,它可以簡化上述賦值表達式。例如

(push "~/.my-emacs" load-path)

以後,倘若我説,向 init.el 裏添加某些代碼時,你可以酌情考慮,是否應該將其加入你的 my-config.el 文件。我的建議是,my-config.el 永遠只存放你真正熟悉的那部分代碼,你甚至對其中每一行代碼都瞭如指掌,它們構成了你在 Emacs 世界的自主之地。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.