Skip to content

Commit 7a7a858

Browse files
authored
perf: rewrite lsp--all-watchable-directories iteratively (#5013)
Replaces -map/-filter closures, f-join, f-symlink?, and apply/nconc with an explicit stack-based traversal. Removes lsp--path-is-watchable-directory (now inlined to avoid building the full path twice per entry).
1 parent 5b8a904 commit 7a7a858

1 file changed

Lines changed: 18 additions & 32 deletions

File tree

lsp-mode.el

Lines changed: 18 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2079,42 +2079,28 @@ Do you want to watch all files in %s? "
20792079
(concat "You can configure this warning with the `lsp-enable-file-watchers' "
20802080
"and `lsp-file-watch-threshold' variables"))))
20812081

2082-
2083-
(defun lsp--path-is-watchable-directory (path dir ignored-directories)
2084-
"Figure out whether PATH (inside of DIR) is meant to have a file watcher set.
2085-
IGNORED-DIRECTORIES is a list of regexes to filter out directories we don't
2086-
want to watch."
2087-
(let
2088-
((full-path (f-join dir path)))
2089-
(and (file-accessible-directory-p full-path)
2090-
(not (equal path "."))
2091-
(not (equal path ".."))
2092-
(not (lsp--string-match-any ignored-directories full-path)))))
2093-
2094-
20952082
(defun lsp--all-watchable-directories (dir ignored-directories &optional visited)
20962083
"Traverse DIR recursively returning a list of paths that should have watchers.
20972084
IGNORED-DIRECTORIES will be used for exclusions.
20982085
VISITED is used to track already-visited directories to avoid infinite loops."
2099-
(let* ((dir (if (f-symlink? dir)
2100-
(file-truename dir)
2101-
dir))
2102-
;; Initialize visited directories if not provided
2103-
(visited (or visited (make-hash-table :test 'equal))))
2104-
(if (gethash dir visited)
2105-
;; If the directory has already been visited, skip it
2106-
nil
2107-
;; Mark the current directory as visited
2108-
(puthash dir t visited)
2109-
(apply #'nconc
2110-
;; the directory itself is assumed to be part of the set
2111-
(list dir)
2112-
;; collect all subdirectories that are watchable
2113-
(-map
2114-
(lambda (path) (lsp--all-watchable-directories (f-join dir path) ignored-directories visited))
2115-
;; but only look at subdirectories that are watchable
2116-
(-filter (lambda (path) (lsp--path-is-watchable-directory path dir ignored-directories))
2117-
(directory-files dir)))))))
2086+
(let ((visited (or visited (make-hash-table :test 'equal)))
2087+
(stack (list (if (file-symlink-p dir) (file-truename dir) dir)))
2088+
result)
2089+
(while stack
2090+
(let ((cur (pop stack)))
2091+
(unless (gethash cur visited)
2092+
(puthash cur t visited)
2093+
(push cur result)
2094+
(dolist (entry (directory-files cur))
2095+
(unless (or (string= entry ".") (string= entry ".."))
2096+
(let ((full-path (expand-file-name entry cur)))
2097+
(when (and (file-accessible-directory-p full-path)
2098+
(not (lsp--string-match-any ignored-directories full-path)))
2099+
(push (if (file-symlink-p full-path)
2100+
(file-truename full-path)
2101+
full-path)
2102+
stack))))))))
2103+
(nreverse result)))
21182104

21192105
(defun lsp-watch-root-folder (dir callback ignored-files ignored-directories &optional watch warn-big-repo?)
21202106
"Create recursive file notification watch in DIR.

0 commit comments

Comments
 (0)