flymake 设置为“保存时检查”后遇到的问题:需要重复保存两次才能提示正确的检查结果

为了避免 flymake 频繁检查导致 emacs 卡顿,我将 flymake 设置为了“保存时检查”((setq flymake-no-changes-timeout nil)),但是每次需要保存两次(即重复按两次 C-x C-s)才能正确检查。

第一次按下 C-x C-s 时 flymake 会提示错误的检查结果,然后我只能稍微修改文件(比如加个空格)触发第二次保存,flymake 才能正确对文件进行检查。

这个问题困扰了我很久,请问大家遇到过吗?

我试了一下, (setq flymake-no-changes-timeout nil) 没什么问题, 不能重现问题.

也许可以advicing一下flymake-after-save-hook, 原代码,

(defun flymake-after-save-hook ()
  (when flymake-start-on-save-buffer
    (flymake-log :debug "starting syntax check as buffer was saved")
    (flymake-start t)))

(flymake-start t)改成 (flymake-start).

我发现问题了,似乎是和 eglot 一起使用的时候才会出现这个问题,要么将 eglot-send-changed-idle-time 设置为 0,要么不将 flymake-no-changes-timeout 设置为 nil

这里 flymake 可能是让 eglot 作为后端的。假设我让 eglot-send-changed-idle-time = 1flymake-no-changes-timeout = nil,那么我打了一大段字然后马上按 C-x C-s,此时eglot一直没有访问 LSP server,所以拿到的都是旧数据。因此报的错也都是旧的错误。

实际上最好是当我按下 C-x C-s 的时候,eglot 先和 LSP server 通信更新错误列表,然后再让 flymake 显示。

2 个赞

eglot-send-changed-idle-time设为零或较小的数值。类似设置在我自己的插件(如wucuo)也有。目的就是减小启动后台重量级进程的频率。所以保存并不一定触发后台进程。算是一个性能优化特性,不能算bug.

eglot 作者在新的 issue 给了一个解决方案(我这边试了下没问题)

(cl-defmethod eglot-handle-notification :after
  (_server (_method (eql textDocument/publishDiagnostics)) &key uri
           &allow-other-keys)
  (when-let ((buffer (find-buffer-visiting (eglot-uri-to-path uri))))
    (with-current-buffer buffer
      (if (and (eq nil flymake-no-changes-timeout)
               (not (buffer-modified-p)))
          (flymake-start t)))))
1 个赞

感谢!虽然在这半年里我差不多习惯了不开 diagnostics :rofl: