symbol-overlay 和 haskell-mode 有冲突

最近在用 Haskell-mode 的时候发现输入[1..10] 这样的列表时,会造成 Emacs 卡死。 经过debug 发是 symbol-overlay-mode 造成的。但是又很难说是哪个包的问题,不知道该向哪个包提交issue。
请教下大家有没有遇到类似的问题的?

以下最小配置可以重现问题:

(require 'package)
(add-to-list 'package-archives '( "melpa" . "https://melpa.org/packages/") t)
(package-initialize)

(require 'symbol-overlay)
(global-set-key (kbd "M-i") 'symbol-overlay-put)
(global-set-key (kbd "M-n") 'symbol-overlay-switch-forward)
(global-set-key (kbd "M-p") 'symbol-overlay-switch-backward)
(global-set-key (kbd "<f7>") 'symbol-overlay-mode)
(global-set-key (kbd "<f8>") 'symbol-overlay-remove-all)

(require 'haskell-mode)
(add-hook 'haskell-mode-hook 'interactive-haskell-mode)

比如输入以下haskell 代码, 在输入1 以后再输入空格或者 . 都会卡死,C-g 可以取消:

triples = [(a,b,c) | c <- [1..10], a <- [1..c], b <- [1..a]]

OS: Window 10 和 Mac big sur
Emacs 28 和 27.2

我试了一下,没有你说的卡死问题,你可以用emacs-sandbox试一下你自己的配置,看是不是别的问题. 我是Arch,Emacs 27.2

我在不同机器上用上面的最小配置都能重现问题。用上面的配置需要 按 f7 启动symbol-overlay-mode

你如何加载最小配置,是用 emacs -Q 吗,如果不是的话则测试可能已经受到干扰。

而且操作步骤描述也不够具体,如:

这个描述看不太懂,输入 1 的时候光标在哪里?光标后面的内容已经存在了吗?

假如没有开启 electric-pair-mode,则依次输入的时候括号不会自动闭合(█ 表示光标):

triples = [(a,b,c) | c <- [1..█

开启了 electric-pair-mode 则是括号会自动闭合:

triples = [(a,b,c) | c <- [1..█]]

然而不管怎样,我这里(配置稍作修改,使之自动就绪,处于等待输入的状态)都无法重现你所说的问题:

  • 测试 1(括号未闭合)
$ emacsq.sh -p ~/.local/bin/emacs -P haskell-mode,symbol-overlay --eval "
  (progn
    (add-hook 'haskell-mode-hook 'interactive-haskell-mode)
    (add-hook 'haskell-mode-hook 'symbol-overlay-mode)
    (switch-to-buffer \"*.hs\")
    (haskell-mode)
    (insert \"triples = [(a,b,c) | c <- [1\")
    (goto-char (point-max)))" -nw
  • 测试 2(括号闭合)
$ emacsq.sh -p ~/.local/bin/emacs -P haskell-mode,symbol-overlay --eval "
  (progn
    (add-hook 'haskell-mode-hook 'interactive-haskell-mode)
    (add-hook 'haskell-mode-hook 'symbol-overlay-mode)
    (switch-to-buffer \"*.hs\")
    (haskell-mode)
    (insert \"triples = [(a,b,c) | c <- [1]]\")
    (goto-char (- (point-max) 2)))" -nw

  • macOS 10.12.6
  • Emacs 27.1 & 28.0.50 (6f776fbc3532a96dc86eb4e6091ed94f4c52aae7)
  • emacsq.sh 是一个辅助测试的脚本

不好意思,是我描述的不够清楚。 我没用 emacs -Q 来测试,我是去掉了自己的配置,直接重新安装新的包,保证完全没干扰。我的操作步骤如下:

  1. 备份自己当前配置的 .emacs.d 文件为其他名称
  2. 在当前用户的 HOME 目录(比如:我的HOME 是 C:\Users\Aqua 目录)下创建 .emacs 文件,并将下面的代码复制到 .emacs 文件中。
(require 'package)
(add-to-list 'package-archives '( "melpa" . "https://melpa.org/packages/") t)
(package-initialize)

(require 'symbol-overlay)
(global-set-key (kbd "M-i") 'symbol-overlay-put)
(global-set-key (kbd "M-n") 'symbol-overlay-switch-forward)
(global-set-key (kbd "M-p") 'symbol-overlay-switch-backward)
(global-set-key (kbd "<f7>") 'symbol-overlay-mode)
(global-set-key (kbd "<f8>") 'symbol-overlay-remove-all)

(require 'haskell-mode)
(add-hook 'haskell-mode-hook 'interactive-haskell-mode)
  1. 启动Emacs,这时会报错,因为还没安装需要的包。
  2. 手动刷新 Package 列表 并安装 haskell-modesymbol-overlay
M-x package-refresh-contents
M-x package-install RET haskell-mode
M-x package-install RET symbol-overlay
  1. 重启 Emacs,这时可以正常启动了。

  2. C-x,C-f 在任意目录下创建一个 test.hs 文件,按 开启 symbol-overlay-mode
    在空的 test.hs 文件中从头输入下面的内容

triples = [(a,b,c) | c <- [1..10], a <- [1..c], b <- [1..a]]

当输入到第三个 1 的后面时, 再输入空格 或者 . 就会卡住(如下图,光标在箭头所指示的位置)。

其他: 我只用了上面的配置,其他都是 Emacs 默认,electric-pair-mode 我是没开的。

1 个赞

的确在第三个 1 的时候无响应,我打开 profiler 看了一下,问题似乎出在 symbol-overlay-refresh 函数:

  • *CPU-Profiler-Report 2021-08-05 14:22:44*
Function                                                CPU samples    %
+ ...                                                           847  54%
- command-execute                                               717  45%
 - call-interactively                                           717  45%
  - funcall-interactively                                       703  44%
   - self-insert-command                                        639  40%
    - symbol-overlay-refresh                                    639  40%
     - looking-at                                               639  40%
      - internal--syntax-propertize                             639  40%
       - syntax-propertize                                      639  40%
        - haskell-syntax-propertize                             616  39%
         - haskell-lexeme-looking-at-token                      510  32%
            haskell-lexeme-looking-at-qidsym                    110   7%
            haskell-lexeme-looking-at-char-literal               38   2%
            haskell-lexeme-looking-at-string-lit...              28   1%
            match-string-no-properties                           10   0%
  • *Messages*
For information about GNU Emacs and the GNU system, type C-h C-a.
Package cl is deprecated
CPU profiler started
You can run the command ‘profiler-start’ with M-x p-sta RET
CPU profiler started
Symbol-Overlay mode enabled in current buffer
Error during redisplay: (internal--syntax-propertize 57) signaled (quit)
2 个赞

估计是 Symbol-Overlay 的问题更多一些,先给这个包报个 issue吧。

这个问题,上游一直没有解决。

干脆直接弃用 symbol-overlay了。这个包平时用的最多的功能就是通过 M-nM-p 在相同的 symbol 上跳转,非常方便。

其实上面提到的这个 feature 在 embark 已经集成了

(use-package embark
  :bind
  ("C-." . embark-act)
  ("M-." . embark-dwim)
  ("M-n" . embark-next-symbol)
  ("M-p" . embark-previous-symbol)
)

而且去掉 symbol-overlay 后,输入流畅度有明显提升,可能因为 embark 默认没高亮 symbol 的原因。

1 个赞