惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Heimdal Security Blog
C
Check Point Blog
Jina AI
Jina AI
T
Tailwind CSS Blog
IT之家
IT之家
Stack Overflow Blog
Stack Overflow Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
人人都是产品经理
人人都是产品经理
S
SegmentFault 最新的问题
U
Unit 42
Cyberwarzone
Cyberwarzone
T
The Blog of Author Tim Ferriss
I
Intezer
V
Visual Studio Blog
月光博客
月光博客
A
Arctic Wolf
L
LINUX DO - 热门话题
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
T
Threatpost
F
Fortinet All Blogs
Simon Willison's Weblog
Simon Willison's Weblog
酷 壳 – CoolShell
酷 壳 – CoolShell
K
Kaspersky official blog
L
Lohrmann on Cybersecurity
T
Tenable Blog
爱范儿
爱范儿
大猫的无限游戏
大猫的无限游戏
博客园_首页
Recent Announcements
Recent Announcements
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
C
Cybersecurity and Infrastructure Security Agency CISA
P
Privacy International News Feed
The Register - Security
The Register - Security
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
J
Java Code Geeks
I
InfoQ
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Webroot Blog
Webroot Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
The Last Watchdog
The Last Watchdog
AWS News Blog
AWS News Blog
Last Week in AI
Last Week in AI
Spread Privacy
Spread Privacy
云风的 BLOG
云风的 BLOG
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Apple Machine Learning Research
Apple Machine Learning Research
F
Full Disclosure
Vercel News
Vercel News
The Hacker News
The Hacker News

少数派

