大概一周前就遇到过,今天第二次:我的 Emacs 用过一段时间 if
的缩进出了问题:
(if a
b
c)
正确缩进是:
(if a
b
c)
Emacs -Q 试下没问题,应该是我配置问题,但简单搜索了下 lisp-indent-function
,没发现我的配置和第三方包有修改 if
的缩进。我跑到 lisp-mode.el
下重现执行了一遍
(put 'if 'lisp-indent-function 2)
然后缩进就正常了,不知道谁在什么时候把这个属性给删掉了,大家有没有类似经历,或者 Debug 的思路。
看看有没有用 aggressive-indent ? 这个自动化缩进的插件很有问题,用了很久以后现在全部禁用掉了。
建议配置文件二分查找法重启做对比测试来定位问题。
没安装这个。
manateelazycat:
建议配置文件二分查找法重启做对比测试来定位问题。
还没发现稳定重现的方法,不是一开启 Emacs 就会有这个问题,不太好正向(从配置)调查,等第三次出现这个问题再调查,感觉先了解出现这个现象的哪些可能会有所帮助。
cireu
2019 年5 月 26 日 00:14
5
cl的if是
(IF COND THEN-FORM &optional ELSE-FORM)
Elisp的if是
(IF COND THEN-FORM &rest ELSE-FORM)
elisp的else-form是被progn隐式包裹的,所以和CL的缩进方法不同
抓了几个lisp方言来试,Common Lisp, Scheme, Clojure是optional else-form,elisp和hy是rest else-form
1 个赞
是不是设置过 lisp-indent-function
变量?
(let ((lisp-indent-function 'common-lisp-indent-function))
(with-current-buffer (generate-new-buffer "test-if.el")
(erase-buffer)
(insert "(if t
foo
bar)")
(lisp-mode)
(pp-buffer)
(buffer-substring-no-properties (point-min) (point-max))))
;; =>
;; "(if t
;; foo
;; bar)
;; "
(let ((lisp-indent-function 'lisp-indent-function))
(with-current-buffer (generate-new-buffer "test-if.el")
(erase-buffer)
(insert "(if t
foo
bar)")
(lisp-mode)
(pp-buffer)
(buffer-substring-no-properties (point-min) (point-max))))
;; =>
;; "(if t
;; foo
;; bar)
;; "
2 个赞
之前搜索过 lisp-indent-function
,没发现有改过它。
这个问题没法重现,如果遇到第三次我再调查。
找到根源了,缩进被 newlisp-mode 给修改了:
(if (string-match "true" res)
'utf-8 'shift_jis)))
(setq newlisp-primitive-keywords
(car (read-from-string
(shell-command-to-string
(format "%s -n -e \"(map term (filter (fn (s) (global? s)) (symbols MAIN)))\""
newlisp-command)))))
t)
;; FIXME: This code influence other lisp-mode indent.
(defmacro defindent (operator indentation)
`(put ',operator 'lisp-indent-function ',indentation))
(defindent define 1)
(defindent fn 1)
(defindent begin 0)
(defindent local 1)
(defindent letex 1)
(defindent for 1)
(defindent lambda-macro 1)
我安装了这个包,但压根就没用,之所以 Emacs 依旧执行了这个文件,貌似是 Emacs 26.1 新加入的这个特性的锅:
** New var 'definition-prefixes' is a hash table mapping prefixes to
the files where corresponding definitions can be found. This can be
used to fetch definitions that are not yet loaded, for example for
'C-h f'.
所以解决方法就是把这个包给删了,看样子安装了一个包,就算不用,Emacs 也会可能加载,通过 C-h f 补全自行加载。
一出现这个问题,我立马用 C-h v load-history
查看那些文件加载了,从上往下一个一个文件搜索 lisp-indent-function
,然后就发现了 newlisp-mode.el。
3 个赞
cireu
2019 年6 月 30 日 15:29
11
用了下common-lisp-indent-function
大部分时间可以正确handle,不过偶尔会抽风挺不爽的,缩进cl-flet
的时候比普通lisp-indent-function好看
common-lisp-indent-function
(cl-flet ((update-db! ()
;; The copy is necessary because our SQL query action
;; may conflicts with running Firefox.
(copy-file counsel-ffdata-database-path
counsel-ffdata--temp-db-path)
(clrhash counsel-ffdata--cache)))
(let* ((path counsel-ffdata--temp-db-path))
(condition-case e
(if (file-exists-p path)
(when force-update?
(delete-file path)
(update-db!))
(update-db!))
(error "Failed to ensure firefox database: %s" e))
nil))
lisp-indent-function
(cl-flet ((update-db! ()
;; The copy is necessary because our SQL query action
;; may conflicts with running Firefox.
(copy-file counsel-ffdata-database-path
counsel-ffdata--temp-db-path)
(clrhash counsel-ffdata--cache)))
(let* ((path counsel-ffdata--temp-db-path))
(condition-case e
(if (file-exists-p path)
(when force-update?
(delete-file path)
(update-db!))
(update-db!))
(error "Failed to ensure firefox database: %s" e))
nil))
对,但是我懒得折腾,而且也不是所有人都很讲究,缩进不一样需要协作时就会难受。
我自己一般取个折中写法:
(cl-flet ((mean
(numbers)
(/ (apply #'+ numbers)
(float (length numbers)))))
(mean '(1 2 3 4)))
cireu
2019 年7 月 1 日 03:41
13
总的来说还是利大于弊
(cl-defun func (&whole
whole-args
normal args
&optional
optionA
&key
keyA
keyB
&allow-other-keys
&rest
rest-part))
lisp-indent-function没法漂亮缩进带上CL扩展的参数列表
xuchunyang:
缩进不一样需要协作时就会难受
git hooks强制就好了,哈哈
common-lisp-indent-function
的确大部分时候表现良好,但我已经忘了为何我用了一段时间之后放弃了。
我现在回到 lisp-indent-function
,但是针对 plist 做了些改进。
以前:
;; '(:a 1
;; :b 2
;; :c 3)
现在:
;; '(:a 1
;; :b 2
;; :c 3)
冒号不对齐太难受了。
cireu
2019 年7 月 1 日 04:26
15
给lisp-indent-function
写handler只有两个参数:发生缩进的位置(一般是行首)parse-partial-sexp
的返回值,不是人用的。
lisp-indent-function
最难受的是不能很好识别和缩进带keyword的参数列表,比如
(propertize icon 'face `(:inherit ,face
:height 1.1)
默认显示为
(propertize icon 'face `(:inherit ,face
:height 1.1)
最后找了个改装版本才搞定。
我现在用的 indent 函数是抄来的,能偷懒则偷懒:.emacs.d/redef.el at af82072196564fa57726bdbabf97f1d35c43b7f7 · Fuco1/.emacs.d · GitHub
parse-partial-sexp
我需要把 docstring 贴在旁边作为注释,或者:
(let* ((st (parse-partial-sexp (point-min) (point)))
(depth (nth 0 st))
(start-of-innermost (nth 1 st))
(start-of-last-sexp (nth 2 st))
(inside-a-string? (nth 3 st))
...
))
cireu
2019 年7 月 1 日 05:59
18
不如直接用模式匹配
(pcase (parse-partial-sexp)
(`(,depth ,start-of-inner-most ,start-of-last-sexp ,inside-str? . ,rest)))
就你这个例子,可以转而用 list
绕过这个问题(如果非要换行的话,我一定会这么干)。