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"
|
DOOM = "bin/doom"
|
||||||
MODULES = $(patsubst modules/%/, %, $(sort $(dir $(wildcard modules/*/ modules/*/*/))))
|
MODULES = $(patsubst modules/%/, %, $(sort $(dir $(wildcard modules/*/ modules/*/*/))))
|
||||||
|
|
||||||
all:
|
all: deprecated
|
||||||
@$(DOOM) refresh
|
@$(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
|
## Shortcuts
|
||||||
a: autoloads
|
a: autoloads
|
||||||
i: install
|
i: install
|
||||||
|
@ -16,34 +25,33 @@ cp: compile-plugins
|
||||||
re: recompile
|
re: recompile
|
||||||
d: doctor
|
d: doctor
|
||||||
|
|
||||||
quickstart:
|
quickstart: install
|
||||||
@$(DOOM) quickstart
|
|
||||||
|
|
||||||
|
|
||||||
## Package management
|
## Package management
|
||||||
install:
|
install: deprecated
|
||||||
@$(DOOM) install
|
@$(DOOM) install
|
||||||
update:
|
update: deprecated
|
||||||
@$(DOOM) update
|
@$(DOOM) update
|
||||||
autoremove:
|
autoremove: deprecated
|
||||||
@$(DOOM) autoremove
|
@$(DOOM) autoremove
|
||||||
autoloads:
|
autoloads: deprecated
|
||||||
@$(DOOM) autoloads
|
@$(DOOM) autoloads
|
||||||
upgrade:
|
upgrade: deprecated
|
||||||
@$(DOOM) upgrade
|
@$(DOOM) upgrade
|
||||||
|
|
||||||
## Byte compilation
|
## Byte compilation
|
||||||
compile:
|
compile: deprecated
|
||||||
@$(DOOM) compile
|
@$(DOOM) compile
|
||||||
compile-core:
|
compile-core: deprecated
|
||||||
@$(DOOM) compile :core
|
@$(DOOM) compile :core
|
||||||
compile-private:
|
compile-private: deprecated
|
||||||
@$(DOOM) compile :private
|
@$(DOOM) compile :private
|
||||||
compile-plugins:
|
compile-plugins: deprecated
|
||||||
@$(DOOM) compile :plugins
|
@$(DOOM) build
|
||||||
recompile:
|
recompile: deprecated
|
||||||
@$(DOOM) recompile
|
@$(DOOM) recompile
|
||||||
clean:
|
clean: deprecated
|
||||||
@$(DOOM) clean
|
@$(DOOM) clean
|
||||||
# compile-module
|
# compile-module
|
||||||
# compile-module/submodule
|
# compile-module/submodule
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
**Quick start**
|
**Quick start**
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/hlissner/doom-emacs ~/.emacs.d
|
git clone https://github.com/hlissner/doom-emacs ~/.emacs.d
|
||||||
~/.emacs.d/bin/doom quickstart
|
~/.emacs.d/bin/doom install
|
||||||
```
|
```
|
||||||
|
|
||||||
**Table of Contents**
|
**Table of Contents**
|
||||||
|
@ -109,7 +109,7 @@ Feature Highlights
|
||||||
support for a variety of languages.
|
support for a variety of languages.
|
||||||
- A jump-to-definition/references implementation for all languages that tries to
|
- A jump-to-definition/references implementation for all languages that tries to
|
||||||
"just work," resorting to mode-specific functionality, before falling back on
|
"just work," resorting to mode-specific functionality, before falling back on
|
||||||
[dump-jump][url:dump-jump].
|
[dumb-jump][url:dumb-jump].
|
||||||
|
|
||||||
|
|
||||||
Troubleshooting
|
Troubleshooting
|
||||||
|
@ -178,7 +178,7 @@ contributions:
|
||||||
|
|
||||||
[url:company-mode]: https://github.com/company-mode/company-mode
|
[url:company-mode]: https://github.com/company-mode/company-mode
|
||||||
[url:doom-themes]: https://github.com/hlissner/emacs-doom-themes
|
[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:editorconfig]: http://editorconfig.org/
|
||||||
[url:evil-mode]: https://github.com/emacs-evil/evil
|
[url:evil-mode]: https://github.com/emacs-evil/evil
|
||||||
[url:helm]: https://github.com/emacs-helm/helm
|
[url:helm]: https://github.com/emacs-helm/helm
|
||||||
|
|
92
bin/doom
92
bin/doom
|
@ -10,6 +10,11 @@
|
||||||
":"; exec $EMACS --script "$0" -- "$@"
|
":"; exec $EMACS --script "$0" -- "$@"
|
||||||
":"; exit 0
|
":"; exit 0
|
||||||
|
|
||||||
|
(setq user-emacs-directory
|
||||||
|
(or (getenv "EMACSDIR")
|
||||||
|
(expand-file-name "../" (file-name-directory (file-truename load-file-name)))))
|
||||||
|
|
||||||
|
|
||||||
(defun usage ()
|
(defun usage ()
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert (format! "%s %s [COMMAND] [ARGS...]\n"
|
(insert (format! "%s %s [COMMAND] [ARGS...]\n"
|
||||||
|
@ -35,15 +40,14 @@
|
||||||
" -d --debug\t\tTurns on doom-debug-mode (and debug-on-error)\n"
|
" -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"
|
" -e --emacsd DIR\tUse the emacs config at DIR (e.g. ~/.emacs.d)\n"
|
||||||
" -i --insecure\t\tDisable TLS/SSL validation (not recommended)\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"
|
" -p --private DIR\tUse the private module at DIR (e.g. ~/.doom.d)\n"
|
||||||
" -y --yes\t\tAuto-accept all confirmation prompts\n\n")
|
" -y --yes\t\tAuto-accept all confirmation prompts\n\n")
|
||||||
(princ (buffer-string)))
|
(princ (buffer-string)))
|
||||||
(doom--dispatch-help))
|
(doom--dispatch-help))
|
||||||
|
|
||||||
;;
|
;;
|
||||||
(let ((args (cdr (cdr (cdr command-line-args))))
|
(let ((args (cdr (cdr (cdr command-line-args)))))
|
||||||
(emacs-dir (or (getenv "EMACSDIR")
|
|
||||||
(expand-file-name "../" (file-name-directory (file-truename load-file-name))))))
|
|
||||||
;; Parse options
|
;; Parse options
|
||||||
(while (ignore-errors (string-prefix-p "-" (car args)))
|
(while (ignore-errors (string-prefix-p "-" (car args)))
|
||||||
(pcase (pop args)
|
(pcase (pop args)
|
||||||
|
@ -62,47 +66,57 @@
|
||||||
(or (file-directory-p doom-private-dir)
|
(or (file-directory-p doom-private-dir)
|
||||||
(message "Warning: %s does not exist"
|
(message "Warning: %s does not exist"
|
||||||
(abbreviate-file-name doom-private-dir))))
|
(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")
|
((or "-e" "--emacsd")
|
||||||
(setq emacs-dir (expand-file-name (concat (pop args) "/")))
|
(setq user-emacs-directory (expand-file-name (concat (pop args) "/")))
|
||||||
(message "Emacs directory changed to %s" emacs-dir))
|
(message "Emacs directory changed to %s" user-emacs-directory))
|
||||||
((or "-y" "--yes")
|
((or "-y" "--yes")
|
||||||
(setenv "YES" "1")
|
(setenv "YES" "1")
|
||||||
(message "Auto-yes mode on"))))
|
(message "Auto-yes mode on"))))
|
||||||
|
|
||||||
(or (file-directory-p emacs-dir)
|
(unless (file-directory-p user-emacs-directory)
|
||||||
(error "%s does not exist" emacs-dir))
|
(error "%s does not exist" user-emacs-directory))
|
||||||
|
|
||||||
;; Bootstrap Doom
|
;; Bootstrap Doom
|
||||||
(load (expand-file-name "init" emacs-dir)
|
(if (not noninteractive)
|
||||||
nil 'nomessage)
|
(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)
|
(cond ((and (not (cdr args))
|
||||||
(doom|run-all-startup-hooks))
|
(member (car args) '("help" "h")))
|
||||||
((and (not (cdr args))
|
(usage))
|
||||||
(member (car args) '("help" "h")))
|
((not args)
|
||||||
(usage))
|
(print! (error "No command detected.\n"))
|
||||||
((not args)
|
(usage))
|
||||||
(message "No command detected, aborting!\n\nRun %s help for documentation."
|
((require 'core-cli)
|
||||||
(file-name-nondirectory load-file-name)))
|
(let ((default-directory user-emacs-directory))
|
||||||
((let ((default-directory emacs-dir))
|
(setq argv nil)
|
||||||
(setq argv nil
|
(condition-case e
|
||||||
noninteractive 'doom)
|
(doom-dispatch (car args) (cdr args))
|
||||||
(condition-case e
|
(user-error
|
||||||
(doom-dispatch (car args) (cdr args))
|
(print! (error "%s\n") (error-message-string e))
|
||||||
(user-error
|
(print! (yellow "See 'doom help %s' for documentation on this command.") (car args)))
|
||||||
(signal (car e) (cdr e)))
|
((debug error)
|
||||||
((debug error)
|
(message "--------------------------------------------------\n")
|
||||||
(message "--------------------------------------------------\n")
|
(message "There was an unexpected error:")
|
||||||
(message "There was an unexpected error:")
|
(message " %s (%s)" (get (car e) 'error-message) (car e))
|
||||||
(message " %s (%s)" (get (car e) 'error-message) (car e))
|
(dolist (item (cdr e))
|
||||||
(dolist (item (cdr e))
|
(message " %s" item))
|
||||||
(message " %s" item))
|
(unless debug-on-error
|
||||||
(unless debug-on-error
|
(message
|
||||||
(message
|
(concat "\nRun the command again with the -d (or --debug) option to enable debug\n"
|
||||||
(concat "\nRun the command again with the -d (or --debug) option to enable debug\n"
|
"mode and, hopefully, generate a stack trace. If you decide to file a bug\n"
|
||||||
"mode and, hopefully, generate a stack trace. If you decide to file a bug\n"
|
"report, please include it!\n\n"
|
||||||
"report, please include it!\n\n"
|
"Emacs outputs to standard error, so you'll need to redirect stderr to\n"
|
||||||
"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"
|
||||||
"stdout to pipe this to a file or clipboard!\n\n"
|
" e.g. doom -d install 2>&1 | clipboard-program"))
|
||||||
" 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)
|
;; specified by the EMACSDIR envvar)
|
||||||
(setq user-emacs-directory
|
(setq user-emacs-directory
|
||||||
(or (getenv "EMACSDIR")
|
(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)
|
(unless (file-directory-p user-emacs-directory)
|
||||||
(error "Couldn't find a Doom config!"))
|
(error "Couldn't find a Doom config!"))
|
||||||
|
@ -27,8 +28,9 @@
|
||||||
(when (getenv "DEBUG")
|
(when (getenv "DEBUG")
|
||||||
(setq debug-on-error t))
|
(setq debug-on-error t))
|
||||||
|
|
||||||
|
(require 'subr-x)
|
||||||
(require 'pp)
|
(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)
|
(defvar doom-init-p nil)
|
||||||
|
@ -147,7 +149,7 @@
|
||||||
emacs-version)
|
emacs-version)
|
||||||
(explain! "Byte-code compiled in one version of Emacs may not work in another 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"
|
"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...")
|
(section! "Checking for Emacs config conflicts...")
|
||||||
(when (file-exists-p "~/.emacs")
|
(when (file-exists-p "~/.emacs")
|
||||||
|
@ -182,109 +184,7 @@
|
||||||
;; on windows?
|
;; on windows?
|
||||||
(when (memq system-type '(windows-nt ms-dos cygwin))
|
(when (memq system-type '(windows-nt ms-dos cygwin))
|
||||||
(warn! "Warning: Windows detected")
|
(warn! "Warning: Windows detected")
|
||||||
(explain! "DOOM was designed for MacOS and Linux. Expect a bumpy ride!"))
|
(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."))))
|
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
|
@ -292,24 +192,17 @@
|
||||||
|
|
||||||
(condition-case-unless-debug ex
|
(condition-case-unless-debug ex
|
||||||
(let ((after-init-time (current-time))
|
(let ((after-init-time (current-time))
|
||||||
(doom-message-backend 'ansi)
|
(doom-format-backend 'ansi)
|
||||||
noninteractive)
|
noninteractive)
|
||||||
(section! "Checking DOOM Emacs...")
|
(section! "Checking DOOM Emacs...")
|
||||||
(load (concat user-emacs-directory "core/core.el") nil t)
|
(load (concat user-emacs-directory "core/core.el") nil t)
|
||||||
(unless (file-directory-p doom-private-dir)
|
(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))
|
(let ((indent 2))
|
||||||
;; Make sure everything is loaded
|
;; Make sure Doom is initialized and loaded
|
||||||
(require 'core-cli)
|
(doom-initialize 'force)
|
||||||
(require 'core-keybinds)
|
(doom-initialize-core)
|
||||||
(require 'core-ui)
|
|
||||||
(require 'core-projects)
|
|
||||||
(require 'core-editor)
|
|
||||||
(require 'core-packages)
|
|
||||||
|
|
||||||
;; ...and initialized
|
|
||||||
(doom-initialize)
|
|
||||||
(success! "Initialized Doom Emacs %s" doom-version)
|
(success! "Initialized Doom Emacs %s" doom-version)
|
||||||
|
|
||||||
(doom-initialize-modules)
|
(doom-initialize-modules)
|
||||||
|
@ -332,26 +225,23 @@
|
||||||
(when doom-modules
|
(when doom-modules
|
||||||
(section! "Checking your enabled modules...")
|
(section! "Checking your enabled modules...")
|
||||||
(let ((indent (+ indent 2)))
|
(let ((indent (+ indent 2)))
|
||||||
(advice-add #'require :around #'doom*shut-up)
|
(advice-add #'require :around #'doom-shut-up-a)
|
||||||
(maphash
|
(maphash
|
||||||
(lambda (key plist)
|
(lambda (key plist)
|
||||||
(let ((prefix (format! (bold "(%s %s) " (car key) (cdr key)))))
|
(let ((prefix (format! (bold "(%s %s) " (car key) (cdr key)))))
|
||||||
(condition-case-unless-debug ex
|
(condition-case-unless-debug ex
|
||||||
(let ((doctor-file (doom-module-path (car key) (cdr key) "doctor.el"))
|
(let ((doctor-file (doom-module-path (car key) (cdr key) "doctor.el"))
|
||||||
(packages-file (doom-module-path (car key) (cdr key) "packages.el")))
|
(packages-file (doom-module-path (car key) (cdr key) "packages.el")))
|
||||||
(cl-loop with doom--stage = 'packages
|
(cl-loop for name in (let (doom-packages
|
||||||
for name in (let (doom-packages
|
|
||||||
doom-disabled-packages)
|
doom-disabled-packages)
|
||||||
(load packages-file 'noerror 'nomessage)
|
(load packages-file 'noerror 'nomessage)
|
||||||
(mapcar #'car doom-packages))
|
(mapcar #'car doom-packages))
|
||||||
for name = (doom-package-true-name name)
|
unless (or (doom-package-get name :disable)
|
||||||
unless (or (doom-package-prop name :disable)
|
(eval (doom-package-get name :ignore))
|
||||||
(eval (doom-package-prop name :ignore))
|
(doom-package-built-in-p name)
|
||||||
(package-built-in-p name)
|
(doom-package-installed-p name))
|
||||||
(package-installed-p name))
|
|
||||||
do (error! "%s is not installed" 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)))
|
(file-missing (error! "%s" (error-message-string ex)))
|
||||||
(error (error! "Syntax error: %s" ex)))))
|
(error (error! "Syntax error: %s" ex)))))
|
||||||
doom-modules)))))
|
doom-modules)))))
|
||||||
|
|
|
@ -250,46 +250,11 @@ regex PATTERN. Returns the number of killed buffers."
|
||||||
;; Hooks
|
;; Hooks
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom|mark-buffer-as-real ()
|
(defun doom-mark-buffer-as-real-h ()
|
||||||
"Hook function that marks the current buffer as real."
|
"Hook function that marks the current buffer as real."
|
||||||
(doom-set-buffer-real (current-buffer) t))
|
(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
|
;; 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
|
;; This little library thinly wraps around persistent-soft (which is a pcache
|
||||||
;; wrapper, how about that). It has three purposes:
|
;; 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
|
name under `pcache-directory' (by default a subdirectory under
|
||||||
`doom-cache-dir'). One file may contain multiple cache entries.")
|
`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
|
"Hook to run when an Emacs session is killed. Saves all persisted variables
|
||||||
listed in `doom-cache-alists' to files."
|
listed in `doom-cache-alists' to files."
|
||||||
(dolist (alist (butlast doom-cache-alists 1))
|
(dolist (alist (butlast doom-cache-alists 1))
|
||||||
|
@ -29,7 +29,7 @@ listed in `doom-cache-alists' to files."
|
||||||
for var in (cdr alist)
|
for var in (cdr alist)
|
||||||
if (symbol-value var)
|
if (symbol-value var)
|
||||||
do (doom-cache-set var it nil key))))
|
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; -*-
|
;;; core/autoload/cli.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;; Externs
|
||||||
|
(defvar evil-collection-mode-list)
|
||||||
|
|
||||||
(require 'core-cli)
|
(require 'core-cli)
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom-cli-run (command &rest _args)
|
(defun doom--cli-run (command &rest _args)
|
||||||
(when (featurep 'general)
|
(when (featurep 'general)
|
||||||
(general-auto-unbind-keys))
|
(general-auto-unbind-keys))
|
||||||
(let* ((evil-collection-mode-list nil)
|
(let* ((evil-collection-mode-list nil)
|
||||||
(default-directory doom-emacs-dir)
|
(default-directory doom-emacs-dir)
|
||||||
(buf (get-buffer-create " *bin/doom*"))
|
(buf (get-buffer-create " *bin/doom*"))
|
||||||
(doom-message-backend 'ansi)
|
(doom-format-backend 'ansi)
|
||||||
(ignore-window-parameters t)
|
(ignore-window-parameters t)
|
||||||
(noninteractive t)
|
(noninteractive t)
|
||||||
(standard-output
|
(standard-output
|
||||||
|
@ -39,21 +42,21 @@
|
||||||
"TODO"
|
"TODO"
|
||||||
(interactive "P")
|
(interactive "P")
|
||||||
(let ((doom-auto-accept yes))
|
(let ((doom-auto-accept yes))
|
||||||
(doom-cli-run "autoloads")))
|
(doom--cli-run "autoloads")))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom//update (&optional yes)
|
(defun doom//update (&optional yes)
|
||||||
"TODO"
|
"TODO"
|
||||||
(interactive "P")
|
(interactive "P")
|
||||||
(let ((doom-auto-accept yes))
|
(let ((doom-auto-accept yes))
|
||||||
(doom-cli-run "update")))
|
(doom--cli-run "update")))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom//upgrade (&optional yes)
|
(defun doom//upgrade (&optional yes)
|
||||||
"TODO"
|
"TODO"
|
||||||
(interactive "P")
|
(interactive "P")
|
||||||
(let ((doom-auto-accept yes))
|
(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?")
|
(when (y-or-n-p "You must restart Emacs for the upgrade to take effect. Restart?")
|
||||||
(doom/restart-and-restore)))
|
(doom/restart-and-restore)))
|
||||||
|
|
||||||
|
@ -62,18 +65,18 @@
|
||||||
"TODO"
|
"TODO"
|
||||||
(interactive "P")
|
(interactive "P")
|
||||||
(let ((doom-auto-accept yes))
|
(let ((doom-auto-accept yes))
|
||||||
(doom-cli-run "install")))
|
(doom--cli-run "install")))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom//autoremove (&optional yes)
|
(defun doom//autoremove (&optional yes)
|
||||||
"TODO"
|
"TODO"
|
||||||
(interactive "P")
|
(interactive "P")
|
||||||
(let ((doom-auto-accept yes))
|
(let ((doom-auto-accept yes))
|
||||||
(doom-cli-run "autoremove")))
|
(doom--cli-run "autoremove")))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom//refresh (&optional yes)
|
(defun doom//refresh (&optional yes)
|
||||||
"TODO"
|
"TODO"
|
||||||
(interactive "P")
|
(interactive "P")
|
||||||
(let ((doom-auto-accept yes))
|
(let ((doom-auto-accept yes))
|
||||||
(doom-cli-run "refresh")))
|
(doom--cli-run "refresh")))
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
;;; core/autoload/config.el -*- lexical-binding: t; -*-
|
;;; 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
|
;;;###autoload
|
||||||
(defvar doom-reloading-p nil
|
(defvar doom-reloading-p nil
|
||||||
"TODO")
|
"TODO")
|
||||||
|
@ -19,7 +23,7 @@
|
||||||
(doom-project-find-file doom-private-dir))
|
(doom-project-find-file doom-private-dir))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom/reload (&optional force-p)
|
(defun doom/reload ()
|
||||||
"Reloads your private config.
|
"Reloads your private config.
|
||||||
|
|
||||||
This is experimental! It will try to do as `bin/doom refresh' does, but from
|
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.
|
reloads your package list, and lastly, reloads your private config.el.
|
||||||
|
|
||||||
Runs `doom-reload-hook' afterwards."
|
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)
|
(require 'core-cli)
|
||||||
(general-auto-unbind-keys)
|
|
||||||
(let ((doom-reloading-p t))
|
(let ((doom-reloading-p t))
|
||||||
(when (getenv "DOOMENV")
|
(compile (format "%s/bin/doom refresh -f" doom-emacs-dir))
|
||||||
(doom-reload-env-file 'force))
|
(while compilation-in-progress
|
||||||
(doom-reload-autoloads force-p)
|
(sit-for 1))
|
||||||
(let (doom-init-p)
|
(doom-initialize 'force)
|
||||||
(doom-initialize))
|
|
||||||
(with-demoted-errors "PRIVATE CONFIG ERROR: %s"
|
(with-demoted-errors "PRIVATE CONFIG ERROR: %s"
|
||||||
(let (doom-init-modules-p)
|
(general-auto-unbind-keys)
|
||||||
(doom-initialize-modules)))
|
(unwind-protect
|
||||||
(when (bound-and-true-p doom-packages)
|
(doom-initialize-modules 'force)
|
||||||
(doom/reload-packages))
|
(general-auto-unbind-keys t)))
|
||||||
(run-hook-wrapped 'doom-reload-hook #'doom-try-run-hook))
|
(run-hook-wrapped 'doom-reload-hook #'doom-try-run-hook))
|
||||||
(general-auto-unbind-keys t)
|
|
||||||
(message "Finished!"))
|
(message "Finished!"))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom/reload-autoloads (&optional force-p)
|
(defun doom/reload-autoloads ()
|
||||||
"Reload only `doom-autoload-file' and `doom-package-autoload-file'.
|
"Reload only `doom-autoload-file' and `doom-package-autoload-file'.
|
||||||
|
|
||||||
This is much faster and safer than `doom/reload', but not as comprehensive. This
|
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
|
It is useful to only pull in changes performed by 'doom refresh' on the command
|
||||||
line."
|
line."
|
||||||
(interactive "P")
|
(interactive)
|
||||||
(doom-initialize-autoloads doom-autoload-file)
|
(require 'core-cli)
|
||||||
(doom-initialize-autoloads doom-package-autoload-file))
|
(require 'core-packages)
|
||||||
|
(doom-initialize-packages)
|
||||||
|
(doom-reload-autoloads nil 'force))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom/reload-env ()
|
(defun doom/reload-env ()
|
||||||
|
@ -70,26 +79,4 @@ Uses the same mechanism as 'bin/doom env reload'."
|
||||||
(sit-for 1))
|
(sit-for 1))
|
||||||
(unless (file-readable-p doom-env-file)
|
(unless (file-readable-p doom-env-file)
|
||||||
(error "Failed to generate env file"))
|
(error "Failed to generate env file"))
|
||||||
(doom-load-env-vars doom-env-file))
|
(doom-load-envvars-file 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)))
|
|
||||||
|
|
|
@ -1,5 +1,19 @@
|
||||||
;;; core/autoload/debug.el -*- lexical-binding: t; -*-
|
;;; 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
|
;;; Helpers
|
||||||
|
|
||||||
|
@ -16,65 +30,67 @@ ready to be pasted in a bug report on github."
|
||||||
(require 'vc-git)
|
(require 'vc-git)
|
||||||
(let ((default-directory doom-emacs-dir)
|
(let ((default-directory doom-emacs-dir)
|
||||||
(doom-modules (doom-modules)))
|
(doom-modules (doom-modules)))
|
||||||
(format
|
(cl-letf
|
||||||
(concat "- OS: %s (%s)\n"
|
(((symbol-function 'sh)
|
||||||
"- Shell: %s\n"
|
(lambda (format)
|
||||||
"- Emacs: %s (%s)\n"
|
(string-trim
|
||||||
"- Doom: %s (%s)\n"
|
(shell-command-to-string format)))))
|
||||||
"- Graphic display: %s (daemon: %s)\n"
|
`((emacs
|
||||||
"- System features: %s\n"
|
(version . ,emacs-version)
|
||||||
"- Details:\n"
|
(features ,@system-configuration-features)
|
||||||
" ```elisp\n"
|
(build . ,(format-time-string "%b %d, %Y" emacs-build-time))
|
||||||
" env bootstrapper: %s\n"
|
(buildopts ,system-configuration-options))
|
||||||
" elc count: %s\n"
|
(doom
|
||||||
" uname -a: %s\n"
|
(version . ,doom-version)
|
||||||
" modules: %s\n"
|
(build . ,(sh "git log -1 --format=\"%D %h %ci\"")))
|
||||||
" packages: %s\n"
|
(system
|
||||||
" exec-path: %s\n"
|
(type . ,system-type)
|
||||||
" ```")
|
(config . ,system-configuration)
|
||||||
system-type system-configuration
|
(shell . ,shell-file-name)
|
||||||
shell-file-name
|
(uname . ,(if IS-WINDOWS
|
||||||
emacs-version (format-time-string "%b %d, %Y" emacs-build-time)
|
"n/a"
|
||||||
doom-version
|
(sh "uname -msrv")))
|
||||||
(or (string-trim (shell-command-to-string "git log -1 --format=\"%D %h %ci\""))
|
(path . ,(mapcar #'abbreviate-file-name exec-path)))
|
||||||
"n/a")
|
(config
|
||||||
(display-graphic-p) (daemonp)
|
(envfile
|
||||||
(bound-and-true-p system-configuration-features)
|
. ,(cond ((file-exists-p doom-env-file) 'envvar-file)
|
||||||
(cond ((file-exists-p doom-env-file) 'envvar-file)
|
((featurep 'exec-path-from-shell) 'exec-path-from-shell)))
|
||||||
((featurep 'exec-path-from-shell) 'exec-path-from-shell))
|
(elc-files
|
||||||
;; details
|
. ,(length (doom-files-in `(,@doom-modules-dirs
|
||||||
(length (doom-files-in `(,@doom-modules-dirs
|
,doom-core-dir
|
||||||
,doom-core-dir
|
,doom-private-dir)
|
||||||
,doom-private-dir)
|
:type 'files :match "\\.elc$")))
|
||||||
:type 'files :match "\\.elc$" :sort nil))
|
(modules
|
||||||
(if IS-WINDOWS
|
,@(or (cl-loop with cat = nil
|
||||||
"n/a"
|
for key being the hash-keys of doom-modules
|
||||||
(with-temp-buffer
|
if (or (not cat) (not (eq cat (car key))))
|
||||||
(unless (zerop (call-process "uname" nil t nil "-msrv"))
|
do (setq cat (car key))
|
||||||
(insert (format "%s" system-type)))
|
and collect cat
|
||||||
(string-trim (buffer-string))))
|
and collect (cdr key)
|
||||||
(or (cl-loop with cat = nil
|
else collect
|
||||||
for key being the hash-keys of doom-modules
|
(let ((flags (doom-module-get cat (cdr key) :flags)))
|
||||||
if (or (not cat) (not (eq cat (car key))))
|
(if flags
|
||||||
do (setq cat (car key))
|
`(,(cdr key) ,@flags)
|
||||||
and collect cat
|
(cdr key))))
|
||||||
and collect (cdr key)
|
'("n/a")))
|
||||||
else collect
|
(packages
|
||||||
(let ((flags (doom-module-get cat (cdr key) :flags)))
|
,@(or (ignore-errors
|
||||||
(if flags
|
(require 'core-packages)
|
||||||
`(,(cdr key) ,@flags)
|
(doom-initialize-packages)
|
||||||
(cdr key))))
|
(cl-loop for (name . plist) in doom-packages
|
||||||
"n/a")
|
if (doom-package-private-p name)
|
||||||
(or (ignore-errors
|
collect
|
||||||
(require 'use-package)
|
(format
|
||||||
(cl-loop for (name . plist) in (doom-find-packages :private t)
|
"%s" (if-let (splist (doom-plist-delete (copy-sequence plist)
|
||||||
if (use-package-plist-delete (copy-sequence plist) :modules)
|
:modules))
|
||||||
collect (format "%s" (cons name it))
|
(cons name splist)
|
||||||
else
|
name))))
|
||||||
collect (symbol-name name)))
|
'("n/a")))
|
||||||
"n/a")
|
(elpa-packages
|
||||||
;; abbreviate $HOME to hide username
|
,@(or (ignore-errors
|
||||||
(mapcar #'abbreviate-file-name exec-path))))
|
(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."
|
branch and commit."
|
||||||
(interactive)
|
(interactive)
|
||||||
(require 'vc-git)
|
(require 'vc-git)
|
||||||
(print! "Doom v%s (Emacs v%s)\nBranch: %s\nCommit: %s"
|
(let ((default-directory doom-core-dir))
|
||||||
doom-version
|
(print! "Doom v%s (Emacs v%s)\nBranch: %s\nCommit: %s\nBuild date: %s"
|
||||||
emacs-version
|
doom-version
|
||||||
(or (vc-git--symbolic-ref doom-core-dir)
|
emacs-version
|
||||||
"n/a")
|
(or (vc-git--symbolic-ref doom-core-dir)
|
||||||
(or (vc-git-working-revision doom-core-dir)
|
"n/a")
|
||||||
"n/a")))
|
(or (vc-git-working-revision doom-core-dir)
|
||||||
|
"n/a")
|
||||||
|
(or (string-trim (shell-command-to-string "git log -1 --format=%ci"))
|
||||||
|
"n/a"))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom/info ()
|
(defun doom/info (&optional raw)
|
||||||
"Collects some debug information about your Emacs session, formats it into
|
"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!"
|
markdown and copies it to your clipboard, ready to be pasted into bug reports!"
|
||||||
(interactive)
|
(interactive "P")
|
||||||
(message "Generating Doom info...")
|
(let ((buffer (get-buffer-create "*doom-info*"))
|
||||||
(if noninteractive
|
(info (doom-info)))
|
||||||
(print! (doom-info))
|
(with-current-buffer buffer
|
||||||
(kill-new (doom-info))
|
(unless (or noninteractive
|
||||||
(message "Done! Copied to clipboard.")))
|
(eq major-mode 'markdown-mode)
|
||||||
|
(not (fboundp 'markdown-mode)))
|
||||||
|
(markdown-mode))
|
||||||
|
(erase-buffer)
|
||||||
|
(if raw
|
||||||
|
(progn
|
||||||
|
(save-excursion
|
||||||
|
(pp info (current-buffer)))
|
||||||
|
(when (re-search-forward "(modules " nil t)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(cl-destructuring-bind (beg . end)
|
||||||
|
(bounds-of-thing-at-point 'sexp)
|
||||||
|
(let ((sexp (prin1-to-string (sexp-at-point))))
|
||||||
|
(delete-region beg end)
|
||||||
|
(insert sexp)))))
|
||||||
|
(insert "<details>\n\n```\n")
|
||||||
|
(dolist (group info)
|
||||||
|
(insert! "%-8s%-10s %s\n"
|
||||||
|
((car group)
|
||||||
|
(caadr group)
|
||||||
|
(cdadr group)))
|
||||||
|
(dolist (spec (cddr group))
|
||||||
|
(insert! (indent 8 "%-10s %s\n")
|
||||||
|
((car spec) (cdr spec)))))
|
||||||
|
(insert "```\n</details>"))
|
||||||
|
(if noninteractive
|
||||||
|
(print! (buffer-string))
|
||||||
|
(switch-to-buffer buffer)
|
||||||
|
(kill-new (buffer-string))
|
||||||
|
(print! (green "Copied markdown to clipboard"))))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom/am-i-secure ()
|
(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
|
(macroexp-progn
|
||||||
(append `((setq noninteractive nil
|
(append `((setq noninteractive nil
|
||||||
doom-debug-mode t
|
doom-debug-mode t
|
||||||
|
load-path ',load-path
|
||||||
package--init-file-ensured t
|
package--init-file-ensured t
|
||||||
package-user-dir ,package-user-dir
|
package-user-dir ,package-user-dir
|
||||||
package-archives ',package-archives
|
package-archives ',package-archives
|
||||||
user-emacs-directory ,doom-emacs-dir
|
user-emacs-directory ,doom-emacs-dir)
|
||||||
doom--modules-cache nil)
|
|
||||||
(with-eval-after-load 'undo-tree
|
(with-eval-after-load 'undo-tree
|
||||||
;; undo-tree throws errors because `buffer-undo-tree' isn't
|
;; undo-tree throws errors because `buffer-undo-tree' isn't
|
||||||
;; corrrectly initialized
|
;; 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)))
|
(load! "config" (plist-get plist :path) t)))
|
||||||
doom-modules)
|
doom-modules)
|
||||||
(run-hook-wrapped 'doom-init-modules-hook #'doom-try-run-hook)
|
(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
|
(`vanilla-doom ; only Doom core
|
||||||
`((setq doom-private-dir "/tmp/does/not/exist"
|
`((setq doom-private-dir "/tmp/does/not/exist"
|
||||||
doom-init-modules-p t)
|
doom-init-modules-p t)
|
||||||
(load-file ,user-init-file)
|
(load-file ,user-init-file)
|
||||||
(doom|run-all-startup-hooks)))
|
(doom-run-all-startup-hooks-h)))
|
||||||
(`vanilla ; nothing loaded
|
(`vanilla ; nothing loaded
|
||||||
`((package-initialize)))))))
|
`((package-initialize)))))))
|
||||||
"\n(unwind-protect (progn\n" contents "\n)\n"
|
"\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
|
init-file
|
||||||
esup-server-port
|
esup-server-port
|
||||||
esup-depth)
|
esup-depth)
|
||||||
"--eval=(doom|run-all-startup-hooks)"))))
|
"--eval=(doom-run-all-startup-hooks-h)"))))
|
||||||
(when esup-run-as-batch-p
|
(when esup-run-as-batch-p
|
||||||
(setq process-args (append process-args '("--batch"))))
|
(setq process-args (append process-args '("--batch"))))
|
||||||
(setq esup-child-process (apply #'start-process process-args)))
|
(setq esup-child-process (apply #'start-process process-args)))
|
||||||
|
|
|
@ -1,24 +1,94 @@
|
||||||
;;; core/autoload/files.el -*- lexical-binding: t; -*-
|
;;; core/autoload/files.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
;;
|
(defun doom--resolve-path-forms (spec &optional directory)
|
||||||
;; Public library
|
"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
|
;;;###autoload
|
||||||
(cl-defun doom-files-in
|
(cl-defun doom-files-in
|
||||||
(path-or-paths &rest rest
|
(paths &rest rest
|
||||||
&key
|
&key
|
||||||
filter
|
filter
|
||||||
map
|
map
|
||||||
full
|
(full t)
|
||||||
(sort t) ; TODO Allow a function for custom sorting?
|
(follow-symlinks t)
|
||||||
(follow-symlinks t)
|
(type 'files)
|
||||||
(type 'files)
|
(relative-to (unless full default-directory))
|
||||||
(relative-to (unless full default-directory))
|
(depth 99999)
|
||||||
(depth 99999)
|
(mindepth 0)
|
||||||
(mindepth 0)
|
(match "/[^._][^/]+"))
|
||||||
(match "/[^._]"))
|
"Return a list of files/directories in PATHS (one string or a list of them).
|
||||||
"Returns a list of files/directories in PATH-OR-PATHS (one string path or a
|
|
||||||
list of them).
|
|
||||||
|
|
||||||
FILTER is a function or symbol that takes one argument (the path). If it returns
|
FILTER is a function or symbol that takes one argument (the path). If it returns
|
||||||
non-nil, the entry will be excluded.
|
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.
|
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."
|
MATCH is a string regexp. Only entries that match it will be included."
|
||||||
(cond
|
(let (file-name-handler-alist
|
||||||
((listp path-or-paths)
|
result)
|
||||||
(cl-loop for path in path-or-paths
|
(dolist (file (mapcan (doom-rpartial #'doom-glob "*") (doom-enlist paths)))
|
||||||
if (file-directory-p path)
|
(cond ((file-directory-p file)
|
||||||
nconc (apply #'doom-files-in path (plist-put rest :relative-to relative-to))))
|
(nconcq! result
|
||||||
((let ((path path-or-paths)
|
(and (memq type '(t dirs))
|
||||||
result)
|
(string-match-p match file)
|
||||||
(when (file-directory-p path)
|
(not (and filter (funcall filter file)))
|
||||||
(dolist (file (directory-files path nil "." sort))
|
(not (and (file-symlink-p file)
|
||||||
(unless (member file '("." ".."))
|
(not follow-symlinks)))
|
||||||
(let ((fullpath (expand-file-name file path)))
|
(<= mindepth 0)
|
||||||
(cond ((file-directory-p fullpath)
|
(list (cond (map (funcall map file))
|
||||||
(when (and (memq type '(t dirs))
|
(relative-to (file-relative-name file relative-to))
|
||||||
(string-match-p match fullpath)
|
(file))))
|
||||||
(not (and filter (funcall filter fullpath)))
|
(and (>= depth 1)
|
||||||
(not (and (file-symlink-p fullpath)
|
(apply #'doom-files-in file
|
||||||
(not follow-symlinks)))
|
(append (list :mindepth (1- mindepth)
|
||||||
(<= mindepth 0))
|
:depth (1- depth)
|
||||||
(setq result
|
:relative-to relative-to)
|
||||||
(nconc result
|
rest)))))
|
||||||
(list (cond (map (funcall map fullpath))
|
((and (memq type '(t files))
|
||||||
(relative-to (file-relative-name fullpath relative-to))
|
(string-match-p match file)
|
||||||
(fullpath))))))
|
(not (and filter (funcall filter file)))
|
||||||
(unless (< depth 1)
|
(<= mindepth 0))
|
||||||
(setq result
|
(push (if relative-to
|
||||||
(nconc result (apply #'doom-files-in fullpath
|
(file-relative-name file relative-to)
|
||||||
(append `(:mindepth ,(1- mindepth)
|
file)
|
||||||
:depth ,(1- depth)
|
result))))
|
||||||
:relative-to ,relative-to)
|
result))
|
||||||
rest))))))
|
|
||||||
((and (memq type '(t files))
|
;;;###autoload
|
||||||
(string-match-p match fullpath)
|
(defmacro file-exists-p! (files &optional directory)
|
||||||
(not (and filter (funcall filter fullpath)))
|
"Returns non-nil if the FILES in DIRECTORY all exist.
|
||||||
(<= mindepth 0))
|
|
||||||
(push (if relative-to
|
DIRECTORY is a path; defaults to `default-directory'.
|
||||||
(file-relative-name fullpath relative-to)
|
|
||||||
fullpath)
|
Returns the last file found to meet the rules set by FILES, which can be a
|
||||||
result))))))
|
single file or nested compound statement of `and' and `or' statements."
|
||||||
result)))))
|
`(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)
|
(defun doom--forget-file (old-path &optional new-path)
|
||||||
"Ensure `recentf', `projectile' and `save-place' forget OLD-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
|
;;;###autoload
|
||||||
(defun doom/delete-this-file (&optional path force-p)
|
(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))
|
(let ((new-size (+ (string-to-number (aref font xlfd-regexp-pixelsize-subnum))
|
||||||
increment)))
|
increment)))
|
||||||
(unless (> new-size 0)
|
(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)))
|
(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
|
;; Set point size & width to "*", so frame width will adjust to new font size
|
||||||
(aset font xlfd-regexp-pointsize-subnum "*")
|
(aset font xlfd-regexp-pointsize-subnum "*")
|
||||||
|
@ -65,6 +65,15 @@ FRAME parameter defaults to current frame."
|
||||||
;;
|
;;
|
||||||
;;; Commands
|
;;; 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
|
;;;###autoload
|
||||||
(defun doom/increase-font-size (count)
|
(defun doom/increase-font-size (count)
|
||||||
"Enlargens the font size across the current frame."
|
"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
|
;;; Documentation commands
|
||||||
|
|
||||||
|
(defvar org-agenda-files)
|
||||||
(defun doom--org-headings (files &optional depth include-files)
|
(defun doom--org-headings (files &optional depth include-files)
|
||||||
"TODO"
|
"TODO"
|
||||||
(require 'org)
|
(require 'org)
|
||||||
|
@ -155,6 +156,7 @@ selection of all minor-modes, active or not."
|
||||||
(mapc #'kill-buffer org-agenda-new-buffers)
|
(mapc #'kill-buffer org-agenda-new-buffers)
|
||||||
(setq org-agenda-new-buffers nil))))
|
(setq org-agenda-new-buffers nil))))
|
||||||
|
|
||||||
|
(defvar ivy-sort-functions-alist)
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom-completing-read-org-headings (prompt files &optional depth include-files initial-input)
|
(defun doom-completing-read-org-headings (prompt files &optional depth include-files initial-input)
|
||||||
"TODO"
|
"TODO"
|
||||||
|
@ -197,8 +199,7 @@ selection of all minor-modes, active or not."
|
||||||
"Find in News: "
|
"Find in News: "
|
||||||
(nreverse (doom-files-in (expand-file-name "news" doom-docs-dir)
|
(nreverse (doom-files-in (expand-file-name "news" doom-docs-dir)
|
||||||
:match "/[0-9]"
|
:match "/[0-9]"
|
||||||
:relative-to doom-docs-dir
|
:relative-to doom-docs-dir))
|
||||||
:sort t))
|
|
||||||
nil t initial-input))
|
nil t initial-input))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
|
@ -365,10 +366,14 @@ current file is in, or d) the module associated with the current major mode (see
|
||||||
(recenter)
|
(recenter)
|
||||||
(message "Couldn't find the config block"))))))))
|
(message "Couldn't find the config block"))))))))
|
||||||
|
|
||||||
|
(defvar doom--help-packages-list nil)
|
||||||
(defun doom--help-packages-list (&optional refresh)
|
(defun doom--help-packages-list (&optional refresh)
|
||||||
(or (unless refresh
|
(or (unless refresh
|
||||||
(doom-cache-get 'help-packages))
|
doom--help-packages-list)
|
||||||
(doom-cache-set 'help-packages (doom-package-list 'all))))
|
(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)
|
(defun doom--help-package-configs (package)
|
||||||
;; TODO Add git checks, in case ~/.emacs.d isn't a git repo
|
;; 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
|
(split-string
|
||||||
(shell-command-to-string
|
(shell-command-to-string
|
||||||
(format "git grep --no-break --no-heading --line-number '%s %s\\($\\| \\)'"
|
(format "git grep --no-break --no-heading --line-number '%s %s\\($\\| \\)'"
|
||||||
"\\(^;;;###package\\|(after!\\|(def-package!\\)"
|
"\\(^;;;###package\\|(after!\\|(use-package!\\)"
|
||||||
package))
|
package))
|
||||||
"\n" t)))
|
"\n" t)))
|
||||||
|
|
||||||
|
@ -392,59 +397,66 @@ If prefix arg is present, refresh the cache."
|
||||||
(let* ((guess (or (function-called-at-point)
|
(let* ((guess (or (function-called-at-point)
|
||||||
(symbol-at-point))))
|
(symbol-at-point))))
|
||||||
(require 'finder-inf nil t)
|
(require 'finder-inf nil t)
|
||||||
|
(require 'package)
|
||||||
(unless package--initialized
|
(unless package--initialized
|
||||||
(package-initialize t))
|
(package-initialize t))
|
||||||
(let* ((doom--packages (doom--help-packages-list))
|
(let ((packages (cl-delete-duplicates
|
||||||
(packages (cl-delete-duplicates
|
(append (mapcar 'car package-alist)
|
||||||
(append (mapcar 'car package-alist)
|
(mapcar 'car package--builtins)
|
||||||
(mapcar 'car package--builtins)
|
(mapcar 'car (doom--help-packages-list))
|
||||||
(mapcar 'car doom--packages)
|
nil))))
|
||||||
nil))))
|
|
||||||
(unless (memq guess packages)
|
(unless (memq guess packages)
|
||||||
(setq guess nil))
|
(setq guess nil))
|
||||||
(list (intern (completing-read (if guess
|
(list
|
||||||
(format "Select package to search for (default %s): "
|
(intern
|
||||||
guess)
|
(completing-read (if guess
|
||||||
"Describe package: ")
|
(format "Select package to search for (default %s): "
|
||||||
packages nil t nil nil
|
guess)
|
||||||
(if guess (symbol-name guess))))))))
|
"Describe package: ")
|
||||||
|
packages nil t nil nil
|
||||||
|
(if guess (symbol-name guess))))))))
|
||||||
(if (or (package-desc-p package)
|
(if (or (package-desc-p package)
|
||||||
(and (symbolp package)
|
(and (symbolp package)
|
||||||
(or (assq package package-alist)
|
(or (assq package package-alist)
|
||||||
(assq package package-archive-contents)
|
|
||||||
(assq package package--builtins))))
|
(assq package package--builtins))))
|
||||||
(describe-package package)
|
(describe-package package)
|
||||||
(help-setup-xref (list #'doom/help-packages package)
|
(help-setup-xref (list #'doom/help-packages package)
|
||||||
(called-interactively-p 'interactive))
|
(called-interactively-p 'interactive))
|
||||||
(with-help-window (help-buffer)
|
(with-help-window (help-buffer)))
|
||||||
(with-current-buffer standard-output
|
|
||||||
(prin1 package)
|
|
||||||
(princ " is a site package.\n\n"))))
|
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(with-current-buffer (help-buffer)
|
(with-current-buffer (help-buffer)
|
||||||
(let ((doom-packages (doom--help-packages-list))
|
(let ((doom-packages (doom--help-packages-list))
|
||||||
(inhibit-read-only t)
|
(inhibit-read-only t)
|
||||||
(indent (make-string 13 ? )))
|
(indent (make-string 13 ? )))
|
||||||
(goto-char (point-min))
|
(goto-char (point-max))
|
||||||
(if (re-search-forward "^ *Status: " nil t)
|
(if (re-search-forward "^ *Status: " nil t)
|
||||||
(progn
|
(progn
|
||||||
(end-of-line)
|
(end-of-line)
|
||||||
(insert "\n"))
|
(insert "\n"))
|
||||||
(re-search-forward "\n\n" nil t))
|
(re-search-forward "\n\n" nil t))
|
||||||
|
|
||||||
|
(package--print-help-section "Package")
|
||||||
|
(insert (symbol-name package) "\n")
|
||||||
|
|
||||||
(package--print-help-section "Source")
|
(package--print-help-section "Source")
|
||||||
(insert (or (pcase (ignore-errors (doom-package-backend package))
|
(insert (or (pcase (doom-package-backend package)
|
||||||
(`elpa (concat "[M]ELPA " (doom--package-url package)))
|
(`straight
|
||||||
(`quelpa (format "QUELPA %s" (prin1-to-string (doom-package-prop package :recipe))))
|
(format! "Straight\n%s"
|
||||||
(`emacs "Built-in")
|
(indent
|
||||||
(_ (symbol-file package)))
|
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")
|
"unknown")
|
||||||
"\n")
|
"\n")
|
||||||
|
|
||||||
(when (assq package doom-packages)
|
(when (assq package doom-packages)
|
||||||
(package--print-help-section "Modules")
|
(package--print-help-section "Modules")
|
||||||
(insert "Declared by the following Doom modules:\n")
|
(insert "Declared by the following Doom modules:\n")
|
||||||
(dolist (m (doom-package-prop package :modules))
|
(dolist (m (doom-package-get package :modules))
|
||||||
(insert indent)
|
(insert indent)
|
||||||
(doom--help-package-insert-button
|
(doom--help-package-insert-button
|
||||||
(format "%s %s" (car m) (or (cdr m) ""))
|
(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))
|
(find-file (expand-file-name file doom-emacs-dir))
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(forward-line (1- line))
|
(forward-line (1- line))
|
||||||
(recenter)))))))))
|
(recenter)))))
|
||||||
|
|
||||||
|
(insert "\n\n")))))
|
||||||
|
|
||||||
(defvar doom--package-cache nil)
|
(defvar doom--package-cache nil)
|
||||||
(defun doom--package-list ()
|
(defun doom--package-list ()
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
;;; core/autoload/line-numbers.el -*- lexical-binding: t; -*-
|
;;; core/autoload/line-numbers.el -*- lexical-binding: t; -*-
|
||||||
;;;###if (version< emacs-version "26.1")
|
;;;###if (version< emacs-version "26.1")
|
||||||
|
|
||||||
;; This was lifted out of the display-line-numbers library in Emacs 26.1 and
|
;; DEPRECATED This was lifted out of the display-line-numbers library in Emacs
|
||||||
;; modified to use nlinum for Emacs 25.x users. It should be removed should
|
;; 26.1 and modified to use nlinum for Emacs 25.x users. It should be removed
|
||||||
;; Emacs 25 support be removed.
|
;; should Emacs 25 support be removed.
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defvar display-line-numbers t
|
(defvar display-line-numbers t
|
||||||
|
@ -52,7 +52,7 @@ to display all line numbers in the buffer."
|
||||||
:type 'boolean)
|
:type 'boolean)
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun line-number-display-width ()
|
(defun line-number-display-width (&optional _)
|
||||||
"Return the width used for displaying line numbers in the
|
"Return the width used for displaying line numbers in the
|
||||||
selected window."
|
selected window."
|
||||||
(length (save-excursion (goto-char (point-max))
|
(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; -*-
|
;;; 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
|
;;; Package metadata
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom-package-plist (package)
|
(defun doom-package-get (package &optional prop nil-value)
|
||||||
"Returns PACKAGE's `package!' recipe from `doom-packages'."
|
"Returns PACKAGE's `package!' recipe from `doom-packages'."
|
||||||
(cdr (assq package doom-packages)))
|
(let ((plist (cdr (assq package doom-packages))))
|
||||||
|
(if prop
|
||||||
|
(if (plist-member plist prop)
|
||||||
|
(plist-get plist prop)
|
||||||
|
nil-value)
|
||||||
|
plist)))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom-package-desc (package)
|
(defun doom-package-recipe (package &optional prop nil-value)
|
||||||
"Returns PACKAGE's desc struct from `package-alist'."
|
"Returns the `straight' recipe PACKAGE was registered with."
|
||||||
(cadr (assq (or (car (doom-package-prop package :recipe))
|
(let ((plist (gethash (symbol-name package) straight--recipe-cache)))
|
||||||
package)
|
(if prop
|
||||||
package-alist)))
|
(if (plist-member plist prop)
|
||||||
|
(plist-get plist prop)
|
||||||
|
nil-value)
|
||||||
|
plist)))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom-package-true-name (package)
|
(defun doom-package-build-recipe (package &optional prop nil-value)
|
||||||
"Return PACKAGE's true name.
|
"Returns the `straight' recipe PACKAGE was installed with."
|
||||||
|
(let ((plist (nth 2 (gethash (symbol-name package) straight--build-cache))))
|
||||||
It is possible for quelpa packages to be given a psuedonym (the first argument
|
(if prop
|
||||||
of `package!'). Its real name is the car of package's :recipe. e.g.
|
(if (plist-member plist prop)
|
||||||
|
(plist-get plist prop)
|
||||||
(package! X :recipe (Y :fetcher github :repo \"abc/def\"))
|
nil-value)
|
||||||
|
plist)))
|
||||||
X's real name is Y."
|
|
||||||
(let ((sym (car (doom-package-prop package :recipe))))
|
|
||||||
(or (and (symbolp sym)
|
|
||||||
(not (keywordp sym))
|
|
||||||
sym)
|
|
||||||
package)))
|
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom-package-psuedo-name (package)
|
(defun doom-package-build-time (package)
|
||||||
"TODO"
|
"TODO"
|
||||||
(or (cl-loop for (package . plist) in doom-packages
|
(car (gethash (symbol-name package) straight--build-cache)))
|
||||||
for recipe-name = (car (plist-get plist :recipe))
|
|
||||||
if (eq recipe-name package)
|
|
||||||
return recipe-name)
|
|
||||||
package))
|
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom-package-backend (package &optional noerror)
|
(defun doom-package-dependencies (package &optional recursive noerror)
|
||||||
"Return backend that PACKAGE was installed with.
|
"Return a list of dependencies for a package."
|
||||||
|
(let ((deps (nth 1 (gethash (symbol-name package) straight--build-cache))))
|
||||||
|
(if recursive
|
||||||
|
(nconc deps (mapcan (lambda (dep) (doom-package-dependencies dep t t))
|
||||||
|
deps))
|
||||||
|
deps)))
|
||||||
|
|
||||||
Can either be elpa, quelpa or emacs (built-in). Throws an error if NOERROR is
|
(defun doom-package-depending-on (package &optional noerror)
|
||||||
nil and the package isn't installed.
|
"Return a list of packages that depend on the package named NAME."
|
||||||
|
(cl-check-type name symbol)
|
||||||
See `doom-package-recipe-backend' to get the backend PACKAGE is registered with
|
;; can't get dependencies for built-in packages
|
||||||
\(as opposed to what it is was installed with)."
|
(unless (or (doom-package-build-recipe name)
|
||||||
(cl-check-type package symbol)
|
noerror)
|
||||||
(let ((package-truename (doom-package-true-name package)))
|
(error "Couldn't find %s, is it installed?" name))
|
||||||
(cond ((assq package-truename quelpa-cache) 'quelpa)
|
(cl-loop for pkg in (hash-table-keys straight--build-cache)
|
||||||
((assq package-truename package-alist) 'elpa)
|
for deps = (doom-package-dependencies pkg)
|
||||||
((doom-package-built-in-p package) 'emacs)
|
if (memq package deps)
|
||||||
((not noerror) (error "%s package is not installed" package)))))
|
collect pkg
|
||||||
|
and append (doom-package-depending-on pkg t)))
|
||||||
;;;###autoload
|
|
||||||
(defun doom-package-recipe-backend (package &optional noerror)
|
|
||||||
"Return backend that PACKAGE is registered with.
|
|
||||||
|
|
||||||
See `doom-package-backend' to get backend for currently installed package."
|
|
||||||
(cl-check-type package symbol)
|
|
||||||
(cond ((not (doom-package-registered-p package))
|
|
||||||
(unless noerror
|
|
||||||
(error "%s package is not registered" package)))
|
|
||||||
((let ((builtin (eval (doom-package-prop package :built-in) t)))
|
|
||||||
(or (and (eq builtin 'prefer)
|
|
||||||
(locate-library (symbol-name package) nil doom-site-load-path))
|
|
||||||
(eq builtin 't)))
|
|
||||||
'emacs)
|
|
||||||
((doom-package-prop package :recipe)
|
|
||||||
'quelpa)
|
|
||||||
('elpa)))
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(defun doom-package-prop (package prop &optional nil-value)
|
|
||||||
"Return PROPerty in PACKAGE's plist.
|
|
||||||
|
|
||||||
Otherwise returns NIL-VALUE if package isn't registered or PROP doesn't
|
|
||||||
exist/isn't specified."
|
|
||||||
(cl-check-type package symbol)
|
|
||||||
(cl-check-type prop keyword)
|
|
||||||
(if-let (plist (doom-package-plist package))
|
|
||||||
(if (plist-member plist prop)
|
|
||||||
(plist-get plist prop)
|
|
||||||
nil-value)
|
|
||||||
nil-value))
|
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
|
@ -131,212 +67,94 @@ exist/isn't specified."
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom-package-built-in-p (package)
|
(defun doom-package-built-in-p (package)
|
||||||
"Return non-nil if PACKAGE (a symbol) is built-in."
|
"Return non-nil if PACKAGE (a symbol) is built-in."
|
||||||
(unless (doom-package-installed-p package)
|
(eq (doom-package-build-recipe package :type)
|
||||||
(or (package-built-in-p (doom-package-true-name package))
|
'built-in))
|
||||||
(locate-library (symbol-name package) nil doom-site-load-path))))
|
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom-package-installed-p (package)
|
(defun doom-package-installed-p (package)
|
||||||
"Return non-nil if PACKAGE (a symbol) is installed."
|
"Return non-nil if PACKAGE (a symbol) is installed."
|
||||||
(when-let (desc (doom-package-desc package))
|
(file-directory-p (straight--build-dir (symbol-name package))))
|
||||||
(and (package-installed-p desc)
|
|
||||||
(file-directory-p (package-desc-dir desc)))))
|
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom-package-registered-p (package)
|
(defun doom-package-registered-p (package)
|
||||||
"Return non-nil if PACKAGE (a symbol) has been registered with `package!'.
|
"Return non-nil if PACKAGE (a symbol) has been registered with `package!'.
|
||||||
|
|
||||||
Excludes packages that have a non-nil :built-in property."
|
Excludes packages that have a non-nil :built-in property."
|
||||||
(let ((package (or (cl-loop for (pkg . plist) in doom-packages
|
(when-let (plist (doom-package-get package))
|
||||||
for newname = (car (plist-get plist :recipe))
|
(not (eval (plist-get plist :ignore) t))))
|
||||||
if (and (symbolp newname)
|
|
||||||
(eq newname package))
|
|
||||||
return pkg)
|
|
||||||
package)))
|
|
||||||
(when-let (plist (doom-package-plist package))
|
|
||||||
(not (eval (plist-get plist :ignore))))))
|
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom-package-private-p (package)
|
(defun doom-package-private-p (package)
|
||||||
"Return non-nil if PACKAGE was installed by the user's private config."
|
"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
|
;;;###autoload
|
||||||
(defun doom-package-protected-p (package)
|
(defun doom-package-protected-p (package)
|
||||||
"Return non-nil if PACKAGE is protected.
|
"Return non-nil if PACKAGE is protected.
|
||||||
|
|
||||||
A protected package cannot be deleted and will be auto-installed if missing."
|
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
|
;;;###autoload
|
||||||
(defun doom-package-core-p (package)
|
(defun doom-package-core-p (package)
|
||||||
"Return non-nil if PACKAGE is a core Doom package."
|
"Return non-nil if PACKAGE is a core Doom package."
|
||||||
(or (doom-package-protected-p package)
|
(or (doom-package-protected-p package)
|
||||||
(assq :core (doom-package-prop package :modules))))
|
(assq :core (doom-package-get package :modules))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom-package-different-backend-p (package)
|
(defun doom-package-backend (package)
|
||||||
"Return t if a PACKAGE (a symbol) has a new backend than what it was installed
|
"Return 'straight, 'builtin, 'elpa or 'other, depending on how PACKAGE is
|
||||||
with. Returns nil otherwise, or if package isn't installed."
|
installed."
|
||||||
(cl-check-type package symbol)
|
(cond ((gethash (symbol-name package) straight--build-cache)
|
||||||
(and (doom-package-installed-p package)
|
'straight)
|
||||||
(not (doom-get-depending-on package)) ; not a dependency
|
((or (doom-package-built-in-p package)
|
||||||
(not (eq (doom-package-backend package 'noerror)
|
(assq package package--builtins))
|
||||||
(doom-package-recipe-backend package 'noerror)))))
|
'builtin)
|
||||||
|
((assq package package-alist)
|
||||||
|
'elpa)
|
||||||
|
('other)))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom-package-different-recipe-p (name)
|
(defun doom-package-different-recipe-p (name)
|
||||||
"Return t if a package named NAME (a symbol) has a different recipe than it
|
"Return t if a package named NAME (a symbol) has a different recipe than it
|
||||||
was installed with."
|
was installed with."
|
||||||
(cl-check-type name symbol)
|
(cl-check-type name symbol)
|
||||||
(when (doom-package-installed-p name)
|
;; TODO
|
||||||
(let ((package-truename (doom-package-true-name name)))
|
;; (when (doom-package-installed-p name)
|
||||||
(when-let* ((quelpa-recipe (assq package-truename quelpa-cache))
|
;; (when-let* ((doom-recipe (assq name doom-packages))
|
||||||
(doom-recipe (assq package-truename doom-packages)))
|
;; (install-recipe (doom-package-recipe)))
|
||||||
(not (equal (cdr quelpa-recipe)
|
;; (not (equal (cdr quelpa-recipe)
|
||||||
(cdr (plist-get (cdr doom-recipe) :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)))))
|
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;;; Package list getters
|
;;; Package list getters
|
||||||
|
|
||||||
;;;###autoload
|
(defun doom--read-module-packages-file (file &optional eval noerror)
|
||||||
(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)
|
|
||||||
(with-temp-buffer ; prevent buffer-local settings from propagating
|
(with-temp-buffer ; prevent buffer-local settings from propagating
|
||||||
(condition-case e
|
(condition-case e
|
||||||
(if (not raw)
|
(if (not eval)
|
||||||
(load file noerror t t)
|
(load file noerror t t)
|
||||||
(when (file-readable-p file)
|
(when (file-readable-p file)
|
||||||
(insert-file-contents file)
|
(insert-file-contents file)
|
||||||
|
(delay-mode-hooks (emacs-lisp-mode))
|
||||||
(while (re-search-forward "(package! " nil t)
|
(while (re-search-forward "(package! " nil t)
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(goto-char (match-beginning 0))
|
(goto-char (match-beginning 0))
|
||||||
(cl-destructuring-bind (name . plist) (cdr (sexp-at-point))
|
(unless (let ((ppss (syntax-ppss)))
|
||||||
(push (cons name
|
(or (nth 3 ppss)
|
||||||
(plist-put plist :modules
|
(nth 4 ppss)))
|
||||||
(cond ((file-in-directory-p file doom-private-dir)
|
(cl-destructuring-bind (name . plist)
|
||||||
'((:private)))
|
(cdr (sexp-at-point))
|
||||||
((file-in-directory-p file doom-core-dir)
|
(push (cons
|
||||||
'((:core)))
|
name (plist-put
|
||||||
((doom-module-from-path file)))))
|
plist :modules
|
||||||
doom-packages))))))
|
(list (doom-module-from-path file))))
|
||||||
|
doom-packages)))))))
|
||||||
((debug error)
|
((debug error)
|
||||||
(signal 'doom-package-error
|
(signal 'doom-package-error
|
||||||
(list (or (doom-module-from-path file)
|
(list (doom-module-from-path file)
|
||||||
'(:private . packages))
|
|
||||||
e))))))
|
e))))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###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
|
If ALL-P, gather packages unconditionally across all modules, including disabled
|
||||||
ones."
|
ones."
|
||||||
(let ((noninteractive t)
|
(let ((noninteractive t)
|
||||||
(doom--stage 'packages)
|
|
||||||
(doom-modules (doom-modules))
|
(doom-modules (doom-modules))
|
||||||
doom-packages
|
doom-packages
|
||||||
doom-disabled-packages
|
doom-disabled-packages)
|
||||||
package-pinned-packages)
|
(doom--read-module-packages-file
|
||||||
(doom--read-module-packages-file (expand-file-name "packages.el" doom-core-dir) all-p)
|
(doom-path doom-core-dir "packages.el") all-p t)
|
||||||
(let ((private-packages (expand-file-name "packages.el" doom-private-dir)))
|
(let ((private-packages (doom-path doom-private-dir "packages.el")))
|
||||||
(unless all-p
|
(unless all-p
|
||||||
;; We load the private packages file twice to ensure disabled packages
|
;; We load the private packages file twice to ensure disabled packages
|
||||||
;; are seen ASAP, and a second time to ensure privately overridden
|
;; are seen ASAP, and a second time to ensure privately overridden
|
||||||
;; packages are properly overwritten.
|
;; 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
|
(if all-p
|
||||||
(mapc #'doom--read-module-packages-file
|
(mapc #'doom--read-module-packages-file
|
||||||
(doom-files-in doom-modules-dir
|
(doom-files-in doom-modules-dir
|
||||||
:depth 2
|
:depth 2
|
||||||
:full t
|
:match "/packages\\.el$"))
|
||||||
:match "/packages\\.el$"
|
|
||||||
:sort nil))
|
|
||||||
(cl-loop for key being the hash-keys of doom-modules
|
(cl-loop for key being the hash-keys of doom-modules
|
||||||
for path = (doom-module-path (car key) (cdr key) "packages.el")
|
for path = (doom-module-path (car key) (cdr key) "packages.el")
|
||||||
for doom--current-module = key
|
for doom--current-module = key
|
||||||
do (doom--read-module-packages-file path nil t)))
|
do (doom--read-module-packages-file path nil t)))
|
||||||
(doom--read-module-packages-file private-packages all-p t))
|
(doom--read-module-packages-file private-packages all-p t))
|
||||||
(append (cl-loop for package in doom-core-packages
|
(nreverse doom-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)))
|
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;; Main functions
|
;;; 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
|
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom/reload-packages ()
|
(defun doom/reload-packages ()
|
||||||
"Reload `doom-packages', `package' and `quelpa'."
|
"Reload `doom-packages', `package' and `quelpa'."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
;; HACK straight.el must be loaded for this to work
|
||||||
(message "Reloading packages")
|
(message "Reloading packages")
|
||||||
(doom-initialize-packages t)
|
(doom-initialize-packages t)
|
||||||
(message "Reloading packages...DONE"))
|
(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)
|
(defvar projectile-project-root nil)
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload (autoload 'projectile-relevant-known-projects "projectile")
|
||||||
(autoload 'projectile-relevant-known-projects "projectile")
|
|
||||||
|
|
||||||
;;;###autodef
|
;;;###autodef
|
||||||
(cl-defun set-project-type! (name &key predicate compile run test configure dir)
|
(cl-defun set-project-type! (name &key predicate compile run test configure dir)
|
||||||
|
@ -23,16 +22,6 @@
|
||||||
;;
|
;;
|
||||||
;;; Macros
|
;;; 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
|
;;;###autoload
|
||||||
(defmacro project-file-exists-p! (files)
|
(defmacro project-file-exists-p! (files)
|
||||||
"Checks if the project has the specified 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.
|
"Return the name of the current project.
|
||||||
|
|
||||||
Returns '-' if not in a valid project."
|
Returns '-' if not in a valid project."
|
||||||
(if-let* ((project-root (or (doom-project-root dir)
|
(if-let (project-root (or (doom-project-root dir)
|
||||||
(if dir (expand-file-name dir)))))
|
(if dir (expand-file-name dir))))
|
||||||
(funcall projectile-project-name-function project-root)
|
(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))
|
(setq projectile-enable-caching nil))
|
||||||
(call-interactively
|
(call-interactively
|
||||||
;; Intentionally avoid `helm-projectile-find-file', because it runs
|
;; Intentionally avoid `helm-projectile-find-file', because it runs
|
||||||
;; asynchronously, and thus doesn't see the lexical `default-directory'
|
;; asynchronously, and thus doesn't see the lexical
|
||||||
(if (featurep! :completion ivy)
|
;; `default-directory'
|
||||||
|
(if (doom-module-p :completion 'ivy)
|
||||||
#'counsel-projectile-find-file
|
#'counsel-projectile-find-file
|
||||||
#'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
|
((fboundp 'counsel-file-jump) ; ivy only
|
||||||
(call-interactively #'counsel-file-jump))
|
(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)
|
((fboundp 'helm-find-files)
|
||||||
(call-interactively #'helm-find-files))
|
(call-interactively #'helm-find-files))
|
||||||
((call-interactively #'find-file)))))
|
((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."
|
"Traverse a file structure starting linearly from DIR."
|
||||||
(let ((default-directory (file-truename (expand-file-name dir))))
|
(let ((default-directory (file-truename (expand-file-name dir))))
|
||||||
(call-interactively
|
(call-interactively
|
||||||
(cond ((featurep! :completion ivy)
|
(cond ((doom-module-p :completion 'ivy)
|
||||||
#'counsel-find-file)
|
#'counsel-find-file)
|
||||||
((featurep! :completion helm)
|
((doom-module-p :completion 'helm)
|
||||||
#'helm-find-files)
|
#'helm-find-files)
|
||||||
(#'find-file)))))
|
(#'find-file)))))
|
||||||
|
|
|
@ -19,18 +19,22 @@ following:
|
||||||
(defvar doom-scratch-buffers nil
|
(defvar doom-scratch-buffers nil
|
||||||
"A list of active scratch buffers.")
|
"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.")
|
"The name of the project associated with the current scratch buffer.")
|
||||||
|
|
||||||
(defvar doom-scratch-buffer-hook ()
|
(defvar doom-scratch-buffer-hook ()
|
||||||
"The hooks to run after a scratch buffer is created.")
|
"The hooks to run after a scratch buffer is created.")
|
||||||
|
|
||||||
|
|
||||||
(defun doom--load-persistent-scratch-buffer (name)
|
(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
|
||||||
doom-scratch-dir)))
|
(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)
|
(make-directory doom-scratch-dir t)
|
||||||
(if (not (file-readable-p scratch-file))
|
(when (file-readable-p scratch-file)
|
||||||
nil
|
|
||||||
(erase-buffer)
|
(erase-buffer)
|
||||||
(insert-file-contents scratch-file)
|
(insert-file-contents scratch-file)
|
||||||
(set-auto-mode)
|
(set-auto-mode)
|
||||||
|
@ -39,48 +43,54 @@ following:
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom-scratch-buffer (&optional mode directory project-name)
|
(defun doom-scratch-buffer (&optional mode directory project-name)
|
||||||
"Return a scratchpad buffer in major MODE."
|
"Return a scratchpad buffer in major MODE."
|
||||||
(let* ((buffer-name (if project-name
|
(with-current-buffer
|
||||||
(format "*doom:scratch (%s)*" project-name)
|
(get-buffer-create (if project-name
|
||||||
"*doom:scratch*"))
|
(format "*doom:scratch (%s)*" project-name)
|
||||||
(buffer (get-buffer buffer-name)))
|
"*doom:scratch*"))
|
||||||
(with-current-buffer (get-buffer-create buffer-name)
|
(setq default-directory directory)
|
||||||
(unless buffer
|
(unless doom-scratch-current-project
|
||||||
(setq buffer (current-buffer)
|
(doom--load-persistent-scratch-buffer project-name)
|
||||||
default-directory directory
|
(when (and (eq major-mode 'fundamental-mode)
|
||||||
doom-scratch-current-project project-name)
|
(functionp mode))
|
||||||
(setq doom-scratch-buffers (cl-delete-if-not #'buffer-live-p doom-scratch-buffers))
|
(funcall mode)))
|
||||||
(cl-pushnew buffer doom-scratch-buffers)
|
(cl-pushnew (current-buffer) doom-scratch-buffers)
|
||||||
(doom--load-persistent-scratch-buffer project-name)
|
(add-hook 'kill-buffer-hook #'doom-persist-scratch-buffer-h nil 'local)
|
||||||
(when (and (eq major-mode 'fundamental-mode)
|
(add-hook 'doom-switch-buffer-hook #'doom-persist-scratch-buffers-after-switch-h)
|
||||||
(functionp mode))
|
(run-hooks 'doom-scratch-buffer-created-hook)
|
||||||
(funcall mode))
|
(current-buffer)))
|
||||||
(add-hook 'kill-buffer-hook #'doom|persist-scratch-buffer nil 'local)
|
|
||||||
(run-hooks 'doom-scratch-buffer-created-hook))
|
|
||||||
buffer)))
|
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;;; Persistent scratch buffer
|
;;; Persistent scratch buffer
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom|persist-scratch-buffer ()
|
(defun doom-persist-scratch-buffer-h ()
|
||||||
"Save the current buffer to `doom-scratch-dir'."
|
"Save the current buffer to `doom-scratch-dir'."
|
||||||
(write-region
|
(write-region
|
||||||
(point-min) (point-max)
|
(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)))
|
doom-scratch-dir)))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom|persist-scratch-buffers ()
|
(defun doom-persist-scratch-buffers-h ()
|
||||||
"Save all scratch buffers to `doom-scratch-dir'."
|
"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)
|
(dolist (buffer doom-scratch-buffers)
|
||||||
(with-current-buffer buffer
|
(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
|
;;;###autoload
|
||||||
(unless noninteractive
|
(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
|
;;;###autoload
|
||||||
(defun doom/switch-to-scratch-buffer (&optional project-p)
|
(defun doom/switch-to-scratch-buffer (&optional project-p)
|
||||||
"Like `doom/open-scratch-buffer', but switches to it in the current window."
|
"Like `doom/open-scratch-buffer', but switches to it in the current window.
|
||||||
(interactive)
|
|
||||||
(doom/open-scratch-buffer t))
|
If passed the prefix arg, open project scratch buffer."
|
||||||
|
(interactive "P")
|
||||||
|
(doom/open-scratch-buffer t project-p))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###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.
|
"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")
|
(interactive "P")
|
||||||
(doom/open-scratch-buffer arg 'project))
|
(doom/open-scratch-buffer current-window 'project))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom/switch-to-project-scratch-buffer ()
|
(defun doom/switch-to-project-scratch-buffer ()
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
;;; core/autoload/sessions.el -*- lexical-binding: t; -*-
|
;;; core/autoload/sessions.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(defvar desktop-base-file-name)
|
||||||
|
(defvar desktop-dirname)
|
||||||
|
(defvar desktop-restore-eager)
|
||||||
|
(defvar desktop-file-modtime)
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;;; Helpers
|
;;; Helpers
|
||||||
|
|
||||||
|
@ -59,9 +65,6 @@
|
||||||
"TODO"
|
"TODO"
|
||||||
(add-hook 'window-setup-hook #'doom-load-session 'append))
|
(add-hook 'window-setup-hook #'doom-load-session 'append))
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(add-to-list 'command-switch-alist (cons "--restore" #'doom-restore-session-handler))
|
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;;; Commands
|
;;; Commands
|
||||||
|
|
|
@ -25,6 +25,41 @@ lines, above and below, with only whitespace in between."
|
||||||
(or (not balanced)
|
(or (not balanced)
|
||||||
(= (- pt nbeg) (- nend pt))))))))))))
|
(= (- 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
|
;; Commands
|
||||||
|
@ -186,9 +221,13 @@ Respects `require-final-newline'."
|
||||||
(setq indent-tabs-mode (not indent-tabs-mode))
|
(setq indent-tabs-mode (not indent-tabs-mode))
|
||||||
(message "Indent style changed to %s" (if indent-tabs-mode "tabs" "spaces")))
|
(message "Indent style changed to %s" (if indent-tabs-mode "tabs" "spaces")))
|
||||||
|
|
||||||
|
(defvar editorconfig-lisp-use-default-indent)
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom/set-indent-width (width)
|
(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
|
(interactive
|
||||||
(list (if (integerp current-prefix-arg)
|
(list (if (integerp current-prefix-arg)
|
||||||
current-prefix-arg
|
current-prefix-arg
|
||||||
|
@ -211,25 +250,25 @@ Respects `require-final-newline'."
|
||||||
;; Hooks
|
;; Hooks
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom|enable-delete-trailing-whitespace ()
|
(defun doom-enable-delete-trailing-whitespace-h ()
|
||||||
"Enables the automatic deletion of trailing whitespaces upon file save.
|
"Enables the automatic deletion of trailing whitespaces upon file save.
|
||||||
|
|
||||||
i.e. enables `ws-butler-mode' in the current buffer."
|
i.e. enables `ws-butler-mode' in the current buffer."
|
||||||
(ws-butler-mode +1))
|
(ws-butler-mode +1))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom|disable-delete-trailing-whitespace ()
|
(defun doom-disable-delete-trailing-whitespace-h ()
|
||||||
"Disables the automatic deletion of trailing whitespaces upon file save.
|
"Disables the automatic deletion of trailing whitespaces upon file save.
|
||||||
|
|
||||||
i.e. disables `ws-butler-mode' in the current buffer."
|
i.e. disables `ws-butler-mode' in the current buffer."
|
||||||
(ws-butler-mode -1))
|
(ws-butler-mode -1))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom|enable-show-trailing-whitespace ()
|
(defun doom-enable-show-trailing-whitespace-h ()
|
||||||
"Enable `show-trailing-whitespace' in the current buffer."
|
"Enable `show-trailing-whitespace' in the current buffer."
|
||||||
(setq-local show-trailing-whitespace t))
|
(setq-local show-trailing-whitespace t))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom|disable-show-trailing-whitespace ()
|
(defun doom-disable-show-trailing-whitespace-h ()
|
||||||
"Disable `show-trailing-whitespace' in the current buffer."
|
"Disable `show-trailing-whitespace' in the current buffer."
|
||||||
(setq-local show-trailing-whitespace nil))
|
(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
|
;; Advice
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom*recenter (&rest _)
|
(defun doom-recenter-a (&rest _)
|
||||||
"Generic advisor for recentering window (typically :after other functions)."
|
"Generic advisor for recentering window (typically :after other functions)."
|
||||||
(recenter))
|
(recenter))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom*shut-up (orig-fn &rest args)
|
(defun doom-shut-up-a (orig-fn &rest args)
|
||||||
"Generic advisor for silencing noisy functions."
|
"Generic advisor for silencing noisy functions."
|
||||||
(quiet! (apply orig-fn args)))
|
(quiet! (apply orig-fn args)))
|
||||||
|
|
||||||
|
@ -41,14 +41,14 @@ are open."
|
||||||
;; Hooks
|
;; Hooks
|
||||||
|
|
||||||
;;;###autoload
|
;;;###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
|
"Applies ansi codes to the compilation buffers. Meant for
|
||||||
`compilation-filter-hook'."
|
`compilation-filter-hook'."
|
||||||
(with-silent-modifications
|
(with-silent-modifications
|
||||||
(ansi-color-apply-on-region compilation-filter-start (point))))
|
(ansi-color-apply-on-region compilation-filter-start (point))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom|disable-show-paren-mode ()
|
(defun doom-disable-show-paren-mode-h ()
|
||||||
"Turn off `show-paren-mode' buffer-locally."
|
"Turn off `show-paren-mode' buffer-locally."
|
||||||
(setq-local show-paren-mode nil))
|
(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."
|
See `display-line-numbers' for what these values mean."
|
||||||
(interactive)
|
(interactive)
|
||||||
(defvar doom--line-number-style display-line-numbers-type)
|
(defvar doom--line-number-style display-line-numbers-type)
|
||||||
|
;; DEPRECATED
|
||||||
(let* ((styles `(t ,(if (and EMACS26+ visual-line-mode) 'visual 'relative) nil))
|
(let* ((styles `(t ,(if (and EMACS26+ visual-line-mode) 'visual 'relative) nil))
|
||||||
(order (cons display-line-numbers-type (remq display-line-numbers-type styles)))
|
(order (cons display-line-numbers-type (remq display-line-numbers-type styles)))
|
||||||
(queue (memq doom--line-number-style order))
|
(queue (memq doom--line-number-style order))
|
||||||
|
@ -74,6 +75,7 @@ See `display-line-numbers' for what these values mean."
|
||||||
(car order)
|
(car order)
|
||||||
(car (cdr queue)))))
|
(car (cdr queue)))))
|
||||||
(setq doom--line-number-style next)
|
(setq doom--line-number-style next)
|
||||||
|
;; DEPRECATED
|
||||||
(if EMACS26+
|
(if EMACS26+
|
||||||
(setq display-line-numbers next)
|
(setq display-line-numbers next)
|
||||||
(pcase next
|
(pcase next
|
||||||
|
|
|
@ -1,16 +1,12 @@
|
||||||
;;; core/cli/autoloads.el -*- lexical-binding: t; -*-
|
;;; core/cli/autoloads.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
(dispatcher! (autoloads a)
|
(require 'autoload)
|
||||||
(doom-reload-autoloads nil 'force)
|
|
||||||
"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',
|
(defvar doom-autoload-excluded-packages '("gh")
|
||||||
`package-activated-list' and `auto-mode-alist'.")
|
"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
|
;; external variables
|
||||||
(defvar autoload-timestamps)
|
(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)
|
(defcli! (autoloads a) ()
|
||||||
"Packages that have silly or destructive autoload files that try to load
|
"Regenerates Doom's autoloads files.
|
||||||
everyone in the universe and their dog, causing errors that make babies cry. No
|
|
||||||
one wants that.")
|
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)
|
(defun doom-delete-autoloads-file (file)
|
||||||
"Delete FILE (an autoloads file) and accompanying *.elc file, if any."
|
"Delete FILE (an autoloads file) and accompanying *.elc file, if any."
|
||||||
(cl-check-type file string)
|
(cl-check-type file string)
|
||||||
(when (file-exists-p file)
|
(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
|
(with-current-buffer buf
|
||||||
(set-buffer-modified-p nil))
|
(set-buffer-modified-p nil))
|
||||||
(kill-buffer buf))
|
(kill-buffer buf))
|
||||||
(delete-file file)
|
(delete-file file)
|
||||||
(ignore-errors (delete-file (byte-compile-dest-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 ()
|
(defun doom--warn-refresh-session-h ()
|
||||||
(print! (bold (green "\nFinished!")))
|
(message "Restart or reload Doom Emacs for changes to take effect:\n")
|
||||||
(message "If you have a running Emacs Session, you will need to restart it or")
|
|
||||||
(message "reload Doom for changes to take effect:\n")
|
|
||||||
(message " M-x doom/restart-and-restore")
|
(message " M-x doom/restart-and-restore")
|
||||||
(message " M-x doom/restart")
|
(message " M-x doom/restart")
|
||||||
(message " M-x doom/reload"))
|
(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)
|
(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))
|
(byte-compile-dynamic-docstrings t))
|
||||||
(condition-case e
|
(condition-case-unless-debug e
|
||||||
(when (byte-compile-file file)
|
(when (byte-compile-file file)
|
||||||
;; Give autoloads file a chance to report error
|
(prog1 (load file 'noerror 'nomessage)
|
||||||
(load (if doom-debug-mode
|
(when noninteractive
|
||||||
file
|
(add-hook 'doom-cli-post-success-execute-hook #'doom--warn-refresh-session-h))))
|
||||||
(byte-compile-dest-file file))
|
|
||||||
nil t)
|
|
||||||
(unless noninteractive
|
|
||||||
(message "Finished compiling %s" short-name)))
|
|
||||||
((debug error)
|
((debug error)
|
||||||
(let ((backup-file (concat file ".bk")))
|
(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))
|
(copy-file file backup-file 'overwrite))
|
||||||
(doom-delete-autoloads-file file)
|
(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)
|
(defun doom-reload-autoloads (&optional file force-p)
|
||||||
"Reloads FILE (an autoload file), if it needs reloading.
|
"Reloads FILE (an autoload file), if it needs reloading.
|
||||||
|
@ -82,71 +78,128 @@ even if it doesn't need reloading!"
|
||||||
(signal 'wrong-type-argument (list 'stringp file)))
|
(signal 'wrong-type-argument (list 'stringp file)))
|
||||||
(if (stringp file)
|
(if (stringp file)
|
||||||
(cond ((file-equal-p file doom-autoload-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)
|
((file-equal-p file doom-package-autoload-file)
|
||||||
(doom-reload-package-autoloads force-p))
|
(doom-reload-package-autoloads force-p))
|
||||||
((error "Invalid autoloads file: %s" file)))
|
((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-reload-package-autoloads force-p)))
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;;; Doom autoloads
|
;;; 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)
|
(defun doom--generate-header (func)
|
||||||
(goto-char (point-min))
|
(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"))
|
";; This file is autogenerated by `" (symbol-name func) "', DO NOT EDIT !!\n\n"))
|
||||||
|
|
||||||
(defun doom--generate-autoloads (targets)
|
(defun doom--generate-autoloads (targets)
|
||||||
(require 'autoload)
|
(let ((n 0))
|
||||||
(dolist (file targets)
|
(dolist (file targets)
|
||||||
(let* ((file (file-truename file))
|
(insert
|
||||||
(generated-autoload-file doom-autoload-file)
|
(with-temp-buffer
|
||||||
(generated-autoload-load-name (file-name-sans-extension file))
|
(cond ((not (doom-file-cookie-p file))
|
||||||
(noninteractive (not doom-debug-mode))
|
(print! (debug "Ignoring %s") (relpath file)))
|
||||||
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))))))
|
|
||||||
|
|
||||||
(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
|
(let ((load-path
|
||||||
;; NOTE With `doom-private-dir' in `load-path', Doom autoloads files
|
;; NOTE With `doom-private-dir' in `load-path', Doom autoloads files
|
||||||
;; will be unable to declare autoloads for the built-in autoload.el
|
;; will be unable to declare autoloads for the built-in autoload.el
|
||||||
;; Emacs package, should $DOOMDIR/autoload.el exist. Not sure why
|
;; Emacs package, should $DOOMDIR/autoload.el exist. Not sure why
|
||||||
;; they'd want to though, so it's an acceptable compromise.
|
;; 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
|
doom-modules-dirs
|
||||||
load-path))
|
(straight--directory-files (straight--build-dir) nil t)
|
||||||
cache)
|
load-path)))
|
||||||
(while (re-search-forward "^\\s-*(autoload\\s-+'[^ ]+\\s-+\"\\([^\"]*\\)\"" nil t)
|
(defvar doom--autoloads-path-cache nil)
|
||||||
|
(while (re-search-forward "^\\s-*(\\(?:custom-\\)?autoload\\s-+'[^ ]+\\s-+\"\\([^\"]*\\)\"" nil t)
|
||||||
(let ((path (match-string 1)))
|
(let ((path (match-string 1)))
|
||||||
(replace-match
|
(replace-match
|
||||||
(or (cdr (assoc path cache))
|
(or (cdr (assoc path doom--autoloads-path-cache))
|
||||||
(when-let* ((libpath (locate-library path))
|
(when-let* ((libpath (or (and allow-internal-paths
|
||||||
(libpath (file-name-sans-extension libpath)))
|
(locate-library path nil (cons doom-emacs-dir doom-modules-dirs)))
|
||||||
(push (cons path (abbreviate-file-name libpath)) cache)
|
(locate-library path)))
|
||||||
|
(libpath (file-name-sans-extension libpath))
|
||||||
|
(libpath (abbreviate-file-name libpath)))
|
||||||
|
(push (cons path libpath) doom--autoloads-path-cache)
|
||||||
libpath)
|
libpath)
|
||||||
path)
|
path)
|
||||||
t t nil 1)))))
|
t t nil 1)))))
|
||||||
|
|
||||||
|
(defun doom--generate-autodefs-1 (path &optional member-p)
|
||||||
|
(let (forms)
|
||||||
|
(while (re-search-forward "^;;;###autodef *\\([^\n]+\\)?\n" nil t)
|
||||||
|
(let* ((sexp (sexp-at-point))
|
||||||
|
(alt-sexp (match-string 1))
|
||||||
|
(type (car sexp))
|
||||||
|
(name (doom-unquote (cadr sexp)))
|
||||||
|
(origin (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
|
||||||
|
(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."))))
|
||||||
|
(condition-case-unless-debug e
|
||||||
|
(if alt-sexp
|
||||||
|
(read alt-sexp)
|
||||||
|
(append
|
||||||
|
(list (pcase type
|
||||||
|
(`defun 'defmacro)
|
||||||
|
(`cl-defun `cl-defmacro)
|
||||||
|
(_ type))
|
||||||
|
name arglist docstring)
|
||||||
|
(cl-loop for arg in arglist
|
||||||
|
if (and (symbolp arg)
|
||||||
|
(not (keywordp arg))
|
||||||
|
(not (memq arg cl--lambda-list-keywords)))
|
||||||
|
collect arg into syms
|
||||||
|
else if (listp arg)
|
||||||
|
collect (car arg) into syms
|
||||||
|
finally return (if syms `((ignore ,@syms))))))
|
||||||
|
('error
|
||||||
|
(print! "- Ignoring autodef %s (%s)" name e)
|
||||||
|
nil))))
|
||||||
|
`(put ',name 'doom-module ',origin)))))
|
||||||
|
|
||||||
|
((eq type 'defalias)
|
||||||
|
(cl-destructuring-bind (_type name target &optional docstring) sexp
|
||||||
|
(let ((name (doom-unquote name))
|
||||||
|
(target (doom-unquote target)))
|
||||||
|
(unless member-p
|
||||||
|
(setq target #'ignore
|
||||||
|
docstring
|
||||||
|
(format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s"
|
||||||
|
origin docstring)))
|
||||||
|
(appendq! forms `((put ',name 'doom-module ',origin)
|
||||||
|
(defalias ',name #',target ,docstring))))))
|
||||||
|
|
||||||
|
(member-p (push sexp forms)))))
|
||||||
|
forms))
|
||||||
|
|
||||||
(defun doom--generate-autodefs (targets enabled-targets)
|
(defun doom--generate-autodefs (targets enabled-targets)
|
||||||
(goto-char (point-max))
|
(goto-char (point-max))
|
||||||
(search-backward ";;;***" nil t)
|
(search-backward ";;;***" nil t)
|
||||||
|
@ -155,83 +208,17 @@ even if it doesn't need reloading!"
|
||||||
(insert
|
(insert
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert-file-contents path)
|
(insert-file-contents path)
|
||||||
(let ((member-p (or (member path enabled-targets)
|
(if-let (forms (doom--generate-autodefs-1 path (member path enabled-targets)))
|
||||||
(file-in-directory-p path doom-core-dir)))
|
(concat (mapconcat #'prin1-to-string (nreverse forms) "\n")
|
||||||
forms)
|
"\n")
|
||||||
(while (re-search-forward "^;;;###autodef *\\([^\n]+\\)?\n" nil t)
|
"")))))
|
||||||
(let* ((sexp (sexp-at-point))
|
|
||||||
(alt-sexp (match-string 1))
|
|
||||||
(type (car sexp))
|
|
||||||
(name (doom-unquote (cadr sexp)))
|
|
||||||
(origin (cond ((doom-module-from-path path))
|
|
||||||
((file-in-directory-p path doom-private-dir)
|
|
||||||
`(:private . ,(intern (file-name-base path))))
|
|
||||||
((file-in-directory-p path doom-emacs-dir)
|
|
||||||
`(:core . ,(intern (file-name-base path))))))
|
|
||||||
(doom-file-form
|
|
||||||
`(put ',name 'doom-file ,(abbreviate-file-name path))))
|
|
||||||
(cond ((and (not member-p) alt-sexp)
|
|
||||||
(push (read alt-sexp) forms))
|
|
||||||
|
|
||||||
((memq type '(defun defmacro cl-defun cl-defmacro))
|
|
||||||
(cl-destructuring-bind (_ name arglist &rest body) sexp
|
|
||||||
(let ((docstring (if (stringp (car body))
|
|
||||||
(pop body)
|
|
||||||
"No documentation.")))
|
|
||||||
(push (if member-p
|
|
||||||
(make-autoload sexp (abbreviate-file-name (file-name-sans-extension path)))
|
|
||||||
(push doom-file-form forms)
|
|
||||||
(setq docstring (format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s"
|
|
||||||
origin docstring))
|
|
||||||
(condition-case-unless-debug e
|
|
||||||
(if alt-sexp
|
|
||||||
(read alt-sexp)
|
|
||||||
(append (list (pcase type
|
|
||||||
(`defun 'defmacro)
|
|
||||||
(`cl-defun `cl-defmacro)
|
|
||||||
(_ type))
|
|
||||||
name arglist docstring)
|
|
||||||
(cl-loop for arg in arglist
|
|
||||||
if (and (symbolp arg)
|
|
||||||
(not (keywordp arg))
|
|
||||||
(not (memq arg cl--lambda-list-keywords)))
|
|
||||||
collect arg into syms
|
|
||||||
else if (listp arg)
|
|
||||||
collect (car arg) into syms
|
|
||||||
finally return (if syms `((ignore ,@syms))))))
|
|
||||||
('error
|
|
||||||
(message "Ignoring autodef %s (%s)"
|
|
||||||
name e)
|
|
||||||
nil)))
|
|
||||||
forms)
|
|
||||||
(push `(put ',name 'doom-module ',origin) forms))))
|
|
||||||
|
|
||||||
((eq type 'defalias)
|
|
||||||
(cl-destructuring-bind (_type name target &optional docstring) sexp
|
|
||||||
(let ((name (doom-unquote name))
|
|
||||||
(target (doom-unquote target)))
|
|
||||||
(unless member-p
|
|
||||||
(setq docstring (format "THIS FUNCTION DOES NOTHING BECAUSE %s IS DISABLED\n\n%s"
|
|
||||||
origin docstring))
|
|
||||||
(setq target #'ignore))
|
|
||||||
(push doom-file-form forms)
|
|
||||||
(push `(put ',name 'doom-module ',origin) forms)
|
|
||||||
(push `(defalias ',name #',target ,docstring)
|
|
||||||
forms))))
|
|
||||||
|
|
||||||
(member-p
|
|
||||||
(push sexp forms)))))
|
|
||||||
(if forms
|
|
||||||
(concat (mapconcat #'prin1-to-string (nreverse forms) "\n")
|
|
||||||
"\n")
|
|
||||||
""))))))
|
|
||||||
|
|
||||||
(defun doom--cleanup-autoloads ()
|
(defun doom--cleanup-autoloads ()
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(when (re-search-forward "^;;\\(;[^\n]*\\| no-byte-compile: t\\)\n" nil t)
|
(when (re-search-forward "^;;\\(;[^\n]*\\| no-byte-compile: t\\)\n" nil t)
|
||||||
(replace-match "" t 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).
|
"Refreshes `doom-autoload-file', if necessary (or if FORCE-P is non-nil).
|
||||||
|
|
||||||
It scans and reads autoload cookies (;;;###autoload) in core/autoload/*.el,
|
It scans and reads autoload cookies (;;;###autoload) in core/autoload/*.el,
|
||||||
|
@ -241,62 +228,77 @@ modules/*/*/autoload.el and modules/*/*/autoload/*.el, and generates
|
||||||
Run this whenever your `doom!' block, or a module autoload file, is modified."
|
Run this whenever your `doom!' block, or a module autoload file, is modified."
|
||||||
(let* ((default-directory doom-emacs-dir)
|
(let* ((default-directory doom-emacs-dir)
|
||||||
(doom-modules (doom-modules))
|
(doom-modules (doom-modules))
|
||||||
(abbreviated-home-dir (if IS-WINDOWS "\\`'" abbreviated-home-dir))
|
|
||||||
(targets
|
;; The following bindings are in `package-generate-autoloads'.
|
||||||
(file-expand-wildcards
|
;; Presumably for a good reason, so I just copied them
|
||||||
(expand-file-name "autoload/*.el" doom-core-dir)))
|
(noninteractive t)
|
||||||
(enabled-targets (copy-sequence targets))
|
(backup-inhibited t)
|
||||||
case-fold-search)
|
(version-control 'never)
|
||||||
(dolist (path (doom-module-load-path t))
|
(case-fold-search nil) ; reduce magic
|
||||||
(let* ((auto-dir (expand-file-name "autoload" path))
|
(autoload-timestamps nil)
|
||||||
(auto-file (expand-file-name "autoload.el" path))
|
|
||||||
(module (doom-module-from-path auto-file))
|
;; Where we'll store the files we'll scan for autoloads. This should
|
||||||
(module-p (or (doom-module-p (car module) (cdr module))
|
;; contain *all* autoload files, even in disabled modules, so we can
|
||||||
(file-equal-p path doom-private-dir))))
|
;; scan those for autodefs. We start with the core libraries.
|
||||||
(when (file-exists-p auto-file)
|
(targets (doom-glob doom-core-dir "autoload/*.el"))
|
||||||
(push auto-file targets)
|
;; A subset of `targets' in enabled modules
|
||||||
(if module-p (push auto-file enabled-targets)))
|
(active-targets (copy-sequence targets)))
|
||||||
(dolist (file (doom-files-in auto-dir :match "\\.el$" :full t :sort nil))
|
|
||||||
(push file targets)
|
(dolist (path (doom-module-load-path 'all-p))
|
||||||
(if module-p (push file enabled-targets)))))
|
(when-let* ((files (cons (doom-glob path "autoload.el")
|
||||||
(if (and (not force-p)
|
(doom-files-in (doom-path path "autoload")
|
||||||
(not doom-emacs-changed-p)
|
:match "\\.el$")))
|
||||||
(file-exists-p doom-autoload-file)
|
(files (delq nil files)))
|
||||||
(not (file-newer-than-file-p (expand-file-name "init.el" doom-private-dir)
|
(appendq! targets files)
|
||||||
doom-autoload-file))
|
(when (or (doom-module-from-path path 'enabled-only)
|
||||||
(not (cl-loop for file in targets
|
(file-equal-p path doom-private-dir))
|
||||||
if (file-newer-than-file-p file doom-autoload-file)
|
(appendq! active-targets files))))
|
||||||
return t)))
|
|
||||||
(progn (print! (green "Doom core autoloads is up-to-date"))
|
(print! (start "Checking core autoloads file"))
|
||||||
(doom-initialize-autoloads doom-autoload-file)
|
(print-group!
|
||||||
nil)
|
(if (and (not force-p)
|
||||||
(doom-delete-autoloads-file doom-autoload-file)
|
(file-exists-p doom-autoload-file)
|
||||||
(message "Generating new autoloads.el")
|
(not (file-newer-than-file-p doom-emacs-dir doom-autoload-file))
|
||||||
(make-directory (file-name-directory doom-autoload-file) t)
|
(not (cl-loop for dir
|
||||||
(with-temp-file doom-autoload-file
|
in (append (doom-glob doom-private-dir "init.el*")
|
||||||
(doom--generate-header 'doom-reload-doom-autoloads)
|
targets)
|
||||||
(prin1 `(setq doom--modules-cache ',doom-modules) (current-buffer))
|
if (file-newer-than-file-p dir doom-autoload-file)
|
||||||
(save-excursion
|
return t)))
|
||||||
(doom--generate-autoloads (reverse enabled-targets)))
|
(ignore
|
||||||
;; Replace autoload paths (only for module autoloads) with absolute
|
(print! (success "Skipping core autoloads, they are up-to-date"))
|
||||||
;; paths for faster resolution during load and simpler `load-path'
|
(doom-load-autoloads-file doom-autoload-file))
|
||||||
(save-excursion
|
(print! (start "Regenerating core autoloads file"))
|
||||||
(doom--expand-autoloads)
|
|
||||||
(print! (green "✓ Expanded module autoload paths")))
|
(if (doom-delete-autoloads-file doom-autoload-file)
|
||||||
;; Generates stub definitions for functions/macros defined in disabled
|
(print! (success "Deleted old %s") (filename doom-autoload-file))
|
||||||
;; modules, so that you will never get a void-function when you use
|
(make-directory (file-name-directory doom-autoload-file) t))
|
||||||
;; them.
|
|
||||||
(save-excursion
|
(with-temp-file doom-autoload-file
|
||||||
(doom--generate-autodefs (reverse targets) enabled-targets)
|
(doom--generate-header 'doom-reload-core-autoloads)
|
||||||
(print! (green "✓ Generated autodefs")))
|
(save-excursion
|
||||||
;; Remove byte-compile-inhibiting file variables so we can byte-compile
|
(doom--generate-autoloads active-targets)
|
||||||
;; the file, and autoload comments.
|
(print! (success "Generated new autoloads.el")))
|
||||||
(doom--cleanup-autoloads)
|
;; Replace autoload paths (only for module autoloads) with absolute
|
||||||
(print! (green "✓ Clean up autoloads")))
|
;; paths for faster resolution during load and simpler `load-path'
|
||||||
;; Byte compile it to give the file a chance to reveal errors.
|
(save-excursion
|
||||||
(doom--byte-compile-file doom-autoload-file)
|
(doom--expand-autoload-paths 'allow-internal-paths)
|
||||||
(doom--reload-files doom-autoload-file)
|
(print! (success "Expanded module autoload paths")))
|
||||||
t)))
|
;; Generates stub definitions for functions/macros defined in disabled
|
||||||
|
;; modules, so that you will never get a void-function when you use
|
||||||
|
;; them.
|
||||||
|
(save-excursion
|
||||||
|
(doom--generate-autodefs targets (reverse active-targets))
|
||||||
|
(print! (success "Generated autodefs")))
|
||||||
|
;; Remove byte-compile-inhibiting file variables so we can byte-compile
|
||||||
|
;; the file, and autoload comments.
|
||||||
|
(doom--cleanup-autoloads)
|
||||||
|
(print! (success "Clean up autoloads")))
|
||||||
|
;; Byte compile it to give the file a chance to reveal errors (and buy us a
|
||||||
|
;; few marginal performance boosts)
|
||||||
|
(print! "> Byte-compiling %s..." (relpath doom-autoload-file))
|
||||||
|
(when (doom--byte-compile-file doom-autoload-file)
|
||||||
|
(print! (success "Finished compiling %s") (relpath doom-autoload-file))))
|
||||||
|
t)))
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
|
@ -304,23 +306,24 @@ Run this whenever your `doom!' block, or a module autoload file, is modified."
|
||||||
|
|
||||||
(defun doom--generate-package-autoloads ()
|
(defun doom--generate-package-autoloads ()
|
||||||
"Concatenates package autoload files, let-binds `load-file-name' around
|
"Concatenates package autoload files, let-binds `load-file-name' around
|
||||||
them,and remove unnecessary `provide' statements or blank links.
|
them,and remove unnecessary `provide' statements or blank links."
|
||||||
|
(dolist (pkg (hash-table-keys straight--build-cache))
|
||||||
Skips over packages in `doom-autoload-excluded-packages'."
|
(unless (member pkg doom-autoload-excluded-packages)
|
||||||
(dolist (spec (doom-get-package-alist))
|
(let ((file (straight--autoloads-file pkg)))
|
||||||
(if-let* ((pkg (car spec))
|
(when (file-exists-p file)
|
||||||
(desc (cdr spec)))
|
(insert-file-contents-literally file)
|
||||||
(unless (memq pkg doom-autoload-excluded-packages)
|
(save-excursion
|
||||||
(let ((file (concat (package--autoloads-file-name desc) ".el")))
|
(while (re-search-forward "\\(?:\\_<load-file-name\\|#\\$\\)\\_>" nil t)
|
||||||
(when (file-exists-p file)
|
;; `load-file-name' is meaningless in a concatenated
|
||||||
(insert "(let ((load-file-name " (prin1-to-string (abbreviate-file-name file)) "))\n")
|
;; mega-autoloads file, so we replace references to it and #$ with
|
||||||
(insert-file-contents file)
|
;; the file they came from.
|
||||||
(while (re-search-forward "^\\(?:;;\\(.*\n\\)\\|\n\\|(provide '[^\n]+\\)" nil t)
|
(unless (doom-point-in-string-or-comment-p)
|
||||||
(unless (nth 8 (syntax-ppss))
|
(replace-match (prin1-to-string (abbreviate-file-name file))
|
||||||
(replace-match "" t t)))
|
t t))))
|
||||||
(unless (bolp) (insert "\n"))
|
(while (re-search-forward "^\\(?:;;\\(.*\n\\)\\|\n\\|(provide '[^\n]+\\)" nil t)
|
||||||
(insert ")\n"))))
|
(unless (doom-point-in-string-p)
|
||||||
(message "Couldn't find package desc for %s" (car spec)))))
|
(replace-match "" t t)))
|
||||||
|
(unless (bolp) (insert "\n")))))))
|
||||||
|
|
||||||
(defun doom--generate-var-cache ()
|
(defun doom--generate-var-cache ()
|
||||||
"Print a `setq' form for expensive-to-initialize variables, so we can 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
|
(prin1 `(setq load-path ',load-path
|
||||||
auto-mode-alist ',auto-mode-alist
|
auto-mode-alist ',auto-mode-alist
|
||||||
Info-directory-list ',Info-directory-list
|
Info-directory-list ',Info-directory-list
|
||||||
doom-disabled-packages ',(mapcar #'car (doom-find-packages :disabled t))
|
doom-disabled-packages ',doom-disabled-packages)
|
||||||
package-activated-list ',package-activated-list)
|
|
||||||
(current-buffer)))
|
(current-buffer)))
|
||||||
|
|
||||||
(defun doom--cleanup-package-autoloads ()
|
(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.
|
FORCE-P (universal argument) is non-nil, regenerate it anyway.
|
||||||
|
|
||||||
This should be run whenever your `doom!' block or update your packages."
|
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"))
|
||||||
(if (and (not force-p)
|
(print-group!
|
||||||
(not doom-emacs-changed-p)
|
(if (and (not force-p)
|
||||||
(file-exists-p doom-package-autoload-file)
|
(file-exists-p doom-package-autoload-file)
|
||||||
(not (file-newer-than-file-p doom-packages-dir doom-package-autoload-file))
|
(not (file-newer-than-file-p doom-elpa-dir doom-package-autoload-file))
|
||||||
(not (ignore-errors
|
(not (cl-loop for dir in (straight--directory-files (straight--build-dir))
|
||||||
(cl-loop for key being the hash-keys of (doom-modules)
|
if (cl-find-if
|
||||||
for path = (doom-module-path (car key) (cdr key) "packages.el")
|
(lambda (dir)
|
||||||
if (file-newer-than-file-p path doom-package-autoload-file)
|
(file-newer-than-file-p dir doom-package-autoload-file))
|
||||||
return t))))
|
(doom-glob (straight--build-dir dir) "*.el"))
|
||||||
(ignore (print! (green "Doom package autoloads is up-to-date"))
|
return t))
|
||||||
(doom-initialize-autoloads doom-package-autoload-file))
|
(not (cl-loop with doom-modules = (doom-modules)
|
||||||
(let (case-fold-search)
|
for key being the hash-keys of doom-modules
|
||||||
(doom-delete-autoloads-file doom-package-autoload-file)
|
for path = (doom-module-path (car key) (cdr key) "packages.el")
|
||||||
(with-temp-file doom-package-autoload-file
|
if (file-newer-than-file-p path doom-package-autoload-file)
|
||||||
(doom--generate-header 'doom-reload-package-autoloads)
|
return t)))
|
||||||
(save-excursion
|
(ignore
|
||||||
;; Cache important and expensive-to-initialize state here.
|
(print! (success "Skipping package autoloads, they are up-to-date"))
|
||||||
(doom--generate-var-cache)
|
(doom-load-autoloads-file doom-package-autoload-file))
|
||||||
(print! (green "✓ Cached package state"))
|
(let (;; The following bindings are in `package-generate-autoloads'.
|
||||||
;; Concatenate the autoloads of all installed packages.
|
;; Presumably for a good reason, so I just copied them
|
||||||
(doom--generate-package-autoloads)
|
(noninteractive t)
|
||||||
(print! (green "✓ Package autoloads included")))
|
(backup-inhibited t)
|
||||||
;; Remove `load-path' and `auto-mode-alist' modifications (most of them,
|
(version-control 'never)
|
||||||
;; at least); they are cached later, so all those membership checks are
|
(case-fold-search nil) ; reduce magit
|
||||||
;; unnecessary overhead.
|
(autoload-timestamps nil))
|
||||||
(doom--cleanup-package-autoloads)
|
(print! (start "Regenerating package autoloads file"))
|
||||||
(print! (green "✓ Removed load-path/auto-mode-alist entries"))))
|
|
||||||
(doom--byte-compile-file doom-package-autoload-file)
|
(if (doom-delete-autoloads-file doom-package-autoload-file)
|
||||||
(doom--reload-files doom-package-autoload-file)
|
(print! (success "Deleted old %s") (filename doom-package-autoload-file))
|
||||||
t)))
|
(make-directory (file-name-directory doom-autoload-file) t))
|
||||||
|
|
||||||
|
(with-temp-file doom-package-autoload-file
|
||||||
|
(doom--generate-header 'doom-reload-package-autoloads)
|
||||||
|
|
||||||
|
(save-excursion
|
||||||
|
;; Cache important and expensive-to-initialize state here.
|
||||||
|
(doom--generate-var-cache)
|
||||||
|
(print! (success "Cached package state"))
|
||||||
|
;; Concatenate the autoloads of all installed packages.
|
||||||
|
(doom--generate-package-autoloads)
|
||||||
|
(print! (success "Package autoloads included")))
|
||||||
|
|
||||||
|
;; Replace autoload paths (only for module autoloads) with absolute
|
||||||
|
;; paths for faster resolution during load and simpler `load-path'
|
||||||
|
(save-excursion
|
||||||
|
(doom--expand-autoload-paths)
|
||||||
|
(print! (success "Expanded module autoload paths")))
|
||||||
|
|
||||||
|
;; Remove `load-path' and `auto-mode-alist' modifications (most of them,
|
||||||
|
;; at least); they are cached later, so all those membership checks are
|
||||||
|
;; unnecessary overhead.
|
||||||
|
(doom--cleanup-package-autoloads)
|
||||||
|
(print! (success "Removed load-path/auto-mode-alist entries")))
|
||||||
|
;; Byte compile it to give the file a chance to reveal errors (and buy us a
|
||||||
|
;; few marginal performance boosts)
|
||||||
|
(print! (start "Byte-compiling %s...") (relpath doom-package-autoload-file))
|
||||||
|
(when (doom--byte-compile-file doom-package-autoload-file)
|
||||||
|
(print! (success "Finished compiling %s") (relpath doom-package-autoload-file)))))
|
||||||
|
t))
|
||||||
|
|
|
@ -1,21 +1,24 @@
|
||||||
;;; core/cli/byte-compile.el -*- lexical-binding: t; -*-
|
;;; 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.
|
"Byte-compiles your config or selected modules.
|
||||||
|
|
||||||
compile [TARGETS...]
|
compile [TARGETS...]
|
||||||
compile :core :private lang/python
|
compile :core :private lang/python
|
||||||
compile feature lang
|
compile feature lang
|
||||||
|
|
||||||
Accepts :core, :private and :plugins as special arguments, indicating you want
|
Accepts :core and :private as special arguments, which target Doom's core files
|
||||||
to byte-compile Doom's core files, your private config or your ELPA plugins,
|
and your private config files, respectively. To recompile your packages, use
|
||||||
respectively.")
|
'doom rebuild' instead."
|
||||||
|
(doom-byte-compile targets))
|
||||||
|
|
||||||
(dispatcher! (recompile rc) (doom-byte-compile args 'recompile)
|
(defcli! (recompile rc) (&rest targets)
|
||||||
"Re-byte-compiles outdated *.elc files.")
|
"Re-byte-compiles outdated *.elc files."
|
||||||
|
(doom-byte-compile targets 'recompile))
|
||||||
|
|
||||||
(dispatcher! clean (doom-clean-byte-compiled-files)
|
(defcli! clean ()
|
||||||
"Delete all *.elc files.")
|
"Delete all *.elc files."
|
||||||
|
(doom-clean-byte-compiled-files))
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
|
@ -25,9 +28,10 @@ respectively.")
|
||||||
(let ((filename (file-name-nondirectory path)))
|
(let ((filename (file-name-nondirectory path)))
|
||||||
(or (string-prefix-p "." filename)
|
(or (string-prefix-p "." filename)
|
||||||
(string-prefix-p "test-" 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.
|
"Byte compiles your emacs configuration.
|
||||||
|
|
||||||
init.el is always byte-compiled by this.
|
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."
|
If RECOMPILE-P is non-nil, only recompile out-of-date files."
|
||||||
(let ((default-directory doom-emacs-dir)
|
(let ((default-directory doom-emacs-dir)
|
||||||
(total-ok 0)
|
(doom-modules (doom-modules))
|
||||||
(total-fail 0)
|
(byte-compile-verbose doom-debug-mode)
|
||||||
(total-noop 0)
|
(byte-compile-warnings '(not free-vars unresolved noruntime lexical make-local))
|
||||||
compile-plugins-p
|
|
||||||
|
;; In case it is changed during compile-time
|
||||||
|
(auto-mode-alist auto-mode-alist)
|
||||||
|
(noninteractive t)
|
||||||
|
|
||||||
targets)
|
targets)
|
||||||
(dolist (module (delete-dups modules) (nreverse targets))
|
|
||||||
(pcase module
|
(let (target-dirs)
|
||||||
(":core" (push doom-core-dir targets))
|
(dolist (module (delete-dups modules))
|
||||||
(":private" (push doom-private-dir targets))
|
(pcase module
|
||||||
(":plugins"
|
(":core"
|
||||||
(cl-loop for (_name . desc) in (doom-get-package-alist)
|
(push (doom-glob doom-emacs-dir "init.el") targets)
|
||||||
do (package--compile desc))
|
(push doom-core-dir target-dirs))
|
||||||
(setq compile-plugins-p t
|
(":private"
|
||||||
modules (delete ":plugins" modules)))
|
(push doom-private-dir target-dirs))
|
||||||
((pred file-directory-p)
|
((pred file-directory-p)
|
||||||
(push module targets))
|
(push module target-dirs))
|
||||||
((pred (string-match "^\\([^/]+\\)/\\([^/]+\\)$"))
|
((pred (string-match "^\\([^/]+\\)/\\([^/]+\\)$"))
|
||||||
(push (doom-module-locate-path
|
(push (doom-module-locate-path
|
||||||
(doom-keyword-intern (match-string 1 module))
|
(doom-keyword-intern (match-string 1 module))
|
||||||
(intern (match-string 2 module)))
|
(intern (match-string 2 module)))
|
||||||
targets))))
|
target-dirs))
|
||||||
(cl-block 'byte-compile
|
(_ (user-error "%S is not a valid target" module))))
|
||||||
;; If we're just here to byte-compile our plugins, we're done!
|
|
||||||
(and (not modules)
|
(and (or (null modules) (member ":private" modules))
|
||||||
compile-plugins-p
|
(not recompile-p)
|
||||||
(cl-return-from 'byte-compile t))
|
(not (or doom-auto-accept
|
||||||
(unless (or (equal modules '(":core"))
|
|
||||||
recompile-p)
|
|
||||||
(unless (or doom-auto-accept
|
|
||||||
(y-or-n-p
|
(y-or-n-p
|
||||||
(concat "Warning: byte compiling is for advanced users. It will interfere with your\n"
|
(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"
|
"efforts to debug issues. It is not recommended you do it if you frequently\n"
|
||||||
|
@ -82,109 +87,117 @@ If RECOMPILE-P is non-nil, only recompile out-of-date files."
|
||||||
"Doom core files, as these don't change often.\n\n"
|
"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"
|
"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"
|
"`bin/doom clean` to clear out your *.elc files.\n\n"
|
||||||
"Byte-compile anyway?")))
|
"Byte-compile anyway?"))))
|
||||||
(message "Aborting.")
|
(user-error "Aborting"))
|
||||||
(cl-return-from 'byte-compile)))
|
|
||||||
(when (and (not recompile-p)
|
;; But first we must be sure that Doom and your private config have been
|
||||||
(or (null modules)
|
;; fully loaded. Which usually aren't so in an noninteractive session.
|
||||||
(equal modules '(":core"))))
|
(let (noninteractive)
|
||||||
(doom-clean-byte-compiled-files))
|
(doom-initialize 'force)
|
||||||
(let (doom-emacs-changed-p
|
(doom-initialize-core)
|
||||||
noninteractive)
|
|
||||||
;; But first we must be sure that Doom and your private config have been
|
|
||||||
;; fully loaded. Which usually aren't so in an noninteractive session.
|
|
||||||
(unless (and (doom-initialize-autoloads doom-autoload-file)
|
|
||||||
(doom-initialize-autoloads doom-package-autoload-file))
|
|
||||||
(doom-reload-autoloads))
|
|
||||||
(doom-initialize)
|
|
||||||
(doom-initialize-modules 'force))
|
(doom-initialize-modules 'force))
|
||||||
;; If no targets were supplied, then we use your module list.
|
|
||||||
(unless modules
|
;;
|
||||||
(let ((doom-modules-dirs (delete (expand-file-name "modules/" doom-private-dir)
|
(unless target-dirs
|
||||||
doom-modules-dirs)))
|
(push (doom-glob doom-emacs-dir "init.el") targets)
|
||||||
(setq targets
|
;; If no targets were supplied, then we use your module list.
|
||||||
(append (list doom-core-dir)
|
(appendq! target-dirs
|
||||||
(delete doom-private-dir (doom-module-load-path))))))
|
(list doom-core-dir)
|
||||||
;; Assemble el files we want to compile; taking into account that
|
(nreverse
|
||||||
;; MODULES may be a list of MODULE/SUBMODULE strings from the command
|
(cl-remove-if-not
|
||||||
;; line.
|
(lambda (path) (file-in-directory-p path doom-emacs-dir))
|
||||||
(let ((target-files (doom-files-in targets :filter #'doom--byte-compile-ignore-file-p :sort nil)))
|
;; Omit `doom-private-dir', which is always first
|
||||||
(when (or (not modules)
|
(cdr (doom-module-load-path))))))
|
||||||
(member ":core" modules))
|
|
||||||
(push (expand-file-name "init.el" doom-emacs-dir)
|
;; Assemble el files we want to compile; taking into account that MODULES
|
||||||
target-files))
|
;; may be a list of MODULE/SUBMODULE strings from the command line.
|
||||||
(unless target-files
|
(appendq! targets
|
||||||
(if targets
|
(doom-files-in target-dirs
|
||||||
(message "Couldn't find any valid targets")
|
:match "\\.el$"
|
||||||
(message "No targets to %scompile" (if recompile-p "re" "")))
|
:filter #'doom--byte-compile-ignore-file-p)))
|
||||||
(cl-return-from 'byte-compile))
|
|
||||||
(require 'use-package)
|
(unless targets
|
||||||
(condition-case e
|
(print!
|
||||||
(let ((use-package-defaults use-package-defaults)
|
(if targets
|
||||||
(use-package-expand-minimally t)
|
(warn "Couldn't find any valid targets")
|
||||||
(load-path load-path)
|
(info "No targets to %scompile" (if recompile-p "re" ""))))
|
||||||
kill-emacs-hook kill-buffer-query-functions)
|
(cl-return nil))
|
||||||
;; Prevent packages from being loaded at compile time if they
|
|
||||||
;; don't meet their own predicates.
|
(print!
|
||||||
(push (list :no-require t
|
(info (if recompile-p
|
||||||
(lambda (_name args)
|
"Recompiling stale elc files..."
|
||||||
(or (when-let (pred (or (plist-get args :if)
|
"Byte-compiling your config (may take a while)...")))
|
||||||
(plist-get args :when)))
|
(print-group!
|
||||||
(not (eval pred t)))
|
(require 'use-package)
|
||||||
(when-let (pred (plist-get args :unless))
|
(condition-case e
|
||||||
(eval pred t)))))
|
(let ((total-ok 0)
|
||||||
use-package-defaults)
|
(total-fail 0)
|
||||||
(dolist (target (cl-delete-duplicates (mapcar #'file-truename target-files) :test #'equal))
|
(total-noop 0)
|
||||||
(if (or (not recompile-p)
|
(use-package-defaults use-package-defaults)
|
||||||
(let ((elc-file (byte-compile-dest-file target)))
|
(use-package-expand-minimally t)
|
||||||
(and (file-exists-p elc-file)
|
kill-emacs-hook kill-buffer-query-functions)
|
||||||
(file-newer-than-file-p target elc-file))))
|
;; Prevent packages from being loaded at compile time if they
|
||||||
(let ((result (if (or (string-match-p "/\\(?:packages\\|doctor\\)\\.el$" target)
|
;; don't meet their own predicates.
|
||||||
(not (doom--file-cookie-p target)))
|
(push (list :no-require t
|
||||||
'no-byte-compile
|
(lambda (_name args)
|
||||||
(byte-compile-file target)))
|
(or (when-let (pred (or (plist-get args :if)
|
||||||
(short-name (if (file-in-directory-p target doom-emacs-dir)
|
(plist-get args :when)))
|
||||||
(file-relative-name target doom-emacs-dir)
|
(not (eval pred t)))
|
||||||
(abbreviate-file-name target))))
|
(when-let (pred (plist-get args :unless))
|
||||||
(cl-incf
|
(eval pred t)))))
|
||||||
(cond ((eq result 'no-byte-compile)
|
use-package-defaults)
|
||||||
(print! (dark (white "⚠ Ignored %s")) short-name)
|
|
||||||
total-noop)
|
(unless recompile-p
|
||||||
((null result)
|
(doom-clean-byte-compiled-files))
|
||||||
(print! (red "✕ Failed to compile %s") short-name)
|
|
||||||
total-fail)
|
(dolist (target (delete-dups targets))
|
||||||
(t
|
(cl-incf
|
||||||
(print! (green "✓ Compiled %s") short-name)
|
(if (not (or (not recompile-p)
|
||||||
(load target t t)
|
(let ((elc-file (byte-compile-dest-file target)))
|
||||||
total-ok))))
|
(and (file-exists-p elc-file)
|
||||||
(cl-incf total-noop)))
|
(file-newer-than-file-p target elc-file)))))
|
||||||
(print! (bold (color (if (= total-fail 0) 'green 'red)
|
total-noop
|
||||||
"%s %d/%d file(s) (%d ignored)"))
|
(pcase (if (doom-file-cookie-p target)
|
||||||
(if recompile-p "Recompiled" "Compiled")
|
(byte-compile-file target)
|
||||||
total-ok (- (length target-files) total-noop)
|
'no-byte-compile)
|
||||||
total-noop)
|
(`no-byte-compile
|
||||||
(or (= total-fail 0)
|
(print! (info "Ignored %s") (relpath target))
|
||||||
(error "Failed to compile some files")))
|
total-noop)
|
||||||
((debug error)
|
(`nil
|
||||||
(print! (red "\nThere were breaking errors.\n\n%s")
|
(print! (error "Failed to compile %s") (relpath target))
|
||||||
"Reverting changes...")
|
total-fail)
|
||||||
(signal 'doom-error (list 'byte-compile e))))))))
|
(_
|
||||||
|
(print! (success "Compiled %s") (relpath target))
|
||||||
|
(load target t t)
|
||||||
|
total-ok)))))
|
||||||
|
(print! (class (if (= total-fail 0) 'success 'error)
|
||||||
|
"%s %d/%d file(s) (%d ignored)")
|
||||||
|
(if recompile-p "Recompiled" "Compiled")
|
||||||
|
total-ok (- (length targets) total-noop)
|
||||||
|
total-noop)
|
||||||
|
t)
|
||||||
|
((debug error)
|
||||||
|
(print! (error "\nThere were breaking errors.\n\n%s")
|
||||||
|
"Reverting changes...")
|
||||||
|
(signal 'doom-error (list 'byte-compile e)))))))
|
||||||
|
|
||||||
(defun doom-clean-byte-compiled-files ()
|
(defun doom-clean-byte-compiled-files ()
|
||||||
"Delete all the compiled elc files in your Emacs configuration and private
|
"Delete all the compiled elc files in your Emacs configuration and private
|
||||||
module. This does not include your byte-compiled, third party packages.'"
|
module. This does not include your byte-compiled, third party packages.'"
|
||||||
(cl-loop with default-directory = doom-emacs-dir
|
(print! (start "Cleaning .elc files"))
|
||||||
for path
|
(print-group!
|
||||||
in (append (doom-files-in doom-emacs-dir :match "\\.elc$" :depth 0 :sort nil)
|
(cl-loop with default-directory = doom-emacs-dir
|
||||||
(doom-files-in doom-private-dir :match "\\.elc$" :depth 1 :sort nil)
|
with success = nil
|
||||||
(doom-files-in doom-core-dir :match "\\.elc$" :sort nil)
|
for path
|
||||||
(doom-files-in doom-modules-dirs :match "\\.elc$" :depth 4 :sort nil))
|
in (append (doom-glob doom-emacs-dir "*.elc")
|
||||||
for truepath = (file-truename path)
|
(doom-files-in doom-private-dir :match "\\.elc$" :depth 1)
|
||||||
if (file-exists-p path)
|
(doom-files-in doom-core-dir :match "\\.elc$")
|
||||||
do (delete-file path)
|
(doom-files-in doom-modules-dirs :match "\\.elc$" :depth 4))
|
||||||
and do
|
if (file-exists-p path)
|
||||||
(print! (green "✓ Deleted %s")
|
do (delete-file path)
|
||||||
(if (file-in-directory-p truepath default-directory)
|
and do (print! (success "Deleted %s") (relpath path))
|
||||||
(file-relative-name truepath)
|
and do (setq success t)
|
||||||
(abbreviate-file-name truepath)))
|
finally do
|
||||||
finally do (print! (bold (green "Everything is clean")))))
|
(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; -*-
|
;;; core/cli/debug.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
(dispatcher! info (doom/info)
|
(load! "autoload/debug" doom-core-dir)
|
||||||
"Output system info in markdown for bug reports.")
|
|
||||||
|
|
||||||
(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)
|
||||||
|
|
163
core/cli/env.el
163
core/cli/env.el
|
@ -1,44 +1,46 @@
|
||||||
;;; core/cli/env.el -*- lexical-binding: t; -*-
|
;;; core/cli/env.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
(dispatcher! env
|
(defcli! env (&rest args)
|
||||||
(let ((env-file (abbreviate-file-name doom-env-file)))
|
"Creates or regenerates your envvars file.
|
||||||
(pcase (car args)
|
|
||||||
((or "refresh" "re")
|
|
||||||
(doom-reload-env-file 'force))
|
|
||||||
((or "enable" "auto")
|
|
||||||
(setenv "DOOMENV" "1")
|
|
||||||
(print! (green "Enabling auto-reload of %S") env-file)
|
|
||||||
(doom-reload-env-file 'force)
|
|
||||||
(print! (green "Done! `doom refresh' will now refresh your envvar file.")))
|
|
||||||
("clear"
|
|
||||||
(setenv "DOOMENV" nil)
|
|
||||||
(unless (file-exists-p env-file)
|
|
||||||
(user-error "%S does not exist to be cleared" env-file))
|
|
||||||
(delete-file env-file)
|
|
||||||
(print! (green "Disabled envvar file by deleting %S") env-file))
|
|
||||||
(_
|
|
||||||
(print! "%s\n\n%s"
|
|
||||||
(bold (red "No valid subcommand provided."))
|
|
||||||
"See `doom help env` to see available commands."))))
|
|
||||||
"Manages your envvars file.
|
|
||||||
|
|
||||||
env [SUBCOMMAND]
|
doom env [-c|--clear]
|
||||||
|
|
||||||
Available subcommands:
|
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.
|
||||||
|
|
||||||
refresh Create or regenerate your envvar file
|
The envvars file is created by scraping your (interactive) shell environment
|
||||||
auto enable auto-reloading of your envvars file (on `doom refresh`)
|
into newline-delimited KEY=VALUE pairs. Typically by running '$SHELL -ic env'
|
||||||
clear deletes your envvar file (if it exists) and disables auto-reloading
|
(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).
|
||||||
|
|
||||||
An envvars file (its location is controlled by the `doom-env-file' variable)
|
This is useful in cases where you cannot guarantee that Emacs (or the daemon)
|
||||||
will contain a list of environment variables scraped from your shell environment
|
will be launched from the correct environment (e.g. on MacOS or through certain
|
||||||
and loaded when Doom starts (if it exists). This is necessary when Emacs can't
|
app launchers on Linux).
|
||||||
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
|
This file is automatically regenerated when you run this command or 'doom
|
||||||
auto-reloaded when running `doom refresh`, run `doom env enable` instead (only
|
refresh'. However, 'doom refresh' will only regenerate this file if it exists.
|
||||||
needs to be run once).")
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
((user-error "I don't understand 'doom env %s'"
|
||||||
|
(string-join args " "))))))
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
|
@ -55,7 +57,8 @@ needs to be run once).")
|
||||||
;; Doom envvars
|
;; Doom envvars
|
||||||
"^INSECURE$"
|
"^INSECURE$"
|
||||||
"^DEBUG$"
|
"^DEBUG$"
|
||||||
"^YES$")
|
"^YES$"
|
||||||
|
"^__")
|
||||||
"Environment variables to not save in `doom-env-file'.
|
"Environment variables to not save in `doom-env-file'.
|
||||||
|
|
||||||
Each string is a regexp, matched against variable names to omit from
|
Each string is a regexp, matched against variable names to omit from
|
||||||
|
@ -86,50 +89,54 @@ default, on Linux, this is '$SHELL -ic /usr/bin/env'. Variables in
|
||||||
`doom-env-ignored-vars' are removed."
|
`doom-env-ignored-vars' are removed."
|
||||||
(when (or force-p (not (file-exists-p doom-env-file)))
|
(when (or force-p (not (file-exists-p doom-env-file)))
|
||||||
(with-temp-file 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)
|
(if (file-exists-p doom-env-file)
|
||||||
"Regenerating"
|
"Regenerating"
|
||||||
"Generating")
|
"Generating")
|
||||||
(abbreviate-file-name doom-env-file))
|
(relpath doom-env-file doom-emacs-dir))
|
||||||
(let ((process-environment doom-site-process-environment))
|
(let ((process-environment doom--initial-process-environment))
|
||||||
(insert
|
(let ((shell-command-switch doom-env-switches)
|
||||||
(concat
|
(error-buffer (get-buffer-create "*env errors*")))
|
||||||
"# -*- mode: dotenv -*-\n"
|
(print! (info "Scraping shell environment with '%s %s %s'")
|
||||||
(format "# Generated with: %s %s %s\n"
|
(filename shell-file-name)
|
||||||
shell-file-name
|
shell-command-switch
|
||||||
doom-env-switches
|
(filename doom-env-executable))
|
||||||
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"
|
|
||||||
"#\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"
|
|
||||||
"# ---------------------------------------------------------------------------\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
|
(save-excursion
|
||||||
(insert (shell-command-to-string doom-env-executable)))
|
(shell-command doom-env-executable (current-buffer) error-buffer))
|
||||||
;; Remove undesireable variables
|
(print-group!
|
||||||
(while (re-search-forward "\n\\([^= \n]+\\)=" nil t)
|
(let ((errors (with-current-buffer error-buffer (buffer-string))))
|
||||||
(save-excursion
|
(unless (string-empty-p errors)
|
||||||
(let* ((valend (or (save-match-data
|
(print! (info "Error output:\n\n%s") (indent 4 errors))))
|
||||||
(when (re-search-forward "^\\([^= ]+\\)=" nil t)
|
;; Remove undesireable variables
|
||||||
(line-beginning-position)))
|
(insert
|
||||||
(point-max)))
|
(concat
|
||||||
(var (match-string 1))
|
"# -*- mode: dotenv -*-\n"
|
||||||
(value (buffer-substring-no-properties (point) (1- valend))))
|
(format "# Generated with: %s %s %s\n"
|
||||||
(when (cl-loop for regexp in doom-env-ignored-vars
|
shell-file-name
|
||||||
if (string-match-p regexp var)
|
doom-env-switches
|
||||||
return t)
|
doom-env-executable)
|
||||||
(message "Ignoring %s" var)
|
"# ---------------------------------------------------------------------------\n"
|
||||||
(delete-region (match-beginning 0) (1- valend))))))
|
"# This file was auto-generated by `doom env'. It contains a list of environment\n"
|
||||||
(print! (green "Envvar successfully generated")))))))
|
"# 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 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"))
|
||||||
|
(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)))
|
||||||
|
(when (cl-loop for regexp in doom-env-ignored-vars
|
||||||
|
if (string-match-p regexp var)
|
||||||
|
return t)
|
||||||
|
(print! (info "Ignoring %s") var)
|
||||||
|
(delete-region (match-beginning 0) (1- valend)))))))
|
||||||
|
(print! (success "Successfully generated %S")
|
||||||
|
(relpath doom-env-file doom-emacs-dir))
|
||||||
|
t)))))
|
||||||
|
|
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; -*-
|
;; -*- no-byte-compile: t; -*-
|
||||||
;;; core/cli/packages.el
|
;;; core/cli/packages.el
|
||||||
|
|
||||||
;;
|
(defmacro doom--ensure-autoloads-while (&rest body)
|
||||||
;;; Helpers
|
`(progn
|
||||||
|
(doom-reload-core-autoloads)
|
||||||
(defmacro doom--condition-case! (&rest body)
|
(when (progn ,@body)
|
||||||
`(condition-case-unless-debug e
|
(doom-reload-package-autoloads 'force-p))
|
||||||
(progn ,@body)
|
t))
|
||||||
('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)))
|
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;;; Dispatchers
|
;;; Dispatchers
|
||||||
|
|
||||||
(dispatcher! (install i)
|
(defcli! (update u) (&rest args)
|
||||||
(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)
|
|
||||||
"Updates packages.
|
"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
|
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)
|
(defcli! (rebuild build b) (&rest args)
|
||||||
(doom--ensure-autoloads-while #'doom-packages-autoremove)
|
"Rebuilds all installed packages.
|
||||||
"Removes packages that are no longer needed.
|
|
||||||
|
|
||||||
This includes packages installed with 'M-x package-install' without an
|
This ensures that all needed files are symlinked from their package repo and
|
||||||
accompanying `package!' declaration in an enabled module's packages.el file or
|
their elisp files are byte-compiled."
|
||||||
your private one.")
|
(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
|
Unless AUTO-ACCEPT-P is non-nil, this function will prompt for confirmation with
|
||||||
a list of packages that will be installed."
|
a list of packages that will be installed."
|
||||||
(print! "Looking for packages to install...")
|
(print! "> Installing & building packages...")
|
||||||
(let ((packages (doom-get-missing-packages)))
|
(print-group!
|
||||||
(cond ((not packages)
|
(let ((n 0))
|
||||||
(print! (green "No packages to install!"))
|
(dolist (package (hash-table-keys straight--recipe-cache))
|
||||||
nil)
|
(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)
|
(defun doom-packages-rebuild (&optional auto-accept-p all)
|
||||||
(doom-refresh-packages-maybe doom-debug-mode)
|
"(Re)build all packages."
|
||||||
(dolist (pkg packages)
|
(print! (start "(Re)building %spackages...") (if all "all " ""))
|
||||||
(print! "Installing %s" (car pkg))
|
(print-group!
|
||||||
(doom--condition-case!
|
(let ((n 0))
|
||||||
(let ((result
|
(if all
|
||||||
(or (and (doom-package-installed-p (car pkg))
|
(let ((straight--packages-to-rebuild :all)
|
||||||
(not (doom-package-different-backend-p (car pkg)))
|
(straight--packages-not-to-rebuild (make-hash-table :test #'equal)))
|
||||||
(not (doom-package-different-recipe-p (car pkg)))
|
(dolist (package (hash-table-keys straight--recipe-cache))
|
||||||
'already-installed)
|
(straight-use-package
|
||||||
(and (doom-install-package (car pkg) (cdr pkg))
|
(intern package) nil (lambda (_) (cl-incf n) nil) " ")))
|
||||||
(setq success t)
|
(dolist (recipe (hash-table-values straight--recipe-cache))
|
||||||
'success)
|
(straight--with-plist recipe (package local-repo no-build)
|
||||||
'failure))
|
(unless (or no-build (null local-repo))
|
||||||
(pin-label
|
;; REVIEW We do these modification checks manually because
|
||||||
(and (plist-member (cdr pkg) :pin)
|
;; Straight's checks seem to miss stale elc files. Need
|
||||||
(format " [pinned: %s]" (plist-get (cdr pkg) :pin)))))
|
;; more tests to confirm this.
|
||||||
(print! "%s%s"
|
(when (or (ignore-errors
|
||||||
(pcase result
|
(gethash package straight--packages-to-rebuild))
|
||||||
(`already-installed (dark (white "⚠ ALREADY INSTALLED")))
|
(gethash package straight--cached-package-modifications)
|
||||||
(`success (green "✓ DONE"))
|
(not (file-directory-p (straight--build-dir package)))
|
||||||
(`failure (red "✕ FAILED")))
|
(cl-loop for file
|
||||||
(or pin-label "")))))
|
in (doom-files-in (straight--build-dir package)
|
||||||
(print! (bold (green "Finished!")))
|
:match "\\.el$"
|
||||||
(when success
|
:full t)
|
||||||
(set-file-times doom-packages-dir)
|
for elc-file = (byte-compile-dest-file file)
|
||||||
(doom-delete-autoloads-file doom-package-autoload-file))
|
if (and (file-exists-p elc-file)
|
||||||
success)))))
|
(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.
|
"Updates packages.
|
||||||
|
|
||||||
Unless AUTO-ACCEPT-P is non-nil, this function will prompt for confirmation with
|
Unless AUTO-ACCEPT-P is non-nil, this function will prompt for confirmation with
|
||||||
a list of packages that will be updated."
|
a list of packages that will be updated."
|
||||||
(print! "Looking for outdated packages...")
|
(print! (start "Scanning for outdated packages (this may take a while)..."))
|
||||||
(let ((packages (cl-sort (cl-copy-list (doom-get-outdated-packages)) #'string-lessp
|
(print-group!
|
||||||
:key #'car)))
|
(when timeout
|
||||||
(cond ((not packages)
|
(print! (info "Using %S as timeout value" timeout)))
|
||||||
(print! (green "Everything is up-to-date"))
|
;; REVIEW Does this fail gracefully enough? Is it error tolerant?
|
||||||
nil)
|
;; 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\n\nThere %s %d package%s available to update. Update them?"
|
||||||
|
(mapconcat
|
||||||
|
(lambda (spec)
|
||||||
|
(cl-destructuring-bind (n pretime time recipe) spec
|
||||||
|
(straight--with-plist recipe (package)
|
||||||
|
(format! "+ %-33s %s commit(s) behind %s -> %s"
|
||||||
|
(yellow package) (yellow n)
|
||||||
|
(format-time-string "%Y%m%d" pretime)
|
||||||
|
(format-time-string "%Y%m%d" time)))))
|
||||||
|
specs
|
||||||
|
"\n")
|
||||||
|
(if (cdr specs) "are" "is")
|
||||||
|
(length specs)
|
||||||
|
(if (cdr specs) "s" "")))))
|
||||||
|
(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)))))))
|
||||||
|
|
||||||
((not (or auto-accept-p
|
|
||||||
(y-or-n-p
|
|
||||||
(format "%s packages will be updated:\n\n%s\n\nProceed?"
|
|
||||||
(length packages)
|
|
||||||
(let ((max-len
|
|
||||||
(or (car (sort (mapcar (lambda (it) (length (symbol-name (car it)))) packages)
|
|
||||||
#'>))
|
|
||||||
10)))
|
|
||||||
(mapconcat
|
|
||||||
(lambda (pkg)
|
|
||||||
(format (format "+ %%-%ds (%%s) %%-%ds -> %%s"
|
|
||||||
(+ max-len 2) 14)
|
|
||||||
(symbol-name (car pkg))
|
|
||||||
(doom-package-backend (car pkg))
|
|
||||||
(package-version-join (cadr pkg))
|
|
||||||
(package-version-join (cl-caddr pkg))))
|
|
||||||
packages
|
|
||||||
"\n"))))))
|
|
||||||
(user-error "Aborted!"))
|
|
||||||
|
|
||||||
((let (success)
|
;;; PURGE (for the emperor)
|
||||||
(dolist (pkg packages)
|
(defun doom--prompt-p (list-fn list preamble postamble)
|
||||||
(print! "Updating %s" (car pkg))
|
(or (y-or-n-p (format "%s%s\n\n%s"
|
||||||
(doom--condition-case!
|
(if preamble (concat preamble "\n\n") "")
|
||||||
(print!
|
(mapconcat list-fn list "\n")
|
||||||
(let ((result (doom-update-package (car pkg) t)))
|
(or postamble "")))
|
||||||
(when result (setq success t))
|
(user-error! "Aborted")))
|
||||||
(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)
|
(defun doom--prompt-columns-p (row-fn list preamble postamble)
|
||||||
"Auto-removes orphaned packages.
|
(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
|
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.
|
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
|
Unless AUTO-ACCEPT-P is non-nil, this function will prompt for confirmation with
|
||||||
a list of packages that will be removed."
|
a list of packages that will be removed."
|
||||||
(print! "Looking for orphaned packages...")
|
(print! (start "Searching for orphaned packages to purge (for the emperor)..."))
|
||||||
(let ((packages (doom-get-orphaned-packages)))
|
(cl-destructuring-bind (&optional builds-to-purge repos-to-purge repos-to-regraft)
|
||||||
(cond ((not packages)
|
(let ((rdirs (straight--directory-files (straight--repos-dir) nil nil 'sort))
|
||||||
(print! (green "No unused packages to remove"))
|
(bdirs (straight--directory-files (straight--build-dir) nil nil 'sort)))
|
||||||
nil)
|
(list (cl-remove-if (doom-rpartial #'gethash straight--profile-cache)
|
||||||
|
bdirs)
|
||||||
((not
|
(cl-remove-if (doom-rpartial #'straight--checkhash straight--repo-cache)
|
||||||
(or auto-accept-p
|
rdirs)
|
||||||
(y-or-n-p
|
(cl-remove-if-not (doom-rpartial #'straight--checkhash straight--repo-cache)
|
||||||
(format "%s packages will be deleted:\n\n%s\n\nProceed?"
|
rdirs)))
|
||||||
(length packages)
|
(let (success)
|
||||||
(mapconcat
|
(print-group!
|
||||||
(lambda (sym)
|
(if (not builds-p)
|
||||||
(let ((old-backend (doom-package-backend sym 'noerror))
|
(print! (info "Skipping builds"))
|
||||||
(new-backend (doom-package-recipe-backend sym 'noerror)))
|
(and (/= 0 (doom--packages-purge-builds builds-to-purge auto-accept-p))
|
||||||
(format "+ %s (%s)" sym
|
(setq success t)
|
||||||
(cond ((null new-backend)
|
(straight-prune-build-cache)))
|
||||||
"removed")
|
(if (not elpa-p)
|
||||||
((eq old-backend new-backend)
|
(print! (info "Skipping elpa packages"))
|
||||||
(symbol-name new-backend))
|
(and (/= 0 (doom--packages-purge-elpa auto-accept-p))
|
||||||
((format "%s -> %s" old-backend new-backend))))))
|
(setq success t)))
|
||||||
(sort (cl-copy-list packages) #'string-lessp)
|
(if (not repos-p)
|
||||||
"\n")))))
|
(print! (info "Skipping repos"))
|
||||||
(user-error "Aborted!"))
|
(and (/= 0 (doom--packages-purge-repos repos-to-purge auto-accept-p))
|
||||||
|
(setq success t))
|
||||||
((let (success)
|
(and (doom--packages-regraft-repos repos-to-regraft auto-accept-p)
|
||||||
(dolist (pkg packages)
|
(setq success t)))
|
||||||
(doom--condition-case!
|
(when success
|
||||||
(let ((result (doom-delete-package pkg t)))
|
(doom--finalize-straight)
|
||||||
(if result (setq success t))
|
t)))))
|
||||||
(print! (color (if result 'green 'red) "%s %s")
|
|
||||||
(if result "✓ Removed" "✕ Failed to remove")
|
|
||||||
pkg))))
|
|
||||||
(print! (bold (green "Finished!")))
|
|
||||||
(when success
|
|
||||||
(set-file-times doom-packages-dir)
|
|
||||||
(doom-delete-autoloads-file doom-package-autoload-file))
|
|
||||||
success)))))
|
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
;;; core/cli/patch-macos.el -*- lexical-binding: t; -*-
|
;;; core/cli/patch-macos.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
(dispatcher! (patch-macos)
|
(defcli! patch-macos () ; DEPRECATED
|
||||||
(doom-patch-macos (or (member "--undo" args)
|
|
||||||
(member "-u" args))
|
|
||||||
(doom--find-emacsapp-path))
|
|
||||||
"Patches Emacs.app to respect your shell environment.
|
"Patches Emacs.app to respect your shell environment.
|
||||||
|
|
||||||
WARNING: This command is deprecated. Use 'doom env' instead.
|
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
|
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
|
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))
|
(message "%s successfully unpatched" appdir))
|
||||||
|
|
||||||
((file-exists-p newbin)
|
((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
|
((user-error "patch-macos has been disabled. Please use 'doom env refresh' instead")))))
|
||||||
(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)))))
|
|
||||||
|
|
|
@ -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; -*-
|
;;; core/cli/test.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
(dispatcher! test (doom-run-tests args)
|
(defcli! test (&rest targets)
|
||||||
"Run Doom unit tests.")
|
"Run Doom unit tests."
|
||||||
|
(let (files error)
|
||||||
|
(unless targets
|
||||||
;;
|
(setq targets
|
||||||
;; Library
|
(cons doom-core-dir
|
||||||
|
(cl-remove-if-not
|
||||||
(defun doom-run-tests (&optional modules)
|
(lambda (path) (file-in-directory-p path doom-emacs-dir))
|
||||||
"Run all loaded tests, specified by MODULES (a list of module cons cells) or
|
;; Omit `doom-private-dir', which is always first
|
||||||
command line args following a double dash (each arg should be in the
|
(let (doom-modules)
|
||||||
'module/submodule' format).
|
(load! "test/init" doom-core-dir)
|
||||||
|
(cdr (doom-module-load-path)))))))
|
||||||
If neither is available, run all tests in all enabled modules."
|
(while targets
|
||||||
;; Core libraries aren't fully loaded in a noninteractive session, so we
|
(let ((target (pop targets)))
|
||||||
;; reload it with `noninteractive' set to nil to force them to.
|
(cond ((equal target ":core")
|
||||||
(let* ((noninteractive t)
|
(appendq! files (nreverse (doom-glob doom-core-dir "test/test-*.el"))))
|
||||||
(doom-modules (doom-modules)))
|
((file-directory-p target)
|
||||||
(quiet! (doom-reload-autoloads))
|
(setq target (expand-file-name target))
|
||||||
(let ((target-paths
|
(appendq! files (nreverse (doom-glob target "test/test-*.el"))))
|
||||||
;; Convert targets into a list of string paths, pointing to the root
|
((file-exists-p target)
|
||||||
;; directory of modules
|
(push target files)))))
|
||||||
(cond ((stringp (car modules)) ; command line
|
(require 'restart-emacs)
|
||||||
(save-match-data
|
(with-temp-buffer
|
||||||
(cl-loop for arg in modules
|
(setenv "DOOMDIR" (concat doom-core-dir "test/"))
|
||||||
if (string= arg ":core") collect doom-core-dir
|
(setenv "DOOMLOCALDIR" (concat doom-local-dir "test/"))
|
||||||
else if (string-match-p "/" arg)
|
(print! (start "Bootstrapping test environment, if necessary..."))
|
||||||
nconc (mapcar (apply-partially #'expand-file-name arg)
|
(if (zerop
|
||||||
doom-modules-dirs)
|
(call-process
|
||||||
else
|
(restart-emacs--get-emacs-binary)
|
||||||
nconc (cl-loop for dir in doom-modules-dirs
|
nil t nil "--batch"
|
||||||
for path = (expand-file-name arg dir)
|
"-l" (concat doom-core-dir "core.el")
|
||||||
if (file-directory-p path)
|
"--eval" (prin1-to-string
|
||||||
nconc (doom-files-in path :type 'dirs :depth 1 :full t :sort nil))
|
`(progn (doom-initialize 'force)
|
||||||
finally do (setq argv nil))))
|
(doom-initialize-modules)
|
||||||
|
(require 'core-cli)
|
||||||
(modules ; cons-cells given to MODULES
|
(unless (package-installed-p 'buttercup)
|
||||||
(cl-loop for (module . submodule) in modules
|
(package-refresh-contents)
|
||||||
if (doom-module-locate-path module submodule)
|
(package-install 'buttercup))
|
||||||
collect it))
|
(doom-reload-core-autoloads 'force)
|
||||||
|
(when (doom-packages-install 'auto-accept)
|
||||||
((append (list doom-core-dir)
|
(doom-reload-package-autoloads 'force))))))
|
||||||
(doom-module-load-path))))))
|
(message "%s" (buffer-string))
|
||||||
;; Load all the unit test files...
|
(message "%s" (buffer-string))
|
||||||
(require 'buttercup)
|
(error "Failed to bootstrap unit tests")))
|
||||||
(mapc (lambda (file) (load file :noerror (not doom-debug-mode)))
|
(dolist (file files)
|
||||||
(doom-files-in (mapcar (apply-partially #'expand-file-name "test/")
|
(if (doom-file-cookie-p file)
|
||||||
target-paths)
|
(with-temp-buffer
|
||||||
:match "\\.el$" :full t))
|
(unless
|
||||||
;; ... then run them
|
(zerop
|
||||||
(when doom-debug-mode
|
(call-process
|
||||||
(setq buttercup-stack-frame-style 'pretty))
|
(restart-emacs--get-emacs-binary)
|
||||||
(let ((split-width-threshold 0)
|
nil t nil "--batch"
|
||||||
(split-height-threshold 0)
|
"-l" (concat doom-core-dir "core.el")
|
||||||
(window-min-width 0)
|
"-l" (concat doom-core-dir "test/helpers.el")
|
||||||
(window-min-height 0))
|
"--eval" (prin1-to-string `(doom-initialize 'force))
|
||||||
(buttercup-run)))))
|
"-l" "buttercup"
|
||||||
|
"-l" file
|
||||||
|
"-f" "buttercup-run"))
|
||||||
;;
|
(setq error t))
|
||||||
;; Test library
|
(message "%s" (buffer-string)))
|
||||||
|
(print! (info "Ignoring %s" (relpath file)))))
|
||||||
(defmacro insert! (&rest text)
|
(if error
|
||||||
"Insert TEXT in buffer, then move cursor to last {0} marker."
|
(error "A test failed")
|
||||||
`(progn
|
t)))
|
||||||
(insert ,@text)
|
|
||||||
(when (search-backward "{0}" nil t)
|
|
||||||
(replace-match "" t t))))
|
|
||||||
|
|
|
@ -1,86 +1,110 @@
|
||||||
;;; core/cli/upgrade.el -*- lexical-binding: t; -*-
|
;;; core/cli/upgrade.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
(dispatcher! (upgrade up) (doom-upgrade)
|
(defcli! (upgrade up) (&rest args)
|
||||||
"Checks out the latest Doom on this branch.
|
"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
|
cd ~/.emacs.d
|
||||||
git pull
|
git pull --rebase
|
||||||
bin/doom clean
|
bin/doom clean
|
||||||
bin/doom refresh
|
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"
|
(defvar doom-repo-url "https://github.com/hlissner/doom-emacs"
|
||||||
"TODO")
|
"The git repo url for Doom Emacs.")
|
||||||
(defvar doom-repo-remote "_upgrade"
|
(defvar doom-repo-remote "_upgrade"
|
||||||
"TODO")
|
"The name to use as our staging remote.")
|
||||||
|
|
||||||
(defun doom--working-tree-dirty-p (dir)
|
(defun doom--working-tree-dirty-p (dir)
|
||||||
(with-temp-buffer
|
(cl-destructuring-bind (success . stdout)
|
||||||
(let ((default-directory dir))
|
(doom-sh "git" "status" "--porcelain" "-uno")
|
||||||
(if (zerop (process-file "git" nil (current-buffer) nil
|
(if (= 0 success)
|
||||||
"status" "--porcelain" "-uno"))
|
(string-match-p "[^ \t\n]" (buffer-string))
|
||||||
(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."
|
"Upgrade Doom to the latest version non-destructively."
|
||||||
(require 'vc-git)
|
(require 'vc-git)
|
||||||
(let* ((gitdir (expand-file-name ".git" doom-emacs-dir))
|
(let ((default-directory doom-emacs-dir)
|
||||||
(branch (vc-git--symbolic-ref doom-emacs-dir))
|
process-file-side-effects)
|
||||||
(default-directory doom-emacs-dir))
|
(print! (start "Preparing to upgrade Doom Emacs and its packages..."))
|
||||||
(unless (file-exists-p gitdir)
|
|
||||||
(error "Couldn't find %s. Was Doom cloned properly?"
|
(let* ((branch (vc-git--symbolic-ref doom-emacs-dir))
|
||||||
(abbreviate-file-name gitdir)))
|
(target-remote (format "%s/%s" doom-repo-remote branch)))
|
||||||
(unless branch
|
(unless branch
|
||||||
(error "Couldn't detect what branch you're using. Is Doom detached?"))
|
(error! (if (file-exists-p! ".git" doom-emacs-dir)
|
||||||
(when (doom--working-tree-dirty-p doom-emacs-dir)
|
"Couldn't find Doom's .git directory. Was Doom cloned properly?"
|
||||||
(user-error "Refusing to upgrade because %S has been modified. Stash or undo your changes"
|
"Couldn't detect what branch you're on. Is Doom detached?")))
|
||||||
(abbreviate-file-name doom-emacs-dir)))
|
|
||||||
(with-temp-buffer
|
;; We assume that a dirty .emacs.d is intentional and abort
|
||||||
(let ((buf (current-buffer)))
|
(when (doom--working-tree-dirty-p default-directory)
|
||||||
(condition-case-unless-debug e
|
(if (not force-p)
|
||||||
(progn
|
(user-error! "%s\n\n%s"
|
||||||
(process-file "git" nil buf nil "remote" "remove" doom-repo-remote)
|
(format "Refusing to upgrade because %S has been modified." (path doom-emacs-dir))
|
||||||
(unless (zerop (process-file "git" nil buf nil "remote" "add"
|
"Either stash/undo your changes or run 'doom upgrade -f' to discard local changes.")
|
||||||
doom-repo-remote doom-repo-url))
|
(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
|
||||||
|
(or (zerop (car (doom-sh "git" "remote" "add" doom-repo-remote doom-repo-url)))
|
||||||
(error "Failed to add %s to remotes" doom-repo-remote))
|
(error "Failed to add %s to remotes" doom-repo-remote))
|
||||||
(unless (zerop (process-file "git" nil buf nil "fetch" "--tags"
|
(or (zerop (car (doom-sh "git" "fetch" "--tags" doom-repo-remote branch)))
|
||||||
doom-repo-remote branch))
|
|
||||||
(error "Failed to fetch from upstream"))
|
(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)))))
|
(let ((this-rev (vc-git--rev-parse "HEAD"))
|
||||||
(unless rev
|
(new-rev (vc-git--rev-parse target-remote)))
|
||||||
(error "Couldn't detect Doom's version. Is %s a repo?"
|
(cond
|
||||||
(abbreviate-file-name doom-emacs-dir)))
|
((and (null this-rev)
|
||||||
(if (equal current-rev rev)
|
(null new-rev))
|
||||||
(message "Doom is up to date!")
|
(error "Failed to get revisions for %s" target-remote))
|
||||||
(message "Updates for Doom are available!\n\n Old revision: %s\n New revision: %s\n"
|
|
||||||
current-rev rev)
|
((equal this-rev new-rev)
|
||||||
(message "Comparision diff: https://github.com/hlissner/doom-emacs/compare/%s...%s\n"
|
(print! (success "Doom is already up-to-date!"))
|
||||||
(substring current-rev 0 10) (substring rev 0 10))
|
t)
|
||||||
;; TODO Display newsletter diff
|
|
||||||
(unless (or doom-auto-accept (y-or-n-p "Proceed?"))
|
((print! (info "A new version of Doom Emacs is available!\n\n Old revision: %s (%s)\n New revision: %s (%s)\n"
|
||||||
(user-error "Aborted"))
|
(substring this-rev 0 10)
|
||||||
(message "Removing byte-compiled files from your config (if any)")
|
(cdr (doom-sh "git" "log" "-1" "--format=%cr" "HEAD"))
|
||||||
(doom-clean-byte-compiled-files)
|
(substring new-rev 0 10)
|
||||||
(unless (zerop (process-file "git" nil buf nil "reset" "--hard"
|
(cdr (doom-sh "git" "log" "-1" "--format=%cr" target-remote))))
|
||||||
(format "%s/%s" doom-repo-remote branch)))
|
|
||||||
(error "An error occurred while checking out the latest commit\n\n%s"
|
(when (y-or-n-p "View the comparison diff in your browser?")
|
||||||
(buffer-string)))
|
(print! (info "Opened github in your browser."))
|
||||||
(unless (equal (vc-git-working-revision doom-emacs-dir) rev)
|
(browse-url (format "https://github.com/hlissner/doom-emacs/compare/%s...%s"
|
||||||
(error "Failed to checkout latest commit.\n\n%s" (buffer-string))))
|
this-rev
|
||||||
(doom-refresh 'force-p)
|
new-rev)))
|
||||||
(when (doom-packages-update doom-auto-accept)
|
(if (not (y-or-n-p "Proceed with upgrade?"))
|
||||||
(doom-reload-package-autoloads))
|
(ignore (print! (error "Aborted")))
|
||||||
(message "Done! Please restart Emacs for changes to take effect")))
|
(print! (start "Upgrading Doom Emacs..."))
|
||||||
(user-error
|
(print-group!
|
||||||
(message "%s Aborting." (error-message-string e)))
|
(doom-clean-byte-compiled-files)
|
||||||
(error
|
(unless (and (zerop (car (doom-sh "git" "reset" "--hard" target-remote)))
|
||||||
(message "There was an unexpected error.\n\n%s\n\nOutput:\n%s"
|
(equal (vc-git--rev-parse "HEAD") new-rev))
|
||||||
e (buffer-string))))))))
|
(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))))))
|
||||||
|
|
298
core/core-cli.el
298
core/core-cli.el
|
@ -1,54 +1,98 @@
|
||||||
;;; -*- lexical-binding: t; no-byte-compile: t; -*-
|
;;; -*- lexical-binding: t; no-byte-compile: t; -*-
|
||||||
|
|
||||||
;; Eagerly load these libraries because this module may be loaded in a session
|
(require 'seq)
|
||||||
;; that hasn't been fully initialized (where autoloads files haven't been
|
|
||||||
;; generated or `load-path' populated).
|
|
||||||
(load! "autoload/debug")
|
|
||||||
(load! "autoload/files")
|
|
||||||
(load! "autoload/message")
|
|
||||||
(load! "autoload/packages")
|
|
||||||
|
|
||||||
|
|
||||||
;;
|
|
||||||
;; Dispatcher API
|
|
||||||
|
|
||||||
(defvar doom-auto-accept (getenv "YES")
|
(defvar doom-auto-accept (getenv "YES")
|
||||||
"If non-nil, Doom will auto-accept any confirmation prompts during batch
|
"If non-nil, Doom will auto-accept any confirmation prompts during batch
|
||||||
commands like `doom-packages-install', `doom-packages-update' and
|
commands like `doom-packages-install', `doom-packages-update' and
|
||||||
`doom-packages-autoremove'.")
|
`doom-packages-autoremove'.")
|
||||||
|
|
||||||
(defconst doom--dispatch-command-alist ())
|
(defvar doom-cli-pre-execute-hook nil
|
||||||
(defconst doom--dispatch-alias-alist ())
|
"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)
|
(defun doom--dispatch-format (desc &optional short)
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(let ((fill-column 72))
|
(let ((fill-column 72))
|
||||||
(insert desc)
|
(save-excursion
|
||||||
(goto-char (point-min))
|
(insert desc)
|
||||||
(while (re-search-forward "\n\n[^ \n]" nil t)
|
(while (re-search-backward "\n\n[^ \n]" nil t)
|
||||||
(fill-paragraph)))
|
(fill-paragraph))))
|
||||||
(if (not short)
|
(if (not short)
|
||||||
(buffer-string)
|
(buffer-string)
|
||||||
(goto-char (point-min))
|
(buffer-substring (line-beginning-position)
|
||||||
(buffer-substring-no-properties
|
(line-end-position)))))
|
||||||
(line-beginning-position)
|
|
||||||
(line-end-position)))))
|
|
||||||
|
|
||||||
(defun doom--dispatch-help (&optional command desc &rest args)
|
(defun doom--dispatch-help-1 (command)
|
||||||
"Display help documentation for a dispatcher command. If COMMAND and DESC are
|
(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
|
||||||
|
(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."
|
omitted, show all available commands, their aliases and brief descriptions."
|
||||||
(if command
|
(if fn
|
||||||
(princ (doom--dispatch-format desc))
|
(princ (documentation fn))
|
||||||
(print! (bold "%-10s\t%s\t%s" "Command:" "Alias" "Description"))
|
(print! (bold "%-11s\t%s\t%s" "Command:" "Alias" "Description"))
|
||||||
(dolist (spec (cl-sort doom--dispatch-command-alist #'string-lessp
|
(print-group!
|
||||||
:key #'car))
|
(dolist (group (seq-group-by (lambda (key) (plist-get (gethash key doom--cli-commands) :group))
|
||||||
(cl-destructuring-bind (command &key desc _body) spec
|
(hash-table-keys doom--cli-commands)))
|
||||||
(let ((aliases (cl-loop for (alias . cmd) in doom--dispatch-alias-alist
|
(if (null (car group))
|
||||||
if (eq cmd command)
|
(mapc #'doom--dispatch-help-1 (cdr group))
|
||||||
collect (symbol-name alias))))
|
(print! "%-30s\t%s" (bold (car group)) (gethash (car group) doom--cli-groups))
|
||||||
(print! " %-10s\t%s\t%s"
|
(print-group!
|
||||||
command (if aliases (string-join aliases ",") "")
|
(mapc #'doom--dispatch-help-1 (cdr group))))
|
||||||
(doom--dispatch-format desc t)))))))
|
(terpri)))))
|
||||||
|
|
||||||
(defun doom-dispatch (cmd args &optional show-help)
|
(defun doom-dispatch (cmd args &optional show-help)
|
||||||
"Parses ARGS and invokes a dispatcher.
|
"Parses ARGS and invokes a dispatcher.
|
||||||
|
@ -59,17 +103,33 @@ If SHOW-HELP is non-nil, show the documentation for said dispatcher."
|
||||||
(when args
|
(when args
|
||||||
(setq cmd (car args)
|
(setq cmd (car args)
|
||||||
args (cdr args))))
|
args (cdr args))))
|
||||||
(cl-destructuring-bind (command &key desc body)
|
(let ((fn (doom--dispatch-command cmd)))
|
||||||
(let ((sym (intern cmd)))
|
(unless (fboundp fn)
|
||||||
(or (assq sym doom--dispatch-command-alist)
|
(user-error "%S is not any command *I* know!" cmd))
|
||||||
(assq (cdr (assq sym doom--dispatch-alias-alist))
|
|
||||||
doom--dispatch-command-alist)
|
|
||||||
(user-error "Invalid command: %s" sym)))
|
|
||||||
(if show-help
|
(if show-help
|
||||||
(apply #'doom--dispatch-help command desc args)
|
(doom--dispatch-help fn args)
|
||||||
(funcall body 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
|
"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
|
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
|
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."
|
BODY will be run when this dispatcher is called."
|
||||||
(declare (indent defun) (doc-string 3))
|
(declare (indent defun) (doc-string 3))
|
||||||
(cl-destructuring-bind (cmd &rest aliases)
|
(let* ((names (mapcar #'symbol-name (doom-enlist names)))
|
||||||
(doom-enlist command)
|
(fn (intern (format "doom-cli-%s" (car names))))
|
||||||
|
(plist (cl-loop while (keywordp (car body))
|
||||||
|
collect (pop body)
|
||||||
|
collect (pop body))))
|
||||||
(macroexp-progn
|
(macroexp-progn
|
||||||
(append
|
(reverse
|
||||||
(when aliases
|
`((let ((plist ',plist))
|
||||||
`((dolist (alias ',aliases)
|
(setq plist (plist-put plist :aliases ',(cdr names)))
|
||||||
(setf (alist-get alias doom--dispatch-alias-alist) ',cmd))))
|
(unless (or (plist-member plist :group)
|
||||||
`((setf (alist-get ',cmd doom--dispatch-command-alist)
|
(null doom--cli-group))
|
||||||
(list :desc ,docstring
|
(plist-put plist :group doom--cli-group))
|
||||||
:body (lambda (args) (ignore args) ,form))))))))
|
(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
|
;; Load all of our subcommands
|
||||||
;; documentation for them, so...
|
(defcli! (refresh re) (&rest args)
|
||||||
|
"Ensure Doom is properly set up.
|
||||||
(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.
|
|
||||||
|
|
||||||
This is the equivalent of running autoremove, install, autoloads, then
|
This is the equivalent of running autoremove, install, autoloads, then
|
||||||
recompile. Run this whenever you:
|
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
|
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
|
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)
|
(provide 'core-cli)
|
||||||
;;; core-cli.el ends here
|
;;; core-cli.el ends here
|
||||||
|
|
|
@ -1,66 +1,89 @@
|
||||||
;;; core-editor.el -*- lexical-binding: t; -*-
|
;;; core-editor.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
(defvar doom-large-file-size 2
|
(defvar doom-detect-indentation-excluded-modes '(fundamental-mode)
|
||||||
"Size (in MB) above which the user will be prompted to open the file literally
|
"A list of major modes in which indentation should be automatically
|
||||||
to avoid performance issues. Opening literally means that no major or minor
|
detected.")
|
||||||
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-local doom-inhibit-indent-detection nil
|
(defvar-local doom-inhibit-indent-detection nil
|
||||||
"A buffer-local flag that indicates whether `dtrt-indent' should try to detect
|
"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
|
indentation settings or not. This should be set by editorconfig if it
|
||||||
successfully sets indent_style/indent_size.")
|
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
|
;;; File handling
|
||||||
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
|
|
||||||
tab-always-indent t
|
|
||||||
tab-width 4
|
|
||||||
tabify-regexp "^\t* [ \t]+" ; for :retab
|
|
||||||
;; Wrapping
|
|
||||||
truncate-lines t
|
|
||||||
truncate-partial-width-windows 50)
|
|
||||||
|
|
||||||
;; Remove hscroll-margin in shells, otherwise it causes jumpiness
|
;; Resolve symlinks when opening files, so that any operations are conducted
|
||||||
(setq-hook! '(eshell-mode-hook term-mode-hook) hscroll-margin 0)
|
;; from the file's true directory (like `find-file').
|
||||||
|
(setq find-file-visit-truename t)
|
||||||
|
|
||||||
(defun doom*optimize-literal-mode-for-large-files (buffer)
|
;; Disable the warning "X and Y are the same file". It's fine to ignore this
|
||||||
(with-current-buffer buffer
|
;; warning as it will redirect you to the existing buffer anyway.
|
||||||
(when find-file-literally
|
(setq find-file-suppress-same-file-warnings t)
|
||||||
(setq buffer-read-only t)
|
|
||||||
(buffer-disable-undo))
|
;; Create missing directories when we open a file that doesn't exist under a
|
||||||
buffer))
|
;; directory tree that may not exist.
|
||||||
(advice-add #'find-file-noselect-1 :filter-return #'doom*optimize-literal-mode-for-large-files)
|
(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
|
||||||
|
indent-tabs-mode nil
|
||||||
|
fill-column 80)
|
||||||
|
|
||||||
|
;; Word wrapping
|
||||||
|
(setq-default word-wrap t
|
||||||
|
truncate-lines t
|
||||||
|
truncate-partial-width-windows nil)
|
||||||
|
|
||||||
|
(setq sentence-end-double-space nil
|
||||||
|
delete-trailing-lines nil
|
||||||
|
require-final-newline t
|
||||||
|
tabify-regexp "^\t* [ \t]+") ; for :retab
|
||||||
|
|
||||||
|
|
||||||
|
;;
|
||||||
|
;;; 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
|
;;; Built-in plugins
|
||||||
|
|
||||||
(def-package! autorevert
|
(use-package! autorevert
|
||||||
;; revert buffers when their files/state have changed
|
;; revert buffers when their files/state have changed
|
||||||
:hook (focus-in . doom|auto-revert-buffers)
|
:hook (focus-in . doom-auto-revert-buffers-h)
|
||||||
:hook (after-save . doom|auto-revert-buffers)
|
:hook (after-save . doom-auto-revert-buffers-h)
|
||||||
:hook (doom-switch-buffer . doom|auto-revert-buffer)
|
:hook (doom-switch-buffer . doom-auto-revert-buffer-h)
|
||||||
:hook (doom-switch-window . doom|auto-revert-buffer)
|
:hook (doom-switch-window . doom-auto-revert-buffer-h)
|
||||||
:config
|
:config
|
||||||
(setq auto-revert-verbose t ; let us know when it happens
|
(setq auto-revert-verbose t ; let us know when it happens
|
||||||
auto-revert-use-notify nil
|
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
|
;; 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
|
;; 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.
|
;; 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)."
|
"Auto revert's stale buffers (that are visible)."
|
||||||
(unless auto-revert-mode
|
(unless auto-revert-mode
|
||||||
(dolist (buf (doom-visible-buffers))
|
(dolist (buf (doom-visible-buffers))
|
||||||
(with-current-buffer buf
|
(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
|
;; Keep track of recently opened files
|
||||||
:defer-incrementally (easymenu tree-widget timer)
|
:defer-incrementally easymenu tree-widget timer
|
||||||
:after-call after-find-file
|
:after-call after-find-file
|
||||||
:commands recentf-open-files
|
:commands recentf-open-files
|
||||||
:config
|
:config
|
||||||
|
@ -126,27 +155,27 @@ detected.")
|
||||||
file))
|
file))
|
||||||
(setq recentf-filename-handlers '(doom--recent-file-truename abbreviate-file-name))
|
(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)
|
||||||
"Bump file in recent file list when it is switched or written to."
|
(defun doom--recentf-touch-buffer-h ()
|
||||||
(when buffer-file-name
|
"Bump file in recent file list when it is switched or written to."
|
||||||
(recentf-add-file buffer-file-name))
|
(when buffer-file-name
|
||||||
;; Return nil for `write-file-functions'
|
(recentf-add-file buffer-file-name))
|
||||||
nil)
|
;; Return nil for `write-file-functions'
|
||||||
(add-hook 'doom-switch-window-hook #'doom|recentf-touch-buffer)
|
nil))
|
||||||
(add-hook 'write-file-functions #'doom|recentf-touch-buffer)
|
|
||||||
|
|
||||||
(defun doom|recentf-add-dired-directory ()
|
(add-hook! 'dired-mode-hook
|
||||||
"Add dired directory to recentf file list."
|
(defun doom--recentf-add-dired-directory-h ()
|
||||||
(recentf-add-file default-directory))
|
"Add dired directory to recentf file list."
|
||||||
(add-hook 'dired-mode-hook #'doom|recentf-add-dired-directory)
|
(recentf-add-file default-directory)))
|
||||||
|
|
||||||
(unless noninteractive
|
(unless noninteractive
|
||||||
(add-hook 'kill-emacs-hook #'recentf-cleanup)
|
(add-hook 'kill-emacs-hook #'recentf-cleanup)
|
||||||
(quiet! (recentf-mode +1))))
|
(quiet! (recentf-mode +1))))
|
||||||
|
|
||||||
(def-package! savehist
|
|
||||||
|
(use-package! savehist
|
||||||
;; persist variables across sessions
|
;; persist variables across sessions
|
||||||
:defer-incrementally (custom)
|
:defer-incrementally custom
|
||||||
:after-call post-command-hook
|
:after-call post-command-hook
|
||||||
:config
|
:config
|
||||||
(setq savehist-file (concat doom-cache-dir "savehist")
|
(setq savehist-file (concat doom-cache-dir "savehist")
|
||||||
|
@ -155,32 +184,32 @@ detected.")
|
||||||
savehist-additional-variables '(kill-ring search-ring regexp-search-ring))
|
savehist-additional-variables '(kill-ring search-ring regexp-search-ring))
|
||||||
(savehist-mode +1)
|
(savehist-mode +1)
|
||||||
|
|
||||||
(defun doom|unpropertize-kill-ring ()
|
(add-hook! 'kill-emacs-hook
|
||||||
"Remove text properties from `kill-ring' in the interest of shrinking the
|
(defun doom-unpropertize-kill-ring-h ()
|
||||||
savehist file."
|
"Remove text properties from `kill-ring' for a smaller savehist file."
|
||||||
(setq kill-ring (cl-loop for item in kill-ring
|
(setq kill-ring (cl-loop for item in kill-ring
|
||||||
if (stringp item)
|
if (stringp item)
|
||||||
collect (substring-no-properties item)
|
collect (substring-no-properties item)
|
||||||
else if item collect it)))
|
else if item collect it)))))
|
||||||
(add-hook 'kill-emacs-hook #'doom|unpropertize-kill-ring))
|
|
||||||
|
|
||||||
(def-package! saveplace
|
|
||||||
|
(use-package! saveplace
|
||||||
;; persistent point location in buffers
|
;; persistent point location in buffers
|
||||||
:after-call (after-find-file dired-initial-position-hook)
|
:after-call after-find-file dired-initial-position-hook
|
||||||
:config
|
:config
|
||||||
(setq save-place-file (concat doom-cache-dir "saveplace")
|
(setq save-place-file (concat doom-cache-dir "saveplace")
|
||||||
save-place-forget-unreadable-files t
|
save-place-forget-unreadable-files t
|
||||||
save-place-limit 200)
|
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."
|
"Recenter on cursor when loading a saved place."
|
||||||
|
:after-while #'save-place-find-file-hook
|
||||||
(if buffer-file-name (ignore-errors (recenter))))
|
(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))
|
(save-place-mode +1))
|
||||||
|
|
||||||
(def-package! server
|
|
||||||
|
(use-package! server
|
||||||
:when (display-graphic-p)
|
: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
|
:init
|
||||||
(when-let (name (getenv "EMACS_SERVER_NAME"))
|
(when-let (name (getenv "EMACS_SERVER_NAME"))
|
||||||
(setq server-name name))
|
(setq server-name name))
|
||||||
|
@ -192,8 +221,8 @@ savehist file."
|
||||||
;;
|
;;
|
||||||
;;; Packages
|
;;; Packages
|
||||||
|
|
||||||
(def-package! better-jumper
|
(use-package! better-jumper
|
||||||
:after-call (pre-command-hook)
|
:after-call pre-command-hook
|
||||||
:init
|
:init
|
||||||
(global-set-key [remap evil-jump-forward] #'better-jumper-jump-forward)
|
(global-set-key [remap evil-jump-forward] #'better-jumper-jump-forward)
|
||||||
(global-set-key [remap evil-jump-backward] #'better-jumper-jump-backward)
|
(global-set-key [remap evil-jump-backward] #'better-jumper-jump-backward)
|
||||||
|
@ -202,14 +231,14 @@ savehist file."
|
||||||
(better-jumper-mode +1)
|
(better-jumper-mode +1)
|
||||||
(add-hook 'better-jumper-post-jump-hook #'recenter)
|
(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."
|
"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)))
|
(better-jumper-set-jump (if (markerp (car args)) (car args)))
|
||||||
(let ((evil--jumps-jumping t)
|
(let ((evil--jumps-jumping t)
|
||||||
(better-jumper--jumping t))
|
(better-jumper--jumping t))
|
||||||
(apply orig-fn args)))
|
(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."
|
"Set a jump point if ORIG-FN returns non-nil."
|
||||||
(let ((origin (point-marker))
|
(let ((origin (point-marker))
|
||||||
(result
|
(result
|
||||||
|
@ -224,13 +253,13 @@ savehist file."
|
||||||
origin))))
|
origin))))
|
||||||
result))
|
result))
|
||||||
|
|
||||||
(defun doom|set-jump ()
|
(defun doom-set-jump-h ()
|
||||||
"Run `better-jumper-set-jump' but return nil, for short-circuiting hooks."
|
"Run `better-jumper-set-jump' but return nil, for short-circuiting hooks."
|
||||||
(better-jumper-set-jump)
|
(better-jumper-set-jump)
|
||||||
nil))
|
nil))
|
||||||
|
|
||||||
|
|
||||||
(def-package! command-log-mode
|
(use-package! command-log-mode
|
||||||
:commands global-command-log-mode
|
:commands global-command-log-mode
|
||||||
:config
|
:config
|
||||||
(setq command-log-mode-auto-show t
|
(setq command-log-mode-auto-show t
|
||||||
|
@ -239,21 +268,20 @@ savehist file."
|
||||||
command-log-mode-window-size 50))
|
command-log-mode-window-size 50))
|
||||||
|
|
||||||
|
|
||||||
(def-package! dtrt-indent
|
(use-package! dtrt-indent
|
||||||
;; Automatic detection of indent settings
|
;; Automatic detection of indent settings
|
||||||
:unless noninteractive
|
:unless noninteractive
|
||||||
:defer t
|
:defer t
|
||||||
:init
|
:init
|
||||||
(defun doom|detect-indentation ()
|
|
||||||
(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)
|
(add-hook! '(change-major-mode-after-body-hook read-only-mode-hook)
|
||||||
#'doom|detect-indentation)
|
(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)))))
|
||||||
:config
|
:config
|
||||||
(setq dtrt-indent-run-after-smie t)
|
(setq dtrt-indent-run-after-smie t)
|
||||||
|
|
||||||
|
@ -261,9 +289,10 @@ savehist file."
|
||||||
(push '(t tab-width) dtrt-indent-hook-generic-mapping-list)
|
(push '(t tab-width) dtrt-indent-hook-generic-mapping-list)
|
||||||
|
|
||||||
(defvar dtrt-indent-run-after-smie)
|
(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
|
"Some smie modes throw errors when trying to guess their indentation, like
|
||||||
`nim-mode'. This prevents them from leaving Emacs in a broken state."
|
`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))
|
(let ((dtrt-indent-run-after-smie dtrt-indent-run-after-smie))
|
||||||
(cl-letf* ((old-smie-config-guess (symbol-function 'smie-config-guess))
|
(cl-letf* ((old-smie-config-guess (symbol-function 'smie-config-guess))
|
||||||
((symbol-function 'smie-config-guess)
|
((symbol-function 'smie-config-guess)
|
||||||
|
@ -273,11 +302,10 @@ savehist file."
|
||||||
(message "[WARNING] Indent detection: %s"
|
(message "[WARNING] Indent detection: %s"
|
||||||
(error-message-string e))
|
(error-message-string e))
|
||||||
(message "")))))) ; warn silently
|
(message "")))))) ; warn silently
|
||||||
(funcall orig-fn arg))))
|
(funcall orig-fn arg)))))
|
||||||
(advice-add #'dtrt-indent-mode :around #'doom*fix-broken-smie-modes))
|
|
||||||
|
|
||||||
|
|
||||||
(def-package! helpful
|
(use-package! helpful
|
||||||
;; a better *help* buffer
|
;; a better *help* buffer
|
||||||
:commands helpful--read-symbol
|
:commands helpful--read-symbol
|
||||||
:init
|
:init
|
||||||
|
@ -288,6 +316,12 @@ savehist file."
|
||||||
[remap describe-key] #'helpful-key
|
[remap describe-key] #'helpful-key
|
||||||
[remap describe-symbol] #'doom/describe-symbol)
|
[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
|
(after! apropos
|
||||||
;; patch apropos buttons to call helpful instead of help
|
;; patch apropos buttons to call helpful instead of help
|
||||||
(dolist (fun-bt '(apropos-function apropos-macro apropos-command))
|
(dolist (fun-bt '(apropos-function apropos-macro apropos-command))
|
||||||
|
@ -306,44 +340,69 @@ savehist file."
|
||||||
(add-hook 'imenu-after-jump-hook #'recenter)
|
(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,
|
;; Auto-close delimiters and blocks as you type. It's more powerful than that,
|
||||||
;; but that is all Doom uses it for.
|
;; but that is all Doom uses it for.
|
||||||
:after-call (doom-switch-buffer-hook after-find-file)
|
: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)
|
:commands sp-pair sp-local-pair sp-with-modes sp-point-in-comment sp-point-in-string
|
||||||
:config
|
:config
|
||||||
|
;; Load default smartparens rules for various languages
|
||||||
(require 'smartparens-config)
|
(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
|
(setq sp-highlight-pair-overlay nil
|
||||||
sp-highlight-wrap-overlay nil
|
sp-highlight-wrap-overlay nil
|
||||||
sp-highlight-wrap-tag-overlay nil
|
sp-highlight-wrap-tag-overlay nil)
|
||||||
sp-show-pair-from-inside t
|
;; But if someone does want overlays enabled, evil users will be stricken with
|
||||||
sp-cancel-autoskip-on-backward-movement nil
|
;; an off-by-one issue where smartparens assumes you're outside the pair when
|
||||||
sp-show-pair-delay 0.1
|
;; you're really at the last character in insert mode. We must correct this
|
||||||
sp-max-pair-length 4
|
;; vile injustice.
|
||||||
sp-max-prefix-length 50
|
(setq sp-show-pair-from-inside t)
|
||||||
sp-escape-quotes-after-insert nil) ; not smart enough
|
;; ...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'
|
;; Silence some harmless but annoying echo-area spam
|
||||||
(defun doom|init-smartparens-in-eval-expression ()
|
(dolist (key '(:unmatched-expression :no-matching-tag))
|
||||||
"Enable `smartparens-mode' in the minibuffer, during `eval-expression' or
|
(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'."
|
`evil-ex'."
|
||||||
(when (memq this-command '(eval-expression evil-ex))
|
(when (memq this-command '(eval-expression evil-ex))
|
||||||
(smartparens-mode)))
|
(smartparens-mode))))
|
||||||
(add-hook 'minibuffer-setup-hook #'doom|init-smartparens-in-eval-expression)
|
|
||||||
|
|
||||||
|
;; 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)
|
||||||
(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-entry-hook #'turn-off-smartparens-mode)
|
||||||
(add-hook 'evil-replace-state-exit-hook #'turn-on-smartparens-mode)
|
(add-hook 'evil-replace-state-exit-hook #'turn-on-smartparens-mode)
|
||||||
|
|
||||||
(smartparens-global-mode +1))
|
(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
|
;; Branching & persistent undo
|
||||||
:after-call (doom-switch-buffer-hook after-find-file)
|
:after-call doom-switch-buffer-hook after-find-file
|
||||||
:config
|
:config
|
||||||
(setq undo-tree-auto-save-history nil ; disable because unstable
|
(setq undo-tree-auto-save-history nil ; disable because unstable
|
||||||
;; undo-in-region is known to cause undo history corruption, which can
|
;; 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/"))))
|
`(("." . ,(concat doom-cache-dir "undo-tree-hist/"))))
|
||||||
|
|
||||||
(when (executable-find "zstd")
|
(when (executable-find "zstd")
|
||||||
(defun doom*undo-tree-make-history-save-file-name (file)
|
(defadvice! doom--undo-tree-make-history-save-file-name-a (file)
|
||||||
(concat file ".zst"))
|
:filter-return #'undo-tree-make-history-save-file-name
|
||||||
(advice-add #'undo-tree-make-history-save-file-name :filter-return
|
(concat file ".zst")))
|
||||||
#'doom*undo-tree-make-history-save-file-name))
|
|
||||||
|
|
||||||
(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)
|
(dolist (item buffer-undo-list)
|
||||||
(and (consp item)
|
(and (consp item)
|
||||||
(stringp (car item))
|
(stringp (car item))
|
||||||
(setcar item (substring-no-properties (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))
|
(global-undo-tree-mode +1))
|
||||||
|
|
||||||
|
|
||||||
(def-package! ws-butler
|
(use-package! ws-butler
|
||||||
;; a less intrusive `delete-trailing-whitespaces' on save
|
;; a less intrusive `delete-trailing-whitespaces' on save
|
||||||
:after-call (after-find-file)
|
:after-call after-find-file
|
||||||
:config
|
:config
|
||||||
(setq ws-butler-global-exempt-modes
|
(appendq! ws-butler-global-exempt-modes
|
||||||
(append ws-butler-global-exempt-modes
|
'(special-mode comint-mode term-mode eshell-mode))
|
||||||
'(special-mode comint-mode term-mode eshell-mode)))
|
|
||||||
(ws-butler-global-mode))
|
(ws-butler-global-mode))
|
||||||
|
|
||||||
(provide 'core-editor)
|
(provide 'core-editor)
|
||||||
|
|
|
@ -6,26 +6,18 @@
|
||||||
;; entirely for performance reasons).
|
;; entirely for performance reasons).
|
||||||
|
|
||||||
(defvar doom-leader-key "SPC"
|
(defvar doom-leader-key "SPC"
|
||||||
"The leader prefix key for Evil users.
|
"The leader prefix key for Evil users.")
|
||||||
|
|
||||||
This needs to be changed from $DOOMDIR/init.el.")
|
|
||||||
|
|
||||||
(defvar doom-leader-alt-key "M-SPC"
|
(defvar doom-leader-alt-key "M-SPC"
|
||||||
"An alternative leader prefix key, used for Insert and Emacs states, and for
|
"An alternative leader prefix key, used for Insert and Emacs states, and for
|
||||||
non-evil users.
|
non-evil users.")
|
||||||
|
|
||||||
This needs to be changed from $DOOMDIR/init.el.")
|
|
||||||
|
|
||||||
(defvar doom-localleader-key "SPC m"
|
(defvar doom-localleader-key "SPC m"
|
||||||
"The localleader prefix key, for major-mode specific commands.
|
"The localleader prefix key, for major-mode specific commands.")
|
||||||
|
|
||||||
This needs to be changed from $DOOMDIR/init.el.")
|
|
||||||
|
|
||||||
(defvar doom-localleader-alt-key "M-SPC m"
|
(defvar doom-localleader-alt-key "M-SPC m"
|
||||||
"The localleader prefix key, for major-mode specific commands. Used for Insert
|
"The localleader prefix key, for major-mode specific commands. Used for Insert
|
||||||
and Emacs states, and for non-evil users.
|
and Emacs states, and for non-evil users.")
|
||||||
|
|
||||||
This needs to be changed from $DOOMDIR/init.el.")
|
|
||||||
|
|
||||||
(defvar doom-leader-map (make-sparse-keymap)
|
(defvar doom-leader-map (make-sparse-keymap)
|
||||||
"An overriding keymap for <leader> keys.")
|
"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
|
;;; General + leader/localleader keys
|
||||||
|
|
||||||
(require 'general)
|
(use-package general
|
||||||
;; Convenience aliases
|
:init
|
||||||
(defalias 'define-key! #'general-def)
|
;; Convenience aliases
|
||||||
(defalias 'unmap! #'general-unbind)
|
(defalias 'define-key! #'general-def)
|
||||||
|
(defalias 'unmap! #'general-unbind))
|
||||||
|
|
||||||
;; `map!' uses this instead of `define-leader-key!' because it consumes 20-30%
|
;; HACK `map!' uses this instead of `define-leader-key!' because it consumes
|
||||||
;; more startup time, so we reimplement it ourselves.
|
;; 20-30% more startup time, so we reimplement it ourselves.
|
||||||
(defmacro doom--define-leader-key (&rest keys)
|
(defmacro doom--define-leader-key (&rest keys)
|
||||||
(let (prefix forms wkforms)
|
(let (prefix forms wkforms)
|
||||||
(while keys
|
(while keys
|
||||||
|
@ -99,19 +92,16 @@ If any hook returns non-nil, all hooks after it are ignored.")
|
||||||
,bdef)
|
,bdef)
|
||||||
forms))
|
forms))
|
||||||
(when-let (desc (cadr (memq :which-key udef)))
|
(when-let (desc (cadr (memq :which-key udef)))
|
||||||
(push `(which-key-add-key-based-replacements
|
(prependq!
|
||||||
(general--concat t doom-leader-alt-key ,key)
|
wkforms `((which-key-add-key-based-replacements
|
||||||
,desc)
|
(general--concat t doom-leader-alt-key ,key)
|
||||||
wkforms)
|
,desc)
|
||||||
(push `(which-key-add-key-based-replacements
|
(which-key-add-key-based-replacements
|
||||||
(general--concat t doom-leader-key ,key)
|
(general--concat t doom-leader-key ,key)
|
||||||
,desc)
|
,desc))))))))
|
||||||
wkforms))))))
|
|
||||||
(macroexp-progn
|
(macroexp-progn
|
||||||
(append (nreverse forms)
|
(cons `(after! which-key ,@(nreverse wkforms))
|
||||||
(when wkforms
|
(nreverse forms)))))
|
||||||
`((after! which-key
|
|
||||||
,@(nreverse wkforms))))))))
|
|
||||||
|
|
||||||
(defmacro define-leader-key! (&rest args)
|
(defmacro define-leader-key! (&rest args)
|
||||||
"Define <leader> keys.
|
"Define <leader> keys.
|
||||||
|
@ -157,26 +147,26 @@ localleader prefix."
|
||||||
|
|
||||||
;; Bind `doom-leader-key' and `doom-leader-alt-key' as late as possible to give
|
;; Bind `doom-leader-key' and `doom-leader-alt-key' as late as possible to give
|
||||||
;; the user a chance to modify them.
|
;; the user a chance to modify them.
|
||||||
(defun doom|init-leader-keys ()
|
(add-hook! 'doom-after-init-modules-hook
|
||||||
"Bind `doom-leader-key' and `doom-leader-alt-key'."
|
(defun doom-init-leader-keys-h ()
|
||||||
(let ((map general-override-mode-map))
|
"Bind `doom-leader-key' and `doom-leader-alt-key'."
|
||||||
(if (not (featurep 'evil))
|
(let ((map general-override-mode-map))
|
||||||
(progn
|
(if (not (featurep 'evil))
|
||||||
(cond ((equal doom-leader-alt-key "C-c")
|
(progn
|
||||||
(set-keymap-parent doom-leader-map mode-specific-map))
|
(cond ((equal doom-leader-alt-key "C-c")
|
||||||
((equal doom-leader-alt-key "C-x")
|
(set-keymap-parent doom-leader-map mode-specific-map))
|
||||||
(set-keymap-parent doom-leader-map ctl-x-map)))
|
((equal doom-leader-alt-key "C-x")
|
||||||
(define-key map (kbd doom-leader-alt-key) 'doom/leader))
|
(set-keymap-parent doom-leader-map ctl-x-map)))
|
||||||
(evil-define-key* '(normal visual motion) map (kbd doom-leader-key) 'doom/leader)
|
(define-key map (kbd doom-leader-alt-key) 'doom/leader))
|
||||||
(evil-define-key* '(emacs insert) map (kbd doom-leader-alt-key) 'doom/leader))
|
(evil-define-key* '(normal visual motion) map (kbd doom-leader-key) 'doom/leader)
|
||||||
(general-override-mode +1)))
|
(evil-define-key* '(emacs insert) map (kbd doom-leader-alt-key) 'doom/leader))
|
||||||
(add-hook 'doom-after-init-modules-hook #'doom|init-leader-keys)
|
(general-override-mode +1))))
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;;; Packages
|
;;; Packages
|
||||||
|
|
||||||
(def-package! which-key
|
(use-package! which-key
|
||||||
:defer 1
|
:defer 1
|
||||||
:after-call pre-command-hook
|
:after-call pre-command-hook
|
||||||
:init
|
:init
|
||||||
|
@ -198,10 +188,6 @@ localleader prefix."
|
||||||
(which-key-mode +1))
|
(which-key-mode +1))
|
||||||
|
|
||||||
|
|
||||||
;;;###package hydra
|
|
||||||
(setq lv-use-seperator t)
|
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;;; `map!' macro
|
;;; `map!' macro
|
||||||
|
|
||||||
|
@ -216,7 +202,7 @@ localleader prefix."
|
||||||
(?g . global))
|
(?g . global))
|
||||||
"A list of cons cells that map a letter to a evil state symbol.")
|
"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.
|
"Convert a KEYWORD into a list of evil state symbols.
|
||||||
|
|
||||||
For example, :nvi will map to (list 'normal 'visual 'insert). See
|
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 :leader 'lisp-indent-function 'defun)
|
||||||
(put :localleader 'lisp-indent-function 'defun)
|
(put :localleader 'lisp-indent-function 'defun)
|
||||||
(put :map 'lisp-indent-function 'defun)
|
(put :map 'lisp-indent-function 'defun)
|
||||||
(put :keymap 'lisp-indent-function 'defun)
|
|
||||||
(put :mode 'lisp-indent-function 'defun)
|
(put :mode 'lisp-indent-function 'defun)
|
||||||
(put :prefix 'lisp-indent-function 'defun)
|
(put :prefix 'lisp-indent-function 'defun)
|
||||||
(put :prefix-map 'lisp-indent-function 'defun)
|
(put :prefix-map 'lisp-indent-function 'defun)
|
||||||
(put :unless 'lisp-indent-function 'defun)
|
|
||||||
(put :when 'lisp-indent-function 'defun)
|
|
||||||
|
|
||||||
;; specials
|
;; specials
|
||||||
(defvar doom--map-forms nil)
|
(defvar doom--map-forms nil)
|
||||||
|
@ -271,7 +254,7 @@ For example, :nvi will map to (list 'normal 'visual 'insert). See
|
||||||
(setq rest nil))
|
(setq rest nil))
|
||||||
(:desc
|
(:desc
|
||||||
(setq desc (pop rest)))
|
(setq desc (pop rest)))
|
||||||
((or :map :map* :keymap)
|
(:map
|
||||||
(doom--map-set :keymaps `(quote ,(doom-enlist (pop rest)))))
|
(doom--map-set :keymaps `(quote ,(doom-enlist (pop rest)))))
|
||||||
(:mode
|
(:mode
|
||||||
(push (cl-loop for m in (doom-enlist (pop rest))
|
(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)))
|
doom--map-forms)))
|
||||||
(_
|
(_
|
||||||
(condition-case _
|
(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
|
||||||
(error "Not a valid `map!' property: %s" key)))
|
(error "Not a valid `map!' property: %s" key)))
|
||||||
(setq desc nil))))
|
(setq desc nil))))
|
||||||
|
@ -414,7 +399,6 @@ Properties
|
||||||
:localleader [...] bind to localleader; requires a keymap
|
:localleader [...] bind to localleader; requires a keymap
|
||||||
:mode [MODE(s)] [...] inner keybinds are applied to major MODE(s)
|
:mode [MODE(s)] [...] inner keybinds are applied to major MODE(s)
|
||||||
:map [KEYMAP(s)] [...] inner keybinds are applied to KEYMAP(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
|
:prefix [PREFIX] [...] set keybind prefix for following keys. PREFIX
|
||||||
can be a cons cell: (PREFIX . DESCRIPTION)
|
can be a cons cell: (PREFIX . DESCRIPTION)
|
||||||
:prefix-map [PREFIX] [...] same as :prefix, but defines a prefix keymap
|
:prefix-map [PREFIX] [...] same as :prefix, but defines a prefix keymap
|
||||||
|
|
668
core/core-lib.el
668
core/core-lib.el
|
@ -1,6 +1,6 @@
|
||||||
;;; core-lib.el -*- lexical-binding: t; -*-
|
;;; core-lib.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
(let ((load-path doom-site-load-path))
|
(let ((load-path doom--initial-load-path))
|
||||||
(require 'subr-x)
|
(require 'subr-x)
|
||||||
(require 'cl-lib))
|
(require 'cl-lib))
|
||||||
|
|
||||||
|
@ -12,56 +12,36 @@
|
||||||
;; if-let and when-let were moved to (if|when)-let* in Emacs 26+ so we alias
|
;; if-let and when-let were moved to (if|when)-let* in Emacs 26+ so we alias
|
||||||
;; them for 25 users.
|
;; them for 25 users.
|
||||||
(defalias 'if-let* #'if-let)
|
(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
|
;;; 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)
|
(defun doom--resolve-hook-forms (hooks)
|
||||||
"Converts a list of modes into a list of hook symbols.
|
"Converts a list of modes into a list of hook symbols.
|
||||||
|
|
||||||
|
@ -76,20 +56,25 @@ list is returned as-is."
|
||||||
collect (cadr hook)
|
collect (cadr hook)
|
||||||
else collect (intern (format "%s-hook" (symbol-name hook)))))))
|
else collect (intern (format "%s-hook" (symbol-name hook)))))))
|
||||||
|
|
||||||
(defun doom--assert-stage-p (stage macro)
|
(defun doom--setq-hook-fns (hooks rest &optional singles)
|
||||||
(unless (or (bound-and-true-p byte-compile-current-file)
|
(unless (or singles (= 0 (% (length rest) 2)))
|
||||||
;; Don't complain if we're being evaluated on-the-fly. Since forms
|
(signal 'wrong-number-of-arguments (list #'evenp (length rest))))
|
||||||
;; are often evaluated (by `eval-region') or expanded (by
|
(cl-loop with vars = (let ((args rest)
|
||||||
;; macroexpand) in a temp buffer in `emacs-lisp-mode'...
|
vars)
|
||||||
(eq major-mode 'emacs-lisp-mode))
|
(while args
|
||||||
(cl-assert (eq stage doom--stage)
|
(push (if singles
|
||||||
nil
|
(list (pop args))
|
||||||
"Found %s call in non-%s.el file (%s)"
|
(cons (pop args) (pop args)))
|
||||||
macro (symbol-name stage)
|
vars))
|
||||||
(let ((path (FILE!)))
|
(nreverse vars))
|
||||||
(if (file-in-directory-p path doom-emacs-dir)
|
for hook in (doom--resolve-hook-forms hooks)
|
||||||
(file-relative-name path doom-emacs-dir)
|
for mode = (string-remove-suffix "-hook" (symbol-name hook))
|
||||||
(abbreviate-file-name path))))))
|
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)
|
(defun doom-keyword-name (keyword)
|
||||||
"Returns the string name of KEYWORD (`keywordp') minus the leading colon."
|
"Returns the string name of KEYWORD (`keywordp') minus the leading colon."
|
||||||
(declare (pure t) (side-effect-free t))
|
(declare (pure t) (side-effect-free t))
|
||||||
(cl-check-type :test keyword)
|
(cl-check-type keyword keyword)
|
||||||
(substring (symbol-name keyword) 1))
|
(substring (symbol-name keyword) 1))
|
||||||
|
|
||||||
(defmacro doom-log (format-string &rest args)
|
(defmacro doom-log (format-string &rest args)
|
||||||
|
@ -136,57 +121,239 @@ Accepts the same arguments as `message'."
|
||||||
format-string)
|
format-string)
|
||||||
,@args))))
|
,@args))))
|
||||||
|
|
||||||
(defun FILE! ()
|
(defalias 'doom-partial #'apply-partially)
|
||||||
"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))))
|
|
||||||
|
|
||||||
(defun DIR! ()
|
(defun doom-rpartial (fn &rest args)
|
||||||
"Returns the directory of the emacs lisp file this macro is called from."
|
"Return a function that is a partial application of FUN to right-hand ARGS.
|
||||||
(let ((file (FILE!)))
|
|
||||||
(and file (file-name-directory file))))
|
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)
|
(defmacro λ! (&rest body)
|
||||||
"Expands to (lambda () (interactive) ,@body)."
|
"Expands to (lambda () (interactive) ,@body)."
|
||||||
(declare (doc-string 1))
|
(declare (doc-string 1))
|
||||||
`(lambda () (interactive) ,@body))
|
`(lambda () (interactive) ,@body))
|
||||||
|
(defalias 'lambda! 'λ!)
|
||||||
|
|
||||||
(defmacro λ!! (command &optional arg)
|
(defun λ!! (command &optional arg)
|
||||||
"Expands to a command that interactively calls COMMAND with prefix ARG."
|
"Expands to a command that interactively calls COMMAND with prefix ARG."
|
||||||
(declare (doc-string 1))
|
(declare (doc-string 1))
|
||||||
`(lambda () (interactive)
|
(lambda () (interactive)
|
||||||
(let ((current-prefix-arg ,arg))
|
(let ((current-prefix-arg arg))
|
||||||
(call-interactively ,command))))
|
(call-interactively command))))
|
||||||
|
|
||||||
(defalias 'lambda! 'λ!)
|
|
||||||
(defalias 'lambda!! 'λ!!)
|
(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)
|
(defmacro pushnew! (place &rest values)
|
||||||
"Like `cl-pushnew', but will prepend VALUES to PLACE.
|
"Push VALUES sequentially into PLACE, if they aren't already present.
|
||||||
The order VALUES is preserved."
|
This is a variadic `cl-pushnew'."
|
||||||
`(dolist (--value-- (nreverse (list ,@values)))
|
(let ((var (make-symbol "result")))
|
||||||
(cl-pushnew --value-- ,place)))
|
`(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)
|
(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
|
`(setq ,list
|
||||||
(delq ,(if fetcher
|
(delq ,(if fetcher
|
||||||
`(funcall ,fetcher ,elt ,list)
|
`(funcall ,fetcher ,elt ,list)
|
||||||
elt)
|
elt)
|
||||||
,list)))
|
,list)))
|
||||||
|
|
||||||
(defmacro cond! (&rest clauses)
|
(defmacro delete! (elt list)
|
||||||
"An anaphoric `cond', which stores the conditional value in `it'."
|
"Delete ELT from LIST in-place."
|
||||||
`(let (it)
|
`(setq ,list (delete ,elt ,list)))
|
||||||
(cond ,@(cl-loop for (cond . body) in clauses
|
|
||||||
collect `((setq it ,cond)
|
(defmacro add-transient-hook! (hook-or-function &rest forms)
|
||||||
,@body)))))
|
"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)
|
(defmacro defer-until! (condition &rest body)
|
||||||
"Run BODY when CONDITION is true (checks on `after-load-functions'). Meant to
|
"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))
|
(declare (indent defun) (debug t))
|
||||||
`(if ,condition
|
`(if ,condition
|
||||||
(progn ,@body)
|
(progn ,@body)
|
||||||
,(let ((fun (make-symbol "doom|delay-form-")))
|
,(let ((fn (intern (format "doom--delay-form-%s-h" (sxhash (cons condition body))))))
|
||||||
`(progn
|
`(progn
|
||||||
(fset ',fun (lambda (&rest args)
|
(fset ',fn (lambda (&rest args)
|
||||||
(when ,(or condition t)
|
(when ,(or condition t)
|
||||||
(remove-hook 'after-load-functions #',fun)
|
(remove-hook 'after-load-functions #',fn)
|
||||||
(unintern ',fun nil)
|
(unintern ',fn nil)
|
||||||
(ignore args)
|
(ignore args)
|
||||||
,@body)))
|
,@body)))
|
||||||
(put ',fun 'permanent-local-hook t)
|
(put ',fn 'permanent-local-hook t)
|
||||||
(add-hook 'after-load-functions #',fun)))))
|
(add-hook 'after-load-functions #',fn)))))
|
||||||
|
|
||||||
(defmacro defer-feature! (feature &optional mode)
|
(defmacro defer-feature! (feature &optional mode)
|
||||||
"Pretend FEATURE hasn't been loaded yet, until FEATURE-hook is triggered.
|
"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,
|
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
|
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."
|
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)))
|
(mode (or mode feature)))
|
||||||
`(progn
|
`(progn
|
||||||
(setq features (delq ',feature features))
|
(setq features (delq ',feature features))
|
||||||
|
@ -250,291 +417,32 @@ writes to `standard-output'."
|
||||||
(save-silently t))
|
(save-silently t))
|
||||||
(prog1 ,@forms (message ""))))))
|
(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
|
(defmacro defadvice! (symbol arglist &optional docstring &rest body)
|
||||||
advised)."
|
"Define an advice called SYMBOL and add it to PLACES.
|
||||||
(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 add-hook! (&rest args)
|
ARGLIST is as in `defun'. WHERE is a keyword as passed to `advice-add', and
|
||||||
"A convenience macro for adding N functions to M hooks.
|
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'.
|
\(fn SYMBOL ARGLIST &optional DOCSTRING &rest [WHERE PLACES...] BODY\)"
|
||||||
|
(declare (doc-string 3) (indent defun))
|
||||||
This macro accepts, in order:
|
(unless (stringp docstring)
|
||||||
|
(push docstring body)
|
||||||
1. Optional properties :local and/or :append, which will make the hook
|
(setq docstring nil))
|
||||||
buffer-local or append to the list of hooks (respectively),
|
(let (where-alist)
|
||||||
2. The hook(s) to be added to: either an unquoted mode, an unquoted list of
|
(while (keywordp (car body))
|
||||||
modes, a quoted hook variable or a quoted list of hook variables. If
|
(push `(cons ,(pop body) (doom-enlist ,(pop body)))
|
||||||
unquoted, '-hook' will be appended to each symbol.
|
where-alist))
|
||||||
3. The function(s) to be added: this can be one function, a list thereof, or
|
`(progn
|
||||||
body forms (implicitly wrapped in a closure).
|
(defun ,symbol ,arglist ,docstring ,@body)
|
||||||
|
,(when where-alist
|
||||||
Examples:
|
`(dolist (targets (list ,@(nreverse where-alist)))
|
||||||
(add-hook! 'some-mode-hook 'enable-something) (same as `add-hook')
|
(dolist (target (cdr targets))
|
||||||
(add-hook! some-mode '(enable-something and-another))
|
(advice-add target (car targets) #',symbol)))))))
|
||||||
(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))))
|
|
||||||
`(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))
|
|
||||||
|
|
||||||
(provide 'core-lib)
|
(provide 'core-lib)
|
||||||
;;; core-lib.el ends here
|
;;; core-lib.el ends here
|
||||||
|
|
|
@ -11,9 +11,6 @@
|
||||||
doom-modules-dir)
|
doom-modules-dir)
|
||||||
"A list of module root directories. Order determines priority.")
|
"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
|
(defconst doom-obsolete-modules
|
||||||
'((:feature (version-control (:emacs vc) (:ui vc-gutter))
|
'((:feature (version-control (:emacs vc) (:ui vc-gutter))
|
||||||
(spellcheck (:tools flyspell))
|
(spellcheck (:tools flyspell))
|
||||||
|
@ -34,7 +31,8 @@
|
||||||
(term (:term term)))
|
(term (:term term)))
|
||||||
(:ui (doom-modeline (:ui modeline))
|
(:ui (doom-modeline (:ui modeline))
|
||||||
(fci (:ui fill-column))
|
(fci (:ui fill-column))
|
||||||
(evil-goggles (:ui ophints)))
|
(evil-goggles (:ui ophints))
|
||||||
|
(tabbar (:ui tabs)))
|
||||||
(:app (email (:email mu4e))
|
(:app (email (:email mu4e))
|
||||||
(notmuch (:email notmuch))))
|
(notmuch (:email notmuch))))
|
||||||
"A tree alist that maps deprecated modules to their replacement(s).
|
"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
|
your `doom!' block, a warning is emitted before replacing it with :emacs vc and
|
||||||
:ui vc-gutter.")
|
:ui vc-gutter.")
|
||||||
|
|
||||||
(defvar doom--current-module nil)
|
(defvar doom-inhibit-module-warnings (not noninteractive)
|
||||||
(defvar doom--current-flags nil)
|
"If non-nil, don't emit deprecated or missing module warnings at startup.")
|
||||||
(defvar doom--modules-cache ())
|
|
||||||
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; Custom hooks
|
;;; Custom hooks
|
||||||
|
|
||||||
(defvar doom-before-init-modules-hook nil
|
(defvar doom-before-init-modules-hook nil
|
||||||
"A list of hooks to run before Doom's modules' config.el files are loaded, but
|
"A list of hooks to run before Doom's modules' config.el files are loaded, but
|
||||||
after their init.el files are loaded.")
|
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)
|
(defvaralias 'doom-after-init-modules-hook 'after-init-hook)
|
||||||
|
|
||||||
(define-obsolete-variable-alias 'doom-post-init-hook 'doom-init-modules-hook "2.1.0")
|
(defvar doom--current-module nil)
|
||||||
(define-obsolete-variable-alias 'doom-init-hook 'doom-before-init-modules-hook "2.1.0")
|
(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
|
"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
|
session of Dooming. Will noop if used more than once, unless FORCE-P is
|
||||||
non-nil."
|
non-nil."
|
||||||
(when (and (or force-p
|
(when (or force-p (not doom-init-modules-p))
|
||||||
(not doom-init-modules-p))
|
(setq doom-init-modules-p t
|
||||||
(not (setq doom-modules nil))
|
doom-modules nil)
|
||||||
(load! "init" doom-private-dir t))
|
(when (load! "init" doom-private-dir t)
|
||||||
(setq doom-init-modules-p t)
|
(when doom-modules
|
||||||
(unless (hash-table-p doom-modules)
|
(maphash (lambda (key plist)
|
||||||
(setq doom-modules (make-hash-table :test 'equal)))
|
(let ((doom--current-module key)
|
||||||
(maphash (lambda (key plist)
|
(doom--current-flags (plist-get plist :flags)))
|
||||||
(let ((doom--current-module key)
|
(load! "init" (plist-get plist :path) t)))
|
||||||
(doom--current-flags (plist-get plist :flags)))
|
doom-modules))
|
||||||
(load! "init" (plist-get plist :path) t)))
|
(run-hook-wrapped 'doom-before-init-modules-hook #'doom-try-run-hook)
|
||||||
doom-modules)
|
(unless noninteractive
|
||||||
(run-hook-wrapped 'doom-before-init-modules-hook #'doom-try-run-hook)
|
(when doom-modules
|
||||||
(unless noninteractive
|
(maphash (lambda (key plist)
|
||||||
(maphash (lambda (key plist)
|
(let ((doom--current-module key)
|
||||||
(let ((doom--current-module key)
|
(doom--current-flags (plist-get plist :flags)))
|
||||||
(doom--current-flags (plist-get plist :flags)))
|
(load! "config" (plist-get plist :path) t)))
|
||||||
(load! "config" (plist-get plist :path) t)))
|
doom-modules))
|
||||||
doom-modules)
|
(run-hook-wrapped 'doom-init-modules-hook #'doom-try-run-hook)
|
||||||
(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)
|
(defun doom-module-p (category module &optional flag)
|
||||||
"Returns t if CATEGORY MODULE is enabled (ie. present in `doom-modules')."
|
"Returns t if CATEGORY MODULE is enabled (ie. present in `doom-modules')."
|
||||||
(declare (pure t) (side-effect-free t))
|
(declare (pure t) (side-effect-free t))
|
||||||
(when (hash-table-p doom-modules)
|
(let ((plist (gethash (cons category module) doom-modules)))
|
||||||
(let ((plist (gethash (cons category module) doom-modules)))
|
(and plist
|
||||||
(and plist
|
(or (null flag)
|
||||||
(or (null flag)
|
(memq flag (plist-get plist :flags)))
|
||||||
(memq flag (plist-get plist :flags)))
|
t)))
|
||||||
t))))
|
|
||||||
|
|
||||||
(defun doom-module-get (category module &optional property)
|
(defun doom-module-get (category module &optional property)
|
||||||
"Returns the plist for CATEGORY MODULE. Gets PROPERTY, specifically, if set."
|
"Returns the plist for CATEGORY MODULE. Gets PROPERTY, specifically, if set."
|
||||||
|
@ -128,7 +120,7 @@ non-nil."
|
||||||
of PROPERTY and VALUEs.
|
of PROPERTY and VALUEs.
|
||||||
|
|
||||||
\(fn CATEGORY MODULE PROPERTY VALUE &rest [PROPERTY VALUE [...]])"
|
\(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
|
(progn
|
||||||
(when plist
|
(when plist
|
||||||
(when (cl-oddp (length 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
|
If the category isn't enabled this will always return nil. For finding disabled
|
||||||
modules use `doom-module-locate-path'."
|
modules use `doom-module-locate-path'."
|
||||||
(let ((path (doom-module-get category module :path))
|
(let ((path (doom-module-get category module :path)))
|
||||||
file-name-handler-alist)
|
(if file
|
||||||
(if file (expand-file-name file path)
|
(let (file-name-handler-alist)
|
||||||
|
(expand-file-name file path))
|
||||||
path)))
|
path)))
|
||||||
|
|
||||||
(defun doom-module-locate-path (category &optional module file)
|
(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)
|
if (file-exists-p path)
|
||||||
return (expand-file-name path)))
|
return (expand-file-name path)))
|
||||||
|
|
||||||
(defun doom-module-from-path (&optional path)
|
(defun doom-module-from-path (&optional path enabled-only)
|
||||||
"Returns a cons cell (CATEGORY . MODULE) derived from PATH (a file path)."
|
"Returns a cons cell (CATEGORY . MODULE) derived from PATH (a file path).
|
||||||
(or doom--current-module
|
If ENABLED-ONLY, return nil if the containing module isn't enabled."
|
||||||
(let* (file-name-handler-alist
|
(if (null path)
|
||||||
(path (or path (FILE!))))
|
(if doom--current-module
|
||||||
(save-match-data
|
(if enabled-only
|
||||||
(setq path (file-truename path))
|
(and (doom-module-p (car doom--current-module)
|
||||||
(when (string-match "/modules/\\([^/]+\\)/\\([^/]+\\)\\(?:/.*\\)?$" path)
|
(cdr doom--current-module))
|
||||||
(when-let* ((category (match-string 1 path))
|
doom--current-module)
|
||||||
(module (match-string 2 path)))
|
doom--current-module)
|
||||||
(cons (doom-keyword-intern category)
|
(doom-module-from-path (file!)))
|
||||||
(intern module))))))))
|
(let* ((file-name-handler-alist nil)
|
||||||
|
(path (file-truename (or path (file!)))))
|
||||||
|
(save-match-data
|
||||||
|
(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)
|
(defun doom-module-load-path (&optional module-dirs)
|
||||||
"Return an unsorted list of absolute file paths to activated modules.
|
"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))
|
(declare (pure t) (side-effect-free t))
|
||||||
(append (if all-p
|
(append (list doom-private-dir)
|
||||||
(doom-files-in doom-modules-dirs
|
(if module-dirs
|
||||||
|
(doom-files-in (if (listp module-dirs)
|
||||||
|
module-dirs
|
||||||
|
doom-modules-dirs)
|
||||||
:type 'dirs
|
:type 'dirs
|
||||||
:mindepth 1
|
:mindepth 1
|
||||||
:depth 1
|
:depth 1)
|
||||||
:full t
|
|
||||||
:sort nil)
|
|
||||||
(cl-loop for plist being the hash-values of (doom-modules)
|
(cl-loop for plist being the hash-values of (doom-modules)
|
||||||
collect (plist-get plist :path)))
|
collect (plist-get plist :path)))
|
||||||
(list doom-private-dir)))
|
nil))
|
||||||
|
|
||||||
(defun doom-modules (&optional refresh-p)
|
(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)
|
(or (unless refresh-p doom-modules)
|
||||||
(let ((noninteractive t)
|
(let ((noninteractive t)
|
||||||
doom-modules
|
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-minimum-reported-time (if doom-debug-mode 0 0.1)
|
||||||
use-package-expand-minimally (not noninteractive)))
|
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:
|
;; expand its lazy-loading capabilities. They are:
|
||||||
;;
|
;;
|
||||||
;; :after-call SYMBOL|LIST
|
;; Check out `use-package!'s documentation for more about these two.
|
||||||
;; :defer-incrementally SYMBOL|LIST|t
|
;; :after-call SYMBOL|LIST
|
||||||
|
;; :defer-incrementally SYMBOL|LIST|t
|
||||||
|
;;
|
||||||
|
;; Provided by `auto-minor-mode' package:
|
||||||
|
;; :minor
|
||||||
|
;; :magic-minor
|
||||||
;;
|
;;
|
||||||
;; Check out `def-package!'s documentation for more about these two.
|
|
||||||
(defvar doom--deferred-packages-alist '(t))
|
(defvar doom--deferred-packages-alist '(t))
|
||||||
|
|
||||||
(with-eval-after-load 'use-package-core
|
(with-eval-after-load 'use-package-core
|
||||||
;; Macros are already fontified, no need for this
|
;; Macros are already fontified, no need for this
|
||||||
(font-lock-remove-keywords 'emacs-lisp-mode use-package-font-lock-keywords)
|
(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
|
;; Register all new keywords
|
||||||
;; 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
|
|
||||||
(dolist (keyword '(:defer-incrementally :after-call))
|
(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
|
(setq use-package-keywords
|
||||||
(use-package-list-insert keyword use-package-keywords :after)))
|
(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)
|
(defalias 'use-package-normalize/:defer-incrementally #'use-package-normalize-symlist)
|
||||||
(defun use-package-handler/:defer-incrementally (name _keyword targets rest state)
|
(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)
|
(defun use-package-handler/:after-call (name _keyword hooks rest state)
|
||||||
(if (plist-get state :demand)
|
(if (plist-get state :demand)
|
||||||
(use-package-process-keywords name rest state)
|
(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
|
(use-package-concat
|
||||||
`((fset ',fn
|
`((fset ',fn
|
||||||
(lambda (&rest _)
|
(lambda (&rest _)
|
||||||
(doom-log "Loading deferred package %s from %s" ',name ',fn)
|
(doom-log "Loading deferred package %s from %s" ',name ',fn)
|
||||||
(condition-case e
|
(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)
|
((debug error)
|
||||||
(message "Failed to load deferred package %s: %s" ',name e)))
|
(message "Failed to load deferred package %s: %s" ',name e)))
|
||||||
(when-let (deferral-list (assq ',name doom--deferred-packages-alist))
|
(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
|
;;; 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)
|
(defmacro doom! (&rest modules)
|
||||||
"Bootstraps DOOM Emacs and its modules.
|
"Bootstraps DOOM Emacs and its modules.
|
||||||
|
|
||||||
|
@ -335,51 +361,62 @@ The overall load order of Doom is as follows:
|
||||||
Module load order is determined by your `doom!' block. See `doom-modules-dirs'
|
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
|
for a list of all recognized module trees. Order defines precedence (from most
|
||||||
to least)."
|
to least)."
|
||||||
(if doom--modules-cache
|
(unless (keywordp (car modules))
|
||||||
(progn
|
(setq modules (eval modules t)))
|
||||||
(setq doom-modules doom--modules-cache)
|
(let ((doom-modules
|
||||||
(doom-log "Using `doom-modules' cache"))
|
(make-hash-table :test 'equal
|
||||||
(unless doom-modules
|
:size (if modules (length modules) 150)
|
||||||
(setq doom-modules
|
:rehash-threshold 1.0))
|
||||||
(make-hash-table :test 'equal
|
(inhibit-message doom-inhibit-module-warnings)
|
||||||
:size (if modules (length modules) 150)
|
category m)
|
||||||
:rehash-threshold 1.0)))
|
(while modules
|
||||||
(let ((inhibit-message doom-inhibit-module-warnings)
|
(setq m (pop modules))
|
||||||
category m)
|
(cond ((keywordp m) (setq category m))
|
||||||
(while modules
|
((not category) (error "No module category specified for %s" m))
|
||||||
(setq m (pop modules))
|
((and (listp m)
|
||||||
(cond ((keywordp m) (setq category m))
|
(keywordp (car m)))
|
||||||
((not category) (error "No module category specified for %s" m))
|
(pcase (car m)
|
||||||
((catch 'doom-modules
|
(:cond
|
||||||
(let* ((module (if (listp m) (car m) m))
|
(cl-loop for (cond . mods) in (cdr m)
|
||||||
(flags (if (listp m) (cdr m))))
|
if (eval cond t)
|
||||||
(when-let* ((obsolete (assq category doom-obsolete-modules))
|
return (prependq! modules mods)))
|
||||||
(new (assq module obsolete)))
|
(:if (if (eval (cadr m) t)
|
||||||
(let ((newkeys (cdr new)))
|
(push (caddr m) modules)
|
||||||
(if (null newkeys)
|
(prependq! modules (cdddr m))))
|
||||||
(message "WARNING %s module was removed" key)
|
(fn (if (or (eval (cadr m) t)
|
||||||
(if (cdr newkeys)
|
(eq fn :unless))
|
||||||
(message "WARNING %s module was removed and split into the %s modules"
|
(prependq! modules (cddr m))))))
|
||||||
(list category module) (mapconcat #'prin1-to-string newkeys ", "))
|
((catch 'doom-modules
|
||||||
(message "WARNING %s module was moved to %s"
|
(let* ((module (if (listp m) (car m) m))
|
||||||
(list category module) (car newkeys)))
|
(flags (if (listp m) (cdr m))))
|
||||||
(push category modules)
|
(when-let* ((obsolete (assq category doom-obsolete-modules))
|
||||||
(dolist (key newkeys)
|
(new (assq module obsolete)))
|
||||||
(push (if flags
|
(let ((newkeys (cdr new)))
|
||||||
(nconc (cdr key) flags)
|
(if (null newkeys)
|
||||||
(cdr key))
|
(message "WARNING %s module was removed" key)
|
||||||
modules)
|
(if (cdr newkeys)
|
||||||
(push (car key) modules))
|
(message "WARNING %s module was removed and split into the %s modules"
|
||||||
(throw 'doom-modules t))))
|
(list category module) (mapconcat #'prin1-to-string newkeys ", "))
|
||||||
(if-let (path (doom-module-locate-path category module))
|
(message "WARNING %s module was moved to %s"
|
||||||
(doom-module-set category module :flags flags :path path)
|
(list category module) (car newkeys)))
|
||||||
(message "WARNING Couldn't find the %s %s module" category module)))))))))
|
(push category modules)
|
||||||
(when noninteractive
|
(dolist (key newkeys)
|
||||||
(setq doom-inhibit-module-warnings t))
|
(push (if flags
|
||||||
`(setq doom-modules ',doom-modules))
|
(nconc (cdr key) flags)
|
||||||
|
(cdr key))
|
||||||
|
modules)
|
||||||
|
(push (car key) modules))
|
||||||
|
(throw 'doom-modules t))))
|
||||||
|
(if-let (path (doom-module-locate-path category module))
|
||||||
|
(doom-module-set category module :flags flags :path path)
|
||||||
|
(message "WARNING Couldn't find the %s %s module" category module)))))))
|
||||||
|
(when noninteractive
|
||||||
|
(setq doom-inhibit-module-warnings t))
|
||||||
|
`(setq doom-modules ',doom-modules)))
|
||||||
|
|
||||||
(defvar doom-disabled-packages)
|
(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.
|
"Declares and configures a package.
|
||||||
|
|
||||||
This is a thin wrapper around `use-package', and is ignored if the NAME 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
|
The first time any of these functions or hooks are executed, the package is
|
||||||
loaded. e.g.
|
loaded. e.g.
|
||||||
|
|
||||||
(def-package! projectile
|
(use-package! projectile
|
||||||
:after-call (pre-command-hook after-find-file dired-before-readin-hook)
|
: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
|
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.
|
specify it. A value of `t' implies NAME, e.g.
|
||||||
|
|
||||||
(def-package! abc
|
(use-package! abc
|
||||||
;; This is equivalent to :defer-incrementally (abc)
|
;; This is equivalent to :defer-incrementally (abc)
|
||||||
:defer-incrementally t
|
:defer-incrementally t
|
||||||
...)"
|
...)"
|
||||||
|
(declare (indent 1))
|
||||||
(unless (or (memq name doom-disabled-packages)
|
(unless (or (memq name doom-disabled-packages)
|
||||||
;; At compile-time, use-package will forcibly load packages to
|
;; At compile-time, use-package will forcibly load packages to
|
||||||
;; prevent compile-time errors. However, if a Doom user has
|
;; prevent compile-time errors. However, if a Doom user has
|
||||||
|
@ -420,8 +458,9 @@ two extra properties:
|
||||||
(not (locate-library (symbol-name name)))))
|
(not (locate-library (symbol-name name)))))
|
||||||
`(use-package ,name ,@plist)))
|
`(use-package ,name ,@plist)))
|
||||||
|
|
||||||
(defmacro def-package-hook! (package when &rest body)
|
(define-obsolete-function-alias 'def-package-hook! 'use-package-hook!) ; DEPRECATED
|
||||||
"Reconfigures a package's `def-package!' block.
|
(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.
|
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
|
:pre-init :post-init :pre-config :post-config
|
||||||
|
|
||||||
WARNING: If :pre-init or :pre-config hooks return nil, the original
|
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)."
|
to have them return non-nil (or exploit that to overwrite Doom's config)."
|
||||||
(declare (indent defun))
|
(declare (indent defun))
|
||||||
(doom--assert-stage-p 'init #'package!)
|
|
||||||
(unless (memq when '(:pre-init :post-init :pre-config :post-config))
|
(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
|
`(progn
|
||||||
(setq use-package-inject-hooks t)
|
(setq use-package-inject-hooks t)
|
||||||
(add-hook!
|
(add-hook ',(intern (format "use-package--%s--%s-hook"
|
||||||
',(intern (format "use-package--%s--%s-hook"
|
package
|
||||||
package
|
(substring (symbol-name when) 1)))
|
||||||
(substring (symbol-name when) 1)))
|
(lambda () ,@body)
|
||||||
,@body)))
|
'append)))
|
||||||
|
|
||||||
(defmacro require! (category module &rest flags)
|
(defmacro require! (category module &rest flags)
|
||||||
"Loads the CATEGORY MODULE module with FLAGS.
|
"Loads the CATEGORY MODULE module with FLAGS.
|
||||||
|
@ -470,8 +508,7 @@ module."
|
||||||
(let ((doom--current-module ',(cons category module))
|
(let ((doom--current-module ',(cons category module))
|
||||||
(doom--current-flags ',flags))
|
(doom--current-flags ',flags))
|
||||||
(load! "init" module-path :noerror)
|
(load! "init" module-path :noerror)
|
||||||
(let ((doom--stage 'config))
|
(load! "config" module-path :noerror))
|
||||||
(load! "config" module-path :noerror)))
|
|
||||||
('error
|
('error
|
||||||
(lwarn 'doom-modules :error
|
(lwarn 'doom-modules :error
|
||||||
"%s in '%s %s' -> %s"
|
"%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)))
|
(and (cond (flag (memq flag (doom-module-get category module :flags)))
|
||||||
(module (doom-module-p category module))
|
(module (doom-module-p category module))
|
||||||
(doom--current-flags (memq category doom--current-flags))
|
(doom--current-flags (memq category doom--current-flags))
|
||||||
((let ((module-pair
|
((let ((module (doom-module-from-path)))
|
||||||
(or doom--current-module
|
(unless module
|
||||||
(doom-module-from-path (FILE!)))))
|
(error "featurep! couldn't figure out what module it was called from (in %s)"
|
||||||
(unless module-pair
|
(file!)))
|
||||||
(error "featurep! call couldn't auto-detect what module its in (from %s)" (FILE!)))
|
(memq category (doom-module-get (car module) (cdr module) :flags)))))
|
||||||
(memq category (doom-module-get (car module-pair) (cdr module-pair) :flags)))))
|
|
||||||
t))
|
t))
|
||||||
|
|
||||||
(defmacro after! (targets &rest body)
|
(defmacro after! (package &rest body)
|
||||||
"Evaluate BODY after TARGETS (packages) have loaded.
|
"Evaluate BODY after PACKAGE have loaded.
|
||||||
|
|
||||||
This is a wrapper around `with-eval-after-load' that:
|
PACKAGE is a symbol or list of them. These are package names, not modes,
|
||||||
|
functions or variables. It can be:
|
||||||
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:
|
|
||||||
|
|
||||||
- An unquoted package symbol (the name of a package)
|
- An unquoted package symbol (the name of a package)
|
||||||
(after! helm BODY...)
|
(after! helm BODY...)
|
||||||
- An unquoted list of package symbols (i.e. BODY is evaluated once both magit
|
- An unquoted list of package symbols (i.e. BODY is evaluated once both magit
|
||||||
and git-gutter have loaded)
|
and git-gutter have loaded)
|
||||||
(after! (magit git-gutter) BODY...)
|
(after! (magit git-gutter) BODY...)
|
||||||
- An unquoted, nested list of compound package lists, using :or/:any and/or
|
- An unquoted, nested list of compound package lists, using any combination of
|
||||||
:and/:all
|
:or/:any and :and/:all
|
||||||
(after! (:or package-a package-b ...) BODY...)
|
(after! (:or package-a package-b ...) BODY...)
|
||||||
(after! (:and package-a package-b ...) BODY...)
|
(after! (:and package-a package-b ...) BODY...)
|
||||||
(after! (:and package-a (:or package-b package-c) ...) BODY...)
|
(after! (:and package-a (:or package-b package-c) ...) BODY...)
|
||||||
|
Without :or/:any/:and/:all, :and/:all are implied.
|
||||||
|
|
||||||
Note that:
|
This is a wrapper around `eval-after-load' that:
|
||||||
- :or and :any are equivalent
|
|
||||||
- :and and :all are equivalent
|
1. Suppresses warnings for disabled packages at compile-time
|
||||||
- If these are omitted, :and is implied."
|
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))
|
(declare (indent defun) (debug t))
|
||||||
(unless (and (symbolp targets)
|
(if (symbolp package)
|
||||||
(memq targets (bound-and-true-p doom-disabled-packages)))
|
(unless (memq package (bound-and-true-p doom-disabled-packages))
|
||||||
(list (if (or (not (bound-and-true-p byte-compile-current-file))
|
(list (if (or (not (bound-and-true-p byte-compile-current-file))
|
||||||
(dolist (next (doom-enlist targets))
|
(require package nil 'noerror))
|
||||||
(unless (keywordp next)
|
#'progn
|
||||||
(if (symbolp next)
|
#'with-no-warnings)
|
||||||
(require next nil :no-error)
|
(let ((body (macroexp-progn body)))
|
||||||
(load next :no-message :no-error)))))
|
`(if (featurep ',package)
|
||||||
#'progn
|
,body
|
||||||
#'with-no-warnings)
|
;; We intentionally avoid `with-eval-after-load' to prevent
|
||||||
(if (symbolp targets)
|
;; eager macro expansion from pulling (or failing to pull) in
|
||||||
`(with-eval-after-load ',targets ,@body)
|
;; autoloaded macros/packages.
|
||||||
(pcase (car-safe targets)
|
(eval-after-load ',package ',body)))))
|
||||||
((or :or :any)
|
(let ((p (car package)))
|
||||||
(macroexp-progn
|
(cond ((not (keywordp p))
|
||||||
(cl-loop for next in (cdr targets)
|
`(after! (:and ,@package) ,@body))
|
||||||
collect `(after! ,next ,@body))))
|
((memq p '(:or :any))
|
||||||
((or :and :all)
|
(macroexp-progn
|
||||||
(dolist (next (cdr targets))
|
(cl-loop for next in (cdr package)
|
||||||
(setq body `((after! ,next ,@body))))
|
collect `(after! ,next ,@body))))
|
||||||
(car body))
|
((memq p '(:and :all))
|
||||||
(_ `(after! (:and ,@targets) ,@body)))))))
|
(dolist (next (cdr package))
|
||||||
|
(setq body `((after! ,next ,@body))))
|
||||||
|
(car body))))))
|
||||||
|
|
||||||
(provide 'core-modules)
|
(provide 'core-modules)
|
||||||
;;; core-modules.el ends here
|
;;; 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; -*-
|
;;; core/core-packages.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
;; Emacs package management is opinionated, and so am I. I've bound together
|
;; Emacs package management is opinionated, and so is Doom. Doom uses `straight'
|
||||||
;; `use-package', `quelpa' and package.el to create my own, rolling-release,
|
;; to create a declarative, lazy-loaded and optionally rolling-release package
|
||||||
;; lazily-loaded package management system for Emacs.
|
;; 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.
|
;; ANyhow, interacting with this package management system is done through the
|
||||||
;; + `bin/doom update`: Updates packages that are out-of-date.
|
;; bin/doom script included with Doom Emacs. You'll find more about it by
|
||||||
;; + `bin/doom autoremove`: Uninstalls packages that are no longer needed.
|
;; 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
|
;; + `bin/doom install`: a wizard that guides you through setting up Doom and
|
||||||
;; in `doom-core-dir'). These contain `package!' blocks that tell DOOM what
|
;; 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.
|
;; plugins to install and where from.
|
||||||
;;
|
;;
|
||||||
;; Why all the trouble? Because:
|
;; All that said, you can still use package.el's commands, but 'bin/doom
|
||||||
;; 1. *Scriptability:* I live in the command line. I want a shell-scriptable
|
;; refresh' will purge ELPA packages.
|
||||||
;; interface for updating and installing Emacs packages.
|
|
||||||
;; 2. *Reach:* I want packages from sources other than ELPA (like github or
|
(defvar doom-init-packages-p nil
|
||||||
;; gitlab). Some plugins are out-of-date through official channels, have
|
"If non-nil, Doom's package management system has been initialized.")
|
||||||
;; 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.
|
|
||||||
|
|
||||||
(defvar doom-packages ()
|
(defvar doom-packages ()
|
||||||
"A list of enabled packages. Each element is a sublist, whose CAR is the
|
"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's name as a symbol, and whose CDR is the plist supplied to its
|
||||||
`package!' declaration. Set by `doom-initialize-packages'.")
|
`package!' declaration. Set by `doom-initialize-packages'.")
|
||||||
|
|
||||||
(defvar doom-core-packages
|
(defvar doom-core-packages '(straight use-package async)
|
||||||
'(persistent-soft use-package quelpa async)
|
|
||||||
"A list of packages that must be installed (and will be auto-installed if
|
"A list of packages that must be installed (and will be auto-installed if
|
||||||
missing) and shouldn't be deleted.")
|
missing) and shouldn't be deleted.")
|
||||||
|
|
||||||
(defvar doom-disabled-packages ()
|
(defvar doom-core-package-sources
|
||||||
"A list of packages that should be ignored by `def-package!' and `after!'.")
|
'((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
|
(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-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
|
;; I omit Marmalade because its packages are manually submitted rather
|
||||||
;; than pulled, so packages are often out of date with upstream.
|
;; than pulled, so packages are often out of date with upstream.
|
||||||
package-archives
|
package-archives
|
||||||
`(("gnu" . "https://elpa.gnu.org/packages/")
|
(let ((proto (if gnutls-verify-error "https" "http")))
|
||||||
("melpa" . "https://melpa.org/packages/")
|
`(("gnu" . ,(concat proto "://elpa.gnu.org/packages/"))
|
||||||
("org" . "https://orgmode.org/elpa/")))
|
("melpa" . ,(concat proto "://melpa.org/packages/"))
|
||||||
|
("org" . ,(concat proto "://orgmode.org/elpa/")))))
|
||||||
|
|
||||||
;; Don't save `package-selected-packages' to `custom-file'
|
;; Don't save `package-selected-packages' to `custom-file'
|
||||||
(advice-add #'package--save-selected-packages :override
|
(defadvice! doom--package-inhibit-custom-file-a (&optional value)
|
||||||
(lambda (&optional value) (if value (setq package-selected-packages value))))
|
:override #'package--save-selected-packages
|
||||||
|
(if value (setq package-selected-packages value)))
|
||||||
|
|
||||||
(when (or (not gnutls-verify-error)
|
;;; straight
|
||||||
(not (ignore-errors (gnutls-available-p))))
|
(setq straight-base-dir doom-local-dir
|
||||||
(dolist (archive package-archives)
|
straight-repository-branch "develop"
|
||||||
(setcdr archive (replace-regexp-in-string "^https://" "http://" (cdr archive) t nil))))
|
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
|
;; Straight is hardcoded to operate out of ~/.emacs.d/straight. Not on my watch!
|
||||||
(setq quelpa-dir (expand-file-name "quelpa" doom-packages-dir)
|
(defadvice! doom--straight-use-local-dir-a (orig-fn &rest args)
|
||||||
quelpa-verbose doom-debug-mode
|
: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
|
(defun doom--finalize-straight ()
|
||||||
quelpa-checkout-melpa-p nil
|
(mapc #'funcall (delq nil (mapcar #'cdr straight--transaction-alist)))
|
||||||
quelpa-update-melpa-p nil
|
(setq straight--transaction-alist nil))
|
||||||
quelpa-melpa-recipe-stores nil
|
|
||||||
quelpa-self-upgrade-p nil)
|
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;;; Bootstrapper
|
;;; Bootstrapper
|
||||||
|
|
||||||
(defun doom-initialize-packages (&optional force-p)
|
(defun doom-initialize-packages (&optional force-p)
|
||||||
"Ensures that Doom's package management system, package.el and quelpa are
|
"Ensures that Doom's package system and straight.el are initialized.
|
||||||
initialized, and `doom-packages', `packages-alist' and `quelpa-cache' are
|
|
||||||
populated, if they aren't already.
|
|
||||||
|
|
||||||
If FORCE-P is non-nil, do it anyway.
|
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
|
This ensure `doom-packages' is populated, if isn't aren't already. Use this
|
||||||
ensure all the necessary package metadata is initialized and available for
|
before any of straight's or Doom's package management's API to ensure all the
|
||||||
them."
|
necessary package metadata is initialized and available for them."
|
||||||
(let ((load-prefer-newer t)) ; reduce stale code issues
|
(unless doom-init-packages-p
|
||||||
;; package.el and quelpa handle themselves if their state changes during the
|
(setq force-p t))
|
||||||
;; 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."
|
|
||||||
(when (or force-p (not (bound-and-true-p package--initialized)))
|
(when (or force-p (not (bound-and-true-p package--initialized)))
|
||||||
|
(doom-log "Initializing package.el")
|
||||||
(require 'package)
|
(require 'package)
|
||||||
(setq package-activated-list nil
|
(package-initialize))
|
||||||
package--initialized nil)
|
(when (or force-p (not doom-packages))
|
||||||
(let (byte-compile-warnings)
|
(doom-log "Initializing straight")
|
||||||
(condition-case _
|
(setq doom-init-packages-p t)
|
||||||
(package-initialize)
|
(unless (fboundp 'straight--reset-caches)
|
||||||
('error (package-refresh-contents)
|
(doom-ensure-straight)
|
||||||
(setq doom--refreshed-p t)
|
(require 'straight))
|
||||||
(package-initialize))))))
|
(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 ()
|
(defun doom-ensure-straight ()
|
||||||
"Make sure `doom-core-packages' are installed."
|
"Ensure `straight' is installed and was compiled with this version of Emacs."
|
||||||
(when-let (core-packages (cl-remove-if #'package-installed-p doom-core-packages))
|
(defvar bootstrap-version)
|
||||||
(message "Installing core packages")
|
(let* (;; Force straight to install into ~/.emacs.d/.local/straight instead of
|
||||||
(unless doom--refreshed-p
|
;; ~/.emacs.d/straight by pretending `doom-local-dir' is our .emacs.d.
|
||||||
(package-refresh-contents))
|
(user-emacs-directory straight-base-dir)
|
||||||
(dolist (package core-packages)
|
(bootstrap-file (doom-path straight-base-dir "straight/repos/straight.el/straight.el"))
|
||||||
(let ((inhibit-message t))
|
(bootstrap-version 5))
|
||||||
(package-install package))
|
(make-directory (doom-path straight-base-dir "straight/build") 'parents)
|
||||||
(if (package-installed-p package)
|
(unless (featurep 'straight)
|
||||||
(message "✓ Installed %s" package)
|
(unless (or (require 'straight nil t)
|
||||||
(error "✕ Couldn't install %s" package)))
|
(file-readable-p bootstrap-file))
|
||||||
(message "Installing core packages...done")))
|
(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).
|
"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
|
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
|
:recipe RECIPE
|
||||||
Takes a MELPA-style recipe (see `quelpa-recipe' in `quelpa' for an example);
|
Takes a MELPA-style recipe (see `quelpa-recipe' in `quelpa' for an example);
|
||||||
for packages to be installed from external sources.
|
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
|
:disable BOOL
|
||||||
Do not install or update this package AND disable all of its `def-package!'
|
Do not install or update this package AND disable all of its `def-package!'
|
||||||
blocks.
|
blocks.
|
||||||
|
@ -179,63 +227,55 @@ Accepts the following properties:
|
||||||
Returns t if package is successfully registered, and nil if it was disabled
|
Returns t if package is successfully registered, and nil if it was disabled
|
||||||
elsewhere."
|
elsewhere."
|
||||||
(declare (indent defun))
|
(declare (indent defun))
|
||||||
(doom--assert-stage-p 'packages #'package!)
|
|
||||||
(let ((old-plist (cdr (assq name doom-packages))))
|
(let ((old-plist (cdr (assq name doom-packages))))
|
||||||
(when recipe
|
;; Add current module to :modules
|
||||||
(when (cl-evenp (length recipe))
|
|
||||||
(setq plist (plist-put plist :recipe (cons name recipe))))
|
|
||||||
(setq pin nil
|
|
||||||
plist (plist-put plist :pin nil)))
|
|
||||||
(let ((module-list (plist-get old-plist :modules))
|
(let ((module-list (plist-get old-plist :modules))
|
||||||
(module (or doom--current-module
|
(module (doom-module-from-path)))
|
||||||
(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)))))))
|
|
||||||
(unless (member module module-list)
|
(unless (member module module-list)
|
||||||
(setq module-list (append module-list (list module) nil)
|
(plist-put! plist :modules
|
||||||
plist (plist-put plist :modules module-list))))
|
(append module-list
|
||||||
(when built-in
|
(list module)
|
||||||
(doom-log "Ignoring built-in package %S" name)
|
nil))))
|
||||||
(when (equal built-in '(quote prefer))
|
|
||||||
(setq built-in `(locate-library ,(symbol-name name) nil doom-site-load-path))))
|
;; Handle :built-in
|
||||||
(setq plist (plist-put plist :ignore (or built-in ignore)))
|
(unless ignore
|
||||||
(while plist
|
(when built-in
|
||||||
(unless (null (cadr plist))
|
(doom-log "Ignoring built-in package %S" name)
|
||||||
(setq old-plist (plist-put old-plist (car plist) (cadr plist))))
|
(when (equal built-in '(quote prefer))
|
||||||
(pop plist)
|
(setq built-in `(locate-library ,(symbol-name name) nil doom--initial-load-path))))
|
||||||
(pop plist))
|
(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)
|
(setq plist old-plist)
|
||||||
|
|
||||||
|
;; TODO Add `straight-use-package-pre-build-function' support
|
||||||
(macroexp-progn
|
(macroexp-progn
|
||||||
(append (when pin
|
(append `((setf (alist-get ',name doom-packages) ',plist))
|
||||||
(doom-log "Pinning package '%s' to '%s'" name pin)
|
|
||||||
`((setf (alist-get ',name package-pinned-packages) ,pin)))
|
|
||||||
`((setf (alist-get ',name doom-packages) ',plist))
|
|
||||||
(when disable
|
(when disable
|
||||||
(doom-log "Disabling package '%s'" name)
|
`((doom-log "Disabling package %S" ',name)
|
||||||
`((add-to-list 'doom-disabled-packages ',name nil 'eq)
|
(add-to-list 'doom-disabled-packages ',name nil 'eq)
|
||||||
nil))))))
|
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)
|
(defmacro disable-packages! (&rest packages)
|
||||||
"A convenience macro like `package!', but allows you to disable multiple
|
"A convenience macro for disabling packages in bulk.
|
||||||
packages at once.
|
Only use this macro in a module's (or your private) packages.el file."
|
||||||
|
|
||||||
Only use this macro in a module's packages.el file."
|
|
||||||
(doom--assert-stage-p 'packages #'disable-packages!)
|
|
||||||
(macroexp-progn
|
(macroexp-progn
|
||||||
(cl-loop for pkg in packages
|
(cl-loop for p in packages
|
||||||
collect (macroexpand `(package! ,pkg :disable t)))))
|
collect `(package! ,p :disable t))))
|
||||||
|
|
||||||
(provide 'core-packages)
|
(provide 'core-packages)
|
||||||
;;; core-packages.el ends here
|
;;; core-packages.el ends here
|
||||||
|
|
|
@ -11,7 +11,8 @@ Emacs.")
|
||||||
"If non-nil, non-projects are purged from the cache on `kill-emacs-hook'.")
|
"If non-nil, non-projects are purged from the cache on `kill-emacs-hook'.")
|
||||||
|
|
||||||
(defvar doom-projectile-fd-binary
|
(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")
|
"name of `fd-find' executable binary")
|
||||||
|
|
||||||
(defvar doom-projectile-cache-timer-file (concat doom-cache-dir "projectile.timers")
|
(defvar doom-projectile-cache-timer-file (concat doom-cache-dir "projectile.timers")
|
||||||
|
@ -21,8 +22,8 @@ Emacs.")
|
||||||
;;
|
;;
|
||||||
;;; Packages
|
;;; Packages
|
||||||
|
|
||||||
(def-package! projectile
|
(use-package! projectile
|
||||||
:after-call (after-find-file dired-before-readin-hook minibuffer-setup-hook)
|
:after-call after-find-file dired-before-readin-hook minibuffer-setup-hook
|
||||||
:commands (projectile-project-root
|
:commands (projectile-project-root
|
||||||
projectile-project-name
|
projectile-project-name
|
||||||
projectile-project-p
|
projectile-project-p
|
||||||
|
@ -44,59 +45,42 @@ Emacs.")
|
||||||
(global-set-key [remap find-tag] #'projectile-find-tag)
|
(global-set-key [remap find-tag] #'projectile-find-tag)
|
||||||
|
|
||||||
:config
|
: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)
|
(projectile-mode +1)
|
||||||
|
|
||||||
;; a more generic project root file
|
;; a more generic project root file
|
||||||
(push ".project" projectile-project-root-files-bottom-up)
|
(push ".project" projectile-project-root-files-bottom-up)
|
||||||
(push (abbreviate-file-name doom-local-dir) projectile-globally-ignored-directories)
|
(push (abbreviate-file-name doom-local-dir) projectile-globally-ignored-directories)
|
||||||
|
|
||||||
(defun doom*projectile-default-generic-command (orig-fn &rest args)
|
;; Treat current directory in dired as a "file in a project" and track it
|
||||||
"If projectile can't tell what kind of project you're in, it issues an error
|
(add-hook 'dired-before-readin-hook #'projectile-track-known-projects-find-file-hook)
|
||||||
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)
|
|
||||||
|
|
||||||
;; Accidentally indexing big directories like $HOME or / will massively bloat
|
;; Accidentally indexing big directories like $HOME or / will massively bloat
|
||||||
;; projectile's cache (into the hundreds of MBs). This purges those entries
|
;; projectile's cache (into the hundreds of MBs). This purges those entries
|
||||||
;; when exiting Emacs to prevent slowdowns/freezing when cache files are
|
;; when exiting Emacs to prevent slowdowns/freezing when cache files are
|
||||||
;; loaded or written to.
|
;; loaded or written to.
|
||||||
(defun doom|cleanup-project-cache ()
|
(add-hook! 'kill-emacs-hook
|
||||||
"Purge projectile cache entries that:
|
(defun doom-cleanup-project-cache-h ()
|
||||||
|
"Purge projectile cache entries that:
|
||||||
|
|
||||||
a) have too many files (see `doom-projectile-cache-limit'),
|
a) have too many files (see `doom-projectile-cache-limit'),
|
||||||
b) represent blacklisted directories that are too big, change too often or are
|
b) represent blacklisted directories that are too big, change too often or are
|
||||||
private. (see `doom-projectile-cache-blacklist'),
|
private. (see `doom-projectile-cache-blacklist'),
|
||||||
c) are not valid projectile projects."
|
c) are not valid projectile projects."
|
||||||
(when (bound-and-true-p projectile-projects-cache)
|
(when (and (bound-and-true-p projectile-projects-cache)
|
||||||
(cl-loop with blacklist = (mapcar #'file-truename doom-projectile-cache-blacklist)
|
(not noninteractive))
|
||||||
for proot in (hash-table-keys projectile-projects-cache)
|
(cl-loop with blacklist = (mapcar #'file-truename doom-projectile-cache-blacklist)
|
||||||
if (or (not (stringp proot))
|
for proot in (hash-table-keys projectile-projects-cache)
|
||||||
(>= (length (gethash proot projectile-projects-cache))
|
if (or (not (stringp proot))
|
||||||
doom-projectile-cache-limit)
|
(>= (length (gethash proot projectile-projects-cache))
|
||||||
(member (substring proot 0 -1) blacklist)
|
doom-projectile-cache-limit)
|
||||||
(and doom-projectile-cache-purge-non-projects
|
(member (substring proot 0 -1) blacklist)
|
||||||
(not (doom-project-p proot))))
|
(and doom-projectile-cache-purge-non-projects
|
||||||
do (doom-log "Removed %S from projectile cache" proot)
|
(not (doom-project-p proot))))
|
||||||
and do (remhash proot projectile-projects-cache)
|
do (doom-log "Removed %S from projectile cache" proot)
|
||||||
and do (remhash proot projectile-projects-cache-time)
|
and do (remhash proot projectile-projects-cache)
|
||||||
and do (remhash proot projectile-project-type-cache))
|
and do (remhash proot projectile-projects-cache-time)
|
||||||
(projectile-serialize-cache)))
|
and do (remhash proot projectile-project-type-cache))
|
||||||
(unless noninteractive
|
(projectile-serialize-cache))))
|
||||||
(add-hook 'kill-emacs-hook #'doom|cleanup-project-cache))
|
|
||||||
|
|
||||||
;; It breaks projectile's project root resolution if HOME is a project (e.g.
|
;; 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
|
;; 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)
|
||||||
projectile-project-root-files-bottom-up nil)))
|
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
|
(cond
|
||||||
;; If fd exists, use it for git and generic projects. fd is a rust program
|
;; 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
|
;; that is significantly faster than git ls-files or find, and it respects
|
||||||
;; .gitignore. This is recommended in the projectile docs.
|
;; .gitignore. This is recommended in the projectile docs.
|
||||||
(doom-projectile-fd-binary
|
((executable-find doom-projectile-fd-binary)
|
||||||
(setq projectile-git-command (concat
|
(setq projectile-git-command (concat
|
||||||
doom-projectile-fd-binary
|
doom-projectile-fd-binary
|
||||||
" . --color=never --type f -0 -H -E .git")
|
" . --color=never --type f -0 -H -E .git")
|
||||||
|
@ -143,10 +117,42 @@ c) are not valid projectile projects."
|
||||||
projectile-indexing-method 'alien)
|
projectile-indexing-method 'alien)
|
||||||
;; fix breakage on windows in git projects
|
;; fix breakage on windows in git projects
|
||||||
(unless (executable-find "tr")
|
(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
|
(defvar doom-project-hook nil
|
||||||
"Hook run when a project is enabled. The name of the project's mode and its
|
"Hook run when a project is enabled. The name of the project's mode and its
|
||||||
|
@ -197,30 +203,54 @@ should be activated. If they are *all* true, NAME is activated.
|
||||||
Relevant: `doom-project-hook'."
|
Relevant: `doom-project-hook'."
|
||||||
(declare (indent 1))
|
(declare (indent 1))
|
||||||
(let ((init-var (intern (format "%s-init" name))))
|
(let ((init-var (intern (format "%s-init" name))))
|
||||||
`(progn
|
(macroexp-progn
|
||||||
,(if on-load `(defvar ,init-var nil))
|
(append
|
||||||
(define-minor-mode ,name
|
(when on-load
|
||||||
"A project minor mode generated by `def-project-mode!'."
|
`((defvar ,init-var nil)))
|
||||||
:init-value nil
|
`((define-minor-mode ,name
|
||||||
:lighter ""
|
"A project minor mode generated by `def-project-mode!'."
|
||||||
:keymap (make-sparse-keymap)
|
:init-value nil
|
||||||
(if (not ,name)
|
:lighter ""
|
||||||
,on-exit
|
:keymap (make-sparse-keymap)
|
||||||
(run-hook-with-args 'doom-project-hook ',name ,name)
|
(if (not ,name)
|
||||||
,(when on-load
|
,on-exit
|
||||||
`(unless ,init-var
|
(run-hook-with-args 'doom-project-hook ',name ,name)
|
||||||
,on-load
|
,(when on-load
|
||||||
(setq ,init-var t)))
|
`(unless ,init-var
|
||||||
,on-enter))
|
,on-load
|
||||||
,@(cl-loop for hook in add-hooks
|
(setq ,init-var t)))
|
||||||
collect `(add-hook ',(intern (format "%s-hook" name))
|
,on-enter))
|
||||||
#',hook))
|
(dolist (hook ,add-hooks)
|
||||||
,(when (or modes match files when)
|
(add-hook ',(intern (format "%s-hook" name)) hook)))
|
||||||
`(associate! ,name
|
(cond ((or files modes when)
|
||||||
:modes ,modes
|
(cl-check-type files (or null list string))
|
||||||
:match ,match
|
(let ((fn
|
||||||
:files ,files
|
`(lambda ()
|
||||||
:when ,when)))))
|
(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)
|
(provide 'core-projects)
|
||||||
;;; core-projects.el ends here
|
;;; core-projects.el ends here
|
||||||
|
|
551
core/core-ui.el
551
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
|
It is recommended you don't set specify a font-size, as to inherit `doom-font's
|
||||||
size.")
|
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
|
;;; 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-window nil)
|
||||||
(defvar doom--last-frame nil)
|
(defvar doom--last-frame nil)
|
||||||
|
|
||||||
(defun doom|run-switch-window-hooks ()
|
(defun doom-run-switch-window-hooks-h ()
|
||||||
(let ((gc-cons-threshold doom-gc-cons-upper-limit))
|
(let ((gc-cons-threshold most-positive-fixnum))
|
||||||
(unless (or doom-inhibit-switch-window-hooks
|
(unless (or doom-inhibit-switch-window-hooks
|
||||||
(eq doom--last-window (selected-window))
|
(eq doom--last-window (selected-window))
|
||||||
(minibufferp))
|
(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)
|
(run-hooks 'doom-switch-window-hook)
|
||||||
(setq doom--last-window (selected-window))))))
|
(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
|
(unless (or doom-inhibit-switch-frame-hooks
|
||||||
(eq doom--last-frame (selected-frame))
|
(eq doom--last-frame (selected-frame))
|
||||||
(frame-parameter nil 'parent-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)
|
(run-hooks 'doom-switch-frame-hook)
|
||||||
(setq doom--last-frame (selected-frame)))))
|
(setq doom--last-frame (selected-frame)))))
|
||||||
|
|
||||||
(defun doom*run-switch-buffer-hooks (orig-fn buffer-or-name &rest args)
|
(defun doom-run-switch-buffer-hooks-a (orig-fn buffer-or-name &rest args)
|
||||||
(let ((gc-cons-threshold doom-gc-cons-upper-limit))
|
(let ((gc-cons-threshold most-positive-fixnum))
|
||||||
(if (or doom-inhibit-switch-buffer-hooks
|
(if (or doom-inhibit-switch-buffer-hooks
|
||||||
(eq (current-buffer) (get-buffer buffer-or-name))
|
(eq (current-buffer) (get-buffer buffer-or-name))
|
||||||
(and (eq orig-fn #'switch-to-buffer) (car args)))
|
(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))
|
(run-hooks 'doom-switch-buffer-hook))
|
||||||
buffer)))))
|
buffer)))))
|
||||||
|
|
||||||
(defun doom*run-switch-to-next-prev-buffer-hooks (orig-fn &rest args)
|
(defun doom-run-switch-to-next-prev-buffer-hooks-a (orig-fn &rest args)
|
||||||
(let ((gc-cons-threshold doom-gc-cons-upper-limit))
|
(let ((gc-cons-threshold most-positive-fixnum))
|
||||||
(if doom-inhibit-switch-buffer-hooks
|
(if doom-inhibit-switch-buffer-hooks
|
||||||
(apply orig-fn args)
|
(apply orig-fn args)
|
||||||
(let ((doom-inhibit-switch-buffer-hooks t))
|
(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))
|
(run-hooks 'doom-switch-buffer-hook))
|
||||||
buffer)))))
|
buffer)))))
|
||||||
|
|
||||||
(defun doom*run-load-theme-hooks (theme &optional _no-confirm no-enable)
|
(defun doom-protect-fallback-buffer-h ()
|
||||||
"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 ()
|
|
||||||
"Don't kill the scratch buffer. Meant for `kill-buffer-query-functions'."
|
"Don't kill the scratch buffer. Meant for `kill-buffer-query-functions'."
|
||||||
(not (eq (current-buffer) (doom-fallback-buffer))))
|
(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.
|
"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
|
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)
|
(set (make-local-variable 'whitespace-style)
|
||||||
(let ((style (if indent-tabs-mode '(indentation) '(tabs tab-mark))))
|
(let ((style (if indent-tabs-mode '(indentation) '(tabs tab-mark))))
|
||||||
(if whitespace-mode
|
(if whitespace-mode
|
||||||
(cl-union style whitespace-style)
|
(cl-union style whitespace-active-style)
|
||||||
`(face ,@style))))
|
style)))
|
||||||
(add-to-list 'whitespace-style 'face)
|
(cl-pushnew 'face whitespace-style)
|
||||||
(whitespace-mode +1)))
|
(whitespace-mode +1)))
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;;; General configuration
|
;;; General UX
|
||||||
|
|
||||||
(setq-default
|
;; Simpler confirmation prompt when killing Emacs
|
||||||
ansi-color-for-comint-mode t
|
(setq confirm-kill-emacs #'doom-quit-p)
|
||||||
bidi-display-reordering nil ; disable bidirectional text for tiny performance boost
|
|
||||||
blink-matching-paren nil ; don't blink--too distracting
|
(setq uniquify-buffer-name-style 'forward
|
||||||
compilation-always-kill t ; kill compilation process before starting another
|
;; no beeping or blinking please
|
||||||
compilation-ask-about-save nil ; save all buffers on `compile'
|
ring-bell-function #'ignore
|
||||||
compilation-scroll-output 'first-error
|
visible-bell nil)
|
||||||
confirm-nonexistent-file-or-buffer t
|
|
||||||
confirm-kill-emacs #'doom-quit-p ; custom confirmation when killing Emacs
|
;; middle-click paste at point, not at click
|
||||||
cursor-in-non-selected-windows nil ; hide cursors in other windows
|
(setq mouse-yank-at-point t)
|
||||||
custom-theme-directory (expand-file-name "themes/" doom-private-dir)
|
|
||||||
display-line-numbers-width 3
|
;; Enable mouse in terminal Emacs
|
||||||
echo-keystrokes 0.02
|
(add-hook 'tty-setup-hook #'xterm-mouse-mode)
|
||||||
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
|
;;; Scrolling
|
||||||
fringe-indicator-alist
|
|
||||||
(delq (assq 'continuation fringe-indicator-alist)
|
(setq hscroll-margin 2
|
||||||
fringe-indicator-alist)
|
hscroll-step 1
|
||||||
highlight-nonselected-windows nil
|
scroll-conservatively 10
|
||||||
image-animate-loop t
|
scroll-margin 0
|
||||||
indicate-buffer-boundaries nil
|
scroll-preserve-screen-position t
|
||||||
indicate-empty-lines nil
|
;; mouse
|
||||||
max-mini-window-height 0.3
|
mouse-wheel-scroll-amount '(5 ((shift) . 2))
|
||||||
mode-line-default-help-echo nil ; disable mode-line mouseovers
|
mouse-wheel-progressive-speed nil) ; don't accelerate scrolling
|
||||||
mouse-yank-at-point t ; middle-click paste at point, not at click
|
|
||||||
show-help-function nil ; hide :help-echo text
|
;; Remove hscroll-margin in shells, otherwise it causes jumpiness
|
||||||
use-dialog-box nil ; always avoid GUI
|
(setq-hook! '(eshell-mode-hook term-mode-hook) hscroll-margin 0)
|
||||||
uniquify-buffer-name-style 'forward
|
|
||||||
visible-cursor nil
|
(when IS-MAC
|
||||||
x-stretch-cursor nil
|
;; sane trackpad/mouse scroll settings
|
||||||
;; Favor vertical splits
|
(setq mac-redisplay-dont-reset-vscroll t
|
||||||
split-width-threshold 160
|
mac-mouse-wheel-smooth-scroll nil))
|
||||||
split-height-threshold nil
|
|
||||||
;; `pos-tip' defaults
|
|
||||||
pos-tip-internal-border-width 6
|
;;
|
||||||
pos-tip-border-width 1
|
;;; Cursor
|
||||||
;; no beeping or blinking please
|
|
||||||
ring-bell-function #'ignore
|
;; Don't blink the cursor, it's too distracting.
|
||||||
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)
|
(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)
|
|
||||||
|
|
||||||
;; Use `show-trailing-whitespace' instead of `whitespace-mode' because it's
|
;; Don't blink the paren matching the one at point, it's too distracting.
|
||||||
;; faster (implemented in C). But try to only enable it in editing buffers.
|
(setq blink-matching-paren nil)
|
||||||
(setq-default show-trailing-whitespace nil)
|
|
||||||
(setq-hook! '(prog-mode-hook text-mode-hook conf-mode-hook) show-trailing-whitespace t)
|
(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,
|
;; The native border "consumes" a pixel of the fringe on righter-most splits,
|
||||||
;; `window-divider' does not. Available since Emacs 25.1.
|
;; `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-bottom-width 1
|
||||||
window-divider-default-right-width 1)
|
window-divider-default-right-width 1)
|
||||||
(add-hook 'doom-init-ui-hook #'window-divider-mode)
|
(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
|
;;; 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
|
:defer t
|
||||||
:init
|
:init
|
||||||
(setq ediff-diff-options "-w" ; turn off whitespace checking
|
(setq ediff-diff-options "-w" ; turn off whitespace checking
|
||||||
|
@ -252,23 +379,21 @@ read-only or not file-visiting."
|
||||||
:config
|
:config
|
||||||
(defvar doom--ediff-saved-wconf nil)
|
(defvar doom--ediff-saved-wconf nil)
|
||||||
;; Restore window config after quitting ediff
|
;; Restore window config after quitting ediff
|
||||||
(defun doom|ediff-save-wconf ()
|
(add-hook! 'ediff-before-setup-hook
|
||||||
(setq doom--ediff-saved-wconf (current-window-configuration)))
|
(defun doom-ediff-save-wconf-h ()
|
||||||
(add-hook 'ediff-before-setup-hook #'doom|ediff-save-wconf)
|
(setq doom--ediff-saved-wconf (current-window-configuration))))
|
||||||
|
(add-hook! '(ediff-quit-hook ediff-suspend-hook) :append
|
||||||
(defun doom|ediff-restore-wconf ()
|
(defun doom-ediff-restore-wconf-h ()
|
||||||
(when (window-configuration-p doom--ediff-saved-wconf)
|
(when (window-configuration-p doom--ediff-saved-wconf)
|
||||||
(set-window-configuration 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))
|
|
||||||
|
|
||||||
|
|
||||||
(def-package! hl-line
|
(use-package! hl-line
|
||||||
;; Highlights the current line
|
;; Highlights the current line
|
||||||
:hook ((prog-mode text-mode conf-mode) . hl-line-mode)
|
:hook ((prog-mode text-mode conf-mode) . hl-line-mode)
|
||||||
:config
|
:config
|
||||||
;; I don't need hl-line showing in other windows. This also offers a small
|
;; Not having to render the hl-line overlay in multiple buffers offers a tiny
|
||||||
;; speed boost when buffer is displayed in multiple windows.
|
;; performance boost. I also don't need to see it in other buffers.
|
||||||
(setq hl-line-sticky-flag nil
|
(setq hl-line-sticky-flag nil
|
||||||
global-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.
|
;; selection region harder to see while in evil visual mode.
|
||||||
(after! evil
|
(after! evil
|
||||||
(defvar doom-buffer-hl-line-mode nil)
|
(defvar doom-buffer-hl-line-mode nil)
|
||||||
|
(add-hook! 'evil-visual-state-entry-hook
|
||||||
(defun doom|disable-hl-line ()
|
(defun doom-disable-hl-line-h ()
|
||||||
(when hl-line-mode
|
(when hl-line-mode
|
||||||
(setq-local doom-buffer-hl-line-mode t)
|
(setq-local doom-buffer-hl-line-mode t)
|
||||||
(hl-line-mode -1)))
|
(hl-line-mode -1))))
|
||||||
(add-hook 'evil-visual-state-entry-hook #'doom|disable-hl-line)
|
(add-hook! 'evil-visual-state-exit-hook
|
||||||
|
(defun doom-enable-hl-line-maybe-h ()
|
||||||
(defun doom|enable-hl-line-maybe ()
|
(when doom-buffer-hl-line-mode
|
||||||
(when doom-buffer-hl-line-mode
|
(hl-line-mode +1))))))
|
||||||
(hl-line-mode +1)))
|
|
||||||
(add-hook 'evil-visual-state-exit-hook #'doom|enable-hl-line-maybe)))
|
|
||||||
|
|
||||||
|
|
||||||
(def-package! winner
|
(use-package! winner
|
||||||
;; undo/redo changes to Emacs' window layout
|
;; 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)
|
:preface (defvar winner-dont-bind-my-keys t)
|
||||||
:config (winner-mode +1)) ; I'll bind keys myself
|
:config (winner-mode +1)) ; I'll bind keys myself
|
||||||
|
|
||||||
|
|
||||||
(def-package! paren
|
(use-package! paren
|
||||||
;; highlight matching delimiters
|
;; highlight matching delimiters
|
||||||
:after-call (after-find-file doom-switch-buffer-hook)
|
:after-call after-find-file doom-switch-buffer-hook
|
||||||
:config
|
:config
|
||||||
(setq show-paren-delay 0.1
|
(setq show-paren-delay 0.1
|
||||||
show-paren-highlight-openparen t
|
show-paren-highlight-openparen t
|
||||||
|
@ -316,56 +439,63 @@ read-only or not file-visiting."
|
||||||
(newline-mark ?\n [?¬ ?\n])
|
(newline-mark ?\n [?¬ ?\n])
|
||||||
(space-mark ?\ [?·] [?.])))
|
(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
|
;;; Third party packages
|
||||||
|
|
||||||
(def-package! all-the-icons
|
(use-package! all-the-icons
|
||||||
:commands (all-the-icons-octicon all-the-icons-faicon all-the-icons-fileicon
|
:commands (all-the-icons-octicon
|
||||||
all-the-icons-wicon all-the-icons-material all-the-icons-alltheicon)
|
all-the-icons-faicon
|
||||||
|
all-the-icons-fileicon
|
||||||
|
all-the-icons-wicon
|
||||||
|
all-the-icons-material
|
||||||
|
all-the-icons-alltheicon)
|
||||||
:init
|
:init
|
||||||
(defun doom*disable-all-the-icons-in-tty (orig-fn &rest args)
|
(defadvice! doom--disable-all-the-icons-in-tty-a (orig-fn &rest args)
|
||||||
(if (display-graphic-p)
|
"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)
|
||||||
|
(if (display-multi-font-p)
|
||||||
(apply orig-fn args)
|
(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
|
|
||||||
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)))
|
|
||||||
|
|
||||||
;;;###package hide-mode-line-mode
|
;;;###package hide-mode-line-mode
|
||||||
(add-hook 'completion-list-mode-hook #'hide-mode-line-mode)
|
(add-hook! '(completion-list-mode-hook Man-mode-hook)
|
||||||
(add-hook 'Man-mode-hook #'hide-mode-line-mode)
|
#'hide-mode-line-mode)
|
||||||
|
|
||||||
;; Better fontification of number literals in code
|
;; Better fontification of number literals in code
|
||||||
(def-package! highlight-numbers
|
(use-package! highlight-numbers
|
||||||
:hook ((prog-mode conf-mode) . highlight-numbers-mode)
|
:hook ((prog-mode conf-mode) . highlight-numbers-mode)
|
||||||
:config (setq highlight-numbers-generic-regexp "\\_<[[:digit:]]+\\(?:\\.[0-9]*\\)?\\_>"))
|
:config (setq highlight-numbers-generic-regexp "\\_<[[:digit:]]+\\(?:\\.[0-9]*\\)?\\_>"))
|
||||||
|
|
||||||
|
;;;###package image
|
||||||
|
(setq image-animate-loop t)
|
||||||
|
|
||||||
;;;###package rainbow-delimiters
|
;;;###package rainbow-delimiters
|
||||||
;; Helps us distinguish stacked delimiter pairs, especially in parentheses-drunk
|
;; Helps us distinguish stacked delimiter pairs, especially in parentheses-drunk
|
||||||
;; languages like Lisp.
|
;; languages like Lisp.
|
||||||
(setq rainbow-delimiters-max-face-count 3)
|
(setq rainbow-delimiters-max-face-count 3)
|
||||||
|
|
||||||
|
;;;###package pos-tip
|
||||||
|
(setq pos-tip-internal-border-width 6
|
||||||
|
pos-tip-border-width 1)
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;;; Line numbers
|
;;; Line numbers
|
||||||
|
|
||||||
|
(setq-default display-line-numbers-width 3)
|
||||||
|
|
||||||
;; line numbers in most modes
|
;; 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-enable-line-numbers-h () (display-line-numbers-mode +1))
|
||||||
(defun doom|disable-line-numbers () (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.
|
;; DEPRECATED `nlinum' is used for Emacs 25 users; 26+ has native line numbers.
|
||||||
(def-package! nlinum
|
(use-package! nlinum
|
||||||
;; Line number column. A faster (or equivalent, in the worst case) line number
|
;; Line number column. A faster (or equivalent, in the worst case) line number
|
||||||
;; plugin than `linum-mode'.
|
;; plugin than `linum-mode'.
|
||||||
:unless EMACS26+
|
:unless EMACS26+
|
||||||
|
@ -407,14 +537,14 @@ character that looks like a space that `whitespace-mode' won't affect.")
|
||||||
str))
|
str))
|
||||||
(setq nlinum-format-function #'doom-nlinum-format-fn)
|
(setq nlinum-format-function #'doom-nlinum-format-fn)
|
||||||
|
|
||||||
(defun doom|init-nlinum-width ()
|
(add-hook! 'nlinum-mode-hook
|
||||||
"Calculate line number column width beforehand (optimization)."
|
(defun doom-init-nlinum-width-h ()
|
||||||
(setq nlinum--width
|
"Calculate line number column width beforehand (optimization)."
|
||||||
(length (save-excursion (goto-char (point-max))
|
(setq nlinum--width
|
||||||
(format-mode-line "%l")))))
|
(length (save-excursion (goto-char (point-max))
|
||||||
(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
|
;; Fixes disappearing line numbers in nlinum and other quirks
|
||||||
:unless EMACS26+
|
:unless EMACS26+
|
||||||
:after nlinum
|
:after nlinum
|
||||||
|
@ -430,7 +560,7 @@ character that looks like a space that `whitespace-mode' won't affect.")
|
||||||
;; forces them to resize.
|
;; forces them to resize.
|
||||||
(add-hook 'after-setting-font-hook #'nlinum-hl-flush-all-windows))
|
(add-hook 'after-setting-font-hook #'nlinum-hl-flush-all-windows))
|
||||||
|
|
||||||
(def-package! nlinum-relative
|
(use-package! nlinum-relative
|
||||||
:unless EMACS26+
|
:unless EMACS26+
|
||||||
:defer t
|
:defer t
|
||||||
:config
|
:config
|
||||||
|
@ -441,7 +571,14 @@ character that looks like a space that `whitespace-mode' won't affect.")
|
||||||
;;
|
;;
|
||||||
;;; Theme & font
|
;;; 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.
|
"Loads fonts.
|
||||||
|
|
||||||
Fonts are specified by `doom-font', `doom-variable-pitch-font',
|
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)
|
((display-graphic-p)
|
||||||
(setq doom-font (face-attribute 'default :font))))
|
(setq doom-font (face-attribute 'default :font))))
|
||||||
(when doom-serif-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
|
(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)
|
((debug error)
|
||||||
(if (string-prefix-p "Font not available: " (error-message-string e))
|
(if (string-prefix-p "Font not available: " (error-message-string e))
|
||||||
(lwarn 'doom-ui :warning
|
(lwarn 'doom-ui :warning
|
||||||
|
@ -468,56 +607,61 @@ Fonts are specified by `doom-font', `doom-variable-pitch-font',
|
||||||
(font-get (caddr e) :family))
|
(font-get (caddr e) :family))
|
||||||
(signal 'doom-error e)))))
|
(signal 'doom-error e)))))
|
||||||
|
|
||||||
(defun doom|init-emoji-fonts (frame)
|
(defun doom-init-theme-h (&optional 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)
|
|
||||||
"Load the theme specified by `doom-theme' in FRAME."
|
"Load the theme specified by `doom-theme' in FRAME."
|
||||||
(when (and doom-theme (not (memq doom-theme custom-enabled-themes)))
|
(when (and doom-theme (not (memq doom-theme custom-enabled-themes)))
|
||||||
(with-selected-frame (or frame (selected-frame))
|
(with-selected-frame (or frame (selected-frame))
|
||||||
(let ((doom--prefer-theme-elc t))
|
(let ((doom--prefer-theme-elc t))
|
||||||
(load-theme doom-theme 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
|
;;; Bootstrap
|
||||||
|
|
||||||
(defun doom|init-ui ()
|
(defun doom-init-ui-h ()
|
||||||
"Initialize Doom's user interface by applying all its advice and hooks."
|
"Initialize Doom's user interface by applying all its advice and hooks."
|
||||||
(run-hook-wrapped 'doom-init-ui-hook #'doom-try-run-hook)
|
(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-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)
|
(add-hook 'after-change-major-mode-hook #'doom-highlight-non-default-indentation-h 'append)
|
||||||
|
|
||||||
;; Initialize custom switch-{buffer,window,frame} hooks:
|
;; Initialize custom switch-{buffer,window,frame} hooks:
|
||||||
;; + `doom-switch-buffer-hook'
|
;; + `doom-switch-buffer-hook'
|
||||||
;; + `doom-switch-window-hook'
|
;; + `doom-switch-window-hook'
|
||||||
;; + `doom-switch-frame-hook'
|
;; + `doom-switch-frame-hook'
|
||||||
(add-hook 'buffer-list-update-hook #'doom|run-switch-window-hooks)
|
(add-hook 'buffer-list-update-hook #'doom-run-switch-window-hooks-h)
|
||||||
(add-hook 'focus-in-hook #'doom|run-switch-frame-hooks)
|
(add-hook 'focus-in-hook #'doom-run-switch-frame-hooks-h)
|
||||||
(advice-add! '(switch-to-next-buffer switch-to-prev-buffer)
|
(dolist (fn '(switch-to-next-buffer switch-to-prev-buffer))
|
||||||
:around #'doom*run-switch-to-next-prev-buffer-hooks)
|
(advice-add fn :around #'doom-run-switch-to-next-prev-buffer-hooks-a))
|
||||||
(advice-add! '(switch-to-buffer display-buffer)
|
(dolist (fn '(switch-to-buffer display-buffer))
|
||||||
:around #'doom*run-switch-buffer-hooks))
|
(advice-add fn :around #'doom-run-switch-buffer-hooks-a)))
|
||||||
|
|
||||||
;; Apply `doom-theme'
|
;; Apply `doom-theme'
|
||||||
(add-hook (if (daemonp)
|
(add-hook 'doom-init-ui-hook #'doom-init-theme-h)
|
||||||
'after-make-frame-functions
|
|
||||||
'doom-init-ui-hook)
|
|
||||||
#'doom|init-theme)
|
|
||||||
;; Apply `doom-font' et co
|
;; Apply `doom-font' et co
|
||||||
(add-hook 'doom-after-init-modules-hook #'doom|init-fonts)
|
(add-hook 'doom-after-init-modules-hook #'doom-init-fonts-h)
|
||||||
;; 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 '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)
|
(unless (fboundp 'define-fringe-bitmap)
|
||||||
(defun define-fringe-bitmap (&rest _)))
|
(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
|
(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
|
"`whitespace-mode' inundates child frames with whitspace markers, so disable
|
||||||
it to fix all that visual noise."
|
it to fix all that visual noise."
|
||||||
(unless (frame-parameter nil 'parent-frame)
|
(unless (frame-parameter nil 'parent-frame)
|
||||||
(funcall orig-fn)))
|
(funcall orig-fn)))
|
||||||
(add-function :around whitespace-enable-predicate #'doom*disable-whitespace-mode-in-childframes)
|
(add-function :around whitespace-enable-predicate #'doom-disable-whitespace-mode-in-childframes-a))
|
||||||
|
|
||||||
(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)
|
|
||||||
|
|
||||||
;; Don't display messages in the minibuffer when using the minibuffer
|
;; Don't display messages in the minibuffer when using the minibuffer
|
||||||
(defmacro doom-silence-motion-key (command key)
|
(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 backward-delete-char "<backspace>")
|
||||||
(doom-silence-motion-key delete-char "<delete>")
|
(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)
|
(provide 'core-ui)
|
||||||
;;; core-ui.el ends here
|
;;; core-ui.el ends here
|
||||||
|
|
538
core/core.el
538
core/core.el
|
@ -1,9 +1,10 @@
|
||||||
;;; core.el --- the heart of the beast -*- lexical-binding: t; -*-
|
;;; core.el --- the heart of the beast -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
(eval-when-compile
|
(defvar doom-init-p nil
|
||||||
(and (version< emacs-version "25.3")
|
"Non-nil if Doom has been initialized.")
|
||||||
(error "Detected Emacs %s. Doom only supports Emacs 25.3 and higher"
|
|
||||||
emacs-version)))
|
(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)
|
(defvar doom-debug-mode (or (getenv "DEBUG") init-file-debug)
|
||||||
"If non-nil, Doom will log more.
|
"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
|
Use `doom/toggle-debug-mode' to toggle it. The --debug-init flag and setting the
|
||||||
DEBUG envvar will enable this at startup.")
|
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
|
;;; Constants
|
||||||
|
|
||||||
(defconst doom-version "2.0.9"
|
(defconst doom-version "2.0.9"
|
||||||
"Current version of Doom Emacs.")
|
"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-WINDOWS (memq system-type '(cygwin windows-nt ms-dos)))
|
||||||
(defconst IS-BSD (or IS-MAC (eq system-type 'berkeley-unix)))
|
(defconst IS-BSD (or IS-MAC (eq system-type 'berkeley-unix)))
|
||||||
|
|
||||||
|
;;; Directories/files
|
||||||
;;
|
|
||||||
(defvar doom-emacs-dir
|
(defvar doom-emacs-dir
|
||||||
(eval-when-compile (file-truename user-emacs-directory))
|
(eval-when-compile (file-truename user-emacs-directory))
|
||||||
"The path to the currently loaded .emacs.d directory. Must end with a slash.")
|
"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/")
|
(defvar doom-modules-dir (concat doom-emacs-dir "modules/")
|
||||||
"The root directory for Doom's modules. Must end with a slash.")
|
"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.
|
"Root directory for local storage.
|
||||||
|
|
||||||
Use this as a storage location for this system's installation of Doom Emacs.
|
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.")
|
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.
|
"Where package.el and quelpa plugins (and their caches) are stored.
|
||||||
|
|
||||||
Must end with a slash.")
|
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.")
|
whichever is found first. Must end in a slash.")
|
||||||
|
|
||||||
(defvar doom-autoload-file (concat doom-local-dir "autoloads.el")
|
(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
|
This file is responsible for informing Emacs where to find all of Doom's
|
||||||
autoloaded core functions (in core/autoload/*.el).")
|
autoloaded core functions (in core/autoload/*.el).")
|
||||||
|
|
||||||
(defvar doom-package-autoload-file (concat doom-local-dir "autoloads.pkg.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
|
This file is compiled from the autoloads files of all installed packages
|
||||||
combined.")
|
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
|
\(easily) be launched from the correct shell session (particularly for MacOS
|
||||||
users).")
|
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
|
;;; Custom error types
|
||||||
|
|
||||||
(define-error 'doom-error "Error in Doom Emacs core")
|
(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-hook-error "Error in a Doom startup hook" 'doom-error)
|
||||||
(define-error 'doom-autoload-error "Error in an autoloads file" 'doom-error)
|
(define-error 'doom-autoload-error "Error in an autoloads file" 'doom-error)
|
||||||
|
@ -144,111 +114,168 @@ Doom was setup, which may cause problems.")
|
||||||
(define-error 'doom-package-error "Error with packages" 'doom-error)
|
(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
|
;;; 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
|
;; UTF-8 as the default coding system
|
||||||
(when (fboundp 'set-charset-priority)
|
(when (fboundp 'set-charset-priority)
|
||||||
(set-charset-priority 'unicode)) ; pretty
|
(set-charset-priority 'unicode)) ; pretty
|
||||||
(prefer-coding-system 'utf-8) ; pretty
|
(prefer-coding-system 'utf-8) ; pretty
|
||||||
(setq locale-coding-system 'utf-8) ; please
|
(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
|
(unless IS-WINDOWS
|
||||||
(setq selection-coding-system 'utf-8)) ; with sugar on top
|
(setq selection-coding-system 'utf-8)) ; with sugar on top
|
||||||
|
|
||||||
(setq-default
|
;; Disable warnings from legacy advice system. They aren't useful, and we can't
|
||||||
ad-redefinition-action 'accept ; silence redefined function warnings
|
;; often do anything about them besides changing packages upstream
|
||||||
apropos-do-all t ; make `apropos' more useful
|
(setq ad-redefinition-action 'accept)
|
||||||
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
|
|
||||||
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
|
|
||||||
tls-checktrust gnutls-verify-error
|
|
||||||
tls-program (list "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")
|
|
||||||
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/")))
|
|
||||||
custom-file (concat doom-private-dir "init.el")
|
|
||||||
desktop-dirname (concat doom-etc-dir "desktop")
|
|
||||||
desktop-base-file-name "autosave"
|
|
||||||
desktop-base-lock-name "autosave-lock"
|
|
||||||
pcache-directory (concat doom-cache-dir "pcache/")
|
|
||||||
request-storage-directory (concat doom-cache-dir "request")
|
|
||||||
server-auth-dir (concat doom-cache-dir "server/")
|
|
||||||
shared-game-score-directory (concat doom-etc-dir "shared-game-score/")
|
|
||||||
tramp-auto-save-directory (concat doom-cache-dir "tramp-auto-save/")
|
|
||||||
tramp-backup-directory-alist backup-directory-alist
|
|
||||||
tramp-persistency-file-name (concat doom-cache-dir "tramp-persistency.el")
|
|
||||||
url-cache-directory (concat doom-cache-dir "url/")
|
|
||||||
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)
|
;; Make apropos omnipotent. It's more useful this way.
|
||||||
"If a `doom-file' symbol property exists on SYMBOL, use that instead of the
|
(setq apropos-do-all t)
|
||||||
original value of `symbol-file'."
|
|
||||||
(or (if (symbolp symbol) (get symbol 'doom-file))
|
;; Don't make a second case-insensitive pass over `auto-mode-alist'. If it has
|
||||||
(funcall orig-fn symbol type)))
|
;; to, it's our (the user's) failure. One case for all!
|
||||||
(advice-add #'symbol-file :around #'doom*symbol-file)
|
(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)
|
||||||
|
(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 '("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"))
|
||||||
|
|
||||||
|
;; 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")
|
||||||
|
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"
|
||||||
|
pcache-directory (concat doom-cache-dir "pcache/")
|
||||||
|
request-storage-directory (concat doom-cache-dir "request")
|
||||||
|
server-auth-dir (concat doom-cache-dir "server/")
|
||||||
|
shared-game-score-directory (concat doom-etc-dir "shared-game-score/")
|
||||||
|
tramp-auto-save-directory (concat doom-cache-dir "tramp-auto-save/")
|
||||||
|
tramp-backup-directory-alist backup-directory-alist
|
||||||
|
tramp-persistency-file-name (concat doom-cache-dir "tramp-persistency.el")
|
||||||
|
url-cache-directory (concat doom-cache-dir "url/")
|
||||||
|
url-configuration-directory (concat doom-etc-dir "url/")
|
||||||
|
gamegrid-user-score-file-directory (concat doom-etc-dir "games/"))
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;;; Minor mode version of `auto-mode-alist'
|
;;; Optimizations
|
||||||
|
|
||||||
(defvar doom-auto-minor-mode-alist '()
|
;; Disable bidirectional text rendering for a modest performance boost. Of
|
||||||
"Alist mapping filename patterns to corresponding minor mode functions, like
|
;; course, this renders Emacs unable to detect/display right-to-left languages
|
||||||
`auto-mode-alist'. All elements of this alist are checked, meaning you can
|
;; (sorry!), but for us left-to-right language speakers/writers, it's a boon.
|
||||||
enable multiple minor modes for the same regexp.")
|
(setq-default bidi-display-reordering 'left-to-right)
|
||||||
|
|
||||||
(defun doom|enable-minor-mode-maybe ()
|
;; Reduce rendering/line scan work for Emacs by not rendering cursors or regions
|
||||||
"Check file name against `doom-auto-minor-mode-alist'."
|
;; in non-focused windows.
|
||||||
(when (and buffer-file-name doom-auto-minor-mode-alist)
|
(setq-default cursor-in-non-selected-windows nil)
|
||||||
(let ((name buffer-file-name)
|
(setq highlight-nonselected-windows nil)
|
||||||
(remote-id (file-remote-p buffer-file-name))
|
|
||||||
(alist doom-auto-minor-mode-alist))
|
;; More performant rapid scrolling over unfontified regions. May cause brief
|
||||||
;; Remove backup-suffixes from file name.
|
;; spells of inaccurate fontification immediately after scrolling.
|
||||||
(setq name (file-name-sans-versions name))
|
(setq fast-but-imprecise-scrolling t)
|
||||||
;; Remove remote file name identification.
|
|
||||||
(when (and (stringp remote-id)
|
;; Resizing the Emacs frame can be a terribly expensive part of changing the
|
||||||
(string-match (regexp-quote remote-id) name))
|
;; font. By inhibiting this, we easily halve startup times with fonts that are
|
||||||
(setq name (substring name (match-end 0))))
|
;; larger than the system default.
|
||||||
(while (and alist (caar alist) (cdar alist))
|
(setq frame-inhibit-implied-resize t)
|
||||||
(if (string-match-p (caar alist) name)
|
|
||||||
(funcall (cdar alist) 1))
|
;; Don't ping things that look like domain names.
|
||||||
(setq alist (cdr alist))))))
|
(setq ffap-machine-p-known 'reject)
|
||||||
(add-hook 'find-file-hook #'doom|enable-minor-mode-maybe)
|
|
||||||
|
;; 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
|
;; 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
|
;; have run. If you want hook functions to be aware of these customizations, add
|
||||||
;; them to MODE-local-vars-hook instead.
|
;; 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 MODE-local-vars-hook after local variables are initialized."
|
||||||
(run-hook-wrapped (intern-soft (format "%s-local-vars-hook" major-mode))
|
(run-hook-wrapped (intern-soft (format "%s-local-vars-hook" major-mode))
|
||||||
#'doom-try-run-hook))
|
#'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
|
;; If `enable-local-variables' is disabled, then `hack-local-variables-hook' is
|
||||||
;; never triggered.
|
;; never triggered.
|
||||||
(defun doom|run-local-var-hooks-if-necessary ()
|
(defun doom-run-local-var-hooks-if-necessary-h ()
|
||||||
"Run `doom|run-local-var-hooks' if `enable-local-variables' is disabled."
|
"Run `doom-run-local-var-hooks-h' if `enable-local-variables' is disabled."
|
||||||
(unless enable-local-variables
|
(unless enable-local-variables
|
||||||
(doom|run-local-var-hooks)))
|
(doom-run-local-var-hooks-h)))
|
||||||
(add-hook 'after-change-major-mode-hook #'doom|run-local-var-hooks-if-necessary 'append)
|
(add-hook 'after-change-major-mode-hook
|
||||||
|
#'doom-run-local-var-hooks-if-necessary-h
|
||||||
(defun doom|create-non-existent-directories ()
|
'append)
|
||||||
"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)
|
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
|
@ -298,7 +319,7 @@ broken up into:
|
||||||
This is already done by the lang/org module, however.
|
This is already done by the lang/org module, however.
|
||||||
|
|
||||||
If you want to disable incremental loading altogether, either remove
|
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.")
|
`doom-incremental-first-idle-timer' to nil.")
|
||||||
|
|
||||||
(defvar doom-incremental-first-idle-timer 2
|
(defvar doom-incremental-first-idle-timer 2
|
||||||
|
@ -317,13 +338,19 @@ intervals."
|
||||||
(if (not now)
|
(if (not now)
|
||||||
(nconc doom-incremental-packages packages)
|
(nconc doom-incremental-packages packages)
|
||||||
(when packages
|
(when packages
|
||||||
(let ((gc-cons-threshold doom-gc-cons-upper-limit)
|
(let ((gc-cons-threshold most-positive-fixnum)
|
||||||
(reqs (cl-delete-if #'featurep packages))
|
(file-name-handler-alist nil)
|
||||||
file-name-handler-alist)
|
(reqs (cl-delete-if #'featurep packages)))
|
||||||
(when-let (req (if reqs (ignore-errors (pop reqs))))
|
(when-let (req (if reqs (pop reqs)))
|
||||||
(doom-log "Incrementally loading %s" req)
|
(doom-log "Incrementally loading %s" req)
|
||||||
(condition-case e
|
(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))
|
(push req reqs))
|
||||||
((error debug)
|
((error debug)
|
||||||
(message "Failed to load '%s' package incrementally, because: %s"
|
(message "Failed to load '%s' package incrementally, because: %s"
|
||||||
|
@ -334,7 +361,7 @@ intervals."
|
||||||
reqs t)
|
reqs t)
|
||||||
(doom-log "Finished incremental loading")))))))
|
(doom-log "Finished incremental loading")))))))
|
||||||
|
|
||||||
(defun doom|load-packages-incrementally ()
|
(defun doom-load-packages-incrementally-h ()
|
||||||
"Begin incrementally loading packages in `doom-incremental-packages'.
|
"Begin incrementally loading packages in `doom-incremental-packages'.
|
||||||
|
|
||||||
If this is a daemon session, load them all immediately instead."
|
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
|
nil #'doom-load-packages-incrementally
|
||||||
(cdr doom-incremental-packages) t))))
|
(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
|
;; return nil so `run-hook-wrapped' won't short circuit
|
||||||
nil)
|
nil)
|
||||||
|
|
||||||
(defun doom-ensure-same-emacs-version-p ()
|
(defun doom-display-benchmark-h (&optional return-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)
|
|
||||||
"Display a benchmark, showing number of packages and modules, and how quickly
|
"Display a benchmark, showing number of packages and modules, and how quickly
|
||||||
they were loaded at startup.
|
they were loaded at startup.
|
||||||
|
|
||||||
If RETURN-P, return the message as a string instead of displaying it."
|
If RETURN-P, return the message as a string instead of displaying it."
|
||||||
(funcall (if return-p #'format #'message)
|
(funcall (if return-p #'format #'message)
|
||||||
"Doom loaded %s packages across %d modules in %.03fs"
|
"Doom loaded %d packages across %d modules in %.03fs"
|
||||||
(length package-activated-list)
|
(- (length load-path) (length doom--initial-load-path))
|
||||||
(if doom-modules (hash-table-count doom-modules) 0)
|
(if doom-modules (hash-table-count doom-modules) 0)
|
||||||
(or doom-init-time
|
(or doom-init-time
|
||||||
(setq doom-init-time (float-time (time-subtract (current-time) before-init-time))))))
|
(setq doom-init-time (float-time (time-subtract (current-time) before-init-time))))))
|
||||||
|
|
||||||
(defun doom|run-all-startup-hooks ()
|
(defun doom-load-autoloads-file (file)
|
||||||
"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)
|
|
||||||
"Tries to load FILE (an autoloads file). Return t on success, throws an error
|
"Tries to load FILE (an autoloads file). Return t on success, throws an error
|
||||||
in interactive sessions, nil otherwise (but logs a warning)."
|
in interactive sessions, nil otherwise (but logs a warning)."
|
||||||
(condition-case e
|
(condition-case e
|
||||||
(load (file-name-sans-extension file) 'noerror 'nomessage)
|
(let (command-switch-alist)
|
||||||
|
(load (substring file 0 -3) 'noerror 'nomessage))
|
||||||
((debug error)
|
((debug error)
|
||||||
(if noninteractive
|
(if noninteractive
|
||||||
(message "Autoload file warning: %s -> %s" (car e) (error-message-string e))
|
(message "Autoload file warning: %s -> %s" (car e) (error-message-string e))
|
||||||
(signal 'doom-autoload-error (list (file-name-nondirectory file) 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."
|
"Read and set envvars in FILE."
|
||||||
(if (not (file-readable-p 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
|
(with-temp-buffer
|
||||||
(insert-file-contents file)
|
(insert-file-contents file)
|
||||||
(search-forward "\n\n" nil t)
|
(search-forward "\n\n" nil t)
|
||||||
|
@ -443,11 +431,12 @@ in interactive sessions, nil otherwise (but logs a warning)."
|
||||||
(line-beginning-position))
|
(line-beginning-position))
|
||||||
(point-max))))))
|
(point-max))))))
|
||||||
(setenv var value)))))
|
(setenv var value)))))
|
||||||
(setq exec-path (append (split-string (getenv "PATH")
|
(setq-default
|
||||||
(if IS-WINDOWS ";" ":"))
|
exec-path (append (split-string (getenv "PATH")
|
||||||
(list exec-directory))
|
(if IS-WINDOWS ";" ":"))
|
||||||
shell-file-name (or (getenv "SHELL")
|
(list exec-directory))
|
||||||
shell-file-name))
|
shell-file-name (or (getenv "SHELL")
|
||||||
|
shell-file-name))
|
||||||
t))
|
t))
|
||||||
|
|
||||||
(defun doom-initialize (&optional force-p)
|
(defun doom-initialize (&optional force-p)
|
||||||
|
@ -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'
|
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
|
for a list of all recognized module trees. Order defines precedence (from most
|
||||||
to least)."
|
to least)."
|
||||||
(add-to-list 'load-path doom-core-dir)
|
|
||||||
(require 'core-lib)
|
|
||||||
|
|
||||||
(when (or force-p (not doom-init-p))
|
(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
|
;; Reset as much state as possible, so `doom-initialize' can be treated like
|
||||||
(setq exec-path doom-site-exec-path
|
;; a reset function. Particularly useful for reloading the config.
|
||||||
load-path doom-site-load-path
|
(setq exec-path doom--initial-exec-path
|
||||||
process-environment doom-site-process-environment
|
load-path doom--initial-load-path
|
||||||
shell-file-name doom-site-shell-file-name)
|
process-environment doom--initial-process-environment)
|
||||||
|
|
||||||
;; `doom-autoload-file' tells Emacs where to load all its autoloaded
|
(require 'core-lib)
|
||||||
;; functions from. This includes everything in core/autoload/*.el and all
|
(require 'core-modules)
|
||||||
;; 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)
|
;; Load shell environment, optionally generated from 'doom env'
|
||||||
(doom-ensure-packages-initialized force-p)
|
(when (and (or (display-graphic-p)
|
||||||
(doom-ensure-core-packages)
|
(daemonp))
|
||||||
|
(file-exists-p doom-env-file))
|
||||||
|
(doom-load-envvars-file doom-env-file))
|
||||||
|
|
||||||
(unless (or force-p noninteractive)
|
(let (;; `doom-autoload-file' tells Emacs where to load all its functions
|
||||||
(user-error "Your doom autoloads are missing! Run `bin/doom refresh' to regenerate them")))
|
;; 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))))
|
||||||
|
|
||||||
;; Loads `doom-package-autoload-file', which loads a concatenated package
|
(if (and core-autoloads-p (not force-p))
|
||||||
;; autoloads file and caches `load-path', `auto-mode-alist',
|
;; In case we want to use package.el or straight via M-x
|
||||||
;; `Info-directory-list', `doom-disabled-packages' and
|
(progn
|
||||||
;; `package-activated-list'. A big reduction in startup time.
|
(with-eval-after-load 'package
|
||||||
(let (command-switch-alist)
|
(require 'core-packages))
|
||||||
(unless (or force-p
|
(with-eval-after-load 'straight
|
||||||
(doom-initialize-autoloads doom-package-autoload-file)
|
(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)
|
noninteractive)
|
||||||
(user-error "Your package autoloads are missing! Run `bin/doom refresh' to regenerate them")))
|
(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")))))
|
||||||
|
|
||||||
;; Load shell environment
|
(defun doom-initialize-core ()
|
||||||
(unless noninteractive
|
"Load Doom's core files for an interactive session."
|
||||||
(doom-load-env-vars doom-env-file)))
|
(require 'core-keybinds)
|
||||||
|
(require 'core-ui)
|
||||||
(require 'core-modules)
|
(require 'core-projects)
|
||||||
(require 'core-os)
|
(require 'core-editor))
|
||||||
(if noninteractive
|
|
||||||
(require 'core-cli)
|
|
||||||
(add-hook 'window-setup-hook #'doom|display-benchmark)
|
|
||||||
(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))
|
|
||||||
|
|
||||||
(provide 'core)
|
(provide 'core)
|
||||||
;;; core.el ends here
|
;;; core.el ends here
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
(/ size 1024))
|
(/ size 1024))
|
||||||
(explain! "Consider deleting it from your system (manually)"))))
|
(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")
|
(warn! "Couldn't find the `fd' binary; project file searches will be slightly slower")
|
||||||
(unless (executable-find "rg")
|
(unless (executable-find "rg")
|
||||||
(warn! "Couldn't find the `rg' binary either; project file searches will be even slower")))
|
(warn! "Couldn't find the `rg' binary either; project file searches will be even slower")))
|
||||||
|
|
|
@ -3,12 +3,7 @@
|
||||||
|
|
||||||
;; core.el
|
;; core.el
|
||||||
(package! dotenv-mode)
|
(package! dotenv-mode)
|
||||||
|
(package! auto-minor-mode)
|
||||||
;; core-os.el
|
|
||||||
(if (not IS-MAC)
|
|
||||||
(package! xclip)
|
|
||||||
(package! osx-clipboard)
|
|
||||||
(package! ns-auto-titlebar))
|
|
||||||
|
|
||||||
;; core-ui.el
|
;; core-ui.el
|
||||||
(package! all-the-icons)
|
(package! all-the-icons)
|
||||||
|
@ -26,10 +21,16 @@
|
||||||
(package! command-log-mode)
|
(package! command-log-mode)
|
||||||
(package! dtrt-indent)
|
(package! dtrt-indent)
|
||||||
(package! helpful)
|
(package! helpful)
|
||||||
|
(package! ns-auto-titlebar :ignore (not IS-MAC))
|
||||||
(package! pcre2el)
|
(package! pcre2el)
|
||||||
(package! smartparens)
|
(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! undo-tree)
|
||||||
(package! ws-butler)
|
(package! ws-butler)
|
||||||
|
(package! xclip :ignore IS-LINUX)
|
||||||
|
|
||||||
;; core-projects.el
|
;; core-projects.el
|
||||||
(package! projectile)
|
(package! projectile)
|
||||||
|
@ -37,13 +38,6 @@
|
||||||
;; core-keybinds.el
|
;; core-keybinds.el
|
||||||
(package! general)
|
(package! general)
|
||||||
(package! which-key)
|
(package! which-key)
|
||||||
(package! hydra)
|
|
||||||
|
|
||||||
;; core-packages.el
|
|
||||||
(package! gnu-elpa-keyring-update)
|
|
||||||
|
|
||||||
;; autoload/debug.el
|
;; autoload/debug.el
|
||||||
(package! esup)
|
(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
|
(doom! :completion
|
||||||
company
|
company
|
|
@ -62,13 +62,15 @@
|
||||||
(setq a (switch-to-buffer (get-buffer-create "a"))
|
(setq a (switch-to-buffer (get-buffer-create "a"))
|
||||||
b (get-buffer-create "b"))
|
b (get-buffer-create "b"))
|
||||||
(spy-on 'hook)
|
(spy-on 'hook)
|
||||||
(add-hook 'buffer-list-update-hook #'doom|run-switch-window-hooks)
|
(add-hook 'buffer-list-update-hook #'doom-run-switch-window-hooks-h)
|
||||||
(add-hook 'focus-in-hook #'doom|run-switch-frame-hooks)
|
(add-hook 'focus-in-hook #'doom-run-switch-frame-hooks-h)
|
||||||
(advice-add! '(switch-to-buffer display-buffer) :around #'doom*run-switch-buffer-hooks))
|
(dolist (fn '(switch-to-buffer display-buffer))
|
||||||
|
(advice-add fn :around #'doom-run-switch-buffer-hooks-a)))
|
||||||
(after-each
|
(after-each
|
||||||
(remove-hook 'buffer-list-update-hook #'doom|run-switch-window-hooks)
|
(remove-hook 'buffer-list-update-hook #'doom-run-switch-window-hooks-h)
|
||||||
(remove-hook 'focus-in-hook #'doom|run-switch-frame-hooks)
|
(remove-hook 'focus-in-hook #'doom-run-switch-frame-hooks-h)
|
||||||
(advice-remove! '(switch-to-buffer display-buffer) #'doom*run-switch-buffer-hooks)
|
(dolist (fn '(switch-to-buffer display-buffer))
|
||||||
|
(advice-remove fn #'doom-run-switch-buffer-hooks-a))
|
||||||
(kill-buffer a)
|
(kill-buffer a)
|
||||||
(kill-buffer b))
|
(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.
|
;; before package and UI initialization happens.
|
||||||
|
|
||||||
;; Defer garbage collection further back in the startup process
|
;; 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
|
;; In Emacs 27+, package initialization occurs before `user-init-file' is
|
||||||
;; loaded, but after `early-init-file'. Doom handles package
|
;; loaded, but after `early-init-file'. Doom handles package initialization, so
|
||||||
;; initialization, so we must prevent Emacs from doing it early!
|
;; we must prevent Emacs from doing it early!
|
||||||
(setq package-enable-at-startup nil)
|
(setq package-enable-at-startup nil)
|
||||||
|
|
||||||
;; Prevent the glimpse of un-styled Emacs by setting these early.
|
;; Prevent the glimpse of un-styled Emacs by disabling these UI elements early.
|
||||||
(add-to-list 'default-frame-alist '(tool-bar-lines . 0))
|
(push '(menu-bar-lines . 0) default-frame-alist)
|
||||||
(add-to-list 'default-frame-alist '(menu-bar-lines . 0))
|
(push '(tool-bar-lines . 0) default-frame-alist)
|
||||||
(add-to-list 'default-frame-alist '(vertical-scroll-bars))
|
(push '(vertical-scroll-bars) default-frame-alist)
|
||||||
|
|
||||||
;; One less file to load at startup
|
;; Resizing the Emacs frame can be a terribly expensive part of changing the
|
||||||
(setq site-run-file nil)
|
;; 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
|
;;; License: MIT
|
||||||
|
|
||||||
(defvar doom-gc-cons-threshold 16777216 ; 16mb
|
(when (version< emacs-version "25.3")
|
||||||
"The default value to use for `gc-cons-threshold'. If you experience freezing,
|
(error "Detected Emacs %s. Doom only supports Emacs 25.3 and higher"
|
||||||
decrease this. If you experience stuttering, increase this.")
|
emacs-version))
|
||||||
|
|
||||||
(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))
|
|
||||||
|
|
||||||
|
|
||||||
;; Ensure Doom is running out of this file's directory
|
;; Ensure Doom is running out of this file's directory
|
||||||
(setq user-emacs-directory (file-name-directory load-file-name))
|
(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
|
;; In noninteractive sessions, prioritize non-byte-compiled source files to
|
||||||
;; prevent stale, byte-compiled code from running. However, if you're getting
|
;; prevent the use of stale byte-code. Otherwise, it saves us a little IO time
|
||||||
;; recursive load errors, it may help to set this to nil.
|
;; to skip the mtime checks on every *.elc file we load.
|
||||||
(setq load-prefer-newer noninteractive)
|
(setq load-prefer-newer noninteractive)
|
||||||
|
|
||||||
|
;; Load the heart of Doom Emacs
|
||||||
;; Let 'er rip!
|
|
||||||
(require 'core (concat user-emacs-directory "core/core"))
|
(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; -*-
|
;;; init.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
;; Copy this file to ~/.doom.d/init.el or ~/.config/doom/init.el ('doom
|
;; Copy this file to ~/.doom.d/init.el or ~/.config/doom/init.el ('doom install'
|
||||||
;; quickstart' will do this for you). The `doom!' block below controls what
|
;; will do this for you). The `doom!' block below controls what modules are
|
||||||
;; modules are enabled and in what order they will be loaded. Remember to run
|
;; enabled and in what order they will be loaded. Remember to run 'doom refresh'
|
||||||
;; 'doom refresh' after modifying it.
|
;; after modifying it.
|
||||||
;;
|
;;
|
||||||
;; More information about these modules (and what flags they support) can be
|
;; More information about these modules (and what flags they support) can be
|
||||||
;; found in modules/README.org.
|
;; found in modules/README.org.
|
||||||
|
@ -24,7 +24,8 @@
|
||||||
doom-dashboard ; a nifty splash screen for Emacs
|
doom-dashboard ; a nifty splash screen for Emacs
|
||||||
doom-quit ; DOOM quit-message prompts when you quit Emacs
|
doom-quit ; DOOM quit-message prompts when you quit Emacs
|
||||||
;;fill-column ; a `fill-column' indicator
|
;;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
|
;;indent-guides ; highlighted indent columns
|
||||||
modeline ; snazzy, Atom-inspired modeline, plus API
|
modeline ; snazzy, Atom-inspired modeline, plus API
|
||||||
nav-flash ; blink the current line after jumping
|
nav-flash ; blink the current line after jumping
|
||||||
|
@ -34,8 +35,8 @@
|
||||||
+all ; catch all popups that start with an asterix
|
+all ; catch all popups that start with an asterix
|
||||||
+defaults) ; default popup rules
|
+defaults) ; default popup rules
|
||||||
;;pretty-code ; replace bits of code with pretty symbols
|
;;pretty-code ; replace bits of code with pretty symbols
|
||||||
;;tabbar ; FIXME an (incomplete) tab bar for Emacs
|
;;tabs ; an tab bar for Emacs
|
||||||
treemacs ; a project drawer, like neotree but cooler
|
;;treemacs ; a project drawer, like neotree but cooler
|
||||||
;;unicode ; extended unicode support for various languages
|
;;unicode ; extended unicode support for various languages
|
||||||
vc-gutter ; vcs diff in the fringe
|
vc-gutter ; vcs diff in the fringe
|
||||||
vi-tilde-fringe ; fringe tildes to mark beyond EOB
|
vi-tilde-fringe ; fringe tildes to mark beyond EOB
|
||||||
|
@ -53,12 +54,10 @@
|
||||||
;;parinfer ; turn lisp into python, sort of
|
;;parinfer ; turn lisp into python, sort of
|
||||||
rotate-text ; cycle region at point between text candidates
|
rotate-text ; cycle region at point between text candidates
|
||||||
snippets ; my elves. They type so I don't have to
|
snippets ; my elves. They type so I don't have to
|
||||||
|
;;word-wrap ; soft wrapping with language-aware indent
|
||||||
|
|
||||||
:emacs
|
:emacs
|
||||||
(dired ; making dired pretty [functional]
|
dired ; making dired pretty [functional]
|
||||||
;;+ranger ; bringing the goodness of ranger to dired
|
|
||||||
;;+icons ; colorful icons for dired-mode
|
|
||||||
)
|
|
||||||
electric ; smarter, keyword-based electric-indent
|
electric ; smarter, keyword-based electric-indent
|
||||||
vc ; version-control and Emacs, sitting in a tree
|
vc ; version-control and Emacs, sitting in a tree
|
||||||
|
|
||||||
|
@ -159,17 +158,13 @@
|
||||||
;; should be loaded late.
|
;; should be loaded late.
|
||||||
:app
|
:app
|
||||||
;;calendar
|
;;calendar
|
||||||
;;irc ; how neckbeards socialize
|
;;irc ; how neckbeards socialize
|
||||||
;;(rss +org) ; emacs as an RSS reader
|
;;(rss +org) ; emacs as an RSS reader
|
||||||
;;twitter ; twitter client https://twitter.com/vnought
|
;;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
|
;; +wordnut ; wordnet (wn) search
|
||||||
;; +langtool) ; a proofreader (grammar/style check) for Emacs
|
;; +langtool) ; a proofreader (grammar/style check) for Emacs
|
||||||
|
|
||||||
:collab
|
|
||||||
;;floobits ; peer programming for a price
|
|
||||||
;;impatient-mode ; show off code over HTTP
|
|
||||||
|
|
||||||
:config
|
:config
|
||||||
;; For literate config users. This will tangle+compile a config.org
|
;; For literate config users. This will tangle+compile a config.org
|
||||||
;; literate config in your `doom-private-dir' whenever it changes.
|
;; literate config in your `doom-private-dir' whenever it changes.
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
- [[#lang][:lang]]
|
- [[#lang][:lang]]
|
||||||
- [[#email][:email]]
|
- [[#email][:email]]
|
||||||
- [[#app][:app]]
|
- [[#app][:app]]
|
||||||
- [[#collab][:collab]]
|
|
||||||
- [[#config][:config]]
|
- [[#config][:config]]
|
||||||
|
|
||||||
* :completion
|
* :completion
|
||||||
|
@ -38,7 +37,7 @@ Aesthetic modules that affect the Emacs interface or user experience.
|
||||||
+ [[file:ui/ophints/README.org][ophints]]:
|
+ [[file:ui/ophints/README.org][ophints]]:
|
||||||
+ [[file:ui/popup/README.org][popup]] =+all +defaults=: Makes temporary/disposable windows less intrusive
|
+ [[file:ui/popup/README.org][popup]] =+all +defaults=: Makes temporary/disposable windows less intrusive
|
||||||
+ pretty-code:
|
+ pretty-code:
|
||||||
+ [[file:ui/tabbar/README.org][tabbar]]:
|
+ [[file:ui/tabs/README.org][tabs]]:
|
||||||
+ treemacs:
|
+ treemacs:
|
||||||
+ [[file:ui/unicode/README.org][unicode]]:
|
+ [[file:ui/unicode/README.org][unicode]]:
|
||||||
+ vc-gutter:
|
+ vc-gutter:
|
||||||
|
@ -58,6 +57,7 @@ Modules that affect and augment your ability to manipulate or insert text.
|
||||||
+ [[file:editor/parinfer/README.org][parinfer]]:
|
+ [[file:editor/parinfer/README.org][parinfer]]:
|
||||||
+ rotate-text:
|
+ rotate-text:
|
||||||
+ [[file:editor/snippets/README.org][snippets]]: Snippet expansion for lazy typists
|
+ [[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
|
* :emacs
|
||||||
Modules that reconfigure or augment packages or features built into 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:
|
+ ansible:
|
||||||
+ debugger: A (nigh-)universal debugger in Emacs
|
+ debugger: A (nigh-)universal debugger in Emacs
|
||||||
+ [[file:tools/docker/README.org][docker]]:
|
+ [[file:tools/docker/README.org][docker]]:
|
||||||
|
+ [[file:tools/direnv/README.org][direnv]]:
|
||||||
+ [[file:tools/editorconfig/README.org][editorconfig]]:
|
+ [[file:tools/editorconfig/README.org][editorconfig]]:
|
||||||
+ [[file:tools/ein/README.org][ein]]:
|
+ [[file:tools/ein/README.org][ein]]:
|
||||||
+ [[file:tools/eval/README.org][eval]]: REPL & code evaluation support for a variety of languages
|
+ [[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:
|
+ qt:
|
||||||
+ racket:
|
+ racket:
|
||||||
+ [[file:lang/rest/README.org][rest]]:
|
+ [[file:lang/rest/README.org][rest]]:
|
||||||
+ ruby =+lsp=:
|
+ ruby =+lsp +rvm +rbenv=:
|
||||||
+ [[file:lang/rust/README.org][rust]] =+lsp=:
|
+ [[file:lang/rust/README.org][rust]] =+lsp=:
|
||||||
+ scala:
|
+ scala:
|
||||||
+ [[file:lang/sh/README.org][sh]] =+fish +lsp=:
|
+ [[file:lang/sh/README.org][sh]] =+fish +lsp=:
|
||||||
|
@ -166,12 +167,6 @@ Doom-specific porcelains.
|
||||||
+ twitter:
|
+ twitter:
|
||||||
+ [[file:app/write/README.org][write]] =+wordnut +langtool=:
|
+ [[file:app/write/README.org][write]] =+wordnut +langtool=:
|
||||||
|
|
||||||
* :collab
|
|
||||||
Modules that enable collaborative programming over the internet.
|
|
||||||
|
|
||||||
+ floobits:
|
|
||||||
+ impatient-mode:
|
|
||||||
|
|
||||||
* :config
|
* :config
|
||||||
Modules that configure Emacs one way or another, or focus on making it easier
|
Modules that configure Emacs one way or another, or focus on making it easier
|
||||||
for you to customize it yourself.
|
for you to customize it yourself.
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
)))
|
)))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun +calendar*cfw:render-button (title command &optional state)
|
(defun +calendar-cfw:render-button-a (title command &optional state)
|
||||||
"render-button
|
"render-button
|
||||||
TITLE
|
TITLE
|
||||||
COMMAND
|
COMMAND
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
;;
|
;;
|
||||||
;; Packages
|
;; Packages
|
||||||
|
|
||||||
(def-package! calfw
|
(use-package! calfw
|
||||||
:commands (cfw:open-calendar-buffer)
|
:commands cfw:open-calendar-buffer
|
||||||
:config
|
:config
|
||||||
;; better frame for calendar
|
;; better frame for calendar
|
||||||
(setq cfw:face-item-separator-color nil
|
(setq cfw:face-item-separator-color nil
|
||||||
|
@ -24,20 +24,20 @@
|
||||||
|
|
||||||
(define-key cfw:calendar-mode-map "q" #'+calendar/quit)
|
(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)
|
(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
|
:commands (cfw:open-org-calendar
|
||||||
cfw:org-create-source
|
cfw:org-create-source
|
||||||
cfw:open-org-calendar-withkevin
|
cfw:open-org-calendar-withkevin
|
||||||
my-open-calendar))
|
my-open-calendar))
|
||||||
|
|
||||||
|
|
||||||
(def-package! org-gcal
|
(use-package! org-gcal
|
||||||
:commands (org-gcal-sync
|
:commands (org-gcal-sync
|
||||||
org-gcal-fetch
|
org-gcal-fetch
|
||||||
org-gcal-post-at-point
|
org-gcal-post-at-point
|
||||||
|
@ -48,4 +48,4 @@
|
||||||
(message "org-gcal::%s - %s" title mes)))
|
(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)
|
(interactive)
|
||||||
(when (derived-mode-p 'circe-mode)
|
(when (derived-mode-p 'circe-mode)
|
||||||
(tracking-next-buffer)))
|
(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
|
;; Packages
|
||||||
|
|
||||||
(def-package! circe
|
(use-package! circe
|
||||||
:commands (circe circe-server-buffers)
|
:commands circe circe-server-buffers
|
||||||
:init (setq circe-network-defaults nil)
|
:init (setq circe-network-defaults nil)
|
||||||
:config
|
:config
|
||||||
(setq circe-default-quit-message nil
|
(setq circe-default-quit-message nil
|
||||||
|
@ -90,48 +90,32 @@ playback.")
|
||||||
circe-format-server-lurker-activity
|
circe-format-server-lurker-activity
|
||||||
(+irc--pad "Lurk" "{nick} joined {joindelta} ago"))
|
(+irc--pad "Lurk" "{nick} joined {joindelta} ago"))
|
||||||
|
|
||||||
(add-hook 'circe-channel-mode-hook #'turn-on-visual-line-mode)
|
|
||||||
|
|
||||||
(defun +irc*circe-disconnect-hook (&rest _)
|
|
||||||
(run-hooks '+irc-disconnect-hook))
|
|
||||||
(advice-add 'circe--irc-conn-disconnected :after #'+irc*circe-disconnect-hook)
|
|
||||||
|
|
||||||
(defun +irc*circe-truncate-nicks ()
|
|
||||||
"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)
|
|
||||||
(let ((end (next-single-property-change beg 'lui-format-argument))
|
|
||||||
(nick (plist-get (plist-get (text-properties-at beg) 'lui-keywords)
|
|
||||||
: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)
|
|
||||||
|
|
||||||
(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)
|
(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-message-option-bot (nick &rest ignored)
|
(defadvice! +irc--circe-run-disconnect-hook-a (&rest _)
|
||||||
"Fontify known bots and mark them to not be tracked."
|
"Runs `+irc-disconnect-hook' after circe disconnects."
|
||||||
(when (member nick +irc-bot-list)
|
:after #'circe--irc-conn-disconnected
|
||||||
'((text-properties . (face circe-fool-face lui-do-not-track t)))))
|
(run-hooks '+irc-disconnect-hook))
|
||||||
(add-hook 'circe-message-option-functions #'+irc|circe-message-option-bot)
|
|
||||||
|
|
||||||
(defun +irc|add-circe-buffer-to-persp ()
|
(add-hook! 'lui-pre-output-hook
|
||||||
(let ((persp (get-current-persp))
|
(defun +irc-circe-truncate-nicks-h ()
|
||||||
(buf (current-buffer)))
|
"Truncate long nicknames in chat output non-destructively."
|
||||||
;; Add a new circe buffer to irc workspace when we're in another workspace
|
(when-let (beg (text-property-any (point-min) (point-max) 'lui-format-argument 'nick))
|
||||||
(unless (eq (safe-persp-name persp) +irc--workspace-name)
|
(goto-char beg)
|
||||||
;; Add new circe buffers to the persp containing circe buffers
|
(let ((end (next-single-property-change beg 'lui-format-argument))
|
||||||
(persp-add-buffer buf (persp-get-by-name +irc--workspace-name))
|
(nick (plist-get (plist-get (text-properties-at beg) 'lui-keywords)
|
||||||
;; Remove new buffer from accidental workspace
|
:nick)))
|
||||||
(persp-remove-buffer buf persp))))
|
(when (> (length nick) +irc-left-padding)
|
||||||
(add-hook 'circe-mode-hook #'+irc|add-circe-buffer-to-persp)
|
(compose-region (+ beg +irc-left-padding -1) end
|
||||||
|
+irc-truncate-nick-char))))))
|
||||||
|
|
||||||
|
(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))))))
|
||||||
|
|
||||||
;; Let `+irc/quit' and `circe' handle buffer cleanup
|
;; Let `+irc/quit' and `circe' handle buffer cleanup
|
||||||
(define-key circe-mode-map [remap kill-buffer] #'bury-buffer)
|
(define-key circe-mode-map [remap kill-buffer] #'bury-buffer)
|
||||||
|
@ -152,14 +136,14 @@ playback.")
|
||||||
"n" #'circe-command-NAMES)))
|
"n" #'circe-command-NAMES)))
|
||||||
|
|
||||||
|
|
||||||
(def-package! circe-color-nicks
|
(use-package! circe-color-nicks
|
||||||
:hook (circe-channel-mode . enable-circe-color-nicks)
|
:hook (circe-channel-mode . enable-circe-color-nicks)
|
||||||
:config
|
:config
|
||||||
(setq circe-color-nicks-min-constrast-ratio 4.5
|
(setq circe-color-nicks-min-constrast-ratio 4.5
|
||||||
circe-color-nicks-everywhere t))
|
circe-color-nicks-everywhere t))
|
||||||
|
|
||||||
|
|
||||||
(def-package! circe-new-day-notifier
|
(use-package! circe-new-day-notifier
|
||||||
:after circe
|
:after circe
|
||||||
:config
|
:config
|
||||||
(enable-circe-new-day-notifier)
|
(enable-circe-new-day-notifier)
|
||||||
|
@ -167,7 +151,7 @@ playback.")
|
||||||
(+irc--pad "Day" "Date changed [{day}]")))
|
(+irc--pad "Day" "Date changed [{day}]")))
|
||||||
|
|
||||||
|
|
||||||
(def-package! circe-notifications
|
(use-package! circe-notifications
|
||||||
:commands enable-circe-notifications
|
:commands enable-circe-notifications
|
||||||
:init
|
:init
|
||||||
(if +irc-defer-notifications
|
(if +irc-defer-notifications
|
||||||
|
@ -181,10 +165,11 @@ playback.")
|
||||||
circe-notifications-emacs-focused nil
|
circe-notifications-emacs-focused nil
|
||||||
circe-notifications-alert-style
|
circe-notifications-alert-style
|
||||||
(cond (IS-MAC 'osx-notifier)
|
(cond (IS-MAC 'osx-notifier)
|
||||||
(IS-LINUX 'libnotify))))
|
(IS-LINUX 'libnotify)
|
||||||
|
(circe-notifications-alert-style))))
|
||||||
|
|
||||||
|
|
||||||
(def-package! lui
|
(use-package! lui
|
||||||
:commands lui-mode
|
:commands lui-mode
|
||||||
:config
|
:config
|
||||||
(define-key lui-mode-map "\C-u" #'lui-kill-to-beginning-of-line)
|
(define-key lui-mode-map "\C-u" #'lui-kill-to-beginning-of-line)
|
||||||
|
@ -194,20 +179,21 @@ playback.")
|
||||||
(setq lui-flyspell-p t))
|
(setq lui-flyspell-p t))
|
||||||
|
|
||||||
(after! evil
|
(after! evil
|
||||||
(defun +irc|evil-insert ()
|
(defun +irc-evil-insert-h ()
|
||||||
"Ensure entering insert mode will put us at the prompt, unless editing
|
"Ensure entering insert mode will put us at the prompt, unless editing
|
||||||
after prompt marker."
|
after prompt marker."
|
||||||
(when (> (marker-position lui-input-marker) (point))
|
(when (> (marker-position lui-input-marker) (point))
|
||||||
(goto-char (point-max))))
|
(goto-char (point-max))))
|
||||||
|
|
||||||
(add-hook! 'lui-mode-hook
|
(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))
|
(mapc (lambda (cmd) (push cmd +irc-scroll-to-bottom-on-commands))
|
||||||
'(evil-paste-after evil-paste-before evil-open-above evil-open-below)))
|
'(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.
|
"Go to the end of the buffer in all windows showing it.
|
||||||
Courtesy of esh-mode.el"
|
Courtesy of esh-mode.el"
|
||||||
(when (memq this-command +irc-scroll-to-bottom-on-commands)
|
(when (memq this-command +irc-scroll-to-bottom-on-commands)
|
||||||
|
@ -224,28 +210,26 @@ Courtesy of esh-mode.el"
|
||||||
nil t)))))
|
nil t)))))
|
||||||
|
|
||||||
(add-hook! 'lui-mode-hook
|
(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
|
;; 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
|
||||||
(setq lui-time-stamp-position 'right-margin
|
(defun +irc-init-lui-margins-h ()
|
||||||
lui-time-stamp-format +irc-time-stamp-format
|
(setq lui-time-stamp-position 'right-margin
|
||||||
right-margin-width (length (format-time-string lui-time-stamp-format))))
|
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
|
(setq fringes-outside-margins t
|
||||||
word-wrap t
|
word-wrap t
|
||||||
wrap-prefix (make-string (+ +irc-left-padding 3) ? )))
|
wrap-prefix (make-string (+ +irc-left-padding 3) ? )))))
|
||||||
|
|
||||||
(add-hook! 'lui-mode-hook #'(+irc|init-lui-margins +irc|init-lui-wrapping)))
|
|
||||||
|
|
||||||
|
|
||||||
(def-package! lui-logging
|
(use-package! lui-logging
|
||||||
:after lui
|
:after lui
|
||||||
:config (enable-lui-logging))
|
:config (enable-lui-logging))
|
||||||
|
|
||||||
|
|
||||||
(def-package! lui-autopaste
|
(use-package! lui-autopaste
|
||||||
:hook (circe-channel-mode . enable-lui-autopaste))
|
:hook (circe-channel-mode . enable-lui-autopaste))
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
;; Hooks
|
;; Hooks
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun +rss|elfeed-wrap ()
|
(defun +rss-elfeed-wrap-h ()
|
||||||
"Enhances an elfeed entry's readability by wrapping it to a width of
|
"Enhances an elfeed entry's readability by wrapping it to a width of
|
||||||
`fill-column'."
|
`fill-column'."
|
||||||
(let ((inhibit-read-only t)
|
(let ((inhibit-read-only t)
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
(set-buffer-modified-p nil)))
|
(set-buffer-modified-p nil)))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun +rss|cleanup ()
|
(defun +rss-cleanup-h ()
|
||||||
"Clean up after an elfeed session. Kills all elfeed and elfeed-org files."
|
"Clean up after an elfeed session. Kills all elfeed and elfeed-org files."
|
||||||
(interactive)
|
(interactive)
|
||||||
;; `delete-file-projectile-remove-from-cache' slows down `elfeed-db-compact'
|
;; `delete-file-projectile-remove-from-cache' slows down `elfeed-db-compact'
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
(kill-buffer buf)))
|
(kill-buffer buf)))
|
||||||
(dolist (b search-buffers)
|
(dolist (b search-buffers)
|
||||||
(with-current-buffer b
|
(with-current-buffer b
|
||||||
(remove-hook 'kill-buffer-hook #'+rss|cleanup :local)
|
(remove-hook 'kill-buffer-hook #'+rss-cleanup-h :local)
|
||||||
(kill-buffer b)))
|
(kill-buffer b)))
|
||||||
(mapc #'kill-buffer show-buffers)))
|
(mapc #'kill-buffer show-buffers)))
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@
|
||||||
collect url)))
|
collect url)))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun +rss-put-sliced-image (spec alt &optional flags)
|
(defun +rss-put-sliced-image-fn (spec alt &optional flags)
|
||||||
"TODO"
|
"TODO"
|
||||||
(cl-letf (((symbol-function #'insert-image)
|
(cl-letf (((symbol-function #'insert-image)
|
||||||
(lambda (image &optional alt _area _slice)
|
(lambda (image &optional alt _area _slice)
|
||||||
|
@ -108,7 +108,7 @@
|
||||||
(shr-put-image spec alt flags)))
|
(shr-put-image spec alt flags)))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun +rss-render-image-tag-without-underline (dom &optional url)
|
(defun +rss-render-image-tag-without-underline-fn (dom &optional url)
|
||||||
"TODO"
|
"TODO"
|
||||||
(let ((start (point)))
|
(let ((start (point)))
|
||||||
(shr-tag-img dom url)
|
(shr-tag-img dom url)
|
||||||
|
|
|
@ -19,7 +19,7 @@ easier to scroll through.")
|
||||||
;;
|
;;
|
||||||
;; Packages
|
;; Packages
|
||||||
|
|
||||||
(def-package! elfeed
|
(use-package! elfeed
|
||||||
:commands elfeed
|
:commands elfeed
|
||||||
:config
|
:config
|
||||||
(setq elfeed-search-filter "@2-week-ago "
|
(setq elfeed-search-filter "@2-week-ago "
|
||||||
|
@ -36,21 +36,21 @@ easier to scroll through.")
|
||||||
(make-directory elfeed-db-directory t)
|
(make-directory elfeed-db-directory t)
|
||||||
|
|
||||||
;; Ensure elfeed buffers are treated as real
|
;; Ensure elfeed buffers are treated as real
|
||||||
(defun +rss-buffer-p (buf)
|
(add-hook! 'doom-real-buffer-functions
|
||||||
(string-match-p "^\\*elfeed" (buffer-name buf)))
|
(defun +rss-buffer-p (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
|
;; 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! '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
|
;; Large images are annoying to scroll through, because scrolling follows the
|
||||||
;; cursor, so we force shr to insert images in slices.
|
;; cursor, so we force shr to insert images in slices.
|
||||||
(when +rss-enable-sliced-images
|
(when +rss-enable-sliced-images
|
||||||
(setq-hook! 'elfeed-show-mode-hook
|
(setq-hook! 'elfeed-show-mode-hook
|
||||||
shr-put-image-function #'+rss-put-sliced-image
|
shr-put-image-function #'+rss-put-sliced-image-fn
|
||||||
shr-external-rendering-functions '((img . +rss-render-image-tag-without-underline))))
|
shr-external-rendering-functions '((img . +rss-render-image-tag-without-underline-fn))))
|
||||||
|
|
||||||
;; Keybindings
|
;; Keybindings
|
||||||
(after! elfeed-show
|
(after! elfeed-show
|
||||||
|
@ -64,11 +64,11 @@ easier to scroll through.")
|
||||||
(kbd "M-RET") #'elfeed-search-browse-url)))
|
(kbd "M-RET") #'elfeed-search-browse-url)))
|
||||||
|
|
||||||
|
|
||||||
(def-package! elfeed-org
|
(use-package! elfeed-org
|
||||||
:when (featurep! +org)
|
:when (featurep! +org)
|
||||||
:after elfeed
|
:after elfeed
|
||||||
:config
|
:config
|
||||||
(setq rmh-elfeed-org-files
|
(let ((default-directory org-directory))
|
||||||
(let ((default-directory org-directory))
|
(setq rmh-elfeed-org-files
|
||||||
(mapcar #'expand-file-name +rss-elfeed-files)))
|
(mapcar #'expand-file-name +rss-elfeed-files)))
|
||||||
(elfeed-org))
|
(elfeed-org))
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
"The name to use for the twitter workspace.")
|
"The name to use for the twitter workspace.")
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun +twitter-display-buffer (buf)
|
(defun +twitter-display-buffer-fn (buf)
|
||||||
"A replacement display-buffer command for `twittering-pop-to-buffer-function'
|
"A replacement display-buffer command for `twittering-pop-to-buffer-function'
|
||||||
that works with the feature/popup module."
|
that works with the feature/popup module."
|
||||||
(let ((win (selected-window)))
|
(let ((win (selected-window)))
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
;;; app/twitter/config.el -*- lexical-binding: t; -*-
|
;;; app/twitter/config.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
(def-package! twittering-mode
|
(use-package! twittering-mode
|
||||||
:commands twit
|
:commands twit
|
||||||
:config
|
: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-use-master-password t
|
||||||
twittering-request-confirmation-on-posting t
|
twittering-request-confirmation-on-posting t
|
||||||
;; twittering-icon-mode t
|
;; twittering-icon-mode t
|
||||||
|
@ -35,24 +36,16 @@
|
||||||
|
|
||||||
(add-hook 'doom-real-buffer-functions #'+twitter-buffer-p)
|
(add-hook 'doom-real-buffer-functions #'+twitter-buffer-p)
|
||||||
(when (featurep! :ui popup)
|
(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
|
(after! solaire-mode
|
||||||
(add-hook 'twittering-mode-hook #'solaire-mode))
|
(add-hook 'twittering-mode-hook #'solaire-mode))
|
||||||
|
|
||||||
;; Custom header-line for twitter buffers
|
;; Custom header-line for twitter buffers
|
||||||
(defun +twitter|switch-mode-and-header-line ()
|
(add-hook! 'twittering-mode-hook
|
||||||
(setq header-line-format mode-line-format
|
(defun +twitter-switch-mode-and-header-line-h ()
|
||||||
mode-line-format nil))
|
(setq header-line-format mode-line-format
|
||||||
(add-hook 'twittering-mode-hook #'+twitter|switch-mode-and-header-line)
|
mode-line-format nil)))
|
||||||
|
|
||||||
(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))))
|
|
||||||
|
|
||||||
;; `epa--decode-coding-string' isn't defined in later versions of Emacs 27
|
;; `epa--decode-coding-string' isn't defined in later versions of Emacs 27
|
||||||
(unless (fboundp 'epa--decode-coding-string)
|
(unless (fboundp 'epa--decode-coding-string)
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
;;
|
;;
|
||||||
;; Packages
|
;; Packages
|
||||||
|
|
||||||
(def-package! langtool
|
(use-package! langtool
|
||||||
:when (featurep! +langtool)
|
:when (featurep! +langtool)
|
||||||
:commands (langtool-check
|
:commands (langtool-check
|
||||||
langtool-check-done
|
langtool-check-done
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
(locate-file "libexec/languagetool-commandline.jar"
|
(locate-file "libexec/languagetool-commandline.jar"
|
||||||
(doom-files-in "/usr/local/Cellar/languagetool"
|
(doom-files-in "/usr/local/Cellar/languagetool"
|
||||||
:type 'dirs
|
:type 'dirs
|
||||||
:depth 1)))
|
:depth 2)))
|
||||||
(IS-LINUX
|
(IS-LINUX
|
||||||
"/usr/share/java/languagetool/languagetool-commandline.jar")))))
|
"/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
|
;;; Hooks
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun +company|init-backends ()
|
(defun +company-init-backends-h ()
|
||||||
"Set `company-backends' for the current buffer."
|
"Set `company-backends' for the current buffer."
|
||||||
(if (not company-mode)
|
(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)
|
(unless (eq major-mode 'fundamental-mode)
|
||||||
(setq-local company-backends (+company--backends)))
|
(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
|
(`candidates
|
||||||
(all-completions
|
(all-completions
|
||||||
arg
|
arg
|
||||||
(split-string
|
(delete-dups
|
||||||
(replace-regexp-in-string
|
(split-string
|
||||||
"^[\t\s]+" ""
|
(replace-regexp-in-string
|
||||||
(concat (buffer-substring-no-properties (point-min) (line-beginning-position))
|
"^[\t\s]+" ""
|
||||||
(buffer-substring-no-properties (line-end-position) (point-max))))
|
(concat (buffer-substring-no-properties (point-min) (line-beginning-position))
|
||||||
"\\(\r\n\\|[\n\r]\\)" t)))))
|
(buffer-substring-no-properties (line-end-position) (point-max))))
|
||||||
|
"\\(\r\n\\|[\n\r]\\)" t))))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun +company/dict-or-keywords ()
|
(defun +company/dict-or-keywords ()
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
;;; completion/company/config.el -*- lexical-binding: t; -*-
|
;;; completion/company/config.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
(def-package! company
|
(use-package! company
|
||||||
:commands (company-complete-common company-manual-begin company-grab-line)
|
:commands company-complete-common company-manual-begin company-grab-line
|
||||||
:after-call (evil-insert-state-entry-hook evil-emacs-state-entry-hook)
|
:after-call evil-insert-state-entry-hook evil-emacs-state-entry-hook
|
||||||
:init
|
:init
|
||||||
(setq company-minimum-prefix-length 2
|
(setq company-minimum-prefix-length 2
|
||||||
company-tooltip-limit 14
|
company-tooltip-limit 14
|
||||||
|
@ -27,16 +27,16 @@
|
||||||
;; Allow users to switch between backends on the fly. E.g. C-x C-s followed
|
;; 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
|
;; by C-x C-n, will switch from `company-yasnippet' to
|
||||||
;; `company-dabbrev-code'.
|
;; `company-dabbrev-code'.
|
||||||
(defun +company*abort-previous (&rest _) (company-abort))
|
(defadvice! +company--abort-previous-a (&rest _)
|
||||||
(advice-add #'company-begin-backend :before #'+company*abort-previous))
|
: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))
|
(global-company-mode +1))
|
||||||
|
|
||||||
|
|
||||||
(def-package! company-tng
|
(use-package! company-tng
|
||||||
:when (featurep! +tng)
|
:when (featurep! +tng)
|
||||||
:defer 2
|
|
||||||
:after-call post-self-insert-hook
|
:after-call post-self-insert-hook
|
||||||
:config
|
:config
|
||||||
(add-to-list 'company-frontends 'company-tng-frontend)
|
(add-to-list 'company-frontends 'company-tng-frontend)
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
;;
|
;;
|
||||||
;; Packages
|
;; Packages
|
||||||
|
|
||||||
(def-package! company-prescient
|
(use-package! company-prescient
|
||||||
:hook (company-mode . company-prescient-mode)
|
:hook (company-mode . company-prescient-mode)
|
||||||
:config
|
:config
|
||||||
;; NOTE prescient config duplicated with `ivy'
|
;; NOTE prescient config duplicated with `ivy'
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
(prescient-persist-mode +1))
|
(prescient-persist-mode +1))
|
||||||
|
|
||||||
|
|
||||||
(def-package! company-box
|
(use-package! company-box
|
||||||
:when (and EMACS26+ (featurep! +childframe))
|
:when (and EMACS26+ (featurep! +childframe))
|
||||||
:hook (company-mode . company-box-mode)
|
:hook (company-mode . company-box-mode)
|
||||||
:config
|
:config
|
||||||
|
@ -68,7 +68,10 @@
|
||||||
company-box-max-candidates 50
|
company-box-max-candidates 50
|
||||||
company-box-icons-alist 'company-box-icons-all-the-icons
|
company-box-icons-alist 'company-box-icons-all-the-icons
|
||||||
company-box-icons-functions
|
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
|
company-box-icons-all-the-icons
|
||||||
`((Unknown . ,(all-the-icons-material "find_in_page" :height 0.8 :face 'all-the-icons-purple))
|
`((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))
|
(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))
|
(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))))
|
(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)
|
(when (get-text-property 0 'yas-annotation candidate)
|
||||||
'Yasnippet))
|
'Yasnippet))
|
||||||
|
|
||||||
(defun +company-box-icons--elisp (candidate)
|
(defun +company-box-icons--elisp-fn (candidate)
|
||||||
(when (derived-mode-p 'emacs-lisp-mode)
|
(when (derived-mode-p 'emacs-lisp-mode)
|
||||||
(let ((sym (intern candidate)))
|
(let ((sym (intern candidate)))
|
||||||
(cond ((fboundp sym) 'ElispFunction)
|
(cond ((fboundp sym) 'ElispFunction)
|
||||||
|
@ -116,14 +119,13 @@
|
||||||
((facep sym) 'ElispFace))))))
|
((facep sym) 'ElispFace))))))
|
||||||
|
|
||||||
|
|
||||||
(def-package! company-dict
|
(use-package! company-dict
|
||||||
:defer t
|
:defer t
|
||||||
:config
|
:config
|
||||||
(setq company-dict-dir (expand-file-name "dicts" doom-private-dir))
|
(setq company-dict-dir (expand-file-name "dicts" doom-private-dir))
|
||||||
(defun +company|enable-project-dicts (mode &rest _)
|
(add-hook! 'doom-project-hook
|
||||||
"Enable per-project dictionaries."
|
(defun +company-enable-project-dicts-h (mode &rest _)
|
||||||
(if (symbol-value mode)
|
"Enable per-project dictionaries."
|
||||||
(add-to-list 'company-dict-minor-mode-list mode nil #'eq)
|
(if (symbol-value mode)
|
||||||
(setq company-dict-minor-mode-list (delq mode company-dict-minor-mode-list))))
|
(add-to-list 'company-dict-minor-mode-list mode nil #'eq)
|
||||||
(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; -*-
|
;;; completion/helm/autoload/posframe.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
(add-hook 'helm-cleanup-hook #'+helm|posframe-cleanup)
|
|
||||||
|
|
||||||
;;;###autoload
|
;;;###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
|
"Display the child frame in the center of the frame, slightly closer to the
|
||||||
bottom, which is easier on the eyes on big displays."
|
bottom, which is easier on the eyes on big displays."
|
||||||
(let ((parent-frame (plist-get info :parent-frame))
|
(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)
|
(defvar +helm--posframe-buffer nil)
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun +helm-posframe-display (buffer &optional _resume)
|
(defun +helm-posframe-display-fn (buffer &optional _resume)
|
||||||
"TODO"
|
"TODO"
|
||||||
(setq helm--buffer-in-new-frame-p t)
|
(setq helm--buffer-in-new-frame-p t)
|
||||||
(let ((solaire-p (bound-and-true-p solaire-mode))
|
(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)))))
|
(text-scale-set +helm-posframe-text-scale)))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun +helm|posframe-cleanup ()
|
(defun +helm-posframe-cleanup-h ()
|
||||||
"TODO"
|
"TODO"
|
||||||
;; Ensure focus is properly returned to the underlying window, by forcing a
|
;; Ensure focus is properly returned to the underlying window. This gives the
|
||||||
;; chance in buffer/window focus. This gives the modeline a chance to refresh.
|
;; modeline a chance to refresh.
|
||||||
(switch-to-buffer +helm--posframe-buffer t)
|
(switch-to-buffer +helm--posframe-buffer t))
|
||||||
;;
|
|
||||||
(posframe-delete +helm--posframe-buffer))
|
|
||||||
|
|
||||||
|
(add-hook 'helm-cleanup-hook #'+helm-posframe-cleanup-h)
|
||||||
;;;###autoload
|
|
||||||
(defun +helm*fix-get-font-height (orig-fn position)
|
|
||||||
(ignore-errors (funcall orig-fn position)))
|
|
||||||
|
|
|
@ -11,8 +11,7 @@ silently ignored.
|
||||||
This falls back to git-grep (then grep) if none of these available.")
|
This falls back to git-grep (then grep) if none of these available.")
|
||||||
|
|
||||||
;; Posframe (requires +childframe)
|
;; Posframe (requires +childframe)
|
||||||
(defvar +helm-posframe-handler
|
(defvar +helm-posframe-handler #'+helm-poshandler-frame-center-near-bottom-fn
|
||||||
#'+helm-poshandler-frame-center-near-bottom
|
|
||||||
"The function that determines the location of the childframe. It should return
|
"The function that determines the location of the childframe. It should return
|
||||||
a cons cell representing the X and Y coordinates. See
|
a cons cell representing the X and Y coordinates. See
|
||||||
`posframe-poshandler-frame-center' as a reference.")
|
`posframe-poshandler-frame-center' as a reference.")
|
||||||
|
@ -33,7 +32,7 @@ be negative.")
|
||||||
;;
|
;;
|
||||||
;;; Packages
|
;;; Packages
|
||||||
|
|
||||||
(def-package! helm-mode
|
(use-package! helm-mode
|
||||||
:defer t
|
:defer t
|
||||||
:after-call pre-command-hook
|
:after-call pre-command-hook
|
||||||
:init
|
:init
|
||||||
|
@ -58,7 +57,7 @@ be negative.")
|
||||||
(add-to-list 'helm-completing-read-handlers-alist (cons #'find-file-at-point nil)))
|
(add-to-list 'helm-completing-read-handlers-alist (cons #'find-file-at-point nil)))
|
||||||
|
|
||||||
|
|
||||||
(def-package! helm
|
(use-package! helm
|
||||||
:after helm-mode
|
:after helm-mode
|
||||||
:preface
|
:preface
|
||||||
(setq helm-candidate-number-limit 50
|
(setq helm-candidate-number-limit 50
|
||||||
|
@ -83,9 +82,7 @@ be negative.")
|
||||||
|
|
||||||
:init
|
:init
|
||||||
(when (and EMACS26+ (featurep! +childframe))
|
(when (and EMACS26+ (featurep! +childframe))
|
||||||
(setq helm-display-function #'+helm-posframe-display)
|
(setq helm-display-function #'+helm-posframe-display-fn))
|
||||||
;; Fix "Specified window is not displaying the current buffer" error
|
|
||||||
(advice-add #'posframe--get-font-height :around #'+helm*fix-get-font-height))
|
|
||||||
|
|
||||||
(let ((fuzzy (featurep! +fuzzy)))
|
(let ((fuzzy (featurep! +fuzzy)))
|
||||||
(setq helm-M-x-fuzzy-match fuzzy
|
(setq helm-M-x-fuzzy-match fuzzy
|
||||||
|
@ -110,27 +107,28 @@ be negative.")
|
||||||
:config
|
:config
|
||||||
(set-popup-rule! "^\\*helm" :vslot -100 :size 0.22 :ttl nil)
|
(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
|
;; Hide the modeline
|
||||||
(defun +helm|hide-mode-line (&rest _)
|
(defun +helm--hide-mode-line (&rest _)
|
||||||
(with-current-buffer (helm-buffer-get)
|
(with-current-buffer (helm-buffer-get)
|
||||||
(unless helm-mode-line-string
|
(unless helm-mode-line-string
|
||||||
(hide-mode-line-mode +1))))
|
(hide-mode-line-mode +1))))
|
||||||
(add-hook 'helm-after-initialize-hook #'+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-display-mode-line :override #'+helm--hide-mode-line)
|
||||||
(advice-add #'helm-ag-show-status-default-mode-line :override #'ignore)
|
(advice-add #'helm-ag-show-status-default-mode-line :override #'ignore)
|
||||||
|
|
||||||
;; TODO Find a better way
|
;; Use helpful instead of describe-* to display documentation
|
||||||
(defun +helm*use-helpful (orig-fn arg)
|
(dolist (fn '(helm-describe-variable helm-describe-function))
|
||||||
(cl-letf (((symbol-function #'describe-function)
|
(advice-add fn :around #'doom-use-helpful-a)))
|
||||||
(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))
|
|
||||||
|
|
||||||
|
|
||||||
(def-package! helm-flx
|
(use-package! helm-flx
|
||||||
:when (featurep! +fuzzy)
|
:when (featurep! +fuzzy)
|
||||||
:hook (helm-mode . helm-flx-mode)
|
:hook (helm-mode . helm-flx-mode)
|
||||||
:config (helm-flx-mode +1))
|
:config (helm-flx-mode +1))
|
||||||
|
@ -142,9 +140,9 @@ be negative.")
|
||||||
(define-key helm-ag-edit-map [remap quit-window] #'helm-ag--edit-abort)
|
(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)
|
(set-popup-rule! "^\\*helm-ag-edit" :size 0.35 :ttl 0 :quit nil)
|
||||||
;; Recenter after jumping to match
|
;; 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
|
;; 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
|
;;;###package helm-bookmark
|
||||||
|
@ -164,7 +162,7 @@ be negative.")
|
||||||
|
|
||||||
|
|
||||||
;;;###package helm-projectile
|
;;;###package helm-projectile
|
||||||
(def-package! helm-projectile
|
(use-package! helm-projectile
|
||||||
:commands (helm-projectile-find-file
|
:commands (helm-projectile-find-file
|
||||||
helm-projectile-recentf
|
helm-projectile-recentf
|
||||||
helm-projectile-switch-project
|
helm-projectile-switch-project
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
(package! helm-ag)
|
(package! helm-ag)
|
||||||
(package! helm-c-yasnippet)
|
(package! helm-c-yasnippet)
|
||||||
(package! helm-company)
|
(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! helm-projectile)
|
||||||
(package! swiper-helm)
|
(package! swiper-helm)
|
||||||
(when (featurep! +fuzzy)
|
(when (featurep! +fuzzy)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
;;; completion/ido/config.el -*- lexical-binding: t; -*-
|
;;; completion/ido/config.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
(defun +ido|init ()
|
(defun +ido-init-h ()
|
||||||
(setq ido-ignore-buffers
|
(setq ido-ignore-buffers
|
||||||
'("\\` " "^\\*ESS\\*" "^\\*Messages\\*" "^\\*Help\\*" "^\\*Buffer"
|
'("\\` " "^\\*ESS\\*" "^\\*Messages\\*" "^\\*Help\\*" "^\\*Buffer"
|
||||||
"^\\*.*Completions\\*$" "^\\*Ediff" "^\\*tramp" "^\\*cvs-"
|
"^\\*.*Completions\\*$" "^\\*Ediff" "^\\*tramp" "^\\*cvs-"
|
||||||
|
@ -28,8 +28,9 @@
|
||||||
(insert "~/")
|
(insert "~/")
|
||||||
(call-interactively #'self-insert-command))))
|
(call-interactively #'self-insert-command))))
|
||||||
|
|
||||||
(defun +ido*sort-mtime ()
|
(defadvice! +ido--sort-mtime-a ()
|
||||||
"Sort ido filelist by mtime instead of alphabetically."
|
"Sort ido filelist by mtime instead of alphabetically."
|
||||||
|
:override #'ido-sort-mtime
|
||||||
(setq ido-temp-list
|
(setq ido-temp-list
|
||||||
(sort ido-temp-list
|
(sort ido-temp-list
|
||||||
(lambda (a b)
|
(lambda (a b)
|
||||||
|
@ -40,8 +41,8 @@
|
||||||
(cl-loop for x in ido-temp-list
|
(cl-loop for x in ido-temp-list
|
||||||
if (char-equal (string-to-char x) ?.)
|
if (char-equal (string-to-char x) ?.)
|
||||||
collect x)))
|
collect x)))
|
||||||
(advice-add #'ido-sort-mtime :override #'+ido*sort-mtime)
|
(add-hook! '(ido-make-file-list-hook ido-make-dir-list-hook)
|
||||||
(add-hook! (ido-make-file-list ido-make-dir-list) #'+ido*sort-mtime)
|
#'ido-sort-mtime)
|
||||||
|
|
||||||
;;
|
;;
|
||||||
(ido-mode 1)
|
(ido-mode 1)
|
||||||
|
@ -52,7 +53,7 @@
|
||||||
(crm-custom-mode +1)
|
(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,32 +1,33 @@
|
||||||
;;; completion/ivy/autoload/hydras.el -*- lexical-binding: t; -*-
|
;;; completion/ivy/autoload/hydras.el -*- lexical-binding: t; -*-
|
||||||
|
;;;###if (featurep! :ui hydra)
|
||||||
|
|
||||||
;;;###autoload
|
(eval-when-compile (require 'ivy-hydra))
|
||||||
(after! ivy-hydra
|
|
||||||
(with-no-warnings
|
;;;###autoload (autoload 'hydra-ivy/body "completion/ivy/autoload/hydras" nil nil)
|
||||||
(defhydra+ hydra-ivy (:hint nil :color pink)
|
(defhydra+ hydra-ivy (:hint nil :color pink)
|
||||||
"
|
"
|
||||||
Move ^^^^^^^^^^ | Call ^^^^ | Cancel^^ | Options^^ | Action _w_/_s_/_a_: %s(ivy-action-name)
|
Move ^^^^^^^^^^ | Call ^^^^ | Cancel^^ | Options^^ | Action _w_/_s_/_a_: %s(ivy-action-name)
|
||||||
----------^^^^^^^^^^-+--------------^^^^-+-------^^-+--------^^-+---------------------------------
|
----------^^^^^^^^^^-+--------------^^^^-+-------^^-+--------^^-+---------------------------------
|
||||||
_g_ ^ ^ _k_ ^ ^ _u_ | _f_orward _o_ccur | _i_nsert | _c_alling: %-7s(if ivy-calling \"on\" \"off\") _C_ase-fold: %-10`ivy-case-fold-search
|
_g_ ^ ^ _k_ ^ ^ _u_ | _f_orward _o_ccur | _i_nsert | _c_alling: %-7s(if ivy-calling \"on\" \"off\") _C_ase-fold: %-10`ivy-case-fold-search
|
||||||
^↨^ _h_ ^+^ _l_ ^↕^ | _RET_ done ^^ | _q_uit | _m_atcher: %-7s(ivy--matcher-desc) _t_runcate: %-11`truncate-lines
|
^↨^ _h_ ^+^ _l_ ^↕^ | _RET_ done ^^ | _q_uit | _m_atcher: %-7s(ivy--matcher-desc) _t_runcate: %-11`truncate-lines
|
||||||
_G_ ^ ^ _j_ ^ ^ _d_ | _TAB_ alt-done ^^ | ^ ^ | _<_/_>_: shrink/grow
|
_G_ ^ ^ _j_ ^ ^ _d_ | _TAB_ alt-done ^^ | ^ ^ | _<_/_>_: shrink/grow
|
||||||
"
|
"
|
||||||
;; arrows
|
;; arrows
|
||||||
("l" ivy-alt-done)
|
("l" ivy-alt-done)
|
||||||
("h" ivy-backward-delete-char)
|
("h" ivy-backward-delete-char)
|
||||||
("g" ivy-beginning-of-buffer)
|
("g" ivy-beginning-of-buffer)
|
||||||
("G" ivy-end-of-buffer)
|
("G" ivy-end-of-buffer)
|
||||||
("d" ivy-scroll-up-command)
|
("d" ivy-scroll-up-command)
|
||||||
("u" ivy-scroll-down-command)
|
("u" ivy-scroll-down-command)
|
||||||
("e" ivy-scroll-down-command)
|
("e" ivy-scroll-down-command)
|
||||||
;; actions
|
;; actions
|
||||||
("q" keyboard-escape-quit :exit t)
|
("q" keyboard-escape-quit :exit t)
|
||||||
("<escape>" keyboard-escape-quit :exit t)
|
("<escape>" keyboard-escape-quit :exit t)
|
||||||
("TAB" ivy-alt-done :exit nil)
|
("TAB" ivy-alt-done :exit nil)
|
||||||
("RET" ivy-done :exit t)
|
("RET" ivy-done :exit t)
|
||||||
("C-SPC" ivy-call-and-recenter :exit nil)
|
("C-SPC" ivy-call-and-recenter :exit nil)
|
||||||
("f" ivy-call)
|
("f" ivy-call)
|
||||||
("c" ivy-toggle-calling)
|
("c" ivy-toggle-calling)
|
||||||
("m" ivy-toggle-fuzzy)
|
("m" ivy-toggle-fuzzy)
|
||||||
("t" (setq truncate-lines (not truncate-lines)))
|
("t" (setq truncate-lines (not truncate-lines)))
|
||||||
("o" ivy-occur :exit t))))
|
("o" ivy-occur :exit t))
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
;;;###if (featurep! +childframe)
|
;;;###if (featurep! +childframe)
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun +ivy-display-at-frame-center-near-bottom (str)
|
(defun +ivy-display-at-frame-center-near-bottom-fn (str)
|
||||||
"TODO"
|
"TODO"
|
||||||
(ivy-posframe--display str #'+ivy-poshandler-frame-center-near-bottom))
|
(ivy-posframe--display str #'+ivy-poshandler-frame-center-near-bottom-fn))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun +ivy-poshandler-frame-center-near-bottom (info)
|
(defun +ivy-poshandler-frame-center-near-bottom-fn (info)
|
||||||
"TODO"
|
"TODO"
|
||||||
(let ((parent-frame (plist-get info :parent-frame))
|
(let ((parent-frame (plist-get info :parent-frame))
|
||||||
(pos (posframe-poshandler-frame-center info)))
|
(pos (posframe-poshandler-frame-center info)))
|
||||||
|
|
|
@ -43,7 +43,7 @@ immediately runs it on the current candidate (ending the ivy session)."
|
||||||
;;
|
;;
|
||||||
;;; Packages
|
;;; Packages
|
||||||
|
|
||||||
(def-package! ivy
|
(use-package! ivy
|
||||||
:defer 1
|
:defer 1
|
||||||
:after-call pre-command-hook
|
:after-call pre-command-hook
|
||||||
:init
|
: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')
|
;; enable ability to select prompt (alternative to `ivy-immediate-done')
|
||||||
ivy-use-selectable-prompt t)
|
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
|
;; Ensure a jump point is registered before jumping to new locations with ivy
|
||||||
(defvar +ivy--origin nil)
|
(defvar +ivy--origin nil)
|
||||||
|
(defun +ivy--record-position-maybe-fn ()
|
||||||
(defun +ivy|record-position-maybe ()
|
|
||||||
(with-ivy-window
|
(with-ivy-window
|
||||||
(setq +ivy--origin (point-marker))))
|
(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
|
||||||
(when (and (markerp +ivy--origin)
|
(defun +ivy--set-jump-point-maybe-h ()
|
||||||
(not (equal (with-ivy-window (point-marker)) +ivy--origin)))
|
(with-demoted-errors "Ivy error: %s"
|
||||||
(with-current-buffer (marker-buffer +ivy--origin)
|
(when (and (markerp +ivy--origin)
|
||||||
(better-jumper-set-jump +ivy--origin)))
|
(not (equal (with-ivy-window (point-marker))
|
||||||
(setq +ivy--origin nil))
|
+ivy--origin)))
|
||||||
(add-hook 'minibuffer-exit-hook #'+ivy|set-jump-point-maybe)
|
(with-current-buffer (marker-buffer +ivy--origin)
|
||||||
|
(better-jumper-set-jump +ivy--origin)))
|
||||||
|
(setq +ivy--origin nil))))
|
||||||
|
|
||||||
(after! yasnippet
|
(after! yasnippet
|
||||||
(add-to-list 'yas-prompt-functions #'+ivy-yas-prompt nil #'eq))
|
(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
|
"`ivy-completion-in-region' struggles with completing certain
|
||||||
evil-ex-specific constructs, so we disable it solely in evil-ex."
|
evil-ex-specific constructs, so we disable it solely in evil-ex."
|
||||||
|
:around #'evil-ex
|
||||||
(let ((completion-in-region-function #'completion--in-region))
|
(let ((completion-in-region-function #'completion--in-region))
|
||||||
(apply orig-fn args)))
|
(apply orig-fn args)))
|
||||||
(advice-add #'evil-ex :around #'+ivy*inhibit-ivy-in-evil-ex)
|
|
||||||
|
|
||||||
(define-key! ivy-mode-map
|
(define-key! ivy-mode-map
|
||||||
[remap switch-to-buffer] #'+ivy/switch-buffer
|
[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)
|
(ivy-mode +1)
|
||||||
|
|
||||||
(def-package! ivy-hydra
|
(use-package! ivy-hydra
|
||||||
:commands (ivy-dispatching-done-hydra ivy--matcher-desc ivy-hydra/body)
|
:commands (ivy-dispatching-done-hydra ivy--matcher-desc ivy-hydra/body)
|
||||||
:init
|
:init
|
||||||
(define-key! ivy-minibuffer-map
|
(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)))
|
(define-key ivy-minibuffer-map (kbd "M-o") #'hydra-ivy/body)))
|
||||||
|
|
||||||
|
|
||||||
(def-package! ivy-rich
|
(use-package! ivy-rich
|
||||||
:after ivy
|
:after ivy
|
||||||
:config
|
:config
|
||||||
(when (featurep! +icons)
|
(when (featurep! +icons)
|
||||||
|
@ -159,7 +185,7 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
||||||
(ivy-rich-mode +1))
|
(ivy-rich-mode +1))
|
||||||
|
|
||||||
|
|
||||||
(def-package! all-the-icons-ivy
|
(use-package! all-the-icons-ivy
|
||||||
:when (featurep! +icons)
|
:when (featurep! +icons)
|
||||||
:after ivy
|
:after ivy
|
||||||
:config
|
:config
|
||||||
|
@ -175,7 +201,7 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
||||||
(all-the-icons-ivy-setup))))
|
(all-the-icons-ivy-setup))))
|
||||||
|
|
||||||
|
|
||||||
(def-package! counsel
|
(use-package! counsel
|
||||||
:commands counsel-describe-face
|
:commands counsel-describe-face
|
||||||
:init
|
:init
|
||||||
(map! [remap apropos] #'counsel-apropos
|
(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"))))
|
'(("O" +ivy-git-grep-other-window-action "open in other window"))))
|
||||||
|
|
||||||
|
|
||||||
(def-package! counsel-projectile
|
(use-package! counsel-projectile
|
||||||
:defer t
|
:defer t
|
||||||
:init
|
:init
|
||||||
(map! [remap projectile-find-file] #'+ivy/projectile-find-file
|
(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))
|
(ivy-set-display-transformer #'counsel-projectile-find-file nil))
|
||||||
|
|
||||||
|
|
||||||
(def-package! wgrep
|
(use-package! wgrep
|
||||||
:commands wgrep-change-to-wgrep-mode
|
:commands wgrep-change-to-wgrep-mode
|
||||||
:config (setq wgrep-auto-save-buffer t))
|
:config (setq wgrep-auto-save-buffer t))
|
||||||
|
|
||||||
|
|
||||||
(def-package! ivy-posframe
|
(use-package! ivy-posframe
|
||||||
:when (and EMACS26+ (featurep! +childframe))
|
:when (and EMACS26+ (featurep! +childframe))
|
||||||
:hook (ivy-mode . ivy-posframe-mode)
|
:hook (ivy-mode . ivy-posframe-mode)
|
||||||
:config
|
:config
|
||||||
|
@ -277,14 +303,16 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
||||||
(min-height . ,ivy-height)))
|
(min-height . ,ivy-height)))
|
||||||
|
|
||||||
;; default to posframe display function
|
;; 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
|
;; posframe doesn't work well with async sources
|
||||||
(dolist (fn '(swiper counsel-ag counsel-grep counsel-git-grep))
|
(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)
|
:when (and (featurep! +fuzzy)
|
||||||
(not (featurep! +prescient)))
|
(not (featurep! +prescient)))
|
||||||
:defer t ; is loaded by ivy
|
: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))
|
ivy-flx-limit 10000))
|
||||||
|
|
||||||
|
|
||||||
(def-package! ivy-prescient
|
(use-package! ivy-prescient
|
||||||
:hook (ivy-mode . ivy-prescient-mode)
|
:hook (ivy-mode . ivy-prescient-mode)
|
||||||
:when (featurep! +prescient)
|
:when (featurep! +prescient)
|
||||||
:init
|
:init
|
||||||
|
@ -323,5 +351,5 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
|
||||||
(prescient-persist-mode +1))
|
(prescient-persist-mode +1))
|
||||||
|
|
||||||
|
|
||||||
;; Used by `counsel-M-x'
|
;;;###package amx
|
||||||
(setq amx-save-file (concat doom-cache-dir "amx-items"))
|
(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 "Initialize repo" "r" #'magit-init
|
||||||
:desc "Clone repo" "R" #'+magit/clone
|
:desc "Clone repo" "R" #'+magit/clone
|
||||||
:desc "Commit" "c" #'magit-commit-create
|
:desc "Commit" "c" #'magit-commit-create
|
||||||
|
:desc "Fixup" "f" #'magit-commit-fixup
|
||||||
:desc "Issue" "i" #'forge-create-issue
|
:desc "Issue" "i" #'forge-create-issue
|
||||||
:desc "Pull request" "p" #'forge-create-pullreq)))
|
:desc "Pull request" "p" #'forge-create-pullreq)))
|
||||||
|
|
||||||
|
|
|
@ -9,15 +9,14 @@
|
||||||
(setq shift-select-mode t)
|
(setq shift-select-mode t)
|
||||||
(delete-selection-mode +1)
|
(delete-selection-mode +1)
|
||||||
|
|
||||||
(def-package! expand-region
|
(use-package! expand-region
|
||||||
:commands (er/contract-region er/mark-symbol er/mark-word)
|
:commands (er/contract-region er/mark-symbol er/mark-word)
|
||||||
:config
|
:config
|
||||||
(defun doom*quit-expand-region ()
|
(defadvice! doom--quit-expand-region-a ()
|
||||||
"Properly abort an expand-region region."
|
"Properly abort an expand-region region."
|
||||||
|
:before '(evil-escape doom/escape)
|
||||||
(when (memq last-command '(er/expand-region er/contract-region))
|
(when (memq last-command '(er/expand-region er/contract-region))
|
||||||
(er/contract-region 0)))
|
(er/contract-region 0))))
|
||||||
(advice-add #'evil-escape :before #'doom*quit-expand-region)
|
|
||||||
(advice-add #'doom/escape :before #'doom*quit-expand-region))
|
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
|
|
|
@ -4,10 +4,15 @@
|
||||||
|
|
||||||
;; Don't let evil-collection interfere with certain keys
|
;; Don't let evil-collection interfere with certain keys
|
||||||
(setq evil-collection-key-blacklist
|
(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-key doom-localleader-key
|
||||||
doom-leader-alt-key doom-localleader-alt-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
|
;;; Global keybindings
|
||||||
|
@ -53,6 +58,9 @@
|
||||||
|
|
||||||
;; misc
|
;; misc
|
||||||
:n "C-S-f" #'toggle-frame-fullscreen
|
: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
|
;; ported from vim
|
||||||
:m "]m" #'+evil/next-beginning-of-method
|
:m "]m" #'+evil/next-beginning-of-method
|
||||||
|
@ -140,7 +148,6 @@
|
||||||
"C-r" #'winner-redo
|
"C-r" #'winner-redo
|
||||||
"o" #'doom/window-enlargen
|
"o" #'doom/window-enlargen
|
||||||
;; Delete window
|
;; Delete window
|
||||||
"c" #'+workspace/close-window-or-workspace
|
|
||||||
"C-C" #'ace-delete-window)
|
"C-C" #'ace-delete-window)
|
||||||
|
|
||||||
;; Plugins
|
;; Plugins
|
||||||
|
@ -162,8 +169,8 @@
|
||||||
:bind ((evil-snipe-scope 'buffer)
|
:bind ((evil-snipe-scope 'buffer)
|
||||||
(evil-snipe-enable-highlight)
|
(evil-snipe-enable-highlight)
|
||||||
(evil-snipe-enable-incremental-highlight)))
|
(evil-snipe-enable-incremental-highlight)))
|
||||||
"SPC" (λ!! #'avy-goto-char-timer t)
|
"SPC" (λ!! #'evil-avy-goto-char-timer t)
|
||||||
"/" #'avy-goto-char-timer)
|
"/" #'evil-avy-goto-char-timer)
|
||||||
|
|
||||||
;; text object plugins
|
;; text object plugins
|
||||||
:textobj "x" #'evil-inner-xml-attr #'evil-outer-xml-attr
|
:textobj "x" #'evil-inner-xml-attr #'evil-outer-xml-attr
|
||||||
|
@ -520,6 +527,7 @@
|
||||||
:desc "Switch workspace buffer" "," #'persp-switch-to-buffer
|
:desc "Switch workspace buffer" "," #'persp-switch-to-buffer
|
||||||
:desc "Switch buffer" "<" #'switch-to-buffer)
|
:desc "Switch buffer" "<" #'switch-to-buffer)
|
||||||
|
|
||||||
|
:desc "Switch to last buffer" "`" #'evil-switch-to-windows-last-buffer
|
||||||
:desc "Resume last search" "'"
|
:desc "Resume last search" "'"
|
||||||
(cond ((featurep! :completion ivy) #'ivy-resume)
|
(cond ((featurep! :completion ivy) #'ivy-resume)
|
||||||
((featurep! :completion helm) #'helm-resume))
|
((featurep! :completion helm) #'helm-resume))
|
||||||
|
@ -580,7 +588,9 @@
|
||||||
:desc "Switch buffer" "B" #'switch-to-buffer)
|
:desc "Switch buffer" "B" #'switch-to-buffer)
|
||||||
(:unless (featurep! :ui workspaces)
|
(:unless (featurep! :ui workspaces)
|
||||||
:desc "Switch buffer" "b" #'switch-to-buffer)
|
:desc "Switch buffer" "b" #'switch-to-buffer)
|
||||||
|
:desc "Kill buffer" "d" #'kill-current-buffer
|
||||||
:desc "Kill buffer" "k" #'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 "Next buffer" "n" #'next-buffer
|
||||||
:desc "New empty buffer" "N" #'evil-buffer-new
|
:desc "New empty buffer" "N" #'evil-buffer-new
|
||||||
:desc "Kill other buffers" "o" #'doom/kill-other-buffers
|
:desc "Kill other buffers" "o" #'doom/kill-other-buffers
|
||||||
|
@ -674,6 +684,7 @@
|
||||||
:desc "Initialize repo" "r" #'magit-init
|
:desc "Initialize repo" "r" #'magit-init
|
||||||
:desc "Clone repo" "R" #'+magit/clone
|
:desc "Clone repo" "R" #'+magit/clone
|
||||||
:desc "Commit" "c" #'magit-commit-create
|
:desc "Commit" "c" #'magit-commit-create
|
||||||
|
:desc "Fixup" "f" #'magit-commit-fixup
|
||||||
:desc "Branch" "b" #'magit-branch-and-checkout
|
:desc "Branch" "b" #'magit-branch-and-checkout
|
||||||
:desc "Issue" "i" #'forge-create-issue
|
:desc "Issue" "i" #'forge-create-issue
|
||||||
:desc "Pull request" "p" #'forge-create-pullreq)))
|
:desc "Pull request" "p" #'forge-create-pullreq)))
|
||||||
|
@ -715,6 +726,9 @@
|
||||||
(:when (featurep! :ui treemacs)
|
(:when (featurep! :ui treemacs)
|
||||||
:desc "Project sidebar" "p" #'+treemacs/toggle
|
:desc "Project sidebar" "p" #'+treemacs/toggle
|
||||||
:desc "Find file in project sidebar" "P" #'+treemacs/find-file)
|
: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)
|
(:when (featurep! :term term)
|
||||||
:desc "Toggle terminal popup" "t" #'+term/toggle
|
:desc "Toggle terminal popup" "t" #'+term/toggle
|
||||||
:desc "Open terminal here" "T" #'+term/here)
|
:desc "Open terminal here" "T" #'+term/here)
|
||||||
|
@ -724,16 +738,6 @@
|
||||||
(:when (featurep! :term eshell)
|
(:when (featurep! :term eshell)
|
||||||
:desc "Toggle eshell popup" "e" #'+eshell/toggle
|
:desc "Toggle eshell popup" "e" #'+eshell/toggle
|
||||||
:desc "Open eshell here" "E" #'+eshell/here)
|
: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)
|
(:when (featurep! :tools macos)
|
||||||
:desc "Reveal in Finder" "o" #'+macos/reveal-in-finder
|
:desc "Reveal in Finder" "o" #'+macos/reveal-in-finder
|
||||||
:desc "Reveal project in Finder" "O" #'+macos/reveal-project-in-finder
|
:desc "Reveal project in Finder" "O" #'+macos/reveal-project-in-finder
|
||||||
|
@ -795,11 +799,11 @@
|
||||||
(:prefix-map ("s" . "snippets")
|
(:prefix-map ("s" . "snippets")
|
||||||
:desc "View snippet for mode" "/" #'+snippets/find-for-current-mode
|
:desc "View snippet for mode" "/" #'+snippets/find-for-current-mode
|
||||||
:desc "View snippet (global)" "?" #'+snippets/find
|
: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 "View private snippet" "f" #'+snippets/find-private
|
||||||
:desc "Insert snippet" "i" #'yas-insert-snippet
|
:desc "Insert snippet" "i" #'yas-insert-snippet
|
||||||
:desc "New snippet" "n" #'+snippet/new
|
:desc "New snippet" "n" #'+snippets/new
|
||||||
:desc "New snippet alias" "N" #'+snippet/new-alias
|
:desc "New snippet alias" "N" #'+snippets/new-alias
|
||||||
:desc "Reload snippets" "r" #'yas-reload-all
|
:desc "Reload snippets" "r" #'yas-reload-all
|
||||||
:desc "Create temporary snippet" "s" #'aya-create
|
:desc "Create temporary snippet" "s" #'aya-create
|
||||||
:desc "Expand temporary snippet" "e" #'aya-expand))
|
:desc "Expand temporary snippet" "e" #'aya-expand))
|
||||||
|
@ -810,10 +814,10 @@
|
||||||
:desc "Flycheck" "f" #'flycheck-mode
|
:desc "Flycheck" "f" #'flycheck-mode
|
||||||
:desc "Frame fullscreen" "F" #'toggle-frame-fullscreen
|
:desc "Frame fullscreen" "F" #'toggle-frame-fullscreen
|
||||||
:desc "Evil goggles" "g" #'evil-goggles-mode
|
:desc "Evil goggles" "g" #'evil-goggles-mode
|
||||||
:desc "Impatient mode" "h" #'+impatient-mode/toggle
|
|
||||||
:desc "Indent guides" "i" #'highlight-indent-guides-mode
|
:desc "Indent guides" "i" #'highlight-indent-guides-mode
|
||||||
:desc "Indent style" "I" #'doom/toggle-indent-style
|
:desc "Indent style" "I" #'doom/toggle-indent-style
|
||||||
:desc "Line numbers" "l" #'doom/toggle-line-numbers
|
: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 "org-tree-slide mode" "p" #'+org-present/start
|
||||||
:desc "Flyspell" "s" #'flyspell-mode))
|
: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)
|
(defmacro set-repeater! (command next-func prev-func)
|
||||||
"Makes ; and , the universal repeat-keys in evil-mode.
|
"Makes ; and , the universal repeat-keys in evil-mode.
|
||||||
To change these keys see `+default-repeat-keys'."
|
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
|
`(progn
|
||||||
(defun ,fn-sym (&rest _)
|
(defun ,fn-sym (&rest _)
|
||||||
(evil-define-key* 'motion 'local
|
(evil-define-key* 'motion 'local
|
||||||
|
|
|
@ -119,6 +119,7 @@ languages)."
|
||||||
(if (and (sp-point-in-comment)
|
(if (and (sp-point-in-comment)
|
||||||
comment-line-break-function)
|
comment-line-break-function)
|
||||||
(funcall comment-line-break-function)
|
(funcall comment-line-break-function)
|
||||||
|
(delete-horizontal-space t)
|
||||||
(newline nil t)
|
(newline nil t)
|
||||||
(indent-according-to-mode)))
|
(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.
|
"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."
|
If prefix ARG is set, prompt for a known project to search from."
|
||||||
(interactive
|
(interactive
|
||||||
(list current-prefix-arg (thing-at-point 'symbol t)))
|
(list current-prefix-arg (or (thing-at-point 'symbol t) "")))
|
||||||
(let ((default-directory
|
(let ((default-directory
|
||||||
(if arg
|
(if arg
|
||||||
(if-let* ((projects (projectile-relevant-known-projects)))
|
(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 ()
|
(defun +default/org-notes-headlines ()
|
||||||
"Jump to an Org headline in `org-agenda-files'."
|
"Jump to an Org headline in `org-agenda-files'."
|
||||||
(interactive)
|
(interactive)
|
||||||
(completing-read
|
(doom-completing-read-org-headings
|
||||||
"Jump to org headline: "
|
"Jump to org headline: " org-agenda-files 3 t))
|
||||||
(doom-completing-read-org-headings org-agenda-files 3 t)))
|
|
||||||
|
|
|
@ -44,13 +44,18 @@
|
||||||
;; or specific :post-handlers with:
|
;; or specific :post-handlers with:
|
||||||
;; (sp-pair "{" nil :post-handlers '(:rem ("| " "SPC")))
|
;; (sp-pair "{" nil :post-handlers '(:rem ("| " "SPC")))
|
||||||
(after! smartparens
|
(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
|
;; 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
|
;; 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!
|
;; be reactivated for non-evil users though. Needs more testing!
|
||||||
(defun doom|disable-smartparens-navigate-skip-match ()
|
(add-hook! 'after-change-major-mode-hook
|
||||||
(setq sp-navigate-skip-match nil
|
(defun doom-disable-smartparens-navigate-skip-match-h ()
|
||||||
sp-navigate-consider-sgml-tags nil))
|
(setq sp-navigate-skip-match 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
|
;; Autopair quotes more conservatively; if I'm next to a word/before another
|
||||||
;; quote, I likely don't want to open a new pair.
|
;; quote, I likely don't want to open a new pair.
|
||||||
|
@ -101,10 +106,27 @@
|
||||||
;; intelligently. The result isn't very intelligent (causes redundant
|
;; intelligently. The result isn't very intelligent (causes redundant
|
||||||
;; characters), so just do it ourselves.
|
;; characters), so just do it ourselves.
|
||||||
(define-key! c++-mode-map "<" nil ">" nil)
|
(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
|
;; ...and leave it to smartparens
|
||||||
(sp-local-pair '(c++-mode objc-mode)
|
(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")))
|
:post-handlers '(("| " "SPC")))
|
||||||
|
|
||||||
(sp-local-pair '(c-mode c++-mode objc-mode java-mode)
|
(sp-local-pair '(c-mode c++-mode objc-mode java-mode)
|
||||||
|
@ -138,6 +160,27 @@
|
||||||
:actions '(insert)
|
:actions '(insert)
|
||||||
:post-handlers '(("| " "SPC") ("|\n[i]*)[d-2]" "RET")))))
|
: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:
|
;; Highjacks backspace to:
|
||||||
;; a) balance spaces inside brackets/parentheses ( | ) -> (|)
|
;; a) balance spaces inside brackets/parentheses ( | ) -> (|)
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
(defalias '+literate/reload #'doom/reload)
|
(defalias '+literate/reload #'doom/reload)
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun +literate|recompile-maybe ()
|
(defun +literate-recompile-maybe-h ()
|
||||||
"Recompile config.org if we're editing an org file in our DOOMDIR.
|
"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
|
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; -*-
|
;;; config/literate/init.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
(defvar +literate-config-file
|
(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.")
|
"The file path of your literate config file.")
|
||||||
|
|
||||||
(defvar +literate-config-cache-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
|
"The file path that `+literate-config-file' will be tangled to, then
|
||||||
byte-compiled from.")
|
byte-compiled from.")
|
||||||
|
|
||||||
|
@ -13,32 +13,34 @@ byte-compiled from.")
|
||||||
;;
|
;;
|
||||||
(defun +literate-tangle (&optional force-p)
|
(defun +literate-tangle (&optional force-p)
|
||||||
"Tangles `+literate-config-file' if it has changed."
|
"Tangles `+literate-config-file' if it has changed."
|
||||||
(let ((default-directory doom-private-dir)
|
(let ((default-directory doom-private-dir))
|
||||||
(org +literate-config-file))
|
(when (or (file-newer-than-file-p +literate-config-file
|
||||||
(when (or force-p (file-newer-than-file-p org +literate-config-cache-file))
|
+literate-config-cache-file)
|
||||||
|
force-p)
|
||||||
(message "Compiling your literate config...")
|
(message "Compiling your literate config...")
|
||||||
|
|
||||||
(let* ((org (file-truename +literate-config-file))
|
(let* ((org (file-truename +literate-config-file))
|
||||||
(dest (concat (file-name-sans-extension org) ".el")))
|
(dest (concat (file-name-sans-extension org) ".el"))
|
||||||
(or (and (if (fboundp 'org-babel-tangle-file)
|
(output (get-buffer-create "*org-tangle*")))
|
||||||
(org-babel-tangle-file org dest "emacs-lisp")
|
(unwind-protect
|
||||||
;; We tangle in a separate, blank process because loading it
|
;; We tangle in a separate, blank process because loading it here
|
||||||
;; here would load all of :lang org (very expensive!).
|
;; would load all of :lang org (very expensive!).
|
||||||
(zerop (call-process
|
(or (and (zerop (call-process
|
||||||
"emacs" nil nil nil
|
"emacs" nil output nil
|
||||||
"-q" "--batch" "-l" "ob-tangle" "--eval"
|
"-q" "--batch"
|
||||||
(format "(org-babel-tangle-file %S %S \"emacs-lisp\")"
|
"-l" "ob-tangle"
|
||||||
org dest))))
|
"--eval" (format "(org-babel-tangle-file %S %S)"
|
||||||
;; Write the cache file to serve as our mtime cache
|
org dest)))
|
||||||
(with-temp-file +literate-config-cache-file
|
(with-current-buffer output
|
||||||
(message "Done!")))
|
(message "%s" (buffer-string))
|
||||||
(warn "There was a problem tangling your literate config!"))))))
|
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!"))
|
||||||
|
(kill-buffer output))))))
|
||||||
|
|
||||||
|
|
||||||
;; Let 'er rip!
|
;; Let 'er rip!
|
||||||
(when noninteractive
|
|
||||||
(require 'ob-tangle nil t))
|
|
||||||
|
|
||||||
(+literate-tangle (or doom-reloading-p noninteractive))
|
(+literate-tangle (or doom-reloading-p noninteractive))
|
||||||
;; No need to load the resulting file. Doom will do this for us after all
|
;; No need to load the resulting file. Doom will do this for us after all
|
||||||
;; modules have finished loading.
|
;; modules have finished loading.
|
||||||
|
@ -46,4 +48,4 @@ byte-compiled from.")
|
||||||
|
|
||||||
;; Recompile our literate config if we modify it
|
;; Recompile our literate config if we modify it
|
||||||
(after! org
|
(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; -*-
|
;;; 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
|
;;; Custom commands
|
||||||
;; Editing
|
;; Editing
|
||||||
(evil-ex-define-cmd "@" #'+evil:macro-on-all-lines) ; TODO Test me
|
(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]o" #'doom/kill-other-buffers)
|
||||||
(evil-ex-define-cmd "k[ill]b" #'doom/kill-buried-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 "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)
|
(evil-ex-define-cmd "pop[up]" #'doom/popup-this-buffer)
|
||||||
|
|
||||||
;;; Project navigation
|
;;; Project navigation
|
||||||
|
|
|
@ -9,11 +9,10 @@
|
||||||
;; 2. This ensures a predictable load order, versus lazy loading using :defer or
|
;; 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
|
;; :after-call. This means users can use (after! org ...) and be sure that
|
||||||
;; their changes will override evil-collection's.
|
;; their changes will override evil-collection's.
|
||||||
;; 3. Eventually, I'd like to remove evil-collection. It changes too often,
|
;; 3. Ideally, we'd do away with evil-collection entirely. It changes too often,
|
||||||
;; introduces breaking bugs too frequently, and I don't always agree with
|
;; introduces breaking bugs too frequently, and I don't agree with all their
|
||||||
;; their design choices. Regardless, there are useful tidbits I'd like to
|
;; design choices. Regardless, it does mork than it causes trouble, so it may
|
||||||
;; keep. This will be a slow transition, but this file is where most of it
|
;; be here to stay.
|
||||||
;; will happen.
|
|
||||||
;; 4. Adds `+evil-collection-disabled-list', to make it easier for users to
|
;; 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
|
;; 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).
|
;; `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)
|
(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.
|
;; 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
|
(defvar evil-collection-mode-list
|
||||||
`(2048-game
|
`(2048-game
|
||||||
ag
|
ag
|
||||||
|
@ -152,7 +161,7 @@ variable for an explanation of the defaults (in comments). See
|
||||||
rtags
|
rtags
|
||||||
simple
|
simple
|
||||||
slime
|
slime
|
||||||
(term term ansi-term)
|
(term term ansi-term multi-term)
|
||||||
tetris
|
tetris
|
||||||
tide
|
tide
|
||||||
transmission
|
transmission
|
||||||
|
@ -173,15 +182,15 @@ variable for an explanation of the defaults (in comments). See
|
||||||
youtube-dl
|
youtube-dl
|
||||||
(ztree ztree-diff)))
|
(ztree ztree-diff)))
|
||||||
|
|
||||||
(defun +evil-collection-init (module)
|
(defun +evil-collection-init (module &optional disabled-list)
|
||||||
"Initialize evil-collection-MODULE.
|
"Initialize evil-collection-MODULE.
|
||||||
|
|
||||||
Unlike `evil-collection-init', this respects `+evil-collection-disabled-list',
|
Unlike `evil-collection-init', this respects `+evil-collection-disabled-list',
|
||||||
and complains if a module is loaded too early (during startup)."
|
and complains if a module is loaded too early (during startup)."
|
||||||
(unless (memq (or (car-safe module) module) +evil-collection-disabled-list)
|
(unless (memq (or (car-safe module) module) disabled-list)
|
||||||
(let ((module-sym (or (car-safe module) module)))
|
(doom-log "Initialized evil-collection-%s %s"
|
||||||
(doom-log "Initialized evil-collection-%s %s"
|
(or (car-safe module) module)
|
||||||
module-sym (if doom-init-time "" "(too early!)")))
|
(if doom-init-time "" "(too early!)"))
|
||||||
(with-demoted-errors "evil-collection error: %s"
|
(with-demoted-errors "evil-collection error: %s"
|
||||||
(evil-collection-init (list module)))))
|
(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
|
;; 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 to load immediately. We avoid this by loading them after
|
||||||
;; evil-collection has first loaded...
|
;; evil-collection has first loaded...
|
||||||
(after! evil-collection
|
(with-eval-after-load 'evil-collection
|
||||||
(let (+evil-collection-disabled-list)
|
(mapc #'+evil-collection-init '(comint custom help)))
|
||||||
(mapc #'+evil-collection-init '(comint custom help))))
|
|
||||||
|
|
||||||
;; ...or on first invokation of their associated major/minor modes.
|
;; ...or on first invokation of their associated major/minor modes.
|
||||||
(add-transient-hook! 'Buffer-menu-mode
|
(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 (mode evil-collection-mode-list)
|
||||||
(dolist (req (or (cdr-safe mode) (list mode)))
|
(dolist (req (or (cdr-safe mode) (list mode)))
|
||||||
(with-eval-after-load req
|
(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; -*-
|
;;; editor/evil/autoload/advice.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
(defun +evil--insert-newline (&optional above _noextranewline)
|
;;;###autoload
|
||||||
(let ((pos (save-excursion (beginning-of-line-text) (point)))
|
(defun +evil-escape-a (&rest _)
|
||||||
comment-auto-fill-only-comments)
|
"Call `doom/escape' if `evil-force-normal-state' is called interactively."
|
||||||
(require 'smartparens)
|
(when (called-interactively-p 'any)
|
||||||
(evil-narrow-to-field
|
(call-interactively #'doom/escape)))
|
||||||
(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
|
;;;###autoload
|
||||||
(defun +evil*insert-newline-below-and-respect-comments (orig-fn count)
|
(defun +evil-resolve-vim-path-a (file-name)
|
||||||
(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)
|
|
||||||
"Take a path and resolve any vim-like filename modifiers in it. This adds
|
"Take a path and resolve any vim-like filename modifiers in it. This adds
|
||||||
support for most vim file modifiers, as well as:
|
support for most vim file modifiers, as well as:
|
||||||
|
|
||||||
|
@ -148,8 +85,77 @@ more information on modifiers."
|
||||||
path file-name t t 1))))
|
path file-name t t 1))))
|
||||||
(replace-regexp-in-string regexp "\\1" file-name t)))
|
(replace-regexp-in-string regexp "\\1" file-name t)))
|
||||||
|
|
||||||
;;;###autoload (autoload '+evil*window-split "editor/evil/autoload/advice" nil t)
|
(defun +evil--insert-newline (&optional above _noextranewline)
|
||||||
(evil-define-command +evil*window-split (&optional count file)
|
(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."
|
"Same as `evil-window-split', but focuses (and recenters) the new split."
|
||||||
:repeat nil
|
:repeat nil
|
||||||
(interactive "P<f>")
|
(interactive "P<f>")
|
||||||
|
@ -164,8 +170,8 @@ more information on modifiers."
|
||||||
(balance-windows (window-parent)))
|
(balance-windows (window-parent)))
|
||||||
(if file (evil-edit file)))
|
(if file (evil-edit file)))
|
||||||
|
|
||||||
;;;###autoload (autoload '+evil*window-vsplit "editor/evil/autoload/advice" nil t)
|
;;;###autoload (autoload '+evil-window-vsplit-a "editor/evil/autoload/advice" nil t)
|
||||||
(evil-define-command +evil*window-vsplit (&optional count file)
|
(evil-define-command +evil-window-vsplit-a (&optional count file)
|
||||||
"Same as `evil-window-vsplit', but focuses (and recenters) the new split."
|
"Same as `evil-window-vsplit', but focuses (and recenters) the new split."
|
||||||
:repeat nil
|
:repeat nil
|
||||||
(interactive "P<f>")
|
(interactive "P<f>")
|
||||||
|
@ -181,18 +187,12 @@ more information on modifiers."
|
||||||
(if file (evil-edit file)))
|
(if file (evil-edit file)))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun +evil*escape (&rest _)
|
(defun +evil--make-numbered-markers-global-a (orig-fn char)
|
||||||
"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)
|
|
||||||
(or (and (>= char ?2) (<= char ?9))
|
(or (and (>= char ?2) (<= char ?9))
|
||||||
(funcall orig-fn char)))
|
(funcall orig-fn char)))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###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
|
"Make `try-expand-dabbrev' from `hippie-expand' work in minibuffer. See
|
||||||
`he-dabbrev-beg', so we need to redefine syntax for '/'."
|
`he-dabbrev-beg', so we need to redefine syntax for '/'."
|
||||||
(set-syntax-table (let* ((table (make-syntax-table)))
|
(set-syntax-table (let* ((table (make-syntax-table)))
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
;; editor/evil/autoload/evil.el -*- lexical-binding: t; -*-
|
;; editor/evil/autoload/evil.el -*- lexical-binding: t; -*-
|
||||||
;;;###if (featurep! :editor evil)
|
|
||||||
|
|
||||||
;;;###autodef
|
;;;###autodef
|
||||||
(defun set-evil-initial-state! (modes state)
|
(defun set-evil-initial-state! (modes state)
|
||||||
|
@ -12,72 +11,6 @@
|
||||||
(evil-set-initial-state modes state))))
|
(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
|
;;; Interactive commands
|
||||||
|
|
||||||
|
@ -167,28 +100,6 @@ integration."
|
||||||
t))
|
t))
|
||||||
prefix)))))
|
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)
|
;;;###autoload (autoload '+evil:apply-macro "editor/evil/autoload/evil" nil t)
|
||||||
(evil-define-operator +evil:apply-macro (beg end)
|
(evil-define-operator +evil:apply-macro (beg end)
|
||||||
"Apply macro to each line."
|
"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"))
|
(user-error "Must be called from a file-visiting buffer"))
|
||||||
(let* ((directory (file-name-directory buffer-file-name))
|
(let* ((directory (file-name-directory buffer-file-name))
|
||||||
(filename (file-name-nondirectory buffer-file-name))
|
(filename (file-name-nondirectory buffer-file-name))
|
||||||
(files (doom-files-in directory :depth 0 :sort t :match "/[^._][^/]*$"))
|
(files (doom-glob (file-name-directory buffer-file-name) "[!.]*"))
|
||||||
(index (cl-position filename files :test #'string=)))
|
(index (cl-position filename files :test #'file-equal-p)))
|
||||||
(when (null index)
|
(when (null index)
|
||||||
(user-error "Couldn't find this file in current directory"))
|
(user-error "Couldn't find this file in current directory"))
|
||||||
(let ((index (+ index n)))
|
(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-u-scroll t)
|
||||||
(defvar evil-want-C-w-scroll t)
|
(defvar evil-want-C-w-scroll t)
|
||||||
(defvar evil-want-Y-yank-to-eol 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)
|
:hook (doom-init-modules . evil-mode)
|
||||||
:demand t
|
:demand t
|
||||||
:preface
|
:preface
|
||||||
|
@ -36,9 +37,9 @@ directives. By default, this only recognizes C directives.")
|
||||||
;; more vim-like behavior
|
;; more vim-like behavior
|
||||||
evil-symbol-word-search t
|
evil-symbol-word-search t
|
||||||
;; cursor appearance
|
;; cursor appearance
|
||||||
evil-default-cursor '+evil-default-cursor
|
evil-default-cursor '+evil-default-cursor-fn
|
||||||
evil-normal-state-cursor 'box
|
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-insert-state-cursor 'bar
|
||||||
evil-visual-state-cursor 'hollow
|
evil-visual-state-cursor 'hollow
|
||||||
;; must be set before evil/evil-collection is loaded
|
;; 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)
|
(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
|
;; Start help-with-tutorial in emacs state
|
||||||
(advice-add #'help-with-tutorial :after (lambda (&rest _) (evil-emacs-state +1)))
|
(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
|
;; 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
|
||||||
(set-popup-rules!
|
(defun +evil--init-popup-rules-h ()
|
||||||
'(("^\\*evil-registers" :size 0.3)
|
(set-popup-rules!
|
||||||
("^\\*Command Line" :size 8))))
|
'(("^\\*evil-registers" :size 0.3)
|
||||||
(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
|
;; 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
|
;; 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--default-cursor-color "#ffffff")
|
||||||
(defvar +evil--emacs-cursor-color "#ff9999")
|
(defvar +evil--emacs-cursor-color "#ff9999")
|
||||||
|
|
||||||
(defun +evil|update-cursor-color ()
|
(add-hook! 'doom-load-theme-hook
|
||||||
(setq +evil--default-cursor-color (face-background 'cursor)
|
(defun +evil-update-cursor-color-h ()
|
||||||
+evil--emacs-cursor-color (face-foreground 'warning)))
|
(setq +evil--default-cursor-color (face-background 'cursor)
|
||||||
(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))
|
(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))
|
(evil-set-cursor-color +evil--emacs-cursor-color))
|
||||||
|
|
||||||
(defun +evil|update-shift-width ()
|
(setq-hook! 'after-change-major-mode-hook evil-shift-width tab-width)
|
||||||
(setq evil-shift-width tab-width))
|
|
||||||
(add-hook 'after-change-major-mode-hook #'+evil|update-shift-width)
|
|
||||||
|
|
||||||
|
|
||||||
;; --- keybind fixes ----------------------
|
;; --- keybind fixes ----------------------
|
||||||
|
@ -86,92 +91,101 @@ directives. By default, this only recognizes C directives.")
|
||||||
;; `evil-delete' in wgrep buffers.
|
;; `evil-delete' in wgrep buffers.
|
||||||
(define-key wgrep-mode-map [remap evil-delete] #'+evil-delete))
|
(define-key wgrep-mode-map [remap evil-delete] #'+evil-delete))
|
||||||
|
|
||||||
(defun +evil|disable-highlights ()
|
(add-hook! 'doom-escape-hook
|
||||||
"Disable ex search buffer highlights."
|
(defun +evil-disable-ex-highlights-h ()
|
||||||
(when (evil-ex-hl-active-p 'evil-ex-search)
|
"Disable ex search buffer highlights."
|
||||||
(evil-ex-nohighlight)
|
(when (evil-ex-hl-active-p 'evil-ex-search)
|
||||||
t))
|
(evil-ex-nohighlight)
|
||||||
(add-hook 'doom-escape-hook #'+evil|disable-highlights)
|
t)))
|
||||||
|
|
||||||
|
|
||||||
;; --- evil hacks -------------------------
|
;; --- evil hacks -------------------------
|
||||||
(defun +evil|display-vimlike-save-message ()
|
|
||||||
"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
|
(unless noninteractive
|
||||||
(setq save-silently t)
|
(setq save-silently t)
|
||||||
(add-hook 'after-save-hook #'+evil|display-vimlike-save-message))
|
(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)))))
|
||||||
;; Make ESC (from normal mode) the universal escaper. See `doom-escape-hook'.
|
;; 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
|
;; 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
|
;; 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,
|
;; file modifiers like %:p:h. This adds support for most of vim's modifiers,
|
||||||
;; and one custom one: %:P (expand to the project root).
|
;; 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
|
;; 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
|
;; Focus and recenter new splits
|
||||||
(advice-add #'evil-window-split :override #'+evil*window-split)
|
(advice-add #'evil-window-split :override #'+evil-window-split-a)
|
||||||
(advice-add #'evil-window-vsplit :override #'+evil*window-vsplit)
|
(advice-add #'evil-window-vsplit :override #'+evil-window-vsplit-a)
|
||||||
|
|
||||||
;; In evil, registers 2-9 are buffer-local. In vim, they're global, so...
|
;; 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')
|
;; 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-above :around #'+evil--insert-newline-above-and-respect-comments-a)
|
||||||
(advice-add #'evil-open-below :around #'+evil*insert-newline-below-and-respect-comments)
|
(advice-add #'evil-open-below :around #'+evil--insert-newline-below-and-respect-comments-a)
|
||||||
|
|
||||||
;; Recenter screen after most searches
|
;; 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-visualstar/begin-search-backward
|
||||||
evil-ex-search-word-backward
|
evil-ex-search-word-backward
|
||||||
evil-ex-search-word-backward
|
evil-ex-search-word-backward
|
||||||
evil-ex-search-forward
|
evil-ex-search-forward
|
||||||
evil-ex-search-backward)
|
evil-ex-search-backward))
|
||||||
:after #'doom*recenter)
|
(advice-add fn :after #'doom-recenter-a))
|
||||||
|
|
||||||
;; --- custom interactive codes -----------
|
;; --- custom interactive codes -----------
|
||||||
;; These arg types will highlight matches in the current buffer
|
;; 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 regexp-match
|
||||||
(evil-ex-define-argument-type global-match :runner +evil-ex-global-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
|
;; Other commands can make use of this
|
||||||
(evil-define-interactive-code "<//>"
|
(evil-define-interactive-code "<//>"
|
||||||
:ex-arg buffer-match (list (if (evil-ex-p) evil-ex-argument)))
|
:ex-arg regexp-match
|
||||||
(evil-define-interactive-code "<//g>"
|
(+evil--regexp-match-args evil-ex-argument))
|
||||||
:ex-arg global-match (list (if (evil-ex-p) evil-ex-argument)))
|
|
||||||
|
|
||||||
;; By default :g[lobal] doesn't highlight matches in the current buffer. I've
|
(evil-define-interactive-code "<//!>"
|
||||||
;; got to write my own argument type and interactive code to get it to do so.
|
:ex-arg regexp-global-match
|
||||||
(evil-ex-define-argument-type global-delim-match :runner +evil-ex-global-delim-match)
|
(+evil--regexp-match-args evil-ex-argument))
|
||||||
(dolist (sym '(evil-ex-global evil-ex-global-inverted))
|
|
||||||
(evil-set-command-property sym :ex-arg 'global-delim-match))
|
|
||||||
|
|
||||||
;; Forward declare these so that ex completion works, even if the autoloaded
|
;; Forward declare these so that ex completion works, even if the autoloaded
|
||||||
;; functions aren't loaded yet.
|
;; functions aren't loaded yet.
|
||||||
(evil-set-command-properties
|
(evil-add-command-properties '+evil:align :ex-arg 'regexp-match)
|
||||||
'+evil:align :move-point t :ex-arg 'buffer-match :ex-bang t :keep-visual t :suppress-operator t)
|
(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'
|
;; `evil-collection'
|
||||||
(when (and (featurep! +everywhere)
|
(when (and (featurep! +everywhere)
|
||||||
(not doom-reloading-p))
|
(not doom-reloading-p))
|
||||||
(load! "+everywhere"))
|
(load! "+everywhere"))
|
||||||
|
|
||||||
;; Custom evil ex commands
|
;; Lazy load evil ex commands
|
||||||
(load! "+commands"))
|
(delq! 'evil-ex features)
|
||||||
|
(add-transient-hook! 'evil-ex (provide 'evil-ex))
|
||||||
|
(after! evil-ex (load! "+commands")))
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;; Packages
|
;; Packages
|
||||||
|
|
||||||
(def-package! evil-commentary
|
(use-package! evil-commentary
|
||||||
:commands (evil-commentary
|
:commands (evil-commentary
|
||||||
evil-commentary-yank
|
evil-commentary-yank
|
||||||
evil-commentary-yank-line
|
evil-commentary-yank-line
|
||||||
|
@ -179,8 +193,8 @@ directives. By default, this only recognizes C directives.")
|
||||||
:config (evil-commentary-mode 1))
|
:config (evil-commentary-mode 1))
|
||||||
|
|
||||||
|
|
||||||
(def-package! evil-easymotion
|
(use-package! evil-easymotion
|
||||||
:commands (evilem-create evilem-default-keybindings)
|
:commands evilem-create evilem-default-keybindings
|
||||||
:config
|
:config
|
||||||
;; Use evil-search backend, instead of isearch
|
;; Use evil-search backend, instead of isearch
|
||||||
(evilem-make-motion evilem-motion-search-next #'evil-ex-search-next
|
(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))))
|
:bind ((evil-ex-search-highlight-all nil))))
|
||||||
|
|
||||||
|
|
||||||
(def-package! evil-embrace
|
(use-package! evil-embrace
|
||||||
:commands (embrace-add-pair embrace-add-pair-regexp)
|
:commands embrace-add-pair embrace-add-pair-regexp
|
||||||
:hook (LaTeX-mode . embrace-LaTeX-mode-hook)
|
:hook (LaTeX-mode . embrace-LaTeX-mode-hook)
|
||||||
:hook (org-mode . embrace-org-mode-hook)
|
:hook (org-mode . embrace-org-mode-hook)
|
||||||
:hook ((ruby-mode enh-ruby-mode) . embrace-ruby-mode-hook)
|
:hook ((ruby-mode enh-ruby-mode) . embrace-ruby-mode-hook)
|
||||||
:hook (emacs-lisp-mode . embrace-emacs-lisp-mode-hook)
|
:hook (emacs-lisp-mode . embrace-emacs-lisp-mode-hook)
|
||||||
:hook ((lisp-mode emacs-lisp-mode clojure-mode racket-mode)
|
:hook ((lisp-mode emacs-lisp-mode clojure-mode racket-mode)
|
||||||
. +evil|embrace-lisp-mode-hook)
|
. +evil-embrace-lisp-mode-hook-h)
|
||||||
:hook ((org-mode LaTeX-mode) . +evil|embrace-latex-mode-hook)
|
: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)
|
: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
|
:init
|
||||||
(after! evil-surround
|
(after! evil-surround
|
||||||
(evil-embrace-enable-evil-surround-integration))
|
(evil-embrace-enable-evil-surround-integration))
|
||||||
:config
|
:config
|
||||||
(setq evil-embrace-show-help-p nil)
|
(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))
|
(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
|
(push (cons ?f (make-embrace-pair-struct
|
||||||
:key ?f
|
:key ?f
|
||||||
:read-function #'+evil--embrace-elisp-fn
|
:read-function #'+evil--embrace-elisp-fn
|
||||||
|
@ -222,7 +236,7 @@ directives. By default, this only recognizes C directives.")
|
||||||
:right-regexp ")"))
|
:right-regexp ")"))
|
||||||
embrace--pairs-list))
|
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)
|
(set (make-local-variable 'evil-embrace-evil-surround-keys)
|
||||||
(delq ?< evil-embrace-evil-surround-keys))
|
(delq ?< evil-embrace-evil-surround-keys))
|
||||||
(push (cons ?< (make-embrace-pair-struct
|
(push (cons ?< (make-embrace-pair-struct
|
||||||
|
@ -241,9 +255,9 @@ directives. By default, this only recognizes C directives.")
|
||||||
:right-regexp "\\[]})]")))
|
:right-regexp "\\[]})]")))
|
||||||
|
|
||||||
|
|
||||||
(def-package! evil-escape
|
(use-package! evil-escape
|
||||||
:commands (evil-escape)
|
:commands evil-escape
|
||||||
:after-call (evil-normal-state-exit-hook)
|
:after-call evil-normal-state-exit-hook
|
||||||
:init
|
:init
|
||||||
(setq evil-escape-excluded-states '(normal visual multiedit emacs motion)
|
(setq evil-escape-excluded-states '(normal visual multiedit emacs motion)
|
||||||
evil-escape-excluded-major-modes '(neotree-mode treemacs-mode vterm-mode)
|
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))
|
(evil-escape-mode +1))
|
||||||
|
|
||||||
|
|
||||||
(def-package! evil-exchange
|
(use-package! evil-exchange
|
||||||
:commands evil-exchange
|
:commands evil-exchange
|
||||||
:config
|
:config
|
||||||
(defun +evil|escape-exchange ()
|
(add-hook! 'doom-escape-hook
|
||||||
(when evil-exchange--overlays
|
(defun +evil--escape-exchange-h ()
|
||||||
(evil-exchange-cancel)
|
(when evil-exchange--overlays
|
||||||
t))
|
(evil-exchange-cancel)
|
||||||
(add-hook 'doom-escape-hook #'+evil|escape-exchange))
|
t))))
|
||||||
|
|
||||||
|
|
||||||
(def-package! evil-snipe
|
(use-package! evil-snipe
|
||||||
:commands (evil-snipe-mode evil-snipe-override-mode
|
:commands (evil-snipe-mode
|
||||||
evil-snipe-local-mode evil-snipe-override-local-mode)
|
evil-snipe-override-mode
|
||||||
|
evil-snipe-local-mode
|
||||||
|
evil-snipe-override-local-mode)
|
||||||
:after-call pre-command-hook
|
:after-call pre-command-hook
|
||||||
:init
|
:init
|
||||||
(setq evil-snipe-smart-case t
|
(setq evil-snipe-smart-case t
|
||||||
|
@ -282,7 +298,7 @@ directives. By default, this only recognizes C directives.")
|
||||||
(evil-snipe-override-mode +1))
|
(evil-snipe-override-mode +1))
|
||||||
|
|
||||||
|
|
||||||
(def-package! evil-surround
|
(use-package! evil-surround
|
||||||
:commands (global-evil-surround-mode
|
:commands (global-evil-surround-mode
|
||||||
evil-surround-edit
|
evil-surround-edit
|
||||||
evil-Surround-edit
|
evil-Surround-edit
|
||||||
|
@ -290,8 +306,17 @@ directives. By default, this only recognizes C directives.")
|
||||||
:config (global-evil-surround-mode 1))
|
: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 #
|
;; Allows you to use the selection for * and #
|
||||||
(def-package! evil-visualstar
|
(use-package! evil-visualstar
|
||||||
:commands (evil-visualstar/begin-search
|
:commands (evil-visualstar/begin-search
|
||||||
evil-visualstar/begin-search-forward
|
evil-visualstar/begin-search-forward
|
||||||
evil-visualstar/begin-search-backward)
|
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
|
(use-package! exato
|
||||||
:commands (evil-outer-xml-attr evil-inner-xml-attr))
|
:commands evil-outer-xml-attr evil-inner-xml-attr)
|
||||||
|
|
|
@ -9,14 +9,14 @@
|
||||||
(package! evil-escape)
|
(package! evil-escape)
|
||||||
(package! evil-exchange)
|
(package! evil-exchange)
|
||||||
(package! evil-indent-plus)
|
(package! evil-indent-plus)
|
||||||
(package! evil-numbers :recipe (:fetcher github :repo "janpath/evil-numbers"))
|
(package! evil-numbers :recipe (:host github :repo "janpath/evil-numbers"))
|
||||||
(package! evil-textobj-anyblock)
|
|
||||||
(package! evil-snipe)
|
(package! evil-snipe)
|
||||||
(package! evil-surround)
|
(package! evil-surround)
|
||||||
|
(package! evil-textobj-anyblock)
|
||||||
|
(package! evil-traces)
|
||||||
(package! evil-visualstar)
|
(package! evil-visualstar)
|
||||||
(package! exato)
|
(package! exato)
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
(when (featurep! +everywhere)
|
(when (featurep! +everywhere)
|
||||||
;; `evil-collection-neotree' uses the `neotree-make-executor' macro, but this
|
;; `evil-collection-neotree' uses the `neotree-make-executor' macro, but this
|
||||||
|
|
|
@ -10,10 +10,10 @@
|
||||||
(after-all
|
(after-all
|
||||||
(unload-feature 'evil t))
|
(unload-feature 'evil t))
|
||||||
(before-each
|
(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)))
|
(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"
|
(describe "file modifiers"
|
||||||
(it "supports basic vim file modifiers"
|
(it "supports basic vim file modifiers"
|
||||||
(let ((buffer-file-name "~/.emacs.d/test/modules/feature/test-evil.el")
|
(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)
|
(or (file-in-directory-p file doom-private-dir)
|
||||||
(file-in-directory-p file doom-emacs-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
|
"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
|
must be non-read-only, empty, and there must be a rule in
|
||||||
`+file-templates-alist' that applies to it."
|
`+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)
|
(bobp) (eobp)
|
||||||
(not (string-match-p "^ *\\*" (buffer-name))))
|
(not (string-match-p "^ *\\*" (buffer-name))))
|
||||||
(when-let (rule (cl-find-if #'+file-template-p +file-templates-alist))
|
(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)))
|
(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)
|
:group 'doom-themes)
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun +fold-hideshow-haml-forward-sexp (arg)
|
(defun +fold-hideshow-haml-forward-sexp-fn (arg)
|
||||||
(haml-forward-sexp arg)
|
(haml-forward-sexp arg)
|
||||||
(move-beginning-of-line 1))
|
(move-beginning-of-line 1))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun +fold-hideshow-forward-block-by-indent (_arg)
|
(defun +fold-hideshow-forward-block-by-indent-fn (_arg)
|
||||||
(let ((start (current-indentation)))
|
(let ((start (current-indentation)))
|
||||||
(forward-line)
|
(forward-line)
|
||||||
(unless (= start (current-indentation))
|
(unless (= start (current-indentation))
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
(end-of-line)))))
|
(end-of-line)))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun +fold-hideshow-set-up-overlay (ov)
|
(defun +fold-hideshow-set-up-overlay-fn (ov)
|
||||||
(when (eq 'code (overlay-get ov 'hs))
|
(when (eq 'code (overlay-get ov 'hs))
|
||||||
(when (featurep 'vimish-fold)
|
(when (featurep 'vimish-fold)
|
||||||
(overlay-put
|
(overlay-put
|
||||||
|
|
|
@ -17,21 +17,22 @@
|
||||||
;;
|
;;
|
||||||
;; Packages
|
;; Packages
|
||||||
|
|
||||||
(def-package! hideshow ; built-in
|
(use-package! hideshow ; built-in
|
||||||
:commands (hs-toggle-hiding hs-hide-block hs-hide-level hs-show-all hs-hide-all)
|
:commands (hs-toggle-hiding
|
||||||
|
hs-hide-block
|
||||||
|
hs-hide-level
|
||||||
|
hs-show-all
|
||||||
|
hs-hide-all)
|
||||||
:config
|
:config
|
||||||
(setq hs-hide-comments-when-hiding-all nil
|
(setq hs-hide-comments-when-hiding-all nil
|
||||||
;; Nicer code-folding overlays (with fringe indicators)
|
;; 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."
|
"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)
|
(unless (bound-and-true-p hs-minor-mode)
|
||||||
(hs-minor-mode +1)))
|
(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
|
;; extra folding support for more languages
|
||||||
(unless (assq 't hs-special-modes-alist)
|
(unless (assq 't hs-special-modes-alist)
|
||||||
|
@ -41,8 +42,8 @@
|
||||||
(yaml-mode "\\s-*\\_<\\(?:[^:]+\\)\\_>"
|
(yaml-mode "\\s-*\\_<\\(?:[^:]+\\)\\_>"
|
||||||
""
|
""
|
||||||
"#"
|
"#"
|
||||||
+fold-hideshow-forward-block-by-indent nil)
|
+fold-hideshow-forward-block-by-indent-fn nil)
|
||||||
(haml-mode "[#.%]" "\n" "/" +fold-hideshow-haml-forward-sexp nil)
|
(haml-mode "[#.%]" "\n" "/" +fold-hideshow-haml-forward-sexp-fn nil)
|
||||||
(ruby-mode "class\\|d\\(?:ef\\|o\\)\\|module\\|[[{]"
|
(ruby-mode "class\\|d\\(?:ef\\|o\\)\\|module\\|[[{]"
|
||||||
"end\\|[]}]"
|
"end\\|[]}]"
|
||||||
"#\\|=begin"
|
"#\\|=begin"
|
||||||
|
@ -61,7 +62,7 @@
|
||||||
'((t))))))
|
'((t))))))
|
||||||
|
|
||||||
|
|
||||||
(def-package! evil-vimish-fold
|
(use-package! evil-vimish-fold
|
||||||
:when (featurep! :editor evil)
|
:when (featurep! :editor evil)
|
||||||
:commands (evil-vimish-fold/next-fold evil-vimish-fold/previous-fold
|
:commands (evil-vimish-fold/next-fold evil-vimish-fold/previous-fold
|
||||||
evil-vimish-fold/delete evil-vimish-fold/delete-all
|
evil-vimish-fold/delete evil-vimish-fold/delete-all
|
||||||
|
|
|
@ -98,7 +98,7 @@ Stolen shamelessly from go-mode"
|
||||||
(if fmt (cons (intern fmt) t))))
|
(if fmt (cons (intern fmt) t))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun +format*probe (orig-fn)
|
(defun +format-probe-a (orig-fn)
|
||||||
"Use `+format-with' instead, if it is set."
|
"Use `+format-with' instead, if it is set."
|
||||||
(if +format-with
|
(if +format-with
|
||||||
(list +format-with t)
|
(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.
|
position of the first change in the buffer.
|
||||||
|
|
||||||
See `+format/buffer' for the interactive version of this function, and
|
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)
|
(if (not formatter)
|
||||||
'no-formatter
|
'no-formatter
|
||||||
(let ((f-function (gethash formatter format-all--format-table))
|
(let ((f-function (gethash formatter format-all--format-table))
|
||||||
|
@ -228,12 +228,12 @@ is selected)."
|
||||||
;; Hooks
|
;; Hooks
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun +format|enable-on-save ()
|
(defun +format-enable-on-save-h ()
|
||||||
"Enables formatting on save."
|
"Enables formatting on save."
|
||||||
(add-hook 'before-save-hook #'+format|buffer nil t))
|
(add-hook 'before-save-hook #'+format-buffer-h nil t))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defalias '+format|buffer #'+format/buffer
|
(defalias '+format-buffer-h #'+format/buffer
|
||||||
"Format the source code in the current buffer with minimal feedback.
|
"Format the source code in the current buffer with minimal feedback.
|
||||||
|
|
||||||
Meant for `before-save-hook'.")
|
Meant for `before-save-hook'.")
|
||||||
|
|
|
@ -25,7 +25,7 @@ Indentation is always preserved when formatting regions.")
|
||||||
;;
|
;;
|
||||||
;;; Bootstrap
|
;;; Bootstrap
|
||||||
|
|
||||||
(defun +format|enable-on-save-maybe ()
|
(defun +format-enable-on-save-maybe-h ()
|
||||||
"Enable formatting on save in certain major modes.
|
"Enable formatting on save in certain major modes.
|
||||||
|
|
||||||
This is controlled by `+format-on-save-enabled-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)))
|
(format-all-mode +1)))
|
||||||
|
|
||||||
(when (featurep! +onsave)
|
(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
|
;; Allow a specific formatter to be used by setting `+format-with', either
|
||||||
;; buffer-locally or let-bound.
|
;; 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
|
;; Doom uses a modded `format-all-buffer', which
|
||||||
;; 1. Enables partial reformatting (while preserving leading indentation),
|
;; 1. Enables partial reformatting (while preserving leading indentation),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
;;; editor/lispy/config.el -*- lexical-binding: t; -*-
|
;;; editor/lispy/config.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
(def-package! lispy
|
(use-package! lispy
|
||||||
:hook ((common-lisp-mode . lispy-mode)
|
:hook ((common-lisp-mode . lispy-mode)
|
||||||
(emacs-lisp-mode . lispy-mode)
|
(emacs-lisp-mode . lispy-mode)
|
||||||
(scheme-mode . lispy-mode)
|
(scheme-mode . lispy-mode)
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
(setq lispy-close-quotes-at-end-p t)
|
(setq lispy-close-quotes-at-end-p t)
|
||||||
(add-hook 'lispy-mode-hook #'turn-off-smartparens-mode))
|
(add-hook 'lispy-mode-hook #'turn-off-smartparens-mode))
|
||||||
|
|
||||||
(def-package! lispyville
|
(use-package! lispyville
|
||||||
:when (featurep! :editor evil)
|
:when (featurep! :editor evil)
|
||||||
:hook (lispy-mode . lispyville-mode)
|
:hook (lispy-mode . lispyville-mode)
|
||||||
:config
|
:config
|
||||||
|
|
|
@ -1,18 +1,27 @@
|
||||||
;;; editor/multiple-cursors/config.el -*- lexical-binding: t; -*-
|
;;; editor/multiple-cursors/config.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
(def-package! evil-mc
|
(use-package! evil-mc
|
||||||
:when (featurep! :editor evil)
|
:when (featurep! :editor evil)
|
||||||
:commands (evil-mc-make-cursor-here evil-mc-make-all-cursors
|
:commands (evil-mc-make-cursor-here
|
||||||
evil-mc-undo-all-cursors evil-mc-pause-cursors
|
evil-mc-make-all-cursors
|
||||||
evil-mc-resume-cursors evil-mc-make-and-goto-first-cursor
|
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-and-goto-last-cursor
|
||||||
evil-mc-make-cursor-move-next-line
|
evil-mc-make-cursor-move-next-line
|
||||||
evil-mc-make-cursor-move-prev-line evil-mc-make-cursor-at-pos
|
evil-mc-make-cursor-move-prev-line
|
||||||
evil-mc-has-cursors-p evil-mc-make-and-goto-next-cursor
|
evil-mc-make-cursor-at-pos
|
||||||
evil-mc-skip-and-goto-next-cursor evil-mc-make-and-goto-prev-cursor
|
evil-mc-has-cursors-p
|
||||||
evil-mc-skip-and-goto-prev-cursor evil-mc-make-and-goto-next-match
|
evil-mc-make-and-goto-next-cursor
|
||||||
evil-mc-skip-and-goto-next-match evil-mc-skip-and-goto-next-match
|
evil-mc-skip-and-goto-next-cursor
|
||||||
evil-mc-make-and-goto-prev-match evil-mc-skip-and-goto-prev-match)
|
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
|
:init
|
||||||
(defvar evil-mc-key-map (make-sparse-keymap))
|
(defvar evil-mc-key-map (make-sparse-keymap))
|
||||||
:config
|
:config
|
||||||
|
@ -39,13 +48,13 @@
|
||||||
;; disable evil-escape in evil-mc; causes unwanted text on invocation
|
;; disable evil-escape in evil-mc; causes unwanted text on invocation
|
||||||
(add-to-list 'evil-mc-incompatible-minor-modes 'evil-escape-mode nil #'eq)
|
(add-to-list 'evil-mc-incompatible-minor-modes 'evil-escape-mode nil #'eq)
|
||||||
|
|
||||||
(defun +multiple-cursors|escape-multiple-cursors ()
|
(add-hook! 'doom-escape-hook
|
||||||
"Clear evil-mc cursors and restore state."
|
(defun +multiple-cursors-escape-multiple-cursors-h ()
|
||||||
(when (evil-mc-has-cursors-p)
|
"Clear evil-mc cursors and restore state."
|
||||||
(evil-mc-undo-all-cursors)
|
(when (evil-mc-has-cursors-p)
|
||||||
(evil-mc-resume-cursors)
|
(evil-mc-undo-all-cursors)
|
||||||
t))
|
(evil-mc-resume-cursors)
|
||||||
(add-hook 'doom-escape-hook #'+multiple-cursors|escape-multiple-cursors)
|
t)))
|
||||||
|
|
||||||
;; Forward declare these so that ex completion and evil-mc support is
|
;; Forward declare these so that ex completion and evil-mc support is
|
||||||
;; recognized before the autoloaded functions are loaded.
|
;; recognized before the autoloaded functions are loaded.
|
||||||
|
@ -71,45 +80,45 @@
|
||||||
(defvar +mc--compat-evil-prev-state nil)
|
(defvar +mc--compat-evil-prev-state nil)
|
||||||
(defvar +mc--compat-mark-was-active nil)
|
(defvar +mc--compat-mark-was-active nil)
|
||||||
|
|
||||||
(defun +multiple-cursors|compat-switch-to-emacs-state ()
|
(add-hook! 'multiple-cursors-mode-enabled-hook
|
||||||
(when (and (bound-and-true-p evil-mode)
|
(defun +multiple-cursors-compat-switch-to-emacs-state-h ()
|
||||||
(not (memq evil-state '(insert emacs))))
|
(when (and (bound-and-true-p evil-mode)
|
||||||
(setq +mc--compat-evil-prev-state evil-state)
|
(not (memq evil-state '(insert emacs))))
|
||||||
(when (region-active-p)
|
(setq +mc--compat-evil-prev-state evil-state)
|
||||||
(setq +mc--compat-mark-was-active t))
|
(when (region-active-p)
|
||||||
(let ((mark-before (mark))
|
(setq +mc--compat-mark-was-active t))
|
||||||
(point-before (point)))
|
(let ((mark-before (mark))
|
||||||
(evil-emacs-state 1)
|
(point-before (point)))
|
||||||
(when (or +mc--compat-mark-was-active (region-active-p))
|
(evil-emacs-state 1)
|
||||||
(goto-char point-before)
|
(when (or +mc--compat-mark-was-active (region-active-p))
|
||||||
(set-mark mark-before)))))
|
(goto-char point-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
|
||||||
(when +mc--compat-evil-prev-state
|
(defun +multiple-cursors-compat-back-to-previous-state-h ()
|
||||||
(unwind-protect
|
(when +mc--compat-evil-prev-state
|
||||||
(case +mc--compat-evil-prev-state
|
(unwind-protect
|
||||||
((normal visual) (evil-force-normal-state))
|
(case +mc--compat-evil-prev-state
|
||||||
(t (message "Don't know how to handle previous state: %S"
|
((normal visual) (evil-force-normal-state))
|
||||||
+mc--compat-evil-prev-state)))
|
(t (message "Don't know how to handle previous state: %S"
|
||||||
(setq +mc--compat-evil-prev-state nil)
|
+mc--compat-evil-prev-state)))
|
||||||
(setq +mc--compat-mark-was-active nil))))
|
(setq +mc--compat-evil-prev-state 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
|
;; When running edit-lines, point will return (position + 1) as a result of
|
||||||
;; result of how evil deals with regions
|
;; how evil deals with regions
|
||||||
(defun +multiple-cursors*adjust-mark-for-evil (&rest _)
|
(defadvice! +multiple--cursors-adjust-mark-for-evil-a (&rest _)
|
||||||
|
:before #'mc/edit-lines
|
||||||
(when (and (bound-and-true-p evil-mode)
|
(when (and (bound-and-true-p evil-mode)
|
||||||
(not (memq evil-state '(insert emacs))))
|
(not (memq evil-state '(insert emacs))))
|
||||||
(if (> (point) (mark))
|
(if (> (point) (mark))
|
||||||
(goto-char (1- (point)))
|
(goto-char (1- (point)))
|
||||||
(push-mark (1- (mark))))))
|
(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
|
||||||
(if rectangular-region-mode
|
(defun +multiple-cursors-evil-compat-rect-switch-state-h ()
|
||||||
(+multiple-cursors|compat-switch-to-emacs-state)
|
(if rectangular-region-mode
|
||||||
(setq +mc--compat-evil-prev-state nil)))
|
(+multiple-cursors-compat-switch-to-emacs-state-h)
|
||||||
(add-hook 'rectangular-region-mode-hook '+multiple-cursors|evil-compat-rect-switch-state)
|
(setq +mc--compat-evil-prev-state nil))))
|
||||||
|
|
||||||
(defvar mc--default-cmds-to-run-once nil)))
|
(defvar mc--default-cmds-to-run-once nil)))
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
;;; editor/objed/config.el -*- lexical-binding: t; -*-
|
;;; editor/objed/config.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
(def-package! objed
|
(use-package! objed
|
||||||
:after-call pre-command-hook
|
:after-call pre-command-hook
|
||||||
:config
|
:config
|
||||||
|
|
||||||
;; Prevent undo actions from exiting edit state
|
;; Prevent undo actions from exiting edit state
|
||||||
(add-to-list 'objed-keeper-commands 'undo-tree-undo)
|
(add-to-list 'objed-keeper-commands 'undo-tree-undo)
|
||||||
(add-to-list 'objed-keeper-commands 'undo-tree-redo)
|
(add-to-list 'objed-keeper-commands 'undo-tree-redo)
|
||||||
|
@ -11,21 +10,20 @@
|
||||||
|
|
||||||
(defvar +objed--extra-face-remaps nil)
|
(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."
|
"Add extra face remaps when objed activates."
|
||||||
|
:after 'objed--init
|
||||||
(when (memq 'objed-hl (assq 'hl-line face-remapping-alist))
|
(when (memq 'objed-hl (assq 'hl-line face-remapping-alist))
|
||||||
(push (face-remap-add-relative 'solaire-hl-line-face 'objed-hl)
|
(push (face-remap-add-relative 'solaire-hl-line-face 'objed-hl)
|
||||||
+objed--extra-face-remaps)))
|
+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."
|
"Remove extra face remaps when objed de-activates."
|
||||||
|
:after 'objed--reset
|
||||||
(unless (memq 'objed-hl (assq 'hl-line face-remapping-alist))
|
(unless (memq 'objed-hl (assq 'hl-line face-remapping-alist))
|
||||||
(dolist (remap +objed--extra-face-remaps)
|
(dolist (remap +objed--extra-face-remaps)
|
||||||
(face-remap-remove-relative remap))
|
(face-remap-remove-relative remap))
|
||||||
(setq +objed--extra-face-remaps nil)))
|
(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)
|
(unless (featurep! +manual)
|
||||||
(objed-mode +1)))
|
(objed-mode +1)))
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
;;; editor/parinfer/config.el -*- lexical-binding: t; -*-
|
;;; 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)
|
:hook ((emacs-lisp-mode clojure-mode scheme-mode lisp-mode) . parinfer-mode)
|
||||||
:init
|
:init
|
||||||
(setq parinfer-extensions
|
(setq parinfer-extensions
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
`rotate-text' will cycle through."
|
`rotate-text' will cycle through."
|
||||||
(declare (indent defun))
|
(declare (indent defun))
|
||||||
(dolist (mode (doom-enlist modes))
|
(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
|
(fset fn-name
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(setq-local rotate-text-local-symbols symbols)
|
(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