派早报:Google 发布 Fitbit Air 等 - 少数派 「新人报到」確認需求,再開始 - 少数派 从 SOLO 独立开发者社区,我看到了越来越多开发者开始做自己的产品 - 少数派 我怎么管理那些"不常做,但总会忘"的生活事项 - 少数派 人形机器人量产元年,数据才是具身智能的“生死线” - 少数派 BuhoLaunchpad 高度还原 Mac 启动台:开发历程与思考 - 少数派 五年陪伴依然不舍,DIY 换壳后让罗技 MX Master 3 继续服役 - 少数派 新玩意 240|少数派的编辑们最近买了啥? - 少数派 一日一技|为什么你应该关闭 iOS 的键盘声音 - 少数派 我做了个插件和 Skills,一键提取任何网站的设计规范 Design.md - 少数派 住在三四线城市的你,该开始录播客了 - 少数派 甘南秘境,大白高国 - 少数派 AI的审美:谁让把我变成川内倫子 - 少数派 返工怎能不烦恼,打工人片单总有一部是你的「嘴替」 - 少数派 为了让「上厕所」更健康,我做了一个小工具 - 少数派 AI + Skill,能够让生成的文章去除 AI 味吗? - 少数派 新玩意|韶音OpenDots ONE 耳夹式耳机 - 少数派 《美满》| 在每一个春天的晚上相爱(362) - 少数派 新玩意|优篮子 PS01 MagSnap 磁吸支架 - 少数派 自我整合手记 | 我开始早睡了:用稳定规则,为自由托底 - 少数派 用龙虾(OpenClaw)两个多月,我最深的12个体会 - 少数派 听歌时间到,12 张你可能错过的 2025 华语乐坛好专辑 - 少数派 承诺能追吗 - 少数派 macOS 26启动台没了? 我做了个不一样的App启动器 - Keboard - 少数派 《四海为家的人》| INTJ对话INTJ(361) - 少数派 你发过的那些黑历史,是时候一次清干净了 - 少数派 新玩意:安安静静玩,越玩越专注:计客密码机 - 少数派 iPad 用户首次体验 Android 平板:vivo Pad6 Pro - 少数派 数据逻辑强 - 少数派 极北行+ | 一路向北,探访日本至北之地 | 001 - 少数派 万字剖析:千问App深度体验报告(2026) - 少数派 在2026年,如何真正防止别人抄袭你的作品 - 少数派 怎么用 50 块搭个 AI 语音助手?我踩了 3 天坑 - 少数派 YeeroAI:让 AI 对话真正成为知识管理的一部分 - 少数派 爬泰山 - 少数派 「旅图显影」 App 更新:这次,我们补上了一点「手感」 - 少数派 假期出门太折磨?我的 23 条经验帮你规划惬意旅行 - 少数派 工作流会变吗 - 少数派 Claude Opus 4.6 怎么用最省钱?我测了 5 种方案 - 少数派 GPT Image 2 让图文并茂不再稀罕 - 少数派 用户侧出发——什么是AI,我要不要学习? - 少数派 找片、转存、整理、播放一条龙!让你的付费网盘值回票价 - 少数派 欢迎试用!日课一问2.0插件 - 少数派 自己做的MDeditor,原本想购买 Typora 试了两次支付不成功,干脆自己做一个 - 少数派 vibe coding了一个 3MB 的小工具,让 ~/Downloads 彻底告别混乱 - 少数派 因为受不了 Mac 的风扇策略,我做了一个风扇控制工具 - 少数派 别只怪模型 - 少数派 Warp 终端的 AI 功能怎么用?我测了一周的体验 - 少数派 AI 写代码老是出 bug?这 5 个配置我后悔没早知道 - 少数派 「新玩意」苹果出相机可能就这样:Sigma BF + 45mm F2.8 DG Contemporary - 少数派 一个面向2030年的AI操作系统是什么样子的:浅谈cola这款有灵魂的Agent - 少数派 别只看写代码 - 少数派 每天解决10个问题,还是一口气攻坚解决400个? - 少数派 AI 交易机器人怎么搭?我用 Claude 跑了一周实盘 - 少数派 Maptoposter Online:把你爱的城市画成艺术海报 - 少数派 Function Calling 怎么用?我测了 3 个模型发现差距真大 - 少数派 Legend Talk:我做了个 AI 圆桌,让 160 位思想家围着你的问题转 - 少数派 如何找到自己的蓝方?在小县城寻找压力测试 - 少数派 语音输入与软件接口|2026年聊AI时,我们都聊些什么(上) - 少数派 混动已经卖爆,纯电又来补刀——钛7闪充版简直“不讲武德” - 少数派 本月玩什么|朋友收藏、识质存在、沙罗周期 - 少数派 为什么要每天坚持输出? - 少数派 Claude API 挂了好几个小时,你的项目有备用方案吗? - 少数派 Function Calling 没你想的复杂——我用它做了个有点用的工具 - 少数派 登录系统立即播放视频或者图片音乐的软件 - 少数派 我为什么创建 FlipHTML5 下载工具 - 少数派 残局没电?多品牌外设电量统一管理软件EasyBluetooth已支持RTSS游戏内显示以及AIDA64 - 少数派 前往通义路的路 - 少数派 太好看了,媲美Sun的个人导航页,NAS部署星云门户 - 少数派 乌黑嘴唇“一键检测”上线了 - 少数派 派早报:Claude AI 接入多个创意软件生态、FILCO 生产方接手品牌等 - 少数派 【更新】BearCLI、Claude 连接器与 MCP 服务器 - 少数派 记了上千条流水,还是看不懂财务?我做了一个让 AI 读懂账本的工作台 - 少数派 MINI R56 升级原厂 Sport 模式 - 少数派 新玩意 | 一棵柠檬树(仿真版) - 少数派 Momenta的“物理AI”野望,需迈过“含摩量”这道关 - 少数派 网页直接投屏控制手机!NAS一键部署PandaScrcpy,流畅丝滑可远程。 - 少数派 众测|邀你一同探索随身 AI 硬件入口 YoooClaw C·ONE - 少数派 2050大会:分享时间是真诚 参会记 - 少数派 iPad 赋能电影创作:国内首部宣纸手绘长片《燃比娃》的幕后故事 - 少数派 AI的审美:我用 8 个大模型给 100 张旅行照片打分 - 少数派 普通人如何破圈?去参加一个本地协会 - 少数派 把极空间的图标全换了,主题DIY全攻略打造你的专属NAS桌面 - 少数派 电子便签墙,帮你实现便签自由 - 少数派 我如何用三个 CLI 工具取代文档创建需求 - 少数派 原来真的有人可以玩一辈子 - 少数派 社区速递 139 | 派友热议三月买了啥、复古单反尼康 Df 体验 - 少数派 06 作品的赏析与评价 - 少数派 TDS REVIEW|索尼 WF-1000XM6 降噪真无线耳机体验 - 少数派 35.98万起售的第二代腾势D9,我看重的不是堆料,而是不凑合 - 少数派 鼠须管 Squirrel 皮肤配置指北 - 少数派 从watch ultra2换到redmi watch6 - 少数派 派早报:阿里巴巴发布视频生成模型 HappyHorse 1.0 等 - 少数派 别迷信1M - 少数派 家人们天塌了!网盘“大封杀”,多个渠道多条路,NAS部署PanHub - 少数派 AI与人勾心斗角!NAS一键部署AI狼人杀,假日休闲必备。 - 少数派 电商必备!Comfyui工作流批量生图插件,一次生成12张!支持Nano banana pro模型 - 少数派 Comfyui工作流配置Gpt-image-2模型教程,0.03/张 - 少数派 OpenClaw第三方APi怎么配置?可使用Gpt-image-2模型 - 少数派 会员社区话题精选 Ep. 103 - 少数派
Emacs高手修炼手册 (2023年,Emacs 29) - 少数派
2023-12-02 · via 少数派

