Spacemacs 的配置
Table of Contents
很早之前就聽說過 Spacemacs,並且簡單使用了一下,之前有被它的界面和初始化的流暢性震撼過。但是自己嘗試去配置時就放棄了,有點復雜,一層一層的 layer,配置一下還會報錯。最近一兩年,很少有時間折騰 emacs,最近稍微有點時間,想配置一個 vue,於是搜了一下 emacs + vue 相關的,發現 Spacemacs 的配置是最活躍的,經常有很多人在討論。並且,這個配置出來也已經有一兩年的時間了,可以說是經過了市場的驗證了。既然這么多人來貢獻配置出來的,自然在很多方面是比較成熟的。比單靠自己來配置要節省更多的時間,很多坑可能別人都已經解決。正是抱着這個希望,所以,重新按照教程把 Spacemacs 使用起來了。
1 安利
由於這個是多人參與維護的一個開源配置,功能穩定性還是不錯的、界面漂亮、啟動速度也很快。最主要的變化是對快捷鍵的重新定義,原來的快捷鍵基本上是按照 package 來分組管理的。很多時候,快捷鍵之間也會有沖突,互相覆蓋的情況。Spacemacs 采用獨有的分組方式,按照不同的功能類型來分組管理,並用 a-z 字母開頭的不同的單詞來區分,如 a 代表 applications 應用相關, b 代表 buffers 相關的功能,等等。
這個其實對於我這種使用 emacs 時間比較長的人來說,反倒是很多按鍵找不到了,每次要 M-x 去找命令,然后記住快捷鍵。但使用時間長了之后應該差別不大。
但是,它配合 which-key
之后,給人的感覺還是不錯的。原來自己也用過 which-key,但是是用的豎直模式,在右邊顯示出按鍵提示,經常出現把這個屏幕都擋住,然后回不去的情況,應該是 which-key 的一個問題吧。但使用 spacemacs 之后,發現可以把這個提示放在 bottom 的,並且再也不會出現把屏幕弄亂的情況了,這個體驗要好很多。(當然,其他的配置也可以配置在 bottom,甚至覺得默認就應該修改為 bottom,而不是右邊,這個是題外話。)
spacemacs 好的地方在於,自己也可以在這些功能分類里面添加自己認為合適的功能。這一點比原來按照包的方式來分類和管理要合理一些。因為總不至於在別的包的按鍵 map 里面加其他的功能吧。
另外一個就是 major-mode
的按鍵,全部使用 C-M-m
來做 leader-key
,這個太好了,有統一的使用體驗。不管什么模式,可以按相同的按鍵來使用 major-mode
里面的功能。
2 安裝
這個按照官網的指導來:
https://github.com/syl20bnr/spacemacs
將 github 的代碼 clone 下來,放在 ~/.emacs.d 文件夾中即可。
但是啟動的時候,大多數情況下會失敗。因為大陸是有牆的,連不上 melpa。可以在 ~/.spacemacs.d/init.el 中加入大陸的源,就能正常的安裝所有依賴的包了:
(defun dotspacemacs/user-init () "Initialization function for user code. It is called immediately after `dotspacemacs/init', before layer configuration executes. This function is mostly useful for variables that need to be set before packages are loaded. If you are unsure, you should try in setting them in `dotspacemacs/user-config' first." (setq-default configuration-layer--elpa-archives '(("gnu" . "http://elpa.emacs-china.org/gnu/") ("melpa" . "http://elpa.emacs-china.org/melpa/") ("melpa-stable" . "http://elpa.emacs-china.org/melpa-stable/") ("marmalade" . "http://elpa.emacs-china.org/marmalade/") ("org" . "http://elpa.emacs-china.org/org/") ("SC" . "http://elpa.emacs-china.org/sunrise-commander/") ("user42" . "http://elpa.emacs-china.org/user42/"))))
3 layer
Spacemacs 相對於以往的配置,最大的不同就是引入了 layer 這個概念。 layer 是比 package 更高一個層級的抽象。基本上一個 layer 是一個完整的可用的功能集的總稱。比如,一個語言 javascript,通常指的是 javascript-mode 的 package。但是實際上,這個包僅僅是提供了語法支持,要想使用得更爽,就需要自動補全,語法檢查,跳轉等等其他的包的支持。而一個 layer 可能就是所有這些包的配置的一個集合。把所有需要的 package 的配置放在一起,一目了然。
另外,自動補全,語法檢查等包,基本上所有的語言都需要,但是所有的語言又不同,全部配置到一起的話,文件內容太多,很多都是不關心的內容。每個語言都單獨配置的話,包的基本配置又是相同的,往往每個不同的語言只需要稍微修改或者添加一些功能就可以了。
於是,layer 就可以定義 owner 用於初始化,使用 init-PACKAGE
方法來完成基本的設置,另外,可以使用 post-init-PACKAGE
在不同的 layer 中做一些差異化的定制。這樣可以保證跨語言的功能的靈活定制,和可維護性。
4 自帶的 layer
Spacemacs 的自帶 layer 配置還是相當的豐富的,要求不是很高的時候,大多數只使用自帶的 layer 就可以滿足了。下面使用了其中的一些自帶 layer:
dotspacemacs-configuration-layers '( ;; ---------------------------------------------------------------- ;; Example of useful layers you may want to use right away. ;; Uncomment some layer names and press <SPC f e R> (Vim style) or ;; <M-m f e R> (Emacs style) to install them. ;; ---------------------------------------------------------------- ;; -------- standard -------- spacemacs-bootstrap better-defaults chinese helm (ibuffer :variables ibuffer-group-buffers-by 'projects) (syntax-checking :variables syntax-checking-enable-by-default nil syntax-checking-enable-tooltips nil) (spell-checking :variables spell-checking-enable-by-default nil) (auto-completion :variables auto-completion-enable-sort-by-usage t auto-completion-enable-snippets-in-popup t :disabled-for org markdown) git version-control (gtags :disabled-for clojure emacs-lisp javascript latex python shell-scripts) imenu-list nginx org graphviz markdown emacs-lisp csv html javascript (typescript :variables typescript-fmt-on-save t typescript-fmt-tool 'typescript-formatter) react python restclient sql (shell :variables shell-default-shell 'eshell shell-default-height 30 shell-default-position 'bottom) shell-scripts windows-scripts yaml osx )
5 better-editing
對於基礎編輯功能的改善,由於之前多年的 emacs 使用,有一些很好用的 package 和常用按鍵配置是不能少的。
5.1 multiple-cursors
multiple-cursors 應該來說,是 emacs 里面最喜歡的一個功能了。編輯,特別是修改代碼的神器。
(defun better-editing/init-multiple-cursors () (use-package multiple-cursors :defer t :bind* (("C-;" . mc/mark-all-like-this-dwim) ("C-:" . mc/mark-all-like-this-in-defun-dwim) ("C->" . mc/mark-next-like-this) ("C-<" . mc/mark-previous-like-this) ("C-M->" . mc/skip-to-next-like-this) ("C-M-<" . mc/skip-to-previous-like-this) ("C-;" . mc/mark-all-like-this-dwim) ("C-:" . mc/mark-all-like-this-in-defun-dwim) ("C-》" . mc/mark-next-like-this) ("C-《" . mc/mark-previous-like-this) ("C-M-》" . mc/skip-to-next-like-this) ("C-M-《" . mc/skip-to-previous-like-this) ("C-S-<mouse-1>" . mc/add-cursor-on-click) :map mc/keymap ("C-|" . mc/vertical-align-with-space) ("C-_" . undo) ;undo-tree-undo point position wrong. ("C-—" . undo) ;chinese ("M-n" . mc/cycle-forward) ("M-p" . mc/cycle-backward)) :init (progn (require 'multiple-cursors) (setq mc/list-file better-editing/mc-config-file mc/insert-numbers-default 1 mc/cycle-looping-behaviour 'stop)) :config (progn (defun mc/my-quit () "Quit from mark mode." (interactive) (mc/keyboard-quit) (multiple-cursors-mode 0)) (defun mc/mark-all-symbols-like-this-toggle () "Toogle when only one matches!" (interactive) (if (or multiple-cursors-mode (region-active-p)) (mc/my-quit) (mc/mark-all-symbols-like-this))) (defun mc/mark-all-like-this-dwim () "Toggle when not using region. When using region, search first, if only one candidate searched, then quit!" (interactive) (if multiple-cursors-mode (mc/my-quit) (if (not (region-active-p)) (mc/mark-all-symbols-like-this) (mc/mark-all-like-this) (unless multiple-cursors-mode (mc/my-quit))))) (defun mc/mark-all-like-this-in-defun-dwim () "Like `mc/mark-all-like-this-dwim', but only in defun." (interactive) (if multiple-cursors-mode (mc/my-quit) (if (not (region-active-p)) (mc/mark-all-symbols-like-this-in-defun) (mc/mark-all-like-this-in-defun) (unless multiple-cursors-mode (mc/my-quit))))))))
特別是配合一些其他的包,比如 number:
(defun better-editing/init-number () (use-package number :defer t :commands mc/number/add mc/number/divide mc/number/multiply number/add number/sub number/multiply number/divide number/eval ))
對應於 multiple-cursors 中的命令:
(defmacro better-editing/defun-mc-number-commands (commands) "Create mc number COMMANDS." `(progn ,@(mapcar (lambda (command) `(defun ,(intern (concat "mc/" (symbol-name command))) (n) ,(concat "Multiply-cursors support for " (symbol-name command) ", N default 1.") (interactive (list (mc//number-read-from-minibuffer))) (let* ((cmd (lambda () (interactive) (,command n)))) (mc/execute-command-for-all-cursors cmd)))) commands))) (better-editing/defun-mc-number-commands (number/add number/divide number/multiply))
這樣就可以使用 mc/insert-numbers
一次插入多個遞增的數字:
var| var1 var| -> var2 var| var3
或者 mc/number/add
將所有的數字加上或者減掉一個數字:
var1 var2 var2 -> var3 var3 var4
還有下划線和駝峰的互換:
bar_foo barFoo bar_foo_tar -> barFooTar tar_bar tarBar
barFoo bar_foo barFooTar -> bar_foo_tar tarBar tar_bar
5.2 smart-tab
可以將大多數的補全和對齊相關的操作全部集中在 tab 鍵中,當需要補全時就補全,當不需要補全時,退回到原始的設置。
比如 org-mode 中,默認的 tab 鍵綁定的是 org-cycle 功能。使用 smart-tab 之后,可以在正文中補全、yas-expand,也可以在 headline 中折疊或者打開。