14

Is there a way, possibly using a package, to recursively list all the files (with paths) and sub-directories (or at least the empty sub-directories, since the paths to the non-empty ones can be gleaned from the paths of the files contained therein) of the current directory?

The closest I could find is the projectile-find-file function of the projectile package (alternatively, the helm-projectile-find-file function of the helm-projectile package), but it doesn't seem to be able to list empty folders. Additionally, it seems to work only with Git and other version control repositories, but there may be a workaround for this limitation.

  • 2
    'm not quite shure what you try to do, but [this blog post](www.turingmachine.org/bl/2013-05-29-recursively-listing-directories-in-elisp.html) might contain what you need, or you may try [this one](ergoemacs.org/emacs/elisp_traverse_dir.html) as a starter. – theldoria Jun 6 '17 at 9:46
  • What do you mean by "list"? Do you want an Emacs Lisp functions that return a list of strings with the paths? Do you want a buffer with the paths in it, say, one per line? Do you want a dired buffer with all the files? (That last one is easy, add "-R" to the ls switches in dired.) – Omar Jun 6 '17 at 16:17
  • @Omar: I have to ideal requirements: (1) that it will be either part of Emacs or part of a package, (2) that it will work with either helm or ivy, i.e. that the results will be displayed in a helm or ivy buffer. If it is impossible to satisfy both requirements, the 2nd one is more important for me. – Evan Aad Jun 7 '17 at 6:48
  • 1
    That's really two different questions. But OK, I provided an answer for each. – Drew Jun 10 '17 at 22:30
7

Assuming you use ivy you can use this function

    (defun fhd/counsel-everything ()
      "list everything recursively"
      (interactive)
      (let* ((cands (split-string
                     (shell-command-to-string "find .") "\n" t)))
        (ivy-read "File: " cands
                  :action #'find-file
                  :caller 'fhd/counsel-everything)))
  • Thanks. What if I use helm? – Evan Aad Jun 6 '17 at 10:20
  • 1
    Sorry, I don't know about helm. ivy is pretty lightweight. Give it shot. – fhdhsni Jun 6 '17 at 10:26
10

directory-files-recursively

(I think this was added in Emacs 25)

here's the link to the manual: https://www.gnu.org/software/emacs/manual/html_node/elisp/Contents-of-Directories.html

Return all files under directory whose names match regexp. This function searches the specified directory and its sub-directories, recursively, for files whose basenames (i.e., without the leading directories) match the specified regexp, and returns a list of the absolute file names of the matching files (see absolute file names). The file names are returned in depth-first order, meaning that files in some sub-directory are returned before the files in its parent directory. In addition, matching files found in each subdirectory are sorted alphabetically by their basenames. By default, directories whose names match regexp are omitted from the list, but if the optional argument include-directories is non-nil, they are included.

Example

(directory-files-recursively default-directory "")
  • It doesn't find empty directories – fhdhsni Jun 6 '17 at 12:57
  • 1
    @fhdhsni did you try setting include-directories to t? I'm at work on Emacs 24, and cannot try this right now, but I can test this at home in few hours. – wvxvw Jun 6 '17 at 13:00
  • My bad. I didn't do that. You may want to include it in your answer. – fhdhsni Jun 6 '17 at 13:09
4

This answer assumes that you want to display a listing of the file and dir names, instead of obtaining a Lisp list of them.

Use standard Emacs commands find-dired , find-name-dired, or find-grep-dired. The found file and dir names are displayed in a Dired-mode buffer. (You can put all the power of Dired to work on the results.)

If you use library find-dired+.el then you have enhanced versions of those standard Emacs commands, plush you have a command find-time-dired, which find files that are newer or older than a given timestamp.

  • find-dired is exactly what I'm looking for, but is there a way to print only names? Because otherwise single filename takes multiple lines for no reason as I absolutely don't care of size, date, or permissions of files. I've tried running (setcar find-ls-option "-printf '%p\n'") prior to find-dired, but for some reason this way dired don't want to open a file upon pressing Enter over an item. – Hi-Angel Oct 23 '17 at 20:01
  • 2
    @Hi-Angel: The buffer that the results are displayed in is in Dired mode. So you can just hit ( to toggle showing more than the file names on/off. I leave it off most of the time (no details shown), and just toggle it on briefly when I want to check some details. – Drew Oct 24 '17 at 1:37
1

See https://github.com/technomancy/find-file-in-project

There are commands to either find file or find directories. But not both.

If you just want to list all sub-directories and files recursively in one buffer, there are two commands built in Emacs for ages:

  1. M-x find-dired. It's dependent on CLI tool find. At Windows, you need install Cygwin or MYSYS which has find

  2. M-x find-lisp-find-dired. Same as find-dired but written in Lisp. So there is no third party dependency. Besides, it can recognize locale out of box. But it's slower than find-dired

  • My use case would be the same as anyone who uses the UNIX shell command ls, or the Emacs function find-file, both of which list both files and directories, including empty directories. – Evan Aad Jun 6 '17 at 11:00
  • Are find-dired and find-lisp-find-dired recursive in that they list not only the contents of the current directory, but also the contents of each of its sub-directories, sub-sub-directories, etc.? – Evan Aad Jun 6 '17 at 19:06
  • Yes, recursively – chen bin Jun 7 '17 at 0:33
1

This answer assumes that you want to obtain a Lisp list of the file and dir names, instead of displaying a listing of them.

If you use library Dired+ then you can use function diredp-files-within. (You need not be in a Dired buffer to use it.)

This works with any Emacs version, and it is more general than directory-files-recursively.

  • You can pass it a list of files and dirs, and it acts recursively in each of them.

  • Or you can pass it a function that returns such a list.

    • If there is a Dired buffer for a directory that gets processed then the function is invoked in that buffer to return the list of files to include.

      For example, if the function is dired-get-marked-files then only the marked files and subdirectories are included.

  • You can pass it a predicate that each each file or directory must satisfy. Regexp matching is of course one kind of predicate.

  • You can tell it not to follow symbolic links.

0
(defun my-dir-list (source)
  ;;
  ;; Print list files in current buffer
  ;;
  ;; Not tested, system-type: gnu
  ;; Tested,     system-type: windows-nt
  ;;
  (interactive "sDirectory: ")
  (let ((n 0)
    (l-file-dir (and (cd source) (directory-files-and-attributes "./")))
    (dir-list '())
    (file-list '())
    )
    (princ (format "%s\n" default-directory) (current-buffer))
    (while l-file-dir
      (if (nth 1 (car l-file-dir))
      (setq n (1+ n)
        dir-list (cons ((lambda (source)
                  (and (not (string-prefix-p "." (car source))) source))
                (car l-file-dir)) dir-list)
        )
    (princ (format "%s\n" (concat default-directory
                      (and (string-match "\\.[0-9|A-z]" (caar l-file-dir))
                       (caar l-file-dir)))) (current-buffer))
    )
      (setq l-file-dir (cdr l-file-dir))
      )
    (while (caar dir-list)
      (setq dir-list (cdr dir-list))
      (cd "..")
      )
    )
  'ok
  )

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.