core-popups: refactor window parameters & popup init

This commit is contained in:
Henrik Lissner 2017-02-22 21:54:10 -05:00
parent 8271342b2e
commit 92fb1e3417
2 changed files with 93 additions and 84 deletions

View file

@ -5,9 +5,7 @@
(defun doom-popup-p (&optional window) (defun doom-popup-p (&optional window)
"Return t if WINDOW is a popup. Uses current window if WINDOW is omitted." "Return t if WINDOW is a popup. Uses current window if WINDOW is omitted."
(let ((window (or window (selected-window)))) (let ((window (or window (selected-window))))
(and window (and window (window-parameter window 'popup))))
(or (window-parameter window 'popup)
(buffer-local-value 'doom-popup-mode (window-buffer window))))))
;;;###autoload ;;;###autoload
(defun doom-popup-buffer (buffer &rest plist) (defun doom-popup-buffer (buffer &rest plist)
@ -35,7 +33,9 @@ possible rules."
;;;###autoload ;;;###autoload
(defun doom/popup-restore () (defun doom/popup-restore ()
"Restore the last popups." "Restore the last popups. If the buffers have been killed, and represented
real files, they will be restored. Special buffers or buffers with non-nil
:autokill properties will not be."
(interactive) (interactive)
(unless doom-popup-history (unless doom-popup-history
(error "No popups to restore")) (error "No popups to restore"))
@ -72,14 +72,11 @@ possible rules."
;;;###autoload ;;;###autoload
(defun doom/popup-close-all () (defun doom/popup-close-all ()
"Closes all open popups. If DONT-KILL is non-nil, don't kill their buffers." "Closes all open popups."
(interactive) (interactive)
(let* ((orig-win (selected-window)) (let ((orig-win (selected-window)))
(popups (cl-remove-if-not (lambda (win) (and (doom-popup-p win) (when-let (popups (doom-popup-windows))
(not (eq win orig-win)))) (setq doom-popup-history (mapcar 'doom--popup-data popups))
(window-list))))
(when popups
(setq doom-popup-history (mapcar 'doom--popup-data (doom-popup-windows)))
(let (doom-popup-remember-history) (let (doom-popup-remember-history)
(mapc 'delete-window popups))))) (mapc 'delete-window popups)))))
@ -88,7 +85,7 @@ possible rules."
"Close the current popup *if* its window doesn't have a noesc parameter." "Close the current popup *if* its window doesn't have a noesc parameter."
(interactive) (interactive)
(let ((window (selected-window))) (let ((window (selected-window)))
(if (window-parameter window 'noesc) (if (window-parameter window :noesc)
(call-interactively (if (featurep 'evil) (call-interactively (if (featurep 'evil)
'evil-force-normal-state 'evil-force-normal-state
'keyboard-escape-quit)) 'keyboard-escape-quit))

View file

@ -34,6 +34,10 @@
map) map)
"Active keymap in popup windows.") "Active keymap in popup windows.")
(defvar doom-popup-window-parameters '(:noesc :modeline :autokill)
"A list of window parameters that are set (and cleared) when `doom-popup-mode
is enabled/disabled.'")
(@def-setting :popup (&rest rules) (@def-setting :popup (&rest rules)
"Prepend a new popup rule to `shackle-rules'." "Prepend a new popup rule to `shackle-rules'."
(if (cl-every 'listp rules) (if (cl-every 'listp rules)
@ -61,7 +65,7 @@
("*Pp Eval Output*" :size 0.3 :autokill t) ("*Pp Eval Output*" :size 0.3 :autokill t)
("*Apropos*" :size 0.3) ("*Apropos*" :size 0.3)
("*Backtrace*" :size 25 :noselect t) ("*Backtrace*" :size 25 :noselect t)
("*Help*" :size 16 :autokill t) ("*Help*" :size 16)
("*Messages*" :size 10) ("*Messages*" :size 10)
("*Warnings*" :size 10 :noselect t :autokill t) ("*Warnings*" :size 10 :noselect t :autokill t)
("*command-log*" :size 28 :noselect t :align right) ("*command-log*" :size 28 :noselect t :align right)
@ -73,87 +77,98 @@
(tabulated-list-mode :noesc t))) (tabulated-list-mode :noesc t)))
:config :config
(shackle-mode 1)) (shackle-mode 1)
(defun doom*shackle-always-align (plist)
;; "Ensure popups are always aligned and selected by default. Eliminates the need
;; Modifications
;;
(defun doom*shackle-always-align (plist)
"Ensure popups are always aligned and selected by default. Eliminates the need
for :align t on every rule." for :align t on every rule."
(when plist (when plist
(unless (plist-member plist :align) (unless (plist-member plist :align)
(plist-put plist :align t)) (plist-put plist :align t))
(unless (or (plist-member plist :select) (unless (or (plist-member plist :select)
(plist-member plist :noselect)) (plist-member plist :noselect))
(plist-put plist :select t))) (plist-put plist :select t)))
plist) plist)
(advice-add 'shackle--match :filter-return 'doom*shackle-always-align) (advice-add 'shackle--match :filter-return 'doom*shackle-always-align))
;;
;; Integration
;;
;; Tell `window-state-get' and `current-window-configuration' to persist these ;; Tell `window-state-get' and `current-window-configuration' to persist these
;; custom parameters. Allows `persp-mode' to remember popup states. ;; custom parameters. Helpful for `persp-mode' to persist popup windows.
(nconc window-persistent-parameters (push (cons 'no-other-window 'writable) window-persistent-parameters)
'((popup . writable) (dolist (param doom-popup-window-parameters)
(noesc . writable) (push (cons param 'writable) window-persistent-parameters))
(autokill . writable)))
(define-minor-mode doom-popup-mode (define-minor-mode doom-popup-mode
"Minor mode for popup windows." "Minor mode for popup windows."
:init-value nil :init-value nil
:keymap doom-popup-mode-map :keymap doom-popup-mode-map
;; Don't show modeline in popup windows without a :modeline rule. If one (let ((window (selected-window)))
;; exists and it's a symbol, use `doom-modeline' to grab the format. If ;; Major mode changes (and other things) may call
;; non-nil, show the mode-line as normal. If nil (or omitted), then hide the ;; `kill-all-local-variables', turning off things like `doom-popup-mode'.
;; modeline entirely. ;; This prevents that.
(if (and (not doom-popup-mode) (put 'doom-popup-mode 'permanent-local doom-popup-mode)
doom-hide-modeline-mode) ;; Ensure that buffer-opening functions/commands (like
(doom-hide-modeline-mode -1) ;; `switch-to-buffer-other-window' won't use this window).
(let ((modeline (plist-get doom-popup-rules :modeline))) (set-window-parameter window 'no-other-window doom-popup-mode)
(cond ((or (eq modeline 'nil) ;; Makes popup window resist interactively changing its buffer.
(not modeline)) (set-window-dedicated-p window doom-popup-mode)
(doom-hide-modeline-mode +1)) (cond (doom-popup-mode
((symbolp modeline) ;; Don't show modeline in popup windows without a :modeline rule. If
(let ((doom--hidden-modeline-format (doom-modeline modeline))) ;; one exists and it's a symbol, use `doom-modeline' to grab the
(doom-hide-modeline-mode +1))))))) ;; format. If non-nil, show the mode-line as normal. If nil (or
(put 'doom-popup-mode 'permanent-local t) ;; omitted, by default), then hide the modeline entirely.
(let ((modeline (plist-get doom-popup-rules :modeline)))
(cond ((or (eq modeline 'nil)
(not modeline))
(doom-hide-modeline-mode +1))
((symbolp modeline)
(let ((doom--hidden-modeline-format (doom-modeline modeline)))
(doom-hide-modeline-mode +1)))))
;; Save metadata into window parameters so it can be saved by window
;; config persisting plugins like workgroups or persp-mode.
(set-window-parameter window 'popup (or doom-popup-rules t))
(when doom-popup-rules
(dolist (param doom-popup-window-parameters)
(when-let (val (plist-get doom-popup-rules param))
(set-window-parameter window param val)))))
(t
;; show modeline
(when doom-hide-modeline-mode
(doom-hide-modeline-mode -1))
;; Ensure window parameters are cleaned up
(set-window-parameter window 'popup nil)
(dolist (param doom-popup-window-parameters)
(set-window-parameter window param nil))))))
;; Hide modeline in completion popups ;; Hide modeline in completion popups
(@add-hook (completion-in-region-mode completion-list-mode) 'doom-hide-modeline-mode) (@add-hook (completion-in-region-mode completion-list-mode) 'doom-hide-modeline-mode)
(defun doom-popup--init (window &optional plist)
"Initializes a window as a popup window. Sets custom window parameters and
enables `doom-popup-mode'."
(unless window
(error "No window was found for %s: %s" (car args) plist))
(unless plist
(setq plist (shackle-match (window-buffer window))))
(mapc (lambda (cfg) (set-window-parameter window (car cfg) (cdr cfg)))
(append `((popup . ,plist)
(no-other-window . ,t))
(when (plist-get plist :noesc)
`((noesc . ,t)))
(when (plist-get plist :autokill)
`((autokill . ,t)))))
(with-selected-window window
(unless (eq plist t)
(setq-local doom-popup-rules plist))
(doom-popup-mode +1))
window)
;; ;;
(defun doom*popup-init (orig-fn &rest args) (defun doom*popup-init (orig-fn &rest args)
"Invokes `doom-popup--init' on windows that qualify as popups. Returns the window." "Initializes a window as a popup window by enabling `doom-popup-mode' in it.
Returns the window."
(unless (doom-popup-p) (unless (doom-popup-p)
(setq doom-popup-other-window (selected-window))) (setq doom-popup-other-window (selected-window)))
(doom-popup--init (apply orig-fn args) (nth 2 args))) (let ((plist (or (nth 2 args)
(and (bufferp (car args))
(shackle-match (window-buffer (car args))))))
(window (apply orig-fn args)))
(unless window
(error "No popup window was found for %s: %s" (car args) plist))
(with-selected-window window
(unless (eq plist t)
(setq-local doom-popup-rules plist))
(doom-popup-mode +1))
window))
(defun doom*popups-save (orig-fn &rest args) (defun doom*popups-save (orig-fn &rest args)
"Puts aside all popups before executing the original function, usually to "Sets aside all popups before executing the original function, usually to
prevent popups from messaging up the UI (or vice versa)." prevent the popup(s) from messing up the UI (or vice versa)."
(let ((in-popup-p (doom-popup-p)) (let ((in-popup-p (doom-popup-p))
(popups (doom-popup-windows)) (popups (doom-popup-windows))
(doom-popup-remember-history t)) (doom-popup-remember-history t))
@ -166,25 +181,22 @@ prevent popups from messaging up the UI (or vice versa)."
(unless in-popup-p (unless in-popup-p
(select-window origin))))))) (select-window origin)))))))
(defun doom*delete-popup-window (orig-fn &rest args) (defun doom*delete-popup-window (&optional window)
"Ensure that popups are deleted properly, and killed if they have :autokill "Ensure that popups are deleted properly, and killed if they have :autokill
properties." properties."
(let ((window (or (car args) (selected-window)))) (let ((window (or window (selected-window))))
(when (doom-popup-p window) (when (doom-popup-p window)
(when doom-popup-remember-history (when doom-popup-remember-history
(setq doom-popup-history (list (doom--popup-data window)))) (setq doom-popup-history (list (doom--popup-data window))))
(set-window-dedicated-p window nil) (let ((autokill-p (window-parameter window :autokill)))
(if (window-parameter window 'autokill)
(kill-buffer (window-buffer window))
(with-selected-window window (with-selected-window window
(doom-popup-mode -1))) (doom-popup-mode -1)
(mapc (lambda (cfg) (set-window-parameter window cfg nil)) (when autokill-p
'(popup no-other-window noesc autokill)))) (kill-buffer (current-buffer))))))))
(apply orig-fn args))
(advice-add 'shackle-display-buffer :around 'doom*popup-init) (advice-add 'shackle-display-buffer :around 'doom*popup-init)
(advice-add 'balance-windows :around 'doom*popups-save) (advice-add 'balance-windows :around 'doom*popups-save)
(advice-add 'delete-window :around 'doom*delete-popup-window) (advice-add 'delete-window :before 'doom*delete-popup-window)
;; ;;