dev: merge branch 'master' of github.com:doomemacs

This commit is contained in:
Matt Nish-Lapidus 2024-09-12 11:08:58 -04:00
commit a2ae771393
36 changed files with 792 additions and 241 deletions

View file

@ -164,7 +164,7 @@ EXIT CODES:
5 Invalid, missing, or extra options/arguments 5 Invalid, missing, or extra options/arguments
6-15 Reserved for Doom 6-15 Reserved for Doom
16-192 Reserved for the user's extensions 16-192 Reserved for the user's extensions
254 Successful run (but then execute `doom-cli-restart-script') 254 Successful run (then execute the dynamically generated after-script)
255 Uncaught critical errors 255 Uncaught critical errors
SEE ALSO: SEE ALSO:

View file

@ -22,7 +22,16 @@ fi
case "$EMACS" in case "$EMACS" in
*term*) EMACS=emacs ;; # in {ansi-,v}term *term*) EMACS=emacs ;; # in {ansi-,v}term
*) EMACS="${EMACS:-emacs}" ;; *\ *) ;;
*) EMACS="${EMACS:-emacs}"
# Only sanity-check $EMACS if it's a path or executable
if ! type "$EMACS" >/dev/null 2>&1; then
echo "Error: failed to run Emacs with command '$EMACS'"
echo
echo "Are you sure Emacs is installed and in your \$PATH?"
exit 1
fi >&2
;;
esac esac
# Careful not to use -Q! It implies --no-site-lisp, which omits the site-lisp # Careful not to use -Q! It implies --no-site-lisp, which omits the site-lisp
@ -31,17 +40,6 @@ esac
# (like Snap or NixOS). # (like Snap or NixOS).
emacs="$EMACS -q --no-site-file --batch" emacs="$EMACS -q --no-site-file --batch"
# $TMPDIR (or $TEMP and $TMP on Windows) aren't guaranteed to have values, and
# mktemp isn't available on all systems, but you know what is? Emacs! So I rely
# on it to provide TMPDIR. And can second as a quick existence check for Emacs.
TMPDIR="${TMPDIR:-$($emacs --eval '(princ (temporary-file-directory))' 2>/dev/null)}"
if [ -z "$TMPDIR" ]; then
echo "Error: failed to run Emacs with command '$EMACS'"
echo
echo "Are you sure Emacs is installed and in your \$PATH?"
exit 1
fi >&2
# Doom respects $EMACSDIR to tell it where Doom lives. If it fails, then this is # Doom respects $EMACSDIR to tell it where Doom lives. If it fails, then this is
# either isn't bash, or it's a posix shell being directly sourced with sh, which # either isn't bash, or it's a posix shell being directly sourced with sh, which
# is unsupported. # is unsupported.
@ -79,6 +77,11 @@ exit=$?
# To simulate execve syscalls (which replaces the running process), Doom # To simulate execve syscalls (which replaces the running process), Doom
# generates a temporary exit-script if a Doomscript returns a 254 exit code. # generates a temporary exit-script if a Doomscript returns a 254 exit code.
if [ "${exit:-0}" -eq 254 ]; then if [ "${exit:-0}" -eq 254 ]; then
# $TMPDIR (or $TEMP and $TMP on Windows) aren't guaranteed to have values,
# and mktemp isn't available on all systems, but you know what is? Emacs! So
# I rely on it to provide TMPDIR.
export TMPDIR="${TMPDIR:-${TMP:-${TEMP:-$($emacs -Q --eval '(princ (temporary-file-directory))' 2>/dev/null)}}}"
# The user may have a noexec flag set on /tmp, so the exit-script should be # The user may have a noexec flag set on /tmp, so the exit-script should be
# passed to /bin/sh rather than executed directly. # passed to /bin/sh rather than executed directly.
sh "${TMPDIR}/doom.${__DOOMPID}.${__DOOMSTEP}.sh" "$0" "$@" sh "${TMPDIR}/doom.${__DOOMPID}.${__DOOMSTEP}.sh" "$0" "$@"

View file

@ -105,38 +105,37 @@
;; To reduce that burden -- and since Doom doesn't load any dynamic modules ;; To reduce that burden -- and since Doom doesn't load any dynamic modules
;; this early -- I remove `.so' from `load-suffixes' and pass the ;; this early -- I remove `.so' from `load-suffixes' and pass the
;; `must-suffix' arg to `load'. See the docs of `load' for details. ;; `must-suffix' arg to `load'. See the docs of `load' for details.
(if (let ((load-suffixes '(".elc" ".el"))) (if (let ((load-suffixes '(".elc" ".el"))
(doom-file (expand-file-name "lisp/doom" user-emacs-directory)))
;; I avoid `load's NOERROR argument because it suppresses other, ;; I avoid `load's NOERROR argument because it suppresses other,
;; legitimate errors (like permission or IO errors), which gets ;; legitimate errors (like permission or IO errors), which gets
;; incorrectly interpreted as "this is not a Doom config". ;; incorrectly interpreted as "this is not a Doom config".
(condition-case-unless-debug _ (if (file-exists-p (concat doom-file ".el"))
;; Load the heart of Doom Emacs. ;; Load the heart of Doom Emacs.
(load (expand-file-name "lisp/doom" user-emacs-directory) (load doom-file nil (not init-file-debug) nil 'must-suffix)
nil (not init-file-debug) nil 'must-suffix) ;; Failing that, assume we're loading a non-Doom config...
;; Failing that, assume that we're loading a non-Doom config. ;; HACK: `startup--load-user-init-file' resolves $EMACSDIR from a
(file-missing ;; lexical (and so, not-trivially-modifiable)
;; HACK: `startup--load-user-init-file' resolves $EMACSDIR from a ;; `startup-init-directory', so Emacs will fail to locate the
;; lexical (and so, not-trivially-modifiable) ;; correct $EMACSDIR/init.el without help.
;; `startup-init-directory', so Emacs will fail to locate the (define-advice startup--load-user-init-file (:filter-args (args) reroute-to-profile)
;; correct $EMACSDIR/init.el without help. (list (lambda () (expand-file-name "init.el" user-emacs-directory))
(define-advice startup--load-user-init-file (:filter-args (args) reroute-to-profile) nil (nth 2 args)))
(list (lambda () (expand-file-name "init.el" user-emacs-directory)) ;; (Re)set `user-init-file' for the `load' call further below, and do
nil (nth 2 args))) ;; so here while our `file-name-handler-alist' optimization is still
;; (Re)set `user-init-file' for the `load' call further below, and ;; effective (benefits `expand-file-name'). BTW: Emacs resets
;; do so here while our `file-name-handler-alist' optimization is ;; `user-init-file' and `early-init-file' after this file is loaded.
;; still effective (benefits `expand-file-name'). BTW: Emacs resets (setq user-init-file (expand-file-name "early-init" user-emacs-directory))
;; `user-init-file' and `early-init-file' after this file is loaded. ;; COMPAT: I make no assumptions about the config we're going to
(setq user-init-file (expand-file-name "early-init" user-emacs-directory)) ;; load, so undo this file's global side-effects.
;; COMPAT: I make no assumptions about the config we're going to (setq load-prefer-newer t)
;; load, so undo this file's global side-effects. ;; PERF: But make an exception for `gc-cons-threshold', which I think
(setq load-prefer-newer t) ;; all Emacs users and configs will benefit from. Still, setting it
;; PERF: But make an exception for `gc-cons-threshold', which I ;; to `most-positive-fixnum' is dangerous if downstream does not
;; think all Emacs users and configs will benefit from. Still, ;; reset it later to something reasonable, so I use 16mb as a best
;; setting it to `most-positive-fixnum' is dangerous if downstream ;; fit guess. It's better than Emacs' 80kb default.
;; does not reset it later to something reasonable, so I use 16mb (setq gc-cons-threshold (* 16 1024 1024))
;; as a best fit guess. It's better than Emacs' 80kb default. nil))
(setq gc-cons-threshold (* 16 1024 1024))
nil)))
;; ...Otherwise, we're loading a Doom config, so continue as normal. ;; ...Otherwise, we're loading a Doom config, so continue as normal.
(doom-require (if noninteractive 'doom-cli 'doom-start)))) (doom-require (if noninteractive 'doom-cli 'doom-start))))

View file

@ -43,7 +43,7 @@ performance, it is best to run Doom out of ~/.config/emacs or ~/.emacs.d."
;; Evaluate piped-in text directly, if given. ;; Evaluate piped-in text directly, if given.
(eval (read input) t) (eval (read input) t)
(doom-run-repl context)) (doom-run-repl context))
(let* ((tempdir (doom-path (temporary-file-directory) "doom.run")) (let* ((tempdir (doom-path (temporary-file-directory) "doom.run"))
(tempemacsdir (doom-path tempdir ".emacs.d"))) (tempemacsdir (doom-path tempdir ".emacs.d")))
(delete-directory tempdir t) ; start from scratch (delete-directory tempdir t) ; start from scratch
(make-directory tempemacsdir t) (make-directory tempemacsdir t)
@ -51,18 +51,20 @@ performance, it is best to run Doom out of ~/.config/emacs or ~/.emacs.d."
;; configs, or binscripts, we symlink these to the sandbox. ;; configs, or binscripts, we symlink these to the sandbox.
;; REVIEW: Use `--init-directory' when we drop 29 support OR when Doom is ;; REVIEW: Use `--init-directory' when we drop 29 support OR when Doom is
;; in bootloader mode. ;; in bootloader mode.
(dolist (dir (list (or (getenv "XDG_DATA_HOME") "~/.local/share") (dolist (dir (list (cons "XDG_DATA_HOME" ".local/share")
(or (getenv "XDG_BIN_HOME") "~/.local/bin") (cons "XDG_STATE_HOME" ".local/state")
(or (getenv "XDG_CONFIG_HOME") "~/.config") (cons "XDG_BIN_HOME" ".local/bin")
(or (getenv "XDG_CACHE_HOME") "~/.cache"))) (cons "XDG_CONFIG_HOME" ".config")
(let* ((xdg-dir (doom-path dir)) (cons "XDG_CACHE_HOME" ".cache")))
(target (doom-path tempdir (file-relative-name xdg-dir "~")))) (let* ((source (expand-file-name (or (getenv (car dir)) (expand-file-name (cdr dir) "~"))))
(when (file-directory-p xdg-dir) (target (expand-file-name (cdr dir) tempdir)))
(when (file-directory-p source)
(unless (file-symlink-p target) (unless (file-symlink-p target)
(make-directory (file-name-directory target) t) (make-directory (file-name-directory target) t)
(make-symbolic-link xdg-dir target))))) (make-symbolic-link source target)))))
(with-temp-file (doom-path tempemacsdir "early-init.el") (with-temp-file (doom-path tempemacsdir "early-init.el")
(prin1 `(progn (prin1 `(progn
;; Restore sane values for these envvars
(setenv "HOME" ,(getenv "HOME")) (setenv "HOME" ,(getenv "HOME"))
(setenv "EMACSDIR" ,doom-emacs-dir) (setenv "EMACSDIR" ,doom-emacs-dir)
(setenv "DOOMDIR" ,doom-user-dir) (setenv "DOOMDIR" ,doom-user-dir)

View file

@ -361,6 +361,71 @@ Or to create aliases for functions that behave differently:
(:baz hello :boop nil) (:baz hello :boop nil)
(:bar 42))) (:bar 42)))
#+end_src #+end_src
* letf!
:PROPERTIES:
:added: 3.0.0-pre
:END:
#+begin_src emacs-lisp :eval yes
(letf! (defun greet (name)
(message "Hello %s" name))
(greet "Doom")) ; #=> Hello Doom
#+end_src
#+RESULTS:
: Hello Doom
Multiple definitions:
#+begin_src emacs-lisp :eval yes :results output
(letf! ((defun greet (name)
(princ (format "Hello %s" name))
(terpri))
(defun destroy (name)
(princ (format "Blood for the %s god!" name))
(terpri)))
(greet "Doom")
(destroy "Doom"))
#+end_src
#+RESULTS:
: Hello Doom
: Blood for the Doom god!
If defining an already-existing function, the old definition will be bound to a
variable by the same name:
#+begin_src emacs-lisp :eval yes :results output
(letf! (defun princ (str)
(funcall princ (format "[overwritten] %s" str)))
(princ "Doom Emacs"))
#+end_src
#+RESULTS:
: [overwritten] Doom Emacs
Defining temporary advice:
#+begin_src emacs-lisp :eval yes
(letf! ((defun advised-message (fn message &rest args)
(apply fn (concat "[advised (1)] " message) args))
(defadvice #'message :around #'advised-message)
(defadvice message (:around (fn message &rest args))
(apply fn (concat "[advised (2)] " message) args)))
(message "Hello world"))
#+end_src
#+RESULTS:
: [advised (1)] [advised (2)] Hello world
Calling "lexical" functions recursively:
#+begin_src emacs-lisp :eval yes
(letf! (defun* triangle (number)
(cond ((<= number 0) 0)
((= number 1) 1)
((> number 1)
(+ number (triangle (1- number))))))
(triangle 5))
#+end_src
#+RESULTS:
: 15
* load! * load!
:PROPERTIES: :PROPERTIES:

View file

@ -1877,7 +1877,6 @@ errors to `doom-cli-error-file')."
(error "Cannot nest `run!' calls")) (error "Cannot nest `run!' calls"))
(doom-run-hooks 'doom-after-init-hook) (doom-run-hooks 'doom-after-init-hook)
(doom-context-with 'cli (doom-context-with 'cli
;; (doom-modules-initialize)
(let* ((args (flatten-list args)) (let* ((args (flatten-list args))
(context (make-doom-cli-context :prefix prefix :whole args)) (context (make-doom-cli-context :prefix prefix :whole args))
(doom-cli--context context) (doom-cli--context context)

View file

@ -7,6 +7,7 @@
(define-error 'doom-font-error "Could not find a font on your system" 'doom-error) (define-error 'doom-font-error "Could not find a font on your system" 'doom-error)
(define-error 'doom-nosync-error "Doom hasn't been initialized yet; did you remember to run 'doom sync' in the shell?" 'doom-error) (define-error 'doom-nosync-error "Doom hasn't been initialized yet; did you remember to run 'doom sync' in the shell?" 'doom-error)
(define-error 'doom-core-error "Unexpected error in Doom's core" 'doom-error) (define-error 'doom-core-error "Unexpected error in Doom's core" 'doom-error)
(define-error 'doom-context-error "Incorrect context error" 'doom-error)
(define-error 'doom-hook-error "Error in a Doom startup hook" 'doom-error) (define-error 'doom-hook-error "Error in a Doom startup hook" 'doom-error)
(define-error 'doom-autoload-error "Error in Doom's autoloads file" 'doom-error) (define-error 'doom-autoload-error "Error in Doom's autoloads file" 'doom-error)
(define-error 'doom-user-error "Error caused by user's config or system" 'doom-error) (define-error 'doom-user-error "Error caused by user's config or system" 'doom-error)
@ -19,10 +20,27 @@
;;; Logging ;;; Logging
(defvar doom-inhibit-log (not (or noninteractive init-file-debug)) (defvar doom-inhibit-log (not (or noninteractive init-file-debug))
"If non-nil, suppress `doom-log' output.") "If non-nil, suppress `doom-log' output completely.")
(defun doom--log (text &rest args) (defvar doom-log-level
(let ((inhibit-message (not init-file-debug)) (if init-file-debug
(if-let ((level (getenv-internal "DEBUG"))
(level (string-to-number level))
((not (zerop level))))
level
2)
0)
"How verbosely to log from `doom-log' calls.
0 -- No logging at all.
1 -- Only warnings.
2 -- Warnings and notices.
3 -- Debug info, warnings, and notices.")
(defun doom--log (level text &rest args)
(let ((inhibit-message (if noninteractive
(not init-file-debug)
(> level doom-log-level)))
(absolute? (string-prefix-p ":" text))) (absolute? (string-prefix-p ":" text)))
(apply #'message (apply #'message
(propertize (concat "* %.06f:%s" (if (not absolute?) ":") text) (propertize (concat "* %.06f:%s" (if (not absolute?) ":") text)
@ -38,14 +56,19 @@
":") ":")
args))) args)))
;; This is a macro instead of a function to prevent the potentially expensive
;; evaluation of its arguments when debug mode is off. Return non-nil.
(defmacro doom-log (message &rest args) (defmacro doom-log (message &rest args)
"Log a message in *Messages*. "Log a message to stderr or *Messages* (without displaying in the echo area)."
Does not emit the message in the echo area. This is a macro instead of a
function to prevent the potentially expensive evaluation of its arguments when
debug mode is off. Return non-nil."
(declare (debug t)) (declare (debug t))
`(unless doom-inhibit-log (doom--log ,message ,@args))) (let ((level (if (integerp message)
(prog1 message
(setq message (pop args)))
2)))
`(when (and (not doom-inhibit-log)
(or (not noninteractive)
(<= ,level doom-log-level)))
(doom--log ,level ,message ,@args))))
;; ;;
@ -290,14 +313,13 @@ TRIGGER-HOOK is a list of quoted hooks and/or sharp-quoted functions."
(defmacro file! () (defmacro file! ()
"Return the file of the file this macro was called." "Return the file of the file this macro was called."
(or (or (bound-and-true-p byte-compile-current-file)
;; REVIEW: Use `macroexp-file-name' once 27 support is dropped. load-file-name
(let ((file (car (last current-load-list)))) (buffer-file-name (buffer-base-buffer)) ; for `eval'
(if (stringp file) file)) ;; REVIEW: Use `macroexp-file-name' once 27 support is dropped.
(bound-and-true-p byte-compile-current-file) (let ((file (car (last current-load-list))))
load-file-name (if (stringp file) file))
buffer-file-name ; for `eval' (error "file!: cannot deduce the current file path")))
(error "file!: cannot deduce the current file path")))
(defmacro dir! () (defmacro dir! ()
"Return the directory of the file in which this macro was called." "Return the directory of the file in which this macro was called."
@ -311,24 +333,26 @@ TRIGGER-HOOK is a list of quoted hooks and/or sharp-quoted functions."
"Temporarily rebind function, macros, and advice in BODY. "Temporarily rebind function, macros, and advice in BODY.
Intended as syntax sugar for `cl-letf', `cl-labels', `cl-macrolet', and Intended as syntax sugar for `cl-letf', `cl-labels', `cl-macrolet', and
temporary advice. temporary advice (`define-advice').
BINDINGS is either: BINDINGS is either:
A list of, or a single, `defun', `defun*', `defmacro', or `defadvice' forms.
A list of (PLACE VALUE) bindings as `cl-letf*' would accept. A list of (PLACE VALUE) bindings as `cl-letf*' would accept.
A list of, or a single, `defun', `defun*', `defmacro', or `defadvice' forms.
TYPE is one of: The def* forms accepted are:
`defun' (uses `cl-letf') (defun NAME (ARGS...) &rest BODY)
`defun*' (uses `cl-labels'; allows recursive references), Defines a temporary function with `cl-letf'
`defmacro' (uses `cl-macrolet') (defun* NAME (ARGS...) &rest BODY)
`defadvice' (uses `defadvice!' before BODY, then `undefadvice!' after) Defines a temporary function with `cl-labels' (allows recursive
definitions).
NAME, ARGLIST, and BODY are the same as `defun', `defun*', `defmacro', and (defmacro NAME (ARGS...) &rest BODY)
`defadvice!', respectively. Uses `cl-macrolet'.
(defadvice FUNCTION WHERE ADVICE)
\(fn ((TYPE NAME ARGLIST &rest BODY) ...) BODY...)" Uses `advice-add' (then `advice-remove' afterwards).
(defadvice FUNCTION (HOW LAMBDA-LIST &optional NAME DEPTH) &rest BODY)
Defines temporary advice with `define-advice'."
(declare (indent defun)) (declare (indent defun))
(setq body (macroexp-progn body)) (setq body (macroexp-progn body))
(when (memq (car bindings) '(defun defun* defmacro defadvice)) (when (memq (car bindings) '(defun defun* defmacro defadvice))
@ -339,16 +363,33 @@ NAME, ARGLIST, and BODY are the same as `defun', `defun*', `defmacro', and
(setq (setq
body (pcase type body (pcase type
(`defmacro `(cl-macrolet ((,@rest)) ,body)) (`defmacro `(cl-macrolet ((,@rest)) ,body))
(`defadvice `(progn (defadvice! ,@rest) (`defadvice
(unwind-protect ,body (undefadvice! ,@rest)))) (if (keywordp (cadr rest))
((or `defun `defun*) (cl-destructuring-bind (target where fn) rest
`(when-let (fn ,fn)
(advice-add ,target ,where fn)
(unwind-protect ,body (advice-remove ,target fn))))
(let* ((fn (pop rest))
(argspec (pop rest)))
(when (< (length argspec) 3)
(setq argspec
(list (nth 0 argspec)
(nth 1 argspec)
(or (nth 2 argspec) (gensym (format "%s-a" (symbol-name fn)))))))
(let ((name (nth 2 argspec)))
`(progn
(define-advice ,fn ,argspec ,@rest)
(unwind-protect ,body
(advice-remove #',fn #',name)
,(if name `(fmakunbound ',name))))))))
(`defun
`(cl-letf ((,(car rest) (symbol-function #',(car rest)))) `(cl-letf ((,(car rest) (symbol-function #',(car rest))))
(ignore ,(car rest)) (ignore ,(car rest))
,(if (eq type 'defun*) (cl-letf (((symbol-function #',(car rest))
`(cl-labels ((,@rest)) ,body) (lambda! ,(cadr rest) ,@(cddr rest))))
`(cl-letf (((symbol-function #',(car rest)) ,body)))
(lambda! ,(cadr rest) ,@(cddr rest)))) (`defun*
,body)))) `(cl-labels ((,@rest)) ,body))
(_ (_
(when (eq (car-safe type) 'function) (when (eq (car-safe type) 'function)
(setq type (list 'symbol-function type))) (setq type (list 'symbol-function type)))

View file

@ -50,7 +50,7 @@ NOT IMPLEMENTED YET. This file contains a module's metadata: their version,
maintainers, checks, features, submodules, debug information, etc. And are used maintainers, checks, features, submodules, debug information, etc. And are used
to locate modules in the user's file tree.") to locate modules in the user's file tree.")
;; DEPRECATED: Module warnings will be rewritten in v3, and this variable will no longer be needed. ;; DEPRECATED: Remove in v3, as it will be handled in the CLI
(make-obsolete-variable 'doom-obsolete-modules nil "3.0.0") (make-obsolete-variable 'doom-obsolete-modules nil "3.0.0")
(defconst doom-obsolete-modules (defconst doom-obsolete-modules
'((:feature (version-control (:emacs vc) (:ui vc-gutter)) '((:feature (version-control (:emacs vc) (:ui vc-gutter))

View file

@ -143,11 +143,6 @@
(setq selection-coding-system 'utf-8)) (setq selection-coding-system 'utf-8))
;;; Support for Doom-specific file extensions
(add-to-list 'auto-mode-alist '("/\\.doom\\(?:project\\|module\\|profile\\)\\'" . lisp-data-mode))
(add-to-list 'auto-mode-alist '("/\\.doomrc\\'" . emacs-lisp-mode))
;; ;;
;;; MODE-local-vars-hook ;;; MODE-local-vars-hook
@ -339,9 +334,8 @@ If RETURN-P, return the message as a string instead of displaying it."
;; TODO: Catch errors ;; TODO: Catch errors
(load! (string-remove-suffix ".el" doom-module-init-file) doom-user-dir t) (load! (string-remove-suffix ".el" doom-module-init-file) doom-user-dir t)
;;; Load the rest of $DOOMDIR + modules if noninteractive
;; If the user is loading this file from a batch script, let's assume they want ;; If the user is loading this file from a batch script, let's assume they want
;; to load their userland config as well. ;; to load their userland config immediately.
(when noninteractive (when noninteractive
(doom-require 'doom-profiles) (doom-require 'doom-profiles)
(let ((init-file (doom-profile-init-file))) (let ((init-file (doom-profile-init-file)))
@ -353,6 +347,7 @@ If RETURN-P, return the message as a string instead of displaying it."
(doom-load init-file 'noerror) (doom-load init-file 'noerror)
(doom-initialize-packages)))) (doom-initialize-packages))))
;;; Entry point ;;; Entry point
;; HACK: This advice hijacks Emacs' initfile loader to accomplish the following: ;; HACK: This advice hijacks Emacs' initfile loader to accomplish the following:
;; ;;

View file

@ -1,6 +1,6 @@
;;; doom-ui.el --- defaults for Doom's aesthetics -*- lexical-binding: t; -*- ;;; doom-ui.el --- defaults for Doom's aesthetics -*- lexical-binding: t; -*-
;;; Commentary: ;;; Commentary:
;;; Code; ;;; Code:
;; ;;
;;; Variables ;;; Variables
@ -590,10 +590,18 @@ windows, switch to `doom-fallback-buffer'. Otherwise, delegate to original
(put 'doom-theme 'previous-themes (or last-themes 'none)) (put 'doom-theme 'previous-themes (or last-themes 'none))
;; DEPRECATED Hook into `enable-theme-functions' when we target 29 ;; DEPRECATED Hook into `enable-theme-functions' when we target 29
(doom-run-hooks 'doom-load-theme-hook) (doom-run-hooks 'doom-load-theme-hook)
(when-let* ((fg (face-foreground 'default nil t)) ;; Fix incorrect fg/bg in new frames created after the initial frame
(bg (face-background 'default nil t))) ;; (which are reroneously displayed as black).
(setf (alist-get 'foreground-color default-frame-alist) fg (pcase-dolist (`(,param ,fn ,face)
(alist-get 'background-color default-frame-alist) bg))))))) '((foreground-color face-foreground default)
(background-color face-background default)
(cursor-color face-background cursor)
(border-color face-background border)
(mouse-color face-background mouse)))
(when-let* ((color (funcall fn face nil t))
((stringp color))
((not (string-prefix-p "unspecified-" color))))
(setf (alist-get param default-frame-alist) color))))))))
;; ;;
@ -657,11 +665,11 @@ triggering hooks during startup."
(fset 'set-fontset-font #'ignore)) (fset 'set-fontset-font #'ignore))
(after! whitespace (after! whitespace
(defun doom-is-childframes-p () (defun doom--in-parent-frame-p ()
"`whitespace-mode' inundates child frames with whitespace markers, so "`whitespace-mode' inundates child frames with whitespace markers, so
disable it to fix all that visual noise." disable it to fix all that visual noise."
(null (frame-parameter nil 'parent-frame))) (null (frame-parameter nil 'parent-frame)))
(add-function :before-while whitespace-enable-predicate #'doom-is-childframes-p)) (add-function :before-while whitespace-enable-predicate #'doom--in-parent-frame-p))
(provide 'doom-ui) (provide 'doom-ui)
;;; doom-ui.el ends here ;;; doom-ui.el ends here

View file

@ -54,7 +54,8 @@
;; - hook: `window-setup-hook' ;; - hook: `window-setup-hook'
;; - hook: `doom-init-ui-hook' ;; - hook: `doom-init-ui-hook'
;; - hook: `doom-after-init-hook' ;; - hook: `doom-after-init-hook'
;; > After startup is complete: ;; > After startup is complete (if file(s) have been opened from the command
;; line, these will trigger much earlier):
;; - On first input: `doom-first-input-hook' ;; - On first input: `doom-first-input-hook'
;; - On first switched-to buffer: `doom-first-buffer-hook' ;; - On first switched-to buffer: `doom-first-buffer-hook'
;; - On first opened file: `doom-first-file-hook' ;; - On first opened file: `doom-first-file-hook'
@ -374,13 +375,13 @@ users).")
(let ((old-value (default-toplevel-value 'file-name-handler-alist))) (let ((old-value (default-toplevel-value 'file-name-handler-alist)))
(set-default-toplevel-value (set-default-toplevel-value
'file-name-handler-alist 'file-name-handler-alist
;; HACK: The libraries bundled with Emacs can either be compiled, ;; HACK: The elisp libraries bundled with Emacs are either compressed or
;; compressed, or neither. We use calc-loaddefs.el as a heuristic to ;; not, never both. So if calc-loaddefs.el.gz exists, calc-loaddefs.el
;; guess what state all these libraries are in. If they're compressed, we ;; won't, and vice versa. This heuristic is used to guess the state of
;; need to leave the gzip file handler in `file-name-handler-alist' so ;; all other built-in (or site); if they're compressed, we must leave the
;; Emacs knows how to load them. If they're compiled or neither, we can ;; gzip file handler in `file-name-handler-alist' so Emacs knows how to
;; omit the gzip handler altogether (at least during startup) for a boost ;; load them. Otherwise, we can omit it (at least during startup) for a
;; in startup and package load time. ;; boost in package load time.
(if (eval-when-compile (if (eval-when-compile
(locate-file-internal "calc-loaddefs.el" load-path)) (locate-file-internal "calc-loaddefs.el" load-path))
nil nil
@ -469,28 +470,35 @@ users).")
(add-hook! 'doom-before-init-hook (add-hook! 'doom-before-init-hook
(defun doom--reset-custom-dont-initialize-h () (defun doom--reset-custom-dont-initialize-h ()
(setq custom-dont-initialize nil))) (setq custom-dont-initialize nil)))
(define-advice command-line-1 (:around (fn args-left) respect-defcustom-setters)
(let ((custom-dont-initialize nil))
(funcall fn args-left)))
;; PERF: The mode-line procs a couple dozen times during startup, before the ;; These optimizations are brittle, difficult to debug, and obscure other
;; user even sees the first mode-line. This is normally fast, but we can't ;; issues, so bow out when debug mode is on.
;; predict what the user (or packages) will put into the mode-line. Also, (unless init-file-debug
;; mode-line packages have a bad habit of throwing performance to the ;; PERF: The mode-line procs a couple dozen times during startup, before
;; wind, so best we just disable the mode-line until we can see one. ;; the user even sees the first mode-line. This is normally fast, but we
(put 'mode-line-format 'initial-value (default-toplevel-value 'mode-line-format)) ;; can't predict what the user (or packages) will put into the
(setq-default mode-line-format nil) ;; mode-line. Also, mode-line packages have a bad habit of throwing
(dolist (buf (buffer-list)) ;; performance to the wind, so best we just disable the mode-line until
(with-current-buffer buf (setq mode-line-format nil))) ;; we can see one.
;; PERF,UX: Premature redisplays/redraws can substantially affect startup (put 'mode-line-format 'initial-value (default-toplevel-value 'mode-line-format))
;; times and/or flash a white/unstyled Emacs frame during startup, so I (setq-default mode-line-format nil)
;; try real hard to suppress them until we're sure the session is ready. (dolist (buf (buffer-list))
(setq-default inhibit-redisplay t (with-current-buffer buf (setq mode-line-format nil)))
inhibit-message t) ;; PERF,UX: Premature redisplays/redraws can substantially affect startup
;; COMPAT: If the above vars aren't reset, Emacs could appear frozen or ;; times and/or flash a white/unstyled Emacs frame during startup, so I
;; garbled after startup (or in case of an startup error). ;; try real hard to suppress them until we're sure the session is ready.
(defun doom--reset-inhibited-vars-h () (setq-default inhibit-redisplay t
(setq-default inhibit-redisplay nil inhibit-message t)
inhibit-message nil) ;; COMPAT: If the above vars aren't reset, Emacs could appear frozen or
(remove-hook 'post-command-hook #'doom--reset-inhibited-vars-h)) ;; garbled after startup (or in case of an startup error).
(add-hook 'post-command-hook #'doom--reset-inhibited-vars-h -100) (defun doom--reset-inhibited-vars-h ()
(setq-default inhibit-redisplay nil
inhibit-message nil)
(remove-hook 'post-command-hook #'doom--reset-inhibited-vars-h))
(add-hook 'post-command-hook #'doom--reset-inhibited-vars-h -100))
;; PERF: Doom disables the UI elements by default, so that there's less for ;; PERF: Doom disables the UI elements by default, so that there's less for
;; the frame to initialize. However, `tool-bar-setup' is still called and ;; the frame to initialize. However, `tool-bar-setup' is still called and
@ -515,10 +523,11 @@ users).")
(progn (progn
(when (setq site-run-file (get 'site-run-file 'initial-value)) (when (setq site-run-file (get 'site-run-file 'initial-value))
(let ((inhibit-startup-screen inhibit-startup-screen)) (let ((inhibit-startup-screen inhibit-startup-screen))
(letf! ((defun load-file (file) (load file nil 'nomessage)) (letf! ((defun load-file (file)
(load file nil (not init-file-debug)))
(defun load (file &optional noerror _nomessage &rest args) (defun load (file &optional noerror _nomessage &rest args)
(apply load file noerror t args))) (apply load file noerror (not init-file-debug) args)))
(load site-run-file t t)))) (load site-run-file t))))
(apply fn args)) (apply fn args))
;; Now it's safe to be verbose. ;; Now it's safe to be verbose.
(setq-default inhibit-message nil) (setq-default inhibit-message nil)
@ -762,7 +771,7 @@ appropriately against `noninteractive' or the `cli' context."
;;; Last minute initialization ;;; Last minute initialization
(when (daemonp) (when (daemonp)
(message "Starting Doom Emacs in daemon mode!") (message "Starting Doom Emacs in daemon mode...")
(unless doom-inhibit-log (unless doom-inhibit-log
(add-hook! 'doom-after-init-hook :depth 106 (add-hook! 'doom-after-init-hook :depth 106
(unless doom-inhibit-log (unless doom-inhibit-log
@ -783,8 +792,8 @@ appropriately against `noninteractive' or the `cli' context."
(when (doom-context-push 'init) (when (doom-context-push 'init)
;; HACK: Ensure OS checks are as fast as possible (given their ubiquity). ;; HACK: Ensure OS checks are as fast as possible (given their ubiquity).
(setq features (cons :system (delq :system features))) (setq features (cons :system (delq :system features)))
;; Remember these variables' initial values, so we can safely reset them at ;; Remember these variables' initial values, so we can safely reset them
;; a later time, or consult them without fear of contamination. ;; at a later time, or consult them without fear of contamination.
(dolist (var '(exec-path load-path process-environment)) (dolist (var '(exec-path load-path process-environment))
(put var 'initial-value (default-toplevel-value var)))))) (put var 'initial-value (default-toplevel-value var))))))

View file

@ -22,7 +22,7 @@ https://assets.doomemacs.org/completion/company/overlay.png
** Module flags ** Module flags
- +childframe :: - +childframe ::
Display completion candidates in a [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Child-Frames.html][child frame]] rather than an overlay or Display completion candidates in a [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Child-Frames.html][childframe]] rather than an overlay or
tooltip. *Requires GUI Emacs.* tooltip. *Requires GUI Emacs.*
- +tng :: - +tng ::
Invoke completion on [[kbd:][TAB]] instad of [[kbd:][C-SPC]]. When company is active, [[kbd:][TAB]] and Invoke completion on [[kbd:][TAB]] instad of [[kbd:][C-SPC]]. When company is active, [[kbd:][TAB]] and

View file

@ -511,8 +511,8 @@
:desc "Copy link to homepage" "Y" #'+vc/browse-at-remote-kill-homepage :desc "Copy link to homepage" "Y" #'+vc/browse-at-remote-kill-homepage
:desc "Git time machine" "t" #'git-timemachine-toggle :desc "Git time machine" "t" #'git-timemachine-toggle
(:when (modulep! :ui vc-gutter) (:when (modulep! :ui vc-gutter)
:desc "Revert hunk at point" "r" #'+vc-gutter/revert-hunk :desc "Revert hunk at point" "r" #'+vc-gutter/save-and-revert-hunk
:desc "stage hunk at point" "s" #'+vc-gutter/stage-hunk :desc "Stage hunk at point" "s" #'+vc-gutter/stage-hunk
:desc "Jump to next hunk" "]" #'+vc-gutter/next-hunk :desc "Jump to next hunk" "]" #'+vc-gutter/next-hunk
:desc "Jump to previous hunk" "[" #'+vc-gutter/previous-hunk) :desc "Jump to previous hunk" "[" #'+vc-gutter/previous-hunk)
(:when (modulep! :tools magit) (:when (modulep! :tools magit)

View file

@ -181,8 +181,8 @@ This is performed with an asyncronous Emacs process, except when
(defun +literate-recompile-maybe-h () (defun +literate-recompile-maybe-h ()
"Recompile literate config to `doom-user-dir'. "Recompile literate config to `doom-user-dir'.
We assume any org file in `doom-user-dir' is connected to your literate We assume any org file in `doom-user-dir' is connected to your literate config,
config, and should trigger a recompile if changed." and should trigger a recompile if changed."
(and (file-in-directory-p (and (file-in-directory-p
(buffer-file-name (buffer-base-buffer)) (buffer-file-name (buffer-base-buffer))
(file-name-directory (file-truename +literate-config-file))) (file-name-directory (file-truename +literate-config-file)))

View file

@ -369,8 +369,7 @@ directives. By default, this only recognizes C directives.")
;; ;;
;;; Keybinds ;;; Keybinds
;; Keybinds that have no Emacs+evil analogues (i.e. don't exist): ;; TODO: zu{q,w} - undo last marking
;; zu{q,w} - undo last marking
(map! :v "@" #'+evil:apply-macro (map! :v "@" #'+evil:apply-macro
:m [C-i] #'evil-jump-forward :m [C-i] #'evil-jump-forward
@ -530,6 +529,7 @@ directives. By default, this only recognizes C directives.")
;; evil-easymotion ;; evil-easymotion
(:after evil-easymotion (:after evil-easymotion
:m "gs" evilem-map :m "gs" evilem-map
;; TODO: Use named functions
(:map evilem-map (:map evilem-map
"a" (evilem-create #'evil-forward-arg) "a" (evilem-create #'evil-forward-arg)
"A" (evilem-create #'evil-backward-arg) "A" (evilem-create #'evil-backward-arg)

View file

@ -7,7 +7,7 @@
#+title: `(+file-templates-module-for-path)` #+title: `(+file-templates-module-for-path)`
#+subtitle: <A one-line quip about this module to display in init.example.el> #+subtitle: <A one-line quip about this module to display in init.example.el>
#+created: `(format-time-string "%B %d, %Y")` #+created: `(format-time-string "%B %d, %Y")`
#+since: `(car (split-string doom-version "-"))` (#COMMIT-OR-PR-REF) #+since: `(car (split-string doom-modules-version "-"))` (#COMMIT-OR-PR-REF)
* Description :unfold: * Description :unfold:
$0Replace this with a short (1-2 sentence) description of what this module does. $0Replace this with a short (1-2 sentence) description of what this module does.

View file

@ -38,9 +38,6 @@ this."
(after! org (after! org
(setq org-ellipsis +fold-ellipsis)) (setq org-ellipsis +fold-ellipsis))
(after! mule-util
(setq truncate-string-ellipsis +fold-ellipsis))
;; ;;
;;; Packages ;;; Packages

View file

@ -0,0 +1,55 @@
:PROPERTIES:
:ID: 4f6e0ee2-7837-4d15-853f-c8863d065f21
:END:
#+title: :emacs eww
#+subtitle: The internet is gross
#+created: September 11, 2024
#+since: 24.10
* Description :unfold:
This module augments eww (Emacs Web Wowser); Emacs' built-in web browser, with
some reasonable defaults and helper commands.
** Maintainers
/This module has no dedicated maintainers./ [[doom-contrib-maintainer:][Become a maintainer?]]
** Module flags
/This module has no flags./
** Packages
/This module doesn't install any packages./
** Hacks
- The buffer is renamed to match the current page's URL or title.
** TODO Changelog
# This section will be machine generated. Don't edit it by hand.
/This module does not have a changelog yet./
* Installation
[[id:01cffea4-3329-45e2-a892-95a384ab2338][Enable this module in your ~doom!~ block.]]
/This module has no external requirements./
* Usage
#+begin_quote
󱌣 /This module's usage documentation is incomplete./ [[doom-contrib-module:][Complete it?]]
#+end_quote
Type ~M-x eww~ and enter an URL.
* TODO Configuration
#+begin_quote
󱌣 This module has no configuration documentation yet. [[doom-contrib-module:][Write some?]]
#+end_quote
* Troubleshooting
/There are no known problems with this module./ [[doom-report:][Report one?]]
* Frequently asked questions
/This module has no FAQs yet./ [[doom-suggest-faq:][Ask one?]]
* TODO Appendix
#+begin_quote
󱌣 This module has no appendix yet. [[doom-contrib-module:][Write one?]]
#+end_quote

View file

@ -0,0 +1,128 @@
;;; emacs/eww/autoload.el -*- lexical-binding: t; -*-
;; NOTE: Many of these functions were adapted from Protesilaos Stavrou's
;; dotfiles. See https://protesilaos.com/codelog/2021-03-25-emacs-eww
;; Adapted from `prot-eww-jump-to-url-on-page'
(defun eww--capture-url-on-page (&optional position)
"Capture all the links on the current web page.
Return a list of strings. Strings are in the form LABEL @ URL.
When optional argument POSITION is non-nil, include position info in the strings
too, so strings take the form: LABEL @ URL ~ POSITION."
(let (links match)
(save-excursion
(goto-char (point-max))
;; NOTE 2021-07-25: The first clause in the `or' is meant to address a bug
;; where if a URL is in `point-min' it does not get captured.
(while (setq match (text-property-search-backward 'shr-url))
(let* ((raw-url (prop-match-value match))
(start-point-prop (prop-match-beginning match))
(end-point-prop (prop-match-end match))
(url (when (stringp raw-url)
(propertize raw-url 'face 'link)))
(label (replace-regexp-in-string
"\n" " " ; NOTE 2021-07-25: newlines break completion
(buffer-substring-no-properties
start-point-prop end-point-prop)))
(point start-point-prop)
(line (line-number-at-pos point t))
(column (save-excursion (goto-char point) (current-column)))
(coordinates (propertize
(format "%d,%d (%d)" line column point)
'face 'shadow)))
(when url
(push (if position
(format "%-15s ~ %s @ %s" coordinates label url)
(format "%s @ %s" label url))
links)))))
links))
;; Adapted from `prot-eww--rename-buffer'
(defun +eww-page-title-or-url (&rest _)
(let ((prop (if (string-empty-p (plist-get eww-data :title)) :url :title)))
(format "*%s # eww*" (plist-get eww-data prop))))
;;
;;; Commands
;; Adapted from `prot-eww-quit'
;;;###autoload
(defun +eww/quit ()
"Quit eww and kill all its buffers."
(interactive nil 'eww-mode)
(when (yes-or-no-p "Are you sure you want to quit eww?")
(save-match-data
(cl-loop with case-fold-search = t
for buf in (doom-buffer-list)
if (with-current-buffer buf
(or (eq major-mode 'eww-mode)
(and (derived-mode-p 'special-mode)
(string-match "\\*.*eww.*\\*" (buffer-name)))))
do (kill-buffer buf)))))
;; Adapted from `prot-eww-jump-to-url-on-page'
;;;###autoload
(defun +eww/jump-to-url-on-page (&optional arg)
"Jump to URL position on the page using completion.
When called without ARG (\\[universal-argument]) get URLs only
from the visible portion of the buffer. But when ARG is provided
consider whole buffer."
(interactive "P" 'eww-mode)
(unless (derived-mode-p 'eww-mode)
(user-error "Not in an eww buffer!"))
(let* ((links
(if arg
(eww--capture-url-on-page t)
(save-restriction
(if (use-region-p)
(narrow-to-region (region-beginning) (region-end))
(narrow-to-region (window-start) (window-end)))
(eww--capture-url-on-page t))))
(prompt-scope (if arg
(propertize "URL on the page" 'face 'warning)
"visible URL"))
(prompt (format "Jump to %s: " prompt-scope))
(selection (completing-read prompt links nil t))
(position (replace-regexp-in-string "^.*(\\([0-9]+\\))[\s\t]+~" "\\1" selection))
(point (string-to-number position)))
(goto-char point)
(recenter)))
;; Adapted from `prot-eww-open-in-other-window'
;;;###autoload
(defun +eww/open-in-other-window ()
"Use `eww-open-in-new-buffer' in another window."
(interactive nil 'ewe-mode)
(other-window-prefix)
(eww-open-in-new-buffer))
;;;###autoload
(defun +eww/copy-current-url ()
"Copy the open page's URL to the kill ring."
(interactive nil 'eww-mode)
(let ((url (eww-current-url)))
(kill-new url)
(message url)))
;;;###autoload
(defun +eww/increase-font-size ()
"Increase the font size in `eww-mode'."
(interactive nil 'eww-mode)
(if shr-use-fonts
(let* ((cur (face-attribute 'shr-text :height nil))
(cur (if (floatp cur) cur 1.0)))
(set-face-attribute 'shr-text nil :height (+ cur 0.1)))
(text-scale-increase 0.5)))
;;;###autoload
(defun +eww/decrease-font-size ()
"Decrease the font size in `eww-mode'."
(interactive nil 'eww-mode)
(if shr-use-fonts
(let* ((cur (face-attribute 'shr-text :height nil))
(cur (if (floatp cur) cur 1.0)))
(set-face-attribute 'shr-text nil :height (- cur 0.1)))
(text-scale-decrease 0.5)))

View file

@ -0,0 +1,48 @@
;;; emacs/eww/config.el -*- lexical-binding: t; -*-
(use-package! eww
:defer t
:config
(map! :map eww-mode-map
[remap text-scale-increase] #'+eww/increase-font-size
[remap text-scale-decrease] #'+eww/decrease-font-size
[remap imenu] #'+eww/jump-to-url-on-page
[remap quit-window] #'+eww/quit
:ni [C-return] #'+eww/open-in-other-window
:n "yy" #'+eww/copy-current-url
:n "zk" #'text-scale-increase
:n "zj" #'text-scale-decrease
(:localleader
:desc "external browser" "e" #'eww-browse-with-external-browser
:desc "buffers" "b" #'eww-switch-to-buffer
(:prefix ("t" . "toggle")
:desc "readable" "r" #'eww-readable
:desc "colors" "c" #'eww-toggle-colors
:desc "fonts" "f" #'eww-toggle-fonts
:desc "images" "i" #'eww-toggle-images)
(:prefix ("y" . "copy")
:desc "copy url" "y" #'+eww/copy-current-url
:desc "copy for Org" "o" #'org-eww-copy-for-org-mode)))
;; HACK: There are packages that use eww to pop up html documentation; we want
;; those to open in a popup, but if the user calls `eww' directly, it should
;; open in the current window.
(defadvice! +eww-open-in-fullscreen-if-interactive-a (fn &rest args)
:around #'eww
(if (called-interactively-p 'any)
(apply fn args)
(let (display-buffer-alist)
(apply fn args))))
;; HACK: Rename the eww buffer to match the open page's title or URL.
(if (boundp 'eww-auto-rename-buffer)
(setq eww-auto-rename-buffer #'+eww-page-title-or-url) ; for >=29.1
;; REVIEW: Remove when we drop 28 support
(add-hook! 'eww-after-render-hook
(defun +eww--rename-buffer-to-page-title-or-url-h (&rest _)
(rename-buffer (+eww-page-title-or-url))))
(advice-add #'eww-back-url :after #'+eww--rename-buffer-to-page-title-or-url-h)
(advice-add #'eww-forward-url :after #'+eww--rename-buffer-to-page-title-or-url-h)))

View file

@ -0,0 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; emacs/eww/packages.el
(package! eww :built-in t)

View file

@ -2,7 +2,7 @@
(defvar +mu4e-backend 'mbsync (defvar +mu4e-backend 'mbsync
"Which backend to use. Can either be offlineimap, mbsync or nil (manual).") "Which backend to use. Can either be offlineimap, mbsync or nil (manual).")
(make-obsolete-variable '+mu4e-backend "Use the :email mu4e module's +mbsync or +offlineimap flags instead" "3.0.0") (make-obsolete-variable '+mu4e-backend "Use the :email mu4e module's +mbsync or +offlineimap flags instead" "24.09")
(defvar +mu4e-personal-addresses 'nil (defvar +mu4e-personal-addresses 'nil
"Alternative to mu4e-personal-addresses that can be set for each account (mu4e context).") "Alternative to mu4e-personal-addresses that can be set for each account (mu4e context).")

View file

@ -0,0 +1,64 @@
:PROPERTIES:
:ID: 3efe8402-e4a1-41c3-ad1a-9aaa3783f68f
:END:
#+title: :lang graphviz
#+subtitle: Diagrams to confuse yourself even more
#+created: Nov 14, 2023
#+since: 23.09.0-pre
* Description :unfold:
This module adds graphviz support to Emacs, allowing you to generate diagrams
from plain text. Flycheck is supported.
** Maintainers
/This module has no dedicated maintainers./ [[doom-contrib-maintainer:][Become a maintainer?]]
** Module flags
/This module has no flags./
** Packages
- [[doom-package:graphviz-dot-mode]]
** Hacks
/No hacks documented for this module./
** TODO Changelog
# This section will be machine generated. Don't edit it by hand.
/This module does not have a changelog yet./
* Installation
[[id:01cffea4-3329-45e2-a892-95a384ab2338][Enable this module in your ~doom!~ block.]]
This module requires that the =graphviz= package be installed on your system to
build diagrams with. You can install it using:
#+begin_src shell
sudo dnf install graphviz # For fedora
sudo apt install graphviz # For debian/ubuntu
#+end_src
* Usage
This module should configure "out-of-the-box" if you have installed graphviz on
your system.
With org-babel LaTeX/PDF-export, use a file naming ending with ".pdf", otherwise
LaTeX might complain about a non-existant ~\\includesvg~ command.
#+begin_src dot :file graph-1.pdf
digraph {
A -> B;
B -> D;
}
#+end_src
* Configuration
There is nothing to configure. Just install dot and it should work.
* Troubleshooting
/There are no known problems with this module./ [[doom-report:][Report one?]]
* Frequently asked questions
/This module has no FAQs yet./ [[doom-suggest-faq:][Ask one?]]
* TODO Appendix
#+begin_quote
󱌣 This module has no appendix yet. [[doom-contrib-module:][Write one?]]
#+end_quote

View file

@ -0,0 +1,19 @@
;;; lang/graphviz/autoload.el -*- lexical-binding: t; -*-
;;;###autoload
(cl-defun +graphviz-formatter (&key _buffer scratch callback &allow-other-keys)
"Format graphviz graphs."
(with-current-buffer scratch
(let ((inhibit-message t)
(message-log-max nil))
(goto-char (point-min))
(graphviz-dot-indent-graph))
(funcall callback)))
;;;###autoload
(defun +graphviz/toggle-preview ()
"Toggle `graphviz-dot-auto-preview-on-save'."
(interactive nil 'graphviz-dot-mode)
(if graphviz-dot-auto-preview-on-save
(graphviz-turn-off-live-preview)
(graphviz-turn-on-live-preview)))

View file

@ -0,0 +1,37 @@
;;; lang/graphviz/config.el -*- lexical-binding: t; -*-
(use-package! graphviz-dot-mode
:mode "\\.\\(?:nw\\|rack\\)diag\\'"
:init
(after! org-src
(add-to-list 'org-src-lang-modes '("dot" . graphviz-dot)))
:config
(set-company-backend! 'graphviz-dot-mode 'company-graphviz-dot-backend)
(set-formatter! 'graphviz-dot #'+graphviz-formatter :modes '(graphviz-dot-mode))
(set-tree-sitter-lang! 'graphviz-dot-mode 'dot)
(when (modulep! +tree-sitter)
(add-hook 'graphiz-dot-mode-hook #'tree-sitter!))
(after! dtrt-indent
(add-to-list 'dtrt-indent-hook-mapping-list '(graphviz-mode graphviz-dot-indent-width)))
(when (and (modulep! :checker syntax)
(not (modulep! :checker syntax +flymake)))
(after! flycheck
(flycheck-define-checker graphviz-dot
"A checker using graphviz dot."
:command ("dot")
:standard-input t
:error-patterns ((error line-start "Error: <stdin>: " (message "syntax error in line " line (* nonl)))
;; I have no idea if this can actually be printed
(error line-start "Error: <stdin>: " (message)))
:modes graphviz-dot-mode)
(add-to-list 'flycheck-checkers 'graphviz-dot)))
(map! :map graphviz-dot-mode-map
:localleader
:desc "External view" :nv "e" #'graphviz-dot-view
:desc "Preview" :nv "p" #'graphviz-dot-preview
:prefix ("t" . "toggle")
:desc "Preview" :nv "p" #'+graphviz/toggle-preview))

View file

@ -0,0 +1,6 @@
;; -*- lexical-binding: t; no-byte-compile: t; -*-
;;; lang/graphviz/doctor.el
(when (require 'graphviz-dot-mode nil t)
(unless (executable-find graphviz-dot-dot-program)
(warn! "Couldn't find dot. Previewing and exporting will not work")))

View file

@ -0,0 +1,4 @@
;; -*- no-byte-compile: t; -*-
;;; lang/graphviz/packages.el
(package! graphviz-dot-mode :pin "8ff793b13707cb511875f56e167ff7f980a31136")

View file

@ -14,8 +14,12 @@ This module adds support for the [[https://www.racket-lang.org/][Racket programm
Enable support for ~racket-mode~. Requires [[doom-module::tools lsp]] and a langserver Enable support for ~racket-mode~. Requires [[doom-module::tools lsp]] and a langserver
(supports [[https://github.com/jeapostrophe/racket-langserver][racket-langserver]]). (supports [[https://github.com/jeapostrophe/racket-langserver][racket-langserver]]).
- +xp :: - +xp ::
Enable the explore mode (~racket-xp-mode~), which "analyzes expanded code to Enable the explore minor mode (~racket-xp-mode~), which "analyzes expanded
explain and explore." code to explain and explore."
- +hash-lang ::
Enable the hash-lang major mode (~racket-hash-lang-mode~), which "uses
color-lexer, indent, and navigation supplied by a #lang." This flag can be
used along with the ~+xp~ flag.
** Packages ** Packages
- [[doom-package:racket-mode]] - [[doom-package:racket-mode]]

View file

@ -8,88 +8,106 @@
;; ;;
;;; Packages ;;; Packages
(use-package! racket-mode (let (mode
:mode "\\.rkt\\'" ; give it precedence over :lang scheme mode-map
:config mode-exts
(set-repl-handler! 'racket-mode #'+racket/open-repl) mode-hook
(set-lookup-handlers! '(racket-mode racket-repl-mode) mode-local-vars-hook)
:definition #'+racket-lookup-definition (if (modulep! +hash-lang)
:documentation #'+racket-lookup-documentation) (setq mode 'racket-hash-lang-mode
(set-docsets! 'racket-mode "Racket") mode-exts '("\\.rkt\\'" ; Racket
(set-ligatures! 'racket-mode "\\.scrbl\\'" ; Scribble
:lambda "lambda" "\\.rhm\\'")) ; Rhombus
:map "map" (setq mode 'racket-mode
:dot ".") mode-exts `("\\.rkt\\'")))
(set-rotate-patterns! 'racket-mode (let ((mode-name (symbol-name mode)))
:symbols '(("#true" "#false"))) (setq mode-map (intern (format "%s-map" mode-name))
(set-formatter! 'raco-fmt '("raco" "fmt") :modes '(racket-mode)) mode-hook (intern (format "%s-hook" mode-name))
mode-local-vars-hook (intern (format "%s-local-vars-hook" mode-name))))
(add-hook! 'racket-mode-hook (use-package! racket-mode
#'rainbow-delimiters-mode :defer t
#'highlight-quoted-mode) :init
(dolist (entry mode-exts)
(add-to-list 'auto-mode-alist (cons entry mode)))
:config
(set-repl-handler! mode #'+racket/open-repl)
(set-lookup-handlers! `(,mode racket-repl-mode)
:definition #'+racket-lookup-definition
:documentation #'+racket-lookup-documentation)
(set-docsets! mode "Racket")
(set-ligatures! mode
:lambda "lambda"
:map "map"
:dot ".")
(set-rotate-patterns! mode :symbols '(("#true" "#false")))
(set-formatter! 'raco-fmt '("raco" "fmt") :modes (list mode))
(when (modulep! +lsp) (add-hook mode-hook #'rainbow-delimiters-mode)
(add-hook 'racket-mode-local-vars-hook #'lsp! 'append)) (add-hook mode-hook #'highlight-quoted-mode)
(when (modulep! +xp) (when (modulep! +lsp)
(add-hook 'racket-mode-local-vars-hook #'racket-xp-mode) (add-hook mode-local-vars-hook #'lsp! 'append))
;; Both flycheck and racket-xp produce error popups, but racket-xp's are
;; higher quality so disable flycheck's:
(when (modulep! :checkers syntax)
(add-hook! 'racket-xp-mode-hook
(defun +racket-disable-flycheck-h ()
(cl-pushnew 'racket flycheck-disabled-checkers)))))
(unless (or (modulep! :editor parinfer) (when (modulep! +xp)
(modulep! :editor lispy)) (add-hook mode-local-vars-hook #'racket-xp-mode)
(add-hook 'racket-mode-hook #'racket-smart-open-bracket-mode)) ;; Both flycheck and racket-xp produce error popups, but racket-xp's are
;; higher quality so disable flycheck's:
(when (modulep! :checkers syntax)
(add-hook! 'racket-xp-mode-hook
(defun +racket-disable-flycheck-h ()
(cl-pushnew 'racket flycheck-disabled-checkers)))))
(map! (:map racket-xp-mode-map (unless (or (modulep! :editor parinfer)
[remap racket-doc] #'racket-xp-documentation (modulep! :editor lispy))
[remap racket-visit-definition] #'racket-xp-visit-definition (add-hook mode-hook #'racket-smart-open-bracket-mode))
[remap next-error] #'racket-xp-next-error
[remap previous-error] #'racket-xp-previous-error) (map! (:map racket-xp-mode-map
(:localleader [remap racket-doc] #'racket-xp-documentation
:map racket-mode-map [remap racket-visit-definition] #'racket-xp-visit-definition
"a" #'racket-align [remap next-error] #'racket-xp-next-error
"A" #'racket-unalign [remap previous-error] #'racket-xp-previous-error)
"f" #'racket-fold-all-tests (:localleader
"F" #'racket-unfold-all-tests :map ,mode-map
"h" #'racket-doc "a" #'racket-align
"i" #'racket-unicode-input-method-enable "A" #'racket-unalign
"l" #'racket-logger "f" #'racket-fold-all-tests
"o" #'racket-profile "F" #'racket-unfold-all-tests
"p" #'racket-cycle-paren-shapes "h" #'racket-doc
"r" #'racket-run "i" #'racket-unicode-input-method-enable
"R" #'racket-run-and-switch-to-repl "l" #'racket-logger
"t" #'racket-test "o" #'racket-profile
"u" #'racket-backward-up-list "p" #'racket-cycle-paren-shapes
"y" #'racket-insert-lambda "r" #'racket-run
(:prefix ("m" . "macros") "R" #'racket-run-and-switch-to-repl
"d" #'racket-expand-definition "t" #'racket-test
"e" #'racket-expand-last-sexp "u" #'racket-backward-up-list
"r" #'racket-expand-region "y" #'racket-insert-lambda
"a" #'racket-expand-again) (:prefix ("m" . "macros")
(:prefix ("g" . "goto") "d" #'racket-expand-definition
"b" #'racket-unvisit "e" #'racket-expand-last-sexp
"d" #'racket-visit-definition "r" #'racket-expand-region
"m" #'racket-visit-module "a" #'racket-expand-again)
"r" #'racket-open-require-path) (:prefix ("g" . "goto")
(:prefix ("s" . "send") "b" #'racket-unvisit
"d" #'racket-send-definition "d" #'racket-visit-definition
"e" #'racket-send-last-sexp "m" #'racket-visit-module
"r" #'racket-send-region) "r" #'racket-open-require-path)
:map racket-repl-mode-map (:prefix ("s" . "send")
"l" #'racket-logger "d" #'racket-send-definition
"h" #'racket-repl-documentation "e" #'racket-send-last-sexp
"y" #'racket-insert-lambda "r" #'racket-send-region)
"u" #'racket-backward-up-list :map racket-repl-mode-map
(:prefix ("m" . "macros") "l" #'racket-logger
"d" #'racket-expand-definition "h" #'racket-repl-documentation
"e" #'racket-expand-last-sexp "y" #'racket-insert-lambda
"f" #'racket-expand-file "u" #'racket-backward-up-list
"r" #'racket-expand-region) (:prefix ("m" . "macros")
(:prefix ("g" . "goto") "d" #'racket-expand-definition
"b" #'racket-unvisit "e" #'racket-expand-last-sexp
"m" #'racket-visit-module "f" #'racket-expand-file
"d" #'racket-repl-visit-definition)))) "r" #'racket-expand-region)
(:prefix ("g" . "goto")
"b" #'racket-unvisit
"m" #'racket-visit-module
"d" #'racket-repl-visit-definition)))))

View file

@ -91,6 +91,16 @@
"P" #'rubocop-autocorrect-project)) "P" #'rubocop-autocorrect-project))
(use-package! ruby-json-to-hash
:defer t
:init
(map! :after ruby-mode
:map ruby-mode-map
:localleader
"J" #'ruby-json-to-hash-parse-json
"j" #'ruby-json-to-hash-toggle-let))
;; ;;
;;; Package & Ruby version management ;;; Package & Ruby version management
@ -182,6 +192,9 @@
"v" #'minitest-verify)) "v" #'minitest-verify))
;;
;;; Rails integration
(use-package! projectile-rails (use-package! projectile-rails
:when (modulep! +rails) :when (modulep! +rails)
:hook ((ruby-mode inf-ruby-mode projectile-rails-server-mode) . projectile-rails-mode) :hook ((ruby-mode inf-ruby-mode projectile-rails-server-mode) . projectile-rails-mode)
@ -199,3 +212,29 @@
(map! :localleader (map! :localleader
:map projectile-rails-mode-map :map projectile-rails-mode-map
"r" #'projectile-rails-command-map)) "r" #'projectile-rails-command-map))
(use-package! rails-routes
:when (featurep! +rails)
:defer t
:init
(map! :after ruby-mode
:map ruby-mode-map
"C-c o" #'rails-routes-insert
"C-c C-o" #'rails-routes-insert-no-cache
"C-c ! o" #'rails-routes-jump)
(map! :after web-mode
:map web-mode-map
"C-c o" #'rails-routes-insert
"C-c C-o" #'rails-routes-insert-no-cache
"C-c ! o" #'rails-routes-jump))
(use-package! rails-i18n
:when (featurep! +rails)
:defer t
:init
(map! :after ruby-mode
:map ruby-mode-map
"C-c i" #'rails-i18n-insert-with-cache)
(map! :after web-mode
:map web-mode-map
"C-c i" #'rails-i18n-insert-with-cache))

View file

@ -30,7 +30,12 @@
(package! rspec-mode :pin "29df3d081c6a1cbdf840cd13d45ea1c100c5bbaa") (package! rspec-mode :pin "29df3d081c6a1cbdf840cd13d45ea1c100c5bbaa")
(package! minitest :pin "5999c45c047212cee15a2be67e78787776a79c35") (package! minitest :pin "5999c45c047212cee15a2be67e78787776a79c35")
;; Refactoring
(package! ruby-json-to-hash :pin "383b22bb2e007289ac0dba146787d02ff99d4415")
;; Rails ;; Rails
(when (modulep! +rails) (when (modulep! +rails)
(package! rails-routes :pin "eab995a9297ca5bd9bd4f4c2737f2fecfc36def0")
(package! rails-i18n :pin "8e87e4e48e31902b8259ded28a208c2e7efea6e9")
(package! projectile-rails :pin "701784df7befe17b861f1b53fe9cbc59d0b94b9f") (package! projectile-rails :pin "701784df7befe17b861f1b53fe9cbc59d0b94b9f")
(package! inflections :pin "55caa66a7cc6e0b1a76143fd40eff38416928941")) (package! inflections :pin "55caa66a7cc6e0b1a76143fd40eff38416928941"))

View file

@ -1,7 +0,0 @@
;; This file supplies some metadata about this module repo to Doom's module
;; manager. None of them are required, but it's a good idea to include them so
;; Doom can perform some sanity checks for you.
:root "./" ; where the module tree starts
:version "21.12" ; version of this repo
:requires "3.0.0" ; minimum supported version of Doom's core

View file

@ -45,6 +45,8 @@ be enabled. If any function returns non-nil, the mode will not be activated."
;; TODO: Uncomment once we support treesit ;; TODO: Uncomment once we support treesit
;; (setq indent-bars-treesit-support (modulep! :tools tree-sitter)) ;; (setq indent-bars-treesit-support (modulep! :tools tree-sitter))
;; indent-bars adds this to `enable-theme-functions', which was introduced in
;; 29.1, which will be redundant with `doom-load-theme-hook'.
(unless (boundp 'enable-theme-functions) (unless (boundp 'enable-theme-functions)
(add-hook 'doom-load-theme-hook #'indent-bars-reset-styles)) (add-hook 'doom-load-theme-hook #'indent-bars-reset-styles))

View file

@ -3,4 +3,4 @@
(package! indent-bars (package! indent-bars
:recipe (:host github :repo "jdtsmith/indent-bars") :recipe (:host github :repo "jdtsmith/indent-bars")
:pin "c8376cf4373a6444ca88e88736db7576dedb51d6") :pin "c8376cf4373a6444ca88e88736db7576dedb51d6")

View file

@ -124,6 +124,11 @@ and cannot run in."
(setq prettify-symbols-unprettify-at-point 'right-edge) (setq prettify-symbols-unprettify-at-point 'right-edge)
(when (modulep! +extra) (when (modulep! +extra)
;; Lisp modes offer their own defaults for `prettify-symbols-mode' (just a
;; lambda symbol substitution), but this might be unexpected if the user
;; enables +extra but has unset `+ligatures-extra-symbols'.
(setq lisp-prettify-symbols-alist nil)
(add-hook 'after-change-major-mode-hook #'+ligatures-init-extra-symbols-h)) (add-hook 'after-change-major-mode-hook #'+ligatures-init-extra-symbols-h))
(cond (cond

View file

@ -69,7 +69,8 @@
:emacs :emacs
dired ; making dired pretty [functional] dired ; making dired pretty [functional]
electric ; smarter, keyword-based electric-indent electric ; smarter, keyword-based electric-indent
;;ibuffer ; interactive buffer management ;;eww ; the internet is gross
;;ibuffer ; interactive buffer management
undo ; persistent, smarter undo for your inevitable mistakes undo ; persistent, smarter undo for your inevitable mistakes
vc ; version-control and Emacs, sitting in a tree vc ; version-control and Emacs, sitting in a tree
@ -154,6 +155,7 @@
org ; organize your plain life in plain text org ; organize your plain life in plain text
;;php ; perl's insecure younger brother ;;php ; perl's insecure younger brother
;;plantuml ; diagrams for confusing people more ;;plantuml ; diagrams for confusing people more
;;graphviz ; diagrams for confusing yourself even more
;;purescript ; javascript, but functional ;;purescript ; javascript, but functional
;;python ; beautiful is better than ugly ;;python ; beautiful is better than ugly
;;qt ; the 'cutest' gui framework ever ;;qt ; the 'cutest' gui framework ever