core-lib: add auto-minor-mode, revise def-project-mode!
- Adds the auto-minor-mode package to replace our in-house implementation. - Merges associate! into the def-project-mode! macro because associate! on its own is less useful than auto-minor-mode-alist, auto-minor-mode-magic-alist or hooks. - Changes the semantics of :modes and :add-hooks properties of def-project-mode!. Its arguments are evaluated as is; lists will need to be quoted. squash! core-lib: remove associate! macro
This commit is contained in:
parent
3404899ec3
commit
0a84d2f0a9
15 changed files with 88 additions and 137 deletions
|
@ -451,51 +451,6 @@ DOCSTRING and BODY are as in `defun'."
|
||||||
(advice-remove target #',symbol)
|
(advice-remove target #',symbol)
|
||||||
(advice-add target ,where #',symbol)))))
|
(advice-add target ,where #',symbol)))))
|
||||||
|
|
||||||
(cl-defmacro associate! (mode &key modes match files when)
|
|
||||||
"Enables a minor mode if certain conditions are met.
|
|
||||||
|
|
||||||
The available conditions are:
|
|
||||||
|
|
||||||
:modes SYMBOL_LIST
|
|
||||||
A list of major/minor modes in which this minor mode may apply.
|
|
||||||
:match REGEXP
|
|
||||||
A regexp to be tested against the current file path.
|
|
||||||
:files SPEC
|
|
||||||
Accepts what `project-file-exists-p!' accepts. Checks if certain files or
|
|
||||||
directories exist relative to the project root.
|
|
||||||
:when FORM
|
|
||||||
Whenever FORM returns non-nil."
|
|
||||||
(declare (indent 1))
|
|
||||||
(unless noninteractive
|
|
||||||
(cond ((or files modes when)
|
|
||||||
(when (and files
|
|
||||||
(not (or (listp files)
|
|
||||||
(stringp files))))
|
|
||||||
(user-error "associate! :files expects a string or list of strings"))
|
|
||||||
(let ((hook-name (intern (format "doom--enable-mode-%s-h" mode))))
|
|
||||||
`(progn
|
|
||||||
(fset ',hook-name
|
|
||||||
(lambda ()
|
|
||||||
(and (fboundp ',mode)
|
|
||||||
(not (bound-and-true-p ,mode))
|
|
||||||
(and buffer-file-name (not (file-remote-p buffer-file-name)))
|
|
||||||
,(or (not match)
|
|
||||||
`(if buffer-file-name (string-match-p ,match buffer-file-name)))
|
|
||||||
,(or (not files)
|
|
||||||
(doom--resolve-path-forms
|
|
||||||
(if (stringp (car files)) (cons 'and files) files)
|
|
||||||
'(doom-project-root)))
|
|
||||||
,(or when t)
|
|
||||||
(,mode 1))))
|
|
||||||
,@(if (and modes (listp modes))
|
|
||||||
(cl-loop for hook in (doom--resolve-hook-forms modes)
|
|
||||||
collect `(add-hook ',hook #',hook-name))
|
|
||||||
`((add-hook 'after-change-major-mode-hook #',hook-name))))))
|
|
||||||
(match
|
|
||||||
`(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)))))
|
|
||||||
|
|
||||||
(defmacro file-exists-p! (spec &optional directory)
|
(defmacro file-exists-p! (spec &optional directory)
|
||||||
"Returns non-nil if the files in SPEC all exist.
|
"Returns non-nil if the files in SPEC all exist.
|
||||||
|
|
||||||
|
|
|
@ -236,31 +236,39 @@ If ALL-P is non-nil, return paths of possible modules, activated or otherwise."
|
||||||
use-package-minimum-reported-time (if doom-debug-mode 0 0.1)
|
use-package-minimum-reported-time (if doom-debug-mode 0 0.1)
|
||||||
use-package-expand-minimally (not noninteractive)))
|
use-package-expand-minimally (not noninteractive)))
|
||||||
|
|
||||||
;; Adds two new keywords to `use-package' (and consequently, `def-package!') to
|
;; Adds four new keywords to `use-package' (and consequently, `def-package!') to
|
||||||
;; expand its lazy-loading capabilities. They are:
|
;; expand its lazy-loading capabilities. They are:
|
||||||
;;
|
;;
|
||||||
;; :after-call SYMBOL|LIST
|
|
||||||
;; :defer-incrementally SYMBOL|LIST|t
|
|
||||||
;;
|
|
||||||
;; Check out `def-package!'s documentation for more about these two.
|
;; Check out `def-package!'s documentation for more about these two.
|
||||||
|
;; :after-call SYMBOL|LIST
|
||||||
|
;; :defer-incrementally SYMBOL|LIST|t
|
||||||
|
;;
|
||||||
|
;; Provided by `auto-minor-mode' package:
|
||||||
|
;; :minor
|
||||||
|
;; :magic-minor
|
||||||
|
;;
|
||||||
(defvar doom--deferred-packages-alist '(t))
|
(defvar doom--deferred-packages-alist '(t))
|
||||||
|
|
||||||
(with-eval-after-load 'use-package-core
|
(with-eval-after-load 'use-package-core
|
||||||
;; Macros are already fontified, no need for this
|
;; Macros are already fontified, no need for this
|
||||||
(font-lock-remove-keywords 'emacs-lisp-mode use-package-font-lock-keywords)
|
(font-lock-remove-keywords 'emacs-lisp-mode use-package-font-lock-keywords)
|
||||||
|
|
||||||
;; Disable :ensure and :pin, because they don't work with Doom because we do
|
;; Register all new keywords
|
||||||
;; our own package management.
|
|
||||||
(with-eval-after-load 'use-package-ensure
|
|
||||||
(dolist (keyword '(:ensure :pin))
|
|
||||||
(delq! keyword use-package-keywords)
|
|
||||||
(delq! keyword use-package-defaults 'assq)))
|
|
||||||
|
|
||||||
;; Insert new deferring keywords
|
|
||||||
(dolist (keyword '(:defer-incrementally :after-call))
|
(dolist (keyword '(:defer-incrementally :after-call))
|
||||||
(add-to-list 'use-package-deferring-keywords keyword nil #'eq)
|
(push keyword use-package-deferring-keywords)
|
||||||
(setq use-package-keywords
|
(setq use-package-keywords
|
||||||
(use-package-list-insert keyword use-package-keywords :after)))
|
(use-package-list-insert keyword use-package-keywords :after)))
|
||||||
|
(dolist (keyword '(:minor :magic-minor))
|
||||||
|
(setq use-package-keywords
|
||||||
|
(use-package-list-insert keyword use-package-keywords :commands)))
|
||||||
|
|
||||||
|
(defalias 'use-package-normalize/:minor #'use-package-normalize-mode)
|
||||||
|
(defun use-package-handler/:minor (name _ arg rest state)
|
||||||
|
(use-package-handle-mode name 'auto-minor-mode-alist arg rest state))
|
||||||
|
|
||||||
|
(defalias 'use-package-normalize/:magic-minor #'use-package-normalize-mode)
|
||||||
|
(defun use-package-handler/:magic-minor (name _ arg rest state)
|
||||||
|
(use-package-handle-mode name 'auto-minor-mode-magic-alist arg rest state))
|
||||||
|
|
||||||
(defalias 'use-package-normalize/:defer-incrementally #'use-package-normalize-symlist)
|
(defalias 'use-package-normalize/:defer-incrementally #'use-package-normalize-symlist)
|
||||||
(defun use-package-handler/:defer-incrementally (name _keyword targets rest state)
|
(defun use-package-handler/:defer-incrementally (name _keyword targets rest state)
|
||||||
|
|
|
@ -200,30 +200,47 @@ should be activated. If they are *all* true, NAME is activated.
|
||||||
Relevant: `doom-project-hook'."
|
Relevant: `doom-project-hook'."
|
||||||
(declare (indent 1))
|
(declare (indent 1))
|
||||||
(let ((init-var (intern (format "%s-init" name))))
|
(let ((init-var (intern (format "%s-init" name))))
|
||||||
`(progn
|
(macroexp-progn
|
||||||
,(if on-load `(defvar ,init-var nil))
|
(append
|
||||||
(define-minor-mode ,name
|
(when on-load
|
||||||
"A project minor mode generated by `def-project-mode!'."
|
`((defvar ,init-var nil)))
|
||||||
:init-value nil
|
`((define-minor-mode ,name
|
||||||
:lighter ""
|
"A project minor mode generated by `def-project-mode!'."
|
||||||
:keymap (make-sparse-keymap)
|
:init-value nil
|
||||||
(if (not ,name)
|
:lighter ""
|
||||||
,on-exit
|
:keymap (make-sparse-keymap)
|
||||||
(run-hook-with-args 'doom-project-hook ',name ,name)
|
(if (not ,name)
|
||||||
,(when on-load
|
,on-exit
|
||||||
`(unless ,init-var
|
(run-hook-with-args 'doom-project-hook ',name ,name)
|
||||||
,on-load
|
,(when on-load
|
||||||
(setq ,init-var t)))
|
`(unless ,init-var
|
||||||
,on-enter))
|
,on-load
|
||||||
,@(cl-loop for hook in add-hooks
|
(setq ,init-var t)))
|
||||||
collect `(add-hook ',(intern (format "%s-hook" name))
|
,on-enter))
|
||||||
#',hook))
|
(dolist (hook ,add-hooks)
|
||||||
,(when (or modes match files when)
|
(add-hook ',(intern (format "%s-hook" name)) hook)))
|
||||||
`(associate! ,name
|
(cond ((or files modes when)
|
||||||
:modes ,modes
|
(cl-check-type files (or null list string))
|
||||||
:match ,match
|
(let ((fn `(lambda ()
|
||||||
:files ,files
|
(and (not (bound-and-true-p ,name))
|
||||||
:when ,when)))))
|
(and buffer-file-name (not (file-remote-p buffer-file-name nil t)))
|
||||||
|
,(or (null match)
|
||||||
|
`(if buffer-file-name (string-match-p ,match buffer-file-name)))
|
||||||
|
,(or (null files)
|
||||||
|
(doom--resolve-path-forms
|
||||||
|
(if (stringp (car files)) (cons 'and files) files)
|
||||||
|
'(doom-project-root)))
|
||||||
|
,(or when t)
|
||||||
|
(,name 1)))))
|
||||||
|
`((dolist (mode ,modes)
|
||||||
|
(let ((hook-name (intern (format "doom--enable-%s%s-h" ',name
|
||||||
|
(if (eq mode t) "" (format "-in-" mode))))))
|
||||||
|
(fset hook-name #',fn)
|
||||||
|
(if (eq mode t)
|
||||||
|
(add-to-list 'auto-minor-mode-magic-alist (cons hook-name #',name))
|
||||||
|
(add-hook (intern (format "%s-hook" mode)) hook-name)))))))
|
||||||
|
(match
|
||||||
|
`((add-to-list 'auto-minor-mode-alist (cons ,match #',name)))))))))
|
||||||
|
|
||||||
(provide 'core-projects)
|
(provide 'core-projects)
|
||||||
;;; core-projects.el ends here
|
;;; core-projects.el ends here
|
||||||
|
|
27
core/core.el
27
core/core.el
|
@ -299,33 +299,6 @@ users).")
|
||||||
(add-hook 'focus-out-hook #'garbage-collect)
|
(add-hook 'focus-out-hook #'garbage-collect)
|
||||||
|
|
||||||
|
|
||||||
;;
|
|
||||||
;;; Minor mode version of `auto-mode-alist'
|
|
||||||
|
|
||||||
(defvar doom-auto-minor-mode-alist '()
|
|
||||||
"Alist mapping filename patterns to corresponding minor mode functions, like
|
|
||||||
`auto-mode-alist'. All elements of this alist are checked, meaning you can
|
|
||||||
enable multiple minor modes for the same regexp.")
|
|
||||||
|
|
||||||
(defun doom-enable-minor-mode-maybe-h ()
|
|
||||||
"Check file name against `doom-auto-minor-mode-alist'."
|
|
||||||
(when (and buffer-file-name doom-auto-minor-mode-alist)
|
|
||||||
(let ((name buffer-file-name)
|
|
||||||
(remote-id (file-remote-p buffer-file-name))
|
|
||||||
(alist doom-auto-minor-mode-alist))
|
|
||||||
;; Remove backup-suffixes from file name.
|
|
||||||
(setq name (file-name-sans-versions name))
|
|
||||||
;; Remove remote file name identification.
|
|
||||||
(when (and (stringp remote-id)
|
|
||||||
(string-match (regexp-quote remote-id) name))
|
|
||||||
(setq name (substring name (match-end 0))))
|
|
||||||
(while (and alist (caar alist) (cdar alist))
|
|
||||||
(if (string-match-p (caar alist) name)
|
|
||||||
(funcall (cdar alist) 1))
|
|
||||||
(setq alist (cdr alist))))))
|
|
||||||
(add-hook 'find-file-hook #'doom-enable-minor-mode-maybe-h)
|
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;;; MODE-local-vars-hook
|
;;; MODE-local-vars-hook
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
;; core.el
|
;; core.el
|
||||||
(package! dotenv-mode)
|
(package! dotenv-mode)
|
||||||
|
(package! auto-minor-mode)
|
||||||
|
|
||||||
;; core-ui.el
|
;; core-ui.el
|
||||||
(package! all-the-icons)
|
(package! all-the-icons)
|
||||||
|
@ -44,6 +45,3 @@
|
||||||
|
|
||||||
;; autoload/debug.el
|
;; autoload/debug.el
|
||||||
(package! esup)
|
(package! esup)
|
||||||
|
|
||||||
;; cli/test.el
|
|
||||||
(package! buttercup)
|
|
||||||
|
|
|
@ -62,5 +62,5 @@
|
||||||
(add-to-list 'auto-mode-alist '("\\.shader$" . shader-mode))
|
(add-to-list 'auto-mode-alist '("\\.shader$" . shader-mode))
|
||||||
|
|
||||||
(def-project-mode! +csharp-unity-mode
|
(def-project-mode! +csharp-unity-mode
|
||||||
:modes (csharp-mode shader-mode)
|
:modes '(csharp-mode shader-mode)
|
||||||
:files (and "Assets" "Library/MonoManager.asset" "Library/ScriptMapper")))
|
:files (and "Assets" "Library/MonoManager.asset" "Library/ScriptMapper")))
|
||||||
|
|
|
@ -38,3 +38,4 @@
|
||||||
(def-project-mode! +data-vagrant-mode
|
(def-project-mode! +data-vagrant-mode
|
||||||
:files ("Vagrantfile"))
|
:files ("Vagrantfile"))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -125,18 +125,16 @@ This marks a foldable marker for `outline-minor-mode' in elisp buffers.")
|
||||||
(advice-add 'helpful-update :after #'elisp-demos-advice-helpful-update))
|
(advice-add 'helpful-update :after #'elisp-demos-advice-helpful-update))
|
||||||
|
|
||||||
|
|
||||||
|
(def-package! buttercup
|
||||||
|
:defer t
|
||||||
|
:minor ("/test[/-].+\\.el$" . buttercup-minor-mode)
|
||||||
|
:config (set-yas-minor-mode! 'buttercup-minor-mode))
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;;; Project modes
|
;;; Project modes
|
||||||
|
|
||||||
(def-project-mode! +emacs-lisp-ert-mode
|
(def-project-mode! +emacs-lisp-ert-mode
|
||||||
:modes (emacs-lisp-mode)
|
:modes '(emacs-lisp-mode)
|
||||||
:match "/test[/-].+\\.el$"
|
:match "/test[/-].+\\.el$"
|
||||||
:add-hooks (overseer-enable-mode))
|
:add-hooks '(overseer-enable-mode))
|
||||||
|
|
||||||
(associate! buttercup-minor-mode
|
|
||||||
:modes (emacs-lisp-mode)
|
|
||||||
:match "/test[/-].+\\.el$")
|
|
||||||
|
|
||||||
(after! buttercup
|
|
||||||
(set-yas-minor-mode! 'buttercup-minor-mode))
|
|
||||||
|
|
||||||
|
|
|
@ -11,3 +11,5 @@
|
||||||
|
|
||||||
(when (featurep! :tools flycheck)
|
(when (featurep! :tools flycheck)
|
||||||
(package! flycheck-cask))
|
(package! flycheck-cask))
|
||||||
|
|
||||||
|
(package! buttercup)
|
||||||
|
|
|
@ -250,9 +250,9 @@ to tide."
|
||||||
;;; Projects
|
;;; Projects
|
||||||
|
|
||||||
(def-project-mode! +javascript-npm-mode
|
(def-project-mode! +javascript-npm-mode
|
||||||
:modes (html-mode css-mode web-mode typescript-mode js2-mode rjsx-mode json-mode markdown-mode)
|
:modes '(html-mode css-mode web-mode typescript-mode js2-mode rjsx-mode json-mode markdown-mode)
|
||||||
:when (locate-dominating-file default-directory "package.json")
|
:when (locate-dominating-file default-directory "package.json")
|
||||||
:add-hooks (+javascript|add-node-modules-path npm-mode))
|
:add-hooks '(+javascript|add-node-modules-path npm-mode))
|
||||||
|
|
||||||
(def-project-mode! +javascript-gulp-mode
|
(def-project-mode! +javascript-gulp-mode
|
||||||
:when (locate-dominating-file default-directory "gulpfile.js"))
|
:when (locate-dominating-file default-directory "gulpfile.js"))
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
;;; Frameworks
|
;;; Frameworks
|
||||||
|
|
||||||
(def-project-mode! +lua-love-mode
|
(def-project-mode! +lua-love-mode
|
||||||
:modes (moonscript-mode lua-mode markdown-mode json-mode)
|
:modes '(moonscript-mode lua-mode markdown-mode json-mode)
|
||||||
:when #'+lua-love-project-root
|
:when #'+lua-love-project-root
|
||||||
:on-load
|
:on-load
|
||||||
(progn
|
(progn
|
||||||
|
|
|
@ -96,10 +96,9 @@
|
||||||
;; Projects
|
;; Projects
|
||||||
|
|
||||||
(def-project-mode! +php-laravel-mode
|
(def-project-mode! +php-laravel-mode
|
||||||
:modes (php-mode yaml-mode web-mode nxml-mode js2-mode scss-mode)
|
:modes '(php-mode yaml-mode web-mode nxml-mode js2-mode scss-mode)
|
||||||
:files (and "artisan" "server.php"))
|
:files (and "artisan" "server.php"))
|
||||||
|
|
||||||
(def-project-mode! +php-composer-mode
|
(def-project-mode! +php-composer-mode
|
||||||
:modes (web-mode php-mode)
|
:modes '(web-mode php-mode)
|
||||||
:files ("composer.json"))
|
:files ("composer.json"))
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,7 @@ called.")
|
||||||
(def-package! nose
|
(def-package! nose
|
||||||
:commands nose-mode
|
:commands nose-mode
|
||||||
:preface (defvar nose-mode-map (make-sparse-keymap))
|
:preface (defvar nose-mode-map (make-sparse-keymap))
|
||||||
:init (associate! nose-mode :match "/test_.+\\.py$" :modes (python-mode))
|
:minor-mode ("/test_.+\\.py$" . nose-mode)
|
||||||
:config
|
:config
|
||||||
(set-popup-rule! "^\\*nosetests" :size 0.4 :select nil)
|
(set-popup-rule! "^\\*nosetests" :size 0.4 :select nil)
|
||||||
(set-yas-minor-mode! 'nose-mode)
|
(set-yas-minor-mode! 'nose-mode)
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
;; Framework-based minor-modes
|
;; Framework-based minor-modes
|
||||||
|
|
||||||
(def-project-mode! +web-jekyll-mode
|
(def-project-mode! +web-jekyll-mode
|
||||||
:modes (web-mode js-mode coffee-mode css-mode haml-mode pug-mode)
|
:modes '(web-mode js-mode coffee-mode css-mode haml-mode pug-mode)
|
||||||
:files (and (or "_config.yml" "_config.toml")
|
:files (and (or "_config.yml" "_config.toml")
|
||||||
(or "_layouts/" "_posts/"))
|
(or "_layouts/" "_posts/"))
|
||||||
:on-enter
|
:on-enter
|
||||||
|
@ -30,18 +30,18 @@
|
||||||
(web-mode-set-engine "django")))
|
(web-mode-set-engine "django")))
|
||||||
|
|
||||||
(def-project-mode! +web-wordpress-mode
|
(def-project-mode! +web-wordpress-mode
|
||||||
:modes (php-mode web-mode css-mode haml-mode pug-mode)
|
:modes '(php-mode web-mode css-mode haml-mode pug-mode)
|
||||||
:files (or "wp-config.php" "wp-config-sample.php"))
|
:files (or "wp-config.php" "wp-config-sample.php"))
|
||||||
|
|
||||||
(when (featurep! :lang javascript)
|
(when (featurep! :lang javascript)
|
||||||
(def-project-mode! +web-angularjs-mode
|
(def-project-mode! +web-angularjs-mode
|
||||||
:modes (+javascript-npm-mode)
|
:modes '(+javascript-npm-mode)
|
||||||
:when (+javascript-npm-dep-p 'angular))
|
:when (+javascript-npm-dep-p 'angular))
|
||||||
|
|
||||||
(def-project-mode! +web-react-mode
|
(def-project-mode! +web-react-mode
|
||||||
:modes (+javascript-npm-mode)
|
:modes '(+javascript-npm-mode)
|
||||||
:when (+javascript-npm-dep-p 'react))
|
:when (+javascript-npm-dep-p 'react))
|
||||||
|
|
||||||
(def-project-mode! +web-phaser-mode
|
(def-project-mode! +web-phaser-mode
|
||||||
:modes (+javascript-npm-mode)
|
:modes '(+javascript-npm-mode)
|
||||||
:when (+javascript-npm-dep-p '(or phaser phaser-ce))))
|
:when (+javascript-npm-dep-p '(or phaser phaser-ce))))
|
||||||
|
|
|
@ -20,6 +20,6 @@
|
||||||
:mode "\\.j2$")
|
:mode "\\.j2$")
|
||||||
|
|
||||||
(def-project-mode! +ansible-yaml-mode
|
(def-project-mode! +ansible-yaml-mode
|
||||||
:modes (yaml-mode)
|
:modes '(yaml-mode)
|
||||||
:add-hooks (ansible ansible-auto-decrypt-encrypt ansible-doc-mode)
|
:add-hooks '(ansible ansible-auto-decrypt-encrypt ansible-doc-mode)
|
||||||
:files ("roles/"))
|
:files ("roles/"))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue