Emacs/SLIME bug求助: [Text is read-only]

在SLIME上写代码是经常用到 Tab 键来自动补全的, 但时不时又变成了一按Tab就回到该行最前面
image
清空一下buffer (slime-repl-clear-buffer) 就正常了
网上搜了是有这个bug, 但是我照着做还是没解决, 再求助一下…

https://lists.gnu.org/archive/html/emacs-devel/2017-05/msg00618.html



按TAB的时候会先缩进,然后再补全(见indent-for-tab-command),缩进这步出错了。

缩进这步,buffer中有不平衡的括号,导致(indent--funcall-widened indent-line-function)调用lisp-indent-line计算出的缩进是错的,最终indent-line-to尝试删除指定数量的字符以实现缩进,结果删除的范围包括prompt,prompt是readonly的,导致出错。

举个出错的例子:

CL-USER> 
; No value
;; 输出,包含不平衡的括号
(unbalanced-paren
CL-USER> (set;在这里按TAB

建议你找出不平衡的输出,把不平衡内容周围加上 " 或者多行注释 #||# ,从而使得不平衡内容被解析成字符串或者注释,这样不会影响我们的缩进,或者把括号平衡上,再或者删除不平衡的内容,等等。最后再回去补全。

我们可以修改indent-line-function、或者搞些advice,比如在prompt line不缩进,直接补全(之后第二行会按前面的位置缩进,所以缩进会变得正常),等等,但是只要不平衡内容在,可能会有很多边界情况会出问题,所以还是按上面操作会好点。

2 个赞

偏题问一下,左下角的火焰icon是什么东西?

我上面的例子写错了,得写成下面这样才会出错:

CL-USER> 
(unbalanced-paren
;; 输出,包含不平衡的括号
CL-USER> (set;在这里按TA

一个简单的workaround就是在prompt line的时候不缩进,直接补全,之后第二行会相对prompt line的代码缩进,所以不受之前缩进的影响,这样就不会出错了:

(defvar-local my/slime-repl-old-indent-line-function nil)

(defun my/slime-repl-at-prompt-line ()
  (let ((prompt-line-range
         (save-excursion
           (cons (progn (goto-char slime-repl-prompt-start-mark) (point))
                 (progn (let ((inhibit-field-text-motion t))
                          (end-of-line))
                        (point))))))
    (<= (car prompt-line-range) (point) (cdr prompt-line-range))))

(defun my/lisp-indent-line (&rest args)
  (if (my/slime-repl-at-prompt-line)
      'noindent
    (apply my/slime-repl-old-indent-line-function args)))

(add-hook 'slime-repl-mode-hook
          (lambda ()
            (setq my/slime-repl-old-indent-line-function indent-line-function)
            (setq-local indent-line-function #'my/lisp-indent-line)))

如果不用lispy等等包就不会出问题,我个人还是倾向于用引号或者注释包围不平衡的内容,不然感觉很多边界情况会出错。。不过如果频繁出现不平衡的内容,那还是用个workaround会比较好。

就是一个表情符号 :fire:
可能我的系统不一样截图给你看到的不一样吧

感谢, 找到原因了, 原来就是因为REPL前面的括号不均衡 所以后方也受影响
估计是因为我写了一个 #/abcd $var $(+ 1 2) /# 这样的方式来解析里面的 $开头的标量或者函数(类似JS/ES6 里的反单引号语法)
image

还是解决不了, 按Tab就弹出错误的声音并把光标(cursor) 跳回到最前面 我就要通过清扫屏幕(slime-repl-clear-buffer)来解决 但是我不想清扫啊…

最近真是有点烦躁了 :sob: