上一篇我们完成了emacs输入法的配置以及将emacs配置成了使用vim的操作方式。但是emacs目前有些默认行为我不太喜欢,这节我们一起来修改它
备份设置
我们打开emacs的配置文件所在路径,发现有大量的~
结尾的文件,这是emacs的备份文件。这里,我们不使用这个特性,可以通过git等版本管理软件进行版本的控制和备份的管理。而且去掉这些还能让目录干净点。
(setq make-backup-files nil) ; 不自动备份
(setq auto-save-default nil) ; 不使用Emacs自带的自动保存
将用户设置独立开来
在修改这些配置的时候经常会发现在init.el 中出现类似下面的代码被修改
(custom-set-variables;; custom-set-variables was added by Custom.;; If you edit it by hand, you could mess it up, so be careful.;; Your init file should contain only one such instance.;; If there is more than one, they won't work right.'(package-selected-packages nil))
(custom-set-faces;; custom-set-faces was added by Custom.;; If you edit it by hand, you could mess it up, so be careful.;; Your init file should contain only one such instance.;; If there is more than one, they won't work right.)
这里保存的是使用编辑器接口产生的配置信息。如果让它们随意堆砌在init.el 中不利于版本的管理,我们将它放入到另一个文件中
(setq custom-file (expand-file-name "~/.emacs.d/custom.el"))
(load custom-file 'no-error 'no-message)
之前我们用 require
来加载一个代码文件,这里我们使用 load
来加载代码文件。它们有什么区别呢?
- 首先
require
需要加载一个已经被定义为库的代码文件,也就是通过provide
定义的库文件。而load传入文件路径来加载 - 其次
require
会根据provide
定义的库文件自动处理库文件,每个库文件只加载一次,并且会自动处理依赖。而load
这些操作都需要手动进行 load
可以根据if条件来有选择的加载不同的库文件。而require
则无法做到load
可以进行错误处理,例如上面我们定义在加载时通过noerror
限制错误,通过no-message
不输出信息。而require
是严格报错的。
其他的一些基础设置
这里再添加一些其他的基础配置
(fset 'yes-or-no-p 'y-or-n-p) ;; 将所有的 yes-or-no-p 都替换为 y-or-n-p
(setq confirm-kill-emacs #'y-or-n-p) ; 在关闭 Emacs 前询问是否确认关闭,防止误触
(electric-pair-mode t) ; 自动补全括号
(column-number-mode t) ; 在 Mode line 上显示列号
(global-auto-revert-mode t) ; 当另一程序修改了文件时,让 Emacs 及时刷新 Buffer
(delete-selection-mode t) ; 选中文本后输入文本会替换文本(更符合我们习惯了的其它编辑器的逻辑)(add-hook 'prog-mode-hook #'hs-minor-mode) ; 编程模式下,可以折叠代码块
(add-hook 'prog-mode-hook #'show-paren-mode) ; 编程模式下,光标在括号上时高亮另一个括号
(fset 'yes-or-no-p 'y-or-n-p)
将所有的 yes-or-no-p
都替换为 y-or-n-p
。这样在每次确定的时候能从 yes 或者 no的输入变成输入 y 或者 n,能少输入几个字符。
这里又看到了一个新的符号#
,它代表的意思是取符号的函数部分。前面我们介绍符号的时候说,符号有两个部分的值,变量值和函数值。我们可以通过 function
来获取符号的函数部分的值。它的作用等同于 (setq confirm-kill-emacs (function y-or-n-p))
。
这里又有一个新的函数 function
。我们在介绍符号的时候介绍过使用 symbol-function
来获取符号的函数,那么他们两个有什么区别呢?
首先 function
返回的是函数对象,而 symbol-function
返回函数本身。这个比较的抽象,我们使用例子来说明
(setq bar "I am a bar variable")
(defun bar()"I am a bar function")(function bar) ;; ==> bar
(symbol-function 'bar) ;; ==> #[nil ("I am a bar function") (t)](functionp bar) ;; ==> nil
(functionp (function bar)) ;; ==> t
上面的例子中,我们实际上定义了bar的变量部分和函数部分的值。同一 bar
符号它既可以作为变量使用,也可以作为函数使用。我们在使用 function
对 bar
求值的时候,得到的返回虽然也是 bar
但是它返回的是它的函数部分,而 symbol-function
则直接返回函数的结构,因为lisp代码本身就是一个列表结构,所以这里它返回的实际上是函数的代码。它返回的比 function
更加的底层。
下面我们使用 functionp
进行了测试,发现 function
返回的是一个函数对象。
虽然在理解上有些差别,但是都可以直接通过 funcall
来调用
(bar) ;; ==> "I am a bar function"
(funcall bar) ;; ==> error
(funcall (function bar)) ;; ==> "I am a bar function"
(funcall (symbol-function 'bar)) ;; ==> "I am a bar function"
我们发现当一个符号既有值部分,又有函数部分,是无法通过 funcall
来直接调用的。所以上述代码使用 #
这个语法糖来保证后续正常调用这个符号对应的函数部分。