Emacs 29.x + Mac GUI。字体:Sarasa Term SC Nerd,主题:doom-one。
1、安装 emacs-plus
brew reinstall gcc libgccjit
brew tap d12frosted/emacs-plus
brew install emacs-plus@29 --with-cacodemon-icon
ln -s /usr/local/opt/emacs-plus@29/Emacs.app /Applications
卸载 brew uninstall emacs-plus@29
。
2、安装 Emacs package
git clone https://github.com/zhangjie2012/emacs.d.git ~/.emacs.d
打开 Emacs 时自动安装依赖包。我使用中科大的源(清华源更新经常出问题)。或者官方源 + 代理:
(setq package-archives
'(("gnu" . "http://elpa.gnu.org/packages/")
("melpa" . "https://melpa.org/packages/")
("melpa-stable" . "https://stable.melpa.org/packages/")
("nongnu" . "https://elpa.nongnu.org/nongnu/")
))
(setq url-proxy-services
'(("no_proxy" . "^\\(localhost\\|10.*\\)")
("http" . "127.0.0.1:1087")
("https" . "127.0.0.1:1087")))
或者 http_proxy=http://127.0.0.1:7890 emacs
。
如果遇到安装问题执行 M-x package-refresh-content
然后重启 Emacs。
3、安装依赖二进制
- ripgrep
brew install ripgrep
- 编码,更多见下方 IDE:
- 语法检测 flycheck Supported languages
- 统一使用 lsp,需要安装对应语言的 Languages
4、安装字体:brew install –cask font-sarasa-nerd[fn:6]
4、安装 nerd-icon:doom-mode-line 4.0.0 之后不再支持 all-the-icons 由 nerd-icons 代替:打开 nerdfont ,下载 Symbols Nerd Font 即可。
<2023-02-10 Fri> 从 lsp-mode 换到了 eglot。原因:
- 从需求上:对我来说,必须的功能有 4 个,其他功能也基本没用过:
- 跳转到定义、反跳转
M-.
M-,
- 查找所有引用
- 查找所有 interface 实现
- 跳转到定义、反跳转
- 从复杂度上:eglot 配置简单(基本上没啥可配置的),lsp-mode 配置复杂(大项目会慢)
- 从未来发展上:Emacs 29 之后,eglot 会作为内置组件
按照 官方说明 安装 Go,LSP server 用的是 gopls。
GO111MODULE=on go install golang.org/x/tools/gopls@latest
lint 工具:
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.50.1
配置文件在:https://github.com/zhangjie2012/dotfiles/blob/master/_golangci.yaml
另外安装 gomodifytags。
go install github.com/fatih/gomodifytags@latest
lsp-server python3 -m pip install 'python-lsp-server[all]'
lint python3 -m pip install flake8
配置文件:https://github.com/zhangjie2012/dotfiles/blob/master/_flake8
format python3 -m pip install black
适用于 React 开发。
使用安装 ESLint npm install -g eslint
。flycheck 配置 ESLint 经常出现各种奇奇怪怪的问题,从来没有一次性成功过,汇总的自查方法:
- 全局安装 ESLint,我不使用项目中单独的配置
(setq flycheck-javascript-eslint-executable "eslint")
指定 eslint 路径flycheck-select-checker
指定 ESLintflycheck-verify-setup
查看二进制路径和配置文件是否生效- ESLint 全局配置文件在用户目录下,具体可以查看 ESLint 的文档,ESLint 一直更新可能会有变化
- 我的配置在 https://github.com/zhangjie2012/dotfiles/blob/master/_eslintrc.json
ln -s dotfiles/_eslintrc.json .eslintrc.json
添加软连接
- 以上 Emacs 都没问题,但是检测不符合预期,要检查下用的是哪里的配置文件,以及配置文件是否有问题
eslint --print-config file.js
查看使用的配置文件是什么eslint file.js
查看错误提示与 Emacs 是否相同- 看 eslint 报错,缺什么 全局 安装
核心思路是:先保证 eslint 本身运行没问题,再看 Emacs flycheck 配置是否正常。
核心在 core 目录下:
init-base
基础设置init-ui
主题、modeline、字体等init-modern
更加现代化:项目管理、多光标操作等init-enhance
对 Emacs 已经具备的能力进行增强init-lang
编码相关init-config
yaml, protobuf, nginx, thrift 等轻量化语言配置init-document
标记语言设置,markdown + orgmodeinit-keymap
额外的快捷键绑定init-feed
rss 订阅管理
(use-package doom-themes
:ensure t
:init
(defun toggle-theme ()
(interactive)
(cond ((eq (car custom-enabled-themes) 'doom-one)
(mapc #'disable-theme custom-enabled-themes)
(load-theme 'doom-snazzy t))
((eq (car custom-enabled-themes) 'doom-snazzy)
(mapc #'disable-theme custom-enabled-themes)
(load-theme 'doom-one t))))
;; day/night use diff theme: via https://github.com/jakebox/jake-emacs
(let ((hour (string-to-number (substring (current-time-string) 11 13))))
(if (or (> hour 17) (< hour 7))
(load-theme 'doom-one t)
(load-theme 'doom-snazzy t)))
:config
(setq doom-themes-enable-bold t
doom-themes-enable-italic nil)
(doom-themes-visual-bell-config)
(doom-themes-org-config)
(global-set-key (kbd "<f5>") 'toggle-theme))
(use-package cape
:ensure t
:init
(add-to-list 'completion-at-point-functions #'cape-dabbrev)
(add-to-list 'completion-at-point-functions #'cape-file)
(add-to-list 'completion-at-point-functions #'cape-keyword)
(add-to-list 'completion-at-point-functions #'cape-history))
(use-package corfu
:ensure t
:hook (prog-mode . corfu-mode)
:bind (:map corfu-map
("C-n" . corfu-next)
("C-p" . corfu-previous))
:config
(setq corfu-auto t
corfu-auto-prefix 1
corfu-auto-delay 0.1
corfu-quit-no-match t
corfu-quit-at-boundary t)
(add-hook 'multiple-cursors-mode-enabled-hook (lambda () (corfu-mode -1)))
(add-hook 'multiple-cursors-mode-disabled-hook (lambda () (corfu-mode 1))))
<2023-05-13 Sat> 从 projectile
切换到了 project.el
留一份老的配置备忘:
(use-package projectile
:ensure t
:bind (:map projectile-mode-map
("<f8>" . projectile-command-map)
("C-c p" . projectile-command-map)
:map projectile-command-map
("F" . projectile-find-file-other-window)
("w" . projectile-find-file-in-known-projects)
("D" . projectile-dired-other-window)
("k" . projectile-kill-buffers)
("v" . projectile-vc)
("b" . projectile-switch-to-buffer))
:config
;; 打开项目缓存, 否则大的项目每次构建会比较慢
;; 你可以通过下面两个名称来清除缓存
;; - projectile-purge-file-from-cache
;; - projectile-purge-dir-from-cache
(setq projectile-enable-caching t)
;; projectile 有三种构建索引的方式: native, hybird, alien
;; native 使用 Emacs lisp 实现, hybird/alien 使用外部命令类似 find, git 来实现
;; alien 优化了 hybird 的性能: 它不会对外部命令返回的结果做任何处理和排序, 以获得最好的性能
;; 使用外部命令的话, 类似 .gitignore 会自动生效
;; 注意: alien 会忽略 .projectile 文件
(setq projectile-indexing-method 'alien)
;; 在每个目录下都可用(即使没有项目文件)
(setq projectile-require-project-root 'prompt)
;; 对结果进行排序(active buffer + recently opened)
(setq projectile-sort-order 'recentf-active)
;; fix windows system "projectile-find-file" throw
;; 'tr' is not recognized as an internal or external command ...
;; via: https://github.com/bbatsov/projectile/issues/1302
(setq projectile-git-submodule-command nil)
(defun project-find-go-module (dir)
(when-let ((root (locate-dominating-file dir "go.mod")))
(cons 'go-module root)))
(cl-defmethod project-root ((project (head go-module)))
(cdr project))
:init
(projectile-mode +1))
M-x emacs-init-time
可以查看 Emacs 启动耗费时间。
多一个插件都会增加启动成本,不信你 emacs -Q
试试,所以要尽可能的减少插件。你可以使用 keyfreq 来查看你常用的快捷键有哪些。
筛选出不常用的插件给干掉,这是解决启动速度慢的根本办法。
如何定位插件耗时?
- 使用 profiler:https://punchagan.muse-amuse.in/blog/how-i-learnt-to-use-emacs-profiler/
- 使用 esup:https://github.com/jschaf/esup
- 使用 https://github.com/purcell/emacs.d/blob/master/lisp/init-benchmarking.el
定位之后如何优化?
elisp 比较熟的有自己的办法优化,当然我不熟。我的解决办法是:
使用 use-package ,use-package 并不是包管理工具,只是一个宏,用来配置和加载包。你可以通过配置(合理的使用 init、config、hook、 bind 等)实现延迟加载,提高打开的速度。
可以在 +OPTIONS
中设置 ^:nil
来禁掉它。
orgmode 9.2 之后不再直接支持 <s [Tab]
的快捷方式插入代码块,而提供了统一的 org-insert-structure-template
函数,
快捷键为 C-c C-,
。如果想要提供以前的简洁方式,需要引入 org-tempo
,比如 (require 'org-tempo)
我使用的是
(use-package org-tempo)
。具体见:
- 任务可以分优先级
[#A], [#B], [#C]
三种。使用<shift> + <up/down>
进行切换 org-sort-entris
对任务进行排序(很有用),选择按照权重[p]riority
排序
打开文件后,控制几级标题展示 #STARTUP
选项:
#+STARTUP: overview #+STARTUP: content #+STARTUP: showall #+STARTUP: show2levels #+STARTUP: show3levels #+STARTUP: show4levels #+STARTUP: show5levels #+STARTUP: showeverything
全局在 org 配置中打开 org-startup-fold
[fn:1]。
- 新建
Table Of Content
以及标题,后面加上:TOC:
注解,保存自动生成 - 控制显示多级标题
TOC_n
,默认为TOC_2
,即显示到两级标题
tabify
空格转 tabuntabify
tab 转空格
语言的开发环境配置一直很费时间,我记得以前刚配置 C/C++ 的开发环境时,折腾了一个月左右时间才找到一个相对比较 满意的开发环境(折腾完之后使用起来可真爽啊):
xcscope + etags + c++-mode
。写 Python 的时候也折腾了长时间的缩进问题。 Go 就更不用说了···,Go 工具链很完整,但由于 Go 的版本升级很快,工具链根本跟不上,
gocode已经迁移了三次地址了。后来看到了 LSP(Language Server Protocol) 项目,感觉这个项目才是终极解法:插件化,C/S 模式。 目前已经默认支持 Python 和 Go 了,虽然还是有许许多多的 Bug,但比起 2018 年我试的时候已经成熟太多了。有社区的驱动,发展很快。
lsp-workspace-folders-remove
可以移出之前添加的 workspace,但是如果遇到大的目录变更,一个一个的移出很慢。 目前似乎没有提供一次性 remove all 的方法。一个解决办法是删除 lsp 的存储文件(lsp 提供了lsp-session-file
变量来定义文件路径, 默认在.emacs.d/.lsp-session-*
路径下,如果没找到也可以在 lsp 源代码中搜索 lsp-session-file)。当前 LSP 还不太稳定,遇到各种问题就可以重启是最有效的办法:lsp-workspace-restart
lsp-mode 的功能比较多,官方提供了 开启/关闭 lsp-mode 特性介绍,否则真的抓瞎。
<2023-02-10 Fri> 由 lsp-mode 换到了 eglot。
使用 projectile 管理项目,非常方便。svn/git 项目会认为是一个 projectile,而且 ignore 的文件和目录也会自动过滤。
你也可以手动添加 .projectile
标识。
已经切换到内置的 project.el
。
company
只是个补全框架,实现依赖于底层语言的补全工具(lsp)。
之前给 lsp-mode 提过 issue:emacs-lsp/lsp-mode#2215 ,后来也没有提供直接的解决方案。
事实上,lsp-go 中有控制,但没有暴露出去。我简单粗暴的把 lsp-go.el 中的 completion-in-comments
设置为了 nil
,
然后删掉 lsp-go.elc
文件。
核心解决思路是加上(据说是 fctix 的 bug) env LC_CTYPE=zh_CN.UTF-8
环境变量。解决办法:
- GUI 修改
/usr/share/application/emacs.desktop
中的启动命令Exec=env LC_CTYPE=zh_CN.UTF-8 /usr/bin/emacs %F
- TUI 就简单了,直接在
.bashrc
加个alias
具体可以见这个帖子:https://emacs-china.org/t/topic/974/20 ,正如 scutdk 所说,修改系统全局的 locale 可能带来其他问题。
有点乱,参差不齐:
- 开箱即用的配置:
- purcell/emacs.d:久负盛名
- redguardtoo/emacs.d
- hlissner/doom-emacs
- Emacs initialisation file (dotemacs): wiki + 配置
- crafted-emacs:System Crafters 的配置,他在 YouTube 上有很多视频
- emacs-bootstrap: 动态生成 Emacs 配置
- 文章集合
- 博客 & Github
- awesome-emacs
- Planet Emacslife:Emacs 百科全书,大杂烩
- Emacs Themes:主题集合
- oremacs
- dotemacs 完善的 Emacs 配置 Wiki
- 我平常是怎么使用 Emacs 的?
- GTD 相关文章:
- 视频:
- Using Emacs Series:cestlaz 的使用 Emacs 系列,偏向于插件介绍
- emacsrocks 很多短视频,偏向于插件介绍
- ToolTime 前两节是讲 Emacs 的,理论+实践,有视频还有配套的 PPT,一般的资料都是讲什么用,而这个课程讲了为什么是这样,由浅入深;非常推荐。
- 关于 Emacs 的补全
- 我自己写的:
- <2019-06-17 Mon> Emacs 心路历程(上)、Emacs 心路历程(下) 感悟
- <2014-12-01 Mon> Emacs 简易教程 内容比较旧了,已经不再维护
- Emacs 基于 org-reveal 做幻灯片
- 使用 org-mode 搭建网站
[fn:6] https://github.com/laishulu/Sarasa-Term-SC-Nerd
[fn:5] https://emacs-china.org/t/homebrew-emacs-plus-28/19106
[fn:4] https://github.com/joaotavora/eglot#emacscore
[fn:3] https://github.com/jwiegley/use-package
[fn:2] https://www.masteringemacs.org/article/converting-tabs-whitespace
[fn:1] https://stackoverflow.com/questions/52722096/build-emacs-and-gnutls-not-found