面向产品经理的Emacs教程:3. 使用Org mode来管理Emacs配置文件

· 2226字 · 5分钟

1 Emacs配置文件的管理方式 🔗

我们通常可以有如下几种方式来管理配置文件:

  1. 将所有配置都放到 ~/.emacs 文件里(比较老的方式,不推荐)
  2. 将所有配置文件都统一放到 ~/.emacs.d/init.el 里;
  3. 将所有配置文件通过一个org文件来管理,通过 org-babel-load-file 函数来加载;
  4. 将所有配置文件模块化,通过 init.el 来统一加载(这是众多大佬采用的方式);
  5. 将所有配置文件通过一个org文件来管理,通过tangle的技术实现模块化(最优解);

这里我们讲解我个人认为的最优解——将所有配置文件放到一个org文件来管理,并通过Org mode的tangle功能实现模块化。这也是为什么我们第二讲先简单讲Org mode的原因。

使用Org mode来管理所有的配置文件的好处是,通过Org mode强大的文学编程功能,我们可以让我们的配置文件更加清晰有序,并且可以添加很多注释之外的资料、链接等,让我们的配置更加易读和可管理。

2 通过Org mode的tangle功能管理模块化配置 🔗

2.1 在Emacs配置文件目录创建Org文件 🔗

第一步,在Emacs的配置文件目录 ~/.emacs.d/ 下创建一个后缀为 .org 的文件,例如 emacs-config.org

当然,理论上你可以在电脑的任何位置创建这个org文件,因为在使用Org mode tangle功能的时候,填好路径就可以自动的将代码块里的配置代码写入指定位置的文件。

做完以上工作后,我们 ~/.emacs.d 文件夹可能长下面这样:

/Users/randolph/.emacs.d/
└── emacs-config.org

2.2 写上标题等信息 🔗

在Org文件里写上标题等信息。这里几行代码的含义如下:

  • #+TITLE:: 这一行填这个文档的标题
  • #+AUTHOR:: 这一行填这个文档的作者
  • #+DATE:: 这一行填这个文档的创建时间
  • #+STARTUP:: 这一行表示每次打开这个org文档的时候,默认把所有的标题行折叠起来(Overview)
#+TITLE: Emacs配置文件
#+AUTHOR: Randolph
#+DATE: 2022/12/22 14:23:50

#+STARTUP: overview

2.3 Org babel tangle 🔗

这个功能是Org mode的一个非常棒的功能,它能够自动的将代码块里的代码,写入到指定的文件里去。而且它的配置方式也非常灵活,可以在代码块的参数行配置tangle参数,也可以在Org mode的标题行添加标题参数配置。

后者的好处在于,不需要为每个代码块都配置tangle参数。

2.3.1 代码块配置tangle 🔗

下面的例子展示如何在代码块来配置tangle参数。在代码块写语言类型的这一行,添加 :tangle 参数,后面跟着的是你期望这个代码块的代码自动写入到哪个文件。在这个例子里,代码 (+ 1 2) 将写入到 ~/.emacs.d/test.el 这个文件里。

#+BEGIN_SRC emacs-lisp :tangle ~/.emacs.d/test.el
(+ 1 2)
#+END_SRC

2.3.2 标题行配置tangle 🔗

下面的例子展示如何在标题栏通过标题参数来配置tangle。在标题行下方,紧接着通过 :PROPERTIES::END: 包裹的区域,即 属性抽屉 里,添加 :HEADER-ARGS: 行,通过 :tangle 后加上指定自动写入的文件路径,来配置这个标题行下所有的代码块的自动写入行为。

当配置了标题行级别的tangle,那这个标题行下所有的代码块(包括这个标题级别下的子标题内的代码块),自动写入配置的文件中,且代码块的参数行不需要再配置 :tangle 参数了。

* early-init.el
:PROPERTIES:
:HEADER-ARGS: :tangle early-init.el
:END:

在Emacs刚启动,还未加载主要配置文件时的配置文件。

有人肯定会问,那万一在这个标题行下面,我有一个代码块,并不想写入文件怎么办?或者我有一个子标题下面的所有代码快都不想写入文件怎么办?

  1. 如果不想让某个代码块写入,直接在代码块的参数行写上 :tangle no 就可以了。
  2. 如果不想让某个子标题下的所有代码块写入,那直接给这个子标题添加一个属性抽屉包裹的标题参数 :HEADER-ARGS: :tangle no 就可以了。

