(defvar file-loadable-regexp (replace-regexp-in-string "\\." "\\\\." (let (string (suffix-list (get-load-suffixes))) (concat (car suffix-list) "$" (dolist (extension (cdr suffix-list) string) (setq string (concat "\\|" extension "$" string)))))) "Regular expression that matches any file name with a file extension returned by `get-load-suffixes'.") (defun file-loadable-p (file) "Return t if FILE is an Emacs lisp file. More precisely, return t if the file name extension matches `file-loadable-regexp'" (string-match file-loadable-regexp file)) (defun load-dir (&optional directory recurse) "Load all Emacs Lisp files in DIRECTORY. Load files whose file name satisfies predicate `file-loadable-p'. Non-interactively, DIRECTORY must be specified. If both compiled and uncompiled versions of the same file exist, only load the compiled file. If optional argument RECURSE is non-nil, (or, interactively, with prefix argument) recursively load subdirectories." (interactive "P") ;; The idea here is to allow a prefix arg to specify recursion, but ;; also to read from the minibuffer the directory name; yet in ;; non-interactive use to only need the one directory-name argument, ;; as in: (load-dir "~/foo") (let* ((recurse (if recurse recurse (when current-prefix-arg t))) (directory (if (stringp directory) directory (when (called-interactively-p 'any) (read-directory-name (concat (if recurse "Recursively l" "L") "oad all Emacs lisp files from directory: ") default-directory default-directory t)))) errors) ;; For non-interactive use (when (not (called-interactively-p 'any)) (unless directory (error "Must specify a directory to when called non-interactively"))) (unless (file-directory-p directory) (error "%s is not a directory" directory)) (let ((file-list (directory-files (expand-file-name directory) t directory-files-no-dot-files-regexp))) (dolist (file file-list) (cond ((and ;; This will include gzipped elisp files (file-loadable-p file) ;; Ignore symlinks to nonexistent targets. (file-exists-p file) ;; Don't try to load directies whose names end in ".el" ;; etc., as if they were files. Note that we do not ;; predicate on "permission denied" problems, instead ;; letting things fail in that case so the user knows. (not (file-directory-p file)) ;; If there exist both compiled and uncompiled versions of ;; the same library, only load the compiled one. (This is ;; why we let-bind the `file-list'.) This could perhaps be ;; factored out, and currently still double-loads gzipped ;; libraries. (not (and (string= (file-name-extension file t) ".el") (member (concat (file-name-sans-extension file) ".elc") file-list)))) (condition-case err (load file) (error (message "error while loading %s: %s" file err) (setq errors (cons (file-name-nondirectory file) errors))))) ((and (file-directory-p file) recurse) (setq errors (nconc (load-dir file t) errors)))))) (if errors (progn (setq inhibit-startup-screen t) (display-buffer "*Messages*") (message "Errors occured while loading: %s" (mapconcat 'identity errors " ")))) errors)) (provide 'load-dir)