   "If non-nil, install missing packages. Otherwise, strip :ensure and :quelpa
 from `package!' calls.")
 
-(defvar doom--dont-load-p nil
-  "If non-nil, don't actually load modules, only keep track of them.")
+(defvar doom--prefer-el-p (or noninteractive doom--auto-install-p)
+  "If non-nil, load uncompiled .el config files.")
 
 (defvar doom--load-path (append (list doom-core-dir
                                       doom-modules-dir)

    ;; MELPA lookups by quelpa.
    (when (and recipe (= 0 (mod (length recipe) 2)))
      (push name recipe)
      (plist-put plist :quelpa (append (list name) recipe)))
    (if doom--auto-install-p
        (unless (package-installed-p name)
          (add-to-list 'doom--packages name))
      (setq plist (use-package-plist-delete plist :ensure))
      (setq plist (use-package-plist-delete plist :quelpa)))
    `(progn
       (add-to-list 'doom-packages '(,name ,@recipe))
       ,(macroexpand-all `(use-package ,name ,@plist)))))

(defmacro load! (file-or-module-sym &optional submodule)
  "Load a module from `doom-modules-dir'. Plays the same role as
`load-relative', but is specific to DOOM emacs modules and submodules.

Examples:
(load! :lang emacs-lisp)

  Loads modules/lang/emacs-lisp/(packages|config).el; package.el if
  `doom--auto-install-p' is non-nil, config.el otherwise.

(load! +local-module)

  NOTE: Requires that the calling module be loaded with `load!'.
  If called from ./config.el, loads ./+local-module.el"
  (let (path file)
    (cond ((null submodule)
           (setq path (f-dirname load-file-name)
                 file (list (if (symbolp file-or-module-sym)
                                (symbol-name file-or-module-sym)
                              file-or-module-sym))))
          (t
           (setq path (f-slash (doom-module-path file-or-module-sym submodule))
                 file (if doom--auto-install-p "packages.el" "config.el"))))
    (setq path (f-slash path)
          file (concat path file))
    (when (f-exists-p file)
      `(let ((__FILE__ ,file)
             (__DIR__  ,path))
         (load ,(if noninteractive file (f-no-ext file))
               nil ,(not doom-debug-mode) noninteractive)))))

(defvar __DIR__ nil "The directory of the currently loaded file (with `load!')")
(defvar __FILE__ nil "The full path of the currently loaded file (with `load!')")

(defun doom-module-path (module submodule &optional file)
  (f-expand (concat (substring (symbol-name module) 1) "/" (symbol-name submodule) "/" file)
            doom-modules-dir))


;;
;; Commands
;;

