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))))