Table of Contents
仿 Centaur Emacs 的个人配置.
git clone --depth 1 https://github.com/condy0919/.emacs.d ~/.emacs.d仅包含C/C++/Rust/OCaml/Haskell相关配置,且全线使用lsp。当前由于haskell-ide-engine水土不服,故haskell没有采用lsp。
保持着尽量使用Emacs自带功能的原则,能用自带的就用自带的。
hunspell(optional) 拼写检查,目前仅在git-commit-mode下默认启用rg更快的greppandoc(optional) 文本转换工具,markdown-mode渲染需要markdown(optional) 文本转换工具,markdown-mode渲染需要cmakec++项目的构建工具git这个就不用说了吧?gcc这个就不用说了吧?fd(optional) 更现代的find,projectile会自动检测
最基础的配置包含了那些在所有mode下都不会变更的配置,包含了:
| 包名 | 功能 |
|---|---|
| align | align-regexp可以自动对齐选择的符号 |
| appt | 任务提醒,可以与org-mode结合 |
| hippie-expand | 用来展开文本 |
| hl-line | 高亮当前行 |
| newcomment | 注释、反注释功能 |
| paren | 高亮匹配的括号 |
| saveplace | 自动记录上次打开文件的位置 |
| simple | 在modeline里显示行号、列号以及当前文本的大小 |
| so-long | 打开长行的文件不再痛苦 (Emacs 27+ 自带) |
| tab-bar | 窗口布局管理 (Emacs 27+ 自带) |
| tramp | 远程编辑就靠它 |
而这几个包也是Emacs自带的。
为了保持界面的整洁,禁用了菜单栏、工具栏和滚动条。
package.el(自带的)来安装包、use-package来管理配置。对于elpa, melpa里没有的包,使用quelpa辅助下载。
为什么我会从straight.el切换至quelpa呢?
主要是straight.el不支持单个文件的下载、配置,为了使用llvm-mode.el而 clone 整个 llvm repo 就显得有点得不尝失了。相关配置见init-cpp.el内的llvm-mode配置项。另外由于quelpa与 package-quickstart冲突,llvm-mode和tablegen-mode需要人工执行对应的quelpa代码块来提前安装,而不是通过use-package自动检测、下载。不过因为quelpa安装过后的包也会在~/.emacs.d/elpa/里放一份,所以最终效果跟package.el是一样的。
Emacs 29 引入了 package-upgrade-all,需要更新直接 M-x package-upgrade-all 即可。
使用了doom-themes和doom-modeline,简直惊艳!doom-one的界面非常好看!
rg是比较常用的工具,更有projectile管理项目,让项目编译、测试、运行变得更加方便。
avy用来代替vim-easymotion。而且avy还提供了goto-line的功能,这下都不用开相对行号8k 9j这样跳了。
以前是ivy用户,现在则是仅使用vertico, embark, consult 和 marginalia 了。
Emacs下的org-mode/markdown-mode让人惊艳,突然觉得写文档也会这么快乐。与之相辅相成的还有separedit,让人在代码里写documentation comments不再烦恼。
valign 提供了像素级别的表格对齐,终于不用再靠西文半宽的字体了!
从neovim迁移过来的我,自然是常开evil-mode,相关的evil套件有:
evilevil-collection(已包含evil-magit)evil-surround
开启了evil-collection-want-unimpaired-p (由evil-collection提供) 而获得了如下键绑定:
| key | function |
|---|---|
| [b | previous-buffer 切换至上一个 buffer |
| ]b | next-buffer 切换至下一个 buffer |
| [e | evil-collection-unimpaired-move-text-up 将当前行移动至上一行 |
| ]e | evil-collection-unimpaired-move-text-down 将当前行移动至下一行 |
| [l | evil-collection-unimpaired-previous-error 上一个错误 |
| ]l | evil-collection-unimpaired-next-error 下一个错误 |
| [ SPC | evil-collection-unimpaired-insert-newline-above 在上方插入一空行 |
| ] SPC | evil-collection-unimpaired-insert-newline-below 在下方插入一空行 |
| [u | evil-collection-unimpaired-url-encode 对所选内容进行url参数编码 |
| ]u | evil-collection-unimpaired-url-decode 对所选内容进行url参数解码 |
此外,凭借 avy 模拟了 evil-snipe 的 s 和 f 功能。
| key | function |
|---|---|
| s | evil-avy-goto-char-timer |
| f | evil-avy-goto-char-in-line |
本配置里使用hideshow来fold代码块。由于hideshow本身提供的快捷键非常长,非常推荐使用evil-mode在normal状态下定义的键绑定。
| key | function |
|---|---|
| zm | evil-close-folds隐藏所有代码块 |
| zr | evil-open-folds显示所有被隐藏的代码块 |
| zo | evil-open-fold隐藏当前代码块 |
| zO | evil-open-fold-rec递归地隐藏当前以及之内的代码块 |
| zc | evil-close-fold显示当前被隐藏的代码块 |
| zC | evil-close-fold-rec递归地显示当前以及之内的代码块 |
| za | evil-toggle-fold来切换是否隐藏代码 |
与文件相关的Leader键绑定如下:
| key | function |
|---|---|
| ff | find-file打开文件, f.有相同效果 |
| fF | find-file-other-window同上,不过是在另一窗口打开, f/有相同效果 |
| f/ | 同上 |
| fD | +delete-current-file删除当前文件 |
| fC | +copy-current-file拷贝当前文件至其他地方 |
| fy | +copy-current-filename拷贝当前文件的绝对路径 |
| fR | +rename-current-file重命名当前文件 |
| fr | recentf-open-files访问最近使用过的文件 |
| fl | find-file-literally采用朴素模式打开文件 |
| fj | dired-jump进入当前文件的目录 |
| fJ | dired-jump-other-window同上,不过是在另一窗口打开 |
与buffer、bookmark相关的键绑定:
| key | function |
|---|---|
| bb | switch-to-buffer切换buffer |
| bB | switch-to-buffer-other-window同上,不过是在另一窗口打开 |
| bc | clone-indirect-buffer将当前buffer克隆至另一buffer,它们可以使用不同major-mode |
| bC | clone-indirect-buffer-other-window同上,不过是在另一窗口打开 |
| bv | revert-buffer重新读取当前buffer对应的文件 |
| bx | scratch-buffer直接跳转到 *scratch* buffer |
| by | +copy-current-buffer-name复制当前buffer的名字 |
| bz | bury-buffer退出当前buffer的显示,当前buffer未被 kill |
| key | function |
|---|---|
| bj | bookmark-jump跳转至书签 |
| bJ | bookmark-jump-other-window同上,不过是在另一窗口打开 |
| bm | bookmark-set设置书签 |
| bM | bookmark-set-no-overwrite同上,但是不会覆盖同名的书签 |
| bd | bookmark-delete删除书签 |
| bi | bookmark-insert插入书签的内容 |
| bl | bookmark-bmenu-list打开书签列表 |
| br | bookmark-rename重命名书签 |
| bs | bookmark-save保存书签 |
| bw | bookmark-write将书签保存至其他文件 |
打开其他程序的Leader键绑定:
| key | function |
|---|---|
| ot | ansi-term打开ansi-term |
| oe | eshell打开eshell |
| os | shell打开shell |
| ol | org-store-link存储URL |
| oc | org-capture随时记录一些想法、URL等 |
打开一些看起来像是独立的应用:
| key | function |
|---|---|
| aa | org-agenda日程 |
| ac | calendar日历 |
| ag | gnus查看新闻组 |
| ai | rcirc上 IRC |
搜索相关的Leader键绑定:
| key | function |
|---|---|
| si | imenu |
| sj | evil-show-jumps |
| sm | evil-show-marks |
| sr | evil-show-registers |
| sp | consult-ripgrep |
| ss | consult-line |
与代码相关的Leader键绑定:
| key | function |
|---|---|
| cc | compile编译 |
| cC | recompile重新编译 |
| ck | kill-compilation打断当前的编译过程 |
| cl | +switch-to-compilation快速切换到 *compilation* buffer |
| cx | quickrun快速运行当前程序 |
| cX | quickrun-shell在eshell里查看输出 |
| cd | rmsbolt-compile查看编译器的输出,如汇编、IR表示 |
| cw | delete-trailing-whitespace删除行末空白字符 |
| key | function |
|---|---|
| M-` | 打开一个弹出式shell以临时执行一些命令 |
| M-; | comment-or-uncomment 注释与反注释 |
| C-c ' | 通过separedit在注释中快乐地写代码 |
| C-c p | projectile调用前缀 |
| C-x g | 呼出 magit |
| M-g M-l | 调用avy-goto-line |
因为projectile比较常用,故把它单独拿出来说。
| key | function |
|---|---|
| C-c p f | projectile-find-file在项目内查找其他文件 |
| C-c p b | projectile-switch-to-buffer切换至其他buffer(限定在本project下) |
| C-c p C | projectile-configure-project配置当前项目 |
| C-c p c | projectile-compile-project编译当前项目 |
| C-c p u | projectile-run-project运行当前项目 |
| C-c p P | projectile-test-project测试当前项目 |
| C-c p p | projectile-switch-project切换至其他项目 |
| C-c p s r | projectile-ripgrep使用ripgrep来搜索当前项目内的文本。 |
基于同样的理由,把flycheck单独拎了出来。
| key | function |
|---|---|
| C-c ! l | flycheck-list-errors列出所有lint错误 |
| C-c ! n | flycheck-next-error下一个lint错误 |
| C-c ! p | flycheck-previous-error上一下lint错误 |
更详细的按键绑定请直接看代码. :-)
C-c h是所有hydra的前缀,目前有 2 个,分别是:
background-opacity-menu方便执行调整真透明度scroll-other-window-menu在不改变焦点的情况下移动另一窗口的buffer
- 显示行末空白字符
- 高亮TODO FIXME等关键字
rg作为lsp-find-definition失败后的备份手段magit作为git客户端hideshow来显示/隐藏结构化的代码块,如 "{ }" 函数体等rmsbolt作为一个本地的 Compiler Explorer 相比于godbolt快速一点ispell拼写检查器,evil用户可以快速通过z= (ispell-word) 来检查flyspell拼写检查器,仅在magit写提交信息时启用quickrun作为一个能够执行部分区域内的代码块,方便快速验证函数功能tempo作为代码片段展开工具,spdx然后再M-x tempo-expand-if-complete即可。也可以通过hippie-expand来触发
使用lsp-mode作为补全、符号查找的工具,默认后端使用clangd,一般发行版的源里都会有对应的包。如果想使用ccls,可以customize对应的变量:
(setq lsp-clients-clangd-executable "ccls"
lsp-clients-clangd-args nil)如果想使用ccls的lsp扩展功能,需要安装ccls扩展。
此外,
cmake-mode可使用company-mode进行符号补全- 启用了
hide-ifdef-mode,可以令#if 0到#endif之间的代码看起来像注释一样。也可以#define一些宏,放入hide-ifdef-env中即生效。 - 部分常用
snippet,如ifndef,main等等。详细列表见init-cpp.el文件 cmake-mode增加了一个简单 lib 的snippet,可以通过lib关键字展开
使用lsp-mode作为补全、符号查找的工具,默认后端使用rust-analyzer,需要额外安装rust-analyzer的包。lsp-mode会首先考虑rust-analyzer,如果未在exec-path中找到则会转而使用rls。rls 通常与rust这个包捆绑在一起。
rust-mode开启了保存时格式化文件,需要确保rustfmt二进制包存在- 使用了cargo来提供深度集成化的
cargo命令
使用lsp-mode作为补全、符号查找的工具。在Arch Linux上,可以使用 ocaml-lsp-git 这个包。
由于ocaml-lsp-git目前只实现了lsp-format-buffer且额外依赖ocamlformat。
所以这里额外使用了ocp-indent,通过ocp-indent-region, ocp-indent-buffer来提供格式化代码的功能。
同时也集成了dune。
ocp-indent和dune都依赖系统级别的包。
如果你是Arch Linux可以直接通过如下命令安装:
yay -S ocaml-ocp-indent dune非常纯粹, 其实是平常不怎么写 haskell。
dashboard 图标显示异常
依赖 nerd-icons, 请确保 M-x nerd-icons-install-fonts 安装对应的字体以显示图标。
如果您在使用国内镜像源时出现这个问题,多数情况都是由镜像源同步不一致导致的,可以切换成上游来规避这个问题。
(setq package-archives
'(("melpa" . "https://melpa.org/packages/")
("gnu" . "https://elpa.gnu.org/packages/")
("nongnu" . "https://elpa.nongnu.org/nongnu/")))可以使用 init-mini.el 这个最小配置来临时救急一下。
emacs -Q -l init-mini.el虽然咱都是直接开 nvim 的
欢迎提issue给出建议,感谢!



