Emacs Lisp: Traverse Directory
There are these ways to traverse a directory:
(find-lisp-find-files dirpath regex) → recursive, filter by regex.
(find-lisp-find-files-internal dirpath 'file-predicate-p 'dir-predicate-p) → recursive, filter by predicate functions.
(directory-files directory …) → no recurse into sub-directories. Can filter by regex. See optional params.
They return a list of all files in the directory dirpath.
Here's a simple example:
;; traverse a dir (require 'find-lisp) ;; insert file path of all html files in the directory, recursive all sub-directory (mapc (lambda (x) (insert x) (insert "\n")) (find-lisp-find-files "/home/john/web/" "\\.html$" ))
Filter by a General Predicate Function
Sometimes you need to use a general function that answer yes or no for a file/directory, not just by regex.
In that case, you can use the function
(find-lisp-find-files-internal DIRECTORY FILE-PREDICATE DIRECTORY-PREDICATE) Find files under DIRECTORY which satisfy FILE-PREDICATE. FILE-PREDICATE is a function which takes two arguments: the file and its directory. DIRECTORY-PREDICATE is used to decide whether to descend into directories. It is a function which takes two arguments, the directory and its parent.
;; traverse a dir (require 'find-lisp) (find-lisp-find-files-internal dirpath 'xah-find-files-file-predicate-p 'xah-find-files-dir-predicate-p)
are filter functions. They should return t if the file/directory is to be processed.
Each will receive 2 args, fname (short name, no path) and its parent directory parent-dir.
If the function returns true, then that file/directory will be visited.
Here's a example of file name filter:
(defun xah-find-files-file-predicate-p (fname parentdir) "return true if fname ends in .html and doesn't begin with xx." (and (string-match "\\.html$" fname) (not (string-match "^xx" fname)) ))
〔►see Emacs Lisp: Regex Tutorial〕
WARNING: the DIRECTORY-PREDICATE and Dot Directory
WARNING: the DIRECTORY-PREDICATE function will also receive itself (the dot directory), and the parent directory (the dot dot directory).
If you are not careful, it'll be infinite recursion.
So, to solve that problem, you add the default filter
find-lisp-default-directory-predicate to yours. Like this:
Note: in unix, directory is considered a special file. So, in emacs doc and other unix doc, the term “file name” may also refer to directory name.
or, buy something from Best Keyboard for Emacs