Emacs eglot reload after cabal file is changed

hi guys

question for those who use emacs

how you make eglot restart after cabal file is changed. Every time when I need to change something in cabal I have to manually restart eglot

here is my config

(use-package eglot
  :ensure t
  :config
  (add-hook 'haskell-mode-hook 'eglot-ensure)
  (add-hook 'haskell-mode-hook 'company-mode)
  (add-hook 'haskell-mode-hook 'turn-on-haskell-indentation)
  (custom-set-variables
   '(haskell-stylish-on-save t)
   '(haskell-tags-on-save t)
   '(haskell-process-suggest-remove-import-lines t)
   '(haskell-process-auto-import-loaded-modules t)
   '(haskell-process-log t))
  (eval-after-load 'haskell-mode '(progn
				    (define-key haskell-mode-map (kbd "C-c C-l") 'haskell-process-load-or-reload)
				    (define-key haskell-mode-map (kbd "C-c C-z") 'haskell-interactive-switch)
				    (define-key haskell-mode-map (kbd "C-c C-o") 'haskell-compile)
				    (define-key haskell-mode-map (kbd "C-c v c") 'haskell-cabal-visit-file)))
  :custom
  (eglot-autoshutdown t)  ;; shutdown language server after closing last file
  (eglot-confirm-server-initiated-edits nil)  ;; allow edits without confirmation
  (eglot-send-changes-idle-time 0.1)
)

(let ((my-cabal-path (expand-file-name "~/.cabal/bin")))
  (setenv "PATH" (concat my-cabal-path path-separator (getenv "PATH")))
  (add-to-list 'exec-path my-cabal-path))

(add-hook 'after-save-hook 'my/eglot-reconnect-on-cabal-change)
(add-hook 'find-file-hook 'my/eglot-reconnect-on-cabal-change)

(defun my/eglot-reconnect-on-cabal-change ()
  "Reconnect Eglot when a cabal file is changed."
  (when (and (bound-and-true-p eglot--managed-mode)   ;; Check if eglot is active
             (string-match-p "\\.cabal\\'" buffer-file-name))
    (message "Triggering eglot-reconnect for cabal file")  ;; Debug message
    (eglot-reconnect)))  ;; Use eglot-reconnect instead of eglot-reload

I’ve asked chatGPT about it and she proposed to add extra hooks + function my/eglot-reconnect-on-cabal-change but it doesn’t work

how you make eglot restart after changing cabal?

please, help! it’s a pain to restart it manually every time

P.S I know that my config might have mistakes or something, so please, I need your help

OS: macOS
HSL: 2.7.0.0 (GHC: 9.2.8)

Kind of seems like a HLS bug/missing feature, that it’s not picking up .cabal file changes?

I’m guessing the reason your hook is not being triggered is because the test for (bound-and-true-p eglot--managed-mode) fails in the .cabal buffer – at least it does for me (while succeeding in a .hs file of the same project after I’ve done M-x eglot). By default, eglot doesn’t run a language server for .cabal files.

A workaround would be to check if the file is in a project where an eglot server was started:

(when (and (gethash (project-current) eglot--servers-by-project) ; should be truish (non-nil) if eglot was started in the project that the current buffer is in
           (string-match-p "\\.cabal\\'" buffer-file-name))

However HLS seems to support .cabal files too these days, so maybe a better solution would be to enable support for eglot in haskell-cabal-mode buffers. Put this in your eglot :config

(when-let ((entry (assoc 'haskell-mode eglot-server-programs)))
      (setcar entry '(haskell-cabal-mode haskell-mode)))

and you can keep the simple (bound-and-true-p eglot--managed-mode) test. This also gives you HLS-checking of .cabal files.

In case, I’m sure it’ll have some kind of hickups if you save twice fast or something (while HLS is still starting up).

This was implemented, but is currently broken.

Personally, I’m quite happy with it being broken. I often make trivial changes to Cabal files (e.g. metadata or temporary debugging dependencies) and HLS reloads are expensive.