From: João Távora Date: Sat, 10 Apr 2021 13:31:14 +0000 (+0100) Subject: Attempt to speed up initial directory/glob correspondence X-Git-Tag: emacs-29.0.90~1616^2~524^2~4^2~148 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=83b993258b9c96cde165b4055fe1d32820907e99;p=emacs.git Attempt to speed up initial directory/glob correspondence 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 --- diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index c2363886769..59804da9e4d 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/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 ;;;