上一章:文本跨行提取segmentfault
從第 1 章就定義了的 princ\'
函數被我一路使用至今,我一直以爲它頗有用處,特別是在我調試程序的時候。我認可,用這種辦法調試程序很原始。不過,筷子也很原始。爲了避免再張貼完整的代碼之時附上它的定義,我決定創建一個 Elisp 庫,用於存放它的定義以及從此我定義的其餘函數。bash
我將這個庫的所有代碼存放在一份名爲 newbie.el 文件裏,目前只有 princ\'
的定義:函數
(defun princ\' (x) (princ x) (princ "\n"))
可是,newbie.el 應當放在何處?操作系統
系統環境變量 EMACSLOADPATH
可爲庫文件指定路徑。假設我將 newbie.el 放在 $HOME/.my-scripts/elisp
目錄裏,那麼在個人機器上,因爲我用的 Shell 是 Bash,所以可在 $HOME/.bashrc 文件裏設定調試
export EMACSLOADPATH=$HOME/.my-scripts/elisp:$EMACSLOADPATH
在當前終端裏執行code
$ source $HOME/.bashrc
或從新打開一個終端窗口,令上述設定生效。接口
假設我要寫一個 foo.el 程序,它須要調用 newbie.el 裏定義的函數 princ\'
,只需在調用 princ\'
以前,載入 newbie.el 便可。例如ip
(load "newbie") (princ\' "Hello world!")
在終端執行 foo.el 程序,get
$ emacs -Q --script foo.el
程序輸出emacs
Loading /home/garfileo/.my-scripts/elisp/newbie.el (source)... Hello world!
load
函數是 Elisp 的內建函數,它的第一個參數是庫文件名,可是沒有擴展名。由於 load
函數會在 $EMACSLOADPATH
指定的目錄中自動搜索三種庫文件。對於上例,load
函數會依序搜索 newbie.elc,newbie.el,newbie.ext 這三個文件,只要搜到其中之一,搜索過程便終止,而後將搜到的文件內容載入至當前程序。newbie.ext 中的「ext」取決於系統平臺,在 Linux 系統裏,「ext」是「so」;在 Windows 系統裏,「ext」是「dll」;亦即 newbie.ext 能夠是 C 語言接口的共享庫。沒錯,Elisp 能夠載入 C 庫,可是須要爲它們編寫接口綁定,這是後話,暫且不表。
若是不但願程序執行時在終端輸出庫的加載信息,只需令 load
函數的第三個參數爲 t
:
(load "newbie" nil t)
其中,第 2 個參數是被迫寫上的,由於沒有第 2,怎麼會有第 3 呢?第 2 個參數若是是 nil
,load
函數在搜索不到待載入的庫文件時會在終端裏輸出錯誤信息,不然不會。
系統變量 EMACSLOADPATH
的設定,依賴於具體的操做系統。不依賴操做系統的庫文件搜索路徑的設定方法也是有的。Emacs 有個全局變量 load-path
,它是列表。
若是我將 foo.el 程序修改成
(load "newbie" nil t) (princ\' load-path)
執行該程序,在個人機器上會獲得如下結果:
(/home/garfileo/.my-scripts/elisp /usr/share/emacs/27.2/lisp ...)
不難發現,我經過 EMACSLOADPATH
設定的路徑也被加入到了這個列表。
用 Elisp 語言如何操縱列表,如今應該是不廢吹灰之力,所以將 foo.el 程序寫成
(setq load-path (cons "$HOME/.my-scripts/elisp" load-path)) (load "newbie" nil t) (princ\' "Hello world!")
沒什麼理由不會在終端裏輸出
Hello world!
不過,Elisp 對列表提供了幾個能夠添加元素的函數,例如 push
。如下代碼
(push "$HOME/.my-scripts/elisp" load-path)
與
(setq load-path (cons "$HOME/.my-scripts/elisp" load-path))
等價。
能少些一些代碼,很不錯。