Refactor add-hook! and associate!; associate! only for minor modes now

This commit is contained in:
Henrik Lissner 2017-03-02 18:14:52 -05:00
parent ea8ed1f997
commit c037c325a1
4 changed files with 75 additions and 47 deletions

View file

@ -26,6 +26,39 @@
s-capitalized-words s-titleized-words s-word-initials)) s-capitalized-words s-titleized-words s-word-initials))
;;
;; Helpers
;;
(defun doom--resolve-paths (paths &optional root)
(cond ((stringp paths)
`(file-exists-p
(expand-file-name
,paths ,(if (or (string-prefix-p "./" paths)
(string-prefix-p "../" paths))
'default-directory
root))))
((listp paths)
(let (forms)
(dolist (i paths (nreverse forms))
(push (doom--resolve-paths i root) forms))))
(t paths)))
(defun doom--resolve-hooks (hooks)
(let ((quoted-p (eq (car-safe hooks) 'quote))
ret-hooks)
(when quoted-p
(setq hooks (cadr hooks)))
(dolist (hook (if (listp hooks) hooks (list hooks)) (nreverse ret-hooks))
(push (cond ((eq (car-safe hook) 'quote)
(cadr hook))
((string-suffix-p "-hook" (symbol-name hook))
hook)
(t
(intern (format "%s-hook" (symbol-name hook)))))
ret-hooks))))
;; ;;
;; Library ;; Library
;; ;;
@ -96,33 +129,32 @@ Examples:
(add-hook! :append (one-mode second-mode) 'enable-something) (add-hook! :append (one-mode second-mode) 'enable-something)
(add-hook! :local (one-mode second-mode) 'enable-something) (add-hook! :local (one-mode second-mode) 'enable-something)
(add-hook! (one-mode second-mode) (setq v 5) (setq a 2)) (add-hook! (one-mode second-mode) (setq v 5) (setq a 2))
(add-hook! :append :local (one-mode second-mode) (setq v 5) (setq a 2))" (add-hook! :append :local (one-mode second-mode) (setq v 5) (setq a 2))
Body forms can access the hook's arguments through the let-bound variable
`args'."
(declare (indent defun) (debug t)) (declare (indent defun) (debug t))
(let (hook append-p local-p) (let (hook append-p local-p)
(while (keywordp (car args)) (while (keywordp (car args))
(cl-ecase (pop args) (pcase (pop args)
(:append (setq append-p t)) (:append (setq append-p t))
(:local (setq local-p t)))) (:local (setq local-p t))))
(let* ((hooks (pop args)) (let ((hooks (doom--resolve-hooks (pop args)))
(quoted-p (eq (car-safe hooks) 'quote)) (funcs
(funcs (let ((val (car args)))
(let ((val (car args))) (if (eq (car-safe val) 'quote)
(if (eq (car-safe val) 'quote) (if (cdr-safe (cadr val))
(if (cdr-safe (cadr val)) (cadr val)
(cadr val) (list (cadr val)))
(list (cadr val))) (list args))))
(list args)))) forms)
forms)
(when quoted-p
(setq hooks (cadr hooks)))
(unless (listp hooks)
(setq hooks (list hooks)))
(dolist (fn funcs) (dolist (fn funcs)
(setq fn (if (symbolp fn) `(quote ,fn) `(lambda (&rest args) ,@args))) (setq fn (if (symbolp fn)
(dolist (h hooks) `(quote ,fn)
`(lambda (&rest args) ,@args)))
(dolist (hook hooks)
(push `(,(if (boundp 'hook-fn) hook-fn 'add-hook) (push `(,(if (boundp 'hook-fn) hook-fn 'add-hook)
',(if quoted-p h (intern (format "%s-hook" h))) ',hook ,fn ,append-p ,local-p)
,fn ,append-p ,local-p)
forms))) forms)))
`(progn ,@(nreverse forms))))) `(progn ,@(nreverse forms)))))
@ -133,40 +165,36 @@ Examples:
(macroexpand `(add-hook! ,@args)))) (macroexpand `(add-hook! ,@args))))
(defmacro associate! (mode &rest plist) (defmacro associate! (mode &rest plist)
"Associate a major or minor mode to certain patterns and project files." "Associate a minor mode to certain patterns and project files."
(declare (indent 1)) (declare (indent 1))
(unless noninteractive (unless noninteractive
(let* ((minor (plist-get plist :minor)) (let* ((modes (plist-get plist :modes))
(in (plist-get plist :in))
(match (plist-get plist :match)) (match (plist-get plist :match))
(files (plist-get plist :files)) (files (plist-get plist :files))
(pred (plist-get plist :when))) (pred-form (plist-get plist :when)))
(cond ((or files in pred) (cond ((or files modes pred-form)
(when (and files (when (and files
(not (or (listp files) (not (or (listp files)
(stringp files)))) (stringp files))))
(user-error "associate! :files expects a string or list of strings")) (user-error "associate! :files expects a string or list of strings"))
(let ((hook-name (intern (format "doom--init-mode-%s" mode)))) (let ((hook-name (intern (format "doom--init-mode-%s" mode))))
(macroexp-progn `(progn
(list `(defun ,hook-name () (defun ,hook-name ()
(when (and ,(if match `(if buffer-file-name (string-match-p ,match buffer-file-name)) t) (when (and (boundp ',mode)
(or ,(not files) (not ,mode)
(and (boundp ',mode) ,(if match `(if buffer-file-name (string-match-p ,match buffer-file-name)) t)
(not ,mode) ,(if files (doom--resolve-paths files) t)
(doom-project-has-files ,@(if (listp files) files (list files))))) ,(or pred-form t))
(or (not ,pred) (,mode 1)))
(funcall ,pred buffer-file-name))) ,@(if (and modes (listp modes))
(,mode 1))) (let (forms)
(if (and in (listp in)) (dolist (hook (doom--resolve-hooks modes) (nreverse forms))
(macroexp-progn (push `(add-hook ',hook ',hook-name) forms)))
(mapcar (lambda (h) `(add-hook ',h ',hook-name)) `((add-hook 'after-change-major-mode-hook ',hook-name))))))
(mapcar (lambda (m) (intern (format "%s-hook" m))) in)))
`(add-hook 'find-file-hook ',hook-name))))))
(match (match
`(add-to-list ',(if minor 'doom-auto-minor-mode-alist 'auto-mode-alist) `(push (cons ,match ',mode) doom-auto-minor-mode-alist))
(cons ,match ',mode))) (t (user-error "associate! invalid rules for mode [%s] (modes %s) (match %s) (files %s)"
(t (user-error "associate! invalid rules for mode [%s] (in %s) (match %s) (files %s)" mode modes match files))))))
mode in match files))))))
;; Provides a centralized configuration system that a) won't evaluate its ;; Provides a centralized configuration system that a) won't evaluate its

View file

@ -1,6 +1,6 @@
;;; module-data.el ;;; module-data.el
(associate! conf-mode :match "/sxhkdrc$") (push '("/sxhkdrc" . conf-mode) auto-mode-alist)
(def-package! nxml-mode (def-package! nxml-mode

View file

@ -60,7 +60,7 @@
:preface :preface
(defvar nose-mode-map (make-sparse-keymap)) (defvar nose-mode-map (make-sparse-keymap))
:init :init
(associate! nose-mode :match "/test_.+\\.py$" :in (python-mode)) (associate! nose-mode :match "/test_.+\\.py$" :modes (python-mode))
:config :config
(set! :popup "*nosetests*" :size 0.4 :noselect t) (set! :popup "*nosetests*" :size 0.4 :noselect t)
(set! :yas-minor-mode 'nose-mode) (set! :yas-minor-mode 'nose-mode)

View file

@ -44,7 +44,7 @@
:mode ("/\\.rspec$" . text-mode) :mode ("/\\.rspec$" . text-mode)
:init :init
(associate! rspec-mode :match "/\\.rspec$") (associate! rspec-mode :match "/\\.rspec$")
(associate! rspec-mode :in (ruby-mode yaml-mode) :files ("/spec/")) (associate! rspec-mode :modes (ruby-mode yaml-mode) :files ("/spec/"))
(defvar rspec-mode-verifiable-map (make-sparse-keymap)) (defvar rspec-mode-verifiable-map (make-sparse-keymap))
(defvar evilmi-ruby-match-tags (defvar evilmi-ruby-match-tags
'((("unless" "if") ("elsif" "else") "end") '((("unless" "if") ("elsif" "else") "end")