写在前面的话

《Emacs高手修炼手册》这个标题已经用了好几年了,但感觉自己始终没有达到自己心目中的〔高手〕的境界。所以我还是在〔修炼〕,用这个标题继续写一些自己的实践——当然更多的,还是配置。

其实当我写2023这个2.0版本的时候,我一直在想,如何把这个系列写的跟之前的不一样。如果还是之前的样子,那么其实没有必要写新的一篇,读者也没有必要读新的一篇——我们都不喜欢水文。

于是我回头看了自己这一年的使用上的变化,自己对比了自己在配置上的变化,我总结出了自己这篇文章需要有的特点:

简洁,我的配置越来越简洁,代码行越来越少,但功能却不因此而变的简单;

实用,Emacs终究还是一个工具,一个编辑器,一个可以让自己的想法得到验证的工具;

速度,过去的一年,我有大量的时间是在使用Windows操作系统,所以速度对我来说,毫无疑问是一个挑战与要追求的点;

虽然我在上面提到的这些特点,都是非常优美的词汇,但不可否认的是,我的这篇文章也有一些问题:

不兼容旧版本,我的配置只兼容最新的版本,我希望自己(以及大家)能够尊重他们最新的努力,以及为最新版本付出更多的测试与反馈;

追求新特性,这一点算优点也算缺点。比如29一出来,我就热烈的拥抱了treesit特性。

我知道这样的一些特点,一定会有人喜欢,也一定会有人讨厌。但没关系,我们重在交流思路。如果你准备好了跟我一同前行,那么请升级你的Emacs到29版本,我们出发了。

关于安装

由于这是2.0版本,我们不在安装部分下大篇幅。你直接在官网下载你对应的操作系统的版本安装即可;或者使用你对应操作系统的包管理器(如apt,dnf,pacman,scoop,winget,homebrew等)进行安装即可。

先说说early-init.el

这个文件是被非常早的加载的一个文件,所以我们可以适当的用来优化一些启动方面的参数。例如:

(setq gc-cons-threshold most-positive-fixnum)
(add-hook 'after-init-hook #'(lambda () (setq gc-cons-threshold 800000)))

这样的代码已经被证实可以非常好的优化启动速度。

同时你也可以把一些界面禁用的操作放到这里来,例如:

