Merge branch 'develop' of https://github.com/hlissner/doom-emacs into develop

This commit is contained in:
Patrick Elliott 2018-06-26 02:19:25 +02:00
commit e5fc8b6c81
81 changed files with 1423 additions and 900 deletions

View file

@ -10,34 +10,33 @@
set -e
cleanup() {
emacsclient --eval '(kill-emacs)'
emacsclient --eval '(let (kill-emacs-hook) (kill-emacs))'
}
# If emacs isn't running, we start a temporary daemon, solely for this window.
daemon=
if ! pgrep emacs >/dev/null; then
emacs --daemon
trap cleanup EXIT INT TERM
daemon=1
if ! emacsclient -e nil; then
emacs --daemon
trap cleanup EXIT INT TERM
daemon=1
fi
# org-capture key mapped to argument flags
keys=$(emacsclient -e "(+org-capture-available-keys)" | cut -d '"' -f2)
while getopts $keys opt; do
key="\"$opt\""
break
key="\"$opt\""
break
done
shift $((OPTIND-1))
[ -t 0 ] && str="$*" || str=$(cat)
if [[ $daemon ]]; then
emacsclient -a "" \
-c -F '((name . "org-capture") (width . 70) (height . 25) (transient . t))' \
-e "(+org-capture/open-frame \"$str\" ${key:-nil})"
emacsclient -a "" \
-c -F '((name . "org-capture") (width . 70) (height . 25) (transient . t))' \
-e "(+org-capture/open-frame \"$str\" ${key:-nil} t)"
else
# Non-daemon servers flicker a lot if frames are created from terminal, so
# we do it internally instead.
emacsclient -a "" \
-e "(+org-capture/open-frame \"$str\" ${key:-nil})"
# Non-daemon servers flicker a lot if frames are created from terminal, so we
# do it internally instead.
emacsclient -a "" \
-e "(+org-capture/open-frame \"$str\" ${key:-nil})"
fi

View file

@ -12,7 +12,7 @@
;; Like persistent-soft, caches assume a 2-tier structure, where all caches are
;; namespaced by location.
(defvar doom-cache-alists ()
(defvar doom-cache-alists '(t)
"An alist of alists, containing lists of variables for the doom cache library
to persist across Emacs sessions.")
@ -24,7 +24,7 @@ name under `pcache-directory' (by default a subdirectory under
(defun doom|save-persistent-cache ()
"Hook to run when an Emacs session is killed. Saves all persisted variables
listed in `doom-cache-alists' to files."
(dolist (alist doom-cache-alists)
(dolist (alist (butlast doom-cache-alists 1))
(cl-loop with key = (car alist)
for var in (cdr alist)
if (symbol-value var)
@ -54,8 +54,8 @@ Warning: this is incompatible with buffer-local variables."
(dolist (var variables)
(when (doom-cache-exists var location)
(set var (doom-cache-get var location))))
(map-put doom-cache-alists location
(append variables (cdr (assq location doom-cache-alists)))))
(setf (alist-get location doom-cache-alists)
(append variables (cdr (assq location doom-cache-alists)))))
;;;###autoload
(defun doom-cache-desist (location &optional variables)
@ -63,10 +63,11 @@ Warning: this is incompatible with buffer-local variables."
`doom-cache-alists', thus preventing them from being saved between sessions.
Does not affect the actual variables themselves or their values."
(if variables
(map-put doom-cache-alists location
(cl-set-difference (cdr (assq location doom-cache-alists))
variables))
(map-delete doom-cache-alists location)))
(setf (alist-get location doom-cache-alists)
(cl-set-difference (cdr (assq location doom-cache-alists))
variables))
(delq (assq location doom-cache-alists)
doom-cache-alists)))
;;;###autoload
(defun doom-cache-get (key &optional location)

View file

@ -186,8 +186,7 @@ possible, or just one char if that's not possible."
(save-excursion
(insert-char ?\s (- ocol (current-column)) nil))))
;;
((and (= n 1)
(bound-and-true-p smartparens-mode))
((and (= n 1) (bound-and-true-p smartparens-mode))
(cond ((and (memq (char-before) (list ?\ ?\t))
(save-excursion
(and (> (- (skip-chars-backward " \t" (line-beginning-position))) 0)
@ -213,7 +212,7 @@ possible, or just one char if that's not possible."
((run-hook-with-args-until-success 'doom-delete-backward-functions))
((doom/backward-delete-whitespace-to-column)))))))
;; Otherwise, do simple deletion.
(t (delete-char (- n) killflag))))
((delete-char (- n) killflag))))
;;;###autoload
(defun doom/retab (arg &optional beg end)

47
core/autoload/hydras.el Normal file
View file

@ -0,0 +1,47 @@
;;; core/autoload/hydras.el -*- lexical-binding: t; -*-
;;;###autoload (autoload 'doom-text-zoom-hydra/body "core/autoload/hydras" nil nil)
(defhydra doom-text-zoom-hydra (:hint t :color red)
"
Text zoom: _j_:zoom in, _k_:zoom out, _0_:reset
"
("j" text-scale-increase "in")
("k" text-scale-decrease "out")
("0" (text-scale-set 0) "reset"))
;;;###autoload (autoload 'doom-window-nav-hydra/body "core/autoload/hydras" nil nil)
(defhydra doom-window-nav-hydra (:hint nil)
"
Split: _v_ert _s_:horz
Delete: _c_lose _o_nly
Switch Window: _h_:left _j_:down _k_:up _l_:right
Buffers: _p_revious _n_ext _b_:select _f_ind-file
Resize: _H_:splitter left _J_:splitter down _K_:splitter up _L_:splitter right
Move: _a_:up _z_:down _i_menu
"
("z" scroll-up-line)
("a" scroll-down-line)
("i" idomenu)
("h" windmove-left)
("j" windmove-down)
("k" windmove-up)
("l" windmove-right)
("p" previous-buffer)
("n" next-buffer)
("b" switch-to-buffer)
("f" find-file)
("s" split-window-below)
("v" split-window-right)
("c" delete-window)
("o" delete-other-windows)
("H" hydra-move-splitter-left)
("J" hydra-move-splitter-down)
("K" hydra-move-splitter-up)
("L" hydra-move-splitter-right)
("q" nil))

View file

@ -1,31 +0,0 @@
;;; core/autoload/memoize.el -*- lexical-binding: t; -*-
;;;###autoload
(defvar doom-memoized-table (make-hash-table :test 'equal :size 10)
"A lookup table containing memoized functions. The keys are argument lists,
and the value is the function's return value.")
;;;###autoload
(defun doom-memoize (name)
"Memoizes an existing function. NAME is a symbol."
(let ((func (symbol-function name)))
(put name 'function-documentation
(concat (documentation func) " (memoized)"))
(fset name
`(lambda (&rest args)
(let ((key (cons ',name args)))
(or (gethash key doom-memoized-table)
(puthash key (apply ',func args)
doom-memoized-table)))))))
;;;###autoload
(defmacro def-memoized! (name arglist &rest body)
"Create a memoize'd function. NAME, ARGLIST, DOCSTRING and BODY
have the same meaning as in `defun'."
(declare (indent defun) (doc-string 3))
`(,(if (bound-and-true-p byte-compile-current-file)
'with-no-warnings
'progn)
(defun ,name ,arglist ,@body)
(doom-memoize ',name)))

View file

@ -14,15 +14,17 @@
table))))
(defmacro doom--condition-case! (&rest body)
`(condition-case-unless-debug ex
`(condition-case-unless-debug e
(progn ,@body)
('user-error
(print! (bold (red " NOTICE: %s" ex))))
(print! (bold (red " NOTICE: %s" e))))
('file-error
(print! (bold (red " FILE ERROR: %s" (error-message-string ex))))
(print! (bold (red " FILE ERROR: %s" (error-message-string e))))
(print! " Trying again...")
(quiet! (doom-refresh-packages-maybe t))
,@body)))
,@body)
('error
(print! (bold (red " FATAL ERROR: %s\n Run again with the -d flag for details" e))))))
(defun doom--refresh-pkg-cache ()
"Clear the cache for `doom-refresh-packages-maybe'."
@ -88,11 +90,12 @@ list of the package."
(list name old-version new-version)))))
;;;###autoload
(defun doom-package-prop (name prop)
(defun doom-package-prop (name prop &optional eval)
"Return PROPerty in NAME's plist."
(cl-check-type name symbol)
(cl-check-type prop keyword)
(plist-get (cdr (assq name doom-packages)) prop))
(let ((value (plist-get (cdr (assq name doom-packages)) prop)))
(if eval (eval value) value)))
;;;###autoload
(defun doom-package-different-backend-p (name)
@ -164,9 +167,9 @@ files."
if (and (or (not backend)
(eq (doom-package-backend sym t) backend))
(or (eq ignored 'any)
(if ignored
(plist-get plist :ignore)
(not (plist-get plist :ignore))))
(let* ((form (plist-get plist :ignore))
(value (eval form)))
(if ignored value (not value))))
(or (eq disabled 'any)
(if disabled
(plist-get plist :disable)
@ -236,9 +239,9 @@ Used by `doom-packages-update'."
(let (quelpa-pkgs elpa-pkgs)
;; Separate quelpa from elpa packages
(dolist (pkg (mapcar #'car package-alist))
(when (and (or (not (doom-package-prop pkg :freeze))
(when (and (or (not (doom-package-prop pkg :freeze 'eval))
include-frozen-p)
(not (doom-package-prop pkg :ignore))
(not (doom-package-prop pkg :ignore 'eval))
(not (doom-package-different-backend-p pkg)))
(push pkg
(if (eq (doom-package-backend pkg) 'quelpa)
@ -345,7 +348,7 @@ example; the package name can be omitted)."
(package-install name))
(if (not (package-installed-p name))
(doom--delete-package-files name)
(map-put doom-packages name plist)
(setf (alist-get name doom-packages) plist)
name)))
;;;###autoload
@ -388,9 +391,10 @@ package.el as appropriate."
(unless (package-installed-p name)
(user-error "%s isn't installed" name))
(let ((inhibit-message (not doom-debug-mode))
(spec (assq name quelpa-cache))
quelpa-p)
(when (assq name quelpa-cache)
(setq quelpa-cache (map-delete quelpa-cache name))
(when spec
(setq quelpa-cache (delq spec quelpa-cache))
(quelpa-save-cache)
(setq quelpa-p t))
(package-delete (cadr (assq name package-alist)) force-p)
@ -439,11 +443,11 @@ calls."
"Update `quelpa-cache' upon a successful `package-delete'."
(doom-initialize-packages)
(let ((name (package-desc-name desc)))
(when (and (not (package-installed-p name))
(assq name quelpa-cache))
(setq quelpa-cache (map-delete quelpa-cache name))
(quelpa-save-cache)
(doom--delete-package-files name))))
(unless (package-installed-p name)
(when-let* ((spec (assq name quelpa-cache)))
(setq quelpa-cache (delq spec quelpa-cache))
(quelpa-save-cache)
(doom--delete-package-files name)))))
;;

View file

@ -78,10 +78,10 @@ BODY will be run when this dispatcher is called."
(append
(when aliases
`((dolist (alias ',aliases)
(map-put doom--dispatch-alias-alist alias ',cmd))))
`((map-put doom--dispatch-command-alist ',cmd
(list :desc ,docstring
:body (lambda (args) ,form))))))))
(setf (alist-get alias doom--dispatch-alias-alist) ',cmd))))
`((setf (alist-get ',cmd doom--dispatch-command-alist)
(list :desc ,docstring
:body (lambda (args) ,form))))))))
;;
@ -749,6 +749,7 @@ If RECOMPILE-P is non-nil, only recompile out-of-date files."
(message "Couldn't find any valid targets")
(message "No targets to %scompile" (if recompile-p "re" "")))
(cl-return-from 'byte-compile))
(require 'use-package)
(condition-case e
(let ((use-package-defaults use-package-defaults)
(use-package-expand-minimally t))
@ -796,7 +797,7 @@ If RECOMPILE-P is non-nil, only recompile out-of-date files."
(if recompile-p "Recompiled" "Compiled")
total-ok (- (length target-files) total-noop)
total-noop))))
(error
((debug error)
(print! (red "\n%s\n\n%%s" "There were breaking errors.")
"Reverting changes...")
(signal 'doom-error (list 'byte-compile e))))))))

View file

@ -148,22 +148,27 @@ fundamental-mode) for performance sake."
sp-show-pair-from-inside t
sp-cancel-autoskip-on-backward-movement nil
sp-show-pair-delay 0.1
sp-max-pair-length 3)
sp-max-pair-length 4
sp-max-prefix-length 50)
;; smartparens conflicts with evil-mode's replace state
(add-hook 'evil-replace-state-entry-hook #'turn-off-smartparens-mode)
(add-hook 'evil-replace-state-exit-hook #'turn-on-smartparens-mode)
;; Slim down on smartparens' opinionated behavior
(defun doom|disable-smartparens-navigate-skip-match ()
(setq sp-navigate-skip-match nil
sp-navigate-consider-sgml-tags nil))
(add-hook 'after-change-major-mode-hook #'doom|disable-smartparens-navigate-skip-match)
;; autopairing in `eval-expression' and `evil-ex'
(defun doom|init-smartparens-in-eval-expression ()
"Enable `smartparens-mode' in the minibuffer, during `eval-expression' or
`evil-ex'."
(when (memq this-command '(eval-expression evil-ex))
(smartparens-mode)))
(add-hook 'minibuffer-setup-hook #'doom|init-smartparens-in-eval-expression)
(sp-local-pair 'minibuffer-inactive-mode "'" nil :actions nil)
(sp-local-pair '(xml-mode nxml-mode php-mode) "<!--" "-->"
:post-handlers '(("| " "SPC")))
;; smartparenss conflicts with evil-mode's replace state
(add-hook 'evil-replace-state-entry-hook #'turn-off-smartparens-mode)
(add-hook 'evil-replace-state-exit-hook #'turn-on-smartparens-mode)
(smartparens-global-mode +1))

View file

@ -46,68 +46,25 @@ If any hook returns non-nil, all hooks after it are ignored.")
;;
(def-package! which-key
:config
:defer 1
:after-call pre-command-hook
:init
(setq which-key-sort-order #'which-key-prefix-then-key-order
which-key-sort-uppercase-first nil
which-key-add-column-padding 1
which-key-max-display-columns nil
which-key-min-display-lines 6
which-key-side-window-slot -10)
:config
;; embolden local bindings
(set-face-attribute 'which-key-local-map-description-face nil :weight 'bold)
(which-key-setup-side-window-bottom)
(setq-hook! 'which-key-init-buffer-hook line-spacing 3)
(add-hook 'doom-post-init-hook #'which-key-mode))
(which-key-mode +1))
(def-package! hydra
:defer t
:config
(setq lv-use-seperator t)
(defhydra doom@text-zoom (:hint t :color red)
"
Text zoom: _j_:zoom in, _k_:zoom out, _0_:reset
"
("j" text-scale-increase "in")
("k" text-scale-decrease "out")
("0" (text-scale-set 0) "reset"))
(defhydra doom@window-nav (:hint nil)
"
Split: _v_ert _s_:horz
Delete: _c_lose _o_nly
Switch Window: _h_:left _j_:down _k_:up _l_:right
Buffers: _p_revious _n_ext _b_:select _f_ind-file
Resize: _H_:splitter left _J_:splitter down _K_:splitter up _L_:splitter right
Move: _a_:up _z_:down _i_menu
"
("z" scroll-up-line)
("a" scroll-down-line)
("i" idomenu)
("h" windmove-left)
("j" windmove-down)
("k" windmove-up)
("l" windmove-right)
("p" previous-buffer)
("n" next-buffer)
("b" switch-to-buffer)
("f" find-file)
("s" split-window-below)
("v" split-window-right)
("c" delete-window)
("o" delete-other-windows)
("H" hydra-move-splitter-left)
("J" hydra-move-splitter-down)
("K" hydra-move-splitter-up)
("L" hydra-move-splitter-right)
("q" nil)))
;; `hydra'
(setq lv-use-seperator t)
;;
@ -117,10 +74,11 @@ If any hook returns non-nil, all hooks after it are ignored.")
KEYS should be a string in kbd format.
DESC should be a string describing what KEY does.
MODES should be a list of major mode symbols."
(if modes
(dolist (mode modes)
(which-key-add-major-mode-key-based-replacements mode key desc))
(which-key-add-key-based-replacements key desc)))
(after! which-key
(if modes
(dolist (mode modes)
(which-key-add-major-mode-key-based-replacements mode key desc))
(which-key-add-key-based-replacements key desc))))
(defun doom--keyword-to-states (keyword)

View file

@ -3,7 +3,6 @@
;; Built in packages we use a lot of
(require 'subr-x)
(require 'cl-lib)
(require 'map)
(eval-and-compile
(unless EMACS26+
@ -11,7 +10,23 @@
;; if-let and when-let are deprecated in Emacs 26+ in favor of their
;; if-let* variants, so we alias them for 25 users.
(defalias 'if-let* #'if-let)
(defalias 'when-let* #'when-let))))
(defalias 'when-let* #'when-let)
;; `alist-get' doesn't have its 5th argument before Emacs 26
(defun doom*alist-get (key alist &optional default remove testfn)
"Return the value associated with KEY in ALIST.
If KEY is not found in ALIST, return DEFAULT.
Use TESTFN to lookup in the alist if non-nil. Otherwise, use `assq'.
This is a generalized variable suitable for use with `setf'.
When using it to set a value, optional argument REMOVE non-nil
means to remove KEY from ALIST if the new value is `eql' to DEFAULT."
(ignore remove) ;;Silence byte-compiler.
(let ((x (if (not testfn)
(assq key alist)
(assoc key alist testfn))))
(if x (cdr x) default)))
(advice-add #'alist-get :override #'doom*alist-get))))
;;
@ -36,6 +51,7 @@ Returns
(file-exists-p \"/an/absolute/path\"))))
This is used by `associate!', `file-exists-p!' and `project-file-exists-p!'."
(declare (pure t) (side-effect-free t))
(cond ((stringp spec)
`(file-exists-p
,(if (file-name-absolute-p spec)
@ -57,6 +73,7 @@ This is used by `associate!', `file-exists-p!' and `project-file-exists-p!'."
(t spec)))
(defun doom--resolve-hook-forms (hooks)
(declare (pure t) (side-effect-free t))
(cl-loop with quoted-p = (eq (car-safe hooks) 'quote)
for hook in (doom-enlist (doom-unquote hooks))
if (eq (car-safe hook) 'quote)
@ -82,24 +99,26 @@ This is used by `associate!', `file-exists-p!' and `project-file-exists-p!'."
(defun doom-unquote (exp)
"Return EXP unquoted."
(declare (pure t) (side-effect-free t))
(while (memq (car-safe exp) '(quote function))
(setq exp (cadr exp)))
exp)
(defun doom-enlist (exp)
"Return EXP wrapped in a list, or as-is if already a list."
(declare (pure t) (side-effect-free t))
(if (listp exp) exp (list exp)))
(defun doom-keyword-intern (str)
"Converts STR (a string) into a keyword (`keywordp')."
(or (stringp str)
(signal 'wrong-type-argument (list 'stringp str)))
(declare (pure t) (side-effect-free t))
(cl-check-type str string)
(intern (concat ":" str)))
(defun doom-keyword-name (keyword)
"Returns the string name of KEYWORD (`keywordp') minus the leading colon."
(or (keywordp keyword)
(signal 'wrong-type-argument (list 'keywordp keyword)))
(declare (pure t) (side-effect-free t))
(cl-check-type :test keyword)
(substring (symbol-name keyword) 1))
(cl-defun doom-files-in
@ -184,17 +203,17 @@ MATCH is a string regexp. Only entries that match it will be included."
;; Macros
;;
(defmacro FILE! ()
(defun FILE! ()
"Return the emacs lisp file this macro is called from."
`(cond ((bound-and-true-p byte-compile-current-file))
((stringp (car-safe current-load-list)) (car current-load-list))
(load-file-name)
(buffer-file-name)))
(cond ((bound-and-true-p byte-compile-current-file))
(load-file-name)
(buffer-file-name)
((stringp (car-safe current-load-list)) (car current-load-list))))
(defmacro DIR! ()
(defun DIR! ()
"Returns the directory of the emacs lisp file this macro is called from."
`(let ((file (FILE!)))
(and file (file-name-directory file))))
(let ((file (FILE!)))
(and file (file-name-directory file))))
(defmacro λ! (&rest body)
"A shortcut for inline interactive lambdas."
@ -402,7 +421,7 @@ The available conditions are:
collect `(add-hook ',hook #',hook-name))
`((add-hook 'after-change-major-mode-hook #',hook-name))))))
(match
`(map-put doom-auto-minor-mode-alist ,match ',mode))
`(add-to-list 'doom-auto-minor-mode-alist '(,match . ,mode)))
((user-error "Invalid `associate!' rules for mode [%s] (:modes %s :match %s :files %s :when %s)"
mode modes match files when)))))

