(defun find-directory-files-recursively (dir regexp &optional include-directories _p follow-symlinks) (cl-assert (null _p) t "find-directory-files-recursively can't accept arbitrary predicates") (with-temp-buffer (setq case-fold-search nil) (cd dir) (let* ((command (append (list "find" (file-local-name dir)) (if follow-symlinks '("-L") '("!" "(" "-type" "l" "-xtype" "d" ")")) (unless (string-empty-p regexp) (list "-regex" (concat ".*" regexp ".*"))) (unless include-directories '("!" "-type" "d")) '("-print0") )) (remote (file-remote-p dir)) (proc (if remote (let ((proc (apply #'start-file-process "find" (current-buffer) command))) (set-process-sentinel proc (lambda (_proc _state))) (set-process-query-on-exit-flag proc nil) proc) (make-process :name "find" :buffer (current-buffer) :connection-type 'pipe :noquery t :sentinel (lambda (_proc _state)) :command command)))) (while (accept-process-output proc)) (let ((start (goto-char (point-min))) ret) (while (search-forward "\0" nil t) (push (concat remote (buffer-substring-no-properties start (1- (point)))) ret) (setq start (point))) ret)))) (defun find-directory-files-recursively-2 (dir regexp &optional include-directories _p follow-symlinks) (cl-assert (null _p) t "find-directory-files-recursively can't accept arbitrary predicates") (cl-assert (not (file-remote-p dir))) (let* (buffered result (proc (make-process :name "find" :buffer nil :connection-type 'pipe :noquery t :sentinel (lambda (_proc _state)) :filter (lambda (proc data) (let ((start 0)) (when-let (end (string-search "\0" data start)) (push (concat buffered (substring data start end)) result) (setq buffered "") (setq start (1+ end)) (while-let ((end (string-search "\0" data start))) (push (substring data start end) result) (setq start (1+ end)))) (setq buffered (concat buffered (substring data start))))) :command (append (list "find" (file-local-name dir)) (if follow-symlinks '("-L") '("!" "(" "-type" "l" "-xtype" "d" ")")) (unless (string-empty-p regexp) (list "-regex" (concat ".*" regexp ".*"))) (unless include-directories '("!" "-type" "d")) '("-print0") )))) (while (accept-process-output proc)) result)) (defun find-directory-files-recursively-3 (dir regexp &optional include-directories _p follow-symlinks) (cl-assert (null _p) t "find-directory-files-recursively can't accept arbitrary predicates") (cl-assert (not (file-remote-p dir))) (let ((args `(,(file-local-name dir) ,@(if follow-symlinks '("-L") '("!" "(" "-type" "l" "-xtype" "d" ")")) ,@(unless (string-empty-p regexp) (list "-regex" (concat ".*" regexp ".*"))) ,@(unless include-directories '("!" "-type" "d")) "-print0"))) (with-temp-buffer (let ((status (apply #'process-file "find" nil t nil args)) (pt (point-min)) res) (unless (zerop status) (error "Listing failed")) (goto-char (point-min)) (while (search-forward "\0" nil t) (push (buffer-substring-no-properties pt (1- (point))) res) (setq pt (point))) res)))) (defun my-bench (count path regexp) (setq path (expand-file-name path)) ;; (let ((old (directory-files-recursively path regexp)) ;; (new (find-directory-files-recursively-3 path regexp))) ;; (dolist (path old) ;; (unless (member path new) (error "! %s not in" path))) ;; (dolist (path new) ;; (unless (member path old) (error "!! %s not in" path)))) (list (cons "built-in" (benchmark count (list 'directory-files-recursively path regexp))) (cons "with-find" (benchmark count (list 'find-directory-files-recursively path regexp))) (cons "with-find-p" (benchmark count (list 'find-directory-files-recursively-2 path regexp))) (cons "with-find-sync" (benchmark count (list 'find-directory-files-recursively-3 path regexp)))))