💥 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

@ -1,151 +1,160 @@
;;; ui/popup/config.el -*- lexical-binding: t; -*-
(defconst +popup-window-parameters
'(transient quit select modeline popup)
(defconst +popup-window-parameters '(ttl quit select modeline popup)
"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)
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
(defvar +popup-default-display-buffer-actions
'(display-buffer-reuse-window +popup-display-buffer-stacked-side-window)
"The functions to use to display the popup buffer.")
(defvar +popup-default-alist
'((window-height . 0.16)
'((window-height . 0.16) ; remove later
(reusable-frames . visible))
"The default alist for `display-buffer-alist' rules.")
(defvar +popup-default-parameters
'((transient . t)
(quit . t)
(select . ignore)
'((transient . t) ; remove later
(quit . t) ; remove later
(select . ignore) ; remove later
(no-other-window . t))
"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
"Size of the margins to give popup windows. Set this to nil to disable margin
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
;;
(set-popup-rules!
(when (featurep! +all)
'(("^\\*" ((slot . 1) (vslot . -1)) ((select . t)))
("^ \\*" ((slot . 1) (vslot . -1) (size . +popup-shrink-to-fit)))))
'(("^\\*" :slot 1 :vslot -1 :select t)
("^ \\*" :slot 1 :vslot -1 :size +popup-shrink-to-fit)))
(when (featurep! +defaults)
'(("^\\*Completions"
((slot . -1) (vslot . -2))
((transient . 0)))
:slot -1 :vslot -2 :ttl 0)
("^\\*Compil\\(?:ation\\|e-Log\\)"
((size . 0.3))
((transient . 0) (quit . t)))
:size 0.3 :ttl 0 :quit t)
("^\\*\\(?:scratch\\|Messages\\)"
nil
((autosave . t) (transient)))
:autosave t :ttl nil)
("^\\*Man "
:size 0.45 :vslot -6 :ttl 0 :quit t :select t)
("^\\*doom \\(?:term\\|eshell\\)"
((size . 0.25) (vslot . -10))
((select . t) (quit) (transient . 0)))
:size 0.25 :vslot -10 :select t :quit nil :ttl 0)
("^\\*doom:"
((size . 0.35) (side . bottom))
((autosave . t) (select . t) (modeline . t) (quit) (transient . t)))
:size 0.35 :size bottom :autosave t :select t :modeline t :quit nil)
("^\\*\\(?:\\(?:Pp E\\|doom e\\)val\\)"
((size . +popup-shrink-to-fit))
((transient . 0) (select . ignore)))
:size +popup-shrink-to-fit :ttl 0 :select ignore)
("^\\*Customize"
((slot . 2) (side . right))
((modeline . nil) (select . t) (quit . t)))
:slot 2 :side right :select t :quit t)
("^ \\*undo-tree\\*"
((slot . 2) (side . left) (size . 20))
((modeline . nil) (select . t) (quit . t)))
:slot 2 :side left :size 20 :select t :quit t)
;; `help-mode', `helpful-mode'
("^\\*[Hh]elp"
((slot . 2) (vslot . 2) (size . 0.25))
((select . t)))
:slot 2 :vslot 2 :size 0.35 :select t)
;; `Info-mode'
("^\\*info\\*$"
((slot . 2) (vslot . 2) (size . 0.45))
((select . t))))))
:slot 2 :vslot 2 :size 0.45 :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
#'(+popup|adjust-fringes
+popup|adjust-margins
@ -157,5 +166,4 @@ adjustment.")
;; Hacks
;;
(when (featurep! +defaults)
(load! "+hacks"))
(load! "+hacks")