【求助】company 与 haskell-interactive 的兼容性

据说 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 函数运行期间,我的光标在正常闪烁,并且我也可以正常输入,没有卡死)

output

但是看 Github 上似乎并没有停止抱怨这个问题,直到 2022 年底,还有评论称此问题依旧。

所以,我请问下论坛里有此方面经验/环境的前辈:

  1. 你们是否也有此问题?
  2. 上面的代码,如果没有解决,那该如何复现问题?

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
   ))

原来是这样

感谢分享 :handshake:

不过我上面的代码已经解决了我卡住的问题,等遇到新的问题再说吧。 :laughing: