💥 Replace package.el/quelpa with straight #374
There are a few kinks to iron out, but for the most part it's done. Doom Emacs, powered by straight. Goodbye gnutls and elpa/quelpa issues. This update doesn't come with rollback or lockfile support yet, but I will eventually include one with Doom, and packages will be (by default, anyway) updated in sync with Doom. Relevant threads: #1577 #1566 #1473
This commit is contained in:
parent
492f2dea1e
commit
b90dede1ab
35 changed files with 1542 additions and 1771 deletions
5
Makefile
5
Makefile
|
@ -25,8 +25,7 @@ cp: compile-plugins
|
|||
re: recompile
|
||||
d: doctor
|
||||
|
||||
quickstart: deprecated
|
||||
@$(DOOM) quickstart
|
||||
quickstart: install
|
||||
|
||||
|
||||
## Package management
|
||||
|
@ -49,7 +48,7 @@ compile-core: deprecated
|
|||
compile-private: deprecated
|
||||
@$(DOOM) compile :private
|
||||
compile-plugins: deprecated
|
||||
@$(DOOM) compile :plugins
|
||||
@$(DOOM) build
|
||||
recompile: deprecated
|
||||
@$(DOOM) recompile
|
||||
clean: deprecated
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
**Quick start**
|
||||
```bash
|
||||
git clone https://github.com/hlissner/doom-emacs ~/.emacs.d
|
||||
~/.emacs.d/bin/doom quickstart
|
||||
~/.emacs.d/bin/doom install
|
||||
```
|
||||
|
||||
**Table of Contents**
|
||||
|
|
122
bin/doom-doctor
122
bin/doom-doctor
|
@ -27,6 +27,7 @@
|
|||
(when (getenv "DEBUG")
|
||||
(setq debug-on-error t))
|
||||
|
||||
(require 'subr-x)
|
||||
(require 'pp)
|
||||
(load (expand-file-name "core/autoload/format" user-emacs-directory) nil t)
|
||||
|
||||
|
@ -147,7 +148,7 @@
|
|||
emacs-version)
|
||||
(explain! "Byte-code compiled in one version of Emacs may not work in another version."
|
||||
"It is recommended that you reinstall your plugins or recompile them with"
|
||||
"`bin/doom compile :plugins'.")))
|
||||
"`bin/doom rebuild'.")))
|
||||
|
||||
(section! "Checking for Emacs config conflicts...")
|
||||
(when (file-exists-p "~/.emacs")
|
||||
|
@ -182,109 +183,7 @@
|
|||
;; on windows?
|
||||
(when (memq system-type '(windows-nt ms-dos cygwin))
|
||||
(warn! "Warning: Windows detected")
|
||||
(explain! "DOOM was designed for MacOS and Linux. Expect a bumpy ride!"))
|
||||
|
||||
;; gnutls-cli & openssl
|
||||
(section! "Checking gnutls/openssl...")
|
||||
(cond ((executable-find "gnutls-cli"))
|
||||
((executable-find "openssl")
|
||||
(let* ((output (sh "openssl ciphers -v"))
|
||||
(protocols
|
||||
(let (protos)
|
||||
(mapcar (lambda (row)
|
||||
(add-to-list 'protos (cadr (split-string row " " t))))
|
||||
(split-string (sh "openssl ciphers -v") "\n"))
|
||||
(delq nil protos))))
|
||||
(unless (or (member "TLSv1.1" protocols)
|
||||
(member "TLSv1.2" protocols))
|
||||
(let ((version (cadr (split-string (sh "openssl version") " " t))))
|
||||
(warn! "Warning: couldn't find gnutls-cli, and OpenSSL is out-of-date (v%s)" version)
|
||||
(explain!
|
||||
"This may not affect your Emacs experience, but there are security "
|
||||
"vulnerabilities in the SSL2/3 & TLS1.0 protocols. You should use "
|
||||
"TLS 1.1+, which wasn't introduced until OpenSSL v1.0.1.\n\n"
|
||||
|
||||
"Please consider updating (or install gnutls-cli, which is preferred).")))))
|
||||
(t
|
||||
(error! "Important: couldn't find either gnutls-cli nor openssl")
|
||||
(explain!
|
||||
"You may not be able to install/update packages because Emacs won't be able to "
|
||||
"verify HTTPS ELPA sources. Install gnutls-cli or openssl v1.0.0+. If for some "
|
||||
"reason you can't, you can bypass this verification with the INSECURE flag:\n\n"
|
||||
|
||||
" INSECURE=1 make install\n\n"
|
||||
|
||||
"Or change `package-archives' to use non-https sources.\n\n"
|
||||
|
||||
"But remember that you're leaving your security in the hands of your "
|
||||
"network, provider, government, neckbearded mother-in-laws, geeky roommates, "
|
||||
"or just about anyone who knows more about computers than you do!")))
|
||||
|
||||
;; are certificates validated properly?
|
||||
(section! "Testing your root certificates...")
|
||||
(cond ((not (ignore-errors (gnutls-available-p)))
|
||||
(warn! "Warning: Emacs wasn't installed with gnutls support")
|
||||
(explain!
|
||||
"This may cause 'pecular error' errors with the Doom doctor, and is likely to "
|
||||
"interfere with package management. Your mileage may vary."
|
||||
(when (eq system-type 'darwin)
|
||||
(concat "\nMacOS users are advised to install Emacs via homebrew with one of the following:\n"
|
||||
" brew install emacs --with-gnutls"
|
||||
" or"
|
||||
" brew tap d12frosted/emacs-plus"
|
||||
" brew install emacs-plus"))))
|
||||
|
||||
((not (fboundp 'url-retrieve-synchronously))
|
||||
(error! "Can't find url-retrieve-synchronously function. Are you sure you're on Emacs 24+?"))
|
||||
|
||||
((or (executable-find "gnutls-cli")
|
||||
(executable-find "openssl"))
|
||||
(let ((tls-checktrust t)
|
||||
(gnutls-verify-error t))
|
||||
(dolist (url '("https://elpa.gnu.org" "https://melpa.org"))
|
||||
(pcase (condition-case-unless-debug e
|
||||
(unless (let ((inhibit-message t)) (url-retrieve-synchronously url))
|
||||
'empty)
|
||||
('timed-out 'timeout)
|
||||
('error e))
|
||||
(`nil nil)
|
||||
(`empty (error! "Couldn't reach %s" url))
|
||||
(`timeout (error! "Timed out trying to contact %s" ex))
|
||||
(it
|
||||
(error! "Failed to validate %s" url)
|
||||
(explain! (pp-to-string it)))))
|
||||
(dolist (url '("https://self-signed.badssl.com"
|
||||
"https://wrong.host.badssl.com/"))
|
||||
(pcase (condition-case-unless-debug e
|
||||
(if (let ((inhibit-message t)) (url-retrieve-synchronously url))
|
||||
t
|
||||
'empty)
|
||||
('timed-out 'timeout)
|
||||
('error))
|
||||
(`nil nil)
|
||||
(`empty (error! "Couldn't reach %s" url))
|
||||
(`timeout (error! "Timed out trying to contact %s" ex))
|
||||
(_
|
||||
(error! "Validated %s (this shouldn't happen!)" url)))))))
|
||||
|
||||
;; which variant of tar is on your system? bsd or gnu tar?
|
||||
(section! "Checking for GNU/BSD tar...")
|
||||
(let ((tar-bin (or (executable-find "gtar")
|
||||
(executable-find "tar"))))
|
||||
(if tar-bin
|
||||
(unless (string-match-p "(GNU tar)" (sh "%s --version" tar-bin))
|
||||
(warn! "Warning: BSD tar detected")
|
||||
(explain!
|
||||
"QUELPA (through package-build) uses the system tar to build plugins, but it "
|
||||
"expects GNU tar. BSD tar *could* cause errors during package installation or "
|
||||
"updating from non-ELPA sources."
|
||||
(when (eq system-type 'darwin)
|
||||
(concat "\nMacOS users can install gnu-tar via homebrew:\n"
|
||||
" brew install gnu-tar"))))
|
||||
(error! "Important: Couldn't find tar")
|
||||
(explain!
|
||||
"This is required by package.el and QUELPA to build packages and will "
|
||||
"prevent you from installing & updating packages."))))
|
||||
(explain! "DOOM was designed for MacOS and Linux. Expect a bumpy ride!")))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -292,12 +191,11 @@
|
|||
|
||||
(condition-case-unless-debug ex
|
||||
(let ((after-init-time (current-time))
|
||||
(doom-message-backend 'ansi)
|
||||
noninteractive)
|
||||
(doom-format-backend 'ansi))
|
||||
(section! "Checking DOOM Emacs...")
|
||||
(load (concat user-emacs-directory "core/core.el") nil t)
|
||||
(unless (file-directory-p doom-private-dir)
|
||||
(error "No DOOMDIR was found, did you run `doom quickstart` yet?"))
|
||||
(error "No DOOMDIR was found, did you run `doom install` yet?"))
|
||||
|
||||
(let ((indent 2))
|
||||
;; Make sure everything is loaded
|
||||
|
@ -317,6 +215,7 @@
|
|||
(success! "Initialized %d modules" (hash-table-count doom-modules))
|
||||
(warn! "Failed to load any modules. Do you have an private init.el?"))
|
||||
|
||||
(doom-ensure-straight)
|
||||
(doom-initialize-packages)
|
||||
(success! "Initialized %d packages" (length doom-packages))
|
||||
|
||||
|
@ -343,11 +242,10 @@
|
|||
doom-disabled-packages)
|
||||
(load packages-file 'noerror 'nomessage)
|
||||
(mapcar #'car doom-packages))
|
||||
for name = (doom-package-true-name name)
|
||||
unless (or (doom-package-prop name :disable)
|
||||
(eval (doom-package-prop name :ignore))
|
||||
(package-built-in-p name)
|
||||
(package-installed-p name))
|
||||
unless (or (doom-package-get name :disable)
|
||||
(eval (doom-package-get name :ignore))
|
||||
(doom-package-built-in-p name)
|
||||
(doom-package-installed-p name))
|
||||
do (error! "%s is not installed" name))
|
||||
(load doctor-file 'noerror 'nomessage))
|
||||
(file-missing (error! "%s" (error-message-string ex)))
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
;;; core/autoload/cli.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; Externs
|
||||
(defvar evil-collection-mode-list)
|
||||
|
||||
(require 'core-cli)
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-cli-run (command &rest _args)
|
||||
(defun doom--cli-run (command &rest _args)
|
||||
(when (featurep 'general)
|
||||
(general-auto-unbind-keys))
|
||||
(let* ((evil-collection-mode-list nil)
|
||||
(default-directory doom-emacs-dir)
|
||||
(buf (get-buffer-create " *bin/doom*"))
|
||||
(doom-message-backend 'ansi)
|
||||
(doom-format-backend 'ansi)
|
||||
(ignore-window-parameters t)
|
||||
(noninteractive t)
|
||||
(standard-output
|
||||
|
@ -39,21 +42,21 @@
|
|||
"TODO"
|
||||
(interactive "P")
|
||||
(let ((doom-auto-accept yes))
|
||||
(doom-cli-run "autoloads")))
|
||||
(doom--cli-run "autoloads")))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom//update (&optional yes)
|
||||
"TODO"
|
||||
(interactive "P")
|
||||
(let ((doom-auto-accept yes))
|
||||
(doom-cli-run "update")))
|
||||
(doom--cli-run "update")))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom//upgrade (&optional yes)
|
||||
"TODO"
|
||||
(interactive "P")
|
||||
(let ((doom-auto-accept yes))
|
||||
(doom-cli-run "upgrade"))
|
||||
(doom--cli-run "upgrade"))
|
||||
(when (y-or-n-p "You must restart Emacs for the upgrade to take effect. Restart?")
|
||||
(doom/restart-and-restore)))
|
||||
|
||||
|
@ -62,18 +65,18 @@
|
|||
"TODO"
|
||||
(interactive "P")
|
||||
(let ((doom-auto-accept yes))
|
||||
(doom-cli-run "install")))
|
||||
(doom--cli-run "install")))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom//autoremove (&optional yes)
|
||||
"TODO"
|
||||
(interactive "P")
|
||||
(let ((doom-auto-accept yes))
|
||||
(doom-cli-run "autoremove")))
|
||||
(doom--cli-run "autoremove")))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom//refresh (&optional yes)
|
||||
"TODO"
|
||||
(interactive "P")
|
||||
(let ((doom-auto-accept yes))
|
||||
(doom-cli-run "refresh")))
|
||||
(doom--cli-run "refresh")))
|
||||
|
|
|
@ -16,65 +16,54 @@ ready to be pasted in a bug report on github."
|
|||
(require 'vc-git)
|
||||
(let ((default-directory doom-emacs-dir)
|
||||
(doom-modules (doom-modules)))
|
||||
(format
|
||||
(concat "- OS: %s (%s)\n"
|
||||
"- Shell: %s\n"
|
||||
"- Emacs: %s (%s)\n"
|
||||
"- Doom: %s (%s)\n"
|
||||
"- Graphic display: %s (daemon: %s)\n"
|
||||
"- System features: %s\n"
|
||||
"- Details:\n"
|
||||
" ```elisp\n"
|
||||
" env bootstrapper: %s\n"
|
||||
" elc count: %s\n"
|
||||
" uname -a: %s\n"
|
||||
" modules: %s\n"
|
||||
" packages: %s\n"
|
||||
" exec-path: %s\n"
|
||||
" ```")
|
||||
system-type system-configuration
|
||||
shell-file-name
|
||||
emacs-version (format-time-string "%b %d, %Y" emacs-build-time)
|
||||
doom-version
|
||||
(or (string-trim (shell-command-to-string "git log -1 --format=\"%D %h %ci\""))
|
||||
"n/a")
|
||||
(display-graphic-p) (daemonp)
|
||||
(bound-and-true-p system-configuration-features)
|
||||
(cond ((file-exists-p doom-env-file) 'envvar-file)
|
||||
((featurep 'exec-path-from-shell) 'exec-path-from-shell))
|
||||
;; details
|
||||
(length (doom-files-in `(,@doom-modules-dirs
|
||||
,doom-core-dir
|
||||
,doom-private-dir)
|
||||
:type 'files :match "\\.elc$" :sort nil))
|
||||
(if IS-WINDOWS
|
||||
"n/a"
|
||||
(with-temp-buffer
|
||||
(unless (zerop (call-process "uname" nil t nil "-msrv"))
|
||||
(insert (format "%s" system-type)))
|
||||
(string-trim (buffer-string))))
|
||||
(or (cl-loop with cat = nil
|
||||
for key being the hash-keys of doom-modules
|
||||
if (or (not cat) (not (eq cat (car key))))
|
||||
do (setq cat (car key))
|
||||
and collect cat
|
||||
and collect (cdr key)
|
||||
else collect
|
||||
(let ((flags (doom-module-get cat (cdr key) :flags)))
|
||||
(if flags
|
||||
`(,(cdr key) ,@flags)
|
||||
(cdr key))))
|
||||
"n/a")
|
||||
(or (ignore-errors
|
||||
(require 'use-package)
|
||||
(cl-loop for (name . plist) in (doom-find-packages :private t)
|
||||
if (use-package-plist-delete (copy-sequence plist) :modules)
|
||||
collect (format "%s" (cons name it))
|
||||
else
|
||||
collect (symbol-name name)))
|
||||
"n/a")
|
||||
;; abbreviate $HOME to hide username
|
||||
(mapcar #'abbreviate-file-name exec-path))))
|
||||
(cl-letf
|
||||
(((symbol-function 'sh)
|
||||
(lambda (format)
|
||||
(string-trim
|
||||
(shell-command-to-string format)))))
|
||||
`((emacs
|
||||
(version . ,emacs-version)
|
||||
(features ,@system-configuration-features)
|
||||
(build . ,(format-time-string "%b %d, %Y" emacs-build-time))
|
||||
(buildopts ,system-configuration-options))
|
||||
(doom
|
||||
(version . ,doom-version)
|
||||
(build . ,(sh "git log -1 --format=\"%D %h %ci\"")))
|
||||
(system
|
||||
(type . ,system-type)
|
||||
(config . ,system-configuration)
|
||||
(shell . ,shell-file-name)
|
||||
(uname . ,(if IS-WINDOWS
|
||||
"n/a"
|
||||
(sh "uname -msrv")))
|
||||
(path . ,(mapcar #'abbreviate-file-name exec-path)))
|
||||
(config
|
||||
(envfile . ,(cond ((file-exists-p doom-env-file) 'envvar-file)
|
||||
((featurep 'exec-path-from-shell) 'exec-path-from-shell)))
|
||||
(elc-files . ,(length (doom-files-in `(,@doom-modules-dirs
|
||||
,doom-core-dir
|
||||
,doom-private-dir)
|
||||
:type 'files :match "\\.elc$" :sort nil)))
|
||||
(modules ,@(or (cl-loop with cat = nil
|
||||
for key being the hash-keys of doom-modules
|
||||
if (or (not cat) (not (eq cat (car key))))
|
||||
do (setq cat (car key))
|
||||
and collect cat
|
||||
and collect (cdr key)
|
||||
else collect
|
||||
(let ((flags (doom-module-get cat (cdr key) :flags)))
|
||||
(if flags
|
||||
`(,(cdr key) ,@flags)
|
||||
(cdr key))))
|
||||
'("n/a")))
|
||||
(packages ,@(or (ignore-errors
|
||||
(require 'use-package)
|
||||
(cl-loop for (name . plist) in (doom-find-packages :private t)
|
||||
if (use-package-plist-delete (copy-sequence plist) :modules)
|
||||
collect (format "%s" (cons name it))
|
||||
else
|
||||
collect (symbol-name name)))
|
||||
'("n/a"))))))))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -86,24 +75,55 @@ ready to be pasted in a bug report on github."
|
|||
branch and commit."
|
||||
(interactive)
|
||||
(require 'vc-git)
|
||||
(print! "Doom v%s (Emacs v%s)\nBranch: %s\nCommit: %s"
|
||||
(print! "Doom v%s (Emacs v%s)\nBranch: %s\nCommit: %s\nBuild date: %s"
|
||||
doom-version
|
||||
emacs-version
|
||||
(or (vc-git--symbolic-ref doom-core-dir)
|
||||
"n/a")
|
||||
(or (vc-git-working-revision doom-core-dir)
|
||||
"n/a")
|
||||
(or (string-trim (shell-command-to-string "git log -1 --format=%ci"))
|
||||
"n/a")))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/info ()
|
||||
(defun doom/info (&optional raw)
|
||||
"Collects some debug information about your Emacs session, formats it into
|
||||
markdown and copies it to your clipboard, ready to be pasted into bug reports!"
|
||||
(interactive)
|
||||
(message "Generating Doom info...")
|
||||
(if noninteractive
|
||||
(print! (doom-info))
|
||||
(kill-new (doom-info))
|
||||
(message "Done! Copied to clipboard.")))
|
||||
(interactive "P")
|
||||
(let ((buffer (get-buffer-create "*doom-info*"))
|
||||
(info (doom-info)))
|
||||
(with-current-buffer buffer
|
||||
(unless (or noninteractive
|
||||
(eq major-mode 'markdown-mode)
|
||||
(not (fboundp 'markdown-mode)))
|
||||
(markdown-mode))
|
||||
(erase-buffer)
|
||||
(if raw
|
||||
(progn
|
||||
(save-excursion
|
||||
(pp info (current-buffer)))
|
||||
(when (re-search-forward "(modules " nil t)
|
||||
(goto-char (match-beginning 0))
|
||||
(cl-destructuring-bind (beg . end)
|
||||
(bounds-of-thing-at-point 'sexp)
|
||||
(let ((sexp (prin1-to-string (sexp-at-point))))
|
||||
(delete-region beg end)
|
||||
(insert sexp)))))
|
||||
(insert "<details>\n\n```\n")
|
||||
(dolist (group info)
|
||||
(insert! "%-8s%-10s %s\n"
|
||||
((car group)
|
||||
(caadr group)
|
||||
(cdadr group)))
|
||||
(dolist (spec (cddr group))
|
||||
(insert! (indent 8 "%-10s %s\n")
|
||||
((car spec) (cdr spec)))))
|
||||
(insert "```\n</details>"))
|
||||
(if noninteractive
|
||||
(print! (buffer-string))
|
||||
(switch-to-buffer buffer)
|
||||
(kill-new (buffer-string))
|
||||
(print! (green "Copied markdown to clipboard"))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/am-i-secure ()
|
||||
|
@ -144,11 +164,11 @@ markdown and copies it to your clipboard, ready to be pasted into bug reports!"
|
|||
(macroexp-progn
|
||||
(append `((setq noninteractive nil
|
||||
doom-debug-mode t
|
||||
load-path ',load-path
|
||||
package--init-file-ensured t
|
||||
package-user-dir ,package-user-dir
|
||||
package-archives ',package-archives
|
||||
user-emacs-directory ,doom-emacs-dir
|
||||
doom--modules-cache nil)
|
||||
user-emacs-directory ,doom-emacs-dir)
|
||||
(with-eval-after-load 'undo-tree
|
||||
;; undo-tree throws errors because `buffer-undo-tree' isn't
|
||||
;; corrrectly initialized
|
||||
|
|
|
@ -365,10 +365,14 @@ current file is in, or d) the module associated with the current major mode (see
|
|||
(recenter)
|
||||
(message "Couldn't find the config block"))))))))
|
||||
|
||||
(defvar doom--help-packages-list nil)
|
||||
(defun doom--help-packages-list (&optional refresh)
|
||||
(or (unless refresh
|
||||
(doom-cache-get 'help-packages))
|
||||
(doom-cache-set 'help-packages (doom-package-list 'all))))
|
||||
doom--help-packages-list)
|
||||
(setq doom--help-packages-list
|
||||
(append (cl-loop for package in doom-core-packages
|
||||
collect (list package :modules '((:core internal))))
|
||||
(doom-package-list 'all)))))
|
||||
|
||||
(defun doom--help-package-configs (package)
|
||||
;; TODO Add git checks, in case ~/.emacs.d isn't a git repo
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
;;; core/autoload/hydras.el -*- lexical-binding: t; -*-
|
||||
;;; core/autoload/hydras.el -*- lexical-binding: t; no-byte-compile: t; -*-
|
||||
|
||||
;;;###autoload (autoload 'doom-text-zoom-hydra/body "core/autoload/hydras" nil t)
|
||||
(defhydra doom-text-zoom-hydra (:hint t :color red)
|
||||
|
|
|
@ -1,128 +1,67 @@
|
|||
;;; core/autoload/packages.el -*- lexical-binding: t; -*-
|
||||
|
||||
(require 'core-packages)
|
||||
(load! "cache") ; in case autoloads haven't been generated yet
|
||||
|
||||
|
||||
(defun doom--packages-choose (prompt)
|
||||
(let ((table (cl-loop for pkg in package-alist
|
||||
unless (doom-package-built-in-p (cdr pkg))
|
||||
collect (cons (package-desc-full-name (cdr pkg))
|
||||
(cdr pkg)))))
|
||||
(cdr (assoc (completing-read prompt
|
||||
(mapcar #'car table)
|
||||
nil t)
|
||||
table))))
|
||||
|
||||
(defun doom--refresh-pkg-cache ()
|
||||
"Clear the cache for `doom-refresh-packages-maybe'."
|
||||
(setq doom--refreshed-p nil)
|
||||
(doom-cache-set 'last-pkg-refresh nil))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-refresh-packages-maybe (&optional force-p)
|
||||
"Refresh ELPA packages, if it hasn't been refreshed recently."
|
||||
(when force-p
|
||||
(doom--refresh-pkg-cache))
|
||||
(unless (or (doom-cache-get 'last-pkg-refresh)
|
||||
doom--refreshed-p)
|
||||
(condition-case e
|
||||
(progn
|
||||
(message "Refreshing package archives")
|
||||
(package-refresh-contents)
|
||||
(doom-cache-set 'last-pkg-refresh t 1200))
|
||||
((debug error)
|
||||
(doom--refresh-pkg-cache)
|
||||
(signal 'doom-error e)))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Package metadata
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-plist (package)
|
||||
(defun doom-package-get (package &optional prop nil-value)
|
||||
"Returns PACKAGE's `package!' recipe from `doom-packages'."
|
||||
(cdr (assq package doom-packages)))
|
||||
(let ((plist (cdr (assq package doom-packages))))
|
||||
(if prop
|
||||
(if (plist-member plist prop)
|
||||
(plist-get plist prop)
|
||||
nil-value)
|
||||
plist)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-desc (package)
|
||||
"Returns PACKAGE's desc struct from `package-alist'."
|
||||
(cadr (assq (or (car (doom-package-prop package :recipe))
|
||||
package)
|
||||
package-alist)))
|
||||
(defun doom-package-recipe (package &optional prop nil-value)
|
||||
"Returns the `straight' recipe PACKAGE was registered with."
|
||||
(let ((plist (gethash (symbol-name package) straight--recipe-cache)))
|
||||
(if prop
|
||||
(if (plist-member plist prop)
|
||||
(plist-get plist prop)
|
||||
nil-value)
|
||||
plist)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-true-name (package)
|
||||
"Return PACKAGE's true name.
|
||||
|
||||
It is possible for quelpa packages to be given a psuedonym (the first argument
|
||||
of `package!'). Its real name is the car of package's :recipe. e.g.
|
||||
|
||||
(package! X :recipe (Y :fetcher github :repo \"abc/def\"))
|
||||
|
||||
X's real name is Y."
|
||||
(let ((sym (car (doom-package-prop package :recipe))))
|
||||
(or (and (symbolp sym)
|
||||
(not (keywordp sym))
|
||||
sym)
|
||||
package)))
|
||||
(defun doom-package-build-recipe (package &optional prop nil-value)
|
||||
"Returns the `straight' recipe PACKAGE was installed with."
|
||||
(let ((plist (nth 2 (gethash (symbol-name package) straight--build-cache))))
|
||||
(if prop
|
||||
(if (plist-member plist prop)
|
||||
(plist-get plist prop)
|
||||
nil-value)
|
||||
plist)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-psuedo-name (package)
|
||||
(defun doom-package-build-time (package)
|
||||
"TODO"
|
||||
(or (cl-loop for (package . plist) in doom-packages
|
||||
for recipe-name = (car (plist-get plist :recipe))
|
||||
if (eq recipe-name package)
|
||||
return recipe-name)
|
||||
package))
|
||||
(car (gethash (symbol-name package) straight--build-cache)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-backend (package &optional noerror)
|
||||
"Return backend that PACKAGE was installed with.
|
||||
(defun doom-package-dependencies (package &optional recursive noerror)
|
||||
"Return a list of dependencies for a package."
|
||||
(let ((deps (nth 1 (gethash (symbol-name package) straight--build-cache))))
|
||||
(if recursive
|
||||
(nconc deps (mapcan (lambda (dep) (doom-package-dependencies dep t t))
|
||||
deps))
|
||||
deps)))
|
||||
|
||||
Can either be elpa, quelpa or emacs (built-in). Throws an error if NOERROR is
|
||||
nil and the package isn't installed.
|
||||
|
||||
See `doom-package-recipe-backend' to get the backend PACKAGE is registered with
|
||||
\(as opposed to what it is was installed with)."
|
||||
(cl-check-type package symbol)
|
||||
(let ((package-truename (doom-package-true-name package)))
|
||||
(cond ((assq package-truename quelpa-cache) 'quelpa)
|
||||
((assq package-truename package-alist) 'elpa)
|
||||
((doom-package-built-in-p package) 'emacs)
|
||||
((not noerror) (error "%s package is not installed" package)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-recipe-backend (package &optional noerror)
|
||||
"Return backend that PACKAGE is registered with.
|
||||
|
||||
See `doom-package-backend' to get backend for currently installed package."
|
||||
(cl-check-type package symbol)
|
||||
(cond ((not (doom-package-registered-p package))
|
||||
(unless noerror
|
||||
(error "%s package is not registered" package)))
|
||||
((let ((builtin (eval (doom-package-prop package :built-in) t)))
|
||||
(or (and (eq builtin 'prefer)
|
||||
(locate-library (symbol-name package) nil doom-site-load-path))
|
||||
(eq builtin 't)))
|
||||
'emacs)
|
||||
((doom-package-prop package :recipe)
|
||||
'quelpa)
|
||||
('elpa)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-prop (package prop &optional nil-value)
|
||||
"Return PROPerty in PACKAGE's plist.
|
||||
|
||||
Otherwise returns NIL-VALUE if package isn't registered or PROP doesn't
|
||||
exist/isn't specified."
|
||||
(cl-check-type package symbol)
|
||||
(cl-check-type prop keyword)
|
||||
(if-let (plist (doom-package-plist package))
|
||||
(if (plist-member plist prop)
|
||||
(plist-get plist prop)
|
||||
nil-value)
|
||||
nil-value))
|
||||
(defun doom-package-depending-on (package &optional noerror)
|
||||
"Return a list of packages that depend on the package named NAME."
|
||||
(cl-check-type name symbol)
|
||||
;; can't get dependencies for built-in packages
|
||||
(unless (or (doom-package-build-recipe name)
|
||||
noerror)
|
||||
(error "Couldn't find %s, is it installed?" name))
|
||||
(cl-loop for pkg in (hash-table-keys straight--build-cache)
|
||||
for deps = (doom-package-dependencies pkg)
|
||||
if (memq package deps)
|
||||
collect pkg
|
||||
and append (doom-package-depending-on pkg t)))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -131,99 +70,52 @@ exist/isn't specified."
|
|||
;;;###autoload
|
||||
(defun doom-package-built-in-p (package)
|
||||
"Return non-nil if PACKAGE (a symbol) is built-in."
|
||||
(unless (doom-package-installed-p package)
|
||||
(or (package-built-in-p (doom-package-true-name package))
|
||||
(locate-library (symbol-name package) nil doom-site-load-path))))
|
||||
(eq (doom-package-build-recipe package :type)
|
||||
'built-in))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-installed-p (package)
|
||||
"Return non-nil if PACKAGE (a symbol) is installed."
|
||||
(when-let (desc (doom-package-desc package))
|
||||
(and (package-installed-p desc)
|
||||
(file-directory-p (package-desc-dir desc)))))
|
||||
(file-directory-p (straight--build-dir (symbol-name package))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-registered-p (package)
|
||||
"Return non-nil if PACKAGE (a symbol) has been registered with `package!'.
|
||||
|
||||
Excludes packages that have a non-nil :built-in property."
|
||||
(let ((package (or (cl-loop for (pkg . plist) in doom-packages
|
||||
for newname = (car (plist-get plist :recipe))
|
||||
if (and (symbolp newname)
|
||||
(eq newname package))
|
||||
return pkg)
|
||||
package)))
|
||||
(when-let (plist (doom-package-plist package))
|
||||
(not (eval (plist-get plist :ignore))))))
|
||||
(when-let (plist (doom-package-get package))
|
||||
(not (eval (plist-get plist :ignore) t))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-private-p (package)
|
||||
"Return non-nil if PACKAGE was installed by the user's private config."
|
||||
(doom-package-prop package :private))
|
||||
(doom-package-get package :private))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-protected-p (package)
|
||||
"Return non-nil if PACKAGE is protected.
|
||||
|
||||
A protected package cannot be deleted and will be auto-installed if missing."
|
||||
(memq (doom-package-true-name package) doom-core-packages))
|
||||
(memq package doom-core-packages))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-core-p (package)
|
||||
"Return non-nil if PACKAGE is a core Doom package."
|
||||
(or (doom-package-protected-p package)
|
||||
(assq :core (doom-package-prop package :modules))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-different-backend-p (package)
|
||||
"Return t if a PACKAGE (a symbol) has a new backend than what it was installed
|
||||
with. Returns nil otherwise, or if package isn't installed."
|
||||
(cl-check-type package symbol)
|
||||
(and (doom-package-installed-p package)
|
||||
(not (doom-get-depending-on package)) ; not a dependency
|
||||
(not (eq (doom-package-backend package 'noerror)
|
||||
(doom-package-recipe-backend package 'noerror)))))
|
||||
(assq :core (doom-package-get package :modules))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-different-recipe-p (name)
|
||||
"Return t if a package named NAME (a symbol) has a different recipe than it
|
||||
was installed with."
|
||||
(cl-check-type name symbol)
|
||||
(when (doom-package-installed-p name)
|
||||
(let ((package-truename (doom-package-true-name name)))
|
||||
(when-let* ((quelpa-recipe (assq package-truename quelpa-cache))
|
||||
(doom-recipe (assq package-truename doom-packages)))
|
||||
(not (equal (cdr quelpa-recipe)
|
||||
(cdr (plist-get (cdr doom-recipe) :recipe))))))))
|
||||
|
||||
(defvar quelpa-upgrade-p)
|
||||
;;;###autoload
|
||||
(defun doom-package-outdated-p (name)
|
||||
"Determine whether NAME (a symbol) is outdated or not.
|
||||
|
||||
If outdated, returns a list, whose car is NAME, and cdr the current version list
|
||||
and latest version list of the package."
|
||||
(cl-check-type name symbol)
|
||||
(when-let (desc (doom-package-desc name))
|
||||
(let* ((old-version (package-desc-version desc))
|
||||
(new-version
|
||||
(pcase (doom-package-backend name)
|
||||
(`quelpa
|
||||
(let ((recipe (doom-package-prop name :recipe))
|
||||
(dir (expand-file-name (symbol-name name) quelpa-build-dir))
|
||||
(inhibit-message (not doom-debug-mode))
|
||||
(quelpa-upgrade-p t))
|
||||
(if-let (ver (quelpa-checkout recipe dir))
|
||||
(version-to-list ver)
|
||||
old-version)))
|
||||
(`elpa
|
||||
(let ((desc (cadr (assq name package-archive-contents))))
|
||||
(when (package-desc-p desc)
|
||||
(package-desc-version desc)))))))
|
||||
(unless (and (listp old-version) (listp new-version))
|
||||
(error "Couldn't get version for %s" name))
|
||||
(when (version-list-< old-version new-version)
|
||||
(list name old-version new-version)))))
|
||||
;; TODO
|
||||
;; (when (doom-package-installed-p name)
|
||||
;; (when-let* ((doom-recipe (assq name doom-packages))
|
||||
;; (install-recipe (doom-package-recipe)))
|
||||
;; (not (equal (cdr quelpa-recipe)
|
||||
;; (cdr (plist-get (cdr doom-recipe) :recipe))))))
|
||||
)
|
||||
|
||||
|
||||
;;
|
||||
|
@ -307,32 +199,37 @@ files."
|
|||
collect (cons sym plist)
|
||||
and if (and deps (not (doom-package-built-in-p sym)))
|
||||
nconc
|
||||
(cl-loop for pkg in (doom-get-dependencies-for sym 'recursive 'noerror)
|
||||
(cl-loop for pkg in (doom-package-dependencies sym 'recursive 'noerror)
|
||||
if (or (eq installed 'any)
|
||||
(if installed
|
||||
(doom-package-installed-p pkg)
|
||||
(not (doom-package-installed-p pkg))))
|
||||
collect (cons pkg (cdr (assq pkg doom-packages)))))))
|
||||
|
||||
(defun doom--read-module-packages-file (file &optional raw noerror)
|
||||
(defun doom--read-module-packages-file (file &optional eval noerror)
|
||||
(with-temp-buffer ; prevent buffer-local settings from propagating
|
||||
(condition-case e
|
||||
(if (not raw)
|
||||
(if (not eval)
|
||||
(load file noerror t t)
|
||||
(when (file-readable-p file)
|
||||
(insert-file-contents file)
|
||||
(delay-mode-hooks (emacs-lisp-mode))
|
||||
(while (re-search-forward "(package! " nil t)
|
||||
(save-excursion
|
||||
(goto-char (match-beginning 0))
|
||||
(cl-destructuring-bind (name . plist) (cdr (sexp-at-point))
|
||||
(push (cons name
|
||||
(plist-put plist :modules
|
||||
(cond ((file-in-directory-p file doom-private-dir)
|
||||
'((:private)))
|
||||
((file-in-directory-p file doom-core-dir)
|
||||
'((:core)))
|
||||
((doom-module-from-path file)))))
|
||||
doom-packages))))))
|
||||
(unless (string-match-p
|
||||
"^.*;" (buffer-substring-no-properties
|
||||
(line-beginning-position)
|
||||
(point)))
|
||||
(cl-destructuring-bind (name . plist) (cdr (sexp-at-point))
|
||||
(push (cons name
|
||||
(plist-put plist :modules
|
||||
(cond ((file-in-directory-p file doom-private-dir)
|
||||
'((:private)))
|
||||
((file-in-directory-p file doom-core-dir)
|
||||
'((:core)))
|
||||
((doom-module-from-path file)))))
|
||||
doom-packages)))))))
|
||||
((debug error)
|
||||
(signal 'doom-package-error
|
||||
(list (or (doom-module-from-path file)
|
||||
|
@ -350,15 +247,16 @@ ones."
|
|||
(let ((noninteractive t)
|
||||
(doom-modules (doom-modules))
|
||||
doom-packages
|
||||
doom-disabled-packages
|
||||
package-pinned-packages)
|
||||
(doom--read-module-packages-file (expand-file-name "packages.el" doom-core-dir) all-p)
|
||||
doom-disabled-packages)
|
||||
(doom--read-module-packages-file
|
||||
(expand-file-name "packages.el" doom-core-dir)
|
||||
all-p t)
|
||||
(let ((private-packages (expand-file-name "packages.el" doom-private-dir)))
|
||||
(unless all-p
|
||||
;; We load the private packages file twice to ensure disabled packages
|
||||
;; are seen ASAP, and a second time to ensure privately overridden
|
||||
;; packages are properly overwritten.
|
||||
(doom--read-module-packages-file private-packages nil t))
|
||||
(doom--read-module-packages-file private-packages t t))
|
||||
(if all-p
|
||||
(mapc #'doom--read-module-packages-file
|
||||
(doom-files-in doom-modules-dir
|
||||
|
@ -371,192 +269,11 @@ ones."
|
|||
for doom--current-module = key
|
||||
do (doom--read-module-packages-file path nil t)))
|
||||
(doom--read-module-packages-file private-packages all-p t))
|
||||
(append (cl-loop for package in doom-core-packages
|
||||
collect (list package :modules '((:core internal))))
|
||||
(nreverse doom-packages))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-get-package-alist ()
|
||||
"Returns a list of all desired packages, their dependencies and their desc
|
||||
objects, in the order of their `package! blocks.'"
|
||||
(cl-remove-duplicates
|
||||
(cl-loop for name in (mapcar #'car doom-packages)
|
||||
if (assq name package-alist)
|
||||
nconc (cl-loop for dep in (package--get-deps name)
|
||||
if (assq dep package-alist)
|
||||
collect (cons dep (cadr it)))
|
||||
and collect (cons name (cadr it)))
|
||||
:key #'car
|
||||
:from-end t))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-get-depending-on (name &optional noerror)
|
||||
"Return a list of packages that depend on the package named NAME."
|
||||
(cl-check-type name symbol)
|
||||
(setq name (or (car (doom-package-prop name :recipe)) name))
|
||||
(unless (doom-package-built-in-p name)
|
||||
(if-let (desc (cadr (assq name package-alist)))
|
||||
(mapcar #'package-desc-name (package--used-elsewhere-p desc nil t))
|
||||
(unless noerror
|
||||
(error "Couldn't find %s, is it installed?" name)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-get-dependencies-for (name &optional recursive noerror)
|
||||
"Return a list of dependencies for a package."
|
||||
(cl-check-type name symbol)
|
||||
;; can't get dependencies for built-in packages
|
||||
(unless (doom-package-built-in-p name)
|
||||
(if-let (desc (doom-package-desc name))
|
||||
(let* ((deps (mapcar #'car (package-desc-reqs desc)))
|
||||
(deps (cl-remove-if #'doom-package-built-in-p deps)))
|
||||
(if recursive
|
||||
(nconc deps (mapcan (lambda (dep) (doom-get-dependencies-for dep t t))
|
||||
deps))
|
||||
deps))
|
||||
(unless noerror
|
||||
(error "Couldn't find %s, is it installed?" name)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-get-outdated-packages (&optional include-frozen-p)
|
||||
"Return a list of packages that are out of date. Each element is a list,
|
||||
containing (PACKAGE-SYMBOL OLD-VERSION-LIST NEW-VERSION-LIST).
|
||||
|
||||
If INCLUDE-FROZEN-P is non-nil, check frozen packages as well.
|
||||
|
||||
Used by `doom-packages-update'."
|
||||
(doom-refresh-packages-maybe doom-debug-mode)
|
||||
(cl-loop for package in (mapcar #'car package-alist)
|
||||
when (and (or (not (eval (doom-package-prop package :freeze)))
|
||||
include-frozen-p)
|
||||
(not (eval (doom-package-prop package :ignore)))
|
||||
(not (doom-package-different-backend-p package))
|
||||
(doom-package-outdated-p package))
|
||||
collect it))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-get-orphaned-packages ()
|
||||
"Return a list of symbols representing packages that are no longer needed or
|
||||
depended on.
|
||||
|
||||
Used by `doom-packages-autoremove'."
|
||||
(let ((package-selected-packages
|
||||
(mapcar #'car (doom-find-packages :ignored nil :disabled nil))))
|
||||
(append (cl-remove-if #'doom-package-registered-p (package--removable-packages))
|
||||
(cl-loop for pkg in package-selected-packages
|
||||
if (and (doom-package-different-backend-p pkg)
|
||||
(not (doom-package-built-in-p pkg)))
|
||||
collect pkg))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-get-missing-packages ()
|
||||
"Return a list of requested packages that aren't installed or built-in, but
|
||||
are enabled (with a `package!' directive). Each element is a list whose CAR is
|
||||
the package symbol, and whose CDR is a plist taken from that package's
|
||||
`package!' declaration.
|
||||
|
||||
Used by `doom-packages-install'."
|
||||
(cl-loop for (name . plist)
|
||||
in (doom-find-packages :ignored nil
|
||||
:disabled nil
|
||||
:deps t)
|
||||
if (and (equal (plist-get plist :pin)
|
||||
(ignore-errors
|
||||
(package-desc-archive
|
||||
(cadr (assq name package-alist)))))
|
||||
(or (not (doom-package-installed-p name))
|
||||
(doom-package-different-backend-p name)
|
||||
(doom-package-different-recipe-p name)))
|
||||
collect (cons name plist)))
|
||||
(nreverse doom-packages)))
|
||||
|
||||
|
||||
;;
|
||||
;; Main functions
|
||||
|
||||
(defun doom--delete-package-files (name-or-desc)
|
||||
(let ((pkg-build-dir
|
||||
(if (package-desc-p name-or-desc)
|
||||
(package-desc-dir name-or-desc)
|
||||
(expand-file-name (symbol-name name-or-desc) quelpa-build-dir))))
|
||||
(when (file-directory-p pkg-build-dir)
|
||||
(delete-directory pkg-build-dir t))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-install-package (name &optional plist)
|
||||
"Installs package NAME with optional quelpa RECIPE (see `quelpa-recipe' for an
|
||||
example; the package name can be omitted)."
|
||||
(cl-check-type name symbol)
|
||||
(when (and (doom-package-installed-p name)
|
||||
(not (doom-package-built-in-p name)))
|
||||
(if (or (doom-package-different-backend-p name)
|
||||
(doom-package-different-recipe-p name))
|
||||
(doom-delete-package name t)
|
||||
(user-error "%s is already installed" name)))
|
||||
(let* ((inhibit-message (not doom-debug-mode))
|
||||
(plist (or plist (doom-package-plist name))))
|
||||
(if-let (recipe (plist-get plist :recipe))
|
||||
(condition-case e
|
||||
(let (quelpa-upgrade-p)
|
||||
(quelpa recipe))
|
||||
((debug error)
|
||||
(doom--delete-package-files name)
|
||||
(signal (car e) (cdr e))))
|
||||
(package-install name))
|
||||
(if (not (doom-package-installed-p name))
|
||||
(doom--delete-package-files name)
|
||||
(add-to-list 'package-selected-packages name nil 'eq)
|
||||
(setf (alist-get name doom-packages) plist)
|
||||
name)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-update-package (name &optional force-p)
|
||||
"Updates package NAME (a symbol) if it is out of date, using quelpa or
|
||||
package.el as appropriate."
|
||||
(cl-check-type name symbol)
|
||||
(unless (doom-package-installed-p name)
|
||||
(error "%s isn't installed" name))
|
||||
(when (doom-package-different-backend-p name)
|
||||
(user-error "%s's backend has changed and must be uninstalled first" name))
|
||||
(when (or force-p (doom-package-outdated-p name))
|
||||
(let ((inhibit-message (not doom-debug-mode))
|
||||
(desc (doom-package-desc name)))
|
||||
(pcase (doom-package-backend name)
|
||||
(`quelpa
|
||||
(let ((name (doom-package-true-name name)))
|
||||
(condition-case e
|
||||
(let ((quelpa-upgrade-p t))
|
||||
(quelpa (assq name quelpa-cache)))
|
||||
((debug error)
|
||||
(doom--delete-package-files name)
|
||||
(signal (car e) (cdr e))))))
|
||||
(`elpa
|
||||
(let* ((archive (cadr (assq name package-archive-contents)))
|
||||
(packages
|
||||
(if (package-desc-p archive)
|
||||
(package-compute-transaction (list archive) (package-desc-reqs archive))
|
||||
(package-compute-transaction () (list (list archive))))))
|
||||
(package-download-transaction packages))))
|
||||
(unless (doom-package-outdated-p name)
|
||||
(doom--delete-package-files desc)
|
||||
t))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-delete-package (name &optional force-p)
|
||||
"Uninstalls package NAME if it exists, and clears it from `quelpa-cache'."
|
||||
(cl-check-type name symbol)
|
||||
(unless (doom-package-installed-p name)
|
||||
(user-error "%s isn't installed" name))
|
||||
(let ((inhibit-message (not doom-debug-mode))
|
||||
(name (doom-package-true-name name)))
|
||||
(when-let (spec (assq name quelpa-cache))
|
||||
(delq! spec quelpa-cache)
|
||||
(quelpa-save-cache))
|
||||
(package-delete (doom-package-desc name) force-p)
|
||||
(doom--delete-package-files name)
|
||||
(not (doom-package-installed-p name))))
|
||||
|
||||
|
||||
;;
|
||||
;; Interactive commands
|
||||
;;; Main functions
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/reload-packages ()
|
||||
|
@ -565,61 +282,3 @@ package.el as appropriate."
|
|||
(message "Reloading packages")
|
||||
(doom-initialize-packages t)
|
||||
(message "Reloading packages...DONE"))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/update-package (pkg)
|
||||
"Prompts the user with a list of outdated packages and updates the selected
|
||||
package. Use this interactively. Use `doom-update-package' for direct
|
||||
calls."
|
||||
(declare (interactive-only t))
|
||||
(interactive
|
||||
(let* ((packages (doom-get-outdated-packages))
|
||||
(selection (if packages
|
||||
(completing-read "Update package: "
|
||||
(mapcar #'car packages)
|
||||
nil t)
|
||||
(user-error "All packages are up to date")))
|
||||
(name (car (assoc (intern selection) package-alist))))
|
||||
(unless name
|
||||
(user-error "'%s' is already up-to-date" selection))
|
||||
(list (assq name packages))))
|
||||
(cl-destructuring-bind (package old-version new-version) pkg
|
||||
(if-let (desc (doom-package-outdated-p package))
|
||||
(let ((old-v-str (package-version-join old-version))
|
||||
(new-v-str (package-version-join new-version)))
|
||||
(if (y-or-n-p (format "%s will be updated from %s to %s. Update?"
|
||||
package old-v-str new-v-str))
|
||||
(message "%s %s (%s => %s)"
|
||||
(if (doom-update-package package t) "Updated" "Failed to update")
|
||||
package old-v-str new-v-str)
|
||||
(message "Aborted")))
|
||||
(message "%s is up-to-date" package))))
|
||||
|
||||
|
||||
;;
|
||||
;; Advice
|
||||
|
||||
;;;###autoload
|
||||
(defun doom*package-delete (desc &rest _)
|
||||
"Update `quelpa-cache' upon a successful `package-delete'."
|
||||
(let ((name (package-desc-name desc)))
|
||||
(unless (doom-package-installed-p name)
|
||||
(when-let (spec (assq name quelpa-cache))
|
||||
(setq quelpa-cache (delq spec quelpa-cache))
|
||||
(quelpa-save-cache)
|
||||
(doom--delete-package-files name)))))
|
||||
|
||||
|
||||
;;
|
||||
;; Make package.el cooperate with Doom
|
||||
|
||||
;; Updates QUELPA after deleting a package
|
||||
;;;###autoload
|
||||
(advice-add #'package-delete :after #'doom*package-delete)
|
||||
|
||||
;; Replace with Doom variants
|
||||
;;;###autoload
|
||||
(advice-add #'package-autoremove :override #'doom//autoremove)
|
||||
|
||||
;;;###autoload
|
||||
(advice-add #'package-install-selected-packages :override #'doom//install)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
;;; core/cli/autoloads.el -*- lexical-binding: t; -*-
|
||||
|
||||
(dispatcher! (autoloads a)
|
||||
(doom-reload-autoloads nil 'force)
|
||||
(def-command! (autoloads a) ()
|
||||
"Regenerates Doom's autoloads files.
|
||||
|
||||
It scans and reads autoload cookies (;;;###autoload) in core/autoload/*.el,
|
||||
|
@ -10,7 +9,8 @@ byte-compiles `doom-autoload-file', as well as `doom-package-autoload-file'
|
|||
(created from the concatenated autoloads files of all installed packages).
|
||||
|
||||
It also caches `load-path', `Info-directory-list', `doom-disabled-packages',
|
||||
`package-activated-list' and `auto-mode-alist'.")
|
||||
`package-activated-list' and `auto-mode-alist'."
|
||||
(doom-reload-autoloads nil 'force))
|
||||
|
||||
;; external variables
|
||||
(defvar autoload-timestamps)
|
||||
|
@ -21,55 +21,45 @@ It also caches `load-path', `Info-directory-list', `doom-disabled-packages',
|
|||
;;
|
||||
;;; Helpers
|
||||
|
||||
(defvar doom-autoload-excluded-packages '(marshal gh)
|
||||
"Packages that have silly or destructive autoload files that try to load
|
||||
everyone in the universe and their dog, causing errors that make babies cry. No
|
||||
one wants that.")
|
||||
|
||||
(defun doom-delete-autoloads-file (file)
|
||||
"Delete FILE (an autoloads file) and accompanying *.elc file, if any."
|
||||
(cl-check-type file string)
|
||||
(when (file-exists-p file)
|
||||
(when-let (buf (find-buffer-visiting doom-autoload-file))
|
||||
(when-let (buf (find-buffer-visiting file))
|
||||
(with-current-buffer buf
|
||||
(set-buffer-modified-p nil))
|
||||
(kill-buffer buf))
|
||||
(delete-file file)
|
||||
(ignore-errors (delete-file (byte-compile-dest-file file)))
|
||||
(message "Deleted old %s" (file-name-nondirectory file))))
|
||||
t))
|
||||
|
||||
(defun doom--warn-refresh-session ()
|
||||
(print! (bold (green "\nFinished!")))
|
||||
(message "If you have a running Emacs Session, you will need to restart it or")
|
||||
(message "reload Doom for changes to take effect:\n")
|
||||
(message "Restart or reload Doom Emacs for changes to take effect:\n")
|
||||
(message " M-x doom/restart-and-restore")
|
||||
(message " M-x doom/restart")
|
||||
(message " M-x doom/reload"))
|
||||
|
||||
(defun doom--reload-files (&rest files)
|
||||
(if (not noninteractive)
|
||||
(dolist (file files)
|
||||
(load-file (byte-compile-dest-file file)))
|
||||
(add-hook 'kill-emacs-hook #'doom--warn-refresh-session)))
|
||||
(if noninteractive
|
||||
(add-hook 'doom-cli-post-execute-hook #'doom--warn-refresh-session)
|
||||
(dolist (file files)
|
||||
(load-file (byte-compile-dest-file file)))))
|
||||
|
||||
(defun doom--byte-compile-file (file)
|
||||
(let ((short-name (file-name-nondirectory file))
|
||||
(byte-compile-dynamic-docstrings t))
|
||||
(let ((byte-compile-warnings (if doom-debug-mode byte-compile-warnings)))
|
||||
(condition-case e
|
||||
(when (byte-compile-file file)
|
||||
;; Give autoloads file a chance to report error
|
||||
(load (if doom-debug-mode
|
||||
file
|
||||
(byte-compile-dest-file file))
|
||||
nil t)
|
||||
(unless noninteractive
|
||||
(message "Finished compiling %s" short-name)))
|
||||
nil t))
|
||||
((debug error)
|
||||
(let ((backup-file (concat file ".bk")))
|
||||
(message "Copied backup to %s" backup-file)
|
||||
(print! (warn "- Copied backup to %s") (relpath backup-file))
|
||||
(copy-file file backup-file 'overwrite))
|
||||
(doom-delete-autoloads-file file)
|
||||
(signal 'doom-autoload-error (list short-name e))))))
|
||||
(signal 'doom-autoload-error (list file e))))))
|
||||
|
||||
(defun doom-reload-autoloads (&optional file force-p)
|
||||
"Reloads FILE (an autoload file), if it needs reloading.
|
||||
|
@ -82,71 +72,133 @@ even if it doesn't need reloading!"
|
|||
(signal 'wrong-type-argument (list 'stringp file)))
|
||||
(if (stringp file)
|
||||
(cond ((file-equal-p file doom-autoload-file)
|
||||
(doom-reload-doom-autoloads force-p))
|
||||
(doom-reload-core-autoloads force-p))
|
||||
((file-equal-p file doom-package-autoload-file)
|
||||
(doom-reload-package-autoloads force-p))
|
||||
((error "Invalid autoloads file: %s" file)))
|
||||
(doom-reload-doom-autoloads force-p)
|
||||
(doom-reload-core-autoloads force-p)
|
||||
(doom-reload-package-autoloads force-p)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Doom autoloads
|
||||
|
||||
(defun doom--file-cookie-p (file)
|
||||
"Returns the return value of the ;;;###if predicate form in FILE."
|
||||
(with-temp-buffer
|
||||
(insert-file-contents-literally file nil 0 256)
|
||||
(if (and (re-search-forward "^;;;###if " nil t)
|
||||
(<= (line-number-at-pos) 3))
|
||||
(let ((load-file-name file))
|
||||
(eval (sexp-at-point)))
|
||||
t)))
|
||||
|
||||
(defun doom--generate-header (func)
|
||||
(goto-char (point-min))
|
||||
(insert ";; -*- lexical-binding:t -*-\n"
|
||||
(insert ";; -*- lexical-binding:t; byte-compile-dynamic-docstrings: t; -*-\n"
|
||||
";; This file is autogenerated by `" (symbol-name func) "', DO NOT EDIT !!\n\n"))
|
||||
|
||||
(defun doom--generate-autoloads (targets)
|
||||
(require 'autoload)
|
||||
(dolist (file targets)
|
||||
(let* ((file (file-truename file))
|
||||
(generated-autoload-file doom-autoload-file)
|
||||
(generated-autoload-load-name (file-name-sans-extension file))
|
||||
(noninteractive (not doom-debug-mode))
|
||||
autoload-timestamps)
|
||||
(print!
|
||||
(cond ((not (doom--file-cookie-p file))
|
||||
"⚠ Ignoring %s")
|
||||
((autoload-generate-file-autoloads file (current-buffer))
|
||||
(yellow "✕ Nothing in %s"))
|
||||
((green "✓ Scanned %s")))
|
||||
(if (file-in-directory-p file default-directory)
|
||||
(file-relative-name file)
|
||||
(abbreviate-file-name file))))))
|
||||
(let ((n 0))
|
||||
(dolist (file targets)
|
||||
(insert
|
||||
(with-temp-buffer
|
||||
(cond ((not (doom-file-cookie-p file))
|
||||
(print! (debug "Ignoring %s") (relpath file)))
|
||||
|
||||
(defun doom--expand-autoloads ()
|
||||
((let ((generated-autoload-load-name (file-name-sans-extension file)))
|
||||
(require 'autoload)
|
||||
(autoload-generate-file-autoloads file (current-buffer)))
|
||||
(print! (debug "Nothing in %s") (relpath file)))
|
||||
|
||||
((cl-incf n)
|
||||
(print! (debug "Scanning %s...") (relpath file))))
|
||||
(buffer-string))))
|
||||
(print! (class (if (> n 0) 'success 'info)
|
||||
"Scanned %d file(s)")
|
||||
n)))
|
||||
|
||||
(defun doom--expand-autoload-paths (&optional allow-internal-paths)
|
||||
(let ((load-path
|
||||
;; NOTE With `doom-private-dir' in `load-path', Doom autoloads files
|
||||
;; will be unable to declare autoloads for the built-in autoload.el
|
||||
;; Emacs package, should $DOOMDIR/autoload.el exist. Not sure why
|
||||
;; they'd want to though, so it's an acceptable compromise.
|
||||
(append (list doom-private-dir doom-emacs-dir)
|
||||
(append (list doom-private-dir)
|
||||
doom-modules-dirs
|
||||
load-path))
|
||||
cache)
|
||||
(while (re-search-forward "^\\s-*(autoload\\s-+'[^ ]+\\s-+\"\\([^\"]*\\)\"" nil t)
|
||||
(straight--directory-files (straight--build-dir) nil t)
|
||||
load-path)))
|
||||
(defvar doom--autoloads-path-cache nil)
|
||||
(while (re-search-forward "^\\s-*(\\(?:custom-\\)?autoload\\s-+'[^ ]+\\s-+\"\\([^\"]*\\)\"" nil t)
|
||||
(let ((path (match-string 1)))
|
||||
(replace-match
|
||||
(or (cdr (assoc path cache))
|
||||
(when-let* ((libpath (locate-library path))
|
||||
(libpath (file-name-sans-extension libpath)))
|
||||
(push (cons path (abbreviate-file-name libpath)) cache)
|
||||
(or (cdr (assoc path doom--autoloads-path-cache))
|
||||
(when-let* ((libpath (or (and allow-internal-paths
|
||||
(locate-library path nil (cons doom-emacs-dir doom-modules-dirs)))
|
||||
(locate-library path)))
|
||||
(libpath (file-name-sans-extension libpath))
|
||||
(libpath (abbreviate-file-name libpath)))
|
||||
(push (cons path libpath) doom--autoloads-path-cache)
|
||||
libpath)
|
||||
path)
|
||||
t t nil 1)))))
|
||||
|
||||
(defun doom--generate-autodefs-1 (path &optional member-p)
|
||||
(let (forms)
|
||||
(while (re-search-forward "^;;;###autodef *\\([^\n]+\\)?\n" nil t)
|
||||
(let* ((sexp (sexp-at-point))
|
||||
(alt-sexp (match-string 1))
|
||||
(type (car sexp))
|
||||
(name (doom-unquote (cadr sexp)))
|
||||
(origin (cond ((doom-module-from-path path))
|
||||
((file-in-directory-p path doom-private-dir)
|
||||
`(:private . ,(intern (file-name-base path))))
|
||||
((file-in-directory-p path doom-emacs-dir)
|
||||
`(:core . ,(intern (file-name-base path)))))))
|
||||
(cond
|
||||
((and (not member-p)
|
||||
alt-sexp)
|
||||
(push (read alt-sexp) forms))
|
||||
|
||||
((memq type '(defun defmacro cl-defun cl-defmacro))
|
||||
(cl-destructuring-bind (_ _name arglist &rest body) sexp
|
||||
(let ((docstring (if (stringp (car body))
|
||||
(pop body)
|
||||
"No documentation.")))
|
||||
(appendq!
|
||||
forms
|
||||
(list (if member-p
|
||||
(make-autoload sexp (abbreviate-file-name (file-name-sans-extension path)))
|
||||
(setq docstring (format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s"
|
||||
origin docstring))
|
||||
(condition-case-unless-debug e
|
||||
(if alt-sexp
|
||||
(read alt-sexp)
|
||||
(append (list (pcase type
|
||||
(`defun 'defmacro)
|
||||
(`cl-defun `cl-defmacro)
|
||||
(_ type))
|
||||
name arglist docstring)
|
||||
(cl-loop for arg in arglist
|
||||
if (and (symbolp arg)
|
||||
(not (keywordp arg))
|
||||
(not (memq arg cl--lambda-list-keywords)))
|
||||
collect arg into syms
|
||||
else if (listp arg)
|
||||
collect (car arg) into syms
|
||||
finally return (if syms `((ignore ,@syms))))))
|
||||
('error
|
||||
(print! "- Ignoring autodef %s (%s)" name e)
|
||||
nil)))
|
||||
`(put ',name 'doom-module ',origin))))))
|
||||
|
||||
((eq type 'defalias)
|
||||
(cl-destructuring-bind (_type name target &optional docstring) sexp
|
||||
(let ((name (doom-unquote name))
|
||||
(target (doom-unquote target)))
|
||||
(unless member-p
|
||||
(setq target #'ignore
|
||||
docstring
|
||||
(format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s"
|
||||
origin docstring)))
|
||||
(appendq!
|
||||
forms
|
||||
`((put ',name 'doom-module ',origin)
|
||||
(defalias ',name #',target ,docstring))))))
|
||||
|
||||
(member-p (push sexp forms)))))
|
||||
forms))
|
||||
|
||||
(defun doom--generate-autodefs (targets enabled-targets)
|
||||
(goto-char (point-max))
|
||||
(search-backward ";;;***" nil t)
|
||||
|
@ -155,83 +207,17 @@ even if it doesn't need reloading!"
|
|||
(insert
|
||||
(with-temp-buffer
|
||||
(insert-file-contents path)
|
||||
(let ((member-p (or (member path enabled-targets)
|
||||
(file-in-directory-p path doom-core-dir)))
|
||||
forms)
|
||||
(while (re-search-forward "^;;;###autodef *\\([^\n]+\\)?\n" nil t)
|
||||
(let* ((sexp (sexp-at-point))
|
||||
(alt-sexp (match-string 1))
|
||||
(type (car sexp))
|
||||
(name (doom-unquote (cadr sexp)))
|
||||
(origin (cond ((doom-module-from-path path))
|
||||
((file-in-directory-p path doom-private-dir)
|
||||
`(:private . ,(intern (file-name-base path))))
|
||||
((file-in-directory-p path doom-emacs-dir)
|
||||
`(:core . ,(intern (file-name-base path))))))
|
||||
(doom-file-form
|
||||
`(put ',name 'doom-file ,(abbreviate-file-name path))))
|
||||
(cond ((and (not member-p) alt-sexp)
|
||||
(push (read alt-sexp) forms))
|
||||
|
||||
((memq type '(defun defmacro cl-defun cl-defmacro))
|
||||
(cl-destructuring-bind (_ name arglist &rest body) sexp
|
||||
(let ((docstring (if (stringp (car body))
|
||||
(pop body)
|
||||
"No documentation.")))
|
||||
(push (if member-p
|
||||
(make-autoload sexp (abbreviate-file-name (file-name-sans-extension path)))
|
||||
(push doom-file-form forms)
|
||||
(setq docstring (format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s"
|
||||
origin docstring))
|
||||
(condition-case-unless-debug e
|
||||
(if alt-sexp
|
||||
(read alt-sexp)
|
||||
(append (list (pcase type
|
||||
(`defun 'defmacro)
|
||||
(`cl-defun `cl-defmacro)
|
||||
(_ type))
|
||||
name arglist docstring)
|
||||
(cl-loop for arg in arglist
|
||||
if (and (symbolp arg)
|
||||
(not (keywordp arg))
|
||||
(not (memq arg cl--lambda-list-keywords)))
|
||||
collect arg into syms
|
||||
else if (listp arg)
|
||||
collect (car arg) into syms
|
||||
finally return (if syms `((ignore ,@syms))))))
|
||||
('error
|
||||
(message "Ignoring autodef %s (%s)"
|
||||
name e)
|
||||
nil)))
|
||||
forms)
|
||||
(push `(put ',name 'doom-module ',origin) forms))))
|
||||
|
||||
((eq type 'defalias)
|
||||
(cl-destructuring-bind (_type name target &optional docstring) sexp
|
||||
(let ((name (doom-unquote name))
|
||||
(target (doom-unquote target)))
|
||||
(unless member-p
|
||||
(setq docstring (format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s"
|
||||
origin docstring))
|
||||
(setq target #'ignore))
|
||||
(push doom-file-form forms)
|
||||
(push `(put ',name 'doom-module ',origin) forms)
|
||||
(push `(defalias ',name #',target ,docstring)
|
||||
forms))))
|
||||
|
||||
(member-p
|
||||
(push sexp forms)))))
|
||||
(if forms
|
||||
(concat (mapconcat #'prin1-to-string (nreverse forms) "\n")
|
||||
"\n")
|
||||
""))))))
|
||||
(if-let (forms (doom--generate-autodefs-1 path (member path enabled-targets)))
|
||||
(concat (mapconcat #'prin1-to-string (nreverse forms) "\n")
|
||||
"\n")
|
||||
"")))))
|
||||
|
||||
(defun doom--cleanup-autoloads ()
|
||||
(goto-char (point-min))
|
||||
(when (re-search-forward "^;;\\(;[^\n]*\\| no-byte-compile: t\\)\n" nil t)
|
||||
(replace-match "" t t)))
|
||||
|
||||
(defun doom-reload-doom-autoloads (&optional force-p)
|
||||
(defun doom-reload-core-autoloads (&optional force-p)
|
||||
"Refreshes `doom-autoload-file', if necessary (or if FORCE-P is non-nil).
|
||||
|
||||
It scans and reads autoload cookies (;;;###autoload) in core/autoload/*.el,
|
||||
|
@ -241,62 +227,78 @@ modules/*/*/autoload.el and modules/*/*/autoload/*.el, and generates
|
|||
Run this whenever your `doom!' block, or a module autoload file, is modified."
|
||||
(let* ((default-directory doom-emacs-dir)
|
||||
(doom-modules (doom-modules))
|
||||
(abbreviated-home-dir (if IS-WINDOWS "\\`'" abbreviated-home-dir))
|
||||
(targets
|
||||
(file-expand-wildcards
|
||||
(expand-file-name "autoload/*.el" doom-core-dir)))
|
||||
(enabled-targets (copy-sequence targets))
|
||||
case-fold-search)
|
||||
(dolist (path (doom-module-load-path t))
|
||||
(let* ((auto-dir (expand-file-name "autoload" path))
|
||||
(auto-file (expand-file-name "autoload.el" path))
|
||||
(module (doom-module-from-path auto-file))
|
||||
(module-p (or (doom-module-p (car module) (cdr module))
|
||||
(file-equal-p path doom-private-dir))))
|
||||
(when (file-exists-p auto-file)
|
||||
(push auto-file targets)
|
||||
(if module-p (push auto-file enabled-targets)))
|
||||
(dolist (file (doom-files-in auto-dir :match "\\.el$" :full t :sort nil))
|
||||
(push file targets)
|
||||
(if module-p (push file enabled-targets)))))
|
||||
(if (and (not force-p)
|
||||
(not doom-emacs-changed-p)
|
||||
(file-exists-p doom-autoload-file)
|
||||
(not (file-newer-than-file-p (expand-file-name "init.el" doom-private-dir)
|
||||
doom-autoload-file))
|
||||
(not (cl-loop for file in targets
|
||||
if (file-newer-than-file-p file doom-autoload-file)
|
||||
return t)))
|
||||
(progn (print! (green "Doom core autoloads is up-to-date"))
|
||||
(doom-initialize-autoloads doom-autoload-file)
|
||||
nil)
|
||||
(doom-delete-autoloads-file doom-autoload-file)
|
||||
(message "Generating new autoloads.el")
|
||||
(make-directory (file-name-directory doom-autoload-file) t)
|
||||
(with-temp-file doom-autoload-file
|
||||
(doom--generate-header 'doom-reload-doom-autoloads)
|
||||
(prin1 `(setq doom--modules-cache ',doom-modules) (current-buffer))
|
||||
(save-excursion
|
||||
(doom--generate-autoloads (reverse enabled-targets)))
|
||||
;; Replace autoload paths (only for module autoloads) with absolute
|
||||
;; paths for faster resolution during load and simpler `load-path'
|
||||
(save-excursion
|
||||
(doom--expand-autoloads)
|
||||
(print! (green "✓ Expanded module autoload paths")))
|
||||
;; Generates stub definitions for functions/macros defined in disabled
|
||||
;; modules, so that you will never get a void-function when you use
|
||||
;; them.
|
||||
(save-excursion
|
||||
(doom--generate-autodefs (reverse targets) enabled-targets)
|
||||
(print! (green "✓ Generated autodefs")))
|
||||
;; Remove byte-compile-inhibiting file variables so we can byte-compile
|
||||
;; the file, and autoload comments.
|
||||
(doom--cleanup-autoloads)
|
||||
(print! (green "✓ Clean up autoloads")))
|
||||
;; Byte compile it to give the file a chance to reveal errors.
|
||||
(doom--byte-compile-file doom-autoload-file)
|
||||
(doom--reload-files doom-autoload-file)
|
||||
t)))
|
||||
|
||||
;; The following bindings are in `package-generate-autoloads'.
|
||||
;; Presumably for a good reason, so I just copied them
|
||||
(noninteractive t)
|
||||
(backup-inhibited t)
|
||||
(version-control 'never)
|
||||
(case-fold-search nil) ; reduce magit
|
||||
(autoload-timestamps nil)
|
||||
|
||||
;; Where we'll store the files we'll scan for autoloads. This should
|
||||
;; contain *all* autoload files, even in disabled modules, so we can
|
||||
;; scan those for autodefs. We start with the core libraries.
|
||||
(targets (doom-glob doom-core-dir "autoload/*.el"))
|
||||
;; A subset of `targets' in enabled modules
|
||||
(active-targets (copy-sequence targets)))
|
||||
|
||||
(dolist (path (doom-module-load-path 'all-p))
|
||||
(when-let* ((files (cons (doom-glob path "autoload.el")
|
||||
(doom-files-in (doom-path path "autoload")
|
||||
:match "\\.el$")))
|
||||
(files (delq nil files)))
|
||||
(appendq! targets files)
|
||||
(when (or (doom-module-from-path path 'enabled-only)
|
||||
(file-equal-p path doom-private-dir))
|
||||
(appendq! active-targets files))))
|
||||
|
||||
(print! (start "Checking core autoloads file"))
|
||||
(print-group!
|
||||
(if (and (not force-p)
|
||||
(file-exists-p doom-autoload-file)
|
||||
(not (file-newer-than-file-p doom-emacs-dir doom-autoload-file))
|
||||
(not (cl-loop for dir
|
||||
in (append (doom-glob doom-private-dir "init.el*")
|
||||
targets)
|
||||
if (file-newer-than-file-p dir doom-autoload-file)
|
||||
return t)))
|
||||
(ignore
|
||||
(print! (success "Skipping core autoloads, they are up-to-date"))
|
||||
(doom-initialize-autoloads doom-autoload-file))
|
||||
(print! (start "Regenerating core autoloads file"))
|
||||
|
||||
(if (doom-delete-autoloads-file doom-autoload-file)
|
||||
(print! (success "Deleted old %s") (filename doom-autoload-file))
|
||||
(make-directory (file-name-directory doom-autoload-file) t))
|
||||
|
||||
(with-temp-file doom-autoload-file
|
||||
(doom--generate-header 'doom-reload-core-autoloads)
|
||||
(save-excursion
|
||||
(doom--generate-autoloads active-targets)
|
||||
(print! (success "Generated new autoloads.el")))
|
||||
;; Replace autoload paths (only for module autoloads) with absolute
|
||||
;; paths for faster resolution during load and simpler `load-path'
|
||||
(save-excursion
|
||||
(doom--expand-autoload-paths 'allow-internal-paths)
|
||||
(print! (success "Expanded module autoload paths")))
|
||||
;; Generates stub definitions for functions/macros defined in disabled
|
||||
;; modules, so that you will never get a void-function when you use
|
||||
;; them.
|
||||
(save-excursion
|
||||
(doom--generate-autodefs targets (reverse active-targets))
|
||||
(print! (success "Generated autodefs")))
|
||||
;; Remove byte-compile-inhibiting file variables so we can byte-compile
|
||||
;; the file, and autoload comments.
|
||||
(doom--cleanup-autoloads)
|
||||
(print! (success "Clean up autoloads")))
|
||||
;; Byte compile it to give the file a chance to reveal errors (and buy us a
|
||||
;; few marginal performance boosts)
|
||||
(print! "> Byte-compiling %s..." (relpath doom-autoload-file))
|
||||
(when (doom--byte-compile-file doom-autoload-file)
|
||||
(print! (success "Finished compiling %s") (relpath doom-autoload-file)))
|
||||
(doom--reload-files doom-autoload-file))
|
||||
t)))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -304,33 +306,49 @@ Run this whenever your `doom!' block, or a module autoload file, is modified."
|
|||
|
||||
(defun doom--generate-package-autoloads ()
|
||||
"Concatenates package autoload files, let-binds `load-file-name' around
|
||||
them,and remove unnecessary `provide' statements or blank links.
|
||||
|
||||
Skips over packages in `doom-autoload-excluded-packages'."
|
||||
(dolist (spec (doom-get-package-alist))
|
||||
(if-let* ((pkg (car spec))
|
||||
(desc (cdr spec)))
|
||||
(unless (memq pkg doom-autoload-excluded-packages)
|
||||
(let ((file (concat (package--autoloads-file-name desc) ".el")))
|
||||
(when (file-exists-p file)
|
||||
(insert "(let ((load-file-name " (prin1-to-string (abbreviate-file-name file)) "))\n")
|
||||
(insert-file-contents file)
|
||||
(while (re-search-forward "^\\(?:;;\\(.*\n\\)\\|\n\\|(provide '[^\n]+\\)" nil t)
|
||||
(unless (nth 8 (syntax-ppss))
|
||||
(replace-match "" t t)))
|
||||
(unless (bolp) (insert "\n"))
|
||||
(insert ")\n"))))
|
||||
(message "Couldn't find package desc for %s" (car spec)))))
|
||||
them,and remove unnecessary `provide' statements or blank links."
|
||||
(dolist (pkg (straight--directory-files (straight--build-dir)))
|
||||
(let ((file (straight--autoloads-file pkg)))
|
||||
(when (file-exists-p file)
|
||||
(insert-file-contents file)
|
||||
(when (save-excursion
|
||||
(and (re-search-forward "\\_<load-file-name\\_>" nil t)
|
||||
(not (nth 8 (syntax-ppss)))))
|
||||
;; Set `load-file-name' so that the contents of autoloads
|
||||
;; files can pretend they're in the file they're expected to
|
||||
;; be in, rather than `doom-package-autoload-file'.
|
||||
(insert (format "(setq load-file-name %S)\n" (abbreviate-file-name file))))
|
||||
(while (re-search-forward "^\\(?:;;\\(.*\n\\)\\|\n\\|(provide '[^\n]+\\)" nil t)
|
||||
(unless (nth 8 (syntax-ppss))
|
||||
(replace-match "" t t)))
|
||||
(unless (bolp) (insert "\n"))))))
|
||||
|
||||
(defun doom--generate-var-cache ()
|
||||
"Print a `setq' form for expensive-to-initialize variables, so we can cache
|
||||
them in Doom's autoloads file."
|
||||
(doom-initialize-packages)
|
||||
(prin1 `(setq load-path ',load-path
|
||||
auto-mode-alist ',auto-mode-alist
|
||||
auto-mode-alist
|
||||
',(let ((alist (copy-sequence auto-mode-alist))
|
||||
newalist
|
||||
last-group
|
||||
last-mode
|
||||
it)
|
||||
(while (setq it (pop alist))
|
||||
(cl-destructuring-bind (re . mode) it
|
||||
(unless (eq mode last-mode)
|
||||
(when last-mode
|
||||
(push (cons (if (cdr last-group)
|
||||
(concat "\\(?:" (string-join last-group "\\)\\|\\(?:") "\\)")
|
||||
(car last-group))
|
||||
last-mode)
|
||||
newalist))
|
||||
(setq last-mode mode
|
||||
last-group nil))
|
||||
(push re last-group)))
|
||||
(nreverse newalist))
|
||||
Info-directory-list ',Info-directory-list
|
||||
doom-disabled-packages ',(mapcar #'car (doom-find-packages :disabled t))
|
||||
package-activated-list ',package-activated-list)
|
||||
doom-disabled-packages ',doom-disabled-packages)
|
||||
(current-buffer)))
|
||||
|
||||
(defun doom--cleanup-package-autoloads ()
|
||||
|
@ -351,34 +369,63 @@ Will do nothing if none of your installed packages have been modified. If
|
|||
FORCE-P (universal argument) is non-nil, regenerate it anyway.
|
||||
|
||||
This should be run whenever your `doom!' block or update your packages."
|
||||
(let ((abbreviated-home-dir (if IS-WINDOWS "\\`'" abbreviated-home-dir)))
|
||||
(if (and (not force-p)
|
||||
(not doom-emacs-changed-p)
|
||||
(file-exists-p doom-package-autoload-file)
|
||||
(not (file-newer-than-file-p doom-packages-dir doom-package-autoload-file))
|
||||
(not (ignore-errors
|
||||
(cl-loop for key being the hash-keys of (doom-modules)
|
||||
for path = (doom-module-path (car key) (cdr key) "packages.el")
|
||||
if (file-newer-than-file-p path doom-package-autoload-file)
|
||||
return t))))
|
||||
(ignore (print! (green "Doom package autoloads is up-to-date"))
|
||||
(doom-initialize-autoloads doom-package-autoload-file))
|
||||
(let (case-fold-search)
|
||||
(doom-delete-autoloads-file doom-package-autoload-file)
|
||||
(with-temp-file doom-package-autoload-file
|
||||
(doom--generate-header 'doom-reload-package-autoloads)
|
||||
(save-excursion
|
||||
;; Cache important and expensive-to-initialize state here.
|
||||
(doom--generate-var-cache)
|
||||
(print! (green "✓ Cached package state"))
|
||||
;; Concatenate the autoloads of all installed packages.
|
||||
(doom--generate-package-autoloads)
|
||||
(print! (green "✓ Package autoloads included")))
|
||||
;; Remove `load-path' and `auto-mode-alist' modifications (most of them,
|
||||
;; at least); they are cached later, so all those membership checks are
|
||||
;; unnecessary overhead.
|
||||
(doom--cleanup-package-autoloads)
|
||||
(print! (green "✓ Removed load-path/auto-mode-alist entries"))))
|
||||
(doom--byte-compile-file doom-package-autoload-file)
|
||||
(doom--reload-files doom-package-autoload-file)
|
||||
t)))
|
||||
(print! (start "Checking package autoloads file"))
|
||||
(print-group!
|
||||
(if (and (not force-p)
|
||||
(file-exists-p doom-package-autoload-file)
|
||||
(not (file-newer-than-file-p doom-elpa-dir doom-package-autoload-file))
|
||||
(not (ignore-errors
|
||||
(cl-loop for dir in (straight--directory-files (straight--repos-dir))
|
||||
if (cl-find-if (lambda (dir) (file-newer-than-file-p dir doom-package-autoload-file))
|
||||
(glob! (straight--repos-dir dir) "*.el"))
|
||||
return t)))
|
||||
(not (ignore-errors
|
||||
(cl-loop for key being the hash-keys of (doom-modules)
|
||||
for path = (doom-module-path (car key) (cdr key) "packages.el")
|
||||
if (file-newer-than-file-p path doom-package-autoload-file)
|
||||
return t))))
|
||||
(ignore
|
||||
(print! (success "Skipping package autoloads, they are up-to-date"))
|
||||
(doom-initialize-autoloads doom-package-autoload-file))
|
||||
(let (;; The following bindings are in `package-generate-autoloads'.
|
||||
;; Presumably for a good reason, so I just copied them
|
||||
(noninteractive t)
|
||||
(backup-inhibited t)
|
||||
(version-control 'never)
|
||||
(case-fold-search nil) ; reduce magit
|
||||
(autoload-timestamps nil))
|
||||
(print! (start "Regenerating package autoloads file"))
|
||||
|
||||
(if (doom-delete-autoloads-file doom-package-autoload-file)
|
||||
(print! (success "Deleted old %s") (filename doom-package-autoload-file))
|
||||
(make-directory (file-name-directory doom-autoload-file) t))
|
||||
|
||||
(with-temp-file doom-package-autoload-file
|
||||
(doom--generate-header 'doom-reload-package-autoloads)
|
||||
|
||||
(save-excursion
|
||||
;; Cache important and expensive-to-initialize state here.
|
||||
(doom--generate-var-cache)
|
||||
(print! (success "Cached package state"))
|
||||
;; Concatenate the autoloads of all installed packages.
|
||||
(doom--generate-package-autoloads)
|
||||
(print! (success "Package autoloads included")))
|
||||
|
||||
;; Replace autoload paths (only for module autoloads) with absolute
|
||||
;; paths for faster resolution during load and simpler `load-path'
|
||||
(save-excursion
|
||||
(doom--expand-autoload-paths)
|
||||
(print! (success "Expanded module autoload paths")))
|
||||
|
||||
;; Remove `load-path' and `auto-mode-alist' modifications (most of them,
|
||||
;; at least); they are cached later, so all those membership checks are
|
||||
;; unnecessary overhead.
|
||||
(doom--cleanup-package-autoloads)
|
||||
(print! (success "Removed load-path/auto-mode-alist entries")))
|
||||
;; Byte compile it to give the file a chance to reveal errors (and buy us a
|
||||
;; few marginal performance boosts)
|
||||
(print! (start "Byte-compiling %s...") (relpath doom-package-autoload-file))
|
||||
(when (doom--byte-compile-file doom-package-autoload-file)
|
||||
(print! (success "Finished compiling %s") (relpath doom-package-autoload-file)))
|
||||
(doom--reload-files doom-package-autoload-file)))
|
||||
t))
|
||||
|
|
|
@ -1,21 +1,24 @@
|
|||
;;; core/cli/byte-compile.el -*- lexical-binding: t; -*-
|
||||
|
||||
(dispatcher! (compile c) (doom-byte-compile args)
|
||||
(def-command! (compile c) (&rest targets)
|
||||
"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.")
|
||||
Accepts :core and :private as special arguments, which target Doom's core files
|
||||
and your private config files, respectively. To recompile your packages, use
|
||||
'doom rebuild' instead."
|
||||
(doom-byte-compile targets))
|
||||
|
||||
(dispatcher! (recompile rc) (doom-byte-compile args 'recompile)
|
||||
"Re-byte-compiles outdated *.elc files.")
|
||||
(def-command! (recompile rc) (&rest targets)
|
||||
"Re-byte-compiles outdated *.elc files."
|
||||
(doom-byte-compile targets 'recompile))
|
||||
|
||||
(dispatcher! clean (doom-clean-byte-compiled-files)
|
||||
"Delete all *.elc files.")
|
||||
(def-command! clean ()
|
||||
"Delete all *.elc files."
|
||||
(doom-clean-byte-compiled-files))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -25,9 +28,10 @@ respectively.")
|
|||
(let ((filename (file-name-nondirectory path)))
|
||||
(or (string-prefix-p "." filename)
|
||||
(string-prefix-p "test-" filename)
|
||||
(not (equal (file-name-extension path) "el")))))
|
||||
(not (equal (file-name-extension path) "el"))
|
||||
(member filename (list "packages.el" "doctor.el")))))
|
||||
|
||||
(defun doom-byte-compile (&optional modules recompile-p)
|
||||
(cl-defun doom-byte-compile (&optional modules recompile-p)
|
||||
"Byte compiles your emacs configuration.
|
||||
|
||||
init.el is always byte-compiled by this.
|
||||
|
@ -45,35 +49,35 @@ byte-compilation.
|
|||
|
||||
If RECOMPILE-P is non-nil, only recompile out-of-date files."
|
||||
(let ((default-directory doom-emacs-dir)
|
||||
(total-ok 0)
|
||||
(total-fail 0)
|
||||
(total-noop 0)
|
||||
compile-plugins-p
|
||||
(doom-modules (doom-modules))
|
||||
(byte-compile-verbose doom-debug-mode)
|
||||
(byte-compile-warnings '(not free-vars unresolved noruntime lexical make-local))
|
||||
|
||||
;; In case it is changed during compile-time
|
||||
(auto-mode-alist auto-mode-alist)
|
||||
(noninteractive t)
|
||||
|
||||
targets)
|
||||
(dolist (module (delete-dups modules) (nreverse targets))
|
||||
(pcase module
|
||||
(":core" (push doom-core-dir targets))
|
||||
(":private" (push doom-private-dir targets))
|
||||
(":plugins"
|
||||
(cl-loop for (_name . desc) in (doom-get-package-alist)
|
||||
do (package--compile desc))
|
||||
(setq compile-plugins-p t
|
||||
modules (delete ":plugins" modules)))
|
||||
((pred file-directory-p)
|
||||
(push module targets))
|
||||
((pred (string-match "^\\([^/]+\\)/\\([^/]+\\)$"))
|
||||
(push (doom-module-locate-path
|
||||
(doom-keyword-intern (match-string 1 module))
|
||||
(intern (match-string 2 module)))
|
||||
targets))))
|
||||
(cl-block 'byte-compile
|
||||
;; If we're just here to byte-compile our plugins, we're done!
|
||||
(and (not modules)
|
||||
compile-plugins-p
|
||||
(cl-return-from 'byte-compile t))
|
||||
(unless (or (equal modules '(":core"))
|
||||
recompile-p)
|
||||
(unless (or doom-auto-accept
|
||||
|
||||
(let (target-dirs)
|
||||
(dolist (module (delete-dups modules))
|
||||
(pcase module
|
||||
(":core"
|
||||
(push (doom-glob doom-emacs-dir "init.el") targets)
|
||||
(push doom-core-dir target-dirs))
|
||||
(":private"
|
||||
(push doom-private-dir target-dirs))
|
||||
((pred file-directory-p)
|
||||
(push module target-dirs))
|
||||
((pred (string-match "^\\([^/]+\\)/\\([^/]+\\)$"))
|
||||
(push (doom-module-locate-path
|
||||
(doom-keyword-intern (match-string 1 module))
|
||||
(intern (match-string 2 module)))
|
||||
target-dirs))))
|
||||
|
||||
(and (or (null modules) (member ":private" modules))
|
||||
(not recompile-p)
|
||||
(not (or doom-auto-accept
|
||||
(y-or-n-p
|
||||
(concat "Warning: byte compiling is for advanced users. It will interfere with your\n"
|
||||
"efforts to debug issues. It is not recommended you do it if you frequently\n"
|
||||
|
@ -82,109 +86,113 @@ If RECOMPILE-P is non-nil, only recompile out-of-date files."
|
|||
"Doom core files, as these don't change often.\n\n"
|
||||
"If you have issues, please make sure byte-compilation isn't the cause by using\n"
|
||||
"`bin/doom clean` to clear out your *.elc files.\n\n"
|
||||
"Byte-compile anyway?")))
|
||||
(message "Aborting.")
|
||||
(cl-return-from 'byte-compile)))
|
||||
(when (and (not recompile-p)
|
||||
(or (null modules)
|
||||
(equal modules '(":core"))))
|
||||
(doom-clean-byte-compiled-files))
|
||||
(let (doom-emacs-changed-p
|
||||
noninteractive)
|
||||
;; But first we must be sure that Doom and your private config have been
|
||||
;; fully loaded. Which usually aren't so in an noninteractive session.
|
||||
(unless (and (doom-initialize-autoloads doom-autoload-file)
|
||||
(doom-initialize-autoloads doom-package-autoload-file))
|
||||
(doom-reload-autoloads))
|
||||
(doom-initialize)
|
||||
(doom-initialize-modules 'force))
|
||||
;; If no targets were supplied, then we use your module list.
|
||||
(unless modules
|
||||
(let ((doom-modules-dirs (delete (expand-file-name "modules/" doom-private-dir)
|
||||
doom-modules-dirs)))
|
||||
(setq targets
|
||||
(append (list doom-core-dir)
|
||||
(delete doom-private-dir (doom-module-load-path))))))
|
||||
;; Assemble el files we want to compile; taking into account that
|
||||
;; MODULES may be a list of MODULE/SUBMODULE strings from the command
|
||||
;; line.
|
||||
(let ((target-files (doom-files-in targets :filter #'doom--byte-compile-ignore-file-p :sort nil)))
|
||||
(when (or (not modules)
|
||||
(member ":core" modules))
|
||||
(push (expand-file-name "init.el" doom-emacs-dir)
|
||||
target-files))
|
||||
(unless target-files
|
||||
(if targets
|
||||
(message "Couldn't find any valid targets")
|
||||
(message "No targets to %scompile" (if recompile-p "re" "")))
|
||||
(cl-return-from 'byte-compile))
|
||||
(require 'use-package)
|
||||
(condition-case e
|
||||
(let ((use-package-defaults use-package-defaults)
|
||||
(use-package-expand-minimally t)
|
||||
(load-path load-path)
|
||||
kill-emacs-hook kill-buffer-query-functions)
|
||||
;; Prevent packages from being loaded at compile time if they
|
||||
;; don't meet their own predicates.
|
||||
(push (list :no-require t
|
||||
(lambda (_name args)
|
||||
(or (when-let (pred (or (plist-get args :if)
|
||||
(plist-get args :when)))
|
||||
(not (eval pred t)))
|
||||
(when-let (pred (plist-get args :unless))
|
||||
(eval pred t)))))
|
||||
use-package-defaults)
|
||||
(dolist (target (cl-delete-duplicates (mapcar #'file-truename target-files) :test #'equal))
|
||||
(if (or (not recompile-p)
|
||||
(let ((elc-file (byte-compile-dest-file target)))
|
||||
(and (file-exists-p elc-file)
|
||||
(file-newer-than-file-p target elc-file))))
|
||||
(let ((result (if (or (string-match-p "/\\(?:packages\\|doctor\\)\\.el$" target)
|
||||
(not (doom--file-cookie-p target)))
|
||||
'no-byte-compile
|
||||
(byte-compile-file target)))
|
||||
(short-name (if (file-in-directory-p target doom-emacs-dir)
|
||||
(file-relative-name target doom-emacs-dir)
|
||||
(abbreviate-file-name target))))
|
||||
(cl-incf
|
||||
(cond ((eq result 'no-byte-compile)
|
||||
(print! (dark (white "⚠ Ignored %s")) short-name)
|
||||
total-noop)
|
||||
((null result)
|
||||
(print! (red "✕ Failed to compile %s") short-name)
|
||||
total-fail)
|
||||
(t
|
||||
(print! (green "✓ Compiled %s") short-name)
|
||||
(load target t t)
|
||||
total-ok))))
|
||||
(cl-incf total-noop)))
|
||||
(print! (bold (color (if (= total-fail 0) 'green 'red)
|
||||
"%s %d/%d file(s) (%d ignored)"))
|
||||
(if recompile-p "Recompiled" "Compiled")
|
||||
total-ok (- (length target-files) total-noop)
|
||||
total-noop)
|
||||
(or (= total-fail 0)
|
||||
(error "Failed to compile some files")))
|
||||
((debug error)
|
||||
(print! (red "\nThere were breaking errors.\n\n%s")
|
||||
"Reverting changes...")
|
||||
(signal 'doom-error (list 'byte-compile e))))))))
|
||||
"Byte-compile anyway?"))))
|
||||
(user-error "Aborting"))
|
||||
|
||||
;; But first we must be sure that Doom and your private config have been
|
||||
;; fully loaded. Which usually aren't so in an noninteractive session.
|
||||
(doom-initialize-autoloads doom-autoload-file)
|
||||
(doom-initialize-autoloads doom-package-autoload-file)
|
||||
|
||||
;;
|
||||
(unless target-dirs
|
||||
(push (doom-glob doom-emacs-dir "init.el") targets)
|
||||
;; If no targets were supplied, then we use your module list.
|
||||
(appendq! target-dirs
|
||||
(list doom-core-dir)
|
||||
;; Omit `doom-private-dir', which is always first
|
||||
(cl-remove-if-not (lambda (path) (file-in-directory-p path doom-emacs-dir))
|
||||
(cdr (doom-module-load-path)))))
|
||||
|
||||
;; Assemble el files we want to compile; taking into account that MODULES
|
||||
;; may be a list of MODULE/SUBMODULE strings from the command line.
|
||||
(appendq! targets
|
||||
(doom-files-in target-dirs
|
||||
:match "\\.el$"
|
||||
:filter #'doom--byte-compile-ignore-file-p)))
|
||||
|
||||
(unless targets
|
||||
(print!
|
||||
(if targets
|
||||
(warn "Couldn't find any valid targets")
|
||||
(info "No targets to %scompile" (if recompile-p "re" ""))))
|
||||
(cl-return nil))
|
||||
|
||||
(print!
|
||||
(info (if recompile-p
|
||||
"Recompiling stale elc files..."
|
||||
"Byte-compiling your config (may take a while)...")))
|
||||
(print-group!
|
||||
(require 'use-package)
|
||||
(condition-case e
|
||||
(let ((total-ok 0)
|
||||
(total-fail 0)
|
||||
(total-noop 0)
|
||||
(use-package-defaults use-package-defaults)
|
||||
(use-package-expand-minimally t)
|
||||
kill-emacs-hook kill-buffer-query-functions)
|
||||
;; Prevent packages from being loaded at compile time if they
|
||||
;; don't meet their own predicates.
|
||||
(push (list :no-require t
|
||||
(lambda (_name args)
|
||||
(or (when-let (pred (or (plist-get args :if)
|
||||
(plist-get args :when)))
|
||||
(not (eval pred t)))
|
||||
(when-let (pred (plist-get args :unless))
|
||||
(eval pred t)))))
|
||||
use-package-defaults)
|
||||
|
||||
(unless recompile-p
|
||||
(doom-clean-byte-compiled-files))
|
||||
|
||||
(dolist (target (delete-dups targets))
|
||||
(cl-incf
|
||||
(if (not (or (not recompile-p)
|
||||
(let ((elc-file (byte-compile-dest-file target)))
|
||||
(and (file-exists-p elc-file)
|
||||
(file-newer-than-file-p target elc-file)))))
|
||||
total-noop
|
||||
(pcase (if (doom-file-cookie-p target)
|
||||
(byte-compile-file target)
|
||||
'no-byte-compile)
|
||||
(`no-byte-compile
|
||||
(print! (info "Ignored %s") (relpath target))
|
||||
total-noop)
|
||||
(`nil
|
||||
(print! (error "Failed to compile %s") (relpath target))
|
||||
total-fail)
|
||||
(_
|
||||
(print! (success "Compiled %s") (relpath target))
|
||||
(load target t t)
|
||||
total-ok)))))
|
||||
(print! (class (if (= total-fail 0) 'success 'error)
|
||||
"%s %d/%d file(s) (%d ignored)")
|
||||
(if recompile-p "Recompiled" "Compiled")
|
||||
total-ok (- (length targets) total-noop)
|
||||
total-noop)
|
||||
t)
|
||||
((debug error)
|
||||
(print! (error "\nThere were breaking errors.\n\n%s")
|
||||
"Reverting changes...")
|
||||
(signal 'doom-error (list 'byte-compile e)))))))
|
||||
|
||||
(defun doom-clean-byte-compiled-files ()
|
||||
"Delete all the compiled elc files in your Emacs configuration and private
|
||||
module. This does not include your byte-compiled, third party packages.'"
|
||||
(cl-loop with default-directory = doom-emacs-dir
|
||||
for path
|
||||
in (append (doom-files-in doom-emacs-dir :match "\\.elc$" :depth 0 :sort nil)
|
||||
(doom-files-in doom-private-dir :match "\\.elc$" :depth 1 :sort nil)
|
||||
(doom-files-in doom-core-dir :match "\\.elc$" :sort nil)
|
||||
(doom-files-in doom-modules-dirs :match "\\.elc$" :depth 4 :sort nil))
|
||||
for truepath = (file-truename path)
|
||||
if (file-exists-p path)
|
||||
do (delete-file path)
|
||||
and do
|
||||
(print! (green "✓ Deleted %s")
|
||||
(if (file-in-directory-p truepath default-directory)
|
||||
(file-relative-name truepath)
|
||||
(abbreviate-file-name truepath)))
|
||||
finally do (print! (bold (green "Everything is clean")))))
|
||||
(print! (start "Cleaning .elc files"))
|
||||
(print-group!
|
||||
(cl-loop with default-directory = doom-emacs-dir
|
||||
with success = nil
|
||||
for path
|
||||
in (append (doom-glob doom-emacs-dir "*.elc")
|
||||
(doom-files-in doom-private-dir :match "\\.elc$" :depth 1 :sort nil)
|
||||
(doom-files-in doom-core-dir :match "\\.elc$" :sort nil)
|
||||
(doom-files-in doom-modules-dirs :match "\\.elc$" :depth 4 :sort nil))
|
||||
if (file-exists-p path)
|
||||
do (delete-file path)
|
||||
and do (print! (success "Deleted %s") (relpath path))
|
||||
and do (setq success t)
|
||||
finally do
|
||||
(print! (if success
|
||||
(success "All elc files deleted")
|
||||
(info "No elc files to clean"))))))
|
||||
|
|
|
@ -1,7 +1,26 @@
|
|||
;;; core/cli/debug.el -*- lexical-binding: t; -*-
|
||||
|
||||
(dispatcher! info (doom/info)
|
||||
"Output system info in markdown for bug reports.")
|
||||
(load! "autoload/debug" doom-core-dir)
|
||||
|
||||
(dispatcher! (version v) (doom/version)
|
||||
"Reports the version of Doom and Emacs.")
|
||||
|
||||
;;
|
||||
;;; Commands
|
||||
|
||||
(def-command! info (&optional format)
|
||||
"Output system info in markdown for bug reports."
|
||||
(pcase format
|
||||
("json"
|
||||
(require 'json)
|
||||
(with-temp-buffer
|
||||
(insert (json-encode (doom-info)))
|
||||
(json-pretty-print-buffer)
|
||||
(print! (buffer-string))))
|
||||
((or "md" "markdown")
|
||||
(doom/info))
|
||||
(_ (doom/info 'raw)))
|
||||
nil)
|
||||
|
||||
(def-command! (version v) ()
|
||||
"Reports the version of Doom and Emacs."
|
||||
(doom/version)
|
||||
nil)
|
||||
|
|
|
@ -1,25 +1,6 @@
|
|||
;;; core/cli/env.el -*- lexical-binding: t; -*-
|
||||
|
||||
(dispatcher! env
|
||||
(let ((env-file (abbreviate-file-name doom-env-file)))
|
||||
(pcase (car args)
|
||||
((or "refresh" "re")
|
||||
(doom-reload-env-file 'force))
|
||||
((or "enable" "auto")
|
||||
(setenv "DOOMENV" "1")
|
||||
(print! (green "Enabling auto-reload of %S") env-file)
|
||||
(doom-reload-env-file 'force)
|
||||
(print! (green "Done! `doom refresh' will now refresh your envvar file.")))
|
||||
("clear"
|
||||
(setenv "DOOMENV" nil)
|
||||
(unless (file-exists-p env-file)
|
||||
(user-error "%S does not exist to be cleared" env-file))
|
||||
(delete-file env-file)
|
||||
(print! (green "Disabled envvar file by deleting %S") env-file))
|
||||
(_
|
||||
(print! "%s\n\n%s"
|
||||
(bold (red "No valid subcommand provided."))
|
||||
"See `doom help env` to see available commands."))))
|
||||
(def-command! env (&optional command)
|
||||
"Manages your envvars file.
|
||||
|
||||
env [SUBCOMMAND]
|
||||
|
@ -38,7 +19,18 @@ on Linux).
|
|||
|
||||
To generate a file, run `doom env refresh`. If you'd like this file to be
|
||||
auto-reloaded when running `doom refresh`, run `doom env enable` instead (only
|
||||
needs to be run once).")
|
||||
needs to be run once)."
|
||||
(let ((default-directory doom-emacs-dir))
|
||||
(pcase command
|
||||
("clear"
|
||||
(unless (file-exists-p doom-env-file)
|
||||
(user-error! "%S does not exist to be cleared"
|
||||
(relpath doom-env-file)))
|
||||
(delete-file doom-env-file)
|
||||
(print! (success "Successfully deleted %S")
|
||||
(relpath doom-env-file)))
|
||||
(_
|
||||
(doom-reload-env-file 'force)))))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -86,12 +78,12 @@ default, on Linux, this is '$SHELL -ic /usr/bin/env'. Variables in
|
|||
`doom-env-ignored-vars' are removed."
|
||||
(when (or force-p (not (file-exists-p doom-env-file)))
|
||||
(with-temp-file doom-env-file
|
||||
(message "%s envvars file at %S"
|
||||
(print! (start "%s envvars file at %S")
|
||||
(if (file-exists-p doom-env-file)
|
||||
"Regenerating"
|
||||
"Generating")
|
||||
(abbreviate-file-name doom-env-file))
|
||||
(let ((process-environment doom-site-process-environment))
|
||||
(relpath doom-env-file doom-emacs-dir))
|
||||
(let ((process-environment doom--initial-process-environment))
|
||||
(insert
|
||||
(concat
|
||||
"# -*- mode: dotenv -*-\n"
|
||||
|
@ -111,25 +103,31 @@ default, on Linux, this is '$SHELL -ic /usr/bin/env'. Variables in
|
|||
"# To auto-regenerate this file when `doom reload` is run, use `doom env auto' or\n"
|
||||
"# set DOOMENV=1 in your shell environment/config.\n"
|
||||
"# ---------------------------------------------------------------------------\n\n"))
|
||||
(let ((shell-command-switch doom-env-switches))
|
||||
(message "Scraping env from '%s %s %s'"
|
||||
shell-file-name
|
||||
shell-command-switch
|
||||
doom-env-executable)
|
||||
(let ((shell-command-switch doom-env-switches)
|
||||
(error-buffer (get-buffer-create "*env errors*")))
|
||||
(print! (info "Scraping shell environment with '%s %s %s'")
|
||||
(filename shell-file-name)
|
||||
shell-command-switch
|
||||
(filename doom-env-executable))
|
||||
(save-excursion
|
||||
(insert (shell-command-to-string doom-env-executable)))
|
||||
;; Remove undesireable variables
|
||||
(while (re-search-forward "\n\\([^= \n]+\\)=" nil t)
|
||||
(save-excursion
|
||||
(let* ((valend (or (save-match-data
|
||||
(when (re-search-forward "^\\([^= ]+\\)=" nil t)
|
||||
(line-beginning-position)))
|
||||
(point-max)))
|
||||
(var (match-string 1))
|
||||
(value (buffer-substring-no-properties (point) (1- valend))))
|
||||
(when (cl-loop for regexp in doom-env-ignored-vars
|
||||
if (string-match-p regexp var)
|
||||
return t)
|
||||
(message "Ignoring %s" var)
|
||||
(delete-region (match-beginning 0) (1- valend))))))
|
||||
(print! (green "Envvar successfully generated")))))))
|
||||
(shell-command doom-env-executable (current-buffer) error-buffer))
|
||||
(print-group!
|
||||
(let ((errors (with-current-buffer error-buffer (buffer-string))))
|
||||
(unless (string-empty-p errors)
|
||||
(print! (info "Error output:\n\n%s") (indent 4 errors))))
|
||||
;; Remove undesireable variables
|
||||
(while (re-search-forward "\n\\([^= \n]+\\)=" nil t)
|
||||
(save-excursion
|
||||
(let* ((valend (or (save-match-data
|
||||
(when (re-search-forward "^\\([^= ]+\\)=" nil t)
|
||||
(line-beginning-position)))
|
||||
(point-max)))
|
||||
(var (match-string 1)))
|
||||
(when (cl-loop for regexp in doom-env-ignored-vars
|
||||
if (string-match-p regexp var)
|
||||
return t)
|
||||
(print! (info "Ignoring %s") var)
|
||||
(delete-region (match-beginning 0) (1- valend)))))))
|
||||
(print! (success "Successfully generated %S")
|
||||
(relpath doom-env-file doom-emacs-dir))
|
||||
t)))))
|
||||
|
|
|
@ -1,55 +1,47 @@
|
|||
;; -*- no-byte-compile: t; -*-
|
||||
;;; core/cli/packages.el
|
||||
|
||||
;;
|
||||
;;; Helpers
|
||||
|
||||
(defmacro doom--condition-case! (&rest body)
|
||||
`(condition-case-unless-debug e
|
||||
(progn ,@body)
|
||||
('user-error
|
||||
(print! (bold (red " NOTICE: %s")) e))
|
||||
('file-error
|
||||
(print! " %s\n %s"
|
||||
(bold (red "FILE ERROR: %s" (error-message-string e)))
|
||||
"Trying again...")
|
||||
(quiet! (doom-refresh-packages-maybe t))
|
||||
,@body)
|
||||
('error
|
||||
(print! (bold (red " %s %s\n %s"))
|
||||
"FATAL ERROR: " e
|
||||
"Run again with the -d flag for details"))))
|
||||
|
||||
(defsubst doom--ensure-autoloads-while (fn)
|
||||
(doom-reload-doom-autoloads)
|
||||
(when (funcall fn doom-auto-accept)
|
||||
(doom-reload-package-autoloads)))
|
||||
(defmacro doom--ensure-autoloads-while (&rest body)
|
||||
`(progn
|
||||
(doom-reload-core-autoloads)
|
||||
(when (progn ,@body)
|
||||
(doom-reload-package-autoloads 'force-p))
|
||||
t))
|
||||
|
||||
|
||||
;;
|
||||
;;; Dispatchers
|
||||
|
||||
(dispatcher! (install i)
|
||||
(doom--ensure-autoloads-while #'doom-packages-install)
|
||||
"Installs wanted packages that aren't installed.
|
||||
|
||||
Package management in Doom is declarative. A `package!' declaration in an
|
||||
enabled module or your private packages.el marks a package as 'wanted'.")
|
||||
|
||||
(dispatcher! (update u)
|
||||
(doom--ensure-autoloads-while #'doom-packages-update)
|
||||
(def-command! (update u) ()
|
||||
"Updates packages.
|
||||
|
||||
This excludes packages whose `package!' declaration contains a non-nil :freeze
|
||||
or :ignore property.")
|
||||
or :ignore property."
|
||||
(doom--ensure-autoloads-while
|
||||
(straight-check-all)
|
||||
(when (doom-packages-update doom-auto-accept)
|
||||
(doom-packages-rebuild doom-auto-accept)
|
||||
t)))
|
||||
|
||||
(dispatcher! (autoremove r)
|
||||
(doom--ensure-autoloads-while #'doom-packages-autoremove)
|
||||
"Removes packages that are no longer needed.
|
||||
(def-command! (rebuild b) ()
|
||||
"Rebuilds all installed packages.
|
||||
|
||||
This includes packages installed with 'M-x package-install' without an
|
||||
accompanying `package!' declaration in an enabled module's packages.el file or
|
||||
your private one.")
|
||||
This ensures that all needed files are symlinked from their package repo and
|
||||
their elisp files are byte-compiled."
|
||||
(doom--ensure-autoloads-while
|
||||
(doom-packages-rebuild doom-auto-accept (member "all" args))))
|
||||
|
||||
(def-command! (purge p) ()
|
||||
"Deletes any unused packages and package repos.
|
||||
|
||||
You should run this once in a while, as repos tend to build up over time."
|
||||
(doom--ensure-autoloads-while
|
||||
(straight-check-all)
|
||||
(doom-packages-purge doom-auto-accept)))
|
||||
|
||||
;; (def-command! rollback () ; TODO rollback
|
||||
;; "<Not implemented yet>"
|
||||
;; (user-error "Not implemented yet, sorry!"))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -63,153 +55,212 @@ declaration) or dependency thereof that hasn't already been.
|
|||
|
||||
Unless AUTO-ACCEPT-P is non-nil, this function will prompt for confirmation with
|
||||
a list of packages that will be installed."
|
||||
(print! "Looking for packages to install...")
|
||||
(let ((packages (doom-get-missing-packages)))
|
||||
(cond ((not packages)
|
||||
(print! (green "No packages to install!"))
|
||||
nil)
|
||||
(print! "> Installing & building packages...")
|
||||
(print-group!
|
||||
(let ((n 0))
|
||||
(dolist (package (hash-table-keys straight--recipe-cache))
|
||||
(straight--with-plist (gethash package straight--recipe-cache)
|
||||
(local-repo)
|
||||
(let ((existed-p (file-directory-p (straight--repos-dir package))))
|
||||
(condition-case-unless-debug e
|
||||
(and (straight-use-package (intern package) nil nil " ")
|
||||
(not existed-p)
|
||||
(file-directory-p (straight--repos-dir package))
|
||||
(cl-incf n))
|
||||
(error
|
||||
(signal 'doom-package-error
|
||||
(list e (straight--process-get-output))))))))
|
||||
(if (= n 0)
|
||||
(ignore (print! (success "No packages need to be installed")))
|
||||
(print! (success "Installed & built %d packages") n)
|
||||
t))))
|
||||
|
||||
((not (or auto-accept-p
|
||||
(y-or-n-p
|
||||
(format "%s packages will be installed:\n\n%s\n\nProceed?"
|
||||
(length packages)
|
||||
(mapconcat
|
||||
(lambda (pkg)
|
||||
(format "+ %s (%s)"
|
||||
(car pkg)
|
||||
(cond ((doom-package-different-recipe-p (car pkg))
|
||||
"new recipe")
|
||||
((doom-package-different-backend-p (car pkg))
|
||||
(format "%s -> %s"
|
||||
(doom-package-backend (car pkg) 'noerror)
|
||||
(doom-package-recipe-backend (car pkg) 'noerror)))
|
||||
((plist-get (cdr pkg) :recipe)
|
||||
"quelpa")
|
||||
("elpa"))))
|
||||
(cl-sort (cl-copy-list packages) #'string-lessp
|
||||
:key #'car)
|
||||
"\n")))))
|
||||
(user-error "Aborted!"))
|
||||
|
||||
((let (success)
|
||||
(doom-refresh-packages-maybe doom-debug-mode)
|
||||
(dolist (pkg packages)
|
||||
(print! "Installing %s" (car pkg))
|
||||
(doom--condition-case!
|
||||
(let ((result
|
||||
(or (and (doom-package-installed-p (car pkg))
|
||||
(not (doom-package-different-backend-p (car pkg)))
|
||||
(not (doom-package-different-recipe-p (car pkg)))
|
||||
'already-installed)
|
||||
(and (doom-install-package (car pkg) (cdr pkg))
|
||||
(setq success t)
|
||||
'success)
|
||||
'failure))
|
||||
(pin-label
|
||||
(and (plist-member (cdr pkg) :pin)
|
||||
(format " [pinned: %s]" (plist-get (cdr pkg) :pin)))))
|
||||
(print! "%s%s"
|
||||
(pcase result
|
||||
(`already-installed (dark (white "⚠ ALREADY INSTALLED")))
|
||||
(`success (green "✓ DONE"))
|
||||
(`failure (red "✕ FAILED")))
|
||||
(or pin-label "")))))
|
||||
(print! (bold (green "Finished!")))
|
||||
(when success
|
||||
(set-file-times doom-packages-dir)
|
||||
(doom-delete-autoloads-file doom-package-autoload-file))
|
||||
success)))))
|
||||
(defun doom-packages-rebuild (&optional auto-accept-p all)
|
||||
"(Re)build all packages."
|
||||
(print! (start "(Re)building %spackages...") (if all "all " ""))
|
||||
(print-group!
|
||||
(let ((n 0))
|
||||
(if all
|
||||
(let ((straight--packages-to-rebuild :all)
|
||||
(straight--packages-not-to-rebuild (make-hash-table :test #'equal)))
|
||||
(dolist (package (hash-table-keys straight--recipe-cache))
|
||||
(straight-use-package
|
||||
(intern package) nil (lambda (_) (cl-incf n) nil) " ")))
|
||||
(let ((straight-check-for-modifications '(find-when-checking)))
|
||||
(straight-check-all)
|
||||
(dolist (recipe (hash-table-values straight--recipe-cache))
|
||||
(straight--with-plist recipe (package local-repo no-build)
|
||||
(unless (or no-build (null local-repo))
|
||||
;; REVIEW We do these modification checks manually because
|
||||
;; Straight's checks seem to miss stale elc files. Need
|
||||
;; more tests to confirm this.
|
||||
(when (or (gethash package straight--cached-package-modifications)
|
||||
(file-newer-than-file-p (straight--repos-dir local-repo)
|
||||
(straight--build-dir package))
|
||||
(cl-loop for file
|
||||
in (doom-files-in (straight--build-dir package)
|
||||
:match "\\.el$"
|
||||
:full t)
|
||||
for elc-file = (byte-compile-dest-file file)
|
||||
if (and (file-exists-p elc-file)
|
||||
(file-newer-than-file-p file elc-file))
|
||||
return t))
|
||||
(print! (info "Rebuilding %s") package)
|
||||
;; REVIEW `straight-rebuild-package' alone wasn't enough. Why?
|
||||
(delete-directory (straight--build-dir package) 'recursive)
|
||||
(straight-rebuild-package package)
|
||||
(cl-incf n)))))))
|
||||
(if (= n 0)
|
||||
(ignore (print! (success "No packages need rebuilding")))
|
||||
(print! (success "Rebuilt %d package(s)" n))
|
||||
t))))
|
||||
|
||||
|
||||
(defun doom-packages-update (&optional auto-accept-p)
|
||||
"Updates packages.
|
||||
|
||||
Unless AUTO-ACCEPT-P is non-nil, this function will prompt for confirmation with
|
||||
a list of packages that will be updated."
|
||||
(print! "Looking for outdated packages...")
|
||||
(let ((packages (cl-sort (cl-copy-list (doom-get-outdated-packages)) #'string-lessp
|
||||
:key #'car)))
|
||||
(cond ((not packages)
|
||||
(print! (green "Everything is up-to-date"))
|
||||
nil)
|
||||
(print! (start "Scanning for outdated packages (this may take a while)..."))
|
||||
(print-group!
|
||||
;; REVIEW Does this fail gracefully enough? Is it error tolerant?
|
||||
;; TODO Add version-lock checks; don't want to spend all this effort on
|
||||
;; packages that shouldn't be updated
|
||||
(condition-case e
|
||||
(let (futures)
|
||||
(dolist (group (seq-partition (hash-table-values straight--repo-cache) 8))
|
||||
(push (async-start
|
||||
`(lambda ()
|
||||
(setq load-path ',load-path
|
||||
doom-modules ',doom-modules)
|
||||
(load ,(concat doom-core-dir "core.el"))
|
||||
(let (packages)
|
||||
(when (require 'straight nil t)
|
||||
(dolist (recipe ',group)
|
||||
(straight--with-plist recipe (package local-repo)
|
||||
(when (and local-repo (straight--repository-is-available-p recipe))
|
||||
(straight-fetch-package package)
|
||||
;; REVIEW Isn't there a better way to get this information? Maybe with `vc'?
|
||||
(let* ((default-directory (straight--repos-dir local-repo))
|
||||
(n (string-to-number
|
||||
(shell-command-to-string "git rev-list --right-only --count HEAD..@'{u}'")))
|
||||
(pretime
|
||||
(string-to-number
|
||||
(shell-command-to-string "git log -1 --format=%at HEAD")))
|
||||
(time
|
||||
(string-to-number
|
||||
(shell-command-to-string "git log -1 --format=%at FETCH_HEAD"))))
|
||||
(when (> n 0)
|
||||
(push (list n pretime time recipe)
|
||||
packages)))))))
|
||||
(nreverse packages))))
|
||||
futures))
|
||||
(let ((total (length futures))
|
||||
(futures (nreverse futures))
|
||||
(specs '(t)))
|
||||
(while futures
|
||||
(while (not (async-ready (car futures)))
|
||||
(sleep-for 2)
|
||||
(print! "."))
|
||||
(nconc specs (async-get (pop futures))))
|
||||
(terpri)
|
||||
(if-let (specs (delq nil (cdr specs)))
|
||||
(if (or auto-accept-p
|
||||
(y-or-n-p
|
||||
(format! "%s\n\nThere %s %d package%s available to update. Update them?"
|
||||
(mapconcat
|
||||
(lambda (spec)
|
||||
(cl-destructuring-bind (n pretime time recipe) spec
|
||||
(straight--with-plist recipe (package)
|
||||
(format! "+ %-33s %s commit(s) behind %s -> %s"
|
||||
(yellow package) (yellow n)
|
||||
(format-time-string "%Y%m%d" pretime)
|
||||
(format-time-string "%Y%m%d" time)))))
|
||||
specs
|
||||
"\n")
|
||||
(if (cdr specs) "are" "is")
|
||||
(length specs)
|
||||
(if (cdr specs) "s" ""))))
|
||||
(terpri)
|
||||
(dolist (spec specs t)
|
||||
(cl-destructuring-bind (n pretime time recipe) spec
|
||||
(straight--with-plist recipe (local-repo package)
|
||||
(let ((default-directory (straight--repos-dir local-repo)))
|
||||
(print! (start "Updating %S") package)
|
||||
;; HACK `straight' doesn't assume it would ever be used
|
||||
;; non-interactively, but here we are. If the repo is
|
||||
;; dirty, the command will lock up, waiting for
|
||||
;; interaction that will never come, so discard all local
|
||||
;; changes. Doom doesn't want you modifying those anyway.
|
||||
(and (straight--get-call "git" "reset" "--hard")
|
||||
(straight--get-call "git" "clean" "-ffd"))
|
||||
(straight-merge-package package)
|
||||
;; HACK `straight-rebuild-package' doesn't pick up that
|
||||
;; this package has changed, so we do it manually. Is
|
||||
;; there a better way?
|
||||
(run-hook-with-args 'straight-use-package-pre-build-functions package)
|
||||
(straight--build-package recipe " "))
|
||||
(with-current-buffer (straight--process-get-buffer)
|
||||
(with-silent-modifications
|
||||
(erase-buffer))))))
|
||||
(print! (info "Aborted update"))
|
||||
nil)
|
||||
(print! (success "No packages to update"))
|
||||
nil)))
|
||||
(error
|
||||
(message "Output:\n%s" (straight--process-get-output))
|
||||
(signal (car e) (error-message-string e))))))
|
||||
|
||||
((not (or auto-accept-p
|
||||
(y-or-n-p
|
||||
(format "%s packages will be updated:\n\n%s\n\nProceed?"
|
||||
(length packages)
|
||||
(let ((max-len
|
||||
(or (car (sort (mapcar (lambda (it) (length (symbol-name (car it)))) packages)
|
||||
#'>))
|
||||
10)))
|
||||
(mapconcat
|
||||
(lambda (pkg)
|
||||
(format (format "+ %%-%ds (%%s) %%-%ds -> %%s"
|
||||
(+ max-len 2) 14)
|
||||
(symbol-name (car pkg))
|
||||
(doom-package-backend (car pkg))
|
||||
(package-version-join (cadr pkg))
|
||||
(package-version-join (cl-caddr pkg))))
|
||||
packages
|
||||
"\n"))))))
|
||||
(user-error "Aborted!"))
|
||||
|
||||
((let (success)
|
||||
(dolist (pkg packages)
|
||||
(print! "Updating %s" (car pkg))
|
||||
(doom--condition-case!
|
||||
(print!
|
||||
(let ((result (doom-update-package (car pkg) t)))
|
||||
(when result (setq success t))
|
||||
(color (if result 'green 'red)
|
||||
(if result "✓ DONE" "✕ FAILED"))))))
|
||||
(print! (bold (green "Finished!")))
|
||||
(when success
|
||||
(set-file-times doom-packages-dir)
|
||||
(doom-delete-autoloads-file doom-package-autoload-file))
|
||||
success)))))
|
||||
(defun doom--packages-to-purge ()
|
||||
(let (builds repos)
|
||||
(dolist (name (straight--directory-files (straight--repos-dir)))
|
||||
(unless (straight--checkhash name straight--repo-cache)
|
||||
(push name repos)))
|
||||
(dolist (name (straight--directory-files (straight--build-dir)))
|
||||
(unless (gethash name straight--profile-cache)
|
||||
(push name builds)))
|
||||
(straight-prune-build-cache)
|
||||
(list builds repos)))
|
||||
|
||||
(defun doom-packages-autoremove (&optional auto-accept-p)
|
||||
"Auto-removes orphaned packages.
|
||||
(defun doom-packages-purge (&optional auto-accept-p)
|
||||
"Auto-removes orphaned packages and repos.
|
||||
|
||||
An orphaned package is a package that isn't a primary package (i.e. doesn't have
|
||||
a `package!' declaration) or isn't depended on by another primary package.
|
||||
|
||||
Unless AUTO-ACCEPT-P is non-nil, this function will prompt for confirmation with
|
||||
a list of packages that will be removed."
|
||||
(print! "Looking for orphaned packages...")
|
||||
(let ((packages (doom-get-orphaned-packages)))
|
||||
(cond ((not packages)
|
||||
(print! (green "No unused packages to remove"))
|
||||
nil)
|
||||
|
||||
((not
|
||||
(or auto-accept-p
|
||||
(y-or-n-p
|
||||
(format "%s packages will be deleted:\n\n%s\n\nProceed?"
|
||||
(length packages)
|
||||
(mapconcat
|
||||
(lambda (sym)
|
||||
(let ((old-backend (doom-package-backend sym 'noerror))
|
||||
(new-backend (doom-package-recipe-backend sym 'noerror)))
|
||||
(format "+ %s (%s)" sym
|
||||
(cond ((null new-backend)
|
||||
"removed")
|
||||
((eq old-backend new-backend)
|
||||
(symbol-name new-backend))
|
||||
((format "%s -> %s" old-backend new-backend))))))
|
||||
(sort (cl-copy-list packages) #'string-lessp)
|
||||
"\n")))))
|
||||
(user-error "Aborted!"))
|
||||
|
||||
((let (success)
|
||||
(dolist (pkg packages)
|
||||
(doom--condition-case!
|
||||
(let ((result (doom-delete-package pkg t)))
|
||||
(if result (setq success t))
|
||||
(print! (color (if result 'green 'red) "%s %s")
|
||||
(if result "✓ Removed" "✕ Failed to remove")
|
||||
pkg))))
|
||||
(print! (bold (green "Finished!")))
|
||||
(when success
|
||||
(set-file-times doom-packages-dir)
|
||||
(doom-delete-autoloads-file doom-package-autoload-file))
|
||||
success)))))
|
||||
(print! (start "Searching for orphaned packages..."))
|
||||
(cl-destructuring-bind (builds repos) (doom--packages-to-purge)
|
||||
(unless (bound-and-true-p package--initialized)
|
||||
(package-initialize))
|
||||
(print-group!
|
||||
(let ((packages (append builds (mapcar #'car package-alist) nil)))
|
||||
(if (not packages)
|
||||
(ignore (print! (success "No orphaned packages to purge")))
|
||||
(or auto-accept-p
|
||||
(y-or-n-p
|
||||
(format! "\n%s\n\n%d packages are orphaned. Purge them (for the Emperor)?"
|
||||
(mapconcat (lambda (pkgs)
|
||||
(mapconcat (lambda (p) (format " + %-20.20s" p))
|
||||
pkgs
|
||||
""))
|
||||
(seq-partition (cl-sort (copy-sequence packages) #'string-lessp)
|
||||
3)
|
||||
"\n")
|
||||
(length packages)))
|
||||
(user-error "Aborted"))
|
||||
(let ((n 0))
|
||||
(dolist (dir (append (mapcar #'straight--repos-dir repos)
|
||||
(mapcar #'straight--build-dir builds)))
|
||||
(print! (info "Deleting %S") (relpath dir (straight--dir)))
|
||||
(delete-directory dir 'recursive)
|
||||
(unless (file-directory-p dir)
|
||||
(cl-incf n)))
|
||||
(straight-prune-build-cache)
|
||||
(when (file-directory-p package-user-dir)
|
||||
(delete-directory package-user-dir t)
|
||||
t)
|
||||
(> n 0)))))))
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
;;; core/cli/patch-macos.el -*- lexical-binding: t; -*-
|
||||
|
||||
(dispatcher! (patch-macos)
|
||||
(doom-patch-macos (or (member "--undo" args)
|
||||
(member "-u" args))
|
||||
(doom--find-emacsapp-path))
|
||||
(def-command! patch-macos ()
|
||||
"Patches Emacs.app to respect your shell environment.
|
||||
|
||||
WARNING: This command is deprecated. Use 'doom env' instead.
|
||||
|
@ -30,7 +27,11 @@ It can be undone with the --undo or -u options.
|
|||
|
||||
Alternatively, you can install the exec-path-from-shell Emacs plugin, which will
|
||||
scrape your shell environment remotely, at startup. However, this can be slow
|
||||
depending on your shell configuration and isn't always reliable.")
|
||||
depending on your shell configuration and isn't always reliable."
|
||||
:hidden t
|
||||
(doom-patch-macos (or (member "--undo" args)
|
||||
(member "-u" args))
|
||||
(doom--find-emacsapp-path)))
|
||||
|
||||
|
||||
;;
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
;;; core/cli/quickstart.el -*- lexical-binding: t; -*-
|
||||
|
||||
(dispatcher! (quickstart qs) (apply #'doom-quickstart args)
|
||||
"Guides you through setting up Doom for first time use.
|
||||
(def-command! quickstart (&rest args) ; DEPRECATED
|
||||
""
|
||||
:hidden t
|
||||
(apply #'doom-cli-install args))
|
||||
|
||||
(def-command! (install i) ()
|
||||
"A wizard for installing Doom for the first time.
|
||||
|
||||
This command does the following:
|
||||
|
||||
|
@ -17,89 +22,80 @@ This command is idempotent and safe to reuse.
|
|||
The location of DOOMDIR can be changed with the -p option, or by setting the
|
||||
DOOMDIR environment variable. e.g.
|
||||
|
||||
doom -p ~/.config/doom quickstart
|
||||
DOOMDIR=~/.config/doom doom quickstart
|
||||
doom -p ~/.config/doom install
|
||||
DOOMDIR=~/.config/doom doom install
|
||||
|
||||
Quickstart understands the following switches:
|
||||
install understands the following switches:
|
||||
|
||||
--no-config Don't create DOOMDIR or dummy files therein
|
||||
--no-install Don't auto-install packages
|
||||
--no-env Don't generate an envvars file (see `doom help env`)
|
||||
--no-fonts Don't install (or prompt to install) all-the-icons fonts")
|
||||
|
||||
|
||||
;;
|
||||
;; Library
|
||||
|
||||
(defun doom-quickstart (&rest args)
|
||||
"Quickly deploy a private module and setup Doom.
|
||||
|
||||
This deploys a barebones config to `doom-private-dir', installs all missing
|
||||
packages, prompts to install all-the-icons fonts, generates an env file and
|
||||
regenerates the autoloads file."
|
||||
;; Create `doom-private-dir'
|
||||
(let ((short-private-dir (abbreviate-file-name doom-private-dir)))
|
||||
--no-fonts Don't install (or prompt to install) all-the-icons fonts"
|
||||
(print! (green "Installing Doom Emacs!\n"))
|
||||
(let ((default-directory (doom-dir "~")))
|
||||
;; Create `doom-private-dir'
|
||||
(if (member "--no-config" args)
|
||||
(print! (yellow "Not copying private config template, as requested"))
|
||||
(print! "Creating %s" short-private-dir)
|
||||
(make-directory doom-private-dir t)
|
||||
(print! (green "Done!"))
|
||||
(print! (warn "Not copying private config template, as requested"))
|
||||
(print! "> Creating %s" (relpath doom-private-dir))
|
||||
(make-directory doom-private-dir 'parents)
|
||||
(print! (success "Created %s") (relpath doom-private-dir))
|
||||
|
||||
;; Create init.el, config.el & packages.el
|
||||
(dolist (file (list (cons "init.el"
|
||||
(lambda ()
|
||||
(insert-file-contents (expand-file-name "init.example.el" doom-emacs-dir))))
|
||||
(cons "config.el"
|
||||
(lambda ()
|
||||
(insert (format ";;; %sconfig.el -*- lexical-binding: t; -*-\n\n"
|
||||
short-private-dir)
|
||||
";; Place your private configuration here\n")))
|
||||
(cons "packages.el"
|
||||
(lambda ()
|
||||
(insert (format ";; -*- no-byte-compile: t; -*-\n;;; %spackages.el\n\n"
|
||||
short-private-dir)
|
||||
";;; Examples:\n"
|
||||
";; (package! some-package)\n"
|
||||
";; (package! another-package :recipe (:fetcher github :repo \"username/repo\"))\n"
|
||||
";; (package! builtin-package :disable t)\n")))))
|
||||
(cl-destructuring-bind (path . fn) file
|
||||
(if (file-exists-p! path doom-private-dir)
|
||||
(print! "%s already exists, skipping" path)
|
||||
(print! "Creating %s%s" short-private-dir path)
|
||||
(with-temp-file (expand-file-name path doom-private-dir)
|
||||
(funcall fn))
|
||||
(print! (green "Done!")))))))
|
||||
(mapc (lambda (file)
|
||||
(cl-destructuring-bind (filename . fn) file
|
||||
(if (file-exists-p! filename doom-private-dir)
|
||||
(print! (warn "%s already exists, skipping") filename)
|
||||
(print! (info "Creating %s%s") (relpath doom-private-dir) filename)
|
||||
(with-temp-file (doom-path doom-private-dir filename)
|
||||
(funcall fn))
|
||||
(print! (success "Done!")))))
|
||||
'(("init.el" .
|
||||
(lambda ()
|
||||
(insert-file-contents (doom-dir "init.example.el"))))
|
||||
("config.el" .
|
||||
(lambda ()
|
||||
(insert! ";;; %sconfig.el -*- lexical-binding: t; -*-\n\n"
|
||||
";; Place your private configuration here\n"
|
||||
((relpath doom-private-dir)))))
|
||||
("packages.el" .
|
||||
(lambda ()
|
||||
(insert! ";; -*- no-byte-compile: t; -*-\n;;; %spackages.el\n\n"
|
||||
";;; Examples:\n"
|
||||
";; (package! some-package)\n"
|
||||
";; (package! another-package :recipe (:fetcher github :repo \"username/repo\"))\n"
|
||||
";; (package! builtin-package :disable t)\n"
|
||||
((relpath doom-private-dir))))))))
|
||||
|
||||
;; In case no init.el was present the first time `doom-initialize-modules' was
|
||||
;; called in core.el (e.g. on first install)
|
||||
(doom-initialize-packages 'force-p)
|
||||
;; In case no init.el was present the first time `doom-initialize-modules' was
|
||||
;; called in core.el (e.g. on first install)
|
||||
(doom-initialize-packages 'force-p)
|
||||
|
||||
;; Ask if Emacs.app should be patched
|
||||
(if (member "--no-env" args)
|
||||
(print! (yellow "Not generating envvars file, as requested"))
|
||||
(when (or doom-auto-accept
|
||||
(y-or-n-p "Generate an env file? (see `doom help env` for details)"))
|
||||
(doom-reload-env-file 'force-p)))
|
||||
;; Ask if Emacs.app should be patched
|
||||
(if (member "--no-env" args)
|
||||
(print! (warn "- Not generating envvars file, as requested"))
|
||||
(when (or doom-auto-accept
|
||||
(y-or-n-p "Generate an env file? (see `doom help env` for details)"))
|
||||
(doom-reload-env-file 'force-p)))
|
||||
|
||||
;; Install Doom packages
|
||||
(if (member "--no-install" args)
|
||||
(print! (yellow "Not installing plugins, as requested"))
|
||||
(print! "Installing plugins")
|
||||
(doom-packages-install doom-auto-accept))
|
||||
;; Install Doom packages
|
||||
(if (member "--no-install" args)
|
||||
(print! (warn "- Not installing plugins, as requested"))
|
||||
(print! "Installing plugins")
|
||||
(doom-packages-install doom-auto-accept))
|
||||
|
||||
(print! "Regenerating autoloads files")
|
||||
(doom-reload-autoloads nil 'force-p)
|
||||
(print! "Regenerating autoloads files")
|
||||
(doom-reload-autoloads nil 'force-p)
|
||||
|
||||
(if (member "--no-fonts" args)
|
||||
(print! (yellow "Not installing fonts, as requested"))
|
||||
(when (or doom-auto-accept
|
||||
(y-or-n-p "Download and install all-the-icon's fonts?"))
|
||||
(require 'all-the-icons)
|
||||
(let ((window-system (cond (IS-MAC 'ns)
|
||||
(IS-LINUX 'x))))
|
||||
(all-the-icons-install-fonts 'yes))))
|
||||
(if (member "--no-fonts" args)
|
||||
(print! (warn "- Not installing fonts, as requested"))
|
||||
(when (or doom-auto-accept
|
||||
(y-or-n-p "Download and install all-the-icon's fonts?"))
|
||||
(require 'all-the-icons)
|
||||
(let ((window-system (cond (IS-MAC 'ns)
|
||||
(IS-LINUX 'x))))
|
||||
(all-the-icons-install-fonts 'yes))))
|
||||
|
||||
(print! (bold (green "\nFinished! Doom is ready to go!\n")))
|
||||
(with-temp-buffer
|
||||
(doom-template-insert "QUICKSTART_INTRO")
|
||||
(print! (buffer-string))))
|
||||
(print! (success "\nFinished! Doom is ready to go!\n"))
|
||||
(with-temp-buffer
|
||||
(doom-template-insert "QUICKSTART_INTRO")
|
||||
(print! (buffer-string)))))
|
||||
|
|
108
core/cli/test.el
108
core/cli/test.el
|
@ -1,67 +1,73 @@
|
|||
;;; core/cli/test.el -*- lexical-binding: t; -*-
|
||||
|
||||
(dispatcher! test (doom-run-tests args)
|
||||
(def-command! test ()
|
||||
"Run Doom unit tests.")
|
||||
|
||||
|
||||
;;
|
||||
;; Library
|
||||
;;; Library
|
||||
|
||||
(defun doom-run-tests (&optional modules)
|
||||
"Run all loaded tests, specified by MODULES (a list of module cons cells) or
|
||||
command line args following a double dash (each arg should be in the
|
||||
'module/submodule' format).
|
||||
(defun doom-run-tests ()
|
||||
"Discover and load test files, then run all defined suites.
|
||||
|
||||
If neither is available, run all tests in all enabled modules."
|
||||
;; Core libraries aren't fully loaded in a noninteractive session, so we
|
||||
;; reload it with `noninteractive' set to nil to force them to.
|
||||
(let* ((noninteractive t)
|
||||
(doom-modules (doom-modules)))
|
||||
(quiet! (doom-reload-autoloads))
|
||||
(let ((target-paths
|
||||
;; Convert targets into a list of string paths, pointing to the root
|
||||
;; directory of modules
|
||||
(cond ((stringp (car modules)) ; command line
|
||||
(save-match-data
|
||||
(cl-loop for arg in modules
|
||||
if (string= arg ":core") collect doom-core-dir
|
||||
else if (string-match-p "/" arg)
|
||||
nconc (mapcar (apply-partially #'expand-file-name arg)
|
||||
doom-modules-dirs)
|
||||
else
|
||||
nconc (cl-loop for dir in doom-modules-dirs
|
||||
for path = (expand-file-name arg dir)
|
||||
if (file-directory-p path)
|
||||
nconc (doom-files-in path :type 'dirs :depth 1 :full t :sort nil))
|
||||
finally do (setq argv nil))))
|
||||
|
||||
(modules ; cons-cells given to MODULES
|
||||
(cl-loop for (module . submodule) in modules
|
||||
if (doom-module-locate-path module submodule)
|
||||
collect it))
|
||||
|
||||
((append (list doom-core-dir)
|
||||
(doom-module-load-path))))))
|
||||
;; Load all the unit test files...
|
||||
(require 'buttercup)
|
||||
(mapc (lambda (file) (load file :noerror (not doom-debug-mode)))
|
||||
(doom-files-in (mapcar (apply-partially #'expand-file-name "test/")
|
||||
target-paths)
|
||||
:match "\\.el$" :full t))
|
||||
;; ... then run them
|
||||
(when doom-debug-mode
|
||||
(setq buttercup-stack-frame-style 'pretty))
|
||||
(let ((split-width-threshold 0)
|
||||
(split-height-threshold 0)
|
||||
(window-min-width 0)
|
||||
(window-min-height 0))
|
||||
(buttercup-run)))))
|
||||
Takes directories as command line arguments, defaulting to the
|
||||
current directory."
|
||||
(let ((dirs nil)
|
||||
(patterns nil)
|
||||
(args command-line-args-left)
|
||||
(doom-modules (doom-modules)))
|
||||
(doom-initialize-autoloads doom-autoload-file)
|
||||
(doom-initialize-autoloads doom-package-autoload-file)
|
||||
(while args
|
||||
(cond
|
||||
;; ((member (car args) '("--traceback"))
|
||||
;; (when (not (cdr args))
|
||||
;; (error "Option requires argument: %s" (car args)))
|
||||
;; ;; Make sure it's a valid style by trying to format a dummy
|
||||
;; ;; frame with it
|
||||
;; (buttercup--format-stack-frame '(t myfun 1 2) (intern (cadr args)))
|
||||
;; (setq buttercup-stack-frame-style (intern (cadr args)))
|
||||
;; (setq args (cddr args)))
|
||||
;; ((member (car args) '("-p" "--pattern"))
|
||||
;; (when (not (cdr args))
|
||||
;; (error "Option requires argument: %s" (car args)))
|
||||
;; (push (cadr args) patterns)
|
||||
;; (setq args (cddr args)))
|
||||
;; ((member (car args) '("-c" "--no-color"))
|
||||
;; (setq buttercup-color nil)
|
||||
;; (setq args (cdr args)))
|
||||
(t
|
||||
(push (car args) dirs)
|
||||
(setq args (cdr args)))))
|
||||
(setq command-line-args-left nil)
|
||||
(dolist (dir (or dirs '(".")))
|
||||
(setq dir (if (string= dir "core")
|
||||
doom-core-dir
|
||||
(expand-file-name dir doom-modules-dir)))
|
||||
(let ((test-dir (expand-file-name "test" dir)))
|
||||
(when (or (string= dir doom-core-dir)
|
||||
(cl-destructuring-bind (category . module)
|
||||
(or (doom-module-from-path dir)
|
||||
(cons nil nil))
|
||||
(and category module (doom-module-p category module))))
|
||||
(dolist (file (nreverse (doom-glob test-dir "test-*.el")))
|
||||
(when (doom-file-cookie-p file)
|
||||
(load file nil t))))))
|
||||
(when patterns
|
||||
(dolist (spec (buttercup--specs buttercup-suites))
|
||||
(let ((spec-full-name (buttercup-spec-full-name spec)))
|
||||
(unless (cl-dolist (p patterns)
|
||||
(when (string-match p spec-full-name)
|
||||
(cl-return t)))
|
||||
(setf (buttercup-spec-function spec)
|
||||
(lambda () (signal 'buttercup-pending "SKIPPED")))))))
|
||||
(buttercup-run)))
|
||||
|
||||
|
||||
;;
|
||||
;; Test library
|
||||
|
||||
(defmacro insert! (&rest text)
|
||||
(defmacro insert!! (&rest text)
|
||||
"Insert TEXT in buffer, then move cursor to last {0} marker."
|
||||
`(progn
|
||||
(insert ,@text)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
;;; core/cli/upgrade.el -*- lexical-binding: t; -*-
|
||||
|
||||
(dispatcher! (upgrade up) (doom-upgrade)
|
||||
"Checks out the latest Doom on this branch.
|
||||
(def-command! (upgrade up) ()
|
||||
"Updates Doom and packages.
|
||||
|
||||
Doing so is equivalent to:
|
||||
|
||||
|
@ -9,7 +9,8 @@ Doing so is equivalent to:
|
|||
git pull
|
||||
bin/doom clean
|
||||
bin/doom refresh
|
||||
bin/doom update")
|
||||
bin/doom update"
|
||||
(doom-upgrade))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -75,7 +76,7 @@ Doing so is equivalent to:
|
|||
(buffer-string)))
|
||||
(unless (equal (vc-git-working-revision doom-emacs-dir) rev)
|
||||
(error "Failed to checkout latest commit.\n\n%s" (buffer-string))))
|
||||
(doom-refresh 'force-p)
|
||||
(doom-cli-refresh 'force-p)
|
||||
(when (doom-packages-update doom-auto-accept)
|
||||
(doom-reload-package-autoloads))
|
||||
(message "Done! Please restart Emacs for changes to take effect")))
|
||||
|
|
286
core/core-cli.el
286
core/core-cli.el
|
@ -1,54 +1,82 @@
|
|||
;;; -*- lexical-binding: t; no-byte-compile: t; -*-
|
||||
|
||||
;; 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).
|
||||
(load! "autoload/debug")
|
||||
(load! "autoload/files")
|
||||
(load! "autoload/message")
|
||||
(load! "autoload/packages")
|
||||
|
||||
|
||||
;;
|
||||
;; Dispatcher API
|
||||
|
||||
(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'.")
|
||||
|
||||
(defconst doom--dispatch-command-alist ())
|
||||
(defconst doom--dispatch-alias-alist ())
|
||||
(defvar doom-cli-pre-execute-hook nil
|
||||
"TODO")
|
||||
(defvar doom-cli-post-execute-hook nil
|
||||
"TODO")
|
||||
|
||||
(defvar doom--cli-commands (make-hash-table :test 'equal))
|
||||
(defvar doom--cli-groups (make-hash-table :test 'equal))
|
||||
(defvar doom--cli-group nil)
|
||||
|
||||
|
||||
;;
|
||||
;;; Dispatcher API
|
||||
|
||||
(defun doom-file-cookie-p (file)
|
||||
(with-temp-buffer
|
||||
(insert-file-contents-literally file nil 0 256)
|
||||
(if (and (re-search-forward "^;;;###if " nil t)
|
||||
(<= (line-number-at-pos) 3))
|
||||
(let ((load-file-name file))
|
||||
(eval (sexp-at-point) t))
|
||||
t)))
|
||||
|
||||
(defun doom--dispatch-command (command)
|
||||
(when (symbolp command)
|
||||
(setq command (symbol-name command)))
|
||||
(cl-check-type command string)
|
||||
(intern-soft
|
||||
(format "doom-cli-%s"
|
||||
(if (gethash command doom--cli-commands)
|
||||
command
|
||||
(cl-loop for key
|
||||
being the hash-keys in doom--cli-commands
|
||||
for aliases = (plist-get (gethash key doom--cli-commands) :aliases)
|
||||
if (member command aliases)
|
||||
return key)))))
|
||||
|
||||
(defun doom--dispatch-format (desc &optional short)
|
||||
(with-temp-buffer
|
||||
(let ((fill-column 72))
|
||||
(insert desc)
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "\n\n[^ \n]" nil t)
|
||||
(fill-paragraph)))
|
||||
(save-excursion
|
||||
(insert desc)
|
||||
(while (re-search-backward "\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)))))
|
||||
(buffer-substring (line-beginning-position)
|
||||
(line-end-position)))))
|
||||
|
||||
(defun doom--dispatch-help (&optional command desc &rest args)
|
||||
"Display help documentation for a dispatcher command. If COMMAND and DESC are
|
||||
(defun doom--dispatch-help-1 (command)
|
||||
(cl-destructuring-bind (&key aliases _group)
|
||||
(gethash command doom--cli-commands)
|
||||
(print! "%-11s\t%s\t%s"
|
||||
command (if aliases (string-join aliases ",") "")
|
||||
(doom--dispatch-format
|
||||
(documentation (doom--dispatch-command command))
|
||||
t))))
|
||||
|
||||
(defun doom--dispatch-help (&optional fn &rest args)
|
||||
"Display help documentation for a dispatcher command. If fn and DESC are
|
||||
omitted, show all available commands, their aliases and brief descriptions."
|
||||
(if command
|
||||
(princ (doom--dispatch-format desc))
|
||||
(print! (bold "%-10s\t%s\t%s" "Command:" "Alias" "Description"))
|
||||
(dolist (spec (cl-sort doom--dispatch-command-alist #'string-lessp
|
||||
:key #'car))
|
||||
(cl-destructuring-bind (command &key desc _body) spec
|
||||
(let ((aliases (cl-loop for (alias . cmd) in doom--dispatch-alias-alist
|
||||
if (eq cmd command)
|
||||
collect (symbol-name alias))))
|
||||
(print! " %-10s\t%s\t%s"
|
||||
command (if aliases (string-join aliases ",") "")
|
||||
(doom--dispatch-format desc t)))))))
|
||||
(if fn
|
||||
(princ (documentation fn))
|
||||
(print! (bold "%-11s\t%s\t%s" "Command:" "Alias" "Description"))
|
||||
(print-group!
|
||||
(dolist (group (seq-group-by (lambda (key) (plist-get (gethash key doom--cli-commands) :group))
|
||||
(hash-table-keys doom--cli-commands)))
|
||||
(if (null (car group))
|
||||
(mapc #'doom--dispatch-help-1 (cdr group))
|
||||
(print! "%-30s\t%s" (bold (car group)) (gethash (car group) doom--cli-groups))
|
||||
(print-group!
|
||||
(mapc #'doom--dispatch-help-1 (cdr group))))
|
||||
(terpri)))))
|
||||
|
||||
(defun doom-dispatch (cmd args &optional show-help)
|
||||
"Parses ARGS and invokes a dispatcher.
|
||||
|
@ -59,17 +87,31 @@ If SHOW-HELP is non-nil, show the documentation for said dispatcher."
|
|||
(when args
|
||||
(setq cmd (car args)
|
||||
args (cdr args))))
|
||||
(cl-destructuring-bind (command &key desc body)
|
||||
(let ((sym (intern cmd)))
|
||||
(or (assq sym doom--dispatch-command-alist)
|
||||
(assq (cdr (assq sym doom--dispatch-alias-alist))
|
||||
doom--dispatch-command-alist)
|
||||
(user-error "Invalid command: %s" sym)))
|
||||
(let ((fn (doom--dispatch-command cmd)))
|
||||
(unless (fboundp fn)
|
||||
(user-error "%s is not any command *I* know!" fn))
|
||||
(if show-help
|
||||
(apply #'doom--dispatch-help command desc args)
|
||||
(funcall body args))))
|
||||
(doom--dispatch-help fn args)
|
||||
(let ((start-time (current-time)))
|
||||
(run-hooks 'doom-cli-pre-execute-hook)
|
||||
(when-let (ret (apply fn args))
|
||||
(print!
|
||||
"\n%s"
|
||||
(success "Finished! (%.4fs)"
|
||||
(float-time
|
||||
(time-subtract (current-time)
|
||||
start-time))))
|
||||
(run-hooks 'doom-cli-post-execute-hook)
|
||||
ret)))))
|
||||
|
||||
(defmacro dispatcher! (command form &optional docstring)
|
||||
(defmacro def-command-group! (name docstring &rest body)
|
||||
"TODO"
|
||||
(declare (indent defun) (doc-string 2))
|
||||
`(let ((doom--cli-group ,name))
|
||||
(puthash doom--cli-group ,docstring doom--cli-groups)
|
||||
,@body))
|
||||
|
||||
(defmacro def-command! (names arglist docstring &rest body)
|
||||
"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
|
||||
|
@ -77,79 +119,38 @@ bin/doom help.
|
|||
|
||||
BODY will be run when this dispatcher is called."
|
||||
(declare (indent defun) (doc-string 3))
|
||||
(cl-destructuring-bind (cmd &rest aliases)
|
||||
(doom-enlist command)
|
||||
(let* ((names (mapcar #'symbol-name (doom-enlist names)))
|
||||
(fn (intern (format "doom-cli-%s" (car names))))
|
||||
(plist (cl-loop while (keywordp (car body))
|
||||
collect (pop body)
|
||||
collect (pop body))))
|
||||
(macroexp-progn
|
||||
(append
|
||||
(when aliases
|
||||
`((dolist (alias ',aliases)
|
||||
(setf (alist-get alias doom--dispatch-alias-alist) ',cmd))))
|
||||
`((setf (alist-get ',cmd doom--dispatch-command-alist)
|
||||
(list :desc ,docstring
|
||||
:body (lambda (args) (ignore args) ,form))))))))
|
||||
(reverse
|
||||
`((unless ,(plist-get plist :hidden)
|
||||
(let ((plist ',plist))
|
||||
(setq plist (plist-put plist :aliases ',(cdr names)))
|
||||
(unless (or (plist-member plist :group)
|
||||
(null doom--cli-group))
|
||||
(plist-put plist :group doom--cli-group))
|
||||
(puthash ,(car names) plist doom--cli-commands)))
|
||||
(defun ,fn ,arglist
|
||||
,docstring
|
||||
,@body))))))
|
||||
|
||||
|
||||
;;
|
||||
;; Dummy dispatch commands
|
||||
;;; Dispatch commands
|
||||
|
||||
;; These are handled by bin/doom, except we still want 'help CMD' to print out
|
||||
;; documentation for them, so...
|
||||
|
||||
(dispatcher! run :noop
|
||||
"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
|
||||
|
||||
WARNING: this command exists for convenience and testing. Doom will suffer
|
||||
additional overhead by being started this way. For the best performance, it is
|
||||
best to run Doom out of ~/.emacs.d and ~/.doom.d.")
|
||||
|
||||
(dispatcher! (doctor doc) :noop
|
||||
"Checks for issues with your environment & Doom config.
|
||||
|
||||
Use the doctor to diagnose common problems or list missing dependencies in
|
||||
enabled modules.")
|
||||
|
||||
(dispatcher! (help h) :noop
|
||||
"Look up additional information about a command.")
|
||||
;; 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).
|
||||
(load! "autoload/format")
|
||||
(load! "autoload/packages")
|
||||
|
||||
|
||||
;;
|
||||
;; Real dispatch commands
|
||||
|
||||
(load! "cli/autoloads")
|
||||
(load! "cli/byte-compile")
|
||||
(load! "cli/debug")
|
||||
(load! "cli/env")
|
||||
(load! "cli/packages")
|
||||
(load! "cli/patch-macos")
|
||||
(load! "cli/quickstart")
|
||||
(load! "cli/upgrade")
|
||||
(load! "cli/test")
|
||||
|
||||
|
||||
;;
|
||||
(defun doom-refresh (&optional force-p)
|
||||
"Ensure Doom is in a working state by checking autoloads and packages, and
|
||||
recompiling any changed compiled files. This is the shotgun solution to most
|
||||
problems with doom."
|
||||
(when (getenv "DOOMENV")
|
||||
(doom-reload-env-file 'force))
|
||||
(doom-reload-doom-autoloads force-p)
|
||||
(unwind-protect
|
||||
(progn
|
||||
(ignore-errors
|
||||
(doom-packages-autoremove doom-auto-accept))
|
||||
(ignore-errors
|
||||
(doom-packages-install doom-auto-accept)))
|
||||
(doom-reload-package-autoloads force-p)
|
||||
(doom-byte-compile nil 'recompile)))
|
||||
|
||||
(dispatcher! (refresh re) (doom-refresh 'force)
|
||||
"Refresh Doom.
|
||||
;; Load all of our subcommands
|
||||
(def-command! (refresh re) (&optional force-p)
|
||||
"Ensure Doom is properly set up.
|
||||
|
||||
This is the equivalent of running autoremove, install, autoloads, then
|
||||
recompile. Run this whenever you:
|
||||
|
@ -161,7 +162,68 @@ recompile. Run this whenever you:
|
|||
|
||||
It will ensure that unneeded packages are removed, all needed packages are
|
||||
installed, autoloads files are up-to-date and no byte-compiled files have gone
|
||||
stale.")
|
||||
stale."
|
||||
(print! (green "Initiating a refresh of Doom Emacs...\n"))
|
||||
(let (success)
|
||||
(when (file-exists-p doom-env-file)
|
||||
(doom-reload-env-file 'force))
|
||||
(doom-reload-core-autoloads force-p)
|
||||
(unwind-protect
|
||||
(progn
|
||||
(and (doom-packages-install doom-auto-accept)
|
||||
(setq success t))
|
||||
(and (doom-packages-rebuild doom-auto-accept)
|
||||
(setq success t))
|
||||
(and (doom-packages-purge doom-auto-accept)
|
||||
(setq success t)))
|
||||
(doom-reload-package-autoloads (or success force-p))
|
||||
(doom-byte-compile nil 'recompile))
|
||||
t))
|
||||
|
||||
|
||||
;; Load all of our subcommands
|
||||
(load! "cli/quickstart")
|
||||
|
||||
(def-command-group! "Diagnostics"
|
||||
"For troubleshooting and diagnostics"
|
||||
(def-command! (doctor doc) ()
|
||||
"Checks for issues with your environment & Doom config.
|
||||
|
||||
Use the doctor to diagnose common problems or list missing dependencies in
|
||||
enabled modules.")
|
||||
|
||||
(load! "cli/debug")
|
||||
(load! "cli/test"))
|
||||
|
||||
(def-command-group! "Maintenance"
|
||||
"For managing your config and packages"
|
||||
(load! "cli/env")
|
||||
(load! "cli/upgrade")
|
||||
(load! "cli/packages")
|
||||
(load! "cli/autoloads")
|
||||
(load! "cli/patch-macos"))
|
||||
|
||||
(def-command-group! "Byte compilation"
|
||||
"For byte-compiling Doom and your config"
|
||||
(load! "cli/byte-compile"))
|
||||
|
||||
(def-command-group! "Utilities"
|
||||
"Conveniences for interacting with Doom externally"
|
||||
(def-command! 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
|
||||
|
||||
WARNING: this command exists for convenience and testing. Doom will suffer
|
||||
additional overhead by being started this way. For the best performance, it is
|
||||
best to run Doom out of ~/.emacs.d and ~/.doom.d.")
|
||||
|
||||
;; (load! "cli/batch")
|
||||
;; (load! "cli/org")
|
||||
)
|
||||
|
||||
(provide 'core-cli)
|
||||
;;; core-cli.el ends here
|
||||
|
|
|
@ -11,9 +11,6 @@
|
|||
doom-modules-dir)
|
||||
"A list of module root directories. Order determines priority.")
|
||||
|
||||
(defvar doom-inhibit-module-warnings (not noninteractive)
|
||||
"If non-nil, don't emit deprecated or missing module warnings at startup.")
|
||||
|
||||
(defconst doom-obsolete-modules
|
||||
'((:feature (version-control (:emacs vc) (:ui vc-gutter))
|
||||
(spellcheck (:tools flyspell))
|
||||
|
@ -50,14 +47,10 @@ syntax-checker modules obsolete. e.g. If :feature version-control is found in
|
|||
your `doom!' block, a warning is emitted before replacing it with :emacs vc and
|
||||
:ui vc-gutter.")
|
||||
|
||||
(defvar doom--current-module nil)
|
||||
(defvar doom--current-flags nil)
|
||||
(defvar doom--modules-cache ())
|
||||
(defvar doom-inhibit-module-warnings (not noninteractive)
|
||||
"If non-nil, don't emit deprecated or missing module warnings at startup.")
|
||||
|
||||
|
||||
;;
|
||||
;;; Custom hooks
|
||||
|
||||
(defvar doom-before-init-modules-hook nil
|
||||
"A list of hooks to run before Doom's modules' config.el files are loaded, but
|
||||
after their init.el files are loaded.")
|
||||
|
@ -68,8 +61,8 @@ before the user's private module.")
|
|||
|
||||
(defvaralias 'doom-after-init-modules-hook 'after-init-hook)
|
||||
|
||||
(define-obsolete-variable-alias 'doom-post-init-hook 'doom-init-modules-hook "2.1.0")
|
||||
(define-obsolete-variable-alias 'doom-init-hook 'doom-before-init-modules-hook "2.1.0")
|
||||
(defvar doom--current-module nil)
|
||||
(defvar doom--current-flags nil)
|
||||
|
||||
|
||||
;;
|
||||
|
@ -79,27 +72,26 @@ before the user's private module.")
|
|||
"Loads the init.el in `doom-private-dir' and sets up hooks for a healthy
|
||||
session of Dooming. Will noop if used more than once, unless FORCE-P is
|
||||
non-nil."
|
||||
(when (and (or force-p
|
||||
(not doom-init-modules-p))
|
||||
(not (setq doom-modules nil))
|
||||
(load! "init" doom-private-dir t))
|
||||
(setq doom-init-modules-p t)
|
||||
(unless (hash-table-p doom-modules)
|
||||
(setq doom-modules (make-hash-table :test 'equal)))
|
||||
(maphash (lambda (key plist)
|
||||
(let ((doom--current-module key)
|
||||
(doom--current-flags (plist-get plist :flags)))
|
||||
(load! "init" (plist-get plist :path) t)))
|
||||
doom-modules)
|
||||
(run-hook-wrapped 'doom-before-init-modules-hook #'doom-try-run-hook)
|
||||
(unless noninteractive
|
||||
(maphash (lambda (key plist)
|
||||
(let ((doom--current-module key)
|
||||
(doom--current-flags (plist-get plist :flags)))
|
||||
(load! "config" (plist-get plist :path) t)))
|
||||
doom-modules)
|
||||
(run-hook-wrapped 'doom-init-modules-hook #'doom-try-run-hook)
|
||||
(load! "config" doom-private-dir t))))
|
||||
(when (or force-p (not doom-init-modules-p))
|
||||
(setq doom-init-modules-p t
|
||||
doom-modules nil)
|
||||
(when (load! "init" doom-private-dir t)
|
||||
(when doom-modules
|
||||
(maphash (lambda (key plist)
|
||||
(let ((doom--current-module key)
|
||||
(doom--current-flags (plist-get plist :flags)))
|
||||
(load! "init" (plist-get plist :path) t)))
|
||||
doom-modules))
|
||||
(run-hook-wrapped 'doom-before-init-modules-hook #'doom-try-run-hook)
|
||||
(unless noninteractive
|
||||
(when doom-modules
|
||||
(maphash (lambda (key plist)
|
||||
(let ((doom--current-module key)
|
||||
(doom--current-flags (plist-get plist :flags)))
|
||||
(load! "config" (plist-get plist :path) t)))
|
||||
doom-modules))
|
||||
(run-hook-wrapped 'doom-init-modules-hook #'doom-try-run-hook)
|
||||
(load! "config" doom-private-dir t)))))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -108,12 +100,11 @@ non-nil."
|
|||
(defun doom-module-p (category module &optional flag)
|
||||
"Returns t if CATEGORY MODULE is enabled (ie. present in `doom-modules')."
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(when (hash-table-p doom-modules)
|
||||
(let ((plist (gethash (cons category module) doom-modules)))
|
||||
(and plist
|
||||
(or (null flag)
|
||||
(memq flag (plist-get plist :flags)))
|
||||
t))))
|
||||
(let ((plist (gethash (cons category module) doom-modules)))
|
||||
(and plist
|
||||
(or (null flag)
|
||||
(memq flag (plist-get plist :flags)))
|
||||
t)))
|
||||
|
||||
(defun doom-module-get (category module &optional property)
|
||||
"Returns the plist for CATEGORY MODULE. Gets PROPERTY, specifically, if set."
|
||||
|
@ -128,7 +119,7 @@ non-nil."
|
|||
of PROPERTY and VALUEs.
|
||||
|
||||
\(fn CATEGORY MODULE PROPERTY VALUE &rest [PROPERTY VALUE [...]])"
|
||||
(if-let* ((old-plist (doom-module-get category module)))
|
||||
(if-let (old-plist (doom-module-get category module))
|
||||
(progn
|
||||
(when plist
|
||||
(when (cl-oddp (length plist))
|
||||
|
@ -159,9 +150,10 @@ MODULE (symbol).
|
|||
|
||||
If the category isn't enabled this will always return nil. For finding disabled
|
||||
modules use `doom-module-locate-path'."
|
||||
(let ((path (doom-module-get category module :path))
|
||||
file-name-handler-alist)
|
||||
(if file (expand-file-name file path)
|
||||
(let ((path (doom-module-get category module :path)))
|
||||
(if file
|
||||
(let (file-name-handler-alist)
|
||||
(expand-file-name file path))
|
||||
path)))
|
||||
|
||||
(defun doom-module-locate-path (category &optional module file)
|
||||
|
@ -183,37 +175,42 @@ This doesn't require modules to be enabled. For enabled modules us
|
|||
if (file-exists-p path)
|
||||
return (expand-file-name path)))
|
||||
|
||||
(defun doom-module-from-path (&optional path)
|
||||
"Returns a cons cell (CATEGORY . MODULE) derived from PATH (a file path)."
|
||||
(defun doom-module-from-path (&optional path enabled-only)
|
||||
"Returns a cons cell (CATEGORY . MODULE) derived from PATH (a file path).
|
||||
If ENABLED-ONLY, return nil if the containing module isn't enabled."
|
||||
(or doom--current-module
|
||||
(let* (file-name-handler-alist
|
||||
(path (or path (FILE!))))
|
||||
(let* ((file-name-handler-alist nil)
|
||||
(path (file-truename (or path (file!)))))
|
||||
(save-match-data
|
||||
(setq path (file-truename path))
|
||||
(when (string-match "/modules/\\([^/]+\\)/\\([^/]+\\)\\(?:/.*\\)?$" path)
|
||||
(when-let* ((category (match-string 1 path))
|
||||
(module (match-string 2 path)))
|
||||
(cons (doom-keyword-intern category)
|
||||
(intern module))))))))
|
||||
(when-let* ((category (doom-keyword-intern (match-string 1 path)))
|
||||
(module (intern (match-string 2 path))))
|
||||
(and (or (null enabled-only)
|
||||
(doom-module-p category module))
|
||||
(cons category module))))))))
|
||||
|
||||
(defun doom-module-load-path (&optional all-p)
|
||||
"Return an unsorted list of absolute file paths to activated modules.
|
||||
(defun doom-module-load-path (&optional module-dirs)
|
||||
"Return a list of file paths to activated modules.
|
||||
|
||||
If ALL-P is non-nil, return paths of possible modules, activated or otherwise."
|
||||
The list is in no particular order and its file paths are absolute. If
|
||||
MODULE-DIRS is non-nil, include all modules (even disabled ones) available in
|
||||
those directories."
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(append (if all-p
|
||||
(doom-files-in doom-modules-dirs
|
||||
(append (list doom-private-dir)
|
||||
(if module-dirs
|
||||
(doom-files-in (if (listp module-dirs)
|
||||
module-dirs
|
||||
doom-modules-dirs)
|
||||
:type 'dirs
|
||||
:mindepth 1
|
||||
:depth 1
|
||||
:full t
|
||||
:sort nil)
|
||||
:depth 1)
|
||||
(cl-loop for plist being the hash-values of (doom-modules)
|
||||
collect (plist-get plist :path)))
|
||||
(list doom-private-dir)))
|
||||
nil))
|
||||
|
||||
(defun doom-modules (&optional refresh-p)
|
||||
"Minimally initialize `doom-modules' (a hash table) and return it."
|
||||
"Minimally initialize `doom-modules' (a hash table) and return it.
|
||||
This value is cached. If REFRESH-P, then don't use the cached value."
|
||||
(or (unless refresh-p doom-modules)
|
||||
(let ((noninteractive t)
|
||||
doom-modules
|
||||
|
@ -343,45 +340,43 @@ The overall load order of Doom is as follows:
|
|||
Module load order is determined by your `doom!' block. See `doom-modules-dirs'
|
||||
for a list of all recognized module trees. Order defines precedence (from most
|
||||
to least)."
|
||||
(if doom--modules-cache
|
||||
(progn
|
||||
(setq doom-modules doom--modules-cache)
|
||||
(doom-log "Using `doom-modules' cache"))
|
||||
(unless doom-modules
|
||||
(setq doom-modules
|
||||
(make-hash-table :test 'equal
|
||||
:size (if modules (length modules) 150)
|
||||
:rehash-threshold 1.0)))
|
||||
(let ((inhibit-message doom-inhibit-module-warnings)
|
||||
category m)
|
||||
(while modules
|
||||
(setq m (pop modules))
|
||||
(cond ((keywordp m) (setq category m))
|
||||
((not category) (error "No module category specified for %s" m))
|
||||
((catch 'doom-modules
|
||||
(let* ((module (if (listp m) (car m) m))
|
||||
(flags (if (listp m) (cdr m))))
|
||||
(when-let* ((obsolete (assq category doom-obsolete-modules))
|
||||
(new (assq module obsolete)))
|
||||
(let ((newkeys (cdr new)))
|
||||
(if (null newkeys)
|
||||
(message "WARNING %s module was removed" key)
|
||||
(if (cdr newkeys)
|
||||
(message "WARNING %s module was removed and split into the %s modules"
|
||||
(list category module) (mapconcat #'prin1-to-string newkeys ", "))
|
||||
(message "WARNING %s module was moved to %s"
|
||||
(list category module) (car newkeys)))
|
||||
(push category modules)
|
||||
(dolist (key newkeys)
|
||||
(push (if flags
|
||||
(nconc (cdr key) flags)
|
||||
(cdr key))
|
||||
modules)
|
||||
(push (car key) modules))
|
||||
(throw 'doom-modules t))))
|
||||
(if-let (path (doom-module-locate-path category module))
|
||||
(doom-module-set category module :flags flags :path path)
|
||||
(message "WARNING Couldn't find the %s %s module" category module)))))))))
|
||||
(unless (keywordp (car modules))
|
||||
(setq modules (eval modules t)))
|
||||
(unless doom-modules
|
||||
(setq doom-modules
|
||||
(make-hash-table :test 'equal
|
||||
:size (if modules (length modules) 150)
|
||||
:rehash-threshold 1.0)))
|
||||
(let ((inhibit-message doom-inhibit-module-warnings)
|
||||
category m)
|
||||
(while modules
|
||||
(setq m (pop modules))
|
||||
(cond ((keywordp m) (setq category m))
|
||||
((not category) (error "No module category specified for %s" m))
|
||||
((catch 'doom-modules
|
||||
(let* ((module (if (listp m) (car m) m))
|
||||
(flags (if (listp m) (cdr m))))
|
||||
(when-let* ((obsolete (assq category doom-obsolete-modules))
|
||||
(new (assq module obsolete)))
|
||||
(let ((newkeys (cdr new)))
|
||||
(if (null newkeys)
|
||||
(message "WARNING %s module was removed" key)
|
||||
(if (cdr newkeys)
|
||||
(message "WARNING %s module was removed and split into the %s modules"
|
||||
(list category module) (mapconcat #'prin1-to-string newkeys ", "))
|
||||
(message "WARNING %s module was moved to %s"
|
||||
(list category module) (car newkeys)))
|
||||
(push category modules)
|
||||
(dolist (key newkeys)
|
||||
(push (if flags
|
||||
(nconc (cdr key) flags)
|
||||
(cdr key))
|
||||
modules)
|
||||
(push (car key) modules))
|
||||
(throw 'doom-modules t))))
|
||||
(if-let (path (doom-module-locate-path category module))
|
||||
(doom-module-set category module :flags flags :path path)
|
||||
(message "WARNING Couldn't find the %s %s module" category module))))))))
|
||||
(when noninteractive
|
||||
(setq doom-inhibit-module-warnings t))
|
||||
`(setq doom-modules ',doom-modules))
|
||||
|
@ -505,9 +500,9 @@ CATEGORY and MODULE can be omitted When this macro is used from inside a module
|
|||
(doom--current-flags (memq category doom--current-flags))
|
||||
((let ((module-pair
|
||||
(or doom--current-module
|
||||
(doom-module-from-path (FILE!)))))
|
||||
(doom-module-from-path (file!)))))
|
||||
(unless module-pair
|
||||
(error "featurep! call couldn't auto-detect what module its in (from %s)" (FILE!)))
|
||||
(error "featurep! call couldn't auto-detect what module its in (from %s)" (file!)))
|
||||
(memq category (doom-module-get (car module-pair) (cdr module-pair) :flags)))))
|
||||
t))
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
;;; core/core-packages.el -*- lexical-binding: t; -*-
|
||||
|
||||
(require 'core-modules)
|
||||
|
||||
;; Emacs package management is opinionated, and so am I. I've bound together
|
||||
;; `use-package', `quelpa' and package.el to create my own, rolling-release,
|
||||
;; lazily-loaded package management system for Emacs.
|
||||
|
@ -32,123 +34,164 @@
|
|||
;;
|
||||
;; See core/autoload/packages.el for more functions.
|
||||
|
||||
(defvar doom-init-packages-p nil
|
||||
"If non-nil, Doom's package management system has been initialized.")
|
||||
|
||||
(defvar doom-packages ()
|
||||
"A list of enabled packages. Each element is a sublist, whose CAR is the
|
||||
package's name as a symbol, and whose CDR is the plist supplied to its
|
||||
`package!' declaration. Set by `doom-initialize-packages'.")
|
||||
|
||||
(defvar doom-core-packages
|
||||
'(persistent-soft use-package quelpa async)
|
||||
(defvar doom-core-packages '(straight use-package async)
|
||||
"A list of packages that must be installed (and will be auto-installed if
|
||||
missing) and shouldn't be deleted.")
|
||||
|
||||
(defvar doom-core-package-sources
|
||||
'((org-elpa :local-repo nil)
|
||||
(melpa
|
||||
:type git :host github
|
||||
:repo "melpa/melpa"
|
||||
:no-build t)
|
||||
(gnu-elpa-mirror
|
||||
:type git :host github
|
||||
:repo "emacs-straight/gnu-elpa-mirror"
|
||||
:no-build t)
|
||||
(emacsmirror-mirror
|
||||
:type git :host github
|
||||
:repo "emacs-straight/emacsmirror-mirror"
|
||||
:no-build t))
|
||||
"A list of recipes for straight's recipe repos.")
|
||||
|
||||
(defvar doom-disabled-packages ()
|
||||
"A list of packages that should be ignored by `def-package!' and `after!'.")
|
||||
|
||||
;;; package.el
|
||||
|
||||
;;
|
||||
;;; Package managers
|
||||
|
||||
;; Ensure that, if we do need package.el, it is configured correctly. You really
|
||||
;; shouldn't be using it, but it may be convenient for quick package testing.
|
||||
(setq package--init-file-ensured t
|
||||
package-user-dir (expand-file-name "elpa" doom-packages-dir)
|
||||
package-gnupghome-dir (expand-file-name "gpg" doom-packages-dir)
|
||||
package-enable-at-startup nil
|
||||
package-user-dir doom-elpa-dir
|
||||
package-gnupghome-dir (expand-file-name "gpg" doom-elpa-dir)
|
||||
;; I omit Marmalade because its packages are manually submitted rather
|
||||
;; than pulled, so packages are often out of date with upstream.
|
||||
package-archives
|
||||
`(("gnu" . "https://elpa.gnu.org/packages/")
|
||||
("melpa" . "https://melpa.org/packages/")
|
||||
("org" . "https://orgmode.org/elpa/")))
|
||||
(let ((proto (if gnutls-verify-error "http" "https")))
|
||||
`(("gnu" . ,(concat proto "://elpa.gnu.org/packages/"))
|
||||
("melpa" . ,(concat proto "://melpa.org/packages/"))
|
||||
("org" . ,(concat proto "://orgmode.org/elpa/")))))
|
||||
|
||||
;; Don't save `package-selected-packages' to `custom-file'
|
||||
(advice-add #'package--save-selected-packages :override
|
||||
(lambda (&optional value) (if value (setq package-selected-packages value))))
|
||||
(def-advice! doom--package-inhibit-custom-file-a (&optional value)
|
||||
:override #'package--save-selected-packages
|
||||
(if value (setq package-selected-packages value)))
|
||||
|
||||
(when (or (not gnutls-verify-error)
|
||||
(not (ignore-errors (gnutls-available-p))))
|
||||
(dolist (archive package-archives)
|
||||
(setcdr archive (replace-regexp-in-string "^https://" "http://" (cdr archive) t nil))))
|
||||
;;; straight
|
||||
(setq straight-cache-autoloads nil ; we already do this, and better.
|
||||
;; Doom doesn't encourage you to modify packages in place. Disabling this
|
||||
;; makes 'doom refresh' instant (once everything set up), which is much
|
||||
;; nicer UX than the several seconds modification checks add.
|
||||
straight-check-for-modifications nil
|
||||
;; We do this ourselves, and a little more comprehensively.
|
||||
straight-enable-package-integration nil
|
||||
;; Before switching to straight, `doom-local-dir' would average out at
|
||||
;; around 100mb. Afterwards, at around 1gb. With shallow cloning, that is
|
||||
;; reduced to ~400mb. This imposes an isuse with packages that require
|
||||
;; their git history for certain things to work (like magit and org), but
|
||||
;; we're prepared for that.
|
||||
straight-vc-git-default-clone-depth 1
|
||||
;; Straight's own emacsmirror mirro is a little smaller and faster.
|
||||
straight-recipes-emacsmirror-use-mirror t
|
||||
;; Prefix declarations are unneeded bulk added to our autoloads file. Best
|
||||
;; we just don't have to deal with them at all.
|
||||
autoload-compute-prefixes nil)
|
||||
|
||||
;;; quelpa
|
||||
(setq quelpa-dir (expand-file-name "quelpa" doom-packages-dir)
|
||||
quelpa-verbose doom-debug-mode
|
||||
|
||||
;; Don't track MELPA, we'll use package.el for that
|
||||
quelpa-checkout-melpa-p nil
|
||||
quelpa-update-melpa-p nil
|
||||
quelpa-melpa-recipe-stores nil
|
||||
quelpa-self-upgrade-p nil)
|
||||
;; Straight is hardcoded to operate out of ~/.emacs.d/straight. Not on my watch!
|
||||
(def-advice! doom--straight-use-local-dir-a (orig-fn &rest args)
|
||||
:around #'straight--emacs-dir
|
||||
(let ((user-emacs-directory doom-local-dir))
|
||||
(apply orig-fn args)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Bootstrapper
|
||||
|
||||
(defun doom-initialize-packages (&optional force-p)
|
||||
"Ensures that Doom's package management system, package.el and quelpa are
|
||||
initialized, and `doom-packages', `packages-alist' and `quelpa-cache' are
|
||||
populated, if they aren't already.
|
||||
"Ensures that Doom's package system and straight.el are initialized.
|
||||
|
||||
If FORCE-P is non-nil, do it anyway.
|
||||
If FORCE-P is 'internal, only (re)populate `doom-packages'.
|
||||
|
||||
Use this before any of package.el, quelpa or Doom's package management's API to
|
||||
ensure all the necessary package metadata is initialized and available for
|
||||
them."
|
||||
(let ((load-prefer-newer t)) ; reduce stale code issues
|
||||
;; package.el and quelpa handle themselves if their state changes during the
|
||||
;; current session, but if you change a packages.el file in a module,
|
||||
;; there's no non-trivial way to detect that, so to reload only
|
||||
;; `doom-packages' pass 'internal as FORCE-P or use `doom/reload-packages'.
|
||||
(unless (eq force-p 'internal)
|
||||
;; `package-alist'
|
||||
(when (or force-p (not (bound-and-true-p package-alist)))
|
||||
(doom-ensure-packages-initialized 'force)
|
||||
(setq load-path (cl-delete-if-not #'file-directory-p load-path)))
|
||||
;; `quelpa-cache'
|
||||
(when (or force-p (not (bound-and-true-p quelpa-cache)))
|
||||
;; ensure un-byte-compiled version of quelpa is loaded
|
||||
(unless (featurep 'quelpa)
|
||||
(load (locate-library "quelpa.el") nil t t))
|
||||
(setq quelpa-initialized-p nil)
|
||||
(or (quelpa-setup-p)
|
||||
(error "Could not initialize quelpa"))))
|
||||
;; `doom-packages'
|
||||
(when (or force-p (not doom-packages))
|
||||
(setq doom-packages (doom-package-list)))))
|
||||
This ensure `doom-packages' is populated, if isn't aren't already. Use this
|
||||
before any of straight's or Doom's package management's API to ensure all the
|
||||
necessary package metadata is initialized and available for them."
|
||||
(when (or force-p (not doom-init-packages-p))
|
||||
(setq doom-init-packages-p t)
|
||||
(straight--reset-caches)
|
||||
(mapc #'straight-use-recipes doom-core-package-sources)
|
||||
(straight-register-package
|
||||
`(straight :type git :host github
|
||||
:repo ,(format "%s/straight.el" straight-repository-user)
|
||||
:files ("straight*.el")
|
||||
:branch ,straight-repository-branch))
|
||||
(mapc #'straight-use-package doom-core-packages)
|
||||
(when noninteractive
|
||||
(add-hook 'kill-emacs-hook #'straight--transaction-finalize))
|
||||
(dolist (package (straight--directory-files (straight--build-dir)))
|
||||
(add-to-list 'load-path (directory-file-name (straight--build-dir package)))))
|
||||
(when (or force-p (not doom-packages))
|
||||
(setq doom-disabled-packages nil
|
||||
doom-packages (doom-package-list))
|
||||
(cl-loop for (pkg . plist) in doom-packages
|
||||
for ignored = (eval (plist-get plist :ignore) t)
|
||||
for disabled = (eval (plist-get plist :disable) t)
|
||||
if disabled
|
||||
do (add-to-list 'doom-disabled-packages pkg)
|
||||
else if (not ignored)
|
||||
do (with-demoted-errors "Package error: %s"
|
||||
(straight-register-package
|
||||
(if-let (recipe (plist-get plist :recipe))
|
||||
`(,pkg ,@recipe)
|
||||
pkg))))))
|
||||
|
||||
(defun doom-ensure-straight ()
|
||||
"Ensure `straight' is installed and was compiled with this version of Emacs."
|
||||
(defvar bootstrap-version)
|
||||
(let* ((straight-dir (expand-file-name "straight/" doom-local-dir))
|
||||
(bootstrap-file (expand-file-name "repos/straight.el/straight.el" straight-dir))
|
||||
(bootstrap-version 5)
|
||||
;; Force straight to install into ~/.emacs.d/.local/straight instead of
|
||||
;; ~/.emacs.d/straight by pretending `doom-local-dir' is our .emacs.d.
|
||||
(user-emacs-directory doom-local-dir))
|
||||
(cl-block 'straight
|
||||
;; Straight will throw `emacs-version-changed' if it's loaded with a
|
||||
;; version of Emacs that doesn't match the one it was compiled with.
|
||||
;; Getting this error isn't very good UX...
|
||||
(catch 'emacs-version-changed
|
||||
(unless (require 'straight nil t)
|
||||
(unless (file-exists-p bootstrap-file)
|
||||
(with-current-buffer
|
||||
(url-retrieve-synchronously
|
||||
"https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
|
||||
'silent 'inhibit-cookies)
|
||||
(goto-char (point-max))
|
||||
(eval-print-last-sexp)))
|
||||
(load bootstrap-file nil 'nomessage))
|
||||
(cl-return-from 'straight t))
|
||||
;; ...so we transform it into a more graceful error message:
|
||||
(with-temp-buffer
|
||||
(insert-file-contents-literally (expand-file-name "build-cache.el" straight-dir))
|
||||
(let ((_ (read (current-buffer)))
|
||||
(last-emacs-version (read (current-buffer))))
|
||||
(user-error "Your version of Emacs has changed (from %S to %S). You must rebuild your packages with 'doom rebuild'."
|
||||
emacs-version last-emacs-version))))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Package API
|
||||
;;; Module package macros
|
||||
|
||||
(defun doom-ensure-packages-initialized (&optional force-p)
|
||||
"Make sure package.el is initialized."
|
||||
(when (or force-p (not (bound-and-true-p package--initialized)))
|
||||
(require 'package)
|
||||
(setq package-activated-list nil
|
||||
package--initialized nil)
|
||||
(let (byte-compile-warnings)
|
||||
(condition-case _
|
||||
(package-initialize)
|
||||
('error (package-refresh-contents)
|
||||
(setq doom--refreshed-p t)
|
||||
(package-initialize))))))
|
||||
|
||||
(defun doom-ensure-core-packages ()
|
||||
"Make sure `doom-core-packages' are installed."
|
||||
(when-let (core-packages (cl-remove-if #'package-installed-p doom-core-packages))
|
||||
(message "Installing core packages")
|
||||
(unless doom--refreshed-p
|
||||
(package-refresh-contents))
|
||||
(dolist (package core-packages)
|
||||
(let ((inhibit-message t))
|
||||
(package-install package))
|
||||
(if (package-installed-p package)
|
||||
(message "✓ Installed %s" package)
|
||||
(error "✕ Couldn't install %s" package)))
|
||||
(message "Installing core packages...done")))
|
||||
|
||||
|
||||
;;
|
||||
;; Module package macros
|
||||
|
||||
(cl-defmacro package! (name &rest plist &key built-in recipe pin disable ignore _freeze)
|
||||
(cl-defmacro package! (name &rest plist &key built-in _recipe disable ignore _freeze)
|
||||
"Declares a package and how to install it (if applicable).
|
||||
|
||||
This macro is declarative and does not load nor install packages. It is used to
|
||||
|
@ -162,9 +205,6 @@ Accepts the following properties:
|
|||
:recipe RECIPE
|
||||
Takes a MELPA-style recipe (see `quelpa-recipe' in `quelpa' for an example);
|
||||
for packages to be installed from external sources.
|
||||
:pin ARCHIVE-NAME
|
||||
Instructs ELPA to only look for this package in ARCHIVE-NAME. e.g. \"org\".
|
||||
Ignored if RECIPE is present.
|
||||
:disable BOOL
|
||||
Do not install or update this package AND disable all of its `def-package!'
|
||||
blocks.
|
||||
|
@ -180,14 +220,9 @@ Returns t if package is successfully registered, and nil if it was disabled
|
|||
elsewhere."
|
||||
(declare (indent defun))
|
||||
(let ((old-plist (cdr (assq name doom-packages))))
|
||||
(when recipe
|
||||
(when (cl-evenp (length recipe))
|
||||
(setq plist (plist-put plist :recipe (cons name recipe))))
|
||||
(setq pin nil
|
||||
plist (plist-put plist :pin nil)))
|
||||
(let ((module-list (plist-get old-plist :modules))
|
||||
(module (or doom--current-module
|
||||
(let ((file (FILE!)))
|
||||
(let ((file (file!)))
|
||||
(cond ((file-in-directory-p file doom-private-dir)
|
||||
(list :private))
|
||||
((file-in-directory-p file doom-core-dir)
|
||||
|
@ -199,7 +234,7 @@ elsewhere."
|
|||
(when built-in
|
||||
(doom-log "Ignoring built-in package %S" name)
|
||||
(when (equal built-in '(quote prefer))
|
||||
(setq built-in `(locate-library ,(symbol-name name) nil doom-site-load-path))))
|
||||
(setq built-in `(locate-library ,(symbol-name name) nil doom--initial-load-path))))
|
||||
(setq plist (plist-put plist :ignore (or built-in ignore)))
|
||||
(while plist
|
||||
(unless (null (cadr plist))
|
||||
|
@ -207,22 +242,20 @@ elsewhere."
|
|||
(pop plist)
|
||||
(pop plist))
|
||||
(setq plist old-plist)
|
||||
;; TODO Add `straight-use-package-pre-build-function' support
|
||||
(macroexp-progn
|
||||
(append (when pin
|
||||
(doom-log "Pinning package '%s' to '%s'" name pin)
|
||||
`((setf (alist-get ',name package-pinned-packages) ,pin)))
|
||||
`((setf (alist-get ',name doom-packages) ',plist))
|
||||
(append `((setf (alist-get ',name doom-packages) ',plist))
|
||||
(when disable
|
||||
(doom-log "Disabling package '%s'" name)
|
||||
`((add-to-list 'doom-disabled-packages ',name nil 'eq)
|
||||
`((doom-log "Disabling package %S" ',name)
|
||||
(add-to-list 'doom-disabled-packages ',name nil 'eq)
|
||||
nil))))))
|
||||
|
||||
(defmacro disable-packages! (&rest packages)
|
||||
"A convenience macro for disabling packages in bulk.
|
||||
Only use this macro in a module's (or your private) packages.el file."
|
||||
(macroexp-progn
|
||||
(cl-loop for pkg in packages
|
||||
collect (macroexpand `(package! ,pkg :disable t)))))
|
||||
(cl-loop for p in packages
|
||||
collect `(package! ,p :disable t))))
|
||||
|
||||
(provide 'core-packages)
|
||||
;;; core-packages.el ends here
|
||||
|
|
85
core/core.el
85
core/core.el
|
@ -56,7 +56,7 @@ dependencies or long-term shared data. Must end with a slash.")
|
|||
|
||||
Use this for files that change often, like cache files. Must end with a slash.")
|
||||
|
||||
(defvar doom-packages-dir (concat doom-local-dir "packages/")
|
||||
(defvar doom-elpa-dir (concat doom-local-dir "elpa/")
|
||||
"Where package.el and quelpa plugins (and their caches) are stored.
|
||||
|
||||
Must end with a slash.")
|
||||
|
@ -78,13 +78,13 @@ Defaults to ~/.config/doom, ~/.doom.d or the value of the DOOMDIR envvar;
|
|||
whichever is found first. Must end in a slash.")
|
||||
|
||||
(defvar doom-autoload-file (concat doom-local-dir "autoloads.el")
|
||||
"Where `doom-reload-doom-autoloads' stores its core autoloads.
|
||||
"Where `doom-reload-core-autoloads' stores its core autoloads.
|
||||
|
||||
This file is responsible for informing Emacs where to find all of Doom's
|
||||
autoloaded core functions (in core/autoload/*.el).")
|
||||
|
||||
(defvar doom-package-autoload-file (concat doom-local-dir "autoloads.pkg.el")
|
||||
"Where `doom-reload-package-autoloads' stores its package.el autoloads.
|
||||
"Where `doom-reload-package-autoloads' stores its package autoloads.
|
||||
|
||||
This file is compiled from the autoloads files of all installed packages
|
||||
combined.")
|
||||
|
@ -404,35 +404,6 @@ Meant to be used with `run-hook-wrapped'."
|
|||
;; return nil so `run-hook-wrapped' won't short circuit
|
||||
nil)
|
||||
|
||||
(defun doom-ensure-same-emacs-version-p ()
|
||||
"Check if the running version of Emacs has changed and set
|
||||
`doom-emacs-changed-p' if it has."
|
||||
(if (load doom--last-emacs-file 'noerror 'nomessage 'nosuffix)
|
||||
(setq doom-emacs-changed-p
|
||||
(not (equal emacs-version doom--last-emacs-version)))
|
||||
(with-temp-file doom--last-emacs-file
|
||||
(princ `(setq doom--last-emacs-version ,(prin1-to-string emacs-version))
|
||||
(current-buffer))))
|
||||
(cond ((not doom-emacs-changed-p))
|
||||
((y-or-n-p
|
||||
(format
|
||||
(concat "Your version of Emacs has changed from %s to %s, which may cause incompatibility\n"
|
||||
"issues. If you run into errors, run `bin/doom compile :plugins` or reinstall your\n"
|
||||
"plugins to resolve them.\n\n"
|
||||
"Continue?")
|
||||
doom--last-emacs-version
|
||||
emacs-version))
|
||||
(delete-file doom--last-emacs-file))
|
||||
(noninteractive (error "Aborting"))
|
||||
((kill-emacs))))
|
||||
|
||||
(defun doom-ensure-core-directories-exist ()
|
||||
"Make sure all Doom's essential local directories (in and including
|
||||
`doom-local-dir') exist."
|
||||
(dolist (dir (list doom-local-dir doom-etc-dir doom-cache-dir doom-packages-dir))
|
||||
(unless (file-directory-p dir)
|
||||
(make-directory dir t))))
|
||||
|
||||
(defun doom-display-benchmark-h (&optional return-p)
|
||||
"Display a benchmark, showing number of packages and modules, and how quickly
|
||||
they were loaded at startup.
|
||||
|
@ -461,7 +432,9 @@ If RETURN-P, return the message as a string instead of displaying it."
|
|||
"Tries to load FILE (an autoloads file). Return t on success, throws an error
|
||||
in interactive sessions, nil otherwise (but logs a warning)."
|
||||
(condition-case e
|
||||
(load (file-name-sans-extension file) 'noerror 'nomessage)
|
||||
(let (command-switch-alist)
|
||||
(load (if noninteractive file (file-name-sans-extension file))
|
||||
'noerror 'nomessage))
|
||||
((debug error)
|
||||
(if noninteractive
|
||||
(message "Autoload file warning: %s -> %s" (car e) (error-message-string e))
|
||||
|
@ -470,7 +443,7 @@ in interactive sessions, nil otherwise (but logs a warning)."
|
|||
(defun doom-load-env-vars (file)
|
||||
"Read and set envvars in FILE."
|
||||
(if (not (file-readable-p file))
|
||||
(doom-log "Couldn't read %S envvar file" file)
|
||||
(signal 'file-error (list "Couldn't read envvar file" file))
|
||||
(with-temp-buffer
|
||||
(insert-file-contents file)
|
||||
(search-forward "\n\n" nil t)
|
||||
|
@ -527,37 +500,45 @@ to least)."
|
|||
load-path doom--initial-load-path
|
||||
process-environment doom--initial-process-environment)
|
||||
|
||||
;; `doom-autoload-file' tells Emacs where to load all its autoloaded
|
||||
;; functions from. This includes everything in core/autoload/*.el and all
|
||||
;; the autoload files in your enabled modules.
|
||||
(when (or force-p (not (doom-initialize-autoloads doom-autoload-file)))
|
||||
(doom-ensure-core-directories-exist)
|
||||
(doom-ensure-same-emacs-version-p)
|
||||
;; `doom-autoload-file' tells Emacs where to load all its functions from.
|
||||
;; This includes everything in core/autoload/*.el and autoload files in
|
||||
;; enabled modules.
|
||||
(when (or (not (doom-initialize-autoloads doom-autoload-file))
|
||||
force-p)
|
||||
(dolist (dir (list doom-local-dir doom-etc-dir doom-cache-dir doom-elpa-dir))
|
||||
(unless (file-directory-p dir)
|
||||
(make-directory dir 'parents-too)))
|
||||
|
||||
;; Ensure the package management system (and straight) are ready for
|
||||
;; action (and all core packages/repos are installed)
|
||||
(require 'core-packages)
|
||||
(doom-ensure-packages-initialized force-p)
|
||||
(doom-ensure-core-packages)
|
||||
(doom-ensure-straight)
|
||||
(doom-initialize-packages force-p)
|
||||
|
||||
(unless (or force-p noninteractive)
|
||||
(user-error "Your doom autoloads are missing! Run `bin/doom refresh' to regenerate them")))
|
||||
|
||||
;; Loads `doom-package-autoload-file', which loads a concatenated package
|
||||
;; autoloads file and caches `load-path', `auto-mode-alist',
|
||||
;; `Info-directory-list', `doom-disabled-packages' and
|
||||
;; `package-activated-list'. A big reduction in startup time.
|
||||
(let (command-switch-alist)
|
||||
(unless (or force-p
|
||||
(doom-initialize-autoloads doom-package-autoload-file)
|
||||
noninteractive)
|
||||
(user-error "Your package autoloads are missing! Run `bin/doom refresh' to regenerate them")))
|
||||
;; autoloads file which caches `load-path', `auto-mode-alist',
|
||||
;; `Info-directory-list', and `doom-disabled-packages'. A big reduction in
|
||||
;; startup time.
|
||||
(unless (or force-p
|
||||
(doom-initialize-autoloads doom-package-autoload-file)
|
||||
noninteractive)
|
||||
(user-error "Your package autoloads are missing! Run `bin/doom refresh' to regenerate them"))
|
||||
|
||||
;; Load shell environment
|
||||
(unless noninteractive
|
||||
(when (and (not noninteractive)
|
||||
(file-exists-p doom-env-file))
|
||||
(doom-load-env-vars doom-env-file)))
|
||||
|
||||
;; In case we want to use package.el's API
|
||||
(with-eval-after-load 'package
|
||||
(require 'core-packages)))
|
||||
(require 'core-packages))
|
||||
;; Or straight interactively
|
||||
(with-eval-after-load 'straight
|
||||
(require 'core-packages)
|
||||
(doom-initialize-packages)))
|
||||
|
||||
|
||||
;;
|
||||
|
|
|
@ -40,8 +40,5 @@
|
|||
(package! which-key)
|
||||
(package! hydra)
|
||||
|
||||
;; core-packages.el
|
||||
(package! gnu-elpa-keyring-update)
|
||||
|
||||
;; autoload/debug.el
|
||||
(package! esup)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
;;; init.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copy this file to ~/.doom.d/init.el or ~/.config/doom/init.el ('doom
|
||||
;; quickstart' will do this for you). The `doom!' block below controls what
|
||||
;; modules are enabled and in what order they will be loaded. Remember to run
|
||||
;; 'doom refresh' after modifying it.
|
||||
;; Copy this file to ~/.doom.d/init.el or ~/.config/doom/init.el ('doom install'
|
||||
;; will do this for you). The `doom!' block below controls what modules are
|
||||
;; enabled and in what order they will be loaded. Remember to run 'doom refresh'
|
||||
;; after modifying it.
|
||||
;;
|
||||
;; More information about these modules (and what flags they support) can be
|
||||
;; found in modules/README.org.
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
(package! helm-ag)
|
||||
(package! helm-c-yasnippet)
|
||||
(package! helm-company)
|
||||
(package! helm-describe-modes :recipe (:fetcher github :repo "emacs-helm/helm-describe-modes"))
|
||||
(package! helm-describe-modes :recipe (:host github :repo "emacs-helm/helm-describe-modes"))
|
||||
(package! helm-projectile)
|
||||
(package! swiper-helm)
|
||||
(when (featurep! +fuzzy)
|
||||
|
|
|
@ -9,14 +9,13 @@
|
|||
(package! evil-escape)
|
||||
(package! evil-exchange)
|
||||
(package! evil-indent-plus)
|
||||
(package! evil-numbers :recipe (:fetcher github :repo "janpath/evil-numbers"))
|
||||
(package! evil-numbers :recipe (:host github :repo "janpath/evil-numbers"))
|
||||
(package! evil-textobj-anyblock)
|
||||
(package! evil-snipe)
|
||||
(package! evil-surround)
|
||||
(package! evil-visualstar)
|
||||
(package! exato)
|
||||
|
||||
|
||||
;;
|
||||
(when (featurep! +everywhere)
|
||||
;; `evil-collection-neotree' uses the `neotree-make-executor' macro, but this
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
;; -*- no-byte-compile: t; -*-
|
||||
;;; editor/rotate-text/packages.el
|
||||
|
||||
(package! rotate-text :recipe (:fetcher github :repo "debug-ito/rotate-text.el"))
|
||||
(package! rotate-text :recipe (:host github :repo "debug-ito/rotate-text.el"))
|
||||
|
|
|
@ -5,6 +5,6 @@
|
|||
(package! auto-yasnippet)
|
||||
|
||||
(package! doom-snippets
|
||||
:recipe (:fetcher github
|
||||
:recipe (:host github
|
||||
:repo "hlissner/doom-snippets"
|
||||
:files ("*.el" "snippets")))
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
(when (package! glsl-mode)
|
||||
(when (featurep! :completion company)
|
||||
(package! company-glsl :recipe (:fetcher github :repo "Kaali/company-glsl"))))
|
||||
(package! company-glsl :recipe (:host github :repo "Kaali/company-glsl"))))
|
||||
|
||||
(if (featurep! +lsp)
|
||||
(package! ccls)
|
||||
|
|
|
@ -16,18 +16,8 @@
|
|||
;; by default quelpa generated a version 0pre0.20180929.192844, which got
|
||||
;; parsed into (0 -1 0 ...), which when compared with version nil (0) in
|
||||
;; package-installed-p always yielded false
|
||||
(package! ocamlformat :recipe (:fetcher github :repo "ocaml-ppx/ocamlformat" :files ("emacs/*.el"))))
|
||||
(package! ocamlformat :recipe
|
||||
(:host github :repo "ocaml-ppx/ocamlformat" :files ("emacs/*.el"))))
|
||||
|
||||
(package! dune :recipe (:fetcher github :repo "ocaml/dune" :files ("editor-integration/emacs/*.el")))
|
||||
|
||||
|
||||
;; (defvar +ocaml-elisp-dir
|
||||
;; (when (executable-find "opam")
|
||||
;; (let ((opam-share (ignore-errors (car (process-lines "opam" "config" "var" "share" "--safe")))))
|
||||
;; (when (and opam-share (file-directory-p opam-share))
|
||||
;; (expand-file-name "emacs/site-lisp" opam-share)))))
|
||||
;;
|
||||
;; (defmacro localpackage! (name)
|
||||
;; `(package! ,name :recipe (:fetcher file :path ,+ocaml-elisp-dir)))
|
||||
;;
|
||||
;; (localpackage! opam-site-lisp)
|
||||
(package! dune :recipe
|
||||
(:host github :repo "ocaml/dune" :files ("editor-integration/emacs/*.el")))
|
||||
|
|
|
@ -882,3 +882,12 @@ compelling reason, so..."
|
|||
(org-clock-load))
|
||||
:config
|
||||
(add-hook 'kill-emacs-hook #'org-clock-save)))
|
||||
|
||||
|
||||
;; HACK A necessary hack because org requires a compilation step after being
|
||||
;; cloned, and during that compilation a org-version.el is generated with these
|
||||
;; two functions, which return the output of a 'git describe ...' call in the
|
||||
;; repo's root. Of course, this command won't work in a sparse clone, and more
|
||||
;; than that, initiating these compilation step is a hassle, so...
|
||||
(defun org-release () "")
|
||||
(defun org-git-version () "")
|
||||
|
|
|
@ -1,15 +1,8 @@
|
|||
;; -*- no-byte-compile: t; -*-
|
||||
;;; lang/org/packages.el
|
||||
|
||||
;; Prevent built-in Org from playing into the byte-compilation of
|
||||
;; `org-plus-contrib'.
|
||||
(when-let (orglib (locate-library "org" nil doom-site-load-path))
|
||||
(setq load-path (delete (substring (file-name-directory orglib) 0 -1)
|
||||
load-path)))
|
||||
(package! org-plus-contrib) ; install cutting-edge version of org-mode
|
||||
(package! org :ignore t) ; ignore org on ELPA, if possible
|
||||
|
||||
(package! org-bullets :recipe (:fetcher github :repo "Kaligule/org-bullets"))
|
||||
(package! org-plus-contrib) ; install cutting-edge version of org-mode
|
||||
(package! org-bullets :recipe (:host github :repo "Kaligule/org-bullets"))
|
||||
(package! toc-org)
|
||||
(when (featurep! :editor evil)
|
||||
(package! evil-org))
|
||||
|
@ -17,7 +10,7 @@
|
|||
(package! org-pdfview))
|
||||
(package! htmlize)
|
||||
(package! ox-clip)
|
||||
(package! org-yt :recipe (:fetcher github :repo "TobiasZawada/org-yt"))
|
||||
(package! org-yt :recipe (:host github :repo "TobiasZawada/org-yt"))
|
||||
|
||||
;;; Babel
|
||||
(package! ob-async)
|
||||
|
@ -28,7 +21,7 @@
|
|||
(when (featurep! :lang nim)
|
||||
(package! ob-nim))
|
||||
(when (featurep! :lang racket)
|
||||
(package! ob-racket :recipe (:fetcher github :repo "DEADB17/ob-racket")))
|
||||
(package! ob-racket :recipe (:host github :repo "DEADB17/ob-racket")))
|
||||
(when (featurep! :lang rest)
|
||||
(package! ob-restclient))
|
||||
(when (featurep! :lang rust)
|
||||
|
@ -37,18 +30,14 @@
|
|||
;;; Modules
|
||||
(when (featurep! +dragndrop)
|
||||
(package! org-download))
|
||||
|
||||
(when (featurep! +gnuplot)
|
||||
(package! gnuplot)
|
||||
(package! gnuplot-mode))
|
||||
|
||||
(when (featurep! +ipython)
|
||||
(package! ob-ipython))
|
||||
|
||||
(when (featurep! +pandoc)
|
||||
(package! ox-pandoc))
|
||||
|
||||
(when (featurep! +present)
|
||||
(package! centered-window :recipe (:fetcher github :repo "anler/centered-window-mode"))
|
||||
(package! centered-window :recipe (:host github :repo "anler/centered-window-mode"))
|
||||
(package! org-tree-slide)
|
||||
(package! ox-reveal))
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
;;; lang/php/packages.el
|
||||
|
||||
(package! php-boris)
|
||||
(package! php-extras :recipe (:fetcher github :repo "arnested/php-extras"))
|
||||
(package! php-extras :recipe (:host github :repo "arnested/php-extras"))
|
||||
(package! php-mode)
|
||||
(package! php-refactor-mode)
|
||||
(package! phpunit)
|
||||
|
||||
(when (featurep! +hack)
|
||||
(package! hack-mode :recipe (:fetcher github :repo "hhvm/hack-mode")))
|
||||
(package! hack-mode :recipe (:host github :repo "hhvm/hack-mode")))
|
||||
|
||||
(unless (featurep! +lsp)
|
||||
(package! phpactor))
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
;; -*- no-byte-compile: t; -*-
|
||||
;;; lang/lua/packages.el
|
||||
|
||||
(package! terra-mode :recipe (:fetcher github :repo "StanfordLegion/terra-mode"))
|
||||
(package! terra-mode
|
||||
:recipe (:host github :repo "StanfordLegion/terra-mode"))
|
||||
|
||||
(when (featurep! :completion company)
|
||||
(package! company-lua))
|
||||
|
|
|
@ -17,6 +17,11 @@ It is passed a user and repository name.")
|
|||
(setq transient-levels-file (concat doom-etc-dir "transient/levels")
|
||||
transient-values-file (concat doom-etc-dir "transient/values")
|
||||
transient-history-file (concat doom-etc-dir "transient/history"))
|
||||
|
||||
;; HACK Magit complains loudly when it can't determine its own version, which
|
||||
;; is the case when magit is built through straight. The warning is
|
||||
;; harmless, however, so we just need it to shut up.
|
||||
(advice-add #'magit-version :around #'ignore)
|
||||
:config
|
||||
(setq transient-default-level 5
|
||||
magit-revision-show-gravatars '("^Author: " . "^Commit: ")
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
;; an older version of `auto-source-pass' is built into Emacs 26+, so we must
|
||||
;; install the new version directly from the source and with a psuedonym.
|
||||
(package! auth-source-pass-new
|
||||
:recipe (auth-source-pass :fetcher github :repo "DamienCassou/auth-password-store"))
|
||||
(package! auth-source-pass
|
||||
:recipe (:host github :repo "DamienCassou/auth-password-store"))
|
||||
|
||||
(when (featurep! :completion ivy)
|
||||
(package! ivy-pass))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue