💥 Change set-popup-rule! usage

Now accepts a flat plist of all its former parameters, including new
:parameters and :actions properties to increase your control over the
fate of your windows.

The old usage of set-popup-rule! is deprecated and may not work right!

The :ui popup module has also seen a major refactor to improve
efficiency and load times.

Sorry! This is the last "big" change before 2.1!
This commit is contained in:
Henrik Lissner 2018-06-18 02:26:05 +02:00
parent 4e5c8b6052
commit 6808c46b58
No known key found for this signature in database
GPG key ID: 5F6C0EA160557395
26 changed files with 356 additions and 351 deletions

View file

@ -47,10 +47,6 @@ https://mediatemple.net"
"TODO") "TODO")
(set-popup-rules! (set-popup-rules!
'(("^\\*doom-regex\\*$" '(("^\\*doom-regex\\*$" :size 4 :quit nil)
((size . 4)) ("^\\*doom-regex-groups" :side 'left :size 28 :select nil :quit nil)))
((quit)))
("^\\*doom-regex-groups"
((side . left) (size . 28))
((select) (quit)))))

View file

@ -27,8 +27,8 @@ absolute paths.")
shr-max-image-proportion 0.6) shr-max-image-proportion 0.6)
(set-popup-rule! "^\\*elfeed-entry" (set-popup-rule! "^\\*elfeed-entry"
'((size . 0.75) (side . bottom)) :size 0.75 :side 'bottom
'((select . t) (quit) (transient . t))) :select t :quit nil :ttl t)
(make-directory elfeed-db-directory t) (make-directory elfeed-db-directory t)

View file

@ -25,9 +25,7 @@
twittering-initial-timeline-spec-string twittering-initial-timeline-spec-string
'(":home" ":mentions" ":direct_messages")) '(":home" ":mentions" ":direct_messages"))
(set-popup-rule! "^\\*twittering-edit" (set-popup-rule! "^\\*twittering-edit" :size 15 :ttl nil :quit nil :select t)
'((size . 15))
'((transient) (quit) (select . t)))
(defface twitter-divider (defface twitter-divider
'((((background dark)) (:underline (:color "#141519"))) '((((background dark)) (:underline (:color "#141519")))

View file

@ -94,9 +94,7 @@
;; `helm-ag' ;; `helm-ag'
(after! helm-ag (after! helm-ag
(define-key helm-ag-edit-map [remap quit-window] #'helm-ag--edit-abort) (define-key helm-ag-edit-map [remap quit-window] #'helm-ag--edit-abort)
(set-popup-rule! "^\\*helm-ag-edit" (set-popup-rule! "^\\*helm-ag-edit" :size 0.35 :ttl 0 :quit nil))
'((size . 0.35))
'((transient . 0) (quit))))
;; `helm-bookmark' ;; `helm-bookmark'

View file

@ -86,7 +86,7 @@ immediately runs it on the current candidate (ending the ivy session)."
[remap swiper] #'counsel-grep-or-swiper) [remap swiper] #'counsel-grep-or-swiper)
:config :config
(set-popup-rule! "^\\*ivy-occur" '((size . 0.35)) '((transient . 0) (quit))) (set-popup-rule! "^\\*ivy-occur" :size 0.35 :ttl 0 :quit nil)
(setq counsel-find-file-ignore-regexp "\\(?:^[#.]\\)\\|\\(?:[#~]$\\)\\|\\(?:^Icon?\\)" (setq counsel-find-file-ignore-regexp "\\(?:^[#.]\\)\\|\\(?:[#~]$\\)\\|\\(?:^Icon?\\)"
;; Add smart-casing and compressed archive searching (-zS) to default ;; Add smart-casing and compressed archive searching (-zS) to default

View file

@ -8,8 +8,7 @@
(setq imenu-list-idle-update-delay 0.5) (setq imenu-list-idle-update-delay 0.5)
(set-popup-rule! "^\\*Ilist" (set-popup-rule! "^\\*Ilist"
'((side . right) (size . 35)) :side 'right :size 35 :quit 'current :select nil :ttl 0)
'((quit . current) (select) (transient . 0)))
(defun +imenu|cleanup-on-popup-close () (defun +imenu|cleanup-on-popup-close ()
"Clean up after `imenu-list-minor-mode' when killing the list window." "Clean up after `imenu-list-minor-mode' when killing the list window."

View file

@ -3,8 +3,7 @@
(def-package! realgud (def-package! realgud
:commands (realgud:gdb realgud:trepanjs realgud:bashdb realgud:zshdb) :commands (realgud:gdb realgud:trepanjs realgud:bashdb realgud:zshdb)
:config :config
(set-popup-rule! "^\\*\\(?trepanjs:\\(?:g\\|zsh\\|bash\\)db\\)" (set-popup-rule! "^\\*\\(?trepanjs:\\(?:g\\|zsh\\|bash\\)db\\)" :size 20)
'((size . 20)))
;; TODO Temporary Ex commands for the debugger ;; TODO Temporary Ex commands for the debugger
;; (def-tmp-excmd! doom:def-debug-on doom:def-debug-off ;; (def-tmp-excmd! doom:def-debug-on doom:def-debug-off

View file

@ -17,7 +17,7 @@
:config :config
(setq quickrun-focus-p nil) (setq quickrun-focus-p nil)
(set-popup-rule! "^\\*quickrun" '((size . 0.3)) '((transient . 0))) (set-popup-rule! "^\\*quickrun" :size 0.3 :ttl 0)
(defun +eval*quickrun-auto-close (&rest _) (defun +eval*quickrun-auto-close (&rest _)
"Allows us to silently re-run quickrun from within the quickrun buffer." "Allows us to silently re-run quickrun from within the quickrun buffer."

View file

@ -68,8 +68,8 @@ variable for an explanation of the defaults (in comments). See
(put 'evil-define-key* 'lisp-indent-function 'defun) (put 'evil-define-key* 'lisp-indent-function 'defun)
(set-popup-rules! (set-popup-rules!
'(("^\\*evil-registers" ((size . 0.3))) '(("^\\*evil-registers" :size 0.3)
("^\\*Command Line" ((size . 8))))) ("^\\*Command Line" :size 8)))
;; Change the cursor color in emacs mode ;; Change the cursor color in emacs mode
(defvar +evil--default-cursor-color "#ffffff") (defvar +evil--default-cursor-color "#ffffff")

View file

@ -20,7 +20,7 @@
(git-gutter-mode +1))) (git-gutter-mode +1)))
(add-hook! (text-mode prog-mode conf-mode) #'+version-control|git-gutter-maybe) (add-hook! (text-mode prog-mode conf-mode) #'+version-control|git-gutter-maybe)
:config :config
(set-popup-rule! "^\\*git-gutter" nil '((select))) (set-popup-rule! "^\\*git-gutter" :select nil)
;; Update git-gutter on focus (in case I was using git externally) ;; Update git-gutter on focus (in case I was using git externally)
(add-hook 'focus-in-hook #'git-gutter:update-all-windows) (add-hook 'focus-in-hook #'git-gutter:update-all-windows)

View file

@ -12,8 +12,8 @@
(after! vc-annotate (after! vc-annotate
(set-popup-rules! (set-popup-rules!
'(("^\\vc-d" nil ((select))) ; *vc-diff* '(("^\\vc-d" :select) ; *vc-diff*
("^\\vc-c" nil ((select . t))))) ; *vc-change-log* ("^\\vc-c" :select t))) ; *vc-change-log*
(set-evil-initial-state! (set-evil-initial-state!
'(vc-annotate-mode vc-git-log-view-mode) '(vc-annotate-mode vc-git-log-view-mode)
'normal)) 'normal))

View file

@ -30,7 +30,7 @@
(figwheel-sidecar.repl-api/start-figwheel!) (figwheel-sidecar.repl-api/start-figwheel!)
(figwheel-sidecar.repl-api/cljs-repl))") (figwheel-sidecar.repl-api/cljs-repl))")
(set-popup-rule! "^\\*cider-repl" nil '((quit) (select))) (set-popup-rule! "^\\*cider-repl" :quit nil :select nil)
(set-repl-handler! 'clojure-mode #'+clojure/repl) (set-repl-handler! 'clojure-mode #'+clojure/repl)
(set-eval-handler! 'clojure-mode #'cider-eval-region) (set-eval-handler! 'clojure-mode #'cider-eval-region)
(set-lookup-handlers! 'clojure-mode (set-lookup-handlers! 'clojure-mode

View file

@ -33,7 +33,7 @@
font-latex-fontify-sectioning 1.15) font-latex-fontify-sectioning 1.15)
(setq-default TeX-master nil) (setq-default TeX-master nil)
;; Display the output of the latex commands in a popup. ;; Display the output of the latex commands in a popup.
(set-popup-rule! " output\\*$" '((size . 15))) (set-popup-rule! " output\\*$" :size 15)
;; TeX Font Styling ;; TeX Font Styling
;; (def-package! tex-style :defer t) ;; (def-package! tex-style :defer t)

View file

@ -73,17 +73,17 @@ string). Stops at the first function to return non-nil.")
:config :config
(set-popup-rules! (set-popup-rules!
'(("^\\*Org Src" '(("^\\*Org Src"
((size . 100) (side . right) (slot . -1) (window-height . 0.6)) :side 'right :size 100 :height 0.6 :slot -1
((quit) (select . t) (modeline))) :quit nil :select t)
("^\\*Python" ("^\\*Python"
((slot . 0) (side . right) (size . 100)) :slot 0 :side 'right :size 100
((select) (quit) (transient))) :select nil :quit nil :ttl nil)
("\\*ob-ipython.*" ("\\*ob-ipython.*"
((slot . 2) (side . right) (size . 100) (window-height . 0.2)) :slot 2 :side 'right :size 100 :height 0.2
((select) (quit) (transient))) :select nil :quit nil :transient nil)
("\\*Python:.*" ("\\*Python:.*"
((slot . 0) (side . right) (size . 100)) :slot 0 :side 'right :size 100
((select) (quit) (transient))))) :select nil :quit nil :transient nil)))
;; TODO Add more popup styles ;; TODO Add more popup styles
;; advices for remote kernel and org-src-edit ;; advices for remote kernel and org-src-edit

View file

@ -140,17 +140,10 @@ unfold to point on startup."
"Defines popup rules for org-mode (does nothing if :ui popup is disabled)." "Defines popup rules for org-mode (does nothing if :ui popup is disabled)."
(set-popup-rules! (set-popup-rules!
'(("^\\*\\(?:Agenda Com\\|Calendar\\|Org \\(?:Links\\|Export Dispatcher\\|Select\\)\\)" '(("^\\*\\(?:Agenda Com\\|Calendar\\|Org \\(?:Links\\|Export Dispatcher\\|Select\\)\\)"
((slot . -1) (vslot . -1) (size . +popup-shrink-to-fit)) :slot -1 :vslot -1 :size #'+popup-shrink-to-fit :ttl 0)
((transient . 0))) ("^\\*Org Agenda" :size 0.35 :select t :ttl nil)
("^\\*Org Agenda" ("^\\*Org Src" :size 0.3 :quit nil :select t)
((size . 0.35)) ("^CAPTURE.*\\.org$" :size 0.2 :quit nil :select t))))
((select . t) (transient)))
("^\\*Org Src"
((size . 0.3))
((quit) (select . t)))
("^CAPTURE.*\\.org$"
((size . 0.2))
((quit) (select . t))))))
(defun +org|setup-pretty-code () (defun +org|setup-pretty-code ()
"Setup the default pretty symbols for" "Setup the default pretty symbols for"

View file

@ -6,7 +6,7 @@
(setq plantuml-jar-path (concat doom-etc-dir "plantuml.jar") (setq plantuml-jar-path (concat doom-etc-dir "plantuml.jar")
org-plantuml-jar-path plantuml-jar-path) org-plantuml-jar-path plantuml-jar-path)
:config :config
(set-popup-rule! "^\\*PLANTUML" '((size . 0.4)) '((select) (transient . 0)))) (set-popup-rule! "^\\*PLANTUML" :size 0.4 :select nil :ttl 0))
(def-package! flycheck-plantuml (def-package! flycheck-plantuml

View file

@ -98,7 +98,7 @@ environment variables."
(add-hook 'python-mode-hook #'anaconda-mode) (add-hook 'python-mode-hook #'anaconda-mode)
(add-hook 'anaconda-mode-hook #'anaconda-eldoc-mode) (add-hook 'anaconda-mode-hook #'anaconda-eldoc-mode)
(set-company-backend! 'python-mode '(company-anaconda)) (set-company-backend! 'python-mode '(company-anaconda))
(set-popup-rule! "^\\*anaconda-mode" nil '((select))) (set-popup-rule! "^\\*anaconda-mode" :select nil)
(set-lookup-handlers! 'python-mode (set-lookup-handlers! 'python-mode
:definition #'anaconda-mode-find-definitions :definition #'anaconda-mode-find-definitions
:references #'anaconda-mode-find-references :references #'anaconda-mode-find-references
@ -130,7 +130,7 @@ environment variables."
:init :init
(associate! nose-mode :match "/test_.+\\.py$" :modes (python-mode)) (associate! nose-mode :match "/test_.+\\.py$" :modes (python-mode))
:config :config
(set-popup-rule! "^\\*nosetests" '((size . 0.4)) '((select))) (set-popup-rule! "^\\*nosetests" :size 0.4 :select nil)
(set-yas-minor-mode! 'nose-mode) (set-yas-minor-mode! 'nose-mode)
(map! :map nose-mode-map (map! :map nose-mode-map
:localleader :localleader

View file

@ -3,7 +3,7 @@
(def-package! restclient (def-package! restclient
:mode ("\\.http\\'" . restclient-mode) :mode ("\\.http\\'" . restclient-mode)
:config :config
(set-popup-rule! "^\\*HTTP Response" '((size . 0.4)) '((quit . other))) (set-popup-rule! "^\\*HTTP Response" :size 0.4 :quit 'other)
(map! :mode restclient-mode (map! :mode restclient-mode
:n [M-return] 'restclient-http-send-current :n [M-return] 'restclient-http-send-current
:localleader :localleader

View file

@ -18,12 +18,8 @@
(set-popup-rules! (set-popup-rules!
'(("\\*ein: .*" :ignore t) '(("\\*ein: .*" :ignore t)
("\\*ein:tb .*" ("\\*ein:tb .*" :side 'bottom :size 0.3 :quit t :ttl nil :select nil)
((side . bottom) (size . 0.3)) ("\\*ein:notebooklist *" :side 'left :size 50 :select nil)))
((quit . t) (transient) (select)))
("\\*ein:notebooklist *"
((side . left) (size . 50))
((select)))))
(when (featurep! :completion company) (when (featurep! :completion company)
;; Code completion with company ;; Code completion with company

View file

@ -26,7 +26,7 @@ load everything.")
magit-display-buffer-function #'+magit-display-buffer-fullscreen magit-display-buffer-function #'+magit-display-buffer-fullscreen
magit-popup-display-buffer-action '((display-buffer-in-side-window))) magit-popup-display-buffer-action '((display-buffer-in-side-window)))
(set-popup-rule! "^\\(?:\\*magit\\|magit:\\)" :ignore) (set-popup-rule! "^\\(?:\\*magit\\|magit:\\)" :ignore t)
;; Consider magit buffers real (so they can switched to) ;; Consider magit buffers real (so they can switched to)
(add-hook 'magit-mode-hook #'doom|mark-buffer-as-real) (add-hook 'magit-mode-hook #'doom|mark-buffer-as-real)
;; no mode-line in magit popups ;; no mode-line in magit popups

View file

@ -28,9 +28,7 @@
(after! pass (after! pass
(set-env! "PASSWORD_STORE_DIR") (set-env! "PASSWORD_STORE_DIR")
(set-evil-initial-state! 'pass-mode 'emacs) (set-evil-initial-state! 'pass-mode 'emacs)
(set-popup-rule! "^\\*Password-Store" (set-popup-rule! "^\\*Password-Store" :side 'left :size 0.25 :quit nil)
'((side . left) (size . 0.25))
'((quit)))
(define-key! pass-mode-map (define-key! pass-mode-map
"j" #'pass-next-entry "j" #'pass-next-entry
"k" #'pass-prev-entry "k" #'pass-prev-entry

View file

@ -34,9 +34,9 @@
(load! "+modeline") (load! "+modeline")
(add-hook! 'pdf-tools-enabled-hook (doom-set-modeline 'pdf-tools-modeline))) (add-hook! 'pdf-tools-enabled-hook (doom-set-modeline 'pdf-tools-modeline)))
;; Handle PDF-tools related popups better ;; Handle PDF-tools related popups better
(set-popup-rule! "^\\*Outline*" '((side . right) (size . 40)) '((select))) (set-popup-rule! "^\\*Outline*" :side 'right :size 40 :select nil)
;; TODO: Add additional important windows that should be handled differently ;; TODO: Add additional important windows that should be handled differently
;; TODO: These two next rules don't work (they should), investigate ;; TODO: These two next rules don't work (they should), investigate
;; (set-popup-rule! "\\*Contents\\*" '((side . right) (size . 40)) nil) ;; (set-popup-rule! "\\*Contents\\*" :side 'right :size 40)
;; (set-popup-rule! "* annots\\*$" '((side . left) (size . 40)) '((select))) ;; (set-popup-rule! "* annots\\*$" :side 'left :size 40 :select nil)
) )

View file

@ -36,8 +36,8 @@
"^#.*#$")) "^#.*#$"))
(set-popup-rule! "^ ?\\*NeoTree" (set-popup-rule! "^ ?\\*NeoTree"
`((side . ,neo-window-position) (size . ,neo-window-width)) :side neo-window-position :size neo-window-width
'((quit . current) (select . t))) :quit 'current :select t)
(after! winner (after! winner
(cl-pushnew neo-buffer-name winner-boring-buffers)) (cl-pushnew neo-buffer-name winner-boring-buffers))

View file

@ -83,10 +83,11 @@ and enables `+popup-buffer-mode'."
;; integer = ttl ;; integer = ttl
;; nil = no timer ;; nil = no timer
(unless +popup--inhibit-transient (unless +popup--inhibit-transient
(setq ttl (+popup-parameter-fn 'transient window buffer)) (setq ttl (+popup-parameter-fn 'ttl window buffer))
(when ttl (when ttl
(when (eq ttl t) (when (eq ttl t)
(setq ttl +popup-ttl)) (setq ttl (or (plist-get +popup-defaults :ttl)
0)))
(cl-assert (integerp ttl) t) (cl-assert (integerp ttl) t)
(if (= ttl 0) (if (= ttl 0)
(+popup--kill-buffer buffer 0) (+popup--kill-buffer buffer 0)
@ -97,23 +98,26 @@ and enables `+popup-buffer-mode'."
(defun +popup--normalize-alist (alist) (defun +popup--normalize-alist (alist)
"Merge `+popup-default-alist' and `+popup-default-parameters' with ALIST." "Merge `+popup-default-alist' and `+popup-default-parameters' with ALIST."
(if (not alist) (let ((alist ; handle defaults
(setq alist +popup-default-alist) (cl-remove-duplicates
(let* ((alist (map-merge 'list +popup-default-alist alist)) (append alist +popup-default-alist)
(params (map-merge 'list :key #'car :from-end t))
+popup-default-parameters (parameters
(cdr (assq 'window-parameters alist))))) (cl-remove-duplicates
;; translate side => window-(width|height) (append (cdr (assq 'window-parameters alist))
(when-let* ((size (cdr (assq 'size alist))) +popup-default-parameters)
(side (or (cdr (assq 'side alist)) 'bottom))) :key #'car :from-end t)))
(map-delete alist 'size) ;; handle `size'
(map-put alist (if (memq side '(left right)) (when-let* ((size (cdr (assq 'size alist)))
(side (or (cdr (assq 'side alist)) 'bottom))
(param (if (memq side '(left right))
'window-width 'window-width
'window-height) 'window-height)))
size)) (setq alist (map-delete alist 'size))
;; (map-put alist param size))
(map-put alist 'window-parameters params) (setcdr (assq 'window-parameters alist)
(nreverse alist)))) (cl-remove-if #'null parameters :key #'cdr))
(cl-remove-if #'null alist :key #'cdr)))
;; ;;
@ -145,18 +149,21 @@ and enables `+popup-buffer-mode'."
;;;###autoload ;;;###autoload
(defun +popup-buffer (buffer &optional alist) (defun +popup-buffer (buffer &optional alist)
"Open BUFFER in a popup window. ALIST describes its features." "Open BUFFER in a popup window. ALIST describes its features."
(let ((old-window (selected-window)) (let* ((origin (selected-window))
(alist (+popup--normalize-alist alist)) (window-min-height 3)
(window-min-height 3)) (alist (+popup--normalize-alist alist))
(when-let* ((new-window (run-hook-with-args-until-success (actions (or (cdr (assq 'actions alist))
'+popup-display-buffer-actions buffer alist))) +popup-default-display-buffer-actions)))
(+popup--init new-window alist) (when-let* ((popup (cl-loop for func in actions
if (funcall func buffer alist)
return it)))
(+popup--init popup alist)
(unless +popup--inhibit-select (unless +popup--inhibit-select
(let ((select (+popup-parameter 'select new-window))) (let ((select (+popup-parameter 'select popup)))
(if (functionp select) (if (functionp select)
(funcall select new-window old-window) (funcall select popup origin)
(select-window (if select new-window old-window))))) (select-window (if select popup origin)))))
new-window))) popup)))
;;;###autoload ;;;###autoload
(defun +popup-parameter (parameter &optional window) (defun +popup-parameter (parameter &optional window)
@ -188,70 +195,6 @@ Uses `shrink-window-if-larger-than-buffer'."
(shrink-window-if-larger-than-buffer window))) (shrink-window-if-larger-than-buffer window)))
;;
;; Minor mode
;;
;;;###autoload
(defvar +popup-mode-map (make-sparse-keymap)
"Active keymap in a session with the popup system enabled. See
`+popup-mode'.")
;;;###autoload
(defvar +popup-buffer-mode-map
(let ((map (make-sparse-keymap)))
(when (featurep! :feature evil)
;; for maximum escape coverage in emacs state buffers
(define-key map [escape] #'doom/escape)
(define-key map (kbd "ESC") #'doom/escape))
map)
"Active keymap in popup windows. See `+popup-buffer-mode'.")
;;;###autoload
(define-minor-mode +popup-mode
"Global minor mode representing Doom's popup management system."
:init-value nil
:global t
:keymap +popup-mode-map
(cond (+popup-mode
(add-hook 'doom-unreal-buffer-functions #'+popup-buffer-p)
(add-hook 'doom-escape-hook #'+popup|close-on-escape t)
(add-hook 'doom-cleanup-hook #'+popup|cleanup-rules)
(add-hook 'after-change-major-mode-hook #'+popup|set-modeline-on-enable)
(setq +popup--old-display-buffer-alist display-buffer-alist
display-buffer-alist +popup--display-buffer-alist
window--sides-inhibit-check t)
(dolist (prop +popup-window-parameters)
(push (cons prop 'writable) window-persistent-parameters)))
(t
(remove-hook 'doom-unreal-buffer-functions #'+popup-buffer-p)
(remove-hook 'doom-escape-hook #'+popup|close-on-escape)
(remove-hook 'doom-cleanup-hook #'+popup|cleanup-rules)
(remove-hook 'after-change-major-mode-hook #'+popup|set-modeline-on-enable)
(setq display-buffer-alist +popup--old-display-buffer-alist
window--sides-inhibit-check nil)
(+popup|cleanup-rules)
(dolist (prop +popup-window-parameters)
(setq window-persistent-parameters
(map-delete window-persistent-parameters prop))))))
;;;###autoload
(define-minor-mode +popup-buffer-mode
"Minor mode for individual popup windows.
It is enabled when a buffer is displayed in a popup window and disabled when
that window has been changed or closed."
:init-value nil
:keymap +popup-buffer-mode-map
(when (and +popup-buffer-mode (timerp +popup--timer))
(remove-hook 'kill-buffer-hook #'+popup|kill-buffer-hook t)
(cancel-timer +popup--timer)
(setq +popup--timer nil)))
(put '+popup-buffer-mode 'permanent-local t)
(put '+popup-buffer-mode 'permanent-local-hook t)
;; ;;
;; Hooks ;; Hooks
;; ;;
@ -289,6 +232,7 @@ restoring it if `+popup-buffer-mode' is disabled."
((symbolp modeline) ((symbolp modeline)
(when-let* ((hide-mode-line-format (doom-modeline modeline))) (when-let* ((hide-mode-line-format (doom-modeline modeline)))
(hide-mode-line-mode +1))))))) (hide-mode-line-mode +1)))))))
(put '+popup|set-modeline-on-enable 'permanent-local-hook t)
;;;###autoload ;;;###autoload
(defun +popup|unset-modeline-on-disable () (defun +popup|unset-modeline-on-disable ()
@ -416,53 +360,11 @@ the message buffer in a popup window."
(let ((window (selected-window)) (let ((window (selected-window))
(buffer (current-buffer)) (buffer (current-buffer))
+popup--remember-last) +popup--remember-last)
(set-window-parameter window 'transient nil) (set-window-parameter window 'ttl nil)
(+popup/close window 'force) (+popup/close window 'force)
(display-buffer-pop-up-window buffer nil))) (display-buffer-pop-up-window buffer nil)))
;;
;; Macros
;;
;;;###autoload
(defmacro with-popup-rules! (rules &rest body)
"Evaluate BODY with popup RULES. RULES is a list of popup rules. Each rule
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)
,@(cl-loop for rule in rules collect `(set-popup-rule! ,@rule))
(when (bound-and-true-p +popup-mode)
(setq display-buffer-alist +popup--display-buffer-alist))
,@body))
;;;###autoload
(defmacro without-popups! (&rest body)
"Run BODY with a default `display-buffer-alist', ignoring the popup rules set
with the :popup setting."
`(let ((display-buffer-alist +popup--old-display-buffer-alist))
,@body))
;;;###autoload
(defmacro save-popups! (&rest body)
"Sets aside all popups before executing the original function, usually to
prevent the popup(s) from messing up the UI (or vice versa)."
`(let* ((in-popup-p (+popup-buffer-p))
(popups (+popup-windows))
(+popup--inhibit-transient t)
+popup--last)
(dolist (p popups)
(+popup/close p 'force))
(unwind-protect
(progn ,@body)
(when popups
(let ((origin (selected-window)))
(+popup/restore)
(unless in-popup-p
(select-window origin)))))))
;; ;;
;; Advice ;; Advice
;; ;;

View file

@ -2,69 +2,187 @@
(defvar +popup--display-buffer-alist nil) (defvar +popup--display-buffer-alist nil)
(defsubst +popup--rule (args) ;;;###autoload
(cl-destructuring-bind (condition &optional alist parameters) args (defvar +popup-defaults
(if (eq alist :ignore) (list :side 'bottom
(list condition nil) :height 0.16
`(,condition (+popup-buffer) :width 40
,@alist :quit t
(window-parameters ,@parameters))))) :select #'ignore
:ttl 5)
"Default setup for `set-popup-rule!' ")
(defun +popup--define (condition &optional alist parameters) ;;;###autoload
(when after-init-time (defun +popup--make (predicate plist)
(setq +popup--display-buffer-alist (cond ((not (keywordp (car plist)))
(map-delete +popup--display-buffer-alist condition))) ;; FIXME deprecated popup rule support
(push (+popup--rule (list condition alist parameters)) (message "Warning: the old usage of `set-popup-rule!' is deprecated; update the rule for '%s'"
+popup--display-buffer-alist)) predicate)
(cl-destructuring-bind (condition &optional alist parameters)
(list predicate (car plist) (cadr plist))
(if (eq alist :ignore)
(list condition nil)
`(,condition (+popup-buffer)
,@alist
(window-parameters ,@parameters)))))
((plist-get plist :ignore)
(list predicate nil))
((let* ((plist (append plist +popup-defaults))
(alist
`((actions . ,(plist-get plist :actions))
(side . ,(plist-get plist :side))
(size . ,(plist-get plist :size))
(window-width . ,(plist-get plist :width))
(window-height . ,(plist-get plist :height))
(slot . ,(plist-get plist :slot))
(vslot . ,(plist-get plist :vslot))))
(params
`((ttl . ,(plist-get plist :ttl))
(quit . ,(plist-get plist :quit))
(select . ,(plist-get plist :select))
(modeline . ,(plist-get plist :modeline))
(autosave . ,(plist-get plist :autosave))
,@(plist-get plist :parameters))))
`(,predicate (+popup-buffer)
,@alist
(window-parameters ,@params))))))
;;;###autodef ;;;###autodef
(defun set-popup-rule! (condition &optional alist parameters) (defun set-popup-rule! (predicate &rest plist)
"Define a popup rule. "Define a popup rule.
CONDITION can be a regexp string or a function. 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
For ALIST, see `display-buffer' and `display-buffer-alist' for a list of
possible entries, which instruct the display system how to initialize the popup
window.
ALIST also supports the `size' parameter, which will be translated to
`window-width' or `window-height' depending on `side'.
PARAMETERS is an alist of window parameters. See `+popup-window-parameters' for
a list of custom parameters provided by the popup module. If certain
attributes/parameters are omitted, the ones from `+popup-default-alist' and
`+popup-default-parameters' will be used.
The buffers of new windows displayed by `pop-to-buffer' and `display-buffer'
will be tested against CONDITION, which is either a) a regexp string (which is
matched against the buffer's name) or b) a function that takes no arguments and matched against the buffer's name) or b) a function that takes no arguments and
returns a boolean. returns a boolean.
See `def-popups!' for defining multiple rules in bulk." 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).
PLIST can be made up of any of the following properties:
:actions ACTIONS
ACTIONS is a list of functions or an alist containing (FUNCTION . ALIST). See
`display-buffer''s second argument for more information on its format and what
it accepts. If omitted, `+popup-default-display-buffer-actions' is used.
:side 'bottom|'top|'left|'right
Which side of the frame to open the popup on. This is only respected if
`+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.
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
character width (width).
: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.
On the other hand, vslot operates the same way, but controls how popups are
stacked.
When a popup is opened on the left and right, slot determines vertical
position and vslot horizontal.
: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.
If t, CDR will default to `+popup-ttl'.
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.
: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.
If t, close the popup if ESC/C-g is pressed inside or outside of popups.
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.
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.
:select BOOL|FN
CDR 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.
:modeline BOOL|SYMBOL|FN
CDR 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.
: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.
If t, no prompts. Just save them automatically (if they're file-visiting
buffers).
If 'ignore, no prompts, no saving. Just silently kill it.
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.
:parameters ALIST
An alist of custom window parameters. See \(info window-parameters)
If any of these are omitted, defaults derived from `+popup-defaults' will be
used."
(declare (indent defun)) (declare (indent defun))
(+popup--define condition alist parameters) (push (+popup--make predicate plist) +popup--display-buffer-alist)
(when (bound-and-true-p +popup-mode) (when (bound-and-true-p +popup-mode)
(setq display-buffer-alist +popup--display-buffer-alist)) (setq display-buffer-alist +popup--display-buffer-alist))
+popup--display-buffer-alist) +popup--display-buffer-alist)
;;;###autodef ;;;###autodef
(defun set-popup-rules! (&rest rulesets) (defun set-popup-rules! (&rest rulesets)
"Define multiple popup rules. See `def-popup!' for the specifications of each "Like `set-popup-rules!', but defines multiple popup rules. Every entry in RULESETS
individual rule. should be a list of lists (each sublist is a popup rule that could be passed to
`set-popup-rule!').
(set-popup-rules! Example:
'((\"^ \\*\" ((slot . 1) (vslot . -1) (size . +popup-shrink-to-fit)))
(\"^\\*\" ((slot . 1) (vslot . -1)) ((select . t)))))" (set-popup-rules!
(dolist (ruleset rulesets) '((\"^ \\*\" :slot 1 :vslot -1 :size #'+popup-shrink-to-fit)
(dolist (rule ruleset) (\"^\\*\" :slot 1 :vslot -1 :select t))
(apply #'+popup--define rule))) '((\"^\\*Completions\" :slot -1 :vslot -2 :ttl 0)
(\"^\\*Compil\\(?:ation\\|e-Log\\)\" :size 0.3 :ttl 0 :quit t)))"
(declare (indent 0))
(dolist (rules rulesets)
(dolist (rule rules)
(push (+popup--make (car rule) (cdr rule))
+popup--display-buffer-alist)))
(when (bound-and-true-p +popup-mode) (when (bound-and-true-p +popup-mode)
(setq display-buffer-alist +popup--display-buffer-alist)) (setq display-buffer-alist +popup--display-buffer-alist))
+popup--display-buffer-alist) +popup--display-buffer-alist)
;; ;;
;; Obsolete ;; Obsolete settings
;; ;;
;; FIXME obsolete :popup ;; FIXME obsolete :popup

View file

@ -1,151 +1,160 @@
;;; ui/popup/config.el -*- lexical-binding: t; -*- ;;; ui/popup/config.el -*- lexical-binding: t; -*-
(defconst +popup-window-parameters (defconst +popup-window-parameters '(ttl quit select modeline popup)
'(transient quit select modeline popup)
"A list of custom parameters to be added to `window-persistent-parameters'. "A list of custom parameters to be added to `window-persistent-parameters'.
Modifying this has no effect, unless done before ui/popup loads. Modifying this has no effect, unless done before ui/popup loads.")
(transient . CDR) (defvar +popup-default-display-buffer-actions
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.
If t, CDR will default to `+popup-ttl'.
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.
(quit . CDR)
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.
If t, close the popup if ESC/C-g is pressed inside or outside of popups.
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.
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.
(select . CDR)
CDR 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.
(modeline . CDR)
CDR 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.
(autosave . CDR)
This parameter determines what to do with modified buffers in closing popup
windows. CDR can be a 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.
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.
(popup . t)
This is for internal use, do not change this. It simply marks a window as a
popup window.
Since I can't find this information anywhere but the Emacs manual, I'll include
a brief description of some native window parameters that Emacs uses:
(delete-window . CDR)
(delete-other-window . CDR)
(split-window . CDR)
(other-window . CDR)
This applies to all four of the above: CDR can be t or a function. If t, using
those functions on this window will ignore all window parameters.
If CDR is a function, it will replace the native function when used on this
window. e.g. if CDR is #'ignore (delete-window popup) will run (ignore popup)
instead of deleting the window!
(no-other-window . BOOL)
If CDR is non-nil, this window becomes invisible to `other-window' and
`pop-to-buffer'. Doom popups sets this. The default is nil.")
(defvar +popup-display-buffer-actions
'(display-buffer-reuse-window +popup-display-buffer-stacked-side-window) '(display-buffer-reuse-window +popup-display-buffer-stacked-side-window)
"The functions to use to display the popup buffer.") "The functions to use to display the popup buffer.")
(defvar +popup-default-alist (defvar +popup-default-alist
'((window-height . 0.16) '((window-height . 0.16) ; remove later
(reusable-frames . visible)) (reusable-frames . visible))
"The default alist for `display-buffer-alist' rules.") "The default alist for `display-buffer-alist' rules.")
(defvar +popup-default-parameters (defvar +popup-default-parameters
'((transient . t) '((transient . t) ; remove later
(quit . t) (quit . t) ; remove later
(select . ignore) (select . ignore) ; remove later
(no-other-window . t)) (no-other-window . t))
"The default window parameters.") "The default window parameters.")
(defvar +popup-ttl 5
"The default time-to-live for transient buffers whose popup buffers have been
deleted.")
(defvar +popup-margin-width 1 (defvar +popup-margin-width 1
"Size of the margins to give popup windows. Set this to nil to disable margin "Size of the margins to give popup windows. Set this to nil to disable margin
adjustment.") adjustment.")
;;
;; Global modes
;;
(defvar +popup-mode-map (make-sparse-keymap)
"Active keymap in a session with the popup system enabled. See
`+popup-mode'.")
(defvar +popup-buffer-mode-map
(let ((map (make-sparse-keymap)))
(when (featurep! :feature evil)
;; for maximum escape coverage in emacs state buffers
(define-key map [escape] #'doom/escape)
(define-key map (kbd "ESC") #'doom/escape))
map)
"Active keymap in popup windows. See `+popup-buffer-mode'.")
(define-minor-mode +popup-mode
"Global minor mode representing Doom's popup management system."
:init-value nil
:global t
:keymap +popup-mode-map
(cond (+popup-mode
(add-hook 'doom-escape-hook #'+popup|close-on-escape t)
(add-hook 'doom-cleanup-hook #'+popup|cleanup-rules)
(setq +popup--old-display-buffer-alist display-buffer-alist
display-buffer-alist +popup--display-buffer-alist
window--sides-inhibit-check t)
(dolist (prop +popup-window-parameters)
(push (cons prop 'writable) window-persistent-parameters)))
(t
(remove-hook 'doom-escape-hook #'+popup|close-on-escape)
(remove-hook 'doom-cleanup-hook #'+popup|cleanup-rules)
(setq display-buffer-alist +popup--old-display-buffer-alist
window--sides-inhibit-check nil)
(+popup|cleanup-rules)
(dolist (prop +popup-window-parameters)
(setq window-persistent-parameters
(map-delete window-persistent-parameters prop))))))
(define-minor-mode +popup-buffer-mode
"Minor mode for individual popup windows.
It is enabled when a buffer is displayed in a popup window and disabled when
that window has been changed or closed."
:init-value nil
:keymap +popup-buffer-mode-map
(if (not +popup-buffer-mode)
(remove-hook 'after-change-major-mode-hook #'+popup|set-modeline-on-enable t)
(add-hook 'after-change-major-mode-hook #'+popup|set-modeline-on-enable nil t)
(when (timerp +popup--timer)
(remove-hook 'kill-buffer-hook #'+popup|kill-buffer-hook t)
(cancel-timer +popup--timer)
(setq +popup--timer nil))))
(put '+popup-buffer-mode 'permanent-local t)
(put '+popup-buffer-mode 'permanent-local-hook t)
(put '+popup|set-modeline-on-enable 'permanent-local-hook t)
;;
;; Macros
;;
(defmacro with-popup-rules! (rules &rest body)
"Evaluate BODY with popup RULES. RULES is a list of popup rules. Each rule
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)
(when (bound-and-true-p +popup-mode)
(setq display-buffer-alist +popup--display-buffer-alist))
,@body))
(defmacro save-popups! (&rest body)
"Sets aside all popups before executing the original function, usually to
prevent the popup(s) from messing up the UI (or vice versa)."
`(let* ((in-popup-p (+popup-buffer-p))
(popups (+popup-windows))
(+popup--inhibit-transient t)
+popup--last)
(dolist (p popups)
(+popup/close p 'force))
(unwind-protect
(progn ,@body)
(when popups
(let ((origin (selected-window)))
(+popup/restore)
(unless in-popup-p
(select-window origin)))))))
;; ;;
;; Default popup rules & bootstrap ;; Default popup rules & bootstrap
;; ;;
(set-popup-rules! (set-popup-rules!
(when (featurep! +all) (when (featurep! +all)
'(("^\\*" ((slot . 1) (vslot . -1)) ((select . t))) '(("^\\*" :slot 1 :vslot -1 :select t)
("^ \\*" ((slot . 1) (vslot . -1) (size . +popup-shrink-to-fit))))) ("^ \\*" :slot 1 :vslot -1 :size +popup-shrink-to-fit)))
(when (featurep! +defaults) (when (featurep! +defaults)
'(("^\\*Completions" '(("^\\*Completions"
((slot . -1) (vslot . -2)) :slot -1 :vslot -2 :ttl 0)
((transient . 0)))
("^\\*Compil\\(?:ation\\|e-Log\\)" ("^\\*Compil\\(?:ation\\|e-Log\\)"
((size . 0.3)) :size 0.3 :ttl 0 :quit t)
((transient . 0) (quit . t)))
("^\\*\\(?:scratch\\|Messages\\)" ("^\\*\\(?:scratch\\|Messages\\)"
nil :autosave t :ttl nil)
((autosave . t) (transient))) ("^\\*Man "
:size 0.45 :vslot -6 :ttl 0 :quit t :select t)
("^\\*doom \\(?:term\\|eshell\\)" ("^\\*doom \\(?:term\\|eshell\\)"
((size . 0.25) (vslot . -10)) :size 0.25 :vslot -10 :select t :quit nil :ttl 0)
((select . t) (quit) (transient . 0)))
("^\\*doom:" ("^\\*doom:"
((size . 0.35) (side . bottom)) :size 0.35 :size bottom :autosave t :select t :modeline t :quit nil)
((autosave . t) (select . t) (modeline . t) (quit) (transient . t)))
("^\\*\\(?:\\(?:Pp E\\|doom e\\)val\\)" ("^\\*\\(?:\\(?:Pp E\\|doom e\\)val\\)"
((size . +popup-shrink-to-fit)) :size +popup-shrink-to-fit :ttl 0 :select ignore)
((transient . 0) (select . ignore)))
("^\\*Customize" ("^\\*Customize"
((slot . 2) (side . right)) :slot 2 :side right :select t :quit t)
((modeline . nil) (select . t) (quit . t)))
("^ \\*undo-tree\\*" ("^ \\*undo-tree\\*"
((slot . 2) (side . left) (size . 20)) :slot 2 :side left :size 20 :select t :quit t)
((modeline . nil) (select . t) (quit . t)))
;; `help-mode', `helpful-mode' ;; `help-mode', `helpful-mode'
("^\\*[Hh]elp" ("^\\*[Hh]elp"
((slot . 2) (vslot . 2) (size . 0.25)) :slot 2 :vslot 2 :size 0.35 :select t)
((select . t)))
;; `Info-mode' ;; `Info-mode'
("^\\*info\\*$" ("^\\*info\\*$"
((slot . 2) (vslot . 2) (size . 0.45)) :slot 2 :vslot 2 :size 0.45 :select t)))
((select . t)))))) '(("^\\*Backtrace" :ignore t)))
(add-hook 'doom-init-ui-hook #'+popup-mode :append)
(add-hook 'doom-init-ui-hook #'+popup-mode)
(add-hook! '+popup-buffer-mode-hook (add-hook! '+popup-buffer-mode-hook
#'(+popup|adjust-fringes #'(+popup|adjust-fringes
+popup|adjust-margins +popup|adjust-margins
@ -157,5 +166,4 @@ adjustment.")
;; Hacks ;; Hacks
;; ;;
(when (featurep! +defaults) (load! "+hacks")
(load! "+hacks"))