据说 company 与 haskell-interactive 有一个很古老的兼容问题,由于 haskell REPL 是单线程,所以当 REPL 进入 IO action 等待用户输入时,如果 company 请求了补全,就会被阻塞导致卡住 Emacs(好在可以通过 C-g
恢复)。
Github上该 issue 已经开了很久:
咱们论坛也有前辈提及过这一点(并且相较于 company,似乎 corfu 就没有此问题):
但是 Github 上早在 2016 年就有人想通过 haskll process 的状态来绕过这个问题,大概是下面这个样子:
(define-advice haskell-process-get-repl-completions
(:around (orig &rest arg) company)
(unless (haskell-process-evaluating-p (haskell-interactive-process))
(apply orig arg)))
我试用了一下,确实就没再出现 REPL 等待用户输入时的卡死现象了。
(如下动图,在 main 函数运行期间,我的光标在正常闪烁,并且我也可以正常输入,没有卡死)
但是看 Github 上似乎并没有停止抱怨这个问题,直到 2022 年底,还有评论称此问题依旧。
所以,我请问下论坛里有此方面经验/环境的前辈:
- 你们是否也有此问题?
- 上面的代码,如果没有解决,那该如何复现问题?
2024 年,写 Haskell 还是建议用 VS CODE。
vscode-haskell 已经做得很完善了,非常稳定。
说实话,我想不出必须使用 Emacs 的理由。
因为 haskell-lsp-server 在 2022 年以后终于可以支持大部分 GHC 版本了,(刚开始因为 cabal 和 stack 混乱的版本管理和编译器更新激进基本没法用)现在都是用 lsp,没人用 company 了,虽然现在用 lsp-mode 居多,Emacs 自带的 eglot 也能适配
https://brittanderson.github.io/posts/2024-04-19-haskell-emacs.html
压根就没装 VSCode
我用的 lsp-mode
,不知道我理解的对不对,就算用 lsp,也是需要补全前端的。
比如我现在就是,开启 lsp-mode
后,company
用作补全前端,company-backends
只有一个 (company-capf)
,所有的补全选项都是来自 lsp server 的。
就是在这种情况下,在 haskell-interactive-mode 会卡住。
莫非可以完全关闭 company,只用 lsp-mode 吗?
capf 本身就是 emacs 自带的补全,只是界面简单点了,在 repl 里禁用 company 未必不是个办法
关于 subprocess 异步锁死 emacs 的问题,我遇到过 Wanderlust 同时调用 IMAP 和 eww 下载图片导致锁死的问题,想过一个办法,但是不确定是不是管用
;; Fix deadlock
(defvar accept-process-output-mutex (make-mutex "APO-MUTEX"))
(cl-macrolet ((advice-reentry (&rest fns)
`(progn ,@(cl-loop for fn in fns
collect `(define-advice ,fn
(:around (oldfun &rest r)
inhibit-reentry)
(with-mutex accept-process-output-mutex
(apply oldfun r)))))))
(advice-reentry
accept-process-output
;; wait_reading_process_output users (not all users)
sleep-for
process-send-eof
process-send-region
process-send-string
))
原来是这样
感谢分享
不过我上面的代码已经解决了我卡住的问题,等遇到新的问题再说吧。