Monday 9 November 2020

Force lsp-mode to update when I visit the buffer

I use lsp-mode to edit typescript project files in emacs. When I update definitions in a file, lsp flymake diagnostics are not updated in other files until I perform an edit on the other file. Having to insert a space character and then undo it to see the latest errors quickly becomes annoying. Is there a way to "trigger lsp check when I focus on the buffer"?

At first I tried the buffer-list-update-hook, but found that this was impractical as lsp-mode creates temporary buffers. The documentation says:

Functions run by this hook should avoid calling
‘select-window’ with a nil NORECORD argument or ‘with-temp-buffer’
since either may lead to infinite recursion.

Debugging using good old message found that the hook I added was called too many times. So I needed to find another way. Fortunately I am on emacs 27.1, which comes with redesigned window change functions:

Hooks reacting to window changes run now only when redisplay detects
that a change has actually occurred.  Six hooks are now provided:
'window-buffer-change-functions' (run after window buffers have
changed), 'window-size-change-functions' (run after a window was
assigned a new buffer or size), 'window-configuration-change-hook'
(like the former but run also when a window was deleted),
'window-selection-change-functions' (run when the selected window
changed) and 'window-state-change-functions' and
'window-state-change-hook' (run when any of the preceding ones is
run).

The hook we're interested in is window-state-change-functions. When a function is added buffer locally here, the function will be called whenever the buffer is selected or deselected. Bingo!

(defun trigger-lsp-update (window)
  (if lsp-mode (run-with-timer 1 nil 'lsp-on-change 0 1 1)))
(defun add-trigger-lsp-update ()
  (make-local-variable 'window-state-change-functions)
  (add-to-list 'window-state-change-functions 'trigger-lsp-update))
(add-hook 'typescript-mode-hook #'add-trigger-lsp-update)

Normally, the function lsp-on-change is called when there are edits to the file. By calling it with a 0 1 1 argument, I am basically telling (lying to) the language server that the first character of the file has been edited, which then updates the diagnostics like I want. I added a timer so that I can easily see what diagnostics have been added/removed.

No comments:

Post a Comment