From 928812da8a5499fed68a6733776b47a5a7f25b6b Mon Sep 17 00:00:00 2001 From: Henrik Lissner Date: Mon, 19 Jun 2017 00:22:04 +0200 Subject: [PATCH] Make def-setting! behave more like defmacro set! used to aggressively evaluate its arguments (at expansion-time), even if placed inside an after! block. This causes unavoidable errors if those arguments use functions/variables that don't exist yet. Fixes #112 --- CHANGELOG.org | 9 ++++- core/core-editor.el | 17 ++++------ core/core-lib.el | 17 +++++----- core/core-popups.el | 6 ++-- modules/app/email/config.el | 40 ++++++++++++++--------- modules/app/irc/config.el | 12 ++----- modules/completion/company/config.el | 12 +++---- modules/feature/eval/config.el | 40 ++++++++++++----------- modules/feature/evil/config.el | 19 ++++------- modules/feature/version-control/config.el | 5 ++- modules/tools/electric-indent/config.el | 12 +++---- modules/tools/rotate-text/config.el | 22 +++++-------- 12 files changed, 104 insertions(+), 107 deletions(-) diff --git a/CHANGELOG.org b/CHANGELOG.org index a429e91f8..50f56d749 100644 --- a/CHANGELOG.org +++ b/CHANGELOG.org @@ -64,7 +64,6 @@ + Add README.org's with working babel blocks to modules. + Document best practices for customizing DOOM emacs. + =ui/doom-modeline= fix hardcoded spacing in between segments. -+ Fix ~def-setting!~ to act more like ~defmacro~, and not aggressively evaluate its arguments on expansion (and update all ~set!~ calls). + Rewrite main README.md to include more information about setting up, customizing, and troubleshooting DOOM Emacs. * Unreleased (master) @@ -79,6 +78,7 @@ + Fix =private//init.el= not being auto-loaded when the user's private module is absent in the root init.el file. + Improve error handling across the board. Emacs should now report more helpful errors. Catastrophic errors will be less likely to inhibit later modules from being loaded. + Unit-tests have been moved to their respective modules (and =core/test/=). + + Fix ~def-setting!~ to act more like ~defmacro~; don't aggressively evaluate its arguments on expansion. + =core-ui= + Add quit confirmation when trying to close a frame that contains real buffers. + Fix quit confirmations for clients connected to ~emacs --daemon~ with ~emacsclient~. @@ -96,6 +96,13 @@ + =feature= + =feature/evil= + Remove =goto-last-change=, which conflicts with =goto-chg=, which is a dependency of evil (that does the exact same thing, but is what evil uses). + + =feature/jump= + + Remove ~:xref-backend~ setting (replaced with ~:jump~). + + Add ~:jump MAJOR-MODE &rest PLIST~ setting, which recognizes four properties (that accept functions/commands): + + ~:definition~: jumps to the definition of the symbol under point. + + ~:references~: lists all references of the symbol at point and lets you jump to them. + + ~:documentation~: shows documentation for the symbol at point. + + ~:xref-backend~: a function that serves as an xref backend; this replaces ~:definition~ and ~:references~. + =ui= + =ui/doom= + Vastly improve daemon and terminal support for doom-themes by reloading the theme when a new client is attached, or new terminal/daemon frame is created. This prevents incorrect colors from bleeding across face class barriers. diff --git a/core/core-editor.el b/core/core-editor.el index b8d1f504e..f6dd3ec7c 100644 --- a/core/core-editor.el +++ b/core/core-editor.el @@ -138,16 +138,13 @@ fundamental-mode) for performance sake." :init (def-setting! :editorconfig (action value) ":add or :remove an entry in `editorconfig-indentation-alist'." - `(after! editorconfig - ,(cond ((eq action :add) - `(push ',value editorconfig-indentation-alist)) - ((eq action :remove) - (unless (symbolp value) - (error "%s is not a valid major-mode in editorconfig-indentation-alist" value)) - `(setq editorconfig-indentation-alist - (delq (assq ',value editorconfig-indentation-alist) - editorconfig-indentation-alist))) - (t (error "%s is an invalid action for :editorconfig" action))))) + (cond ((eq action :add) + `(push ,value editorconfig-indentation-alist)) + ((eq action :remove) + `(setq editorconfig-indentation-alist + (assq-delete-all ,value editorconfig-indentation-alist))) + (t (error "%s is an invalid action for :editorconfig" + action)))) :config (add-hook 'doom-init-hook #'editorconfig-mode) diff --git a/core/core-lib.el b/core/core-lib.el index 8d0a9c57e..9f45fb086 100644 --- a/core/core-lib.el +++ b/core/core-lib.el @@ -226,20 +226,21 @@ executed when called with `set!'. FORMS are not evaluated until `set!' calls it. (declare (indent defun) (doc-string 3)) (unless (keywordp keyword) (error "Not a valid property name: %s" keyword)) - `(progn - (defun ,(intern (format "doom-setting--setter%s" keyword)) ,arglist - ,docstring - ,@forms) - (cl-pushnew ,keyword doom-settings))) + (let ((fn (intern (format "doom-setting--setter%s" keyword)))) + `(progn + (defun ,fn ,arglist + ,docstring + ,@forms) + (cl-pushnew ',(cons keyword fn) doom-settings :test #'eq :key #'car)))) (defmacro set! (keyword &rest values) "Set an option defined by `def-setting!'. Skip if doesn't exist." (declare (indent defun)) (unless values (error "Empty set! for %s" keyword)) - (let ((fn (intern (format "doom-setting--setter%s" keyword)))) - (if (functionp fn) - (apply fn (eval `(list ,@values))) + (let ((fn (cdr (assq keyword doom-settings)))) + (if fn + (apply fn values) (when doom-debug-mode (message "No setting found for %s" keyword))))) diff --git a/core/core-popups.el b/core/core-popups.el index cbf2adcfe..aa3a065f1 100644 --- a/core/core-popups.el +++ b/core/core-popups.el @@ -38,9 +38,9 @@ is enabled/disabled.'") (def-setting! :popup (&rest rules) "Prepend a new popup rule to `shackle-rules'." - (if (cl-every #'listp rules) - `(setq shackle-rules (nconc ',rules shackle-rules)) - `(push ',rules shackle-rules))) + (if (cl-every #'listp (mapcar #'doom-unquote rules)) + `(setq shackle-rules (nconc (list ,@rules) shackle-rules)) + `(push (list ,@rules) shackle-rules))) ;; diff --git a/modules/app/email/config.el b/modules/app/email/config.el index d5d609327..7afb090a3 100644 --- a/modules/app/email/config.el +++ b/modules/app/email/config.el @@ -12,20 +12,27 @@ ;; Config ;; -(defvar +email--accounts nil) +(def-setting! :email (label letvars &optional default-p) + "Registers an email address for mu4e. The LABEL is a string. LETVARS are a +list of cons cells (VARIABLE . VALUE) -- you may want to modify: -(def-setting! :email (label letvars &optional default) - "Registers an email address for mu4e." - (let ((name (or (cdr (assq 'user-full-name letvars)) user-full-name)) - (address (cdr (assq 'user-mail-address letvars)))) - (dolist (var letvars) - (let ((val (cdr var))) - (when (and (stringp val) (string-match-p "%s" val)) - (setcdr var (format val label))))) - `(progn - (push ',(cons label letvars) +email--accounts) - ,(when address - `(add-to-list 'mu4e-user-mail-address-list ,address)) + + `user-full-name' (this or the global `user-full-name' is required) + + `user-mail-address' (required) + + `smtpmail-smtp-user' (required for sending mail from Emacs) + +OPTIONAL: + + `mu4e-sent-folder' + + `mu4e-drafts-folder' + + `mu4e-trash-folder' + + `mu4e-refile-folder' + + `mu4e-compose-signature' + +DEFAULT-P is a boolean. If non-nil, it marks that email account as the +default/fallback account." + `(after! mu4e + (let ((account-vars ,letvars)) + (when-let (address (cdr (assq 'user-mail-address account-vars))) + (cl-pushnew address mu4e-user-mail-address-list :test #'equal)) (let ((context (make-mu4e-context :name ,label :enter-func (lambda () (mu4e-message "Switched to %s" ,label)) @@ -33,10 +40,11 @@ :match-func (lambda (msg) (when msg - (string-prefix-p (format "/%s" ,label) (mu4e-message-field msg :maildir)))) - :vars ',letvars))) + (string-prefix-p (format "/%s" ,label) + (mu4e-message-field msg :maildir)))) + :vars ,letvars))) (push context mu4e-contexts) - ,(when default + ,(when default-p `(setq-default mu4e-context-current context)))))) diff --git a/modules/app/irc/config.el b/modules/app/irc/config.el index ed65c40e6..fdde7bf4b 100644 --- a/modules/app/irc/config.el +++ b/modules/app/irc/config.el @@ -15,9 +15,6 @@ (defvar +irc-notifications-watch-strings nil "TODO") -(defvar +irc-connections nil - "A list of connections set with :irc. W") - (defvar +irc-defer-notifications nil "How long to defer enabling notifications, in seconds (e.g. 5min = 300). Useful for ZNC users who want to avoid the deluge of notifications during buffer @@ -25,8 +22,9 @@ playback.") (def-setting! :irc (server letvars) "Registers an irc server for circe." - `(cl-pushnew (cons ,server ,letvars) +irc-connections - :test #'equal :key #'car)) + `(after! circe + (cl-pushnew (cons ,server ,letvars) circe-network-options + :test #'equal :key #'car))) (defvar +irc--defer-timer nil) @@ -39,10 +37,6 @@ playback.") :commands (circe circe-server-buffers) :init (setq circe-network-defaults nil) :config - ;; change hands - (setq circe-network-options +irc-connections) - (defvaralias '+irc-connections 'circe-network-options) - (defsubst +irc--pad (left right) (format (format "%%%ds | %%s" +irc-left-padding) (concat "*** " left) right)) diff --git a/modules/completion/company/config.el b/modules/completion/company/config.el index 4c3b00363..da4c566c9 100644 --- a/modules/completion/company/config.el +++ b/modules/completion/company/config.el @@ -2,17 +2,15 @@ (def-setting! :company-backend (modes backends) "Register company BACKENDS to MODES." - (let* ((modes (if (listp modes) modes (list modes))) - (backends (if (listp backends) backends (list backends))) + (let* ((modes (doom-enlist (doom-unquote modes))) + (backends (doom-enlist (doom-unquote backends))) (def-name (intern (format "doom--init-company-%s" - (mapconcat #'identity (mapcar #'symbol-name modes) "-"))))) - ;; TODO more type checks + (mapconcat #'symbol-name modes "-"))))) `(prog1 (defun ,def-name () - (when (memq major-mode ',modes) + (when (memq major-mode ,modes) (require 'company) - (unless (member ',backends company-backends) - (setq-local company-backends (append '((,@backends)) company-backends))))) + (cl-pushnew ,backends company-backends :test #'equal))) (add-hook! ,modes #',def-name)))) diff --git a/modules/feature/eval/config.el b/modules/feature/eval/config.el index 8012ca535..3e02fffb2 100644 --- a/modules/feature/eval/config.el +++ b/modules/feature/eval/config.el @@ -15,11 +15,12 @@ PLIST accepts the following properties: :when FORM A predicate to determine if the builder is appropriate for this buffer." - `(dolist (mode ',(if (listp modes) modes (list modes)) +eval-builders) + `(dolist (mode ',(doom-enlist (doom-unquote modes)) +eval-builders) (unless (assq mode +eval-builders) (push (list mode) +eval-builders)) - (push (cons ',name (append (list :fn #',fn) ',plist)) - (cdr (assq mode +eval-builders))))) + (cl-pushnew (cons ,name (append (list :fn ,fn) (list ,@plist))) + (cdr (assq mode +eval-builders)) + :test #'eq :key #'car))) ;; @@ -35,9 +36,9 @@ PLIST accepts the following properties: :init-value nil) (def-setting! :repl (mode command) - "Define a REPL for a mode. MODE is a major mode and COMMAND is a function that -invokes the repl. Takes the same arguements as `rtog/add-repl'." - `(push ',(cons mode command) +eval-repls)) + "Define a REPL for a mode. MODE is a major mode symbol and COMMAND is a +function that creates and returns the REPL buffer." + `(push (cons ,mode ,command) +eval-repls)) (set! :popup '(:custom (lambda (b &rest _) (buffer-local-value '+eval-repl-mode b))) @@ -67,19 +68,20 @@ invokes the repl. Takes the same arguements as `rtog/add-repl'." (quickrun-add-command MODE COMMAND :mode MODE). 4. If MODE is not a string and COMMANd is a symbol, add it to `+eval-runners-alist', which is used by `+eval/region'." - (cond ((symbolp command) - `(push ',(cons mode command) +eval-runners-alist)) - ((stringp command) - `(after! quickrun - (push ',(cons mode command) - ,(if (stringp mode) - 'quickrun-file-alist - 'quickrun--major-mode-alist)))) - ((listp command) - `(after! quickrun - (quickrun-add-command - ,(symbol-name mode) - ',command :mode ',mode))))) + (let ((command (doom-unquote command))) + (cond ((symbolp command) + `(push (cons ,mode ',command) +eval-runners-alist)) + ((stringp command) + `(after! quickrun + (push (cons ,mode ',command) + ,(if (stringp mode) + 'quickrun-file-alist + 'quickrun--major-mode-alist)))) + ((listp command) + `(after! quickrun + (quickrun-add-command + ,(symbol-name (doom-unquote mode)) + ',command :mode ,mode)))))) (def-package! quickrun :commands (quickrun diff --git a/modules/feature/evil/config.el b/modules/feature/evil/config.el index 559c8e81f..b20dc6940 100644 --- a/modules/feature/evil/config.el +++ b/modules/feature/evil/config.el @@ -3,19 +3,14 @@ ;; 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. -(def-setting! :evil-state (&rest mode-state-list) +(def-setting! :evil-state (modes state) "Set the initialize STATE of MODE using `evil-set-initial-state'." - (if (cl-every #'listp mode-state-list) - `(progn - ,@(let (forms) - (dolist (it mode-state-list (nreverse forms)) - (unless (consp it) - (error ":evil-state expected cons cells, got %s" it)) - (push `(evil-set-initial-state ',(car it) ',(cdr it)) forms)))) - (let ((argc (length mode-state-list))) - (unless (= argc 2) - (error ":evil-state expected 2 arguments, got %s" argc))) - `(evil-set-initial-state ',(car mode-state-list) ',(cadr mode-state-list)))) + (let ((unquoted-modes (doom-unquote modes))) + (if (listp unquoted-modes) + `(progn + ,@(cl-loop for mode in unquoted-modes + collect `(evil-set-initial-state ',mode ,state))) + `(evil-set-initial-state ,modes ,state)))) ;; diff --git a/modules/feature/version-control/config.el b/modules/feature/version-control/config.el index e422a0a6e..95d45108e 100644 --- a/modules/feature/version-control/config.el +++ b/modules/feature/version-control/config.el @@ -11,6 +11,5 @@ '("*vc-change-log*" :size 15) '(vc-annotate-mode :same t)) - (set! :evil-state - '(vc-annotate-mode . normal) - '(vc-git-log-view-mode . normal))) + (set! :evil-state 'vc-annotate-mode 'normal) + (set! :evil-state 'vc-git-log-view-mode 'normal)) diff --git a/modules/tools/electric-indent/config.el b/modules/tools/electric-indent/config.el index a36cb28de..9eb04db3f 100644 --- a/modules/tools/electric-indent/config.el +++ b/modules/tools/electric-indent/config.el @@ -22,15 +22,15 @@ "Declare :words (list of strings) or :chars (lists of chars) in MODES that trigger electric indentation." (declare (indent 1)) - (let ((modes (if (listp modes) modes (list modes))) - (chars (plist-get plist :chars)) - (words (plist-get plist :words))) + (let ((modes (doom-enlist (doom-unquote modes))) + (chars (doom-unquote (plist-get plist :chars))) + (words (doom-unquote (plist-get plist :words)))) (when (or chars words) - (let ((fn-name (intern (format "doom--electric-%s" (string-join (mapcar #'symbol-name modes) "-"))))) + (let ((fn-name (intern (format "doom--init-electric-%s" (mapconcat #'symbol-name modes "-"))))) `(progn (defun ,fn-name () (electric-indent-local-mode +1) - ,(if chars `(setq electric-indent-chars ',chars)) - ,(if words `(setq doom-electric-indent-words ',words))) + ,@(if chars `((setq electric-indent-chars ',chars))) + ,@(if words `((setq doom-electric-indent-words ',words)))) (add-hook! ,modes #',fn-name)))))) diff --git a/modules/tools/rotate-text/config.el b/modules/tools/rotate-text/config.el index 9fccf985e..488ce72a7 100644 --- a/modules/tools/rotate-text/config.el +++ b/modules/tools/rotate-text/config.el @@ -9,17 +9,13 @@ (def-setting! :rotate (modes &rest plist) "Declare :symbols, :words or :patterns that `rotate-text' will cycle through." (declare (indent 1)) - (let ((modes (if (listp modes) modes (list modes))) - (symbols (plist-get plist :symbols)) - (words (plist-get plist :words)) - (patterns (plist-get plist :patterns))) - (when (or symbols words patterns) - (let ((fn-name (intern (format "doom--rotate-%s" (string-join (mapcar #'symbol-name modes) "-"))))) - `(progn - (defun ,fn-name () - (require 'rotate-text) - ,(if symbols `(setq rotate-text-local-symbols ',symbols)) - ,(if words `(setq rotate-text-local-words ',words)) - ,(if patterns `(setq rotate-text-local-patterns ',patterns))) - (add-hook! ,modes #',fn-name)))))) + (let* ((modes (doom-enlist (doom-unquote modes))) + (fn-name (intern (format "doom--rotate-%s" (mapconcat #'symbol-name modes "-"))))) + `(progn + (defun ,fn-name () + (let ((plist (list ,@plist))) + (setq rotate-text-local-symbols (plist-get plist :symbols) + rotate-text-local-words (plist-get plist :words) + rotate-text-local-patterns (plist-get plist :patterns)))) + (add-hook! ,modes #',fn-name))))