View file

@ -7,7 +7,8 @@
"A hash table of enabled modules. Set by `doom-initialize-modules'.")
(defvar doom-modules-dirs
(list (expand-file-name "modules/" doom-private-dir) doom-modules-dir)
(list (expand-file-name "modules/" doom-private-dir)
doom-modules-dir)
"A list of module root directories. Order determines priority.")
(defconst doom-obsolete-modules
@ -35,8 +36,6 @@ A warning will be put out if these deprecated modules are used.")
session of Dooming. Will noop if used more than once, unless FORCE-P is
non-nil."
(when (or force-p (not doom-init-modules-p))
;; Set `doom-init-modules-p' early, so `doom-pre-init-hook' won't infinitely
;; recurse by accident if any of them need `doom-initialize-modules'.
(setq doom-init-modules-p t)
(when doom-private-dir
(condition-case e
@ -52,12 +51,14 @@ non-nil."
(defun doom-module-p (category module)
"Returns t if CATEGORY MODULE is enabled (ie. present in `doom-modules')."
(declare (pure t) (side-effect-free t))
(and (hash-table-p doom-modules)
(gethash (cons category module) doom-modules)
t))
(defun doom-module-get (category module &optional property)
"Returns the plist for CATEGORY MODULE. Gets PROPERTY, specifically, if set."
(declare (pure t) (side-effect-free t))
(when-let* ((plist (gethash (cons category module) doom-modules)))
(if property
(plist-get plist property)
@ -103,7 +104,8 @@ MODULE (symbol).
If the category isn't enabled this will always return nil. For finding disabled
modules use `doom-module-locate-path'."
(let ((path (doom-module-get category module :path)))
(let ((path (doom-module-get category module :path))
file-name-handler-alist)
(if file (expand-file-name file path)
path)))
@ -120,7 +122,8 @@ This doesn't require modules to be enabled. For enabled modules us
(setq category (substring (symbol-name category) 1)))
(when (and module (symbolp module))
(setq module (symbol-name module)))
(cl-loop for default-directory in doom-modules-dirs
(cl-loop with file-name-handler-alist = nil
for default-directory in doom-modules-dirs
for path = (concat category "/" module "/" file)
if (file-exists-p path)
return (expand-file-name path)))
@ -140,6 +143,7 @@ This doesn't require modules to be enabled. For enabled modules us
(defun doom-module-load-path (&optional all-p)
"Return a list of absolute file paths to activated modules. If ALL-P is
non-nil, return paths of possible modules, activated or otherwise."
(declare (pure t) (side-effect-free t))
(append (if all-p
(doom-files-in doom-modules-dirs
:type 'dirs
@ -184,7 +188,7 @@ non-nil, return paths of possible modules, activated or otherwise."
;;
;; This will load X on the first invokation of `find-file-hook' (then it will
;; remove itself from the hook/function).
(defvar doom--deferred-packages-alist ())
(defvar doom--deferred-packages-alist '(t))
(after! use-package-core
(add-to-list 'use-package-deferring-keywords :after-call nil #'eq)
(setq use-package-keywords
@ -192,10 +196,9 @@ non-nil, return paths of possible modules, activated or otherwise."
(defalias 'use-package-normalize/:after-call 'use-package-normalize-symlist)
(defun use-package-handler/:after-call (name _keyword hooks rest state)
(let ((fn (intern (format "doom|transient-hook--load-%s" name)))
(hooks (delete-dups hooks)))
(if (plist-get state :demand)
(use-package-process-keywords name rest state)
(if (plist-get state :demand)
(use-package-process-keywords name rest state)
(let ((fn (intern (format "doom|transient-hook--load-%s" name))))
(use-package-concat
`((fset ',fn
(lambda (&rest _)
@ -208,15 +211,19 @@ non-nil, return paths of possible modules, activated or otherwise."
(if (functionp hook)
(advice-remove hook #',fn)
(remove-hook hook #',fn)))
(map-delete doom--deferred-packages-alist ',name)
(delq (assq ',name doom--deferred-packages-alist)
doom--deferred-packages-alist)
(fmakunbound ',fn))))
(cl-loop for hook in hooks
collect (if (functionp hook)
`(advice-add #',hook :before #',fn)
`(add-hook ',hook #',fn)))
`((map-put doom--deferred-packages-alist
',name
'(,@hooks ,@(cdr (assq name doom--deferred-packages-alist)))))
(let (forms)
(dolist (hook hooks forms)
(push (if (functionp hook)
`(advice-add #',hook :before #',fn)
`(add-hook ',hook #',fn))
forms)))
`((unless (assq ',name doom--deferred-packages-alist)
(push '(,name) doom--deferred-packages-alist))
(nconc (assq ',name doom--deferred-packages-alist)
'(,@hooks)))
(use-package-process-keywords name rest state))))))
@ -276,7 +283,7 @@ to least)."
(throw 'doom-modules t))))
(let ((path (doom-module-locate-path category module)))
(if (not path)
(message "Couldn't find the %s %s module" category module)
(message "Warning: couldn't find the %s %s module" category module)
(let ((key (cons category module)))
(doom-module-set category module :flags flags :path path)
(push `(let ((doom--current-module ',key))
@ -330,23 +337,21 @@ to have them return non-nil (or exploit that to overwrite Doom's config)."
(defmacro require! (category module &rest plist)
"Loads the module specified by CATEGORY (a keyword) and MODULE (a symbol)."
(let ((doom-modules (copy-hash-table doom-modules)))
(apply #'doom-module-set category module
(mapcar #'eval plist))
(let ((module-path (doom-module-locate-path category module)))
(if (directory-name-p module-path)
`(condition-case-unless-debug ex
(let ((doom--current-module ',(cons category module)))
(load! "init" ,module-path :noerror)
(let ((doom--stage 'config))
(load! "config" ,module-path :noerror)))
('error
(lwarn 'doom-modules :error
"%s in '%s %s' -> %s"
(car ex) ,category ',module
(error-message-string ex))))
(warn 'doom-modules :warning "Couldn't find module '%s %s'"
category module)))))
`(let ((module-path (doom-module-locate-path ,category ',module)))
(doom-module-set ,category ',module ,@plist)
(if (directory-name-p module-path)
(condition-case-unless-debug ex
(let ((doom--current-module ',(cons category module)))
(load! "init" module-path :noerror)
(let ((doom--stage 'config))
(load! "config" module-path :noerror)))
('error
(lwarn 'doom-modules :error
"%s in '%s %s' -> %s"
(car ex) ,category ',module
(error-message-string ex))))
(warn 'doom-modules :warning "Couldn't find module '%s %s'"
,category ',module))))
(defmacro featurep! (module &optional submodule flag)
"Returns t if MODULE SUBMODULE is enabled. If FLAG is provided, returns t if
@ -370,8 +375,8 @@ omitted. eg. (featurep! +flag1)"
module (car module-pair)
submodule (cdr module-pair))))
(if flag
(and (memq flag (doom-module-get module submodule :flags)) t)
(doom-module-p module submodule)))
`(and (memq ',flag (doom-module-get ,module ',submodule :flags)) t)
`(doom-module-p ,module ',submodule)))
;;

View file

@ -171,7 +171,7 @@ them."
;; Module package macros
;;
(defmacro package! (name &rest plist)
(cl-defmacro package! (name &rest plist &key recipe pin disable _ignore _freeze)
"Declares a package and how to install it (if applicable).
This macro is declarative and does not load nor install packages. It is used to
@ -200,31 +200,27 @@ Returns t if package is successfully registered, and nil if it was disabled
elsewhere."
(declare (indent defun))
(doom--assert-stage-p 'packages #'package!)
(let* ((old-plist (cdr (assq name doom-packages)))
(pkg-recipe (or (plist-get plist :recipe)
(and old-plist (plist-get old-plist :recipe))))
(pkg-pin (or (plist-get plist :pin)
(and old-plist (plist-get old-plist :pin))))
(pkg-disable (or (plist-get plist :disable)
(and old-plist (plist-get old-plist :disable)))))
(when pkg-disable
(add-to-list 'doom-disabled-packages name nil #'eq))
(when pkg-recipe
(when (= 0 (% (length pkg-recipe) 2))
(setq plist (plist-put plist :recipe (cons name pkg-recipe))))
(when pkg-pin
(setq plist (plist-put plist :pin nil))))
(dolist (prop '(:ignore :freeze))
(when-let* ((val (plist-get plist prop)))
(setq plist (plist-put plist prop (eval val)))))
(when (file-in-directory-p (or (bound-and-true-p byte-compile-current-file)
load-file-name)
doom-private-dir)
(let ((plist (append plist (cdr (assq name doom-packages)))))
(when recipe
(when (cl-evenp (length recipe))
(setq plist (plist-put plist :recipe (cons name recipe))))
(setq pin nil
plist (plist-put plist :pin nil)))
(when (file-in-directory-p (FILE!) doom-private-dir)
(setq plist (plist-put plist :private t)))
`(progn
,(if pkg-pin `(map-put package-pinned-packages ',name ,pkg-pin))
(map-put doom-packages ',name ',plist)
(not (memq ',name doom-disabled-packages)))))
(let (newplist)
(while plist
(unless (null (cadr plist))
(push (cadr plist) newplist)
(push (car plist) newplist))
(pop plist)
(pop plist))
(setq plist newplist))
(macroexp-progn
(append (if disable `((add-to-list 'doom-disabled-packages ',name nil #'eq)))
(if pin `((setf (alist-get ',name package-pinned-packages) ,pin)))
`((setf (alist-get ',name doom-packages) ',plist)
(not (memq ',name doom-disabled-packages)))))))
(defmacro packages! (&rest packages)
"A convenience macro like `package!', but allows you to declare multiple

View file

@ -67,7 +67,9 @@ Also see `doom-before-switch-buffer-hook'.")
enable-recursive-minibuffers nil
frame-inhibit-implied-resize t
;; remove continuation arrow on right fringe
fringe-indicator-alist (map-delete fringe-indicator-alist 'continuation)
fringe-indicator-alist
(delq (assq 'continuation fringe-indicator-alist)
fringe-indicator-alist)
highlight-nonselected-windows nil
image-animate-loop t
indicate-buffer-boundaries nil
@ -126,13 +128,13 @@ Also see `doom-before-switch-buffer-hook'.")
(format "%s modeline segment" name))))
(cond ((and (symbolp (car body))
(not (cdr body)))
(map-put doom--modeline-var-alist name (car body))
`(map-put doom--modeline-var-alist ',name ',(car body)))
(add-to-list 'doom--modeline-var-alist (cons name (car body)))
`(add-to-list 'doom--modeline-var-alist (cons ',name ',(car body))))
(t
(map-put doom--modeline-fn-alist name sym)
(add-to-list 'doom--modeline-fn-alist (cons name sym))
`(progn
(fset ',sym (lambda () ,docstring ,@body))
(map-put doom--modeline-fn-alist ',name ',sym)
(add-to-list 'doom--modeline-fn-alist (cons ',name ',sym))
,(unless (bound-and-true-p byte-compile-current-file)
`(let (byte-compile-warnings)
(byte-compile #',sym))))))))
@ -308,7 +310,7 @@ DEFAULT is non-nil, set the default mode-line for all buffers."
;; highlight matching delimiters
(def-package! paren
:after-call post-command-hook
:after-call (after-find-file doom-before-switch-buffer-hook)
:config
(setq show-paren-delay 0.1
show-paren-highlight-openparen t
@ -549,7 +551,7 @@ frame's window-system, the theme will be reloaded.")
(custom-set-faces
(when (fontp doom-font)
(let ((xlfd (font-xlfd-name doom-font)))
(map-put default-frame-alist 'font xlfd)
(add-to-list 'default-frame-alist (cons 'font xlfd))
`(fixed-pitch ((t (:font ,xlfd))))))
(when (fontp doom-variable-pitch-font)
`(variable-pitch ((t (:font ,(font-xlfd-name doom-variable-pitch-font))))))
@ -712,7 +714,7 @@ windows, switch to `doom-fallback-buffer'. Otherwise, delegate to original
(defun doom|init-ui ()
"Initialize Doom's user interface by applying all its advice and hooks."
;; Make `next-buffer', `other-buffer', etc. ignore unreal buffers.
(map-put default-frame-alist 'buffer-predicate #'doom-buffer-frame-predicate)
(add-to-list 'default-frame-alist (cons 'buffer-predicate #'doom-buffer-frame-predicate))
;; Switch to `doom-fallback-buffer' if on last real buffer
(advice-add #'kill-this-buffer :around #'doom*switch-to-fallback-buffer-maybe)
;; Don't kill the fallback buffer

View file

@ -7,6 +7,7 @@
company
:ui
doom-dashboard
popup
:tools
password-store
:lang

View file

@ -12,17 +12,18 @@
(defun +email--mark-seen (docid msg target)
(mu4e~proc-move docid (mu4e~mark-check-target target) "+S-u-N"))
(map-delete mu4e-marks 'delete)
(map-put mu4e-marks 'trash
(list :char '("d" . "")
:prompt "dtrash"
:dyn-target (lambda (_target msg) (mu4e-get-trash-folder msg))
:action #'+email--mark-seen))
;; Refile will be my "archive" function.
(map-put mu4e-marks 'refile
(list :char '("r" . "") :prompt "refile"
:show-target (lambda (_target) "archive")
:action #'+email--mark-seen))
(delq (assq 'delete mu4e-marks) mu4e-marks)
(setf (alist-get 'trash mu4e-marks)
(list :char '("d" . "")
:prompt "dtrash"
:dyn-target (lambda (_target msg) (mu4e-get-trash-folder msg))
:action #'+email--mark-seen)
;; Refile will be my "archive" function.
(alist-get 'refile mu4e-marks)
(list :char '("d" . "")
:prompt "dtrash"
:dyn-target (lambda (_target msg) (mu4e-get-trash-folder msg))
:action #'+email--mark-seen))
;; This hook correctly modifies gmail flags on emails when they are marked.
;; Without it, refiling (archiving), trashing, and flagging (starring) email

View file

@ -40,6 +40,7 @@ default/fallback account."
(setq-default mu4e-context-current context))
context)))
;; FIXME obsolete :email
;;;###autoload
(def-setting! :email (label letvars &optional default-p)
:obsolete set-email-account!

View file

@ -3,10 +3,12 @@
This module turns adds an IRC client to Emacs ([[https://github.com/jorgenschaefer/circe][~circe~)]] with native notifications ([[https://github.com/eqyiel/circe-notifications][circe-notifications]]).
* Table of Contents :TOC:
- [[#dependencies][Dependencies]]
- [[#configure][Configure]]
- [[#pass-the-unix-password-manager][Pass: the unix password manager]]
- [[#emacs-auth-source-api][Emacs' auth-source API]]
- [[Dependencies][Dependencies]]
- [[Configure][Configure]]
- [[Pass: the unix password manager][Pass: the unix password manager]]
- [[Emacs' auth-source API][Emacs' auth-source API]]
- [[Appendix][Appendix]]
- [[Commands][Commands]]
* Dependencies
This module has no dependencies, besides =gnutls-cli= or =openssl= for secure connections.
@ -52,6 +54,15 @@ But wait, there's more! This stores your password in a public variable which cou
And you're good to go!
Note that =+pass-get-user= tries to find your username by looking for the fields
listed in =+pass-user-fields= (by default =login=, =user==, =username== and =email=)=).
An example configuration looks like
#+BEGIN_SRC txt :tangle no
mysecretpassword
username: myusername
#+END_SRC
** Emacs' auth-source API
~auth-source~ is built into Emacs. As suggested [[https://github.com/jorgenschaefer/circe/wiki/Configuration#safer-password-management][in the circe wiki]], you can store (and retrieve) encrypted passwords with it.
@ -78,3 +89,24 @@ And you're good to go!
:channels ("#emacs")))
#+END_SRC
* Appendix
** Commands
To connect to IRC you can invoke the ~=irc~ function using =M-x= or your own
custom keybinding.
| command | description |
|---------+-------------------------------------------|
| ~=irc~ | Connect to IRC and all configured servers |
When in a circe buffer these keybindings will be available.
| command | key | description |
|------------------------+-----------+----------------------------------------------|
| ~tracking-next-buffer~ | =SPC m a= | Switch to the next active buffer |
| ~circe-command-JOIN~ | =SPC m j= | Join a channel |
| ~+irc/send-message~ | =SPC m m= | Send a private message |
| ~circe-command-NAMES~ | =SPC m n= | List the names of the current channel |
| ~circe-command-PART~ | =SPC m p= | Part the current channel |
| ~+irc/quit~ | =SPC m Q= | Kill the current circe session and workgroup |
| ~circe-reconnect~ | =SPC m R= | Reconnect the current server |

View file

@ -36,6 +36,12 @@ workspace for it."
(and (+irc-setup-wconf inhibit-workspace)
(call-interactively #'circe)))
;;;###autoload
(defun +irc/send-message (who what)
"Send WHO a message containing WHAT."
(interactive "sWho: \nsWhat: ")
(circe-command-MSG who what))
;;;###autoload
(defun +irc/quit ()
"Kill current circe session and workgroup."

View file

@ -0,0 +1,16 @@
;;; app/irc/autoload/settings.el -*- lexical-binding: t; -*-
;;;###autodef
(defun set-irc-server! (server letvars)
"Registers an irc SERVER for circe.
See `circe-network-options' for details."
(after! circe
(push (cons server letvars) circe-network-options)))
;; FIXME obsolete :irc
;;;###autoload
(def-setting! :irc (server letvars)
:obsolete set-irc-server!
`(after! circe
(push (cons ,server ,letvars) circe-network-options)))

View file

@ -36,11 +36,6 @@ See `circe-notifications-watch-strings'.")
Useful for ZNC users who want to avoid the deluge of notifications during buffer
playback.")
(def-setting! :irc (server letvars)
"Registers an irc server for circe."
`(after! circe
(push (cons ,server ,letvars) circe-network-options)))
(defvar +irc--defer-timer nil)
(defsubst +irc--pad (left right)
@ -125,7 +120,23 @@ playback.")
(after! solaire-mode
;; distinguish chat/channel buffers from server buffers.
(add-hook 'circe-chat-mode-hook #'solaire-mode)))
(add-hook 'circe-chat-mode-hook #'solaire-mode))
(map!
(:localleader
(:map circe-mode-map
:desc "Next active buffer" :n "a" #'tracking-next-buffer
:desc "Join channel" :n "j" #'circe-command-JOIN
:desc "Send private message" :n "m" #'+irc/send-message
:desc "Part current channel" :n "p" #'circe-command-PART
:desc "Quit irc" :n "Q" #'+irc/quit
:desc "Reconnect" :n "R" #'circe-reconnect
(:when (featurep! :completion ivy)
:desc "Jump to channel" :n "c" #'+irc/ivy-jump-to-channel))
(:map circe-channel-mode-map
:desc "Show names" :n "n" #'circe-command-NAMES))))
(def-package! circe-color-nicks

View file

@ -28,7 +28,7 @@
:config
(helm-mode +1)
;; helm is too heavy for find-file-at-point
(map-put helm-completing-read-handlers-alist 'find-file-at-point nil))
(add-to-list 'helm-completing-read-handlers-alist (cons #'find-file-at-point nil)))
(def-package! helm
@ -179,11 +179,11 @@
(map! (:after helm
:map helm-map
:ni "M-[" #'helm-previous-source
:ni "M-]" #'helm-next-source
:ni "M-l" #'helm-execute-persistent-action
:ni "M-j" #'helm-next-line
:ni "M-k" #'helm-previous-line
:ni "C-S-p" #'helm-previous-source
:ni "C-S-n" #'helm-next-source
:ni "C-l" #'helm-execute-persistent-action
:ni "C-j" #'helm-next-line
:ni "C-k" #'helm-previous-line
:ni "C-f" #'helm-next-page
:ni "C-b" #'helm-previous-page
:n [tab] #'helm-select-action ; TODO: Ivy has "ga".
@ -206,7 +206,7 @@
:map (helm-find-files-map helm-read-file-map)
:n "go" #'helm-ff-run-switch-other-window
:n "/" #'helm-ff-run-find-sh-command
:ni "S-<return>" #'helm-ff-run-switch-other-window
:ni "M-<return>" #'helm-ff-run-switch-other-window
:ni "M-h" #'helm-find-files-up-one-level
:n "=" #'helm-ff-run-ediff-file
:n "%" #'helm-ff-run-query-replace-regexp
@ -219,16 +219,16 @@
:map helm-buffer-map
:n "go" #'helm-buffer-switch-other-window
:n "gO" #'display-buffer
:ni "S-<return>" #'helm-buffer-switch-other-window
:ni "M-<return>" #'display-buffer
:ni "M-<return>" #'helm-buffer-switch-other-window
:ni "<return>" #'display-buffer
:n "=" #'helm-buffer-run-ediff
:n "%" #'helm-buffer-run-query-replace-regexp
:n "D" #'helm-buffer-run-kill-persistent) ; Ivy has "D".
(:after helm-regexp
:map helm-moccur-map
:n "go" #'helm-moccur-run-goto-line-ow
:ni "S-<return>" #'helm-moccur-run-goto-line-ow)
:ni "M-<return>" #'helm-moccur-run-goto-line-ow)
(:after helm-grep
:map helm-grep-map
:n "go" #'helm-grep-run-other-window-action
:ni "S-<return>" #'helm-grep-run-other-window-action)))
:ni "M-<return>" #'helm-grep-run-other-window-action)))

View file

@ -0,0 +1,43 @@
;;; completion/ivy/autoload/hydras.el -*- lexical-binding: t; -*-
;;;###autoload (autoload '+ivy-coo-hydra/body "completion/ivy/autoload/hydras" nil nil)
(defhydra +ivy-coo-hydra (:hint nil :color pink)
"
Move ^^^^^^^^^^ | Call ^^^^ | Cancel^^ | Options^^ | Action _w_/_s_/_a_: %s(ivy-action-name)
----------^^^^^^^^^^-+--------------^^^^-+-------^^-+--------^^-+---------------------------------
_g_ ^ ^ _k_ ^ ^ _u_ | _f_orward _o_ccur | _i_nsert | _c_alling: %-7s(if ivy-calling \"on\" \"off\") _C_ase-fold: %-10`ivy-case-fold-search
^^ _h_ ^+^ _l_ ^^ | _RET_ done ^^ | _q_uit | _m_atcher: %-7s(ivy--matcher-desc) _t_runcate: %-11`truncate-lines
_G_ ^ ^ _j_ ^ ^ _d_ | _TAB_ alt-done ^^ | ^ ^ | _<_/_>_: shrink/grow
"
;; arrows
("j" ivy-next-line)
("k" ivy-previous-line)
("l" ivy-alt-done)
("h" ivy-backward-delete-char)
("g" ivy-beginning-of-buffer)
("G" ivy-end-of-buffer)
("d" ivy-scroll-up-command)
("u" ivy-scroll-down-command)
("e" ivy-scroll-down-command)
;; actions
("q" keyboard-escape-quit :exit t)
("C-g" keyboard-escape-quit :exit t)
("<escape>" keyboard-escape-quit :exit t)
("C-o" nil)
("i" nil)
("TAB" ivy-alt-done :exit nil)
("C-j" ivy-alt-done :exit nil)
("RET" ivy-done :exit t)
("C-m" ivy-done :exit t)
("C-SPC" ivy-call-and-recenter :exit nil)
("f" ivy-call)
("c" ivy-toggle-calling)
("m" ivy-toggle-fuzzy)
(">" ivy-minibuffer-grow)
("<" ivy-minibuffer-shrink)
("w" ivy-prev-action)
("s" ivy-next-action)
("a" ivy-read-action)
("t" (setq truncate-lines (not truncate-lines)))
("C" ivy-toggle-case-fold)
("o" ivy-occur :exit t))

View file

@ -126,49 +126,8 @@ immediately runs it on the current candidate (ending the ivy session)."
:init
(after! ivy
(define-key! ivy-minibuffer-map
"\C-o" #'+ivy@coo/body
(kbd "M-o") #'ivy-dispatching-done-hydra))
:config
(defhydra +ivy@coo (:hint nil :color pink)
"
Move ^^^^^^^^^^ | Call ^^^^ | Cancel^^ | Options^^ | Action _w_/_s_/_a_: %s(ivy-action-name)
----------^^^^^^^^^^-+--------------^^^^-+-------^^-+--------^^-+---------------------------------
_g_ ^ ^ _k_ ^ ^ _u_ | _f_orward _o_ccur | _i_nsert | _c_alling: %-7s(if ivy-calling \"on\" \"off\") _C_ase-fold: %-10`ivy-case-fold-search
^^ _h_ ^+^ _l_ ^^ | _RET_ done ^^ | _q_uit | _m_atcher: %-7s(ivy--matcher-desc) _t_runcate: %-11`truncate-lines
_G_ ^ ^ _j_ ^ ^ _d_ | _TAB_ alt-done ^^ | ^ ^ | _<_/_>_: shrink/grow
"
;; arrows
("j" ivy-next-line)
("k" ivy-previous-line)
("l" ivy-alt-done)
("h" ivy-backward-delete-char)
("g" ivy-beginning-of-buffer)
("G" ivy-end-of-buffer)
("d" ivy-scroll-up-command)
("u" ivy-scroll-down-command)
("e" ivy-scroll-down-command)
;; actions
("q" keyboard-escape-quit :exit t)
("C-g" keyboard-escape-quit :exit t)
("<escape>" keyboard-escape-quit :exit t)
("C-o" nil)
("i" nil)
("TAB" ivy-alt-done :exit nil)
("C-j" ivy-alt-done :exit nil)
("RET" ivy-done :exit t)
("C-m" ivy-done :exit t)
("C-SPC" ivy-call-and-recenter :exit nil)
("f" ivy-call)
("c" ivy-toggle-calling)
("m" ivy-toggle-fuzzy)
(">" ivy-minibuffer-grow)
("<" ivy-minibuffer-shrink)
("w" ivy-prev-action)
("s" ivy-next-action)
("a" ivy-read-action)
("t" (setq truncate-lines (not truncate-lines)))
("C" ivy-toggle-case-fold)
("o" ivy-occur :exit t)))
"\C-o" #'+ivy-coo-hydra/body
(kbd "M-o") #'ivy-dispatching-done-hydra)))
(def-package! wgrep
@ -186,26 +145,28 @@ immediately runs it on the current candidate (ending the ivy session)."
(advice-add #'ivy-posframe-setup :override #'ignore)
:config
(setq ivy-fixed-height-minibuffer nil
ivy-posframe-parameters `((min-width . 90)
(min-height . ,ivy-height)
(internal-border-width . 10)))
ivy-posframe-parameters
`((min-width . 90)
(min-height . ,ivy-height)
(internal-border-width . 10)))
;; ... let's do it manually
(dolist (fn (list 'ivy-posframe-display-at-frame-bottom-left
'ivy-posframe-display-at-frame-center
'ivy-posframe-display-at-point
'ivy-posframe-display-at-frame-bottom-window-center
'ivy-posframe-display
'ivy-posframe-display-at-window-bottom-left
'ivy-posframe-display-at-window-center
'+ivy-display-at-frame-center-near-bottom))
(map-put ivy-display-functions-props fn '(:cleanup ivy-posframe-cleanup)))
(map-put ivy-display-functions-alist 't '+ivy-display-at-frame-center-near-bottom)
;; ... let's do it manually instead
(unless (assq 'ivy-posframe-display-at-frame-bottom-left ivy-display-functions-props)
(dolist (fn (list 'ivy-posframe-display-at-frame-bottom-left
'ivy-posframe-display-at-frame-center
'ivy-posframe-display-at-point
'ivy-posframe-display-at-frame-bottom-window-center
'ivy-posframe-display
'ivy-posframe-display-at-window-bottom-left
'ivy-posframe-display-at-window-center
'+ivy-display-at-frame-center-near-bottom))
(push (cons fn '(:cleanup ivy-posframe-cleanup)) ivy-display-functions-props)))
;; default to posframe display function
(setf (alist-get t ivy-display-functions-alist) #'+ivy-display-at-frame-center-near-bottom)
;; posframe doesn't work well with async sources
(dolist (fn '(swiper counsel-rg counsel-ag counsel-pt counsel-grep counsel-git-grep))
(map-put ivy-display-functions-alist fn nil)))
(setf (alist-get fn ivy-display-functions-alist) nil)))
(def-package! flx
@ -216,7 +177,8 @@ immediately runs it on the current candidate (ending the ivy session)."
'((counsel-ag . ivy--regex-plus)
(counsel-rg . ivy--regex-plus)
(counsel-pt . ivy--regex-plus)
(counsel-grep-or-swiper . ivy--regex-plus)
(counsel-grep . ivy--regex-plus)
(swiper . ivy--regex-plus)
(t . ivy--regex-fuzzy))
ivy-initial-inputs-alist nil))

View file

@ -162,7 +162,7 @@
"M-RET" (+ivy-do-action! #'+ivy-git-grep-other-window-action))))
;; easymotion
:m "gs" #'+default/easymotion ; lazy-load `evil-easymotion'
:m "gs" #'+evil/easymotion ; lazy-load `evil-easymotion'
(:after evil-easymotion
:map evilem-map
"a" (evilem-create #'evil-forward-arg)

View file

@ -35,18 +35,3 @@
buffers."
(interactive "<a>")
(doom/kill-matching-buffers pattern bang))
;;;###autoload
(defun +default/easymotion ()
"Invoke and lazy-load `evil-easymotion' without compromising which-key
integration."
(interactive)
(let ((prefix (this-command-keys)))
(evil-define-key* 'motion 'global prefix nil)
(evilem-default-keybindings prefix)
(which-key-reload-key-sequence
(vconcat (where-is-internal evil-this-operator
evil-normal-state-map
t)
prefix))))

View file

@ -44,10 +44,6 @@
(sp-local-pair 'ruby-mode "{" "}"
:pre-handlers '(:rem sp-ruby-prehandler)
:post-handlers '(:rem sp-ruby-posthandler))
;; sp's default rules for these modes are obnoxious, so disable them
(provide 'smartparens-elixir)
(provide 'smartparens-latex)
(provide 'smartparens-lua)
;; Expand {|} => { | }
;; Expand {|} => {
@ -63,6 +59,18 @@
(sp-local-pair '(emacs-lisp-mode org-mode markdown-mode gfm-mode)
"[" nil :post-handlers '(:rem ("| " "SPC")))
;; Reasonable default pairs for comments
(sp-local-pair (append sp--html-modes '(markdown-mode gfm-mode))
"<!--" "-->" :actions '(insert) :post-handlers '(("| " "SPC")))
(sp-local-pair
'(js2-mode typescript-mode rjsx-mode rust-mode
c-mode c++-mode objc-mode java-mode php-mode
css-mode scss-mode less-css-mode stylus-mode)
"/*" "*/"
:actions '(insert)
:post-handlers '(("| " "SPC") ("|\n*/[i][d-2]" "RET") ("\n* ||\n*/[i][d-2]" "*")))
;; Highjacks backspace to:
;; a) balance spaces inside brackets/parentheses ( | ) -> (|)
;; b) delete space-indented `tab-width' steps at a time

View file

@ -7,7 +7,8 @@
(signal 'wrong-number-of-arguments (list 'even (length aliases))))
(after! eshell
(while aliases
(map-put +eshell-aliases (pop aliases) (list (pop aliases))))
(setf (alist-get (pop aliases) +eshell-aliases nil nil #'equal)
(list (pop aliases))))
(when (boundp 'eshell-command-aliases-list)
(if +eshell--default-aliases
(setq eshell-command-aliases-list

View file

@ -50,3 +50,42 @@ info in the `header-line-format' is a good indication."
(propertize author 'face 'git-timemachine-minibuffer-author-face)
(propertize sha-or-subject 'face 'git-timemachine-minibuffer-detail-face)
date-full date-relative))))
;;;###autoload (autoload '+hydra-smerge/body "emacs/vc/autoload" nil nil)
(defhydra +hydra-smerge (:hint nil
:pre (if (not smerge-mode) (smerge-mode 1))
;; Disable `smerge-mode' when quitting hydra if
;; no merge conflicts remain.
:post (smerge-auto-leave))
"
[smerge]
Movement Keep Diff Other
^_g_^ [_b_] base [_<_] upper/base [_C_] Combine
^_C-k_^ [_u_] upper [_=_] upper/lower [_r_] resolve
^_k_ ^ [_l_] lower [_>_] base/lower [_R_] remove
^_j_ ^ [_a_] all [_H_] hightlight
^_C-j_^ [_RET_] current [_E_] ediff
^_G_^ [_q_] quit
"
("g" (progn (goto-char (point-min)) (smerge-next)))
("G" (progn (goto-char (point-max)) (smerge-prev)))
("C-j" smerge-next)
("C-k" smerge-prev)
("j" next-line)
("k" previous-line)
("b" smerge-keep-base)
("u" smerge-keep-upper)
("l" smerge-keep-lower)
("a" smerge-keep-all)
("RET" smerge-keep-current)
("\C-m" smerge-keep-current)
("<" smerge-diff-base-upper)
("=" smerge-diff-upper-lower)
(">" smerge-diff-base-lower)
("H" smerge-refine)
("E" smerge-ediff)
("C" smerge-combine-with-next)
("r" smerge-resolve)
("R" smerge-kill-current)
("q" nil :color blue))

View file

@ -22,22 +22,24 @@
;; `git-commit-mode'
;; see https://chris.beams.io/posts/git-commit/
(setq git-commit-fill-column 72
git-commit-summary-max-length 50
git-commit-style-convention-checks '(overlong-summary-line non-empty-second-line))
(defun +vc|enforce-git-commit-conventions ()
"See https://chris.beams.io/posts/git-commit/"
(setq fill-column 72
git-commit-summary-max-length 50
git-commit-style-convention-checks '(overlong-summary-line non-empty-second-line)))
(add-hook 'git-commit-mode-hook #'+vc|enforce-git-commit-conventions)
(when (featurep! :feature evil)
(add-hook 'git-commit-mode-hook #'evil-insert-state))
;;
;; `vc'
;; `vc' (built-in)
;;
;; `vc-hooks'
(setq vc-make-backup-files nil)
;; `vc-annotate'
;; `vc-annotate' (built-in)
(after! vc-annotate
(set-popup-rules!
'(("^\\vc-d" :select nil) ; *vc-diff*
@ -46,18 +48,8 @@
'(vc-annotate-mode vc-git-log-view-mode)
'normal))
;; `smerge-mode'
(defun +vcs|enable-smerge-mode-maybe ()
"Auto-enable `smerge-mode' when merge conflict is detected."
(save-excursion
(goto-char (point-min))
(when (re-search-forward "^<<<<<<< " nil :noerror)
(smerge-mode 1)
(when (and (featurep 'hydra) +vc-auto-hydra-smerge)
(+hydra-smerge/body)))))
(add-hook 'find-file-hook #'+vcs|enable-smerge-mode-maybe)
(after! smerge-mode ; built-in
;; `smerge-mode' (built-in)
(after! smerge-mode
(unless EMACS26+
(with-no-warnings
(defalias #'smerge-keep-upper #'smerge-keep-mine)
@ -66,40 +58,5 @@
(defalias #'smerge-diff-upper-lower #'smerge-diff-mine-other)
(defalias #'smerge-diff-base-lower #'smerge-diff-base-other)))
(defhydra +hydra-smerge (:hint nil
:pre (smerge-mode 1)
;; Disable `smerge-mode' when quitting hydra if
;; no merge conflicts remain.
:post (smerge-auto-leave))
"
Movement Keep Diff Other smerge
^_g_^ [_b_] base [_<_] upper/base [_C_] Combine
^_C-k_^ [_u_] upper [_=_] upper/lower [_r_] resolve
^_k_ ^ [_l_] lower [_>_] base/lower [_R_] remove
^_j_ ^ [_a_] all [_H_] hightlight
^_C-j_^ [_RET_] current [_E_] ediff
^_G_^ [_q_] quit"
("g" (progn (goto-char (point-min)) (smerge-next)))
("G" (progn (goto-char (point-max)) (smerge-prev)))
("C-j" smerge-next)
("C-k" smerge-prev)
("j" next-line)
("k" previous-line)
("b" smerge-keep-base)
("u" smerge-keep-upper)
("l" smerge-keep-lower)
("a" smerge-keep-all)
("RET" smerge-keep-current)
("\C-m" smerge-keep-current)
("<" smerge-diff-base-upper)
("=" smerge-diff-upper-lower)
(">" smerge-diff-base-lower)
("H" smerge-refine)
("E" smerge-ediff)
("C" smerge-combine-with-next)
("r" smerge-resolve)
("R" smerge-kill-current)
("q" nil :color blue)))
(add-hook 'smerge-mode-hook #'+hydra-smerge/body))

View file

@ -18,7 +18,7 @@ function that creates and returns the REPL buffer."
;;;###autoload
(def-setting! :repl (mode command)
:obsolete set-repl-handler!
`(push (cons ,mode ,command) +eval-repls))
`(set-repl-handler! ,mode ,command))
;;

View file

@ -370,3 +370,18 @@ more information on modifiers."
"Call `doom/escape' if `evil-force-normal-state' is called interactively."
(when (called-interactively-p 'any)
(call-interactively #'doom/escape)))
;;;###autoload
(defun +evil/easymotion ()
"Invoke and lazy-load `evil-easymotion' without compromising which-key
integration."
(interactive)
(let ((prefix (this-command-keys)))
(evil-define-key* 'motion 'global prefix nil)
(evilem-default-keybindings prefix)
(which-key-reload-key-sequence
(vconcat (when evil-this-operator
(where-is-internal evil-this-operator
evil-normal-state-map
t))
prefix))))

View file

@ -3,39 +3,6 @@
;; I'm a vimmer at heart. Its modal philosophy suits me better, and this module
;; strives to make Emacs a much better vim than vim was.
(defvar +evil-collection-disabled-list
'(kotlin-mode ; doesn't do anything useful
simple
;; we'll do these ourselves
anaconda-mode
company
dired
helm
ivy
minibuffer
ruby-mode
slime)
"A list of `evil-collection' modules to disable. See the definition of this
variable for an explanation of the defaults (in comments). See
`evil-collection-mode-list' for a list of available options.")
(def-package! evil-collection
:when (featurep! +everywhere)
:defer 1
:after-call post-command-hook
:preface
;; must be set before evil/evil-collection is loaded
(setq evil-want-integration nil
evil-collection-company-use-tng nil)
:config
(dolist (sym +evil-collection-disabled-list)
(setq evil-collection-mode-list
(funcall (if (symbolp sym) #'delq #'delete)
sym evil-collection-mode-list)))
(evil-collection-init))
(def-package! evil
:init
(setq evil-want-C-u-scroll t
@ -60,7 +27,9 @@ variable for an explanation of the defaults (in comments). See
evil-normal-state-cursor 'box
evil-emacs-state-cursor '(box +evil-emacs-cursor)
evil-insert-state-cursor 'bar
evil-visual-state-cursor 'hollow)
evil-visual-state-cursor 'hollow
;; must be set before evil/evil-collection is loaded
evil-want-integration (not (featurep! +everywhere)))
:config
(add-hook 'doom-post-init-hook #'evil-mode)
@ -169,7 +138,193 @@ variable for an explanation of the defaults (in comments). See
(evil-set-command-properties
'+evil:align :move-point t :ex-arg 'buffer-match :ex-bang t :evil-mc t :keep-visual t :suppress-operator t)
(evil-set-command-properties
'+evil:mc :move-point nil :ex-arg 'global-match :ex-bang t :evil-mc t))
'+evil:mc :move-point nil :ex-arg 'global-match :ex-bang t :evil-mc t)
;; `evil-collection'
;; *Truly* lazy-load evil-collection's modules, and do ourselves, here,
;; instead of lazy-loading evil-collection.el so we can ensure `after!' blocks
;; in private configs happen after evil-collection has finished.
;;
;; Also so we can be very selective about what modules it loads.
(when (featurep! +everywhere)
(after! eldoc
(eldoc-add-command-completions "evil-window-"))
(after! comint
(evil-define-key* 'normal comint-mode-map
(kbd "C-d") #'evil-scroll-down
(kbd "C-n") #'comint-next-input
(kbd "C-p") #'comint-previous-input
(kbd "gj") #'comint-next-input
(kbd "gk") #'comint-previous-input
(kbd "]") #'comint-next-input
(kbd "[") #'comint-previous-input)
(evil-define-key* 'insert comint-mode-map
(kbd "<up>") #'comint-previous-input
(kbd "<down>") #'comint-next-input))
(after! cus-edit
(evil-set-initial-state 'Custom-mode 'normal)
(evil-define-key* 'motion custom-mode-map
(kbd "<tab>") 'widget-forward
(kbd "S-<tab>") 'widget-backward
(kbd "<backtab>") 'widget-backward
(kbd "]") 'widget-forward
(kbd "[") 'widget-backward
(kbd "C-n") 'widget-forward
(kbd "C-p") 'widget-backward
"gj" 'widget-forward
"gk" 'widget-backward)
(evil-define-key* 'normal custom-mode-map
(kbd "<return>") 'Custom-newline
(kbd "C-o") 'Custom-goto-parent
"^" 'Custom-goto-parent
"<" 'Custom-goto-parent
;; quit
"q" 'Custom-buffer-done
"ZQ" 'evil-quit
"ZZ" 'Custom-buffer-done))
(after! help
(evil-set-initial-state 'help-mode 'normal)
(evil-define-key* 'normal help-mode-map
;; motion
(kbd "SPC") 'scroll-up-command
(kbd "S-SPC") 'scroll-down-command
(kbd "C-f") 'scroll-up-command
(kbd "C-b") 'scroll-down-command
(kbd "<tab>") 'forward-button
(kbd "<backtab>") 'backward-button
(kbd "C-o") 'help-go-back
(kbd "C-i") 'help-go-forward
;; TODO: Enable more help-go-* bindings?
;; "gj" 'help-go-forward
;; "gk" 'help-go-back
;; "\C-j" 'help-go-forward
;; "\C-k" 'help-go-back
;; The following bindings don't do what they are supposed to. "go" should
;; open in the same window and "gO" should open in a different one.
"go" 'push-button
"gO" 'push-button
"g?" 'describe-mode
"gr" 'revert-buffer
"<" 'help-go-back
">" 'help-go-forward
"r" 'help-follow
;; quit
"q" 'quit-window
"ZQ" 'evil-quit
"ZZ" 'quit-window))
(add-transient-hook! 'image-mode (evil-collection-init 'image))
(add-transient-hook! 'emacs-lisp-mode (evil-collection-init 'elisp-mode))
(defvar evil-collection-mode-list
'(ace-jump-mode
ag
alchemist
;; anaconda-mode
arc-mode
avy
bookmark
(buff-menu "buff-menu")
calc
calendar
cider
cmake-mode
;; comint
;; company
compile
;; custom
cus-theme
daemons
debbugs
debug
diff-mode
;; dired
doc-view
edebug
ediff
;; eldoc
;; elfeed
;; elisp-mode
elisp-refs
emms
epa
;; ert
eshell
eval-sexp-fu
etags-select
eww
flycheck
;; free-keys
geiser
ggtags
git-timemachine
go-mode
;; help
guix
;; helm
ibuffer
;; image
image+
indium
info
;; ivy
js2-mode
log-view
lsp-ui-imenu
lua-mode
;; kotlin-mode
macrostep
man
magit
mu4e
mu4e-conversation
neotree
notmuch
nov
;; occur is in replace.el which was built-in before Emacs 26.
(occur ,(if EMACS26+ 'replace "replace"))
outline
p4
;; (package-menu package)
paren
pass
(pdf pdf-view)
popup
proced
prodigy
profiler
python
quickrun
racer
realgud
reftex
rjsx-mode
robe
;; ruby-mode
rtags
;; simple
;; slime
(term term ansi-term multi-term)
tide
transmission
typescript-mode
vc-annotate
vdiff
view
vlf
which-key
wdired
wgrep
woman
xref
(ztree ztree-diff)))
(dolist (req evil-collection-mode-list)
(with-eval-after-load (car (doom-enlist req))
(evil-collection-init (list req))))))
;;
@ -231,12 +386,12 @@ variable for an explanation of the defaults (in comments). See
(cons (format "(%s " (or (read-string "(") "")) ")"))
;; Add escaped-sequence support to embrace
(map-put (default-value 'embrace--pairs-list)
?\\ (make-embrace-pair-struct
:key ?\\
:read-function #'+evil--embrace-escaped
:left-regexp "\\[[{(]"
:right-regexp "\\[]})]")))
(setf (alist-get ?\\ (default-value 'embrace--pairs-list))
(make-embrace-pair-struct
:key ?\\
:read-function #'+evil--embrace-escaped
:left-regexp "\\[[{(]"
:right-regexp "\\[]})]")))
(def-package! evil-escape
@ -249,12 +404,6 @@ variable for an explanation of the defaults (in comments). See
(add-hook 'pre-command-hook #'evil-escape-pre-command-hook)
(evil-define-key* '(insert replace visual operator) 'global "\C-g" #'evil-escape)
:config
;; TODO PR this upstream
(defun +evil*escape-func (ret)
(if (eq evil-state 'multiedit-insert)
#'evil-multiedit-state
ret))
(advice-add #'evil-escape-func :filter-return #'+evil*escape-func)
;; no `evil-escape' in minibuffer
(add-hook 'evil-escape-inhibit-functions #'minibufferp))
@ -332,8 +481,7 @@ the new algorithm is confusing, like in python or ruby."
;; Add custom commands to whitelisted commands
(dolist (fn '(doom/backward-to-bol-or-indent doom/forward-to-last-non-comment-or-eol
doom/backward-kill-to-bol-and-indent))
(map-put evil-mc-custom-known-commands
fn '((:default . evil-mc-execute-default-call))))
(add-to-list 'evil-mc-custom-known-commands `(,fn (:default . evil-mc-execute-default-call))))
;; Activate evil-mc cursors upon switching to insert mode
(defun +evil-mc|resume-cursors () (setq evil-mc-frozen nil))

View file

@ -2,7 +2,9 @@
(defun +file-templates--set (pred plist)
(if (null (car-safe plist))
(setq +file-templates-alist (map-delete +file-templates-alist pred))
(setq +file-templates-alist
(delq (assoc pred +file-templates-alist)
+file-templates-alist))
(push `(,pred ,@plist) +file-templates-alist)))
;;;###autodef
@ -56,7 +58,7 @@ these properties:
;;
;;;###autoload
(cl-defun +file-templates--expand (pred &key project mode trigger ignore)
(cl-defun +file-templates--expand (pred &key project mode trigger ignore _when)
"Auto insert a yasnippet snippet into current file and enter insert mode (if
evil is loaded and enabled)."
(when (and pred (not ignore))

View file

@ -9,8 +9,9 @@ DOCSET (a string).
See `devdocs-alist' for the defaults. "
(after! (:when (boundp 'devdocs-alist))
(dolist (mode (doom-enlist modes))
(map-put devdocs-alist mode docset))))
(setf (alist-get mode devdocs-alist) docset))))
;; FIXME obsolete :devdocs
;;;###autoload
(def-setting! :devdocs (modes docset)
"Map major MODES (one major-mode symbol or a list of them) to a devdocs

View file

@ -9,9 +9,13 @@
;;;###autodef
(defun set-docset! (modes &rest docsets)
"Registers a list of DOCSETS (strings) for MODES (either one major mode
"Registers a list of DOCSETS (strings) for MODES (either one major/minor mode
symbol or a list of them).
If MODES is a minor mode, you can use :add or :remove as the first element of
DOCSETS, to instruct it to append (or remove) those from the docsets already set
by a major-mode, if any.
Used by `+lookup/in-docsets' and `+lookup/documentation'."
(declare (indent defun))
(dolist (mode (doom-enlist modes))
@ -30,16 +34,9 @@ Used by `+lookup/in-docsets' and `+lookup/documentation'."
docsets)))))
(add-hook hook fn))))))
;; FIXME obsolete :docset
;;;###autoload
(def-setting! :docset (modes &rest docsets)
"Registers a list of DOCSETS (strings) for MODES (either one major mode
symbol or a list of them).
If MODES is a minor mode, you can use :add or :remove as the first element of
DOCSETS, to instruct it to append (or remove) those from the docsets already set
by a major-mode, if any.
Used by `+lookup/in-docsets' and `+lookup/documentation'."
:obsolete set-docset!
`(set-docset! ,modes ,@docsets))

View file

@ -56,6 +56,7 @@ properties:
(add-hook 'xref-backend-functions xref-backend nil t))))))
(add-hook hook fn))))))
;; FIXME obsolete :lookup
;;;###autoload
(def-setting! :lookup (modes &rest plist)
:obsolete set-lookup-handlers!
@ -72,7 +73,7 @@ properties:
"Search on: "
(mapcar #'car +lookup-provider-url-alist)
nil t)))
(map-put +lookup--last-provider key provider)
(setf (alist-get +lookup--last-provider key) provider)
provider))))
(defun +lookup--symbol-or-region (&optional initial)
@ -245,7 +246,7 @@ Otherwise, falls back on `find-file-at-point'."
((not (and +lookup-file-functions
(+lookup--jump-to :file path)))
(let ((fullpath (expand-file-name path)))
(when (file-equal-p fullpath buffer-file-name)
(when (and buffer-file-name (file-equal-p fullpath buffer-file-name))
(user-error "Already here"))
(let* ((insert-default-directory t)
(project-root (doom-project-root 'nocache))
@ -318,7 +319,9 @@ for the provider."
(user-error "The search query is empty"))
(funcall +lookup-open-url-fn (format url (url-encode-url search))))
(error
(map-delete +lookup--last-provider major-mode)
(setq +lookup--last-provider
(delq (assq major-mode +lookup--last-provider)
+lookup--last-provider))
(signal (car e) (cdr e)))))
;;;###autoload

View file

@ -9,6 +9,7 @@ can have its own snippets category, if the folder exists."
(fset fn (lambda () (yas-activate-extra-mode mode)))
(add-hook (intern (format "%s-hook" mode)) fn))))
;; FIXME obsolete :yas-minor-mode
;;;###autoload
(def-setting! :yas-minor-mode (mode)
:obsolete set-yas-minor-mode!

View file

@ -291,7 +291,9 @@ workspace to delete."
current-name))))
(condition-case-unless-debug ex
(let ((workspaces (+workspace-list-names)))
(cond ((> (length workspaces) 1)
(cond ((delq (selected-frame) (persp-frames-with-persp (get-frame-persp)))
(user-error "Can't close workspace, it's visible in another frame"))
((> (length workspaces) 1)
(+workspace-delete name)
(+workspace-switch
(if (+workspace-exists-p +workspace--last)
@ -330,18 +332,16 @@ workspace, otherwise the new workspace is blank."
(interactive "iP")
(unless name
(setq name (format "#%s" (+workspace--generate-id))))
(condition-case-unless-debug ex
(if (+workspace-exists-p name)
(error "%s already exists" name)
(+workspace-switch name t)
(if clone-p
(let ((persp (+workspace-get name)))
(dolist (window (window-list))
(persp-add-buffer (window-buffer window) persp nil)))
(delete-other-windows-internal)
(switch-to-buffer (doom-fallback-buffer)))
(+workspace/display))
('error (+workspace-error (cadr ex) t))))
(condition-case e
(cond ((+workspace-exists-p name)
(error "%s already exists" name))
(clone-p (persp-copy name t))
(t
(+workspace-switch name t)
(persp-delete-other-windows)
(switch-to-buffer (doom-fallback-buffer))
(+workspace/display)))
((debug error) (+workspace-error (cadr e) t))))
;;;###autoload
(defun +workspace/switch-to (index)

View file

@ -29,8 +29,9 @@ stored in `persp-save-dir'.")
;; If emacs is passed --restore, restore the last session on startup. This is
;; particularly useful for the `+workspace/restart-emacs-then-restore' command.
(defun +workspaces-restore-last-session (&rest _)
(add-hook 'emacs-startup-hook #'+workspace/load-session 'append))
(map-put command-switch-alist "--restore" #'+workspaces-restore-last-session)
(add-hook 'emacs-startup-hook #'+workspace/load-session :append))
(add-to-list 'command-switch-alist (cons "--restore" #'+workspaces-restore-last-session))
;;
;; Plugins
@ -41,7 +42,9 @@ stored in `persp-save-dir'.")
:init
(defun +workspaces|init ()
;; Remove default buffer predicate so persp-mode can put in its own
(setq default-frame-alist (map-delete default-frame-alist 'buffer-predicate))
(setq default-frame-alist
(delq (assq 'buffer-predicate default-frame-alist)
default-frame-alist))
(add-hook 'after-make-frame-functions #'+workspaces|init-frame)
(require 'persp-mode)
(unless (daemonp)
@ -160,8 +163,8 @@ Uses `+workspaces-main' to determine the name of the main workspace."
(list tag (buffer-name buf) vars
(buffer-name (buffer-base-buffer))))
:load-function (lambda (savelist &rest _rest)
(destructuring-bind
(buf-name vars base-buf-name &rest _rest) (cdr savelist)
(destructuring-bind (buf-name _vars base-buf-name &rest _)
(cdr savelist)
(push (cons buf-name base-buf-name)
+workspaces--indirect-buffers-to-restore)
nil)))

View file

@ -5,48 +5,49 @@
:var (persp-auto-resume-time
persp-auto-save-opt
persp-switch-to-added-buffer
persp-autokill-persp-when-removed-last-buffer
persp-autokill-buffer-on-remove
in1 in2 out1 out2
persp1 persp1-name persp2 persp2-name
doom-before-switch-buffer-hook
doom-after-switch-buffer-hook)
wconf)
(before-all
(delete-other-windows)
(require! :feature workspaces)
(require 'persp-mode))
(after-all
(unload-feature 'persp-mode t))
(before-each
(setq persp-auto-resume-time -1
(switch-to-buffer "*scratch*")
(setq wconf (current-window-configuration)
persp-auto-resume-time -1
persp-auto-save-opt 0
persp-switch-to-added-buffer nil
in1 (get-buffer-create "a")
in2 (get-buffer-create "b")
out1 (get-buffer-create "c")
out2 (get-buffer-create "d"))
persp-autokill-persp-when-removed-last-buffer nil
persp-autokill-buffer-on-remove nil
in1 (get-buffer-create "in1")
in2 (get-buffer-create "in2")
out1 (get-buffer-create "out1")
out2 (get-buffer-create "out2"))
(doom-set-buffer-real in1 t)
(doom-set-buffer-real out1 t)
(let (noninteractive)
(persp-mode +1))
(let (persp-before-switch-functions persp-activated-functions)
(setq persp1-name +workspaces-main
persp1 (persp-add-new persp1-name)
persp2-name "test"
persp2 (persp-add-new persp2-name))
(persp-frame-switch +workspaces-main))
(delete-other-windows)
(switch-to-buffer in1)
(persp-add-buffer (list in1 in2))
(spy-on 'persp-add-buffer :and-call-through)
(doom|init-custom-hooks))
(persp-mode +1)
(let (persp-before-switch-functions persp-activated-functions)
(setq persp1-name +workspaces-main
persp1 (persp-add-new persp1-name)
persp2-name "test"
persp2 (persp-add-new persp2-name))
(persp-switch persp1-name)
(persp-add-buffer (list in1 in2) persp1))))
(after-each
(doom|init-custom-hooks 'disable)
(let (kill-buffer-query-functions kill-buffer-hook)
(mapc #'kill-buffer (list in1 in2 out1 out2)))
(let (noninteractive)
(mapc #'persp-kill (cdr (persp-names)))
(persp-mode -1)))
(let (noninteractive ignore-window-parameters)
(dolist (persp (persp-names))
(ignore-errors (persp-kill persp)))
(persp-mode -1))
(set-window-configuration wconf)
(mapc #'kill-buffer (list in1 in2 out1 out2))))
;;
(describe "switch"
@ -80,7 +81,7 @@
(expect (+workspace-contains-buffer-p out1) :to-be nil))
(it "automatically adds interactively opened buffers"
(expect (+workspace-contains-buffer-p out1) :to-be nil)
(switch-to-buffer out1)
(with-current-buffer out1 (+workspaces|auto-add-buffer))
(expect (+workspace-contains-buffer-p out1)))
(xit "returns a list of orphaned buffers"
(expect (+workspace-orphaned-buffer-list) :to-contain out2)))
@ -107,20 +108,6 @@
(expect (+workspace-list-names) :not :to-contain persp2-name)))
(describe "command"
(describe "new"
(it "creates a new, blank workspace"
(quiet! (+workspace/new "X"))
(expect (one-window-p))
(expect (current-buffer) :to-be (doom-fallback-buffer)))
(it "clones a workspace"
(quiet! (+workspace/new "X" t))
(expect (current-buffer) :to-be in1)))
(describe "rename"
(it "renames the current workspace"
(quiet! (+workspace/rename "X"))
(expect (+workspace-current-name) :to-equal "X")))
(describe "close-window-or-workspace"
(before-each
(+workspace-switch persp2-name)
@ -132,4 +119,9 @@
(it "kills workspace on last window"
(quiet! (+workspace/close-window-or-workspace)
(+workspace/close-window-or-workspace))
(expect (+workspace-current-name) :to-equal persp1-name)))))
(expect (+workspace-current-name) :to-equal persp1-name)))
(describe "rename"
(it "renames the current workspace"
(quiet! (+workspace/rename "X"))
(expect (+workspace-current-name) :to-equal "X")))))

View file

@ -1,4 +1,4 @@
;;; lang/assembly/autoload.el -*- lexical-binding: t; -*-
;;;###autoload
(map-put auto-mode-alist "\\.hax\\'" 'haxor-mode)
(add-to-list 'auto-mode-alist '("\\.hax\\'" . haxor-mode))

View file

@ -83,35 +83,37 @@ compilation database is present in the project.")
+cc|fontify-constants))
;; Custom style, based off of linux
(map-put c-style-alist "doom"
`((c-basic-offset . ,tab-width)
(c-comment-only-line-offset . 0)
(c-hanging-braces-alist (brace-list-open)
(brace-entry-open)
(substatement-open after)
(block-close . c-snug-do-while)
(arglist-cont-nonempty))
(c-cleanup-list brace-else-brace)
(c-offsets-alist
(statement-block-intro . +)
(knr-argdecl-intro . 0)
(substatement-open . 0)
(substatement-label . 0)
(statement-cont . +)
(case-label . +)
;; align args with open brace OR don't indent at all (if open
;; brace is at eolp and close brace is after arg with no trailing
;; comma)
(arglist-intro . +)
(arglist-close +cc-lineup-arglist-close 0)
;; don't over-indent lambda blocks
(inline-open . 0)
(inlambda . 0)
;; indent access keywords +1 level, and properties beneath them
;; another level
(access-label . -)
(inclass +cc-c++-lineup-inclass +)
(label . 0))))
(unless (assoc "doom" c-style-alist)
(push '("doom"
(c-basic-offset . ,tab-width)
(c-comment-only-line-offset . 0)
(c-hanging-braces-alist (brace-list-open)
(brace-entry-open)
(substatement-open after)
(block-close . c-snug-do-while)
(arglist-cont-nonempty))
(c-cleanup-list brace-else-brace)
(c-offsets-alist
(statement-block-intro . +)
(knr-argdecl-intro . 0)
(substatement-open . 0)
(substatement-label . 0)
(statement-cont . +)
(case-label . +)
;; align args with open brace OR don't indent at all (if open
;; brace is at eolp and close brace is after arg with no trailing
;; comma)
(arglist-intro . +)
(arglist-close +cc-lineup-arglist-close 0)
;; don't over-indent lambda blocks
(inline-open . 0)
(inlambda . 0)
;; indent access keywords +1 level, and properties beneath them
;; another level
(access-label . -)
(inclass +cc-c++-lineup-inclass +)
(label . 0)))
c-style-alist))
;;; Keybindings
;; Disable electric keys because it interferes with smartparens and custom
@ -133,9 +135,6 @@ compilation database is present in the project.")
:when '(+cc-sp-point-is-template-p +cc-sp-point-after-include-p)
:post-handlers '(("| " "SPC"))))
(sp-with-modes '(c-mode c++-mode objc-mode java-mode)
(sp-local-pair "/*" "*/" :post-handlers '(("||\n[i]" "RET") ("| " "SPC")))
;; Doxygen blocks
(sp-local-pair "/**" "*/" :post-handlers '(("||\n[i]" "RET") ("||\n[i]" "SPC")))
(sp-local-pair "/*!" "*/" :post-handlers '(("||\n[i]" "RET") ("[d-1]< | " "SPC")))))

View file

@ -5,14 +5,7 @@
(def-package! clj-refactor
:after clojure-mode
:config
;; setup some extra namespace auto completion for great awesome
(dolist (ns '(("re-frame" . "re-frame.core")
("reagent" . "reagent.core")
("str" . "clojure.string")))
(map-put cljr-magic-require-namespaces (car ns) (cdr ns))))
:after clojure-mode)
(def-package! cider
;; NOTE: if you don't have an org directory set (the dir doesn't exist), cider
@ -23,13 +16,7 @@
(setq nrepl-hide-special-buffers t
cider-stacktrace-default-filters '(tooling dup)
cider-prompt-save-file-on-load nil
cider-repl-use-clojure-font-lock t
;; Setup cider for clojurescript / figwheel dev.
cider-cljs-lein-repl
"(do (require 'figwheel-sidecar.repl-api)
(figwheel-sidecar.repl-api/start-figwheel!)
(figwheel-sidecar.repl-api/cljs-repl))")
cider-repl-use-clojure-font-lock t)
(set-popup-rule! "^\\*cider-repl" :quit nil :select nil)
(set-repl-handler! 'clojure-mode #'+clojure/repl)
(set-eval-handler! 'clojure-mode #'cider-eval-region)

View file

@ -7,9 +7,9 @@
:definition #'crystal-def-jump
:references #'crystal-tool-imp)
(set-eval-handler! 'crystal-mode
'((:command . "crystal")
(:exec . "%c %s")
(:description . "Run Crystal script"))))
'((:command . "crystal")
(:exec . "%c %s")
(:description . "Run Crystal script"))))
(def-package! flycheck-crystal

View file

@ -1,6 +1,7 @@
;;; lang/csharp/config.el -*- lexical-binding: t; -*-
(map-put auto-mode-alist '"\\.shader$" 'dshader-mode) ; unity shaders
;; unity shaders
(add-to-list 'auto-mode-alist '("\\.shader$" . shader-mode))
(def-package! omnisharp

View file

@ -1,10 +1,10 @@
;;; lang/data/config.el -*- lexical-binding: t; -*-
;; Built in plugins
(dolist (spec '(("/sxhkdrc\\'" . conf-mode)
("\\.\\(?:hex\\|nes\\)\\'" . hexl-mode)
("\\.plist\\'" . nxml-mode)))
(map-put auto-mode-alist (car spec) (cdr spec)))
(unless after-init-time
(push '("/sxhkdrc\\'" . conf-mode) auto-mode-alist)
(push '("\\.\\(?:hex\\|nes\\)\\'" . hexl-mode) auto-mode-alist)
(push '("\\.plist\\'" . nxml-mode) auto-mode-alist))
(after! nxml-mode
(set-company-backend! 'nxml-mode '(company-nxml company-yasnippet)))

View file

@ -2,6 +2,9 @@
(def-package! elixir-mode
:defer t
:init
;; disable default smartparens config
(provide 'smartparens-elixir)
:config
;; ...and only complete the basics
(after! smartparens
@ -9,7 +12,6 @@
(sp-local-pair "do" "end"
:when '(("RET" "<evil-ret>"))
:unless '(sp-in-comment-p sp-in-string-p)
:skip-match 'sp-elixir-skip-def-p
:post-handlers '("||\n[i]"))
(sp-local-pair "do " " end" :unless '(sp-in-comment-p sp-in-string-p))
(sp-local-pair "fn " " end" :unless '(sp-in-comment-p sp-in-string-p))))

View file

@ -1,8 +1,8 @@
;;; lang/emacs-lisp/config.el -*- lexical-binding: t; -*-
(def-package! elisp-mode ; built-in
:mode ("/Cask$" . emacs-lisp-mode)
:config
(add-to-list 'auto-mode-alist '("\\.Cask\\'" . emacs-lisp-mode))
(defun +emacs-lisp|init ()
(set-repl-handler! 'emacs-lisp-mode #'+emacs-lisp/repl)
(set-eval-handler! 'emacs-lisp-mode #'+emacs-lisp-eval)
(set-lookup-handlers! 'emacs-lisp-mode :documentation 'info-lookup-symbol)
@ -61,6 +61,8 @@
return t))
(flycheck-mode -1))))
(add-transient-hook! 'emacs-lisp-mode (+emacs-lisp|init))
;;
;; Plugins
@ -74,21 +76,21 @@
;; `macrostep'
(map! :after macrostep
:map macrostep-keymap
:n "RET" #'macrostep-expand
:n "e" #'macrostep-expand
:n "u" #'macrostep-collapse
:n "c" #'macrostep-collapse
:n "RET" #'macrostep-expand
:n "e" #'macrostep-expand
:n "u" #'macrostep-collapse
:n "c" #'macrostep-collapse
:n "TAB" #'macrostep-next-macro
:n "n" #'macrostep-next-macro
:n "J" #'macrostep-next-macro
:n [tab] #'macrostep-next-macro
:n "C-n" #'macrostep-next-macro
:n "J" #'macrostep-next-macro
:n "S-TAB" #'macrostep-prev-macro
:n "K" #'macrostep-prev-macro
:n "p" #'macrostep-prev-macro
:n [backtab] #'macrostep-prev-macro
:n "K" #'macrostep-prev-macro
:n "C-p" #'macrostep-prev-macro
:n "q" #'macrostep-collapse-all
:n "C" #'macrostep-collapse-all)
:n "q" #'macrostep-collapse-all
:n "C" #'macrostep-collapse-all)
(after! evil
;; `evil-normalize-keymaps' seems to be required for macrostep or it won't

View file

@ -5,7 +5,7 @@
"/rebar\\.config\\(?:\\.script\\)?$"
;; erlang configs
"/\\(?:app\\|sys\\)\\.config$"))
(map-put auto-mode-alist regexp 'erlang-mode))
(add-to-list 'auto-mode-alist (cons regexp 'erlang-mode)))
(def-package! flycheck-rebar3

View file

@ -31,7 +31,7 @@
("\\.[Jj][Mm][Dd]\\'" . ess-jags-mode))
:init
(unless (featurep! :lang julia)
(map-put auto-mode-alist "\\.jl\'" 'ess-julia-mode))
(add-to-list 'auto-mode-alist '("\\.jl\\'" . ess-julia-mode)))
:config
(add-hook 'ess-mode-hook #'doom|enable-line-numbers)
(setq ess-offset-continued 'straight

View file

@ -2,17 +2,8 @@
;;;###if (featurep! +dante)
(def-package! dante
:after haskell-mode
:hook (haskell-mode . dante-mode)
:config
(add-hook 'haskell-mode-hook #'interactive-haskell-mode))
(def-package! company-ghc
:when (featurep! :completion company)
:after haskell-mode
:init
(add-hook 'haskell-mode-hook #'ghc-comp-init)
:config
(setq company-ghc-show-info 'oneline)
(set-company-backend! 'haskell-mode #'company-ghc))
(when (featurep! :feature syntax-checker)
(add-hook! 'dante-mode-hook
(flycheck-add-next-checker 'haskell-dante '(warning . haskell-hlint)))))

View file

@ -4,9 +4,8 @@
(when (featurep! +dante)
(unless (executable-find "cabal")
(warn! "Couldn't find cabal, haskell-mode may have issues"))
(unless (executable-find "ghc-mod")
(warn! "Couldn't find ghc-mod on PATH. Code completion will not work")))
(unless (executable-find "hlint")
(warn! "Couldn't find hlint. Flycheck may have issues in haskell-mode/")))
(when (featurep! +intero)
(unless (executable-find "stack")

View file

@ -5,9 +5,7 @@
;;
(cond ((featurep! +dante)
(package! dante)
(when (featurep! :completion company)
(package! company-ghc)))
(package! dante))
(t
(package! intero)
(package! hindent)))

View file

@ -17,11 +17,6 @@
;; Other
:yield "import"))
(after! smartparens
(sp-with-modes '(js2-mode typescript-mode rjsx-mode)
(sp-local-pair "/**" "" :post-handlers '(("| " "SPC") ("|\n*/[i][d-2]" "RET")))
(sp-local-pair "/*" "*/" :post-handlers '(("| " "SPC") ("|\n*/[i][d-2]" "RET")))))
;;
;; Major modes
@ -66,7 +61,7 @@
magic-mode-regexp-match-limit t)
(progn (goto-char (match-beginning 1))
(not (sp-point-in-string-or-comment)))))
(map-put magic-mode-alist #'+javascript-jsx-file-p 'rjsx-mode)
(add-to-list 'magic-mode-alist '(+javascript-jsx-file-p . rjsx-mode))
:config
(set-electric! 'rjsx-mode :chars '(?\} ?\) ?. ?>))
(add-hook! 'rjsx-mode-hook
@ -76,7 +71,7 @@
;; `rjsx-electric-gt' relies on js2's parser to tell it when the cursor is in
;; a self-closing tag, so that it can insert a matching ending tag at point.
;; However, the parser doesn't run immediately, so a fast typist can outrun
;; it, causing issues, so force it to parse.
;; it, causing tags to stay unclosed, so force it to parse.
(defun +javascript|reparse (n)
;; if n != 1, rjsx-electric-gt calls rjsx-maybe-reparse itself
(if (= n 1) (rjsx-maybe-reparse)))
@ -134,23 +129,19 @@
:config
(setq tide-completion-detailed t
tide-always-show-documentation t)
;; code completion
(after! company
;; tide affects the global `company-backends', undo this so doom can handle
;; it buffer-locally
(setq-default company-backends (delq 'company-tide (default-value 'company-backends))))
(set-company-backend! 'tide-mode 'company-tide)
;; navigation
(set-lookup-handlers! 'tide-mode
:definition #'tide-jump-to-definition
:references #'tide-references
:documentation #'tide-documentation-at-point)
;; resolve to `doom-project-root' if `tide-project-root' fails
(advice-add #'tide-project-root :override #'+javascript*tide-project-root)
;; cleanup tsserver when no tide buffers are left
(add-hook! 'tide-mode-hook
(add-hook 'kill-buffer-hook #'+javascript|cleanup-tide-processes nil t))

View file

@ -14,6 +14,9 @@
;; Plugins
;;
;; sp's default rules are obnoxious, so disable them
(provide 'smartparens-latex)
(after! tex
;; Set some varibles to fontify common LaTeX commands.
(load! "+fontification")
@ -75,33 +78,30 @@
(setcar (cdr (assoc "Check" TeX-command-list)) "chktex -v6 %s")
;; Set a custom item indentation
(dolist (env '("itemize" "enumerate" "description"))
(map-put LaTeX-indent-environment-list
env '(+latex/LaTeX-indent-item)))
(add-to-list 'LaTeX-indent-environment-list `(,env +latex/LaTeX-indent-item)))
;;
;; Use Okular if the user says so.
(when (featurep! +okular)
;; Configure Okular as viewer. Including a bug fix
;; (https://bugs.kde.org/show_bug.cgi?id=373855)
(map-put TeX-view-program-list
"Okular" '(("okular --unique file:%o" (mode-io-correlate "#src:%n%a"))))
(map-put TeX-view-program-list 'output-pdf '("Okular")))
(add-to-list 'TeX-view-program-list '("Okular" ("okular --unique file:%o" (mode-io-correlate "#src:%n%a"))))
(add-to-list 'TeX-view-program-selection '(output-pdf "Okular")))
;; Or Skim
(when (featurep! +skim)
(map-put TeX-view-program-list
"Skim" '("/Applications/Skim.app/Contents/SharedSupport/displayline -b -g %n %o %b"))
(map-put TeX-view-program-selection 'output-pdf '("Skim")))
(add-to-list 'TeX-view-program-list '("Skim" "/Applications/Skim.app/Contents/SharedSupport/displayline -b -g %n %o %b"))
(add-to-list 'TeX-view-program-selection 'output-pdf '("Skim")))
;; Or Zathura
(when (featurep! +zathura)
(map-put TeX-view-program-selection 'output-pdf '("Zathura")))
(add-to-list 'TeX-view-program-selection '(output-pdf "Zathura")))
;; Or PDF-tools, but only if the module is also loaded
(when (and (featurep! :tools pdf)
(featurep! +pdf-tools))
(map-put TeX-view-program-list "PDF Tools" '("TeX-pdf-tools-sync-view"))
(map-put TeX-view-program-selection 'output-pdf '("PDF Tools"))
(add-to-list 'TeX-view-program-list ("PDF Tools" "TeX-pdf-tools-sync-view"))
(add-to-list 'TeX-view-program-selection '(output-pdf "PDF Tools"))
;; Enable auto reverting the PDF document with PDF Tools
(add-hook 'TeX-after-compilation-finished-functions #'TeX-revert-document-buffer)))
@ -124,8 +124,8 @@
:init
(setq latex-preview-pane-multifile-mode 'auctex)
:config
(map-put TeX-view-program-list "preview-pane" '(latex-preview-pane-mode))
(map-put TeX-view-program-selection 'output-pdf '("preview-pane"))
(add-to-list 'TeX-view-program-list '("preview-pane" latex-preview-pane-mode))
(add-to-list 'TeX-view-program-selection '(output-pdf "preview-pane"))
(define-key! doc-view-mode-map
(kbd "ESC") #'delete-window
"q" #'delete-window

View file

@ -1,5 +1,8 @@
;;; lang/lua/config.el -*- lexical-binding: t; -*-
;; sp's default rules are obnoxious, so disable them
(provide 'smartparens-lua)
(after! lua-mode
(set-lookup-handlers! 'lua-mode :documentation 'lua-search-documentation)
(set-electric! 'lua-mode :words '("else" "end"))

View file

@ -3,6 +3,9 @@
(def-package! markdown-mode
:mode ("/README\\(?:\\.\\(?:markdown\\|md\\)\\)?\\'" . gfm-mode)
:init
(when (featurep! +pandoc)
(setq markdown-command "pandoc --from=markdown --to=html --standalone --mathjax --highlight-style=pygments"))
(setq markdown-enable-wiki-links t
markdown-italic-underscore t
markdown-asymmetric-header t
@ -47,3 +50,10 @@
:nv "t" #'markdown-toc-generate-toc
:nv "i" #'markdown-insert-image
:nv "l" #'markdown-insert-link)))
(def-package! pandoc-mode
:when (featurep! +pandoc)
:commands
pandoc-mode
:hook
(markdown-mode . conditionally-turn-on-pandoc))

View file

@ -0,0 +1,6 @@
;; -*- lexical-binding: t; no-byte-compile: t; -*-
;;; lang/markdown/doctor.el
(when (featurep! +pandoc)
(unless (executable-find "pandoc")
(warn! "Couldn't find pandoc, markdown-mode may have issues")))

View file

@ -4,3 +4,7 @@
(package! markdown-mode)
(package! markdown-toc)
(when (featurep! +pandoc)
(package! pandoc-mode))

View file

@ -36,7 +36,7 @@ string). Stops at the first function to return non-nil.")
(or (cdr (assq lang +org-babel-mode-alist))
lang)))
nil t)))
(map-put org-babel-load-languages lang t))
(add-to-list 'org-babel-load-languages (cons lang t)))
t)))
(advice-add #'org-babel-confirm-evaluate :around #'+org*babel-lazy-load-library)

View file

@ -25,17 +25,15 @@
:when (featurep! :feature evil +everywhere)
:hook (org-mode . evil-org-mode)
:init
(setq evil-org-key-theme '(navigation insert textobjects))
(defvar evil-org-key-theme '(navigation insert textobjects))
(add-hook 'org-load-hook #'+org|setup-evil)
(add-hook 'evil-org-mode-hook #'evil-normalize-keymaps)
:config
;; in case it is called later
(advice-add #'evil-org-set-key-theme :after #'+org|setup-evil))
(def-package! evil-org-agenda
:when (featurep! :feature evil +everywhere)
:after org-agenda
:config (evil-org-agenda-set-keys))
(advice-add #'evil-org-set-key-theme :after #'+org|setup-evil)
(def-package! evil-org-agenda
:after org-agenda
:config (evil-org-agenda-set-keys)))
;;
@ -266,8 +264,10 @@ between the two."
[remap doom/backward-to-bol-or-indent] #'org-beginning-of-line
[remap doom/forward-to-last-non-comment-or-eol] #'org-end-of-line))
(defun +org|setup-evil (&rest _)
(require 'evil-org)
(defun +org|setup-evil (&rest args)
;; In case this hook is used in an advice on `evil-org-set-key-theme', this
;; prevents recursive requires.
(unless args (require 'evil-org))
;; By default, TAB cycles the visibility of all children under the current
;; tree between three states. I want to toggle the tree between two states,
;; without affecting its children.
@ -341,7 +341,7 @@ between the two."
(defun +org|setup-hacks ()
"Getting org to behave."
;; Don't open separate windows
(map-put org-link-frame-setup 'file #'find-file)
(setf (alist-get 'file org-link-frame-setup) #'find-file)
;; Let OS decide what to do with files when opened
(setq org-file-apps
`(("pdf" . default)

View file

@ -22,9 +22,9 @@
(setq sh-indent-after-continuation 'always)
;; recognize function names with dashes in them
(map-put sh-imenu-generic-expression
'sh '((nil "^\\s-*function\\s-+\\([[:alpha:]_-][[:alnum:]_-]*\\)\\s-*\\(?:()\\)?" 1)
(nil "^\\s-*\\([[:alpha:]_-][[:alnum:]_-]*\\)\\s-*()" 1)))
(add-to-list 'sh-imenu-generic-expression
'(sh (nil "^\\s-*function\\s-+\\([[:alpha:]_-][[:alnum:]_-]*\\)\\s-*\\(?:()\\)?" 1)
(nil "^\\s-*\\([[:alpha:]_-][[:alnum:]_-]*\\)\\s-*()" 1)))
;; `sh-set-shell' is chatty about setting up indentation rules
(advice-add #'sh-set-shell :around #'doom*shut-up)

View file

@ -3,10 +3,6 @@
;; An improved newline+continue comment function
(setq-hook! css-mode comment-indent-function #'+css/comment-indent-new-line)
(after! smartparens
(sp-with-modes '(css-mode scss-mode less-css-mode stylus-mode)
(sp-local-pair "/*" "*/" :post-handlers '(("||\n[i]" "RET") ("| " "SPC")))))
(map! :map* (css-mode-map scss-mode-map less-css-mode-map)
:localleader
:n "rb" #'+css/toggle-inline-or-block)

View file

@ -16,7 +16,25 @@
:mode "templates/.+\\.php$"
:config
(setq web-mode-enable-html-entities-fontification t
web-mode-enable-auto-quoting nil)
web-mode-auto-close-style 2)
(after! smartparens
;; let smartparens handle these
(setq web-mode-enable-auto-quoting nil
web-mode-enable-auto-pairing t)
;; Remove web-mode auto pairs that end with >, because smartparens autopairs
;; them, causing duplicates. Also remove truncated autopairs, like <?p and
;; hp ?>.
(dolist (alist web-mode-engines-auto-pairs)
(setcdr alist (delq nil
(mapcar (lambda (pair)
(unless (string-match-p "^[a-z-]" (cdr pair))
(cons (car pair)
(if (equal (substring (cdr pair) -1) ">")
(substring (cdr pair) 0 -1)
(cdr pair)))))
(cdr alist)))))
(setf (alist-get nil web-mode-engines-auto-pairs) nil))
(map! :map web-mode-map
(:localleader

View file

@ -21,11 +21,12 @@
:after-call (doom-before-switch-buffer after-find-file)
:config
;; Register missing indent variables
(setq editorconfig-indentation-alist
(append '((mips-mode mips-tab-width)
(haxor-mode haxor-tab-width)
(nasm-mode nasm-basic-offset))
editorconfig-indentation-alist))
(unless (assq 'mips-mode editorconfig-indentation-alist)
(setq editorconfig-indentation-alist
(append '((mips-mode mips-tab-width)
(haxor-mode haxor-tab-width)
(nasm-mode nasm-basic-offset))
editorconfig-indentation-alist)))
(defun doom*editorconfig-smart-detection (orig-fn &rest args)
"Retrieve the properties for the current file. If it doesn't have an
@ -51,7 +52,8 @@ extension, try to guess one."
;; editorconfig to ignore indentation there. I prefer dynamic indentation
;; support built into Emacs.
(dolist (mode '(emacs-lisp-mode lisp-mode))
(map-delete editorconfig-indentation-alist mode))
(delq (assq mode editorconfig-indentation-alist)
editorconfig-indentation-alist))
;;
(editorconfig-mode +1))

View file

@ -1,5 +1,6 @@
;;; tools/ein/autoload.el -*- lexical-binding: t; -*-
;; FIXME obsolete :ein-notebook-dir
;;;###autoload
(def-setting! :ein-notebook-dir (dir)
"Set the default directory from where to open Jupyter notebooks."
@ -33,4 +34,47 @@
(goto-char (1+ res))
(widget-button-press (point)))))
;;;###autoload (autoload '+ein-hydra/body "tools/ein/autoload" nil nil)
(defhydra +ein-hydra (:hint t :color red)
"
Operations on Cells^^^^^^ Other
----------------------------^^^^^^ ----------------------------------^^^^
[_k_/_j_]^^ select prev/next [_t_]^^ toggle output
[_K_/_J_]^^ move up/down [_C-l_/_C-S-l_] clear/clear all output
[_C-k_/_C-j_]^^ merge above/below [_C-o_]^^ open console
[_O_/_o_]^^ insert above/below [_C-s_/_C-r_] save/rename notebook
[_y_/_p_/_d_] copy/paste [_x_]^^ close notebook
[_u_]^^^^ change type [_q_]^^ quit
[_RET_]^^^^ execute
"
("q" nil :exit t)
("h" ein:notebook-worksheet-open-prev-or-last)
("j" ein:worksheet-goto-next-input)
("k" ein:worksheet-goto-prev-input)
("l" ein:notebook-worksheet-open-next-or-first)
("H" ein:notebook-worksheet-move-prev)
("J" ein:worksheet-move-cell-down)
("K" ein:worksheet-move-cell-up)
("L" ein:notebook-worksheet-move-next)
("t" ein:worksheet-toggle-output)
("d" ein:worksheet-kill-cell)
("R" ein:worksheet-rename-sheet)
("y" ein:worksheet-copy-cell)
("p" ein:worksheet-yank-cell)
("o" ein:worksheet-insert-cell-below)
("O" ein:worksheet-insert-cell-above)
("u" ein:worksheet-change-cell-type)
("RET" ein:worksheet-execute-cell-and-goto-next)
;; Output
("C-l" ein:worksheet-clear-output)
("C-S-l" ein:worksheet-clear-all-output)
;;Console
("C-o" ein:console-open :exit t)
;; Merge and split cells
("C-k" ein:worksheet-merge-cell)
("C-j" spacemacs/ein:worksheet-merge-cell-next)
("s" ein:worksheet-split-cell-at-point)
;; Notebook
("C-s" ein:notebook-save-notebook-command)
("C-r" ein:notebook-rename-command)
("x" ein:notebook-close :exit t))

View file

@ -40,49 +40,4 @@
;; Ace-link on notebook list buffers
(after! ein-notebooklist
(define-key ein:notebooklist-mode-map "o" #'+ein/ace-link-ein))
;; add hydra
(defhydra +ein/hydra (:hint t :color red)
"
Operations on Cells^^^^^^ Other
----------------------------^^^^^^ ----------------------------------^^^^
[_k_/_j_]^^ select prev/next [_t_]^^ toggle output
[_K_/_J_]^^ move up/down [_C-l_/_C-S-l_] clear/clear all output
[_C-k_/_C-j_]^^ merge above/below [_C-o_]^^ open console
[_O_/_o_]^^ insert above/below [_C-s_/_C-r_] save/rename notebook
[_y_/_p_/_d_] copy/paste [_x_]^^ close notebook
[_u_]^^^^ change type [_q_]^^ quit
[_RET_]^^^^ execute
"
("q" nil :exit t)
("h" ein:notebook-worksheet-open-prev-or-last)
("j" ein:worksheet-goto-next-input)
("k" ein:worksheet-goto-prev-input)
("l" ein:notebook-worksheet-open-next-or-first)
("H" ein:notebook-worksheet-move-prev)
("J" ein:worksheet-move-cell-down)
("K" ein:worksheet-move-cell-up)
("L" ein:notebook-worksheet-move-next)
("t" ein:worksheet-toggle-output)
("d" ein:worksheet-kill-cell)
("R" ein:worksheet-rename-sheet)
("y" ein:worksheet-copy-cell)
("p" ein:worksheet-yank-cell)
("o" ein:worksheet-insert-cell-below)
("O" ein:worksheet-insert-cell-above)
("u" ein:worksheet-change-cell-type)
("RET" ein:worksheet-execute-cell-and-goto-next)
;; Output
("C-l" ein:worksheet-clear-output)
("C-S-l" ein:worksheet-clear-all-output)
;;Console
("C-o" ein:console-open :exit t)
;; Merge and split cells
("C-k" ein:worksheet-merge-cell)
("C-j" spacemacs/ein:worksheet-merge-cell-next)
("s" ein:worksheet-split-cell-at-point)
;; Notebook
("C-s" ein:notebook-save-notebook-command)
("C-r" ein:notebook-rename-command)
("x" ein:notebook-close :exit t)))
(define-key ein:notebooklist-mode-map "o" #'+ein/ace-link-ein)))

View file

@ -64,6 +64,7 @@ search of your username. May prompt for your gpg passphrase."
;; Commands
;;
;;;###autoload (autoload 'password-store-dir "password-store")
;;;###autoload (autoload 'password-store-list "password-store")
;;;###autoload (autoload 'password-store--completing-read "password-store")
@ -113,6 +114,7 @@ fields in `+pass-url-fields' is used to find the url field."
;; Ivy interface
;;
;;;###autoload
(defun +pass/ivy (arg)
"TODO"
(interactive "P")

View file

@ -34,7 +34,7 @@
"k" #'pass-prev-entry
"d" #'pass-kill
"\C-j" #'pass-next-directory
"\C-k" #'pass-next-directory))
"\C-k" #'pass-prev-directory))
;; Is built into Emacs 26+

View file

@ -1,5 +1,6 @@
;;; tools/prodigy/autoload.el -*- lexical-binding: t; -*-
;; FIXME obsolete :service
;;;###autoload
(def-setting! :service (&rest plist)
"TODO"

View file

@ -0,0 +1,13 @@
;;; tools/rgb/autoload.el -*- lexical-binding: t; -*-
;;;###autoload (autoload '+rgb-kurecolor-hydra/body "tools/rgb/autoload" nil nil)
(defhydra +rgb-kurecolor-hydra (:color pink :hint nil)
"
Inc/Dec _w_/_W_ brightness _d_/_D_ saturation _e_/_E_ hue "
("w" kurecolor-decrease-brightness-by-step)
("W" kurecolor-increase-brightness-by-step)
("d" kurecolor-decrease-saturation-by-step)
("D" kurecolor-increase-saturation-by-step)
("e" kurecolor-decrease-hue-by-step)
("E" kurecolor-increase-hue-by-step)
("q" nil "cancel" :color blue))

View file

@ -1,19 +0,0 @@
;;; tools/rgb/config.el -*- lexical-binding: t; -*-
;;
;; Plugins
;;
(def-package! kurecolor
:after rainbow-mode
:config
(defhydra +rgb@kurecolor (:color pink :hint nil)
"
Inc/Dec _w_/_W_ brightness _d_/_D_ saturation _e_/_E_ hue "
("w" kurecolor-decrease-brightness-by-step)
("W" kurecolor-increase-brightness-by-step)
("d" kurecolor-decrease-saturation-by-step)
("D" kurecolor-increase-saturation-by-step)
("e" kurecolor-decrease-hue-by-step)
("E" kurecolor-increase-hue-by-step)
("q" nil "cancel" :color blue)))

View file

@ -1,17 +1,62 @@
;;; tools/wakatime/autoload.el -*- lexical-binding: t; -*-
;;;###autoload
(add-hook 'doom-after-switch-buffer-hook #'+wakatime|autostart)
(defvar +wakatime-api-file (concat doom-cache-dir "wakatime.el")
"Where the wakatime api key is cached.")
(defvar +wakatime-hide-filenames nil
"If non-nil, obfuscate files and only show what projects you're working on.")
;;;###autoload
(defalias '+wakatime/start '+wakatime|autostart)
(add-hook 'doom-post-init-hook #'+wakatime|delayed-autostart)
;;;###autoload
(defun +wakatime|autostart ()
(defun +wakatime/setup ()
"Setup Wakatime in Emacs and start `global-wakatime-mode'.
This will prompt you for your api key. You only need to run this when your api
changes."
(interactive)
(when (y-or-n-p "No API key is registered. Open a browser on the wakatime api key page?")
(browse-url "https://wakatime.com/settings/api-key"))
(let ((api-key (read-string "Enter your wakatime API key: ")))
(unless api-key
(user-error "No api key was received."))
(setq wakatime-api-key api-key)
(with-temp-file +wakatime-api-file
(prin1 `(setq wakatime-api-key ,wakatime-api-key)
(current-buffer)))
(require 'wakatime-mode)
(unless (or (and wakatime-cli-path (file-executable-p wakatime-cli-path))
(not (equal (wakatime-find-binary "wakatime") "wakatime")))
(user-error "Couldn't find wakatime executable (%s)"
(or wakatime-cli-path "wakatime")))
(global-wakatime-mode +1)
(message "Wakatime enabled. You're good to go!")))
;;;###autoload
(defun +wakatime|autostart (&rest _)
"Initialize wakatime (if `wakatime-api-key' is set, otherwise no-op with a
warning)."
(interactive)
(if (boundp 'wakatime-api-key)
(unless (bound-and-true-p wakatime-api-key)
(ignore-errors (load +wakatime-api-file t t)))
(if (bound-and-true-p wakatime-api-key)
(global-wakatime-mode +1)
(message "No `wakatime-api-key' set! wakaktime-mode will stay disabled."))
(remove-hook 'doom-after-switch-buffer-hook #'+wakatime-init))
(message "wakatime-mode isn't set up. Run `M-x +wakatime/start' to do so."))
;;
(remove-hook 'doom-before-switch-buffer-hook #'+wakatime|autostart)
(advice-remove 'after-find-file #'+wakatime|autostart))
;;;###autoload
(defun +wakatime|delayed-autostart (&rest _)
"Lazily initialize `wakatime-mode' until the next time you switch buffers or
open a file."
(add-hook 'doom-before-switch-buffer-hook #'+wakatime|autostart)
;; this is necessary in case the user opens emacs with file arguments
(advice-add 'after-find-file :before #'+wakatime|autostart))
(defun +wakatime*append-hide-filenames-option (ret)
"Enables filename obfuscation in wakatime if `+wakatime-hide-filenames' is
non-nil."
(concat ret (if +wakatime-hide-filenames " --hide-filenames")))
(advice-add #'wakatime-client-command :filter-return #'+wakatime*append-hide-filenames-option )

View file

@ -234,10 +234,7 @@ instead of switch-to-buffer-*."
(defun +popup*org-pop-to-buffer (orig-fn buf &optional norecord)
"Use `pop-to-buffer' instead of `switch-to-buffer' to open buffer.'"
(if +popup-mode
(pop-to-buffer
(cond ((stringp buf) (get-buffer-create buf))
((bufferp buf) buf)
(t (error "Invalid buffer %s" buf))))
(pop-to-buffer buf nil norecord)
(funcall orig-fn buf norecord)))
(advice-add #'org-switch-to-buffer-other-window :around #'+popup*org-pop-to-buffer)

View file

@ -33,6 +33,7 @@ the buffer is visible, then set another timer and try again later."
default window parameters for popup windows, clears leftover transient timers
and enables `+popup-buffer-mode'."
(with-selected-window window
(setq alist (delq (assq 'actions alist) alist))
(when (and alist +popup--populate-wparams)
;; Emacs 26+ will automatically map the window-parameters alist entry to
;; the popup window, so we need this for Emacs 25.x users
@ -58,58 +59,63 @@ and enables `+popup-buffer-mode'."
`transient' window parameter (see `+popup-window-parameters').
+ And finally deletes the window!"
(let ((buffer (window-buffer window))
(inhibit-quit t)
ttl)
(when (and (buffer-file-name buffer)
(buffer-modified-p buffer)
(or (+popup-parameter-fn 'autosave window buffer)
(y-or-n-p "Popup buffer is modified. Save it?")))
(with-current-buffer buffer (save-buffer)))
(set-buffer-modified-p nil)
(inhibit-quit t))
(and (buffer-file-name buffer)
(buffer-modified-p buffer)
(let ((autosave (+popup-parameter 'autosave window)))
(cond ((eq autosave 't))
((null autosave)
(y-or-n-p "Popup buffer is modified. Save it?"))
((functionp autosave)
(funcall autosave buffer))))
(with-current-buffer buffer (save-buffer)))
(let ((ignore-window-parameters t))
(delete-window window))
(if-let* ((wconf (window-parameter window 'saved-wconf)))
(set-window-configuration wconf)
(delete-window window)))
(unless (window-live-p window)
(with-current-buffer buffer
(set-buffer-modified-p nil)
(+popup-buffer-mode -1)
;; t = default
;; integer = ttl
;; nil = no timer
(unless +popup--inhibit-transient
(setq ttl (+popup-parameter-fn 'ttl window buffer))
(when ttl
(when (eq ttl t)
(setq ttl (or (plist-get +popup-defaults :ttl)
0)))
(cl-assert (integerp ttl) t)
(if (= ttl 0)
(+popup--kill-buffer buffer 0)
(add-hook 'kill-buffer-hook #'+popup|kill-buffer-hook nil t)
(setq +popup--timer
(run-at-time ttl nil #'+popup--kill-buffer
buffer ttl)))))))))
(let ((ttl (+popup-parameter 'ttl window)))
(when (eq ttl 't)
(setq ttl (plist-get +popup-defaults :ttl)))
(cond ((null ttl))
((functionp ttl)
(funcall ttl buffer))
((not (integerp ttl))
(signal 'wrong-type-argument (list 'integerp ttl)))
((= ttl 0)
(+popup--kill-buffer buffer 0))
((add-hook 'kill-buffer-hook #'+popup|kill-buffer-hook nil t))
((setq +popup--timer
(run-at-time ttl nil #'+popup--kill-buffer
buffer ttl))))))))))
(defun +popup--normalize-alist (alist)
"Merge `+popup-default-alist' and `+popup-default-parameters' with ALIST."
(let ((alist ; handle defaults
(cl-remove-duplicates
(append alist +popup-default-alist)
:key #'car :from-end t))
(parameters
(cl-remove-duplicates
(append (cdr (assq 'window-parameters alist))
+popup-default-parameters)
:key #'car :from-end t)))
;; handle `size'
(when-let* ((size (cdr (assq 'size alist)))
(side (or (cdr (assq 'side alist)) 'bottom))
(param (if (memq side '(left right))
'window-width
'window-height)))
(setq alist (map-delete alist 'size))
(map-put alist param size))
(setcdr (assq 'window-parameters alist)
(cl-remove-if #'null parameters :key #'cdr))
(cl-remove-if #'null alist :key #'cdr)))
(when alist
(let ((alist ; handle defaults
(cl-remove-duplicates
(append alist +popup-default-alist)
:key #'car :from-end t))
(parameters
(cl-remove-duplicates
(append (cdr (assq 'window-parameters alist))
+popup-default-parameters)
:key #'car :from-end t)))
;; handle `size'
(when-let* ((size (cdr (assq 'size alist)))
(side (or (cdr (assq 'side alist)) 'bottom))
(param (if (memq side '(left right))
'window-width
'window-height)))
(setq list (assq-delete-all 'size alist))
(setcdr (assq param alist) size))
(setcdr (assq 'window-parameters alist)
parameters)
alist)))
;;
@ -120,23 +126,21 @@ and enables `+popup-buffer-mode'."
(defun +popup-buffer-p (&optional buffer)
"Return non-nil if BUFFER is a popup buffer. Defaults to the current buffer."
(when +popup-mode
(unless buffer
(setq buffer (current-buffer)))
(cl-assert (bufferp buffer) t)
(and (buffer-live-p buffer)
(buffer-local-value '+popup-buffer-mode buffer)
buffer)))
(let ((buffer (or buffer (current-buffer))))
(and (bufferp buffer)
(buffer-live-p buffer)
(buffer-local-value '+popup-buffer-mode buffer)
buffer))))
;;;###autoload
(defun +popup-window-p (&optional window)
"Return non-nil if WINDOW is a popup window. Defaults to the current window."
(when +popup-mode
(unless window
(setq window (selected-window)))
(cl-assert (windowp window) t)
(and (window-live-p window)
(window-parameter window 'popup)
window)))
(let ((window (or window (selected-window))))
(and (windowp window)
(window-live-p window)
(window-parameter window 'popup)
window))))
;;;###autoload
(defun +popup-buffer (buffer &optional alist)
@ -216,11 +220,14 @@ restoring it if `+popup-buffer-mode' is disabled."
+ If a function, it takes the current buffer as its argument and must return one
of the above values."
(when (bound-and-true-p +popup-buffer-mode)
(let ((modeline (+popup-parameter-fn 'modeline nil (current-buffer))))
(let ((modeline (+popup-parameter 'modeline)))
(cond ((eq modeline 't))
((or (eq modeline 'nil)
(null modeline))
;; TODO use `mode-line-format' window parameter instead (emacs 26+)
(hide-mode-line-mode +1))
((functionp modeline)
(funcall modeline))
((symbolp modeline)
(when-let* ((hide-mode-line-format (doom-modeline modeline)))
(hide-mode-line-mode +1)))))))
@ -246,9 +253,9 @@ restoring it if `+popup-buffer-mode' is disabled."
(defun +popup|cleanup-rules ()
"Cleans up any duplicate popup rules."
(interactive)
(cl-delete-duplicates
+popup--display-buffer-alist
:key #'car :test #'equal :from-end t)
(setq +popup--display-buffer-alist
(cl-delete-duplicates +popup--display-buffer-alist
:key #'car :test #'equal :from-end t))
(when +popup-mode
(setq display-buffer-alist +popup--display-buffer-alist)))
@ -291,16 +298,15 @@ This will do nothing if the popup's `quit' window parameter is either nil or
(interactive
(list (selected-window)
current-prefix-arg))
(unless window
(setq window (selected-window)))
(when (and (+popup-window-p window)
(or force-p
(memq (+popup-parameter-fn 'quit window window)
'(t current))))
(when +popup--remember-last
(+popup--remember (list window)))
(delete-window window)
t))
(let ((window (or window (selected-window))))
(when (and (+popup-window-p window)
(or force-p
(memq (+popup-parameter-fn 'quit window window)
'(t current))))
(when +popup--remember-last
(+popup--remember (list window)))
(delete-window window)
t)))
;;;###autoload
(defun +popup/close-all (&optional force-p)
@ -372,6 +378,19 @@ the message buffer in a popup window."
prevent the popup(s) from messing up the UI (or vice versa)."
(save-popups! (apply orig-fn args)))
;;;###autoload
(defun +popup-display-buffer-fullframe (buffer alist)
"Displays the buffer fullscreen."
(let ((wconf (current-window-configuration)))
(when-let (window (or (display-buffer-reuse-window buffer alist)
(display-buffer-same-window buffer alist)
(display-buffer-pop-up-window buffer alist)
(display-buffer-use-some-window buffer alist)))
(set-window-parameter window 'saved-wconf wconf)
(add-to-list 'window-persistent-parameters '(saved-wconf . t))
(delete-other-windows window)
window)))
;;;###autoload
(defun +popup-display-buffer-stacked-side-window (buffer alist)
"A `display-buffer' action that serves as an alternative to
@ -426,7 +445,7 @@ Accepts the same arguments as `display-buffer-in-side-window'. You must set
(lambda (_side) (frame-root-window (selected-frame)))))
(when-let* ((window (window--make-major-side-window buffer side slot alist)))
(set-window-parameter window 'window-vslot vslot)
(map-put window-persistent-parameters 'window-vslot 'writable)
(add-to-list 'window-persistent-parameters '(window-vslot . writable))
window)))
(t
;; Scan windows on SIDE.
@ -570,11 +589,11 @@ and may be called only if no window on SIDE exists yet."
;; Initialize `window-side' parameter of new window to SIDE and
;; make that parameter persistent.
(set-window-parameter window 'window-side side)
(map-put window-persistent-parameters 'window-side 'writable)
(add-to-list 'window-persistent-parameters '(window-side . writable))
;; Install `window-slot' parameter of new window and make that
;; parameter persistent.
(set-window-parameter window 'window-slot slot)
(map-put window-persistent-parameters 'window-slot 'writable)
(add-to-list 'window-persistent-parameters '(window-slot . writable))
;; Auto-adjust height/width of new window unless a size has been
;; explicitly requested.
(unless (if left-or-right

View file

@ -10,11 +10,11 @@
:quit t
:select #'ignore
:ttl 5)
"Default setup for `set-popup-rule!' ")
"Default properties for popup rules defined with `set-popup-rule!'.")
;;;###autoload
(defun +popup--make (predicate plist)
(cond ((not (keywordp (car plist)))
(cond ((and plist (not (keywordp (car plist))))
;; FIXME deprecated popup rule support
(message "Warning: the old usage of `set-popup-rule!' is deprecated; update the rule for '%s'"
predicate)
@ -51,14 +51,13 @@
(defun set-popup-rule! (predicate &rest plist)
"Define a popup rule.
Buffers displayed by `pop-to-buffer' and `display-buffer' (or their siblings)
will be tested against PREDICATE, which is either a) a regexp string (which is
matched against the buffer's name) or b) a function that takes no arguments and
returns a boolean.
These rules affect buffers displayed with `pop-to-buffer' and `display-buffer'
(or their siblings). Buffers displayed with `switch-to-buffer' (and its
variants) will not be affected by these rules (as they are unaffected by
`display-buffer-alist', which powers the popup management system).
Buffers displayed with `switch-to-buffer' and its variants will not be affected
by these rules (as they are unaffected by `display-buffer-alist', which powers
the popup management system).
PREDICATE can be either a) a regexp string (matched against the buffer's name)
or b) a function that takes no arguments and returns a boolean.
PLIST can be made up of any of the following properties:
@ -72,83 +71,93 @@ PLIST can be made up of any of the following properties:
`+popup-display-buffer-stacked-side-window' or `display-buffer-in-side-window'
is in :actions or `+popup-default-display-buffer-actions'.
:size/:width/:height FLOAT|INT
Determines the size of the popup. If opened at the top or bottom, the width is
irrelevant unless it is opened in an adjacent slot. Same deal with the left
and right side.
:size/:width/:height FLOAT|INT|FN
Determines the size of the popup. If more tha one of these size properties are
given :size always takes precedence, and is mapped with window-width or
window-height depending on what :side the popup is opened. Setting a height
for a popup that opens on the left or right is harmless, but comes into play
if two popups occupy the same :vslot.
If given a FLOAT (0 < x < 1), the number represents how much of the window
will be consumed by the popup (a percentage).
If given an INT, the number determines the size in lines (height) or units of
If a FLOAT (0 < x < 1), the number represents how much of the window will be
consumed by the popup (a percentage).
If an INT, the number determines the size in lines (height) or units of
character width (width).
If a function, it takes one argument: the popup window, and can do whatever it
wants with it, typically resize it, like `+popup-shrink-to-fit'.
:slot/:vslot INT
This only applies to popups with a :side. For popups opened at the top or
bottom, slot designates the horizontal positioning of a popup. If two popups
are assigned the same slot (and same vslot), the later popup will replace the
earlier one. If the later popup has a lower slot, it will open to the older
popup's left. A higher slot opens it to the old popup's right.
(This only applies to popups with a :side and only if :actions is blank or
contains the `+popup-display-buffer-stacked-side-window' action) These control
how multiple popups are laid out. INT can be any integer, positive and
negative.
On the other hand, vslot operates the same way, but controls how popups are
stacked.
:slot controls lateral positioning (e.g. the horizontal positioning for
top/bottom popups, or vertical positioning for left/right popups).
:vslot controls popup stacking (from the edge of the frame toward the center).
When a popup is opened on the left and right, slot determines vertical
position and vslot horizontal.
Let's assume popup A and B are opened with :side 'bottom, in that order.
If they possess the same :slot and :vslot, popup B will replace popup A.
If popup B has a higher :slot, it will open to the right of popup A.
If popup B has a lower :slot, it will open to the left of popup A.
If popup B has a higher :vslot, it will open above popup A.
If popup B has a lower :vslot, it will open below popup A.
:ttl INT|BOOL|FN
Stands for time-to-live. CDR can be t, an integer, nil or a function that
returns one of these. It represents the number of seconds before the buffer
belonging to a closed popup window is killed.
Stands for time-to-live. It can be t, an integer, nil or a function. This
controls how (and if) the popup system will clean up after the popup.
If t, CDR will default to `+popup-ttl'.
If any non-zero integer, wait that many seconds before killing the buffer (and
any associated processes).
If 0, the buffer is immediately killed.
If nil, the buffer won't be killed.
If a function, it must return one of the other possible values above. It takes
the popup buffer as its sole argument.
If nil, the buffer won't be killed and is left to its own devices.
If t, resort to the default :ttl in `+popup-defaults'. If none exists, this is
the same as nil.
If a function, it takes one argument: the target popup buffer. The popup
system does nothing else and ignores the function's return value.
:quit BOOL|FN
CDR can be t, 'other, 'current, nil, or a function that returns one of these.
This determines the behavior of the ESC/C-g keys in or outside of popup
windows.
:quit FN|BOOL|'other|'current
Can be t, 'other, 'current, nil, or a function. This determines the behavior
of the ESC/C-g keys in or outside of popup windows.
If t, close the popup if ESC/C-g is pressed inside or outside of popups.
If t, close the popup if ESC/C-g is pressed anywhere.
If 'other, close this popup if ESC/C-g is pressed outside of any popup. This
is great for popups you just want to peek at and discard, but might also
want to poke around in, without the risk of closing it from the inside.
is great for popups you may press ESC/C-g a lot in.
If 'current, close the current popup if ESC/C-g is pressed from inside of the
popup.
If nil, pressing ESC/C-g will never close this buffer.
If a function, it is checked each time ESC/C-g is pressed to determine the
fate of the popup window. This function takes one argument: the popup window
and must return one of the other possible values.
popup. This makes it harder to accidentally close a popup until you really
want to.
If nil, pressing ESC/C-g will never close this popup.
If a function, it takes one argument: the to-be-closed popup window, and is
run when ESC/C-g is pressed while that popup is open. It must return one of
the other values to determine the fate of the popup.
:select BOOL|FN
CDR can be a boolean or function. The boolean determines whether to focus the
Can be a boolean or function. The boolean determines whether to focus the
popup window after it opens (non-nil) or focus the origin window (nil).
If a function, it takes two arguments: the popup window and the source window
(where you were before the popup was opened). It does nothing else, and
ignores its return value.
If a function, it takes two arguments: the popup window and originating window
(where you were before the popup opened). The popup system does nothing else
and ignores the function's return value.
:modeline BOOL|SYMBOL|FN
CDR can be t (show the default modeline), a symbol representing the name of a
Can be t (show the default modeline), a symbol representing the name of a
modeline defined with `def-modeline!', nil (show no modeline) or a function
that returns one of these. The function takes one argument: the popup buffer.
that returns a modeline format. The function takes no arguments and is run in
the context of the popup buffer.
:autosave BOOL|FN
This parameter determines what to do with modified buffers in closing popup
windows. CDR can be a t, 'ignore, a function or nil.
This parameter determines what to do with modified buffers when closing popup
windows. It accepts t, 'ignore, a function or nil.
If t, no prompts. Just save them automatically (if they're file-visiting
buffers).
If 'ignore, no prompts, no saving. Just silently kill it.
buffers). Same as 'ignore for non-file-visiting buffers.
If nil (the default), prompt the user what to do if the buffer is
file-visiting and modified.
If a function, the return value must return one of the other values. It takes
two arguments: the popup window and buffer.
If 'ignore, no prompts, no saving. Just silently kill it.
If a function, it is run with one argument: the popup buffer, and must return
non-nil to save or nil to do nothing (but no prompts).
:parameters ALIST
An alist of custom window parameters. See \(info window-parameters)
An alist of custom window parameters. See `(elisp)Window Parameters'.
If any of these are omitted, defaults derived from `+popup-defaults' will be
used."
@ -160,9 +169,11 @@ used."
;;;###autodef
(defun set-popup-rules! (&rest rulesets)
"Like `set-popup-rules!', but defines multiple popup rules. Every entry in RULESETS
should be a list of lists (each sublist is a popup rule that could be passed to
`set-popup-rule!').
"Defines multiple popup rules.
Every entry in RULESETS should be a list of alists where the CAR is the
predicate and CDR is a plist. See `set-popup-rule!' for details on the predicate
and plist.
Example:

View file

@ -70,8 +70,8 @@ adjustment.")
window--sides-inhibit-check nil)
(+popup|cleanup-rules)
(dolist (prop +popup-window-parameters)
(setq window-persistent-parameters
(map-delete window-persistent-parameters prop))))))
(delq (assq prop window-persistent-parameters)
window-persistent-parameters)))))
(define-minor-mode +popup-buffer-mode
"Minor mode for individual popup windows.
@ -103,7 +103,7 @@ should match the arguments of `+popup-define' or the :popup setting."
(declare (indent defun))
`(let ((+popup--display-buffer-alist +popup--old-display-buffer-alist)
display-buffer-alist)
(set-popup-rules! ,@rules)
(set-popup-rules! ,rules)
(when (bound-and-true-p +popup-mode)
(setq display-buffer-alist +popup--display-buffer-alist))
,@body))

View file

@ -0,0 +1,212 @@
;; -*- no-byte-compile: t; -*-
;;; ui/popup/test/test-popup.el
(describe "ui/popup"
:var (display-buffer-alist
+popup-default-display-buffer-actions
+popup--display-buffer-alist
+popup-defaults
wconf)
(before-all
(require! :ui popup)
(delete-other-windows)
(switch-to-buffer "*scratch*")
(setq wconf (current-window-configuration))
(+popup-mode +1))
(after-all
(+popup-mode -1))
(before-each
(setq display-buffer-alist nil
+popup--display-buffer-alist nil
+popup-default-display-buffer-actions '(+popup-display-buffer-stacked-side-window)
+popup-defaults '(:side bottom :select ignore :ttl nil :slot 1 :vslot 1)))
(after-each
(set-window-configuration wconf))
(describe "set-popup-rule!"
(it "sets popup rules"
(set-popup-rule! "does-not-exist" :size 10)
(let ((rule (cdr (assoc "does-not-exist" display-buffer-alist))))
(expect rule :to-contain '(+popup-buffer))
(expect rule :to-contain '(size . 10))))
(it "shadows old rules"
(set-popup-rule! "a" :size 10)
(set-popup-rule! "a" :size 20)
(expect (cdr (assoc "a" display-buffer-alist))
:to-contain '(size . 20)))
(it "resolves to defaults"
(let ((+popup-defaults '(:size 5)))
(set-popup-rule! "a")
(expect (cdr (assoc "a" display-buffer-alist))
:to-contain '(size . 5)))))
(describe "popup rules"
:var (origin a b c d e f g)
(before-all (setq origin (current-buffer)))
(before-each
(dolist (name '(a b c d e f g))
(set name (get-buffer-create (symbol-name name)))))
(after-each
(let (kill-buffer-query-functions kill-buffer-hook)
(dolist (x (list a b c d e f g))
(ignore-errors (delete-window (get-buffer-window x)))
(kill-buffer x))))
(describe "slot positioning"
(before-each
(set-popup-rules!
'(("a" :slot 1 :vslot 1)
("b" :slot 2 :vslot 1)
("c" :slot 1 :vslot 2)
("d" :slot 2 :vslot 2)
("e" :slot 1 :vslot 3)
("f" :slot 1 :vslot 3)
("g"))))
(it "replaces popups with the same slots"
(mapc #'display-buffer (list e f))
(expect (length (+popup-windows)) :to-be 1))
(it "replaces popups among multiple that have the same slots"
(let ((first (display-buffer a))
(second (display-buffer b))
(third (display-buffer e))
(fourth (display-buffer f)))
(expect (+popup-windows) :to-have-same-items-as
(list first second fourth))))
(describe ":slot"
(it "opens left of others if lower"
(let ((first (display-buffer b))
(second (display-buffer a)))
(expect (length (+popup-windows)) :to-be 2)
(expect (window-in-direction 'left first t)
:to-equal second)))
(it "opens right of others if higher"
(let ((first (display-buffer a))
(second (display-buffer b)))
(expect (length (+popup-windows)) :to-be 2)
(expect (window-in-direction 'right first t)
:to-equal second)))
(it "obeys default :slot"
(let ((window (display-buffer g)))
(expect (window-parameter window 'window-slot) :to-be 1)
(expect (window-parameter window 'window-vslot) :to-be 1))))
(describe ":vslot"
;; TODO Implement this, somehow
(xit "opens lower :vslot popups above others"
(let ((first (display-buffer c))
(second (display-buffer a)))
(expect (length (+popup-windows)) :to-be 2)
(expect (window-in-direction 'above first t)
:to-equal second)))
(it "opens higher :vslot popups below others"
(let ((first (display-buffer c))
(second (display-buffer e)))
(expect (length (+popup-windows)) :to-be 2)
(expect (window-in-direction 'below first t)
:to-equal second)))))
(describe ":select"
(it "selects the popup if non-nil"
(set-popup-rule! "^a$" :select t)
(display-buffer a)
(expect (current-buffer) :to-equal a))
(it "selects the originating window if nil"
(set-popup-rule! "^a$" :select nil)
(display-buffer a)
(expect (current-buffer) :to-equal origin))
(it "fall back to base selection if passed #'ignore"
(spy-on 'ignore)
(set-popup-rule! "^a$" :select #'ignore)
(save-window-excursion
(display-buffer a)
(expect (current-buffer) :to-equal origin))
(save-window-excursion
(pop-to-buffer a)
(expect (current-buffer) :to-equal a))
(expect 'ignore :to-have-been-called-times 2)))
(describe ":modeline"
(it "disables the mode-line if nil"
(set-popup-rule! "a" :modeline nil :select t)
(display-buffer a)
(expect mode-line-format :to-be nil))
(it "uses the default mode-line if t"
(set-popup-rule! "a" :modeline t :select t)
(display-buffer a)
(expect mode-line-format :to-equal (default-value 'mode-line-format)))
(it "uses a predefined mode-line if passed a symbol"
(def-modeline! test-popup-modeline ("x") ())
(set-popup-rule! "a" :modeline 'test-popup-modeline :select t)
(display-buffer a)
(expect mode-line-format :to-equal (doom-modeline 'test-popup-modeline)))
(it "runs the handler if passed a function"
(set-popup-rule! "a" :modeline (lambda () (setq mode-line-format '("x"))) :select t)
(display-buffer a)
(expect mode-line-format :to-equal '("x"))))
;; TODO
(xdescribe ":autosave")
(describe ":quit"
(it "will close from anywhere if :quit = t"
(set-popup-rule! "a" :quit t)
(save-window-excursion
(display-buffer a)
(call-interactively #'+popup/close-all)
(expect (get-buffer-window a) :to-be nil))
(save-window-excursion
(pop-to-buffer a)
(call-interactively #'+popup/close)
(expect (get-buffer-window a) :to-be nil)))
(it "will only close from outside if :quit = 'other"
(set-popup-rule! "a" :quit 'other)
(save-window-excursion
(display-buffer a)
(call-interactively #'+popup/close-all)
(expect (get-buffer-window a) :to-be nil))
(save-window-excursion
(pop-to-buffer a)
(call-interactively #'+popup/close)
(expect (get-buffer-window a))))
(it "will only close from inside if :quit = 'current"
(set-popup-rule! "a" :quit 'current)
(save-window-excursion
(display-buffer a)
(call-interactively #'+popup/close-all)
(expect (get-buffer-window a)))
(save-window-excursion
(pop-to-buffer a)
(call-interactively #'+popup/close)
(expect (get-buffer-window a) :to-be nil)))
(it "never close a if :quit = nil"
(set-popup-rule! "a" :quit nil)
(save-window-excursion
(display-buffer a)
(call-interactively #'+popup/close-all)
(expect (get-buffer-window a)))
(save-window-excursion
(pop-to-buffer a)
(call-interactively #'+popup/close)
(expect (get-buffer-window a)))))
;; TODO
(xdescribe ":ttl")
(xdescribe ":size")
(xdescribe ":width")
(xdescribe ":height")
(xdescribe ":side")
(xdescribe ":actions"))
;; TODO
(xdescribe "predicate functions"
(describe "buffer-p")
(describe "window-p"))
;; TODO
(xdescribe "save-popups!")
(xdescribe "with-popup-rules!"))

View file

@ -28,6 +28,7 @@ besides what is listed.")
:lambda "λ"
:def "ƒ"
:composition ""
:map ""
;; Types
:null ""
:true "𝕋"
@ -48,7 +49,8 @@ besides what is listed.")
:yield ""
;; Other
:tuple ""
:pipe "")
:pipe ""
:dot "")
"Options plist for `pretty-code-get-pairs'.")
(defvar +pretty-code--iosevka-ligeratures-enabled nil)

View file

@ -0,0 +1,26 @@
;;; ui/vc-gutter/autoload.el -*- lexical-binding: t; -*-
;;;###autoload (autoload '+vc-gutter-hydra/body "ui/vc-gutter/autoload" nil nil)
(defhydra +vc-gutter-hydra
(:body-pre (git-gutter-mode 1) :hint nil)
"
[git gutter]
Movement Hunk Actions Misc. +%-4s(car (git-gutter:statistic))/ -%-4s(cdr (git-gutter:statistic))
^_g_^ [_s_] stage [_R_] set start Rev
^_k_^ [_r_] revert
^ ^ [_m_] mark
^ ^ [_p_] popup
^_j_^ [_q_] quit
^_G_^ [_Q_] Quit and disable"
("j" (progn (git-gutter:next-hunk 1) (recenter)))
("k" (progn (git-gutter:previous-hunk 1) (recenter)))
("g" (progn (goto-char (point-min)) (git-gutter:next-hunk 1)))
("G" (progn (goto-char (point-min)) (git-gutter:previous-hunk 1)))
("s" git-gutter:stage-hunk)
("r" git-gutter:revert-hunk)
("m" git-gutter:mark-hunk)
("p" git-gutter:popup-hunk)
("R" git-gutter:set-start-revision)
("q" nil :color blue)
("Q" (git-gutter-mode -1) :color blue))

View file

@ -51,30 +51,6 @@ to the right fringe.")
;; update git-gutter when using these commands
(add-hook 'magit-post-refresh-hook #'+version-control|update-git-gutter)
(defhydra +version-control@git-gutter
(:body-pre (git-gutter-mode 1) :hint nil)
"
Movement Hunk Actions Misc. gg: +%-4s(car (git-gutter:statistic))/ -%-3s(cdr (git-gutter:statistic))
^_g_^ [_s_] stage [_R_] set start Rev
^_k_^ [_r_] revert
^ ^ [_m_] mark
^ ^ [_p_] popup
^_j_^ [_q_] quit
^_G_^ [_Q_] Quit and disable"
("j" (progn (git-gutter:next-hunk 1) (recenter)))
("k" (progn (git-gutter:previous-hunk 1) (recenter)))
("g" (progn (goto-char (point-min)) (git-gutter:next-hunk 1)))
("G" (progn (goto-char (point-min)) (git-gutter:previous-hunk 1)))
("s" git-gutter:stage-hunk)
("r" git-gutter:revert-hunk)
("m" git-gutter:mark-hunk)
("p" git-gutter:popup-hunk)
("R" git-gutter:set-start-revision)
("q" nil :color blue)
("Q" (git-gutter-mode -1) :color blue))
;; subtle diff indicators in the fringe
(when +vc-gutter-default-style
;; places the git gutter outside the margins.