Merge branch 'develop' into fix/add-add-featurep-condition-to-global-bindings

This commit is contained in:
Henrik Lissner 2019-10-03 14:57:19 -04:00 committed by GitHub
commit a5d9079c43
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
184 changed files with 2868 additions and 1922 deletions

View file

@ -10,9 +10,6 @@ before_install:
- export PATH="/home/travis/.evm/bin:$PATH" - export PATH="/home/travis/.evm/bin:$PATH"
- evm config path /tmp - evm config path /tmp
- evm install $EVM_EMACS --use --skip - evm install $EVM_EMACS --use --skip
- mkdir -p ~/.config/doom
- cp init.test.el ~/.config/doom/init.el
- bin/doom -y -i install
env: env:
- EVM_EMACS=emacs-25.3-travis - EVM_EMACS=emacs-25.3-travis
- EVM_EMACS=emacs-26.1-travis - EVM_EMACS=emacs-26.1-travis
@ -22,5 +19,5 @@ matrix:
- env: EVM_EMACS=emacs-git-snapshot-travis - env: EVM_EMACS=emacs-git-snapshot-travis
script: script:
- bin/doom version - bin/doom version
- bin/doom -d test - bin/doom test
- bin/doom -y compile - bin/doom -y compile

View file

@ -82,7 +82,7 @@
;; Bootstrap Doom ;; Bootstrap Doom
(if (not noninteractive) (if (not noninteractive)
(progn (let ((doom-interactive-mode t))
(load (expand-file-name "init.el" user-emacs-directory) (load (expand-file-name "init.el" user-emacs-directory)
nil 'nomessage) nil 'nomessage)
(doom-run-all-startup-hooks-h)) (doom-run-all-startup-hooks-h))
@ -91,32 +91,31 @@
(doom-initialize 'force-p) (doom-initialize 'force-p)
(doom-initialize-modules) (doom-initialize-modules)
(cond ((and (not (cdr args)) (cond ((or (not args)
(member (car args) '("help" "h"))) (and (not (cdr args))
(usage)) (member (car args) '("help" "h"))))
((not args) (unless args
(print! (error "No command detected.\n")) (print! (error "No command detected.\n")))
(usage)) (usage))
((require 'core-cli) ((require 'core-cli)
(let ((default-directory user-emacs-directory)) (setq argv nil)
(setq argv nil) (condition-case e
(condition-case e (doom-dispatch (car args) (cdr args))
(doom-dispatch (car args) (cdr args)) (user-error
(user-error (print! (error "%s\n") (error-message-string e))
(print! (error "%s\n") (error-message-string e)) (print! (yellow "See 'doom help %s' for documentation on this command.") (car args)))
(print! (yellow "See 'doom help %s' for documentation on this command.") (car args))) ((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)))))))))

View file

@ -1,7 +1,7 @@
#!/usr/bin/env sh #!/usr/bin/env sh
":"; command -v emacs >/dev/null || { >&2 echo "Emacs isn't installed"; exit 1; } # -*-emacs-lisp-*- ":"; command -v emacs >/dev/null || { >&2 echo "Emacs isn't installed"; exit 1; } # -*-emacs-lisp-*-
":"; VERSION=$(emacs --version | head -n1) ":"; VERSION=$(emacs --version | head -n1)
":"; case $VERSION in *\ 2[0-2].[0-1].[0-9]) echo "You're running $VERSION"; echo "That version is too old to run the doctor. Check your PATH"; echo; exit 2 ;; esac ":"; case $VERSION in *\ 2[0-2].[0-1].[0-9]) echo "You're running $VERSION"; echo "That version is too old to run the doctor (25.3 minimum). Check your PATH"; echo; exit 2 ;; esac
":"; exec emacs --quick --script "$0"; exit 0 ":"; exec emacs --quick --script "$0"; exit 0
;; The Doom doctor is essentially one big, self-contained elisp shell script ;; The Doom doctor is essentially one big, self-contained elisp shell script
@ -43,7 +43,7 @@
(defun sh (cmd &rest args) (defun sh (cmd &rest args)
(ignore-errors (ignore-errors
(string-trim-right (string-trim-right
(shell-command-to-string (apply #'format cmd args))))) (shell-command-to-string (if args (apply #'format cmd args) cmd)))))
(defun elc-check-dir (dir) (defun elc-check-dir (dir)
(dolist (file (directory-files-recursively dir "\\.elc$")) (dolist (file (directory-files-recursively dir "\\.elc$"))
@ -139,18 +139,6 @@
(concat "\nMacOS users should use homebrew (https://brew.sh) to install Emacs\n" (concat "\nMacOS users should use homebrew (https://brew.sh) to install Emacs\n"
" brew install emacs --with-modules --with-imagemagick --with-cocoa")))) " brew install emacs --with-modules --with-imagemagick --with-cocoa"))))
(section! "Checking if your version of Emacs has changed recently...")
(let ((version-file (expand-file-name ".local/emacs-version.el" user-emacs-directory))
doom--last-emacs-version)
(when (and (load version-file 'noerror 'nomessage 'nosuffix)
(not (equal emacs-version doom--last-emacs-version)))
(warn! "Your version of Emacs has changed from %S to %S. Recompile your packages!"
doom--last-emacs-version
emacs-version)
(explain! "Byte-code compiled in one version of Emacs may not work in another version."
"It is recommended that you reinstall your plugins or recompile them with"
"`bin/doom rebuild'.")))
(section! "Checking for Emacs config conflicts...") (section! "Checking for Emacs config conflicts...")
(when (file-exists-p "~/.emacs") (when (file-exists-p "~/.emacs")
(warn! "Detected an ~/.emacs file, which may prevent Doom from loading") (warn! "Detected an ~/.emacs file, which may prevent Doom from loading")

View file

@ -16,7 +16,7 @@ IF NOT [%1]==[] (
) )
IF [%command%]==[run] ( IF [%command%]==[run] (
start runemacs -Q %args% -l ..\init.el -f "doom|run-all-startup-hooks" start runemacs -Q %args% -l ..\init.el -f "doom-run-all-startup-hooks-h"
) ELSE ( ) ELSE (
emacs --quick --script .\doom -- %* emacs --quick --script .\doom -- %*
) )

View file

@ -74,7 +74,7 @@ line."
Uses the same mechanism as 'bin/doom env reload'." Uses the same mechanism as 'bin/doom env reload'."
(interactive) (interactive)
(compile (format "%s env refresh" (expand-file-name "bin/doom" doom-emacs-dir))) (compile (format "%s env" (expand-file-name "bin/doom" doom-emacs-dir)))
(while compilation-in-progress (while compilation-in-progress
(sit-for 1)) (sit-for 1))
(unless (file-readable-p doom-env-file) (unless (file-readable-p doom-env-file)

View file

@ -39,7 +39,12 @@ ready to be pasted in a bug report on github."
(version . ,emacs-version) (version . ,emacs-version)
(features ,@system-configuration-features) (features ,@system-configuration-features)
(build . ,(format-time-string "%b %d, %Y" emacs-build-time)) (build . ,(format-time-string "%b %d, %Y" emacs-build-time))
(buildopts ,system-configuration-options)) (buildopts ,system-configuration-options)
(windowsys . ,(if noninteractive 'batch window-system))
(daemonp . ,(cond ((daemonp) 'daemon)
((and (require 'server)
(server-running-p))
'server-running))))
(doom (doom
(version . ,doom-version) (version . ,doom-version)
(build . ,(sh "git log -1 --format=\"%D %h %ci\""))) (build . ,(sh "git log -1 --format=\"%D %h %ci\"")))
@ -63,11 +68,11 @@ ready to be pasted in a bug report on github."
(modules (modules
,@(or (cl-loop with cat = nil ,@(or (cl-loop with cat = nil
for key being the hash-keys of doom-modules for key being the hash-keys of doom-modules
if (or (not cat) (not (eq cat (car key)))) if (or (not cat)
(not (eq cat (car key))))
do (setq cat (car key)) do (setq cat (car key))
and collect cat and collect cat
and collect (cdr key) collect
else collect
(let ((flags (doom-module-get cat (cdr key) :flags))) (let ((flags (doom-module-get cat (cdr key) :flags)))
(if flags (if flags
`(,(cdr key) ,@flags) `(,(cdr key) ,@flags)
@ -75,18 +80,20 @@ ready to be pasted in a bug report on github."
'("n/a"))) '("n/a")))
(packages (packages
,@(or (ignore-errors ,@(or (ignore-errors
(require 'core-packages) (let ((doom-interactive-mode t)
(doom-initialize-packages) doom-packages
(cl-loop for (name . plist) in doom-packages doom-disabled-packages)
if (doom-package-private-p name) (doom--read-module-packages-file
collect (doom-path doom-private-dir "packages.el")
(format nil t)
"%s" (if-let (splist (doom-plist-delete (copy-sequence plist) (cl-loop for (name . plist) in (nreverse doom-packages)
:modules)) collect
(cons name splist) (if-let (splist (doom-plist-delete (copy-sequence plist)
name)))) :modules))
(prin1-to-string (cons name splist))
name))))
'("n/a"))) '("n/a")))
(elpa-packages (elpa
,@(or (ignore-errors ,@(or (ignore-errors
(cl-loop for (name . _) in package-alist (cl-loop for (name . _) in package-alist
collect (format "%s" name))) collect (format "%s" name)))
@ -203,24 +210,23 @@ markdown and copies it to your clipboard, ready to be pasted into bug reports!"
(setq-default buffer-undo-tree (make-undo-tree)))) (setq-default buffer-undo-tree (make-undo-tree))))
(pcase mode (pcase mode
(`vanilla-doom+ ; Doom core + modules - private config (`vanilla-doom+ ; Doom core + modules - private config
`((setq doom-private-dir "/tmp/does/not/exist") `((setq doom-init-modules-p t)
(load-file ,user-init-file) (load-file ,user-init-file)
(setq doom-modules ',doom-modules) (setq doom-modules ',doom-modules)
(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! "init" (plist-get plist :path) t))) (load! "init" (doom-module-locate-path (car key) (cdr key)) t)))
doom-modules) doom-modules)
(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" (doom-module-locate-path (car key) (cdr key)) 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-h))) (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-init-modules-p t)
doom-init-modules-p t)
(load-file ,user-init-file) (load-file ,user-init-file)
(doom-run-all-startup-hooks-h))) (doom-run-all-startup-hooks-h)))
(`vanilla ; nothing loaded (`vanilla ; nothing loaded
@ -378,42 +384,6 @@ will be automatically appended to the result."
(profiler-stop)) (profiler-stop))
(setq doom--profiler (not doom--profiler))) (setq doom--profiler (not doom--profiler)))
;;;###autoload
(defun doom/profile-emacs ()
"Profile the startup time of Emacs in the background with ESUP.
If INIT-FILE is non-nil, profile that instead of USER-INIT-FILE."
(interactive)
(require 'esup)
(let ((init-file esup-user-init-file))
(message "Starting esup...")
(esup-reset)
(setq esup-server-process (esup-server-create (esup-select-port)))
(setq esup-server-port (process-contact esup-server-process :service))
(message "esup process started on port %s" esup-server-port)
(let ((process-args
(append `("*esup-child*"
"*esup-child*"
,esup-emacs-path
"-Q"
"--eval=(setq after-init-time nil)"
"-L" ,esup-load-path)
(when (bound-and-true-p early-init-file)
`("-l" ,early-init-file))
`("-l" "esup-child"
,(format "--eval=(let ((load-file-name \"%s\")) (esup-child-run \"%s\" \"%s\" %d))"
init-file
init-file
esup-server-port
esup-depth)
"--eval=(doom-run-all-startup-hooks-h)"))))
(when esup-run-as-batch-p
(setq process-args (append process-args '("--batch"))))
(setq esup-child-process (apply #'start-process process-args)))
(set-process-sentinel esup-child-process 'esup-child-process-sentinel)))
;;;###autoload
(advice-add #'esup :override #'doom/profile-emacs)
;;;###autoload ;;;###autoload
(defun doom/toggle-debug-mode (&optional arg) (defun doom/toggle-debug-mode (&optional arg)
"Toggle `debug-on-error' and `doom-debug-mode' for verbose logging." "Toggle `debug-on-error' and `doom-debug-mode' for verbose logging."

View file

@ -72,7 +72,8 @@ See `doom-init-fonts-h'."
(interactive) (interactive)
(when doom-font (when doom-font
(set-frame-font doom-font t)) (set-frame-font doom-font t))
(mapc #'doom-init-fonts-h (frame-list))) (doom-init-fonts-h)
(mapc #'doom-init-extra-fonts-h (frame-list)))
;;;###autoload ;;;###autoload
(defun doom/increase-font-size (count) (defun doom/increase-font-size (count)

View file

@ -91,6 +91,7 @@ Accepts 'ansi and 'text-properties. nil means don't render colors.")
;; ;;
;;; Library ;;; Library
;;;###autoload
(defun doom--format (output) (defun doom--format (output)
(if (string-empty-p (string-trim output)) (if (string-empty-p (string-trim output))
"" ""
@ -99,6 +100,7 @@ Accepts 'ansi and 'text-properties. nil means don't render colors.")
"\n" (concat "\n" (make-string doom-format-indent 32)) "\n" (concat "\n" (make-string doom-format-indent 32))
output t t)))) output t t))))
;;;###autoload
(defun doom--format-print (output) (defun doom--format-print (output)
(unless (string-empty-p output) (unless (string-empty-p output)
(if (not noninteractive) (if (not noninteractive)
@ -107,6 +109,7 @@ Accepts 'ansi and 'text-properties. nil means don't render colors.")
(terpri)) ; newline (terpri)) ; newline
t)) t))
;;;###autoload
(defun doom--format-indent (width text &optional prefix) (defun doom--format-indent (width text &optional prefix)
"Indent TEXT by WIDTH spaces. If ARGS, format TEXT with them." "Indent TEXT by WIDTH spaces. If ARGS, format TEXT with them."
(with-temp-buffer (with-temp-buffer
@ -121,6 +124,7 @@ Accepts 'ansi and 'text-properties. nil means don't render colors.")
(insert prefix))) (insert prefix)))
(buffer-string))) (buffer-string)))
;;;###autoload
(defun doom--format-autofill (&rest msgs) (defun doom--format-autofill (&rest msgs)
"Ensure MSG is split into lines no longer than `fill-column'." "Ensure MSG is split into lines no longer than `fill-column'."
(with-temp-buffer (with-temp-buffer
@ -131,6 +135,7 @@ Accepts 'ansi and 'text-properties. nil means don't render colors.")
(fill-region (point-min) (point-max)) (fill-region (point-min) (point-max))
(buffer-string)))) (buffer-string))))
;;;###autoload
(defun doom--format-color (style format &rest args) (defun doom--format-color (style format &rest args)
"Apply STYLE to formatted MESSAGE with ARGS. "Apply STYLE to formatted MESSAGE with ARGS.
@ -159,6 +164,7 @@ Otherwise, it maps colors to a term-color-* face."
((cddr (assq style doom-format-ansi-alist))))))) ((cddr (assq style doom-format-ansi-alist)))))))
(_ message)))) (_ message))))
;;;###autoload
(defun doom--format-class (class format &rest args) (defun doom--format-class (class format &rest args)
"Apply CLASS to formatted format with ARGS. "Apply CLASS to formatted format with ARGS.
@ -172,6 +178,7 @@ transformative logic."
(args (apply #'format format args)) (args (apply #'format format args))
(format)))) (format))))
;;;###autoload
(defun doom--format-apply (forms &optional sub) (defun doom--format-apply (forms &optional sub)
"Replace color-name functions with calls to `doom--format-color'." "Replace color-name functions with calls to `doom--format-color'."
(cond ((null forms) nil) (cond ((null forms) nil)

View file

@ -147,7 +147,7 @@ selection of all minor-modes, active or not."
(list (or (+org-get-property "TITLE") (list (or (+org-get-property "TITLE")
(file-relative-name buffer-file-name)))) (file-relative-name buffer-file-name))))
path path
(list (replace-regexp-in-string org-any-link-re "\\4" text))) (list (replace-regexp-in-string org-link-any-re "\\4" text)))
" > ") " > ")
tags) tags)
" ") " ")
@ -366,15 +366,6 @@ 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)
(or (unless refresh
doom--help-packages-list)
(setq doom--help-packages-list
(append (cl-loop for package in doom-core-packages
collect (list package :modules '((:core internal))))
(doom-package-list 'all)))))
(defun doom--help-package-configs (package) (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
(let ((default-directory doom-emacs-dir)) (let ((default-directory doom-emacs-dir))
@ -394,16 +385,16 @@ defined and configured.
If prefix arg is present, refresh the cache." If prefix arg is present, refresh the cache."
(interactive (interactive
(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) (require 'core-packages)
(unless package--initialized (doom-initialize-packages)
(package-initialize t)) (let ((packages (delete-dups
(let ((packages (cl-delete-duplicates (append (mapcar #'car package-alist)
(append (mapcar 'car package-alist) (mapcar #'car package--builtins)
(mapcar 'car package--builtins) (mapcar #'intern (hash-table-keys straight--build-cache))
(mapcar 'car (doom--help-packages-list)) (mapcar #'car (doom-package-list 'all))
nil)))) nil))))
(unless (memq guess packages) (unless (memq guess packages)
(setq guess nil)) (setq guess nil))
@ -415,6 +406,8 @@ If prefix arg is present, refresh the cache."
"Describe package: ") "Describe package: ")
packages nil t nil nil packages nil t nil nil
(if guess (symbol-name guess)))))))) (if guess (symbol-name guess))))))))
(require 'core-packages)
(doom-initialize-packages)
(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)
@ -425,8 +418,7 @@ If prefix arg is present, refresh the cache."
(with-help-window (help-buffer))) (with-help-window (help-buffer)))
(save-excursion (save-excursion
(with-current-buffer (help-buffer) (with-current-buffer (help-buffer)
(let ((doom-packages (doom--help-packages-list)) (let ((inhibit-read-only t)
(inhibit-read-only t)
(indent (make-string 13 ? ))) (indent (make-string 13 ? )))
(goto-char (point-max)) (goto-char (point-max))
(if (re-search-forward "^ *Status: " nil t) (if (re-search-forward "^ *Status: " nil t)
@ -441,7 +433,10 @@ If prefix arg is present, refresh the cache."
(package--print-help-section "Source") (package--print-help-section "Source")
(insert (or (pcase (doom-package-backend package) (insert (or (pcase (doom-package-backend package)
(`straight (`straight
(format! "Straight\n%s" (format! "Straight (%s)\n%s"
(let ((default-directory (straight--build-dir (symbol-name package))))
(string-trim
(shell-command-to-string "git log -1 --format=\"%D %h %ci\"")))
(indent (indent
13 (string-trim 13 (string-trim
(pp-to-string (pp-to-string
@ -453,7 +448,7 @@ If prefix arg is present, refresh the cache."
"unknown") "unknown")
"\n") "\n")
(when (assq package doom-packages) (when (gethash (symbol-name package) straight--build-cache)
(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-get package :modules)) (dolist (m (doom-package-get package :modules))
@ -548,7 +543,7 @@ If prefix arg is present, refresh the cache."
;;;###autoload ;;;###autoload
(defun doom/help-package-config (package) (defun doom/help-package-config (package)
"Jump to any `def-package!', `after!' or ;;;###package block for PACKAGE. "Jump to any `use-package!', `after!' or ;;;###package block for PACKAGE.
This only searches `doom-emacs-dir' (typically ~/.emacs.d) and does not include This only searches `doom-emacs-dir' (typically ~/.emacs.d) and does not include
config blocks in your private config." config blocks in your private config."

View file

@ -131,10 +131,10 @@ was installed with."
;; ;;
;;; Package list getters ;;; Package list getters
(defun doom--read-module-packages-file (file &optional eval noerror) (defun doom--read-module-packages-file (file &optional noeval 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 eval) (if (not noeval)
(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)
@ -165,7 +165,7 @@ 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 ((doom-interactive-mode t)
(doom-modules (doom-modules)) (doom-modules (doom-modules))
doom-packages doom-packages
doom-disabled-packages) doom-disabled-packages)

View file

@ -92,8 +92,8 @@
(let ((session-file (doom-session-file))) (let ((session-file (doom-session-file)))
(list (or (read-file-name "Session to restore: " (list (or (read-file-name "Session to restore: "
(file-name-directory session-file) (file-name-directory session-file)
nil t (file-name-nondirectory session-file)
(file-name-nondirectory session-file)) t)
(user-error "No session selected. Aborting"))))) (user-error "No session selected. Aborting")))))
(unless file (unless file
(error "No session file selected")) (error "No session file selected"))
@ -107,7 +107,6 @@
(let ((session-file (doom-session-file))) (let ((session-file (doom-session-file)))
(list (or (read-file-name "Save session to: " (list (or (read-file-name "Save session to: "
(file-name-directory session-file) (file-name-directory session-file)
nil nil
(file-name-nondirectory session-file)) (file-name-nondirectory session-file))
(user-error "No session selected. Aborting"))))) (user-error "No session selected. Aborting")))))
(unless file (unless file

View file

@ -4,7 +4,7 @@
(cond ((listp (car spec)) (cond ((listp (car spec))
(cl-loop for face in (car spec) (cl-loop for face in (car spec)
collect collect
(doom--custom-theme-set-face `(,face ,(cdr spec))))) (car (doom--custom-theme-set-face (cons face (cdr spec))))))
((keywordp (cadr spec)) ((keywordp (cadr spec))
`((,(car spec) ((t ,(cdr spec)))))) `((,(car spec) ((t ,(cdr spec))))))
(`((,(car spec) ,(cdr spec)))))) (`((,(car spec) ,(cdr spec))))))
@ -44,7 +44,5 @@ face format."
(let ((theme (or (car-safe custom-enabled-themes) doom-theme))) (let ((theme (or (car-safe custom-enabled-themes) doom-theme)))
(when theme (when theme
(mapc #'disable-theme custom-enabled-themes)) (mapc #'disable-theme custom-enabled-themes))
(when (and doom-theme (not (memq doom-theme custom-enabled-themes))) (load-theme doom-theme 'noconfirm)
(let (doom--prefer-theme-elc) (doom/reload-font)))
(load-theme doom-theme t)))
(doom-init-fonts-h)))

View file

@ -169,35 +169,67 @@ OPACITY is an integer between 0 to 100, inclusive."
100)))) 100))))
(set-frame-parameter nil 'alpha opacity)) (set-frame-parameter nil 'alpha opacity))
(defvar-local doom--buffer-narrowed-origin nil) (defvar doom--narrowed-base-buffer nil)
(defvar-local doom--buffer-narrowed-window-start nil)
;;;###autoload ;;;###autoload
(defun doom/clone-and-narrow-buffer (beg end &optional clone-p) (defun doom/narrow-buffer-indirectly (beg end)
"Restrict editing in this buffer to the current region, indirectly. With CLONE-P, "Restrict editing in this buffer to the current region, indirectly.
clone the buffer and hard-narrow the selection. If mark isn't active, then widen
the buffer (if narrowed). This recursively creates indirect clones of the current buffer so that the
narrowing doesn't affect other windows displaying the same buffer. Call
`doom/widen-indirectly-narrowed-buffer' to undo it (incrementally).
Inspired from http://demonastery.org/2013/04/emacs-evil-narrow-region/" Inspired from http://demonastery.org/2013/04/emacs-evil-narrow-region/"
(interactive (interactive
(list (or (bound-and-true-p evil-visual-beginning) (region-beginning)) (list (or (bound-and-true-p evil-visual-beginning) (region-beginning))
(or (bound-and-true-p evil-visual-end) (region-end)) (or (bound-and-true-p evil-visual-end) (region-end))
current-prefix-arg)) current-prefix-arg))
(cond ((or (region-active-p) (unless (region-active-p)
(not (buffer-narrowed-p))) (setq beg (line-beginning-position)
(unless (region-active-p) end (line-end-position)))
(setq beg (line-beginning-position) (deactivate-mark)
end (line-end-position))) (let ((orig-buffer (current-buffer)))
(setq deactivate-mark t) (with-current-buffer (switch-to-buffer (clone-indirect-buffer nil nil))
(when clone-p (narrow-to-region beg end)
(let ((old-buf (current-buffer))) (setq-local doom--narrowed-base-buffer orig-buffer))))
(switch-to-buffer (clone-indirect-buffer nil nil))
(setq doom--buffer-narrowed-origin old-buf))) ;;;###autoload
(setq doom--buffer-narrowed-window-start (window-start)) (defun doom/widen-indirectly-narrowed-buffer (&optional arg)
(narrow-to-region beg end)) "Widens narrowed buffers.
(doom--buffer-narrowed-origin
(kill-current-buffer) This command will incrementally kill indirect buffers (under the assumption they
(switch-to-buffer doom--buffer-narrowed-origin) were created by `doom/narrow-buffer-indirectly') and switch to their base
(setq doom--buffer-narrowed-origin nil)) buffer.
(t
(widen) If ARG, then kill all indirect buffers, return the base buffer and widen it.
(set-window-start nil doom--buffer-narrowed-window-start))))
If the current buffer is not an indirect buffer, it is `widen'ed."
(interactive "P")
(unless (buffer-narrowed-p)
(user-error "Buffer isn't narrowed"))
(let ((orig-buffer (current-buffer))
(base-buffer doom--narrowed-base-buffer))
(cond ((or (not base-buffer)
(not (buffer-live-p base-buffer)))
(widen))
(arg
(let ((buffer orig-buffer)
(buffers-to-kill (list orig-buffer)))
(while (setq buffer (buffer-local-value 'doom--narrowed-base-buffer buffer))
(push buffer buffers-to-kill))
(switch-to-buffer (buffer-base-buffer))
(mapc #'kill-buffer (remove (current-buffer) buffers-to-kill))))
((switch-to-buffer base-buffer)
(kill-buffer orig-buffer)))))
;;;###autoload
(defun doom/toggle-narrow-buffer (beg end)
"Narrow the buffer to BEG END. If narrowed, widen it."
(interactive
(list (or (bound-and-true-p evil-visual-beginning) (region-beginning))
(or (bound-and-true-p evil-visual-end) (region-end))))
(if (buffer-narrowed-p)
(widen)
(unless (region-active-p)
(setq beg (line-beginning-position)
end (line-end-position)))
(narrow-to-region beg end)))

View file

@ -27,6 +27,8 @@ byte-compiles `doom-autoload-file', as well as `doom-package-autoload-file'
It also caches `load-path', `Info-directory-list', `doom-disabled-packages', It also caches `load-path', `Info-directory-list', `doom-disabled-packages',
`package-activated-list' and `auto-mode-alist'." `package-activated-list' and `auto-mode-alist'."
;; REVIEW Can we avoid calling `straight-check-all' everywhere?
(straight-check-all)
(doom-reload-autoloads nil 'force)) (doom-reload-autoloads nil 'force))
@ -357,7 +359,7 @@ This should be run whenever your `doom!' block or update your packages."
(print-group! (print-group!
(if (and (not force-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-elpa-dir doom-package-autoload-file)) (not (file-newer-than-file-p package-user-dir doom-package-autoload-file))
(not (cl-loop for dir in (straight--directory-files (straight--build-dir)) (not (cl-loop for dir in (straight--directory-files (straight--build-dir))
if (cl-find-if if (cl-find-if
(lambda (dir) (lambda (dir)
@ -377,7 +379,7 @@ This should be run whenever your `doom!' block or update your packages."
(noninteractive t) (noninteractive t)
(backup-inhibited t) (backup-inhibited t)
(version-control 'never) (version-control 'never)
(case-fold-search nil) ; reduce magit (case-fold-search nil) ; reduce magic
(autoload-timestamps nil)) (autoload-timestamps nil))
(print! (start "Regenerating package autoloads file")) (print! (start "Regenerating package autoloads file"))

View file

@ -92,10 +92,9 @@ If RECOMPILE-P is non-nil, only recompile out-of-date files."
;; But first we must be sure that Doom and your private config have been ;; 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. ;; fully loaded. Which usually aren't so in an noninteractive session.
(let (noninteractive) (let ((doom-interactive-mode 'byte-compile))
(doom-initialize 'force) (doom-initialize 'force)
(doom-initialize-core) (doom-initialize-core))
(doom-initialize-modules 'force))
;; ;;
(unless target-dirs (unless target-dirs

View file

@ -22,22 +22,23 @@ This file is automatically regenerated when you run this command or 'doom
refresh'. However, 'doom refresh' will only regenerate this file if it exists. refresh'. However, 'doom refresh' will only regenerate this file if it exists.
Use the -c or --clear switch to delete your envvar file." Use the -c or --clear switch to delete your envvar file."
(let ((default-directory doom-emacs-dir)) (when (member "clear" args) ; DEPRECATED
(when (member "clear" args) ; DEPRECATED (message "'doom env clear' is deprecated. Use 'doom env -c' or 'doom env --clear' instead")
(message "'doom env clear' is deprecated. Use 'doom env -c' or 'doom env --clear' instead") (push "-c" args))
(push "-c" args)) (let ((env-file (or (cadr (member "-o" args))
doom-env-file)))
(cond ((or (member "-c" args) (cond ((or (member "-c" args)
(member "--clear" args)) (member "--clear" args))
(unless (file-exists-p doom-env-file) (unless (file-exists-p env-file)
(user-error! "%S does not exist to be cleared" (user-error! "%S does not exist to be cleared"
(relpath doom-env-file))) (path env-file)))
(delete-file doom-env-file) (delete-file env-file)
(print! (success "Successfully deleted %S") (print! (success "Successfully deleted %S")
(relpath doom-env-file))) (path env-file)))
((null args) ((or (null args)
(doom-reload-env-file 'force)) (member "-o" args))
(doom-reload-env-file 'force env-file))
((user-error "I don't understand 'doom env %s'" ((user-error "I don't understand 'doom env %s'"
(string-join args " ")))))) (string-join args " "))))))
@ -58,6 +59,7 @@ Use the -c or --clear switch to delete your envvar file."
"^INSECURE$" "^INSECURE$"
"^DEBUG$" "^DEBUG$"
"^YES$" "^YES$"
"^TERM$"
"^__") "^__")
"Environment variables to not save in `doom-env-file'. "Environment variables to not save in `doom-env-file'.
@ -79,64 +81,67 @@ It is rare that you'll need to change this.")
This is a list of strings. Each entry is run separately and in sequence with This is a list of strings. Each entry is run separately and in sequence with
`doom-env-executable' to scrape envvars from your shell environment.") `doom-env-executable' to scrape envvars from your shell environment.")
;; Borrows heavily from Spacemacs' `spacemacs//init-spacemacs-env'. (defun doom-reload-env-file (&optional force-p env-file)
(defun doom-reload-env-file (&optional force-p)
"Generates `doom-env-file', if it doesn't exist (or if FORCE-P). "Generates `doom-env-file', if it doesn't exist (or if FORCE-P).
This scrapes the variables from your shell environment by running This scrapes the variables from your shell environment by running
`doom-env-executable' through `shell-file-name' with `doom-env-switches'. By `doom-env-executable' through `shell-file-name' with `doom-env-switches'. By
default, on Linux, this is '$SHELL -ic /usr/bin/env'. Variables in 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))) (let ((env-file (if env-file
(with-temp-file doom-env-file (expand-file-name env-file)
(print! (start "%s envvars file at %S") doom-env-file)))
(if (file-exists-p doom-env-file) (when (or force-p (not (file-exists-p env-file)))
"Regenerating" (with-temp-file env-file
"Generating") (print! (start "%s envvars file at %S")
(relpath doom-env-file doom-emacs-dir)) (if (file-exists-p env-file)
(let ((process-environment doom--initial-process-environment)) "Regenerating"
(let ((shell-command-switch doom-env-switches) "Generating")
(error-buffer (get-buffer-create "*env errors*"))) (path env-file))
(print! (info "Scraping shell environment with '%s %s %s'") (let ((process-environment doom--initial-process-environment))
(filename shell-file-name) (let ((shell-command-switch doom-env-switches)
shell-command-switch (error-buffer (get-buffer-create "*env errors*")))
(filename doom-env-executable)) (print! (info "Scraping shell environment with '%s %s %s'")
(save-excursion (filename shell-file-name)
(shell-command doom-env-executable (current-buffer) error-buffer)) shell-command-switch
(print-group! (filename doom-env-executable))
(let ((errors (with-current-buffer error-buffer (buffer-string)))) (save-excursion
(unless (string-empty-p errors) (shell-command doom-env-executable (current-buffer) error-buffer))
(print! (info "Error output:\n\n%s") (indent 4 errors)))) (print-group!
;; Remove undesireable variables (let ((errors (with-current-buffer error-buffer (buffer-string))))
(insert (unless (string-empty-p errors)
(concat (print! (info "Warnings:\n\n%s") (indent 4 errors))))
"# -*- mode: dotenv -*-\n" ;; Remove undesireable variables
(format "# Generated with: %s %s %s\n" (insert
shell-file-name (concat
doom-env-switches "# -*- mode: dotenv -*-\n"
doom-env-executable) (format "# Generated with: %s %s %s\n"
"# ---------------------------------------------------------------------------\n" shell-file-name
"# This file was auto-generated by `doom env'. It contains a list of environment\n" doom-env-switches
"# variables scraped from your default shell (excluding variables blacklisted\n" doom-env-executable)
"# in doom-env-ignored-vars).\n" "# ---------------------------------------------------------------------------\n"
"#\n" "# This file was auto-generated by `doom env'. It contains a list of environment\n"
"# It is NOT safe to edit this file. Changes will be overwritten next time that\n" "# variables scraped from your default shell (excluding variables blacklisted\n"
"# `doom refresh` is executed. Alternatively, create your own env file and load\n" "# in doom-env-ignored-vars).\n"
"# it with `(doom-load-envvars-file FILE)` in your private config.el.\n" "#\n"
"# ---------------------------------------------------------------------------\n\n")) "# It is NOT safe to edit this file. Changes will be overwritten next time that\n"
(goto-char (point-min)) "# `doom refresh` is executed. Alternatively, create your own env file with\n"
(while (re-search-forward "\n\\([^= \n]+\\)=" nil t) "# `doom env -o ~/.doom.d/myenv`, then load it with (doom-load-envvars-file FILE)\n"
(save-excursion "# in your private config.el.\n"
(let* ((valend (or (save-match-data "# ---------------------------------------------------------------------------\n\n"))
(when (re-search-forward "^\\([^= ]+\\)=" nil t) (goto-char (point-min))
(line-beginning-position))) (while (re-search-forward "\n\\([^= \n]+\\)=" nil t)
(point-max))) (save-excursion
(var (match-string 1))) (let* ((valend (or (save-match-data
(when (cl-loop for regexp in doom-env-ignored-vars (when (re-search-forward "^\\([^= ]+\\)=" nil t)
if (string-match-p regexp var) (line-beginning-position)))
return t) (point-max)))
(print! (info "Ignoring %s") var) (var (match-string 1)))
(delete-region (match-beginning 0) (1- valend))))))) (when (cl-loop for regexp in doom-env-ignored-vars
(print! (success "Successfully generated %S") if (string-match-p regexp var)
(relpath doom-env-file doom-emacs-dir)) return t)
t))))) (print! (info "Ignoring %s") var)
(delete-region (match-beginning 0) (1- valend)))))))
(print! (success "Successfully generated %S")
(path env-file))
t))))))

View file

@ -8,15 +8,15 @@ See 'doom help install' instead."
(apply #'doom-cli-install args)) (apply #'doom-cli-install args))
(defcli! (install i) (&rest args) (defcli! (install i) (&rest args)
"A wizard for installing Doom for the first time. "Installs and sets up Doom Emacs for the first time.
This command does the following: This command does the following:
1. Creates DOOMDIR at ~/.doom.d, 1. Creates DOOMDIR at ~/.doom.d,
2. Copies ~/.emacs.d/init.example.el to DOOMDIR/init.el (if it doesn't exist), 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, 3. Creates dummy files for $DOOMDIR/{config,packages}.el,
4. Prompts you to generate an envvar file (via 'doom env refresh'), 4. Prompts you to generate an envvar file (same as 'doom env'),
5. Installs any dependencies of enabled modules (specified by DOOMDIR/init.el), 5. Installs any dependencies of enabled modules (specified by $DOOMDIR/init.el),
6. And prompts to install all-the-icons' fonts 6. And prompts to install all-the-icons' fonts
This command is idempotent and safe to reuse. This command is idempotent and safe to reuse.
@ -27,7 +27,7 @@ DOOMDIR environment variable. e.g.
doom -p ~/.config/doom install doom -p ~/.config/doom install
DOOMDIR=~/.config/doom doom install DOOMDIR=~/.config/doom doom install
install understands the following switches: The following switches are recognized:
--no-config Don't create DOOMDIR or dummy files therein --no-config Don't create DOOMDIR or dummy files therein
--no-install Don't auto-install packages --no-install Don't auto-install packages

View file

@ -3,6 +3,7 @@
(defmacro doom--ensure-autoloads-while (&rest body) (defmacro doom--ensure-autoloads-while (&rest body)
`(progn `(progn
(straight-check-all)
(doom-reload-core-autoloads) (doom-reload-core-autoloads)
(when (progn ,@body) (when (progn ,@body)
(doom-reload-package-autoloads 'force-p)) (doom-reload-package-autoloads 'force-p))
@ -19,11 +20,16 @@ This works by fetching all installed package repos and checking the distance
between HEAD and FETCH_HEAD. This can take a while. 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.
Switches:
-t/--timeout TTL Seconds until a thread is timed out (default: 45)
--threads N How many threads to use (default: 8)"
(doom--ensure-autoloads-while (doom--ensure-autoloads-while
(straight-check-all)
(doom-packages-update (doom-packages-update
doom-auto-accept doom-auto-accept
(when-let (threads (cadr (member "--threads" args)))
(string-to-number threads))
(when-let (timeout (cadr (or (member "--timeout" args) (when-let (timeout (cadr (or (member "--timeout" args)
(member "-t" args)))) (member "-t" args))))
(string-to-number timeout))))) (string-to-number timeout)))))
@ -32,26 +38,33 @@ or :ignore property."
"Rebuilds all installed packages. "Rebuilds all installed packages.
This ensures that all needed files are symlinked from their package repo and This ensures that all needed files are symlinked from their package repo and
their elisp files are byte-compiled." their elisp files are byte-compiled.
Switches:
-f Forcibly rebuild autoloads files, even if they're up-to-date"
(doom--ensure-autoloads-while (doom--ensure-autoloads-while
(doom-packages-rebuild doom-auto-accept (member "-f" args)))) (doom-packages-rebuild doom-auto-accept (member "-f" args))))
(defcli! (purge p) (&rest args) (defcli! (purge p) (&rest args)
"Deletes any unused ELPA packages, straight builds, and (optionally) repos. "Deletes any unused ELPA packages, straight builds, and (optionally) repos.
By default, this does not purge repos. By default, this does not purge ELPA packages or repos. It is a good idea to run
'doom purge --all' once in a while, to stymy build-up of repos and ELPA
packages that could be taking up precious space.
Available options: Switches:
--no-builds Don't purge unneeded (built) packages
--no-elpa Don't purge ELPA packages -e / --elpa Don't purge ELPA packages
--no-builds Don't purge unneeded (built) packages -r / --repos Purge unused repos
--repos Purge unused repos" --all Purge builds, elpa packages and repos"
(doom--ensure-autoloads-while (doom--ensure-autoloads-while
(straight-check-all) (doom-packages-purge (or (member "-e" args)
(doom-packages-purge (not (member "--no-elpa" args)) (member "--elpa" args)
(member "--all" args))
(not (member "--no-builds" args)) (not (member "--no-builds" args))
(or (member "-r" args) (or (member "-r" args)
(member "--repos" args)) (member "--repos" args)
(member "--all" args))
doom-auto-accept))) doom-auto-accept)))
;; (defcli! rollback () ; TODO rollback ;; (defcli! rollback () ; TODO rollback
@ -126,7 +139,7 @@ a list of packages that will be installed."
(lambda (&rest _) (cl-incf n))) (lambda (&rest _) (cl-incf n)))
(let ((straight--packages-to-rebuild :all) (let ((straight--packages-to-rebuild :all)
(straight--packages-not-to-rebuild (make-hash-table :test #'equal))) (straight--packages-not-to-rebuild (make-hash-table :test #'equal)))
(straight-use-package (intern package) nil nil " ")) (straight-use-package (intern package) nil nil " "))
(straight--byte-compile-package recipe) (straight--byte-compile-package recipe)
(dolist (dep (straight--get-dependencies package)) (dolist (dep (straight--get-dependencies package))
(when-let (recipe (gethash dep straight--recipe-cache)) (when-let (recipe (gethash dep straight--recipe-cache))
@ -147,12 +160,11 @@ a list of packages that will be installed."
(condition-case e (condition-case e
(let (packages errors) (let (packages errors)
(load ,(concat doom-core-dir "core.el")) (load ,(concat doom-core-dir "core.el"))
(doom-initialize 'force-p) (doom-initialize 'force)
(dolist (recipe ',group) (dolist (recipe ',group)
(when (straight--repository-is-available-p recipe) (when (straight--repository-is-available-p recipe)
(straight-vc-git--destructure recipe (straight-vc-git--destructure recipe
(package local-repo nonrecursive upstream-remote upstream-repo upstream-host (package local-repo nonrecursive upstream-remote upstream-repo upstream-host branch)
branch remote)
(condition-case e (condition-case e
(let ((default-directory (straight--repos-dir local-repo))) (let ((default-directory (straight--repos-dir local-repo)))
;; HACK We normalize packages to avoid certain scenarios ;; HACK We normalize packages to avoid certain scenarios
@ -162,7 +174,7 @@ a list of packages that will be installed."
;; can't use `straight-normalize-package' because could ;; can't use `straight-normalize-package' because could
;; create popup prompts too, so we do it manually: ;; create popup prompts too, so we do it manually:
(shell-command-to-string "git merge --abort") (shell-command-to-string "git merge --abort")
(straight--get-call "git" "reset" "--hard" (format "%s/%s" remote branch)) (straight--get-call "git" "reset" "--hard" branch)
(straight--get-call "git" "clean" "-ffd") (straight--get-call "git" "clean" "-ffd")
(unless nonrecursive (unless nonrecursive
(shell-command-to-string "git submodule update --init --recursive")) (shell-command-to-string "git submodule update --init --recursive"))
@ -208,7 +220,7 @@ a list of packages that will be installed."
(cons 'error e)))))) (cons 'error e))))))
(defun doom-packages-update (&optional auto-accept-p timeout) (defun doom-packages-update (&optional auto-accept-p threads 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
@ -217,14 +229,17 @@ a list of packages that will be updated."
(print-group! (print-group!
(when timeout (when timeout
(print! (info "Using %S as timeout value" timeout))) (print! (info "Using %S as timeout value" timeout)))
(when threads
(print! (info "Limiting to %d thread(s)" threads)))
;; REVIEW Does this fail gracefully enough? Is it error tolerant? ;; REVIEW Does this fail gracefully enough? Is it error tolerant?
;; TODO Add version-lock checks; don't want to spend all this effort on ;; TODO Add version-lock checks; don't want to spend all this effort on
;; packages that shouldn't be updated ;; packages that shouldn't be updated
(let* ((futures (let* ((futures
;; REVIEW We can do better "thread" management here
(or (cl-loop for group (or (cl-loop for group
in (seq-partition (hash-table-values straight--repo-cache) in (seq-partition (hash-table-values straight--repo-cache)
(/ (hash-table-count straight--repo-cache) (/ (hash-table-count straight--repo-cache)
16)) (or threads 8)))
for future = (doom--packages-remove-outdated-f group) for future = (doom--packages-remove-outdated-f group)
if (processp future) if (processp future)
collect (cons future group) collect (cons future group)
@ -422,18 +437,21 @@ a list of packages that will be updated."
(defun doom--packages-purge-elpa (&optional auto-accept-p) (defun doom--packages-purge-elpa (&optional auto-accept-p)
(unless (bound-and-true-p package--initialized) (unless (bound-and-true-p package--initialized)
(package-initialize)) (package-initialize))
(if (not package-alist) (let ((packages (cl-loop for (package desc) in package-alist
(progn (print! (info "No ELPA packages to purge")) for dir = (package-desc-dir desc)
0) if (file-in-directory-p dir package-user-dir)
(doom--prompt-columns-p collect (cons package dir))))
(lambda (p) (format " + %-20.20s" p)) (if (not package-alist)
(mapcar #'car package-alist) nil (progn (print! (info "No ELPA packages to purge"))
(format! "Found %d orphaned ELPA packages. Purge them?" 0)
(length package-alist))) (doom--prompt-columns-p
(mapc (doom-rpartial #'delete-directory 'recursive) (lambda (p) (format " + %-20.20s" p))
(mapcar #'package-desc-dir (mapcar #'car packages) nil
(mapcar #'cadr package-alist))) (format! "Found %d orphaned ELPA packages. Purge them?"
(length package-alist))) (length package-alist)))
(mapc (doom-rpartial #'delete-directory 'recursive)
(mapcar #'cdr packages))
(length packages))))
(defun doom-packages-purge (&optional elpa-p builds-p repos-p auto-accept-p) (defun doom-packages-purge (&optional elpa-p builds-p repos-p auto-accept-p)
"Auto-removes orphaned packages and repos. "Auto-removes orphaned packages and repos.

View file

@ -1,72 +0,0 @@
;;; core/cli/patch-macos.el -*- lexical-binding: t; -*-
(defcli! patch-macos () ; DEPRECATED
"Patches Emacs.app to respect your shell environment.
WARNING: This command is deprecated. Use 'doom env' instead.
A common issue with GUI Emacs on MacOS is that it launches in an environment
independent of your shell configuration, including your PATH and any other
utilities like rbenv, rvm or virtualenv.
This patch fixes this by patching Emacs.app (in /Applications or
~/Applications). It will:
1. Move Contents/MacOS/Emacs to Contents/MacOS/RunEmacs
2. And replace Contents/MacOS/Emacs with the following wrapper script:
#!/user/bin/env bash
args=\"$@\"
pwd=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\"; pwd -P)\"
exec \"$SHELL\" -l -c \"$pwd/RunEmacs $args\"
This ensures that Emacs is always aware of your shell environment, regardless of
how it is launched.
It can be undone with the --undo or -u options.
Alternatively, you can install the exec-path-from-shell Emacs plugin, which will
scrape your shell environment remotely, at startup. However, this can be slow
depending on your shell configuration and isn't always reliable."
:hidden t
(doom-patch-macos (or (member "--undo" args)
(member "-u" args))
(doom--find-emacsapp-path)))
;;
;; Library
(defun doom--find-emacsapp-path ()
(or (getenv "EMACS_APP_PATH")
(cl-loop for dir in (list "/usr/local/opt/emacs"
"/usr/local/opt/emacs-plus"
"/Applications"
"~/Applications")
for appdir = (concat dir "/Emacs.app")
if (file-directory-p appdir)
return appdir)
(user-error "Couldn't find Emacs.app")))
(defun doom-patch-macos (undo-p appdir)
"Patches Emacs.app to respect your shell environment."
(unless IS-MAC
(user-error "You don't seem to be running MacOS"))
(unless (file-directory-p appdir)
(user-error "Couldn't find '%s'" appdir))
(let ((oldbin (expand-file-name "Contents/MacOS/Emacs" appdir))
(newbin (expand-file-name "Contents/MacOS/RunEmacs" appdir)))
(cond (undo-p
(unless (file-exists-p newbin)
(user-error "Emacs.app is not patched"))
(copy-file newbin oldbin 'ok-if-already-exists nil nil 'preserve-permissions)
(unless (file-exists-p oldbin)
(error "Failed to copy %s to %s" newbin oldbin))
(delete-file newbin)
(message "%s successfully unpatched" appdir))
((file-exists-p newbin)
(user-error "%s is already patched. Use 'doom patch-macos --undo' to unpatch it"
appdir))
((user-error "patch-macos has been disabled. Please use 'doom env refresh' instead")))))

View file

@ -1,5 +1,12 @@
;;; core/cli/test.el -*- lexical-binding: t; -*- ;;; core/cli/test.el -*- lexical-binding: t; -*-
(defun doom--emacs-binary ()
(let ((emacs-binary-path (doom-path invocation-directory invocation-name))
(runemacs-binary-path (if IS-WINDOWS (doom-path invocation-directory "runemacs.exe"))))
(if (and runemacs-binary-path (file-exists-p runemacs-binary-path))
runemacs-binary-path
emacs-binary-path)))
(defcli! test (&rest targets) (defcli! test (&rest targets)
"Run Doom unit tests." "Run Doom unit tests."
(let (files error) (let (files error)
@ -14,6 +21,7 @@
(cdr (doom-module-load-path))))))) (cdr (doom-module-load-path)))))))
(while targets (while targets
(let ((target (pop targets))) (let ((target (pop targets)))
;; FIXME Module targets don't work
(cond ((equal target ":core") (cond ((equal target ":core")
(appendq! files (nreverse (doom-glob doom-core-dir "test/test-*.el")))) (appendq! files (nreverse (doom-glob doom-core-dir "test/test-*.el"))))
((file-directory-p target) ((file-directory-p target)
@ -21,26 +29,24 @@
(appendq! files (nreverse (doom-glob target "test/test-*.el")))) (appendq! files (nreverse (doom-glob target "test/test-*.el"))))
((file-exists-p target) ((file-exists-p target)
(push target files))))) (push target files)))))
(require 'restart-emacs)
(with-temp-buffer (with-temp-buffer
(setenv "DOOMDIR" (concat doom-core-dir "test/"))
(setenv "DOOMLOCALDIR" (concat doom-local-dir "test/"))
(print! (start "Bootstrapping test environment, if necessary...")) (print! (start "Bootstrapping test environment, if necessary..."))
(if (zerop (if (zerop
(call-process (call-process
(restart-emacs--get-emacs-binary) (doom--emacs-binary)
nil t nil "--batch" nil t nil "--batch"
"-l" (concat doom-core-dir "core.el")
"--eval" (prin1-to-string "--eval" (prin1-to-string
`(progn (doom-initialize 'force) `(progn
(doom-initialize-modules) (setq doom-emacs-dir ,doom-emacs-dir
(require 'core-cli) doom-local-dir ,(concat doom-local-dir "test/")
(unless (package-installed-p 'buttercup) doom-private-dir ,(concat doom-core-dir "test/"))
(package-refresh-contents) (require 'core ,(locate-library "core"))
(package-install 'buttercup)) (doom-initialize 'force)
(doom-reload-core-autoloads 'force) (doom-initialize-modules)
(when (doom-packages-install 'auto-accept) (require 'core-cli)
(doom-reload-package-autoloads 'force)))))) (doom-reload-core-autoloads 'force)
(when (doom-packages-install 'auto-accept)
(doom-reload-package-autoloads 'force))))))
(message "%s" (buffer-string)) (message "%s" (buffer-string))
(message "%s" (buffer-string)) (message "%s" (buffer-string))
(error "Failed to bootstrap unit tests"))) (error "Failed to bootstrap unit tests")))
@ -49,18 +55,21 @@
(with-temp-buffer (with-temp-buffer
(unless (unless
(zerop (zerop
(call-process (apply #'call-process
(restart-emacs--get-emacs-binary) (doom--emacs-binary)
nil t nil "--batch" nil t nil "--batch"
"-l" (concat doom-core-dir "core.el") (append (list
"-l" (concat doom-core-dir "test/helpers.el") "-L" doom-core-dir
"--eval" (prin1-to-string `(doom-initialize 'force)) "-l" "core"
"-l" "buttercup" "-l" (concat doom-core-dir "test/helpers.el"))
"-l" file (when (file-in-directory-p file doom-modules-dir)
"-f" "buttercup-run")) (list "-f" "doom-initialize-core"))
(list
"-l" file
"-f" "buttercup-run"))))
(setq error t)) (setq error t))
(message "%s" (buffer-string))) (message "%s" (buffer-string)))
(print! (info "Ignoring %s" (relpath file))))) (print! (info "Ignoring %s" (relpath file)))))
(if error (if error
(error "A test failed") (user-error "A test failed")
t))) t)))

View file

@ -10,15 +10,26 @@ following shell commands:
git pull --rebase 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)
Switches:
-t/--timeout TTL Seconds until a thread is timed out (default: 45)
--threads N How many threads to use (default: 8)"
(and (doom-upgrade doom-auto-accept
(or (member "-f" args)
(member "--force" args))) (member "--force" args)))
(doom-packages-update doom-auto-accept) (doom-packages-update
doom-auto-accept
(when-let (threads (cadr (member "--threads" args)))
(string-to-number threads))
(when-let (timeout (cadr (or (member "--timeout" args)
(member "-t" args))))
(string-to-number timeout)))
(doom-reload-package-autoloads 'force-p))) (doom-reload-package-autoloads 'force-p)))
;; ;;
;;; Library ;;; library
(defvar doom-repo-url "https://github.com/hlissner/doom-emacs" (defvar doom-repo-url "https://github.com/hlissner/doom-emacs"
"The git repo url for Doom Emacs.") "The git repo url for Doom Emacs.")
@ -33,7 +44,7 @@ following shell commands:
(error "Failed to check working tree in %s" dir)))) (error "Failed to check working tree in %s" dir))))
(defun doom-upgrade (&optional force-p) (defun doom-upgrade (&optional auto-accept-p 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 ((default-directory doom-emacs-dir) (let ((default-directory doom-emacs-dir)
@ -82,12 +93,15 @@ following shell commands:
(substring new-rev 0 10) (substring new-rev 0 10)
(cdr (doom-sh "git" "log" "-1" "--format=%cr" target-remote)))) (cdr (doom-sh "git" "log" "-1" "--format=%cr" target-remote))))
(when (y-or-n-p "View the comparison diff in your browser?") (when (and (not auto-accept-p)
(y-or-n-p "View the comparison diff in your browser?"))
(print! (info "Opened github in your browser.")) (print! (info "Opened github in your browser."))
(browse-url (format "https://github.com/hlissner/doom-emacs/compare/%s...%s" (browse-url (format "https://github.com/hlissner/doom-emacs/compare/%s...%s"
this-rev this-rev
new-rev))) new-rev)))
(if (not (y-or-n-p "Proceed with upgrade?"))
(if (not (or auto-accept-p
(y-or-n-p "Proceed with upgrade?")))
(ignore (print! (error "Aborted"))) (ignore (print! (error "Aborted")))
(print! (start "Upgrading Doom Emacs...")) (print! (start "Upgrading Doom Emacs..."))
(print-group! (print-group!
@ -97,6 +111,7 @@ following shell commands:
(error "Failed to check out %s" (substring new-rev 0 10))) (error "Failed to check out %s" (substring new-rev 0 10)))
(print! (success "Finished upgrading Doom Emacs"))) (print! (success "Finished upgrading Doom Emacs")))
(doom-delete-autoloads-file doom-autoload-file) (doom-delete-autoloads-file doom-autoload-file)
(doom-delete-autoloads-file doom-package-autoload-file)
(doom-cli-refresh "-f") (doom-cli-refresh "-f")
t) t)

View file

@ -186,7 +186,7 @@ stale."
(setq success t)) (setq success t))
(and (doom-packages-rebuild doom-auto-accept) (and (doom-packages-rebuild doom-auto-accept)
(setq success t)) (setq success t))
(and (doom-packages-purge 'elpa-p 'builds-p nil doom-auto-accept) (and (doom-packages-purge nil 'builds-p nil doom-auto-accept)
(setq success t))) (setq success t)))
(doom-reload-package-autoloads (or success force-p)) (doom-reload-package-autoloads (or success force-p))
(doom-byte-compile nil 'recompile)) (doom-byte-compile nil 'recompile))
@ -212,8 +212,7 @@ enabled modules.")
(load! "cli/env") (load! "cli/env")
(load! "cli/upgrade") (load! "cli/upgrade")
(load! "cli/packages") (load! "cli/packages")
(load! "cli/autoloads") (load! "cli/autoloads"))
(load! "cli/patch-macos"))
(defcligroup! "Byte compilation" (defcligroup! "Byte compilation"
"For byte-compiling Doom and your config" "For byte-compiling Doom and your config"

View file

@ -111,8 +111,8 @@ successfully sets indent_style/indent_size.")
;; ;;
;; This is because autorevert abuses the heck out of inotify handles which can ;; This is because autorevert abuses the heck out of inotify handles which can
;; 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 to revert
;; when we switch to a buffer or when we focus the Emacs frame. ;; changes when we switch to a buffer or when we focus the Emacs frame.
(defun doom-auto-revert-buffer-h () (defun doom-auto-revert-buffer-h ()
"Auto revert current buffer, if necessary." "Auto revert current buffer, if necessary."
(unless auto-revert-mode (unless auto-revert-mode
@ -168,7 +168,7 @@ successfully sets indent_style/indent_size.")
"Add dired directory to recentf file list." "Add dired directory to recentf file list."
(recentf-add-file default-directory))) (recentf-add-file default-directory)))
(unless noninteractive (when doom-interactive-mode
(add-hook 'kill-emacs-hook #'recentf-cleanup) (add-hook 'kill-emacs-hook #'recentf-cleanup)
(quiet! (recentf-mode +1)))) (quiet! (recentf-mode +1))))
@ -198,12 +198,22 @@ successfully sets indent_style/indent_size.")
: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-limit 100)
save-place-limit 200)
(defadvice! doom--recenter-on-load-saveplace-a (&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 :after-while #'save-place-find-file-hook
(if buffer-file-name (ignore-errors (recenter)))) (if buffer-file-name (ignore-errors (recenter))))
(defadvice! doom--dont-prettify-saveplace-cache-a (orig-fn)
"`save-place-alist-to-file' uses `pp' to prettify the contents of its cache.
`pp' can be expensive for longer lists, and there's no reason to prettify cache
files, so we replace calls to `pp' with the much faster `prin1'."
:around #'save-place-alist-to-file
(cl-letf (((symbol-function #'pp)
(symbol-function #'prin1)))
(funcall orig-fn)))
(save-place-mode +1)) (save-place-mode +1))
@ -223,6 +233,10 @@ successfully sets indent_style/indent_size.")
(use-package! better-jumper (use-package! better-jumper
:after-call pre-command-hook :after-call pre-command-hook
:preface
;; REVIEW Suppress byte-compiler warning spawning a *Compile-Log* buffer at
;; startup. This can be removed once gilbertw1/better-jumper#2 is merged.
(defvar better-jumper-local-mode nil)
: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)
@ -259,18 +273,9 @@ successfully sets indent_style/indent_size.")
nil)) nil))
(use-package! command-log-mode
:commands global-command-log-mode
:config
(setq command-log-mode-auto-show t
command-log-mode-open-log-turns-on-mode nil
command-log-mode-is-global t
command-log-mode-window-size 50))
(use-package! dtrt-indent (use-package! dtrt-indent
;; Automatic detection of indent settings ;; Automatic detection of indent settings
:unless noninteractive :when doom-interactive-mode
:defer t :defer t
:init :init
(add-hook! '(change-major-mode-after-body-hook read-only-mode-hook) (add-hook! '(change-major-mode-after-body-hook read-only-mode-hook)
@ -389,8 +394,17 @@ successfully sets indent_style/indent_size.")
(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) (defvar doom-buffer-smartparens-mode nil)
(add-hook 'evil-replace-state-exit-hook #'turn-on-smartparens-mode) (add-hook! 'evil-replace-state-exit-hook
(defun doom-enable-smartparens-mode-maybe-h ()
(when doom-buffer-smartparens-mode
(turn-on-smartparens-mode)
(kill-local-variable 'doom-buffer-smartparens-mode))))
(add-hook! 'evil-replace-state-entry-hook
(defun doom-disable-smartparens-mode-maybe-h ()
(when smartparens-mode
(setq-local doom-buffer-smartparens-mode t)
(turn-off-smartparens-mode))))
(smartparens-global-mode +1)) (smartparens-global-mode +1))
@ -412,11 +426,20 @@ successfully sets indent_style/indent_size.")
undo-tree-history-directory-alist undo-tree-history-directory-alist
`(("." . ,(concat doom-cache-dir "undo-tree-hist/")))) `(("." . ,(concat doom-cache-dir "undo-tree-hist/"))))
;; Compress undo-tree history files with zstd, if available. File size isn't
;; the (only) concern here: the file IO barrier is slow for Emacs to cross;
;; reading a tiny file and piping it in-memory through zstd is *slightly*
;; faster than Emacs reading the entire undo-tree file from the get go (on
;; SSDs). Whether or not that's true in practice, we still enjoy zstd's ~80%
;; file savings (these files add up over time and zstd is so incredibly fast).
(when (executable-find "zstd") (when (executable-find "zstd")
(defadvice! doom--undo-tree-make-history-save-file-name-a (file) (defadvice! doom--undo-tree-make-history-save-file-name-a (file)
:filter-return #'undo-tree-make-history-save-file-name :filter-return #'undo-tree-make-history-save-file-name
(concat file ".zst"))) (concat file ".zst")))
;; Strip text properties from undo-tree data to stave off bloat. File size
;; isn't the concern here; undo cache files bloat easily, which can cause
;; freezing, crashes, GC-induced stuttering or delays when opening files.
(defadvice! doom--undo-tree-strip-text-properties-a (&rest _) (defadvice! doom--undo-tree-strip-text-properties-a (&rest _)
:before #'undo-list-transfer-to-tree :before #'undo-list-transfer-to-tree
(dolist (item buffer-undo-list) (dolist (item buffer-undo-list)

View file

@ -23,6 +23,14 @@ and Emacs states, and for non-evil users.")
"An overriding keymap for <leader> keys.") "An overriding keymap for <leader> keys.")
;;
;;; Keybind settings
(when IS-MAC
(setq mac-command-modifier 'super
mac-option-modifier 'meta))
;; ;;
;;; Universal, non-nuclear escape ;;; Universal, non-nuclear escape
@ -411,18 +419,7 @@ Properties
:unless [CONDITION] [...] :unless [CONDITION] [...]
Any of the above properties may be nested, so that they only apply to a Any of the above properties may be nested, so that they only apply to a
certain group of keybinds. certain group of keybinds."
Example
(map! :map magit-mode-map
:m \"C-r\" 'do-something ; C-r in motion state
:nv \"q\" 'magit-mode-quit-window ; q in normal+visual states
\"C-x C-r\" 'a-global-keybind
:g \"C-x C-r\" 'another-global-keybind ; same as above
(:when IS-MAC
:n \"M-s\" 'some-fn
:i \"M-o\" (lambda (interactive) (message \"Hi\"))))"
(doom--map-process rest)) (doom--map-process rest))
(provide 'core-keybinds) (provide 'core-keybinds)

View file

@ -1,8 +1,7 @@
;;; core-lib.el -*- lexical-binding: t; -*- ;;; core-lib.el -*- lexical-binding: t; -*-
(let ((load-path doom--initial-load-path)) (require 'cl-lib)
(require 'subr-x) (require 'subr-x)
(require 'cl-lib))
;; Polyfills ;; Polyfills
(unless EMACS26+ (unless EMACS26+
@ -175,7 +174,7 @@ at the values with which this function was called."
"Push VALUES sequentially into PLACE, if they aren't already present. "Push VALUES sequentially into PLACE, if they aren't already present.
This is a variadic `cl-pushnew'." This is a variadic `cl-pushnew'."
(let ((var (make-symbol "result"))) (let ((var (make-symbol "result")))
`(dolist (,var (list ,@values)) `(dolist (,var (list ,@values) (with-no-warnings ,place))
(cl-pushnew ,var ,place :test #'equal)))) (cl-pushnew ,var ,place :test #'equal))))
(defmacro prependq! (sym &rest lists) (defmacro prependq! (sym &rest lists)
@ -243,7 +242,7 @@ This macro accepts, in order:
3. The function(s) to be added: this can be one function, a list thereof, a 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). list of `defun's, or body forms (implicitly wrapped in a closure).
\(fn [:append :local] HOOKS FUNCTIONS)" \(fn HOOKS [:append :local] FUNCTIONS)"
(declare (indent (lambda (indent-point state) (declare (indent (lambda (indent-point state)
(goto-char indent-point) (goto-char indent-point)
(when (looking-at-p "\\s-*(") (when (looking-at-p "\\s-*(")
@ -295,17 +294,13 @@ Takes the same arguments as `add-hook!'.
If N and M = 1, there's no benefit to using this macro over `remove-hook'. If N and M = 1, there's no benefit to using this macro over `remove-hook'.
\(fn [:append :local] HOOKS FUNCTIONS)" \(fn HOOKS [:append :local] FUNCTIONS)"
(declare (indent defun) (debug t)) (declare (indent defun) (debug t))
`(add-hook! ,hooks :remove ,@rest)) `(add-hook! ,hooks :remove ,@rest))
(defmacro setq-hook! (hooks &rest var-vals) (defmacro setq-hook! (hooks &rest var-vals)
"Sets buffer-local variables on HOOKS. "Sets buffer-local variables on HOOKS.
(setq-hook! 'markdown-mode-hook
line-spacing 2
fill-column 80)
\(fn HOOKS &rest [SYM VAL]...)" \(fn HOOKS &rest [SYM VAL]...)"
(declare (indent 1)) (declare (indent 1))
(macroexp-progn (macroexp-progn
@ -338,7 +333,10 @@ If NOERROR is non-nil, don't throw an error if the file doesn't exist."
(setq path (or (dir!) (setq path (or (dir!)
(error "Could not detect path to look for '%s' in" (error "Could not detect path to look for '%s' in"
filename)))) filename))))
(let ((file (if path `(expand-file-name ,filename ,path) filename))) (let ((file (if path
`(let (file-name-handler-alist)
(expand-file-name ,filename ,path))
filename)))
`(condition-case e `(condition-case e
(load ,file ,noerror ,(not doom-debug-mode)) (load ,file ,noerror ,(not doom-debug-mode))
((debug doom-error) (signal (car e) (cdr e))) ((debug doom-error) (signal (car e) (cdr e)))
@ -372,36 +370,37 @@ serve as a predicated alternative to `after!'."
(put ',fn 'permanent-local-hook t) (put ',fn 'permanent-local-hook t)
(add-hook 'after-load-functions #',fn))))) (add-hook 'after-load-functions #',fn)))))
(defmacro defer-feature! (feature &optional mode) (defmacro defer-feature! (feature &optional fn)
"Pretend FEATURE hasn't been loaded yet, until FEATURE-hook is triggered. "Pretend FEATURE hasn't been loaded yet, until FEATURE-hook or FN runs.
Some packages (like `elisp-mode' and `lisp-mode') are loaded immediately at Some packages (like `elisp-mode' and `lisp-mode') are loaded immediately at
startup, which will prematurely trigger `after!' (and `with-eval-after-load') 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 FN 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-a" feature))) (let ((advice-fn (intern (format "doom--defer-feature-%s-a" feature)))
(mode (or mode feature))) (fn (or fn feature)))
`(progn `(progn
(setq features (delq ',feature features)) (setq features (delq ',feature features))
(advice-add #',mode :before #',advice-fn) (advice-add #',fn :before #',advice-fn)
(defun ,advice-fn (&rest _) (defun ,advice-fn (&rest _)
;; Some plugins (like yasnippet) will invoke a mode early to parse ;; Some plugins (like yasnippet) will invoke a fn early to parse
;; code, which would prematurely trigger this. In those cases, well ;; code, which would prematurely trigger this. In those cases, well
;; behaved plugins will use `delay-mode-hooks', which we can check for: ;; behaved plugins will use `delay-mode-hooks', which we can check for:
(when (and ,(intern (format "%s-hook" mode)) (when (and ,(intern (format "%s-hook" fn))
(not delay-mode-hooks)) (not delay-mode-hooks))
;; ...Otherwise, announce to the world this package has been loaded, ;; ...Otherwise, announce to the world this package has been loaded,
;; so `after!' handlers can react. ;; so `after!' handlers can react.
(provide ',feature) (provide ',feature)
(advice-remove #',mode #',advice-fn)))))) (advice-remove #',fn #',advice-fn))))))
(defmacro quiet! (&rest forms) (defmacro quiet! (&rest forms)
"Run FORMS without generating any output. "Run FORMS without generating any output.
This silences calls to `message', `load-file', `write-region' and anything that This silences calls to `message', `load-file', `write-region' and anything that
writes to `standard-output'." writes to `standard-output'."
`(cond (noninteractive `(cond (doom-debug-mode ,@forms)
((not doom-interactive-mode)
(let ((old-fn (symbol-function 'write-region))) (let ((old-fn (symbol-function 'write-region)))
(cl-letf ((standard-output (lambda (&rest _))) (cl-letf ((standard-output (lambda (&rest _)))
((symbol-function 'load-file) (lambda (file) (load file nil t))) ((symbol-function 'load-file) (lambda (file) (load file nil t)))
@ -411,8 +410,6 @@ writes to `standard-output'."
(unless visit (setq visit 'no-message)) (unless visit (setq visit 'no-message))
(funcall old-fn start end filename append visit lockname mustbenew)))) (funcall old-fn start end filename append visit lockname mustbenew))))
,@forms))) ,@forms)))
((or doom-debug-mode debug-on-error debug-on-quit)
,@forms)
((let ((inhibit-message t) ((let ((inhibit-message t)
(save-silently t)) (save-silently t))
(prog1 ,@forms (message "")))))) (prog1 ,@forms (message ""))))))

View file

@ -48,7 +48,7 @@ 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-inhibit-module-warnings (not noninteractive) (defvar doom-inhibit-module-warnings doom-interactive-mode
"If non-nil, don't emit deprecated or missing module warnings at startup.") "If non-nil, don't emit deprecated or missing module warnings at startup.")
;;; Custom hooks ;;; Custom hooks
@ -84,7 +84,7 @@ non-nil."
(load! "init" (plist-get plist :path) t))) (load! "init" (plist-get plist :path) t)))
doom-modules)) doom-modules))
(run-hook-wrapped 'doom-before-init-modules-hook #'doom-try-run-hook) (run-hook-wrapped 'doom-before-init-modules-hook #'doom-try-run-hook)
(unless noninteractive (when doom-interactive-mode
(when doom-modules (when doom-modules
(maphash (lambda (key plist) (maphash (lambda (key plist)
(let ((doom--current-module key) (let ((doom--current-module key)
@ -224,7 +224,7 @@ those directories. The first returned path is always `doom-private-dir'."
"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." 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 (doom-interactive-mode
doom-modules doom-modules
doom-init-modules-p) doom-init-modules-p)
(load! "init" doom-private-dir t) (load! "init" doom-private-dir t)
@ -243,30 +243,16 @@ This value is cached. If REFRESH-P, then don't use the cached value."
(setq use-package-compute-statistics doom-debug-mode (setq use-package-compute-statistics doom-debug-mode
use-package-verbose doom-debug-mode use-package-verbose doom-debug-mode
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 doom-interactive-mode))
;; Adds four new keywords to `use-package' (and consequently, `use-package!') to
;; expand its lazy-loading capabilities. They are:
;;
;; Check out `use-package!'s documentation for more about these two.
;; :after-call SYMBOL|LIST
;; :defer-incrementally SYMBOL|LIST|t
;;
;; Provided by `auto-minor-mode' package:
;; :minor
;; :magic-minor
;;
(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)
;; Register all new keywords ;; We define :minor and :magic-minor from the `auto-minor-mode' package here
(dolist (keyword '(:defer-incrementally :after-call)) ;; so we don't have to load `auto-minor-mode' so early.
(push keyword use-package-deferring-keywords)
(setq use-package-keywords
(use-package-list-insert keyword use-package-keywords :after)))
(dolist (keyword '(:minor :magic-minor)) (dolist (keyword '(:minor :magic-minor))
(setq use-package-keywords (setq use-package-keywords
(use-package-list-insert keyword use-package-keywords :commands))) (use-package-list-insert keyword use-package-keywords :commands)))
@ -279,6 +265,17 @@ This value is cached. If REFRESH-P, then don't use the cached value."
(defun use-package-handler/:magic-minor (name _ arg rest state) (defun use-package-handler/:magic-minor (name _ arg rest state)
(use-package-handle-mode name 'auto-minor-mode-magic-alist arg rest state)) (use-package-handle-mode name 'auto-minor-mode-magic-alist arg rest state))
;; Adds two keywords to `use-package' to expand its lazy-loading capabilities:
;;
;; :after-call SYMBOL|LIST
;; :defer-incrementally SYMBOL|LIST|t
;;
;; Check out `use-package!'s documentation for more about these two.
(dolist (keyword '(:defer-incrementally :after-call))
(push keyword use-package-deferring-keywords)
(setq use-package-keywords
(use-package-list-insert keyword use-package-keywords :after)))
(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)
(use-package-concat (use-package-concat
@ -410,7 +407,7 @@ to least)."
(if-let (path (doom-module-locate-path category module)) (if-let (path (doom-module-locate-path category module))
(doom-module-set category module :flags flags :path path) (doom-module-set category module :flags flags :path path)
(message "WARNING Couldn't find the %s %s module" category module))))))) (message "WARNING Couldn't find the %s %s module" category module)))))))
(when noninteractive (unless doom-interactive-mode
(setq doom-inhibit-module-warnings t)) (setq doom-inhibit-module-warnings t))
`(setq doom-modules ',doom-modules))) `(setq doom-modules ',doom-modules)))
@ -428,26 +425,17 @@ two extra properties:
:after-call SYMBOL|LIST :after-call SYMBOL|LIST
Takes a symbol or list of symbols representing functions or hook variables. Takes a symbol or list of symbols representing functions or hook variables.
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.
(use-package! projectile
:after-call (pre-command-hook after-find-file dired-before-readin-hook)
...)
:defer-incrementally SYMBOL|LIST|t :defer-incrementally SYMBOL|LIST|t
Takes a symbol or list of symbols representing packages that will be loaded Takes a symbol or list of symbols representing packages that will be loaded
incrementally at startup before this one. This is helpful for large packages incrementally at startup before this one. This is helpful for large packages
like magit or org, which load a lot of dependencies on first load. This lets like magit or org, which load a lot of dependencies on first load. This lets
you load them piece-meal during idle periods, so that when you finally do need you load them piece-meal during idle periods, so that when you finally do need
the package, it'll load quicker. e.g. the package, it'll load quicker.
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."
(use-package! abc
;; This is equivalent to :defer-incrementally (abc)
:defer-incrementally t
...)"
(declare (indent 1)) (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
@ -462,7 +450,8 @@ two extra properties:
(defmacro use-package-hook! (package when &rest body) (defmacro use-package-hook! (package when &rest body)
"Reconfigures a package's `use-package!' block. "Reconfigures a package's `use-package!' block.
Only use this macro in a module's init.el file. This macro must be used *before* PACKAGE's `use-package!' block. Often, this
means using it from your DOOMDIR/init.el.
Under the hood, this uses use-package's `use-package-inject-hooks'. Under the hood, this uses use-package's `use-package-inject-hooks'.
@ -470,9 +459,13 @@ PACKAGE is a symbol; the package's name.
WHEN should be one of the following: 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 WARNINGS:
`use-package!''s :init/:config block (respectively) is overwritten, so remember - The use of this macro is more often than not a code smell. Use it as last
to have them return non-nil (or exploit that to overwrite Doom's config)." resort. There is almost always a better alternative.
- If you are using this solely for :post-config, stop! `after!' is much better.
- If :pre-init or :pre-config hooks return nil, the original `use-package!''s
:init/:config block (respectively) is overwritten, so remember to have them
return non-nil (or exploit that to overwrite Doom's config)."
(declare (indent defun)) (declare (indent defun))
(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 use-package-hook!" when)) (error "'%s' isn't a valid hook for use-package-hook!" when))
@ -493,7 +486,7 @@ CATEGORY is a keyword, MODULE is a symbol and FLAGS are symbols.
This is for testing and internal use. This is not the correct way to enable a This is for testing and internal use. This is not the correct way to enable a
module." module."
`(let ((doom-modules ,doom-modules) `(let ((doom-modules (or ,doom-modules (doom-modules)))
(module-path (doom-module-locate-path ,category ',module))) (module-path (doom-module-locate-path ,category ',module)))
(doom-module-set (doom-module-set
,category ',module ,category ',module

View file

@ -74,8 +74,8 @@ missing) and shouldn't be deleted.")
;; shouldn't be using it, but it may be convenient for quick package testing. ;; 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-enable-at-startup nil package-enable-at-startup nil
package-user-dir doom-elpa-dir package-user-dir (concat doom-local-dir "elpa/")
package-gnupghome-dir (expand-file-name "gpg" doom-elpa-dir) package-gnupghome-dir (expand-file-name "gpg" package-user-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
@ -112,12 +112,6 @@ missing) and shouldn't be deleted.")
;; we just don't have to deal with them at all. ;; we just don't have to deal with them at all.
autoload-compute-prefixes nil) autoload-compute-prefixes nil)
;; Straight is hardcoded to operate out of ~/.emacs.d/straight. Not on my watch!
(defadvice! doom--straight-use-local-dir-a (orig-fn &rest args)
:around #'straight--emacs-dir
(let ((user-emacs-directory doom-local-dir))
(apply orig-fn args)))
(defun doom--finalize-straight () (defun doom--finalize-straight ()
(mapc #'funcall (delq nil (mapcar #'cdr straight--transaction-alist))) (mapc #'funcall (delq nil (mapcar #'cdr straight--transaction-alist)))
(setq straight--transaction-alist nil)) (setq straight--transaction-alist nil))
@ -155,8 +149,6 @@ necessary package metadata is initialized and available for them."
:branch ,straight-repository-branch :branch ,straight-repository-branch
:no-byte-compile t)) :no-byte-compile t))
(mapc #'straight-use-package doom-core-packages) (mapc #'straight-use-package doom-core-packages)
(when noninteractive
(add-hook 'kill-emacs-hook #'doom--finalize-straight)))
(doom-log "Initializing doom-packages") (doom-log "Initializing doom-packages")
(setq doom-disabled-packages nil (setq doom-disabled-packages nil
doom-packages (doom-package-list)) doom-packages (doom-package-list))
@ -171,7 +163,9 @@ necessary package metadata is initialized and available for them."
(if-let (recipe (plist-get plist :recipe)) (if-let (recipe (plist-get plist :recipe))
(let ((plist (straight-recipes-retrieve pkg))) (let ((plist (straight-recipes-retrieve pkg)))
`(,pkg ,@(doom-plist-merge recipe (cdr plist)))) `(,pkg ,@(doom-plist-merge recipe (cdr plist))))
pkg))))) pkg))))
(unless doom-interactive-mode
(add-hook 'kill-emacs-hook #'doom--finalize-straight))))
(defun doom-ensure-straight () (defun doom-ensure-straight ()
"Ensure `straight' is installed and was compiled with this version of Emacs." "Ensure `straight' is installed and was compiled with this version of Emacs."
@ -214,7 +208,7 @@ Accepts the following properties:
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.
: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 `use-package!'
blocks. blocks.
:ignore FORM :ignore FORM
Do not install this package. Do not install this package.

View file

@ -30,7 +30,7 @@ Emacs.")
projectile-add-known-project) ; TODO PR autoload upstream projectile-add-known-project) ; TODO PR autoload upstream
:init :init
(setq projectile-cache-file (concat doom-cache-dir "projectile.cache") (setq projectile-cache-file (concat doom-cache-dir "projectile.cache")
projectile-enable-caching (not noninteractive) projectile-enable-caching doom-interactive-mode
projectile-known-projects-file (concat doom-cache-dir "projectile.projects") projectile-known-projects-file (concat doom-cache-dir "projectile.projects")
projectile-require-project-root t projectile-require-project-root t
projectile-globally-ignored-files '(".DS_Store" "Icon " "TAGS") projectile-globally-ignored-files '(".DS_Store" "Icon " "TAGS")
@ -51,6 +51,11 @@ Emacs.")
(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)
;; Disable commands that won't work, as is, and that Doom already provides a
;; better alternative for.
(put 'projectile-ag 'disabled "Use +{ivy,helm}/project-search or +{ivy,helm}/ag instead")
(put 'projectile-ripgrep 'disabled "Use +{ivy,helm}/project-search or +{ivy,helm}/rg instead")
;; Treat current directory in dired as a "file in a project" and track it ;; Treat current directory in dired as a "file in a project" and track it
(add-hook 'dired-before-readin-hook #'projectile-track-known-projects-find-file-hook) (add-hook 'dired-before-readin-hook #'projectile-track-known-projects-find-file-hook)
@ -67,7 +72,7 @@ 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 (and (bound-and-true-p projectile-projects-cache) (when (and (bound-and-true-p projectile-projects-cache)
(not noninteractive)) doom-interactive-mode)
(cl-loop with blacklist = (mapcar #'file-truename doom-projectile-cache-blacklist) (cl-loop with blacklist = (mapcar #'file-truename doom-projectile-cache-blacklist)
for proot in (hash-table-keys projectile-projects-cache) for proot in (hash-table-keys projectile-projects-cache)
if (or (not (stringp proot)) if (or (not (stringp proot))
@ -239,14 +244,16 @@ Relevant: `doom-project-hook'."
,(if (stringp (car files)) (cons 'and files) files)))) ,(if (stringp (car files)) (cons 'and files) files))))
,(or when t) ,(or when t)
(,name 1))))) (,name 1)))))
`((dolist (mode ,modes) (if modes
(let ((hook-name `((dolist (mode ,modes)
(intern (format "doom--enable-%s%s-h" ',name (let ((hook-name
(if (eq mode t) "" (format "-in-%s" mode)))))) (intern (format "doom--enable-%s%s-h" ',name
(fset hook-name #',fn) (if (eq mode t) "" (format "-in-%s" mode))))))
(if (eq mode t) (fset hook-name #',fn)
(add-to-list 'auto-minor-mode-magic-alist (cons hook-name #',name)) (if (eq mode t)
(add-hook (intern (format "%s-hook" mode)) hook-name))))))) (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 (match
`((add-to-list 'auto-minor-mode-alist (cons ,match #',name))))))))) `((add-to-list 'auto-minor-mode-alist (cons ,match #',name)))))))))

View file

@ -344,7 +344,7 @@ treat Emacs as a non-application window."
(setq mode-line-default-help-echo nil (setq mode-line-default-help-echo nil
show-help-function nil) show-help-function nil)
;; y/n is easier to type than yes/no ;; Typing yes/no is obnoxious when y/n will do
(fset #'yes-or-no-p #'y-or-n-p) (fset #'yes-or-no-p #'y-or-n-p)
;; Try really hard to keep the cursor from getting stuck in the read-only prompt ;; Try really hard to keep the cursor from getting stuck in the read-only prompt
@ -372,11 +372,11 @@ treat Emacs as a non-application window."
(use-package! ediff (use-package! ediff
:defer t :defer t
:init :config
(setq ediff-diff-options "-w" ; turn off whitespace checking (setq ediff-diff-options "-w" ; turn off whitespace checking
ediff-split-window-function #'split-window-horizontally ediff-split-window-function #'split-window-horizontally
ediff-window-setup-function #'ediff-setup-windows-plain) ediff-window-setup-function #'ediff-setup-windows-plain)
: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
(add-hook! 'ediff-before-setup-hook (add-hook! 'ediff-before-setup-hook
@ -579,26 +579,26 @@ character that looks like a space that `whitespace-mode' won't affect.")
behavior). Do not set this directly, this is let-bound in `doom-init-theme-h'.") behavior). Do not set this directly, this is let-bound in `doom-init-theme-h'.")
(defun doom-init-fonts-h () (defun doom-init-fonts-h ()
"Loads fonts. "Loads `doom-font'."
(cond (doom-font
(add-to-list
'default-frame-alist
(cons 'font
(cond ((stringp doom-font) doom-font)
((fontp doom-font) (font-xlfd-name doom-font))
((signal 'wrong-type-argument (list '(fontp stringp) doom-font)))))))
((display-graphic-p)
(setq doom-font (face-attribute 'default :font)))))
Fonts are specified by `doom-font', `doom-variable-pitch-font', (defun doom-init-extra-fonts-h (&optional frame)
`doom-serif-font' and `doom-unicode-font'." "Loads `doom-variable-pitch-font',`doom-serif-font' and `doom-unicode-font'."
(condition-case e (condition-case e
(progn (with-selected-frame (or frame (selected-frame))
(cond (doom-font
(add-to-list
'default-frame-alist
(cons 'font
(cond ((stringp doom-font) doom-font)
((fontp doom-font) (font-xlfd-name doom-font))
((signal 'wrong-type-argument (list '(fontp stringp) doom-font)))))))
((display-graphic-p)
(setq doom-font (face-attribute 'default :font))))
(when doom-serif-font (when doom-serif-font
(set-face-attribute 'fixed-pitch-serif t :font doom-serif-font)) (set-face-attribute 'fixed-pitch-serif nil :font doom-serif-font))
(when doom-variable-pitch-font (when doom-variable-pitch-font
(set-face-attribute 'variable-pitch t :font doom-variable-pitch-font)) (set-face-attribute 'variable-pitch nil :font doom-variable-pitch-font))
(when doom-unicode-font (when (and doom-unicode-font (fboundp 'set-fontset-font))
(set-fontset-font t 'unicode doom-unicode-font nil 'prepend))) (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))
@ -656,10 +656,15 @@ startup (or theme switch) time, so long as `doom--prefer-theme-elc' is non-nil."
(dolist (fn '(switch-to-buffer display-buffer)) (dolist (fn '(switch-to-buffer display-buffer))
(advice-add fn :around #'doom-run-switch-buffer-hooks-a))) (advice-add fn :around #'doom-run-switch-buffer-hooks-a)))
;; Apply `doom-theme'
(add-hook 'doom-init-ui-hook #'doom-init-theme-h)
;; Apply `doom-font' et co ;; Apply `doom-font' et co
(add-hook 'doom-after-init-modules-hook #'doom-init-fonts-h) (add-hook 'doom-after-init-modules-hook #'doom-init-fonts-h)
(add-hook 'doom-load-theme-hook #'doom-init-extra-fonts-h)
;; Apply `doom-theme'
(add-hook (if (daemonp)
'after-make-frame-functions
'doom-init-ui-hook)
#'doom-init-theme-h)
(add-hook 'window-setup-hook #'doom-init-ui-h) (add-hook 'window-setup-hook #'doom-init-ui-h)
@ -669,7 +674,7 @@ startup (or theme switch) time, so long as `doom--prefer-theme-elc' is non-nil."
;; doesn't exist in terminal Emacs; we define it to prevent errors ;; doesn't exist in terminal Emacs; we define it to prevent errors
(unless (fboundp 'define-fringe-bitmap) (unless (fboundp 'define-fringe-bitmap)
(defun define-fringe-bitmap (&rest _))) (fset 'define-fringe-bitmap #'ignore))
(after! whitespace (after! whitespace
(defun doom-disable-whitespace-mode-in-childframes-a (orig-fn) (defun doom-disable-whitespace-mode-in-childframes-a (orig-fn)

View file

@ -1,5 +1,16 @@
;;; core.el --- the heart of the beast -*- lexical-binding: t; -*- ;;; core.el --- the heart of the beast -*- lexical-binding: t; -*-
(defconst doom-version "2.0.9"
"Current version of Doom Emacs.")
(defconst EMACS26+ (> emacs-major-version 25))
(defconst EMACS27+ (> emacs-major-version 26))
(defconst IS-MAC (eq system-type 'darwin))
(defconst IS-LINUX (eq system-type 'gnu/linux))
(defconst IS-WINDOWS (memq system-type '(cygwin windows-nt ms-dos)))
(defconst IS-BSD (or IS-MAC (eq system-type 'berkeley-unix)))
;;
(defvar doom-init-p nil (defvar doom-init-p nil
"Non-nil if Doom has been initialized.") "Non-nil if Doom has been initialized.")
@ -12,22 +23,13 @@
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-interactive-mode (not noninteractive)
"If non-nil, Emacs is in interactive mode.")
(defvar doom-gc-cons-threshold 16777216 ; 16mb (defvar doom-gc-cons-threshold 16777216 ; 16mb
"The default value to use for `gc-cons-threshold'. If you experience freezing, "The default value to use for `gc-cons-threshold'. If you experience freezing,
decrease this. If you experience stuttering, increase this.") decrease this. If you experience stuttering, increase this.")
;;; Constants
(defconst doom-version "2.0.9"
"Current version of Doom Emacs.")
(defconst EMACS26+ (> emacs-major-version 25))
(defconst EMACS27+ (> emacs-major-version 26))
(defconst IS-MAC (eq system-type 'darwin))
(defconst IS-LINUX (eq system-type 'gnu/linux))
(defconst IS-WINDOWS (memq system-type '(cygwin windows-nt ms-dos)))
(defconst IS-BSD (or IS-MAC (eq system-type 'berkeley-unix)))
;;; Directories/files ;;; 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))
@ -59,11 +61,6 @@ 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-elpa-dir (concat doom-local-dir "elpa/")
"Where package.el and quelpa plugins (and their caches) are stored.
Must end with a slash.")
(defvar doom-docs-dir (concat doom-emacs-dir "docs/") (defvar doom-docs-dir (concat doom-emacs-dir "docs/")
"Where Doom's documentation files are stored. Must end with a slash.") "Where Doom's documentation files are stored. Must end with a slash.")
@ -146,9 +143,6 @@ users).")
;; to, it's our (the user's) failure. One case for all! ;; to, it's our (the user's) failure. One case for all!
(setq auto-mode-case-fold nil) (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 ;; Display the bare minimum at startup. We don't need all that noise. The
;; dashboard/empty scratch buffer is good enough. ;; dashboard/empty scratch buffer is good enough.
(setq inhibit-startup-message t (setq inhibit-startup-message t
@ -202,6 +196,13 @@ users).")
url-cache-directory (concat doom-cache-dir "url/") url-cache-directory (concat doom-cache-dir "url/")
url-configuration-directory (concat doom-etc-dir "url/") url-configuration-directory (concat doom-etc-dir "url/")
gamegrid-user-score-file-directory (concat doom-etc-dir "games/")) gamegrid-user-score-file-directory (concat doom-etc-dir "games/"))
;; HACK
(with-eval-after-load 'x-win
(defun emacs-session-filename (session-id)
"Construct a filename to save a session based on SESSION-ID.
Doom Emacs overrides this function to stop sessions from littering the user
directory. The session files are placed by default in `doom-cache-dir'"
(concat doom-cache-dir "emacs-session." session-id)))
;; ;;
@ -222,8 +223,8 @@ users).")
(setq fast-but-imprecise-scrolling t) (setq fast-but-imprecise-scrolling t)
;; Resizing the Emacs frame can be a terribly expensive part of changing the ;; Resizing the Emacs frame can be a terribly expensive part of changing the
;; font. By inhibiting this, we easily halve startup times with fonts that are ;; font. By inhibiting this, we halve startup times, particularly when we use
;; larger than the system default. ;; fonts that are larger than the system default (which would resize the frame).
(setq frame-inhibit-implied-resize t) (setq frame-inhibit-implied-resize t)
;; Don't ping things that look like domain names. ;; Don't ping things that look like domain names.
@ -320,7 +321,8 @@ 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-h' 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. Incremental loading does not occur
in daemon sessions (they are loaded immediately at startup).")
(defvar doom-incremental-first-idle-timer 2 (defvar doom-incremental-first-idle-timer 2
"How long (in idle seconds) until incremental loading starts. "How long (in idle seconds) until incremental loading starts.
@ -401,7 +403,8 @@ If RETURN-P, return the message as a string instead of displaying it."
(- (length load-path) (length doom--initial-load-path)) (- (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-load-autoloads-file (file) (defun doom-load-autoloads-file (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
@ -410,7 +413,7 @@ in interactive sessions, nil otherwise (but logs a warning)."
(let (command-switch-alist) (let (command-switch-alist)
(load (substring file 0 -3) 'noerror 'nomessage)) (load (substring file 0 -3) 'noerror 'nomessage))
((debug error) ((debug error)
(if noninteractive (if doom-interactive-mode
(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))))))
@ -419,25 +422,27 @@ in interactive sessions, nil otherwise (but logs a warning)."
(if (not (file-readable-p file)) (if (not (file-readable-p file))
(unless noerror (unless noerror
(signal 'file-error (list "Couldn't read envvar file" file))) (signal 'file-error (list "Couldn't read envvar file" file)))
(with-temp-buffer (let (vars)
(insert-file-contents file) (with-temp-buffer
(search-forward "\n\n" nil t) (insert-file-contents file)
(while (re-search-forward "\n\\([^= \n]+\\)=" nil t) (while (re-search-forward "\n *\\([^#][^= \n]+\\)=" nil t)
(save-excursion (save-excursion
(let ((var (match-string 1)) (let ((var (string-trim-left (match-string 1)))
(value (buffer-substring-no-properties (value (buffer-substring-no-properties
(point) (point)
(1- (or (when (re-search-forward "^\\([^= ]+\\)=" nil t) (1- (or (when (re-search-forward "^\\([^= ]+\\)=" nil t)
(line-beginning-position)) (line-beginning-position))
(point-max)))))) (point-max))))))
(setenv var value))))) (push (cons var value) vars)
(setq-default (setenv var value)))))
exec-path (append (split-string (getenv "PATH") (when vars
(if IS-WINDOWS ";" ":")) (setq-default
(list exec-directory)) exec-path (append (split-string (getenv "PATH")
shell-file-name (or (getenv "SHELL") (if IS-WINDOWS ";" ":"))
shell-file-name)) (list exec-directory))
t)) shell-file-name (or (getenv "SHELL")
shell-file-name))
(nreverse vars)))))
(defun doom-initialize (&optional force-p) (defun doom-initialize (&optional force-p)
"Bootstrap Doom, if it hasn't already (or if FORCE-P is non-nil). "Bootstrap Doom, if it hasn't already (or if FORCE-P is non-nil).
@ -495,7 +500,7 @@ to least)."
;; `Info-directory-list', and `doom-disabled-packages'. A big ;; `Info-directory-list', and `doom-disabled-packages'. A big
;; reduction in startup time. ;; reduction in startup time.
(pkg-autoloads-p (pkg-autoloads-p
(unless noninteractive (when doom-interactive-mode
(doom-load-autoloads-file doom-package-autoload-file)))) (doom-load-autoloads-file doom-package-autoload-file))))
(if (and core-autoloads-p (not force-p)) (if (and core-autoloads-p (not force-p))
@ -507,17 +512,16 @@ to least)."
(require 'core-packages) (require 'core-packages)
(doom-initialize-packages))) (doom-initialize-packages)))
;; Eagerly load these libraries because this module may be loaded in a session ;; Eagerly load these libraries because we may be in a session that
;; that hasn't been fully initialized (where autoloads files haven't been ;; hasn't been fully initialized (e.g. where autoloads files haven't
;; generated or `load-path' populated). ;; been generated or `load-path' populated).
(mapc (doom-rpartial #'load 'noerror 'nomessage) (mapc (doom-rpartial #'load 'noerror 'nomessage)
(file-expand-wildcards (concat doom-core-dir "autoload/*.el"))) (file-expand-wildcards (concat doom-core-dir "autoload/*.el")))
;; Create all our core directories to quell file errors ;; Create all our core directories to quell file errors
(dolist (dir (list doom-local-dir (dolist (dir (list doom-local-dir
doom-etc-dir doom-etc-dir
doom-cache-dir doom-cache-dir))
doom-elpa-dir))
(unless (file-directory-p dir) (unless (file-directory-p dir)
(make-directory dir 'parents))) (make-directory dir 'parents)))
@ -528,12 +532,13 @@ to least)."
(unless (or (and core-autoloads-p pkg-autoloads-p) (unless (or (and core-autoloads-p pkg-autoloads-p)
force-p force-p
noninteractive) (not doom-interactive-mode))
(unless core-autoloads-p (unless core-autoloads-p
(message "Your Doom core autoloads file is missing")) (warn "Your Doom core autoloads file is missing"))
(unless pkg-autoloads-p (unless pkg-autoloads-p
(message "Your package autoloads file is missing")) (warn "Your package autoloads file is missing"))
(user-error "Run `bin/doom refresh' to generate them"))))) (signal 'doom-autoload-error "Run `bin/doom refresh' to generate them")))
t))
(defun doom-initialize-core () (defun doom-initialize-core ()
"Load Doom's core files for an interactive session." "Load Doom's core files for an interactive session."

View file

@ -9,6 +9,8 @@
(package! all-the-icons) (package! all-the-icons)
(package! hide-mode-line) (package! hide-mode-line)
(package! highlight-numbers) (package! highlight-numbers)
;; Some early 26.x builds of Emacs do not have `display-line-numbers' yet, so
;; check for it instead of Emacs' version.
(unless (locate-library "display-line-numbers") (unless (locate-library "display-line-numbers")
(package! nlinum) (package! nlinum)
(package! nlinum-hl) (package! nlinum-hl)
@ -18,7 +20,6 @@
;; core-editor.el ;; core-editor.el
(package! better-jumper) (package! better-jumper)
(package! command-log-mode)
(package! dtrt-indent) (package! dtrt-indent)
(package! helpful) (package! helpful)
(package! ns-auto-titlebar :ignore (not IS-MAC)) (package! ns-auto-titlebar :ignore (not IS-MAC))
@ -26,11 +27,14 @@
(package! smartparens) (package! smartparens)
(package! so-long (package! so-long
:built-in 'prefer :built-in 'prefer
:recipe (:repo "https://git.savannah.gnu.org/git/so-long.git")) ;; REVIEW so-long is slated to be published to ELPA eventually, but until then
;; I've created my own mirror for it because git.savannah.gnu.org runs on a
;; potato.
:recipe (:host github :repo "hlissner/emacs-so-long"))
(package! osx-clipboard :ignore (not IS-MAC)) (package! osx-clipboard :ignore (not IS-MAC))
(package! undo-tree) (package! undo-tree)
(package! ws-butler) (package! ws-butler)
(package! xclip :ignore IS-LINUX) (package! xclip :ignore (not IS-LINUX))
;; core-projects.el ;; core-projects.el
(package! projectile) (package! projectile)
@ -38,6 +42,3 @@
;; core-keybinds.el ;; core-keybinds.el
(package! general) (package! general)
(package! which-key) (package! which-key)
;; autoload/debug.el
(package! esup)

View file

@ -1,6 +1,64 @@
;; -*- no-byte-compile: t; -*- ;; -*- lexical-binding: t; no-byte-compile: t; -*-
;;; core/test/helpers.el ;;; core/test/helpers.el
(eval-and-compile
(setq doom-interactive-mode 'test)
(doom-initialize 'force)
(require 'buttercup)
(setq split-width-threshold 0
split-height-threshold 0
window-min-width 0
window-min-height 0))
;;
;;; Buttercup extensions
(buttercup-define-matcher :to-expand-into (form expected)
(cl-destructuring-bind (form expected)
(mapcar #'funcall (list form expected))
(let ((expanded (macroexpand-1 form)))
(if (equal expanded expected)
(cons t (format "Expected `%S' to not expand to `%S'"
form expected))
(cons nil (format "Expected `%S' to not expand to `%S', but got `%S' instead"
form expected expanded))))))
(buttercup-define-matcher :to-output (form &optional expected-output)
(let ((expected-output (and (functionp expected-output)
(funcall expected-output)))
output)
(with-current-buffer (get-buffer "*Messages*")
(let ((standard-output (current-buffer))
(start (point)))
(let ((inhibit-message t))
(funcall form))
(setq output (buffer-substring-no-properties start (point-max)))
(with-silent-modifications (erase-buffer))))
(cond ((null expected-output)
(if (string-empty-p output)
(cons nil (format "Expected output %S, but got none"
expected-output))
(cons t (format "Expected no output, but got %S"
output))))
((not (equal expected-output output))
(cons nil (format "Expected output %S, but got %S instead"
expected-output output)))
((cons t (format "Expected to not get %S as output"
expected-output))))))
(buttercup-define-matcher :to-contain-items (items expected)
(cl-destructuring-bind (items expected)
(mapcar #'funcall (list items expected))
(if-let (missing (cl-set-difference expected items))
(cons nil (format "Expected list to contain %S, but it was missing %S"
expected missing))
(cons t (format "Expected list to not contain %S, but it did: %S"
expected items)))))
;;
;;; Helper macros
(defmacro insert!! (&rest text) (defmacro insert!! (&rest text)
"Insert TEXT in buffer, then move cursor to last {0} marker." "Insert TEXT in buffer, then move cursor to last {0} marker."
`(progn `(progn

4
core/test/packages.el Normal file
View file

@ -0,0 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; core/test/packages.el
(package! buttercup)

View file

@ -1,16 +1,12 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; core/test/test-autoload-buffers.el ;;; core/test/test-autoload-buffers.el
(require 'core-projects)
(load! "autoload/buffers" doom-core-dir)
;;
(describe "core/autoload/buffers" (describe "core/autoload/buffers"
:var (a b c d) :var (a b c d)
(before-all
(spy-on 'buffer-list :and-call-fake (require 'core-projects)
(lambda (&optional _) (load! "autoload/buffers" doom-core-dir)
(cl-remove-if-not #'buffer-live-p (list a b c d)))))
(before-each (before-each
(delete-other-windows) (delete-other-windows)
(setq a (switch-to-buffer (get-buffer-create "a")) (setq a (switch-to-buffer (get-buffer-create "a"))
@ -25,7 +21,7 @@
(describe "buffer-list" (describe "buffer-list"
(it "should only see four buffers" (it "should only see four buffers"
(expect (doom-buffer-list) :to-have-same-items-as (list a b c d)))) (expect (doom-buffer-list) :to-contain-items (list a b c d))))
(describe "project-buffer-list" (describe "project-buffer-list"
:var (projectile-projects-cache-time projectile-projects-cache) :var (projectile-projects-cache-time projectile-projects-cache)
@ -34,7 +30,7 @@
(before-each (before-each
(with-current-buffer a (setq default-directory doom-emacs-dir)) (with-current-buffer a (setq default-directory doom-emacs-dir))
(with-current-buffer b (setq default-directory doom-emacs-dir)) (with-current-buffer b (setq default-directory doom-core-dir))
(with-current-buffer c (setq default-directory "/tmp/")) (with-current-buffer c (setq default-directory "/tmp/"))
(with-current-buffer d (setq default-directory "~")) (with-current-buffer d (setq default-directory "~"))
(projectile-mode +1)) (projectile-mode +1))
@ -44,7 +40,7 @@
(it "returns buffers in the same project" (it "returns buffers in the same project"
(with-current-buffer a (with-current-buffer a
(expect (doom-project-buffer-list) (expect (doom-project-buffer-list)
:to-have-same-items-as (list a b)))) :to-contain-items (list a b))))
(it "returns all buffers if not in a project" (it "returns all buffers if not in a project"
(with-current-buffer c (with-current-buffer c
@ -53,7 +49,10 @@
(describe "fallback-buffer" (describe "fallback-buffer"
(it "returns a live buffer" (it "returns a live buffer"
(expect (buffer-live-p (doom-fallback-buffer))))) (expect (buffer-live-p (doom-fallback-buffer))))
(it "returns the scratch buffer"
(expect (doom-fallback-buffer) :to-equal (get-buffer "*scratch*"))))
(describe "real buffers" (describe "real buffers"
(before-each (before-each
@ -72,7 +71,7 @@
(describe "real-buffer-list" (describe "real-buffer-list"
(it "returns only real buffers" (it "returns only real buffers"
(expect (doom-real-buffer-list) :to-have-same-items-as (list a b))))) (expect (doom-real-buffer-list) :to-contain-items (list a b)))))
(describe "buffer/window management" (describe "buffer/window management"
(describe "buffer search methods" (describe "buffer search methods"
@ -85,14 +84,17 @@
(it "can match buffers by regexp" (it "can match buffers by regexp"
(expect (doom-matching-buffers "^[ac]$") :to-have-same-items-as (list a c))) (expect (doom-matching-buffers "^[ac]$") :to-have-same-items-as (list a c)))
(it "can match buffers by major-mode" (it "can match buffers by major-mode"
(expect (doom-buffers-in-mode 'text-mode) :to-have-same-items-as (list b c))) (expect (doom-buffers-in-mode 'text-mode) :to-have-same-items-as (list b c)))
(it "can find all buried buffers" (it "can find all buried buffers"
(expect (doom-buried-buffers) (expect (doom-buried-buffers) :to-contain-items (list c d)))
:to-have-same-items-as (list c d)))
(it "can find all visible buffers" (it "can find all visible buffers"
(expect (doom-visible-buffers) (expect (doom-visible-buffers)
:to-have-same-items-as (list a b))) :to-have-same-items-as (list a b)))
(it "can find all visible windows" (it "can find all visible windows"
(expect (doom-visible-windows) (expect (doom-visible-windows)
:to-have-same-items-as :to-have-same-items-as
@ -109,7 +111,7 @@
(expect (length (doom-visible-windows)) :to-be 1))) (expect (length (doom-visible-windows)) :to-be 1)))
;; TODO ;; TODO
(describe "kill-all-buffers") (xdescribe "kill-all-buffers")
(describe "kill-other-buffers") (xdescribe "kill-other-buffers")
(describe "kill-matching-buffers") (xdescribe "kill-matching-buffers")
(describe "cleanup-session"))) (xdescribe "cleanup-session")))

View file

@ -1,54 +1,152 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; core/test/test-autoload-files.el ;;; core/test/test-autoload-files.el
;;;
(require 'core-projects)
(require 'projectile)
(describe "core/autoload/files" (describe "core/autoload/files"
:var (src dest projectile-projects-cache-time projectile-projects-cache)
(before-each
(setq src (make-temp-file "test-src")
existing (make-temp-file "test-existing")
dest (expand-file-name "test-dest" temporary-file-directory))
(quiet! (find-file-literally src))
(spy-on 'y-or-n-p :and-return-value nil)
(projectile-mode +1))
(after-each (load! "autoload/files" doom-core-dir)
(projectile-mode -1)
(switch-to-buffer (doom-fallback-buffer))
(ignore-errors (delete-file src))
(ignore-errors (delete-file existing))
(ignore-errors (delete-file dest)))
(describe "move-this-file" (xdescribe "doom-glob")
(it "won't move to itself" (xdescribe "doom-path")
(expect (quiet! (doom/move-this-file src)) :to-throw)) (xdescribe "doom-dir")
(it "will move to another file" (xdescribe "doom-files-in")
(expect (quiet! (doom/move-this-file dest t)))
(expect (file-exists-p dest))
(expect (file-exists-p src) :to-be nil))
(it "will prompt if overwriting a file"
(quiet! (doom/move-this-file existing))
(expect 'y-or-n-p :to-have-been-called-times 1)
(expect (file-exists-p src))))
(describe "copy-this-file" (describe "library"
(it "refuses to copy to itself" (describe "file-exists-p!"
(expect (quiet! (doom/copy-this-file src)) :to-throw)) (it "is a (quasi) drop-in replacement for `file-exists-p'"
(it "copies to another file" (let ((default-directory doom-emacs-dir)
(expect (quiet! (doom/copy-this-file dest t))) (init-file "init.el"))
(expect (file-exists-p! src dest))) (expect (file-exists-p "init.el"))
(it "prompts if overwriting a file" (expect (and (file-exists-p! "init.el")
(quiet! (doom/copy-this-file existing)) (file-exists-p "init.el")))
(expect 'y-or-n-p :to-have-been-called-times 1))) (expect (and (file-exists-p! init-file)
(file-exists-p init-file)))
(expect (and (file-exists-p! doom-emacs-dir)
(file-exists-p doom-emacs-dir)))
(expect (and (not (file-exists-p! "/cant/possibly/exist/please/dont/exist"))
(not (file-exists-p "/cant/possibly/exist/please/dont/exist"))))))
(describe "delete-this-file" (it "returns the file path if it exists"
(it "fails gracefully on non-existent files" (expect (file-exists-p! "init.example.el"
(expect (quiet! (doom/delete-this-file dest)) :to-throw)) doom-emacs-dir)
(it "deletes existing files" :to-equal (expand-file-name "init.example.el" doom-emacs-dir)))
(quiet! (doom/delete-this-file existing t))
(expect (file-exists-p existing) :to-be nil)) (it "understands compound statements"
(it "prompts to delete any existing file" (let ((default-directory doom-emacs-dir))
(quiet! (doom/delete-this-file existing)) (expect (file-exists-p! (and "init.el" "init.example.el")))
(expect 'y-or-n-p :to-have-been-called-times 1)))) (expect (file-exists-p! (or "doesnotexist" "init.example.el")))
(expect (not (file-exists-p! (or "doesnotexist" "DOESNOTEXIST")))))
(expect (file-exists-p! (and "init.el" "init.example.el")
doom-emacs-dir))
(expect (file-exists-p! (and "init.el" "init.example.el")
doom-emacs-dir))
(expect (file-exists-p! (or "doesnotexist" "init.example.el")
doom-emacs-dir))
(expect (not (file-exists-p! (or "doesnotexist" "DOESNOTEXIST")
doom-emacs-dir))))
(it "understands nested compound statements"
(expect (file-exists-p! (and "init.el" "init.example.el"
(or "doesnotexist" "LICENSE"))
doom-emacs-dir))
(expect (file-exists-p! (and "init.el" "init.example.el"
(and "LICENSE" "README.md"
(or "doesnotexist"
"early-init.el")))
doom-emacs-dir))
(expect (file-exists-p! (and "init.el" "init.example.el"
(or "edoesnotexist" "DOESNOTEXIST"
(and "idontexist"
"doanyofusexist?")))
doom-emacs-dir)
:to-be nil))
(it "returns the last form if a compound file check succeeds"
(expect (file-exists-p! (and "init.el" "init.example.el"
(or "doesnotexist" "LICENSE"))
doom-emacs-dir)
:to-equal (expand-file-name "LICENSE" doom-emacs-dir))
(expect (file-exists-p! (and "init.el" "init.example.el"
(or (or "doesnotexist" "DOESNOTEXIST")
"doanyofusreallyexist"
(or "cantexist" "LICENSE")))
doom-emacs-dir)
:to-equal (expand-file-name "LICENSE" doom-emacs-dir)))
(it "disregards the directory argument if given absolute path"
(expect (file-exists-p! "/tmp" "/directory/that/doesnt/exist"))
(expect (file-exists-p! doom-core-dir "/directory/that/doesnt/exist"))
(expect (file-exists-p! (and "/tmp" doom-core-dir) "/directory/that/doesnt/exist"))
(expect (file-exists-p! (or "/tmp" doom-core-dir) "/directory/that/doesnt/exist")))
(it "interpolates variables"
(let ((file-1 "init.el")
(file-2 "init.example.el")
(file-3 "LICENSE")
(file-404 "doesnotexistlikenoreally"))
(expect (file-exists-p! file-1 doom-emacs-dir))
(expect (file-exists-p! (and file-1 file-2) doom-emacs-dir))
(expect (file-exists-p! (and file-1 (or file-404 file-2)) doom-emacs-dir))
(expect (file-exists-p! (or (and file-404 file-2) (and file-3 file-1))
doom-emacs-dir))))
(it "interpolates forms"
(cl-letf (((symbol-function 'getfilename)
(lambda () "init.example.el")))
(expect (file-exists-p! (and (or (if nil "init.el" "doesnotexist")
(getfilename))
"LICENSE")
doom-emacs-dir)
:to-equal (expand-file-name "LICENSE" doom-emacs-dir))))))
(describe "interactive file operations"
:var (src dest projectile-projects-cache-time projectile-projects-cache)
(require 'core-projects)
(require 'projectile)
(before-each
(setq src (make-temp-file "test-src")
existing (make-temp-file "test-existing")
dest (expand-file-name "test-dest" temporary-file-directory))
(quiet! (find-file-literally src))
(spy-on 'y-or-n-p :and-return-value nil)
(projectile-mode +1))
(after-each
(projectile-mode -1)
(switch-to-buffer (doom-fallback-buffer))
(ignore-errors (delete-file src))
(ignore-errors (delete-file existing))
(ignore-errors (delete-file dest)))
(describe "move-this-file"
(it "won't move to itself"
(expect (quiet! (doom/move-this-file src)) :to-throw))
(it "will move to another file"
(expect (quiet! (doom/move-this-file dest t)))
(expect (file-exists-p dest))
(expect (file-exists-p src) :to-be nil))
(it "will prompt if overwriting a file"
(quiet! (doom/move-this-file existing))
(expect 'y-or-n-p :to-have-been-called-times 1)
(expect (file-exists-p src))))
(describe "copy-this-file"
(it "refuses to copy to itself"
(expect (quiet! (doom/copy-this-file src)) :to-throw))
(it "copies to another file"
(expect (quiet! (doom/copy-this-file dest t)))
(expect (file-exists-p! src dest)))
(it "prompts if overwriting a file"
(quiet! (doom/copy-this-file existing))
(expect 'y-or-n-p :to-have-been-called-times 1)))
(describe "delete-this-file"
(it "fails gracefully on non-existent files"
(expect (quiet! (doom/delete-this-file dest)) :to-throw))
(it "deletes existing files"
(quiet! (doom/delete-this-file existing t))
(expect (file-exists-p existing) :to-be nil))
(it "prompts to delete any existing file"
(quiet! (doom/delete-this-file existing))
(expect 'y-or-n-p :to-have-been-called-times 1)))))

View file

@ -1,11 +1,11 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; core/test/test-autoload-message.el ;;; core/test/test-autoload-message.el
(describe "core/autoload/message" (describe "core/autoload/format"
(describe "format!" (describe "format!"
:var (doom-message-backend) :var (doom-format-backend)
(before-all (before-all
(setq doom-message-backend 'ansi)) (setq doom-format-backend 'ansi))
(it "should be a drop-in replacement for `format'" (it "should be a drop-in replacement for `format'"
(expect (format! "Hello %s" "World") (expect (format! "Hello %s" "World")
@ -16,7 +16,7 @@
:to-equal "Hello World")) :to-equal "Hello World"))
(it "supports text properties in interactive sessions" (it "supports text properties in interactive sessions"
(let ((doom-message-backend 'text-properties)) (let ((doom-format-backend 'text-properties))
(expect (get-text-property 0 'face (format! (red "Hello %s") "World")) (expect (get-text-property 0 'face (format! (red "Hello %s") "World"))
:to-equal (list :foreground (face-foreground 'term-color-red))))) :to-equal (list :foreground (face-foreground 'term-color-red)))))
@ -35,4 +35,10 @@
(expect (format! (color 'red "Hello %s") "World") (expect (format! (color 'red "Hello %s") "World")
:to-equal (format! (red "Hello %s") "World")) :to-equal (format! (red "Hello %s") "World"))
(expect (format! (color (if nil 'red 'blue) "Hello %s") "World") (expect (format! (color (if nil 'red 'blue) "Hello %s") "World")
:to-equal (format! (blue "Hello %s") "World"))))) :to-equal (format! (blue "Hello %s") "World"))))
(xdescribe "insert!")
(xdescribe "print!")
(xdescribe "print-group!")
(xdescribe "error!")
(xdescribe "user-error!"))

View file

@ -1,10 +0,0 @@
;; -*- no-byte-compile: t; -*-
;;; core/test/test-autoload-help.el
;; (load! "autoload/help" doom-core-dir)
;;
;; (describe "core/autoload/help"
;; :var (a)
;; (before-each (setq a (switch-to-buffer (get-buffer-create "a"))))
;; (after-each (kill-buffer a)))

View file

@ -1,138 +1,5 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; core/test/test-autoload-package.el ;;; core/test/test-autoload-package.el
;;;###if nil
(describe "core/autoload/packages" (xdescribe "core/autoload/packages")
:var (package-alist
package-archive-contents
package-selected-packages
doom-packages
quelpa-cache
quelpa-initialized-p
doom-packages-dir
doom-core-packages
package-user-dir
quelpa-dir
pkg)
(before-all
(fset 'pkg
(lambda (name version &optional reqs)
(package-desc-create
:name name :version version :reqs reqs
:dir (expand-file-name (format "%s/" name) package-user-dir))))
(require 'package)
(require 'quelpa)
(setq doom-packages-dir (expand-file-name "packages/" (file-name-directory load-file-name))
package-user-dir (expand-file-name "elpa" doom-packages-dir)
quelpa-dir (expand-file-name "quelpa" doom-packages-dir)
quelpa-initialized-p t
doom-core-packages nil)
(spy-on #'package--user-installed-p :and-call-fake (lambda (_p) t))
(spy-on #'doom-initialize-packages :and-call-fake (lambda (&optional _)))
(spy-on #'package-refresh-contents :and-call-fake (lambda (&optional _)))
(spy-on #'quelpa-checkout :and-call-fake
(lambda (rcp _dir)
(when (eq (car rcp) 'doom-quelpa-dummy)
"20170405.1234"))))
(after-all
(unload-feature 'package t)
(unload-feature 'quelpa t))
(before-each
(setq package-alist
`((doom-dummy ,(pkg 'doom-dummy '(20160405 1234)))
(doom-uptodate-dummy ,(pkg 'doom-uptodate-dummy '(20160605 1234)))
(doom-unwanted-dummy ,(pkg 'doom-unwanted-dummy '(20160605 1234)))
(doom-quelpa-dummy ,(pkg 'doom-quelpa-dummy '(20160405 1234)))
(doom-noquelpa-dummy ,(pkg 'doom-noquelpa-dummy '(20160405 1234))))
package-archive-contents
`((doom-dummy ,(pkg 'doom-dummy '(20170405 1234)))
(doom-uptodate-dummy ,(pkg 'doom-uptodate-dummy '(20160605 1234))))
doom-packages
'((doom-dummy)
(doom-uptodate-dummy)
(doom-missing-dummy)
(doom-noquelpa-dummy)
(doom-disabled-dummy :disable t)
(doom-private-dummy :modules ((:private)))
(doom-disabled-private-dummy :modules ((:private)) :disable t)
(doom-quelpa-dummy :recipe (doom-quelpa-dummy :fetcher github :repo "hlissner/does-not-exist")))
quelpa-cache
'((doom-quelpa-dummy :fetcher github :repo "hlissner/does-not-exist")
(doom-noquelpa-dummy :fetcher github :repo "hlissner/does-not-exist-3")
(doom-new-quelpa-dummy :fetcher github :repo "hlissner/does-not-exist-2"))
package-selected-packages (mapcar #'car doom-packages)))
(describe "package-backend"
(it "determines the correct backend of a package"
(expect (doom-package-backend 'doom-dummy) :to-be 'elpa)
(expect (doom-package-backend 'doom-quelpa-dummy) :to-be 'quelpa)
(expect (doom-package-backend 'org) :to-be 'emacs))
(it "errors out if package isn't installed"
(expect (doom-package-backend 'xyz) :to-throw)))
(describe "package-outdated-p (elpa)"
(it "detects outdated ELPA packages and returns both versions"
(expect (doom-package-outdated-p 'doom-dummy)
:to-equal '(doom-dummy (20160405 1234) (20170405 1234))))
(it "ignores up-to-date ELPA packages"
(expect (doom-package-outdated-p 'doom-uptodate-dummy) :to-be nil))
(it "detects outdated QUELPA packages and returns both versions"
(expect (doom-package-outdated-p 'doom-quelpa-dummy)
:to-equal '(doom-quelpa-dummy (20160405 1234) (20170405 1234))))
(it "ignores up-to-date QUELPA packages"
(expect (doom-package-outdated-p 'doom-uptodate-dummy) :to-be nil))
(it "returns nil if package isn't installed"
(expect (doom-package-outdated-p 'xyz) :to-be nil)))
(describe "get-packages"
(before-all
;; In addition to `package-installed-p', `doom-package-installed-p' does
;; file existence checks which won't work here, so we simplify it
(spy-on #'doom-package-installed-p :and-call-fake #'package-installed-p))
(it "returns all packages"
(expect (mapcar #'car (doom-find-packages))
:to-have-same-items-as
(mapcar #'car doom-packages)))
(it "returns only disabled packages"
(expect (mapcar #'car (doom-find-packages :disabled t))
:to-have-same-items-as
'(doom-disabled-dummy doom-disabled-private-dummy)))
(it "returns only non-disabled packages"
(expect (mapcar #'car (doom-find-packages :disabled nil))
:to-have-same-items-as
'(doom-dummy doom-uptodate-dummy doom-quelpa-dummy doom-missing-dummy doom-noquelpa-dummy doom-private-dummy)))
(it "returns only installed packages"
(expect (mapcar #'car (doom-find-packages :disabled nil :installed t))
:to-have-same-items-as
'(doom-dummy doom-uptodate-dummy doom-quelpa-dummy doom-noquelpa-dummy)))
(it "returns only non-installed packages"
(expect (mapcar #'car (doom-find-packages :disabled nil :installed nil))
:to-have-same-items-as
'(doom-missing-dummy doom-private-dummy)))
(it "returns only private packages"
(expect (mapcar #'car (doom-find-packages :private t))
:to-have-same-items-as
'(doom-private-dummy doom-disabled-private-dummy)))
(it "returns only disabled and private packages"
(expect (mapcar #'car (doom-find-packages :disabled t :private t))
:to-have-same-items-as
'(doom-disabled-private-dummy))))
(describe "get-orphaned-packages"
(it "returns orphaned packages"
(expect (doom-get-orphaned-packages) :to-contain 'doom-unwanted-dummy))
(it "returns packages that have changed backends"
(expect (doom-get-orphaned-packages) :to-contain 'doom-noquelpa-dummy)))
(describe "get-missing-packages"
(it "returns packages that haven't been installed"
(expect (mapcar #'car (doom-get-missing-packages))
:to-contain 'doom-missing-dummy))
(it "returns packages that have changed backends"
(expect (mapcar #'car (doom-get-missing-packages))
:to-contain 'doom-noquelpa-dummy))))

View file

@ -1,40 +1,34 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; core/test/test-core-keybinds.el ;;; core/test/test-core-keybinds.el
(require 'core-keybinds)
(buttercup-define-matcher :to-expand-into (src result)
(let ((src (funcall src))
(result (funcall result)))
(or (equal (macroexpand-1 src) result)
(error "'%s' expanded into '%s' instead of '%s'"
src (macroexpand-1 src) result))))
(describe "core/keybinds" (describe "core/keybinds"
(require 'core-keybinds)
(describe "map!" (describe "map!"
:var (doom--map-evil-p doom-map-states) :var (doom--map-evil-p states-alist)
(before-each (before-each
(setq doom--map-evil-p t (setq doom--map-evil-p t
doom-map-states '((:n . normal) states-alist '((:n . normal)
(:v . visual) (:v . visual)
(:i . insert) (:i . insert)
(:e . emacs) (:e . emacs)
(:o . operator) (:o . operator)
(:m . motion) (:m . motion)
(:r . replace)))) (:r . replace))))
(describe "Single keybinds" (describe "Single keybinds"
(it "binds a global key" (it "binds a global key"
(expect '(map! "C-." #'a) :to-expand-into '(general-define-key "C-." #'a))) (expect '(map! "C-." #'a)
:to-expand-into '(general-define-key "C-." #'a)))
(it "binds a key in one evil state" (it "binds a key in one evil state"
(dolist (state doom-map-states) (dolist (state states-alist)
(expect `(map! ,(car state) "C-." #'a) (expect `(map! ,(car state) "C-." #'a)
:to-expand-into :to-expand-into
`(general-define-key :states ',(cdr state) "C-." #'a)))) `(general-define-key :states ',(cdr state) "C-." #'a))))
(it "binds a key in multiple evil states" (it "binds a key in multiple evil states"
(expect `(map! :nvi "C-." #'a) (expect '(map! :nvi "C-." #'a)
:to-expand-into :to-expand-into
'(progn (general-define-key :states 'insert "C-." #'a) '(progn (general-define-key :states 'insert "C-." #'a)
(general-define-key :states 'visual "C-." #'a) (general-define-key :states 'visual "C-." #'a)
@ -54,7 +48,7 @@
'(general-define-key "C-." #'a "C-," #'b "C-/" #'c))) '(general-define-key "C-." #'a "C-," #'b "C-/" #'c)))
(it "binds multiple keybinds in an evil state and preserve order" (it "binds multiple keybinds in an evil state and preserve order"
(dolist (state doom-map-states) (dolist (state states-alist)
(expect `(map! ,(car state) "a" #'a (expect `(map! ,(car state) "a" #'a
,(car state) "b" #'b ,(car state) "b" #'b
,(car state) "c" #'c) ,(car state) "c" #'c)

View file

@ -1,28 +1,130 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; core/test/test-core-lib.el ;;; core/test/test-core-lib.el
(require 'core-lib) (describe "core-lib"
(before-all
(require 'core-lib))
(describe "core/lib"
;; --- Helpers ---------------------------- ;; --- Helpers ----------------------------
(describe "doom-unquote" (describe "doom-unquote"
(it "unquotes a quoted form" (it "unquotes a quoted form"
(expect (doom-unquote '(quote hello)) :to-be 'hello)) (expect (doom-unquote '(quote hello)) :to-be 'hello))
(it "unquotes nested-quoted forms" (it "unquotes nested quoted forms"
(expect (doom-unquote '(quote (quote (a b c)))) :to-equal '(a b c))) (expect (doom-unquote '(quote (quote (a b c)))) :to-equal '(a b c)))
(it "unquotes function-quoted forms" (it "unquotes function-quoted forms"
(expect (doom-unquote '(function a)) :to-be 'a)) (expect (doom-unquote '(function a)) :to-be 'a))
(it "does nothing to unquoted forms" (it "does nothing to unquoted forms"
(expect (doom-unquote 'hello) :to-be 'hello))) (expect (doom-unquote 'hello) :to-be 'hello)
(expect (doom-unquote 5) :to-be 5)
(expect (doom-unquote t) :to-be t)))
(describe "doom-enlist" (describe "doom-enlist"
(it "returns nil if given nil"
(expect (doom-enlist nil) :to-be nil))
(it "creates a list out of non-lists" (it "creates a list out of non-lists"
(expect (doom-enlist 'a) :to-equal '(a))) (expect (doom-enlist 'a) :to-equal '(a)))
(it "does nothing to lists" (it "returns lists as-is"
(expect (doom-enlist '(a)) :to-equal '(a)))) (expect (doom-enlist '(a)) :to-equal '(a))))
(describe "doom-keyword-intern"
(it "returns a keyword"
(expect (doom-keyword-intern "test") :to-equal :test))
(it "errors if given anything but a string"
(expect (doom-keyword-intern t) :to-throw 'wrong-type-argument)))
(describe "doom-keyword-name"
(it "returns the string name of a keyword"
(expect (doom-keyword-name :test) :to-equal "test"))
(it "errors if given anything but a keyword"
(expect (doom-keyword-name "test") :to-throw 'wrong-type-argument)))
(describe "doom-partial"
(it "returns a closure"
(expect (functionp (doom-partial #'+ 1))))
(it "returns a partial closure"
(expect (funcall (doom-partial #'+ 1) 2) :to-be 3)))
(describe "doom-rpartial"
(it "returns a closure"
(expect (functionp (doom-rpartial #'+ 1))))
(it "returns a partial closure with right-aligned arguments"
(expect (funcall (doom-rpartial #'/ 2) 10) :to-be 5)))
;; --- Sugars -----------------------------
(describe "lambda!"
(it "returns an interactive function"
(expect (commandp (lambda!)))
(expect (funcall (lambda! 5)) :to-equal 5)))
(describe "lambda!!"
(it "returns an interactive function with a prefix argument"
(expect (commandp (lambda! #'ignore t)))
(expect (funcall (lambda!! (lambda (arg)
(interactive "P")
arg)
5))
:to-equal 5)))
(describe "file!"
(it "returns the executing file"
(expect (eval-and-compile (file!))
:to-equal (expand-file-name "test/test-core-lib.el"
doom-core-dir))))
(describe "dir!"
(it "returns the executing directory"
(expect (eval-and-compile (dir!))
:to-equal (expand-file-name "test" doom-core-dir))))
(describe "pushnew!"
(it "pushes values onto a list symbol, in order"
(let ((a '(1 2 3)))
(expect (pushnew! a 9 8 7)
:to-equal '(7 8 9 1 2 3))))
(it "only adds values that aren't already in the list"
(let ((a '(1 symbol 3.14 "test")))
(expect (pushnew! a "test" 'symbol 3.14 1)
:to-equal '(1 symbol 3.14 "test")))))
(describe "prependq!"
(it "prepends a list to a list symbol"
(let ((list '(a b c)))
(expect (prependq! list '(d e f))
:to-equal '(d e f a b c)))))
(describe "append!"
(it "appends a list to a list symbol"
(let ((list '(a b c)))
(expect (appendq! list '(d e f))
:to-equal '(a b c d e f)))))
(describe "nconcq!"
(it "nconc's a list to a list symbol"
(let ((list '(a b c)))
(expect (nconcq! list '(d e f))
:to-equal '(a b c d e f)))))
(describe "delq!"
(it "delete's a symbol from a list"
(let ((list '(a b c)))
(delq! 'b list)
(expect list :to-equal '(a c))))
(it "delete's an element from an alist by key"
(let ((alist '((a 1) (b 2) (c 3))))
(delq! 'b alist 'assq)
(expect alist :to-equal '((a 1) (c 3))))))
(describe "delete!"
(it "delete's a string from a list"
(let ((list '("a" "b" "c")))
(delete! "b" list)
(expect list :to-equal '("a" "c"))))
(it "delete's an element from an alist by key"
(let ((alist '(("a" 1) ("b" 2) ("c" 3))))
(delete! (assoc "b" alist) alist)
(expect alist :to-equal '(("a" 1) ("c" 3))))))
;; --- Macros -----------------------------
(describe "hooks" (describe "hooks"
(describe "add-hook!" (describe "add-hook!"
:var (fake-mode-hook other-mode-hook some-mode-hook) :var (fake-mode-hook other-mode-hook some-mode-hook)
@ -31,15 +133,22 @@
other-mode-hook nil other-mode-hook nil
some-mode-hook '(first-hook second-hook))) some-mode-hook '(first-hook second-hook)))
(it "resolves quoted hooks literally"
(expect '(add-hook! 'fake-mode-hook #'ignore) :to-expand-into
`(add-hook 'fake-mode-hook #'ignore nil nil)))
(it "resolves unquoted modes to their hook variables"
(expect '(add-hook! fake-mode #'ignore) :to-expand-into
`(add-hook 'fake-mode-hook #'ignore nil nil)))
(it "adds one-to-one hook" (it "adds one-to-one hook"
(add-hook! fake-mode #'hook-2) (add-hook! fake-mode #'hook-2)
(add-hook! 'fake-mode-hook #'hook-1) (add-hook! 'fake-mode-hook #'hook-1)
(expect fake-mode-hook :to-equal '(hook-1 hook-2 first-hook))) (expect fake-mode-hook :to-equal '(hook-1 hook-2 first-hook)))
(it "adds many-to-one hook" (it "adds one-to-many hook"
(add-hook! (fake-mode other-mode some-mode) #'hook-2) (add-hook! (fake-mode other-mode some-mode) #'hook-2)
(add-hook! '(fake-mode-hook other-mode-hook some-mode-hook) #'hook-1) (add-hook! '(fake-mode-hook other-mode-hook some-mode-hook) #'hook-1)
(add-hook! :append (fake-mode other-mode some-mode) #'last-hook) (add-hook! (fake-mode other-mode some-mode) :append #'last-hook)
(expect fake-mode-hook :to-equal '(hook-1 hook-2 first-hook last-hook)) (expect fake-mode-hook :to-equal '(hook-1 hook-2 first-hook last-hook))
(expect other-mode-hook :to-equal '(hook-1 hook-2 last-hook)) (expect other-mode-hook :to-equal '(hook-1 hook-2 last-hook))
(expect some-mode-hook :to-equal '(hook-1 hook-2 first-hook second-hook last-hook))) (expect some-mode-hook :to-equal '(hook-1 hook-2 first-hook second-hook last-hook)))
@ -47,7 +156,7 @@
(it "adds many-to-many hooks and preserve provided order" (it "adds many-to-many hooks and preserve provided order"
(add-hook! (fake-mode other-mode some-mode) #'(hook-3 hook-4)) (add-hook! (fake-mode other-mode some-mode) #'(hook-3 hook-4))
(add-hook! '(fake-mode-hook other-mode-hook some-mode-hook) #'(hook-1 hook-2)) (add-hook! '(fake-mode-hook other-mode-hook some-mode-hook) #'(hook-1 hook-2))
(add-hook! :append '(fake-mode-hook other-mode-hook some-mode-hook) #'(last-hook-1 last-hook-2)) (add-hook! '(fake-mode-hook other-mode-hook some-mode-hook) :append #'(last-hook-1 last-hook-2))
(expect fake-mode-hook :to-equal '(hook-1 hook-2 hook-3 hook-4 first-hook last-hook-1 last-hook-2)) (expect fake-mode-hook :to-equal '(hook-1 hook-2 hook-3 hook-4 first-hook last-hook-1 last-hook-2))
(expect other-mode-hook :to-equal '(hook-1 hook-2 hook-3 hook-4 last-hook-1 last-hook-2)) (expect other-mode-hook :to-equal '(hook-1 hook-2 hook-3 hook-4 last-hook-1 last-hook-2))
(expect some-mode-hook :to-equal '(hook-1 hook-2 hook-3 hook-4 first-hook second-hook last-hook-1 last-hook-2))) (expect some-mode-hook :to-equal '(hook-1 hook-2 hook-3 hook-4 first-hook second-hook last-hook-1 last-hook-2)))
@ -55,10 +164,18 @@
(it "adds implicit lambda to one hook" (it "adds implicit lambda to one hook"
(add-hook! fake-mode (progn)) (add-hook! fake-mode (progn))
(add-hook! 'other-mode-hook (ignore)) (add-hook! 'other-mode-hook (ignore))
(add-hook! :append 'some-mode-hook (ignore)) (add-hook! 'some-mode-hook :append (ignore))
(expect (caar fake-mode-hook) :to-be 'lambda) (expect (caar fake-mode-hook) :to-be 'lambda)
(expect (caar other-mode-hook) :to-be 'lambda) (expect (caar other-mode-hook) :to-be 'lambda)
(expect (caar (last other-mode-hook)) :to-be 'lambda))) (expect (caar (last other-mode-hook)) :to-be 'lambda))
(it "handles inline defuns as hook symbols"
(add-hook! fake-mode (defun hook-a ()))
(add-hook! 'other-mode-hook
(defun hook-b ())
(defun hook-c ()))
(expect (car fake-mode-hook) :to-be 'hook-a)
(expect other-mode-hook :to-equal '(hook-b hook-c))))
(describe "remove-hook!" (describe "remove-hook!"
:var (fake-mode-hook) :var (fake-mode-hook)
@ -71,22 +188,92 @@
(it "removes multiple hooks" (it "removes multiple hooks"
(remove-hook! fake-mode #'(first-hook third-hook)) (remove-hook! fake-mode #'(first-hook third-hook))
(remove-hook! 'fake-mode-hook #'(second-hook fourth-hook)) (remove-hook! 'fake-mode-hook #'(second-hook fourth-hook))
(expect fake-mode-hook :to-be nil)))) (expect fake-mode-hook :to-be nil)))
(describe "add-transient-hook!" (describe "add-transient-hook!"
(it "adds a transient function to hooks" (it "adds a transient function to hooks"
(let (hooks value) (let (hooks value)
(add-transient-hook! 'hooks (setq value t)) (add-transient-hook! 'hooks (setq value t))
(run-hooks 'hooks) (run-hooks 'hooks)
(expect value) (expect value)
(expect hooks :to-be nil))) (expect hooks :to-be nil)))
(it "advises a function with a transient advisor" (it "advises a function with a transient advisor"
(let (value) (let (value)
(add-transient-hook! #'ignore (setq value (not value))) (add-transient-hook! #'ignore (setq value (not value)))
(ignore t) (ignore t)
(expect value) (expect value)
;; repeat to ensure it was only run once ;; repeat to ensure it was only run once
(ignore t) (ignore t)
(expect value)))) (expect value))))
(xdescribe "associate!")) ; TODO (describe "(un)setq-hook!"
:var (fake-hook x y z)
(before-each
(setq x 10 y 20 z 30))
(it "sets variables buffer-locally"
(setq-hook! 'fake-hook x 1)
(with-temp-buffer
(run-hooks 'fake-hook)
(expect (local-variable-p 'x))
(expect (= x 1)))
(expect (= x 10)))
(it "overwrites earlier hooks"
(setq-hook! 'fake-hook x 1 y 0)
(setq-hook! 'fake-hook x 5 y -1)
(with-temp-buffer
(run-hooks 'fake-hook)
(expect (= x 5))
(expect (= y -1))))
(it "unset setq hooks"
(setq-hook! 'fake-hook x 1 y 0)
(unsetq-hook! 'fake-hook y)
(with-temp-buffer
(run-hooks 'fake-hook)
(expect (local-variable-p 'x))
(expect (= x 1))
(expect (not (local-variable-p 'y)))
(expect (= y 20))))))
(describe "load!"
(before-each
(spy-on 'load :and-return-value t))
(it "loads a file relative to the current directory"
(load! "path")
(expect 'load :to-have-been-called)
(expect 'load :to-have-been-called-with (expand-file-name "path" (eval-when-compile (dir!))) nil t))
(it "loads a file relative to a specified directory"
(load! "path" doom-etc-dir)
(expect 'load :to-have-been-called-with (expand-file-name "path" doom-etc-dir) nil t)))
(describe "quiet!"
(it "suppresses output from message"
(expect (message "hello world") :to-output "hello world\n")
(expect (message "hello world") :to-output)
(let (doom-interactive-mode)
(expect (quiet! (message "hello world")) :not :to-output))
(let ((doom-interactive-mode t))
(expect (quiet! inhibit-message))
(expect (quiet! save-silently))))
(it "suppresses load messages from `load' & `load-file'"
(let ((tmpfile (make-temp-file "test" nil ".el")))
(with-temp-file tmpfile)
(let (doom-interactive-mode)
(expect (load-file tmpfile) :to-output (format "Loading %s (source)...\n" tmpfile))
(expect (quiet! (load-file tmpfile)) :not :to-output))
(delete-file tmpfile)))
(it "won't suppress output in debug mode"
(let ((doom-debug-mode t)
(tmpfile (make-temp-file "test" nil ".el")))
(dolist (doom-interactive-mode (list t nil))
(expect (quiet! (message "hello world"))
:to-output "hello world\n")
(with-temp-file tmpfile)
(expect (quiet! (load-file tmpfile))
:to-output (format "Loading %s (source)...\n" tmpfile)))))))

View file

@ -1,6 +1,7 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; core/test/test-core-modules.el ;;; core/test/test-core-modules.el
;;;###if nil
;; (require 'core-modules) ;; (require 'core-modules)
(describe "core-modules") (xdescribe "core-modules")

View file

@ -1,4 +1,5 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; core/test/test-core-packages.el ;;; core/test/test-core-packages.el
;;;###if nil
(describe "core-packages") (xdescribe "core-packages")

View file

@ -1,12 +1,17 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; ../core/test/test-core-projects.el ;;; core/test/test-core-projects.el
(require 'core-projects)
(require 'projectile)
(describe "core/projects" (describe "core/projects"
(before-each (projectile-mode +1)) :var (projectile-enable-caching)
(after-each (projectile-mode -1))
(require 'core-projects)
(require 'projectile)
(before-each
(setq projectile-enable-caching nil)
(projectile-mode +1))
(after-each
(projectile-mode -1))
(describe "project-p" (describe "project-p"
(it "Should detect when in a valid project" (it "Should detect when in a valid project"

View file

@ -1,17 +1,106 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; -*-
;;; ../core/test/test-core-ui.el ;;; ../core/test/test-core-ui.el
(require 'core-ui)
(describe "core/ui" (describe "core/ui"
(describe "doom|protect-fallback-buffer" (before-all
:var (kill-buffer-query-functions a b) (with-demoted-errors "Import error: %s"
(require 'core-ui)))
(describe "doom-protect-fallback-buffer-h"
:var (kill-buffer-query-functions)
(before-all (before-all
(setq kill-buffer-query-functions '(doom|protect-fallback-buffer))) (setq kill-buffer-query-functions '(doom-protect-fallback-buffer-h)))
(it "should kill other buffers" (it "should kill other buffers"
(expect (kill-buffer (get-buffer-create "a")))) (expect (kill-buffer (get-buffer-create "a"))))
(it "shouldn't kill the fallback buffer" (it "shouldn't kill the fallback buffer"
(expect (not (kill-buffer (doom-fallback-buffer))))))) (expect (not (kill-buffer (doom-fallback-buffer))))))
(describe "custom hooks"
(describe "switch hooks"
:var (before-hook after-hook a b)
(before-each
(setq a (switch-to-buffer (get-buffer-create "a"))
b (get-buffer-create "b"))
(spy-on 'hook)
(add-hook 'buffer-list-update-hook #'doom-run-switch-window-hooks-h)
(add-hook 'focus-in-hook #'doom-run-switch-frame-hooks-h)
(dolist (fn '(switch-to-buffer display-buffer))
(advice-add fn :around #'doom-run-switch-buffer-hooks-a)))
(after-each
(remove-hook 'buffer-list-update-hook #'doom-run-switch-window-hooks-h)
(remove-hook 'focus-in-hook #'doom-run-switch-frame-hooks-h)
(dolist (fn '(switch-to-buffer display-buffer))
(advice-remove fn #'doom-run-switch-buffer-hooks-a))
(kill-buffer a)
(kill-buffer b))
(describe "switch-buffer"
:var (doom-switch-buffer-hook)
(before-each
(setq doom-switch-buffer-hook '(hook)))
(after-each
(setq doom-switch-buffer-hook nil))
(it "should trigger when switching buffers"
(switch-to-buffer b)
(switch-to-buffer a)
(switch-to-buffer b)
(expect 'hook :to-have-been-called-times 3))
(it "should trigger only once on the same buffer"
(switch-to-buffer b)
(switch-to-buffer b)
(switch-to-buffer a)
(expect 'hook :to-have-been-called-times 2)))
(describe "switch-window"
:var (doom-switch-window-hook x y)
(before-each
(delete-other-windows)
(setq x (get-buffer-window a)
y (save-selected-window (split-window)))
(with-selected-window y
(switch-to-buffer b))
(select-window x)
(spy-calls-reset 'hook)
(setq doom-switch-window-hook '(hook)))
(it "should trigger when switching windows"
(select-window y)
(select-window x)
(select-window y)
(expect 'hook :to-have-been-called-times 3))
(it "should trigger only once on the same window"
(select-window y)
(select-window y)
(select-window x)
(expect 'hook :to-have-been-called-times 2)))
(xdescribe "switch-frame"
:var (doom-switch-frame-hook x y)
(before-each
(delete-other-windows)
(setq x (get-buffer-window a)
y (save-selected-window (split-window)))
(with-selected-window y
(switch-to-buffer b))
(select-window x)
(spy-calls-reset 'hook)
(setq doom-switch-window-hook '(hook)))
(it "should trigger when switching windows"
(select-window y)
(select-window x)
(select-window y)
(expect 'hook :to-have-been-called-times 3))
(it "should trigger only once on the same window"
(select-window y)
(select-window y)
(select-window x)
(expect 'hook :to-have-been-called-times 2))))))

View file

@ -2,118 +2,116 @@
;;; core/test/test-core.el ;;; core/test/test-core.el
(describe "core" (describe "core"
(xdescribe "initialize" :var (doom-interactive-mode)
:var (doom-init-p doom-init-modules-p doom-private-dir) (before-each
(before-each (setq doom-interactive-mode nil))
(setq doom-init-p nil
doom-init-modules-p nil
doom-private-dir doom-emacs-dir)
(spy-on 'require) (describe "initialization"
(spy-on 'load) (describe "doom-initialize"
(spy-on 'doom-reload-doom-autoloads) :var (doom-init-p)
(spy-on 'doom-reload-package-autoloads)
(spy-on 'doom-initialize-autoloads)
(spy-on 'doom-ensure-core-directories)
(spy-on 'doom-ensure-core-packages)
(spy-on 'doom-ensure-packages-initialized)
(spy-on 'doom-ensure-same-emacs-version-p))
(describe "in interactive session"
:var (noninteractive)
(before-each (setq noninteractive t))
(it "initializes once, unless forced")
(it "does not initialize on consecutive invokations")
(it "loads all core libraries" )
(it "loads autoloads file" )
(it "does not load autoloads file if forced" )
(it "regenerates missing autoloads" ))
(describe "in non-interactive session"
:var (noninteractive)
(before-each (setq noninteractive nil))
(it "initializes once, unless forced")
(it "does not initialize on consecutive invokations")
(it "does not load all core libraries" )
(it "loads autoloads file" )
(it "does not load autoloads file if forced" )
(it "does not regenerate missing autoloads" )))
(xdescribe "initialize-packages"
(before-each (spy-on 'quelpa-setup-p))
(it "initializes package.el once, unless forced" )
(it "initializes quelpa once, unless forced" )
(it "initializes doom-packages once, unless forced" ))
(xdescribe "initialize-modules"
(it "loads private init.el once, unless forced" ))
(xdescribe "initialize-autoloads"
(it "loads autoloads file" )
(it "ignores autoloads file if cleared" ))
(describe "custom hooks"
(describe "switch hooks"
:var (before-hook after-hook a b)
(before-each (before-each
(setq a (switch-to-buffer (get-buffer-create "a")) (setq doom-init-p nil))
b (get-buffer-create "b"))
(spy-on 'hook)
(add-hook 'buffer-list-update-hook #'doom-run-switch-window-hooks-h)
(add-hook 'focus-in-hook #'doom-run-switch-frame-hooks-h)
(dolist (fn '(switch-to-buffer display-buffer))
(advice-add fn :around #'doom-run-switch-buffer-hooks-a)))
(after-each
(remove-hook 'buffer-list-update-hook #'doom-run-switch-window-hooks-h)
(remove-hook 'focus-in-hook #'doom-run-switch-frame-hooks-h)
(dolist (fn '(switch-to-buffer display-buffer))
(advice-remove fn #'doom-run-switch-buffer-hooks-a))
(kill-buffer a)
(kill-buffer b))
(describe "switch-buffer" (it "initializes once"
:var (doom-switch-buffer-hook) (expect (doom-initialize))
(expect (not (doom-initialize)))
(expect (not (doom-initialize)))
(expect doom-init-p))
(it "initializes multiple times, if forced"
(expect (doom-initialize))
(expect (not (doom-initialize)))
(expect (doom-initialize 'force)))
(describe "package initialization"
(before-each (before-each
(setq doom-switch-buffer-hook '(hook))) (spy-on 'doom-initialize-packages :and-return-value t))
(after-each
(setq doom-switch-buffer-hook nil))
(it "should trigger when switching buffers" (it "initializes packages if core autoload file doesn't exist"
(switch-to-buffer b) (let ((doom-autoload-file "doesnotexist"))
(switch-to-buffer a) (doom-initialize))
(switch-to-buffer b) (expect 'doom-initialize-packages :to-have-been-called))
(expect 'hook :to-have-been-called-times 3))
(it "should trigger only once on the same buffer" (it "doesn't initialize packages if core autoload file was loaded"
(switch-to-buffer b) (let ((doom-interactive-mode t))
(switch-to-buffer b) (spy-on 'doom-load-autoloads-file :and-return-value t)
(switch-to-buffer a) (doom-initialize)
(expect 'hook :to-have-been-called-times 2))) (expect 'doom-load-autoloads-file :to-have-been-called-with doom-package-autoload-file)
(expect 'doom-initialize-packages :to-have-been-called)))
(it "initializes packages when forced"
(doom-initialize 'force)
(expect 'doom-initialize-packages :to-have-been-called)))
(describe "switch-window" (describe "autoloads files"
:var (doom-switch-window-hook x y)
(before-each (before-each
(delete-other-windows) (spy-on 'doom-load-autoloads-file)
(setq x (get-buffer-window a) (spy-on 'warn :and-return-value t))
y (save-selected-window (split-window)))
(with-selected-window y
(switch-to-buffer b))
(select-window x)
(spy-calls-reset 'hook)
(setq doom-switch-window-hook '(hook)))
(it "should trigger when switching windows" (it "loads autoloads file"
(select-window y) (let ((doom-interactive-mode t))
(select-window x) (ignore-errors (doom-initialize)))
(select-window y) (expect 'doom-load-autoloads-file
(expect 'hook :to-have-been-called-times 3)) :to-have-been-called-with doom-autoload-file)
(expect 'doom-load-autoloads-file
:to-have-been-called-with doom-package-autoload-file))
(it "should trigger only once on the same window" (it "does not load package autoloads file if noninteractive"
(select-window y) (doom-initialize)
(select-window y) (expect 'doom-load-autoloads-file
(select-window x) :to-have-been-called-with doom-autoload-file)
(expect 'hook :to-have-been-called-times 2)))))) (expect 'doom-load-autoloads-file
:not :to-have-been-called-with doom-package-autoload-file))
(it "throws doom-autoload-error in interactive session where autoload files don't exist"
(let ((doom-interactive-mode t)
(doom-autoload-file "doesnotexist")
(doom-package-autoload-file "doesnotexist"))
(expect (doom-initialize) :to-throw 'doom-autoload-error)))))
(describe "doom-initialize-core"
(before-each
(spy-on 'require))
(it "loads all doom core libraries"
(doom-initialize-core)
(expect 'require :to-have-been-called-with 'core-keybinds)
(expect 'require :to-have-been-called-with 'core-ui)
(expect 'require :to-have-been-called-with 'core-projects)
(expect 'require :to-have-been-called-with 'core-editor))))
(describe "doom-load-autoloads-file"
(before-each
(spy-on 'load :and-return-value t))
(it "loads the autoloads file"
(doom-load-autoloads-file doom-autoload-file)
(expect 'load :to-have-been-called-with (file-name-sans-extension doom-autoload-file)
'noerror 'nomessage)))
(describe "doom-load-envvars-file"
:var (envvarfile process-environment)
(before-each
(setq process-environment (copy-sequence process-environment))
(with-temp-file doom-env-file
(insert "\n\n\nA=1\nB=2\nC=3\n")))
(after-each
(delete-file doom-env-file))
(it "throws a file-error if file doesn't exist"
(expect (doom-load-envvars-file "/tmp/envvardoesnotexist")
:to-throw 'file-error))
(it "to fail silently if NOERROR is non-nil"
(expect (doom-load-envvars-file "/tmp/envvardoesnotexist" 'noerror)
:not :to-throw))
(it "loads a well-formed envvar file"
(expect (getenv "A") :not :to-be-truthy)
(expect (doom-load-envvars-file doom-env-file)
:to-equal '(("A" . "1") ("B" . "2") ("C" . "3")))
(expect (getenv "A") :to-equal "1"))
(it "fails on an invalid envvar file"
(with-temp-file doom-env-file (insert "A=1\nB=2\nC=3\n"))
(expect (doom-load-envvars-file doom-env-file) :to-throw))))

View file

@ -1,9 +1,40 @@
#+TITLE: API Demos #+TITLE: API Demos
#+PROPERTY: header-args:elisp :results pp
This appendix serves as a reference on how to use Doom Emacs' standard library. This appendix serves as a reference on how to use Doom Emacs' standard library.
It is integrated into Helpful, in Doom. It is integrated into Helpful, in Doom.
* add-hook! * Table of Contents :TOC_3:
- [[#examples-for-dooms-core-library][Examples for Doom's core library]]
- [[#core-lib][core-lib]]
- [[#add-hook][add-hook!]]
- [[#add-transient-hook][add-transient-hook!]]
- [[#after][after!]]
- [[#custom-set-faces][custom-set-faces!]]
- [[#custom-theme-set-faces][custom-theme-set-faces!]]
- [[#defer-feature][defer-feature!]]
- [[#defer-until][defer-until!]]
- [[#disable-packages][disable-packages!]]
- [[#doom][doom!]]
- [[#file-exists-p][file-exists-p!]]
- [[#lambda][lambda!]]
- [[#lambda-1][lambda!!]]
- [[#load][load!]]
- [[#map][map!]]
- [[#package][package!]]
- [[#pushnew][pushnew!]]
- [[#quiet][quiet!]]
- [[#remove-hook][remove-hook!]]
- [[#setq-hook][setq-hook!]]
- [[#unsetq-hook][unsetq-hook!]]
- [[#use-package][use-package!]]
- [[#interesting-snippets][Interesting snippets]]
- [[#persist-emacs-initial-frame-size-across-sessions][Persist Emacs' initial frame size across sessions]]
- [[#persist-emacs-initial-frame-position-dimensions-andor-full-screen-state-across-sessions][Persist Emacs' initial frame position, dimensions and/or full-screen state across sessions]]
* Examples for Doom's core library
** core-lib
*** add-hook!
#+BEGIN_SRC elisp :eval no #+BEGIN_SRC elisp :eval no
;; With only one hook and one function, this is identical to `add-hook'. In that ;; With only one hook and one function, this is identical to `add-hook'. In that
;; case, use that instead. ;; case, use that instead.
@ -31,33 +62,35 @@ It is integrated into Helpful, in Doom.
...)) ...))
#+END_SRC #+END_SRC
* custom-theme-set-faces! *** TODO add-transient-hook!
*** after!
#+BEGIN_SRC elisp :eval no #+BEGIN_SRC elisp :eval no
(custom-theme-set-faces! 'doom-one-theme ;;; `after!' will take:
'(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) ;; An unquoted package symbol (the name of a package)
'((outline-1 outline-2 outline-3 outline-4 outline-5 outline-6) (after! helm ...)
:weight normal)
'((default region)
:background "red" :weight bold))
(let ((red-bg-faces '(default region))) ;; An unquoted list of package symbols (i.e. BODY is evaluated once both magit
(custom-theme-set-faces! '(doom-one-theme doom-one-light-theme) ;; and git-gutter have loaded)
`(,(cl-loop for i from 0 to 6 collect (intern (format "outline-%d" i))) (after! (magit git-gutter) ...)
:weight normal)
`(,red-bg-faces ;; An unquoted, nested list of compound package lists, using any combination of
:background "red" :weight bold))) ;; :or/:any and :and/:all
(after! (:or package-a package-b ...) ...)
(after! (:and package-a package-b ...) ...)
(after! (:and package-a (:or package-b package-c) ...) ...)
;; (Without :or/:any/:and/:all, :and/:all are implied.)
;; A common mistake is to pass it the names of major or minor modes, e.g.
(after! rustic-mode ...)
(after! python-mode ...)
;; But the code in them will never run! rustic-mode is in the `rustic' package
;; and python-mode is in the `python' package. This is what you want:
(after! rustic ...)
(after! python ...)
#+END_SRC #+END_SRC
* custom-set-faces! *** custom-set-faces!
#+BEGIN_SRC elisp :eval no #+BEGIN_SRC elisp :eval no
(custom-set-faces! (custom-set-faces!
'(outline-1 :weight normal) '(outline-1 :weight normal)
@ -81,9 +114,59 @@ It is integrated into Helpful, in Doom.
:weight normal) :weight normal)
`(,red-bg-faces `(,red-bg-faces
:background "red" :weight bold))) :background "red" :weight bold)))
;; If you want to make use of the `doom-themes' package API (e.g. `doom-color',
;; `doom-lighten', `doom-darken', etc.), you must use `custom-set-faces!'
;; *after* the theme has been loaded. e.g.
(load-theme 'doom-one t)
(custom-set-faces!
`(outline-1 :foreground ,(doom-color 'red))
`(outline-2 :background ,(doom-color 'blue)))
#+END_SRC #+END_SRC
* doom! *** 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)))
;; If you want to make use of the `doom-themes' package API (e.g. `doom-color',
;; `doom-lighten', `doom-darken', etc.), you must use `custom-set-faces!'
;; *after* the theme has been loaded. e.g.
(load-theme 'doom-one t)
(custom-theme-set-faces! 'doom-one
`(outline-1 :foreground ,(doom-color 'red))
`(outline-2 :background ,(doom-color 'blue)))
#+END_SRC
*** TODO defer-feature!
*** TODO defer-until!
*** disable-packages!
#+BEGIN_SRC elisp :eval no
;; Disable packages enabled by DOOM
(disable-packages! some-package second-package)
#+END_SRC
*** doom!
#+BEGIN_SRC elisp :eval no #+BEGIN_SRC elisp :eval no
(doom! :completion (doom! :completion
company company
@ -113,7 +196,7 @@ It is integrated into Helpful, in Doom.
(default +bindings +smartparens)) (default +bindings +smartparens))
#+END_SRC #+END_SRC
* file-exists-p! *** file-exists-p!
#+BEGIN_SRC elisp #+BEGIN_SRC elisp
(file-exists-p! "init.el" doom-emacs-dir) (file-exists-p! "init.el" doom-emacs-dir)
#+END_SRC #+END_SRC
@ -130,7 +213,86 @@ It is integrated into Helpful, in Doom.
#+RESULTS: #+RESULTS:
: /home/hlissner/.emacs.d/LICENSE : /home/hlissner/.emacs.d/LICENSE
* remove-hook! *** TODO lambda!
*** TODO lambda!!
*** load!
#+BEGIN_SRC elisp :eval no
;;; Lets say we're in ~/.doom.d/config.el
(load! "lisp/module") ; loads ~/.doom.d/lisp/module.el
(load! "somefile" doom-emacs-dir) ; loads ~/.emacs.d/somefile.el
(load! "anotherfile" doom-private-dir) ; loads ~/.doom.d/anotherfile.el
;; If you don't want a `load!' call to throw an error if the file doesn't exist:
(load! "~/.maynotexist" nil t)
#+END_SRC
*** map!
#+BEGIN_SRC elisp :eval no
(map! :map magit-mode-map
:m "C-r" 'do-something ; C-r in motion state
:nv "q" 'magit-mode-quit-window ; q in normal+visual states
"C-x C-r" 'a-global-keybind
:g "C-x C-r" 'another-global-keybind ; same as above
(:when IS-MAC
:n "M-s" 'some-fn
:i "M-o" (lambda (interactive) (message "Hi"))))
(map! (:when (featurep! :completion company) ; Conditional loading
:i "C-@" #'+company/complete
(:prefix "C-x" ; Use a prefix key
:i "C-l" #'+company/whole-lines)))
(map! (:when (featurep! :lang latex) ; local conditional
(:map LaTeX-mode-map
:localleader ; Use local leader
:desc "View" "v" #'TeX-view)) ; Add which-key description
:leader ; Use leader key from now on
:desc "Eval expression" ";" #'eval-expression)
#+END_SRC
*** package!
#+BEGIN_SRC elisp :eval no
;; To install a package that can be found on ELPA or any of the sources
;; specified in `doom-core-package-sources':
(package! evil)
(package! js2-mode)
(package! rainbow-delimiters)
;; To disable a package included with Doom (which will no-op all its `after!'
;; and `use-package!' blocks):
(package! evil :disable t)
(package! rainbow-delimiters :disable t)
;; To install a package from a github repo
(package! so-long :recipe (:host github :repo "hlissner/emacs-so-long"))
;; If a package is particularly big and comes with submodules you don't need,
;; you can tell the package manager not to clone the repo recursively:
(package! ansible :recipe (:nonrecursive t))
;; To install a particular branch, commit or tag:
(package! evil
;; if :host and :fetcher aren't specified, the package manager will fall back
;; to evil's default source provided by their (M)ELPA recipes:
:recipe (:commit "e7bc39de2f961505e8e112da8c1b315ae8afce52"))
(package! evil :recipe (:branch "stable"))
(package! evil :recipe (:tag "1.2.9"))
;; If you share your config between two computers, and don't want bin/doom
;; refresh to delete packages used only on one system, use :ignore
(package! evil :ignore (not (equal system-name "my-desktop")))
#+END_SRC
*** TODO pushnew!
*** quiet!
#+BEGIN_SRC elisp :eval no
;; Enters recentf-mode without extra output
(quiet! (recentf-mode +1))
#+END_SRC
*** remove-hook!
#+BEGIN_SRC elisp :eval no #+BEGIN_SRC elisp :eval no
;; With only one hook and one function, this is identical to `remove-hook'. In ;; With only one hook and one function, this is identical to `remove-hook'. In
;; that case, use that instead. ;; that case, use that instead.
@ -148,3 +310,78 @@ It is integrated into Helpful, in Doom.
;; Removing arbitrary forms (must be exactly the same as the definition) ;; Removing arbitrary forms (must be exactly the same as the definition)
(remove-hook! (one-mode second-mode) (setq v 5) (setq a 2)) (remove-hook! (one-mode second-mode) (setq v 5) (setq a 2))
#+END_SRC #+END_SRC
*** setq-hook!
#+BEGIN_SRC elisp :eval no
;; Set multiple variables after a hook
(setq-hook! 'markdown-mode-hook
line-spacing 2
fill-column 80)
;; Set variables after multiple hooks
(setq-hook! '(eshell-mode-hook term-mode-hook)
hscroll-margin 0)
#+END_SRC
*** unsetq-hook!
#+BEGIN_SRC elisp :eval no
(unsetq-hook! 'markdown-mode-hook line-spacing)
;; Removes the following variable hook
(setq-hook! 'markdown-mode-hook line-spacing 2)
;; Removing N variables from M hooks
(unsetq-hook! some-mode enable-something and-another)
(unsetq-hook! some-mode (enable-something and-another))
(unsetq-hook! '(one-mode-hook second-mode-hook) enable-something)
(unsetq-hook! (one-mode second-mode) enable-something)
#+END_SRC
*** use-package!
#+BEGIN_SRC elisp :eval no
;; Use after-call to load package before hook
(use-package! projectile
:after-call (pre-command-hook after-find-file dired-before-readin-hook))
;; defer recentf packages one by one
(use-package! recentf
:defer-incrementally easymenu tree-widget timer
:after-call after-find-file)
;; This is equivalent to :defer-incrementally (abc)
(use-package! abc
:defer-incrementally t)
#+END_SRC
* Interesting snippets
** Persist Emacs' initial frame size across sessions
#+BEGIN_SRC elisp
(let ((display-height (display-pixel-height))
(display-width (display-pixel-width)))
(add-to-list 'initial-frame-alist
`((left . ,(/ new-frame-width 2))
(top . ,(/ new-frame-height 2))
(width . ,(/ display-width 2))
(height . ,(/ display-height 2)))))
#+END_SRC
** Persist Emacs' initial frame position, dimensions and/or full-screen state across sessions
#+BEGIN_SRC elisp
;; add to ~/.doom.d/config.el
(when-let* ((dims (doom-cache-get 'last-frame-size)))
(cl-destructuring-bind ((left . top) width height fullscreen) dims
(setq initial-frame-alist
(append initial-frame-alist
`((left . ,left)
(top . ,top)
(width . ,width)
(height . ,height)
(fullscreen . ,fullscreen))))))
(defun save-frame-dimensions ()
(doom-cache-set 'last-frame-size
(list (frame-position)
(frame-width)
(frame-height)
(frame-parameter nil 'fullscreen))))
(add-hook 'kill-emacs-hook #'save-frame-dimensions)
#+END_SRC

View file

@ -20,3 +20,8 @@
;; font. By inhibiting this, we easily halve startup times with fonts that are ;; font. By inhibiting this, we easily halve startup times with fonts that are
;; larger than the system default. ;; larger than the system default.
(setq frame-inhibit-implied-resize t) (setq frame-inhibit-implied-resize t)
;; Ignore X resources; its settings would be redundant with the other settings
;; in this file and can conflict with later config (particularly where the
;; cursor color is concerned).
(advice-add #'x-apply-session-resources :override #'ignore)

18
init.el
View file

@ -27,13 +27,6 @@
;; ;;
;;; License: MIT ;;; License: MIT
(when (version< emacs-version "25.3")
(error "Detected Emacs %s. Doom only supports Emacs 25.3 and higher"
emacs-version))
;; Ensure Doom is running out of this file's directory
(setq user-emacs-directory (file-name-directory load-file-name))
;; A big contributor to startup times is garbage collection. We up the gc ;; 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 ;; threshold to temporarily prevent it from running, then reset it later with
;; `doom-restore-garbage-collection-h'. Not resetting it will cause ;; `doom-restore-garbage-collection-h'. Not resetting it will cause
@ -45,8 +38,17 @@
;; to skip the mtime checks on every *.elc file we load. ;; to skip the mtime checks on every *.elc file we load.
(setq load-prefer-newer noninteractive) (setq load-prefer-newer noninteractive)
(let (file-name-handler-alist)
(when (version< emacs-version "25.3")
(error "Detected Emacs %s. Doom only supports Emacs 25.3 and higher"
emacs-version))
;; Ensure Doom is running out of this file's directory
(setq user-emacs-directory (file-name-directory load-file-name)))
;; Load the heart of Doom Emacs ;; Load the heart of Doom Emacs
(require 'core (concat user-emacs-directory "core/core")) (load (concat user-emacs-directory "core/core")
nil 'nomessage)
;; And let 'er rip! ;; And let 'er rip!
(add-hook 'window-setup-hook #'doom-display-benchmark-h) (add-hook 'window-setup-hook #'doom-display-benchmark-h)

View file

@ -118,6 +118,7 @@
;;julia ; a better, faster MATLAB ;;julia ; a better, faster MATLAB
;;kotlin ; a better, slicker Java(Script) ;;kotlin ; a better, slicker Java(Script)
;;latex ; writing papers in Emacs has never been so fun ;;latex ; writing papers in Emacs has never been so fun
;;lean
;;ledger ; an accounting system in Emacs ;;ledger ; an accounting system in Emacs
;;lua ; one-based indices? one-based indices ;;lua ; one-based indices? one-based indices
markdown ; writing docs for people to ignore markdown ; writing docs for people to ignore
@ -125,10 +126,10 @@
;;nix ; I hereby declare "nix geht mehr!" ;;nix ; I hereby declare "nix geht mehr!"
;;ocaml ; an objective camel ;;ocaml ; an objective camel
(org ; organize your plain life in plain text (org ; organize your plain life in plain text
+dragndrop ; file drag & drop support +dragndrop ; drag & drop files/images into org buffers
+ipython ; ipython support for babel +ipython ; ipython/jupyter support for babel
+pandoc ; pandoc integration into org's exporter +pandoc ; export-with-pandoc support
+present) ; using Emacs for presentations +present) ; using org-mode for presentations
;;perl ; write code no one else can comprehend ;;perl ; write code no one else can comprehend
;;php ; perl's insecure younger brother ;;php ; perl's insecure younger brother
;;plantuml ; diagrams for confusing people more ;;plantuml ; diagrams for confusing people more

View file

@ -42,7 +42,7 @@ Aesthetic modules that affect the Emacs interface or user experience.
+ [[file:ui/unicode/README.org][unicode]]: + [[file:ui/unicode/README.org][unicode]]:
+ vc-gutter: + vc-gutter:
+ vi-tilde-fringe: + vi-tilde-fringe:
+ [[file:ui/window-select/README.org][window-select]]: + [[file:ui/window-select/README.org][window-select]] =+switch-window +numbers=:
+ [[file:ui/workspaces/README.org][workspaces]]: Isolated workspaces + [[file:ui/workspaces/README.org][workspaces]]: Isolated workspaces
* :editor * :editor
@ -64,7 +64,6 @@ Modules that reconfigure or augment packages or features built into Emacs.
+ dired =+ranger +icons=: + dired =+ranger +icons=:
+ electric: + electric:
+ imenu:
+ vc: + vc:
* :term * :term

View file

@ -34,7 +34,7 @@ https://assets.doomemacs.org/completion/company/overlay.png
+ [[https://github.com/company-mode/company-mode][company-mode]] + [[https://github.com/company-mode/company-mode][company-mode]]
+ [[https://github.com/hlissner/emacs-company-dict][company-dict]] + [[https://github.com/hlissner/emacs-company-dict][company-dict]]
+ [[https://github.com/raxod502/prescient.el][company-prescient]] + [[https://github.com/raxod502/prescient.el][company-prescient]]
+ [[https://github.com/sebastiencs/company-box][company-box]] + [[https://github.com/sebastiencs/company-box][company-box]]* (=+childframe=)
* Prerequisites * Prerequisites
This module has no direct prerequisites. This module has no direct prerequisites.

View file

@ -41,6 +41,7 @@ be negative.")
[remap bookmark-jump] #'helm-bookmarks [remap bookmark-jump] #'helm-bookmarks
[remap execute-extended-command] #'helm-M-x [remap execute-extended-command] #'helm-M-x
[remap find-file] #'helm-find-files [remap find-file] #'helm-find-files
[remap locate] #'helm-locate
[remap imenu] #'helm-semantic-or-imenu [remap imenu] #'helm-semantic-or-imenu
[remap noop-show-kill-ring] #'helm-show-kill-ring [remap noop-show-kill-ring] #'helm-show-kill-ring
[remap persp-switch-to-buffer] #'+helm/workspace-mini [remap persp-switch-to-buffer] #'+helm/workspace-mini
@ -158,7 +159,23 @@ be negative.")
;;;###package helm-locate ;;;###package helm-locate
(defvar helm-generic-files-map (make-sparse-keymap)) (defvar helm-generic-files-map (make-sparse-keymap))
(after! helm-locate (set-keymap-parent helm-generic-files-map helm-map)) (after! helm-locate
(when (and IS-MAC
(null helm-locate-command)
(executable-find "mdfind"))
(setq helm-locate-command "mdfind -name %s"))
(set-keymap-parent helm-generic-files-map helm-map))
;;;###package helm-org
(use-package! helm-org
:when (featurep! :lang org)
:defer t
:init
(after! helm-mode
(pushnew! helm-completing-read-handlers-alist
'(org-capture . helm-org-completing-read-tags)
'(org-set-tags . helm-org-completing-read-tags))))
;;;###package helm-projectile ;;;###package helm-projectile

View file

@ -12,3 +12,5 @@
(package! helm-flx)) (package! helm-flx))
(when (and EMACS26+ (featurep! +childframe)) (when (and EMACS26+ (featurep! +childframe))
(package! posframe)) (package! posframe))
(when (featurep! :lang org)
(package! helm-org))

View file

@ -12,6 +12,7 @@
- [[#install][Install]] - [[#install][Install]]
- [[#macos][MacOS]] - [[#macos][MacOS]]
- [[#arch-linux][Arch Linux]] - [[#arch-linux][Arch Linux]]
- [[#opensuse][openSUSE]]
- [[#features][Features]] - [[#features][Features]]
- [[#jump-to-file-project-navigation][Jump-to-file project navigation]] - [[#jump-to-file-project-navigation][Jump-to-file project navigation]]
- [[#project-search--replace][Project search & replace]] - [[#project-search--replace][Project search & replace]]
@ -90,6 +91,11 @@ brew install ripgrep the_silver_searcher
sudo pacman --needed --noconfirm -S ripgrep the_silver_searcher sudo pacman --needed --noconfirm -S ripgrep the_silver_searcher
#+END_SRC #+END_SRC
*** openSUSE
#+BEGIN_SRC sh :dir /sudo::
sudo zypper install ripgrep the_silver_searcher
#+END_SRC
* Features * Features
Ivy and its ilk are large plugins. Covering everything about them is outside of Ivy and its ilk are large plugins. Covering everything about them is outside of
this documentation's scope, so only Doom-specific Ivy features are listed here: this documentation's scope, so only Doom-specific Ivy features are listed here:

View file

@ -214,7 +214,7 @@ If ARG (universal argument), open selection in other-window."
(defun +ivy--tasks-open-action (x) (defun +ivy--tasks-open-action (x)
"Jump to the file and line of the current task." "Jump to the file and line of the current task."
(cl-destructuring-bind (label type file line) x (cl-destructuring-bind (_label type file line) x
(with-ivy-window (with-ivy-window
(find-file (expand-file-name file (doom-project-root))) (find-file (expand-file-name file (doom-project-root)))
(goto-char (point-min)) (goto-char (point-min))

View file

@ -62,8 +62,6 @@ immediately runs it on the current candidate (ending the ivy session)."
projectile-completion-system 'ivy projectile-completion-system 'ivy
;; Don't use ^ as initial input ;; Don't use ^ as initial input
ivy-initial-inputs-alist nil ivy-initial-inputs-alist nil
;; highlight til EOL
ivy-format-function #'ivy-format-function-line
;; disable magic slash on non-match ;; disable magic slash on non-match
ivy-magic-slash-non-match-action nil ivy-magic-slash-non-match-action nil
;; don't show recent files in switch-buffer ;; don't show recent files in switch-buffer
@ -75,6 +73,9 @@ 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)
(setf (alist-get 't ivy-format-functions-alist)
#'ivy-format-function-line)
;; REVIEW Move this somewhere else and perhaps generalize this so both ;; REVIEW Move this somewhere else and perhaps generalize this so both
;; ivy/helm users can enjoy it. ;; ivy/helm users can enjoy it.
(defadvice! +ivy--counsel-file-jump-use-fd-rg-a (args) (defadvice! +ivy--counsel-file-jump-use-fd-rg-a (args)
@ -220,10 +221,13 @@ evil-ex-specific constructs, so we disable it solely in evil-ex."
[remap org-capture] #'counsel-org-capture [remap org-capture] #'counsel-org-capture
[remap swiper] #'counsel-grep-or-swiper [remap swiper] #'counsel-grep-or-swiper
[remap evil-ex-registers] #'counsel-evil-registers [remap evil-ex-registers] #'counsel-evil-registers
[remap yank-pop] #'counsel-yank-pop) [remap yank-pop] #'counsel-yank-pop
[remap locate] #'counsel-locate)
:config :config
(set-popup-rule! "^\\*ivy-occur" :size 0.35 :ttl 0 :quit nil) (set-popup-rule! "^\\*ivy-occur" :size 0.35 :ttl 0 :quit nil)
(when IS-MAC
(setq counsel-locate-cmd #'counsel-locate-cmd-mdfind))
(setq counsel-find-file-ignore-regexp "\\(?:^[#.]\\)\\|\\(?:[#~]$\\)\\|\\(?:^Icon?\\)" (setq counsel-find-file-ignore-regexp "\\(?:^[#.]\\)\\|\\(?:[#~]$\\)\\|\\(?:^Icon?\\)"
counsel-describe-function-function #'helpful-callable counsel-describe-function-function #'helpful-callable
counsel-describe-variable-function #'helpful-variable counsel-describe-variable-function #'helpful-variable

View file

@ -20,20 +20,7 @@
;;; Leader keys ;;; Leader keys
(map! :leader (map! :leader
:desc "Find file in project" "C-f" #'projectile-find-file
:desc "Evaluate line/region" "e" #'+eval/line-or-region :desc "Evaluate line/region" "e" #'+eval/line-or-region
:desc "Open scratch buffer" "x" #'doom/open-scratch-buffer
:desc "Open project scratch buffer" "X" #'doom/switch-to-scratch-buffer
(:when (featurep! :term term)
:desc "Toggle term popup" "`" #'+term/toggle
:desc "Open term here" "~" #'+term/here)
(:when (featurep! :term vterm)
:desc "Toggle vterm popup" "`" #'+vterm/toggle
:desc "Open vterm here" "~" #'+vterm/here)
(:when (featurep! :term eshell)
:desc "Toggle eshell popup" "`" #'+eshell/toggle
:desc "Open eshell here" "~" #'+eshell/here)
(:prefix ("l" . "<localleader>")) ; bound locally (:prefix ("l" . "<localleader>")) ; bound locally
(:prefix ("!" . "checkers")) ; bound by flycheck (:prefix ("!" . "checkers")) ; bound by flycheck
@ -49,6 +36,8 @@
:desc "Browse emacs.d" "E" #'+default/browse-emacsd :desc "Browse emacs.d" "E" #'+default/browse-emacsd
:desc "Find file from here" "f" (if (fboundp 'counsel-file-jump) #'counsel-file-jump #'find-file) :desc "Find file from here" "f" (if (fboundp 'counsel-file-jump) #'counsel-file-jump #'find-file)
:desc "Find file in other project" "F" #'doom/browse-in-other-project :desc "Find file in other project" "F" #'doom/browse-in-other-project
:desc "Delete this file" "K" #'doom/delete-this-file
:desc "Move this file" "m" #'doom/move-this-file
:desc "Find file in project" "p" #'projectile-find-file :desc "Find file in project" "p" #'projectile-find-file
:desc "Find file in other project" "P" #'doom/find-file-in-other-project :desc "Find file in other project" "P" #'doom/find-file-in-other-project
:desc "Recent files" "r" #'recentf-open-files :desc "Recent files" "r" #'recentf-open-files
@ -56,11 +45,25 @@
:desc "Sudo this file" "s" #'doom/sudo-this-file :desc "Sudo this file" "s" #'doom/sudo-this-file
:desc "Sudo find file" "S" #'doom/sudo-find-file :desc "Sudo find file" "S" #'doom/sudo-find-file
:desc "Yank filename" "y" #'+default/yank-buffer-filename :desc "Yank filename" "y" #'+default/yank-buffer-filename
:desc "Delete this file" "X" #'doom/delete-this-file) :desc "Open scratch buffer" "x" #'doom/open-scratch-buffer
:desc "Open project scratch buffer" "X" #'doom/switch-to-scratch-buffer)
;;; <leader> g --- lookup
(:when (featurep! :tools lookup)
(:prefix-map ("g" . "lookup")
"k" #'+lookup/documentation
"d" #'+lookup/definition
"D" #'+lookup/references
"f" #'+lookup/file
"o" #'+lookup/online-select
"i" #'+lookup/in-docsets
"I" #'+lookup/in-all-docsets))
;;; <leader> o --- org ;;; <leader> o --- org
"o" nil ; we need to unbind it first as Org claims this "o" nil ; we need to unbind it first as Org claims this
(:prefix-map ("o". "org") (:prefix-map ("o". "org")
:desc "Do what I mean" "o" #'+org/dwim-at-point
:desc "Display inline images" "i" #'org-display-inline-images
:desc "Search notes for symbol" "." #'+default/search-notes-for-symbol-at-point :desc "Search notes for symbol" "." #'+default/search-notes-for-symbol-at-point
(:prefix ("a" . "org agenda") (:prefix ("a" . "org agenda")
:desc "Agenda" "a" #'org-agenda :desc "Agenda" "a" #'org-agenda
@ -104,6 +107,17 @@
:desc "Create Temp Template" "c" #'aya-create :desc "Create Temp Template" "c" #'aya-create
:desc "Use Temp Template" "e" #'aya-expand) :desc "Use Temp Template" "e" #'aya-expand)
(:prefix-map ("t" . "terminal")
(:when (featurep! :term term)
:desc "Toggle term popup" "t" #'+term/toggle
:desc "Open term here" "T" #'+term/here)
(:when (featurep! :term vterm)
:desc "Toggle vterm popup" "t" #'+vterm/toggle
:desc "Open vterm here" "T" #'+vterm/here)
(:when (featurep! :term eshell)
:desc "Toggle eshell popup" "t" #'+eshell/toggle
:desc "Open eshell here" "T" #'+eshell/here))
;;; <leader> v --- versioning ;;; <leader> v --- versioning
(:prefix-map ("v" . "versioning") (:prefix-map ("v" . "versioning")
:desc "Git revert file" "R" #'vc-revert :desc "Git revert file" "R" #'vc-revert

View file

@ -54,7 +54,7 @@
[remap quit-window] #'kill-current-buffer) [remap quit-window] #'kill-current-buffer)
(:map (help-mode-map helpful-mode-map) (:map (help-mode-map helpful-mode-map)
:n "o" 'ace-link-help) :n "o" #'ace-link-help)
;; misc ;; misc
:n "C-S-f" #'toggle-frame-fullscreen :n "C-S-f" #'toggle-frame-fullscreen
@ -116,6 +116,8 @@
:v "g+" #'evil-numbers/inc-at-pt :v "g+" #'evil-numbers/inc-at-pt
;; custom evil keybinds ;; custom evil keybinds
:n "zn" #'+evil:narrow-buffer
:n "zN" #'doom/widen-indirectly-narrowed-buffer
:n "zx" #'kill-current-buffer :n "zx" #'kill-current-buffer
:n "ZX" #'bury-buffer :n "ZX" #'bury-buffer
;; repeat in visual mode (FIXME buggy) ;; repeat in visual mode (FIXME buggy)
@ -544,6 +546,7 @@
:desc "Search buffer" "b" #'swiper :desc "Search buffer" "b" #'swiper
:desc "Search current directory" "d" #'+default/search-cwd :desc "Search current directory" "d" #'+default/search-cwd
:desc "Search other directory" "D" #'+default/search-other-cwd :desc "Search other directory" "D" #'+default/search-other-cwd
:desc "Locate file" "f" #'locate
:desc "Jump to symbol" "i" #'imenu :desc "Jump to symbol" "i" #'imenu
:desc "Jump to link" "l" #'ace-link :desc "Jump to link" "l" #'ace-link
:desc "Look up online" "o" #'+lookup/online :desc "Look up online" "o" #'+lookup/online
@ -581,7 +584,7 @@
;;; <leader> b --- buffer ;;; <leader> b --- buffer
(:prefix-map ("b" . "buffer") (:prefix-map ("b" . "buffer")
:desc "Toggle narrowing" "-" #'doom/clone-and-narrow-buffer :desc "Toggle narrowing" "-" #'doom/toggle-narrow-buffer
:desc "Previous buffer" "[" #'previous-buffer :desc "Previous buffer" "[" #'previous-buffer
:desc "Next buffer" "]" #'next-buffer :desc "Next buffer" "]" #'next-buffer
(:when (featurep! :ui workspaces) (:when (featurep! :ui workspaces)
@ -594,7 +597,7 @@
:desc "Switch to last buffer" "l" #'evil-switch-to-windows-last-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
:desc "Previous buffer" "p" #'previous-buffer :desc "Previous buffer" "p" #'previous-buffer
:desc "Save buffer" "s" #'save-buffer :desc "Save buffer" "s" #'save-buffer
:desc "Sudo edit this file" "S" #'doom/sudo-this-file :desc "Sudo edit this file" "S" #'doom/sudo-this-file
@ -615,7 +618,9 @@
:desc "Delete trailing whitespace" "w" #'delete-trailing-whitespace :desc "Delete trailing whitespace" "w" #'delete-trailing-whitespace
:desc "Delete trailing newlines" "W" #'doom/delete-trailing-newlines :desc "Delete trailing newlines" "W" #'doom/delete-trailing-newlines
(:when (featurep! :tools flycheck) (:when (featurep! :tools flycheck)
:desc "List errors" "x" #'flycheck-list-errors)) :desc "List errors" "x" #'flycheck-list-errors)
(:unless (featurep! :tools flycheck)
:desc "List errors" "x" #'flymake-show-diagnostics-buffer))
;;; <leader> f --- file ;;; <leader> f --- file
(:prefix-map ("f" . "file") (:prefix-map ("f" . "file")
@ -629,6 +634,7 @@
:desc "Find file in emacs.d" "e" #'+default/find-in-emacsd :desc "Find file in emacs.d" "e" #'+default/find-in-emacsd
:desc "Browse emacs.d" "E" #'+default/browse-emacsd :desc "Browse emacs.d" "E" #'+default/browse-emacsd
:desc "Find file from here" "f" #'find-file :desc "Find file from here" "f" #'find-file
:desc "Locate file" "l" #'locate
:desc "Move/rename file" "m" #'doom/move-this-file :desc "Move/rename file" "m" #'doom/move-this-file
:desc "Find file in private config" "p" #'doom/find-file-in-private-config :desc "Find file in private config" "p" #'doom/find-file-in-private-config
:desc "Browse private config" "P" #'doom/open-private-config :desc "Browse private config" "P" #'doom/open-private-config
@ -642,6 +648,8 @@
;;; <leader> g --- git ;;; <leader> g --- git
(:prefix-map ("g" . "git") (:prefix-map ("g" . "git")
:desc "Git revert file" "R" #'vc-revert :desc "Git revert file" "R" #'vc-revert
:desc "Copy git link" "y" #'git-link
:desc "Copy git link to homepage" "Y" #'git-link-homepage
(:when (featurep! :ui vc-gutter) (:when (featurep! :ui vc-gutter)
:desc "Git revert hunk" "r" #'git-gutter:revert-hunk :desc "Git revert hunk" "r" #'git-gutter:revert-hunk
:desc "Git stage hunk" "s" #'git-gutter:stage-hunk :desc "Git stage hunk" "s" #'git-gutter:stage-hunk
@ -667,7 +675,7 @@
:desc "Find issue" "i" #'forge-visit-issue :desc "Find issue" "i" #'forge-visit-issue
:desc "Find pull request" "p" #'forge-visit-pullreq) :desc "Find pull request" "p" #'forge-visit-pullreq)
(:prefix ("o" . "open in browser") (:prefix ("o" . "open in browser")
:desc "Browse region or line" "." #'+vc/git-browse-region-or-line :desc "Browse region or line" "o" #'+vc/git-browse-region-or-line
:desc "Browse remote" "r" #'forge-browse-remote :desc "Browse remote" "r" #'forge-browse-remote
:desc "Browse commit" "c" #'forge-browse-commit :desc "Browse commit" "c" #'forge-browse-commit
:desc "Browse an issue" "i" #'forge-browse-issue :desc "Browse an issue" "i" #'forge-browse-issue
@ -707,7 +715,12 @@
:desc "Search org agenda headlines" "h" #'+default/org-notes-headlines :desc "Search org agenda headlines" "h" #'+default/org-notes-headlines
:desc "Find file in notes" "n" #'+default/find-in-notes :desc "Find file in notes" "n" #'+default/find-in-notes
:desc "Browse notes" "N" #'+default/browse-notes :desc "Browse notes" "N" #'+default/browse-notes
:desc "Org store link" "l" #'org-store-link) :desc "Org store link" "l" #'org-store-link
(:when (featurep! :lang org +journal)
(:prefix ("j" . "journal")
:desc "New Entry" "j" #'org-journal-new-entry
:desc "Search Forever" "s" #'org-journal-search-forever)))
;;; <leader> o --- open ;;; <leader> o --- open
(:prefix-map ("o" . "open") (:prefix-map ("o" . "open")
@ -813,6 +826,10 @@
;;; <leader> t --- toggle ;;; <leader> t --- toggle
(:prefix-map ("t" . "toggle") (:prefix-map ("t" . "toggle")
:desc "Big mode" "b" #'doom-big-font-mode :desc "Big mode" "b" #'doom-big-font-mode
(:when (featurep! :tools flycheck)
:desc "Flycheck" "f" #'flycheck-mode)
(:unless (featurep! :tools flycheck)
:desc "Flymake" "f" #'flymake-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 "Indent style" "I" #'doom/toggle-indent-style :desc "Indent style" "I" #'doom/toggle-indent-style

View file

@ -1,9 +1,9 @@
;;; config/default/+evil.el -*- lexical-binding: t; -*- ;;; config/default/+evil.el -*- lexical-binding: t; -*-
(defun +default|disable-delete-selection-mode () (defun +default-disable-delete-selection-mode-h ()
(delete-selection-mode -1)) (delete-selection-mode -1))
(add-hook 'evil-insert-state-entry-hook #'delete-selection-mode) (add-hook 'evil-insert-state-entry-hook #'delete-selection-mode)
(add-hook 'evil-insert-state-exit-hook #'+default|disable-delete-selection-mode) (add-hook 'evil-insert-state-exit-hook #'+default-disable-delete-selection-mode-h)
;; ;;

View file

@ -109,7 +109,7 @@ If ARG (universal argument), runs `compile' from the current directory."
((error "No kill-ring search backend available. Enable ivy or helm!"))))) ((error "No kill-ring search backend available. Enable ivy or helm!")))))
;;;###autoload ;;;###autoload
(defun +default*newline-indent-and-continue-comments () (defun +default--newline-indent-and-continue-comments-a ()
"A replacement for `newline-and-indent'. "A replacement for `newline-and-indent'.
Continues comments if executed from a commented line, with special support for Continues comments if executed from a commented line, with special support for
@ -159,7 +159,7 @@ possible, or just one char if that's not possible."
((delete-char -1))))) ((delete-char -1)))))
;;;###autoload ;;;###autoload
(defun +default*delete-backward-char (n &optional killflag) (defun +default--delete-backward-char-a (n &optional killflag)
"Same as `delete-backward-char', but preforms these additional checks: "Same as `delete-backward-char', but preforms these additional checks:
+ If point is surrounded by (balanced) whitespace and a brace delimiter ({} [] + If point is surrounded by (balanced) whitespace and a brace delimiter ({} []
@ -283,11 +283,11 @@ If prefix ARG is set, prompt for a known project to search from."
((rgrep (regexp-quote symbol)))))) ((rgrep (regexp-quote symbol))))))
;;;###autoload ;;;###autoload
(defun +default/search-notes-for-symbol-at-point (&optional arg symbol) (defun +default/search-notes-for-symbol-at-point (&optional symbol)
"Conduct a text search in the current project for symbol at point. If prefix "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." ARG is set, prompt for a known project to search from."
(interactive (interactive
(list current-prefix-arg (thing-at-point 'symbol t))) (list (thing-at-point 'symbol t)))
(require 'org) (require 'org)
(let ((default-directory org-directory)) (let ((default-directory org-directory))
(+default/search-project-for-symbol-at-point (+default/search-project-for-symbol-at-point

View file

@ -34,6 +34,10 @@
;; prompt for the key passphrase. ;; prompt for the key passphrase.
epa-pinentry-mode 'loopback)) epa-pinentry-mode 'loopback))
;;;###package tramp
(unless IS-WINDOWS
(setq tramp-default-method "ssh")) ; faster than the default scp
;; ;;
;;; Smartparens config ;;; Smartparens config
@ -195,10 +199,10 @@
;; e) properly delete smartparen pairs when they are encountered, without ;; e) properly delete smartparen pairs when they are encountered, without
;; the need for strict mode. ;; the need for strict mode.
;; f) do none of this when inside a string ;; f) do none of this when inside a string
(advice-add #'delete-backward-char :override #'+default*delete-backward-char)) (advice-add #'delete-backward-char :override #'+default--delete-backward-char-a))
;; Makes `newline-and-indent' continue comments (and more reliably) ;; Makes `newline-and-indent' continue comments (and more reliably)
(advice-add #'newline-and-indent :override #'+default*newline-indent-and-continue-comments)) (advice-add #'newline-and-indent :override #'+default--newline-indent-and-continue-comments-a))
;; ;;
@ -260,7 +264,6 @@
(define-key! help-map (define-key! help-map
;; new keybinds ;; new keybinds
"'" #'describe-char "'" #'describe-char
"B" #'doom/open-bug-report
"D" #'doom/help "D" #'doom/help
"E" #'doom/sandbox "E" #'doom/sandbox
"M" #'doom/describe-active-minor-mode "M" #'doom/describe-active-minor-mode
@ -312,8 +315,6 @@
"F" #'describe-face "F" #'describe-face
;; replaces `view-hello-file' b/c annoying ;; replaces `view-hello-file' b/c annoying
"h" #'doom/help "h" #'doom/help
;; replaces `describe-language-environment' b/c remapped to C-l
"L" #'global-command-log-mode
;; replaces `view-emacs-news' b/c it's on C-n too ;; replaces `view-emacs-news' b/c it's on C-n too
"n" #'doom/help-news "n" #'doom/help-news
;; replaces `finder-by-keyword' ;; replaces `finder-by-keyword'

View file

@ -53,7 +53,12 @@ variable for an explanation of the defaults (in comments). See
;; (url-retrieve-synchronously "https://raw.githubusercontent.com/emacs-evil/evil-collection/master/evil-collection.el" t t) ;; (url-retrieve-synchronously "https://raw.githubusercontent.com/emacs-evil/evil-collection/master/evil-collection.el" t t)
;; (goto-char (point-min)) ;; (goto-char (point-min))
;; (when (re-search-forward "^(defcustom evil-collection-mode-list\n[^(]+") ;; (when (re-search-forward "^(defcustom evil-collection-mode-list\n[^(]+")
;; (kill-new (thing-at-point 'sexp t)))) ;; (let ((list (sexp-at-point)))
;; ;; Fixes
;; (when (assq 'pdf list)
;; (setf (alist-get 'pdf list) '(pdf-tools)))
;; (kill-new (prin1-to-string list)))))
(defvar evil-collection-mode-list (defvar evil-collection-mode-list
`(2048-game `(2048-game
ag ag
@ -143,7 +148,7 @@ variable for an explanation of the defaults (in comments). See
p4 p4
(package-menu package) (package-menu package)
pass pass
(pdf pdf-view) (pdf pdf-tools)
popup popup
proced proced
process-menu process-menu

View file

@ -135,10 +135,18 @@ integration."
;;;###autoload (autoload '+evil:narrow-buffer "editor/evil/autoload/evil" nil t) ;;;###autoload (autoload '+evil:narrow-buffer "editor/evil/autoload/evil" nil t)
(evil-define-operator +evil:narrow-buffer (beg end &optional bang) (evil-define-operator +evil:narrow-buffer (beg end &optional bang)
"Wrapper around `doom/clone-and-narrow-buffer'." "Narrow the buffer to region between BEG and END.
Widens narrowed buffers first. If BANG, use indirect buffer clones instead."
:move-point nil :move-point nil
(interactive "<r><!>") (interactive "<r><!>")
(doom/clone-and-narrow-buffer beg end bang)) (if (not bang)
(if (buffer-narrowed-p)
(widen)
(narrow-to-region beg end))
(when (buffer-narrowed-p)
(doom/widen-indirectly-narrowed-buffer t))
(doom/narrow-buffer-indirectly beg end)))
;;;###autoload ;;;###autoload
(defun +evil/next-beginning-of-method (count) (defun +evil/next-beginning-of-method (count)
@ -192,13 +200,13 @@ See `+evil/next-preproc-directive' for details."
(dotimes (_ (abs count)) (dotimes (_ (abs count))
(cond ((> count 0) (cond ((> count 0)
(while (and (not (eobp)) (sp-point-in-comment)) (while (and (not (eobp)) (sp-point-in-comment))
(next-line)) (forward-line 1))
(unless (comment-search-forward (point-max) 'noerror) (unless (comment-search-forward (point-max) 'noerror)
(goto-char orig-pt) (goto-char orig-pt)
(user-error "No comment after point"))) (user-error "No comment after point")))
(t (t
(while (and (not (bobp)) (sp-point-in-comment)) (while (and (not (bobp)) (sp-point-in-comment))
(previous-line)) (forward-line -1))
(unless (comment-search-backward nil 'noerror) (unless (comment-search-backward nil 'noerror)
(goto-char orig-pt) (goto-char orig-pt)
(user-error "No comment before point"))))))) (user-error "No comment before point")))))))

View file

@ -177,7 +177,7 @@ If BANG, search Doom documentation."
'module (list cat mod)))) 'module (list cat mod))))
(module (completing-read "Describe module: " modules nil t query)) (module (completing-read "Describe module: " modules nil t query))
(key (get-text-property 0 'module module))) (key (get-text-property 0 'module module)))
(doom/help-modules key))) (doom/help-modules (car key) (cdr key))))
((and (string-match-p "\\(?:SPC\\|[CMsSH]-[^ ]\\|<[^>]+>\\)" query) ((and (string-match-p "\\(?:SPC\\|[CMsSH]-[^ ]\\|<[^>]+>\\)" query)
(helpful-key (kbd (string-trim query))))) (helpful-key (kbd (string-trim query)))))
((apropos query t))))) ((apropos query t)))))

View file

@ -85,31 +85,31 @@
;;; ]u / [u ;;; ]u / [u
;;;###autoload (autoload '+evil:url-encode "editor/evil/autoload/unimpaired" nil t) ;;;###autoload (autoload '+evil:url-encode "editor/evil/autoload/unimpaired" nil t)
(evil-define-operator +evil:url-encode (count &optional beg end type) (evil-define-operator +evil:url-encode (_count &optional beg end)
"TODO" "TODO"
(interactive "<c><R>") (interactive "<c><r>")
(+evil--encode beg end #'url-encode-url)) (+evil--encode beg end #'url-encode-url))
;;;###autoload (autoload '+evil:url-decode "editor/evil/autoload/unimpaired" nil t) ;;;###autoload (autoload '+evil:url-decode "editor/evil/autoload/unimpaired" nil t)
(evil-define-operator +evil:url-decode (count &optional beg end type) (evil-define-operator +evil:url-decode (_count &optional beg end)
"TODO" "TODO"
(interactive "<c><R>") (interactive "<c><r>")
(+evil--encode beg end #'url-unhex-string)) (+evil--encode beg end #'url-unhex-string))
;;; ]y / [y ;;; ]y / [y
;;;###autoload (autoload '+evil:c-string-encode "editor/evil/autoload/unimpaired" nil t) ;;;###autoload (autoload '+evil:c-string-encode "editor/evil/autoload/unimpaired" nil t)
(evil-define-operator +evil:c-string-encode (count &optional beg end type) (evil-define-operator +evil:c-string-encode (_count &optional beg end)
"TODO" "TODO"
(interactive "<c><R>") (interactive "<c><r>")
(+evil--encode (+evil--encode
beg end beg end
(lambda (text) (lambda (text)
(replace-regexp-in-string "[\"\\]" (lambda (ch) (concat "\\" ch)) text)))) (replace-regexp-in-string "[\"\\]" (lambda (ch) (concat "\\" ch)) text))))
;;;###autoload (autoload '+evil:c-string-decode "editor/evil/autoload/unimpaired" nil t) ;;;###autoload (autoload '+evil:c-string-decode "editor/evil/autoload/unimpaired" nil t)
(evil-define-operator +evil:c-string-decode (count &optional beg end type) (evil-define-operator +evil:c-string-decode (_count &optional beg end)
"TODO" "TODO"
(interactive "<c><R>") (interactive "<c><r>")
(+evil--encode (+evil--encode
beg end beg end
(lambda (text) (lambda (text)

View file

@ -257,12 +257,12 @@ directives. By default, this only recognizes C directives.")
(use-package! evil-escape (use-package! evil-escape
:commands evil-escape :commands evil-escape
:after-call evil-normal-state-exit-hook :after-call pre-command-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)
evil-escape-key-sequence "jk" evil-escape-key-sequence "jk"
evil-escape-delay 0.25) evil-escape-delay 0.15)
(evil-define-key* '(insert replace visual operator) 'global "\C-g" #'evil-escape) (evil-define-key* '(insert replace visual operator) 'global "\C-g" #'evil-escape)
:config :config
;; no `evil-escape' in minibuffer ;; no `evil-escape' in minibuffer

View file

@ -3,12 +3,11 @@
(describe "feature/evil" (describe "feature/evil"
:var (resv project-root) :var (resv project-root)
(before-all
(require! :editor evil) (require! :editor evil)
(require 'evil) (require 'evil)
(load! "../autoload/evil")) (load! "../autoload/evil")
(after-all
(unload-feature 'evil t))
(before-each (before-each
(fset 'resv #'+evil-resolve-vim-path-a) (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)))

View file

@ -5,6 +5,8 @@
(defun +multiple-cursors/evil-mc-toggle-cursors () (defun +multiple-cursors/evil-mc-toggle-cursors ()
"Toggle frozen state of evil-mc cursors." "Toggle frozen state of evil-mc cursors."
(interactive) (interactive)
(unless (evil-mc-has-cursors-p)
(user-error "No cursors exist to be toggled"))
(setq evil-mc-frozen (not (and (evil-mc-has-cursors-p) (setq evil-mc-frozen (not (and (evil-mc-has-cursors-p)
evil-mc-frozen))) evil-mc-frozen)))
(if evil-mc-frozen (if evil-mc-frozen
@ -45,12 +47,14 @@ pauses cursors."
(evil-mc-make-cursor-here)))) (evil-mc-make-cursor-here))))
;;;###autoload (autoload '+multiple-cursors:evil-mc "editor/multiple-cursors/autoload/evil-mc" nil t) ;;;###autoload (autoload '+multiple-cursors:evil-mc "editor/multiple-cursors/autoload/evil-mc" nil t)
(evil-define-command +multiple-cursors:evil-mc (beg end type pattern &optional bang) (evil-define-command +multiple-cursors:evil-mc (beg end type pattern &optional flags bang)
"Create mc cursors at each match of PATTERN within BEG and END, and leave the "Create mc cursors at each match of PATTERN within BEG and END.
cursor at the final match. If BANG, then treat PATTERN as literal."
This leaves the cursor at the final match. If BANG, then treat PATTERN as
literal. PATTERN is a delimited regexp (the same that :g or :s uses)."
:move-point nil :move-point nil
:evil-mc t :evil-mc t
(interactive "<R><//g><!>") (interactive "<R><//!><!>")
(unless (and (stringp pattern) (unless (and (stringp pattern)
(not (string-empty-p pattern))) (not (string-empty-p pattern)))
(user-error "A regexp pattern is required")) (user-error "A regexp pattern is required"))
@ -59,9 +63,19 @@ cursor at the final match. If BANG, then treat PATTERN as literal."
(cons (evil-ex-make-search-pattern (cons (evil-ex-make-search-pattern
(if bang (regexp-quote pattern) pattern)) (if bang (regexp-quote pattern) pattern))
(list beg end type))) (list beg end type)))
(save-excursion (evil-with-restriction beg end
(evil-with-restriction beg end (let ((point (point)))
(evil-mc-make-cursors-for-all))) (save-excursion
(goto-char (point-min))
(while (eq (evil-ex-find-next (evil-mc-get-pattern) 'forward t) t)
(goto-char (1- (point)))
(when (/= point (point))
(evil-mc-run-cursors-before)
(evil-mc-make-cursor-at-pos (point)))
(goto-char
(if (memq ?g flags)
(line-beginning-position 2)
(1+ (point))))))))
(evil-exit-visual-state) (evil-exit-visual-state)
(evil-mc-goto-cursor (evil-mc-goto-cursor
(if (= (evil-visual-direction) 1) (if (= (evil-visual-direction) 1)

View file

@ -59,11 +59,7 @@
;; 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.
(evil-add-command-properties '+evil:align :evil-mc t) (evil-add-command-properties '+evil:align :evil-mc t)
(evil-set-command-properties '+multiple-cursors:evil-mc (evil-add-command-properties '+multiple-cursors:evil-mc :evil-mc t))
:move-point nil
:ex-arg 'global-match
:ex-bang t
:evil-mc t))
(after! multiple-cursors-core (after! multiple-cursors-core

View file

@ -5,6 +5,6 @@
"Register minor MODES (one mode symbol or a list of them) with yasnippet so it "Register minor MODES (one mode symbol or a list of them) with yasnippet so it
can have its own snippets category, if the folder exists." can have its own snippets category, if the folder exists."
(dolist (mode (doom-enlist modes)) (dolist (mode (doom-enlist modes))
(let ((fn (intern (format "+snippets|register-%s" mode)))) (let ((fn (intern (format "+snippets-register-%s-h" mode))))
(fset fn (lambda () (yas-activate-extra-mode mode))) (fset fn (lambda () (yas-activate-extra-mode mode)))
(add-hook (intern (format "%s-hook" mode)) fn)))) (add-hook (intern (format "%s-hook" mode)) fn))))

View file

@ -225,7 +225,7 @@ You will be prompted for a snippet to alias."
"# condition: t}\n" "# condition: t}\n"
"# type: command\n" "# type: command\n"
"# --\n" "# --\n"
"(%alias \"${4:" (or template "uuid") "}\")")) "(%alias \"${4:" (or template-uuid "uuid") "}\")"))
(when (bound-and-true-p evil-local-mode) (when (bound-and-true-p evil-local-mode)
(evil-insert-state))))) (evil-insert-state)))))

View file

@ -24,7 +24,7 @@
;; Use GNU ls as `gls' from `coreutils' if available. Add `(setq ;; Use GNU ls as `gls' from `coreutils' if available. Add `(setq
;; dired-use-ls-dired nil)' to your config to suppress the Dired warning ;; dired-use-ls-dired nil)' to your config to suppress the Dired warning
;; when not using GNU ls. ;; when not using GNU ls.
(if-let* ((gls (executable-find "gls"))) (if-let (gls (executable-find "gls"))
(setq insert-directory-program gls) (setq insert-directory-program gls)
;; BSD ls doesn't support --group-directories-first ;; BSD ls doesn't support --group-directories-first
(setq args (delete "--group-directories-first" args)))) (setq args (delete "--group-directories-first" args))))
@ -45,30 +45,12 @@
:hook (dired-mode . diredfl-mode)) :hook (dired-mode . diredfl-mode))
(use-package! dired-k (use-package! diff-hl
:hook (dired-initial-position . dired-k) :hook (dired-mode . diff-hl-dired-mode)
:hook (dired-after-readin . dired-k-no-revert) :hook (magit-post-refresh . diff-hl-magit-post-refresh)
:config :config
(setq dired-k-style 'git ;; use margin instead of fringe
dired-k-padding 1) (diff-hl-margin-mode))
;; Don't highlight based on mtime, this interferes with diredfl and is more
;; confusing than helpful.
(advice-add #'dired-k--highlight-by-file-attribyte :override #'ignore)
(defadvice! +dired--interrupt-process-a (orig-fn &rest args)
"Fixes dired-k killing git processes too abruptly, leaving behind disruptive
.git/index.lock files."
:around #'dired-k--start-git-status
(cl-letf (((symbol-function #'kill-process)
(symbol-function #'interrupt-process)))
(apply orig-fn args)))
(defadvice! +dired--dired-k-highlight-a (orig-fn &rest args)
"Butt out if the requested directory is remote (i.e. through tramp)."
:around #'dired-k--highlight
(unless (file-remote-p default-directory)
(apply orig-fn args))))
(use-package! ranger (use-package! ranger
@ -117,6 +99,7 @@ we have to clean it up ourselves."
(use-package! dired-x (use-package! dired-x
:unless (featurep! +ranger)
:hook (dired-mode . dired-omit-mode) :hook (dired-mode . dired-omit-mode)
:config :config
(setq dired-omit-verbose nil) (setq dired-omit-verbose nil)

View file

@ -2,7 +2,7 @@
;;; emacs/dired/packages.el ;;; emacs/dired/packages.el
(package! diredfl) (package! diredfl)
(package! dired-k) (package! diff-hl)
(package! dired-rsync) (package! dired-rsync)
(when (featurep! +ranger) (when (featurep! +ranger)
(package! ranger)) (package! ranger))

View file

@ -4,16 +4,18 @@
#+STARTUP: inlineimages #+STARTUP: inlineimages
* Table of Contents :TOC: * Table of Contents :TOC:
- [[Description][Description]] - [[#description][Description]]
- [[Module Flags][Module Flags]] - [[#module-flags][Module Flags]]
- [[Plugins][Plugins]] - [[#plugins][Plugins]]
- [[Prerequisites][Prerequisites]] - [[#prerequisites][Prerequisites]]
- [[MacOS][MacOS]] - [[#macos][MacOS]]
- [[Arch Linux][Arch Linux]] - [[#arch-linux][Arch Linux]]
- [[Features][Features]] - [[#nixos][NixOS]]
- [[Configuration][Configuration]] - [[#opensuse][openSUSE]]
- [[offlineimap][offlineimap]] - [[#features][Features]]
- [[mbsync][mbsync]] - [[#configuration][Configuration]]
- [[#offlineimap][offlineimap]]
- [[#mbsync][mbsync]]
* Description * Description
This module makes Emacs an email client, using ~mu4e~. This module makes Emacs an email client, using ~mu4e~.
@ -66,6 +68,15 @@ environment.systemPackages = with pkgs; [
[[https://github.com/Emiller88/dotfiles/blob/master/modules/shell/mail.nix][An example of setting up mbsync with home-manager]] [[https://github.com/Emiller88/dotfiles/blob/master/modules/shell/mail.nix][An example of setting up mbsync with home-manager]]
** openSUSE
Remove ~#~ in ~#sync_program=offlineimap~ to choose ~offlineimap~ instead of ~mbsync~.
#+BEGIN_SRC sh :dir /sudo::
sync_program=isync # mbsync
#sync_program=offlineimap
sudo zypper install maildir-utils $sync_programm
#+END_SRC
* TODO Features * TODO Features
* Configuration * Configuration

View file

@ -36,15 +36,15 @@
when exporting org-mode to html." when exporting org-mode to html."
:filter-args #'org-html-paragraph :filter-args #'org-html-paragraph
(cl-destructuring-bind (paragraph contents info) args (cl-destructuring-bind (paragraph contents info) args
(let* ((fix-regexp "[[:multibyte:]a-zA-Z0-9]") (let* ((fix-regexp "[[:multibyte:]]")
(origin-contents contents) (origin-contents
(replace-regexp-in-string
"<[Bb][Rr] */>"
""
contents))
(fixed-contents (fixed-contents
(replace-regexp-in-string (replace-regexp-in-string
(concat "\\(" (concat "\\(" fix-regexp "\\) *\n *\\(" fix-regexp "\\)")
fix-regexp "\\1\\2"
"\\) *\\(<[Bb][Rr] */>\\)?\n *\\("
fix-regexp
"\\)")
"\\1\\3"
origin-contents))) origin-contents)))
(list paragraph fixed-contents info)))) (list paragraph fixed-contents info))))

View file

@ -22,7 +22,7 @@
(after! helm (helm-migemo-mode +1))))) (after! helm (helm-migemo-mode +1)))))
(use-package pangu-spacing (use-package! pangu-spacing
:hook (text-mode . pangu-spacing-mode) :hook (text-mode . pangu-spacing-mode)
:init :init
;; replacing `chinese-two-byte' by `japanese' ;; replacing `chinese-two-byte' by `japanese'
@ -46,15 +46,15 @@
when exporting org-mode to html." when exporting org-mode to html."
:filter-args #'org-html-paragraph :filter-args #'org-html-paragraph
(cl-destructuring-bind (paragraph contents info) args (cl-destructuring-bind (paragraph contents info) args
(let* ((fix-regexp "[[:multibyte:]a-zA-Z0-9]") (let* ((fix-regexp "[[:multibyte:]]")
(origin-contents contents) (origin-contents
(replace-regexp-in-string
"<[Bb][Rr] */>"
""
contents))
(fixed-contents (fixed-contents
(replace-regexp-in-string (replace-regexp-in-string
(concat "\\(" (concat "\\(" fix-regexp "\\) *\n *\\(" fix-regexp "\\)")
fix-regexp "\\1\\2"
"\\) *\\(<[Bb][Rr] */>\\)?\n *\\("
fix-regexp
"\\)")
"\\1\\3"
origin-contents))) origin-contents)))
(list paragraph fixed-contents info)))) (list paragraph fixed-contents info))))

View file

@ -1,9 +1,4 @@
#+TITLE: :lang agda #+TITLE: :lang agda
This module adds support for the [[http://wiki.portal.chalmers.se/agda/pmwiki.php][agda]] programming language. This module adds support for the [[http://wiki.portal.chalmers.se/agda/pmwiki.php][agda]] programming language. The Emacs support
exists directly in the agda repository but not in melpa.
Emacs support is included in the agda release (you can find installation
instructions [[https://agda.readthedocs.io/en/latest/getting-started/installation.html][here]]). This module attempts to find the location of ~agda2.el~ via
the ~agda-mode locate~ command that comes with the agda release. Users can set
this manually by setting the ~+agda2-dir~ variable.

View file

@ -1,41 +1,31 @@
;;; lang/agda/config.el -*- lexical-binding: t; -*- ;;; lang/agda/config.el -*- lexical-binding: t; -*-
(defvar +agda-dir (map! :after agda2-mode
(when (executable-find "agda-mode") :map agda2-mode-map
(file-name-directory (shell-command-to-string "agda-mode locate")))) :localleader
"?" #'agda2-show-goals
(use-package! agda2 "." #'agda2-goal-and-context-and-inferred
:when +agda-dir "," #'agda2-goal-and-context
:load-path +agda-dir) "=" #'agda2-show-constraints
"SPC" #'agda2-give
(use-package! agda2-mode "a" #'agda2-auto-maybe-all
:defer t "b" #'agda2-previous-goal
:config "c" #'agda2-make-case
(map! :map agda2-mode-map "d" #'agda2-infer-type-maybe-toplevel
:localleader "e" #'agda2-show-context
"?" #'agda2-show-goals "f" #'agda2-next-goal
"." #'agda2-goal-and-context-and-inferred "gG" #'agda2-go-back
"," #'agda2-goal-and-context "h" #'agda2-helper-function-type
"=" #'agda2-show-constraints "l" #'agda2-load
"SPC" #'agda2-give "n" #'agda2-compute-normalised-maybe-toplevel
"a" #'agda2-auto-maybe-all "p" #'agda2-module-contents-maybe-toplevel
"b" #'agda2-previous-goal "r" #'agda2-refine
"c" #'agda2-make-case "s" #'agda2-solveAll
"d" #'agda2-infer-type-maybe-toplevel "t" #'agda2-goal-type
"e" #'agda2-show-context "w" #'agda2-why-in-scope-maybe-toplevel
"f" #'agda2-next-goal (:prefix "x"
"gG" #'agda2-go-back "c" #'agda2-compile
"h" #'agda2-helper-function-type "d" #'agda2-remove-annotations
"l" #'agda2-load "h" #'agda2-display-implicit-arguments
"n" #'agda2-compute-normalised-maybe-toplevel "q" #'agda2-quit
"p" #'agda2-module-contents-maybe-toplevel "r" #'agda2-restart))
"r" #'agda2-refine
"s" #'agda2-solveAll
"t" #'agda2-goal-type
"w" #'agda2-why-in-scope-maybe-toplevel
(:prefix "x"
"c" #'agda2-compile
"d" #'agda2-remove-annotations
"h" #'agda2-display-implicit-arguments
"q" #'agda2-quit
"r" #'agda2-restart)))

View file

@ -1,5 +0,0 @@
;; -*- lexical-binding: t; no-byte-compile: t; -*-
;;; lang/agda/doctor.el
(unless (executable-find "agda-mode")
(warn! "Couldn't find agda-mode. Agda support won't work"))

View file

@ -0,0 +1,15 @@
;; -*- no-byte-compile: t; -*-
;;; lang/agda/packages.el
(package! agda-input
:recipe
(:host github :repo "agda/agda"
:files ("src/data/emacs-mode/agda-input.el")))
(package! agda2-mode
:recipe
(:host github :repo "agda/agda"
:files
("src/data/emacs-mode/*.el"
(:exclude "agda-input.el"))))

View file

@ -11,6 +11,7 @@
- [[#irony-server][irony-server]] - [[#irony-server][irony-server]]
- [[#macos][MacOS]] - [[#macos][MacOS]]
- [[#arch-linux][Arch Linux]] - [[#arch-linux][Arch Linux]]
- [[#opensuse][openSUSE]]
- [[#rtags][rtags]] - [[#rtags][rtags]]
- [[#configure][Configure]] - [[#configure][Configure]]
- [[#project-compile-settings][Project compile settings]] - [[#project-compile-settings][Project compile settings]]
@ -93,6 +94,11 @@ rm -rf irony-mode
pacman -S clang cmake pacman -S clang cmake
#+END_SRC #+END_SRC
*** openSUSE
#+BEGIN_SRC sh :dir /sudo::
sudo zypper install clang cmake
#+END_SRC
** rtags ** rtags
Code navigation requires an [[https://github.com/Andersbakken/rtags][rtags]] server (~rdm~) installed. This should be Code navigation requires an [[https://github.com/Andersbakken/rtags][rtags]] server (~rdm~) installed. This should be
available through your OS's package manager. available through your OS's package manager.

View file

@ -103,7 +103,7 @@ simpler."
(rtags-call-rc :silent t "-J" (or (doom-project-root) default-directory)))) (rtags-call-rc :silent t "-J" (or (doom-project-root) default-directory))))
;; then irony ;; then irony
(when (and (featurep 'irony) irony-mode) (when (and (featurep 'irony) irony-mode)
(+cc|irony-init-compile-options))) (+cc-init-irony-compile-options-h)))
;;;###autoload ;;;###autoload
(defun +cc/imenu () (defun +cc/imenu ()

View file

@ -1,22 +1,22 @@
;;; lang/clojure/config.el -*- lexical-binding: t; -*- ;;; lang/clojure/config.el -*- lexical-binding: t; -*-
;;;###package clojure-mode (after! clojure-mode
(add-hook 'clojure-mode-hook #'rainbow-delimiters-mode) (add-hook 'clojure-mode-hook #'rainbow-delimiters-mode)
(set-repl-handler! 'clojure-mode #'+clojure/repl)
(set-eval-handler! 'clojure-mode #'cider-eval-region))
(use-package! cider (use-package! cider
;; NOTE: if you don't have an org directory set (the dir doesn't exist), ;; NOTE: if you don't have an org directory set (the dir doesn't exist),
;; cider jack in won't work. ;; cider jack in won't work.
:commands (cider-jack-in cider-jack-in-clojurescript) :commands cider-jack-in cider-jack-in-clojurescript
:hook (clojure-mode-local-vars . cider-mode) :hook (clojure-mode-local-vars . cider-mode)
:init :config
(set-repl-handler! 'clojure-mode #'+clojure/repl) (add-hook 'cider-mode-hook #'eldoc-mode)
(set-eval-handler! 'clojure-mode #'cider-eval-region)
(set-lookup-handlers! 'cider-mode (set-lookup-handlers! 'cider-mode
:definition #'+clojure-cider-lookup-definition :definition #'+clojure-cider-lookup-definition
:documentation #'cider-doc) :documentation #'cider-doc)
(add-hook 'cider-mode-hook #'eldoc-mode)
:config
(set-popup-rules! (set-popup-rules!
'(("^\\*cider-error*" :ignore t) '(("^\\*cider-error*" :ignore t)
("^\\*cider-repl" :quit nil) ("^\\*cider-repl" :quit nil)
@ -134,10 +134,9 @@
(use-package! clj-refactor (use-package! clj-refactor
:hook (clojure-mode . clj-refactor-mode) :hook (clojure-mode . clj-refactor-mode)
:init :config
(set-lookup-handlers! 'clj-refactor-mode (set-lookup-handlers! 'clj-refactor-mode
:references #'cljr-find-usages) :references #'cljr-find-usages)
:config
(map! :map clojure-mode-map (map! :map clojure-mode-map
:localleader :localleader
:desc "refactor" "R" #'hydra-cljr-help-menu/body)) :desc "refactor" "R" #'hydra-cljr-help-menu/body))

View file

@ -1,4 +1,15 @@
;;; lang/coq/autoload.el -*- lexical-binding: t; -*- ;;; lang/coq/autoload.el -*- lexical-binding: t; -*-
;; HACK `proof-general' ascertains its own library path at compile time in its
;; autoloads file using `byte-compile-current-file' (and stores it in
;; `pg-init--script-full-path'). This means that when
;; `doom-package-autoload-file' is created and byte-compiled,
;; `pg-init--script-full-path' will be wrong, causing file-missing errors as it
;; tries to load `proof-site'. We prevent this by defining these two variables
;; early, in our own autoloads file.
;;;###autoload
(setq pg-init--script-full-path (locate-library "proof-general")
pg-init--pg-root (file-name-directory pg-init--script-full-path))
;;;###autoload ;;;###autoload
(add-hook 'coq-mode-hook #'company-coq-mode) (add-hook 'coq-mode-hook #'company-coq-mode)

View file

@ -7,6 +7,45 @@
;; library included with Doom). ;; library included with Doom).
(setq coq-mode-abbrev-table '()) (setq coq-mode-abbrev-table '())
(map! :after coq-mode
:map coq-mode-map
:localleader
"]" #'proof-assert-next-command-interactive
"[" #'proof-undo-last-successful-command
"." #'proof-goto-point
(:prefix ("l" . "layout")
"c" #'pg-response-clear-displays
"l" #'proof-layout-windows
"p" #'proof-prf)
(:prefix ("p" . "proof")
"i" #'proof-interrupt-process
"p" #'proof-process-buffer
"q" #'proof-shell-exit
"r" #'proof-retract-buffer)
(:prefix ("a" . "about/print/check")
"a" #'coq-Print
"A" #'coq-Print-with-all
"b" #'coq-About
"B" #'coq-About-with-all
"c" #'coq-Check
"C" #'coq-Check-show-all
"f" #'proof-find-theorems
(:prefix ("i" . "implicits")
"b" #'coq-About-with-implicits
"c" #'coq-Check-show-implicits
"i" #'coq-Print-with-implicits))
(:prefix ("g" . "goto")
"e" #'proof-goto-command-end
"l" #'proof-goto-end-of-locked
"s" #'proof-goto-command-start)
(:prefix ("i" . "insert")
"c" #'coq-insert-command
"e" #'coq-end-Section
"i" #'coq-insert-intros
"r" #'coq-insert-requires
"s" #'coq-insert-section-or-module
"t" #'coq-insert-tactic
"T" #'coq-insert-tactical))
(after! company-coq (after! company-coq
(set-popup-rule! "^\\*\\(?:response\\|goals\\)\\*" :ignore t) (set-popup-rule! "^\\*\\(?:response\\|goals\\)\\*" :ignore t)
@ -15,4 +54,15 @@
:references #'company-coq-grep-symbol :references #'company-coq-grep-symbol
:documentation #'company-coq-doc) :documentation #'company-coq-doc)
(unless (featurep! :completion company) (unless (featurep! :completion company)
(setq company-coq-disabled-features '(company company-defaults)))) (setq company-coq-disabled-features '(company company-defaults)))
(map! :map coq-mode-map
:localleader
(:prefix ("i" . "insert")
"l" #'company-coq-lemma-from-goal
"m" #'company-coq-insert-match-construct)
"ao" #'company-coq-occur
(:prefix ("h" . "help")
"e" #'company-coq-document-error
"E" #'company-coq-browse-error-messages
"h" #'company-coq-doc)))

View file

@ -1,28 +1,39 @@
#+TITLE: :lang csharp #+TITLE: :lang csharp
This module adds C# support to Emacs.
#+begin_quote
I don't use C# for much else than Unity3D and, seldomly, for Mono game
development on Linux.
#+end_quote
* Table of Contents :TOC: * Table of Contents :TOC:
- [[Install][Install]] - [[#description][Description]]
- [[MacOS][MacOS]] - [[#module-flags][Module Flags]]
- [[Arch Linux][Arch Linux]] - [[#plugins][Plugins]]
- [[#prerequisites][Prerequisites]]
- [[#macos][MacOS]]
- [[#arch-linux][Arch Linux]]
- [[#nixos][NixOS]]
* Install * Description
This module adds C# support to Emacs. Powered by omnisharp (directly or through
LSP).
** Module Flags
+ =+lsp= Enables omnisharp through LSP support (requires omnisharp).
+ =+unity= Enables special support for the [[https://unity.com/][Unity game engine]] (particularly,
support for HLSL shaders).
** Plugins
+ [[https://github.com/josteink/csharp-mode][csharp-mode]]
+ [[https://github.com/OmniSharp/omnisharp-emacs][omnisharp]]* (not =+lsp=)
+ [[https://github.com/midnightSuyama/shader-mode][shader-mode]]* (=+unity=)
* Prerequisites
This module needs: This module needs:
+ omnisharp-roslyn (install with ~M-x omnisharp-install-server~) + omnisharp (with the ~+lsp~ flag, this must be installed externally. Without
it, use ~M-x omnisharp-install-server~)
+ .NET SDKs (on Windows) + .NET SDKs (on Windows)
+ Mono (on UNIX platforms) + Mono (on UNIX platforms)
** MacOS ** TODO MacOS
=TODO=
** Arch Linux ** Arch Linux
#+BEGIN_SRC sh :dir /sudo:: :tangle (if (doom-system-os 'arch) "yes") #+BEGIN_SRC sh
sudo pacman --needed --noconfirm -S mono sudo pacman --needed --noconfirm -S mono
#+END_SRC #+END_SRC
** TODO NixOS

View file

@ -3,6 +3,9 @@
(after! csharp-mode (after! csharp-mode
(add-hook 'csharp-mode-hook #'rainbow-delimiters-mode) (add-hook 'csharp-mode-hook #'rainbow-delimiters-mode)
(when (featurep! +lsp)
(add-hook 'csharp-mode-local-vars-hook #'lsp!))
(set-electric! 'csharp-mode :chars '(?\n ?\})) (set-electric! 'csharp-mode :chars '(?\n ?\}))
(set-rotate-patterns! 'csharp-mode (set-rotate-patterns! 'csharp-mode
:symbols '(("public" "protected" "private") :symbols '(("public" "protected" "private")
@ -13,6 +16,7 @@
(use-package! omnisharp (use-package! omnisharp
:unless (featurep! +lsp)
:hook (csharp-mode . omnisharp-mode) :hook (csharp-mode . omnisharp-mode)
:commands omnisharp-install-server :commands omnisharp-install-server
:preface :preface
@ -56,9 +60,10 @@
"b" #'omnisharp-unit-test-buffer))) "b" #'omnisharp-unit-test-buffer)))
;;;###package shader-mode
(when (featurep! +unity) (when (featurep! +unity)
;; `shader-mode' --- unity shaders ;; Unity shaders
(add-to-list 'auto-mode-alist '("\\.shader$" . shader-mode)) (add-to-list 'auto-mode-alist '("\\.shader\\'" . shader-mode))
(def-project-mode! +csharp-unity-mode (def-project-mode! +csharp-unity-mode
:modes '(csharp-mode shader-mode) :modes '(csharp-mode shader-mode)

View file

@ -2,7 +2,9 @@
;;; lang/csharp/packages.el ;;; lang/csharp/packages.el
(package! csharp-mode) (package! csharp-mode)
(package! omnisharp)
(unless (featurep! +lsp)
(package! omnisharp))
(when (featurep! +unity) (when (featurep! +unity)
(package! shader-mode)) (package! shader-mode))

View file

@ -18,7 +18,7 @@
;; ;;
;;; Third-party plugins ;;; Third-party plugins
;; `csv-mode' ;;;###package csv-mode
(map! :after csv-mode (map! :after csv-mode
:localleader :localleader
:map csv-mode-map :map csv-mode-map
@ -37,13 +37,12 @@
:config :config
(set-electric! 'json-mode :chars '(?\n ?: ?{ ?}))) (set-electric! 'json-mode :chars '(?\n ?: ?{ ?})))
(use-package! jsonnet-mode (after! jsonnet-mode
:defer t
:config
(set-electric! 'jsonnet-mode :chars '(?\n ?: ?{ ?}))) (set-electric! 'jsonnet-mode :chars '(?\n ?: ?{ ?})))
;; ;;
;; Frameworks ;;; Frameworks
(def-project-mode! +data-vagrant-mode (def-project-mode! +data-vagrant-mode
:files ("Vagrantfile")) :files ("Vagrantfile"))

View file

@ -11,6 +11,7 @@
- [[#with-asdf][With ~asdf~]] - [[#with-asdf][With ~asdf~]]
- [[#arch-linux][Arch Linux]] - [[#arch-linux][Arch Linux]]
- [[#gentoo-linux][Gentoo Linux]] - [[#gentoo-linux][Gentoo Linux]]
- [[#opensuse][openSUSE]]
- [[#features][Features]] - [[#features][Features]]
* Description * Description
@ -47,6 +48,11 @@ sudo pacman -S elixir
#+BEGIN_SRC sh :dir /sudo:: #+BEGIN_SRC sh :dir /sudo::
sudo emerge -v dev-lang/elixir sudo emerge -v dev-lang/elixir
#+END_SRC #+END_SRC
*** openSUSE
#+BEGIN_SRC sh :dir /sudo::
sudo zypper install elixir
#+END_SRC
* Features * Features
- Code completion (~:completion company~) - Code completion (~:completion company~)
- Documentation lookup (~:tools lookup~) - Documentation lookup (~:tools lookup~)

View file

@ -32,18 +32,6 @@
(when (featurep! +lsp) (when (featurep! +lsp)
(add-hook 'elixir-mode-local-vars-hook #'lsp!)) (add-hook 'elixir-mode-local-vars-hook #'lsp!))
(use-package! alchemist-company
:when (featurep! :completion company)
:commands alchemist-company
:init
(set-company-backend! 'elixir-mode '(alchemist-company company-yasnippet))
:config
;; Alchemist doesn't use hook symbols to add these backends, so we have to
;; use the entire closure to get rid of it.
(let ((fn (byte-compile (lambda () (add-to-list (make-local-variable 'company-backends) 'alchemist-company)))))
(remove-hook 'alchemist-mode-hook fn)
(remove-hook 'alchemist-iex-mode-hook fn)))
(use-package! flycheck-credo (use-package! flycheck-credo
:when (featurep! :tools flycheck) :when (featurep! :tools flycheck)
:config (flycheck-credo-setup))) :config (flycheck-credo-setup)))
@ -51,9 +39,24 @@
(use-package! alchemist (use-package! alchemist
:hook (elixir-mode . alchemist-mode) :hook (elixir-mode . alchemist-mode)
:init
(after! elixir-mode
(set-lookup-handlers! 'elixir-mode
:definition #'alchemist-goto-definition-at-point
:documentation #'alchemist-help-search-at-point)
(set-eval-handler! 'elixir-mode #'alchemist-eval-region)
(set-repl-handler! 'elixir-mode #'alchemist-iex-project-run)))
(use-package! alchemist-company
:when (featurep! :completion company)
:commands alchemist-company
:init
(after! elixir-mode
(set-company-backend! 'elixir-mode '(alchemist-company company-yasnippet)))
:config :config
(set-lookup-handlers! 'elixir-mode ;; Alchemist doesn't use hook symbols to add these backends, so we have to use
:definition #'alchemist-goto-definition-at-point ;; the entire closure to get rid of it.
:documentation #'alchemist-help-search-at-point) (let ((fn (byte-compile (lambda () (add-to-list (make-local-variable 'company-backends) 'alchemist-company)))))
(set-eval-handler! 'elixir-mode #'alchemist-eval-region) (remove-hook 'alchemist-mode-hook fn)
(set-repl-handler! 'elixir-mode #'alchemist-iex-project-run)) (remove-hook 'alchemist-iex-mode-hook fn)))

View file

@ -1,8 +1,5 @@
;;; lang/elm/config.el -*- lexical-binding: t; -*- ;;; lang/elm/config.el -*- lexical-binding: t; -*-
;; `elm-mode'
(setq elm-format-on-save t)
(after! elm-mode (after! elm-mode
(add-hook 'elm-mode-hook #'rainbow-delimiters-mode) (add-hook 'elm-mode-hook #'rainbow-delimiters-mode)

View file

@ -135,7 +135,7 @@ if it's callable, `apropos' otherwise."
`(("Section" "^[ \t]*;;;;*[ \t]+\\([^\n]+\\)" 1) `(("Section" "^[ \t]*;;;;*[ \t]+\\([^\n]+\\)" 1)
("Evil commands" "^\\s-*(evil-define-\\(?:command\\|operator\\|motion\\) +\\(\\_<[^ ()\n]+\\_>\\)" 1) ("Evil commands" "^\\s-*(evil-define-\\(?:command\\|operator\\|motion\\) +\\(\\_<[^ ()\n]+\\_>\\)" 1)
("Unit tests" "^\\s-*(\\(?:ert-deftest\\|describe\\) +\"\\([^\")]+\\)\"" 1) ("Unit tests" "^\\s-*(\\(?:ert-deftest\\|describe\\) +\"\\([^\")]+\\)\"" 1)
("Package" "^\\s-*(\\(?:;;;###package\\|def-package!\\|package!\\|use-package\\|after!\\) +\\(\\_<[^ ()\n]+\\_>\\)" 1) ("Package" "^\\s-*(\\(?:;;;###package\\|package!\\|use-package!?\\|after!\\) +\\(\\_<[^ ()\n]+\\_>\\)" 1)
("Major modes" "^\\s-*(define-derived-mode +\\([^ ()\n]+\\)" 1) ("Major modes" "^\\s-*(define-derived-mode +\\([^ ()\n]+\\)" 1)
("Minor modes" "^\\s-*(define-\\(?:global\\(?:ized\\)?-minor\\|generic\\|minor\\)-mode +\\([^ ()\n]+\\)" 1) ("Minor modes" "^\\s-*(define-\\(?:global\\(?:ized\\)?-minor\\|generic\\|minor\\)-mode +\\([^ ()\n]+\\)" 1)
("Modelines" "^\\s-*(def-modeline! +\\([^ ()\n]+\\)" 1) ("Modelines" "^\\s-*(def-modeline! +\\([^ ()\n]+\\)" 1)
@ -174,3 +174,15 @@ verbosity when editing a file in `doom-private-dir' or `doom-emacs-dir'."
" " " "
(default-value 'flycheck-emacs-lisp-check-form) (default-value 'flycheck-emacs-lisp-check-form)
")")))) ")"))))
;;;###autoload
(defun +emacs-lisp/edebug-instrument-defun-on ()
"Toggle on instrumentalisation for the function under `defun'."
(interactive)
(eval-defun 'edebugit))
;;;###autoload
(defun +emacs-lisp/edebug-instrument-defun-off ()
"Toggle off instrumentalisation for the function under `defun'."
(interactive)
(eval-defun nil))

View file

@ -77,8 +77,10 @@ This marks a foldable marker for `outline-minor-mode' in elisp buffers.")
(map! :localleader (map! :localleader
:map emacs-lisp-mode-map :map emacs-lisp-mode-map
"e" #'macrostep-expand)) "e" #'macrostep-expand
(:prefix ("d" . "debug")
("f" #'+emacs-lisp/edebug-instrument-defun-on)
("F" #'+emacs-lisp/edebug-instrument-defun-off))))
;; ;;
;;; Packages ;;; Packages
@ -112,8 +114,20 @@ This marks a foldable marker for `outline-minor-mode' in elisp buffers.")
"Add Doom's own demos to help buffers." "Add Doom's own demos to help buffers."
:around #'elisp-demos--search :around #'elisp-demos--search
(or (funcall orig-fn symbol) (or (funcall orig-fn symbol)
(when-let* ((elisp-demos--elisp-demos.org (doom-glob doom-docs-dir "api.org"))) (when-let (demos-file (doom-glob doom-docs-dir "api.org"))
(funcall orig-fn symbol))))) (with-temp-buffer
(insert-file-contents demos-file)
(goto-char (point-min))
(when (re-search-forward
(format "^\\*\\*\\* %s$" (regexp-quote (symbol-name symbol)))
nil t)
(let (beg end)
(forward-line 1)
(setq beg (point))
(if (re-search-forward "^\\*" nil t)
(setq end (line-beginning-position))
(setq end (point-max)))
(string-trim (buffer-substring-no-properties beg end)))))))))
(use-package! buttercup (use-package! buttercup

View file

@ -1,9 +1,9 @@
;;; lang/erlang/config.el -*- lexical-binding: t; -*- ;;; lang/erlang/config.el -*- lexical-binding: t; -*-
(use-package! erlang (use-package! erlang
:mode ("\\.erlang$" . erlang-mode) :mode ("\\.erlang\\'" . erlang-mode)
:mode ("/rebar\\.config\\(?:\\.script\\)?$" . erlang-mode) :mode ("/rebar\\.config\\(?:\\.script\\)?\\'" . erlang-mode)
:mode ("/\\(?:app\\|sys\\)\\.config$" . erlang-mode)) :mode ("/\\(?:app\\|sys\\)\\.config\\'" . erlang-mode))
(use-package! flycheck-rebar3 (use-package! flycheck-rebar3

View file

@ -1,7 +1,7 @@
;;; lang/ess/config.el -*- lexical-binding: t; -*- ;;; lang/ess/config.el -*- lexical-binding: t; -*-
(use-package! ess (use-package! ess
:commands (stata SAS) :commands stata SAS
:init :init
(setq ess-smart-S-assign-key nil) (setq ess-smart-S-assign-key nil)
(unless (featurep! :lang julia) (unless (featurep! :lang julia)

View file

@ -4,15 +4,15 @@
#+STARTUP: inlineimages #+STARTUP: inlineimages
* Table of Contents :TOC: * Table of Contents :TOC:
- [[Description][Description]] - [[#description][Description]]
- [[Module Flags][Module Flags]] - [[#module-flags][Module Flags]]
- [[Plugins][Plugins]] - [[#plugins][Plugins]]
- [[Prerequisites][Prerequisites]] - [[#prerequisites][Prerequisites]]
- [[Go][Go]] - [[#go][Go]]
- [[Dependencies][Dependencies]] - [[#dependencies][Dependencies]]
- [[Features][Features]] - [[#features][Features]]
- [[Configuration][Configuration]] - [[#configuration][Configuration]]
- [[Troubleshooting][Troubleshooting]] - [[#troubleshooting][Troubleshooting]]
* Description * Description
This module adds [[https://golang.org][Go]] support. This module adds [[https://golang.org][Go]] support.
@ -35,6 +35,7 @@ This module provides no flags.
+ [[https://github.com/syohex/emacs-go-eldoc][go-eldoc]] + [[https://github.com/syohex/emacs-go-eldoc][go-eldoc]]
+ [[https://github.com/dominikh/go-mode.el][go-guru]] + [[https://github.com/dominikh/go-mode.el][go-guru]]
+ [[https://github.com/manute/gorepl-mode][gorepl-mode]] + [[https://github.com/manute/gorepl-mode][gorepl-mode]]
+ [[https://github.com/syohex/emacs-go-add-tags][go-add-tags]]
+ [[https://github.com/mdempsky/gocode][company-go]]* + [[https://github.com/mdempsky/gocode][company-go]]*
* Prerequisites * Prerequisites
@ -51,6 +52,11 @@ brew install go
sudo pacman -S go sudo pacman -S go
#+END_SRC #+END_SRC
*** openSUSE
#+BEGIN_SRC sh :dir /sudo::
sudo zypper install go
#+END_SRC
** Dependencies ** Dependencies
This module requires a valid ~GOPATH~, and the following Go packages: This module requires a valid ~GOPATH~, and the following Go packages:

View file

@ -6,17 +6,21 @@
(defvar +go-test-last nil (defvar +go-test-last nil
"The last test run.") "The last test run.")
(defun +go--run-tests (args) (defun +go--spawn (cmd)
(require 'async)
(save-selected-window (save-selected-window
(async-shell-command (concat "go test " args)))) (compile cmd)))
(defun +go--run-tests (args)
(let ((cmd (concat "go test " args)))
(setq +go-test-last (concat "cd " default-directory ";" cmd))
(+go--spawn cmd)))
;;;###autoload ;;;###autoload
(defun +go/test-rerun () (defun +go/test-rerun ()
(interactive) (interactive)
(if +go-test-last (if +go-test-last
(funcall +go-test-last) (+go--spawn +go-test-last)
(+go/run-all-tests))) (+go/test-all)))
;;;###autoload ;;;###autoload
(defun +go/test-all () (defun +go/test-all ()

View file

@ -1,7 +1,7 @@
;;; lang/go/config.el -*- lexical-binding: t; -*- ;;; lang/go/config.el -*- lexical-binding: t; -*-
;; ;;
;; Packages ;;; Packages
(after! go-mode (after! go-mode
(set-docsets! 'go-mode "Go") (set-docsets! 'go-mode "Go")
@ -25,6 +25,7 @@
(map! :map go-mode-map (map! :map go-mode-map
:localleader :localleader
"a" #'go-add-tags
"e" #'+go/play-buffer-or-region "e" #'+go/play-buffer-or-region
"i" #'go-goto-imports ; Go to imports "i" #'go-goto-imports ; Go to imports
(:prefix ("h" . "help") (:prefix ("h" . "help")
@ -58,8 +59,8 @@
(use-package! company-go (use-package! company-go
:when (and (featurep! :completion company) :when (featurep! :completion company)
(not (featurep! +lsp))) :unless (featurep! +lsp)
:after go-mode :after go-mode
:config :config
(set-company-backend! 'go-mode 'company-go) (set-company-backend! 'go-mode 'company-go)

View file

@ -5,6 +5,7 @@
(package! go-guru) (package! go-guru)
(package! go-mode) (package! go-mode)
(package! gorepl-mode) (package! gorepl-mode)
(package! go-add-tags)
(when (featurep! :completion company) (when (featurep! :completion company)
(package! company-go)) (package! company-go))

Some files were not shown because too many files have changed in this diff Show more