2018-05-20 12:21:13 +02:00
|
|
|
;;; -*- lexical-binding: t; no-byte-compile: t; -*-
|
|
|
|
|
2018-05-24 19:03:36 +02:00
|
|
|
;; Eagerly load these libraries because this module may be loaded in a session
|
|
|
|
;; that hasn't been fully initialized (where autoloads files haven't been
|
|
|
|
;; generated or `load-path' populated).
|
2018-05-20 12:21:13 +02:00
|
|
|
(load! autoload/packages)
|
|
|
|
(load! autoload/modules)
|
|
|
|
(load! autoload/debug)
|
|
|
|
(load! autoload/message)
|
|
|
|
|
|
|
|
|
|
|
|
;;
|
2018-05-24 19:03:36 +02:00
|
|
|
;; Dispatcher API
|
2018-05-20 12:21:13 +02:00
|
|
|
;;
|
|
|
|
|
2018-05-24 19:03:36 +02:00
|
|
|
(defvar doom-auto-accept (getenv "YES")
|
|
|
|
"If non-nil, Doom will auto-accept any confirmation prompts during batch
|
|
|
|
commands like `doom//packages-install', `doom//packages-update' and
|
|
|
|
`doom//packages-autoremove'.")
|
2018-05-20 12:21:13 +02:00
|
|
|
|
2018-05-24 19:03:36 +02:00
|
|
|
(defconst doom--dispatch-command-alist ())
|
|
|
|
(defconst doom--dispatch-alias-alist ())
|
2018-05-20 12:21:13 +02:00
|
|
|
|
|
|
|
(defun doom--dispatch-format (desc &optional short)
|
|
|
|
(if (equal desc "TODO")
|
|
|
|
(format! (yellow "TODO"))
|
|
|
|
(with-temp-buffer
|
|
|
|
(let ((fill-column 72))
|
|
|
|
(insert desc)
|
|
|
|
(goto-char (point-min))
|
|
|
|
(while (re-search-forward "\n\n[^ \n]" nil t)
|
|
|
|
(fill-paragraph)))
|
|
|
|
(if (not short)
|
|
|
|
(buffer-string)
|
|
|
|
(goto-char (point-min))
|
|
|
|
(buffer-substring-no-properties
|
|
|
|
(line-beginning-position)
|
|
|
|
(line-end-position))))))
|
|
|
|
|
|
|
|
(defun doom--dispatch-help (&optional command desc &rest args)
|
2018-05-24 19:03:36 +02:00
|
|
|
"Display help documentation for a dispatcher command. If COMMAND and DESC are
|
|
|
|
omitted, show all available commands, their aliases and brief descriptions."
|
2018-05-20 12:21:13 +02:00
|
|
|
(if command
|
|
|
|
(princ (doom--dispatch-format desc))
|
|
|
|
(print! (bold "%-10s\t%s\t%s" "Command:" "Alias" "Description"))
|
2018-05-24 19:03:36 +02:00
|
|
|
(dolist (spec (sort doom--dispatch-command-alist
|
2018-05-20 12:21:13 +02:00
|
|
|
(lambda (x y) (string-lessp (car x) (car y)))))
|
|
|
|
(cl-destructuring-bind (command &key desc _body) spec
|
2018-05-24 19:03:36 +02:00
|
|
|
(let ((aliases (cl-loop for (alias . cmd) in doom--dispatch-alias-alist
|
|
|
|
if (eq cmd command)
|
|
|
|
collect (symbol-name alias))))
|
2018-05-20 12:21:13 +02:00
|
|
|
(print! " %-10s\t%s\t%s"
|
2018-05-24 19:03:36 +02:00
|
|
|
command (if aliases (string-join aliases ",") "")
|
2018-05-20 12:21:13 +02:00
|
|
|
(doom--dispatch-format desc t)))))))
|
|
|
|
|
|
|
|
(defun doom-dispatch (args)
|
2018-05-24 19:03:36 +02:00
|
|
|
"Invoke a dispatcher command and pass ARGS to it."
|
2018-05-20 12:21:13 +02:00
|
|
|
(let ((help (equal (car args) "help")))
|
|
|
|
(if help (pop args))
|
|
|
|
(cl-destructuring-bind (command &key desc body)
|
|
|
|
(let ((sym (intern (car args))))
|
2018-05-24 19:03:36 +02:00
|
|
|
(or (assq sym doom--dispatch-command-alist)
|
|
|
|
(assq (cdr (assq sym doom--dispatch-alias-alist)) doom--dispatch-command-alist)
|
2018-05-20 12:21:13 +02:00
|
|
|
(error "Invalid command: %s" (car args))))
|
|
|
|
(if help
|
|
|
|
(apply #'doom--dispatch-help command desc (cdr args))
|
|
|
|
(funcall body (cdr args))))))
|
|
|
|
|
|
|
|
;; FIXME Clumsy way of registering commands, refactor!
|
|
|
|
(defmacro def-dispatcher! (command desc &rest body)
|
2018-05-24 19:03:36 +02:00
|
|
|
"Define a dispatcher command. COMMAND is a symbol or a list of symbols
|
|
|
|
representing the aliases for this command. DESC is a string description. The
|
|
|
|
first line should be short (under 60 letters), as it will be displayed for
|
|
|
|
bin/doom help.
|
|
|
|
|
|
|
|
BODY will be run when this dispatcher is called."
|
2018-05-20 12:21:13 +02:00
|
|
|
(declare (doc-string 2))
|
|
|
|
(let* ((command (doom-enlist command))
|
|
|
|
(cmd (car command))
|
2018-05-24 19:03:36 +02:00
|
|
|
(aliases (cdr command)))
|
2018-05-20 12:21:13 +02:00
|
|
|
`(progn
|
2018-05-24 19:03:36 +02:00
|
|
|
,(when aliases
|
|
|
|
`(dolist (alias ',aliases)
|
|
|
|
(map-put doom--dispatch-alias-alist alias ',cmd)))
|
|
|
|
(map-put doom--dispatch-command-alist
|
|
|
|
',cmd (list :desc ,desc
|
|
|
|
;; FIXME Implicit args var; ew
|
|
|
|
:body (lambda (args) ,@body))))))
|
|
|
|
|
2018-05-20 12:21:13 +02:00
|
|
|
|
|
|
|
;;
|
2018-05-24 19:03:36 +02:00
|
|
|
;; Dispatch commands
|
|
|
|
;;
|
|
|
|
|
|
|
|
;; Dummy dispatchers (no-op because they're handled especially)
|
2018-05-20 12:21:13 +02:00
|
|
|
(def-dispatcher! run
|
|
|
|
"Run Doom Emacs from bin/doom's parent directory.
|
|
|
|
|
|
|
|
All arguments are passed on to Emacs (except for -p and -e).
|
|
|
|
|
|
|
|
doom run
|
|
|
|
doom run -nw init.el
|
|
|
|
|
2018-05-24 19:03:36 +02:00
|
|
|
WARNING: this command exists for convenience and testing. Doom will suffer
|
|
|
|
additional overhead for be started this way. For the best performance, it
|
|
|
|
is best to run Doom out of ~/.emacs.d and ~/.doom.d.")
|
2018-05-20 12:21:13 +02:00
|
|
|
|
2018-05-21 15:42:27 +02:00
|
|
|
(def-dispatcher! (doctor doc)
|
|
|
|
"Checks for issues with your current Doom config.")
|
|
|
|
|
|
|
|
(def-dispatcher! (help h)
|
|
|
|
"Look up additional information about a command.")
|
|
|
|
|
2018-05-24 19:03:36 +02:00
|
|
|
;; Real dispatchers
|
|
|
|
(def-dispatcher! (quickstart qs)
|
|
|
|
"Quickly deploy a private module and Doom.
|
|
|
|
|
|
|
|
This deploys a barebones config to ~/.doom.d. The destination can be changed
|
|
|
|
with the -p option, e.g.
|
|
|
|
|
|
|
|
doom -p ~/.config/doom quickstart
|
|
|
|
|
|
|
|
This command will refuse to overwrite the private directory if it already
|
|
|
|
exists."
|
2018-05-25 12:49:23 +02:00
|
|
|
(doom//quickstart))
|
2018-05-20 12:21:13 +02:00
|
|
|
|
|
|
|
(def-dispatcher! (install i)
|
|
|
|
"Installs requested plugins that aren't installed."
|
2018-05-24 19:03:36 +02:00
|
|
|
(doom//reload-doom-autoloads)
|
|
|
|
(when (doom//packages-install doom-auto-accept)
|
2018-05-25 02:20:28 +02:00
|
|
|
(doom//reload-package-autoloads)))
|
2018-05-20 12:21:13 +02:00
|
|
|
|
|
|
|
(def-dispatcher! (update u)
|
|
|
|
"Checks for and updates outdated plugins."
|
2018-05-24 19:03:36 +02:00
|
|
|
(doom//reload-doom-autoloads)
|
|
|
|
(when (doom//packages-update doom-auto-accept)
|
2018-05-25 02:20:28 +02:00
|
|
|
(doom//reload-package-autoloads)))
|
2018-05-20 12:21:13 +02:00
|
|
|
|
|
|
|
(def-dispatcher! (autoremove r)
|
|
|
|
"Removes orphaned plugins."
|
2018-05-24 19:03:36 +02:00
|
|
|
(doom//reload-doom-autoloads)
|
|
|
|
(when (doom//packages-autoremove doom-auto-accept)
|
2018-05-25 02:20:28 +02:00
|
|
|
(doom//reload-package-autoloads)))
|
2018-05-20 12:21:13 +02:00
|
|
|
|
|
|
|
(def-dispatcher! (autoloads a)
|
|
|
|
"Regenerates Doom's autoloads file.
|
|
|
|
|
|
|
|
This file tells Emacs where to find your module's autoloaded functions and
|
|
|
|
plugins."
|
2018-05-24 19:03:36 +02:00
|
|
|
(doom//reload-autoloads nil 'force))
|
2018-05-20 12:21:13 +02:00
|
|
|
|
|
|
|
(def-dispatcher! (upgrade up)
|
|
|
|
"Checks out the latest Doom on this branch."
|
|
|
|
(doom//upgrade))
|
|
|
|
|
|
|
|
(def-dispatcher! (compile c)
|
|
|
|
"Byte-compiles your config or selected modules.
|
|
|
|
|
|
|
|
compile [TARGETS...]
|
|
|
|
compile :core :private lang/python
|
|
|
|
compile feature lang
|
|
|
|
|
|
|
|
Accepts :core, :private and :plugins as special arguments, indicating you want
|
|
|
|
to byte-compile Doom's core files, your private config or your ELPA plugins,
|
|
|
|
respectively."
|
|
|
|
(doom//byte-compile args))
|
|
|
|
|
2018-05-24 19:03:36 +02:00
|
|
|
(def-dispatcher! (recompile rc)
|
2018-05-20 12:21:13 +02:00
|
|
|
"Re-byte-compiles outdated *.elc files."
|
|
|
|
(doom//byte-compile args 'recompile))
|
|
|
|
|
|
|
|
(def-dispatcher! clean
|
|
|
|
"Delete all *.elc files."
|
|
|
|
(doom//clean-byte-compiled-files))
|
|
|
|
|
|
|
|
(def-dispatcher! test
|
|
|
|
"Run Doom unit tests."
|
|
|
|
(load! autoload/test)
|
|
|
|
(doom//run-tests args))
|
|
|
|
|
|
|
|
(def-dispatcher! info
|
|
|
|
"Output system info in markdown for bug reports."
|
2018-05-24 19:03:36 +02:00
|
|
|
(doom/info))
|
2018-05-20 12:21:13 +02:00
|
|
|
|
|
|
|
(def-dispatcher! (version v)
|
|
|
|
"Reports the version of Doom and Emacs."
|
2018-05-24 19:03:36 +02:00
|
|
|
(doom/version))
|
2018-05-20 12:21:13 +02:00
|
|
|
|
2018-05-20 20:05:35 +02:00
|
|
|
(def-dispatcher! (refresh re)
|
2018-05-24 19:03:36 +02:00
|
|
|
"Refresh Doom. Same as autoremove+install+autoloads.
|
2018-05-20 12:21:13 +02:00
|
|
|
|
|
|
|
This is the equivalent of running autoremove, install, autoloads, then
|
|
|
|
recompile. Run this whenever you:
|
|
|
|
|
|
|
|
1. Modify your `doom!' block,
|
|
|
|
2. Add or remove `package!' blocks to your config,
|
|
|
|
3. Add or remove autoloaded functions in module autoloaded files.
|
|
|
|
4. Update Doom outside of Doom (e.g. with git)"
|
2018-05-25 02:20:28 +02:00
|
|
|
(let ((doom--inhibit-reload t))
|
|
|
|
(with-demoted-errors "%s" (doom//packages-autoremove))
|
|
|
|
(with-demoted-errors "%s" (doom//packages-install)))
|
|
|
|
(doom//reload-autoloads)
|
2018-05-24 19:03:36 +02:00
|
|
|
(doom//byte-compile nil 'recompile))
|
2018-05-20 12:21:13 +02:00
|
|
|
|
|
|
|
|
|
|
|
;;
|
|
|
|
;; Quality of Life Commands
|
|
|
|
;;
|
|
|
|
|
2018-05-24 19:03:36 +02:00
|
|
|
;; FIXME Detect & enforce remote
|
2018-05-20 12:21:13 +02:00
|
|
|
(defvar doom-remote "origin"
|
|
|
|
"TODO")
|
|
|
|
|
|
|
|
(defun doom//upgrade ()
|
2018-05-24 19:03:36 +02:00
|
|
|
"Upgrade Doom to the latest version."
|
2018-05-20 12:21:13 +02:00
|
|
|
(interactive)
|
2018-05-25 12:49:34 +02:00
|
|
|
(require 'vc-git)
|
2018-05-25 16:55:42 +02:00
|
|
|
(let* ((core-file (expand-file-name "core.el" doom-core-dir))
|
2018-05-25 16:15:58 +02:00
|
|
|
(branch (vc-git--symbolic-ref core-file))
|
|
|
|
(default-directory doom-emacs-dir))
|
2018-05-20 12:21:13 +02:00
|
|
|
(unless (file-exists-p core-file)
|
|
|
|
(error "Couldn't find %s, was Doom cloned properly?"
|
|
|
|
(abbreviate-file-name core-file)))
|
|
|
|
(unless branch
|
|
|
|
(error "Couldn't detect what branch you're using. Is %s a repo?"
|
|
|
|
(abbreviate-file-name doom-emacs-dir)))
|
|
|
|
(unless (eq (vc-state core-file 'Git) 'up-to-date)
|
|
|
|
(user-error "Doom has been modified; refusing to upgrade. Stash or undo your changes"))
|
|
|
|
(with-temp-buffer
|
|
|
|
(let ((buf (current-buffer)))
|
|
|
|
(when (zerop (process-file "git" nil buf nil
|
|
|
|
"fetch" "--tags" doom-remote branch))
|
|
|
|
(let ((current-rev (vc-git-working-revision core-file))
|
|
|
|
(rev (shell-command-to-string (format "git rev-parse %s/%s" doom-remote branch))))
|
|
|
|
(unless rev
|
|
|
|
(error "Couldn't detect Doom's version. Is %s a repo?"
|
|
|
|
(abbreviate-file-name doom-emacs-dir)))
|
|
|
|
(if (equal current-rev rev)
|
|
|
|
(message "Doom is up to date!")
|
2018-05-24 19:03:36 +02:00
|
|
|
(when (or doom-auto-accept
|
2018-05-20 12:21:13 +02:00
|
|
|
(y-or-n-p "Doom is out of date, update?"))
|
|
|
|
(when (file-exists-p (byte-compile-dest-file core-file))
|
|
|
|
(message "Your config is byte-compiled, removing byte-compiled files")
|
|
|
|
(doom//clean-byte-compiled-files))
|
2018-05-25 16:55:42 +02:00
|
|
|
(unless (zerop (process-file "git" nil buf nil
|
|
|
|
"checkout" (format "%s/%s" doom-remote branch)))
|
|
|
|
(error "An error occurred while checking out the latest commit"))
|
2018-05-20 12:21:13 +02:00
|
|
|
(doom//reload)
|
|
|
|
(message "Done! Please restart Emacs for changes to take effect")))))))))
|
|
|
|
|
|
|
|
(defun doom//quickstart ()
|
2018-05-24 19:03:36 +02:00
|
|
|
"Quickly deploy a private module and Doom.
|
|
|
|
|
|
|
|
This deploys a barebones config to `doom-private-dir', installs all missing
|
|
|
|
packages and regenerates the autoloads file."
|
2018-05-20 12:21:13 +02:00
|
|
|
(interactive)
|
|
|
|
(let ((short-private-dir (abbreviate-file-name doom-private-dir)))
|
2018-05-25 12:49:23 +02:00
|
|
|
(if (file-directory-p doom-private-dir)
|
|
|
|
(print! (yellow "%s directory already exists. Skipping." short-private-dir))
|
2018-05-24 19:03:36 +02:00
|
|
|
(print! "Creating %s" short-private-dir)
|
2018-05-25 12:49:23 +02:00
|
|
|
(make-directory doom-private-dir t)
|
|
|
|
(print! (green "Done!")))
|
2018-05-20 12:21:13 +02:00
|
|
|
(let ((init-file (expand-file-name "init.el" doom-private-dir)))
|
2018-05-24 19:03:36 +02:00
|
|
|
(if (file-exists-p init-file)
|
2018-05-25 12:49:23 +02:00
|
|
|
(print! (yellow "%sinit.el already exists. Skipping." short-private-dir))
|
2018-05-24 19:03:36 +02:00
|
|
|
(print! "Copying init.example.el to %s" short-private-dir)
|
2018-05-20 12:21:13 +02:00
|
|
|
(copy-file (expand-file-name "init.example.el" doom-emacs-dir)
|
2018-05-25 12:49:23 +02:00
|
|
|
init-file)
|
|
|
|
(print! (green "Done!"))))
|
2018-05-20 12:21:13 +02:00
|
|
|
(let ((config-file (expand-file-name "config.el" doom-private-dir)))
|
|
|
|
(if (file-exists-p config-file)
|
2018-05-24 19:03:36 +02:00
|
|
|
(print! "%sconfig.el already exists. Skipping." short-private-dir)
|
2018-05-25 12:49:23 +02:00
|
|
|
(print! "Deploying empty config.el file in %s" short-private-dir)
|
|
|
|
(with-temp-file config-file (insert ""))
|
|
|
|
(print! (green "Done!")))))
|
|
|
|
(print! "Installing plugins")
|
2018-05-24 19:03:36 +02:00
|
|
|
(doom//packages-install)
|
2018-05-25 12:49:23 +02:00
|
|
|
(print! "Regenerating autoloads files")
|
|
|
|
(doom//reload-autoloads nil 'force-p)
|
|
|
|
(print! (bold (green "\nFinished! Doom is ready to go!\n")))
|
|
|
|
(with-temp-buffer
|
|
|
|
(doom-template-insert "QUICKSTART_INTRO")
|
|
|
|
(print! (buffer-string))))
|
2018-05-20 12:21:13 +02:00
|
|
|
|
|
|
|
(provide 'core-dispatcher)
|
|
|
|
;;; core-dispatcher.el ends here
|