Skip to content

condy0919/.emacs.d

Repository files navigation

A fast and incredible Emacs config

Build Status License Supports Emacs 28.1-30.x

Table of Contents

个人Emacs配置

overview

仿 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 更快的grep
  • pandoc (optional) 文本转换工具,markdown-mode渲染需要
  • markdown (optional) 文本转换工具,markdown-mode渲染需要
  • cmake c++项目的构建工具
  • 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配置项。另外由于quelpapackage-quickstart冲突,llvm-modetablegen-mode需要人工执行对应的quelpa代码块来提前安装,而不是通过use-package自动检测、下载。不过因为quelpa安装过后的包也会在~/.emacs.d/elpa/里放一份,所以最终效果跟package.el是一样的。

Emacs 29 引入了 package-upgrade-all,需要更新直接 M-x package-upgrade-all 即可。

界面

使用了doom-themesdoom-modeline,简直惊艳!doom-one的界面非常好看!

趁手的工具

rg是比较常用的工具,更有projectile管理项目,让项目编译、测试、运行变得更加方便。

avy用来代替vim-easymotion。而且avy还提供了goto-line的功能,这下都不用开相对行号8k 9j这样跳了。

以前是ivy用户,现在则是仅使用vertico, embark, consultmarginalia 了。

Emacs下的org-mode/markdown-mode让人惊艳,突然觉得写文档也会这么快乐。与之相辅相成的还有separedit,让人在代码里写documentation comments不再烦恼。

valign 提供了像素级别的表格对齐,终于不用再靠西文半宽的字体了!

neovim迁移过来的我,自然是常开evil-mode,相关的evil套件有:

  • evil
  • evil-collection (已包含 evil-magit)
  • evil-surround

按键绑定

evil-mode

开启了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-snipesf 功能。

key function
s evil-avy-goto-char-timer
f evil-avy-goto-char-in-line

本配置里使用hideshowfold代码块。由于hideshow本身提供的快捷键非常长,非常推荐使用evil-modenormal状态下定义的键绑定。

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同上,不过是在另一窗口打开

bufferbookmark相关的键绑定:

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打断当前的编译过程
cx quickrun快速运行当前程序
cX quickrun-shelleshell里查看输出
cd rmsbolt-compile查看编译器的输出,如汇编、IR表示
cw delete-trailing-whitespace删除行末空白字符

Emacs

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 个,分别是:

  1. background-opacity-menu方便执行调整真透明度
  2. scroll-other-window-menu在不改变焦点的情况下移动另一窗口的buffer

通用开发设置

  • 显示行末空白字符
  • 高亮TODO FIXME等关键字
  • dumb-jump作为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 来触发

prog-mode

cc-mode

使用lsp-mode作为补全、符号查找的工具,默认后端使用clangd,一般发行版的源里都会有对应的包。如果想使用ccls,可以customize对应的变量:

(setq lsp-clients-clangd-executable "ccls"
      lsp-clients-clangd-args nil)

如果想使用cclslsp扩展功能,需要安装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关键字展开

rust-mode

使用lsp-mode作为补全、符号查找的工具,默认后端使用rust-analyzer,需要额外安装rust-analyzer的包。lsp-mode会首先考虑rust-analyzer,如果未在exec-path中找到则会转而使用rlsrls 通常与rust这个包捆绑在一起。

  • rust-mode开启了保存时格式化文件,需要确保rustfmt二进制包存在
  • 使用了cargo来提供深度集成化的cargo命令

ocaml-mode

使用lsp-mode作为补全、符号查找的工具。在Arch Linux上,可以使用 ocaml-lsp-git 这个包。

由于ocaml-lsp-git目前实现了lsp-format-buffer且额外依赖ocamlformat

所以这里额外使用了ocp-indent,通过ocp-indent-region, ocp-indent-buffer来提供格式化代码的功能。

同时也集成了dune

ocp-indentdune都依赖系统级别的包。

如果你是Arch Linux可以直接通过如下命令安装:

yay -S ocaml-ocp-indent dune

haskell-mode

非常纯粹, 其实是平常不怎么写 haskell

截图

dashboard

magit_markdown

cpp_company

FAQ

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/")))

Emacs 配置挂了

可以使用 init-mini.el 这个最小配置来临时救急一下。

emacs -Q -l init-mini.el

虽然咱都是直接开 nvim 的

其他

欢迎提issue给出建议,感谢!

Releases

No releases published

Packages

No packages published