Manateelazycat 的 Emacs 启动文件 site-start.el 研究: Difference between revisions
Jump to navigation
Jump to search
Tag: Reverted |
|||
| (3 intermediate revisions by the same user not shown) | |||
| Line 2: | Line 2: | ||
== 源代码 == | == 源代码 == | ||
< | <syntaxhighlight lang="elisp"> | ||
(require 'cl-lib) | (require 'cl-lib) | ||
| Line 42: | Line 42: | ||
(require 'init) | (require 'init) | ||
</ | </syntaxhighlight> | ||
== 详细解析 == | == 详细解析 == | ||
| Line 54: | Line 54: | ||
### let* 把 dolist 包含在内,是划定 let 定义的变量的使用范围 | ### let* 把 dolist 包含在内,是划定 let 定义的变量的使用范围 | ||
### dir 就是把 search-dir 加上后斜杠后的结果 | ### dir 就是把 search-dir 加上后斜杠后的结果 | ||
## dolist 对列表执行操作 | ## dolist 对列表执行操作 | ||
### subdir 是待处理的 VAR | ### subdir 是待处理的 VAR | ||
### cl-remove-if 函数的结果是 LIST | ### cl-remove-if 函数的结果是 LIST | ||
| Line 60: | Line 60: | ||
#### lambda 函数,判断不适宜目录 | #### lambda 函数,判断不适宜目录 | ||
#### cl-remove-if 把 dir 里符合上边两个判断的文件夹移除 | #### cl-remove-if 把 dir 里符合上边两个判断的文件夹移除 | ||
### 执行的操作是,在前提条件下,把 subdir-path 加入 load-path 列表末尾 | ### 执行的操作是,在前提条件下,把 subdir-path 加入 load-path 列表末尾 | ||
#### 拼接 dir 和 subdir,达到找到下一级有效目录的效果 | #### 拼接 dir 和 subdir,达到找到下一级有效目录的效果 | ||
#### cl-some 用 file-regular-p 过滤存有特定后缀文件的文件夹 | #### cl-some 用 file-regular-p 过滤存有特定后缀文件的文件夹 | ||
# 运行 add-subdirs-to-load-path,"/usr/share/emacs/lazycat" 就是 search-dir | # 运行 add-subdirs-to-load-path,"/usr/share/emacs/lazycat" 就是 search-dir | ||
== 先验知识 == | == 先验知识 == | ||
| Line 103: | Line 98: | ||
所有原生函数,都可以通过 C-h f 查询核心结构、用法用途。 | 所有原生函数,都可以通过 C-h f 查询核心结构、用法用途。 | ||
最重要的事:其实 Emacs 本身自带 Eldoc 模式,在 Emacs 里读 elisp 代码,它本身就会显示以下函数的用法。 | |||
<syntaxhighlight lang="elisp"> | <syntaxhighlight lang="elisp"> | ||
# let* 的核心结构 | # let* 的核心结构 | ||
Latest revision as of 19:16, 10 July 2026
Manateelazycat 的 Emacs 启动文件 site-start.el 写得很妙,值得研究。
源代码
(require 'cl-lib)
(tool-bar-mode -1) ;禁用工具栏
(menu-bar-mode -1) ;禁用菜单栏
(scroll-bar-mode -1) ;禁用滚动条
(defun add-subdirs-to-load-path (search-dir)
(interactive)
(let* ((dir (file-name-as-directory search-dir)))
(dolist (subdir
;; 过滤出不必要的目录,提升Emacs启动速度
(cl-remove-if
#'(lambda (subdir)
(or
;; 不是目录的文件都移除
(not (file-directory-p (concat dir subdir)))
;; 父目录、 语言相关和版本控制目录都移除
(member subdir '("." ".."
"dist" "node_modules" "__pycache__"
"RCS" "CVS" "rcs" "cvs" ".git" ".github"))))
(directory-files dir)))
(let ((subdir-path (concat dir (file-name-as-directory subdir))))
;; 目录下有 .el .so .dll 文件的路径才添加到 `load-path' 中,提升Emacs启动速度
(when (cl-some #'(lambda (subdir-file)
(and (file-regular-p (concat subdir-path subdir-file))
;; .so .dll 文件指非Elisp语言编写的Emacs动态库
(member (file-name-extension subdir-file) '("el" "so" "dll"))))
(directory-files subdir-path))
;; 注意:`add-to-list' 函数的第三个参数必须为 t ,表示加到列表末尾
;; 这样Emacs会从父目录到子目录的顺序搜索Elisp插件,顺序反过来会导致Emacs无法正常启动
(add-to-list 'load-path subdir-path t))
;; 继续递归搜索子目录
(add-subdirs-to-load-path subdir-path)))))
(add-subdirs-to-load-path "/usr/share/emacs/lazycat")
(require 'init)
详细解析
- (require 'cl-lib) 为要用到的 cl 做铺势
- -1 的三个选项很简单,不用谈
- 自定义了一个函数,叫 add-subdirs-to-load-path,它的变量是 search-dir
- interactive 意为可交互唤起,简单略
- let* 定义 dir
- 这里只定义了一个 dir,其实可以定义多个局部变量
- 其实可以再加很多局部变量,如 ( (dir (one)) (zhangsan (two)) (lisi (three)) ),所以用了三层括号
- let* 把 dolist 包含在内,是划定 let 定义的变量的使用范围
- dir 就是把 search-dir 加上后斜杠后的结果
- dolist 对列表执行操作
- subdir 是待处理的 VAR
- cl-remove-if 函数的结果是 LIST
- lambda 函数,判断非目录
- lambda 函数,判断不适宜目录
- cl-remove-if 把 dir 里符合上边两个判断的文件夹移除
- 执行的操作是,在前提条件下,把 subdir-path 加入 load-path 列表末尾
- 拼接 dir 和 subdir,达到找到下一级有效目录的效果
- cl-some 用 file-regular-p 过滤存有特定后缀文件的文件夹
- 运行 add-subdirs-to-load-path,"/usr/share/emacs/lazycat" 就是 search-dir
先验知识
在 Emacs 里,(require 'sth) 相当于告诉 Emacs,在 load-path 里找 sth.el 或 sth.elc 等文件。
所以 load-path 如此重要,相当于环境变量。
| 简写 | 全写 | 人话 |
|---|---|---|
'x
|
(quote x)
|
别执行,当数据 |
#'x
|
(function x)
|
别执行,当函数 |
'("A" "B")
|
(quote ("A" "B"))
|
这是列表,不是函数调用 |
#'(lambda (x) x)
|
(function (lambda (x) x))
|
这是匿名函数 |
`(a ,b c)
|
(quasiquote (a (unquote b) c))
|
大模板里局部求值 |
所有原生函数,都可以通过 C-h f 查询核心结构、用法用途。
最重要的事:其实 Emacs 本身自带 Eldoc 模式,在 Emacs 里读 elisp 代码,它本身就会显示以下函数的用法。
# let* 的核心结构
# 按顺序绑定变量,后边的变量可以用前面的变量的值
(let* VARLIST BODY...)
# let 的核心结构
# 同时绑定变量,后边的变量寻求前面的变量的值时,会报错,因为它们同时诞生
(let VARLIST BODY...)
# dolist 的核心结构
(dolist
(VAR LIST [RESULT])
BODY ...)
# cl-remove-if 的核心结构
# cl-remove-if 的作用:Remove all items satisfying PREDICATE in SEQ.
(cl-remove-if PREDICATE SEQ [KEYWORD VALUE]...)
# cl-some 的核心结构
# cl-some 的作用:Say whether PREDICATE is true for any element in the SEQ sequences.
(cl-some PREDICATE SEQ...)
# concat 的核心结构
(concat &rest SEQUENCES)