上一篇我們完成了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
來直接調用的。所以上述代碼使用 #
這個語法糖來保證后續正常調用這個符號對應的函數部分。