(defun doom-package-outdated-p (package)
  "Determine whether PACKAGE (a symbol) is outdated or not. If outdated, returns
a cons cell, whose car is the current version string of PACKAGE (a symbol), and
whose cdr is the latest version of the package. Be sure to run
`package-refresh-contents' beforehand, or the return value could be out of
date."
  (let ((pkg (assq package doom-packages)))
    (when (and pkg (package-installed-p package))
      (let* ((pkg-recipe (cdr pkg))
             (cur-desc (cadr (or (assq package package-alist)
                                 (assq package package--builtins))))
             (cur-version (package-desc-version cur-desc))
             (inhibit-message t)
             new-version)
        (setq new-version
              (if pkg-recipe
                  (let ((ver (quelpa-checkout
                              pkg-recipe
                              (f-expand (symbol-name package) quelpa-build-dir))))
                    (or (and ver (version-to-list ver)) cur-version))
                (package-desc-version (cadr (assq package package-archive-contents)))))
        (unless (version-list-<= new-version cur-version)
          (cons cur-version new-version))))))

(defun doom/packages-reload ()
  "Reload `load-path' by scanning all packages. Run this if you ran make update
or make clean outside of Emacs."
  (interactive)
  (doom-initialize t)
  (when (called-interactively-p 'interactive)
    (message "Reloaded %s packages" (length package-alist))))

(defun doom/packages-install ()
  "Install missing packages."
  (interactive)
  (declare (interactive-only t))
  (doom-initialize t)
  (let ((doom--auto-install-p t))
    (load (concat doom-emacs-dir "init.el") nil nil t)))

(defun doom/packages-update ()
  "Update outdated packages. This includes quelpa-installed packages and ELPA
packages. This will delete old versions of packages as well."
  (interactive)
  (message "Refreshing packages...")
  (package-initialize)
  (package-refresh-contents)
  (if (not package-alist)
      (message "No packages are installed")
    (require 'quelpa)
    (when (quelpa-setup-p)
      (setq quelpa-cache (--filter (package-installed-p (car it)) quelpa-cache)))
    (let* ((err 0)
           (quelpa-packages (-map 'car quelpa-cache))
           (elpa-packages (-difference (package--find-non-dependencies) quelpa-packages))
           outdated-packages)
      (dolist (pkg (append quelpa-packages elpa-packages))
        (-when-let (ver (doom-package-outdated-p pkg))
          (push (list pkg ver) outdated-packages)))
      (cond ((not outdated-packages)
             (message "Everything is up-to-date"))
            ((not (y-or-n-p
                   (format "%s packages will be updated:\n%s\n\nProceed?"
                           (length outdated-packages)
                           (mapconcat (lambda (pkg) (format "%s: %s -> %s"
                                                       (car pkg)
                                                       (car (cdr pkg))
                                                       (cdr (cdr pkg))))
                                      (--sort (string-lessp (symbol-name (car it))
                                                            (symbol-name (car other)))
                                              outdated-packages) ", "))))
             (message "Aborted"))
            (t
             (dolist (pkg outdated-packages)
               (condition-case ex
                   (cond ((assq pkg quelpa-outdated-packages)
                          (let ((inhibit-message t))
                            (quelpa package)))
                         ((memq pkg elpa-outdated-packages)
                          (let ((desc (cadr (assq pkg package-alist)))
                                (archive (cadr (assoc pkg package-archive-contents))))
                            (package-install-from-archive archive)
                            (delete-directory (package-desc-dir desc) t)))
                         (t (error "Not a valid package")))
                 ('error
                  (setq err (1+ err))
                  (message "ERROR (%s): %s" pkg ex))))))
      (if (> err 0)
          (message "Done, but with %s errors" err)
        (message "Done")))))

(defun doom/packages-clean ()
  "Delete packages that are no longer used or depended on."
  (interactive)
  (package-initialize)
  (let* ((package-selected-packages (-intersection (package--find-non-dependencies)
                                                   (mapcar 'car doom-packages)))
         (packages-to-delete (package--removable-packages))
         quelpa-modified-p)
    (cond ((not package-selected-packages)
           (message "No packages installed!"))
          ((not packages-to-delete)
           (message "No unused packages to remove."))
          ((not (y-or-n-p
                 (format "%s packages will be deleted:\n%s\n\nProceed?"
                         (length packages-to-delete)
                         (mapconcat 'symbol-name (reverse packages-to-delete) ", "))))
           (message "Aborted."))
          (t
           (require 'quelpa)
           (quelpa-setup-p)
           (dolist (p packages-to-delete)
             (package-delete (cadr (assq p package-alist)) t)
             (when (and quelpa-cache (assq p quelpa-cache))
               (setq quelpa-cache (assq-delete-all p quelpa-cache)
                     quelpa-modified-p t)))
           (when quelpa-modified-p
             (quelpa-save-cache))))))

(defun doom/byte-compile ()
  "Byte (re)compile the important files in your emacs configuration (i.e.

;;    more stable.
;; 4. No external dependencies (e.g. Cask) for plugin management.

(defvar doom-enabled-modules nil
  "List of enabled modules; each element is a cons cell (MODULE . SUBMODULE),
where MODULE is the module's property symbol, e.g. :lang, and SUBMODULE is the
submodule symbol, e.g. 'evil.")

(defvar doom-packages nil
  "A list of enabled packages.")

(defvar doom-protected-packages '(quelpa-use-package f s dash)
  "A list of packages that shouldn't be deleted.")

(defvar doom--init nil
  "Non-nil if doom's package system has been initialized or not. It may not be
if you have byte-compiled your configuration (as intended).")
