| 更新时间 | 备注 |
|---|---|
| 2023-02-26 | 增加更多判断逻辑, 比如上一行是列表,当前行也是列表,则按正常缩进计算 |
一直以来 yaml-mode 都有一个问题,在使用 (indent-region (point-min) (point-max)) 时已经格式好的内容总是会得到错误的缩进,比如一个简单的配置
1test1: "val"
2test2:
3 - "val1"
4 - "val2"
5test3:
6 test4: "val4"
在调用 indent-regin 后就会变成
1test1: "val"
2test2:
3 - "val1"
4 - "val2"
5 test3:
6 test4: "val4"
而我又总是手痒,写好的配置文件总是会忍不住 indent-region 一番,结果本来正确的格式立马变得各种乱七八糟,当初为了解决这个问题,还专门为 yaml-mode 激活了 lsp-mode, 并且使用 lsp-format-buffer 来进行处理。
本来一切都还正常,但最近发现了另外一个问题,如果在 org-mode 中插入 yaml 的代码片段,调用 indent-region 还是还有之前的问题, org-mode 中又无法直接调用 lsp-format-buffer, 所以专门研究了一下 yaml-mode
发现 yaml-mode 只是定义了 indent-line-function 变量,没有定义 indent-region-function, 导致调用 indent-region 时其实是逐行调用 yaml-indent-line, 这里面有一个计算当前缩进的 yaml-compute-indentation 函数,计算方式有些简单粗暴,如果上一行是一个 hash key, 当前行的缩进就是上一行的缩进加 yaml-indent-offset 的值, 这里并没有判断当前行是新建行还是已经有相关内容,如果是新建行那么缩进就是对的,如果是已有的内容就是错的,所以我修改了这一部分逻辑,如果是 已有内容并且当前行的缩进小于上一行 则不进行处理, 比如:
1 - "val2"
2test3:
虽然增加的判断逻辑很简单,但至少在使用 indent-region 时已经格式好的内容就不会出现混乱的情况了, 也不用专门为 yaml 文件激活一个 lsp 进程。
目前处理的方式还是采用 advice + letf 形式,否则需要修改很多内容,有兴趣的同道可以参考一下
1(defun maple/yaml-compute-indentation()
2 (let ((ci (current-indentation))
3 (cm (looking-at yaml-hash-key-re))
4 (cl (looking-at "^\s*-\s+.*$")))
5 (save-excursion
6 (beginning-of-line)
7 (if (looking-at yaml-document-delimiter-re) 0
8 (forward-line -1)
9 (while (and (looking-at yaml-blank-line-re)
10 (> (point) (point-min)))
11 (forward-line -1))
12 (let ((li (current-indentation))
13 (ll (looking-at "^\s*-\s+.*$")))
14 ;; 如果上一行的缩进大于当前行, 上一行是列表,当前行也是是列表 - 正常缩进
15 ;; 如果上一行的缩进大于当前行, 上一行和当前行有一个不是列表 - 原有缩进
16 ;; 如果上一行的缩进等于当前行, 上一行是字典,当前行是列表 - 正常缩进
17 ;; 如果上一行的缩进等于当前行, 上一行是字典,当前行是不是列表 - 原有缩进
18 ;; 如果上一行的缩进小于当前行, 上一行是字典 - 正常缩进
19 ;; 如果上一行的缩进小于当前行, 上一行是列表,当前行也是列表 - 正常缩进
20 ;; 如果上一行的缩进小于当前行, 上一行是列表,当前行是字典 - 错误/正常缩进
21 (if (or (and (> li ci) (or (not cl) (not ll))) (and (= li ci) cm (not ll))) ci
22 (+ li
23 (if (looking-at yaml-nested-map-re) yaml-indent-offset 0)
24 (if (looking-at yaml-nested-sequence-re) yaml-indent-offset 0)
25 (if (looking-at yaml-block-literal-re) yaml-indent-offset 0))))))))
26
27(defun maple/yaml-indent-region(func &rest args)
28 (if (derived-mode-p 'yaml-mode)
29 (letf (((symbol-function 'yaml-compute-indentation) 'maple/yaml-compute-indentation))
30 (apply func args))
31 (apply func args)))
32
33(advice-add 'indent-region :around 'maple/yaml-indent-region)
知识共享署名-非商业性使用-相同方式共享4.0国际许可协议