上一章:文本跨行提取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))
等价。
能少些一些代码,很不错。