branch: externals/compat commit 3f511afce083cc9874e8f769df84ffb616aeff47 Author: Philip Kaludercic <phil...@posteo.net> Commit: Philip Kaludercic <phil...@posteo.net>
Add directory-files-recursively --- MANUAL | 2 ++ compat-25.el | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/MANUAL b/MANUAL index 6aa23fc97e..c31db87697 100644 --- a/MANUAL +++ b/MANUAL @@ -164,6 +164,8 @@ provided by compat by default: - Macro ~thread-first~ :: Defined in ~subr-x.el~. - Macro ~thread-last~ :: Defined in ~subr-x.el~. - Function ~macroexpand-1~ :: See [[info:elisp#Expansion][(elisp) Expansion]]. +- Function ~directory-files-recursively~ :: See [[info:elisp#Contents of Directories][(elisp) Contents of + Directories]]. These functions are prefixed with ~compat~ prefix, and are only loaded when ~compat-25~ is required: diff --git a/compat-25.el b/compat-25.el index 6ec497d9e9..da084b807e 100644 --- a/compat-25.el +++ b/compat-25.el @@ -265,5 +265,66 @@ So far, FUNCTION can only be a symbol, not a lambda expression." :version "24.4" (put func prop value)) +;;;; Defined in files.el + +(compat-defun directory-files-recursively + (dir regexp &optional include-directories predicate follow-symlinks) + "Return list of all files under directory DIR whose names match REGEXP. +This function works recursively. Files are returned in \"depth +first\" order, and files from each directory are sorted in +alphabetical order. Each file name appears in the returned list +in its absolute form. + +By default, the returned list excludes directories, but if +optional argument INCLUDE-DIRECTORIES is non-nil, they are +included. + +PREDICATE can be either nil (which means that all subdirectories +of DIR are descended into), t (which means that subdirectories that +can't be read are ignored), or a function (which is called with +the name of each subdirectory, and should return non-nil if the +subdirectory is to be descended into). + +If FOLLOW-SYMLINKS is non-nil, symbolic links that point to +directories are followed. Note that this can lead to infinite +recursion." + (let* ((result nil) + (files nil) + (dir (directory-file-name dir)) + ;; When DIR is "/", remote file names like "/method:" could + ;; also be offered. We shall suppress them. + (tramp-mode (and tramp-mode (file-remote-p (expand-file-name dir))))) + (dolist (file (sort (file-name-all-completions "" dir) + 'string<)) + (unless (member file '("./" "../")) + (if (directory-name-p file) + (let* ((leaf (substring file 0 (1- (length file)))) + (full-file (concat dir "/" leaf))) + ;; Don't follow symlinks to other directories. + (when (and (or (not (file-symlink-p full-file)) + (and (file-symlink-p full-file) + follow-symlinks)) + ;; Allow filtering subdirectories. + (or (eq predicate nil) + (eq predicate t) + (funcall predicate full-file))) + (let ((sub-files + (if (eq predicate t) + (condition-case nil + (directory-files-recursively + full-file regexp include-directories + predicate follow-symlinks) + (file-error nil)) + (directory-files-recursively + full-file regexp include-directories + predicate follow-symlinks)))) + (setq result (nconc result sub-files)))) + (when (and include-directories + (string-match regexp leaf)) + (setq result (nconc result (list full-file))))) + (when (string-match regexp file) + (push (concat dir "/" file) files))))) + (nconc result (nreverse files)))) + (provide 'compat-25) ;;; compat-25.el ends here