Function: files--recursively
files--recursively is a byte-compiled function defined in files.el.gz.
Signature
(files--recursively DIR REGEXP &optional INCLUDE-DIRECTORIES PREDICATE FOLLOW-SYMLINKS LESSP)
Documentation
Recursive body of directory-files-recursively.
Expects DIR to be an absolute directory (not file) name,
and tramp-mode and completion-regexp-list to be set
appropriately for file-name-all-completions.
Source Code
;; Defined in /usr/src/emacs/lisp/files.el.gz
(defun files--recursively (dir regexp
&optional include-directories predicate
follow-symlinks lessp)
"Recursive body of `directory-files-recursively'.
Expects DIR to be an absolute directory (not file) name,
and `tramp-mode' and `completion-regexp-list' to be set
appropriately for `file-name-all-completions'."
(let ((result ()) ;; Subdirectories and their files, followed by...
(files ()) ;; ...the current directory's regular files.
(predfn (and (not (booleanp predicate)) predicate))
(comps (file-name-all-completions "" dir)))
;; By returning directory names, `file-name-all-completions' is
;; faster than `directory-files' followed by `file-directory-p'.
;; However, the trailing slash of directory names affects sort
;; order, e.g., it can put "foo-bar/" before "foo/". Since
;; `file-name-all-completions' uses `file-name-as-directory', it is
;; safe, faster, and more predictable to use `substring' in place of
;; `directory-file-name'. In fact, it is faster to compute the
;; `substring' twice (first as a sortkey, then for REGEXP) than to
;; do it once and save the result in a temporary object.
(dolist (file (if (eq lessp t) comps
(sort comps :in-place t :lessp lessp
;; Normalize directory names as file names.
:key (lambda (f)
(if (directory-name-p f)
(substring f nil -1)
f)))))
(cond ((member file '("./" "../")))
;; When FILE is of the form "foo/".
((directory-name-p file)
(let* (;; Nondir part of directory file name,
;; of the form "foo".
(name (substring file nil -1))
;; Absolute directory file name, of the form
;; "/dir/foo". Cheaper than `expand-file-name', and
;; avoids pitfalls with files named, e.g., "~".
(full-file (concat dir name))
;; List of subdirectory's files.
(sub-files
(and
;; Don't follow symlinks to other directories.
(or follow-symlinks
(not (file-symlink-p full-file)))
;; Allow filtering subdirectories.
(or (not predfn)
(funcall predfn full-file))
(if (eq predicate t)
(ignore-error file-error
(files--recursively
(file-name-as-directory full-file) regexp
include-directories predicate
follow-symlinks lessp))
(files--recursively
(file-name-as-directory full-file) regexp
include-directories predicate
follow-symlinks lessp))))
;; Whether to list subdirectory itself.
(sub-dir (and include-directories
(string-match-p regexp name)
(list full-file))))
;; Skip any no-op `nconc' traversals.
(when (or sub-files sub-dir)
(setq result (nconc result sub-files sub-dir)))))
;; When FILE is of the form "foo".
((string-match-p regexp file)
(push (concat dir file) files))))
(nconc result (nreverse files))))