2.4 以 early-init.el 为例配置第一个小模块 🔗

下面以 early-init.el 为例,通过Org文件的tangle功能,我们进行第一个模块化的配置。

先不用管这个配置文件是干嘛用的,也不用弄明白这个配置文件里的每一行是啥意思,对初学者来说,第一步就是学会抄。你要做的就是复制粘贴就可以了。


* early-init.el
:PROPERTIES:
:HEADER-ARGS: :tangle early-init.el
:END:

在Emacs刚启动,还未加载主要配置文件时的配置文件。

#+BEGIN_SRC emacs-lisp
;;; early-init.el --- Emacs pre-initialization config -*- lexical-binding: t -*-
;;; Commentary:

;;; Code:

;; 设置垃圾回收参数
(setq gc-cons-threshold most-positive-fixnum)
(setq gc-cons-percentage 0.6)

;; 启动早期不加载`package.el'包管理器
(setq package-enable-at-startup nil)
;; 不从包缓存中加载
(setq package-quickstart nil)

;; 禁止展示菜单栏、工具栏和纵向滚动条
(push '(menu-bar-lines . 0) default-frame-alist)
(push '(tool-bar-lines . 0) default-frame-alist)
(push '(vertical-scroll-bars) default-frame-alist)

;; 禁止自动缩放窗口先
(setq frame-inhibit-implied-resize t)

;; 禁止菜单栏、工具栏、滚动条模式,禁止启动屏幕和文件对话框
(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)
(setq inhibit-splash-screen t)
(setq use-file-dialog nil)

;; 在这个阶段不编译
(setq comp-deferred-compilation nil)

(provide 'early-init)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; early-init.el ends here
#+END_SRC

所以,最终你的崭新的Emacs里编辑 ~/.emacs.d/emacs-config.org 的界面大概如下:

2.5 tangle代码块 🔗

在Org文件里,写好了代码块,保存文件的时候,Org mode是不会帮你自动写入文件的(未来我们可以通过配置实现),现在,我们需要通过 M-x org-babel-tangle 命令来触发 tangle 这个动作。

你要做的就是按 M-x 后输入 org-babel-tangle 命令,回车,搞定!具体参照下图:

tangle后,在你的 ~/.emacs.d 目录下的结构大致如下:

/Users/randolph/.emacs.d/
├── early-init.el
├── emacs-config.org
└── emacs-config.org~

当你完成了以上这些内容的学习,恭喜你,又迈出了坚实的一步。

3 结语 🔗

经过今天的学习,你的 emacs-config.org 文件,长下面这样:

#+TITLE: Emacs配置文件
#+AUTHOR: Randolph
#+DATE: 2022/12/22 14:23:50

#+STARTUP: overview

* early-init.el
:PROPERTIES:
:HEADER-ARGS: :tangle early-init.el
:END:

在Emacs刚启动,还未加载主要配置文件时的配置文件。

#+BEGIN_SRC emacs-lisp
;;; early-init.el --- Emacs pre-initialization config -*- lexical-binding: t -*-
;;; Commentary:

;;; Code:

;; 设置垃圾回收参数
(setq gc-cons-threshold most-positive-fixnum)
(setq gc-cons-percentage 0.6)

;; 启动早期不加载`package.el'包管理器
(setq package-enable-at-startup nil)
;; 不从包缓存中加载
(setq package-quickstart nil)

;; 禁止展示菜单栏、工具栏和纵向滚动条
(push '(menu-bar-lines . 0) default-frame-alist)
(push '(tool-bar-lines . 0) default-frame-alist)
(push '(vertical-scroll-bars) default-frame-alist)

;; 禁止自动缩放窗口先
(setq frame-inhibit-implied-resize t)

;; 禁止菜单栏、工具栏、滚动条模式,禁止启动屏幕和文件对话框
(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)
(setq inhibit-splash-screen t)
(setq use-file-dialog nil)

;; 在这个阶段不编译
(setq comp-deferred-compilation nil)

(provide 'early-init)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; early-init.el ends here
#+END_SRC