diff --git a/core/core-lib.el b/core/core-lib.el index 1836a41d6..ea54f34d0 100644 --- a/core/core-lib.el +++ b/core/core-lib.el @@ -26,23 +26,19 @@ during compilation." HOOK can be one hook or a list of hooks. If the hook(s) are not quoted, -hook is appended to them automatically. If they are quoted, they are used verbatim. -FUNC-OR-FORMS can be a quoted symbol, a list of quoted symbols, or forms. Forms will be -wrapped in a lambda. A list of symbols will expand into a series of add-hook calls. +FUNC-OR-FORMS can be a quoted symbol, a list of quoted symbols, or forms. Forms +will be wrapped in a lambda. A list of symbols will expand into a series of +add-hook calls. Examples: (add-hook! 'some-mode-hook 'enable-something) (add-hook! some-mode '(enable-something and-another)) (add-hook! '(one-mode-hook second-mode-hook) 'enable-something) (add-hook! (one-mode second-mode) 'enable-something) - (add-hook! (one-mode second-mode) (setq v 5) (setq a 2)) - -If HOOK is omitted, then default to `__PACKAGE__' to determine HOOK." + (add-hook! (one-mode second-mode) (setq v 5) (setq a 2))" (declare (indent defun) (debug t)) (unless func-or-forms - (unless (bound-and-true-p __PACKAGE__) - (error "add-hook!: FUNC-OR-FORMS is empty")) - (setq func-or-forms hook - hook __PACKAGE__)) + (error "add-hook!: FUNC-OR-FORMS is empty")) (let* ((val (car func-or-forms)) (quoted-p (eq (car-safe hook) 'quote)) (hook (if quoted-p (cadr hook) hook)) @@ -60,15 +56,14 @@ If HOOK is omitted, then default to `__PACKAGE__' to determine HOOK." (-list hook))))) funcs)))) -(defmacro associate! (&rest rest) +(defmacro associate! (mode &rest plist) "Associate a major or minor mode to certain patterns and project files." (declare (indent 1)) - (let* ((mode (if (keywordp (car rest)) __PACKAGE__ (pop rest))) - (minor (plist-get rest :minor)) - (in (plist-get rest :in)) - (match (plist-get rest :match)) - (files (plist-get rest :files)) - (pred (plist-get rest :when))) + (let* ((minor (plist-get plist :minor)) + (in (plist-get plist :in)) + (match (plist-get plist :match)) + (files (plist-get plist :files)) + (pred (plist-get plist :when))) (cond ((or files in pred) (when (and files (not (or (listp files) (stringp files)))) (user-error "associate! :files expects a string or list of strings")) diff --git a/core/core-popups.el b/core/core-popups.el index d595d5ca8..31cddcb40 100644 --- a/core/core-popups.el +++ b/core/core-popups.el @@ -37,27 +37,33 @@ "Active keymap in popup windows.") +;; +;; Bootstrap +;; + +(doom-def-setting :popup + (lambda (&rest rule) + (let ((pattern (car rule)) + (plist (cdr rule))) + ;; Align popups by default (error if this doesn't happen) + (unless (plist-member plist :align) + (plist-put plist :align t)) + ;; Select popups by default + (unless (or (plist-member plist :select) + (plist-member plist :noselect)) + (plist-put plist :select t)) + (push (cons pattern plist) shackle-rules))) + "Prepend a new popup rule to `shackle-rules'.") + (package! shackle :demand t - :config - (shackle-mode 1) + :init (setq shackle-default-alignment 'below shackle-select-reused-windows t) - (def-setting! :popup (rule) - "Prepend a new popup rule to `shackle-rules'." - ;; Ensure some default attributes are set for window rules - (let ((pattern (car rule)) - (ruleset (cdr rule))) - ;; Align popups by default (error if this doesn't happen) - (unless (plist-member ruleset :align) - (plist-put ruleset :align shackle-default-alignment)) - ;; Select popups by default - (unless (or (plist-member ruleset :select) - (plist-member ruleset :noselect)) - (plist-put ruleset :select t)) - (setq rule (append (list pattern) ruleset)) - `(push ',rule shackle-rules))) + :config + (shackle-mode 1) + ;;; Baseline popup-window rules ;; :noesc and :modeline are custom settings and are not part of shackle. See ;; `doom*popup-init' and `doom-popup-buffer' for how they're used. (set! :popup diff --git a/core/core-set.el b/core/core-set.el index f2f9342fd..23c8fc3b0 100644 --- a/core/core-set.el +++ b/core/core-set.el @@ -9,27 +9,31 @@ "An alist of settings, mapping setting keywords to setter functions, which can be a lambda or symbol.") -(defmacro def-setting! (keyword arglist &optional docstring &rest body) +(defun doom-def-setting (keyword setter-fn &optional docstring) "Define a setting macro. Takes the same arguments as `defmacro'. This should return forms, which will be run when `set!' is used to call this setting." (declare (indent defun)) (unless (keywordp keyword) - (error "Not a valid property name: %s" name)) - (let ((sym (intern (format "doom--set%s" keyword)))) - (setq doom-settings (assq-delete-all keyword doom-settings)) - `(push (cons ,keyword - (defun ,sym ,arglist - ,docstring - ,@body)) - doom-settings))) + (error "Not a valid property name: %s" keyword)) + (unless (or (symbolp setter-fn) + (functionp setter-fn)) + (error "Not a valid setting function for %s" keyword)) + (push (list keyword + :source load-file-name + :docstring docstring + :fn setter-fn) + doom-settings)) (defmacro set! (keyword &rest rest) - "Set an option defined by `doom-define-settings'. Skip if doesn't exist." + "Set an option defined by `def-setting!'. Skip if doesn't exist." (declare (indent defun)) - (let ((set-fn (cdr (assq keyword doom-settings)))) - (when set-fn + (let* ((plist (cdr (assq keyword doom-settings))) + (fn (plist-get plist :fn))) + (when (and doom-debug-mode (not fn)) + (message "No setting found for %s" keyword)) + (when fn (macroexp-progn - (mapcar (lambda (&rest args) (apply set-fn args)) + (mapcar (lambda (args) `(apply #',fn ',(-list args))) rest))))) (provide 'core-set) diff --git a/modules/feature/evil/config.el b/modules/feature/evil/config.el index 0bfed7a14..64b308ac6 100644 --- a/modules/feature/evil/config.el +++ b/modules/feature/evil/config.el @@ -14,6 +14,10 @@ ;; evil-mode ;; +(doom-def-setting :evil-state + 'evil-set-initial-state + "Set the initialize STATE of MODE using `evil-set-initial-state'.") + (use-package! evil :demand t :init (setq evil-want-C-u-scroll t @@ -316,9 +320,9 @@ if on a delimiter, jump to the matching one (`evilmi-jump-items')." (evil-snipe-mode 1) (evil-snipe-override-mode 1) ;; Switch to evil-easymotion/avy after first snipe - (define-key evil-snipe-parent-transient-map (kbd "C-;") - (λ! (require 'evil-easymotion) - (call-interactively +evil--snipe-repeat-fn)))) + (map! :map evil-snipe-parent-transient-map + "C-;" (λ! (require 'evil-easymotion) + (call-interactively +evil--snipe-repeat-fn)))) (use-package! evil-surround @@ -369,28 +373,27 @@ if on a delimiter, jump to the matching one (`evilmi-jump-items')." "^#.*#$")) :config - (evil-set-initial-state 'neotree-mode 'motion) + (set! :evil-state (neotree-mode motion)) ;; Adding keybindings to `neotree-mode-map' wouldn't work for me (they get ;; overridden when the neotree buffer is spawned). So we bind them in a hook. (add-hook 'neo-after-create-hook '+evil|neotree-init-keymap) (defun +evil|neotree-init-keymap (&rest _) - (let ((map evil-motion-state-local-map)) - (define-key map (kbd "\\\\") 'evil-window-prev) - (define-key map (kbd "RET") 'neotree-enter) - (define-key map (kbd "") 'neotree-enter) - (define-key map (kbd "ESC ESC") 'neotree-hide) - (define-key map [return] 'neotree-enter) - (define-key map "q" 'neotree-hide) - (define-key map "J" 'neotree-select-next-sibling-node) - (define-key map "K" 'neotree-select-previous-sibling-node) - (define-key map "H" 'neotree-select-up-node) - (define-key map "L" 'neotree-select-down-node) - (define-key map "v" 'neotree-enter-vertical-split) - (define-key map "s" 'neotree-enter-horizontal-split) - (define-key map "c" 'neotree-create-node) - (define-key map "d" 'neotree-delete-node) - (define-key map "\C-r" 'neotree-refresh) - (define-key map "r" 'neotree-rename-node) - (define-key map "R" 'neotree-change-root)))) + (map! :Lm "\\\\" 'evil-window-prev + :Lm "RET" 'neotree-enter + :Lm "" 'neotree-enter + :Lm "ESC ESC" 'neotree-hide + :Lm [return] 'neotree-enter + :Lm "q" 'neotree-hide + :Lm "J" 'neotree-select-next-sibling-node + :Lm "K" 'neotree-select-previous-sibling-node + :Lm "H" 'neotree-select-up-node + :Lm "L" 'neotree-select-down-node + :Lm "v" 'neotree-enter-vertical-split + :Lm "s" 'neotree-enter-horizontal-split + :Lm "c" 'neotree-create-node + :Lm "d" 'neotree-delete-node + :Lm "\C-r" 'neotree-refresh + :Lm "r" 'neotree-rename-node + :Lm "R" 'neotree-change-root)))