Merge branch 'develop' into dired
This commit is contained in:
commit
3c4252ffe7
295 changed files with 8141 additions and 6654 deletions
38
Makefile
38
Makefile
|
@ -1,9 +1,18 @@
|
|||
DOOM = "bin/doom"
|
||||
MODULES = $(patsubst modules/%/, %, $(sort $(dir $(wildcard modules/*/ modules/*/*/))))
|
||||
|
||||
all:
|
||||
all: deprecated
|
||||
@$(DOOM) refresh
|
||||
|
||||
deprecated:
|
||||
@echo "Using make to manage your Doom config is deprecated"
|
||||
@echo
|
||||
@echo "Use the 'bin/doom' script instead. The equivalent of 'make' is 'doom refresh'."
|
||||
@echo
|
||||
@echo "See 'doom help' for a list of commands"
|
||||
@echo
|
||||
@read -p "Press enter to continue"
|
||||
|
||||
## Shortcuts
|
||||
a: autoloads
|
||||
i: install
|
||||
|
@ -16,34 +25,33 @@ cp: compile-plugins
|
|||
re: recompile
|
||||
d: doctor
|
||||
|
||||
quickstart:
|
||||
@$(DOOM) quickstart
|
||||
quickstart: install
|
||||
|
||||
|
||||
## Package management
|
||||
install:
|
||||
install: deprecated
|
||||
@$(DOOM) install
|
||||
update:
|
||||
update: deprecated
|
||||
@$(DOOM) update
|
||||
autoremove:
|
||||
autoremove: deprecated
|
||||
@$(DOOM) autoremove
|
||||
autoloads:
|
||||
autoloads: deprecated
|
||||
@$(DOOM) autoloads
|
||||
upgrade:
|
||||
upgrade: deprecated
|
||||
@$(DOOM) upgrade
|
||||
|
||||
## Byte compilation
|
||||
compile:
|
||||
compile: deprecated
|
||||
@$(DOOM) compile
|
||||
compile-core:
|
||||
compile-core: deprecated
|
||||
@$(DOOM) compile :core
|
||||
compile-private:
|
||||
compile-private: deprecated
|
||||
@$(DOOM) compile :private
|
||||
compile-plugins:
|
||||
@$(DOOM) compile :plugins
|
||||
recompile:
|
||||
compile-plugins: deprecated
|
||||
@$(DOOM) build
|
||||
recompile: deprecated
|
||||
@$(DOOM) recompile
|
||||
clean:
|
||||
clean: deprecated
|
||||
@$(DOOM) clean
|
||||
# compile-module
|
||||
# compile-module/submodule
|
||||
|
|
|
@ -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**
|
||||
|
@ -109,7 +109,7 @@ Feature Highlights
|
|||
support for a variety of languages.
|
||||
- A jump-to-definition/references implementation for all languages that tries to
|
||||
"just work," resorting to mode-specific functionality, before falling back on
|
||||
[dump-jump][url:dump-jump].
|
||||
[dumb-jump][url:dumb-jump].
|
||||
|
||||
|
||||
Troubleshooting
|
||||
|
@ -178,7 +178,7 @@ contributions:
|
|||
|
||||
[url:company-mode]: https://github.com/company-mode/company-mode
|
||||
[url:doom-themes]: https://github.com/hlissner/emacs-doom-themes
|
||||
[url:dump-jump]: https://github.com/jacktasia/dumb-jump
|
||||
[url:dumb-jump]: https://github.com/jacktasia/dumb-jump
|
||||
[url:editorconfig]: http://editorconfig.org/
|
||||
[url:evil-mode]: https://github.com/emacs-evil/evil
|
||||
[url:helm]: https://github.com/emacs-helm/helm
|
||||
|
|
50
bin/doom
50
bin/doom
|
@ -10,6 +10,11 @@
|
|||
":"; exec $EMACS --script "$0" -- "$@"
|
||||
":"; exit 0
|
||||
|
||||
(setq user-emacs-directory
|
||||
(or (getenv "EMACSDIR")
|
||||
(expand-file-name "../" (file-name-directory (file-truename load-file-name)))))
|
||||
|
||||
|
||||
(defun usage ()
|
||||
(with-temp-buffer
|
||||
(insert (format! "%s %s [COMMAND] [ARGS...]\n"
|
||||
|
@ -35,15 +40,14 @@
|
|||
" -d --debug\t\tTurns on doom-debug-mode (and debug-on-error)\n"
|
||||
" -e --emacsd DIR\tUse the emacs config at DIR (e.g. ~/.emacs.d)\n"
|
||||
" -i --insecure\t\tDisable TLS/SSL validation (not recommended)\n"
|
||||
" -l --local DIR\tUse DIR as your local storage directory\n"
|
||||
" -p --private DIR\tUse the private module at DIR (e.g. ~/.doom.d)\n"
|
||||
" -y --yes\t\tAuto-accept all confirmation prompts\n\n")
|
||||
(princ (buffer-string)))
|
||||
(doom--dispatch-help))
|
||||
|
||||
;;
|
||||
(let ((args (cdr (cdr (cdr command-line-args))))
|
||||
(emacs-dir (or (getenv "EMACSDIR")
|
||||
(expand-file-name "../" (file-name-directory (file-truename load-file-name))))))
|
||||
(let ((args (cdr (cdr (cdr command-line-args)))))
|
||||
;; Parse options
|
||||
(while (ignore-errors (string-prefix-p "-" (car args)))
|
||||
(pcase (pop args)
|
||||
|
@ -62,35 +66,45 @@
|
|||
(or (file-directory-p doom-private-dir)
|
||||
(message "Warning: %s does not exist"
|
||||
(abbreviate-file-name doom-private-dir))))
|
||||
((or "-l" "--local")
|
||||
(setq doom-local-dir (expand-file-name (concat (pop args) "/")))
|
||||
(setenv "DOOMLOCALDIR" doom-local-dir)
|
||||
(message "DOOMLOCALDIR changed to %s" doom-local-dir))
|
||||
((or "-e" "--emacsd")
|
||||
(setq emacs-dir (expand-file-name (concat (pop args) "/")))
|
||||
(message "Emacs directory changed to %s" emacs-dir))
|
||||
(setq user-emacs-directory (expand-file-name (concat (pop args) "/")))
|
||||
(message "Emacs directory changed to %s" user-emacs-directory))
|
||||
((or "-y" "--yes")
|
||||
(setenv "YES" "1")
|
||||
(message "Auto-yes mode on"))))
|
||||
|
||||
(or (file-directory-p emacs-dir)
|
||||
(error "%s does not exist" emacs-dir))
|
||||
(unless (file-directory-p user-emacs-directory)
|
||||
(error "%s does not exist" user-emacs-directory))
|
||||
|
||||
;; Bootstrap Doom
|
||||
(load (expand-file-name "init" emacs-dir)
|
||||
(if (not noninteractive)
|
||||
(progn
|
||||
(load (expand-file-name "init.el" user-emacs-directory)
|
||||
nil 'nomessage)
|
||||
(doom-run-all-startup-hooks-h))
|
||||
(load (expand-file-name "core/core.el" user-emacs-directory)
|
||||
nil 'nomessage)
|
||||
(doom-initialize 'force-p)
|
||||
(doom-initialize-modules)
|
||||
|
||||
(cond ((not noninteractive)
|
||||
(doom|run-all-startup-hooks))
|
||||
((and (not (cdr args))
|
||||
(cond ((and (not (cdr args))
|
||||
(member (car args) '("help" "h")))
|
||||
(usage))
|
||||
((not args)
|
||||
(message "No command detected, aborting!\n\nRun %s help for documentation."
|
||||
(file-name-nondirectory load-file-name)))
|
||||
((let ((default-directory emacs-dir))
|
||||
(setq argv nil
|
||||
noninteractive 'doom)
|
||||
(print! (error "No command detected.\n"))
|
||||
(usage))
|
||||
((require 'core-cli)
|
||||
(let ((default-directory user-emacs-directory))
|
||||
(setq argv nil)
|
||||
(condition-case e
|
||||
(doom-dispatch (car args) (cdr args))
|
||||
(user-error
|
||||
(signal (car e) (cdr e)))
|
||||
(print! (error "%s\n") (error-message-string e))
|
||||
(print! (yellow "See 'doom help %s' for documentation on this command.") (car args)))
|
||||
((debug error)
|
||||
(message "--------------------------------------------------\n")
|
||||
(message "There was an unexpected error:")
|
||||
|
@ -105,4 +119,4 @@
|
|||
"Emacs outputs to standard error, so you'll need to redirect stderr to\n"
|
||||
"stdout to pipe this to a file or clipboard!\n\n"
|
||||
" e.g. doom -d install 2>&1 | clipboard-program"))
|
||||
(signal 'doom-error e))))))))
|
||||
(signal 'doom-error e)))))))))
|
||||
|
|
146
bin/doom-doctor
146
bin/doom-doctor
|
@ -18,7 +18,8 @@
|
|||
;; specified by the EMACSDIR envvar)
|
||||
(setq user-emacs-directory
|
||||
(or (getenv "EMACSDIR")
|
||||
(expand-file-name "../" (file-name-directory load-file-name))))
|
||||
(expand-file-name "../" (file-name-directory (file-truename load-file-name))))
|
||||
default-directory user-emacs-directory)
|
||||
|
||||
(unless (file-directory-p user-emacs-directory)
|
||||
(error "Couldn't find a Doom config!"))
|
||||
|
@ -27,8 +28,9 @@
|
|||
(when (getenv "DEBUG")
|
||||
(setq debug-on-error t))
|
||||
|
||||
(require 'subr-x)
|
||||
(require 'pp)
|
||||
(load (expand-file-name "core/autoload/message" user-emacs-directory) nil t)
|
||||
(load (expand-file-name "core/autoload/format" user-emacs-directory) nil t)
|
||||
|
||||
|
||||
(defvar doom-init-p nil)
|
||||
|
@ -147,7 +149,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 +184,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,24 +192,17 @@
|
|||
|
||||
(condition-case-unless-debug ex
|
||||
(let ((after-init-time (current-time))
|
||||
(doom-message-backend 'ansi)
|
||||
(doom-format-backend 'ansi)
|
||||
noninteractive)
|
||||
(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
|
||||
(require 'core-cli)
|
||||
(require 'core-keybinds)
|
||||
(require 'core-ui)
|
||||
(require 'core-projects)
|
||||
(require 'core-editor)
|
||||
(require 'core-packages)
|
||||
|
||||
;; ...and initialized
|
||||
(doom-initialize)
|
||||
;; Make sure Doom is initialized and loaded
|
||||
(doom-initialize 'force)
|
||||
(doom-initialize-core)
|
||||
(success! "Initialized Doom Emacs %s" doom-version)
|
||||
|
||||
(doom-initialize-modules)
|
||||
|
@ -332,26 +225,23 @@
|
|||
(when doom-modules
|
||||
(section! "Checking your enabled modules...")
|
||||
(let ((indent (+ indent 2)))
|
||||
(advice-add #'require :around #'doom*shut-up)
|
||||
(advice-add #'require :around #'doom-shut-up-a)
|
||||
(maphash
|
||||
(lambda (key plist)
|
||||
(let ((prefix (format! (bold "(%s %s) " (car key) (cdr key)))))
|
||||
(condition-case-unless-debug ex
|
||||
(let ((doctor-file (doom-module-path (car key) (cdr key) "doctor.el"))
|
||||
(packages-file (doom-module-path (car key) (cdr key) "packages.el")))
|
||||
(cl-loop with doom--stage = 'packages
|
||||
for name in (let (doom-packages
|
||||
(cl-loop for name in (let (doom-packages
|
||||
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))
|
||||
(let ((doom--stage 'doctor))
|
||||
(load doctor-file 'noerror 'nomessage)))
|
||||
(load doctor-file 'noerror 'nomessage))
|
||||
(file-missing (error! "%s" (error-message-string ex)))
|
||||
(error (error! "Syntax error: %s" ex)))))
|
||||
doom-modules)))))
|
||||
|
|
|
@ -250,46 +250,11 @@ regex PATTERN. Returns the number of killed buffers."
|
|||
;; Hooks
|
||||
|
||||
;;;###autoload
|
||||
(defun doom|mark-buffer-as-real ()
|
||||
(defun doom-mark-buffer-as-real-h ()
|
||||
"Hook function that marks the current buffer as real."
|
||||
(doom-set-buffer-real (current-buffer) t))
|
||||
|
||||
|
||||
;;
|
||||
;; Advice
|
||||
|
||||
;;;###autoload
|
||||
(defun doom*switch-to-fallback-buffer-maybe (orig-fn)
|
||||
"Advice for `kill-current-buffer'. If in a dedicated window, delete it. If there
|
||||
are no real buffers left OR if all remaining buffers are visible in other
|
||||
windows, switch to `doom-fallback-buffer'. Otherwise, delegate to original
|
||||
`kill-current-buffer'."
|
||||
(let ((buf (current-buffer)))
|
||||
(cond ((window-dedicated-p)
|
||||
(delete-window))
|
||||
((eq buf (doom-fallback-buffer))
|
||||
(message "Can't kill the fallback buffer."))
|
||||
((doom-real-buffer-p buf)
|
||||
(if (and buffer-file-name
|
||||
(buffer-modified-p buf)
|
||||
(not (y-or-n-p
|
||||
(format "Buffer %s is modified; kill anyway?" buf))))
|
||||
(message "Aborted")
|
||||
(set-buffer-modified-p nil)
|
||||
(let (buffer-list-update-hook)
|
||||
(when (or ;; if there aren't more real buffers than visible buffers,
|
||||
;; then there are no real, non-visible buffers left.
|
||||
(not (cl-set-difference (doom-real-buffer-list)
|
||||
(doom-visible-buffers)))
|
||||
;; if we end up back where we start (or previous-buffer
|
||||
;; returns nil), we have nowhere left to go
|
||||
(memq (switch-to-prev-buffer nil t) (list buf 'nil)))
|
||||
(switch-to-buffer (doom-fallback-buffer)))
|
||||
(unless (delq (selected-window) (get-buffer-window-list buf nil t))
|
||||
(kill-buffer buf)))))
|
||||
((funcall orig-fn)))))
|
||||
|
||||
|
||||
;;
|
||||
;; Interactive commands
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
;;; ../core/autoload/cache.el -*- lexical-binding: t; -*-
|
||||
;;; core/autoload/cache.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; This little library thinly wraps around persistent-soft (which is a pcache
|
||||
;; wrapper, how about that). It has three purposes:
|
||||
|
@ -21,7 +21,7 @@ to persist across Emacs sessions.")
|
|||
name under `pcache-directory' (by default a subdirectory under
|
||||
`doom-cache-dir'). One file may contain multiple cache entries.")
|
||||
|
||||
(defun doom|save-persistent-cache ()
|
||||
(defun doom-save-persistent-cache-h ()
|
||||
"Hook to run when an Emacs session is killed. Saves all persisted variables
|
||||
listed in `doom-cache-alists' to files."
|
||||
(dolist (alist (butlast doom-cache-alists 1))
|
||||
|
@ -29,7 +29,7 @@ listed in `doom-cache-alists' to files."
|
|||
for var in (cdr alist)
|
||||
if (symbol-value var)
|
||||
do (doom-cache-set var it nil key))))
|
||||
(add-hook 'kill-emacs-hook #'doom|save-persistent-cache)
|
||||
(add-hook 'kill-emacs-hook #'doom-save-persistent-cache-h)
|
||||
|
||||
|
||||
;;
|
||||
|
|
|
@ -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")))
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
;;; core/autoload/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defvar doom-reload-hook nil
|
||||
"A list of hooks to run when `doom/reload' is called.")
|
||||
|
||||
;;;###autoload
|
||||
(defvar doom-reloading-p nil
|
||||
"TODO")
|
||||
|
@ -19,7 +23,7 @@
|
|||
(doom-project-find-file doom-private-dir))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/reload (&optional force-p)
|
||||
(defun doom/reload ()
|
||||
"Reloads your private config.
|
||||
|
||||
This is experimental! It will try to do as `bin/doom refresh' does, but from
|
||||
|
@ -27,26 +31,29 @@ within this Emacs session. i.e. it reload autoloads files (if necessary),
|
|||
reloads your package list, and lastly, reloads your private config.el.
|
||||
|
||||
Runs `doom-reload-hook' afterwards."
|
||||
(interactive "P")
|
||||
(interactive)
|
||||
(or (y-or-n-p
|
||||
(concat "You are about to reload your Doom config from within Emacs. This "
|
||||
"is highly experimental and may cause issues. It is recommended you "
|
||||
"use 'bin/doom refresh' on the command line instead.\n\n"
|
||||
"Reload anyway?"))
|
||||
(user-error "Aborted"))
|
||||
(require 'core-cli)
|
||||
(general-auto-unbind-keys)
|
||||
(let ((doom-reloading-p t))
|
||||
(when (getenv "DOOMENV")
|
||||
(doom-reload-env-file 'force))
|
||||
(doom-reload-autoloads force-p)
|
||||
(let (doom-init-p)
|
||||
(doom-initialize))
|
||||
(compile (format "%s/bin/doom refresh -f" doom-emacs-dir))
|
||||
(while compilation-in-progress
|
||||
(sit-for 1))
|
||||
(doom-initialize 'force)
|
||||
(with-demoted-errors "PRIVATE CONFIG ERROR: %s"
|
||||
(let (doom-init-modules-p)
|
||||
(doom-initialize-modules)))
|
||||
(when (bound-and-true-p doom-packages)
|
||||
(doom/reload-packages))
|
||||
(general-auto-unbind-keys)
|
||||
(unwind-protect
|
||||
(doom-initialize-modules 'force)
|
||||
(general-auto-unbind-keys t)))
|
||||
(run-hook-wrapped 'doom-reload-hook #'doom-try-run-hook))
|
||||
(general-auto-unbind-keys t)
|
||||
(message "Finished!"))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/reload-autoloads (&optional force-p)
|
||||
(defun doom/reload-autoloads ()
|
||||
"Reload only `doom-autoload-file' and `doom-package-autoload-file'.
|
||||
|
||||
This is much faster and safer than `doom/reload', but not as comprehensive. This
|
||||
|
@ -55,9 +62,11 @@ not reload your private config.
|
|||
|
||||
It is useful to only pull in changes performed by 'doom refresh' on the command
|
||||
line."
|
||||
(interactive "P")
|
||||
(doom-initialize-autoloads doom-autoload-file)
|
||||
(doom-initialize-autoloads doom-package-autoload-file))
|
||||
(interactive)
|
||||
(require 'core-cli)
|
||||
(require 'core-packages)
|
||||
(doom-initialize-packages)
|
||||
(doom-reload-autoloads nil 'force))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/reload-env ()
|
||||
|
@ -70,26 +79,4 @@ Uses the same mechanism as 'bin/doom env reload'."
|
|||
(sit-for 1))
|
||||
(unless (file-readable-p doom-env-file)
|
||||
(error "Failed to generate env file"))
|
||||
(doom-load-env-vars doom-env-file))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/reload-font ()
|
||||
"Reload your fonts, if they're set.
|
||||
See `doom|init-fonts'."
|
||||
(interactive)
|
||||
(when doom-font
|
||||
(set-frame-font doom-font t))
|
||||
(doom|init-fonts)
|
||||
(mapc #'doom|init-emoji-fonts (frame-list)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/reload-theme ()
|
||||
"Reload the current color theme."
|
||||
(interactive)
|
||||
(let ((theme (or (car-safe custom-enabled-themes) doom-theme)))
|
||||
(when theme
|
||||
(mapc #'disable-theme custom-enabled-themes))
|
||||
(when (and doom-theme (not (memq doom-theme custom-enabled-themes)))
|
||||
(let (doom--prefer-theme-elc)
|
||||
(load-theme doom-theme t)))
|
||||
(doom|init-fonts)))
|
||||
(doom-load-envvars-file doom-env-file))
|
||||
|
|
|
@ -1,5 +1,19 @@
|
|||
;;; core/autoload/debug.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-run-all-startup-hooks-h ()
|
||||
"Run all startup Emacs hooks. Meant to be executed after starting Emacs with
|
||||
-q or -Q, for example:
|
||||
|
||||
emacs -Q -l init.el -f doom-run-all-startup-hooks-h"
|
||||
(run-hook-wrapped 'after-init-hook #'doom-try-run-hook)
|
||||
(setq after-init-time (current-time))
|
||||
(dolist (hook (list 'delayed-warnings-hook
|
||||
'emacs-startup-hook 'term-setup-hook
|
||||
'window-setup-hook))
|
||||
(run-hook-wrapped hook #'doom-try-run-hook)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Helpers
|
||||
|
||||
|
@ -16,44 +30,38 @@ 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
|
||||
(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))
|
||||
(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
|
||||
:type 'files :match "\\.elc$")))
|
||||
(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))
|
||||
|
@ -64,17 +72,25 @@ ready to be pasted in a bug report on github."
|
|||
(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))))
|
||||
'("n/a")))
|
||||
(packages
|
||||
,@(or (ignore-errors
|
||||
(require 'core-packages)
|
||||
(doom-initialize-packages)
|
||||
(cl-loop for (name . plist) in doom-packages
|
||||
if (doom-package-private-p name)
|
||||
collect
|
||||
(format
|
||||
"%s" (if-let (splist (doom-plist-delete (copy-sequence plist)
|
||||
:modules))
|
||||
(cons name splist)
|
||||
name))))
|
||||
'("n/a")))
|
||||
(elpa-packages
|
||||
,@(or (ignore-errors
|
||||
(cl-loop for (name . _) in package-alist
|
||||
collect (format "%s" name)))
|
||||
'("n/a"))))))))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -86,24 +102,56 @@ 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"
|
||||
(let ((default-directory doom-core-dir))
|
||||
(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")))
|
||||
"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...")
|
||||
(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! (doom-info))
|
||||
(kill-new (doom-info))
|
||||
(message "Done! Copied to clipboard.")))
|
||||
(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 +192,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
|
||||
|
@ -169,12 +217,12 @@ markdown and copies it to your clipboard, ready to be pasted into bug reports!"
|
|||
(load! "config" (plist-get plist :path) t)))
|
||||
doom-modules)
|
||||
(run-hook-wrapped 'doom-init-modules-hook #'doom-try-run-hook)
|
||||
(doom|run-all-startup-hooks)))
|
||||
(doom-run-all-startup-hooks-h)))
|
||||
(`vanilla-doom ; only Doom core
|
||||
`((setq doom-private-dir "/tmp/does/not/exist"
|
||||
doom-init-modules-p t)
|
||||
(load-file ,user-init-file)
|
||||
(doom|run-all-startup-hooks)))
|
||||
(doom-run-all-startup-hooks-h)))
|
||||
(`vanilla ; nothing loaded
|
||||
`((package-initialize)))))))
|
||||
"\n(unwind-protect (progn\n" contents "\n)\n"
|
||||
|
@ -357,7 +405,7 @@ If INIT-FILE is non-nil, profile that instead of USER-INIT-FILE."
|
|||
init-file
|
||||
esup-server-port
|
||||
esup-depth)
|
||||
"--eval=(doom|run-all-startup-hooks)"))))
|
||||
"--eval=(doom-run-all-startup-hooks-h)"))))
|
||||
(when esup-run-as-batch-p
|
||||
(setq process-args (append process-args '("--batch"))))
|
||||
(setq esup-child-process (apply #'start-process process-args)))
|
||||
|
|
|
@ -1,24 +1,94 @@
|
|||
;;; core/autoload/files.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;
|
||||
;; Public library
|
||||
(defun doom--resolve-path-forms (spec &optional directory)
|
||||
"Converts a simple nested series of or/and forms into a series of
|
||||
`file-exists-p' checks.
|
||||
|
||||
For example
|
||||
|
||||
(doom--resolve-path-forms
|
||||
'(or A (and B C))
|
||||
\"~\")
|
||||
|
||||
Returns (approximately):
|
||||
|
||||
'(let* ((_directory \"~\")
|
||||
(A (expand-file-name A _directory))
|
||||
(B (expand-file-name B _directory))
|
||||
(C (expand-file-name C _directory)))
|
||||
(or (and (file-exists-p A) A)
|
||||
(and (if (file-exists-p B) B)
|
||||
(if (file-exists-p C) C))))
|
||||
|
||||
This is used by `file-exists-p!' and `project-file-exists-p!'."
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(let ((exists-fn (if (fboundp 'projectile-file-exists-p)
|
||||
#'projectile-file-exists-p
|
||||
#'file-exists-p)))
|
||||
(if (and (listp spec)
|
||||
(memq (car spec) '(or and)))
|
||||
(cons (car spec)
|
||||
(mapcar (doom-rpartial #'doom--resolve-path-forms directory)
|
||||
(cdr spec)))
|
||||
(let ((filevar (make-symbol "file")))
|
||||
`(let* ((file-name-handler-alist nil)
|
||||
(,filevar ,spec))
|
||||
(and ,(if directory
|
||||
`(let ((default-directory ,directory))
|
||||
(,exists-fn ,filevar))
|
||||
(list exists-fn filevar))
|
||||
,filevar))))))
|
||||
|
||||
(defun doom--path (&rest segments)
|
||||
(let (file-name-handler-alist)
|
||||
(let ((dir (pop segments)))
|
||||
(unless segments
|
||||
(setq dir (expand-file-name dir)))
|
||||
(while segments
|
||||
(setq dir (expand-file-name (car segments) dir)
|
||||
segments (cdr segments)))
|
||||
dir)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-glob (&rest segments)
|
||||
"Construct a path from SEGMENTS and expand glob patterns.
|
||||
Returns nil if the path doesn't exist."
|
||||
(let* (case-fold-search
|
||||
file-name-handler-alist
|
||||
(dir (apply #'doom--path segments)))
|
||||
(if (string-match-p "[[*?]" dir)
|
||||
(file-expand-wildcards dir t)
|
||||
(if (file-exists-p dir)
|
||||
dir))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-path (&rest segments)
|
||||
"Constructs a file path from SEGMENTS."
|
||||
(if segments
|
||||
(apply #'doom--path segments)
|
||||
(file!)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-dir (&rest segments)
|
||||
"Constructs a path from SEGMENTS.
|
||||
See `doom-path'."
|
||||
(when-let (path (apply #'doom-path segments))
|
||||
(directory-file-name (file-name-directory path))))
|
||||
|
||||
;;;###autoload
|
||||
(cl-defun doom-files-in
|
||||
(path-or-paths &rest rest
|
||||
(paths &rest rest
|
||||
&key
|
||||
filter
|
||||
map
|
||||
full
|
||||
(sort t) ; TODO Allow a function for custom sorting?
|
||||
(full t)
|
||||
(follow-symlinks t)
|
||||
(type 'files)
|
||||
(relative-to (unless full default-directory))
|
||||
(depth 99999)
|
||||
(mindepth 0)
|
||||
(match "/[^._]"))
|
||||
"Returns a list of files/directories in PATH-OR-PATHS (one string path or a
|
||||
list of them).
|
||||
(match "/[^._][^/]+"))
|
||||
"Return a list of files/directories in PATHS (one string or a list of them).
|
||||
|
||||
FILTER is a function or symbol that takes one argument (the path). If it returns
|
||||
non-nil, the entry will be excluded.
|
||||
|
@ -37,49 +107,50 @@ be relative to it.
|
|||
The search recurses up to DEPTH and no further. DEPTH is an integer.
|
||||
|
||||
MATCH is a string regexp. Only entries that match it will be included."
|
||||
(cond
|
||||
((listp path-or-paths)
|
||||
(cl-loop for path in path-or-paths
|
||||
if (file-directory-p path)
|
||||
nconc (apply #'doom-files-in path (plist-put rest :relative-to relative-to))))
|
||||
((let ((path path-or-paths)
|
||||
(let (file-name-handler-alist
|
||||
result)
|
||||
(when (file-directory-p path)
|
||||
(dolist (file (directory-files path nil "." sort))
|
||||
(unless (member file '("." ".."))
|
||||
(let ((fullpath (expand-file-name file path)))
|
||||
(cond ((file-directory-p fullpath)
|
||||
(when (and (memq type '(t dirs))
|
||||
(string-match-p match fullpath)
|
||||
(not (and filter (funcall filter fullpath)))
|
||||
(not (and (file-symlink-p fullpath)
|
||||
(dolist (file (mapcan (doom-rpartial #'doom-glob "*") (doom-enlist paths)))
|
||||
(cond ((file-directory-p file)
|
||||
(nconcq! result
|
||||
(and (memq type '(t dirs))
|
||||
(string-match-p match file)
|
||||
(not (and filter (funcall filter file)))
|
||||
(not (and (file-symlink-p file)
|
||||
(not follow-symlinks)))
|
||||
(<= mindepth 0))
|
||||
(setq result
|
||||
(nconc result
|
||||
(list (cond (map (funcall map fullpath))
|
||||
(relative-to (file-relative-name fullpath relative-to))
|
||||
(fullpath))))))
|
||||
(unless (< depth 1)
|
||||
(setq result
|
||||
(nconc result (apply #'doom-files-in fullpath
|
||||
(append `(:mindepth ,(1- mindepth)
|
||||
:depth ,(1- depth)
|
||||
:relative-to ,relative-to)
|
||||
rest))))))
|
||||
(<= mindepth 0)
|
||||
(list (cond (map (funcall map file))
|
||||
(relative-to (file-relative-name file relative-to))
|
||||
(file))))
|
||||
(and (>= depth 1)
|
||||
(apply #'doom-files-in file
|
||||
(append (list :mindepth (1- mindepth)
|
||||
:depth (1- depth)
|
||||
:relative-to relative-to)
|
||||
rest)))))
|
||||
((and (memq type '(t files))
|
||||
(string-match-p match fullpath)
|
||||
(not (and filter (funcall filter fullpath)))
|
||||
(string-match-p match file)
|
||||
(not (and filter (funcall filter file)))
|
||||
(<= mindepth 0))
|
||||
(push (if relative-to
|
||||
(file-relative-name fullpath relative-to)
|
||||
fullpath)
|
||||
result))))))
|
||||
result)))))
|
||||
(file-relative-name file relative-to)
|
||||
file)
|
||||
result))))
|
||||
result))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro file-exists-p! (files &optional directory)
|
||||
"Returns non-nil if the FILES in DIRECTORY all exist.
|
||||
|
||||
DIRECTORY is a path; defaults to `default-directory'.
|
||||
|
||||
Returns the last file found to meet the rules set by FILES, which can be a
|
||||
single file or nested compound statement of `and' and `or' statements."
|
||||
`(let ((p ,(doom--resolve-path-forms files directory)))
|
||||
(and p (expand-file-name p ,directory))))
|
||||
|
||||
|
||||
;;
|
||||
;; Helpers
|
||||
;;; Helpers
|
||||
|
||||
(defun doom--forget-file (old-path &optional new-path)
|
||||
"Ensure `recentf', `projectile' and `save-place' forget OLD-PATH."
|
||||
|
@ -131,7 +202,7 @@ MATCH is a string regexp. Only entries that match it will be included."
|
|||
|
||||
|
||||
;;
|
||||
;; Commands
|
||||
;;; Commands
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/delete-this-file (&optional path force-p)
|
||||
|
|
|
@ -50,7 +50,7 @@ FRAME parameter defaults to current frame."
|
|||
(let ((new-size (+ (string-to-number (aref font xlfd-regexp-pixelsize-subnum))
|
||||
increment)))
|
||||
(unless (> new-size 0)
|
||||
(error "Font is to small at %d" new-size))
|
||||
(error "Font is too small at %d" new-size))
|
||||
(aset font xlfd-regexp-pixelsize-subnum (number-to-string new-size)))
|
||||
;; Set point size & width to "*", so frame width will adjust to new font size
|
||||
(aset font xlfd-regexp-pointsize-subnum "*")
|
||||
|
@ -65,6 +65,15 @@ FRAME parameter defaults to current frame."
|
|||
;;
|
||||
;;; Commands
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/reload-font ()
|
||||
"Reload your fonts, if they're set.
|
||||
See `doom-init-fonts-h'."
|
||||
(interactive)
|
||||
(when doom-font
|
||||
(set-frame-font doom-font t))
|
||||
(mapc #'doom-init-fonts-h (frame-list)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/increase-font-size (count)
|
||||
"Enlargens the font size across the current frame."
|
||||
|
|
234
core/autoload/format.el
Normal file
234
core/autoload/format.el
Normal file
|
@ -0,0 +1,234 @@
|
|||
;;; core/autoload/format.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar doom-format-ansi-alist
|
||||
'(;; fx
|
||||
(bold 1 :weight bold)
|
||||
(dark 2)
|
||||
(italic 3 :slant italic)
|
||||
(underscore 4 :underline t)
|
||||
(blink 5)
|
||||
(rapid 6)
|
||||
(contrary 7)
|
||||
(concealed 8)
|
||||
(strike 9 :strike-through t)
|
||||
;; fg
|
||||
(black 30 term-color-black)
|
||||
(red 31 term-color-red)
|
||||
(green 32 term-color-green)
|
||||
(yellow 33 term-color-yellow)
|
||||
(blue 34 term-color-blue)
|
||||
(magenta 35 term-color-magenta)
|
||||
(cyan 36 term-color-cyan)
|
||||
(white 37 term-color-white)
|
||||
;; bg
|
||||
(on-black 40 term-color-black)
|
||||
(on-red 41 term-color-red)
|
||||
(on-green 42 term-color-green)
|
||||
(on-yellow 43 term-color-yellow)
|
||||
(on-blue 44 term-color-blue)
|
||||
(on-magenta 45 term-color-magenta)
|
||||
(on-cyan 46 term-color-cyan)
|
||||
(on-white 47 term-color-white))
|
||||
"An alist of fg/bg/fx names mapped to ansi codes and term-color-* variables.
|
||||
|
||||
This serves as the cipher for converting (COLOR ...) function calls in `print!'
|
||||
and `format!' into colored output, where COLOR is any car of this list.")
|
||||
|
||||
(defvar doom-format-class-alist
|
||||
`((color . doom--format-color)
|
||||
(class . doom--format-class)
|
||||
(indent . doom--format-indent)
|
||||
(autofill . doom--format-autofill)
|
||||
|
||||
(success . (lambda (str &rest args)
|
||||
(apply #'doom--format-color 'green (format "✓ %s" str) args)))
|
||||
(warn . (lambda (str &rest args)
|
||||
(apply #'doom--format-color 'yellow (format "! %s" str) args)))
|
||||
(error . (lambda (str &rest args)
|
||||
(apply #'doom--format-color 'red (format "x %s" str) args)))
|
||||
(info . (lambda (str &rest args)
|
||||
(concat "- " (if args (apply #'format str args) str))))
|
||||
(start . (lambda (str &rest args)
|
||||
(concat "> " (if args (apply #'format str args) str))))
|
||||
(debug . (lambda (str &rest args)
|
||||
(if doom-debug-mode
|
||||
(if args
|
||||
(apply #'format str args)
|
||||
(format "%s" str))
|
||||
"")))
|
||||
(path . abbreviate-file-name)
|
||||
(symbol . symbol-name)
|
||||
(relpath . (lambda (str &optional dir)
|
||||
(if (or (not str)
|
||||
(not (stringp str))
|
||||
(string-empty-p str))
|
||||
str
|
||||
(let ((dir (or dir (file-truename default-directory)))
|
||||
(str (file-truename str)))
|
||||
(if (file-in-directory-p str dir)
|
||||
(file-relative-name str dir)
|
||||
(abbreviate-file-name str))))))
|
||||
(filename . file-name-nondirectory)
|
||||
(dirname . (lambda (path)
|
||||
(unless (file-directory-p path)
|
||||
(setq path (file-name-directory path)))
|
||||
(directory-file-name path))))
|
||||
"An alist of text classes that map to transformation functions.
|
||||
|
||||
Any of these classes can be called like functions from within `format!' and
|
||||
`print!' calls, which will transform their input.")
|
||||
|
||||
(defvar doom-format-indent 0
|
||||
"Level to rigidly indent text returned by `format!' and `print!'.")
|
||||
|
||||
(defvar doom-format-backend
|
||||
(if noninteractive 'ansi 'text-properties)
|
||||
"Determines whether to print colors with ANSI codes or with text properties.
|
||||
|
||||
Accepts 'ansi and 'text-properties. nil means don't render colors.")
|
||||
|
||||
|
||||
;;
|
||||
;;; Library
|
||||
|
||||
(defun doom--format (output)
|
||||
(if (string-empty-p (string-trim output))
|
||||
""
|
||||
(concat (make-string doom-format-indent 32)
|
||||
(replace-regexp-in-string
|
||||
"\n" (concat "\n" (make-string doom-format-indent 32))
|
||||
output t t))))
|
||||
|
||||
(defun doom--format-print (output)
|
||||
(unless (string-empty-p output)
|
||||
(if (not noninteractive)
|
||||
(message "%s" output)
|
||||
(princ output)
|
||||
(terpri)) ; newline
|
||||
t))
|
||||
|
||||
(defun doom--format-indent (width text &optional prefix)
|
||||
"Indent TEXT by WIDTH spaces. If ARGS, format TEXT with them."
|
||||
(with-temp-buffer
|
||||
(setq text (format "%s" text))
|
||||
(insert text)
|
||||
(indent-rigidly (point-min) (point-max) width)
|
||||
(when (stringp prefix)
|
||||
(when (> width 2)
|
||||
(goto-char (point-min))
|
||||
(beginning-of-line-text)
|
||||
(delete-char (- (length prefix)))
|
||||
(insert prefix)))
|
||||
(buffer-string)))
|
||||
|
||||
(defun doom--format-autofill (&rest msgs)
|
||||
"Ensure MSG is split into lines no longer than `fill-column'."
|
||||
(with-temp-buffer
|
||||
(let ((fill-column 76))
|
||||
(dolist (line msgs)
|
||||
(when line
|
||||
(insert (format "%s" line))))
|
||||
(fill-region (point-min) (point-max))
|
||||
(buffer-string))))
|
||||
|
||||
(defun doom--format-color (style format &rest args)
|
||||
"Apply STYLE to formatted MESSAGE with ARGS.
|
||||
|
||||
STYLE is a symbol that correlates to `doom-format-ansi-alist'.
|
||||
|
||||
In a noninteractive session, this wraps the result in ansi color codes.
|
||||
Otherwise, it maps colors to a term-color-* face."
|
||||
(let* ((code (cadr (assq style doom-format-ansi-alist)))
|
||||
(format (format "%s" format))
|
||||
(message (if args (apply #'format format args) format)))
|
||||
(unless code
|
||||
(error "%S is an invalid color" style))
|
||||
(pcase doom-format-backend
|
||||
(`ansi
|
||||
(format "\e[%dm%s\e[%dm" code message 0))
|
||||
(`text-properties
|
||||
(require 'term) ; piggyback on term's color faces
|
||||
(propertize
|
||||
message
|
||||
'face
|
||||
(append (get-text-property 0 'face format)
|
||||
(cond ((>= code 40)
|
||||
`(:background ,(caddr (assq style doom-format-ansi-alist))))
|
||||
((>= code 30)
|
||||
`(:foreground ,(face-foreground (caddr (assq style doom-format-ansi-alist)))))
|
||||
((cddr (assq style doom-format-ansi-alist)))))))
|
||||
(_ message))))
|
||||
|
||||
(defun doom--format-class (class format &rest args)
|
||||
"Apply CLASS to formatted format with ARGS.
|
||||
|
||||
CLASS is derived from `doom-format-class-alist', and can contain any arbitrary,
|
||||
transformative logic."
|
||||
(let (fn)
|
||||
(cond ((setq fn (cdr (assq class doom-format-class-alist)))
|
||||
(if (functionp fn)
|
||||
(apply fn format args)
|
||||
(error "%s does not have a function" class)))
|
||||
(args (apply #'format format args))
|
||||
(format))))
|
||||
|
||||
(defun doom--format-apply (forms &optional sub)
|
||||
"Replace color-name functions with calls to `doom--format-color'."
|
||||
(cond ((null forms) nil)
|
||||
((listp forms)
|
||||
(append (cond ((not (symbolp (car forms)))
|
||||
(list (doom--format-apply (car forms))))
|
||||
(sub
|
||||
(list (car forms)))
|
||||
((assq (car forms) doom-format-ansi-alist)
|
||||
`(doom--format-color ',(car forms)))
|
||||
((assq (car forms) doom-format-class-alist)
|
||||
`(doom--format-class ',(car forms)))
|
||||
((list (car forms))))
|
||||
(doom--format-apply (cdr forms) t)
|
||||
nil))
|
||||
(forms)))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro format! (message &rest args)
|
||||
"An alternative to `format' that understands (color ...) and converts them
|
||||
into faces or ANSI codes depending on the type of sesssion we're in."
|
||||
`(doom--format (format ,@(doom--format-apply `(,message ,@args)))))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro print-group! (&rest body)
|
||||
"Indents any `print!' or `format!' output within BODY."
|
||||
`(let ((doom-format-indent (+ 2 doom-format-indent)))
|
||||
,@body))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro print! (message &rest args)
|
||||
"Uses `message' in interactive sessions and `princ' otherwise (prints to
|
||||
standard out).
|
||||
|
||||
Can be colored using (color ...) blocks:
|
||||
|
||||
(print! \"Hello %s\" (bold (blue \"How are you?\")))
|
||||
(print! \"Hello %s\" (red \"World\"))
|
||||
(print! (green \"Great %s!\") \"success\")
|
||||
|
||||
Uses faces in interactive sessions and ANSI codes otherwise."
|
||||
`(doom--format-print (format! ,message ,@args)))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro insert! (message &rest args)
|
||||
"Like `insert'; the last argument must be format arguments for MESSAGE.
|
||||
|
||||
\(fn MESSAGE... ARGS)"
|
||||
`(insert (format! (concat ,message ,@(butlast args))
|
||||
,@(car (last args)))))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro error! (message &rest args)
|
||||
"Like `error', but with the power of `format!'."
|
||||
`(error (format! ,message ,@args)))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro user-error! (message &rest args)
|
||||
"Like `user-error', but with the power of `format!'."
|
||||
`(user-error (format! ,message ,@args)))
|
|
@ -121,6 +121,7 @@ selection of all minor-modes, active or not."
|
|||
;;
|
||||
;;; Documentation commands
|
||||
|
||||
(defvar org-agenda-files)
|
||||
(defun doom--org-headings (files &optional depth include-files)
|
||||
"TODO"
|
||||
(require 'org)
|
||||
|
@ -155,6 +156,7 @@ selection of all minor-modes, active or not."
|
|||
(mapc #'kill-buffer org-agenda-new-buffers)
|
||||
(setq org-agenda-new-buffers nil))))
|
||||
|
||||
(defvar ivy-sort-functions-alist)
|
||||
;;;###autoload
|
||||
(defun doom-completing-read-org-headings (prompt files &optional depth include-files initial-input)
|
||||
"TODO"
|
||||
|
@ -197,8 +199,7 @@ selection of all minor-modes, active or not."
|
|||
"Find in News: "
|
||||
(nreverse (doom-files-in (expand-file-name "news" doom-docs-dir)
|
||||
:match "/[0-9]"
|
||||
:relative-to doom-docs-dir
|
||||
:sort t))
|
||||
:relative-to doom-docs-dir))
|
||||
nil t initial-input))
|
||||
|
||||
;;;###autoload
|
||||
|
@ -365,10 +366,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
|
||||
|
@ -376,7 +381,7 @@ current file is in, or d) the module associated with the current major mode (see
|
|||
(split-string
|
||||
(shell-command-to-string
|
||||
(format "git grep --no-break --no-heading --line-number '%s %s\\($\\| \\)'"
|
||||
"\\(^;;;###package\\|(after!\\|(def-package!\\)"
|
||||
"\\(^;;;###package\\|(after!\\|(use-package!\\)"
|
||||
package))
|
||||
"\n" t)))
|
||||
|
||||
|
@ -392,17 +397,19 @@ If prefix arg is present, refresh the cache."
|
|||
(let* ((guess (or (function-called-at-point)
|
||||
(symbol-at-point))))
|
||||
(require 'finder-inf nil t)
|
||||
(require 'package)
|
||||
(unless package--initialized
|
||||
(package-initialize t))
|
||||
(let* ((doom--packages (doom--help-packages-list))
|
||||
(packages (cl-delete-duplicates
|
||||
(let ((packages (cl-delete-duplicates
|
||||
(append (mapcar 'car package-alist)
|
||||
(mapcar 'car package--builtins)
|
||||
(mapcar 'car doom--packages)
|
||||
(mapcar 'car (doom--help-packages-list))
|
||||
nil))))
|
||||
(unless (memq guess packages)
|
||||
(setq guess nil))
|
||||
(list (intern (completing-read (if guess
|
||||
(list
|
||||
(intern
|
||||
(completing-read (if guess
|
||||
(format "Select package to search for (default %s): "
|
||||
guess)
|
||||
"Describe package: ")
|
||||
|
@ -411,40 +418,45 @@ If prefix arg is present, refresh the cache."
|
|||
(if (or (package-desc-p package)
|
||||
(and (symbolp package)
|
||||
(or (assq package package-alist)
|
||||
(assq package package-archive-contents)
|
||||
(assq package package--builtins))))
|
||||
(describe-package package)
|
||||
(help-setup-xref (list #'doom/help-packages package)
|
||||
(called-interactively-p 'interactive))
|
||||
(with-help-window (help-buffer)
|
||||
(with-current-buffer standard-output
|
||||
(prin1 package)
|
||||
(princ " is a site package.\n\n"))))
|
||||
(with-help-window (help-buffer)))
|
||||
(save-excursion
|
||||
(with-current-buffer (help-buffer)
|
||||
(let ((doom-packages (doom--help-packages-list))
|
||||
(inhibit-read-only t)
|
||||
(indent (make-string 13 ? )))
|
||||
(goto-char (point-min))
|
||||
(goto-char (point-max))
|
||||
(if (re-search-forward "^ *Status: " nil t)
|
||||
(progn
|
||||
(end-of-line)
|
||||
(insert "\n"))
|
||||
(re-search-forward "\n\n" nil t))
|
||||
|
||||
(package--print-help-section "Package")
|
||||
(insert (symbol-name package) "\n")
|
||||
|
||||
(package--print-help-section "Source")
|
||||
(insert (or (pcase (ignore-errors (doom-package-backend package))
|
||||
(`elpa (concat "[M]ELPA " (doom--package-url package)))
|
||||
(`quelpa (format "QUELPA %s" (prin1-to-string (doom-package-prop package :recipe))))
|
||||
(`emacs "Built-in")
|
||||
(_ (symbol-file package)))
|
||||
(insert (or (pcase (doom-package-backend package)
|
||||
(`straight
|
||||
(format! "Straight\n%s"
|
||||
(indent
|
||||
13 (string-trim
|
||||
(pp-to-string
|
||||
(doom-package-build-recipe package))))))
|
||||
(`elpa
|
||||
(format "[M]ELPA %s" (doom--package-url package)))
|
||||
(`builtin "Built-in")
|
||||
(_ (abbreviate-file-name (symbol-file package))))
|
||||
"unknown")
|
||||
"\n")
|
||||
|
||||
(when (assq package doom-packages)
|
||||
(package--print-help-section "Modules")
|
||||
(insert "Declared by the following Doom modules:\n")
|
||||
(dolist (m (doom-package-prop package :modules))
|
||||
(dolist (m (doom-package-get package :modules))
|
||||
(insert indent)
|
||||
(doom--help-package-insert-button
|
||||
(format "%s %s" (car m) (or (cdr m) ""))
|
||||
|
@ -469,7 +481,9 @@ If prefix arg is present, refresh the cache."
|
|||
(find-file (expand-file-name file doom-emacs-dir))
|
||||
(goto-char (point-min))
|
||||
(forward-line (1- line))
|
||||
(recenter)))))))))
|
||||
(recenter)))))
|
||||
|
||||
(insert "\n\n")))))
|
||||
|
||||
(defvar doom--package-cache nil)
|
||||
(defun doom--package-list ()
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
;;; core/autoload/line-numbers.el -*- lexical-binding: t; -*-
|
||||
;;;###if (version< emacs-version "26.1")
|
||||
|
||||
;; This was lifted out of the display-line-numbers library in Emacs 26.1 and
|
||||
;; modified to use nlinum for Emacs 25.x users. It should be removed should
|
||||
;; Emacs 25 support be removed.
|
||||
;; DEPRECATED This was lifted out of the display-line-numbers library in Emacs
|
||||
;; 26.1 and modified to use nlinum for Emacs 25.x users. It should be removed
|
||||
;; should Emacs 25 support be removed.
|
||||
|
||||
;;;###autoload
|
||||
(defvar display-line-numbers t
|
||||
|
@ -52,7 +52,7 @@ to display all line numbers in the buffer."
|
|||
:type 'boolean)
|
||||
|
||||
;;;###autoload
|
||||
(defun line-number-display-width ()
|
||||
(defun line-number-display-width (&optional _)
|
||||
"Return the width used for displaying line numbers in the
|
||||
selected window."
|
||||
(length (save-excursion (goto-char (point-max))
|
||||
|
|
|
@ -1,132 +0,0 @@
|
|||
;;; core/autoload/message.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar doom-ansi-alist
|
||||
'(;; fx
|
||||
(bold 1 :weight bold)
|
||||
(dark 2)
|
||||
(italic 3 :slant italic)
|
||||
(underscore 4 :underline t)
|
||||
(blink 5)
|
||||
(rapid 6)
|
||||
(contrary 7)
|
||||
(concealed 8)
|
||||
(strike 9 :strike-through t)
|
||||
;; fg
|
||||
(black 30 term-color-black)
|
||||
(red 31 term-color-red)
|
||||
(green 32 term-color-green)
|
||||
(yellow 33 term-color-yellow)
|
||||
(blue 34 term-color-blue)
|
||||
(magenta 35 term-color-magenta)
|
||||
(cyan 36 term-color-cyan)
|
||||
(white 37 term-color-white)
|
||||
;; bg
|
||||
(on-black 40 term-color-black)
|
||||
(on-red 41 term-color-red)
|
||||
(on-green 42 term-color-green)
|
||||
(on-yellow 43 term-color-yellow)
|
||||
(on-blue 44 term-color-blue)
|
||||
(on-magenta 45 term-color-magenta)
|
||||
(on-cyan 46 term-color-cyan)
|
||||
(on-white 47 term-color-white))
|
||||
"TODO")
|
||||
|
||||
(defvar doom-message-backend
|
||||
(if noninteractive 'ansi 'text-properties)
|
||||
"Determines whether to print colors with ANSI codes or with text properties.
|
||||
|
||||
Accepts 'ansi and 'text-properties. nil means don't render colors.")
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-message-indent (width text &rest args)
|
||||
"Indent TEXT by WIDTH spaces. If ARGS, format TEXT with them."
|
||||
(with-temp-buffer
|
||||
(insert (apply #'format text args))
|
||||
(let ((fill-column 80))
|
||||
(fill-region (point-min) (point-max))
|
||||
(indent-rigidly (point-min) (point-max) width))
|
||||
(when (> width 2)
|
||||
(goto-char (point-min))
|
||||
(beginning-of-line-text)
|
||||
(delete-char -2)
|
||||
(insert "> "))
|
||||
(buffer-string)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-message-autofill (&rest msgs)
|
||||
"Ensure MSG is split into lines no longer than `fill-column'."
|
||||
(with-temp-buffer
|
||||
(let ((fill-column 70))
|
||||
(dolist (line msgs)
|
||||
(when line
|
||||
(insert line)))
|
||||
(fill-region (point-min) (point-max))
|
||||
(buffer-string))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-color-apply (style text &rest args)
|
||||
"Apply CODE to formatted MESSAGE with ARGS. CODE is derived from any of
|
||||
`doom-message-fg', `doom-message-bg' or `doom-message-fx'.
|
||||
|
||||
In a noninteractive session, this wraps the result in ansi color codes.
|
||||
Otherwise, it maps colors to a term-color-* face."
|
||||
(let ((code (car (cdr (assq style doom-ansi-alist))))
|
||||
(message (if args (apply #'format text args) text)))
|
||||
(pcase doom-message-backend
|
||||
(`ansi
|
||||
(format "\e[%dm%s\e[%dm"
|
||||
(car (cdr (assq style doom-ansi-alist)))
|
||||
message 0))
|
||||
(`text-properties
|
||||
(require 'term) ; piggyback on term's color faces
|
||||
(propertize
|
||||
message
|
||||
'face
|
||||
(append (get-text-property 0 'face text)
|
||||
(cond ((>= code 40)
|
||||
`(:background ,(caddr (assq style doom-ansi-alist))))
|
||||
((>= code 30)
|
||||
`(:foreground ,(face-foreground (caddr (assq style doom-ansi-alist)))))
|
||||
((cddr (assq style doom-ansi-alist)))))))
|
||||
(_ message))))
|
||||
|
||||
(defun doom--short-color-replace (forms)
|
||||
"Replace color-name functions with calls to `doom-color-apply'."
|
||||
(cond ((null forms) nil)
|
||||
((listp forms)
|
||||
(append (cond ((not (symbolp (car forms)))
|
||||
(list (doom--short-color-replace (car forms))))
|
||||
((assq (car forms) doom-ansi-alist)
|
||||
`(doom-color-apply ',(car forms)))
|
||||
((eq (car forms) 'color)
|
||||
(pop forms)
|
||||
`(doom-color-apply ,(car forms)))
|
||||
((memq (car forms) '(indent autofill))
|
||||
(let ((fn (pop forms)))
|
||||
`(,(intern (format "doom-message-%s" fn))
|
||||
,(car forms))))
|
||||
((list (car forms))))
|
||||
(doom--short-color-replace (cdr forms))
|
||||
nil))
|
||||
(forms)))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro format! (message &rest args)
|
||||
"An alternative to `format' that understands (color ...) and converts them
|
||||
into faces or ANSI codes depending on the type of sesssion we're in."
|
||||
`(format ,@(doom--short-color-replace `(,message ,@args))))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro print! (message &rest args)
|
||||
"Uses `message' in interactive sessions and `princ' otherwise (prints to
|
||||
standard out).
|
||||
|
||||
Can be colored using (color ...) blocks:
|
||||
|
||||
(print! \"Hello %s\" (bold (blue \"How are you?\")))
|
||||
(print! \"Hello %s\" (red \"World\"))
|
||||
(print! (green \"Great %s!\" \"success\"))
|
||||
|
||||
Uses faces in interactive sessions and ANSI codes otherwise."
|
||||
`(progn (princ (format! ,message ,@args))
|
||||
(terpri)))
|
|
@ -1,128 +1,64 @@
|
|||
;;; 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)))
|
||||
|
||||
;;;###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)))
|
||||
|
||||
;;;###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)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-psuedo-name (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))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-package-backend (package &optional noerror)
|
||||
"Return backend that PACKAGE was installed with.
|
||||
|
||||
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))
|
||||
(let ((plist (cdr (assq package doom-packages))))
|
||||
(if prop
|
||||
(if (plist-member plist prop)
|
||||
(plist-get plist prop)
|
||||
nil-value)
|
||||
nil-value))
|
||||
plist)))
|
||||
|
||||
;;;###autoload
|
||||
(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-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-build-time (package)
|
||||
"TODO"
|
||||
(car (gethash (symbol-name package) straight--build-cache)))
|
||||
|
||||
;;;###autoload
|
||||
(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)))
|
||||
|
||||
(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,212 +67,94 @@ 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))
|
||||
(assq :private (doom-package-get package :modules)))
|
||||
|
||||
;;;###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))))
|
||||
(assq :core (doom-package-get 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)))))
|
||||
(defun doom-package-backend (package)
|
||||
"Return 'straight, 'builtin, 'elpa or 'other, depending on how PACKAGE is
|
||||
installed."
|
||||
(cond ((gethash (symbol-name package) straight--build-cache)
|
||||
'straight)
|
||||
((or (doom-package-built-in-p package)
|
||||
(assq package package--builtins))
|
||||
'builtin)
|
||||
((assq package package-alist)
|
||||
'elpa)
|
||||
('other)))
|
||||
|
||||
;;;###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))))))
|
||||
)
|
||||
|
||||
|
||||
;;
|
||||
;;; Package list getters
|
||||
|
||||
;;;###autoload
|
||||
(cl-defun doom-find-packages (&key (installed 'any)
|
||||
(private 'any)
|
||||
(disabled 'any)
|
||||
(pinned 'any)
|
||||
(ignored 'any)
|
||||
(core 'any)
|
||||
_changed
|
||||
backend
|
||||
deps)
|
||||
"Retrieves a list of primary packages (i.e. non-dependencies). Each element is
|
||||
a cons cell, whose car is the package symbol and whose cdr is the quelpa recipe
|
||||
(if any).
|
||||
|
||||
You can build a filtering criteria using one or more of the following
|
||||
properties:
|
||||
|
||||
:backend 'quelpa|'elpa|'emacs|'any
|
||||
Include packages installed through 'quelpa, 'elpa or 'emacs. 'any is the
|
||||
wildcard.
|
||||
:installed BOOL|'any
|
||||
t = only include installed packages
|
||||
nil = exclude installed packages
|
||||
:private BOOL|'any
|
||||
t = only include user-installed packages
|
||||
nil = exclude user-installed packages
|
||||
:core BOOL|'any
|
||||
t = only include Doom core packages
|
||||
nil = exclude Doom core packages
|
||||
:disabled BOOL|'any
|
||||
t = only include disabled packages
|
||||
nil = exclude disabled packages
|
||||
:ignored BOOL|'any
|
||||
t = only include ignored packages
|
||||
nil = exclude ignored packages
|
||||
:pinned BOOL|ARCHIVE
|
||||
Only return packages that are pinned (t), not pinned (nil) or pinned to a
|
||||
specific archive (stringp)
|
||||
:deps BOOL
|
||||
Includes the package's dependencies (t) or not (nil).
|
||||
|
||||
Warning: this function is expensive, as it re-evaluates your all packages.el
|
||||
files."
|
||||
(delete-dups
|
||||
(cl-loop for (sym . plist) in doom-packages
|
||||
if (and (or (not backend)
|
||||
(eq (doom-package-backend sym 'noerror) backend))
|
||||
(or (eq ignored 'any)
|
||||
(let* ((form (plist-get plist :ignore))
|
||||
(value (eval form)))
|
||||
(if ignored value (not value))))
|
||||
(or (eq disabled 'any)
|
||||
(if disabled
|
||||
(plist-get plist :disable)
|
||||
(not (plist-get plist :disable))))
|
||||
(or (eq installed 'any)
|
||||
(if installed
|
||||
(doom-package-installed-p sym)
|
||||
(not (doom-package-installed-p sym))))
|
||||
(or (eq private 'any)
|
||||
(let ((modules (plist-get plist :modules)))
|
||||
(if private
|
||||
(assq :private modules)
|
||||
(not (assq :private modules)))))
|
||||
(or (eq core 'any)
|
||||
(let ((modules (plist-get plist :modules)))
|
||||
(if core
|
||||
(assq :core modules)
|
||||
(not (assq :core modules)))))
|
||||
(or (eq pinned 'any)
|
||||
(cond ((eq pinned 't)
|
||||
(plist-get plist :pin))
|
||||
((null pinned)
|
||||
(not (plist-get plist :pin)))
|
||||
((equal (plist-get plist :pin) pinned)))))
|
||||
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)
|
||||
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 (let ((ppss (syntax-ppss)))
|
||||
(or (nth 3 ppss)
|
||||
(nth 4 ppss)))
|
||||
(cl-destructuring-bind (name . plist)
|
||||
(cdr (sexp-at-point))
|
||||
(push (cons
|
||||
name (plist-put
|
||||
plist :modules
|
||||
(list (doom-module-from-path file))))
|
||||
doom-packages)))))))
|
||||
((debug error)
|
||||
(signal 'doom-package-error
|
||||
(list (or (doom-module-from-path file)
|
||||
'(:private . packages))
|
||||
(list (doom-module-from-path file)
|
||||
e))))))
|
||||
|
||||
;;;###autoload
|
||||
|
@ -348,279 +166,38 @@ This excludes core packages listed in `doom-core-packages'.
|
|||
If ALL-P, gather packages unconditionally across all modules, including disabled
|
||||
ones."
|
||||
(let ((noninteractive t)
|
||||
(doom--stage 'packages)
|
||||
(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)
|
||||
(let ((private-packages (expand-file-name "packages.el" doom-private-dir)))
|
||||
doom-disabled-packages)
|
||||
(doom--read-module-packages-file
|
||||
(doom-path doom-core-dir "packages.el") all-p t)
|
||||
(let ((private-packages (doom-path doom-private-dir "packages.el")))
|
||||
(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
|
||||
:depth 2
|
||||
:full t
|
||||
:match "/packages\\.el$"
|
||||
:sort nil))
|
||||
:match "/packages\\.el$"))
|
||||
(cl-loop for key being the hash-keys of doom-modules
|
||||
for path = (doom-module-path (car key) (cdr key) "packages.el")
|
||||
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 ()
|
||||
"Reload `doom-packages', `package' and `quelpa'."
|
||||
(interactive)
|
||||
;; HACK straight.el must be loaded for this to work
|
||||
(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)
|
||||
|
|
89
core/autoload/plist.el
Normal file
89
core/autoload/plist.el
Normal file
|
@ -0,0 +1,89 @@
|
|||
;;; core/autoload/plist.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;
|
||||
;;; Macros
|
||||
|
||||
;;;###autoload
|
||||
(cl-defmacro doplist! ((arglist plist &optional retval) &rest body)
|
||||
"Loop over a PLIST's (property value) pairs then return RETVAL.
|
||||
|
||||
Evaluate BODY with either ARGLIST bound to (cons PROP VAL) or, if ARGLIST is a
|
||||
list, the pair is destructured into (CAR . CDR)."
|
||||
(declare (indent defun))
|
||||
(let ((plist-var (make-symbol "plist")))
|
||||
`(let ((,plist-var ,plist))
|
||||
(while ,plist-var
|
||||
(let ,(if (listp arglist)
|
||||
`((,(pop arglist) (pop ,plist-var))
|
||||
(,(pop arglist) (pop ,plist-var)))
|
||||
`((,arglist (cons (pop ,plist-var)
|
||||
(pop ,plist-var)))))
|
||||
,@body))
|
||||
,retval)))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro plist-put! (plist prop value)
|
||||
"Set PROP to VALUE in PLIST in-place."
|
||||
`(setq ,plist (plist-put ,plist ,prop ,value)))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro plist-delete! (plist prop)
|
||||
"Delete PROP from PLIST in-place."
|
||||
`(setq ,plist (doom-plist-delete ,plist ,prop)))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro with-plist! (plist props &rest body)
|
||||
"With props bound from PLIST to PROPS, evaluate BODY.
|
||||
|
||||
PROPS is a list of symbols. Each one is converted to a keyword and then its
|
||||
value is looked up in the PLIST and bound to the symbol for the duration of
|
||||
BODY."
|
||||
(declare (indent 2))
|
||||
(let ((plist-sym (make-symbol "plist")))
|
||||
`(let* ((,plist-sym ,plist)
|
||||
,@(cl-loop for prop in props
|
||||
collect
|
||||
`(,prop
|
||||
(plist-get
|
||||
,plist-sym
|
||||
,(doom-keyword-intern (symbol-name prop))))))
|
||||
,@body)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Library
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-plist-get (plist prop &optional nil-value)
|
||||
"Return PROP in PLIST, if it exists. Otherwise NIL-VALUE."
|
||||
(if-let (val (plist-member plist prop))
|
||||
(cadr val)
|
||||
nil-value))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-plist-merge (from-plist to-plist)
|
||||
"Destructively merge FROM-PLIST onto TO-PLIST"
|
||||
(let ((plist (copy-sequence from-plist)))
|
||||
(while plist
|
||||
(plist-put! to-plist (pop plist) (pop plist)))
|
||||
to-plist))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-plist-delete-nil (plist)
|
||||
"Delete `nil' properties from a copy of PLIST."
|
||||
(let (p)
|
||||
(while plist
|
||||
(if (car plist)
|
||||
(plist-put! p (car plist) (nth 1 plist)))
|
||||
(setq plist (cddr plist)))
|
||||
p))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-plist-delete (plist prop)
|
||||
"Delete PROP from a copy of PLIST."
|
||||
(let (p)
|
||||
(while plist
|
||||
(if (not (eq prop (car plist)))
|
||||
(plist-put! p (car plist) (nth 1 plist)))
|
||||
(setq plist (cddr plist)))
|
||||
p))
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
(defvar projectile-project-root nil)
|
||||
|
||||
;;;###autoload
|
||||
(autoload 'projectile-relevant-known-projects "projectile")
|
||||
;;;###autoload (autoload 'projectile-relevant-known-projects "projectile")
|
||||
|
||||
;;;###autodef
|
||||
(cl-defun set-project-type! (name &key predicate compile run test configure dir)
|
||||
|
@ -23,16 +22,6 @@
|
|||
;;
|
||||
;;; Macros
|
||||
|
||||
;;;###autoload
|
||||
(defmacro without-project-cache! (&rest body)
|
||||
"Run BODY with projectile's project-root cache disabled. This is necessary if
|
||||
you want to interactive with a project other than the one you're in."
|
||||
`(let ((projectile-project-root-cache (make-hash-table :test 'equal))
|
||||
projectile-project-name
|
||||
projectile-project-root
|
||||
projectile-require-project-root)
|
||||
,@body))
|
||||
|
||||
;;;###autoload
|
||||
(defmacro project-file-exists-p! (files)
|
||||
"Checks if the project has the specified FILES.
|
||||
|
@ -90,8 +79,8 @@ Returns nil if not in a project."
|
|||
"Return the name of the current project.
|
||||
|
||||
Returns '-' if not in a valid project."
|
||||
(if-let* ((project-root (or (doom-project-root dir)
|
||||
(if dir (expand-file-name dir)))))
|
||||
(if-let (project-root (or (doom-project-root dir)
|
||||
(if dir (expand-file-name dir))))
|
||||
(funcall projectile-project-name-function project-root)
|
||||
"-"))
|
||||
|
||||
|
@ -121,14 +110,16 @@ If DIR is not a project, it will be indexed (but not cached)."
|
|||
(setq projectile-enable-caching nil))
|
||||
(call-interactively
|
||||
;; Intentionally avoid `helm-projectile-find-file', because it runs
|
||||
;; asynchronously, and thus doesn't see the lexical `default-directory'
|
||||
(if (featurep! :completion ivy)
|
||||
;; asynchronously, and thus doesn't see the lexical
|
||||
;; `default-directory'
|
||||
(if (doom-module-p :completion 'ivy)
|
||||
#'counsel-projectile-find-file
|
||||
#'projectile-find-file)))
|
||||
((fboundp 'project-find-file-in) ; emacs 26.1+ only
|
||||
(project-find-file-in nil (list default-directory) nil))
|
||||
((fboundp 'counsel-file-jump) ; ivy only
|
||||
(call-interactively #'counsel-file-jump))
|
||||
((and (fboundp 'project-find-file-in) ; emacs 26.1+ only
|
||||
(project-current))
|
||||
(project-find-file-in nil (list default-directory) nil))
|
||||
((fboundp 'helm-find-files)
|
||||
(call-interactively #'helm-find-files))
|
||||
((call-interactively #'find-file)))))
|
||||
|
@ -138,8 +129,8 @@ If DIR is not a project, it will be indexed (but not cached)."
|
|||
"Traverse a file structure starting linearly from DIR."
|
||||
(let ((default-directory (file-truename (expand-file-name dir))))
|
||||
(call-interactively
|
||||
(cond ((featurep! :completion ivy)
|
||||
(cond ((doom-module-p :completion 'ivy)
|
||||
#'counsel-find-file)
|
||||
((featurep! :completion helm)
|
||||
((doom-module-p :completion 'helm)
|
||||
#'helm-find-files)
|
||||
(#'find-file)))))
|
||||
|
|
|
@ -19,18 +19,22 @@ following:
|
|||
(defvar doom-scratch-buffers nil
|
||||
"A list of active scratch buffers.")
|
||||
|
||||
(defvar-local doom-scratch-current-project nil
|
||||
(defvar doom-scratch-current-project nil
|
||||
"The name of the project associated with the current scratch buffer.")
|
||||
|
||||
(defvar doom-scratch-buffer-hook ()
|
||||
"The hooks to run after a scratch buffer is created.")
|
||||
|
||||
|
||||
(defun doom--load-persistent-scratch-buffer (name)
|
||||
(let ((scratch-file (expand-file-name (or name doom-scratch-default-file)
|
||||
(setq-local doom-scratch-current-project
|
||||
(or name
|
||||
doom-scratch-default-file))
|
||||
(let ((scratch-file
|
||||
(expand-file-name doom-scratch-current-project
|
||||
doom-scratch-dir)))
|
||||
(make-directory doom-scratch-dir t)
|
||||
(if (not (file-readable-p scratch-file))
|
||||
nil
|
||||
(when (file-readable-p scratch-file)
|
||||
(erase-buffer)
|
||||
(insert-file-contents scratch-file)
|
||||
(set-auto-mode)
|
||||
|
@ -39,48 +43,54 @@ following:
|
|||
;;;###autoload
|
||||
(defun doom-scratch-buffer (&optional mode directory project-name)
|
||||
"Return a scratchpad buffer in major MODE."
|
||||
(let* ((buffer-name (if project-name
|
||||
(with-current-buffer
|
||||
(get-buffer-create (if project-name
|
||||
(format "*doom:scratch (%s)*" project-name)
|
||||
"*doom:scratch*"))
|
||||
(buffer (get-buffer buffer-name)))
|
||||
(with-current-buffer (get-buffer-create buffer-name)
|
||||
(unless buffer
|
||||
(setq buffer (current-buffer)
|
||||
default-directory directory
|
||||
doom-scratch-current-project project-name)
|
||||
(setq doom-scratch-buffers (cl-delete-if-not #'buffer-live-p doom-scratch-buffers))
|
||||
(cl-pushnew buffer doom-scratch-buffers)
|
||||
(setq default-directory directory)
|
||||
(unless doom-scratch-current-project
|
||||
(doom--load-persistent-scratch-buffer project-name)
|
||||
(when (and (eq major-mode 'fundamental-mode)
|
||||
(functionp mode))
|
||||
(funcall mode))
|
||||
(add-hook 'kill-buffer-hook #'doom|persist-scratch-buffer nil 'local)
|
||||
(run-hooks 'doom-scratch-buffer-created-hook))
|
||||
buffer)))
|
||||
(funcall mode)))
|
||||
(cl-pushnew (current-buffer) doom-scratch-buffers)
|
||||
(add-hook 'kill-buffer-hook #'doom-persist-scratch-buffer-h nil 'local)
|
||||
(add-hook 'doom-switch-buffer-hook #'doom-persist-scratch-buffers-after-switch-h)
|
||||
(run-hooks 'doom-scratch-buffer-created-hook)
|
||||
(current-buffer)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Persistent scratch buffer
|
||||
|
||||
;;;###autoload
|
||||
(defun doom|persist-scratch-buffer ()
|
||||
(defun doom-persist-scratch-buffer-h ()
|
||||
"Save the current buffer to `doom-scratch-dir'."
|
||||
(write-region
|
||||
(point-min) (point-max)
|
||||
(expand-file-name (or doom-scratch-current-project doom-scratch-default-file)
|
||||
(expand-file-name (or doom-scratch-current-project
|
||||
doom-scratch-default-file)
|
||||
doom-scratch-dir)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom|persist-scratch-buffers ()
|
||||
(defun doom-persist-scratch-buffers-h ()
|
||||
"Save all scratch buffers to `doom-scratch-dir'."
|
||||
(setq doom-scratch-buffers (cl-delete-if-not #'buffer-live-p doom-scratch-buffers))
|
||||
(setq doom-scratch-buffers
|
||||
(cl-delete-if-not #'buffer-live-p doom-scratch-buffers))
|
||||
(dolist (buffer doom-scratch-buffers)
|
||||
(with-current-buffer buffer
|
||||
(doom|persist-scratch-buffer))))
|
||||
(doom-persist-scratch-buffer-h))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-persist-scratch-buffers-after-switch-h ()
|
||||
"Kill scratch buffers when they are no longer visible, saving them to disk."
|
||||
(unless (cl-some #'get-buffer-window doom-scratch-buffers)
|
||||
(mapc #'kill-buffer doom-scratch-buffers)
|
||||
(remove-hook 'doom-switch-buffer-hook #'doom-persist-scratch-buffers-after-switch-h)))
|
||||
|
||||
;;;###autoload
|
||||
(unless noninteractive
|
||||
(add-hook 'kill-emacs-hook #'doom|persist-scratch-buffers))
|
||||
(add-hook 'kill-emacs-hook #'doom-persist-scratch-buffers-h))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -115,17 +125,19 @@ If PROJECT-P is non-nil, open a persistent scratch buffer associated with the
|
|||
|
||||
;;;###autoload
|
||||
(defun doom/switch-to-scratch-buffer (&optional project-p)
|
||||
"Like `doom/open-scratch-buffer', but switches to it in the current window."
|
||||
(interactive)
|
||||
(doom/open-scratch-buffer t))
|
||||
"Like `doom/open-scratch-buffer', but switches to it in the current window.
|
||||
|
||||
If passed the prefix arg, open project scratch buffer."
|
||||
(interactive "P")
|
||||
(doom/open-scratch-buffer t project-p))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/open-project-scratch-buffer (&optional arg)
|
||||
(defun doom/open-project-scratch-buffer (&optional current-window)
|
||||
"Opens the (persistent) project scratch buffer in a popup.
|
||||
|
||||
If passed the prefix ARG, switch to it in the current window."
|
||||
If passed the prefix arg, switch to it in the current window."
|
||||
(interactive "P")
|
||||
(doom/open-scratch-buffer arg 'project))
|
||||
(doom/open-scratch-buffer current-window 'project))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom/switch-to-project-scratch-buffer ()
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
;;; core/autoload/sessions.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar desktop-base-file-name)
|
||||
(defvar desktop-dirname)
|
||||
(defvar desktop-restore-eager)
|
||||
(defvar desktop-file-modtime)
|
||||
|
||||
|
||||
;;
|
||||
;;; Helpers
|
||||
|
||||
|
@ -59,9 +65,6 @@
|
|||
"TODO"
|
||||
(add-hook 'window-setup-hook #'doom-load-session 'append))
|
||||
|
||||
;;;###autoload
|
||||
(add-to-list 'command-switch-alist (cons "--restore" #'doom-restore-session-handler))
|
||||
|
||||
|
||||
;;
|
||||
;;; Commands
|
||||
|
|
|
@ -25,6 +25,41 @@ lines, above and below, with only whitespace in between."
|
|||
(or (not balanced)
|
||||
(= (- pt nbeg) (- nend pt))))))))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-point-in-comment-p (&optional pos)
|
||||
"Return non-nil if POS is in a comment.
|
||||
|
||||
POS defaults to the current position."
|
||||
;; REVIEW Should we cache `syntax-ppss'?
|
||||
(let* ((pos (or pos (point)))
|
||||
(ppss (syntax-ppss pos)))
|
||||
(or (nth 4 ppss)
|
||||
(nth 8 ppss)
|
||||
(and (< pos (point-max))
|
||||
(memq (char-syntax (char-after pos)) '(?< ?>))
|
||||
(not (eq (char-after pos) ?\n)))
|
||||
(when-let (s (car (syntax-after pos)))
|
||||
(or (and (/= 0 (logand (lsh 1 16) s))
|
||||
(nth 4 (doom-syntax-ppss (+ pos 2))))
|
||||
(and (/= 0 (logand (lsh 1 17) s))
|
||||
(nth 4 (doom-syntax-ppss (+ pos 1))))
|
||||
(and (/= 0 (logand (lsh 1 18) s))
|
||||
(nth 4 (doom-syntax-ppss (- pos 1))))
|
||||
(and (/= 0 (logand (lsh 1 19) s))
|
||||
(nth 4 (doom-syntax-ppss (- pos 2)))))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-point-in-string-p (&optional pos)
|
||||
"Return non-nil if POS is in a string."
|
||||
;; REVIEW Should we cache `syntax-ppss'?
|
||||
(nth 3 (syntax-ppss pos)))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom-point-in-string-or-comment-p (&optional pos)
|
||||
"Return non-nil if POS is in a string or comment."
|
||||
(or (doom-point-in-string-p pos)
|
||||
(doom-point-in-comment-p pos)))
|
||||
|
||||
|
||||
;;
|
||||
;; Commands
|
||||
|
@ -186,9 +221,13 @@ Respects `require-final-newline'."
|
|||
(setq indent-tabs-mode (not indent-tabs-mode))
|
||||
(message "Indent style changed to %s" (if indent-tabs-mode "tabs" "spaces")))
|
||||
|
||||
(defvar editorconfig-lisp-use-default-indent)
|
||||
;;;###autoload
|
||||
(defun doom/set-indent-width (width)
|
||||
"Change the indentation width of the current buffer."
|
||||
"Change the indentation size to WIDTH of the current buffer.
|
||||
|
||||
The effectiveness of this command is significantly improved if you have
|
||||
editorconfig or dtrt-indent installed."
|
||||
(interactive
|
||||
(list (if (integerp current-prefix-arg)
|
||||
current-prefix-arg
|
||||
|
@ -211,25 +250,25 @@ Respects `require-final-newline'."
|
|||
;; Hooks
|
||||
|
||||
;;;###autoload
|
||||
(defun doom|enable-delete-trailing-whitespace ()
|
||||
(defun doom-enable-delete-trailing-whitespace-h ()
|
||||
"Enables the automatic deletion of trailing whitespaces upon file save.
|
||||
|
||||
i.e. enables `ws-butler-mode' in the current buffer."
|
||||
(ws-butler-mode +1))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom|disable-delete-trailing-whitespace ()
|
||||
(defun doom-disable-delete-trailing-whitespace-h ()
|
||||
"Disables the automatic deletion of trailing whitespaces upon file save.
|
||||
|
||||
i.e. disables `ws-butler-mode' in the current buffer."
|
||||
(ws-butler-mode -1))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom|enable-show-trailing-whitespace ()
|
||||
(defun doom-enable-show-trailing-whitespace-h ()
|
||||
"Enable `show-trailing-whitespace' in the current buffer."
|
||||
(setq-local show-trailing-whitespace t))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom|disable-show-trailing-whitespace ()
|
||||
(defun doom-disable-show-trailing-whitespace-h ()
|
||||
"Disable `show-trailing-whitespace' in the current buffer."
|
||||
(setq-local show-trailing-whitespace nil))
|
||||
|
|
50
core/autoload/themes.el
Normal file
50
core/autoload/themes.el
Normal file
|
@ -0,0 +1,50 @@
|
|||
;;; core/autoload/themes.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defun doom--custom-theme-set-face (spec)
|
||||
(cond ((listp (car spec))
|
||||
(cl-loop for face in (car spec)
|
||||
collect
|
||||
(doom--custom-theme-set-face `(,face ,(cdr spec)))))
|
||||
((keywordp (cadr spec))
|
||||
`((,(car spec) ((t ,(cdr spec))))))
|
||||
(`((,(car spec) ,(cdr spec))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun custom-theme-set-faces! (theme &rest specs)
|
||||
"Apply a list of face SPECS as user customizations for THEME.
|
||||
|
||||
THEME can be a single symbol or list thereof. If nil, apply these settings to
|
||||
all themes. It will apply to all themes once they are loaded."
|
||||
(let* ((themes (doom-enlist (or theme 'user)))
|
||||
(fn (gensym (format "doom--customize-%s-h-" (mapconcat #'symbol-name themes "-")))))
|
||||
(fset fn
|
||||
(lambda ()
|
||||
(dolist (theme themes)
|
||||
(when (or (eq theme 'user)
|
||||
(custom-theme-enabled-p theme))
|
||||
(apply #'custom-theme-set-faces 'user
|
||||
(mapcan #'doom--custom-theme-set-face
|
||||
specs))))))
|
||||
(funcall fn)
|
||||
(add-hook 'doom-load-theme-hook fn)))
|
||||
|
||||
;;;###autoload
|
||||
(defun custom-set-faces! (&rest specs)
|
||||
"Apply a list of face SPECS as user customizations.
|
||||
|
||||
This is a drop-in replacement for `custom-set-face' that allows for a simplified
|
||||
face format."
|
||||
(apply #'custom-theme-set-faces! 'user specs))
|
||||
|
||||
(defvar doom--prefer-theme-elc)
|
||||
;;;###autoload
|
||||
(defun doom/reload-theme ()
|
||||
"Reload the current color theme."
|
||||
(interactive)
|
||||
(let ((theme (or (car-safe custom-enabled-themes) doom-theme)))
|
||||
(when theme
|
||||
(mapc #'disable-theme custom-enabled-themes))
|
||||
(when (and doom-theme (not (memq doom-theme custom-enabled-themes)))
|
||||
(let (doom--prefer-theme-elc)
|
||||
(load-theme doom-theme t)))
|
||||
(doom-init-fonts-h)))
|
|
@ -27,12 +27,12 @@ are open."
|
|||
;; Advice
|
||||
|
||||
;;;###autoload
|
||||
(defun doom*recenter (&rest _)
|
||||
(defun doom-recenter-a (&rest _)
|
||||
"Generic advisor for recentering window (typically :after other functions)."
|
||||
(recenter))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom*shut-up (orig-fn &rest args)
|
||||
(defun doom-shut-up-a (orig-fn &rest args)
|
||||
"Generic advisor for silencing noisy functions."
|
||||
(quiet! (apply orig-fn args)))
|
||||
|
||||
|
@ -41,14 +41,14 @@ are open."
|
|||
;; Hooks
|
||||
|
||||
;;;###autoload
|
||||
(defun doom|apply-ansi-color-to-compilation-buffer ()
|
||||
(defun doom-apply-ansi-color-to-compilation-buffer-h ()
|
||||
"Applies ansi codes to the compilation buffers. Meant for
|
||||
`compilation-filter-hook'."
|
||||
(with-silent-modifications
|
||||
(ansi-color-apply-on-region compilation-filter-start (point))))
|
||||
|
||||
;;;###autoload
|
||||
(defun doom|disable-show-paren-mode ()
|
||||
(defun doom-disable-show-paren-mode-h ()
|
||||
"Turn off `show-paren-mode' buffer-locally."
|
||||
(setq-local show-paren-mode nil))
|
||||
|
||||
|
@ -67,6 +67,7 @@ visual-line-mode is on, this skips relative and uses visual instead.
|
|||
See `display-line-numbers' for what these values mean."
|
||||
(interactive)
|
||||
(defvar doom--line-number-style display-line-numbers-type)
|
||||
;; DEPRECATED
|
||||
(let* ((styles `(t ,(if (and EMACS26+ visual-line-mode) 'visual 'relative) nil))
|
||||
(order (cons display-line-numbers-type (remq display-line-numbers-type styles)))
|
||||
(queue (memq doom--line-number-style order))
|
||||
|
@ -74,6 +75,7 @@ See `display-line-numbers' for what these values mean."
|
|||
(car order)
|
||||
(car (cdr queue)))))
|
||||
(setq doom--line-number-style next)
|
||||
;; DEPRECATED
|
||||
(if EMACS26+
|
||||
(setq display-line-numbers next)
|
||||
(pcase next
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
;;; core/cli/autoloads.el -*- lexical-binding: t; -*-
|
||||
|
||||
(dispatcher! (autoloads a)
|
||||
(doom-reload-autoloads nil 'force)
|
||||
"Regenerates Doom's autoloads files.
|
||||
(require 'autoload)
|
||||
|
||||
It scans and reads autoload cookies (;;;###autoload) in core/autoload/*.el,
|
||||
modules/*/*/autoload.el and modules/*/*/autoload/*.el, and generates and
|
||||
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'.")
|
||||
(defvar doom-autoload-excluded-packages '("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.")
|
||||
|
||||
;; external variables
|
||||
(defvar autoload-timestamps)
|
||||
|
@ -19,57 +15,57 @@ It also caches `load-path', `Info-directory-list', `doom-disabled-packages',
|
|||
|
||||
|
||||
;;
|
||||
;;; Helpers
|
||||
;;; Commands
|
||||
|
||||
(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.")
|
||||
(defcli! (autoloads a) ()
|
||||
"Regenerates Doom's autoloads files.
|
||||
|
||||
It scans and reads autoload cookies (;;;###autoload) in core/autoload/*.el,
|
||||
modules/*/*/autoload.el and modules/*/*/autoload/*.el, and generates and
|
||||
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'."
|
||||
(doom-reload-autoloads nil 'force))
|
||||
|
||||
|
||||
;;
|
||||
;;; Helpers
|
||||
|
||||
(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")
|
||||
(defun doom--warn-refresh-session-h ()
|
||||
(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)))
|
||||
|
||||
(defun doom--byte-compile-file (file)
|
||||
(let ((short-name (file-name-nondirectory file))
|
||||
(let ((byte-compile-warnings (if doom-debug-mode byte-compile-warnings))
|
||||
(byte-compile-dynamic t)
|
||||
(byte-compile-dynamic-docstrings t))
|
||||
(condition-case e
|
||||
(condition-case-unless-debug 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)))
|
||||
(prog1 (load file 'noerror 'nomessage)
|
||||
(when noninteractive
|
||||
(add-hook 'doom-cli-post-success-execute-hook #'doom--warn-refresh-session-h))))
|
||||
((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,111 +78,96 @@ 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; -*-\n"
|
||||
";; This file is autogenerated by `" (symbol-name func) "', DO NOT EDIT !!\n\n"))
|
||||
|
||||
(defun doom--generate-autoloads (targets)
|
||||
(require 'autoload)
|
||||
(let ((n 0))
|
||||
(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))))))
|
||||
(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)))
|
||||
(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 (targets enabled-targets)
|
||||
(goto-char (point-max))
|
||||
(search-backward ";;;***" nil t)
|
||||
(save-excursion (insert "\n"))
|
||||
(dolist (path targets)
|
||||
(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)
|
||||
(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))))))
|
||||
(doom-file-form
|
||||
`(put ',name 'doom-file ,(abbreviate-file-name path))))
|
||||
(cond ((and (not member-p) alt-sexp)
|
||||
(origin (doom-module-from-path 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))
|
||||
(cl-destructuring-bind (_ _name arglist &rest body) sexp
|
||||
(appendq!
|
||||
forms
|
||||
(list (if member-p
|
||||
(make-autoload sexp path)
|
||||
(let ((docstring
|
||||
(format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s"
|
||||
origin
|
||||
(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))
|
||||
"No documentation."))))
|
||||
(condition-case-unless-debug e
|
||||
(if alt-sexp
|
||||
(read alt-sexp)
|
||||
(append (list (pcase type
|
||||
(append
|
||||
(list (pcase type
|
||||
(`defun 'defmacro)
|
||||
(`cl-defun `cl-defmacro)
|
||||
(_ type))
|
||||
|
@ -200,38 +181,44 @@ even if it doesn't need reloading!"
|
|||
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))))
|
||||
(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 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))))
|
||||
(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)))))
|
||||
(if forms
|
||||
(member-p (push sexp forms)))))
|
||||
forms))
|
||||
|
||||
(defun doom--generate-autodefs (targets enabled-targets)
|
||||
(goto-char (point-max))
|
||||
(search-backward ";;;***" nil t)
|
||||
(save-excursion (insert "\n"))
|
||||
(dolist (path targets)
|
||||
(insert
|
||||
(with-temp-buffer
|
||||
(insert-file-contents path)
|
||||
(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,61 +228,76 @@ 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)))))
|
||||
|
||||
;; 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 magic
|
||||
(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)
|
||||
(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)
|
||||
(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)))
|
||||
(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)
|
||||
(ignore
|
||||
(print! (success "Skipping core autoloads, they are up-to-date"))
|
||||
(doom-load-autoloads-file 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-doom-autoloads)
|
||||
(prin1 `(setq doom--modules-cache ',doom-modules) (current-buffer))
|
||||
(doom--generate-header 'doom-reload-core-autoloads)
|
||||
(save-excursion
|
||||
(doom--generate-autoloads (reverse enabled-targets)))
|
||||
(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-autoloads)
|
||||
(print! (green "✓ Expanded module autoload paths")))
|
||||
(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 (reverse targets) enabled-targets)
|
||||
(print! (green "✓ Generated autodefs")))
|
||||
(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! (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)
|
||||
(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))))
|
||||
t)))
|
||||
|
||||
|
||||
|
@ -304,23 +306,24 @@ 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")))
|
||||
them,and remove unnecessary `provide' statements or blank links."
|
||||
(dolist (pkg (hash-table-keys straight--build-cache))
|
||||
(unless (member pkg doom-autoload-excluded-packages)
|
||||
(let ((file (straight--autoloads-file pkg)))
|
||||
(when (file-exists-p file)
|
||||
(insert "(let ((load-file-name " (prin1-to-string (abbreviate-file-name file)) "))\n")
|
||||
(insert-file-contents file)
|
||||
(insert-file-contents-literally file)
|
||||
(save-excursion
|
||||
(while (re-search-forward "\\(?:\\_<load-file-name\\|#\\$\\)\\_>" nil t)
|
||||
;; `load-file-name' is meaningless in a concatenated
|
||||
;; mega-autoloads file, so we replace references to it and #$ with
|
||||
;; the file they came from.
|
||||
(unless (doom-point-in-string-or-comment-p)
|
||||
(replace-match (prin1-to-string (abbreviate-file-name file))
|
||||
t t))))
|
||||
(while (re-search-forward "^\\(?:;;\\(.*\n\\)\\|\n\\|(provide '[^\n]+\\)" nil t)
|
||||
(unless (nth 8 (syntax-ppss))
|
||||
(unless (doom-point-in-string-p)
|
||||
(replace-match "" t t)))
|
||||
(unless (bolp) (insert "\n"))
|
||||
(insert ")\n"))))
|
||||
(message "Couldn't find package desc for %s" (car spec)))))
|
||||
(unless (bolp) (insert "\n")))))))
|
||||
|
||||
(defun doom--generate-var-cache ()
|
||||
"Print a `setq' form for expensive-to-initialize variables, so we can cache
|
||||
|
@ -329,8 +332,7 @@ them in Doom's autoloads file."
|
|||
(prin1 `(setq load-path ',load-path
|
||||
auto-mode-alist ',auto-mode-alist
|
||||
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 +353,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)))
|
||||
(print! (start "Checking package autoloads file"))
|
||||
(print-group!
|
||||
(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)
|
||||
(not (file-newer-than-file-p doom-elpa-dir doom-package-autoload-file))
|
||||
(not (cl-loop for dir in (straight--directory-files (straight--build-dir))
|
||||
if (cl-find-if
|
||||
(lambda (dir)
|
||||
(file-newer-than-file-p dir doom-package-autoload-file))
|
||||
(doom-glob (straight--build-dir dir) "*.el"))
|
||||
return t))
|
||||
(not (cl-loop with doom-modules = (doom-modules)
|
||||
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)
|
||||
return t)))
|
||||
(ignore
|
||||
(print! (success "Skipping package autoloads, they are up-to-date"))
|
||||
(doom-load-autoloads-file 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! (green "✓ Cached package state"))
|
||||
(print! (success "Cached package state"))
|
||||
;; Concatenate the autoloads of all installed packages.
|
||||
(doom--generate-package-autoloads)
|
||||
(print! (green "✓ Package autoloads included")))
|
||||
(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! (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! (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)))))
|
||||
t))
|
||||
|
|
|
@ -1,21 +1,24 @@
|
|||
;;; core/cli/byte-compile.el -*- lexical-binding: t; -*-
|
||||
|
||||
(dispatcher! (compile c) (doom-byte-compile args)
|
||||
(defcli! (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.")
|
||||
(defcli! (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.")
|
||||
(defcli! 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,36 @@ 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))
|
||||
|
||||
(let (target-dirs)
|
||||
(dolist (module (delete-dups modules))
|
||||
(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)))
|
||||
(":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 targets))
|
||||
(push module target-dirs))
|
||||
((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
|
||||
target-dirs))
|
||||
(_ (user-error "%S is not a valid target" module))))
|
||||
|
||||
(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,47 +87,54 @@ 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)
|
||||
"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.
|
||||
(unless (and (doom-initialize-autoloads doom-autoload-file)
|
||||
(doom-initialize-autoloads doom-package-autoload-file))
|
||||
(doom-reload-autoloads))
|
||||
(doom-initialize)
|
||||
(let (noninteractive)
|
||||
(doom-initialize 'force)
|
||||
(doom-initialize-core)
|
||||
(doom-initialize-modules 'force))
|
||||
|
||||
;;
|
||||
(unless target-dirs
|
||||
(push (doom-glob doom-emacs-dir "init.el") targets)
|
||||
;; 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
|
||||
(appendq! target-dirs
|
||||
(list doom-core-dir)
|
||||
(nreverse
|
||||
(cl-remove-if-not
|
||||
(lambda (path) (file-in-directory-p path doom-emacs-dir))
|
||||
;; Omit `doom-private-dir', which is always first
|
||||
(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
|
||||
(message "Couldn't find any valid targets")
|
||||
(message "No targets to %scompile" (if recompile-p "re" "")))
|
||||
(cl-return-from 'byte-compile))
|
||||
(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 ((use-package-defaults use-package-defaults)
|
||||
(let ((total-ok 0)
|
||||
(total-fail 0)
|
||||
(total-noop 0)
|
||||
(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.
|
||||
|
@ -134,57 +146,58 @@ If RECOMPILE-P is non-nil, only recompile out-of-date files."
|
|||
(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)
|
||||
|
||||
(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))))
|
||||
(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)
|
||||
(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)
|
||||
((null result)
|
||||
(print! (red "✕ Failed to compile %s") short-name)
|
||||
(`nil
|
||||
(print! (error "Failed to compile %s") (relpath target))
|
||||
total-fail)
|
||||
(t
|
||||
(print! (green "✓ Compiled %s") short-name)
|
||||
(_
|
||||
(print! (success "Compiled %s") (relpath target))
|
||||
(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)"))
|
||||
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 target-files) total-noop)
|
||||
total-ok (- (length targets) total-noop)
|
||||
total-noop)
|
||||
(or (= total-fail 0)
|
||||
(error "Failed to compile some files")))
|
||||
t)
|
||||
((debug error)
|
||||
(print! (red "\nThere were breaking errors.\n\n%s")
|
||||
(print! (error "\nThere were breaking errors.\n\n%s")
|
||||
"Reverting changes...")
|
||||
(signal 'doom-error (list 'byte-compile e))))))))
|
||||
(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.'"
|
||||
(print! (start "Cleaning .elc files"))
|
||||
(print-group!
|
||||
(cl-loop with default-directory = doom-emacs-dir
|
||||
with success = nil
|
||||
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)
|
||||
in (append (doom-glob doom-emacs-dir "*.elc")
|
||||
(doom-files-in doom-private-dir :match "\\.elc$" :depth 1)
|
||||
(doom-files-in doom-core-dir :match "\\.elc$")
|
||||
(doom-files-in doom-modules-dirs :match "\\.elc$" :depth 4))
|
||||
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")))))
|
||||
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,38 @@
|
|||
;;; 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
|
||||
|
||||
(defcli! info (&optional format)
|
||||
"Output system info in markdown for bug reports.
|
||||
|
||||
Will print in the following formats:
|
||||
|
||||
--json
|
||||
--md / --markdown
|
||||
--lisp
|
||||
|
||||
If no arguments are given, --raw is assumed."
|
||||
(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))
|
||||
((or `nil "--lisp")
|
||||
(doom/info 'raw))
|
||||
(_
|
||||
(user-error "I don't understand %S. Did you mean --json, --md/--markdown or --lisp?"
|
||||
format)))
|
||||
nil)
|
||||
|
||||
(defcli! (version v) ()
|
||||
"Reports the version of Doom and Emacs."
|
||||
(doom/version)
|
||||
nil)
|
||||
|
|
131
core/cli/env.el
131
core/cli/env.el
|
@ -1,44 +1,46 @@
|
|||
;;; core/cli/env.el -*- lexical-binding: t; -*-
|
||||
|
||||
(dispatcher! env
|
||||
(let ((env-file (abbreviate-file-name doom-env-file)))
|
||||
(pcase (car args)
|
||||
((or "refresh" "re")
|
||||
(defcli! env (&rest args)
|
||||
"Creates or regenerates your envvars file.
|
||||
|
||||
doom env [-c|--clear]
|
||||
|
||||
This is meant to be a faster and more comprehensive alternative to
|
||||
exec-path-from-shell. See the FAQ in the documentation for an explanation why.
|
||||
|
||||
The envvars file is created by scraping your (interactive) shell environment
|
||||
into newline-delimited KEY=VALUE pairs. Typically by running '$SHELL -ic env'
|
||||
(or '$SHELL -c set' on windows). Doom loads this file at startup (if it exists)
|
||||
to ensure Emacs mirrors your shell environment (particularly to ensure PATH and
|
||||
SHELL are correctly set).
|
||||
|
||||
This is useful in cases where you cannot guarantee that Emacs (or the daemon)
|
||||
will be launched from the correct environment (e.g. on MacOS or through certain
|
||||
app launchers on Linux).
|
||||
|
||||
This file is automatically regenerated when you run this command or 'doom
|
||||
refresh'. However, 'doom refresh' will only regenerate this file if it exists.
|
||||
|
||||
Use the -c or --clear switch to delete your envvar file."
|
||||
(let ((default-directory doom-emacs-dir))
|
||||
(when (member "clear" args) ; DEPRECATED
|
||||
(message "'doom env clear' is deprecated. Use 'doom env -c' or 'doom env --clear' instead")
|
||||
(push "-c" args))
|
||||
|
||||
(cond ((or (member "-c" args)
|
||||
(member "--clear" args))
|
||||
(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)))
|
||||
|
||||
((null args)
|
||||
(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."))))
|
||||
"Manages your envvars file.
|
||||
|
||||
env [SUBCOMMAND]
|
||||
|
||||
Available subcommands:
|
||||
|
||||
refresh Create or regenerate your envvar file
|
||||
auto enable auto-reloading of your envvars file (on `doom refresh`)
|
||||
clear deletes your envvar file (if it exists) and disables auto-reloading
|
||||
|
||||
An envvars file (its location is controlled by the `doom-env-file' variable)
|
||||
will contain a list of environment variables scraped from your shell environment
|
||||
and loaded when Doom starts (if it exists). This is necessary when Emacs can't
|
||||
be launched from your shell environment (e.g. on MacOS or certain app launchers
|
||||
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).")
|
||||
((user-error "I don't understand 'doom env %s'"
|
||||
(string-join args " "))))))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -55,7 +57,8 @@ needs to be run once).")
|
|||
;; Doom envvars
|
||||
"^INSECURE$"
|
||||
"^DEBUG$"
|
||||
"^YES$")
|
||||
"^YES$"
|
||||
"^__")
|
||||
"Environment variables to not save in `doom-env-file'.
|
||||
|
||||
Each string is a regexp, matched against variable names to omit from
|
||||
|
@ -86,12 +89,25 @@ 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))
|
||||
(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
|
||||
(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
|
||||
(insert
|
||||
(concat
|
||||
"# -*- mode: dotenv -*-\n"
|
||||
|
@ -100,36 +116,27 @@ default, on Linux, this is '$SHELL -ic /usr/bin/env'. Variables in
|
|||
doom-env-switches
|
||||
doom-env-executable)
|
||||
"# ---------------------------------------------------------------------------\n"
|
||||
"# This file was auto-generated by `doom env refresh'. It contains a list of\n"
|
||||
"# environment variables scraped from your default shell (excluding variables\n"
|
||||
"# blacklisted in doom-env-ignored-vars).\n"
|
||||
"# This file was auto-generated by `doom env'. It contains a list of environment\n"
|
||||
"# variables scraped from your default shell (excluding variables blacklisted\n"
|
||||
"# in doom-env-ignored-vars).\n"
|
||||
"#\n"
|
||||
"# It is NOT safe to edit this file. Changes will be overwritten next time that\n"
|
||||
"# `doom env refresh` is executed. Alternatively, create your own env file and\n"
|
||||
"# load it with `(doom-load-env-vars FILE)`.\n"
|
||||
"#\n"
|
||||
"# 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"
|
||||
"# `doom refresh` is executed. Alternatively, create your own env file and load\n"
|
||||
"# it with `(doom-load-envvars-file FILE)` in your private config.el.\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)
|
||||
(save-excursion
|
||||
(insert (shell-command-to-string doom-env-executable)))
|
||||
;; Remove undesireable variables
|
||||
(goto-char (point-min))
|
||||
(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))))
|
||||
(var (match-string 1)))
|
||||
(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")))))))
|
||||
(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)))))
|
||||
|
|
104
core/cli/install.el
Normal file
104
core/cli/install.el
Normal file
|
@ -0,0 +1,104 @@
|
|||
;;; core/cli/install.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defcli! quickstart (&rest args) ; DEPRECATED
|
||||
"This is a deprecated alias for 'doom install'.
|
||||
|
||||
See 'doom help install' instead."
|
||||
:hidden t
|
||||
(apply #'doom-cli-install args))
|
||||
|
||||
(defcli! (install i) (&rest args)
|
||||
"A wizard for installing Doom for the first time.
|
||||
|
||||
This command does the following:
|
||||
|
||||
1. Creates DOOMDIR at ~/.doom.d,
|
||||
2. Copies ~/.emacs.d/init.example.el to DOOMDIR/init.el (if it doesn't exist),
|
||||
3. Creates dummy files for DOOMDIR/{config,packages}.el,
|
||||
4. Prompts you to generate an envvar file (via 'doom env refresh'),
|
||||
5. Installs any dependencies of enabled modules (specified by DOOMDIR/init.el),
|
||||
6. And prompts to install all-the-icons' fonts
|
||||
|
||||
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 install
|
||||
DOOMDIR=~/.config/doom doom install
|
||||
|
||||
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
|
||||
-y / --yes Auto-accept any confirmation prompts"
|
||||
(print! (green "Installing Doom Emacs!\n"))
|
||||
(let ((default-directory (doom-path "~")))
|
||||
;; Create `doom-private-dir'
|
||||
(if (member "--no-config" args)
|
||||
(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
|
||||
(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-path doom-emacs-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 (:host 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)
|
||||
|
||||
;; 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! (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)
|
||||
|
||||
(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! (success "\nFinished! Doom is ready to go!\n"))
|
||||
(with-temp-buffer
|
||||
(doom-template-insert "QUICKSTART_INTRO")
|
||||
(print! (buffer-string)))))
|
|
@ -1,55 +1,62 @@
|
|||
;; -*- 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)
|
||||
(defcli! (update u) (&rest args)
|
||||
"Updates packages.
|
||||
|
||||
This works by fetching all installed package repos and checking the distance
|
||||
between HEAD and FETCH_HEAD. This can take a while.
|
||||
|
||||
This excludes packages whose `package!' declaration contains a non-nil :freeze
|
||||
or :ignore property.")
|
||||
or :ignore property."
|
||||
(doom--ensure-autoloads-while
|
||||
(straight-check-all)
|
||||
(doom-packages-update
|
||||
doom-auto-accept
|
||||
(when-let (timeout (cadr (or (member "--timeout" args)
|
||||
(member "-t" args))))
|
||||
(string-to-number timeout)))))
|
||||
|
||||
(dispatcher! (autoremove r)
|
||||
(doom--ensure-autoloads-while #'doom-packages-autoremove)
|
||||
"Removes packages that are no longer needed.
|
||||
(defcli! (rebuild build b) (&rest args)
|
||||
"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 "-f" args))))
|
||||
|
||||
(defcli! (purge p) (&rest args)
|
||||
"Deletes any unused ELPA packages, straight builds, and (optionally) repos.
|
||||
|
||||
By default, this does not purge repos.
|
||||
|
||||
Available options:
|
||||
|
||||
--no-elpa Don't purge ELPA packages
|
||||
--no-builds Don't purge unneeded (built) packages
|
||||
--repos Purge unused repos"
|
||||
(doom--ensure-autoloads-while
|
||||
(straight-check-all)
|
||||
(doom-packages-purge (not (member "--no-elpa" args))
|
||||
(not (member "--no-builds" args))
|
||||
(or (member "-r" args)
|
||||
(member "--repos" args))
|
||||
doom-auto-accept)))
|
||||
|
||||
;; (defcli! rollback () ; TODO rollback
|
||||
;; "<Not implemented yet>"
|
||||
;; (user-error "Not implemented yet, sorry!"))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -63,153 +70,410 @@ 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) " ")))
|
||||
(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 (ignore-errors
|
||||
(gethash package straight--packages-to-rebuild))
|
||||
(gethash package straight--cached-package-modifications)
|
||||
(not (file-directory-p (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))
|
||||
(let ((straight-use-package-pre-build-functions
|
||||
straight-use-package-pre-build-functions))
|
||||
(add-hook 'straight-use-package-pre-build-functions
|
||||
(lambda (&rest _) (cl-incf n)))
|
||||
(let ((straight--packages-to-rebuild :all)
|
||||
(straight--packages-not-to-rebuild (make-hash-table :test #'equal)))
|
||||
(straight-use-package (intern package) nil nil " "))
|
||||
(straight--byte-compile-package recipe)
|
||||
(dolist (dep (straight--get-dependencies package))
|
||||
(when-let (recipe (gethash dep straight--recipe-cache))
|
||||
(straight--byte-compile-package recipe)))))))))
|
||||
(if (= n 0)
|
||||
(ignore (print! (success "No packages need rebuilding")))
|
||||
(doom--finalize-straight)
|
||||
(print! (success "Rebuilt %d package(s)" n))
|
||||
t))))
|
||||
|
||||
(defun doom-packages-update (&optional auto-accept-p)
|
||||
|
||||
(defun doom--packages-remove-outdated-f (packages)
|
||||
(async-start
|
||||
`(lambda ()
|
||||
(setq load-path ',load-path
|
||||
doom-modules ',doom-modules
|
||||
user-emacs-directory ',user-emacs-directory)
|
||||
(condition-case e
|
||||
(let (packages errors)
|
||||
(load ,(concat doom-core-dir "core.el"))
|
||||
(doom-initialize 'force-p)
|
||||
(dolist (recipe ',group)
|
||||
(when (straight--repository-is-available-p recipe)
|
||||
(straight-vc-git--destructure recipe
|
||||
(package local-repo nonrecursive upstream-remote upstream-repo upstream-host
|
||||
branch remote)
|
||||
(condition-case e
|
||||
(let ((default-directory (straight--repos-dir local-repo)))
|
||||
;; HACK We normalize packages to avoid certain scenarios
|
||||
;; where `straight-fetch-package' will create an
|
||||
;; interactive popup prompting for action (which will
|
||||
;; cause this async process to block indefinitely). We
|
||||
;; can't use `straight-normalize-package' because could
|
||||
;; create popup prompts too, so we do it manually:
|
||||
(shell-command-to-string "git merge --abort")
|
||||
(straight--get-call "git" "reset" "--hard" (format "%s/%s" remote branch))
|
||||
(straight--get-call "git" "clean" "-ffd")
|
||||
(unless nonrecursive
|
||||
(shell-command-to-string "git submodule update --init --recursive"))
|
||||
(when upstream-repo
|
||||
(let ((desired-url (straight-vc-git--encode-url upstream-repo upstream-host))
|
||||
(actual-url (condition-case nil
|
||||
(straight--get-call "git" "remote" "get-url" upstream-remote)
|
||||
(error nil))))
|
||||
(unless (straight-vc-git--urls-compatible-p actual-url desired-url)
|
||||
(straight--get-call "git" "remote" "remove" upstream-remote)
|
||||
(straight--get-call "git" "remote" "add" upstream-remote desired-url)
|
||||
(straight--get-call "git" "fetch" upstream-remote))))
|
||||
(straight-fetch-package package)
|
||||
;; REVIEW Is there no better way to get this information?
|
||||
(let ((n (length
|
||||
(split-string
|
||||
(straight--get-call "git" "rev-list" "--left-right" "HEAD..@{u}")
|
||||
"\n" t)))
|
||||
(pretime
|
||||
(string-to-number
|
||||
(shell-command-to-string "git log -1 --format=%at HEAD")))
|
||||
(time
|
||||
(string-to-number
|
||||
;; HACK `straight--get-call' has a higher failure
|
||||
;; rate when querying FETCH_HEAD; not sure why.
|
||||
;; Doing this manually, with
|
||||
;; `shell-command-to-string' works fine.
|
||||
(shell-command-to-string "git log -1 --format=%at FETCH_HEAD"))))
|
||||
(with-current-buffer (straight--process-get-buffer)
|
||||
(with-silent-modifications
|
||||
(print! (debug (autofill "%s") (indent 2 (buffer-string))))
|
||||
(erase-buffer)))
|
||||
(when (> n 0)
|
||||
(push (list n pretime time recipe)
|
||||
packages))))
|
||||
(error
|
||||
(push (list package e (string-trim (or (straight--process-get-output) "")))
|
||||
errors))))))
|
||||
(if errors
|
||||
(cons 'error errors)
|
||||
(cons 'ok (nreverse packages))))
|
||||
(error
|
||||
(cons 'error e))))))
|
||||
|
||||
|
||||
(defun doom-packages-update (&optional auto-accept-p timeout)
|
||||
"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)
|
||||
|
||||
((not (or auto-accept-p
|
||||
(print! (start "Scanning for outdated packages (this may take a while)..."))
|
||||
(print-group!
|
||||
(when timeout
|
||||
(print! (info "Using %S as timeout value" timeout)))
|
||||
;; 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
|
||||
(let* ((futures
|
||||
(or (cl-loop for group
|
||||
in (seq-partition (hash-table-values straight--repo-cache)
|
||||
(/ (hash-table-count straight--repo-cache)
|
||||
16))
|
||||
for future = (doom--packages-remove-outdated-f group)
|
||||
if (processp future)
|
||||
collect (cons future group)
|
||||
else
|
||||
do (print! (warn "Failed to create thread for:\n\n%s\n\nReason: %s"
|
||||
group future)))
|
||||
(error! "Failed to create any threads")))
|
||||
(total (length futures))
|
||||
(timeout (or timeout 45)))
|
||||
(condition-case-unless-debug e
|
||||
(let (specs)
|
||||
(while futures
|
||||
(print! ". %.0f%%" (* (/ (- total (length futures))
|
||||
(float total))
|
||||
100))
|
||||
(let ((time 0))
|
||||
(catch 'timeout
|
||||
(while (not (async-ready (caar futures)))
|
||||
(when (> time timeout)
|
||||
(print! (warn "A thread has timed out. The following packages were skipped: %s"
|
||||
(mapconcat (lambda (p) (plist-get p :package))
|
||||
(cdar futures)
|
||||
", ")))
|
||||
(throw 'timeout (pop futures)))
|
||||
(sleep-for 1)
|
||||
(when (cl-evenp time)
|
||||
(print! "."))
|
||||
(cl-incf time))
|
||||
(cl-destructuring-bind (status . result)
|
||||
(or (async-get (car (pop futures)))
|
||||
(cons nil nil))
|
||||
(cond ((null status)
|
||||
(error "Thread returned an invalid result: %S" errors))
|
||||
((eq status 'error)
|
||||
(error "There were errors:\n\n%s"
|
||||
(cond ((and (listp result)
|
||||
(symbolp (car result)))
|
||||
(prin1-to-string result))
|
||||
((stringp result)
|
||||
result)
|
||||
((mapconcat (lambda (e)
|
||||
(format! " - %s: %s" (yellow (car e)) (cdr e)))
|
||||
result
|
||||
"\n")))))
|
||||
((eq status 'ok)
|
||||
(print! (debug "Appended %S to package list") (or result "nothing"))
|
||||
(appendq! specs result))
|
||||
((error "Thread returned a non-standard status: %s\n\n%s"
|
||||
status result)))))))
|
||||
(print! ". 100%%")
|
||||
(terpri)
|
||||
(if-let (specs (delq nil specs))
|
||||
(if (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)))
|
||||
(format!
|
||||
"%s\n\nThere %s %d package%s available to update. Update them?"
|
||||
(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!"))
|
||||
(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" "")))))
|
||||
(ignore (print! (info "Aborted update")))
|
||||
(terpri)
|
||||
(straight--make-package-modifications-available)
|
||||
(let ((straight--packages-to-rebuild (make-hash-table :test #'equal))
|
||||
(straight--packages-not-to-rebuild (make-hash-table :test #'equal)))
|
||||
(dolist (spec specs)
|
||||
(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)
|
||||
(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?
|
||||
(ignore-errors
|
||||
(delete-directory (straight--build-dir package) 'recursive))
|
||||
(puthash package t straight--packages-to-rebuild)
|
||||
(cl-incf n))
|
||||
(with-current-buffer (straight--process-get-buffer)
|
||||
(with-silent-modifications
|
||||
(print! (debug (autofill "%s") (indent 2 (buffer-string))))
|
||||
(erase-buffer))))))
|
||||
(doom--finalize-straight)
|
||||
(doom-packages-rebuild auto-accept-p))
|
||||
t)
|
||||
(print! (success "No packages to update"))
|
||||
nil))
|
||||
(error
|
||||
(message "Output:\n%s" (straight--process-get-output))
|
||||
(signal (car e) (error-message-string e)))))))
|
||||
|
||||
((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-autoremove (&optional auto-accept-p)
|
||||
"Auto-removes orphaned packages.
|
||||
;;; PURGE (for the emperor)
|
||||
(defun doom--prompt-p (list-fn list preamble postamble)
|
||||
(or (y-or-n-p (format "%s%s\n\n%s"
|
||||
(if preamble (concat preamble "\n\n") "")
|
||||
(mapconcat list-fn list "\n")
|
||||
(or postamble "")))
|
||||
(user-error! "Aborted")))
|
||||
|
||||
(defun doom--prompt-columns-p (row-fn list preamble postamble)
|
||||
(doom--prompt-p (lambda (row)
|
||||
(mapconcat row-fn row ""))
|
||||
(seq-partition (cl-sort (copy-sequence list) #'string-lessp)
|
||||
3)
|
||||
preamble
|
||||
postamble))
|
||||
|
||||
(defun doom--packages-purge-build (build)
|
||||
(let ((build-dir (straight--build-dir build)))
|
||||
(print! (start "Purging build/%s..." build))
|
||||
(delete-directory build-dir 'recursive)
|
||||
(if (file-directory-p build-dir)
|
||||
(ignore (print! (error "Failed to purg build/%s" build)))
|
||||
(print! (success "Purged build/%s" build))
|
||||
t)))
|
||||
|
||||
(defun doom--packages-purge-builds (builds &optional auto-accept-p)
|
||||
(if (not builds)
|
||||
(progn (print! (info "No builds to purge"))
|
||||
0)
|
||||
(or auto-accept-p
|
||||
(doom--prompt-columns-p
|
||||
(lambda (p) (format " + %-20.20s" p)) builds nil
|
||||
(format! "Found %d orphaned package builds. Purge them?"
|
||||
(length builds))))
|
||||
(length
|
||||
(delq nil (mapcar #'doom--packages-purge-build builds)))))
|
||||
|
||||
(defun doom--packages-regraft-repo (repo)
|
||||
(let ((default-directory (straight--repos-dir repo)))
|
||||
(if (not (file-directory-p ".git"))
|
||||
(ignore (print! (warn "repos/%s is not a git repo, skipping" repo)))
|
||||
(print! (debug "Regrafting repos/%s..." repo))
|
||||
(straight--call "git" "reset" "--hard")
|
||||
(straight--call "git" "clean" "--ffd")
|
||||
(straight--call "git" "replace" "--graft" "HEAD")
|
||||
(straight--call "git" "gc")
|
||||
(print! (debug "%s" (straight--process-get-output)))
|
||||
(print! (success "Regrafted repos/%s" repo))
|
||||
t)))
|
||||
|
||||
(defun doom--packages-regraft-repos (repos &optional auto-accept-p)
|
||||
(if (not repos)
|
||||
(progn (print! (info "No repos to regraft"))
|
||||
0)
|
||||
(or auto-accept-p
|
||||
(y-or-n-p (format! "Preparing to regraft all %d repos. Continue?"
|
||||
(length repos)))
|
||||
(user-error! "Aborted!"))
|
||||
(if (executable-find "du")
|
||||
(cl-destructuring-bind (status . size)
|
||||
(doom-sh "du" "-sh" (straight--repos-dir))
|
||||
(prog1 (delq nil (mapcar #'doom--packages-regraft-repo repos))
|
||||
(cl-destructuring-bind (status . newsize)
|
||||
(doom-sh "du" "-sh" (straight--repos-dir))
|
||||
(print! (success "Finshed regrafted. Size before: %s and after: %s"
|
||||
(car (split-string size "\t"))
|
||||
(car (split-string newsize "\t")))))))
|
||||
(delq nil (mapcar #'doom--packages-regraft-repo repos)))))
|
||||
|
||||
(defun doom--packages-purge-repo (repo)
|
||||
(print! (debug "Purging repos/%s..." repo))
|
||||
(let ((repo-dir (straight--repos-dir repo)))
|
||||
(delete-directory repo-dir 'recursive)
|
||||
(ignore-errors
|
||||
(delete-file (straight--modified-file repo)))
|
||||
(if (file-directory-p repo-dir)
|
||||
(ignore (print! (error "Failed to purge repos/%s" repo)))
|
||||
(print! (success "Purged repos/%s" repo))
|
||||
t)))
|
||||
|
||||
(defun doom--packages-purge-repos (repos &optional auto-accept-p)
|
||||
(if (not repos)
|
||||
(progn (print! (info "No repos to purge"))
|
||||
0)
|
||||
(or auto-accept-p
|
||||
(doom--prompt-columns-p
|
||||
(lambda (p) (format " + %-20.20s" p)) repos nil
|
||||
(format! "Found %d orphaned repos. Purge them?"
|
||||
(length repos))))
|
||||
(length
|
||||
(delq nil (mapcar #'doom--packages-purge-repo repos)))))
|
||||
|
||||
(defun doom--packages-purge-elpa (&optional auto-accept-p)
|
||||
(unless (bound-and-true-p package--initialized)
|
||||
(package-initialize))
|
||||
(if (not package-alist)
|
||||
(progn (print! (info "No ELPA packages to purge"))
|
||||
0)
|
||||
(doom--prompt-columns-p
|
||||
(lambda (p) (format " + %-20.20s" p))
|
||||
(mapcar #'car package-alist) nil
|
||||
(format! "Found %d orphaned ELPA packages. Purge them?"
|
||||
(length package-alist)))
|
||||
(mapc (doom-rpartial #'delete-directory 'recursive)
|
||||
(mapcar #'package-desc-dir
|
||||
(mapcar #'cadr package-alist)))
|
||||
(length package-alist)))
|
||||
|
||||
(defun doom-packages-purge (&optional elpa-p builds-p repos-p 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.
|
||||
|
||||
If BUILDS-P, include straight package builds.
|
||||
If REPOS-P, include straight repos.
|
||||
If ELPA-P, include packages installed with package.el (M-x package-install).
|
||||
|
||||
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!")))
|
||||
(print! (start "Searching for orphaned packages to purge (for the emperor)..."))
|
||||
(cl-destructuring-bind (&optional builds-to-purge repos-to-purge repos-to-regraft)
|
||||
(let ((rdirs (straight--directory-files (straight--repos-dir) nil nil 'sort))
|
||||
(bdirs (straight--directory-files (straight--build-dir) nil nil 'sort)))
|
||||
(list (cl-remove-if (doom-rpartial #'gethash straight--profile-cache)
|
||||
bdirs)
|
||||
(cl-remove-if (doom-rpartial #'straight--checkhash straight--repo-cache)
|
||||
rdirs)
|
||||
(cl-remove-if-not (doom-rpartial #'straight--checkhash straight--repo-cache)
|
||||
rdirs)))
|
||||
(let (success)
|
||||
(print-group!
|
||||
(if (not builds-p)
|
||||
(print! (info "Skipping builds"))
|
||||
(and (/= 0 (doom--packages-purge-builds builds-to-purge auto-accept-p))
|
||||
(setq success t)
|
||||
(straight-prune-build-cache)))
|
||||
(if (not elpa-p)
|
||||
(print! (info "Skipping elpa packages"))
|
||||
(and (/= 0 (doom--packages-purge-elpa auto-accept-p))
|
||||
(setq success t)))
|
||||
(if (not repos-p)
|
||||
(print! (info "Skipping repos"))
|
||||
(and (/= 0 (doom--packages-purge-repos repos-to-purge auto-accept-p))
|
||||
(setq success t))
|
||||
(and (doom--packages-regraft-repos repos-to-regraft auto-accept-p)
|
||||
(setq success t)))
|
||||
(when success
|
||||
(set-file-times doom-packages-dir)
|
||||
(doom-delete-autoloads-file doom-package-autoload-file))
|
||||
success)))))
|
||||
(doom--finalize-straight)
|
||||
t)))))
|
||||
|
|
|
@ -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))
|
||||
(defcli! patch-macos () ; DEPRECATED
|
||||
"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)))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -65,24 +66,7 @@ depending on your shell configuration and isn't always reliable.")
|
|||
(message "%s successfully unpatched" appdir))
|
||||
|
||||
((file-exists-p newbin)
|
||||
(user-error "%s is already patched" appdir))
|
||||
(user-error "%s is already patched. Use 'doom patch-macos --undo' to unpatch it"
|
||||
appdir))
|
||||
|
||||
((or doom-auto-accept
|
||||
(y-or-n-p
|
||||
(concat "(WARNING: patch-macos is deprecated, use `doom env refresh` instead)\n\n"
|
||||
"Doom would like to patch your Emacs.app bundle so that it respects\n"
|
||||
"your shell configuration. For more information on why and how, run\n\n"
|
||||
" bin/doom help patch-macos\n\n"
|
||||
"Patch Emacs.app?")))
|
||||
(message "Patching '%s'" appdir)
|
||||
(copy-file oldbin newbin nil nil nil 'preserve-permissions)
|
||||
(unless (file-exists-p newbin)
|
||||
(error "Failed to copy %s to %s" oldbin newbin))
|
||||
(with-temp-buffer
|
||||
(insert "#!/usr/bin/env bash\n"
|
||||
"args=\"$@\"\n"
|
||||
"pwd=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\"; pwd -P)\"\n"
|
||||
"exec \"$SHELL\" -l -c \"$pwd/RunEmacs $args\"")
|
||||
(write-file oldbin)
|
||||
(chmod oldbin (file-modes newbin)))
|
||||
(message "%s successfully patched" appdir)))))
|
||||
((user-error "patch-macos has been disabled. Please use 'doom env refresh' instead")))))
|
||||
|
|
|
@ -1,105 +0,0 @@
|
|||
;;; core/cli/quickstart.el -*- lexical-binding: t; -*-
|
||||
|
||||
(dispatcher! (quickstart qs) (apply #'doom-quickstart args)
|
||||
"Guides you through setting up Doom for first time use.
|
||||
|
||||
This command does the following:
|
||||
|
||||
1. Creates DOOMDIR at ~/.doom.d,
|
||||
2. Copies ~/.emacs.d/init.example.el to DOOMDIR/init.el (if it doesn't exist),
|
||||
3. Creates dummy files for DOOMDIR/{config,packages}.el,
|
||||
4. Prompts you to generate an envvar file (via 'doom env refresh'),
|
||||
5. Installs any dependencies of enabled modules (specified by DOOMDIR/init.el),
|
||||
6. And prompts to install all-the-icons' fonts
|
||||
|
||||
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
|
||||
|
||||
Quickstart 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)))
|
||||
(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!"))
|
||||
|
||||
;; 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!")))))))
|
||||
|
||||
;; 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)))
|
||||
|
||||
;; Install Doom packages
|
||||
(if (member "--no-install" args)
|
||||
(print! (yellow "Not installing plugins, as requested"))
|
||||
(print! "Installing plugins")
|
||||
(doom-packages-install doom-auto-accept))
|
||||
|
||||
(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))))
|
||||
|
||||
(print! (bold (green "\nFinished! Doom is ready to go!\n")))
|
||||
(with-temp-buffer
|
||||
(doom-template-insert "QUICKSTART_INTRO")
|
||||
(print! (buffer-string))))
|
131
core/cli/test.el
131
core/cli/test.el
|
@ -1,69 +1,66 @@
|
|||
;;; core/cli/test.el -*- lexical-binding: t; -*-
|
||||
|
||||
(dispatcher! test (doom-run-tests args)
|
||||
"Run Doom unit tests.")
|
||||
|
||||
|
||||
;;
|
||||
;; 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).
|
||||
|
||||
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)))))
|
||||
|
||||
|
||||
;;
|
||||
;; Test library
|
||||
|
||||
(defmacro insert! (&rest text)
|
||||
"Insert TEXT in buffer, then move cursor to last {0} marker."
|
||||
`(progn
|
||||
(insert ,@text)
|
||||
(when (search-backward "{0}" nil t)
|
||||
(replace-match "" t t))))
|
||||
(defcli! test (&rest targets)
|
||||
"Run Doom unit tests."
|
||||
(let (files error)
|
||||
(unless targets
|
||||
(setq targets
|
||||
(cons doom-core-dir
|
||||
(cl-remove-if-not
|
||||
(lambda (path) (file-in-directory-p path doom-emacs-dir))
|
||||
;; Omit `doom-private-dir', which is always first
|
||||
(let (doom-modules)
|
||||
(load! "test/init" doom-core-dir)
|
||||
(cdr (doom-module-load-path)))))))
|
||||
(while targets
|
||||
(let ((target (pop targets)))
|
||||
(cond ((equal target ":core")
|
||||
(appendq! files (nreverse (doom-glob doom-core-dir "test/test-*.el"))))
|
||||
((file-directory-p target)
|
||||
(setq target (expand-file-name target))
|
||||
(appendq! files (nreverse (doom-glob target "test/test-*.el"))))
|
||||
((file-exists-p target)
|
||||
(push target files)))))
|
||||
(require 'restart-emacs)
|
||||
(with-temp-buffer
|
||||
(setenv "DOOMDIR" (concat doom-core-dir "test/"))
|
||||
(setenv "DOOMLOCALDIR" (concat doom-local-dir "test/"))
|
||||
(print! (start "Bootstrapping test environment, if necessary..."))
|
||||
(if (zerop
|
||||
(call-process
|
||||
(restart-emacs--get-emacs-binary)
|
||||
nil t nil "--batch"
|
||||
"-l" (concat doom-core-dir "core.el")
|
||||
"--eval" (prin1-to-string
|
||||
`(progn (doom-initialize 'force)
|
||||
(doom-initialize-modules)
|
||||
(require 'core-cli)
|
||||
(unless (package-installed-p 'buttercup)
|
||||
(package-refresh-contents)
|
||||
(package-install 'buttercup))
|
||||
(doom-reload-core-autoloads 'force)
|
||||
(when (doom-packages-install 'auto-accept)
|
||||
(doom-reload-package-autoloads 'force))))))
|
||||
(message "%s" (buffer-string))
|
||||
(message "%s" (buffer-string))
|
||||
(error "Failed to bootstrap unit tests")))
|
||||
(dolist (file files)
|
||||
(if (doom-file-cookie-p file)
|
||||
(with-temp-buffer
|
||||
(unless
|
||||
(zerop
|
||||
(call-process
|
||||
(restart-emacs--get-emacs-binary)
|
||||
nil t nil "--batch"
|
||||
"-l" (concat doom-core-dir "core.el")
|
||||
"-l" (concat doom-core-dir "test/helpers.el")
|
||||
"--eval" (prin1-to-string `(doom-initialize 'force))
|
||||
"-l" "buttercup"
|
||||
"-l" file
|
||||
"-f" "buttercup-run"))
|
||||
(setq error t))
|
||||
(message "%s" (buffer-string)))
|
||||
(print! (info "Ignoring %s" (relpath file)))))
|
||||
(if error
|
||||
(error "A test failed")
|
||||
t)))
|
||||
|
|
|
@ -1,86 +1,110 @@
|
|||
;;; core/cli/upgrade.el -*- lexical-binding: t; -*-
|
||||
|
||||
(dispatcher! (upgrade up) (doom-upgrade)
|
||||
"Checks out the latest Doom on this branch.
|
||||
(defcli! (upgrade up) (&rest args)
|
||||
"Updates Doom and packages.
|
||||
|
||||
Doing so is equivalent to:
|
||||
This requires that ~/.emacs.d is a git repo, and is the equivalent of the
|
||||
following shell commands:
|
||||
|
||||
cd ~/.emacs.d
|
||||
git pull
|
||||
git pull --rebase
|
||||
bin/doom clean
|
||||
bin/doom refresh
|
||||
bin/doom update")
|
||||
bin/doom update"
|
||||
(and (doom-upgrade (or (member "-f" args)
|
||||
(member "--force" args)))
|
||||
(doom-packages-update
|
||||
doom-auto-accept
|
||||
(when-let (timeout (cadr (or (member "--timeout" args)
|
||||
(member "-t" args))))
|
||||
(string-to-number timeout)))
|
||||
|
||||
(doom-reload-package-autoloads 'force-p)))
|
||||
|
||||
|
||||
;;
|
||||
;; Quality of Life Commands
|
||||
;;; Library
|
||||
|
||||
(defvar doom-repo-url "https://github.com/hlissner/doom-emacs"
|
||||
"TODO")
|
||||
"The git repo url for Doom Emacs.")
|
||||
(defvar doom-repo-remote "_upgrade"
|
||||
"TODO")
|
||||
"The name to use as our staging remote.")
|
||||
|
||||
(defun doom--working-tree-dirty-p (dir)
|
||||
(with-temp-buffer
|
||||
(let ((default-directory dir))
|
||||
(if (zerop (process-file "git" nil (current-buffer) nil
|
||||
"status" "--porcelain" "-uno"))
|
||||
(cl-destructuring-bind (success . stdout)
|
||||
(doom-sh "git" "status" "--porcelain" "-uno")
|
||||
(if (= 0 success)
|
||||
(string-match-p "[^ \t\n]" (buffer-string))
|
||||
(error "Failed to check working tree in %s" dir)))))
|
||||
(error "Failed to check working tree in %s" dir))))
|
||||
|
||||
(defun doom-upgrade ()
|
||||
|
||||
(defun doom-upgrade (&optional force-p)
|
||||
"Upgrade Doom to the latest version non-destructively."
|
||||
(require 'vc-git)
|
||||
(let* ((gitdir (expand-file-name ".git" doom-emacs-dir))
|
||||
(branch (vc-git--symbolic-ref doom-emacs-dir))
|
||||
(default-directory doom-emacs-dir))
|
||||
(unless (file-exists-p gitdir)
|
||||
(error "Couldn't find %s. Was Doom cloned properly?"
|
||||
(abbreviate-file-name gitdir)))
|
||||
(let ((default-directory doom-emacs-dir)
|
||||
process-file-side-effects)
|
||||
(print! (start "Preparing to upgrade Doom Emacs and its packages..."))
|
||||
|
||||
(let* ((branch (vc-git--symbolic-ref doom-emacs-dir))
|
||||
(target-remote (format "%s/%s" doom-repo-remote branch)))
|
||||
(unless branch
|
||||
(error "Couldn't detect what branch you're using. Is Doom detached?"))
|
||||
(when (doom--working-tree-dirty-p doom-emacs-dir)
|
||||
(user-error "Refusing to upgrade because %S has been modified. Stash or undo your changes"
|
||||
(abbreviate-file-name doom-emacs-dir)))
|
||||
(with-temp-buffer
|
||||
(let ((buf (current-buffer)))
|
||||
(condition-case-unless-debug e
|
||||
(error! (if (file-exists-p! ".git" doom-emacs-dir)
|
||||
"Couldn't find Doom's .git directory. Was Doom cloned properly?"
|
||||
"Couldn't detect what branch you're on. Is Doom detached?")))
|
||||
|
||||
;; We assume that a dirty .emacs.d is intentional and abort
|
||||
(when (doom--working-tree-dirty-p default-directory)
|
||||
(if (not force-p)
|
||||
(user-error! "%s\n\n%s"
|
||||
(format "Refusing to upgrade because %S has been modified." (path doom-emacs-dir))
|
||||
"Either stash/undo your changes or run 'doom upgrade -f' to discard local changes.")
|
||||
(print! (info "You have local modifications in Doom's source. Discarding them..."))
|
||||
(doom-sh "git" "reset" "--hard" (format "origin/%s" branch))
|
||||
(doom-sh "git" "clean" "-ffd")))
|
||||
|
||||
(doom-sh "git" "remote" "remove" doom-repo-remote)
|
||||
(unwind-protect
|
||||
(progn
|
||||
(process-file "git" nil buf nil "remote" "remove" doom-repo-remote)
|
||||
(unless (zerop (process-file "git" nil buf nil "remote" "add"
|
||||
doom-repo-remote doom-repo-url))
|
||||
(or (zerop (car (doom-sh "git" "remote" "add" doom-repo-remote doom-repo-url)))
|
||||
(error "Failed to add %s to remotes" doom-repo-remote))
|
||||
(unless (zerop (process-file "git" nil buf nil "fetch" "--tags"
|
||||
doom-repo-remote branch))
|
||||
(or (zerop (car (doom-sh "git" "fetch" "--tags" doom-repo-remote branch)))
|
||||
(error "Failed to fetch from upstream"))
|
||||
(let ((current-rev (vc-git-working-revision doom-emacs-dir))
|
||||
(rev (string-trim (shell-command-to-string (format "git rev-parse %s/%s" doom-repo-remote branch)))))
|
||||
(unless rev
|
||||
(error "Couldn't detect Doom's version. Is %s a repo?"
|
||||
(abbreviate-file-name doom-emacs-dir)))
|
||||
(if (equal current-rev rev)
|
||||
(message "Doom is up to date!")
|
||||
(message "Updates for Doom are available!\n\n Old revision: %s\n New revision: %s\n"
|
||||
current-rev rev)
|
||||
(message "Comparision diff: https://github.com/hlissner/doom-emacs/compare/%s...%s\n"
|
||||
(substring current-rev 0 10) (substring rev 0 10))
|
||||
;; TODO Display newsletter diff
|
||||
(unless (or doom-auto-accept (y-or-n-p "Proceed?"))
|
||||
(user-error "Aborted"))
|
||||
(message "Removing byte-compiled files from your config (if any)")
|
||||
|
||||
(let ((this-rev (vc-git--rev-parse "HEAD"))
|
||||
(new-rev (vc-git--rev-parse target-remote)))
|
||||
(cond
|
||||
((and (null this-rev)
|
||||
(null new-rev))
|
||||
(error "Failed to get revisions for %s" target-remote))
|
||||
|
||||
((equal this-rev new-rev)
|
||||
(print! (success "Doom is already up-to-date!"))
|
||||
t)
|
||||
|
||||
((print! (info "A new version of Doom Emacs is available!\n\n Old revision: %s (%s)\n New revision: %s (%s)\n"
|
||||
(substring this-rev 0 10)
|
||||
(cdr (doom-sh "git" "log" "-1" "--format=%cr" "HEAD"))
|
||||
(substring new-rev 0 10)
|
||||
(cdr (doom-sh "git" "log" "-1" "--format=%cr" target-remote))))
|
||||
|
||||
(when (y-or-n-p "View the comparison diff in your browser?")
|
||||
(print! (info "Opened github in your browser."))
|
||||
(browse-url (format "https://github.com/hlissner/doom-emacs/compare/%s...%s"
|
||||
this-rev
|
||||
new-rev)))
|
||||
(if (not (y-or-n-p "Proceed with upgrade?"))
|
||||
(ignore (print! (error "Aborted")))
|
||||
(print! (start "Upgrading Doom Emacs..."))
|
||||
(print-group!
|
||||
(doom-clean-byte-compiled-files)
|
||||
(unless (zerop (process-file "git" nil buf nil "reset" "--hard"
|
||||
(format "%s/%s" doom-repo-remote branch)))
|
||||
(error "An error occurred while checking out the latest commit\n\n%s"
|
||||
(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)
|
||||
(when (doom-packages-update doom-auto-accept)
|
||||
(doom-reload-package-autoloads))
|
||||
(message "Done! Please restart Emacs for changes to take effect")))
|
||||
(user-error
|
||||
(message "%s Aborting." (error-message-string e)))
|
||||
(error
|
||||
(message "There was an unexpected error.\n\n%s\n\nOutput:\n%s"
|
||||
e (buffer-string))))))))
|
||||
(unless (and (zerop (car (doom-sh "git" "reset" "--hard" target-remote)))
|
||||
(equal (vc-git--rev-parse "HEAD") new-rev))
|
||||
(error "Failed to check out %s" (substring new-rev 0 10)))
|
||||
(print! (success "Finished upgrading Doom Emacs")))
|
||||
(doom-delete-autoloads-file doom-autoload-file)
|
||||
(doom-cli-refresh "-f")
|
||||
t)
|
||||
|
||||
(print! (success "Done! Restart Emacs for changes to take effect."))))))
|
||||
(ignore-errors
|
||||
(doom-sh "git" "remote" "remove" doom-repo-remote))))))
|
||||
|
|
294
core/core-cli.el
294
core/core-cli.el
|
@ -1,54 +1,98 @@
|
|||
;;; -*- 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")
|
||||
(require 'seq)
|
||||
|
||||
|
||||
;;
|
||||
;; 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-success-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-sh (command &rest args)
|
||||
"Execute COMMAND with ARGS in the shell and return (STATUS . OUTPUT).
|
||||
|
||||
STATUS is a boolean"
|
||||
(let ((output (get-buffer-create "*doom-sh-output*")))
|
||||
(unwind-protect
|
||||
(cons (or (apply #'call-process command nil output nil args)
|
||||
-1)
|
||||
(with-current-buffer output
|
||||
(string-trim (buffer-string))))
|
||||
(kill-buffer output))))
|
||||
|
||||
(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))
|
||||
(save-excursion
|
||||
(insert desc)
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "\n\n[^ \n]" nil t)
|
||||
(fill-paragraph)))
|
||||
(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)
|
||||
(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
|
||||
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"
|
||||
(defun doom--dispatch-help-1 (command)
|
||||
(cl-destructuring-bind (&key aliases hidden _group)
|
||||
(gethash command doom--cli-commands)
|
||||
(unless hidden
|
||||
(print! "%-11s\t%s\t%s"
|
||||
command (if aliases (string-join aliases ",") "")
|
||||
(doom--dispatch-format desc t)))))))
|
||||
(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 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 +103,33 @@ 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!" cmd))
|
||||
(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)
|
||||
(unwind-protect
|
||||
(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)
|
||||
(run-hooks 'doom-cli-post-error-execute-hook))))))
|
||||
|
||||
(defmacro dispatcher! (command form &optional docstring)
|
||||
(defmacro defcligroup! (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 defcli! (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 +137,30 @@ 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
|
||||
`((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.")
|
||||
|
||||
|
||||
;;
|
||||
;; 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
|
||||
(defcli! (refresh re) (&rest args)
|
||||
"Ensure Doom is properly set up.
|
||||
|
||||
This is the equivalent of running autoremove, install, autoloads, then
|
||||
recompile. Run this whenever you:
|
||||
|
@ -161,7 +172,70 @@ 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 ((force-p (or (member "-f" args)
|
||||
(member "--force" args)))
|
||||
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 'elpa-p 'builds-p nil 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/install")
|
||||
|
||||
(defcligroup! "Diagnostics"
|
||||
"For troubleshooting and diagnostics"
|
||||
(defcli! (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"))
|
||||
|
||||
(defcligroup! "Maintenance"
|
||||
"For managing your config and packages"
|
||||
(load! "cli/env")
|
||||
(load! "cli/upgrade")
|
||||
(load! "cli/packages")
|
||||
(load! "cli/autoloads")
|
||||
(load! "cli/patch-macos"))
|
||||
|
||||
(defcligroup! "Byte compilation"
|
||||
"For byte-compiling Doom and your config"
|
||||
(load! "cli/byte-compile"))
|
||||
|
||||
(defcligroup! "Utilities"
|
||||
"Conveniences for interacting with Doom externally"
|
||||
(defcli! 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
|
||||
|
|
|
@ -1,66 +1,89 @@
|
|||
;;; core-editor.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar doom-large-file-size 2
|
||||
"Size (in MB) above which the user will be prompted to open the file literally
|
||||
to avoid performance issues. Opening literally means that no major or minor
|
||||
modes are active and the buffer is read-only.")
|
||||
|
||||
(defvar doom-large-file-modes-list
|
||||
'(fundamental-mode special-mode archive-mode tar-mode jka-compr
|
||||
git-commit-mode image-mode doc-view-mode doc-view-mode-maybe
|
||||
ebrowse-tree-mode pdf-view-mode tags-table-mode)
|
||||
"Major modes that `doom|check-large-file' will ignore.")
|
||||
(defvar doom-detect-indentation-excluded-modes '(fundamental-mode)
|
||||
"A list of major modes in which indentation should be automatically
|
||||
detected.")
|
||||
|
||||
(defvar-local doom-inhibit-indent-detection nil
|
||||
"A buffer-local flag that indicates whether `dtrt-indent' should try to detect
|
||||
indentation settings or not. This should be set by editorconfig if it
|
||||
successfully sets indent_style/indent_size.")
|
||||
|
||||
(defvar doom-detect-indentation-excluded-modes '(fundamental-mode)
|
||||
"A list of major modes in which indentation should be automatically
|
||||
detected.")
|
||||
|
||||
(setq-default
|
||||
large-file-warning-threshold 15000000
|
||||
vc-follow-symlinks t
|
||||
;; Save clipboard contents into kill-ring before replacing them
|
||||
save-interprogram-paste-before-kill t
|
||||
;; Bookmarks
|
||||
bookmark-default-file (concat doom-etc-dir "bookmarks")
|
||||
bookmark-save-flag t
|
||||
;; Formatting
|
||||
delete-trailing-lines nil
|
||||
fill-column 80
|
||||
sentence-end-double-space nil
|
||||
word-wrap t
|
||||
;; Scrolling
|
||||
hscroll-margin 2
|
||||
hscroll-step 1
|
||||
scroll-conservatively 1001
|
||||
scroll-margin 0
|
||||
scroll-preserve-screen-position t
|
||||
mouse-wheel-scroll-amount '(5 ((shift) . 2))
|
||||
mouse-wheel-progressive-speed nil ; don't accelerate scrolling
|
||||
;; Whitespace (see `editorconfig')
|
||||
indent-tabs-mode nil
|
||||
require-final-newline t
|
||||
;;
|
||||
;;; File handling
|
||||
|
||||
;; Resolve symlinks when opening files, so that any operations are conducted
|
||||
;; from the file's true directory (like `find-file').
|
||||
(setq find-file-visit-truename t)
|
||||
|
||||
;; Disable the warning "X and Y are the same file". It's fine to ignore this
|
||||
;; warning as it will redirect you to the existing buffer anyway.
|
||||
(setq find-file-suppress-same-file-warnings t)
|
||||
|
||||
;; Create missing directories when we open a file that doesn't exist under a
|
||||
;; directory tree that may not exist.
|
||||
(add-hook! 'find-file-not-found-functions
|
||||
(defun doom-create-missing-directories-h ()
|
||||
"Automatically create missing directories when creating new files."
|
||||
(let ((parent-directory (file-name-directory buffer-file-name)))
|
||||
(when (and (not (file-exists-p parent-directory))
|
||||
(y-or-n-p (format "Directory `%s' does not exist! Create it?" parent-directory)))
|
||||
(make-directory parent-directory t)))))
|
||||
|
||||
;; Don't autosave files or create lock/history/backup files. The
|
||||
;; editor doesn't need to hold our hands so much. We'll rely on git
|
||||
;; and our own good fortune instead. Fingers crossed!
|
||||
(setq auto-save-default nil
|
||||
create-lockfiles nil
|
||||
make-backup-files nil
|
||||
;; But have a place to store them in case we do use them...
|
||||
auto-save-list-file-name (concat doom-cache-dir "autosave")
|
||||
backup-directory-alist `(("." . ,(concat doom-cache-dir "backup/"))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Formatting
|
||||
|
||||
;; Indentation
|
||||
(setq-default tab-width 4
|
||||
tab-always-indent t
|
||||
tab-width 4
|
||||
tabify-regexp "^\t* [ \t]+" ; for :retab
|
||||
;; Wrapping
|
||||
indent-tabs-mode nil
|
||||
fill-column 80)
|
||||
|
||||
;; Word wrapping
|
||||
(setq-default word-wrap t
|
||||
truncate-lines t
|
||||
truncate-partial-width-windows 50)
|
||||
truncate-partial-width-windows nil)
|
||||
|
||||
;; Remove hscroll-margin in shells, otherwise it causes jumpiness
|
||||
(setq-hook! '(eshell-mode-hook term-mode-hook) hscroll-margin 0)
|
||||
(setq sentence-end-double-space nil
|
||||
delete-trailing-lines nil
|
||||
require-final-newline t
|
||||
tabify-regexp "^\t* [ \t]+") ; for :retab
|
||||
|
||||
(defun doom*optimize-literal-mode-for-large-files (buffer)
|
||||
(with-current-buffer buffer
|
||||
(when find-file-literally
|
||||
(setq buffer-read-only t)
|
||||
(buffer-disable-undo))
|
||||
buffer))
|
||||
(advice-add #'find-file-noselect-1 :filter-return #'doom*optimize-literal-mode-for-large-files)
|
||||
|
||||
;;
|
||||
;;; Clipboard / kill-ring
|
||||
|
||||
;; Eliminate duplicates in the kill ring. That is, if you kill the
|
||||
;; same thing twice, you won't have to use M-y twice to get past it
|
||||
;; to older entries in the kill ring.
|
||||
(setq kill-do-not-save-duplicates t)
|
||||
|
||||
;;
|
||||
(setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
|
||||
|
||||
;; Save clipboard contents into kill-ring before replacing them
|
||||
(setq save-interprogram-paste-before-kill t)
|
||||
|
||||
;; Fix the clipboard in terminal or daemon Emacs (non-GUI)
|
||||
(add-hook! 'tty-setup-hook
|
||||
(defun doom-init-clipboard-in-tty-emacs-h ()
|
||||
(unless (getenv "SSH_CONNECTION")
|
||||
(cond (IS-MAC
|
||||
(if (require 'osx-clipboard nil t) (osx-clipboard-mode)))
|
||||
((executable-find "xclip")
|
||||
(if (require 'xclip nil t) (xclip-mode)))))))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -72,12 +95,12 @@ detected.")
|
|||
;;
|
||||
;;; Built-in plugins
|
||||
|
||||
(def-package! autorevert
|
||||
(use-package! autorevert
|
||||
;; revert buffers when their files/state have changed
|
||||
:hook (focus-in . doom|auto-revert-buffers)
|
||||
:hook (after-save . doom|auto-revert-buffers)
|
||||
:hook (doom-switch-buffer . doom|auto-revert-buffer)
|
||||
:hook (doom-switch-window . doom|auto-revert-buffer)
|
||||
:hook (focus-in . doom-auto-revert-buffers-h)
|
||||
:hook (after-save . doom-auto-revert-buffers-h)
|
||||
:hook (doom-switch-buffer . doom-auto-revert-buffer-h)
|
||||
:hook (doom-switch-window . doom-auto-revert-buffer-h)
|
||||
:config
|
||||
(setq auto-revert-verbose t ; let us know when it happens
|
||||
auto-revert-use-notify nil
|
||||
|
@ -90,21 +113,27 @@ detected.")
|
|||
;; grind Emacs to a halt if you do expensive IO (outside of Emacs) on the
|
||||
;; files you have open (like compression). We only really need revert changes
|
||||
;; when we switch to a buffer or when we focus the Emacs frame.
|
||||
(defun doom|auto-revert-buffers ()
|
||||
(defun doom-auto-revert-buffer-h ()
|
||||
"Auto revert current buffer, if necessary."
|
||||
(unless auto-revert-mode
|
||||
(let ((revert-without-query t))
|
||||
(auto-revert-handler))))
|
||||
|
||||
(defun doom-auto-revert-buffers-h ()
|
||||
"Auto revert's stale buffers (that are visible)."
|
||||
(unless auto-revert-mode
|
||||
(dolist (buf (doom-visible-buffers))
|
||||
(with-current-buffer buf
|
||||
(auto-revert-handler)))))
|
||||
(doom-auto-revert-buffer-h))))))
|
||||
|
||||
(defun doom|auto-revert-buffer ()
|
||||
"Auto revert current buffer, if necessary."
|
||||
(unless auto-revert-mode
|
||||
(auto-revert-handler))))
|
||||
|
||||
(def-package! recentf
|
||||
(after! bookmark
|
||||
(setq bookmark-save-flag t))
|
||||
|
||||
|
||||
(use-package! recentf
|
||||
;; Keep track of recently opened files
|
||||
:defer-incrementally (easymenu tree-widget timer)
|
||||
:defer-incrementally easymenu tree-widget timer
|
||||
:after-call after-find-file
|
||||
:commands recentf-open-files
|
||||
:config
|
||||
|
@ -126,27 +155,27 @@ detected.")
|
|||
file))
|
||||
(setq recentf-filename-handlers '(doom--recent-file-truename abbreviate-file-name))
|
||||
|
||||
(defun doom|recentf-touch-buffer ()
|
||||
(add-hook! '(doom-switch-window-hook write-file-functions)
|
||||
(defun doom--recentf-touch-buffer-h ()
|
||||
"Bump file in recent file list when it is switched or written to."
|
||||
(when buffer-file-name
|
||||
(recentf-add-file buffer-file-name))
|
||||
;; Return nil for `write-file-functions'
|
||||
nil)
|
||||
(add-hook 'doom-switch-window-hook #'doom|recentf-touch-buffer)
|
||||
(add-hook 'write-file-functions #'doom|recentf-touch-buffer)
|
||||
nil))
|
||||
|
||||
(defun doom|recentf-add-dired-directory ()
|
||||
(add-hook! 'dired-mode-hook
|
||||
(defun doom--recentf-add-dired-directory-h ()
|
||||
"Add dired directory to recentf file list."
|
||||
(recentf-add-file default-directory))
|
||||
(add-hook 'dired-mode-hook #'doom|recentf-add-dired-directory)
|
||||
(recentf-add-file default-directory)))
|
||||
|
||||
(unless noninteractive
|
||||
(add-hook 'kill-emacs-hook #'recentf-cleanup)
|
||||
(quiet! (recentf-mode +1))))
|
||||
|
||||
(def-package! savehist
|
||||
|
||||
(use-package! savehist
|
||||
;; persist variables across sessions
|
||||
:defer-incrementally (custom)
|
||||
:defer-incrementally custom
|
||||
:after-call post-command-hook
|
||||
:config
|
||||
(setq savehist-file (concat doom-cache-dir "savehist")
|
||||
|
@ -155,32 +184,32 @@ detected.")
|
|||
savehist-additional-variables '(kill-ring search-ring regexp-search-ring))
|
||||
(savehist-mode +1)
|
||||
|
||||
(defun doom|unpropertize-kill-ring ()
|
||||
"Remove text properties from `kill-ring' in the interest of shrinking the
|
||||
savehist file."
|
||||
(add-hook! 'kill-emacs-hook
|
||||
(defun doom-unpropertize-kill-ring-h ()
|
||||
"Remove text properties from `kill-ring' for a smaller savehist file."
|
||||
(setq kill-ring (cl-loop for item in kill-ring
|
||||
if (stringp item)
|
||||
collect (substring-no-properties item)
|
||||
else if item collect it)))
|
||||
(add-hook 'kill-emacs-hook #'doom|unpropertize-kill-ring))
|
||||
else if item collect it)))))
|
||||
|
||||
(def-package! saveplace
|
||||
|
||||
(use-package! saveplace
|
||||
;; persistent point location in buffers
|
||||
:after-call (after-find-file dired-initial-position-hook)
|
||||
:after-call after-find-file dired-initial-position-hook
|
||||
:config
|
||||
(setq save-place-file (concat doom-cache-dir "saveplace")
|
||||
save-place-forget-unreadable-files t
|
||||
save-place-limit 200)
|
||||
(defun doom*recenter-on-load-saveplace (&rest _)
|
||||
(defadvice! doom--recenter-on-load-saveplace-a (&rest _)
|
||||
"Recenter on cursor when loading a saved place."
|
||||
:after-while #'save-place-find-file-hook
|
||||
(if buffer-file-name (ignore-errors (recenter))))
|
||||
(advice-add #'save-place-find-file-hook
|
||||
:after-while #'doom*recenter-on-load-saveplace)
|
||||
(save-place-mode +1))
|
||||
|
||||
(def-package! server
|
||||
|
||||
(use-package! server
|
||||
:when (display-graphic-p)
|
||||
:after-call (pre-command-hook after-find-file focus-out-hook)
|
||||
:after-call pre-command-hook after-find-file focus-out-hook
|
||||
:init
|
||||
(when-let (name (getenv "EMACS_SERVER_NAME"))
|
||||
(setq server-name name))
|
||||
|
@ -192,8 +221,8 @@ savehist file."
|
|||
;;
|
||||
;;; Packages
|
||||
|
||||
(def-package! better-jumper
|
||||
:after-call (pre-command-hook)
|
||||
(use-package! better-jumper
|
||||
:after-call pre-command-hook
|
||||
:init
|
||||
(global-set-key [remap evil-jump-forward] #'better-jumper-jump-forward)
|
||||
(global-set-key [remap evil-jump-backward] #'better-jumper-jump-backward)
|
||||
|
@ -202,14 +231,14 @@ savehist file."
|
|||
(better-jumper-mode +1)
|
||||
(add-hook 'better-jumper-post-jump-hook #'recenter)
|
||||
|
||||
(defun doom*set-jump (orig-fn &rest args)
|
||||
(defadvice! doom-set-jump-a (orig-fn &rest args)
|
||||
"Set a jump point and ensure ORIG-FN doesn't set any new jump points."
|
||||
(better-jumper-set-jump (if (markerp (car args)) (car args)))
|
||||
(let ((evil--jumps-jumping t)
|
||||
(better-jumper--jumping t))
|
||||
(apply orig-fn args)))
|
||||
|
||||
(defun doom*set-jump-maybe (orig-fn &rest args)
|
||||
(defadvice! doom-set-jump-maybe-a (orig-fn &rest args)
|
||||
"Set a jump point if ORIG-FN returns non-nil."
|
||||
(let ((origin (point-marker))
|
||||
(result
|
||||
|
@ -224,13 +253,13 @@ savehist file."
|
|||
origin))))
|
||||
result))
|
||||
|
||||
(defun doom|set-jump ()
|
||||
(defun doom-set-jump-h ()
|
||||
"Run `better-jumper-set-jump' but return nil, for short-circuiting hooks."
|
||||
(better-jumper-set-jump)
|
||||
nil))
|
||||
|
||||
|
||||
(def-package! command-log-mode
|
||||
(use-package! command-log-mode
|
||||
:commands global-command-log-mode
|
||||
:config
|
||||
(setq command-log-mode-auto-show t
|
||||
|
@ -239,21 +268,20 @@ savehist file."
|
|||
command-log-mode-window-size 50))
|
||||
|
||||
|
||||
(def-package! dtrt-indent
|
||||
(use-package! dtrt-indent
|
||||
;; Automatic detection of indent settings
|
||||
:unless noninteractive
|
||||
:defer t
|
||||
:init
|
||||
(defun doom|detect-indentation ()
|
||||
(add-hook! '(change-major-mode-after-body-hook read-only-mode-hook)
|
||||
(defun doom-detect-indentation-h ()
|
||||
(unless (or (not after-init-time)
|
||||
doom-inhibit-indent-detection
|
||||
(member (substring (buffer-name) 0 1) '(" " "*"))
|
||||
(memq major-mode doom-detect-indentation-excluded-modes))
|
||||
;; Don't display messages in the echo area, but still log them
|
||||
(let ((inhibit-message (not doom-debug-mode)))
|
||||
(dtrt-indent-mode +1))))
|
||||
(add-hook! '(change-major-mode-after-body-hook read-only-mode-hook)
|
||||
#'doom|detect-indentation)
|
||||
(dtrt-indent-mode +1)))))
|
||||
:config
|
||||
(setq dtrt-indent-run-after-smie t)
|
||||
|
||||
|
@ -261,9 +289,10 @@ savehist file."
|
|||
(push '(t tab-width) dtrt-indent-hook-generic-mapping-list)
|
||||
|
||||
(defvar dtrt-indent-run-after-smie)
|
||||
(defun doom*fix-broken-smie-modes (orig-fn arg)
|
||||
(defadvice! doom--fix-broken-smie-modes-a (orig-fn arg)
|
||||
"Some smie modes throw errors when trying to guess their indentation, like
|
||||
`nim-mode'. This prevents them from leaving Emacs in a broken state."
|
||||
:around #'dtrt-indent-mode
|
||||
(let ((dtrt-indent-run-after-smie dtrt-indent-run-after-smie))
|
||||
(cl-letf* ((old-smie-config-guess (symbol-function 'smie-config-guess))
|
||||
((symbol-function 'smie-config-guess)
|
||||
|
@ -273,11 +302,10 @@ savehist file."
|
|||
(message "[WARNING] Indent detection: %s"
|
||||
(error-message-string e))
|
||||
(message "")))))) ; warn silently
|
||||
(funcall orig-fn arg))))
|
||||
(advice-add #'dtrt-indent-mode :around #'doom*fix-broken-smie-modes))
|
||||
(funcall orig-fn arg)))))
|
||||
|
||||
|
||||
(def-package! helpful
|
||||
(use-package! helpful
|
||||
;; a better *help* buffer
|
||||
:commands helpful--read-symbol
|
||||
:init
|
||||
|
@ -288,6 +316,12 @@ savehist file."
|
|||
[remap describe-key] #'helpful-key
|
||||
[remap describe-symbol] #'doom/describe-symbol)
|
||||
|
||||
(defun doom-use-helpful-a (orig-fn &rest args)
|
||||
"Force ORIG-FN to use helpful instead of the old describe-* commands."
|
||||
(cl-letf (((symbol-function #'describe-function) #'helpful-function)
|
||||
((symbol-function #'describe-variable) #'helpful-variable))
|
||||
(apply orig-fn args)))
|
||||
|
||||
(after! apropos
|
||||
;; patch apropos buttons to call helpful instead of help
|
||||
(dolist (fun-bt '(apropos-function apropos-macro apropos-command))
|
||||
|
@ -306,44 +340,69 @@ savehist file."
|
|||
(add-hook 'imenu-after-jump-hook #'recenter)
|
||||
|
||||
|
||||
(def-package! smartparens
|
||||
(use-package! smartparens
|
||||
;; Auto-close delimiters and blocks as you type. It's more powerful than that,
|
||||
;; but that is all Doom uses it for.
|
||||
:after-call (doom-switch-buffer-hook after-find-file)
|
||||
:commands (sp-pair sp-local-pair sp-with-modes sp-point-in-comment sp-point-in-string)
|
||||
:after-call doom-switch-buffer-hook after-find-file
|
||||
:commands sp-pair sp-local-pair sp-with-modes sp-point-in-comment sp-point-in-string
|
||||
:config
|
||||
;; Load default smartparens rules for various languages
|
||||
(require 'smartparens-config)
|
||||
|
||||
;; Overlays are too distracting and not terribly helpful. show-parens does
|
||||
;; this for us already, so...
|
||||
(setq sp-highlight-pair-overlay nil
|
||||
sp-highlight-wrap-overlay nil
|
||||
sp-highlight-wrap-tag-overlay nil
|
||||
sp-show-pair-from-inside t
|
||||
sp-cancel-autoskip-on-backward-movement nil
|
||||
sp-show-pair-delay 0.1
|
||||
sp-max-pair-length 4
|
||||
sp-max-prefix-length 50
|
||||
sp-escape-quotes-after-insert nil) ; not smart enough
|
||||
sp-highlight-wrap-tag-overlay nil)
|
||||
;; But if someone does want overlays enabled, evil users will be stricken with
|
||||
;; an off-by-one issue where smartparens assumes you're outside the pair when
|
||||
;; you're really at the last character in insert mode. We must correct this
|
||||
;; vile injustice.
|
||||
(setq sp-show-pair-from-inside t)
|
||||
;; ...and stay highlighted until we've truly escaped the pair!
|
||||
(setq sp-cancel-autoskip-on-backward-movement nil)
|
||||
;; The default is 100, because smartparen's scans are relatively expensive
|
||||
;; (especially with large pair lists for somoe modes), we halve it, as a
|
||||
;; better compromise between performance and accuracy.
|
||||
(setq sp-max-prefix-length 50)
|
||||
;; This speeds up smartparens. No pair has any business being longer than 4
|
||||
;; characters; if they must, the modes that need it set it buffer-locally.
|
||||
(setq sp-max-pair-length 4)
|
||||
;; This isn't always smart enough to determine when we're in a string or not.
|
||||
;; See https://github.com/Fuco1/smartparens/issues/783.
|
||||
(setq sp-escape-quotes-after-insert nil)
|
||||
|
||||
;; autopairing in `eval-expression' and `evil-ex'
|
||||
(defun doom|init-smartparens-in-eval-expression ()
|
||||
;; Silence some harmless but annoying echo-area spam
|
||||
(dolist (key '(:unmatched-expression :no-matching-tag))
|
||||
(setf (cdr (assq key sp-message-alist)) nil))
|
||||
|
||||
(add-hook! 'minibuffer-setup-hook
|
||||
(defun doom-init-smartparens-in-minibuffer-maybe-h ()
|
||||
"Enable `smartparens-mode' in the minibuffer, during `eval-expression' or
|
||||
`evil-ex'."
|
||||
(when (memq this-command '(eval-expression evil-ex))
|
||||
(smartparens-mode)))
|
||||
(add-hook 'minibuffer-setup-hook #'doom|init-smartparens-in-eval-expression)
|
||||
(smartparens-mode))))
|
||||
|
||||
;; You're likely writing lisp in the minibuffer, therefore, disable these
|
||||
;; quote pairs, which lisps doesn't use for strings:
|
||||
(sp-local-pair 'minibuffer-inactive-mode "'" nil :actions nil)
|
||||
(sp-local-pair 'minibuffer-inactive-mode "`" nil :actions nil)
|
||||
|
||||
;; smartparens breaks evil-mode's replace state
|
||||
;; Smartparens breaks evil-mode's replace state
|
||||
(add-hook 'evil-replace-state-entry-hook #'turn-off-smartparens-mode)
|
||||
(add-hook 'evil-replace-state-exit-hook #'turn-on-smartparens-mode)
|
||||
|
||||
(smartparens-global-mode +1))
|
||||
|
||||
|
||||
(def-package! undo-tree
|
||||
(use-package! so-long
|
||||
:after-call after-find-file
|
||||
:config (global-so-long-mode +1))
|
||||
|
||||
|
||||
(use-package! undo-tree
|
||||
;; Branching & persistent undo
|
||||
:after-call (doom-switch-buffer-hook after-find-file)
|
||||
:after-call doom-switch-buffer-hook after-find-file
|
||||
:config
|
||||
(setq undo-tree-auto-save-history nil ; disable because unstable
|
||||
;; undo-in-region is known to cause undo history corruption, which can
|
||||
|
@ -354,28 +413,26 @@ savehist file."
|
|||
`(("." . ,(concat doom-cache-dir "undo-tree-hist/"))))
|
||||
|
||||
(when (executable-find "zstd")
|
||||
(defun doom*undo-tree-make-history-save-file-name (file)
|
||||
(concat file ".zst"))
|
||||
(advice-add #'undo-tree-make-history-save-file-name :filter-return
|
||||
#'doom*undo-tree-make-history-save-file-name))
|
||||
(defadvice! doom--undo-tree-make-history-save-file-name-a (file)
|
||||
:filter-return #'undo-tree-make-history-save-file-name
|
||||
(concat file ".zst")))
|
||||
|
||||
(defun doom*strip-text-properties-from-undo-history (&rest _)
|
||||
(defadvice! doom--undo-tree-strip-text-properties-a (&rest _)
|
||||
:before #'undo-list-transfer-to-tree
|
||||
(dolist (item buffer-undo-list)
|
||||
(and (consp item)
|
||||
(stringp (car item))
|
||||
(setcar item (substring-no-properties (car item))))))
|
||||
(advice-add #'undo-list-transfer-to-tree :before #'doom*strip-text-properties-from-undo-history)
|
||||
|
||||
(global-undo-tree-mode +1))
|
||||
|
||||
|
||||
(def-package! ws-butler
|
||||
(use-package! ws-butler
|
||||
;; a less intrusive `delete-trailing-whitespaces' on save
|
||||
:after-call (after-find-file)
|
||||
:after-call after-find-file
|
||||
:config
|
||||
(setq ws-butler-global-exempt-modes
|
||||
(append ws-butler-global-exempt-modes
|
||||
'(special-mode comint-mode term-mode eshell-mode)))
|
||||
(appendq! ws-butler-global-exempt-modes
|
||||
'(special-mode comint-mode term-mode eshell-mode))
|
||||
(ws-butler-global-mode))
|
||||
|
||||
(provide 'core-editor)
|
||||
|
|
|
@ -6,26 +6,18 @@
|
|||
;; entirely for performance reasons).
|
||||
|
||||
(defvar doom-leader-key "SPC"
|
||||
"The leader prefix key for Evil users.
|
||||
|
||||
This needs to be changed from $DOOMDIR/init.el.")
|
||||
"The leader prefix key for Evil users.")
|
||||
|
||||
(defvar doom-leader-alt-key "M-SPC"
|
||||
"An alternative leader prefix key, used for Insert and Emacs states, and for
|
||||
non-evil users.
|
||||
|
||||
This needs to be changed from $DOOMDIR/init.el.")
|
||||
non-evil users.")
|
||||
|
||||
(defvar doom-localleader-key "SPC m"
|
||||
"The localleader prefix key, for major-mode specific commands.
|
||||
|
||||
This needs to be changed from $DOOMDIR/init.el.")
|
||||
"The localleader prefix key, for major-mode specific commands.")
|
||||
|
||||
(defvar doom-localleader-alt-key "M-SPC m"
|
||||
"The localleader prefix key, for major-mode specific commands. Used for Insert
|
||||
and Emacs states, and for non-evil users.
|
||||
|
||||
This needs to be changed from $DOOMDIR/init.el.")
|
||||
and Emacs states, and for non-evil users.")
|
||||
|
||||
(defvar doom-leader-map (make-sparse-keymap)
|
||||
"An overriding keymap for <leader> keys.")
|
||||
|
@ -73,13 +65,14 @@ If any hook returns non-nil, all hooks after it are ignored.")
|
|||
;;
|
||||
;;; General + leader/localleader keys
|
||||
|
||||
(require 'general)
|
||||
;; Convenience aliases
|
||||
(defalias 'define-key! #'general-def)
|
||||
(defalias 'unmap! #'general-unbind)
|
||||
(use-package general
|
||||
:init
|
||||
;; Convenience aliases
|
||||
(defalias 'define-key! #'general-def)
|
||||
(defalias 'unmap! #'general-unbind))
|
||||
|
||||
;; `map!' uses this instead of `define-leader-key!' because it consumes 20-30%
|
||||
;; more startup time, so we reimplement it ourselves.
|
||||
;; HACK `map!' uses this instead of `define-leader-key!' because it consumes
|
||||
;; 20-30% more startup time, so we reimplement it ourselves.
|
||||
(defmacro doom--define-leader-key (&rest keys)
|
||||
(let (prefix forms wkforms)
|
||||
(while keys
|
||||
|
@ -99,19 +92,16 @@ If any hook returns non-nil, all hooks after it are ignored.")
|
|||
,bdef)
|
||||
forms))
|
||||
(when-let (desc (cadr (memq :which-key udef)))
|
||||
(push `(which-key-add-key-based-replacements
|
||||
(prependq!
|
||||
wkforms `((which-key-add-key-based-replacements
|
||||
(general--concat t doom-leader-alt-key ,key)
|
||||
,desc)
|
||||
wkforms)
|
||||
(push `(which-key-add-key-based-replacements
|
||||
(which-key-add-key-based-replacements
|
||||
(general--concat t doom-leader-key ,key)
|
||||
,desc)
|
||||
wkforms))))))
|
||||
,desc))))))))
|
||||
(macroexp-progn
|
||||
(append (nreverse forms)
|
||||
(when wkforms
|
||||
`((after! which-key
|
||||
,@(nreverse wkforms))))))))
|
||||
(cons `(after! which-key ,@(nreverse wkforms))
|
||||
(nreverse forms)))))
|
||||
|
||||
(defmacro define-leader-key! (&rest args)
|
||||
"Define <leader> keys.
|
||||
|
@ -157,7 +147,8 @@ localleader prefix."
|
|||
|
||||
;; Bind `doom-leader-key' and `doom-leader-alt-key' as late as possible to give
|
||||
;; the user a chance to modify them.
|
||||
(defun doom|init-leader-keys ()
|
||||
(add-hook! 'doom-after-init-modules-hook
|
||||
(defun doom-init-leader-keys-h ()
|
||||
"Bind `doom-leader-key' and `doom-leader-alt-key'."
|
||||
(let ((map general-override-mode-map))
|
||||
(if (not (featurep 'evil))
|
||||
|
@ -169,14 +160,13 @@ localleader prefix."
|
|||
(define-key map (kbd doom-leader-alt-key) 'doom/leader))
|
||||
(evil-define-key* '(normal visual motion) map (kbd doom-leader-key) 'doom/leader)
|
||||
(evil-define-key* '(emacs insert) map (kbd doom-leader-alt-key) 'doom/leader))
|
||||
(general-override-mode +1)))
|
||||
(add-hook 'doom-after-init-modules-hook #'doom|init-leader-keys)
|
||||
(general-override-mode +1))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Packages
|
||||
|
||||
(def-package! which-key
|
||||
(use-package! which-key
|
||||
:defer 1
|
||||
:after-call pre-command-hook
|
||||
:init
|
||||
|
@ -198,10 +188,6 @@ localleader prefix."
|
|||
(which-key-mode +1))
|
||||
|
||||
|
||||
;;;###package hydra
|
||||
(setq lv-use-seperator t)
|
||||
|
||||
|
||||
;;
|
||||
;;; `map!' macro
|
||||
|
||||
|
@ -216,7 +202,7 @@ localleader prefix."
|
|||
(?g . global))
|
||||
"A list of cons cells that map a letter to a evil state symbol.")
|
||||
|
||||
(defun doom--keyword-to-states (keyword)
|
||||
(defun doom--map-keyword-to-states (keyword)
|
||||
"Convert a KEYWORD into a list of evil state symbols.
|
||||
|
||||
For example, :nvi will map to (list 'normal 'visual 'insert). See
|
||||
|
@ -232,12 +218,9 @@ For example, :nvi will map to (list 'normal 'visual 'insert). See
|
|||
(put :leader 'lisp-indent-function 'defun)
|
||||
(put :localleader 'lisp-indent-function 'defun)
|
||||
(put :map 'lisp-indent-function 'defun)
|
||||
(put :keymap 'lisp-indent-function 'defun)
|
||||
(put :mode 'lisp-indent-function 'defun)
|
||||
(put :prefix 'lisp-indent-function 'defun)
|
||||
(put :prefix-map 'lisp-indent-function 'defun)
|
||||
(put :unless 'lisp-indent-function 'defun)
|
||||
(put :when 'lisp-indent-function 'defun)
|
||||
|
||||
;; specials
|
||||
(defvar doom--map-forms nil)
|
||||
|
@ -271,7 +254,7 @@ For example, :nvi will map to (list 'normal 'visual 'insert). See
|
|||
(setq rest nil))
|
||||
(:desc
|
||||
(setq desc (pop rest)))
|
||||
((or :map :map* :keymap)
|
||||
(:map
|
||||
(doom--map-set :keymaps `(quote ,(doom-enlist (pop rest)))))
|
||||
(:mode
|
||||
(push (cl-loop for m in (doom-enlist (pop rest))
|
||||
|
@ -307,7 +290,9 @@ For example, :nvi will map to (list 'normal 'visual 'insert). See
|
|||
doom--map-forms)))
|
||||
(_
|
||||
(condition-case _
|
||||
(doom--map-def (pop rest) (pop rest) (doom--keyword-to-states key) desc)
|
||||
(doom--map-def (pop rest) (pop rest)
|
||||
(doom--map-keyword-to-states key)
|
||||
desc)
|
||||
(error
|
||||
(error "Not a valid `map!' property: %s" key)))
|
||||
(setq desc nil))))
|
||||
|
@ -414,7 +399,6 @@ Properties
|
|||
:localleader [...] bind to localleader; requires a keymap
|
||||
:mode [MODE(s)] [...] inner keybinds are applied to major MODE(s)
|
||||
:map [KEYMAP(s)] [...] inner keybinds are applied to KEYMAP(S)
|
||||
:keymap [KEYMAP(s)] [...] same as :map
|
||||
:prefix [PREFIX] [...] set keybind prefix for following keys. PREFIX
|
||||
can be a cons cell: (PREFIX . DESCRIPTION)
|
||||
:prefix-map [PREFIX] [...] same as :prefix, but defines a prefix keymap
|
||||
|
|
660
core/core-lib.el
660
core/core-lib.el
|
@ -1,6 +1,6 @@
|
|||
;;; core-lib.el -*- lexical-binding: t; -*-
|
||||
|
||||
(let ((load-path doom-site-load-path))
|
||||
(let ((load-path doom--initial-load-path))
|
||||
(require 'subr-x)
|
||||
(require 'cl-lib))
|
||||
|
||||
|
@ -12,56 +12,36 @@
|
|||
;; if-let and when-let were moved to (if|when)-let* in Emacs 26+ so we alias
|
||||
;; them for 25 users.
|
||||
(defalias 'if-let* #'if-let)
|
||||
(defalias 'when-let* #'when-let)))
|
||||
(defalias 'when-let* #'when-let)
|
||||
|
||||
;; `mapcan' was introduced in 26.1. `cl-mapcan' isn't a perfect replacement,
|
||||
;; but it's close enough.
|
||||
(defalias 'mapcan #'cl-mapcan)
|
||||
|
||||
(defun alist-get (key alist &optional default remove testfn)
|
||||
"Return the value associated with KEY in ALIST.
|
||||
If KEY is not found in ALIST, return DEFAULT.
|
||||
Use TESTFN to lookup in the alist if non-nil. Otherwise, use `assq'.
|
||||
|
||||
This is a generalized variable suitable for use with `setf'.
|
||||
When using it to set a value, optional argument REMOVE non-nil
|
||||
means to remove KEY from ALIST if the new value is `eql' to DEFAULT."
|
||||
(ignore remove) ;;Silence byte-compiler.
|
||||
(let ((x (if (not testfn)
|
||||
(assq key alist)
|
||||
;; In Emacs<26, `assoc' has no testfn arg, so we have to
|
||||
;; implement it ourselves
|
||||
(if testfn
|
||||
(cl-loop for entry in alist
|
||||
if (funcall testfn key entry)
|
||||
return entry)
|
||||
(assoc key alist)))))
|
||||
(if x (cdr x) default)))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Helpers
|
||||
|
||||
(defun doom--resolve-path-forms (spec &optional directory)
|
||||
"Converts a simple nested series of or/and forms into a series of
|
||||
`file-exists-p' checks.
|
||||
|
||||
For example
|
||||
|
||||
(doom--resolve-path-forms
|
||||
'(or A (and B C))
|
||||
\"~\")
|
||||
|
||||
Returns (approximately):
|
||||
|
||||
'(let* ((_directory \"~\")
|
||||
(A (expand-file-name A _directory))
|
||||
(B (expand-file-name B _directory))
|
||||
(C (expand-file-name C _directory)))
|
||||
(or (and (file-exists-p A) A)
|
||||
(and (if (file-exists-p B) B)
|
||||
(if (file-exists-p C) C))))
|
||||
|
||||
This is used by `associate!', `file-exists-p!' and `project-file-exists-p!'."
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(cond ((stringp spec)
|
||||
`(let ((--file-- ,(if (file-name-absolute-p spec)
|
||||
spec
|
||||
`(expand-file-name ,spec ,directory))))
|
||||
(and (file-exists-p --file--)
|
||||
--file--)))
|
||||
((and (listp spec)
|
||||
(memq (car spec) '(or and)))
|
||||
`(,(car spec)
|
||||
,@(cl-loop for i in (cdr spec)
|
||||
collect (doom--resolve-path-forms i directory))))
|
||||
((or (symbolp spec)
|
||||
(listp spec))
|
||||
`(let ((--file-- ,(if (and directory
|
||||
(or (not (stringp directory))
|
||||
(file-name-absolute-p directory)))
|
||||
`(expand-file-name ,spec ,directory)
|
||||
spec)))
|
||||
(and (file-exists-p --file--)
|
||||
--file--)))
|
||||
(spec)))
|
||||
|
||||
(defun doom--resolve-hook-forms (hooks)
|
||||
"Converts a list of modes into a list of hook symbols.
|
||||
|
||||
|
@ -76,20 +56,25 @@ list is returned as-is."
|
|||
collect (cadr hook)
|
||||
else collect (intern (format "%s-hook" (symbol-name hook)))))))
|
||||
|
||||
(defun doom--assert-stage-p (stage macro)
|
||||
(unless (or (bound-and-true-p byte-compile-current-file)
|
||||
;; Don't complain if we're being evaluated on-the-fly. Since forms
|
||||
;; are often evaluated (by `eval-region') or expanded (by
|
||||
;; macroexpand) in a temp buffer in `emacs-lisp-mode'...
|
||||
(eq major-mode 'emacs-lisp-mode))
|
||||
(cl-assert (eq stage doom--stage)
|
||||
nil
|
||||
"Found %s call in non-%s.el file (%s)"
|
||||
macro (symbol-name stage)
|
||||
(let ((path (FILE!)))
|
||||
(if (file-in-directory-p path doom-emacs-dir)
|
||||
(file-relative-name path doom-emacs-dir)
|
||||
(abbreviate-file-name path))))))
|
||||
(defun doom--setq-hook-fns (hooks rest &optional singles)
|
||||
(unless (or singles (= 0 (% (length rest) 2)))
|
||||
(signal 'wrong-number-of-arguments (list #'evenp (length rest))))
|
||||
(cl-loop with vars = (let ((args rest)
|
||||
vars)
|
||||
(while args
|
||||
(push (if singles
|
||||
(list (pop args))
|
||||
(cons (pop args) (pop args)))
|
||||
vars))
|
||||
(nreverse vars))
|
||||
for hook in (doom--resolve-hook-forms hooks)
|
||||
for mode = (string-remove-suffix "-hook" (symbol-name hook))
|
||||
append
|
||||
(cl-loop for (var . val) in vars
|
||||
collect
|
||||
(list var val hook
|
||||
(intern (format "doom--setq-%s-for-%s-h"
|
||||
var mode))))))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -116,7 +101,7 @@ list is returned as-is."
|
|||
(defun doom-keyword-name (keyword)
|
||||
"Returns the string name of KEYWORD (`keywordp') minus the leading colon."
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(cl-check-type :test keyword)
|
||||
(cl-check-type keyword keyword)
|
||||
(substring (symbol-name keyword) 1))
|
||||
|
||||
(defmacro doom-log (format-string &rest args)
|
||||
|
@ -136,57 +121,239 @@ Accepts the same arguments as `message'."
|
|||
format-string)
|
||||
,@args))))
|
||||
|
||||
(defun FILE! ()
|
||||
"Return the emacs lisp file this macro is called from."
|
||||
(cond ((bound-and-true-p byte-compile-current-file))
|
||||
(load-file-name)
|
||||
(buffer-file-name)
|
||||
((stringp (car-safe current-load-list)) (car current-load-list))))
|
||||
(defalias 'doom-partial #'apply-partially)
|
||||
|
||||
(defun DIR! ()
|
||||
"Returns the directory of the emacs lisp file this macro is called from."
|
||||
(let ((file (FILE!)))
|
||||
(and file (file-name-directory file))))
|
||||
(defun doom-rpartial (fn &rest args)
|
||||
"Return a function that is a partial application of FUN to right-hand ARGS.
|
||||
|
||||
ARGS is a list of the last N arguments to pass to FUN. The result is a new
|
||||
function which does the same as FUN, except that the last N arguments are fixed
|
||||
at the values with which this function was called."
|
||||
(lambda (&rest pre-args)
|
||||
(apply fn (append pre-args args))))
|
||||
|
||||
|
||||
;;
|
||||
;; Macros
|
||||
;;; Sugars
|
||||
|
||||
(defmacro λ! (&rest body)
|
||||
"Expands to (lambda () (interactive) ,@body)."
|
||||
(declare (doc-string 1))
|
||||
`(lambda () (interactive) ,@body))
|
||||
(defalias 'lambda! 'λ!)
|
||||
|
||||
(defmacro λ!! (command &optional arg)
|
||||
(defun λ!! (command &optional arg)
|
||||
"Expands to a command that interactively calls COMMAND with prefix ARG."
|
||||
(declare (doc-string 1))
|
||||
`(lambda () (interactive)
|
||||
(let ((current-prefix-arg ,arg))
|
||||
(call-interactively ,command))))
|
||||
|
||||
(defalias 'lambda! 'λ!)
|
||||
(lambda () (interactive)
|
||||
(let ((current-prefix-arg arg))
|
||||
(call-interactively command))))
|
||||
(defalias 'lambda!! 'λ!!)
|
||||
|
||||
(defun file! ()
|
||||
"Return the emacs lisp file this macro is called from."
|
||||
(cond ((bound-and-true-p byte-compile-current-file))
|
||||
(load-file-name)
|
||||
((stringp (car-safe current-load-list))
|
||||
(car current-load-list))
|
||||
(buffer-file-name)
|
||||
((error "Cannot get this file-path"))))
|
||||
|
||||
(defun dir! ()
|
||||
"Returns the directory of the emacs lisp file this macro is called from."
|
||||
(when-let (path (file!))
|
||||
(directory-file-name (file-name-directory path))))
|
||||
|
||||
(defmacro setq! (&rest settings)
|
||||
"A stripped-down `customize-set-variable' with the syntax of `setq'."
|
||||
(macroexp-progn
|
||||
(cl-loop for (var val) on settings by 'cddr
|
||||
collect `(funcall (or (get ',var 'custom-set) #'set)
|
||||
',var ,val))))
|
||||
|
||||
(defmacro pushnew! (place &rest values)
|
||||
"Like `cl-pushnew', but will prepend VALUES to PLACE.
|
||||
The order VALUES is preserved."
|
||||
`(dolist (--value-- (nreverse (list ,@values)))
|
||||
(cl-pushnew --value-- ,place)))
|
||||
"Push VALUES sequentially into PLACE, if they aren't already present.
|
||||
This is a variadic `cl-pushnew'."
|
||||
(let ((var (make-symbol "result")))
|
||||
`(dolist (,var (list ,@values))
|
||||
(cl-pushnew ,var ,place :test #'equal))))
|
||||
|
||||
(defmacro prependq! (sym &rest lists)
|
||||
"Prepend LISTS to SYM in place."
|
||||
`(setq ,sym (append ,@lists ,sym)))
|
||||
|
||||
(defmacro appendq! (sym &rest lists)
|
||||
"Append LISTS to SYM in place."
|
||||
`(setq ,sym (append ,sym ,@lists)))
|
||||
|
||||
(defmacro nconcq! (sym &rest lists)
|
||||
"Append LISTS to SYM by altering them in place."
|
||||
`(setq ,sym (nconc ,sym ,@lists)))
|
||||
|
||||
(defmacro delq! (elt list &optional fetcher)
|
||||
"Delete ELT from LIST in-place."
|
||||
"`delq' ELT from LIST in-place.
|
||||
|
||||
If FETCHER is a function, ELT is used as the key in LIST (an alist)."
|
||||
`(setq ,list
|
||||
(delq ,(if fetcher
|
||||
`(funcall ,fetcher ,elt ,list)
|
||||
elt)
|
||||
,list)))
|
||||
|
||||
(defmacro cond! (&rest clauses)
|
||||
"An anaphoric `cond', which stores the conditional value in `it'."
|
||||
`(let (it)
|
||||
(cond ,@(cl-loop for (cond . body) in clauses
|
||||
collect `((setq it ,cond)
|
||||
,@body)))))
|
||||
(defmacro delete! (elt list)
|
||||
"Delete ELT from LIST in-place."
|
||||
`(setq ,list (delete ,elt ,list)))
|
||||
|
||||
(defmacro add-transient-hook! (hook-or-function &rest forms)
|
||||
"Attaches a self-removing function to HOOK-OR-FUNCTION.
|
||||
|
||||
FORMS are evaluated once, when that function/hook is first invoked, then never
|
||||
again.
|
||||
|
||||
HOOK-OR-FUNCTION can be a quoted hook or a sharp-quoted function (which will be
|
||||
advised)."
|
||||
(declare (indent 1))
|
||||
(let ((append (if (eq (car forms) :after) (pop forms)))
|
||||
(fn (intern (format "doom--transient-%s-h" (sxhash hook-or-function)))))
|
||||
`(let ((sym ,hook-or-function))
|
||||
(defun ,fn (&rest _)
|
||||
,@forms
|
||||
(let ((sym ,hook-or-function))
|
||||
(cond ((functionp sym) (advice-remove sym #',fn))
|
||||
((symbolp sym) (remove-hook sym #',fn))))
|
||||
(unintern ',fn nil))
|
||||
(cond ((functionp sym)
|
||||
(advice-add ,hook-or-function ,(if append :after :before) #',fn))
|
||||
((symbolp sym)
|
||||
(put ',fn 'permanent-local-hook t)
|
||||
(add-hook sym #',fn ,append))))))
|
||||
|
||||
(defmacro add-hook! (hooks &rest rest)
|
||||
"A convenience macro for adding N functions to M hooks.
|
||||
|
||||
If N and M = 1, there's no benefit to using this macro over `add-hook'.
|
||||
|
||||
This macro accepts, in order:
|
||||
|
||||
1. Optional properties :local and/or :append, which will make the hook
|
||||
buffer-local or append to the list of hooks (respectively),
|
||||
2. The hook(s) to be added to: either an unquoted mode, an unquoted list of
|
||||
modes, a quoted hook variable or a quoted list of hook variables. If
|
||||
unquoted, '-hook' will be appended to each symbol.
|
||||
3. The function(s) to be added: this can be one function, a list thereof, a
|
||||
list of `defun's, or body forms (implicitly wrapped in a closure).
|
||||
|
||||
\(fn [:append :local] HOOKS FUNCTIONS)"
|
||||
(declare (indent (lambda (indent-point state)
|
||||
(goto-char indent-point)
|
||||
(when (looking-at-p "\\s-*(")
|
||||
(lisp-indent-defform state indent-point))))
|
||||
(debug t))
|
||||
(let* ((hook-forms (doom--resolve-hook-forms hooks))
|
||||
(func-forms ())
|
||||
(defn-forms ())
|
||||
append-p
|
||||
local-p
|
||||
remove-p
|
||||
forms)
|
||||
(while (keywordp (car rest))
|
||||
(pcase (pop rest)
|
||||
(:append (setq append-p t))
|
||||
(:local (setq local-p t))
|
||||
(:remove (setq remove-p t))))
|
||||
(let ((first (car-safe (car rest))))
|
||||
(cond ((null first)
|
||||
(setq func-forms rest))
|
||||
|
||||
((eq first 'defun)
|
||||
(setq func-forms (mapcar #'cadr rest)
|
||||
defn-forms rest))
|
||||
|
||||
((memq first '(quote function))
|
||||
(setq func-forms
|
||||
(if (cdr rest)
|
||||
(mapcar #'doom-unquote rest)
|
||||
(doom-enlist (doom-unquote (car rest))))))
|
||||
|
||||
((setq func-forms (list `(lambda () ,@rest)))))
|
||||
(dolist (hook hook-forms)
|
||||
(dolist (func func-forms)
|
||||
(push (if remove-p
|
||||
`(remove-hook ',hook #',func ,local-p)
|
||||
`(add-hook ',hook #',func ,append-p ,local-p))
|
||||
forms)))
|
||||
(macroexp-progn
|
||||
(append defn-forms
|
||||
(if append-p
|
||||
(nreverse forms)
|
||||
forms))))))
|
||||
|
||||
(defmacro remove-hook! (hooks &rest rest)
|
||||
"A convenience macro for removing N functions from M hooks.
|
||||
|
||||
Takes the same arguments as `add-hook!'.
|
||||
|
||||
If N and M = 1, there's no benefit to using this macro over `remove-hook'.
|
||||
|
||||
\(fn [:append :local] HOOKS FUNCTIONS)"
|
||||
(declare (indent defun) (debug t))
|
||||
`(add-hook! ,hooks :remove ,@rest))
|
||||
|
||||
(defmacro setq-hook! (hooks &rest var-vals)
|
||||
"Sets buffer-local variables on HOOKS.
|
||||
|
||||
(setq-hook! 'markdown-mode-hook
|
||||
line-spacing 2
|
||||
fill-column 80)
|
||||
|
||||
\(fn HOOKS &rest [SYM VAL]...)"
|
||||
(declare (indent 1))
|
||||
(macroexp-progn
|
||||
(cl-loop for (var val hook fn) in (doom--setq-hook-fns hooks var-vals)
|
||||
collect `(defun ,fn (&rest _)
|
||||
,(format "%s = %s" var (pp-to-string val))
|
||||
(setq-local ,var ,val))
|
||||
collect `(remove-hook ',hook #',fn) ; ensure set order
|
||||
collect `(add-hook ',hook #',fn))))
|
||||
|
||||
(defmacro unsetq-hook! (hooks &rest vars)
|
||||
"Unbind setq hooks on HOOKS for VARS.
|
||||
|
||||
\(fn HOOKS &rest [SYM VAL]...)"
|
||||
(declare (indent 1))
|
||||
(macroexp-progn
|
||||
(cl-loop for (_var _val hook fn) in (doom--setq-hook-fns hooks vars 'singles)
|
||||
collect `(remove-hook ',hook #',fn))))
|
||||
|
||||
(defmacro load! (filename &optional path noerror)
|
||||
"Load a file relative to the current executing file (`load-file-name').
|
||||
|
||||
FILENAME is either a file path string or a form that should evaluate to such a
|
||||
string at run time. PATH is where to look for the file (a string representing a
|
||||
directory path). If omitted, the lookup is relative to either `load-file-name',
|
||||
`byte-compile-current-file' or `buffer-file-name' (checked in that order).
|
||||
|
||||
If NOERROR is non-nil, don't throw an error if the file doesn't exist."
|
||||
(unless path
|
||||
(setq path (or (dir!)
|
||||
(error "Could not detect path to look for '%s' in"
|
||||
filename))))
|
||||
(let ((file (if path `(expand-file-name ,filename ,path) filename)))
|
||||
`(condition-case e
|
||||
(load ,file ,noerror ,(not doom-debug-mode))
|
||||
((debug doom-error) (signal (car e) (cdr e)))
|
||||
((debug error)
|
||||
(let* ((source (file-name-sans-extension ,file))
|
||||
(err (cond ((file-in-directory-p source doom-core-dir)
|
||||
(cons 'doom-error doom-core-dir))
|
||||
((file-in-directory-p source doom-private-dir)
|
||||
(cons 'doom-private-error doom-private-dir))
|
||||
((cons 'doom-module-error doom-emacs-dir)))))
|
||||
(signal (car err)
|
||||
(list (file-relative-name
|
||||
(concat source ".el")
|
||||
(cdr err))
|
||||
e)))))))
|
||||
|
||||
(defmacro defer-until! (condition &rest body)
|
||||
"Run BODY when CONDITION is true (checks on `after-load-functions'). Meant to
|
||||
|
@ -194,16 +361,16 @@ serve as a predicated alternative to `after!'."
|
|||
(declare (indent defun) (debug t))
|
||||
`(if ,condition
|
||||
(progn ,@body)
|
||||
,(let ((fun (make-symbol "doom|delay-form-")))
|
||||
,(let ((fn (intern (format "doom--delay-form-%s-h" (sxhash (cons condition body))))))
|
||||
`(progn
|
||||
(fset ',fun (lambda (&rest args)
|
||||
(fset ',fn (lambda (&rest args)
|
||||
(when ,(or condition t)
|
||||
(remove-hook 'after-load-functions #',fun)
|
||||
(unintern ',fun nil)
|
||||
(remove-hook 'after-load-functions #',fn)
|
||||
(unintern ',fn nil)
|
||||
(ignore args)
|
||||
,@body)))
|
||||
(put ',fun 'permanent-local-hook t)
|
||||
(add-hook 'after-load-functions #',fun)))))
|
||||
(put ',fn 'permanent-local-hook t)
|
||||
(add-hook 'after-load-functions #',fn)))))
|
||||
|
||||
(defmacro defer-feature! (feature &optional mode)
|
||||
"Pretend FEATURE hasn't been loaded yet, until FEATURE-hook is triggered.
|
||||
|
@ -213,7 +380,7 @@ startup, which will prematurely trigger `after!' (and `with-eval-after-load')
|
|||
blocks. To get around this we make Emacs believe FEATURE hasn't been loaded yet,
|
||||
then wait until FEATURE-hook (or MODE-hook, if MODE is provided) is triggered to
|
||||
reverse this and trigger `after!' blocks at a more reasonable time."
|
||||
(let ((advice-fn (intern (format "doom|defer-feature-%s" feature)))
|
||||
(let ((advice-fn (intern (format "doom--defer-feature-%s-a" feature)))
|
||||
(mode (or mode feature)))
|
||||
`(progn
|
||||
(setq features (delq ',feature features))
|
||||
|
@ -250,291 +417,32 @@ writes to `standard-output'."
|
|||
(save-silently t))
|
||||
(prog1 ,@forms (message ""))))))
|
||||
|
||||
(defmacro add-transient-hook! (hook-or-function &rest forms)
|
||||
"Attaches a self-removing function to HOOK-OR-FUNCTION.
|
||||
|
||||
FORMS are evaluated once, when that function/hook is first invoked, then never
|
||||
again.
|
||||
;;
|
||||
;;; Definers
|
||||
|
||||
HOOK-OR-FUNCTION can be a quoted hook or a sharp-quoted function (which will be
|
||||
advised)."
|
||||
(declare (indent 1))
|
||||
(let ((append (if (eq (car forms) :after) (pop forms)))
|
||||
(fn (if (symbolp (car forms))
|
||||
(intern (format "doom|transient-hook-%s" (pop forms)))
|
||||
(make-symbol "doom|transient-hook"))))
|
||||
`(let ((sym ,hook-or-function))
|
||||
(fset ',fn
|
||||
(lambda (&rest _)
|
||||
,@forms
|
||||
(let ((sym ,hook-or-function))
|
||||
(cond ((functionp sym) (advice-remove sym #',fn))
|
||||
((symbolp sym) (remove-hook sym #',fn))))
|
||||
(unintern ',fn nil)))
|
||||
(cond ((functionp sym)
|
||||
(advice-add ,hook-or-function ,(if append :after :before) #',fn))
|
||||
((symbolp sym)
|
||||
(put ',fn 'permanent-local-hook t)
|
||||
(add-hook sym #',fn ,append))))))
|
||||
(defmacro defadvice! (symbol arglist &optional docstring &rest body)
|
||||
"Define an advice called SYMBOL and add it to PLACES.
|
||||
|
||||
(defmacro add-hook! (&rest args)
|
||||
"A convenience macro for adding N functions to M hooks.
|
||||
ARGLIST is as in `defun'. WHERE is a keyword as passed to `advice-add', and
|
||||
PLACE is the function to which to add the advice, like in `advice-add'.
|
||||
DOCSTRING and BODY are as in `defun'.
|
||||
|
||||
If N and M = 1, there's no benefit to using this macro over `add-hook'.
|
||||
|
||||
This macro accepts, in order:
|
||||
|
||||
1. Optional properties :local and/or :append, which will make the hook
|
||||
buffer-local or append to the list of hooks (respectively),
|
||||
2. The hook(s) to be added to: either an unquoted mode, an unquoted list of
|
||||
modes, a quoted hook variable or a quoted list of hook variables. If
|
||||
unquoted, '-hook' will be appended to each symbol.
|
||||
3. The function(s) to be added: this can be one function, a list thereof, or
|
||||
body forms (implicitly wrapped in a closure).
|
||||
|
||||
Examples:
|
||||
(add-hook! 'some-mode-hook 'enable-something) (same as `add-hook')
|
||||
(add-hook! some-mode '(enable-something and-another))
|
||||
(add-hook! '(one-mode-hook second-mode-hook) 'enable-something)
|
||||
(add-hook! (one-mode second-mode) 'enable-something)
|
||||
(add-hook! :append (one-mode second-mode) 'enable-something)
|
||||
(add-hook! :local (one-mode second-mode) 'enable-something)
|
||||
(add-hook! (one-mode second-mode) (setq v 5) (setq a 2))
|
||||
(add-hook! :append :local (one-mode second-mode) (setq v 5) (setq a 2))
|
||||
|
||||
\(fn [:append :local] HOOKS FUNCTIONS)"
|
||||
(declare (indent defun) (debug t))
|
||||
(let ((hook-fn 'add-hook)
|
||||
append-p local-p)
|
||||
(while (keywordp (car args))
|
||||
(pcase (pop args)
|
||||
(:append (setq append-p t))
|
||||
(:local (setq local-p t))
|
||||
(:remove (setq hook-fn 'remove-hook))))
|
||||
(let ((hooks (doom--resolve-hook-forms (pop args)))
|
||||
(funcs
|
||||
(let ((val (car args)))
|
||||
(if (memq (car-safe val) '(quote function))
|
||||
(if (cdr-safe (cadr val))
|
||||
(cadr val)
|
||||
(list (cadr val)))
|
||||
(list args))))
|
||||
forms)
|
||||
(dolist (fn funcs)
|
||||
(setq fn (if (symbolp fn)
|
||||
`(function ,fn)
|
||||
`(lambda (&rest _) ,@args)))
|
||||
(dolist (hook hooks)
|
||||
(push (if (eq hook-fn 'remove-hook)
|
||||
`(remove-hook ',hook ,fn ,local-p)
|
||||
`(add-hook ',hook ,fn ,append-p ,local-p))
|
||||
forms)))
|
||||
`(progn ,@(if append-p (nreverse forms) forms)))))
|
||||
|
||||
(defmacro remove-hook! (&rest args)
|
||||
"A convenience macro for removing N functions from M hooks.
|
||||
|
||||
Takes the same arguments as `add-hook!'.
|
||||
|
||||
If N and M = 1, there's no benefit to using this macro over `remove-hook'.
|
||||
|
||||
\(fn [:append :local] HOOKS FUNCTIONS)"
|
||||
(declare (indent defun) (debug t))
|
||||
`(add-hook! :remove ,@args))
|
||||
|
||||
(defmacro setq-hook! (hooks &rest rest)
|
||||
"Sets buffer-local variables on HOOKS.
|
||||
|
||||
(setq-hook! 'markdown-mode-hook
|
||||
line-spacing 2
|
||||
fill-column 80)
|
||||
|
||||
\(fn HOOKS &rest SYM VAL...)"
|
||||
(declare (indent 1))
|
||||
(unless (= 0 (% (length rest) 2))
|
||||
(signal 'wrong-number-of-arguments (list #'evenp (length rest))))
|
||||
(let ((vars (let ((args rest)
|
||||
vars)
|
||||
(while args
|
||||
(push (symbol-name (car args)) vars)
|
||||
(setq args (cddr args)))
|
||||
(string-join (sort vars #'string-lessp) "-"))))
|
||||
(macroexp-progn
|
||||
(cl-loop for hook in (doom--resolve-hook-forms hooks)
|
||||
for mode = (string-remove-suffix "-hook" (symbol-name hook))
|
||||
for fn = (intern (format "doom|setq-%s-for-%s" vars mode))
|
||||
collect `(fset ',fn
|
||||
(lambda (&rest _)
|
||||
,@(let (forms)
|
||||
(while rest
|
||||
(let ((var (pop rest))
|
||||
(val (pop rest)))
|
||||
(push `(setq-local ,var ,val) forms)))
|
||||
(nreverse forms))))
|
||||
collect `(add-hook ',hook #',fn 'append)))))
|
||||
|
||||
(defun advice-add! (symbols where functions)
|
||||
"Variadic version of `advice-add'.
|
||||
|
||||
SYMBOLS and FUNCTIONS can be lists of functions."
|
||||
(let ((functions (if (functionp functions)
|
||||
(list functions)
|
||||
functions)))
|
||||
(dolist (s (doom-enlist symbols))
|
||||
(dolist (f (doom-enlist functions))
|
||||
(advice-add s where f)))))
|
||||
|
||||
(defun advice-remove! (symbols where-or-fns &optional functions)
|
||||
"Variadic version of `advice-remove'.
|
||||
|
||||
WHERE-OR-FNS is ignored if FUNCTIONS is provided. This lets you substitute
|
||||
advice-add with advice-remove and evaluate them without having to modify every
|
||||
statement."
|
||||
(unless functions
|
||||
(setq functions where-or-fns
|
||||
where-or-fns nil))
|
||||
(let ((functions (if (functionp functions)
|
||||
(list functions)
|
||||
functions)))
|
||||
(dolist (s (doom-enlist symbols))
|
||||
(dolist (f (doom-enlist functions))
|
||||
(advice-remove s f)))))
|
||||
|
||||
(cl-defmacro associate! (mode &key modes match files when)
|
||||
"Enables a minor mode if certain conditions are met.
|
||||
|
||||
The available conditions are:
|
||||
|
||||
:modes SYMBOL_LIST
|
||||
A list of major/minor modes in which this minor mode may apply.
|
||||
:match REGEXP
|
||||
A regexp to be tested against the current file path.
|
||||
:files SPEC
|
||||
Accepts what `project-file-exists-p!' accepts. Checks if certain files or
|
||||
directories exist relative to the project root.
|
||||
:when FORM
|
||||
Whenever FORM returns non-nil."
|
||||
(declare (indent 1))
|
||||
(unless noninteractive
|
||||
(cond ((or files modes when)
|
||||
(when (and files
|
||||
(not (or (listp files)
|
||||
(stringp files))))
|
||||
(user-error "associate! :files expects a string or list of strings"))
|
||||
(let ((hook-name (intern (format "doom--init-mode-%s" mode))))
|
||||
\(fn SYMBOL ARGLIST &optional DOCSTRING &rest [WHERE PLACES...] BODY\)"
|
||||
(declare (doc-string 3) (indent defun))
|
||||
(unless (stringp docstring)
|
||||
(push docstring body)
|
||||
(setq docstring nil))
|
||||
(let (where-alist)
|
||||
(while (keywordp (car body))
|
||||
(push `(cons ,(pop body) (doom-enlist ,(pop body)))
|
||||
where-alist))
|
||||
`(progn
|
||||
(fset ',hook-name
|
||||
(lambda ()
|
||||
(and (fboundp ',mode)
|
||||
(not (bound-and-true-p ,mode))
|
||||
(and buffer-file-name (not (file-remote-p buffer-file-name)))
|
||||
,(or (not match)
|
||||
`(if buffer-file-name (string-match-p ,match buffer-file-name)))
|
||||
,(or (not files)
|
||||
(doom--resolve-path-forms
|
||||
(if (stringp (car files)) (cons 'and files) files)
|
||||
'(doom-project-root)))
|
||||
,(or when t)
|
||||
(,mode 1))))
|
||||
,@(if (and modes (listp modes))
|
||||
(cl-loop for hook in (doom--resolve-hook-forms modes)
|
||||
collect `(add-hook ',hook #',hook-name))
|
||||
`((add-hook 'after-change-major-mode-hook #',hook-name))))))
|
||||
(match
|
||||
`(add-to-list 'doom-auto-minor-mode-alist '(,match . ,mode)))
|
||||
((user-error "Invalid `associate!' rules for mode [%s] (:modes %s :match %s :files %s :when %s)"
|
||||
mode modes match files when)))))
|
||||
|
||||
(defmacro file-exists-p! (spec &optional directory)
|
||||
"Returns non-nil if the files in SPEC all exist.
|
||||
|
||||
Returns the last file found to meet the rules set by SPEC. SPEC can be a single
|
||||
file or a list of forms/files. It understands nested (and ...) and (or ...), as
|
||||
well.
|
||||
|
||||
DIRECTORY is where to look for the files in SPEC if they aren't absolute.
|
||||
|
||||
For example:
|
||||
(file-exists-p! (or doom-core-dir \"~/.config\" \"some-file\") \"~\")"
|
||||
(if directory
|
||||
`(let ((--directory-- ,directory))
|
||||
,(doom--resolve-path-forms spec '--directory--))
|
||||
(doom--resolve-path-forms spec)))
|
||||
|
||||
(defmacro load! (filename &optional path noerror)
|
||||
"Load a file relative to the current executing file (`load-file-name').
|
||||
|
||||
FILENAME is either a file path string or a form that should evaluate to such a
|
||||
string at run time. PATH is where to look for the file (a string representing a
|
||||
directory path). If omitted, the lookup is relative to either `load-file-name',
|
||||
`byte-compile-current-file' or `buffer-file-name' (checked in that order).
|
||||
|
||||
If NOERROR is non-nil, don't throw an error if the file doesn't exist."
|
||||
(unless path
|
||||
(setq path (or (DIR!)
|
||||
(error "Could not detect path to look for '%s' in"
|
||||
filename))))
|
||||
(let ((file (if path `(expand-file-name ,filename ,path) filename)))
|
||||
`(condition-case e
|
||||
(load ,file ,noerror ,(not doom-debug-mode))
|
||||
((debug doom-error) (signal (car e) (cdr e)))
|
||||
((debug error)
|
||||
(let* ((source (file-name-sans-extension ,file))
|
||||
(err (cond ((file-in-directory-p source doom-core-dir)
|
||||
(cons 'doom-error doom-core-dir))
|
||||
((file-in-directory-p source doom-private-dir)
|
||||
(cons 'doom-private-error doom-private-dir))
|
||||
((cons 'doom-module-error doom-emacs-dir)))))
|
||||
(signal (car err)
|
||||
(list (file-relative-name
|
||||
(concat source ".el")
|
||||
(cdr err))
|
||||
e)))))))
|
||||
|
||||
(defmacro custom-theme-set-faces! (theme &rest specs)
|
||||
"Apply a list of face specs as user customizations for THEME.
|
||||
|
||||
THEME can be a single symbol or list thereof. If nil, apply these settings to
|
||||
all themes. It will apply to all themes once they are loaded.
|
||||
|
||||
(custom-theme-set-faces! '(doom-one doom-one-light)
|
||||
`(mode-line :foreground ,(doom-color 'blue))
|
||||
`(mode-line-buffer-id :foreground ,(doom-color 'fg) :background \"#000000\")
|
||||
'(mode-line-success-highlight :background \"#00FF00\")
|
||||
'(org-tag :background \"#4499FF\")
|
||||
'(org-ellipsis :inherit org-tag)
|
||||
'(which-key-docstring-face :inherit font-lock-comment-face))"
|
||||
`(let* ((themes (doom-enlist (or ,theme 'user)))
|
||||
(fn (gensym (format "doom|customize-%s-" (mapconcat #'symbol-name themes "-")))))
|
||||
(fset fn
|
||||
(lambda ()
|
||||
(dolist (theme themes)
|
||||
(when (or (eq theme 'user)
|
||||
(custom-theme-enabled-p theme))
|
||||
(apply #'custom-theme-set-faces 'user
|
||||
(cl-loop for (face . spec) in (list ,@specs)
|
||||
if (keywordp (car spec))
|
||||
collect `(,face ((t ,spec)))
|
||||
else collect `(,face ,spec)))))))
|
||||
(funcall fn)
|
||||
(add-hook 'doom-load-theme-hook fn)))
|
||||
|
||||
(defmacro custom-set-faces! (&rest specs)
|
||||
"Apply a list of face specs as user customizations.
|
||||
|
||||
SPECS is a list of face specs.
|
||||
|
||||
This is a drop-in replacement for `custom-set-face' that allows for a simplified
|
||||
face format, e.g.
|
||||
|
||||
(custom-set-faces!
|
||||
`(mode-line :foreground ,(doom-color 'blue))
|
||||
`(mode-line-buffer-id :foreground ,(doom-color 'fg) :background \"#000000\")
|
||||
'(mode-line-success-highlight :background \"#00FF00\")
|
||||
'(org-tag :background \"#4499FF\")
|
||||
'(org-ellipsis :inherit org-tag)
|
||||
'(which-key-docstring-face :inherit font-lock-comment-face))"
|
||||
`(custom-theme-set-faces! 'user ,@specs))
|
||||
(defun ,symbol ,arglist ,docstring ,@body)
|
||||
,(when where-alist
|
||||
`(dolist (targets (list ,@(nreverse where-alist)))
|
||||
(dolist (target (cdr targets))
|
||||
(advice-add target (car targets) #',symbol)))))))
|
||||
|
||||
(provide 'core-lib)
|
||||
;;; core-lib.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))
|
||||
|
@ -34,7 +31,8 @@
|
|||
(term (:term term)))
|
||||
(:ui (doom-modeline (:ui modeline))
|
||||
(fci (:ui fill-column))
|
||||
(evil-goggles (:ui ophints)))
|
||||
(evil-goggles (:ui ophints))
|
||||
(tabbar (:ui tabs)))
|
||||
(:app (email (:email mu4e))
|
||||
(notmuch (:email notmuch))))
|
||||
"A tree alist that maps deprecated modules to their replacement(s).
|
||||
|
@ -50,14 +48,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 +62,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 +73,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)))
|
||||
(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)
|
||||
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)
|
||||
doom-modules))
|
||||
(run-hook-wrapped 'doom-init-modules-hook #'doom-try-run-hook)
|
||||
(load! "config" doom-private-dir t))))
|
||||
(load! "config" doom-private-dir t)))))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -108,12 +101,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))))
|
||||
t)))
|
||||
|
||||
(defun doom-module-get (category module &optional property)
|
||||
"Returns the plist for CATEGORY MODULE. Gets PROPERTY, specifically, if set."
|
||||
|
@ -128,7 +120,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 +151,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 +176,53 @@ 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)."
|
||||
(or doom--current-module
|
||||
(let* (file-name-handler-alist
|
||||
(path (or path (FILE!))))
|
||||
(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."
|
||||
(if (null path)
|
||||
(if doom--current-module
|
||||
(if enabled-only
|
||||
(and (doom-module-p (car doom--current-module)
|
||||
(cdr doom--current-module))
|
||||
doom--current-module)
|
||||
doom--current-module)
|
||||
(doom-module-from-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))))))))
|
||||
(cond ((string-match "/modules/\\([^/]+\\)/\\([^/]+\\)\\(?:/.*\\)?$" path)
|
||||
(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))))
|
||||
((file-in-directory-p path doom-core-dir)
|
||||
(cons :core (intern (file-name-base path))))
|
||||
((file-in-directory-p path doom-private-dir)
|
||||
(cons :private (intern (file-name-base path)))))))))
|
||||
|
||||
(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. The first returned path is always `doom-private-dir'."
|
||||
(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
|
||||
|
@ -236,31 +245,39 @@ If ALL-P is non-nil, return paths of possible modules, activated or otherwise."
|
|||
use-package-minimum-reported-time (if doom-debug-mode 0 0.1)
|
||||
use-package-expand-minimally (not noninteractive)))
|
||||
|
||||
;; Adds two new keywords to `use-package' (and consequently, `def-package!') to
|
||||
;; Adds four new keywords to `use-package' (and consequently, `use-package!') to
|
||||
;; expand its lazy-loading capabilities. They are:
|
||||
;;
|
||||
;; Check out `use-package!'s documentation for more about these two.
|
||||
;; :after-call SYMBOL|LIST
|
||||
;; :defer-incrementally SYMBOL|LIST|t
|
||||
;;
|
||||
;; Check out `def-package!'s documentation for more about these two.
|
||||
;; Provided by `auto-minor-mode' package:
|
||||
;; :minor
|
||||
;; :magic-minor
|
||||
;;
|
||||
(defvar doom--deferred-packages-alist '(t))
|
||||
|
||||
(with-eval-after-load 'use-package-core
|
||||
;; Macros are already fontified, no need for this
|
||||
(font-lock-remove-keywords 'emacs-lisp-mode use-package-font-lock-keywords)
|
||||
|
||||
;; Disable :ensure and :pin, because they don't work with Doom because we do
|
||||
;; our own package management.
|
||||
(with-eval-after-load 'use-package-ensure
|
||||
(dolist (keyword '(:ensure :pin))
|
||||
(delq! keyword use-package-keywords)
|
||||
(delq! keyword use-package-defaults 'assq)))
|
||||
|
||||
;; Insert new deferring keywords
|
||||
;; Register all new keywords
|
||||
(dolist (keyword '(:defer-incrementally :after-call))
|
||||
(add-to-list 'use-package-deferring-keywords keyword nil #'eq)
|
||||
(push keyword use-package-deferring-keywords)
|
||||
(setq use-package-keywords
|
||||
(use-package-list-insert keyword use-package-keywords :after)))
|
||||
(dolist (keyword '(:minor :magic-minor))
|
||||
(setq use-package-keywords
|
||||
(use-package-list-insert keyword use-package-keywords :commands)))
|
||||
|
||||
(defalias 'use-package-normalize/:minor #'use-package-normalize-mode)
|
||||
(defun use-package-handler/:minor (name _ arg rest state)
|
||||
(use-package-handle-mode name 'auto-minor-mode-alist arg rest state))
|
||||
|
||||
(defalias 'use-package-normalize/:magic-minor #'use-package-normalize-mode)
|
||||
(defun use-package-handler/:magic-minor (name _ arg rest state)
|
||||
(use-package-handle-mode name 'auto-minor-mode-magic-alist arg rest state))
|
||||
|
||||
(defalias 'use-package-normalize/:defer-incrementally #'use-package-normalize-symlist)
|
||||
(defun use-package-handler/:defer-incrementally (name _keyword targets rest state)
|
||||
|
@ -275,13 +292,18 @@ If ALL-P is non-nil, return paths of possible modules, activated or otherwise."
|
|||
(defun use-package-handler/:after-call (name _keyword hooks rest state)
|
||||
(if (plist-get state :demand)
|
||||
(use-package-process-keywords name rest state)
|
||||
(let ((fn (make-symbol (format "doom|transient-hook--load-%s" name))))
|
||||
(let ((fn (make-symbol (format "doom--after-call-%s-h" name))))
|
||||
(use-package-concat
|
||||
`((fset ',fn
|
||||
(lambda (&rest _)
|
||||
(doom-log "Loading deferred package %s from %s" ',name ',fn)
|
||||
(condition-case e
|
||||
(require ',name)
|
||||
;; If `default-directory' is a directory that doesn't
|
||||
;; exist or is unreadable, Emacs throws up file-missing
|
||||
;; errors, so we set it to a directory we know exists and
|
||||
;; is readable.
|
||||
(let ((default-directory doom-emacs-dir))
|
||||
(require ',name))
|
||||
((debug error)
|
||||
(message "Failed to load deferred package %s: %s" ',name e)))
|
||||
(when-let (deferral-list (assq ',name doom--deferred-packages-alist))
|
||||
|
@ -306,6 +328,10 @@ If ALL-P is non-nil, return paths of possible modules, activated or otherwise."
|
|||
;;
|
||||
;;; Module config macros
|
||||
|
||||
(put :if 'lisp-indent-function 2)
|
||||
(put :when 'lisp-indent-function 'defun)
|
||||
(put :unless 'lisp-indent-function 'defun)
|
||||
|
||||
(defmacro doom! (&rest modules)
|
||||
"Bootstraps DOOM Emacs and its modules.
|
||||
|
||||
|
@ -335,21 +361,31 @@ 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
|
||||
(unless (keywordp (car modules))
|
||||
(setq modules (eval modules t)))
|
||||
(let ((doom-modules
|
||||
(make-hash-table :test 'equal
|
||||
:size (if modules (length modules) 150)
|
||||
:rehash-threshold 1.0)))
|
||||
(let ((inhibit-message doom-inhibit-module-warnings)
|
||||
:rehash-threshold 1.0))
|
||||
(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))
|
||||
((and (listp m)
|
||||
(keywordp (car m)))
|
||||
(pcase (car m)
|
||||
(:cond
|
||||
(cl-loop for (cond . mods) in (cdr m)
|
||||
if (eval cond t)
|
||||
return (prependq! modules mods)))
|
||||
(:if (if (eval (cadr m) t)
|
||||
(push (caddr m) modules)
|
||||
(prependq! modules (cdddr m))))
|
||||
(fn (if (or (eval (cadr m) t)
|
||||
(eq fn :unless))
|
||||
(prependq! modules (cddr m))))))
|
||||
((catch 'doom-modules
|
||||
(let* ((module (if (listp m) (car m) m))
|
||||
(flags (if (listp m) (cdr m))))
|
||||
|
@ -373,13 +409,14 @@ to least)."
|
|||
(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)))))))))
|
||||
(message "WARNING Couldn't find the %s %s module" category module)))))))
|
||||
(when noninteractive
|
||||
(setq doom-inhibit-module-warnings t))
|
||||
`(setq doom-modules ',doom-modules))
|
||||
`(setq doom-modules ',doom-modules)))
|
||||
|
||||
(defvar doom-disabled-packages)
|
||||
(defmacro def-package! (name &rest plist)
|
||||
(define-obsolete-function-alias 'def-package! 'use-package!) ; DEPRECATED
|
||||
(defmacro use-package! (name &rest plist)
|
||||
"Declares and configures a package.
|
||||
|
||||
This is a thin wrapper around `use-package', and is ignored if the NAME package
|
||||
|
@ -393,7 +430,7 @@ two extra properties:
|
|||
The first time any of these functions or hooks are executed, the package is
|
||||
loaded. e.g.
|
||||
|
||||
(def-package! projectile
|
||||
(use-package! projectile
|
||||
:after-call (pre-command-hook after-find-file dired-before-readin-hook)
|
||||
...)
|
||||
|
||||
|
@ -407,10 +444,11 @@ two extra properties:
|
|||
NAME is implicitly added if this property is present and non-nil. No need to
|
||||
specify it. A value of `t' implies NAME, e.g.
|
||||
|
||||
(def-package! abc
|
||||
(use-package! abc
|
||||
;; This is equivalent to :defer-incrementally (abc)
|
||||
:defer-incrementally t
|
||||
...)"
|
||||
(declare (indent 1))
|
||||
(unless (or (memq name doom-disabled-packages)
|
||||
;; At compile-time, use-package will forcibly load packages to
|
||||
;; prevent compile-time errors. However, if a Doom user has
|
||||
|
@ -420,8 +458,9 @@ two extra properties:
|
|||
(not (locate-library (symbol-name name)))))
|
||||
`(use-package ,name ,@plist)))
|
||||
|
||||
(defmacro def-package-hook! (package when &rest body)
|
||||
"Reconfigures a package's `def-package!' block.
|
||||
(define-obsolete-function-alias 'def-package-hook! 'use-package-hook!) ; DEPRECATED
|
||||
(defmacro use-package-hook! (package when &rest body)
|
||||
"Reconfigures a package's `use-package!' block.
|
||||
|
||||
Only use this macro in a module's init.el file.
|
||||
|
||||
|
@ -432,19 +471,18 @@ WHEN should be one of the following:
|
|||
:pre-init :post-init :pre-config :post-config
|
||||
|
||||
WARNING: If :pre-init or :pre-config hooks return nil, the original
|
||||
`def-package!''s :init/:config block (respectively) is overwritten, so remember
|
||||
`use-package!''s :init/:config block (respectively) is overwritten, so remember
|
||||
to have them return non-nil (or exploit that to overwrite Doom's config)."
|
||||
(declare (indent defun))
|
||||
(doom--assert-stage-p 'init #'package!)
|
||||
(unless (memq when '(:pre-init :post-init :pre-config :post-config))
|
||||
(error "'%s' isn't a valid hook for def-package-hook!" when))
|
||||
(error "'%s' isn't a valid hook for use-package-hook!" when))
|
||||
`(progn
|
||||
(setq use-package-inject-hooks t)
|
||||
(add-hook!
|
||||
',(intern (format "use-package--%s--%s-hook"
|
||||
(add-hook ',(intern (format "use-package--%s--%s-hook"
|
||||
package
|
||||
(substring (symbol-name when) 1)))
|
||||
,@body)))
|
||||
(lambda () ,@body)
|
||||
'append)))
|
||||
|
||||
(defmacro require! (category module &rest flags)
|
||||
"Loads the CATEGORY MODULE module with FLAGS.
|
||||
|
@ -470,8 +508,7 @@ module."
|
|||
(let ((doom--current-module ',(cons category module))
|
||||
(doom--current-flags ',flags))
|
||||
(load! "init" module-path :noerror)
|
||||
(let ((doom--stage 'config))
|
||||
(load! "config" module-path :noerror)))
|
||||
(load! "config" module-path :noerror))
|
||||
('error
|
||||
(lwarn 'doom-modules :error
|
||||
"%s in '%s %s' -> %s"
|
||||
|
@ -497,63 +534,62 @@ CATEGORY and MODULE can be omitted When this macro is used from inside a module
|
|||
(and (cond (flag (memq flag (doom-module-get category module :flags)))
|
||||
(module (doom-module-p category module))
|
||||
(doom--current-flags (memq category doom--current-flags))
|
||||
((let ((module-pair
|
||||
(or doom--current-module
|
||||
(doom-module-from-path (FILE!)))))
|
||||
(unless module-pair
|
||||
(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)))))
|
||||
((let ((module (doom-module-from-path)))
|
||||
(unless module
|
||||
(error "featurep! couldn't figure out what module it was called from (in %s)"
|
||||
(file!)))
|
||||
(memq category (doom-module-get (car module) (cdr module) :flags)))))
|
||||
t))
|
||||
|
||||
(defmacro after! (targets &rest body)
|
||||
"Evaluate BODY after TARGETS (packages) have loaded.
|
||||
(defmacro after! (package &rest body)
|
||||
"Evaluate BODY after PACKAGE have loaded.
|
||||
|
||||
This is a wrapper around `with-eval-after-load' that:
|
||||
|
||||
1. Suppresses warnings for disabled packages at compile-time
|
||||
2. No-ops for TARGETS that are disabled by the user (via `package!')
|
||||
3. Supports compound TARGETS statements (see below)
|
||||
|
||||
TARGETS is a list of packages in one of these formats:
|
||||
PACKAGE is a symbol or list of them. These are package names, not modes,
|
||||
functions or variables. It can be:
|
||||
|
||||
- An unquoted package symbol (the name of a package)
|
||||
(after! helm BODY...)
|
||||
- An unquoted list of package symbols (i.e. BODY is evaluated once both magit
|
||||
and git-gutter have loaded)
|
||||
(after! (magit git-gutter) BODY...)
|
||||
- An unquoted, nested list of compound package lists, using :or/:any and/or
|
||||
:and/:all
|
||||
- An unquoted, nested list of compound package lists, using any combination of
|
||||
:or/:any and :and/:all
|
||||
(after! (:or package-a package-b ...) BODY...)
|
||||
(after! (:and package-a package-b ...) BODY...)
|
||||
(after! (:and package-a (:or package-b package-c) ...) BODY...)
|
||||
Without :or/:any/:and/:all, :and/:all are implied.
|
||||
|
||||
Note that:
|
||||
- :or and :any are equivalent
|
||||
- :and and :all are equivalent
|
||||
- If these are omitted, :and is implied."
|
||||
This is a wrapper around `eval-after-load' that:
|
||||
|
||||
1. Suppresses warnings for disabled packages at compile-time
|
||||
2. No-ops for package that are disabled by the user (via `package!')
|
||||
3. Supports compound package statements (see below)
|
||||
4. Prevents eager expansion pulling in autoloaded macros all at once"
|
||||
(declare (indent defun) (debug t))
|
||||
(unless (and (symbolp targets)
|
||||
(memq targets (bound-and-true-p doom-disabled-packages)))
|
||||
(if (symbolp package)
|
||||
(unless (memq package (bound-and-true-p doom-disabled-packages))
|
||||
(list (if (or (not (bound-and-true-p byte-compile-current-file))
|
||||
(dolist (next (doom-enlist targets))
|
||||
(unless (keywordp next)
|
||||
(if (symbolp next)
|
||||
(require next nil :no-error)
|
||||
(load next :no-message :no-error)))))
|
||||
(require package nil 'noerror))
|
||||
#'progn
|
||||
#'with-no-warnings)
|
||||
(if (symbolp targets)
|
||||
`(with-eval-after-load ',targets ,@body)
|
||||
(pcase (car-safe targets)
|
||||
((or :or :any)
|
||||
(let ((body (macroexp-progn body)))
|
||||
`(if (featurep ',package)
|
||||
,body
|
||||
;; We intentionally avoid `with-eval-after-load' to prevent
|
||||
;; eager macro expansion from pulling (or failing to pull) in
|
||||
;; autoloaded macros/packages.
|
||||
(eval-after-load ',package ',body)))))
|
||||
(let ((p (car package)))
|
||||
(cond ((not (keywordp p))
|
||||
`(after! (:and ,@package) ,@body))
|
||||
((memq p '(:or :any))
|
||||
(macroexp-progn
|
||||
(cl-loop for next in (cdr targets)
|
||||
(cl-loop for next in (cdr package)
|
||||
collect `(after! ,next ,@body))))
|
||||
((or :and :all)
|
||||
(dolist (next (cdr targets))
|
||||
((memq p '(:and :all))
|
||||
(dolist (next (cdr package))
|
||||
(setq body `((after! ,next ,@body))))
|
||||
(car body))
|
||||
(_ `(after! (:and ,@targets) ,@body)))))))
|
||||
(car body))))))
|
||||
|
||||
(provide 'core-modules)
|
||||
;;; core-modules.el ends here
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
;;; core-os.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; clipboard
|
||||
(setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
|
||||
|
||||
;; fewer opts to process for systems that don't need them
|
||||
(unless IS-MAC (setq command-line-ns-option-alist nil))
|
||||
(unless IS-LINUX (setq command-line-x-option-alist nil))
|
||||
|
||||
;; Fix the clipboard in terminal or daemon Emacs (non-GUI)
|
||||
(defun doom|init-clipboard-in-tty-emacs ()
|
||||
(if IS-MAC
|
||||
(if (require 'osx-clipboard nil t) (osx-clipboard-mode))
|
||||
(if (require 'xclip nil t) (xclip-mode))))
|
||||
(add-hook 'tty-setup-hook #'doom|init-clipboard-in-tty-emacs)
|
||||
|
||||
;; Enable mouse in terminal Emacs
|
||||
(add-hook 'tty-setup-hook #'xterm-mouse-mode)
|
||||
|
||||
;; stop copying each visual state move to the clipboard:
|
||||
;; https://bitbucket.org/lyro/evil/issue/336/osx-visual-state-copies-the-region-on
|
||||
;; grokked from: http://stackoverflow.com/questions/15873346/elisp-rename-macro
|
||||
(advice-add #'evil-visual-update-x-selection :override #'ignore)
|
||||
|
||||
(cond (IS-MAC
|
||||
(setq mac-command-modifier 'super
|
||||
mac-option-modifier 'meta
|
||||
;; sane trackpad/mouse scroll settings
|
||||
mac-redisplay-dont-reset-vscroll t
|
||||
mac-mouse-wheel-smooth-scroll nil
|
||||
;; Curse Lion and its sudden but inevitable fullscreen mode!
|
||||
;; NOTE Meaningless to railwaycat's emacs-mac build
|
||||
ns-use-native-fullscreen nil
|
||||
;; Visit files opened outside of Emacs in existing frame, rather
|
||||
;; than a new one
|
||||
ns-pop-up-frames nil)
|
||||
|
||||
;; Syncs ns frame parameters with theme (and fixes mismatching text color
|
||||
;; in the frame title)
|
||||
(when (and (or (daemonp)
|
||||
(display-graphic-p))
|
||||
(require 'ns-auto-titlebar nil t))
|
||||
(add-hook 'doom-load-theme-hook #'ns-auto-titlebar-mode)))
|
||||
|
||||
(IS-LINUX
|
||||
(setq x-gtk-use-system-tooltips nil ; native tooltips are ugly!
|
||||
x-underline-at-descent-line t)) ; draw underline lower
|
||||
|
||||
(IS-WINDOWS
|
||||
(setq w32-get-true-file-attributes nil) ; fix file io slowdowns
|
||||
(when (display-graphic-p)
|
||||
(setenv "GIT_ASKPASS" "git-gui--askpass"))))
|
||||
|
||||
(provide 'core-os)
|
||||
;;; core-os.el ends here
|
|
@ -1,154 +1,205 @@
|
|||
;;; core/core-packages.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; 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.
|
||||
;; Emacs package management is opinionated, and so is Doom. Doom uses `straight'
|
||||
;; to create a declarative, lazy-loaded and optionally rolling-release package
|
||||
;; management system. We use `straight' over `package' because the latter is
|
||||
;; tempermental. ELPA sources suffer downtime occasionally, and often fail at
|
||||
;; building some packages when GNU Tar is unavailable (e.g. MacOS users start
|
||||
;; with BSD tar). There are also known gnutls errors in the current stable
|
||||
;; release of Emacs (26.x) which bork TLS handshakes with ELPA repos (mainly
|
||||
;; gnu.elpa.org). See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=3434.
|
||||
;;
|
||||
;; The three key commands are:
|
||||
;; What's worse, you can only get the latest version of packages through ELPA.
|
||||
;; In an ecosystem that is constantly changing, this is more frustrating than
|
||||
;; convenient. Straight (and Doom) can do rolling release, but it is optional
|
||||
;; (and will eventually be opt-in).
|
||||
;;
|
||||
;; + `bin/doom install`: Installs packages that are wanted, but not installed.
|
||||
;; + `bin/doom update`: Updates packages that are out-of-date.
|
||||
;; + `bin/doom autoremove`: Uninstalls packages that are no longer needed.
|
||||
;; ANyhow, interacting with this package management system is done through the
|
||||
;; bin/doom script included with Doom Emacs. You'll find more about it by
|
||||
;; running 'doom help' (I highly recommend you add it to your PATH), but here
|
||||
;; are the highlights:
|
||||
;;
|
||||
;; This system reads packages.el files located in each activated module (and one
|
||||
;; in `doom-core-dir'). These contain `package!' blocks that tell DOOM what
|
||||
;; + `bin/doom install`: a wizard that guides you through setting up Doom and
|
||||
;; your private config for the first time.
|
||||
;; + `bin/doom refresh`: your go-to command for making sure Doom is in optimal
|
||||
;; condition. It ensures all unneeded packages are removed, all needed ones
|
||||
;; are installed, and all metadata associated with them is generated.
|
||||
;; + `bin/doom upgrade`: upgrades Doom Emacs and your packages to the latest
|
||||
;; versions. There's also 'bin/doom update' for updating only your packages.
|
||||
;;
|
||||
;; How this works is: the system reads packages.el files located in each
|
||||
;; activated module, your private directory (`doom-private-dir'), and one in
|
||||
;; `doom-core-dir'. These contain `package!' declarations that tell DOOM what
|
||||
;; plugins to install and where from.
|
||||
;;
|
||||
;; Why all the trouble? Because:
|
||||
;; 1. *Scriptability:* I live in the command line. I want a shell-scriptable
|
||||
;; interface for updating and installing Emacs packages.
|
||||
;; 2. *Reach:* I want packages from sources other than ELPA (like github or
|
||||
;; gitlab). Some plugins are out-of-date through official channels, have
|
||||
;; changed hands, have a superior fork, or simply aren't available in ELPA
|
||||
;; repos.
|
||||
;; 3. *Performance:* The package management system isn't loaded until you use
|
||||
;; the package management API. Not having to initialize package.el or quelpa
|
||||
;; (and check that your packages are installed) every time you start up (or
|
||||
;; load a package) speeds things up a great deal.
|
||||
;; 4. *Separation of concerns:* It's more organized and reduces cognitive load
|
||||
;; to separate configuring of packages and installing/updating them.
|
||||
;;
|
||||
;; You should be able to use package.el commands without any conflicts.
|
||||
;;
|
||||
;; See core/autoload/packages.el for more functions.
|
||||
;; All that said, you can still use package.el's commands, but 'bin/doom
|
||||
;; refresh' will purge ELPA packages.
|
||||
|
||||
(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-disabled-packages ()
|
||||
"A list of packages that should be ignored by `def-package!' and `after!'.")
|
||||
(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.")
|
||||
|
||||
;;; package.el
|
||||
(defvar doom-disabled-packages ()
|
||||
"A list of packages that should be ignored by `use-package!' and `after!'.")
|
||||
|
||||
|
||||
;;
|
||||
;;; 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 "https" "http")))
|
||||
`(("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))))
|
||||
(defadvice! 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-base-dir doom-local-dir
|
||||
straight-repository-branch "develop"
|
||||
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.
|
||||
straight-check-for-modifications nil
|
||||
;; We handle package.el ourselves (and a little more comprehensively)
|
||||
straight-enable-package-integration nil
|
||||
;; Before switching to straight, `doom-local-dir' would average out at
|
||||
;; around 100mb with half Doom's modules at ~230 packages. Afterwards, at
|
||||
;; around 1gb. With shallow cloning, that is reduced to ~400mb. This
|
||||
;; imposes an issue with packages that require their git history for
|
||||
;; certain things to work (like magit and org), but we can deal with that
|
||||
;; when we cross that bridge.
|
||||
straight-vc-git-default-clone-depth 1
|
||||
;; Straight's own emacsmirror mirror 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
|
||||
;; Straight is hardcoded to operate out of ~/.emacs.d/straight. Not on my watch!
|
||||
(defadvice! 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)))
|
||||
|
||||
;; 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)
|
||||
(defun doom--finalize-straight ()
|
||||
(mapc #'funcall (delq nil (mapcar #'cdr straight--transaction-alist)))
|
||||
(setq straight--transaction-alist nil))
|
||||
|
||||
|
||||
;;
|
||||
;;; 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)))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Package API
|
||||
|
||||
(defun doom-ensure-packages-initialized (&optional force-p)
|
||||
"Make sure package.el is initialized."
|
||||
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."
|
||||
(unless doom-init-packages-p
|
||||
(setq force-p t))
|
||||
(when (or force-p (not (bound-and-true-p package--initialized)))
|
||||
(doom-log "Initializing package.el")
|
||||
(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))))))
|
||||
(package-initialize))
|
||||
(when (or force-p (not doom-packages))
|
||||
(doom-log "Initializing straight")
|
||||
(setq doom-init-packages-p t)
|
||||
(unless (fboundp 'straight--reset-caches)
|
||||
(doom-ensure-straight)
|
||||
(require 'straight))
|
||||
(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
|
||||
:no-byte-compile t))
|
||||
(mapc #'straight-use-package doom-core-packages)
|
||||
(when noninteractive
|
||||
(add-hook 'kill-emacs-hook #'doom--finalize-straight)))
|
||||
(doom-log "Initializing 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 (cl-pushnew pkg doom-disabled-packages)
|
||||
else if (not ignored)
|
||||
do (with-demoted-errors "Package error: %s"
|
||||
(straight-register-package
|
||||
(if-let (recipe (plist-get plist :recipe))
|
||||
(let ((plist (straight-recipes-retrieve pkg)))
|
||||
`(,pkg ,@(doom-plist-merge recipe (cdr plist))))
|
||||
pkg)))))
|
||||
|
||||
(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")))
|
||||
(defun doom-ensure-straight ()
|
||||
"Ensure `straight' is installed and was compiled with this version of Emacs."
|
||||
(defvar bootstrap-version)
|
||||
(let* (;; 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 straight-base-dir)
|
||||
(bootstrap-file (doom-path straight-base-dir "straight/repos/straight.el/straight.el"))
|
||||
(bootstrap-version 5))
|
||||
(make-directory (doom-path straight-base-dir "straight/build") 'parents)
|
||||
(unless (featurep 'straight)
|
||||
(unless (or (require 'straight nil t)
|
||||
(file-readable-p bootstrap-file))
|
||||
(with-current-buffer
|
||||
(url-retrieve-synchronously
|
||||
(format "https://raw.githubusercontent.com/raxod502/straight.el/%s/install.el"
|
||||
straight-repository-branch)
|
||||
'silent 'inhibit-cookies)
|
||||
(goto-char (point-max))
|
||||
(eval-print-last-sexp)))
|
||||
(load bootstrap-file nil t))))
|
||||
|
||||
|
||||
;;
|
||||
;; Module package macros
|
||||
;;; 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 +213,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.
|
||||
|
@ -179,63 +227,55 @@ Accepts the following properties:
|
|||
Returns t if package is successfully registered, and nil if it was disabled
|
||||
elsewhere."
|
||||
(declare (indent defun))
|
||||
(doom--assert-stage-p 'packages #'package!)
|
||||
(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)))
|
||||
;; Add current module to :modules
|
||||
(let ((module-list (plist-get old-plist :modules))
|
||||
(module (or doom--current-module
|
||||
(let ((file (FILE!)))
|
||||
(cond ((file-in-directory-p file doom-private-dir)
|
||||
(list :private))
|
||||
((file-in-directory-p file doom-core-dir)
|
||||
(list :core))
|
||||
((doom-module-from-path file)))))))
|
||||
(module (doom-module-from-path)))
|
||||
(unless (member module module-list)
|
||||
(setq module-list (append module-list (list module) nil)
|
||||
plist (plist-put plist :modules module-list))))
|
||||
(plist-put! plist :modules
|
||||
(append module-list
|
||||
(list module)
|
||||
nil))))
|
||||
|
||||
;; Handle :built-in
|
||||
(unless ignore
|
||||
(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 plist (plist-put plist :ignore (or built-in ignore)))
|
||||
(while plist
|
||||
(unless (null (cadr plist))
|
||||
(setq old-plist (plist-put old-plist (car plist) (cadr plist))))
|
||||
(pop plist)
|
||||
(pop plist))
|
||||
(setq built-in `(locate-library ,(symbol-name name) nil doom--initial-load-path))))
|
||||
(plist-put! plist :ignore built-in))
|
||||
|
||||
;; DEPRECATED Translate :fetcher to :host
|
||||
(with-plist! plist (recipe)
|
||||
(with-plist! recipe (fetcher)
|
||||
(when fetcher
|
||||
(message "%s\n%s"
|
||||
(format "WARNING: The :fetcher property was used for the %S package."
|
||||
name)
|
||||
"This property is deprecated. Replace it with :host.")
|
||||
(plist-put! recipe :host fetcher)
|
||||
(plist-delete! recipe :fetcher))
|
||||
(plist-put! plist :recipe recipe)))
|
||||
|
||||
(doplist! ((prop val) plist)
|
||||
(unless (null val)
|
||||
(plist-put! old-plist prop val)))
|
||||
(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 packages! (&rest packages)
|
||||
"A convenience macro for `package!' for declaring multiple packages at once.
|
||||
|
||||
Only use this macro in a module's packages.el file."
|
||||
(doom--assert-stage-p 'packages #'packages!)
|
||||
(macroexp-progn
|
||||
(cl-loop for desc in packages
|
||||
collect (macroexpand `(package! ,@(doom-enlist desc))))))
|
||||
|
||||
(defmacro disable-packages! (&rest packages)
|
||||
"A convenience macro like `package!', but allows you to disable multiple
|
||||
packages at once.
|
||||
|
||||
Only use this macro in a module's packages.el file."
|
||||
(doom--assert-stage-p 'packages #'disable-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
|
||||
|
|
|
@ -11,7 +11,8 @@ Emacs.")
|
|||
"If non-nil, non-projects are purged from the cache on `kill-emacs-hook'.")
|
||||
|
||||
(defvar doom-projectile-fd-binary
|
||||
(cl-find-if #'executable-find '("fd" "fdfind"))
|
||||
(or (cl-find-if #'executable-find '("fd" "fdfind"))
|
||||
"fd")
|
||||
"name of `fd-find' executable binary")
|
||||
|
||||
(defvar doom-projectile-cache-timer-file (concat doom-cache-dir "projectile.timers")
|
||||
|
@ -21,8 +22,8 @@ Emacs.")
|
|||
;;
|
||||
;;; Packages
|
||||
|
||||
(def-package! projectile
|
||||
:after-call (after-find-file dired-before-readin-hook minibuffer-setup-hook)
|
||||
(use-package! projectile
|
||||
:after-call after-find-file dired-before-readin-hook minibuffer-setup-hook
|
||||
:commands (projectile-project-root
|
||||
projectile-project-name
|
||||
projectile-project-p
|
||||
|
@ -44,44 +45,29 @@ Emacs.")
|
|||
(global-set-key [remap find-tag] #'projectile-find-tag)
|
||||
|
||||
:config
|
||||
(defun doom*projectile-cache-timers ()
|
||||
"Persist `projectile-projects-cache-time' across sessions, so that
|
||||
`projectile-files-cache-expire' checks won't reset when restarting Emacs."
|
||||
(projectile-serialize projectile-projects-cache-time doom-projectile-cache-timer-file))
|
||||
(advice-add #'projectile-serialize-cache :before #'doom*projectile-cache-timers)
|
||||
;; Restore it
|
||||
(setq projectile-projects-cache-time (projectile-unserialize doom-projectile-cache-timer-file))
|
||||
|
||||
(add-hook 'dired-before-readin-hook #'projectile-track-known-projects-find-file-hook)
|
||||
(projectile-mode +1)
|
||||
|
||||
;; a more generic project root file
|
||||
(push ".project" projectile-project-root-files-bottom-up)
|
||||
(push (abbreviate-file-name doom-local-dir) projectile-globally-ignored-directories)
|
||||
|
||||
(defun doom*projectile-default-generic-command (orig-fn &rest args)
|
||||
"If projectile can't tell what kind of project you're in, it issues an error
|
||||
when using many of projectile's command, e.g. `projectile-compile-command',
|
||||
`projectile-run-project', `projectile-test-project', and
|
||||
`projectile-configure-project', for instance.
|
||||
|
||||
This suppresses the error so these commands will still run, but prompt you for
|
||||
the command instead."
|
||||
(ignore-errors (apply orig-fn args)))
|
||||
(advice-add #'projectile-default-generic-command :around #'doom*projectile-default-generic-command)
|
||||
;; Treat current directory in dired as a "file in a project" and track it
|
||||
(add-hook 'dired-before-readin-hook #'projectile-track-known-projects-find-file-hook)
|
||||
|
||||
;; Accidentally indexing big directories like $HOME or / will massively bloat
|
||||
;; projectile's cache (into the hundreds of MBs). This purges those entries
|
||||
;; when exiting Emacs to prevent slowdowns/freezing when cache files are
|
||||
;; loaded or written to.
|
||||
(defun doom|cleanup-project-cache ()
|
||||
(add-hook! 'kill-emacs-hook
|
||||
(defun doom-cleanup-project-cache-h ()
|
||||
"Purge projectile cache entries that:
|
||||
|
||||
a) have too many files (see `doom-projectile-cache-limit'),
|
||||
b) represent blacklisted directories that are too big, change too often or are
|
||||
private. (see `doom-projectile-cache-blacklist'),
|
||||
c) are not valid projectile projects."
|
||||
(when (bound-and-true-p projectile-projects-cache)
|
||||
(when (and (bound-and-true-p projectile-projects-cache)
|
||||
(not noninteractive))
|
||||
(cl-loop with blacklist = (mapcar #'file-truename doom-projectile-cache-blacklist)
|
||||
for proot in (hash-table-keys projectile-projects-cache)
|
||||
if (or (not (stringp proot))
|
||||
|
@ -94,9 +80,7 @@ c) are not valid projectile projects."
|
|||
and do (remhash proot projectile-projects-cache)
|
||||
and do (remhash proot projectile-projects-cache-time)
|
||||
and do (remhash proot projectile-project-type-cache))
|
||||
(projectile-serialize-cache)))
|
||||
(unless noninteractive
|
||||
(add-hook 'kill-emacs-hook #'doom|cleanup-project-cache))
|
||||
(projectile-serialize-cache))))
|
||||
|
||||
;; It breaks projectile's project root resolution if HOME is a project (e.g.
|
||||
;; it's a git repo). In that case, we disable bottom-up root searching to
|
||||
|
@ -111,21 +95,11 @@ c) are not valid projectile projects."
|
|||
projectile-project-root-files)
|
||||
projectile-project-root-files-bottom-up nil)))
|
||||
|
||||
;; Projectile root-searching functions can cause an infinite loop on TRAMP
|
||||
;; connections, so disable them.
|
||||
;; TODO Is this still necessary?
|
||||
(defun doom*projectile-locate-dominating-file (orig-fn file name)
|
||||
"Don't traverse the file system if on a remote connection."
|
||||
(when (and (stringp file)
|
||||
(not (file-remote-p file nil t)))
|
||||
(funcall orig-fn file name)))
|
||||
(advice-add #'projectile-locate-dominating-file :around #'doom*projectile-locate-dominating-file)
|
||||
|
||||
(cond
|
||||
;; If fd exists, use it for git and generic projects. fd is a rust program
|
||||
;; that is significantly faster than git ls-files or find, and it respects
|
||||
;; .gitignore. This is recommended in the projectile docs.
|
||||
(doom-projectile-fd-binary
|
||||
((executable-find doom-projectile-fd-binary)
|
||||
(setq projectile-git-command (concat
|
||||
doom-projectile-fd-binary
|
||||
" . --color=never --type f -0 -H -E .git")
|
||||
|
@ -143,10 +117,42 @@ c) are not valid projectile projects."
|
|||
projectile-indexing-method 'alien)
|
||||
;; fix breakage on windows in git projects
|
||||
(unless (executable-find "tr")
|
||||
(setq projectile-git-submodule-command nil)))))
|
||||
(setq projectile-git-submodule-command nil))))
|
||||
|
||||
(defadvice! doom--projectile-cache-timers-a ()
|
||||
"Persist `projectile-projects-cache-time' across sessions, so that
|
||||
`projectile-files-cache-expire' checks won't reset when restarting Emacs."
|
||||
:before #'projectile-serialize-cache
|
||||
(projectile-serialize projectile-projects-cache-time doom-projectile-cache-timer-file))
|
||||
;; Restore it
|
||||
(when (file-readable-p doom-projectile-cache-timer-file)
|
||||
(setq projectile-projects-cache-time
|
||||
(projectile-unserialize doom-projectile-cache-timer-file)))
|
||||
|
||||
(defadvice! doom--projectile-default-generic-command-a (orig-fn &rest args)
|
||||
"If projectile can't tell what kind of project you're in, it issues an error
|
||||
when using many of projectile's command, e.g. `projectile-compile-command',
|
||||
`projectile-run-project', `projectile-test-project', and
|
||||
`projectile-configure-project', for instance.
|
||||
|
||||
This suppresses the error so these commands will still run, but prompt you for
|
||||
the command instead."
|
||||
:around #'projectile-default-generic-command
|
||||
(ignore-errors (apply orig-fn args)))
|
||||
|
||||
;; Projectile root-searching functions can cause an infinite loop on TRAMP
|
||||
;; connections, so disable them.
|
||||
;; TODO Is this still necessary?
|
||||
(defadvice! doom--projectile-locate-dominating-file-a (orig-fn file name)
|
||||
"Don't traverse the file system if on a remote connection."
|
||||
:around #'projectile-locate-dominating-file
|
||||
(when (and (stringp file)
|
||||
(not (file-remote-p file nil t)))
|
||||
(funcall orig-fn file name))))
|
||||
|
||||
|
||||
;;
|
||||
;; Project-based minor modes
|
||||
;;; Project-based minor modes
|
||||
|
||||
(defvar doom-project-hook nil
|
||||
"Hook run when a project is enabled. The name of the project's mode and its
|
||||
|
@ -197,9 +203,11 @@ should be activated. If they are *all* true, NAME is activated.
|
|||
Relevant: `doom-project-hook'."
|
||||
(declare (indent 1))
|
||||
(let ((init-var (intern (format "%s-init" name))))
|
||||
`(progn
|
||||
,(if on-load `(defvar ,init-var nil))
|
||||
(define-minor-mode ,name
|
||||
(macroexp-progn
|
||||
(append
|
||||
(when on-load
|
||||
`((defvar ,init-var nil)))
|
||||
`((define-minor-mode ,name
|
||||
"A project minor mode generated by `def-project-mode!'."
|
||||
:init-value nil
|
||||
:lighter ""
|
||||
|
@ -212,15 +220,37 @@ Relevant: `doom-project-hook'."
|
|||
,on-load
|
||||
(setq ,init-var t)))
|
||||
,on-enter))
|
||||
,@(cl-loop for hook in add-hooks
|
||||
collect `(add-hook ',(intern (format "%s-hook" name))
|
||||
#',hook))
|
||||
,(when (or modes match files when)
|
||||
`(associate! ,name
|
||||
:modes ,modes
|
||||
:match ,match
|
||||
:files ,files
|
||||
:when ,when)))))
|
||||
(dolist (hook ,add-hooks)
|
||||
(add-hook ',(intern (format "%s-hook" name)) hook)))
|
||||
(cond ((or files modes when)
|
||||
(cl-check-type files (or null list string))
|
||||
(let ((fn
|
||||
`(lambda ()
|
||||
(and (not (bound-and-true-p ,name))
|
||||
(and buffer-file-name (not (file-remote-p buffer-file-name nil t)))
|
||||
,(or (null match)
|
||||
`(if buffer-file-name (string-match-p ,match buffer-file-name)))
|
||||
,(or (null files)
|
||||
;; Wrap this in `eval' to prevent eager expansion
|
||||
;; of `project-file-exists-p!' from pulling in
|
||||
;; autoloaded files prematurely.
|
||||
`(eval
|
||||
'(project-file-exists-p!
|
||||
,(if (stringp (car files)) (cons 'and files) files))))
|
||||
,(or when t)
|
||||
(,name 1)))))
|
||||
(if modes
|
||||
`((dolist (mode ,modes)
|
||||
(let ((hook-name
|
||||
(intern (format "doom--enable-%s%s-h" ',name
|
||||
(if (eq mode t) "" (format "-in-%s" mode))))))
|
||||
(fset hook-name #',fn)
|
||||
(if (eq mode t)
|
||||
(add-to-list 'auto-minor-mode-magic-alist (cons hook-name #',name))
|
||||
(add-hook (intern (format "%s-hook" mode)) hook-name)))))
|
||||
`((add-hook 'change-major-mode-after-body-hook #',fn)))))
|
||||
(match
|
||||
`((add-to-list 'auto-minor-mode-alist (cons ,match #',name)))))))))
|
||||
|
||||
(provide 'core-projects)
|
||||
;;; core-projects.el ends here
|
||||
|
|
531
core/core-ui.el
531
core/core-ui.el
|
@ -51,10 +51,6 @@ examples.
|
|||
It is recommended you don't set specify a font-size, as to inherit `doom-font's
|
||||
size.")
|
||||
|
||||
(defvar doom--prefer-theme-elc nil
|
||||
"If non-nil, `load-theme' will prefer the compiled theme (unlike its default
|
||||
behavior). Do not set this directly, this is let-bound in `doom|init-theme'.")
|
||||
|
||||
|
||||
;;
|
||||
;;; Custom hooks
|
||||
|
@ -85,8 +81,8 @@ behavior). Do not set this directly, this is let-bound in `doom|init-theme'.")
|
|||
(defvar doom--last-window nil)
|
||||
(defvar doom--last-frame nil)
|
||||
|
||||
(defun doom|run-switch-window-hooks ()
|
||||
(let ((gc-cons-threshold doom-gc-cons-upper-limit))
|
||||
(defun doom-run-switch-window-hooks-h ()
|
||||
(let ((gc-cons-threshold most-positive-fixnum))
|
||||
(unless (or doom-inhibit-switch-window-hooks
|
||||
(eq doom--last-window (selected-window))
|
||||
(minibufferp))
|
||||
|
@ -94,7 +90,7 @@ behavior). Do not set this directly, this is let-bound in `doom|init-theme'.")
|
|||
(run-hooks 'doom-switch-window-hook)
|
||||
(setq doom--last-window (selected-window))))))
|
||||
|
||||
(defun doom|run-switch-frame-hooks (&rest _)
|
||||
(defun doom-run-switch-frame-hooks-h (&rest _)
|
||||
(unless (or doom-inhibit-switch-frame-hooks
|
||||
(eq doom--last-frame (selected-frame))
|
||||
(frame-parameter nil 'parent-frame))
|
||||
|
@ -102,8 +98,8 @@ behavior). Do not set this directly, this is let-bound in `doom|init-theme'.")
|
|||
(run-hooks 'doom-switch-frame-hook)
|
||||
(setq doom--last-frame (selected-frame)))))
|
||||
|
||||
(defun doom*run-switch-buffer-hooks (orig-fn buffer-or-name &rest args)
|
||||
(let ((gc-cons-threshold doom-gc-cons-upper-limit))
|
||||
(defun doom-run-switch-buffer-hooks-a (orig-fn buffer-or-name &rest args)
|
||||
(let ((gc-cons-threshold most-positive-fixnum))
|
||||
(if (or doom-inhibit-switch-buffer-hooks
|
||||
(eq (current-buffer) (get-buffer buffer-or-name))
|
||||
(and (eq orig-fn #'switch-to-buffer) (car args)))
|
||||
|
@ -116,8 +112,8 @@ behavior). Do not set this directly, this is let-bound in `doom|init-theme'.")
|
|||
(run-hooks 'doom-switch-buffer-hook))
|
||||
buffer)))))
|
||||
|
||||
(defun doom*run-switch-to-next-prev-buffer-hooks (orig-fn &rest args)
|
||||
(let ((gc-cons-threshold doom-gc-cons-upper-limit))
|
||||
(defun doom-run-switch-to-next-prev-buffer-hooks-a (orig-fn &rest args)
|
||||
(let ((gc-cons-threshold most-positive-fixnum))
|
||||
(if doom-inhibit-switch-buffer-hooks
|
||||
(apply orig-fn args)
|
||||
(let ((doom-inhibit-switch-buffer-hooks t))
|
||||
|
@ -126,17 +122,11 @@ behavior). Do not set this directly, this is let-bound in `doom|init-theme'.")
|
|||
(run-hooks 'doom-switch-buffer-hook))
|
||||
buffer)))))
|
||||
|
||||
(defun doom*run-load-theme-hooks (theme &optional _no-confirm no-enable)
|
||||
"Set up `doom-load-theme-hook' to run after `load-theme' is called."
|
||||
(unless no-enable
|
||||
(setq doom-theme theme)
|
||||
(run-hooks 'doom-load-theme-hook)))
|
||||
|
||||
(defun doom|protect-fallback-buffer ()
|
||||
(defun doom-protect-fallback-buffer-h ()
|
||||
"Don't kill the scratch buffer. Meant for `kill-buffer-query-functions'."
|
||||
(not (eq (current-buffer) (doom-fallback-buffer))))
|
||||
|
||||
(defun doom|highlight-non-default-indentation ()
|
||||
(defun doom-highlight-non-default-indentation-h ()
|
||||
"Highlight whitespace that doesn't match your `indent-tabs-mode' setting.
|
||||
|
||||
e.g. If you indent with spaces by default, tabs will be highlighted. If you
|
||||
|
@ -151,99 +141,236 @@ read-only or not file-visiting."
|
|||
(set (make-local-variable 'whitespace-style)
|
||||
(let ((style (if indent-tabs-mode '(indentation) '(tabs tab-mark))))
|
||||
(if whitespace-mode
|
||||
(cl-union style whitespace-style)
|
||||
`(face ,@style))))
|
||||
(add-to-list 'whitespace-style 'face)
|
||||
(cl-union style whitespace-active-style)
|
||||
style)))
|
||||
(cl-pushnew 'face whitespace-style)
|
||||
(whitespace-mode +1)))
|
||||
|
||||
|
||||
;;
|
||||
;;; General configuration
|
||||
;;; General UX
|
||||
|
||||
(setq-default
|
||||
ansi-color-for-comint-mode t
|
||||
bidi-display-reordering nil ; disable bidirectional text for tiny performance boost
|
||||
blink-matching-paren nil ; don't blink--too distracting
|
||||
compilation-always-kill t ; kill compilation process before starting another
|
||||
compilation-ask-about-save nil ; save all buffers on `compile'
|
||||
compilation-scroll-output 'first-error
|
||||
confirm-nonexistent-file-or-buffer t
|
||||
confirm-kill-emacs #'doom-quit-p ; custom confirmation when killing Emacs
|
||||
cursor-in-non-selected-windows nil ; hide cursors in other windows
|
||||
custom-theme-directory (expand-file-name "themes/" doom-private-dir)
|
||||
display-line-numbers-width 3
|
||||
echo-keystrokes 0.02
|
||||
enable-recursive-minibuffers nil
|
||||
frame-inhibit-implied-resize t
|
||||
frame-title-format '("%b – Doom Emacs") ; simple name in frame title
|
||||
;; remove continuation arrow on right fringe
|
||||
fringe-indicator-alist
|
||||
(delq (assq 'continuation fringe-indicator-alist)
|
||||
fringe-indicator-alist)
|
||||
highlight-nonselected-windows nil
|
||||
image-animate-loop t
|
||||
indicate-buffer-boundaries nil
|
||||
indicate-empty-lines nil
|
||||
max-mini-window-height 0.3
|
||||
mode-line-default-help-echo nil ; disable mode-line mouseovers
|
||||
mouse-yank-at-point t ; middle-click paste at point, not at click
|
||||
show-help-function nil ; hide :help-echo text
|
||||
use-dialog-box nil ; always avoid GUI
|
||||
uniquify-buffer-name-style 'forward
|
||||
visible-cursor nil
|
||||
x-stretch-cursor nil
|
||||
;; Favor vertical splits
|
||||
split-width-threshold 160
|
||||
split-height-threshold nil
|
||||
;; `pos-tip' defaults
|
||||
pos-tip-internal-border-width 6
|
||||
pos-tip-border-width 1
|
||||
;; Simpler confirmation prompt when killing Emacs
|
||||
(setq confirm-kill-emacs #'doom-quit-p)
|
||||
|
||||
(setq uniquify-buffer-name-style 'forward
|
||||
;; no beeping or blinking please
|
||||
ring-bell-function #'ignore
|
||||
visible-bell nil
|
||||
;; don't resize emacs in steps, it looks weird
|
||||
window-resize-pixelwise t
|
||||
frame-resize-pixelwise t)
|
||||
;; y/n instead of yes/no
|
||||
(fset #'yes-or-no-p #'y-or-n-p)
|
||||
;; Truly silence startup message
|
||||
(fset #'display-startup-echo-area-message #'ignore)
|
||||
;; relegate tooltips to echo area only
|
||||
(if (bound-and-true-p tooltip-mode) (tooltip-mode -1))
|
||||
;; enabled by default; no thanks, too distracting
|
||||
(blink-cursor-mode -1)
|
||||
;; Handle ansi codes in compilation buffer
|
||||
(add-hook 'compilation-filter-hook #'doom|apply-ansi-color-to-compilation-buffer)
|
||||
;; Make `next-buffer', `other-buffer', etc. ignore unreal buffers.
|
||||
(add-to-list 'default-frame-alist '(buffer-predicate . doom-buffer-frame-predicate))
|
||||
;; Prevent the glimpse of un-styled Emacs by setting these early.
|
||||
(add-to-list 'default-frame-alist '(tool-bar-lines . 0))
|
||||
(add-to-list 'default-frame-alist '(menu-bar-lines . 0))
|
||||
(add-to-list 'default-frame-alist '(vertical-scroll-bars))
|
||||
;; prompts the user for confirmation when deleting a non-empty frame
|
||||
(global-set-key [remap delete-frame] #'doom/delete-frame)
|
||||
;; don't resize minibuffer for large text
|
||||
(setq resize-mini-windows nil)
|
||||
;; Except when it's asking for input
|
||||
(setq-hook! 'minibuffer-setup-hook resize-mini-windows 'grow-only)
|
||||
visible-bell nil)
|
||||
|
||||
;; Use `show-trailing-whitespace' instead of `whitespace-mode' because it's
|
||||
;; faster (implemented in C). But try to only enable it in editing buffers.
|
||||
(setq-default show-trailing-whitespace nil)
|
||||
(setq-hook! '(prog-mode-hook text-mode-hook conf-mode-hook) show-trailing-whitespace t)
|
||||
;; middle-click paste at point, not at click
|
||||
(setq mouse-yank-at-point t)
|
||||
|
||||
;; Enable mouse in terminal Emacs
|
||||
(add-hook 'tty-setup-hook #'xterm-mouse-mode)
|
||||
|
||||
|
||||
;;
|
||||
;;; Scrolling
|
||||
|
||||
(setq hscroll-margin 2
|
||||
hscroll-step 1
|
||||
scroll-conservatively 10
|
||||
scroll-margin 0
|
||||
scroll-preserve-screen-position t
|
||||
;; mouse
|
||||
mouse-wheel-scroll-amount '(5 ((shift) . 2))
|
||||
mouse-wheel-progressive-speed nil) ; don't accelerate scrolling
|
||||
|
||||
;; Remove hscroll-margin in shells, otherwise it causes jumpiness
|
||||
(setq-hook! '(eshell-mode-hook term-mode-hook) hscroll-margin 0)
|
||||
|
||||
(when IS-MAC
|
||||
;; sane trackpad/mouse scroll settings
|
||||
(setq mac-redisplay-dont-reset-vscroll t
|
||||
mac-mouse-wheel-smooth-scroll nil))
|
||||
|
||||
|
||||
;;
|
||||
;;; Cursor
|
||||
|
||||
;; Don't blink the cursor, it's too distracting.
|
||||
(blink-cursor-mode -1)
|
||||
|
||||
;; Don't blink the paren matching the one at point, it's too distracting.
|
||||
(setq blink-matching-paren nil)
|
||||
|
||||
(setq visible-cursor nil)
|
||||
|
||||
;; Don't stretch the cursor to fit wide characters, it is disorienting,
|
||||
;; especially for tabs.
|
||||
(setq x-stretch-cursor nil)
|
||||
|
||||
|
||||
;;
|
||||
;;; Buffers
|
||||
|
||||
;; Make `next-buffer', `other-buffer', etc. ignore unreal buffers.
|
||||
(push '(buffer-predicate . doom-buffer-frame-predicate) default-frame-alist)
|
||||
|
||||
(setq confirm-nonexistent-file-or-buffer t)
|
||||
|
||||
(defadvice! doom--switch-to-fallback-buffer-maybe-a (orig-fn)
|
||||
"Switch to `doom-fallback-buffer' if on last real buffer.
|
||||
|
||||
Advice for `kill-current-buffer'. If in a dedicated window, delete it. If there
|
||||
are no real buffers left OR if all remaining buffers are visible in other
|
||||
windows, switch to `doom-fallback-buffer'. Otherwise, delegate to original
|
||||
`kill-current-buffer'."
|
||||
:around #'kill-current-buffer
|
||||
(let ((buf (current-buffer)))
|
||||
(cond ((window-dedicated-p)
|
||||
(delete-window))
|
||||
((eq buf (doom-fallback-buffer))
|
||||
(message "Can't kill the fallback buffer."))
|
||||
((doom-real-buffer-p buf)
|
||||
(if (and buffer-file-name
|
||||
(buffer-modified-p buf)
|
||||
(not (y-or-n-p
|
||||
(format "Buffer %s is modified; kill anyway?" buf))))
|
||||
(message "Aborted")
|
||||
(set-buffer-modified-p nil)
|
||||
(let (buffer-list-update-hook)
|
||||
(when (or ;; if there aren't more real buffers than visible buffers,
|
||||
;; then there are no real, non-visible buffers left.
|
||||
(not (cl-set-difference (doom-real-buffer-list)
|
||||
(doom-visible-buffers)))
|
||||
;; if we end up back where we start (or previous-buffer
|
||||
;; returns nil), we have nowhere left to go
|
||||
(memq (switch-to-prev-buffer nil t) (list buf 'nil)))
|
||||
(switch-to-buffer (doom-fallback-buffer)))
|
||||
(unless (delq (selected-window) (get-buffer-window-list buf nil t))
|
||||
(kill-buffer buf)))
|
||||
(run-hooks 'buffer-list-update-hook)))
|
||||
((funcall orig-fn)))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Fringes
|
||||
|
||||
;; Reduce the clutter in the fringes; we'd like to reserve that space for more
|
||||
;; useful information, like git-gutter and flycheck.
|
||||
(setq indicate-buffer-boundaries nil
|
||||
indicate-empty-lines nil)
|
||||
|
||||
;; remove continuation arrow on right fringe
|
||||
(delq! 'continuation fringe-indicator-alist 'assq)
|
||||
|
||||
|
||||
;;
|
||||
;;; Windows/frames
|
||||
|
||||
;; A simple frame title
|
||||
(setq frame-title-format '("%b – Doom Emacs")
|
||||
icon-title-format frame-title-format)
|
||||
|
||||
;; Don't resize emacs in steps, it looks weird.
|
||||
(setq window-resize-pixelwise t
|
||||
frame-resize-pixelwise t)
|
||||
|
||||
(unless EMACS27+ ; We already do this in early-init.el
|
||||
;; Disable tool and scrollbars; Doom encourages keyboard-centric workflows, so
|
||||
;; these are just clutter (the scrollbar also impacts Emacs' performance).
|
||||
(push '(menu-bar-lines . 0) default-frame-alist)
|
||||
(push '(tool-bar-lines . 0) default-frame-alist)
|
||||
(push '(vertical-scroll-bars) default-frame-alist))
|
||||
|
||||
;; Sets `ns-appearance' and `ns-transparent-titlebar' on GUI frames (and fixes
|
||||
;; mismatching text color in the frame title)
|
||||
(when IS-MAC
|
||||
;; Curse Lion and its sudden but inevitable fullscreen mode!
|
||||
;; NOTE Meaningless to railwaycat's emacs-mac build
|
||||
(setq ns-use-native-fullscreen nil
|
||||
;; Visit files opened outside of Emacs in existing frame, rather than a
|
||||
;; new one
|
||||
ns-pop-up-frames nil)
|
||||
|
||||
;; Sets ns-transparent-titlebar and ns-appearance frame parameters as is
|
||||
;; appropriate for the loaded theme.
|
||||
(and (or (daemonp)
|
||||
(display-graphic-p))
|
||||
(require 'ns-auto-titlebar nil t)
|
||||
(ns-auto-titlebar-mode +1))
|
||||
|
||||
(add-hook! 'after-make-frame-functions
|
||||
(defun doom-init-menu-bar-in-gui-frames-h (frame)
|
||||
"On MacOS, the menu bar isn't part of the frame. Disabling it makes MacOS
|
||||
treat Emacs as a non-application window."
|
||||
(when (display-graphic-p frame)
|
||||
(set-frame-parameter frame 'menu-bar-lines 1)))))
|
||||
|
||||
;; The native border "consumes" a pixel of the fringe on righter-most splits,
|
||||
;; `window-divider' does not. Available since Emacs 25.1.
|
||||
(setq-default window-divider-default-places t
|
||||
(setq window-divider-default-places t
|
||||
window-divider-default-bottom-width 1
|
||||
window-divider-default-right-width 1)
|
||||
(add-hook 'doom-init-ui-hook #'window-divider-mode)
|
||||
|
||||
;; Prompt the user for confirmation when deleting a non-empty frame
|
||||
(global-set-key [remap delete-frame] #'doom/delete-frame)
|
||||
|
||||
;; always avoid GUI
|
||||
(setq use-dialog-box nil)
|
||||
;; Don't display floating tooltips; display their contents in the echo-area.
|
||||
(if (bound-and-true-p tooltip-mode) (tooltip-mode -1))
|
||||
;; native linux tooltips are ugly
|
||||
(when IS-LINUX
|
||||
(setq x-gtk-use-system-tooltips nil))
|
||||
|
||||
;; Favor vertical splits over horizontal ones
|
||||
(setq split-width-threshold 160
|
||||
split-height-threshold nil)
|
||||
|
||||
|
||||
;;
|
||||
;;; Minibuffer
|
||||
|
||||
;; Allow for minibuffer-ception. Sometimes we need another minibuffer command
|
||||
;; _while_ we're in the minibuffer.
|
||||
(setq enable-recursive-minibuffers t)
|
||||
|
||||
;; Show current key-sequence in minibuffer, like vim does. Any feedback after
|
||||
;; typing is better UX than no feedback at all.
|
||||
(setq echo-keystrokes 0.02)
|
||||
|
||||
;; Expand the minibuffer to fit multi-line text displayed in the echo-area. This
|
||||
;; doesn't look too great with direnv, however...
|
||||
(setq resize-mini-windows 'grow-only
|
||||
;; But don't let the minibuffer grow beyond this size
|
||||
max-mini-window-height 0.15)
|
||||
|
||||
;; Disable help mouse-overs for mode-line segments (i.e. :help-echo text).
|
||||
;; They're generally unhelpful and only add confusing visual clutter.
|
||||
(setq mode-line-default-help-echo nil
|
||||
show-help-function nil)
|
||||
|
||||
;; y/n is easier to type than yes/no
|
||||
(fset #'yes-or-no-p #'y-or-n-p)
|
||||
|
||||
;; Try really hard to keep the cursor from getting stuck in the read-only prompt
|
||||
;; portion of the minibuffer.
|
||||
(setq minibuffer-prompt-properties '(read-only t intangible t cursor-intangible t face minibuffer-prompt))
|
||||
(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
|
||||
|
||||
|
||||
;;
|
||||
;;; Built-in packages
|
||||
|
||||
(def-package! ediff
|
||||
;;;###package ansi-color
|
||||
(setq ansi-color-for-comint-mode t)
|
||||
|
||||
|
||||
(use-package! compile
|
||||
:defer t
|
||||
:config
|
||||
(setq compilation-always-kill t ; kill compilation process before starting another
|
||||
compilation-ask-about-save nil ; save all buffers on `compile'
|
||||
compilation-scroll-output 'first-error)
|
||||
;; Handle ansi codes in compilation buffer
|
||||
(add-hook 'compilation-filter-hook #'doom-apply-ansi-color-to-compilation-buffer-h))
|
||||
|
||||
|
||||
(use-package! ediff
|
||||
:defer t
|
||||
:init
|
||||
(setq ediff-diff-options "-w" ; turn off whitespace checking
|
||||
|
@ -252,23 +379,21 @@ read-only or not file-visiting."
|
|||
:config
|
||||
(defvar doom--ediff-saved-wconf nil)
|
||||
;; Restore window config after quitting ediff
|
||||
(defun doom|ediff-save-wconf ()
|
||||
(setq doom--ediff-saved-wconf (current-window-configuration)))
|
||||
(add-hook 'ediff-before-setup-hook #'doom|ediff-save-wconf)
|
||||
|
||||
(defun doom|ediff-restore-wconf ()
|
||||
(add-hook! 'ediff-before-setup-hook
|
||||
(defun doom-ediff-save-wconf-h ()
|
||||
(setq doom--ediff-saved-wconf (current-window-configuration))))
|
||||
(add-hook! '(ediff-quit-hook ediff-suspend-hook) :append
|
||||
(defun doom-ediff-restore-wconf-h ()
|
||||
(when (window-configuration-p doom--ediff-saved-wconf)
|
||||
(set-window-configuration doom--ediff-saved-wconf)))
|
||||
(add-hook 'ediff-quit-hook #'doom|ediff-restore-wconf 'append)
|
||||
(add-hook 'ediff-suspend-hook #'doom|ediff-restore-wconf 'append))
|
||||
(set-window-configuration doom--ediff-saved-wconf)))))
|
||||
|
||||
|
||||
(def-package! hl-line
|
||||
(use-package! hl-line
|
||||
;; Highlights the current line
|
||||
:hook ((prog-mode text-mode conf-mode) . hl-line-mode)
|
||||
:config
|
||||
;; I don't need hl-line showing in other windows. This also offers a small
|
||||
;; speed boost when buffer is displayed in multiple windows.
|
||||
;; Not having to render the hl-line overlay in multiple buffers offers a tiny
|
||||
;; performance boost. I also don't need to see it in other buffers.
|
||||
(setq hl-line-sticky-flag nil
|
||||
global-hl-line-sticky-flag nil)
|
||||
|
||||
|
@ -276,29 +401,27 @@ read-only or not file-visiting."
|
|||
;; selection region harder to see while in evil visual mode.
|
||||
(after! evil
|
||||
(defvar doom-buffer-hl-line-mode nil)
|
||||
|
||||
(defun doom|disable-hl-line ()
|
||||
(add-hook! 'evil-visual-state-entry-hook
|
||||
(defun doom-disable-hl-line-h ()
|
||||
(when hl-line-mode
|
||||
(setq-local doom-buffer-hl-line-mode t)
|
||||
(hl-line-mode -1)))
|
||||
(add-hook 'evil-visual-state-entry-hook #'doom|disable-hl-line)
|
||||
|
||||
(defun doom|enable-hl-line-maybe ()
|
||||
(hl-line-mode -1))))
|
||||
(add-hook! 'evil-visual-state-exit-hook
|
||||
(defun doom-enable-hl-line-maybe-h ()
|
||||
(when doom-buffer-hl-line-mode
|
||||
(hl-line-mode +1)))
|
||||
(add-hook 'evil-visual-state-exit-hook #'doom|enable-hl-line-maybe)))
|
||||
(hl-line-mode +1))))))
|
||||
|
||||
|
||||
(def-package! winner
|
||||
(use-package! winner
|
||||
;; undo/redo changes to Emacs' window layout
|
||||
:after-call (after-find-file doom-switch-window-hook)
|
||||
:after-call after-find-file doom-switch-window-hook
|
||||
:preface (defvar winner-dont-bind-my-keys t)
|
||||
:config (winner-mode +1)) ; I'll bind keys myself
|
||||
|
||||
|
||||
(def-package! paren
|
||||
(use-package! paren
|
||||
;; highlight matching delimiters
|
||||
:after-call (after-find-file doom-switch-buffer-hook)
|
||||
:after-call after-find-file doom-switch-buffer-hook
|
||||
:config
|
||||
(setq show-paren-delay 0.1
|
||||
show-paren-highlight-openparen t
|
||||
|
@ -316,56 +439,63 @@ read-only or not file-visiting."
|
|||
(newline-mark ?\n [?¬ ?\n])
|
||||
(space-mark ?\ [?·] [?.])))
|
||||
|
||||
;; Disable these because whitespace should be customized programmatically
|
||||
;; (through `whitespace-style'), and not through these commands.
|
||||
(put 'whitespace-toggle-options 'disabled t)
|
||||
(put 'global-whitespace-toggle-options 'disabled t)
|
||||
|
||||
|
||||
;;
|
||||
;;; Third party packages
|
||||
|
||||
(def-package! all-the-icons
|
||||
:commands (all-the-icons-octicon all-the-icons-faicon all-the-icons-fileicon
|
||||
all-the-icons-wicon all-the-icons-material all-the-icons-alltheicon)
|
||||
(use-package! all-the-icons
|
||||
:commands (all-the-icons-octicon
|
||||
all-the-icons-faicon
|
||||
all-the-icons-fileicon
|
||||
all-the-icons-wicon
|
||||
all-the-icons-material
|
||||
all-the-icons-alltheicon)
|
||||
:init
|
||||
(defun doom*disable-all-the-icons-in-tty (orig-fn &rest args)
|
||||
(if (display-graphic-p)
|
||||
(apply orig-fn args)
|
||||
""))
|
||||
:config
|
||||
;; all-the-icons doesn't work in the terminal, so we "disable" it.
|
||||
(dolist (fn '(all-the-icons-octicon all-the-icons-material
|
||||
(defadvice! doom--disable-all-the-icons-in-tty-a (orig-fn &rest args)
|
||||
"Return a blank string in tty Emacs, which doesn't support multiple fonts."
|
||||
:around '(all-the-icons-octicon all-the-icons-material
|
||||
all-the-icons-faicon all-the-icons-fileicon
|
||||
all-the-icons-wicon all-the-icons-alltheicon))
|
||||
(advice-add fn :around #'doom*disable-all-the-icons-in-tty)))
|
||||
all-the-icons-wicon all-the-icons-alltheicon)
|
||||
(if (display-multi-font-p)
|
||||
(apply orig-fn args)
|
||||
"")))
|
||||
|
||||
;;;###package hide-mode-line-mode
|
||||
(add-hook 'completion-list-mode-hook #'hide-mode-line-mode)
|
||||
(add-hook 'Man-mode-hook #'hide-mode-line-mode)
|
||||
(add-hook! '(completion-list-mode-hook Man-mode-hook)
|
||||
#'hide-mode-line-mode)
|
||||
|
||||
;; Better fontification of number literals in code
|
||||
(def-package! highlight-numbers
|
||||
(use-package! highlight-numbers
|
||||
:hook ((prog-mode conf-mode) . highlight-numbers-mode)
|
||||
:config (setq highlight-numbers-generic-regexp "\\_<[[:digit:]]+\\(?:\\.[0-9]*\\)?\\_>"))
|
||||
|
||||
;;;###package image
|
||||
(setq image-animate-loop t)
|
||||
|
||||
;;;###package rainbow-delimiters
|
||||
;; Helps us distinguish stacked delimiter pairs, especially in parentheses-drunk
|
||||
;; languages like Lisp.
|
||||
(setq rainbow-delimiters-max-face-count 3)
|
||||
|
||||
;;;###package pos-tip
|
||||
(setq pos-tip-internal-border-width 6
|
||||
pos-tip-border-width 1)
|
||||
|
||||
|
||||
;;
|
||||
;;; Line numbers
|
||||
|
||||
(setq-default display-line-numbers-width 3)
|
||||
|
||||
;; line numbers in most modes
|
||||
(add-hook! (prog-mode text-mode conf-mode) #'display-line-numbers-mode)
|
||||
(add-hook! '(prog-mode-hook text-mode-hook conf-mode-hook)
|
||||
#'display-line-numbers-mode)
|
||||
|
||||
(defun doom|enable-line-numbers () (display-line-numbers-mode +1))
|
||||
(defun doom|disable-line-numbers () (display-line-numbers-mode -1))
|
||||
(defun doom-enable-line-numbers-h () (display-line-numbers-mode +1))
|
||||
(defun doom-disable-line-numbers-h () (display-line-numbers-mode -1))
|
||||
|
||||
;; `nlinum' is used for Emacs 25 users, as Emacs 26+ has native line numbers.
|
||||
(def-package! nlinum
|
||||
;; DEPRECATED `nlinum' is used for Emacs 25 users; 26+ has native line numbers.
|
||||
(use-package! nlinum
|
||||
;; Line number column. A faster (or equivalent, in the worst case) line number
|
||||
;; plugin than `linum-mode'.
|
||||
:unless EMACS26+
|
||||
|
@ -407,14 +537,14 @@ character that looks like a space that `whitespace-mode' won't affect.")
|
|||
str))
|
||||
(setq nlinum-format-function #'doom-nlinum-format-fn)
|
||||
|
||||
(defun doom|init-nlinum-width ()
|
||||
(add-hook! 'nlinum-mode-hook
|
||||
(defun doom-init-nlinum-width-h ()
|
||||
"Calculate line number column width beforehand (optimization)."
|
||||
(setq nlinum--width
|
||||
(length (save-excursion (goto-char (point-max))
|
||||
(format-mode-line "%l")))))
|
||||
(add-hook 'nlinum-mode-hook #'doom|init-nlinum-width))
|
||||
(format-mode-line "%l")))))))
|
||||
|
||||
(def-package! nlinum-hl
|
||||
(use-package! nlinum-hl
|
||||
;; Fixes disappearing line numbers in nlinum and other quirks
|
||||
:unless EMACS26+
|
||||
:after nlinum
|
||||
|
@ -430,7 +560,7 @@ character that looks like a space that `whitespace-mode' won't affect.")
|
|||
;; forces them to resize.
|
||||
(add-hook 'after-setting-font-hook #'nlinum-hl-flush-all-windows))
|
||||
|
||||
(def-package! nlinum-relative
|
||||
(use-package! nlinum-relative
|
||||
:unless EMACS26+
|
||||
:defer t
|
||||
:config
|
||||
|
@ -441,7 +571,14 @@ character that looks like a space that `whitespace-mode' won't affect.")
|
|||
;;
|
||||
;;; Theme & font
|
||||
|
||||
(defun doom|init-fonts ()
|
||||
;; Underline looks a bit better when drawn lower
|
||||
(setq x-underline-at-descent-line t)
|
||||
|
||||
(defvar doom--prefer-theme-elc nil
|
||||
"If non-nil, `load-theme' will prefer the compiled theme (unlike its default
|
||||
behavior). Do not set this directly, this is let-bound in `doom-init-theme-h'.")
|
||||
|
||||
(defun doom-init-fonts-h ()
|
||||
"Loads fonts.
|
||||
|
||||
Fonts are specified by `doom-font', `doom-variable-pitch-font',
|
||||
|
@ -458,9 +595,11 @@ Fonts are specified by `doom-font', `doom-variable-pitch-font',
|
|||
((display-graphic-p)
|
||||
(setq doom-font (face-attribute 'default :font))))
|
||||
(when doom-serif-font
|
||||
(set-face-attribute 'fixed-pitch-serif nil :font doom-serif-font))
|
||||
(set-face-attribute 'fixed-pitch-serif t :font doom-serif-font))
|
||||
(when doom-variable-pitch-font
|
||||
(set-face-attribute 'variable-pitch nil :font doom-variable-pitch-font)))
|
||||
(set-face-attribute 'variable-pitch t :font doom-variable-pitch-font))
|
||||
(when (and doom-unicode-font (fboundp 'set-fontset-font))
|
||||
(set-fontset-font t 'unicode doom-unicode-font nil 'prepend)))
|
||||
((debug error)
|
||||
(if (string-prefix-p "Font not available: " (error-message-string e))
|
||||
(lwarn 'doom-ui :warning
|
||||
|
@ -468,56 +607,61 @@ Fonts are specified by `doom-font', `doom-variable-pitch-font',
|
|||
(font-get (caddr e) :family))
|
||||
(signal 'doom-error e)))))
|
||||
|
||||
(defun doom|init-emoji-fonts (frame)
|
||||
"Set up unicode fonts (if `doom-unicode-font' is set).
|
||||
|
||||
By default, this uses Apple Color Emoji on MacOS and Symbola on Linux."
|
||||
(when doom-unicode-font
|
||||
(set-fontset-font t 'unicode doom-unicode-font frame 'prepend)))
|
||||
|
||||
(defun doom|init-theme (&optional frame)
|
||||
(defun doom-init-theme-h (&optional frame)
|
||||
"Load the theme specified by `doom-theme' in FRAME."
|
||||
(when (and doom-theme (not (memq doom-theme custom-enabled-themes)))
|
||||
(with-selected-frame (or frame (selected-frame))
|
||||
(let ((doom--prefer-theme-elc t))
|
||||
(load-theme doom-theme t)))))
|
||||
|
||||
(defadvice! doom--run-load-theme-hooks-a (theme &optional _no-confirm no-enable)
|
||||
"Set up `doom-load-theme-hook' to run after `load-theme' is called."
|
||||
:after-while #'load-theme
|
||||
(unless no-enable
|
||||
(setq doom-theme theme)
|
||||
(run-hooks 'doom-load-theme-hook)))
|
||||
|
||||
(defadvice! doom--prefer-compiled-theme-a (orig-fn &rest args)
|
||||
"Make `load-theme' prioritize the byte-compiled theme for a moderate boost in
|
||||
startup (or theme switch) time, so long as `doom--prefer-theme-elc' is non-nil."
|
||||
:around #'load-theme
|
||||
(if (or (null after-init-time)
|
||||
doom--prefer-theme-elc)
|
||||
(cl-letf* ((old-locate-file (symbol-function 'locate-file))
|
||||
((symbol-function 'locate-file)
|
||||
(lambda (filename path &optional _suffixes predicate)
|
||||
(funcall old-locate-file filename path '("c" "") predicate))))
|
||||
(apply orig-fn args))
|
||||
(apply orig-fn args)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Bootstrap
|
||||
|
||||
(defun doom|init-ui ()
|
||||
(defun doom-init-ui-h ()
|
||||
"Initialize Doom's user interface by applying all its advice and hooks."
|
||||
(run-hook-wrapped 'doom-init-ui-hook #'doom-try-run-hook)
|
||||
|
||||
(add-to-list 'kill-buffer-query-functions #'doom|protect-fallback-buffer nil 'eq)
|
||||
(add-hook 'after-change-major-mode-hook #'doom|highlight-non-default-indentation)
|
||||
(add-to-list 'kill-buffer-query-functions #'doom-protect-fallback-buffer-h nil 'eq)
|
||||
(add-hook 'after-change-major-mode-hook #'doom-highlight-non-default-indentation-h 'append)
|
||||
|
||||
;; Initialize custom switch-{buffer,window,frame} hooks:
|
||||
;; + `doom-switch-buffer-hook'
|
||||
;; + `doom-switch-window-hook'
|
||||
;; + `doom-switch-frame-hook'
|
||||
(add-hook 'buffer-list-update-hook #'doom|run-switch-window-hooks)
|
||||
(add-hook 'focus-in-hook #'doom|run-switch-frame-hooks)
|
||||
(advice-add! '(switch-to-next-buffer switch-to-prev-buffer)
|
||||
:around #'doom*run-switch-to-next-prev-buffer-hooks)
|
||||
(advice-add! '(switch-to-buffer display-buffer)
|
||||
:around #'doom*run-switch-buffer-hooks))
|
||||
(add-hook 'buffer-list-update-hook #'doom-run-switch-window-hooks-h)
|
||||
(add-hook 'focus-in-hook #'doom-run-switch-frame-hooks-h)
|
||||
(dolist (fn '(switch-to-next-buffer switch-to-prev-buffer))
|
||||
(advice-add fn :around #'doom-run-switch-to-next-prev-buffer-hooks-a))
|
||||
(dolist (fn '(switch-to-buffer display-buffer))
|
||||
(advice-add fn :around #'doom-run-switch-buffer-hooks-a)))
|
||||
|
||||
;; Apply `doom-theme'
|
||||
(add-hook (if (daemonp)
|
||||
'after-make-frame-functions
|
||||
'doom-init-ui-hook)
|
||||
#'doom|init-theme)
|
||||
(add-hook 'doom-init-ui-hook #'doom-init-theme-h)
|
||||
;; Apply `doom-font' et co
|
||||
(add-hook 'doom-after-init-modules-hook #'doom|init-fonts)
|
||||
;; Ensure unicode fonts are set on each frame
|
||||
(add-hook 'after-make-frame-functions #'doom|init-emoji-fonts)
|
||||
;; Setup `doom-load-theme-hook' and ensure `doom-theme' is always set to the
|
||||
;; currently loaded theme
|
||||
(advice-add #'load-theme :after #'doom*run-load-theme-hooks)
|
||||
(add-hook 'doom-after-init-modules-hook #'doom-init-fonts-h)
|
||||
|
||||
(add-hook 'window-setup-hook #'doom|init-ui)
|
||||
(add-hook 'window-setup-hook #'doom-init-ui-h)
|
||||
|
||||
|
||||
;;
|
||||
|
@ -527,39 +671,13 @@ By default, this uses Apple Color Emoji on MacOS and Symbola on Linux."
|
|||
(unless (fboundp 'define-fringe-bitmap)
|
||||
(defun define-fringe-bitmap (&rest _)))
|
||||
|
||||
(defun doom*prefer-compiled-theme (orig-fn &rest args)
|
||||
"Make `load-theme' prioritize the byte-compiled theme for a moderate boost in
|
||||
startup (or theme switch) time, so long as `doom--prefer-theme-elc' is non-nil."
|
||||
(if (or (null after-init-time)
|
||||
doom--prefer-theme-elc)
|
||||
(cl-letf* ((old-locate-file (symbol-function 'locate-file))
|
||||
((symbol-function 'locate-file)
|
||||
(lambda (filename path &optional _suffixes predicate)
|
||||
(funcall old-locate-file filename path '("c" "") predicate))))
|
||||
(apply orig-fn args))
|
||||
(apply orig-fn args)))
|
||||
(advice-add #'load-theme :around #'doom*prefer-compiled-theme)
|
||||
|
||||
(after! whitespace
|
||||
(defun doom*disable-whitespace-mode-in-childframes (orig-fn)
|
||||
(defun doom-disable-whitespace-mode-in-childframes-a (orig-fn)
|
||||
"`whitespace-mode' inundates child frames with whitspace markers, so disable
|
||||
it to fix all that visual noise."
|
||||
(unless (frame-parameter nil 'parent-frame)
|
||||
(funcall orig-fn)))
|
||||
(add-function :around whitespace-enable-predicate #'doom*disable-whitespace-mode-in-childframes)
|
||||
|
||||
(defun doom|disable-whitespace-mode-in-childframes (frame)
|
||||
"`whitespace-mode' inundates child frames with whitspace markers, so disable
|
||||
it to fix all that visual noise."
|
||||
(when (frame-parameter frame 'parent-frame)
|
||||
(with-selected-frame frame
|
||||
(setq-local whitespace-style nil)
|
||||
frame)))
|
||||
(add-hook 'after-make-frame-functions #'doom|disable-whitespace-mode-in-childframes))
|
||||
|
||||
;; Don't allow cursor to enter the prompt
|
||||
(setq minibuffer-prompt-properties '(read-only t intangible t cursor-intangible t face minibuffer-prompt))
|
||||
(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
|
||||
(add-function :around whitespace-enable-predicate #'doom-disable-whitespace-mode-in-childframes-a))
|
||||
|
||||
;; Don't display messages in the minibuffer when using the minibuffer
|
||||
(defmacro doom-silence-motion-key (command key)
|
||||
|
@ -572,8 +690,5 @@ it to fix all that visual noise."
|
|||
(doom-silence-motion-key backward-delete-char "<backspace>")
|
||||
(doom-silence-motion-key delete-char "<delete>")
|
||||
|
||||
;; Switch to `doom-fallback-buffer' if on last real buffer
|
||||
(advice-add #'kill-current-buffer :around #'doom*switch-to-fallback-buffer-maybe)
|
||||
|
||||
(provide 'core-ui)
|
||||
;;; core-ui.el ends here
|
||||
|
|
484
core/core.el
484
core/core.el
|
@ -1,9 +1,10 @@
|
|||
;;; core.el --- the heart of the beast -*- lexical-binding: t; -*-
|
||||
|
||||
(eval-when-compile
|
||||
(and (version< emacs-version "25.3")
|
||||
(error "Detected Emacs %s. Doom only supports Emacs 25.3 and higher"
|
||||
emacs-version)))
|
||||
(defvar doom-init-p nil
|
||||
"Non-nil if Doom has been initialized.")
|
||||
|
||||
(defvar doom-init-time nil
|
||||
"The time it took, in seconds, for Doom Emacs to initialize.")
|
||||
|
||||
(defvar doom-debug-mode (or (getenv "DEBUG") init-file-debug)
|
||||
"If non-nil, Doom will log more.
|
||||
|
@ -11,10 +12,11 @@
|
|||
Use `doom/toggle-debug-mode' to toggle it. The --debug-init flag and setting the
|
||||
DEBUG envvar will enable this at startup.")
|
||||
|
||||
(defvar doom-gc-cons-threshold 16777216 ; 16mb
|
||||
"The default value to use for `gc-cons-threshold'. If you experience freezing,
|
||||
decrease this. If you experience stuttering, increase this.")
|
||||
|
||||
;;
|
||||
;;; Constants
|
||||
|
||||
(defconst doom-version "2.0.9"
|
||||
"Current version of Doom Emacs.")
|
||||
|
||||
|
@ -26,8 +28,7 @@ DEBUG envvar will enable this at startup.")
|
|||
(defconst IS-WINDOWS (memq system-type '(cygwin windows-nt ms-dos)))
|
||||
(defconst IS-BSD (or IS-MAC (eq system-type 'berkeley-unix)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Directories/files
|
||||
(defvar doom-emacs-dir
|
||||
(eval-when-compile (file-truename user-emacs-directory))
|
||||
"The path to the currently loaded .emacs.d directory. Must end with a slash.")
|
||||
|
@ -38,7 +39,9 @@ DEBUG envvar will enable this at startup.")
|
|||
(defvar doom-modules-dir (concat doom-emacs-dir "modules/")
|
||||
"The root directory for Doom's modules. Must end with a slash.")
|
||||
|
||||
(defvar doom-local-dir (concat doom-emacs-dir ".local/")
|
||||
(defvar doom-local-dir
|
||||
(or (getenv "DOOMLOCALDIR")
|
||||
(concat doom-emacs-dir ".local/"))
|
||||
"Root directory for local storage.
|
||||
|
||||
Use this as a storage location for this system's installation of Doom Emacs.
|
||||
|
@ -56,7 +59,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 +81,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.")
|
||||
|
@ -97,45 +100,12 @@ which is loaded at startup (if it exists). This is helpful if Emacs can't
|
|||
\(easily) be launched from the correct shell session (particularly for MacOS
|
||||
users).")
|
||||
|
||||
(defvar doom--initial-load-path (cons doom-core-dir load-path))
|
||||
(defvar doom--initial-process-environment process-environment)
|
||||
(defvar doom--initial-exec-path exec-path)
|
||||
(defvar doom--initial-file-name-handler-alist file-name-handler-alist)
|
||||
|
||||
;;
|
||||
;;; Doom core variables
|
||||
|
||||
(defvar doom-init-p nil
|
||||
"Non-nil if Doom has been initialized.")
|
||||
|
||||
(defvar doom-init-time nil
|
||||
"The time it took, in seconds, for Doom Emacs to initialize.")
|
||||
|
||||
(defvar doom-emacs-changed-p nil
|
||||
"If non-nil, the running version of Emacs is different from the first time
|
||||
Doom was setup, which may cause problems.")
|
||||
|
||||
(defvar doom-site-load-path (cons doom-core-dir load-path)
|
||||
"The initial value of `load-path', before it was altered by
|
||||
`doom-initialize'.")
|
||||
|
||||
(defvar doom-site-process-environment process-environment
|
||||
"The initial value of `process-environment', before it was altered by
|
||||
`doom-initialize'.")
|
||||
|
||||
(defvar doom-site-exec-path exec-path
|
||||
"The initial value of `exec-path', before it was altered by
|
||||
`doom-initialize'.")
|
||||
|
||||
(defvar doom-site-shell-file-name shell-file-name
|
||||
"The initial value of `shell-file-name', before it was altered by
|
||||
`doom-initialize'.")
|
||||
|
||||
(defvar doom--last-emacs-file (concat doom-local-dir "emacs-version.el"))
|
||||
(defvar doom--last-emacs-version nil)
|
||||
(defvar doom--refreshed-p nil)
|
||||
(defvar doom--stage 'init)
|
||||
|
||||
|
||||
;;
|
||||
;;; Custom error types
|
||||
|
||||
(define-error 'doom-error "Error in Doom Emacs core")
|
||||
(define-error 'doom-hook-error "Error in a Doom startup hook" 'doom-error)
|
||||
(define-error 'doom-autoload-error "Error in an autoloads file" 'doom-error)
|
||||
|
@ -144,64 +114,81 @@ Doom was setup, which may cause problems.")
|
|||
(define-error 'doom-package-error "Error with packages" 'doom-error)
|
||||
|
||||
|
||||
;;
|
||||
;;; Custom hooks
|
||||
|
||||
(defvar doom-reload-hook nil
|
||||
"A list of hooks to run when `doom/reload' is called.")
|
||||
|
||||
|
||||
;;
|
||||
;;; Emacs core configuration
|
||||
|
||||
;; Ensure `doom-core-dir' is in `load-path'
|
||||
(push doom-core-dir load-path)
|
||||
|
||||
;; Reduce debug output, well, unless we've asked for it.
|
||||
(setq debug-on-error doom-debug-mode
|
||||
jka-compr-verbose doom-debug-mode)
|
||||
|
||||
;; UTF-8 as the default coding system
|
||||
(when (fboundp 'set-charset-priority)
|
||||
(set-charset-priority 'unicode)) ; pretty
|
||||
(prefer-coding-system 'utf-8) ; pretty
|
||||
(setq locale-coding-system 'utf-8) ; please
|
||||
;; Except for the clipboard on Windows, where its contents could be in an
|
||||
;; encoding that's wider than utf-8, so we let Emacs/the OS decide what encoding
|
||||
;; to use.
|
||||
(unless IS-WINDOWS
|
||||
(setq selection-coding-system 'utf-8)) ; with sugar on top
|
||||
|
||||
(setq-default
|
||||
ad-redefinition-action 'accept ; silence redefined function warnings
|
||||
apropos-do-all t ; make `apropos' more useful
|
||||
auto-mode-case-fold nil
|
||||
autoload-compute-prefixes nil
|
||||
debug-on-error doom-debug-mode
|
||||
jka-compr-verbose doom-debug-mode ; silence compression messages
|
||||
ffap-machine-p-known 'reject ; don't ping things that look like domain names
|
||||
find-file-visit-truename t ; resolve symlinks when opening files
|
||||
idle-update-delay 1 ; update ui slightly less often
|
||||
;; be quiet at startup; don't load or display anything unnecessary
|
||||
inhibit-startup-message t
|
||||
;; Disable warnings from legacy advice system. They aren't useful, and we can't
|
||||
;; often do anything about them besides changing packages upstream
|
||||
(setq ad-redefinition-action 'accept)
|
||||
|
||||
;; Make apropos omnipotent. It's more useful this way.
|
||||
(setq apropos-do-all t)
|
||||
|
||||
;; Don't make a second case-insensitive pass over `auto-mode-alist'. If it has
|
||||
;; to, it's our (the user's) failure. One case for all!
|
||||
(setq auto-mode-case-fold nil)
|
||||
|
||||
;; Enable all disabled commands.
|
||||
(setq disabled-command-function nil)
|
||||
|
||||
;; Display the bare minimum at startup. We don't need all that noise. The
|
||||
;; dashboard/empty scratch buffer is good enough.
|
||||
(setq inhibit-startup-message t
|
||||
inhibit-startup-echo-area-message user-login-name
|
||||
inhibit-default-init t
|
||||
initial-major-mode 'fundamental-mode
|
||||
initial-scratch-message nil
|
||||
;; History & backup settings (save nothing, that's what git is for)
|
||||
auto-save-default nil
|
||||
create-lockfiles nil
|
||||
history-length 500
|
||||
make-backup-files nil ; don't create backup~ files
|
||||
;; byte compilation
|
||||
byte-compile-verbose doom-debug-mode
|
||||
byte-compile-warnings '(not free-vars unresolved noruntime lexical make-local)
|
||||
;; security
|
||||
gnutls-verify-error (not (getenv "INSECURE")) ; you shouldn't use this
|
||||
initial-scratch-message nil)
|
||||
(fset #'display-startup-echo-area-message #'ignore)
|
||||
|
||||
;; Emacs "updates" its ui more often than it needs to, so we slow it down
|
||||
;; slightly, from 0.5s:
|
||||
(setq idle-update-delay 1)
|
||||
|
||||
;; Emacs is a huge security vulnerability, what with all the dependencies it
|
||||
;; pulls in from all corners of the globe. Let's at least try to be more
|
||||
;; discerning.
|
||||
(setq gnutls-verify-error (not (getenv "INSECURE"))
|
||||
tls-checktrust gnutls-verify-error
|
||||
tls-program (list "gnutls-cli --x509cafile %t -p %p %h"
|
||||
tls-program '("gnutls-cli --x509cafile %t -p %p %h"
|
||||
;; compatibility fallbacks
|
||||
"gnutls-cli -p %p %h"
|
||||
"openssl s_client -connect %h:%p -no_ssl2 -no_ssl3 -ign_eof")
|
||||
;; Don't store authinfo in plain text!
|
||||
auth-sources (list (expand-file-name "authinfo.gpg" doom-etc-dir)
|
||||
"~/.authinfo.gpg")
|
||||
;; Don't litter `doom-emacs-dir'
|
||||
abbrev-file-name (concat doom-local-dir "abbrev.el")
|
||||
"openssl s_client -connect %h:%p -no_ssl2 -no_ssl3 -ign_eof"))
|
||||
|
||||
;; Emacs stores authinfo in HOME and in plaintext. Let's not do that, mkay? This
|
||||
;; file usually stores usernames, passwords, and other such treasures for the
|
||||
;; aspiring malicious third party.
|
||||
(setq auth-sources (list (expand-file-name "authinfo.gpg" doom-etc-dir)
|
||||
"~/.authinfo.gpg"))
|
||||
|
||||
;; Emacs on Windows frequently confuses HOME (C:\Users\<NAME>) and APPDATA,
|
||||
;; causing `abbreviate-home-dir' to produce incorrect paths.
|
||||
(when IS-WINDOWS
|
||||
(setq abbreviated-home-dir "\\`'"))
|
||||
|
||||
;; Don't litter `doom-emacs-dir'
|
||||
(setq abbrev-file-name (concat doom-local-dir "abbrev.el")
|
||||
async-byte-compile-log-file (concat doom-etc-dir "async-bytecomp.log")
|
||||
auto-save-list-file-name (concat doom-cache-dir "autosave")
|
||||
backup-directory-alist (list (cons "." (concat doom-cache-dir "backup/")))
|
||||
bookmark-default-file (concat doom-etc-dir "bookmarks")
|
||||
custom-file (concat doom-private-dir "init.el")
|
||||
custom-theme-directory (concat doom-private-dir "themes/")
|
||||
desktop-dirname (concat doom-etc-dir "desktop")
|
||||
desktop-base-file-name "autosave"
|
||||
desktop-base-lock-name "autosave-lock"
|
||||
|
@ -216,39 +203,79 @@ Doom was setup, which may cause problems.")
|
|||
url-configuration-directory (concat doom-etc-dir "url/")
|
||||
gamegrid-user-score-file-directory (concat doom-etc-dir "games/"))
|
||||
|
||||
(defun doom*symbol-file (orig-fn symbol &optional type)
|
||||
"If a `doom-file' symbol property exists on SYMBOL, use that instead of the
|
||||
original value of `symbol-file'."
|
||||
(or (if (symbolp symbol) (get symbol 'doom-file))
|
||||
(funcall orig-fn symbol type)))
|
||||
(advice-add #'symbol-file :around #'doom*symbol-file)
|
||||
|
||||
|
||||
;;
|
||||
;;; Minor mode version of `auto-mode-alist'
|
||||
;;; Optimizations
|
||||
|
||||
(defvar doom-auto-minor-mode-alist '()
|
||||
"Alist mapping filename patterns to corresponding minor mode functions, like
|
||||
`auto-mode-alist'. All elements of this alist are checked, meaning you can
|
||||
enable multiple minor modes for the same regexp.")
|
||||
;; Disable bidirectional text rendering for a modest performance boost. Of
|
||||
;; course, this renders Emacs unable to detect/display right-to-left languages
|
||||
;; (sorry!), but for us left-to-right language speakers/writers, it's a boon.
|
||||
(setq-default bidi-display-reordering 'left-to-right)
|
||||
|
||||
(defun doom|enable-minor-mode-maybe ()
|
||||
"Check file name against `doom-auto-minor-mode-alist'."
|
||||
(when (and buffer-file-name doom-auto-minor-mode-alist)
|
||||
(let ((name buffer-file-name)
|
||||
(remote-id (file-remote-p buffer-file-name))
|
||||
(alist doom-auto-minor-mode-alist))
|
||||
;; Remove backup-suffixes from file name.
|
||||
(setq name (file-name-sans-versions name))
|
||||
;; Remove remote file name identification.
|
||||
(when (and (stringp remote-id)
|
||||
(string-match (regexp-quote remote-id) name))
|
||||
(setq name (substring name (match-end 0))))
|
||||
(while (and alist (caar alist) (cdar alist))
|
||||
(if (string-match-p (caar alist) name)
|
||||
(funcall (cdar alist) 1))
|
||||
(setq alist (cdr alist))))))
|
||||
(add-hook 'find-file-hook #'doom|enable-minor-mode-maybe)
|
||||
;; Reduce rendering/line scan work for Emacs by not rendering cursors or regions
|
||||
;; in non-focused windows.
|
||||
(setq-default cursor-in-non-selected-windows nil)
|
||||
(setq highlight-nonselected-windows nil)
|
||||
|
||||
;; More performant rapid scrolling over unfontified regions. May cause brief
|
||||
;; spells of inaccurate fontification immediately after scrolling.
|
||||
(setq fast-but-imprecise-scrolling t)
|
||||
|
||||
;; Resizing the Emacs frame can be a terribly expensive part of changing the
|
||||
;; font. By inhibiting this, we easily halve startup times with fonts that are
|
||||
;; larger than the system default.
|
||||
(setq frame-inhibit-implied-resize t)
|
||||
|
||||
;; Don't ping things that look like domain names.
|
||||
(setq ffap-machine-p-known 'reject)
|
||||
|
||||
;; Performance on Windows is considerably worse than elsewhere. We'll need
|
||||
;; everything we can get.
|
||||
(when IS-WINDOWS
|
||||
;; Reduce the workload when doing file IO
|
||||
(setq w32-get-true-file-attributes nil)
|
||||
|
||||
;; Font compacting can be terribly expensive, especially for rendering icon
|
||||
;; fonts on Windows. Whether it has a noteable affect on Linux and Mac hasn't
|
||||
;; been determined.
|
||||
(setq inhibit-compacting-font-caches t))
|
||||
|
||||
;; Remove command line options that aren't relevant to our current OS; that
|
||||
;; means less to process at startup.
|
||||
(unless IS-MAC (setq command-line-ns-option-alist nil))
|
||||
(unless IS-LINUX (setq command-line-x-option-alist nil))
|
||||
|
||||
;; This is consulted on every `require', `load' and various path/io functions.
|
||||
;; You get a minor speed up by nooping this.
|
||||
(setq file-name-handler-alist nil)
|
||||
|
||||
(defun doom-restore-file-name-handler-alist-h ()
|
||||
(setq file-name-handler-alist doom--initial-file-name-handler-alist))
|
||||
|
||||
(add-hook 'emacs-startup-hook #'doom-restore-file-name-handler-alist-h)
|
||||
|
||||
;; To speed up minibuffer commands (like helm and ivy), we defer garbage
|
||||
;; collection while the minibuffer is active.
|
||||
(defun doom-defer-garbage-collection-h ()
|
||||
"TODO"
|
||||
(setq gc-cons-threshold most-positive-fixnum))
|
||||
|
||||
(defun doom-restore-garbage-collection-h ()
|
||||
"TODO"
|
||||
;; Defer it so that commands launched immediately after will enjoy the
|
||||
;; benefits.
|
||||
(run-at-time
|
||||
1 nil (lambda () (setq gc-cons-threshold doom-gc-cons-threshold))))
|
||||
|
||||
(add-hook 'minibuffer-setup-hook #'doom-defer-garbage-collection-h)
|
||||
(add-hook 'minibuffer-exit-hook #'doom-restore-garbage-collection-h)
|
||||
|
||||
;; Not restoring these to their defaults will cause stuttering/freezes.
|
||||
(add-hook 'emacs-startup-hook #'doom-restore-garbage-collection-h)
|
||||
|
||||
;; When Emacs loses focus seems like a great time to do some garbage collection
|
||||
;; all sneaky breeky like, so we can return a fresh(er) Emacs.
|
||||
(add-hook 'focus-out-hook #'garbage-collect)
|
||||
|
||||
|
||||
;;
|
||||
|
@ -257,27 +284,21 @@ enable multiple minor modes for the same regexp.")
|
|||
;; File+dir local variables are initialized after the major mode and its hooks
|
||||
;; have run. If you want hook functions to be aware of these customizations, add
|
||||
;; them to MODE-local-vars-hook instead.
|
||||
(defun doom|run-local-var-hooks ()
|
||||
(defun doom-run-local-var-hooks-h ()
|
||||
"Run MODE-local-vars-hook after local variables are initialized."
|
||||
(run-hook-wrapped (intern-soft (format "%s-local-vars-hook" major-mode))
|
||||
#'doom-try-run-hook))
|
||||
(add-hook 'hack-local-variables-hook #'doom|run-local-var-hooks)
|
||||
(add-hook 'hack-local-variables-hook #'doom-run-local-var-hooks-h)
|
||||
|
||||
;; If `enable-local-variables' is disabled, then `hack-local-variables-hook' is
|
||||
;; never triggered.
|
||||
(defun doom|run-local-var-hooks-if-necessary ()
|
||||
"Run `doom|run-local-var-hooks' if `enable-local-variables' is disabled."
|
||||
(defun doom-run-local-var-hooks-if-necessary-h ()
|
||||
"Run `doom-run-local-var-hooks-h' if `enable-local-variables' is disabled."
|
||||
(unless enable-local-variables
|
||||
(doom|run-local-var-hooks)))
|
||||
(add-hook 'after-change-major-mode-hook #'doom|run-local-var-hooks-if-necessary 'append)
|
||||
|
||||
(defun doom|create-non-existent-directories ()
|
||||
"Automatically create missing directories when creating new files."
|
||||
(let ((parent-directory (file-name-directory buffer-file-name)))
|
||||
(when (and (not (file-exists-p parent-directory))
|
||||
(y-or-n-p (format "Directory `%s' does not exist! Create it?" parent-directory)))
|
||||
(make-directory parent-directory t))))
|
||||
(add-hook 'find-file-not-found-functions #'doom|create-non-existent-directories)
|
||||
(doom-run-local-var-hooks-h)))
|
||||
(add-hook 'after-change-major-mode-hook
|
||||
#'doom-run-local-var-hooks-if-necessary-h
|
||||
'append)
|
||||
|
||||
|
||||
;;
|
||||
|
@ -298,7 +319,7 @@ broken up into:
|
|||
This is already done by the lang/org module, however.
|
||||
|
||||
If you want to disable incremental loading altogether, either remove
|
||||
`doom|load-packages-incrementally' from `emacs-startup-hook' or set
|
||||
`doom-load-packages-incrementally-h' from `emacs-startup-hook' or set
|
||||
`doom-incremental-first-idle-timer' to nil.")
|
||||
|
||||
(defvar doom-incremental-first-idle-timer 2
|
||||
|
@ -317,13 +338,19 @@ intervals."
|
|||
(if (not now)
|
||||
(nconc doom-incremental-packages packages)
|
||||
(when packages
|
||||
(let ((gc-cons-threshold doom-gc-cons-upper-limit)
|
||||
(reqs (cl-delete-if #'featurep packages))
|
||||
file-name-handler-alist)
|
||||
(when-let (req (if reqs (ignore-errors (pop reqs))))
|
||||
(let ((gc-cons-threshold most-positive-fixnum)
|
||||
(file-name-handler-alist nil)
|
||||
(reqs (cl-delete-if #'featurep packages)))
|
||||
(when-let (req (if reqs (pop reqs)))
|
||||
(doom-log "Incrementally loading %s" req)
|
||||
(condition-case e
|
||||
(or (while-no-input (require req nil t) t)
|
||||
(or (while-no-input
|
||||
;; If `default-directory' is a directory that doesn't exist
|
||||
;; or is unreadable, Emacs throws up file-missing errors, so
|
||||
;; we set it to a directory we know exists and is readable.
|
||||
(let ((default-directory doom-emacs-dir))
|
||||
(require req nil t))
|
||||
t)
|
||||
(push req reqs))
|
||||
((error debug)
|
||||
(message "Failed to load '%s' package incrementally, because: %s"
|
||||
|
@ -334,7 +361,7 @@ intervals."
|
|||
reqs t)
|
||||
(doom-log "Finished incremental loading")))))))
|
||||
|
||||
(defun doom|load-packages-incrementally ()
|
||||
(defun doom-load-packages-incrementally-h ()
|
||||
"Begin incrementally loading packages in `doom-incremental-packages'.
|
||||
|
||||
If this is a daemon session, load them all immediately instead."
|
||||
|
@ -345,7 +372,7 @@ If this is a daemon session, load them all immediately instead."
|
|||
nil #'doom-load-packages-incrementally
|
||||
(cdr doom-incremental-packages) t))))
|
||||
|
||||
(add-hook 'window-setup-hook #'doom|load-packages-incrementally)
|
||||
(add-hook 'emacs-startup-hook #'doom-load-packages-incrementally-h)
|
||||
|
||||
|
||||
;;
|
||||
|
@ -364,73 +391,34 @@ 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 (&optional return-p)
|
||||
(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.
|
||||
|
||||
If RETURN-P, return the message as a string instead of displaying it."
|
||||
(funcall (if return-p #'format #'message)
|
||||
"Doom loaded %s packages across %d modules in %.03fs"
|
||||
(length package-activated-list)
|
||||
"Doom loaded %d packages across %d modules in %.03fs"
|
||||
(- (length load-path) (length doom--initial-load-path))
|
||||
(if doom-modules (hash-table-count doom-modules) 0)
|
||||
(or doom-init-time
|
||||
(setq doom-init-time (float-time (time-subtract (current-time) before-init-time))))))
|
||||
|
||||
(defun doom|run-all-startup-hooks ()
|
||||
"Run all startup Emacs hooks. Meant to be executed after starting Emacs with
|
||||
-q or -Q, for example:
|
||||
|
||||
emacs -Q -l init.el -f doom|run-all-startup-hooks"
|
||||
(run-hook-wrapped 'after-init-hook #'doom-try-run-hook)
|
||||
(setq after-init-time (current-time))
|
||||
(dolist (hook (list 'delayed-warnings-hook
|
||||
'emacs-startup-hook 'term-setup-hook
|
||||
'window-setup-hook))
|
||||
(run-hook-wrapped hook #'doom-try-run-hook)))
|
||||
|
||||
(defun doom-initialize-autoloads (file)
|
||||
(defun doom-load-autoloads-file (file)
|
||||
"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 (substring file 0 -3) 'noerror 'nomessage))
|
||||
((debug error)
|
||||
(if noninteractive
|
||||
(message "Autoload file warning: %s -> %s" (car e) (error-message-string e))
|
||||
(signal 'doom-autoload-error (list (file-name-nondirectory file) e))))))
|
||||
|
||||
(defun doom-load-env-vars (file)
|
||||
(defun doom-load-envvars-file (file &optional noerror)
|
||||
"Read and set envvars in FILE."
|
||||
(if (not (file-readable-p file))
|
||||
(doom-log "Couldn't read %S envvar file" file)
|
||||
(unless noerror
|
||||
(signal 'file-error (list "Couldn't read envvar file" file)))
|
||||
(with-temp-buffer
|
||||
(insert-file-contents file)
|
||||
(search-forward "\n\n" nil t)
|
||||
|
@ -443,7 +431,8 @@ in interactive sessions, nil otherwise (but logs a warning)."
|
|||
(line-beginning-position))
|
||||
(point-max))))))
|
||||
(setenv var value)))))
|
||||
(setq exec-path (append (split-string (getenv "PATH")
|
||||
(setq-default
|
||||
exec-path (append (split-string (getenv "PATH")
|
||||
(if IS-WINDOWS ";" ":"))
|
||||
(list exec-directory))
|
||||
shell-file-name (or (getenv "SHELL")
|
||||
|
@ -479,66 +468,79 @@ 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)."
|
||||
(add-to-list 'load-path doom-core-dir)
|
||||
(require 'core-lib)
|
||||
|
||||
(when (or force-p (not doom-init-p))
|
||||
(setq doom-init-p t) ; Prevent infinite recursion
|
||||
(setq doom-init-p t)
|
||||
|
||||
;; Reset as much state as possible
|
||||
(setq exec-path doom-site-exec-path
|
||||
load-path doom-site-load-path
|
||||
process-environment doom-site-process-environment
|
||||
shell-file-name doom-site-shell-file-name)
|
||||
|
||||
;; `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)
|
||||
|
||||
(require 'core-packages)
|
||||
(doom-ensure-packages-initialized force-p)
|
||||
(doom-ensure-core-packages)
|
||||
|
||||
(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")))
|
||||
|
||||
;; Load shell environment
|
||||
(unless noninteractive
|
||||
(doom-load-env-vars doom-env-file)))
|
||||
;; Reset as much state as possible, so `doom-initialize' can be treated like
|
||||
;; a reset function. Particularly useful for reloading the config.
|
||||
(setq exec-path doom--initial-exec-path
|
||||
load-path doom--initial-load-path
|
||||
process-environment doom--initial-process-environment)
|
||||
|
||||
(require 'core-lib)
|
||||
(require 'core-modules)
|
||||
(require 'core-os)
|
||||
(if noninteractive
|
||||
(require 'core-cli)
|
||||
(add-hook 'window-setup-hook #'doom|display-benchmark)
|
||||
|
||||
;; Load shell environment, optionally generated from 'doom env'
|
||||
(when (and (or (display-graphic-p)
|
||||
(daemonp))
|
||||
(file-exists-p doom-env-file))
|
||||
(doom-load-envvars-file doom-env-file))
|
||||
|
||||
(let (;; `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.
|
||||
(core-autoloads-p (doom-load-autoloads-file doom-autoload-file))
|
||||
;; Loads `doom-package-autoload-file', which loads a concatenated
|
||||
;; package autoloads file which caches `load-path', `auto-mode-alist',
|
||||
;; `Info-directory-list', and `doom-disabled-packages'. A big
|
||||
;; reduction in startup time.
|
||||
(pkg-autoloads-p
|
||||
(unless noninteractive
|
||||
(doom-load-autoloads-file doom-package-autoload-file))))
|
||||
|
||||
(if (and core-autoloads-p (not force-p))
|
||||
;; In case we want to use package.el or straight via M-x
|
||||
(progn
|
||||
(with-eval-after-load 'package
|
||||
(require 'core-packages))
|
||||
(with-eval-after-load 'straight
|
||||
(require 'core-packages)
|
||||
(doom-initialize-packages)))
|
||||
|
||||
;; 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).
|
||||
(mapc (doom-rpartial #'load 'noerror 'nomessage)
|
||||
(file-expand-wildcards (concat doom-core-dir "autoload/*.el")))
|
||||
|
||||
;; Create all our core directories to quell file errors
|
||||
(dolist (dir (list doom-local-dir
|
||||
doom-etc-dir
|
||||
doom-cache-dir
|
||||
doom-elpa-dir))
|
||||
(unless (file-directory-p dir)
|
||||
(make-directory dir 'parents)))
|
||||
|
||||
;; Ensure the package management system (and straight) are ready for
|
||||
;; action (and all core packages/repos are installed)
|
||||
(require 'core-packages)
|
||||
(doom-initialize-packages force-p))
|
||||
|
||||
(unless (or (and core-autoloads-p pkg-autoloads-p)
|
||||
force-p
|
||||
noninteractive)
|
||||
(unless core-autoloads-p
|
||||
(message "Your Doom core autoloads file is missing"))
|
||||
(unless pkg-autoloads-p
|
||||
(message "Your package autoloads file is missing"))
|
||||
(user-error "Run `bin/doom refresh' to generate them")))))
|
||||
|
||||
(defun doom-initialize-core ()
|
||||
"Load Doom's core files for an interactive session."
|
||||
(require 'core-keybinds)
|
||||
(require 'core-ui)
|
||||
(require 'core-projects)
|
||||
(require 'core-editor)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Bootstrap Doom
|
||||
|
||||
(doom-initialize noninteractive)
|
||||
(unless noninteractive
|
||||
(doom-initialize-modules))
|
||||
(with-eval-after-load 'package
|
||||
(require 'core-packages)
|
||||
(doom-initialize-packages))
|
||||
(require 'core-editor))
|
||||
|
||||
(provide 'core)
|
||||
;;; core.el ends here
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
(/ size 1024))
|
||||
(explain! "Consider deleting it from your system (manually)"))))
|
||||
|
||||
(unless (executable-find doom-projectile-fd-binary)
|
||||
(unless (ignore-errors (executable-find doom-projectile-fd-binary))
|
||||
(warn! "Couldn't find the `fd' binary; project file searches will be slightly slower")
|
||||
(unless (executable-find "rg")
|
||||
(warn! "Couldn't find the `rg' binary either; project file searches will be even slower")))
|
||||
|
|
|
@ -3,12 +3,7 @@
|
|||
|
||||
;; core.el
|
||||
(package! dotenv-mode)
|
||||
|
||||
;; core-os.el
|
||||
(if (not IS-MAC)
|
||||
(package! xclip)
|
||||
(package! osx-clipboard)
|
||||
(package! ns-auto-titlebar))
|
||||
(package! auto-minor-mode)
|
||||
|
||||
;; core-ui.el
|
||||
(package! all-the-icons)
|
||||
|
@ -26,10 +21,16 @@
|
|||
(package! command-log-mode)
|
||||
(package! dtrt-indent)
|
||||
(package! helpful)
|
||||
(package! ns-auto-titlebar :ignore (not IS-MAC))
|
||||
(package! pcre2el)
|
||||
(package! smartparens)
|
||||
(package! so-long
|
||||
:built-in 'prefer
|
||||
:recipe (:repo "https://git.savannah.gnu.org/git/so-long.git"))
|
||||
(package! osx-clipboard :ignore (not IS-MAC))
|
||||
(package! undo-tree)
|
||||
(package! ws-butler)
|
||||
(package! xclip :ignore IS-LINUX)
|
||||
|
||||
;; core-projects.el
|
||||
(package! projectile)
|
||||
|
@ -37,13 +38,6 @@
|
|||
;; core-keybinds.el
|
||||
(package! general)
|
||||
(package! which-key)
|
||||
(package! hydra)
|
||||
|
||||
;; core-packages.el
|
||||
(package! gnu-elpa-keyring-update)
|
||||
|
||||
;; autoload/debug.el
|
||||
(package! esup)
|
||||
|
||||
;; cli/test.el
|
||||
(package! buttercup)
|
||||
|
|
9
core/test/helpers.el
Normal file
9
core/test/helpers.el
Normal file
|
@ -0,0 +1,9 @@
|
|||
;; -*- no-byte-compile: t; -*-
|
||||
;;; core/test/helpers.el
|
||||
|
||||
(defmacro insert!! (&rest text)
|
||||
"Insert TEXT in buffer, then move cursor to last {0} marker."
|
||||
`(progn
|
||||
(insert ,@text)
|
||||
(when (search-backward "{0}" nil t)
|
||||
(replace-match "" t t))))
|
|
@ -1,4 +1,6 @@
|
|||
;;; init.test.el -- for automated unit tests -*- lexical-binding: t; -*-
|
||||
;;; core/test/init.el -*- lexical-binding: t; no-byte-compile: t; -*-
|
||||
|
||||
;; An init.el for our unit test suites. Do not use this!
|
||||
|
||||
(doom! :completion
|
||||
company
|
|
@ -62,13 +62,15 @@
|
|||
(setq a (switch-to-buffer (get-buffer-create "a"))
|
||||
b (get-buffer-create "b"))
|
||||
(spy-on 'hook)
|
||||
(add-hook 'buffer-list-update-hook #'doom|run-switch-window-hooks)
|
||||
(add-hook 'focus-in-hook #'doom|run-switch-frame-hooks)
|
||||
(advice-add! '(switch-to-buffer display-buffer) :around #'doom*run-switch-buffer-hooks))
|
||||
(add-hook 'buffer-list-update-hook #'doom-run-switch-window-hooks-h)
|
||||
(add-hook 'focus-in-hook #'doom-run-switch-frame-hooks-h)
|
||||
(dolist (fn '(switch-to-buffer display-buffer))
|
||||
(advice-add fn :around #'doom-run-switch-buffer-hooks-a)))
|
||||
(after-each
|
||||
(remove-hook 'buffer-list-update-hook #'doom|run-switch-window-hooks)
|
||||
(remove-hook 'focus-in-hook #'doom|run-switch-frame-hooks)
|
||||
(advice-remove! '(switch-to-buffer display-buffer) #'doom*run-switch-buffer-hooks)
|
||||
(remove-hook 'buffer-list-update-hook #'doom-run-switch-window-hooks-h)
|
||||
(remove-hook 'focus-in-hook #'doom-run-switch-frame-hooks-h)
|
||||
(dolist (fn '(switch-to-buffer display-buffer))
|
||||
(advice-remove fn #'doom-run-switch-buffer-hooks-a))
|
||||
(kill-buffer a)
|
||||
(kill-buffer b))
|
||||
|
||||
|
|
150
docs/api.org
Normal file
150
docs/api.org
Normal file
|
@ -0,0 +1,150 @@
|
|||
#+TITLE: API Demos
|
||||
|
||||
This appendix serves as a reference on how to use Doom Emacs' standard library.
|
||||
It is integrated into Helpful, in Doom.
|
||||
|
||||
* add-hook!
|
||||
#+BEGIN_SRC elisp :eval no
|
||||
;; With only one hook and one function, this is identical to `add-hook'. In that
|
||||
;; case, use that instead.
|
||||
(add-hook! 'some-mode-hook #'enable-something)
|
||||
|
||||
;; Adding many-to-many functions to hooks
|
||||
(add-hook! some-mode #'enable-something #'and-another)
|
||||
(add-hook! some-mode #'(enable-something and-another))
|
||||
(add-hook! '(one-mode-hook second-mode-hook) #'enable-something)
|
||||
(add-hook! (one-mode second-mode) #'enable-something)
|
||||
|
||||
;; Appending and local hooks
|
||||
(add-hook! (one-mode second-mode) :append #'enable-something)
|
||||
(add-hook! (one-mode second-mode) :local #'enable-something)
|
||||
|
||||
;; With arbitrary forms
|
||||
(add-hook! (one-mode second-mode) (setq v 5) (setq a 2))
|
||||
(add-hook! (one-mode second-mode) :append :local (setq v 5) (setq a 2))
|
||||
|
||||
;; Inline named hook functions
|
||||
(add-hook! '(one-mode-hook second-mode-hook)
|
||||
(defun do-something ()
|
||||
...)
|
||||
(defun do-another-thing ()
|
||||
...))
|
||||
#+END_SRC
|
||||
|
||||
* custom-theme-set-faces!
|
||||
#+BEGIN_SRC elisp :eval no
|
||||
(custom-theme-set-faces! 'doom-one-theme
|
||||
'(outline-1 :weight normal)
|
||||
'(outline-2 :weight normal)
|
||||
'(outline-3 :weight normal)
|
||||
'(outline-4 :weight normal)
|
||||
'(outline-5 :weight normal)
|
||||
'(outline-6 :weight normal)
|
||||
'(default :background "red" :weight bold)
|
||||
'(region :background "red" :weight bold))
|
||||
|
||||
(custom-theme-set-faces! '(doom-one-theme doom-one-light-theme)
|
||||
'((outline-1 outline-2 outline-3 outline-4 outline-5 outline-6)
|
||||
:weight normal)
|
||||
'((default region)
|
||||
:background "red" :weight bold))
|
||||
|
||||
(let ((red-bg-faces '(default region)))
|
||||
(custom-theme-set-faces! '(doom-one-theme doom-one-light-theme)
|
||||
`(,(cl-loop for i from 0 to 6 collect (intern (format "outline-%d" i)))
|
||||
:weight normal)
|
||||
`(,red-bg-faces
|
||||
:background "red" :weight bold)))
|
||||
#+END_SRC
|
||||
|
||||
* custom-set-faces!
|
||||
#+BEGIN_SRC elisp :eval no
|
||||
(custom-set-faces!
|
||||
'(outline-1 :weight normal)
|
||||
'(outline-2 :weight normal)
|
||||
'(outline-3 :weight normal)
|
||||
'(outline-4 :weight normal)
|
||||
'(outline-5 :weight normal)
|
||||
'(outline-6 :weight normal)
|
||||
'(default :background "red" :weight bold)
|
||||
'(region :background "red" :weight bold))
|
||||
|
||||
(custom-set-faces!
|
||||
'((outline-1 outline-2 outline-3 outline-4 outline-5 outline-6)
|
||||
:weight normal)
|
||||
'((default region)
|
||||
:background "red" :weight bold))
|
||||
|
||||
(let ((red-bg-faces '(default region)))
|
||||
(custom-set-faces!
|
||||
`(,(cl-loop for i from 0 to 6 collect (intern (format "outline-%d" i)))
|
||||
:weight normal)
|
||||
`(,red-bg-faces
|
||||
:background "red" :weight bold)))
|
||||
#+END_SRC
|
||||
|
||||
* doom!
|
||||
#+BEGIN_SRC elisp :eval no
|
||||
(doom! :completion
|
||||
company
|
||||
ivy
|
||||
;;helm
|
||||
|
||||
:tools
|
||||
(:if IS-MAC macos)
|
||||
docker
|
||||
lsp
|
||||
|
||||
:lang
|
||||
(cc +lsp)
|
||||
(:cond ((string= system-name "work-pc")
|
||||
python
|
||||
rust
|
||||
web)
|
||||
((string= system-name "writing-pc")
|
||||
(org +dragndrop)
|
||||
ruby))
|
||||
(:if IS-LINUX
|
||||
(web +lsp)
|
||||
web)
|
||||
|
||||
:config
|
||||
literate
|
||||
(default +bindings +smartparens))
|
||||
#+END_SRC
|
||||
|
||||
* file-exists-p!
|
||||
#+BEGIN_SRC elisp
|
||||
(file-exists-p! "init.el" doom-emacs-dir)
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: /home/hlissner/.emacs.d/init.el
|
||||
|
||||
#+BEGIN_SRC elisp
|
||||
(file-exists-p! (and (or "doesnotexist" "init.el")
|
||||
"LICENSE")
|
||||
doom-emacs-dir)
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: /home/hlissner/.emacs.d/LICENSE
|
||||
|
||||
* remove-hook!
|
||||
#+BEGIN_SRC elisp :eval no
|
||||
;; With only one hook and one function, this is identical to `remove-hook'. In
|
||||
;; that case, use that instead.
|
||||
(remove-hook! 'some-mode-hook #'enable-something)
|
||||
|
||||
;; Removing N functions from M hooks
|
||||
(remove-hook! some-mode #'enable-something #'and-another)
|
||||
(remove-hook! some-mode #'(enable-something and-another))
|
||||
(remove-hook! '(one-mode-hook second-mode-hook) #'enable-something)
|
||||
(remove-hook! (one-mode second-mode) #'enable-something)
|
||||
|
||||
;; Removing buffer-local hooks
|
||||
(remove-hook! (one-mode second-mode) :local #'enable-something)
|
||||
|
||||
;; Removing arbitrary forms (must be exactly the same as the definition)
|
||||
(remove-hook! (one-mode second-mode) (setq v 5) (setq a 2))
|
||||
#+END_SRC
|
|
@ -4,17 +4,19 @@
|
|||
;; before package and UI initialization happens.
|
||||
|
||||
;; Defer garbage collection further back in the startup process
|
||||
(setq gc-cons-threshold 268435456)
|
||||
(setq gc-cons-threshold most-positive-fixnum)
|
||||
|
||||
;; Package initialize occurs automatically, before `user-init-file' is
|
||||
;; loaded, but after `early-init-file'. Doom handles package
|
||||
;; initialization, so we must prevent Emacs from doing it early!
|
||||
;; In Emacs 27+, package initialization occurs before `user-init-file' is
|
||||
;; loaded, but after `early-init-file'. Doom handles package initialization, so
|
||||
;; we must prevent Emacs from doing it early!
|
||||
(setq package-enable-at-startup nil)
|
||||
|
||||
;; Prevent the glimpse of un-styled Emacs by setting these early.
|
||||
(add-to-list 'default-frame-alist '(tool-bar-lines . 0))
|
||||
(add-to-list 'default-frame-alist '(menu-bar-lines . 0))
|
||||
(add-to-list 'default-frame-alist '(vertical-scroll-bars))
|
||||
;; Prevent the glimpse of un-styled Emacs by disabling these UI elements early.
|
||||
(push '(menu-bar-lines . 0) default-frame-alist)
|
||||
(push '(tool-bar-lines . 0) default-frame-alist)
|
||||
(push '(vertical-scroll-bars) default-frame-alist)
|
||||
|
||||
;; One less file to load at startup
|
||||
(setq site-run-file nil)
|
||||
;; Resizing the Emacs frame can be a terribly expensive part of changing the
|
||||
;; font. By inhibiting this, we easily halve startup times with fonts that are
|
||||
;; larger than the system default.
|
||||
(setq frame-inhibit-implied-resize t)
|
||||
|
|
74
init.el
74
init.el
|
@ -27,61 +27,33 @@
|
|||
;;
|
||||
;;; License: MIT
|
||||
|
||||
(defvar doom-gc-cons-threshold 16777216 ; 16mb
|
||||
"The default value to use for `gc-cons-threshold'. If you experience freezing,
|
||||
decrease this. If you experience stuttering, increase this.")
|
||||
|
||||
(defvar doom-gc-cons-upper-limit 536870912 ; 512mb
|
||||
"The temporary value for `gc-cons-threshold' to defer it.")
|
||||
|
||||
|
||||
(defvar doom--file-name-handler-alist file-name-handler-alist)
|
||||
|
||||
(defun doom|restore-startup-optimizations ()
|
||||
"Resets garbage collection settings to reasonable defaults (a large
|
||||
`gc-cons-threshold' can cause random freezes otherwise) and resets
|
||||
`file-name-handler-alist'."
|
||||
(setq file-name-handler-alist doom--file-name-handler-alist)
|
||||
;; Do this on idle timer to defer a possible GC pause that could result; also
|
||||
;; allows deferred packages to take advantage of these optimizations.
|
||||
(run-with-idle-timer
|
||||
3 nil
|
||||
(lambda ()
|
||||
(setq-default gc-cons-threshold doom-gc-cons-threshold)
|
||||
;; To speed up minibuffer commands (like helm and ivy), we defer garbage
|
||||
;; collection while the minibuffer is active.
|
||||
(defun doom|defer-garbage-collection ()
|
||||
(setq gc-cons-threshold doom-gc-cons-upper-limit))
|
||||
(defun doom|restore-garbage-collection ()
|
||||
;; Defer it so that commands launched from the minibuffer can enjoy the
|
||||
;; benefits.
|
||||
(run-at-time 1 nil (lambda () (setq gc-cons-threshold doom-gc-cons-threshold))))
|
||||
(add-hook 'minibuffer-setup-hook #'doom|defer-garbage-collection)
|
||||
(add-hook 'minibuffer-exit-hook #'doom|restore-garbage-collection)
|
||||
;; GC all sneaky breeky like
|
||||
(add-hook 'focus-out-hook #'garbage-collect))))
|
||||
|
||||
|
||||
(if (ignore-errors (or after-init-time noninteractive))
|
||||
(setq gc-cons-threshold doom-gc-cons-threshold)
|
||||
;; A big contributor to startup times is garbage collection. We up the gc
|
||||
;; threshold to temporarily prevent it from running, then reset it later in
|
||||
;; `doom|restore-startup-optimizations'.
|
||||
(setq gc-cons-threshold doom-gc-cons-upper-limit)
|
||||
;; This is consulted on every `require', `load' and various path/io functions.
|
||||
;; You get a minor speed up by nooping this.
|
||||
(setq file-name-handler-alist nil)
|
||||
;; Not restoring these to their defaults will cause stuttering/freezes.
|
||||
(add-hook 'after-init-hook #'doom|restore-startup-optimizations))
|
||||
|
||||
(when (version< emacs-version "25.3")
|
||||
(error "Detected Emacs %s. Doom only supports Emacs 25.3 and higher"
|
||||
emacs-version))
|
||||
|
||||
;; Ensure Doom is running out of this file's directory
|
||||
(setq user-emacs-directory (file-name-directory load-file-name))
|
||||
|
||||
;; A big contributor to startup times is garbage collection. We up the gc
|
||||
;; threshold to temporarily prevent it from running, then reset it later with
|
||||
;; `doom-restore-garbage-collection-h'. Not resetting it will cause
|
||||
;; stuttering/freezes.
|
||||
(setq gc-cons-threshold most-positive-fixnum)
|
||||
|
||||
;; In noninteractive sessions, prioritize non-byte-compiled source files to
|
||||
;; prevent stale, byte-compiled code from running. However, if you're getting
|
||||
;; recursive load errors, it may help to set this to nil.
|
||||
;; prevent the use of stale byte-code. Otherwise, it saves us a little IO time
|
||||
;; to skip the mtime checks on every *.elc file we load.
|
||||
(setq load-prefer-newer noninteractive)
|
||||
|
||||
|
||||
;; Let 'er rip!
|
||||
;; Load the heart of Doom Emacs
|
||||
(require 'core (concat user-emacs-directory "core/core"))
|
||||
|
||||
;; And let 'er rip!
|
||||
(add-hook 'window-setup-hook #'doom-display-benchmark-h)
|
||||
(when (cdr command-line-args)
|
||||
(add-to-list 'command-switch-alist
|
||||
(cons "--restore" #'doom-restore-session-handler)))
|
||||
|
||||
(doom-initialize)
|
||||
(doom-initialize-core)
|
||||
(doom-initialize-modules)
|
||||
|
|
|
@ -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.
|
||||
|
@ -24,7 +24,8 @@
|
|||
doom-dashboard ; a nifty splash screen for Emacs
|
||||
doom-quit ; DOOM quit-message prompts when you quit Emacs
|
||||
;;fill-column ; a `fill-column' indicator
|
||||
hl-todo ; highlight TODO/FIXME/NOTE tags
|
||||
hl-todo ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW
|
||||
;;hydra
|
||||
;;indent-guides ; highlighted indent columns
|
||||
modeline ; snazzy, Atom-inspired modeline, plus API
|
||||
nav-flash ; blink the current line after jumping
|
||||
|
@ -34,8 +35,8 @@
|
|||
+all ; catch all popups that start with an asterix
|
||||
+defaults) ; default popup rules
|
||||
;;pretty-code ; replace bits of code with pretty symbols
|
||||
;;tabbar ; FIXME an (incomplete) tab bar for Emacs
|
||||
treemacs ; a project drawer, like neotree but cooler
|
||||
;;tabs ; an tab bar for Emacs
|
||||
;;treemacs ; a project drawer, like neotree but cooler
|
||||
;;unicode ; extended unicode support for various languages
|
||||
vc-gutter ; vcs diff in the fringe
|
||||
vi-tilde-fringe ; fringe tildes to mark beyond EOB
|
||||
|
@ -53,12 +54,10 @@
|
|||
;;parinfer ; turn lisp into python, sort of
|
||||
rotate-text ; cycle region at point between text candidates
|
||||
snippets ; my elves. They type so I don't have to
|
||||
;;word-wrap ; soft wrapping with language-aware indent
|
||||
|
||||
:emacs
|
||||
(dired ; making dired pretty [functional]
|
||||
;;+ranger ; bringing the goodness of ranger to dired
|
||||
;;+icons ; colorful icons for dired-mode
|
||||
)
|
||||
dired ; making dired pretty [functional]
|
||||
electric ; smarter, keyword-based electric-indent
|
||||
vc ; version-control and Emacs, sitting in a tree
|
||||
|
||||
|
@ -162,14 +161,10 @@
|
|||
;;irc ; how neckbeards socialize
|
||||
;;(rss +org) ; emacs as an RSS reader
|
||||
;;twitter ; twitter client https://twitter.com/vnought
|
||||
;;(write ; emacs as a word processor (latex + org + markdown)
|
||||
;;(write ; emacs for writers (fiction, notes, papers, etc.)
|
||||
;; +wordnut ; wordnet (wn) search
|
||||
;; +langtool) ; a proofreader (grammar/style check) for Emacs
|
||||
|
||||
:collab
|
||||
;;floobits ; peer programming for a price
|
||||
;;impatient-mode ; show off code over HTTP
|
||||
|
||||
:config
|
||||
;; For literate config users. This will tangle+compile a config.org
|
||||
;; literate config in your `doom-private-dir' whenever it changes.
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
- [[#lang][:lang]]
|
||||
- [[#email][:email]]
|
||||
- [[#app][:app]]
|
||||
- [[#collab][:collab]]
|
||||
- [[#config][:config]]
|
||||
|
||||
* :completion
|
||||
|
@ -38,7 +37,7 @@ Aesthetic modules that affect the Emacs interface or user experience.
|
|||
+ [[file:ui/ophints/README.org][ophints]]:
|
||||
+ [[file:ui/popup/README.org][popup]] =+all +defaults=: Makes temporary/disposable windows less intrusive
|
||||
+ pretty-code:
|
||||
+ [[file:ui/tabbar/README.org][tabbar]]:
|
||||
+ [[file:ui/tabs/README.org][tabs]]:
|
||||
+ treemacs:
|
||||
+ [[file:ui/unicode/README.org][unicode]]:
|
||||
+ vc-gutter:
|
||||
|
@ -58,6 +57,7 @@ Modules that affect and augment your ability to manipulate or insert text.
|
|||
+ [[file:editor/parinfer/README.org][parinfer]]:
|
||||
+ rotate-text:
|
||||
+ [[file:editor/snippets/README.org][snippets]]: Snippet expansion for lazy typists
|
||||
+ [[file:editor/word-wrap/README.org][word-wrap]]: soft wrapping with language-aware indent
|
||||
|
||||
* :emacs
|
||||
Modules that reconfigure or augment packages or features built into Emacs.
|
||||
|
@ -80,6 +80,7 @@ Small modules that give Emacs access to external tools & services.
|
|||
+ ansible:
|
||||
+ debugger: A (nigh-)universal debugger in Emacs
|
||||
+ [[file:tools/docker/README.org][docker]]:
|
||||
+ [[file:tools/direnv/README.org][direnv]]:
|
||||
+ [[file:tools/editorconfig/README.org][editorconfig]]:
|
||||
+ [[file:tools/ein/README.org][ein]]:
|
||||
+ [[file:tools/eval/README.org][eval]]: REPL & code evaluation support for a variety of languages
|
||||
|
@ -141,7 +142,7 @@ Modules that bring support for a language or group of languages to Emacs.
|
|||
+ qt:
|
||||
+ racket:
|
||||
+ [[file:lang/rest/README.org][rest]]:
|
||||
+ ruby =+lsp=:
|
||||
+ ruby =+lsp +rvm +rbenv=:
|
||||
+ [[file:lang/rust/README.org][rust]] =+lsp=:
|
||||
+ scala:
|
||||
+ [[file:lang/sh/README.org][sh]] =+fish +lsp=:
|
||||
|
@ -166,12 +167,6 @@ Doom-specific porcelains.
|
|||
+ twitter:
|
||||
+ [[file:app/write/README.org][write]] =+wordnut +langtool=:
|
||||
|
||||
* :collab
|
||||
Modules that enable collaborative programming over the internet.
|
||||
|
||||
+ floobits:
|
||||
+ impatient-mode:
|
||||
|
||||
* :config
|
||||
Modules that configure Emacs one way or another, or focus on making it easier
|
||||
for you to customize it yourself.
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +calendar*cfw:render-button (title command &optional state)
|
||||
(defun +calendar-cfw:render-button-a (title command &optional state)
|
||||
"render-button
|
||||
TITLE
|
||||
COMMAND
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
;;
|
||||
;; Packages
|
||||
|
||||
(def-package! calfw
|
||||
:commands (cfw:open-calendar-buffer)
|
||||
(use-package! calfw
|
||||
:commands cfw:open-calendar-buffer
|
||||
:config
|
||||
;; better frame for calendar
|
||||
(setq cfw:face-item-separator-color nil
|
||||
|
@ -24,20 +24,20 @@
|
|||
|
||||
(define-key cfw:calendar-mode-map "q" #'+calendar/quit)
|
||||
|
||||
(add-hook 'cfw:calendar-mode-hook #'doom|mark-buffer-as-real)
|
||||
(add-hook 'cfw:calendar-mode-hook #'doom-mark-buffer-as-real-h)
|
||||
(add-hook 'cfw:calendar-mode-hook 'hide-mode-line-mode)
|
||||
|
||||
(advice-add #'cfw:render-button :override #'+calendar*cfw:render-button))
|
||||
(advice-add #'cfw:render-button :override #'+calendar-cfw:render-button-a))
|
||||
|
||||
|
||||
(def-package! calfw-org
|
||||
(use-package! calfw-org
|
||||
:commands (cfw:open-org-calendar
|
||||
cfw:org-create-source
|
||||
cfw:open-org-calendar-withkevin
|
||||
my-open-calendar))
|
||||
|
||||
|
||||
(def-package! org-gcal
|
||||
(use-package! org-gcal
|
||||
:commands (org-gcal-sync
|
||||
org-gcal-fetch
|
||||
org-gcal-post-at-point
|
||||
|
@ -48,4 +48,4 @@
|
|||
(message "org-gcal::%s - %s" title mes)))
|
||||
|
||||
|
||||
;; (def-package! alert)
|
||||
;; (use-package! alert)
|
||||
|
|
|
@ -97,3 +97,27 @@ argument) is non-nil only show channels in current server."
|
|||
(interactive)
|
||||
(when (derived-mode-p 'circe-mode)
|
||||
(tracking-next-buffer)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Hooks/fns
|
||||
|
||||
;;;###autoload
|
||||
(defun +circe-buffer-p (buf)
|
||||
"Return non-nil if BUF is a `circe-mode' buffer."
|
||||
(with-current-buffer buf
|
||||
(and (derived-mode-p 'circe-mode)
|
||||
(eq (safe-persp-name (get-current-persp))
|
||||
+irc--workspace-name))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +irc--add-circe-buffer-to-persp-h ()
|
||||
(when (bound-and-true-p persp-mode)
|
||||
(let ((persp (get-current-persp))
|
||||
(buf (current-buffer)))
|
||||
;; Add a new circe buffer to irc workspace when we're in another workspace
|
||||
(unless (eq (safe-persp-name persp) +irc--workspace-name)
|
||||
;; Add new circe buffers to the persp containing circe buffers
|
||||
(persp-add-buffer buf (persp-get-by-name +irc--workspace-name))
|
||||
;; Remove new buffer from accidental workspace
|
||||
(persp-remove-buffer buf persp)))))
|
||||
|
|
|
@ -46,8 +46,8 @@ playback.")
|
|||
;;
|
||||
;; Packages
|
||||
|
||||
(def-package! circe
|
||||
:commands (circe circe-server-buffers)
|
||||
(use-package! circe
|
||||
:commands circe circe-server-buffers
|
||||
:init (setq circe-network-defaults nil)
|
||||
:config
|
||||
(setq circe-default-quit-message nil
|
||||
|
@ -90,13 +90,17 @@ playback.")
|
|||
circe-format-server-lurker-activity
|
||||
(+irc--pad "Lurk" "{nick} joined {joindelta} ago"))
|
||||
|
||||
(add-hook 'doom-real-buffer-functions #'+circe-buffer-p)
|
||||
(add-hook 'circe-channel-mode-hook #'turn-on-visual-line-mode)
|
||||
(add-hook 'circe-mode-hook #'+irc--add-circe-buffer-to-persp-h)
|
||||
|
||||
(defun +irc*circe-disconnect-hook (&rest _)
|
||||
(defadvice! +irc--circe-run-disconnect-hook-a (&rest _)
|
||||
"Runs `+irc-disconnect-hook' after circe disconnects."
|
||||
:after #'circe--irc-conn-disconnected
|
||||
(run-hooks '+irc-disconnect-hook))
|
||||
(advice-add 'circe--irc-conn-disconnected :after #'+irc*circe-disconnect-hook)
|
||||
|
||||
(defun +irc*circe-truncate-nicks ()
|
||||
(add-hook! 'lui-pre-output-hook
|
||||
(defun +irc-circe-truncate-nicks-h ()
|
||||
"Truncate long nicknames in chat output non-destructively."
|
||||
(when-let (beg (text-property-any (point-min) (point-max) 'lui-format-argument 'nick))
|
||||
(goto-char beg)
|
||||
|
@ -105,33 +109,13 @@ playback.")
|
|||
:nick)))
|
||||
(when (> (length nick) +irc-left-padding)
|
||||
(compose-region (+ beg +irc-left-padding -1) end
|
||||
+irc-truncate-nick-char)))))
|
||||
(add-hook 'lui-pre-output-hook #'+irc*circe-truncate-nicks)
|
||||
+irc-truncate-nick-char))))))
|
||||
|
||||
(defun +circe-buffer-p (buf)
|
||||
"Return non-nil if BUF is a `circe-mode' buffer."
|
||||
(with-current-buffer buf
|
||||
(and (derived-mode-p 'circe-mode)
|
||||
(eq (safe-persp-name (get-current-persp))
|
||||
+irc--workspace-name))))
|
||||
(add-hook 'doom-real-buffer-functions #'+circe-buffer-p)
|
||||
|
||||
(defun +irc|circe-message-option-bot (nick &rest ignored)
|
||||
(add-hook! 'circe-message-option-functions
|
||||
(defun +irc-circe-message-option-bot-h (nick &rest ignored)
|
||||
"Fontify known bots and mark them to not be tracked."
|
||||
(when (member nick +irc-bot-list)
|
||||
'((text-properties . (face circe-fool-face lui-do-not-track t)))))
|
||||
(add-hook 'circe-message-option-functions #'+irc|circe-message-option-bot)
|
||||
|
||||
(defun +irc|add-circe-buffer-to-persp ()
|
||||
(let ((persp (get-current-persp))
|
||||
(buf (current-buffer)))
|
||||
;; Add a new circe buffer to irc workspace when we're in another workspace
|
||||
(unless (eq (safe-persp-name persp) +irc--workspace-name)
|
||||
;; Add new circe buffers to the persp containing circe buffers
|
||||
(persp-add-buffer buf (persp-get-by-name +irc--workspace-name))
|
||||
;; Remove new buffer from accidental workspace
|
||||
(persp-remove-buffer buf persp))))
|
||||
(add-hook 'circe-mode-hook #'+irc|add-circe-buffer-to-persp)
|
||||
'((text-properties . (face circe-fool-face lui-do-not-track t))))))
|
||||
|
||||
;; Let `+irc/quit' and `circe' handle buffer cleanup
|
||||
(define-key circe-mode-map [remap kill-buffer] #'bury-buffer)
|
||||
|
@ -152,14 +136,14 @@ playback.")
|
|||
"n" #'circe-command-NAMES)))
|
||||
|
||||
|
||||
(def-package! circe-color-nicks
|
||||
(use-package! circe-color-nicks
|
||||
:hook (circe-channel-mode . enable-circe-color-nicks)
|
||||
:config
|
||||
(setq circe-color-nicks-min-constrast-ratio 4.5
|
||||
circe-color-nicks-everywhere t))
|
||||
|
||||
|
||||
(def-package! circe-new-day-notifier
|
||||
(use-package! circe-new-day-notifier
|
||||
:after circe
|
||||
:config
|
||||
(enable-circe-new-day-notifier)
|
||||
|
@ -167,7 +151,7 @@ playback.")
|
|||
(+irc--pad "Day" "Date changed [{day}]")))
|
||||
|
||||
|
||||
(def-package! circe-notifications
|
||||
(use-package! circe-notifications
|
||||
:commands enable-circe-notifications
|
||||
:init
|
||||
(if +irc-defer-notifications
|
||||
|
@ -181,10 +165,11 @@ playback.")
|
|||
circe-notifications-emacs-focused nil
|
||||
circe-notifications-alert-style
|
||||
(cond (IS-MAC 'osx-notifier)
|
||||
(IS-LINUX 'libnotify))))
|
||||
(IS-LINUX 'libnotify)
|
||||
(circe-notifications-alert-style))))
|
||||
|
||||
|
||||
(def-package! lui
|
||||
(use-package! lui
|
||||
:commands lui-mode
|
||||
:config
|
||||
(define-key lui-mode-map "\C-u" #'lui-kill-to-beginning-of-line)
|
||||
|
@ -194,20 +179,21 @@ playback.")
|
|||
(setq lui-flyspell-p t))
|
||||
|
||||
(after! evil
|
||||
(defun +irc|evil-insert ()
|
||||
(defun +irc-evil-insert-h ()
|
||||
"Ensure entering insert mode will put us at the prompt, unless editing
|
||||
after prompt marker."
|
||||
(when (> (marker-position lui-input-marker) (point))
|
||||
(goto-char (point-max))))
|
||||
|
||||
(add-hook! 'lui-mode-hook
|
||||
(add-hook 'evil-insert-state-entry-hook #'+irc|evil-insert nil t))
|
||||
(add-hook 'evil-insert-state-entry-hook #'+irc-evil-insert-h
|
||||
nil 'local))
|
||||
|
||||
(mapc (lambda (cmd) (push cmd +irc-scroll-to-bottom-on-commands))
|
||||
'(evil-paste-after evil-paste-before evil-open-above evil-open-below)))
|
||||
|
||||
|
||||
(defun +irc|preinput-scroll-to-bottom ()
|
||||
(defun +irc-preinput-scroll-to-bottom-h ()
|
||||
"Go to the end of the buffer in all windows showing it.
|
||||
Courtesy of esh-mode.el"
|
||||
(when (memq this-command +irc-scroll-to-bottom-on-commands)
|
||||
|
@ -224,28 +210,26 @@ Courtesy of esh-mode.el"
|
|||
nil t)))))
|
||||
|
||||
(add-hook! 'lui-mode-hook
|
||||
(add-hook 'pre-command-hook #'+irc|preinput-scroll-to-bottom nil t))
|
||||
(add-hook 'pre-command-hook #'+irc-preinput-scroll-to-bottom-h nil t))
|
||||
|
||||
;; enable a horizontal line marking the last read message
|
||||
(add-hook! 'lui-mode-hook #'enable-lui-track-bar)
|
||||
(add-hook 'lui-mode-hook #'enable-lui-track-bar)
|
||||
|
||||
(defun +irc|init-lui-margins ()
|
||||
(add-hook! 'lui-mode-hook
|
||||
(defun +irc-init-lui-margins-h ()
|
||||
(setq lui-time-stamp-position 'right-margin
|
||||
lui-time-stamp-format +irc-time-stamp-format
|
||||
right-margin-width (length (format-time-string lui-time-stamp-format))))
|
||||
|
||||
(defun +irc|init-lui-wrapping ()
|
||||
(defun +irc-init-lui-wrapping-a ()
|
||||
(setq fringes-outside-margins t
|
||||
word-wrap t
|
||||
wrap-prefix (make-string (+ +irc-left-padding 3) ? )))
|
||||
|
||||
(add-hook! 'lui-mode-hook #'(+irc|init-lui-margins +irc|init-lui-wrapping)))
|
||||
wrap-prefix (make-string (+ +irc-left-padding 3) ? )))))
|
||||
|
||||
|
||||
(def-package! lui-logging
|
||||
(use-package! lui-logging
|
||||
:after lui
|
||||
:config (enable-lui-logging))
|
||||
|
||||
|
||||
(def-package! lui-autopaste
|
||||
(use-package! lui-autopaste
|
||||
:hook (circe-channel-mode . enable-lui-autopaste))
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
;; Hooks
|
||||
|
||||
;;;###autoload
|
||||
(defun +rss|elfeed-wrap ()
|
||||
(defun +rss-elfeed-wrap-h ()
|
||||
"Enhances an elfeed entry's readability by wrapping it to a width of
|
||||
`fill-column'."
|
||||
(let ((inhibit-read-only t)
|
||||
|
@ -57,7 +57,7 @@
|
|||
(set-buffer-modified-p nil)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +rss|cleanup ()
|
||||
(defun +rss-cleanup-h ()
|
||||
"Clean up after an elfeed session. Kills all elfeed and elfeed-org files."
|
||||
(interactive)
|
||||
;; `delete-file-projectile-remove-from-cache' slows down `elfeed-db-compact'
|
||||
|
@ -75,7 +75,7 @@
|
|||
(kill-buffer buf)))
|
||||
(dolist (b search-buffers)
|
||||
(with-current-buffer b
|
||||
(remove-hook 'kill-buffer-hook #'+rss|cleanup :local)
|
||||
(remove-hook 'kill-buffer-hook #'+rss-cleanup-h :local)
|
||||
(kill-buffer b)))
|
||||
(mapc #'kill-buffer show-buffers)))
|
||||
|
||||
|
@ -99,7 +99,7 @@
|
|||
collect url)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +rss-put-sliced-image (spec alt &optional flags)
|
||||
(defun +rss-put-sliced-image-fn (spec alt &optional flags)
|
||||
"TODO"
|
||||
(cl-letf (((symbol-function #'insert-image)
|
||||
(lambda (image &optional alt _area _slice)
|
||||
|
@ -108,7 +108,7 @@
|
|||
(shr-put-image spec alt flags)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +rss-render-image-tag-without-underline (dom &optional url)
|
||||
(defun +rss-render-image-tag-without-underline-fn (dom &optional url)
|
||||
"TODO"
|
||||
(let ((start (point)))
|
||||
(shr-tag-img dom url)
|
||||
|
|
|
@ -19,7 +19,7 @@ easier to scroll through.")
|
|||
;;
|
||||
;; Packages
|
||||
|
||||
(def-package! elfeed
|
||||
(use-package! elfeed
|
||||
:commands elfeed
|
||||
:config
|
||||
(setq elfeed-search-filter "@2-week-ago "
|
||||
|
@ -36,21 +36,21 @@ easier to scroll through.")
|
|||
(make-directory elfeed-db-directory t)
|
||||
|
||||
;; Ensure elfeed buffers are treated as real
|
||||
(add-hook! 'doom-real-buffer-functions
|
||||
(defun +rss-buffer-p (buf)
|
||||
(string-match-p "^\\*elfeed" (buffer-name buf)))
|
||||
(add-to-list 'doom-real-buffer-functions #'+rss-buffer-p nil #'eq)
|
||||
(string-match-p "^\\*elfeed" (buffer-name buf))))
|
||||
|
||||
;; Enhance readability of a post
|
||||
(add-hook 'elfeed-show-mode-hook #'+rss|elfeed-wrap)
|
||||
(add-hook 'elfeed-show-mode-hook #'+rss-elfeed-wrap-h)
|
||||
(add-hook! 'elfeed-search-mode-hook
|
||||
(add-hook 'kill-buffer-hook #'+rss|cleanup nil t))
|
||||
(add-hook 'kill-buffer-hook #'+rss-cleanup-h nil 'local))
|
||||
|
||||
;; Large images are annoying to scroll through, because scrolling follows the
|
||||
;; cursor, so we force shr to insert images in slices.
|
||||
(when +rss-enable-sliced-images
|
||||
(setq-hook! 'elfeed-show-mode-hook
|
||||
shr-put-image-function #'+rss-put-sliced-image
|
||||
shr-external-rendering-functions '((img . +rss-render-image-tag-without-underline))))
|
||||
shr-put-image-function #'+rss-put-sliced-image-fn
|
||||
shr-external-rendering-functions '((img . +rss-render-image-tag-without-underline-fn))))
|
||||
|
||||
;; Keybindings
|
||||
(after! elfeed-show
|
||||
|
@ -64,11 +64,11 @@ easier to scroll through.")
|
|||
(kbd "M-RET") #'elfeed-search-browse-url)))
|
||||
|
||||
|
||||
(def-package! elfeed-org
|
||||
(use-package! elfeed-org
|
||||
:when (featurep! +org)
|
||||
:after elfeed
|
||||
:config
|
||||
(setq rmh-elfeed-org-files
|
||||
(let ((default-directory org-directory))
|
||||
(setq rmh-elfeed-org-files
|
||||
(mapcar #'expand-file-name +rss-elfeed-files)))
|
||||
(elfeed-org))
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"The name to use for the twitter workspace.")
|
||||
|
||||
;;;###autoload
|
||||
(defun +twitter-display-buffer (buf)
|
||||
(defun +twitter-display-buffer-fn (buf)
|
||||
"A replacement display-buffer command for `twittering-pop-to-buffer-function'
|
||||
that works with the feature/popup module."
|
||||
(let ((win (selected-window)))
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
;;; app/twitter/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(def-package! twittering-mode
|
||||
(use-package! twittering-mode
|
||||
:commands twit
|
||||
:config
|
||||
(setq twittering-private-info-file (expand-file-name "twittering-mode.gpg" doom-etc-dir)
|
||||
(setq twittering-private-info-file
|
||||
(expand-file-name "twittering-mode.gpg" doom-etc-dir)
|
||||
twittering-use-master-password t
|
||||
twittering-request-confirmation-on-posting t
|
||||
;; twittering-icon-mode t
|
||||
|
@ -35,24 +36,16 @@
|
|||
|
||||
(add-hook 'doom-real-buffer-functions #'+twitter-buffer-p)
|
||||
(when (featurep! :ui popup)
|
||||
(setq twittering-pop-to-buffer-function #'+twitter-display-buffer))
|
||||
(setq twittering-pop-to-buffer-function #'+twitter-display-buffer-fn))
|
||||
|
||||
(after! solaire-mode
|
||||
(add-hook 'twittering-mode-hook #'solaire-mode))
|
||||
|
||||
;; Custom header-line for twitter buffers
|
||||
(defun +twitter|switch-mode-and-header-line ()
|
||||
(add-hook! 'twittering-mode-hook
|
||||
(defun +twitter-switch-mode-and-header-line-h ()
|
||||
(setq header-line-format mode-line-format
|
||||
mode-line-format nil))
|
||||
(add-hook 'twittering-mode-hook #'+twitter|switch-mode-and-header-line)
|
||||
|
||||
(cond ((featurep! :ui doom-modeline +new)
|
||||
(setq-hook! 'twittering-mode-hook mode-line-format-right nil))
|
||||
((featurep! :ui doom-modeline)
|
||||
(def-modeline! 'twitter
|
||||
'(bar matches " %b " selection-info)
|
||||
'())
|
||||
(add-hook! 'twittering-mode-hook (doom-set-modeline 'twitter))))
|
||||
mode-line-format nil)))
|
||||
|
||||
;; `epa--decode-coding-string' isn't defined in later versions of Emacs 27
|
||||
(unless (fboundp 'epa--decode-coding-string)
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
;;
|
||||
;; Packages
|
||||
|
||||
(def-package! langtool
|
||||
(use-package! langtool
|
||||
:when (featurep! +langtool)
|
||||
:commands (langtool-check
|
||||
langtool-check-done
|
||||
|
@ -23,7 +23,7 @@
|
|||
(locate-file "libexec/languagetool-commandline.jar"
|
||||
(doom-files-in "/usr/local/Cellar/languagetool"
|
||||
:type 'dirs
|
||||
:depth 1)))
|
||||
:depth 2)))
|
||||
(IS-LINUX
|
||||
"/usr/share/java/languagetool/languagetool-commandline.jar")))))
|
||||
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
;; -*- no-byte-compile: t; -*-
|
||||
;;; collab/foobits/packages.el
|
||||
|
||||
(package! floobits)
|
|
@ -1,24 +0,0 @@
|
|||
;;; collab/impatient-mode/autoload.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defun +impatient-mode/toggle ()
|
||||
"Toggle `impatient-mode' in the current buffer."
|
||||
(interactive)
|
||||
(unless (process-status "httpd")
|
||||
(httpd-start))
|
||||
(impatient-mode)
|
||||
(if impatient-mode
|
||||
(add-hook 'kill-buffer-hook '+impatient-mode--cleanup-impatient-mode)
|
||||
(+impatient-mode--cleanup-impatient-mode)))
|
||||
|
||||
(defun +impatient-mode--cleanup-impatient-mode ()
|
||||
(unless (cl-loop for buf in (doom-buffer-list)
|
||||
if (buffer-local-value 'impatient-mode buf)
|
||||
return t)
|
||||
(httpd-stop)
|
||||
(cl-loop for buf in (doom-buffer-list)
|
||||
if (buffer-local-value 'impatient-mode buf)
|
||||
do
|
||||
(with-current-buffer buf
|
||||
(impatient-mode -1)))
|
||||
(remove-hook 'kill-buffer-hook '+impatient-mode--cleanup-impatient-mode)))
|
|
@ -1,5 +0,0 @@
|
|||
;; -*- no-byte-compile: t; -*-
|
||||
;;; collab/impatient-mode/packages.el
|
||||
|
||||
(package! htmlize)
|
||||
(package! impatient-mode)
|
|
@ -65,15 +65,15 @@ Examples:
|
|||
;;; Hooks
|
||||
|
||||
;;;###autoload
|
||||
(defun +company|init-backends ()
|
||||
(defun +company-init-backends-h ()
|
||||
"Set `company-backends' for the current buffer."
|
||||
(if (not company-mode)
|
||||
(remove-hook 'change-major-mode-after-body-hook #'+company|init-backends 'local)
|
||||
(remove-hook 'change-major-mode-after-body-hook #'+company-init-backends-h 'local)
|
||||
(unless (eq major-mode 'fundamental-mode)
|
||||
(setq-local company-backends (+company--backends)))
|
||||
(add-hook 'change-major-mode-after-body-hook #'+company|init-backends nil 'local)))
|
||||
(add-hook 'change-major-mode-after-body-hook #'+company-init-backends-h nil 'local)))
|
||||
|
||||
(put '+company|init-backends 'permanent-local-hook t)
|
||||
(put '+company-init-backends-h 'permanent-local-hook t)
|
||||
|
||||
|
||||
;;
|
||||
|
@ -129,12 +129,13 @@ C-x C-l."
|
|||
(`candidates
|
||||
(all-completions
|
||||
arg
|
||||
(delete-dups
|
||||
(split-string
|
||||
(replace-regexp-in-string
|
||||
"^[\t\s]+" ""
|
||||
(concat (buffer-substring-no-properties (point-min) (line-beginning-position))
|
||||
(buffer-substring-no-properties (line-end-position) (point-max))))
|
||||
"\\(\r\n\\|[\n\r]\\)" t)))))
|
||||
"\\(\r\n\\|[\n\r]\\)" t))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +company/dict-or-keywords ()
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
;;; completion/company/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(def-package! company
|
||||
:commands (company-complete-common company-manual-begin company-grab-line)
|
||||
:after-call (evil-insert-state-entry-hook evil-emacs-state-entry-hook)
|
||||
(use-package! company
|
||||
:commands company-complete-common company-manual-begin company-grab-line
|
||||
:after-call evil-insert-state-entry-hook evil-emacs-state-entry-hook
|
||||
:init
|
||||
(setq company-minimum-prefix-length 2
|
||||
company-tooltip-limit 14
|
||||
|
@ -27,16 +27,16 @@
|
|||
;; Allow users to switch between backends on the fly. E.g. C-x C-s followed
|
||||
;; by C-x C-n, will switch from `company-yasnippet' to
|
||||
;; `company-dabbrev-code'.
|
||||
(defun +company*abort-previous (&rest _) (company-abort))
|
||||
(advice-add #'company-begin-backend :before #'+company*abort-previous))
|
||||
(defadvice! +company--abort-previous-a (&rest _)
|
||||
:before #'company-begin-backend
|
||||
(company-abort)))
|
||||
|
||||
(add-hook 'company-mode-hook #'+company|init-backends)
|
||||
(add-hook 'company-mode-hook #'+company-init-backends-h)
|
||||
(global-company-mode +1))
|
||||
|
||||
|
||||
(def-package! company-tng
|
||||
(use-package! company-tng
|
||||
:when (featurep! +tng)
|
||||
:defer 2
|
||||
:after-call post-self-insert-hook
|
||||
:config
|
||||
(add-to-list 'company-frontends 'company-tng-frontend)
|
||||
|
@ -51,7 +51,7 @@
|
|||
;;
|
||||
;; Packages
|
||||
|
||||
(def-package! company-prescient
|
||||
(use-package! company-prescient
|
||||
:hook (company-mode . company-prescient-mode)
|
||||
:config
|
||||
;; NOTE prescient config duplicated with `ivy'
|
||||
|
@ -59,7 +59,7 @@
|
|||
(prescient-persist-mode +1))
|
||||
|
||||
|
||||
(def-package! company-box
|
||||
(use-package! company-box
|
||||
:when (and EMACS26+ (featurep! +childframe))
|
||||
:hook (company-mode . company-box-mode)
|
||||
:config
|
||||
|
@ -68,7 +68,10 @@
|
|||
company-box-max-candidates 50
|
||||
company-box-icons-alist 'company-box-icons-all-the-icons
|
||||
company-box-icons-functions
|
||||
'(+company-box-icons--yasnippet company-box-icons--lsp +company-box-icons--elisp company-box-icons--acphp)
|
||||
'(+company-box-icons--yasnippet-fn
|
||||
company-box-icons--lsp
|
||||
+company-box-icons--elisp-fn
|
||||
company-box-icons--acphp)
|
||||
company-box-icons-all-the-icons
|
||||
`((Unknown . ,(all-the-icons-material "find_in_page" :height 0.8 :face 'all-the-icons-purple))
|
||||
(Text . ,(all-the-icons-material "text_fields" :height 0.8 :face 'all-the-icons-green))
|
||||
|
@ -103,11 +106,11 @@
|
|||
(ElispFeature . ,(all-the-icons-material "stars" :height 0.8 :face 'all-the-icons-orange))
|
||||
(ElispFace . ,(all-the-icons-material "format_paint" :height 0.8 :face 'all-the-icons-pink))))
|
||||
|
||||
(defun +company-box-icons--yasnippet (candidate)
|
||||
(defun +company-box-icons--yasnippet-fn (candidate)
|
||||
(when (get-text-property 0 'yas-annotation candidate)
|
||||
'Yasnippet))
|
||||
|
||||
(defun +company-box-icons--elisp (candidate)
|
||||
(defun +company-box-icons--elisp-fn (candidate)
|
||||
(when (derived-mode-p 'emacs-lisp-mode)
|
||||
(let ((sym (intern candidate)))
|
||||
(cond ((fboundp sym) 'ElispFunction)
|
||||
|
@ -116,14 +119,13 @@
|
|||
((facep sym) 'ElispFace))))))
|
||||
|
||||
|
||||
(def-package! company-dict
|
||||
(use-package! company-dict
|
||||
:defer t
|
||||
:config
|
||||
(setq company-dict-dir (expand-file-name "dicts" doom-private-dir))
|
||||
(defun +company|enable-project-dicts (mode &rest _)
|
||||
(add-hook! 'doom-project-hook
|
||||
(defun +company-enable-project-dicts-h (mode &rest _)
|
||||
"Enable per-project dictionaries."
|
||||
(if (symbol-value mode)
|
||||
(add-to-list 'company-dict-minor-mode-list mode nil #'eq)
|
||||
(setq company-dict-minor-mode-list (delq mode company-dict-minor-mode-list))))
|
||||
(add-hook 'doom-project-hook #'+company|enable-project-dicts))
|
||||
|
||||
(setq company-dict-minor-mode-list (delq mode company-dict-minor-mode-list))))))
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
;;; completion/helm/autoload/posframe.el -*- lexical-binding: t; -*-
|
||||
|
||||
(add-hook 'helm-cleanup-hook #'+helm|posframe-cleanup)
|
||||
|
||||
;;;###autoload
|
||||
(defun +helm-poshandler-frame-center-near-bottom (info)
|
||||
(defun +helm-poshandler-frame-center-near-bottom-fn (info)
|
||||
"Display the child frame in the center of the frame, slightly closer to the
|
||||
bottom, which is easier on the eyes on big displays."
|
||||
(let ((parent-frame (plist-get info :parent-frame))
|
||||
|
@ -14,7 +12,7 @@ bottom, which is easier on the eyes on big displays."
|
|||
|
||||
(defvar +helm--posframe-buffer nil)
|
||||
;;;###autoload
|
||||
(defun +helm-posframe-display (buffer &optional _resume)
|
||||
(defun +helm-posframe-display-fn (buffer &optional _resume)
|
||||
"TODO"
|
||||
(setq helm--buffer-in-new-frame-p t)
|
||||
(let ((solaire-p (bound-and-true-p solaire-mode))
|
||||
|
@ -52,15 +50,10 @@ bottom, which is easier on the eyes on big displays."
|
|||
(text-scale-set +helm-posframe-text-scale)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +helm|posframe-cleanup ()
|
||||
(defun +helm-posframe-cleanup-h ()
|
||||
"TODO"
|
||||
;; Ensure focus is properly returned to the underlying window, by forcing a
|
||||
;; chance in buffer/window focus. This gives the modeline a chance to refresh.
|
||||
(switch-to-buffer +helm--posframe-buffer t)
|
||||
;;
|
||||
(posframe-delete +helm--posframe-buffer))
|
||||
;; Ensure focus is properly returned to the underlying window. This gives the
|
||||
;; modeline a chance to refresh.
|
||||
(switch-to-buffer +helm--posframe-buffer t))
|
||||
|
||||
|
||||
;;;###autoload
|
||||
(defun +helm*fix-get-font-height (orig-fn position)
|
||||
(ignore-errors (funcall orig-fn position)))
|
||||
(add-hook 'helm-cleanup-hook #'+helm-posframe-cleanup-h)
|
||||
|
|
|
@ -11,8 +11,7 @@ silently ignored.
|
|||
This falls back to git-grep (then grep) if none of these available.")
|
||||
|
||||
;; Posframe (requires +childframe)
|
||||
(defvar +helm-posframe-handler
|
||||
#'+helm-poshandler-frame-center-near-bottom
|
||||
(defvar +helm-posframe-handler #'+helm-poshandler-frame-center-near-bottom-fn
|
||||
"The function that determines the location of the childframe. It should return
|
||||
a cons cell representing the X and Y coordinates. See
|
||||
`posframe-poshandler-frame-center' as a reference.")
|
||||
|
@ -33,7 +32,7 @@ be negative.")
|
|||
;;
|
||||
;;; Packages
|
||||
|
||||
(def-package! helm-mode
|
||||
(use-package! helm-mode
|
||||
:defer t
|
||||
:after-call pre-command-hook
|
||||
:init
|
||||
|
@ -58,7 +57,7 @@ be negative.")
|
|||
(add-to-list 'helm-completing-read-handlers-alist (cons #'find-file-at-point nil)))
|
||||
|
||||
|
||||
(def-package! helm
|
||||
(use-package! helm
|
||||
:after helm-mode
|
||||
:preface
|
||||
(setq helm-candidate-number-limit 50
|
||||
|
@ -83,9 +82,7 @@ be negative.")
|
|||
|
||||
:init
|
||||
(when (and EMACS26+ (featurep! +childframe))
|
||||
(setq helm-display-function #'+helm-posframe-display)
|
||||
;; Fix "Specified window is not displaying the current buffer" error
|
||||
(advice-add #'posframe--get-font-height :around #'+helm*fix-get-font-height))
|
||||
(setq helm-display-function #'+helm-posframe-display-fn))
|
||||
|
||||
(let ((fuzzy (featurep! +fuzzy)))
|
||||
(setq helm-M-x-fuzzy-match fuzzy
|
||||
|
@ -110,27 +107,28 @@ be negative.")
|
|||
:config
|
||||
(set-popup-rule! "^\\*helm" :vslot -100 :size 0.22 :ttl nil)
|
||||
|
||||
;; HACK Doom doesn't support these commands, which invite the user to install
|
||||
;; the package via ELPA. Force them to use +helm/* instead, because they work
|
||||
;; out of the box.
|
||||
(advice-add #'helm-projectile-rg :override #'+helm/rg)
|
||||
(advice-add #'helm-projectile-ag :override #'+helm/ag)
|
||||
(advice-add #'helm-projectile-grep :override #'+helm/grep)
|
||||
|
||||
;; Hide the modeline
|
||||
(defun +helm|hide-mode-line (&rest _)
|
||||
(defun +helm--hide-mode-line (&rest _)
|
||||
(with-current-buffer (helm-buffer-get)
|
||||
(unless helm-mode-line-string
|
||||
(hide-mode-line-mode +1))))
|
||||
(add-hook 'helm-after-initialize-hook #'+helm|hide-mode-line)
|
||||
(advice-add #'helm-display-mode-line :override #'+helm|hide-mode-line)
|
||||
(add-hook 'helm-after-initialize-hook #'+helm--hide-mode-line)
|
||||
(advice-add #'helm-display-mode-line :override #'+helm--hide-mode-line)
|
||||
(advice-add #'helm-ag-show-status-default-mode-line :override #'ignore)
|
||||
|
||||
;; TODO Find a better way
|
||||
(defun +helm*use-helpful (orig-fn arg)
|
||||
(cl-letf (((symbol-function #'describe-function)
|
||||
(symbol-function #'helpful-callable))
|
||||
((symbol-function #'describe-variable)
|
||||
(symbol-function #'helpful-variable)))
|
||||
(funcall orig-fn arg)))
|
||||
(advice-add #'helm-describe-variable :around #'+helm*use-helpful)
|
||||
(advice-add #'helm-describe-function :around #'+helm*use-helpful))
|
||||
;; Use helpful instead of describe-* to display documentation
|
||||
(dolist (fn '(helm-describe-variable helm-describe-function))
|
||||
(advice-add fn :around #'doom-use-helpful-a)))
|
||||
|
||||
|
||||
(def-package! helm-flx
|
||||
(use-package! helm-flx
|
||||
:when (featurep! +fuzzy)
|
||||
:hook (helm-mode . helm-flx-mode)
|
||||
:config (helm-flx-mode +1))
|
||||
|
@ -142,9 +140,9 @@ be negative.")
|
|||
(define-key helm-ag-edit-map [remap quit-window] #'helm-ag--edit-abort)
|
||||
(set-popup-rule! "^\\*helm-ag-edit" :size 0.35 :ttl 0 :quit nil)
|
||||
;; Recenter after jumping to match
|
||||
(advice-add #'helm-ag--find-file-action :after-while #'doom*recenter)
|
||||
(advice-add #'helm-ag--find-file-action :after-while #'doom-recenter-a)
|
||||
;; And record position before jumping
|
||||
(advice-add #'helm-ag--find-file-action :around #'doom*set-jump-maybe))
|
||||
(advice-add #'helm-ag--find-file-action :around #'doom-set-jump-maybe-a))
|
||||
|
||||
|
||||
;;;###package helm-bookmark
|
||||
|
@ -164,7 +162,7 @@ be negative.")
|
|||
|
||||
|
||||
;;;###package helm-projectile
|
||||
(def-package! helm-projectile
|
||||
(use-package! helm-projectile
|
||||
:commands (helm-projectile-find-file
|
||||
helm-projectile-recentf
|
||||
helm-projectile-switch-project
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
;;; completion/ido/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defun +ido|init ()
|
||||
(defun +ido-init-h ()
|
||||
(setq ido-ignore-buffers
|
||||
'("\\` " "^\\*ESS\\*" "^\\*Messages\\*" "^\\*Help\\*" "^\\*Buffer"
|
||||
"^\\*.*Completions\\*$" "^\\*Ediff" "^\\*tramp" "^\\*cvs-"
|
||||
|
@ -28,8 +28,9 @@
|
|||
(insert "~/")
|
||||
(call-interactively #'self-insert-command))))
|
||||
|
||||
(defun +ido*sort-mtime ()
|
||||
(defadvice! +ido--sort-mtime-a ()
|
||||
"Sort ido filelist by mtime instead of alphabetically."
|
||||
:override #'ido-sort-mtime
|
||||
(setq ido-temp-list
|
||||
(sort ido-temp-list
|
||||
(lambda (a b)
|
||||
|
@ -40,8 +41,8 @@
|
|||
(cl-loop for x in ido-temp-list
|
||||
if (char-equal (string-to-char x) ?.)
|
||||
collect x)))
|
||||
(advice-add #'ido-sort-mtime :override #'+ido*sort-mtime)
|
||||
(add-hook! (ido-make-file-list ido-make-dir-list) #'+ido*sort-mtime)
|
||||
(add-hook! '(ido-make-file-list-hook ido-make-dir-list-hook)
|
||||
#'ido-sort-mtime)
|
||||
|
||||
;;
|
||||
(ido-mode 1)
|
||||
|
@ -52,7 +53,7 @@
|
|||
(crm-custom-mode +1)
|
||||
|
||||
;;
|
||||
(remove-hook 'ido-setup-hook #'+ido|init))
|
||||
(remove-hook 'ido-setup-hook #'+ido-init-h))
|
||||
|
||||
;;
|
||||
(add-hook 'ido-setup-hook #'+ido|init)
|
||||
(add-hook 'ido-setup-hook #'+ido-init-h)
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
;;; completion/ivy/autoload/hydras.el -*- lexical-binding: t; -*-
|
||||
;;;###if (featurep! :ui hydra)
|
||||
|
||||
;;;###autoload
|
||||
(after! ivy-hydra
|
||||
(with-no-warnings
|
||||
(defhydra+ hydra-ivy (:hint nil :color pink)
|
||||
(eval-when-compile (require 'ivy-hydra))
|
||||
|
||||
;;;###autoload (autoload 'hydra-ivy/body "completion/ivy/autoload/hydras" nil nil)
|
||||
(defhydra+ hydra-ivy (:hint nil :color pink)
|
||||
"
|
||||
Move ^^^^^^^^^^ | Call ^^^^ | Cancel^^ | Options^^ | Action _w_/_s_/_a_: %s(ivy-action-name)
|
||||
----------^^^^^^^^^^-+--------------^^^^-+-------^^-+--------^^-+---------------------------------
|
||||
|
@ -29,4 +30,4 @@
|
|||
("c" ivy-toggle-calling)
|
||||
("m" ivy-toggle-fuzzy)
|
||||
("t" (setq truncate-lines (not truncate-lines)))
|
||||
("o" ivy-occur :exit t))))
|
||||
("o" ivy-occur :exit t))
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
;;;###if (featurep! +childframe)
|
||||
|
||||
;;;###autoload
|
||||
(defun +ivy-display-at-frame-center-near-bottom (str)
|
||||
(defun +ivy-display-at-frame-center-near-bottom-fn (str)
|
||||
"TODO"
|
||||
(ivy-posframe--display str #'+ivy-poshandler-frame-center-near-bottom))
|
||||
(ivy-posframe--display str #'+ivy-poshandler-frame-center-near-bottom-fn))
|
||||
|
||||
;;;###autoload
|
||||
(defun +ivy-poshandler-frame-center-near-bottom (info)
|
||||
(defun +ivy-poshandler-frame-center-near-bottom-fn (info)
|
||||
"TODO"
|
||||
(let ((parent-frame (plist-get info :parent-frame))
|
||||
(pos (posframe-poshandler-frame-center info)))
|
||||
|
|
|
@ -43,7 +43,7 @@ immediately runs it on the current candidate (ending the ivy session)."
|
|||
;;
|
||||
;;; Packages
|
||||
|
||||
(def-package! ivy
|
||||
(use-package! ivy
|
||||
:defer 1
|
||||
:after-call pre-command-hook
|
||||
:init
|
||||
|
@ -75,31 +75,57 @@ immediately runs it on the current candidate (ending the ivy session)."
|
|||
;; enable ability to select prompt (alternative to `ivy-immediate-done')
|
||||
ivy-use-selectable-prompt t)
|
||||
|
||||
;; REVIEW Move this somewhere else and perhaps generalize this so both
|
||||
;; ivy/helm users can enjoy it.
|
||||
(defadvice! +ivy--counsel-file-jump-use-fd-rg-a (args)
|
||||
"Change `counsel-file-jump' to use fd or ripgrep, if they are available."
|
||||
:override #'counsel--find-return-list
|
||||
(cl-destructuring-bind (find-program . args)
|
||||
(cond ((executable-find "fd")
|
||||
(cons "fd" (list "-t" "f" "-E" ".git")))
|
||||
((executable-find "rg")
|
||||
(cons "rg" (list "--files" "--hidden" "--no-messages")))
|
||||
((cons find-program args)))
|
||||
(unless (listp args)
|
||||
(user-error "`counsel-file-jump-args' is a list now, please customize accordingly."))
|
||||
(counsel--call
|
||||
(cons find-program args)
|
||||
(lambda ()
|
||||
(goto-char (point-min))
|
||||
(let ((offset (if (member find-program '("fd" "rg")) 0 2))
|
||||
files)
|
||||
(while (< (point) (point-max))
|
||||
(push (buffer-substring
|
||||
(+ offset (line-beginning-position)) (line-end-position)) files)
|
||||
(forward-line 1))
|
||||
(nreverse files))))))
|
||||
|
||||
;; Ensure a jump point is registered before jumping to new locations with ivy
|
||||
(defvar +ivy--origin nil)
|
||||
|
||||
(defun +ivy|record-position-maybe ()
|
||||
(defun +ivy--record-position-maybe-fn ()
|
||||
(with-ivy-window
|
||||
(setq +ivy--origin (point-marker))))
|
||||
(setq ivy-hooks-alist '((t . +ivy|record-position-maybe)))
|
||||
(setq ivy-hooks-alist '((t . +ivy--record-position-maybe-fn)))
|
||||
|
||||
(defun +ivy|set-jump-point-maybe ()
|
||||
(add-hook! 'minibuffer-exit-hook
|
||||
(defun +ivy--set-jump-point-maybe-h ()
|
||||
(with-demoted-errors "Ivy error: %s"
|
||||
(when (and (markerp +ivy--origin)
|
||||
(not (equal (with-ivy-window (point-marker)) +ivy--origin)))
|
||||
(not (equal (with-ivy-window (point-marker))
|
||||
+ivy--origin)))
|
||||
(with-current-buffer (marker-buffer +ivy--origin)
|
||||
(better-jumper-set-jump +ivy--origin)))
|
||||
(setq +ivy--origin nil))
|
||||
(add-hook 'minibuffer-exit-hook #'+ivy|set-jump-point-maybe)
|
||||
(setq +ivy--origin nil))))
|
||||
|
||||
(after! yasnippet
|
||||
(add-to-list 'yas-prompt-functions #'+ivy-yas-prompt nil #'eq))
|
||||
|
||||
(defun +ivy*inhibit-ivy-in-evil-ex (orig-fn &rest args)
|
||||
(defadvice! +ivy--inhibit-in-evil-ex-a (orig-fn &rest args)
|
||||
"`ivy-completion-in-region' struggles with completing certain
|
||||
evil-ex-specific constructs, so we disable it solely in evil-ex."
|
||||
:around #'evil-ex
|
||||
(let ((completion-in-region-function #'completion--in-region))
|
||||
(apply orig-fn args)))
|
||||
(advice-add #'evil-ex :around #'+ivy*inhibit-ivy-in-evil-ex)
|
||||
|
||||
(define-key! ivy-mode-map
|
||||
[remap switch-to-buffer] #'+ivy/switch-buffer
|
||||
|
@ -110,7 +136,7 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
|||
|
||||
(ivy-mode +1)
|
||||
|
||||
(def-package! ivy-hydra
|
||||
(use-package! ivy-hydra
|
||||
:commands (ivy-dispatching-done-hydra ivy--matcher-desc ivy-hydra/body)
|
||||
:init
|
||||
(define-key! ivy-minibuffer-map
|
||||
|
@ -121,7 +147,7 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
|||
(define-key ivy-minibuffer-map (kbd "M-o") #'hydra-ivy/body)))
|
||||
|
||||
|
||||
(def-package! ivy-rich
|
||||
(use-package! ivy-rich
|
||||
:after ivy
|
||||
:config
|
||||
(when (featurep! +icons)
|
||||
|
@ -159,7 +185,7 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
|||
(ivy-rich-mode +1))
|
||||
|
||||
|
||||
(def-package! all-the-icons-ivy
|
||||
(use-package! all-the-icons-ivy
|
||||
:when (featurep! +icons)
|
||||
:after ivy
|
||||
:config
|
||||
|
@ -175,7 +201,7 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
|||
(all-the-icons-ivy-setup))))
|
||||
|
||||
|
||||
(def-package! counsel
|
||||
(use-package! counsel
|
||||
:commands counsel-describe-face
|
||||
:init
|
||||
(map! [remap apropos] #'counsel-apropos
|
||||
|
@ -247,7 +273,7 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
|||
'(("O" +ivy-git-grep-other-window-action "open in other window"))))
|
||||
|
||||
|
||||
(def-package! counsel-projectile
|
||||
(use-package! counsel-projectile
|
||||
:defer t
|
||||
:init
|
||||
(map! [remap projectile-find-file] #'+ivy/projectile-find-file
|
||||
|
@ -261,12 +287,12 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
|||
(ivy-set-display-transformer #'counsel-projectile-find-file nil))
|
||||
|
||||
|
||||
(def-package! wgrep
|
||||
(use-package! wgrep
|
||||
:commands wgrep-change-to-wgrep-mode
|
||||
:config (setq wgrep-auto-save-buffer t))
|
||||
|
||||
|
||||
(def-package! ivy-posframe
|
||||
(use-package! ivy-posframe
|
||||
:when (and EMACS26+ (featurep! +childframe))
|
||||
:hook (ivy-mode . ivy-posframe-mode)
|
||||
:config
|
||||
|
@ -277,14 +303,16 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
|||
(min-height . ,ivy-height)))
|
||||
|
||||
;; default to posframe display function
|
||||
(setf (alist-get t ivy-posframe-display-functions-alist) #'+ivy-display-at-frame-center-near-bottom)
|
||||
(setf (alist-get t ivy-posframe-display-functions-alist)
|
||||
#'+ivy-display-at-frame-center-near-bottom-fn)
|
||||
|
||||
;; posframe doesn't work well with async sources
|
||||
(dolist (fn '(swiper counsel-ag counsel-grep counsel-git-grep))
|
||||
(setf (alist-get fn ivy-posframe-display-functions-alist) #'ivy-display-function-fallback)))
|
||||
(setf (alist-get fn ivy-posframe-display-functions-alist)
|
||||
#'ivy-display-function-fallback)))
|
||||
|
||||
|
||||
(def-package! flx
|
||||
(use-package! flx
|
||||
:when (and (featurep! +fuzzy)
|
||||
(not (featurep! +prescient)))
|
||||
:defer t ; is loaded by ivy
|
||||
|
@ -294,7 +322,7 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
|||
ivy-flx-limit 10000))
|
||||
|
||||
|
||||
(def-package! ivy-prescient
|
||||
(use-package! ivy-prescient
|
||||
:hook (ivy-mode . ivy-prescient-mode)
|
||||
:when (featurep! +prescient)
|
||||
:init
|
||||
|
@ -323,5 +351,5 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
|||
(prescient-persist-mode +1))
|
||||
|
||||
|
||||
;; Used by `counsel-M-x'
|
||||
(setq amx-save-file (concat doom-cache-dir "amx-items"))
|
||||
;;;###package amx
|
||||
(setq amx-save-file (concat doom-cache-dir "amx-items")) ; used by `counsel-M-x'
|
||||
|
|
|
@ -150,6 +150,7 @@
|
|||
:desc "Initialize repo" "r" #'magit-init
|
||||
:desc "Clone repo" "R" #'+magit/clone
|
||||
:desc "Commit" "c" #'magit-commit-create
|
||||
:desc "Fixup" "f" #'magit-commit-fixup
|
||||
:desc "Issue" "i" #'forge-create-issue
|
||||
:desc "Pull request" "p" #'forge-create-pullreq)))
|
||||
|
||||
|
|
|
@ -9,15 +9,14 @@
|
|||
(setq shift-select-mode t)
|
||||
(delete-selection-mode +1)
|
||||
|
||||
(def-package! expand-region
|
||||
(use-package! expand-region
|
||||
:commands (er/contract-region er/mark-symbol er/mark-word)
|
||||
:config
|
||||
(defun doom*quit-expand-region ()
|
||||
(defadvice! doom--quit-expand-region-a ()
|
||||
"Properly abort an expand-region region."
|
||||
:before '(evil-escape doom/escape)
|
||||
(when (memq last-command '(er/expand-region er/contract-region))
|
||||
(er/contract-region 0)))
|
||||
(advice-add #'evil-escape :before #'doom*quit-expand-region)
|
||||
(advice-add #'doom/escape :before #'doom*quit-expand-region))
|
||||
(er/contract-region 0))))
|
||||
|
||||
|
||||
;;
|
||||
|
|
|
@ -4,10 +4,15 @@
|
|||
|
||||
;; Don't let evil-collection interfere with certain keys
|
||||
(setq evil-collection-key-blacklist
|
||||
(list "C-j" "C-k" "gd" "gf" "K" "[" "]" "gz" "<escape>"
|
||||
(list "gd" "gf" "K" "[" "]" "gz" "<escape>"
|
||||
doom-leader-key doom-localleader-key
|
||||
doom-leader-alt-key doom-localleader-alt-key))
|
||||
|
||||
(defadvice! +default-evil-collection-disable-blacklist-a (orig-fn)
|
||||
:around #'evil-collection-vterm-toggle-send-escape ; allow binding to ESC
|
||||
(let (evil-collection-key-blacklist)
|
||||
(apply orig-fn)))
|
||||
|
||||
|
||||
;;
|
||||
;;; Global keybindings
|
||||
|
@ -53,6 +58,9 @@
|
|||
|
||||
;; misc
|
||||
:n "C-S-f" #'toggle-frame-fullscreen
|
||||
:n "C-+" #'doom/reset-font-size
|
||||
:n "C-=" #'doom/increase-font-size
|
||||
:n "C--" #'doom/decrease-font-size
|
||||
|
||||
;; ported from vim
|
||||
:m "]m" #'+evil/next-beginning-of-method
|
||||
|
@ -140,7 +148,6 @@
|
|||
"C-r" #'winner-redo
|
||||
"o" #'doom/window-enlargen
|
||||
;; Delete window
|
||||
"c" #'+workspace/close-window-or-workspace
|
||||
"C-C" #'ace-delete-window)
|
||||
|
||||
;; Plugins
|
||||
|
@ -162,8 +169,8 @@
|
|||
:bind ((evil-snipe-scope 'buffer)
|
||||
(evil-snipe-enable-highlight)
|
||||
(evil-snipe-enable-incremental-highlight)))
|
||||
"SPC" (λ!! #'avy-goto-char-timer t)
|
||||
"/" #'avy-goto-char-timer)
|
||||
"SPC" (λ!! #'evil-avy-goto-char-timer t)
|
||||
"/" #'evil-avy-goto-char-timer)
|
||||
|
||||
;; text object plugins
|
||||
:textobj "x" #'evil-inner-xml-attr #'evil-outer-xml-attr
|
||||
|
@ -520,6 +527,7 @@
|
|||
:desc "Switch workspace buffer" "," #'persp-switch-to-buffer
|
||||
:desc "Switch buffer" "<" #'switch-to-buffer)
|
||||
|
||||
:desc "Switch to last buffer" "`" #'evil-switch-to-windows-last-buffer
|
||||
:desc "Resume last search" "'"
|
||||
(cond ((featurep! :completion ivy) #'ivy-resume)
|
||||
((featurep! :completion helm) #'helm-resume))
|
||||
|
@ -580,7 +588,9 @@
|
|||
:desc "Switch buffer" "B" #'switch-to-buffer)
|
||||
(:unless (featurep! :ui workspaces)
|
||||
:desc "Switch buffer" "b" #'switch-to-buffer)
|
||||
:desc "Kill buffer" "d" #'kill-current-buffer
|
||||
:desc "Kill buffer" "k" #'kill-current-buffer
|
||||
:desc "Switch to last buffer" "l" #'evil-switch-to-windows-last-buffer
|
||||
:desc "Next buffer" "n" #'next-buffer
|
||||
:desc "New empty buffer" "N" #'evil-buffer-new
|
||||
:desc "Kill other buffers" "o" #'doom/kill-other-buffers
|
||||
|
@ -674,6 +684,7 @@
|
|||
:desc "Initialize repo" "r" #'magit-init
|
||||
:desc "Clone repo" "R" #'+magit/clone
|
||||
:desc "Commit" "c" #'magit-commit-create
|
||||
:desc "Fixup" "f" #'magit-commit-fixup
|
||||
:desc "Branch" "b" #'magit-branch-and-checkout
|
||||
:desc "Issue" "i" #'forge-create-issue
|
||||
:desc "Pull request" "p" #'forge-create-pullreq)))
|
||||
|
@ -715,6 +726,9 @@
|
|||
(:when (featurep! :ui treemacs)
|
||||
:desc "Project sidebar" "p" #'+treemacs/toggle
|
||||
:desc "Find file in project sidebar" "P" #'+treemacs/find-file)
|
||||
(:when (featurep! :term shell)
|
||||
:desc "Toggle shell popup" "t" #'+shell/toggle
|
||||
:desc "Open shell here" "T" #'+shell/here)
|
||||
(:when (featurep! :term term)
|
||||
:desc "Toggle terminal popup" "t" #'+term/toggle
|
||||
:desc "Open terminal here" "T" #'+term/here)
|
||||
|
@ -724,16 +738,6 @@
|
|||
(:when (featurep! :term eshell)
|
||||
:desc "Toggle eshell popup" "e" #'+eshell/toggle
|
||||
:desc "Open eshell here" "E" #'+eshell/here)
|
||||
(:when (featurep! :collab floobits)
|
||||
(:prefix ("f" . "floobits")
|
||||
"c" #'floobits-clear-highlights
|
||||
"f" #'floobits-follow-user
|
||||
"j" #'floobits-join-workspace
|
||||
"l" #'floobits-leave-workspace
|
||||
"R" #'floobits-share-dir-private
|
||||
"s" #'floobits-summon
|
||||
"t" #'floobits-follow-mode-toggle
|
||||
"U" #'floobits-share-dir-public))
|
||||
(:when (featurep! :tools macos)
|
||||
:desc "Reveal in Finder" "o" #'+macos/reveal-in-finder
|
||||
:desc "Reveal project in Finder" "O" #'+macos/reveal-project-in-finder
|
||||
|
@ -795,11 +799,11 @@
|
|||
(:prefix-map ("s" . "snippets")
|
||||
:desc "View snippet for mode" "/" #'+snippets/find-for-current-mode
|
||||
:desc "View snippet (global)" "?" #'+snippets/find
|
||||
:desc "Edit snippet" "c" #'+snippet/edit
|
||||
:desc "Edit snippet" "c" #'+snippets/edit
|
||||
:desc "View private snippet" "f" #'+snippets/find-private
|
||||
:desc "Insert snippet" "i" #'yas-insert-snippet
|
||||
:desc "New snippet" "n" #'+snippet/new
|
||||
:desc "New snippet alias" "N" #'+snippet/new-alias
|
||||
:desc "New snippet" "n" #'+snippets/new
|
||||
:desc "New snippet alias" "N" #'+snippets/new-alias
|
||||
:desc "Reload snippets" "r" #'yas-reload-all
|
||||
:desc "Create temporary snippet" "s" #'aya-create
|
||||
:desc "Expand temporary snippet" "e" #'aya-expand))
|
||||
|
@ -810,10 +814,10 @@
|
|||
:desc "Flycheck" "f" #'flycheck-mode
|
||||
:desc "Frame fullscreen" "F" #'toggle-frame-fullscreen
|
||||
:desc "Evil goggles" "g" #'evil-goggles-mode
|
||||
:desc "Impatient mode" "h" #'+impatient-mode/toggle
|
||||
:desc "Indent guides" "i" #'highlight-indent-guides-mode
|
||||
:desc "Indent style" "I" #'doom/toggle-indent-style
|
||||
:desc "Line numbers" "l" #'doom/toggle-line-numbers
|
||||
:desc "Word-wrap mode" "w" #'+word-wrap-mode
|
||||
:desc "org-tree-slide mode" "p" #'+org-present/start
|
||||
:desc "Flyspell" "s" #'flyspell-mode))
|
||||
|
||||
|
@ -831,7 +835,7 @@ whose CDR is for repeating backward. They should both be kbd-able strings.")
|
|||
(defmacro set-repeater! (command next-func prev-func)
|
||||
"Makes ; and , the universal repeat-keys in evil-mode.
|
||||
To change these keys see `+default-repeat-keys'."
|
||||
(let ((fn-sym (intern (format "+default*repeat-%s" (doom-unquote command)))))
|
||||
(let ((fn-sym (intern (format "+default/repeat-%s" (doom-unquote command)))))
|
||||
`(progn
|
||||
(defun ,fn-sym (&rest _)
|
||||
(evil-define-key* 'motion 'local
|
||||
|
|
|
@ -119,6 +119,7 @@ languages)."
|
|||
(if (and (sp-point-in-comment)
|
||||
comment-line-break-function)
|
||||
(funcall comment-line-break-function)
|
||||
(delete-horizontal-space t)
|
||||
(newline nil t)
|
||||
(indent-according-to-mode)))
|
||||
|
||||
|
@ -267,7 +268,7 @@ If prefix ARG is set, prompt for a known project to search from."
|
|||
"Conduct a text search in the current project for symbol at point.
|
||||
If prefix ARG is set, prompt for a known project to search from."
|
||||
(interactive
|
||||
(list current-prefix-arg (thing-at-point 'symbol t)))
|
||||
(list current-prefix-arg (or (thing-at-point 'symbol t) "")))
|
||||
(let ((default-directory
|
||||
(if arg
|
||||
(if-let* ((projects (projectile-relevant-known-projects)))
|
||||
|
@ -304,6 +305,5 @@ ARG is set, prompt for a known project to search from."
|
|||
(defun +default/org-notes-headlines ()
|
||||
"Jump to an Org headline in `org-agenda-files'."
|
||||
(interactive)
|
||||
(completing-read
|
||||
"Jump to org headline: "
|
||||
(doom-completing-read-org-headings org-agenda-files 3 t)))
|
||||
(doom-completing-read-org-headings
|
||||
"Jump to org headline: " org-agenda-files 3 t))
|
||||
|
|
|
@ -44,13 +44,18 @@
|
|||
;; or specific :post-handlers with:
|
||||
;; (sp-pair "{" nil :post-handlers '(:rem ("| " "SPC")))
|
||||
(after! smartparens
|
||||
;; Smartparens is broken in `cc-mode' as of Emacs 27. See
|
||||
;; <https://github.com/Fuco1/smartparens/issues/963>.
|
||||
(unless EMACS27+
|
||||
(pushnew! sp--special-self-insert-commands 'c-electric-paren 'c-electric-brace))
|
||||
|
||||
;; Smartparens' navigation feature is neat, but does not justify how
|
||||
;; expensive it is. It's also less useful for evil users. This may need to
|
||||
;; be reactivated for non-evil users though. Needs more testing!
|
||||
(defun doom|disable-smartparens-navigate-skip-match ()
|
||||
(add-hook! 'after-change-major-mode-hook
|
||||
(defun doom-disable-smartparens-navigate-skip-match-h ()
|
||||
(setq sp-navigate-skip-match nil
|
||||
sp-navigate-consider-sgml-tags nil))
|
||||
(add-hook 'after-change-major-mode-hook #'doom|disable-smartparens-navigate-skip-match)
|
||||
sp-navigate-consider-sgml-tags nil)))
|
||||
|
||||
;; Autopair quotes more conservatively; if I'm next to a word/before another
|
||||
;; quote, I likely don't want to open a new pair.
|
||||
|
@ -101,10 +106,27 @@
|
|||
;; intelligently. The result isn't very intelligent (causes redundant
|
||||
;; characters), so just do it ourselves.
|
||||
(define-key! c++-mode-map "<" nil ">" nil)
|
||||
|
||||
(defun +default-cc-sp-point-is-template-p (id action context)
|
||||
"Return t if point is in the right place for C++ angle-brackets."
|
||||
(and (sp-in-code-p id action context)
|
||||
(cond ((eq action 'insert)
|
||||
(sp-point-after-word-p id action context))
|
||||
((eq action 'autoskip)
|
||||
(/= (char-before) 32)))))
|
||||
|
||||
(defun +default-cc-sp-point-after-include-p (id action context)
|
||||
"Return t if point is in an #include."
|
||||
(and (sp-in-code-p id action context)
|
||||
(save-excursion
|
||||
(goto-char (line-beginning-position))
|
||||
(looking-at-p "[ ]*#include[^<]+"))))
|
||||
|
||||
;; ...and leave it to smartparens
|
||||
(sp-local-pair '(c++-mode objc-mode)
|
||||
"<" ">"
|
||||
:when '(+cc-sp-point-is-template-p +cc-sp-point-after-include-p)
|
||||
:when '(+default-cc-sp-point-is-template-p
|
||||
+default-cc-sp-point-after-include-p)
|
||||
:post-handlers '(("| " "SPC")))
|
||||
|
||||
(sp-local-pair '(c-mode c++-mode objc-mode java-mode)
|
||||
|
@ -138,6 +160,27 @@
|
|||
:actions '(insert)
|
||||
:post-handlers '(("| " "SPC") ("|\n[i]*)[d-2]" "RET")))))
|
||||
|
||||
(after! smartparens-markdown
|
||||
(sp-with-modes '(markdown-mode gfm-mode)
|
||||
(sp-local-pair "```" "```" :post-handlers '(:add ("||\n[i]" "RET")))
|
||||
|
||||
;; The original rules for smartparens had an odd quirk: inserting two
|
||||
;; asterixex would replace nearby quotes with asterixes. These two rules
|
||||
;; set out to fix this.
|
||||
(sp-local-pair "**" nil :actions :rem)
|
||||
(sp-local-pair "*" "*"
|
||||
:actions '(insert skip)
|
||||
:unless '(:rem sp-point-at-bol-p)
|
||||
;; * then SPC will delete the second asterix and assume
|
||||
;; you wanted a bullet point. * followed by another *
|
||||
;; will produce an extra, assuming you wanted **|**.
|
||||
:post-handlers '(("[d1]" "SPC") ("|*" "*"))))
|
||||
|
||||
;; This keybind allows * to skip over **.
|
||||
(map! :map markdown-mode-map
|
||||
:ig "*" (λ! (if (looking-at-p "\\*\\* *$")
|
||||
(forward-char 2)
|
||||
(call-interactively 'self-insert-command)))))
|
||||
|
||||
;; Highjacks backspace to:
|
||||
;; a) balance spaces inside brackets/parentheses ( | ) -> (|)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
(defalias '+literate/reload #'doom/reload)
|
||||
|
||||
;;;###autoload
|
||||
(defun +literate|recompile-maybe ()
|
||||
(defun +literate-recompile-maybe-h ()
|
||||
"Recompile config.org if we're editing an org file in our DOOMDIR.
|
||||
|
||||
We assume any org file in `doom-private-dir' is connected to your literate
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
;;; config/literate/init.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar +literate-config-file
|
||||
(expand-file-name "config.org" doom-private-dir)
|
||||
(concat doom-private-dir "config.org")
|
||||
"The file path of your literate config file.")
|
||||
|
||||
(defvar +literate-config-cache-file
|
||||
(expand-file-name "literate-last-compile" doom-cache-dir)
|
||||
(concat doom-cache-dir "literate-last-compile")
|
||||
"The file path that `+literate-config-file' will be tangled to, then
|
||||
byte-compiled from.")
|
||||
|
||||
|
@ -13,32 +13,34 @@ byte-compiled from.")
|
|||
;;
|
||||
(defun +literate-tangle (&optional force-p)
|
||||
"Tangles `+literate-config-file' if it has changed."
|
||||
(let ((default-directory doom-private-dir)
|
||||
(org +literate-config-file))
|
||||
(when (or force-p (file-newer-than-file-p org +literate-config-cache-file))
|
||||
(let ((default-directory doom-private-dir))
|
||||
(when (or (file-newer-than-file-p +literate-config-file
|
||||
+literate-config-cache-file)
|
||||
force-p)
|
||||
(message "Compiling your literate config...")
|
||||
|
||||
(let* ((org (file-truename +literate-config-file))
|
||||
(dest (concat (file-name-sans-extension org) ".el")))
|
||||
(or (and (if (fboundp 'org-babel-tangle-file)
|
||||
(org-babel-tangle-file org dest "emacs-lisp")
|
||||
;; We tangle in a separate, blank process because loading it
|
||||
;; here would load all of :lang org (very expensive!).
|
||||
(zerop (call-process
|
||||
"emacs" nil nil nil
|
||||
"-q" "--batch" "-l" "ob-tangle" "--eval"
|
||||
(format "(org-babel-tangle-file %S %S \"emacs-lisp\")"
|
||||
org dest))))
|
||||
(dest (concat (file-name-sans-extension org) ".el"))
|
||||
(output (get-buffer-create "*org-tangle*")))
|
||||
(unwind-protect
|
||||
;; We tangle in a separate, blank process because loading it here
|
||||
;; would load all of :lang org (very expensive!).
|
||||
(or (and (zerop (call-process
|
||||
"emacs" nil output nil
|
||||
"-q" "--batch"
|
||||
"-l" "ob-tangle"
|
||||
"--eval" (format "(org-babel-tangle-file %S %S)"
|
||||
org dest)))
|
||||
(with-current-buffer output
|
||||
(message "%s" (buffer-string))
|
||||
t)
|
||||
;; Write the cache file to serve as our mtime cache
|
||||
(with-temp-file +literate-config-cache-file
|
||||
(message "Done!")))
|
||||
(warn "There was a problem tangling your literate config!"))))))
|
||||
(warn "There was a problem tangling your literate config!"))
|
||||
(kill-buffer output))))))
|
||||
|
||||
|
||||
;; Let 'er rip!
|
||||
(when noninteractive
|
||||
(require 'ob-tangle nil t))
|
||||
|
||||
(+literate-tangle (or doom-reloading-p noninteractive))
|
||||
;; No need to load the resulting file. Doom will do this for us after all
|
||||
;; modules have finished loading.
|
||||
|
@ -46,4 +48,4 @@ byte-compiled from.")
|
|||
|
||||
;; Recompile our literate config if we modify it
|
||||
(after! org
|
||||
(add-hook 'after-save-hook #'+literate|recompile-maybe))
|
||||
(add-hook 'after-save-hook #'+literate-recompile-maybe-h))
|
||||
|
|
|
@ -1,100 +1,6 @@
|
|||
;;; editor/evil/+commands.el -*- lexical-binding: t; -*-
|
||||
|
||||
(evil-define-operator +evil:open-scratch-buffer (bang)
|
||||
(interactive "<!>")
|
||||
(doom/open-scratch-buffer bang))
|
||||
|
||||
(evil-define-command +evil:pwd (bang)
|
||||
"Display the current working directory. If BANG, copy it to your clipboard."
|
||||
(interactive "<!>")
|
||||
(if (not bang)
|
||||
(pwd)
|
||||
(kill-new default-directory)
|
||||
(message "Copied to clipboard")))
|
||||
|
||||
(evil-define-command +evil:make (arguments &optional bang)
|
||||
"Run make with ARGUMENTS.
|
||||
If BANG is non-nil, open compilation output in a comint buffer.
|
||||
|
||||
If BANG, then run ARGUMENTS as a full command. This command understands vim file
|
||||
modifiers (like %:p:h). See `+evil*resolve-vim-path' for details."
|
||||
(interactive "<sh><!>")
|
||||
(+evil:compile (format "make %s"
|
||||
(evil-ex-replace-special-filenames
|
||||
arguments))
|
||||
bang))
|
||||
|
||||
(evil-define-command +evil:compile (arguments &optional bang)
|
||||
"Run `compile-command' with ARGUMENTS.
|
||||
If BANG is non-nil, open compilation output in a comint buffer.
|
||||
|
||||
This command understands vim file modifiers (like %:p:h). See
|
||||
`+evil*resolve-vim-path' for details."
|
||||
(interactive "<sh><!>")
|
||||
(compile (evil-ex-replace-special-filenames
|
||||
(format "%s %s"
|
||||
(eval compile-command)
|
||||
arguments))
|
||||
bang))
|
||||
|
||||
(evil-define-command +evil:reverse-lines (beg end)
|
||||
"Reverse lines between BEG and END."
|
||||
(interactive "<r>")
|
||||
(reverse-region beg end))
|
||||
|
||||
(evil-define-command +evil:cd (&optional path)
|
||||
"Change `default-directory' with `cd'."
|
||||
(interactive "<f>")
|
||||
(let ((path (or path "~")))
|
||||
(cd path)
|
||||
(message "Changed directory to '%s'" (abbreviate-file-name (expand-file-name path)))))
|
||||
|
||||
(evil-define-command +evil:kill-all-buffers (&optional bang)
|
||||
"Kill all buffers. If BANG, kill current session too."
|
||||
(interactive "<!>")
|
||||
(if (and bang (fboundp '+workspace/kill-session))
|
||||
(+workspace/kill-session)
|
||||
(doom/kill-all-buffers)))
|
||||
|
||||
(evil-define-command +evil:kill-matching-buffers (&optional bang pattern)
|
||||
"Kill all buffers matching PATTERN regexp. If BANG, only match project
|
||||
buffers."
|
||||
(interactive "<a>")
|
||||
(doom/kill-matching-buffers pattern bang))
|
||||
|
||||
(evil-define-command +evil:help (&optional bang query)
|
||||
"Look up help documentation for QUERY in Emacs documentation.
|
||||
|
||||
If BANG, search Doom documentation."
|
||||
(interactive "<!><a>")
|
||||
(if bang
|
||||
(doom/help-search query)
|
||||
(cond ((or (null query) (string-empty-p (string-trim query)))
|
||||
(call-interactively
|
||||
(or (command-remapping #'apropos)
|
||||
#'apropos)))
|
||||
((string-match-p "^ *:[a-z]" query)
|
||||
(let* ((modules
|
||||
(cl-loop for path in (doom-module-load-path 'all)
|
||||
for (cat . mod) = (doom-module-from-path path)
|
||||
for format = (format "%s %s" cat mod)
|
||||
if (doom-module-p cat mod)
|
||||
collect (propertize format 'module (list cat mod))
|
||||
else if (and cat mod)
|
||||
collect (propertize format
|
||||
'face 'font-lock-comment-face
|
||||
'module (list cat mod))))
|
||||
(module (completing-read "Describe module: " modules nil t query))
|
||||
(key (get-text-property 0 'module module)))
|
||||
(doom/help-modules key)))
|
||||
((and (string-match-p "\\(?:SPC\\|[CMsSH]-[^ ]\\|<[^>]+>\\)" query)
|
||||
(helpful-key (kbd (string-trim query)))))
|
||||
((apropos query t)))))
|
||||
|
||||
|
||||
;;
|
||||
;; Commands
|
||||
|
||||
;;; Custom commands
|
||||
;; Editing
|
||||
(evil-ex-define-cmd "@" #'+evil:macro-on-all-lines) ; TODO Test me
|
||||
|
@ -142,7 +48,7 @@ If BANG, search Doom documentation."
|
|||
(evil-ex-define-cmd "k[ill]o" #'doom/kill-other-buffers)
|
||||
(evil-ex-define-cmd "k[ill]b" #'doom/kill-buried-buffers)
|
||||
(evil-ex-define-cmd "l[ast]" #'doom/popup-restore)
|
||||
(evil-ex-define-cmd "m[sg]" #'view-echo-area-messages)
|
||||
(evil-ex-define-cmd "messages" #'view-echo-area-messages)
|
||||
(evil-ex-define-cmd "pop[up]" #'doom/popup-this-buffer)
|
||||
|
||||
;;; Project navigation
|
||||
|
|
|
@ -9,11 +9,10 @@
|
|||
;; 2. This ensures a predictable load order, versus lazy loading using :defer or
|
||||
;; :after-call. This means users can use (after! org ...) and be sure that
|
||||
;; their changes will override evil-collection's.
|
||||
;; 3. Eventually, I'd like to remove evil-collection. It changes too often,
|
||||
;; introduces breaking bugs too frequently, and I don't always agree with
|
||||
;; their design choices. Regardless, there are useful tidbits I'd like to
|
||||
;; keep. This will be a slow transition, but this file is where most of it
|
||||
;; will happen.
|
||||
;; 3. Ideally, we'd do away with evil-collection entirely. It changes too often,
|
||||
;; introduces breaking bugs too frequently, and I don't agree with all their
|
||||
;; design choices. Regardless, it does mork than it causes trouble, so it may
|
||||
;; be here to stay.
|
||||
;; 4. Adds `+evil-collection-disabled-list', to make it easier for users to
|
||||
;; disable modules, and to reduce the effort required to maintain our copy of
|
||||
;; `evil-collection-list' (now I can just copy it from time to time).
|
||||
|
@ -43,8 +42,18 @@ variable for an explanation of the defaults (in comments). See
|
|||
|
||||
(defvar evil-collection-setup-minibuffer nil)
|
||||
|
||||
;; We do this ourselves, and better.
|
||||
(defvar evil-collection-want-unimpaired-p nil)
|
||||
|
||||
;; This has to be defined here since evil-collection doesn't autoload its own.
|
||||
;; It must be updated whenever evil-collection updates theirs.
|
||||
;; It must be updated whenever evil-collection updates theirs. Here's an easy
|
||||
;; way to update it:
|
||||
;;
|
||||
;; (with-current-buffer
|
||||
;; (url-retrieve-synchronously "https://raw.githubusercontent.com/emacs-evil/evil-collection/master/evil-collection.el" t t)
|
||||
;; (goto-char (point-min))
|
||||
;; (when (re-search-forward "^(defcustom evil-collection-mode-list\n[^(]+")
|
||||
;; (kill-new (thing-at-point 'sexp t))))
|
||||
(defvar evil-collection-mode-list
|
||||
`(2048-game
|
||||
ag
|
||||
|
@ -152,7 +161,7 @@ variable for an explanation of the defaults (in comments). See
|
|||
rtags
|
||||
simple
|
||||
slime
|
||||
(term term ansi-term)
|
||||
(term term ansi-term multi-term)
|
||||
tetris
|
||||
tide
|
||||
transmission
|
||||
|
@ -173,15 +182,15 @@ variable for an explanation of the defaults (in comments). See
|
|||
youtube-dl
|
||||
(ztree ztree-diff)))
|
||||
|
||||
(defun +evil-collection-init (module)
|
||||
(defun +evil-collection-init (module &optional disabled-list)
|
||||
"Initialize evil-collection-MODULE.
|
||||
|
||||
Unlike `evil-collection-init', this respects `+evil-collection-disabled-list',
|
||||
and complains if a module is loaded too early (during startup)."
|
||||
(unless (memq (or (car-safe module) module) +evil-collection-disabled-list)
|
||||
(let ((module-sym (or (car-safe module) module)))
|
||||
(unless (memq (or (car-safe module) module) disabled-list)
|
||||
(doom-log "Initialized evil-collection-%s %s"
|
||||
module-sym (if doom-init-time "" "(too early!)")))
|
||||
(or (car-safe module) module)
|
||||
(if doom-init-time "" "(too early!)"))
|
||||
(with-demoted-errors "evil-collection error: %s"
|
||||
(evil-collection-init (list module)))))
|
||||
|
||||
|
@ -192,9 +201,8 @@ and complains if a module is loaded too early (during startup)."
|
|||
;; These modes belong to packages that Emacs always loads at startup, causing
|
||||
;; evil-collection to load immediately. We avoid this by loading them after
|
||||
;; evil-collection has first loaded...
|
||||
(after! evil-collection
|
||||
(let (+evil-collection-disabled-list)
|
||||
(mapc #'+evil-collection-init '(comint custom help))))
|
||||
(with-eval-after-load 'evil-collection
|
||||
(mapc #'+evil-collection-init '(comint custom help)))
|
||||
|
||||
;; ...or on first invokation of their associated major/minor modes.
|
||||
(add-transient-hook! 'Buffer-menu-mode
|
||||
|
@ -214,4 +222,4 @@ and complains if a module is loaded too early (during startup)."
|
|||
(dolist (mode evil-collection-mode-list)
|
||||
(dolist (req (or (cdr-safe mode) (list mode)))
|
||||
(with-eval-after-load req
|
||||
(+evil-collection-init mode))))
|
||||
(+evil-collection-init mode +evil-collection-disabled-list))))
|
||||
|
|
|
@ -1,76 +1,13 @@
|
|||
;;; editor/evil/autoload/advice.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defun +evil--insert-newline (&optional above _noextranewline)
|
||||
(let ((pos (save-excursion (beginning-of-line-text) (point)))
|
||||
comment-auto-fill-only-comments)
|
||||
(require 'smartparens)
|
||||
(evil-narrow-to-field
|
||||
(if above
|
||||
(if (save-excursion (nth 4 (sp--syntax-ppss pos)))
|
||||
(evil-save-goal-column
|
||||
(setq evil-auto-indent nil)
|
||||
(goto-char pos)
|
||||
(let ((ws (abs (skip-chars-backward " \t"))))
|
||||
;; FIXME oh god why
|
||||
(save-excursion
|
||||
(if comment-line-break-function
|
||||
(funcall comment-line-break-function)
|
||||
(comment-indent-new-line))
|
||||
(when (and (derived-mode-p 'c-mode 'c++-mode 'objc-mode 'java-mode 'js2-mode)
|
||||
(eq (char-after) ?/))
|
||||
(insert "*"))
|
||||
(insert
|
||||
(make-string (max 0 (+ ws (skip-chars-backward " \t")))
|
||||
32)))
|
||||
(insert (make-string (max 1 ws) 32))))
|
||||
(evil-move-beginning-of-line)
|
||||
(insert (if use-hard-newlines hard-newline "\n"))
|
||||
(forward-line -1)
|
||||
(back-to-indentation))
|
||||
(evil-move-end-of-line)
|
||||
(cond ((sp-point-in-comment pos)
|
||||
(setq evil-auto-indent nil)
|
||||
(if comment-line-break-function
|
||||
(funcall comment-line-break-function)
|
||||
(comment-indent-new-line)))
|
||||
;; TODO Find a better way to do this
|
||||
((and (eq major-mode 'haskell-mode)
|
||||
(fboundp 'haskell-indentation-newline-and-indent))
|
||||
(setq evil-auto-indent nil)
|
||||
(haskell-indentation-newline-and-indent))
|
||||
(t
|
||||
(insert (if use-hard-newlines hard-newline "\n"))
|
||||
(back-to-indentation)))))))
|
||||
;;;###autoload
|
||||
(defun +evil-escape-a (&rest _)
|
||||
"Call `doom/escape' if `evil-force-normal-state' is called interactively."
|
||||
(when (called-interactively-p 'any)
|
||||
(call-interactively #'doom/escape)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil*insert-newline-below-and-respect-comments (orig-fn count)
|
||||
(if (or (not +evil-want-o/O-to-continue-comments)
|
||||
(not (eq this-command 'evil-open-below))
|
||||
(evil-insert-state-p))
|
||||
(funcall orig-fn count)
|
||||
(cl-letf (((symbol-function 'evil-insert-newline-below)
|
||||
(lambda () (+evil--insert-newline))))
|
||||
(let ((evil-auto-indent evil-auto-indent))
|
||||
(funcall orig-fn count)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil*insert-newline-above-and-respect-comments (orig-fn count)
|
||||
(if (or (not +evil-want-o/O-to-continue-comments)
|
||||
(not (eq this-command 'evil-open-above))
|
||||
(evil-insert-state-p))
|
||||
(funcall orig-fn count)
|
||||
(cl-letf (((symbol-function 'evil-insert-newline-above)
|
||||
(lambda () (+evil--insert-newline 'above))))
|
||||
(let ((evil-auto-indent evil-auto-indent))
|
||||
(funcall orig-fn count)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil*static-reindent (orig-fn &rest args)
|
||||
"Don't move cursor on indent."
|
||||
(save-excursion (apply orig-fn args)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil*resolve-vim-path (file-name)
|
||||
(defun +evil-resolve-vim-path-a (file-name)
|
||||
"Take a path and resolve any vim-like filename modifiers in it. This adds
|
||||
support for most vim file modifiers, as well as:
|
||||
|
||||
|
@ -148,8 +85,77 @@ more information on modifiers."
|
|||
path file-name t t 1))))
|
||||
(replace-regexp-in-string regexp "\\1" file-name t)))
|
||||
|
||||
;;;###autoload (autoload '+evil*window-split "editor/evil/autoload/advice" nil t)
|
||||
(evil-define-command +evil*window-split (&optional count file)
|
||||
(defun +evil--insert-newline (&optional above _noextranewline)
|
||||
(let ((pos (save-excursion (beginning-of-line-text) (point)))
|
||||
comment-auto-fill-only-comments)
|
||||
(require 'smartparens)
|
||||
(evil-narrow-to-field
|
||||
(if above
|
||||
(if (save-excursion (nth 4 (sp--syntax-ppss pos)))
|
||||
(evil-save-goal-column
|
||||
(setq evil-auto-indent nil)
|
||||
(goto-char pos)
|
||||
(let ((ws (abs (skip-chars-backward " \t"))))
|
||||
;; FIXME oh god why
|
||||
(save-excursion
|
||||
(if comment-line-break-function
|
||||
(funcall comment-line-break-function)
|
||||
(comment-indent-new-line))
|
||||
(when (and (derived-mode-p 'c-mode 'c++-mode 'objc-mode 'java-mode 'js2-mode)
|
||||
(eq (char-after) ?/))
|
||||
(insert "*"))
|
||||
(insert
|
||||
(make-string (max 0 (+ ws (skip-chars-backward " \t")))
|
||||
32)))
|
||||
(insert (make-string (max 1 ws) 32))))
|
||||
(evil-move-beginning-of-line)
|
||||
(insert (if use-hard-newlines hard-newline "\n"))
|
||||
(forward-line -1)
|
||||
(back-to-indentation))
|
||||
(evil-move-end-of-line)
|
||||
(cond ((sp-point-in-comment pos)
|
||||
(setq evil-auto-indent nil)
|
||||
(if comment-line-break-function
|
||||
(funcall comment-line-break-function)
|
||||
(comment-indent-new-line)))
|
||||
;; TODO Find a better way to do this
|
||||
((and (eq major-mode 'haskell-mode)
|
||||
(fboundp 'haskell-indentation-newline-and-indent))
|
||||
(setq evil-auto-indent nil)
|
||||
(haskell-indentation-newline-and-indent))
|
||||
(t
|
||||
(insert (if use-hard-newlines hard-newline "\n"))
|
||||
(back-to-indentation)))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil--insert-newline-below-and-respect-comments-a (orig-fn count)
|
||||
(if (or (not +evil-want-o/O-to-continue-comments)
|
||||
(not (eq this-command 'evil-open-below))
|
||||
(evil-insert-state-p))
|
||||
(funcall orig-fn count)
|
||||
(cl-letf (((symbol-function 'evil-insert-newline-below)
|
||||
(lambda () (+evil--insert-newline))))
|
||||
(let ((evil-auto-indent evil-auto-indent))
|
||||
(funcall orig-fn count)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil--insert-newline-above-and-respect-comments-a (orig-fn count)
|
||||
(if (or (not +evil-want-o/O-to-continue-comments)
|
||||
(not (eq this-command 'evil-open-above))
|
||||
(evil-insert-state-p))
|
||||
(funcall orig-fn count)
|
||||
(cl-letf (((symbol-function 'evil-insert-newline-above)
|
||||
(lambda () (+evil--insert-newline 'above))))
|
||||
(let ((evil-auto-indent evil-auto-indent))
|
||||
(funcall orig-fn count)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil--static-reindent-a (orig-fn &rest args)
|
||||
"Don't move cursor on indent."
|
||||
(save-excursion (apply orig-fn args)))
|
||||
|
||||
;;;###autoload (autoload '+evil-window-split-a "editor/evil/autoload/advice" nil t)
|
||||
(evil-define-command +evil-window-split-a (&optional count file)
|
||||
"Same as `evil-window-split', but focuses (and recenters) the new split."
|
||||
:repeat nil
|
||||
(interactive "P<f>")
|
||||
|
@ -164,8 +170,8 @@ more information on modifiers."
|
|||
(balance-windows (window-parent)))
|
||||
(if file (evil-edit file)))
|
||||
|
||||
;;;###autoload (autoload '+evil*window-vsplit "editor/evil/autoload/advice" nil t)
|
||||
(evil-define-command +evil*window-vsplit (&optional count file)
|
||||
;;;###autoload (autoload '+evil-window-vsplit-a "editor/evil/autoload/advice" nil t)
|
||||
(evil-define-command +evil-window-vsplit-a (&optional count file)
|
||||
"Same as `evil-window-vsplit', but focuses (and recenters) the new split."
|
||||
:repeat nil
|
||||
(interactive "P<f>")
|
||||
|
@ -181,18 +187,12 @@ more information on modifiers."
|
|||
(if file (evil-edit file)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil*escape (&rest _)
|
||||
"Call `doom/escape' if `evil-force-normal-state' is called interactively."
|
||||
(when (called-interactively-p 'any)
|
||||
(call-interactively #'doom/escape)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil*make-numbered-markers-global (orig-fn char)
|
||||
(defun +evil--make-numbered-markers-global-a (orig-fn char)
|
||||
(or (and (>= char ?2) (<= char ?9))
|
||||
(funcall orig-fn char)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil*fix-dabbrev-in-minibuffer ()
|
||||
(defun +evil--fix-dabbrev-in-minibuffer-h ()
|
||||
"Make `try-expand-dabbrev' from `hippie-expand' work in minibuffer. See
|
||||
`he-dabbrev-beg', so we need to redefine syntax for '/'."
|
||||
(set-syntax-table (let* ((table (make-syntax-table)))
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
;; editor/evil/autoload/evil.el -*- lexical-binding: t; -*-
|
||||
;;;###if (featurep! :editor evil)
|
||||
|
||||
;;;###autodef
|
||||
(defun set-evil-initial-state! (modes state)
|
||||
|
@ -12,72 +11,6 @@
|
|||
(evil-set-initial-state modes state))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Custom arg handlers
|
||||
|
||||
(defvar +evil--flag nil)
|
||||
|
||||
(defun +evil--ex-match-init (name &optional face update-hook)
|
||||
(with-current-buffer evil-ex-current-buffer
|
||||
(cond
|
||||
((eq +evil--flag 'start)
|
||||
(evil-ex-make-hl name
|
||||
:face (or face 'evil-ex-substitute-matches)
|
||||
:update-hook (or update-hook #'evil-ex-pattern-update-ex-info))
|
||||
(setq +evil--flag 'update))
|
||||
|
||||
((eq +evil--flag 'stop)
|
||||
(evil-ex-delete-hl name)))))
|
||||
|
||||
(defun +evil--ex-buffer-match (arg &optional hl-name flags beg end)
|
||||
(when (and (eq +evil--flag 'update)
|
||||
evil-ex-substitute-highlight-all
|
||||
(not (zerop (length arg))))
|
||||
(condition-case lossage
|
||||
(let ((pattern (evil-ex-make-substitute-pattern
|
||||
arg
|
||||
(or flags (list))))
|
||||
(range (or (evil-copy-range evil-ex-range)
|
||||
(evil-range (or beg (line-beginning-position))
|
||||
(or end (line-end-position))
|
||||
'line
|
||||
:expanded t))))
|
||||
(evil-expand-range range)
|
||||
(evil-ex-hl-set-region hl-name
|
||||
(max (evil-range-beginning range) (window-start))
|
||||
(min (evil-range-end range) (window-end)))
|
||||
(evil-ex-hl-change hl-name pattern))
|
||||
(end-of-file
|
||||
(evil-ex-pattern-update-ex-info nil "incomplete replacement"))
|
||||
(user-error
|
||||
(evil-ex-pattern-update-ex-info nil (format "?%s" lossage))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil-ex-buffer-match (flag &optional arg)
|
||||
(let ((hl-name 'evil-ex-buffer-match)
|
||||
(+evil--flag flag))
|
||||
(with-selected-window (minibuffer-selected-window)
|
||||
(+evil--ex-match-init hl-name)
|
||||
(+evil--ex-buffer-match arg hl-name (list (if evil-ex-substitute-global ?g))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil-ex-global-match (flag &optional arg)
|
||||
(let ((hl-name 'evil-ex-global-match)
|
||||
(+evil--flag flag))
|
||||
(with-selected-window (minibuffer-selected-window)
|
||||
(+evil--ex-match-init hl-name)
|
||||
(+evil--ex-buffer-match arg hl-name nil (point-min) (point-max)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil-ex-global-delim-match (flag &optional arg)
|
||||
(let ((hl-name 'evil-ex-global-delim-match)
|
||||
(+evil--flag flag))
|
||||
(with-selected-window (minibuffer-selected-window)
|
||||
(+evil--ex-match-init hl-name)
|
||||
(let ((result (car-safe (evil-delimited-arguments arg 2))))
|
||||
(+evil--ex-buffer-match result hl-name nil (point-min) (point-max))))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Interactive commands
|
||||
|
||||
|
@ -167,28 +100,6 @@ integration."
|
|||
t))
|
||||
prefix)))))
|
||||
|
||||
;;;###autoload (autoload '+evil:align "editor/evil/autoload/evil" nil t)
|
||||
(evil-define-operator +evil:align (beg end pattern &optional bang)
|
||||
"Ex interface to `align-regexp'. PATTERN is a vim-style regexp. If BANG,
|
||||
repeat the alignment for all matches (otherwise just the first match on each
|
||||
line)."
|
||||
(interactive "<r><//g><!>")
|
||||
(align-regexp
|
||||
beg end
|
||||
(concat "\\(\\s-*\\)" (evil-transform-vim-style-regexp pattern))
|
||||
1 1 bang))
|
||||
|
||||
;;;###autoload (autoload '+evil:align-right "editor/evil/autoload/evil" nil t)
|
||||
(evil-define-operator +evil:align-right (beg end pattern &optional bang)
|
||||
"Like `+evil:align', except alignments are right-justified. PATTERN is a
|
||||
vim-style regexp. If BANG, repeat the alignment for all matches (otherwise just
|
||||
the first match on each line)."
|
||||
(interactive "<r><//g><!>")
|
||||
(align-regexp
|
||||
beg end
|
||||
(concat "\\(" (evil-transform-vim-style-regexp pattern) "\\)")
|
||||
-1 1 bang))
|
||||
|
||||
;;;###autoload (autoload '+evil:apply-macro "editor/evil/autoload/evil" nil t)
|
||||
(evil-define-operator +evil:apply-macro (beg end)
|
||||
"Apply macro to each line."
|
||||
|
|
183
modules/editor/evil/autoload/ex.el
Normal file
183
modules/editor/evil/autoload/ex.el
Normal file
|
@ -0,0 +1,183 @@
|
|||
;;; editor/evil/autoload/ex.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defvar +evil--flag nil)
|
||||
|
||||
(defun +evil--ex-match-init (name &optional face update-hook)
|
||||
(with-current-buffer evil-ex-current-buffer
|
||||
(cond
|
||||
((eq +evil--flag 'start)
|
||||
(evil-ex-make-hl name
|
||||
:face (or face 'evil-ex-lazy-highlight)
|
||||
:update-hook (or update-hook #'evil-ex-pattern-update-ex-info))
|
||||
(setq +evil--flag 'update))
|
||||
|
||||
((eq +evil--flag 'stop)
|
||||
(evil-ex-delete-hl name)))))
|
||||
|
||||
(defun +evil--ex-buffer-match (arg &optional hl-name flags beg end)
|
||||
(when (and (eq +evil--flag 'update)
|
||||
evil-ex-substitute-highlight-all
|
||||
(not (zerop (length arg))))
|
||||
(condition-case lossage
|
||||
(let* ((pattern (evil-ex-make-substitute-pattern
|
||||
arg
|
||||
(or flags (list))))
|
||||
(range (or (evil-copy-range evil-ex-range)
|
||||
(evil-range (or beg (line-beginning-position))
|
||||
(or end (line-end-position))
|
||||
'line
|
||||
:expanded t))))
|
||||
(evil-expand-range range)
|
||||
(evil-ex-hl-set-region hl-name
|
||||
(max (evil-range-beginning range) (window-start))
|
||||
(min (evil-range-end range) (window-end)))
|
||||
(evil-ex-hl-change hl-name pattern))
|
||||
(end-of-file
|
||||
(evil-ex-pattern-update-ex-info nil "incomplete replacement"))
|
||||
(user-error
|
||||
(evil-ex-pattern-update-ex-info nil (format "?%s" lossage))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil-ex-regexp-match (flag &optional arg invert)
|
||||
(let ((hl-name 'evil-ex-buffer-match)
|
||||
(+evil--flag flag))
|
||||
(with-selected-window (minibuffer-selected-window)
|
||||
(+evil--ex-match-init hl-name)
|
||||
(cl-destructuring-bind (&optional arg flags)
|
||||
(evil-delimited-arguments arg 2)
|
||||
(let ((evil-ex-substitute-global
|
||||
(if invert
|
||||
(not evil-ex-substitute-global)
|
||||
evil-ex-substitute-global)))
|
||||
(+evil--ex-buffer-match
|
||||
arg hl-name (string-to-list flags)))))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Ex Commands
|
||||
|
||||
;;;###autoload (autoload '+evil:align "editor/evil/autoload/ex" nil t)
|
||||
(evil-define-operator +evil:align (beg end pattern &optional flags)
|
||||
"Ex interface to `align-regexp'. PATTERN is a vim-style regexp. If BANG,
|
||||
repeat the alignment for all matches (otherwise just the first match on each
|
||||
line)."
|
||||
(interactive "<r><//>")
|
||||
(align-regexp
|
||||
beg end
|
||||
(concat "\\(\\s-*\\)" (evil-transform-vim-style-regexp pattern))
|
||||
1 1 (memq ?g flags)))
|
||||
|
||||
;;;###autoload (autoload '+evil:align-right "editor/evil/autoload/ex" nil t)
|
||||
(evil-define-operator +evil:align-right (beg end pattern &optional flags)
|
||||
"Like `+evil:align', except alignments are right-justified. PATTERN is a
|
||||
vim-style regexp. If BANG, repeat the alignment for all matches (otherwise just
|
||||
the first match on each line)."
|
||||
(interactive "<r><//>")
|
||||
(align-regexp
|
||||
beg end
|
||||
(concat "\\(" (evil-transform-vim-style-regexp pattern) "\\)")
|
||||
-1 1 (memq ?g flags)))
|
||||
|
||||
;; ;;;###autoload (autoload '+evil:sort "editor/evil/autoload/ex" nil nil)
|
||||
;; (evil-define-command +evil:sort (beg end &optional pattern flags reverse)
|
||||
;; (interactive "<r><//><!>"))
|
||||
|
||||
;;;###autoload (autoload '+evil:open-scratch-buffer "editor/evil/autoload/ex" nil t)
|
||||
(evil-define-operator +evil:open-scratch-buffer (bang)
|
||||
(interactive "<!>")
|
||||
(doom/open-scratch-buffer bang))
|
||||
|
||||
;;;###autoload (autoload '+evil:pwd "editor/evil/autoload/ex" nil t)
|
||||
(evil-define-command +evil:pwd (bang)
|
||||
"Display the current working directory. If BANG, copy it to your clipboard."
|
||||
(interactive "<!>")
|
||||
(if (not bang)
|
||||
(pwd)
|
||||
(kill-new default-directory)
|
||||
(message "Copied to clipboard")))
|
||||
|
||||
;;;###autoload (autoload '+evil:make "editor/evil/autoload/ex" nil t)
|
||||
(evil-define-command +evil:make (arguments &optional bang)
|
||||
"Run make with ARGUMENTS.
|
||||
If BANG is non-nil, open compilation output in a comint buffer.
|
||||
|
||||
If BANG, then run ARGUMENTS as a full command. This command understands vim file
|
||||
modifiers (like %:p:h). See `+evil-resolve-vim-path-a' for details."
|
||||
(interactive "<sh><!>")
|
||||
(+evil:compile (format "make %s"
|
||||
(evil-ex-replace-special-filenames
|
||||
arguments))
|
||||
bang))
|
||||
|
||||
;;;###autoload (autoload '+evil:compile "editor/evil/autoload/ex" nil t)
|
||||
(evil-define-command +evil:compile (arguments &optional bang)
|
||||
"Run `compile-command' with ARGUMENTS.
|
||||
If BANG is non-nil, open compilation output in a comint buffer.
|
||||
|
||||
This command understands vim file modifiers (like %:p:h). See
|
||||
`+evil-resolve-vim-path-a' for details."
|
||||
(interactive "<sh><!>")
|
||||
(compile (evil-ex-replace-special-filenames
|
||||
(format "%s %s"
|
||||
(eval compile-command)
|
||||
arguments))
|
||||
bang))
|
||||
|
||||
;;;###autoload (autoload '+evil:reverse-lines "editor/evil/autoload/ex" nil t)
|
||||
(evil-define-command +evil:reverse-lines (beg end)
|
||||
"Reverse lines between BEG and END."
|
||||
(interactive "<r>")
|
||||
(reverse-region beg end))
|
||||
|
||||
;;;###autoload (autoload '+evil:cd "editor/evil/autoload/ex" nil t)
|
||||
(evil-define-command +evil:cd (&optional path)
|
||||
"Change `default-directory' with `cd'."
|
||||
(interactive "<f>")
|
||||
(let ((path (or path "~")))
|
||||
(cd path)
|
||||
(message "Changed directory to '%s'" (abbreviate-file-name (expand-file-name path)))))
|
||||
|
||||
;;;###autoload (autoload '+evil:kill-all-buffers "editor/evil/autoload/ex" nil t)
|
||||
(evil-define-command +evil:kill-all-buffers (&optional bang)
|
||||
"Kill all buffers. If BANG, kill current session too."
|
||||
(interactive "<!>")
|
||||
(if (and bang (fboundp '+workspace/kill-session))
|
||||
(+workspace/kill-session)
|
||||
(doom/kill-all-buffers)))
|
||||
|
||||
;;;###autoload (autoload '+evil:kill-matching-buffers "editor/evil/autoload/ex" nil t)
|
||||
(evil-define-command +evil:kill-matching-buffers (&optional bang pattern)
|
||||
"Kill all buffers matching PATTERN regexp. If BANG, only match project
|
||||
buffers."
|
||||
(interactive "<a>")
|
||||
(doom/kill-matching-buffers pattern bang))
|
||||
|
||||
;;;###autoload (autoload '+evil:help "editor/evil/autoload/ex" nil t)
|
||||
(evil-define-command +evil:help (&optional bang query)
|
||||
"Look up help documentation for QUERY in Emacs documentation.
|
||||
|
||||
If BANG, search Doom documentation."
|
||||
(interactive "<!><a>")
|
||||
(if bang
|
||||
(doom/help-search query)
|
||||
(cond ((or (null query) (string-empty-p (string-trim query)))
|
||||
(call-interactively
|
||||
(or (command-remapping #'apropos)
|
||||
#'apropos)))
|
||||
((string-match-p "^ *:[a-z]" query)
|
||||
(let* ((modules
|
||||
(cl-loop for path in (doom-module-load-path 'all)
|
||||
for (cat . mod) = (doom-module-from-path path)
|
||||
for format = (format "%s %s" cat mod)
|
||||
if (doom-module-p cat mod)
|
||||
collect (propertize format 'module (list cat mod))
|
||||
else if (and cat mod)
|
||||
collect (propertize format
|
||||
'face 'font-lock-comment-face
|
||||
'module (list cat mod))))
|
||||
(module (completing-read "Describe module: " modules nil t query))
|
||||
(key (get-text-property 0 'module module)))
|
||||
(doom/help-modules key)))
|
||||
((and (string-match-p "\\(?:SPC\\|[CMsSH]-[^ ]\\|<[^>]+>\\)" query)
|
||||
(helpful-key (kbd (string-trim query)))))
|
||||
((apropos query t)))))
|
|
@ -44,8 +44,8 @@
|
|||
(user-error "Must be called from a file-visiting buffer"))
|
||||
(let* ((directory (file-name-directory buffer-file-name))
|
||||
(filename (file-name-nondirectory buffer-file-name))
|
||||
(files (doom-files-in directory :depth 0 :sort t :match "/[^._][^/]*$"))
|
||||
(index (cl-position filename files :test #'string=)))
|
||||
(files (doom-glob (file-name-directory buffer-file-name) "[!.]*"))
|
||||
(index (cl-position filename files :test #'file-equal-p)))
|
||||
(when (null index)
|
||||
(user-error "Couldn't find this file in current directory"))
|
||||
(let ((index (+ index n)))
|
||||
|
|
|
@ -18,8 +18,9 @@ directives. By default, this only recognizes C directives.")
|
|||
(defvar evil-want-C-u-scroll t)
|
||||
(defvar evil-want-C-w-scroll t)
|
||||
(defvar evil-want-Y-yank-to-eol t)
|
||||
(defvar evil-want-abbrev-expand-on-insert-exit nil)
|
||||
|
||||
(def-package! evil
|
||||
(use-package! evil
|
||||
:hook (doom-init-modules . evil-mode)
|
||||
:demand t
|
||||
:preface
|
||||
|
@ -36,9 +37,9 @@ directives. By default, this only recognizes C directives.")
|
|||
;; more vim-like behavior
|
||||
evil-symbol-word-search t
|
||||
;; cursor appearance
|
||||
evil-default-cursor '+evil-default-cursor
|
||||
evil-default-cursor '+evil-default-cursor-fn
|
||||
evil-normal-state-cursor 'box
|
||||
evil-emacs-state-cursor '(box +evil-emacs-cursor)
|
||||
evil-emacs-state-cursor '(box +evil-emacs-cursor-fn)
|
||||
evil-insert-state-cursor 'bar
|
||||
evil-visual-state-cursor 'hollow
|
||||
;; must be set before evil/evil-collection is loaded
|
||||
|
@ -49,15 +50,21 @@ directives. By default, this only recognizes C directives.")
|
|||
|
||||
(put 'evil-define-key* 'lisp-indent-function 'defun)
|
||||
|
||||
;; stop copying each visual state move to the clipboard:
|
||||
;; https://bitbucket.org/lyro/evil/issue/336/osx-visual-state-copies-the-region-on
|
||||
;; grokked from:
|
||||
;; http://stackoverflow.com/questions/15873346/elisp-rename-macro
|
||||
(advice-add #'evil-visual-update-x-selection :override #'ignore)
|
||||
|
||||
;; Start help-with-tutorial in emacs state
|
||||
(advice-add #'help-with-tutorial :after (lambda (&rest _) (evil-emacs-state +1)))
|
||||
|
||||
;; Done in a hook to ensure the popup rules load as late as possible
|
||||
(defun +evil|init-popup-rules ()
|
||||
(add-hook! 'doom-init-modules-hook
|
||||
(defun +evil--init-popup-rules-h ()
|
||||
(set-popup-rules!
|
||||
'(("^\\*evil-registers" :size 0.3)
|
||||
("^\\*Command Line" :size 8))))
|
||||
(add-hook 'doom-init-modules-hook #'+evil|init-popup-rules)
|
||||
("^\\*Command Line" :size 8)))))
|
||||
|
||||
;; Change the cursor color in emacs state. We do it this roundabout way
|
||||
;; instead of changing `evil-default-cursor' (or `evil-emacs-state-cursor') so
|
||||
|
@ -65,19 +72,17 @@ directives. By default, this only recognizes C directives.")
|
|||
(defvar +evil--default-cursor-color "#ffffff")
|
||||
(defvar +evil--emacs-cursor-color "#ff9999")
|
||||
|
||||
(defun +evil|update-cursor-color ()
|
||||
(add-hook! 'doom-load-theme-hook
|
||||
(defun +evil-update-cursor-color-h ()
|
||||
(setq +evil--default-cursor-color (face-background 'cursor)
|
||||
+evil--emacs-cursor-color (face-foreground 'warning)))
|
||||
(add-hook 'doom-load-theme-hook #'+evil|update-cursor-color)
|
||||
+evil--emacs-cursor-color (face-foreground 'warning))))
|
||||
|
||||
(defun +evil-default-cursor ()
|
||||
(defun +evil-default-cursor-fn ()
|
||||
(evil-set-cursor-color +evil--default-cursor-color))
|
||||
(defun +evil-emacs-cursor ()
|
||||
(defun +evil-emacs-cursor-fn ()
|
||||
(evil-set-cursor-color +evil--emacs-cursor-color))
|
||||
|
||||
(defun +evil|update-shift-width ()
|
||||
(setq evil-shift-width tab-width))
|
||||
(add-hook 'after-change-major-mode-hook #'+evil|update-shift-width)
|
||||
(setq-hook! 'after-change-major-mode-hook evil-shift-width tab-width)
|
||||
|
||||
|
||||
;; --- keybind fixes ----------------------
|
||||
|
@ -86,92 +91,101 @@ directives. By default, this only recognizes C directives.")
|
|||
;; `evil-delete' in wgrep buffers.
|
||||
(define-key wgrep-mode-map [remap evil-delete] #'+evil-delete))
|
||||
|
||||
(defun +evil|disable-highlights ()
|
||||
(add-hook! 'doom-escape-hook
|
||||
(defun +evil-disable-ex-highlights-h ()
|
||||
"Disable ex search buffer highlights."
|
||||
(when (evil-ex-hl-active-p 'evil-ex-search)
|
||||
(evil-ex-nohighlight)
|
||||
t))
|
||||
(add-hook 'doom-escape-hook #'+evil|disable-highlights)
|
||||
t)))
|
||||
|
||||
|
||||
;; --- evil hacks -------------------------
|
||||
(defun +evil|display-vimlike-save-message ()
|
||||
(unless noninteractive
|
||||
(setq save-silently t)
|
||||
(add-hook! 'after-save-hook
|
||||
(defun +evil-display-vimlike-save-message-h ()
|
||||
"Shorter, vim-esque save messages."
|
||||
(message "\"%s\" %dL, %dC written"
|
||||
(if buffer-file-name
|
||||
(file-relative-name (file-truename buffer-file-name) (doom-project-root))
|
||||
(buffer-name))
|
||||
(count-lines (point-min) (point-max))
|
||||
(buffer-size)))
|
||||
(unless noninteractive
|
||||
(setq save-silently t)
|
||||
(add-hook 'after-save-hook #'+evil|display-vimlike-save-message))
|
||||
(buffer-size)))))
|
||||
;; Make ESC (from normal mode) the universal escaper. See `doom-escape-hook'.
|
||||
(advice-add #'evil-force-normal-state :after #'+evil*escape)
|
||||
(advice-add #'evil-force-normal-state :after #'+evil-escape-a)
|
||||
;; Don't move cursor when indenting
|
||||
(advice-add #'evil-indent :around #'+evil*static-reindent)
|
||||
(advice-add #'evil-indent :around #'+evil--static-reindent-a)
|
||||
;; monkey patch `evil-ex-replace-special-filenames' to improve support for
|
||||
;; file modifiers like %:p:h. This adds support for most of vim's modifiers,
|
||||
;; and one custom one: %:P (expand to the project root).
|
||||
(advice-add #'evil-ex-replace-special-filenames :override #'+evil*resolve-vim-path)
|
||||
(advice-add #'evil-ex-replace-special-filenames :override #'+evil-resolve-vim-path-a)
|
||||
|
||||
;; make `try-expand-dabbrev' (from `hippie-expand') work in minibuffer
|
||||
(add-hook 'minibuffer-inactive-mode-hook #'+evil*fix-dabbrev-in-minibuffer)
|
||||
(add-hook 'minibuffer-inactive-mode-hook #'+evil--fix-dabbrev-in-minibuffer-h)
|
||||
|
||||
;; Focus and recenter new splits
|
||||
(advice-add #'evil-window-split :override #'+evil*window-split)
|
||||
(advice-add #'evil-window-vsplit :override #'+evil*window-vsplit)
|
||||
(advice-add #'evil-window-split :override #'+evil-window-split-a)
|
||||
(advice-add #'evil-window-vsplit :override #'+evil-window-vsplit-a)
|
||||
|
||||
;; In evil, registers 2-9 are buffer-local. In vim, they're global, so...
|
||||
(advice-add #'evil-global-marker-p :around #'+evil*make-numbered-markers-global)
|
||||
(advice-add #'evil-global-marker-p :around #'+evil--make-numbered-markers-global-a)
|
||||
|
||||
;; Make o/O continue comments (see `+evil-want-o/O-to-continue-comments')
|
||||
(advice-add #'evil-open-above :around #'+evil*insert-newline-above-and-respect-comments)
|
||||
(advice-add #'evil-open-below :around #'+evil*insert-newline-below-and-respect-comments)
|
||||
(advice-add #'evil-open-above :around #'+evil--insert-newline-above-and-respect-comments-a)
|
||||
(advice-add #'evil-open-below :around #'+evil--insert-newline-below-and-respect-comments-a)
|
||||
|
||||
;; Recenter screen after most searches
|
||||
(advice-add! '(evil-visualstar/begin-search-forward
|
||||
(dolist (fn '(evil-visualstar/begin-search-forward
|
||||
evil-visualstar/begin-search-backward
|
||||
evil-ex-search-word-backward
|
||||
evil-ex-search-word-backward
|
||||
evil-ex-search-forward
|
||||
evil-ex-search-backward)
|
||||
:after #'doom*recenter)
|
||||
evil-ex-search-backward))
|
||||
(advice-add fn :after #'doom-recenter-a))
|
||||
|
||||
;; --- custom interactive codes -----------
|
||||
;; These arg types will highlight matches in the current buffer
|
||||
(evil-ex-define-argument-type buffer-match :runner +evil-ex-buffer-match)
|
||||
(evil-ex-define-argument-type global-match :runner +evil-ex-global-match)
|
||||
(evil-ex-define-argument-type regexp-match
|
||||
:runner (lambda (flag &optional arg) (+evil-ex-regexp-match flag arg 'inverted)))
|
||||
(evil-ex-define-argument-type regexp-global-match
|
||||
:runner +evil-ex-regexp-match)
|
||||
|
||||
(defun +evil--regexp-match-args (arg)
|
||||
(when (evil-ex-p)
|
||||
(cl-destructuring-bind (&optional arg flags)
|
||||
(evil-delimited-arguments arg 2)
|
||||
(list arg (string-to-list flags)))))
|
||||
|
||||
;; Other commands can make use of this
|
||||
(evil-define-interactive-code "<//>"
|
||||
:ex-arg buffer-match (list (if (evil-ex-p) evil-ex-argument)))
|
||||
(evil-define-interactive-code "<//g>"
|
||||
:ex-arg global-match (list (if (evil-ex-p) evil-ex-argument)))
|
||||
:ex-arg regexp-match
|
||||
(+evil--regexp-match-args evil-ex-argument))
|
||||
|
||||
;; By default :g[lobal] doesn't highlight matches in the current buffer. I've
|
||||
;; got to write my own argument type and interactive code to get it to do so.
|
||||
(evil-ex-define-argument-type global-delim-match :runner +evil-ex-global-delim-match)
|
||||
(dolist (sym '(evil-ex-global evil-ex-global-inverted))
|
||||
(evil-set-command-property sym :ex-arg 'global-delim-match))
|
||||
(evil-define-interactive-code "<//!>"
|
||||
:ex-arg regexp-global-match
|
||||
(+evil--regexp-match-args evil-ex-argument))
|
||||
|
||||
;; Forward declare these so that ex completion works, even if the autoloaded
|
||||
;; functions aren't loaded yet.
|
||||
(evil-set-command-properties
|
||||
'+evil:align :move-point t :ex-arg 'buffer-match :ex-bang t :keep-visual t :suppress-operator t)
|
||||
(evil-add-command-properties '+evil:align :ex-arg 'regexp-match)
|
||||
(evil-add-command-properties '+evil:align-right :ex-arg 'regexp-match)
|
||||
(evil-add-command-properties '+multiple-cursors:evil-mc :ex-arg 'regexp-global-match)
|
||||
|
||||
;; `evil-collection'
|
||||
(when (and (featurep! +everywhere)
|
||||
(not doom-reloading-p))
|
||||
(load! "+everywhere"))
|
||||
|
||||
;; Custom evil ex commands
|
||||
(load! "+commands"))
|
||||
;; Lazy load evil ex commands
|
||||
(delq! 'evil-ex features)
|
||||
(add-transient-hook! 'evil-ex (provide 'evil-ex))
|
||||
(after! evil-ex (load! "+commands")))
|
||||
|
||||
|
||||
;;
|
||||
;; Packages
|
||||
|
||||
(def-package! evil-commentary
|
||||
(use-package! evil-commentary
|
||||
:commands (evil-commentary
|
||||
evil-commentary-yank
|
||||
evil-commentary-yank-line
|
||||
|
@ -179,8 +193,8 @@ directives. By default, this only recognizes C directives.")
|
|||
:config (evil-commentary-mode 1))
|
||||
|
||||
|
||||
(def-package! evil-easymotion
|
||||
:commands (evilem-create evilem-default-keybindings)
|
||||
(use-package! evil-easymotion
|
||||
:commands evilem-create evilem-default-keybindings
|
||||
:config
|
||||
;; Use evil-search backend, instead of isearch
|
||||
(evilem-make-motion evilem-motion-search-next #'evil-ex-search-next
|
||||
|
@ -194,27 +208,27 @@ directives. By default, this only recognizes C directives.")
|
|||
:bind ((evil-ex-search-highlight-all nil))))
|
||||
|
||||
|
||||
(def-package! evil-embrace
|
||||
:commands (embrace-add-pair embrace-add-pair-regexp)
|
||||
(use-package! evil-embrace
|
||||
:commands embrace-add-pair embrace-add-pair-regexp
|
||||
:hook (LaTeX-mode . embrace-LaTeX-mode-hook)
|
||||
:hook (org-mode . embrace-org-mode-hook)
|
||||
:hook ((ruby-mode enh-ruby-mode) . embrace-ruby-mode-hook)
|
||||
:hook (emacs-lisp-mode . embrace-emacs-lisp-mode-hook)
|
||||
:hook ((lisp-mode emacs-lisp-mode clojure-mode racket-mode)
|
||||
. +evil|embrace-lisp-mode-hook)
|
||||
:hook ((org-mode LaTeX-mode) . +evil|embrace-latex-mode-hook)
|
||||
. +evil-embrace-lisp-mode-hook-h)
|
||||
:hook ((org-mode LaTeX-mode) . +evil-embrace-latex-mode-hook-h)
|
||||
:hook ((c++-mode rust-mode rustic-mode csharp-mode java-mode swift-mode typescript-mode)
|
||||
. +evil|embrace-angle-bracket-modes-hook)
|
||||
. +evil-embrace-angle-bracket-modes-hook-h)
|
||||
:init
|
||||
(after! evil-surround
|
||||
(evil-embrace-enable-evil-surround-integration))
|
||||
:config
|
||||
(setq evil-embrace-show-help-p nil)
|
||||
|
||||
(defun +evil|embrace-latex-mode-hook ()
|
||||
(defun +evil-embrace-latex-mode-hook-h ()
|
||||
(embrace-add-pair-regexp ?l "\\[a-z]+{" "}" #'+evil--embrace-latex))
|
||||
|
||||
(defun +evil|embrace-lisp-mode-hook ()
|
||||
(defun +evil-embrace-lisp-mode-hook-h ()
|
||||
(push (cons ?f (make-embrace-pair-struct
|
||||
:key ?f
|
||||
:read-function #'+evil--embrace-elisp-fn
|
||||
|
@ -222,7 +236,7 @@ directives. By default, this only recognizes C directives.")
|
|||
:right-regexp ")"))
|
||||
embrace--pairs-list))
|
||||
|
||||
(defun +evil|embrace-angle-bracket-modes-hook ()
|
||||
(defun +evil-embrace-angle-bracket-modes-hook-h ()
|
||||
(set (make-local-variable 'evil-embrace-evil-surround-keys)
|
||||
(delq ?< evil-embrace-evil-surround-keys))
|
||||
(push (cons ?< (make-embrace-pair-struct
|
||||
|
@ -241,9 +255,9 @@ directives. By default, this only recognizes C directives.")
|
|||
:right-regexp "\\[]})]")))
|
||||
|
||||
|
||||
(def-package! evil-escape
|
||||
:commands (evil-escape)
|
||||
:after-call (evil-normal-state-exit-hook)
|
||||
(use-package! evil-escape
|
||||
:commands evil-escape
|
||||
:after-call evil-normal-state-exit-hook
|
||||
:init
|
||||
(setq evil-escape-excluded-states '(normal visual multiedit emacs motion)
|
||||
evil-escape-excluded-major-modes '(neotree-mode treemacs-mode vterm-mode)
|
||||
|
@ -257,19 +271,21 @@ directives. By default, this only recognizes C directives.")
|
|||
(evil-escape-mode +1))
|
||||
|
||||
|
||||
(def-package! evil-exchange
|
||||
(use-package! evil-exchange
|
||||
:commands evil-exchange
|
||||
:config
|
||||
(defun +evil|escape-exchange ()
|
||||
(add-hook! 'doom-escape-hook
|
||||
(defun +evil--escape-exchange-h ()
|
||||
(when evil-exchange--overlays
|
||||
(evil-exchange-cancel)
|
||||
t))
|
||||
(add-hook 'doom-escape-hook #'+evil|escape-exchange))
|
||||
t))))
|
||||
|
||||
|
||||
(def-package! evil-snipe
|
||||
:commands (evil-snipe-mode evil-snipe-override-mode
|
||||
evil-snipe-local-mode evil-snipe-override-local-mode)
|
||||
(use-package! evil-snipe
|
||||
:commands (evil-snipe-mode
|
||||
evil-snipe-override-mode
|
||||
evil-snipe-local-mode
|
||||
evil-snipe-override-local-mode)
|
||||
:after-call pre-command-hook
|
||||
:init
|
||||
(setq evil-snipe-smart-case t
|
||||
|
@ -282,7 +298,7 @@ directives. By default, this only recognizes C directives.")
|
|||
(evil-snipe-override-mode +1))
|
||||
|
||||
|
||||
(def-package! evil-surround
|
||||
(use-package! evil-surround
|
||||
:commands (global-evil-surround-mode
|
||||
evil-surround-edit
|
||||
evil-Surround-edit
|
||||
|
@ -290,8 +306,17 @@ directives. By default, this only recognizes C directives.")
|
|||
:config (global-evil-surround-mode 1))
|
||||
|
||||
|
||||
(use-package! evil-traces
|
||||
:after evil-ex
|
||||
:config
|
||||
(pushnew! evil-traces-argument-type-alist
|
||||
'(+evil:align . evil-traces-global)
|
||||
'(+evil:align-right . evil-traces-global))
|
||||
(evil-traces-mode))
|
||||
|
||||
|
||||
;; Allows you to use the selection for * and #
|
||||
(def-package! evil-visualstar
|
||||
(use-package! evil-visualstar
|
||||
:commands (evil-visualstar/begin-search
|
||||
evil-visualstar/begin-search-forward
|
||||
evil-visualstar/begin-search-backward)
|
||||
|
@ -302,7 +327,7 @@ directives. By default, this only recognizes C directives.")
|
|||
|
||||
|
||||
;;
|
||||
;; Text object plugins
|
||||
;;; Text object plugins
|
||||
|
||||
(def-package! exato
|
||||
:commands (evil-outer-xml-attr evil-inner-xml-attr))
|
||||
(use-package! exato
|
||||
:commands evil-outer-xml-attr evil-inner-xml-attr)
|
||||
|
|
|
@ -9,14 +9,14 @@
|
|||
(package! evil-escape)
|
||||
(package! evil-exchange)
|
||||
(package! evil-indent-plus)
|
||||
(package! evil-numbers :recipe (:fetcher github :repo "janpath/evil-numbers"))
|
||||
(package! evil-textobj-anyblock)
|
||||
(package! evil-numbers :recipe (:host github :repo "janpath/evil-numbers"))
|
||||
(package! evil-snipe)
|
||||
(package! evil-surround)
|
||||
(package! evil-textobj-anyblock)
|
||||
(package! evil-traces)
|
||||
(package! evil-visualstar)
|
||||
(package! exato)
|
||||
|
||||
|
||||
;;
|
||||
(when (featurep! +everywhere)
|
||||
;; `evil-collection-neotree' uses the `neotree-make-executor' macro, but this
|
||||
|
|
|
@ -10,10 +10,10 @@
|
|||
(after-all
|
||||
(unload-feature 'evil t))
|
||||
(before-each
|
||||
(fset 'resv #'+evil*resolve-vim-path)
|
||||
(fset 'resv #'+evil-resolve-vim-path-a)
|
||||
(spy-on 'doom-project-root :and-call-fake (lambda () project-root)))
|
||||
|
||||
;; `evil-ex-replace-special-filenames' / `+evil*resolve-vim-path'
|
||||
;; `evil-ex-replace-special-filenames' / `+evil-resolve-vim-path-a'
|
||||
(describe "file modifiers"
|
||||
(it "supports basic vim file modifiers"
|
||||
(let ((buffer-file-name "~/.emacs.d/test/modules/feature/test-evil.el")
|
||||
|
|
|
@ -114,11 +114,12 @@ information.")
|
|||
(or (file-in-directory-p file doom-private-dir)
|
||||
(file-in-directory-p file doom-emacs-dir)))
|
||||
|
||||
(defun +file-templates|check ()
|
||||
(defun +file-templates-check-h ()
|
||||
"Check if the current buffer is a candidate for file template expansion. It
|
||||
must be non-read-only, empty, and there must be a rule in
|
||||
`+file-templates-alist' that applies to it."
|
||||
(when (and (not buffer-read-only)
|
||||
(when (and (not (file-exists-p (or (buffer-file-name) "")))
|
||||
(not buffer-read-only)
|
||||
(bobp) (eobp)
|
||||
(not (string-match-p "^ *\\*" (buffer-name))))
|
||||
(when-let (rule (cl-find-if #'+file-template-p +file-templates-alist))
|
||||
|
@ -143,4 +144,4 @@ must be non-read-only, empty, and there must be a rule in
|
|||
(yas-reload-all)))
|
||||
|
||||
;;
|
||||
(add-hook 'find-file-hook #'+file-templates|check)
|
||||
(add-hook 'find-file-hook #'+file-templates-check-h)
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
:group 'doom-themes)
|
||||
|
||||
;;;###autoload
|
||||
(defun +fold-hideshow-haml-forward-sexp (arg)
|
||||
(defun +fold-hideshow-haml-forward-sexp-fn (arg)
|
||||
(haml-forward-sexp arg)
|
||||
(move-beginning-of-line 1))
|
||||
|
||||
;;;###autoload
|
||||
(defun +fold-hideshow-forward-block-by-indent (_arg)
|
||||
(defun +fold-hideshow-forward-block-by-indent-fn (_arg)
|
||||
(let ((start (current-indentation)))
|
||||
(forward-line)
|
||||
(unless (= start (current-indentation))
|
||||
|
@ -20,7 +20,7 @@
|
|||
(end-of-line)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +fold-hideshow-set-up-overlay (ov)
|
||||
(defun +fold-hideshow-set-up-overlay-fn (ov)
|
||||
(when (eq 'code (overlay-get ov 'hs))
|
||||
(when (featurep 'vimish-fold)
|
||||
(overlay-put
|
||||
|
|
|
@ -17,21 +17,22 @@
|
|||
;;
|
||||
;; Packages
|
||||
|
||||
(def-package! hideshow ; built-in
|
||||
:commands (hs-toggle-hiding hs-hide-block hs-hide-level hs-show-all hs-hide-all)
|
||||
(use-package! hideshow ; built-in
|
||||
:commands (hs-toggle-hiding
|
||||
hs-hide-block
|
||||
hs-hide-level
|
||||
hs-show-all
|
||||
hs-hide-all)
|
||||
:config
|
||||
(setq hs-hide-comments-when-hiding-all nil
|
||||
;; Nicer code-folding overlays (with fringe indicators)
|
||||
hs-set-up-overlay #'+fold-hideshow-set-up-overlay)
|
||||
hs-set-up-overlay #'+fold-hideshow-set-up-overlay-fn)
|
||||
|
||||
(defun +fold-hideshow*ensure-mode (&rest _)
|
||||
(defadvice! +fold--hideshow-ensure-mode-a (&rest _)
|
||||
"Ensure `hs-minor-mode' is enabled."
|
||||
:before '(hs-toggle-hiding hs-hide-block hs-hide-level hs-show-all hs-hide-all)
|
||||
(unless (bound-and-true-p hs-minor-mode)
|
||||
(hs-minor-mode +1)))
|
||||
(advice-add! '(hs-toggle-hiding
|
||||
hs-hide-block hs-hide-level
|
||||
hs-show-all hs-hide-all)
|
||||
:before #'+fold-hideshow*ensure-mode)
|
||||
|
||||
;; extra folding support for more languages
|
||||
(unless (assq 't hs-special-modes-alist)
|
||||
|
@ -41,8 +42,8 @@
|
|||
(yaml-mode "\\s-*\\_<\\(?:[^:]+\\)\\_>"
|
||||
""
|
||||
"#"
|
||||
+fold-hideshow-forward-block-by-indent nil)
|
||||
(haml-mode "[#.%]" "\n" "/" +fold-hideshow-haml-forward-sexp nil)
|
||||
+fold-hideshow-forward-block-by-indent-fn nil)
|
||||
(haml-mode "[#.%]" "\n" "/" +fold-hideshow-haml-forward-sexp-fn nil)
|
||||
(ruby-mode "class\\|d\\(?:ef\\|o\\)\\|module\\|[[{]"
|
||||
"end\\|[]}]"
|
||||
"#\\|=begin"
|
||||
|
@ -61,7 +62,7 @@
|
|||
'((t))))))
|
||||
|
||||
|
||||
(def-package! evil-vimish-fold
|
||||
(use-package! evil-vimish-fold
|
||||
:when (featurep! :editor evil)
|
||||
:commands (evil-vimish-fold/next-fold evil-vimish-fold/previous-fold
|
||||
evil-vimish-fold/delete evil-vimish-fold/delete-all
|
||||
|
|
|
@ -98,7 +98,7 @@ Stolen shamelessly from go-mode"
|
|||
(if fmt (cons (intern fmt) t))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +format*probe (orig-fn)
|
||||
(defun +format-probe-a (orig-fn)
|
||||
"Use `+format-with' instead, if it is set."
|
||||
(if +format-with
|
||||
(list +format-with t)
|
||||
|
@ -119,7 +119,7 @@ formatted text, ERRORS are any errors in string format, and FIRST-DIFF is the
|
|||
position of the first change in the buffer.
|
||||
|
||||
See `+format/buffer' for the interactive version of this function, and
|
||||
`+format|buffer' to use as a `before-save-hook' hook."
|
||||
`+format-buffer-h' to use as a `before-save-hook' hook."
|
||||
(if (not formatter)
|
||||
'no-formatter
|
||||
(let ((f-function (gethash formatter format-all--format-table))
|
||||
|
@ -228,12 +228,12 @@ is selected)."
|
|||
;; Hooks
|
||||
|
||||
;;;###autoload
|
||||
(defun +format|enable-on-save ()
|
||||
(defun +format-enable-on-save-h ()
|
||||
"Enables formatting on save."
|
||||
(add-hook 'before-save-hook #'+format|buffer nil t))
|
||||
(add-hook 'before-save-hook #'+format-buffer-h nil t))
|
||||
|
||||
;;;###autoload
|
||||
(defalias '+format|buffer #'+format/buffer
|
||||
(defalias '+format-buffer-h #'+format/buffer
|
||||
"Format the source code in the current buffer with minimal feedback.
|
||||
|
||||
Meant for `before-save-hook'.")
|
||||
|
|
|
@ -25,7 +25,7 @@ Indentation is always preserved when formatting regions.")
|
|||
;;
|
||||
;;; Bootstrap
|
||||
|
||||
(defun +format|enable-on-save-maybe ()
|
||||
(defun +format-enable-on-save-maybe-h ()
|
||||
"Enable formatting on save in certain major modes.
|
||||
|
||||
This is controlled by `+format-on-save-enabled-modes'."
|
||||
|
@ -39,7 +39,7 @@ This is controlled by `+format-on-save-enabled-modes'."
|
|||
(format-all-mode +1)))
|
||||
|
||||
(when (featurep! +onsave)
|
||||
(add-hook 'after-change-major-mode-hook #'+format|enable-on-save-maybe))
|
||||
(add-hook 'after-change-major-mode-hook #'+format-enable-on-save-maybe-h))
|
||||
|
||||
|
||||
;;
|
||||
|
@ -47,7 +47,7 @@ This is controlled by `+format-on-save-enabled-modes'."
|
|||
|
||||
;; Allow a specific formatter to be used by setting `+format-with', either
|
||||
;; buffer-locally or let-bound.
|
||||
(advice-add #'format-all--probe :around #'+format*probe)
|
||||
(advice-add #'format-all--probe :around #'+format-probe-a)
|
||||
|
||||
;; Doom uses a modded `format-all-buffer', which
|
||||
;; 1. Enables partial reformatting (while preserving leading indentation),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
;;; editor/lispy/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(def-package! lispy
|
||||
(use-package! lispy
|
||||
:hook ((common-lisp-mode . lispy-mode)
|
||||
(emacs-lisp-mode . lispy-mode)
|
||||
(scheme-mode . lispy-mode)
|
||||
|
@ -12,7 +12,7 @@
|
|||
(setq lispy-close-quotes-at-end-p t)
|
||||
(add-hook 'lispy-mode-hook #'turn-off-smartparens-mode))
|
||||
|
||||
(def-package! lispyville
|
||||
(use-package! lispyville
|
||||
:when (featurep! :editor evil)
|
||||
:hook (lispy-mode . lispyville-mode)
|
||||
:config
|
||||
|
|
|
@ -1,18 +1,27 @@
|
|||
;;; editor/multiple-cursors/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(def-package! evil-mc
|
||||
(use-package! evil-mc
|
||||
:when (featurep! :editor evil)
|
||||
:commands (evil-mc-make-cursor-here evil-mc-make-all-cursors
|
||||
evil-mc-undo-all-cursors evil-mc-pause-cursors
|
||||
evil-mc-resume-cursors evil-mc-make-and-goto-first-cursor
|
||||
:commands (evil-mc-make-cursor-here
|
||||
evil-mc-make-all-cursors
|
||||
evil-mc-undo-all-cursors
|
||||
evil-mc-pause-cursors
|
||||
evil-mc-resume-cursors
|
||||
evil-mc-make-and-goto-first-cursor
|
||||
evil-mc-make-and-goto-last-cursor
|
||||
evil-mc-make-cursor-move-next-line
|
||||
evil-mc-make-cursor-move-prev-line evil-mc-make-cursor-at-pos
|
||||
evil-mc-has-cursors-p evil-mc-make-and-goto-next-cursor
|
||||
evil-mc-skip-and-goto-next-cursor evil-mc-make-and-goto-prev-cursor
|
||||
evil-mc-skip-and-goto-prev-cursor evil-mc-make-and-goto-next-match
|
||||
evil-mc-skip-and-goto-next-match evil-mc-skip-and-goto-next-match
|
||||
evil-mc-make-and-goto-prev-match evil-mc-skip-and-goto-prev-match)
|
||||
evil-mc-make-cursor-move-prev-line
|
||||
evil-mc-make-cursor-at-pos
|
||||
evil-mc-has-cursors-p
|
||||
evil-mc-make-and-goto-next-cursor
|
||||
evil-mc-skip-and-goto-next-cursor
|
||||
evil-mc-make-and-goto-prev-cursor
|
||||
evil-mc-skip-and-goto-prev-cursor
|
||||
evil-mc-make-and-goto-next-match
|
||||
evil-mc-skip-and-goto-next-match
|
||||
evil-mc-skip-and-goto-next-match
|
||||
evil-mc-make-and-goto-prev-match
|
||||
evil-mc-skip-and-goto-prev-match)
|
||||
:init
|
||||
(defvar evil-mc-key-map (make-sparse-keymap))
|
||||
:config
|
||||
|
@ -39,13 +48,13 @@
|
|||
;; disable evil-escape in evil-mc; causes unwanted text on invocation
|
||||
(add-to-list 'evil-mc-incompatible-minor-modes 'evil-escape-mode nil #'eq)
|
||||
|
||||
(defun +multiple-cursors|escape-multiple-cursors ()
|
||||
(add-hook! 'doom-escape-hook
|
||||
(defun +multiple-cursors-escape-multiple-cursors-h ()
|
||||
"Clear evil-mc cursors and restore state."
|
||||
(when (evil-mc-has-cursors-p)
|
||||
(evil-mc-undo-all-cursors)
|
||||
(evil-mc-resume-cursors)
|
||||
t))
|
||||
(add-hook 'doom-escape-hook #'+multiple-cursors|escape-multiple-cursors)
|
||||
t)))
|
||||
|
||||
;; Forward declare these so that ex completion and evil-mc support is
|
||||
;; recognized before the autoloaded functions are loaded.
|
||||
|
@ -71,7 +80,8 @@
|
|||
(defvar +mc--compat-evil-prev-state nil)
|
||||
(defvar +mc--compat-mark-was-active nil)
|
||||
|
||||
(defun +multiple-cursors|compat-switch-to-emacs-state ()
|
||||
(add-hook! 'multiple-cursors-mode-enabled-hook
|
||||
(defun +multiple-cursors-compat-switch-to-emacs-state-h ()
|
||||
(when (and (bound-and-true-p evil-mode)
|
||||
(not (memq evil-state '(insert emacs))))
|
||||
(setq +mc--compat-evil-prev-state evil-state)
|
||||
|
@ -82,10 +92,10 @@
|
|||
(evil-emacs-state 1)
|
||||
(when (or +mc--compat-mark-was-active (region-active-p))
|
||||
(goto-char point-before)
|
||||
(set-mark mark-before)))))
|
||||
(add-hook 'multiple-cursors-mode-enabled-hook #'+multiple-cursors|compat-switch-to-emacs-state)
|
||||
(set-mark mark-before))))))
|
||||
|
||||
(defun +multiple-cursors|compat-back-to-previous-state ()
|
||||
(add-hook! 'multiple-cursors-mode-disabled-hook
|
||||
(defun +multiple-cursors-compat-back-to-previous-state-h ()
|
||||
(when +mc--compat-evil-prev-state
|
||||
(unwind-protect
|
||||
(case +mc--compat-evil-prev-state
|
||||
|
@ -93,23 +103,22 @@
|
|||
(t (message "Don't know how to handle previous state: %S"
|
||||
+mc--compat-evil-prev-state)))
|
||||
(setq +mc--compat-evil-prev-state nil)
|
||||
(setq +mc--compat-mark-was-active nil))))
|
||||
(add-hook 'multiple-cursors-mode-disabled-hook #'+multiple-cursors|compat-back-to-previous-state)
|
||||
(setq +mc--compat-mark-was-active nil)))))
|
||||
|
||||
;; When running edit-lines, point will return (position + 1) as a
|
||||
;; result of how evil deals with regions
|
||||
(defun +multiple-cursors*adjust-mark-for-evil (&rest _)
|
||||
;; When running edit-lines, point will return (position + 1) as a result of
|
||||
;; how evil deals with regions
|
||||
(defadvice! +multiple--cursors-adjust-mark-for-evil-a (&rest _)
|
||||
:before #'mc/edit-lines
|
||||
(when (and (bound-and-true-p evil-mode)
|
||||
(not (memq evil-state '(insert emacs))))
|
||||
(if (> (point) (mark))
|
||||
(goto-char (1- (point)))
|
||||
(push-mark (1- (mark))))))
|
||||
(advice-add #'mc/edit-lines :before #'+multiple-cursors*adjust-mark-for-evil)
|
||||
|
||||
(defun +multiple-cursors|evil-compat-rect-switch-state ()
|
||||
(add-hook! 'rectangular-region-mode-hook
|
||||
(defun +multiple-cursors-evil-compat-rect-switch-state-h ()
|
||||
(if rectangular-region-mode
|
||||
(+multiple-cursors|compat-switch-to-emacs-state)
|
||||
(setq +mc--compat-evil-prev-state nil)))
|
||||
(add-hook 'rectangular-region-mode-hook '+multiple-cursors|evil-compat-rect-switch-state)
|
||||
(+multiple-cursors-compat-switch-to-emacs-state-h)
|
||||
(setq +mc--compat-evil-prev-state nil))))
|
||||
|
||||
(defvar mc--default-cmds-to-run-once nil)))
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
;;; editor/objed/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(def-package! objed
|
||||
(use-package! objed
|
||||
:after-call pre-command-hook
|
||||
:config
|
||||
|
||||
;; Prevent undo actions from exiting edit state
|
||||
(add-to-list 'objed-keeper-commands 'undo-tree-undo)
|
||||
(add-to-list 'objed-keeper-commands 'undo-tree-redo)
|
||||
|
@ -11,21 +10,20 @@
|
|||
|
||||
(defvar +objed--extra-face-remaps nil)
|
||||
|
||||
(defun +objed*add-face-remaps (&rest _)
|
||||
(defadvice! +objed--add-face-remaps-a (&rest _)
|
||||
"Add extra face remaps when objed activates."
|
||||
:after 'objed--init
|
||||
(when (memq 'objed-hl (assq 'hl-line face-remapping-alist))
|
||||
(push (face-remap-add-relative 'solaire-hl-line-face 'objed-hl)
|
||||
+objed--extra-face-remaps)))
|
||||
|
||||
(defun +objed*remove-face-remaps (&rest _)
|
||||
(defadvice! +objed--remove-face-remaps-a (&rest _)
|
||||
"Remove extra face remaps when objed de-activates."
|
||||
:after 'objed--reset
|
||||
(unless (memq 'objed-hl (assq 'hl-line face-remapping-alist))
|
||||
(dolist (remap +objed--extra-face-remaps)
|
||||
(face-remap-remove-relative remap))
|
||||
(setq +objed--extra-face-remaps nil)))
|
||||
|
||||
(advice-add 'objed--init :after #'+objed*add-face-remaps)
|
||||
(advice-add 'objed--reset :after #'+objed*remove-face-remaps)
|
||||
|
||||
(unless (featurep! +manual)
|
||||
(objed-mode +1)))
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
;;; editor/parinfer/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(def-package! parinfer
|
||||
(use-package! parinfer
|
||||
:hook ((emacs-lisp-mode clojure-mode scheme-mode lisp-mode) . parinfer-mode)
|
||||
:init
|
||||
(setq parinfer-extensions
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
`rotate-text' will cycle through."
|
||||
(declare (indent defun))
|
||||
(dolist (mode (doom-enlist modes))
|
||||
(let ((fn-name (intern (format "+rotate-text|init-%s" mode))))
|
||||
(let ((fn-name (intern (format "+rotate-text-init-%s-h" mode))))
|
||||
(fset fn-name
|
||||
(lambda ()
|
||||
(setq-local rotate-text-local-symbols symbols)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue