更新时间 | 备注 |
---|---|
2023-02-26 | 增加更多判断逻辑, 比如上一行是列表,当前行也是列表,则按正常缩进计算 |
一直以来 yaml-mode 都有一个问题,在使用 (indent-region (point-min) (point-max))
时已经格式好的内容总是会得到错误的缩进,比如一个简单的配置
test1: "val" test2: - "val1" - "val2" test3: test4: "val4"
在调用 indent-regin
后就会变成
test1: "val" test2: - "val1" - "val2" test3: 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
的值, 这里并没有判断当前行是新建行还是已经有相关内容,如果是新建行那么缩进就是对的,如果是已有的内容就是错的,所以我修改了这一部分逻辑,如果是 已有内容并且当前行的缩进小于上一行 则不进行处理, 比如:
- "val2"
test3:
虽然增加的判断逻辑很简单,但至少在使用 indent-region
时已经格式好的内容就不会出现混乱的情况了, 也不用专门为 yaml 文件激活一个 lsp 进程。
目前处理的方式还是采用 advice + letf 形式,否则需要修改很多内容,有兴趣的同道可以参考一下
(defun maple/yaml-compute-indentation() (let ((ci (current-indentation)) (cm (looking-at yaml-hash-key-re)) (cl (looking-at "^\s*-\s+.*$"))) (save-excursion (beginning-of-line) (if (looking-at yaml-document-delimiter-re) 0 (forward-line -1) (while (and (looking-at yaml-blank-line-re) (> (point) (point-min))) (forward-line -1)) (let ((li (current-indentation)) (ll (looking-at "^\s*-\s+.*$"))) ;; 如果上一行的缩进大于当前行, 上一行是列表,当前行也是是列表 - 正常缩进 ;; 如果上一行的缩进大于当前行, 上一行和当前行有一个不是列表 - 原有缩进 ;; 如果上一行的缩进等于当前行, 上一行是字典,当前行是列表 - 正常缩进 ;; 如果上一行的缩进等于当前行, 上一行是字典,当前行是不是列表 - 原有缩进 ;; 如果上一行的缩进小于当前行, 上一行是字典 - 正常缩进 ;; 如果上一行的缩进小于当前行, 上一行是列表,当前行也是列表 - 正常缩进 ;; 如果上一行的缩进小于当前行, 上一行是列表,当前行是字典 - 错误/正常缩进 (if (or (and (> li ci) (or (not cl) (not ll))) (and (= li ci) cm (not ll))) ci (+ li (if (looking-at yaml-nested-map-re) yaml-indent-offset 0) (if (looking-at yaml-nested-sequence-re) yaml-indent-offset 0) (if (looking-at yaml-block-literal-re) yaml-indent-offset 0)))))))) (defun maple/yaml-indent-region(func &rest args) (if (derived-mode-p 'yaml-mode) (letf (((symbol-function 'yaml-compute-indentation) 'maple/yaml-compute-indentation)) (apply func args)) (apply func args))) (advice-add 'indent-region :around 'maple/yaml-indent-region)