migrate to emacs24
[emacs-init.git] / lisp / 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         errors)
40    ;; For non-interactive use
41    (when (not (called-interactively-p 'any))
42      (unless directory
43        (error "Must specify a directory to when called non-interactively")))
44    (unless (file-directory-p directory)
45      (error "%s is not a directory" directory))
46    (let ((file-list
47           (directory-files (expand-file-name directory)
48                            t directory-files-no-dot-files-regexp)))
49      (dolist (file file-list)
50        (cond
51         ((and
52           ;; This will include gzipped elisp files
53           (file-loadable-p file)
54           ;; Ignore symlinks to nonexistent targets.
55           (file-exists-p file)
56           ;; Don't try to load directies whose names end in ".el"
57           ;; etc., as if they were files.  Note that we do not
58           ;; predicate on "permission denied" problems, instead
59           ;; letting things fail in that case so the user knows.
60           (not (file-directory-p file))
61           ;; If there exist both compiled and uncompiled versions of
62           ;; the same library, only load the compiled one.  (This is
63           ;; why we let-bind the `file-list'.)  This could perhaps be
64           ;; factored out, and currently still double-loads gzipped
65           ;; libraries.
66           (not (and (string= (file-name-extension file t) ".el")
67                     (member
68                      (concat (file-name-sans-extension file) ".elc")
69                      file-list))))
70          (condition-case err
71              (load file)
72            (error 
73             (message "error while loading %s: %s" file err)
74             (setq errors (cons (file-name-nondirectory file) errors)))))
75         ((and (file-directory-p file)
76               recurse)
77          (setq errors (nconc (load-dir file t) errors))))))
78    (if errors
79        (progn
80          (setq inhibit-startup-screen t)
81          (display-buffer "*Messages*")
82          (message "Errors occured while loading: %s" (mapconcat 'identity errors " "))))
83    errors))
84
85 (provide 'load-dir)