(push '(scroll-bar-mode . nil) default-frame-alist)
(push '(tool-bar-mode . nil) default-frame-alist)

(when (fboundp 'tool-bar-mode) (tool-bar-mode -1))
(when (fboundp 'scroll-bar-mode) (scroll-bar-mode -1))

你甚至还可以放一些其他的内容。看你喜欢。一般来说,我建议你也别放太多,因为从代码的管理上来看,我们把不影响启动的一些配置,还是放到init.el中更合适。

以下所有代码都会在init.el中进行配置,因为代码行总共约300行(含注释)而已,所以我们不再拆分不同的el文件,因为那样也会在读取文件上可能损耗一些(尽管微不足道)的时间。

几个自定义的变量

由于后面的配置中,我们会需要使用到一些判断或者允许其他人在custom.el或者其他位置自定义的一些功能,所以我们提前定义几个变量。定义变量的基本格式是:

(defvar VAR-NAME DEFAULT-VALUE DOCUMENTS)

所以我们定义两个操作系统相关的:

(defvar cabins--os-win (memq system-type '(ms-dos windows-nt cygwin)))
(defvar cabins--os-mac (eq system-type 'darwin))

由于名字取的〔非常好〕,所以我省略了注释。

这里没有定义Linux的原因,不是因为我不喜欢Linux(实际上,我是Linux的忠实粉丝,我甚至在B站有个系列叫《Linux体验周刊》),而是Linux的兼容性非常好,不需要特殊的设置,所以不需要额外的逻辑判断。

此外我还定义了几个字体集变量:

(defvar cabins--fonts-default '("Sometype Mono" "Cascadia Code PL" "Menlo" "Consolas"))
(defvar cabins--fonts-unicode '("Segoe UI Symbol" "Symbola" "Symbol"))
(defvar cabins--fonts-emoji '("Noto Color Emoji" "Apple Color Emoji"))
(defvar cabins--fonts-cjk '("KaiTi" "STKaiTi" "WenQuanYi Micro Hei"))

这里我解释一下,为什么我使用楷体作为默认的中文字体,因为我发现它通过我后面的配置可以非常完美的与英文字体进行等宽显示。至于英文字体,我最近迷上了Sometype Mono这款圆润(而毫无特色)的字体。如果你有自己的喜好,可以修改这几个变量,也可以在其他的位置通过setq函数来改变这几个变量的值。

字体配置

一般来说,这样的配置应该最后讲,但,我偏偏要先说。因为这个地方困扰了太多的人了。为了实现从字体集中选择出最合适的字体(就像CSS中font-family那样),我们先来写一个函数:

(require 'subr-x) ;; cl-loop来自这里

(defun cabins--set-font-common (character font-list &optional scale-factor)
  "Set fonts for multi CHARACTER from FONT-LIST and modify style with SCALE-FACTOR."

  (cl-loop for font in font-list
       when (find-font (font-spec :name font))
       return (if (not character)
              (set-face-attribute 'default nil :family font)
            (when scale-factor (setq face-font-rescale-alist `((,font . ,scale-factor))))
            (set-fontset-font t character (font-spec :family font) nil 'prepend))))

这个函数看着很长,其实就是针对字符集来选择一个字体(如果这个字体已经安装,通过find-font查找),然后进行设置。scale-factor主要是针对中文来进行缩放的。

所以接下来,我们就可以设置我们的字体了:

(defun cabins--font-setup (&optional default-fonts unicode-fonts emoji-fonts cjk-fonts)
  "Font setup, with optional DEFAULT-FONTS, UNICODE-FONTS, EMOJI-FONTS, CJK-FONTS."

  (interactive)
  (when (display-graphic-p)
    (cabins--set-font-common nil (if default-fonts default-fonts cabins--fonts-default))
    (cabins--set-font-common 'unicode (if unicode-fonts unicode-fonts cabins--fonts-unicode))
    (cabins--set-font-common 'emoji (if emoji-fonts emoji-fonts cabins--fonts-emoji))
    (dolist (charset '(kana han bopomofo cjk-misc))
      (cabins--set-font-common charset (if cjk-fonts cjk-fonts cabins--fonts-cjk) 1.2))))

这段代码应该比较容易理解,interactive让这个函数可以通过M-x来调用,那一堆optional的参数实现了你可以在代码中调用这个函数来设置自己的字体集。

经过了上面这两个函数的配置(第一个函数是为了给第二个内部调用),我们的字体基本没有什么恼人的问题了。

主题

说完了字体,我们干脆一起设置一个漂亮的主题。先上代码:

(defun cabins--load-theme()
  "Load theme, Auto change color scheme according to system dark mode on Windows."

  (interactive)
  (when (display-graphic-p)
    ;; choose theme according to system dark/light mode
    (let* ((cmd (cond
         (cabins--os-win
          (concat
           "powershell "
           "(Get-ItemProperty -Path "
           "HKCU:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize "
           "-Name AppsUseLightTheme).AppsUseLightTheme"))
         (cabins--os-mac
          "defaults read -g AppleInterfaceStyle")
         ((eq system-type 'gnu/linux)
          "gsettings get org.gnome.desktop.interface color-scheme")))
       (mode (string-trim (shell-command-to-string cmd))))
      (if (member mode '("0" "Dark" "'prefer-dark'"))
      (load-theme 'modus-vivendi t)
    (load-theme 'modus-operandi t)))))

这个函数可以判断操作系统的暗黑模式或者明亮模式(其中Linux那里只判断了GNOME桌面的,其他桌面的用户可自形容补充),然后根据系统的主题色调来设置Emacs的亮色主题(modus-operandi)还是暗色主题(modus-vivendi)。

针对daemon用户以及希望能够改变了亮暗色就立即生效的用户,我们可以添加如下的代码,使体验更好:

(defun cabins--reset-ui()
  "Try to reset ui options."

  (interactive)
  (cabins--font-setup)
  (cabins--load-theme))

(add-hook 'after-init-hook #'cabins--reset-ui)
;; 下面这条慎用,部分系统上可能有严重的性能问题
;; (add-hook 'window-configuration-change-hook #'cabins--load-theme)
(when (daemonp)
  (add-hook 'after-make-frame-functions
        (lambda (frame) (with-selected-frame frame
                  (cabins--reset-ui)))))

package以及use-package

好消息!Emacs 29已经将use-package这个大杀器内置(built-in)了。所以我们不需要在额外的安装它,而可以放心的直接使用它。那还说什么?先用它来配置一下package这个内置包管理器试试。

(use-package package
  :config
  (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
  (unless (bound-and-true-p package--initialized)
    (package-initialize)))

如果你对use-package有更多的选项配置,其实也可以一起写在这里。

关于内置包

我一定要给你们推荐一些内置包,这些包可以极大程度地减少你对第三方包的依赖。

global-auto-revert-mode(since v25.1) 可以让你的文件内容(因为其他原因改变了的时候)自动加载到最新的内容

auto-save-visited-mode(since v26.1) 可以自动保存,有这个内置包,其他的自动保存的包都扔掉吧

delete-selection-mode(since v20.1) 这个在编辑(删除文字)的时候有用

fido-vertical-mode(since v28.1) 可以让你的minibuffer变成垂直的,非常推荐

flyspell-mode(since v20.3) 拼写检查,依赖系统安装aspell程序,Windows系统慎用,疑似有性能问题〔笔者个人体验结论,非大众普遍观点〕

global-hl-line-mode(since v21.1) 高亮当前行,这个建议图形化(display-graphic-p)情况下使用,感觉在命令行下使用的时候,有的时候体验不好,看个人喜好

recentf-mode(since v22.1),其中v29添加了recentf-open函数,可以打开近期文件。如果你不喜欢recentf-open的行为,可以试试recentf-open-files

repeat-mode(since v28.1) 这个命令我不知道怎么描述,比如你想不停的撤销的时候,你就可以只按一次C-x u而之后就只按u即可,能支持很多类似的命令

几个够用的第三方包

company

第一个当然是自动补全,这对于我们程序员来说,是不能缺少的东西。

(use-package company :ensure t :defer t
  :hook (after-init . global-company-mode))

如果你只喜欢在编程的时候启用,可以将:hook一行改成:hook (prog-mode . company-mode)。默认输入第三个字母的时候开始出现补全选项。我最早会改出1个,但后来发现,完全没有必要,默认3个就很好,毕竟int``def这样的关键字,输入比补全更快。

exec-path-from-shell

这个包你还真必须得安装,它可以帮助读取你的环境变量。不然很多的时候,我们会出现找不到我们〔明明就在那里〕的一些命令。

;; Settings for exec-path-from-shell
;; fix the PATH environment variable issue
(use-package exec-path-from-shell
  :ensure t
  :when (or (memq window-system '(mac ns x))
        (unless cabins--os-win
          (daemonp)))
  :init (exec-path-from-shell-initialize))

format-all

我不知道从什么时候开始,依赖上了格式化工具。我想可能是学习Go与Rust以来,它们提供的gofmt以及rustfmt让我感觉代码格式化是一种必要的东西。所以我就希望,我所有的代码都能够格式化。然后format-all这个工具包就走入了我的必备清单。

;; great for programmers
(use-package format-all :ensure t :defer t
  ;; 开启保存时自动格式化
  :hook (prog-mode . format-all-mode)
  ;; 绑定一个手动格式化的快捷键
  :bind ("C-c f" . #'format-all-region-or-buffer))

gnu-elpa-keyring-update

这个是个可选包,只是我还是希望能够更新下校验的keyring,所以就保留了。

(use-package gnu-elpa-keyring-update :ensure t :defer t)

iedit

这个包我一直没怎么用,直到有一天我在重构代码的时候。它可以让你快速的一次性修改buffer中出现的变量名称。(使用的时候要小心)

(use-package iedit :ensure t :defer t)

move-dup

我承认,我需要这个包,完全是因为被VSCode以及JetBrains系列惯坏了。我需要把代码行移上去,或者移下来的。但其实吧,内置的transpose-line也能完成类似的功能,只是我感觉有的时候跟我想的可能有差距。我需要停下来想一下。所以就保留了这个包。

(use-package move-dup :ensure t :defer t
  :hook (after-init . global-move-dup-mode))

which-key

啊,我一直想如果这个能作为一个内置包就好了。虽然很多的时候我是在使用M-x,但,这个东西可以提示接下来可能用到的快捷键,会让我的安全感爆棚。

(use-package which-key :ensure t :defer t
  :hook (after-init . which-key-mode))

我一共就使用了这7个第三方包,这也是我的配置速度运行快的一个重要的原因。其他的第三方包对我来说没有吸引力主要是因为:

可能拖慢速度(毕竟我过去一年有很多的时间在使用Windows这样的操作系统)

内置包可替代,比如Magit,啊,我已经深深爱上了内置的VC

想不出什么第三方包对我来说是必不可少的了

操作系统相关设置

如果你有我这样的使用Windows系统的经历,你就不应该错过这个小的篇章。

;;Configs for OS
;; Special configs for MS-Windows
(when (and cabins--os-win
       (boundp 'w32-get-true-file-attributes))
  (setq w32-get-true-file-attributes nil
    w32-pipe-read-delay 0
    w32-pipe-buffer-size (* 64 1024)))

;; Special configs for macOS
(when cabins--os-mac
  (setq mac-command-modifier 'meta
    mac-option-modifier 'super
    ns-use-native-fullscreen t))

;; solve the Chinese paste issue
;; let Emacs auto-guess the selection coding according to the Windows/system settings
(unless cabins--os-win
  (set-selection-coding-system 'utf-8))

主要是设置文件、编码以及按键映射。

编程

终于到了这个我最喜欢的环节了。职业病,没有办法。得益于Emacs 29对eglot的内置,我们在这里可以减少了一个第三方包的配置,同时减少了很多的配置代码。但在配置eglot之前,我们先启用几个内置包,来增强我们的编程模式。

(add-hook 'prog-mode-hook 'column-number-mode) ;在ModeLine显示列号
(add-hook 'prog-mode-hook 'display-line-numbers-mode) ;显示行号
(add-hook 'prog-mode-hook 'electric-pair-mode) ;括号的配对
(add-hook 'prog-mode-hook 'flymake-mode) ;错误的提示
(add-hook 'prog-mode-hook 'hs-minor-mode) ;代码的折叠
(add-hook 'prog-mode-hook 'prettify-symbols-mode) ;会将lambda等符号美化为λ

顺便,我们听从flymake的官方建议,给错误跳转绑定两个快捷键(我天天在用):

(global-set-key (kbd "M-n") #'flymake-goto-next-error)
(global-set-key (kbd "M-p") #'flymake-goto-prev-error)

treesit

从v29开始,内置了treesit的支持。它是一个解析器生成工具和增量解析库。 它可以为源文件构建一个具体的语法树, 并在源文件被编辑时高效地更新语法树。 这种技术相对于 Emacs 以前基于正则表达式来实现的语法高亮功能, 性能上要快很多, 而且在复杂表达式场景下的语法高亮准确度要高很多。

同时,v29也内置了许多的-ts-mode,比如go-ts-mode,rust-ts-mode,typescripe-ts-mode等等。让我们(配合eglot)就不再需要go-mode,rust-mode等这些第三方包了。实在爽快!

(use-package treesit
  :when (and (fboundp 'treesit-available-p)
         (treesit-available-p))
  :config (setq treesit-font-lock-level 4)
  :init
  (setq treesit-language-source-alist
    '((bash       . ("https://github.com/tree-sitter/tree-sitter-bash"))
      (c          . ("https://github.com/tree-sitter/tree-sitter-c"))
      (cpp        . ("https://github.com/tree-sitter/tree-sitter-cpp"))
      (css        . ("https://github.com/tree-sitter/tree-sitter-css"))
      (cmake      . ("https://github.com/uyha/tree-sitter-cmake"))
      (csharp     . ("https://github.com/tree-sitter/tree-sitter-c-sharp.git"))
      (dockerfile . ("https://github.com/camdencheek/tree-sitter-dockerfile"))
      (elisp      . ("https://github.com/Wilfred/tree-sitter-elisp"))
      (go         . ("https://github.com/tree-sitter/tree-sitter-go"))
      (gomod      . ("https://github.com/camdencheek/tree-sitter-go-mod.git"))
      (html       . ("https://github.com/tree-sitter/tree-sitter-html"))
      (java       . ("https://github.com/tree-sitter/tree-sitter-java.git"))
      (javascript . ("https://github.com/tree-sitter/tree-sitter-javascript"))
      (json       . ("https://github.com/tree-sitter/tree-sitter-json"))
      (lua        . ("https://github.com/Azganoth/tree-sitter-lua"))
      (make       . ("https://github.com/alemuller/tree-sitter-make"))
      (markdown   . ("https://github.com/MDeiml/tree-sitter-markdown" nil "tree-sitter-markdown/src"))
      (ocaml      . ("https://github.com/tree-sitter/tree-sitter-ocaml" nil "ocaml/src"))
      (org        . ("https://github.com/milisims/tree-sitter-org"))
      (python     . ("https://github.com/tree-sitter/tree-sitter-python"))
      (php        . ("https://github.com/tree-sitter/tree-sitter-php"))
      (typescript . ("https://github.com/tree-sitter/tree-sitter-typescript" nil "typescript/src"))
      (tsx        . ("https://github.com/tree-sitter/tree-sitter-typescript" nil "tsx/src"))
      (ruby       . ("https://github.com/tree-sitter/tree-sitter-ruby"))
      (rust       . ("https://github.com/tree-sitter/tree-sitter-rust"))
      (sql        . ("https://github.com/m-novikov/tree-sitter-sql"))
      (vue        . ("https://github.com/merico-dev/tree-sitter-vue"))
      (yaml       . ("https://github.com/ikatyang/tree-sitter-yaml"))
      (toml       . ("https://github.com/tree-sitter/tree-sitter-toml"))
      (zig        . ("https://github.com/GrayJack/tree-sitter-zig"))))
  (add-to-list 'major-mode-remap-alist '(sh-mode         . bash-ts-mode))
  (add-to-list 'major-mode-remap-alist '(c-mode          . c-ts-mode))
  (add-to-list 'major-mode-remap-alist '(c++-mode        . c++-ts-mode))
  (add-to-list 'major-mode-remap-alist '(c-or-c++-mode   . c-or-c++-ts-mode))
  (add-to-list 'major-mode-remap-alist '(css-mode        . css-ts-mode))
  (add-to-list 'major-mode-remap-alist '(js-mode         . js-ts-mode))
  (add-to-list 'major-mode-remap-alist '(java-mode       . java-ts-mode))
  (add-to-list 'major-mode-remap-alist '(js-json-mode    . json-ts-mode))
  (add-to-list 'major-mode-remap-alist '(makefile-mode   . cmake-ts-mode))
  (add-to-list 'major-mode-remap-alist '(python-mode     . python-ts-mode))
  (add-to-list 'major-mode-remap-alist '(ruby-mode       . ruby-ts-mode))
  (add-to-list 'major-mode-remap-alist '(conf-toml-mode  . toml-ts-mode))
  (add-to-list 'auto-mode-alist '("\\(?:Dockerfile\\(?:\\..*\\)?\\|\\.[Dd]ockerfile\\)\\'" . dockerfile-ts-mode))
  (add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode))
  (add-to-list 'auto-mode-alist '("/go\\.mod\\'" . go-mod-ts-mode))
  (add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-ts-mode))
  (add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-ts-mode))
  (add-to-list 'auto-mode-alist '("\\.y[a]?ml\\'" . yaml-ts-mode)))

其实treesit-language-source-alist里面不需要配置这么多,但这样显得标准而且很专业的样子,所以我就都保留了。而且说不准,谁会用到比如zig这样的语言。

eglot

内置了之后,最大的好处就是〔足够少的配置,开箱即用〕,看,代码已经这么少了:

(use-package eglot
  :hook (prog-mode . eglot-ensure)
  :bind ("C-c e f" . eglot-format))

bind那一行是绑定了一个格式化的快捷键,如果你还记得我前面提到的format-all的话,这个快捷键就不是那么必须了。

可选第三方包

如果你像我一样有些特殊的需求的话,比如显示protobuf或者quickrun等,你可以在这里配置(也可以在custom.el中配置)。

(use-package protobuf-mode :ensure t :defer t)
(use-package quickrun :ensure t :defer t)
(use-package restclient :ensure t :defer t
  :mode (("\\.http\\'" . restclient-mode)))

custom.el

前面有提到这个自定义的配置,这里的配置会因人/平台而异。所以这个文件不建议添加到git管理中。要想加载这个文件,我们需要在我们的init.el文件中写入这样的加载代码:

(setq custom-file (locate-user-emacs-file "custom.el"))
(when (file-exists-p custom-file)
  (load custom-file))

结束语

这就是我全部的配置了。可能随着时间的变化,我会再有一些不一样的想法。如果你想看到我最新的想法,可以star我的配置:https://github.com/cabins/emacs.d

另外,文中提到的一些教程/课程(全都是免费的),可以关注我的B站观看(ID:第253页图灵笔记),或我的掘金频道阅读,后续我也会在少数派继续写更多的文章。

希望你能喜欢。