]> git.eshelyaron.com Git - emacs.git/commitdiff
Attempt to speed up initial directory/glob correspondence
authorJoão Távora <joaotavora@gmail.com>
Sat, 10 Apr 2021 13:31:14 +0000 (14:31 +0100)
committerJoão Távora <joaotavora@gmail.com>
Sat, 10 Apr 2021 13:31:14 +0000 (14:31 +0100)
In https://github.com/joaotavora/eglot/issues/602, not only a new glob processing system was implemented, but
also a new, more correct, way to look for directories that might hold
files matched by one of these globs.

Answering this question is important because the file watchers for
'workspace/didChangeWatchedFiles' are placed on a per-directory basis.
Previously, a glob such as /foo/**/bar/*.el would fail to produce
practical file-watching effects because /foo/**/bar/ isn't really a
directory.

However, answering this question is also expensive, as the globs sent
by the LSP server are meant to match files, not directories.  The only
way is to list all files under the project's root directory and test
each glob on each one.  If it matches at least one file, that file's
directory is meant to be watched.

We suspect that in https://github.com/joaotavora/eglot/issues/645 and https://github.com/joaotavora/eglot/issues/633 we are falling victim to LSP server
who serve a tremendous unoptimized number of globs, one for each file.
So instead of sending just '/foo/**/bar/*.el' they send
'/foo/**/bar/quux.el', '/foo/**/bar/quuz.el', etc...  which would
tremendeously slow down the process.  But this is only a suspicion.

This commit tries some simple optimizations: if a directory is known
to be watch-worthy becasue one of its files matched a single glob, no
more files under that directory are tried.  This should help somewhat.

Also fixed a bug in 'eglot--files-recursively', though I suspect that
doesn't make that much of a difference.

* eglot.el (eglot--directories-matched-by-globs): New helper.
(eglot--files-recursively): Fix bug.

GitHub-reference: per https://github.com/joaotavora/eglot/issues/645

lisp/progmodes/eglot.el

index c2363886769b248f323c9d344475a4eeda5fd7b7..59804da9e4d1358b945852ce098e516675211ecb 100644 (file)
@@ -2674,10 +2674,7 @@ at point.  With prefix argument, prompt for ACTION-KIND."
                    (eglot--glob-compile globPattern t t))
                  watchers))
          (dirs-to-watch
-          (cl-loop for f in (eglot--files-recursively)
-                   when (cl-loop for g in globs thereis (funcall g f))
-                   collect (file-name-directory f) into dirs
-                   finally (cl-return (delete-dups dirs)))))
+          (eglot--directories-matched-by-globs default-directory globs)))
     (cl-labels
         ((handle-event
           (event)
@@ -2784,9 +2781,23 @@ If NOERROR, return predicate, else erroring function."
         (cl-loop with default-directory = dir
                  with completion-regexp-list = '("^[^.]")
                  for f in (file-name-all-completions "" dir)
-                 if (file-name-directory f) append (eglot--files-recursively f)
+                 if (file-directory-p f) append (eglot--files-recursively f)
                  else collect (expand-file-name f))))
 
+(defun eglot--directories-matched-by-globs (dir globs)
+  "Discover subdirectories of DIR with files matched by one of GLOBS.
+Each element of GLOBS is either an uncompiled glob-string or a
+compiled glob."
+  (setq globs (cl-loop for g in globs
+                       collect (if (stringp g) (eglot--glob-compile g t t) g)))
+  (cl-loop for f in (eglot--files-recursively dir)
+           for fdir = (file-name-directory f)
+           when (and
+                 (not (member fdir dirs))
+                 (cl-loop for g in globs thereis (funcall g f)))
+           collect fdir into dirs
+           finally (cl-return (delete-dups dirs))))
+
 \f
 ;;; Rust-specific
 ;;;