]> git.eshelyaron.com Git - emacs.git/commitdiff
Eglot: try reuse file watchers when server over-watches
authorJoão Távora <joaotavora@gmail.com>
Thu, 8 Jun 2023 01:19:06 +0000 (02:19 +0100)
committerJoão Távora <joaotavora@gmail.com>
Thu, 8 Jun 2023 14:08:46 +0000 (15:08 +0100)
GitHub-reference: https://github.com/joaotavora/eglot/pull/1228
GitHub-reference: https://github.com/joaotavora/eglot/discussions/1226

The Pyright language server issues very heavy file watching requests,
which sometimes exceed the OS limit.  Most of these file watches are
useless, but Pyright insists on issuing them.

What's more, for some (absurd?) reason, Pyright issues two file
watching requests for the _same_ directories, only to then almost
immediately ask to undo the effects of one of these requests.

This change to Eglot makes it so that if a single server requests to
watch a specific directory twice, only one file watch object is used.

Suggested by: https://github.com/thejeffphil

* lisp/progmodes/eglot.el (eglot-lsp-server): Change structure of
file-watches field.
(eglot--on-shutdown): Adapt to new structure.
(eglot-register-capability): Rework.
(eglot-unregister-capability): Rework.

* etc/EGLOT-NEWS: Mention change

etc/EGLOT-NEWS
lisp/progmodes/eglot.el

index 569481a8dc112f20ecf7985d095acc0c5c430254..6a2e9051ddc3f99dc1fa62f32f140783bf6538dc 100644 (file)
@@ -17,6 +17,16 @@ This refers to https://github.com/joaotavora/eglot/issues/.  That is,
 to look up issue github#1234, go to
 https://github.com/joaotavora/eglot/issues/1234.
 
+\f
+* Changes in upcoming Eglot
+
+** Optimized file-watching capability
+
+Some servers, like the Pyright language server, issue too many file
+watching requests.  This change slightly reduces the number of file
+watcher objects requested from the operating system, which can be a
+problem, particularly on Mac OS.  See github#1228 and github#1226.
+
 \f
 * Changes in Eglot 1.15 (29/4/2023)
 
index 0140db0c4b3f162630f3574814c7ed1cc8660a57..c171cc2597a152bf2b4ae64ebe814e2294b6e741 100644 (file)
@@ -888,7 +888,7 @@ ACTION is an LSP object of either `CodeAction' or `Command' type."
     :documentation "Generalized boolean inhibiting auto-reconnection if true."
     :accessor eglot--inhibit-autoreconnect)
    (file-watches
-    :documentation "Map ID to list of WATCHES for `didChangeWatchedFiles'."
+    :documentation "Map (DIR -> (WATCH ID1 ID2...)) for `didChangeWatchedFiles'."
     :initform (make-hash-table :test #'equal) :accessor eglot--file-watches)
    (managed-buffers
     :documentation "List of buffers managed by server."
@@ -959,8 +959,8 @@ PRESERVE-BUFFERS as in `eglot-shutdown', which see."
           (eglot-autoshutdown nil))
       (eglot--when-live-buffer buffer (eglot--managed-mode-off))))
   ;; Kill any expensive watches
-  (maphash (lambda (_id watches)
-             (mapcar #'file-notify-rm-watch watches))
+  (maphash (lambda (_dir watch-and-ids)
+             (file-notify-rm-watch (car watch-and-ids)))
            (eglot--file-watches server))
   ;; Kill any autostarted inferior processes
   (when-let (proc (eglot--inferior-process server))
@@ -3564,10 +3564,13 @@ at point.  With prefix argument, prompt for ACTION-KIND."
                (handle-event `(,desc 'created ,file1)))))))
       (unwind-protect
           (progn
-            (dolist (dir dirs-to-watch)
-              (when (file-readable-p dir)
-                (push (file-notify-add-watch dir '(change) #'handle-event)
-                      (gethash id (eglot--file-watches server)))))
+            (cl-loop for dir in dirs-to-watch
+                     for probe =
+                     (and (file-readable-p dir)
+                          (or (gethash dir (eglot--file-watches server))
+                              (puthash dir (list (file-notify-add-watch dir '(change) #'handle-event))
+                                       (eglot--file-watches server))))
+                     when probe do (push id (cdr probe)))
             (setq
              success
              `(:message ,(format "OK, watching %s directories in %s watchers"
@@ -3578,8 +3581,13 @@ at point.  With prefix argument, prompt for ACTION-KIND."
 (cl-defmethod eglot-unregister-capability
   (server (_method (eql workspace/didChangeWatchedFiles)) id)
   "Handle dynamic unregistration of workspace/didChangeWatchedFiles."
-  (mapc #'file-notify-rm-watch (gethash id (eglot--file-watches server)))
-  (remhash id (eglot--file-watches server))
+  (maphash (lambda (dir watch-and-ids)
+             (when (member id (cdr watch-and-ids))
+               (setcdr watch-and-ids (delete id (cdr watch-and-ids)))
+               (when (null (cdr watch-and-ids))
+                 (file-notify-rm-watch (car watch-and-ids))
+                 (remhash dir (eglot--file-watches server)))))
+           (eglot--file-watches server))
   (list t "OK"))
 
 \f