emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 433a452814f 1/2: Eglot: try reuse file watchers when server over-


From: João Távora
Subject: master 433a452814f 1/2: Eglot: try reuse file watchers when server over-watches
Date: Thu, 8 Jun 2023 10:09:58 -0400 (EDT)

branch: master
commit 433a452814fb9eb443819d5a21324364d2600116
Author: João Távora <joaotavora@gmail.com>
Commit: João Távora <joaotavora@gmail.com>

    Eglot: try reuse file watchers when server over-watches
    
    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          | 10 ++++++++++
 lisp/progmodes/eglot.el | 26 +++++++++++++++++---------
 2 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/etc/EGLOT-NEWS b/etc/EGLOT-NEWS
index 569481a8dc1..6a2e9051ddc 100644
--- a/etc/EGLOT-NEWS
+++ b/etc/EGLOT-NEWS
@@ -18,6 +18,16 @@ to look up issue github#1234, go to
 https://github.com/joaotavora/eglot/issues/1234.
 
 
+* 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.
+
+
 * Changes in Eglot 1.15 (29/4/2023)
 
 ** Fix LSP "languageId" detection
diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el
index 0140db0c4b3..c171cc2597a 100644
--- a/lisp/progmodes/eglot.el
+++ b/lisp/progmodes/eglot.el
@@ -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"))
 
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]