New stuff in setup: bindings.el, flyspell.el, mywin.el
[emacs-init.git] / load-dir.el
1 (defvar file-loadable-regexp
2  (replace-regexp-in-string
3   "\\." "\\\\."
4   (let (string
5         (suffix-list (get-load-suffixes)))
6     (concat (car suffix-list) "$"
7             (dolist (extension (cdr suffix-list) string)
8               (setq string (concat "\\|" extension "$" string))))))
9   "Regular expression that matches any file name with a file
10 extension returned by `get-load-suffixes'.")
11
12 (defun file-loadable-p (file)
13  "Return t if FILE is an Emacs lisp file.
14 More precisely, return t if the file name extension matches
15 `file-loadable-regexp'"
16 (string-match file-loadable-regexp file))
17
18 (defun load-dir (&optional directory recurse)
19  "Load all Emacs Lisp files in DIRECTORY.
20
21 Load files whose file name satisfies predicate `file-loadable-p'.
22 Non-interactively, DIRECTORY must be specified.  If both compiled
23 and uncompiled versions of the same file exist, only load the
24 compiled file.  If optional argument RECURSE is non-nil, (or,
25 interactively, with prefix argument) recursively load
26 subdirectories."
27  (interactive "P")
28  ;; The idea here is to allow a prefix arg to specify recursion, but
29  ;; also to read from the minibuffer the directory name; yet in
30  ;; non-interactive use to only need the one directory-name argument,
31  ;; as in: (load-dir "~/foo")
32  (let* ((recurse (if recurse recurse (when current-prefix-arg t)))
33         (directory (if (stringp directory) directory
34                      (when (called-interactively-p 'any)
35                        (read-directory-name
36                         (concat (if recurse "Recursively l" "L")
37                                 "oad all Emacs lisp files from directory: ")
38                         default-directory default-directory t)))))
39    ;; For non-interactive use
40    (when (not (called-interactively-p 'any))
41      (unless directory
42        (error "Must specify a directory to when called non-interactively")))
43    (unless (file-directory-p directory)
44      (error "%s is not a directory" directory))
45    (let ((file-list
46           (directory-files (expand-file-name directory)
47                            t directory-files-no-dot-files-regexp)))
48      (dolist (file file-list)
49        (cond
50         ((and
51           ;; This will include gzipped elisp files
52           (file-loadable-p file)
53           ;; Ignore symlinks to nonexistent targets.
54           (file-exists-p file)
55           ;; Don't try to load directies whose names end in ".el"
56           ;; etc., as if they were files.  Note that we do not
57           ;; predicate on "permission denied" problems, instead
58           ;; letting things fail in that case so the user knows.
59           (not (file-directory-p file))
60           ;; If there exist both compiled and uncompiled versions of
61           ;; the same library, only load the compiled one.  (This is
62           ;; why we let-bind the `file-list'.)  This could perhaps be
63           ;; factored out, and currently still double-loads gzipped
64           ;; libraries.
65           (not (and (string= (file-name-extension file t) ".el")
66                     (member
67                      (concat (file-name-sans-extension file) ".elc")
68                      file-list))))
69          (load file))
70         ((and (file-directory-p file)
71               recurse)
72          (load-dir file t)))))))
73
74 (provide 'load-dir)