Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Emacs lisp: Concise way to get `directory-files` without "." and ".."?

The function directory-files returns the . and .. entries as well. While in a sense it is true, that only this way the function returns all existing entries, I have yet to see a use for including these. On the other hand, every time a use directory-files I also write something like

(unless (string-match-p "^\\.\\.?$" ... 

or for better efficiency

(unless (or (string= "." entry)
            (string= ".." entry))
   ..)

Particularly in interactive use (M-:) the extra code is undesirable.

Is there some predefined function that returns only actual subentries of a directory efficiently?

like image 524
kdb Avatar asked Jun 18 '13 09:06

kdb


1 Answers

You can do this as part of the original function call.

(directory-files DIRECTORY &optional FULL MATCH NOSORT)

If MATCH is non-nil, mention only file names that match the regexp MATCH.

so:

(directory-files (expand-file-name "~/") nil "^\\([^.]\\|\\.[^.]\\|\\.\\..\\)")

or:

(defun my-directory-files (directory &optional full nosort)
  "Like `directory-files' with MATCH hard-coded to exclude \".\" and \"..\"."
  (directory-files directory full "^\\([^.]\\|\\.[^.]\\|\\.\\..\\)" nosort))

although something more akin to your own approach might make for a more efficient wrapper, really.

(defun my-directory-files (directory &optional full match nosort)
  "Like `directory-files', but excluding \".\" and \"..\"."
  (delete "." (delete ".." (directory-files directory full match nosort))))

although that's processing the list twice, and we know there's only one instance of each of the names we wish to exclude (and there's a fair chance they'll appear first), so something more like this might be a good solution if you're expecting to deal with large directories on a frequent basis:

(defun my-directory-files (directory &optional full match nosort)
  "Like `directory-files', but excluding \".\" and \"..\"."
  (let* ((files (cons nil (directory-files directory full match nosort)))
         (parent files)
         (current (cdr files))
         (exclude (list "." ".."))
         (file nil))
    (while (and current exclude)
      (setq file (car current))
      (if (not (member file exclude))
          (setq parent current)
        (setcdr parent (cdr current))
        (setq exclude (delete file exclude)))
      (setq current (cdr current)))
    (cdr files)))
like image 85
phils Avatar answered Sep 24 '22 02:09

phils