branch: externals/eglot commit c34ec4218c7d4ab7c4a7e1643c76c30cb70978ab Author: João Távora <joaotav...@gmail.com> Commit: João Távora <joaotav...@gmail.com>
Per #645: Attempt to speed up initial directory/glob correspondence In #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 #645 and #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. --- eglot.el | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/eglot.el b/eglot.el index c236388..59804da 100644 --- a/eglot.el +++ b/eglot.el @@ -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)))) + ;;; Rust-specific ;;;