core-popups: improve popup management stability
This commit is contained in:
parent
fdcd3aeee6
commit
e342994307
2 changed files with 104 additions and 103 deletions
|
@ -5,23 +5,18 @@
|
||||||
(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 (buffer-local-value 'doom-popup-mode (window-buffer window)))))
|
||||||
(window-parameter window 'popup))))
|
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom-popup-buffer (buffer &rest plist)
|
(defun doom-popup-buffer (buffer &rest plist)
|
||||||
"Display BUFFER in a shackle popup. See `shackle-rules' for possible rules."
|
"Display BUFFER in a shackle popup. See `shackle-rules' for possible rules."
|
||||||
(let* ((buffer-name (cond ((stringp buffer) buffer)
|
(unless (bufferp buffer)
|
||||||
((bufferp buffer) (buffer-name buffer))
|
(error "%s is not a valid buffer" buffer))
|
||||||
(t (error "Not a valid buffer"))))
|
(when (and plist (not (plist-member plist :align)))
|
||||||
(buffer (get-buffer-create buffer-name)))
|
(plist-put plist :align t))
|
||||||
(unless (doom-popup-p)
|
(shackle-display-buffer
|
||||||
(setq doom-popup-other-window (selected-window)))
|
buffer
|
||||||
(when (and plist (not (plist-member plist :align)))
|
nil (or plist (shackle-match buffer))))
|
||||||
(plist-put plist :align t))
|
|
||||||
(shackle-display-buffer
|
|
||||||
buffer
|
|
||||||
nil (or plist (shackle-match buffer-name)))))
|
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom-popup-file (file &rest plist)
|
(defun doom-popup-file (file &rest plist)
|
||||||
|
@ -38,17 +33,18 @@ possible rules."
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom/popup-restore ()
|
(defun doom/popup-restore ()
|
||||||
"Restore the last popup."
|
"Restore the last popups."
|
||||||
(interactive)
|
(interactive)
|
||||||
(unless doom-popup-history
|
(unless doom-popup-history
|
||||||
(error "No popups to restore"))
|
(error "No popups to restore"))
|
||||||
(dolist (spec doom-popup-history)
|
(dolist (spec doom-popup-history)
|
||||||
(let ((buffer (get-buffer (car spec)))
|
(let ((buffer (get-buffer (car spec)))
|
||||||
(path (plist-get spec :file)))
|
(path (plist-get (cdr spec) :file))
|
||||||
|
(rules (plist-get (cdr spec) :rules)))
|
||||||
(when (and (not buffer) path)
|
(when (and (not buffer) path)
|
||||||
(setq buffer (find-file-noselect path t)))
|
(setq buffer (find-file-noselect path t)))
|
||||||
(when buffer
|
(when buffer
|
||||||
(doom-popup-buffer buffer (plist-get spec :rules)))))
|
(apply 'doom-popup-buffer buffer rules))))
|
||||||
(setq doom-popup-history '()))
|
(setq doom-popup-history '()))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
|
@ -70,14 +66,7 @@ possible rules."
|
||||||
`selected-window'. The contained buffer is buried."
|
`selected-window'. The contained buffer is buried."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let ((window (or window (selected-window))))
|
(let ((window (or window (selected-window))))
|
||||||
(when (and (doom-popup-p window)
|
(when (doom-popup-p window)
|
||||||
(window-live-p window))
|
|
||||||
(with-selected-window window
|
|
||||||
(when (called-interactively-p 'interactive)
|
|
||||||
(run-hooks 'doom-popup-close-hook))
|
|
||||||
(doom-popup-mode -1)
|
|
||||||
(when doom-popup-remember-history
|
|
||||||
(setq doom-popup-history (list (doom--popup-data window)))))
|
|
||||||
(delete-window window))))
|
(delete-window window))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
|
@ -89,19 +78,19 @@ possible rules."
|
||||||
(window-list))))
|
(window-list))))
|
||||||
(when popups
|
(when popups
|
||||||
(setq doom-popup-history (mapcar 'doom--popup-data (doom-popup-windows)))
|
(setq doom-popup-history (mapcar 'doom--popup-data (doom-popup-windows)))
|
||||||
(run-hooks 'doom-popup-close-hook)
|
|
||||||
(let (doom-popup-remember-history)
|
(let (doom-popup-remember-history)
|
||||||
(mapc 'doom/popup-close popups)))))
|
(mapc 'delete-window popups)))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun doom/popup-close-maybe ()
|
(defun doom/popup-close-maybe ()
|
||||||
"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)
|
||||||
(if (window-parameter (selected-window) 'noesc)
|
(let ((window (selected-window)))
|
||||||
(call-interactively (if (featurep 'evil)
|
(if (window-parameter window 'noesc)
|
||||||
'evil-force-normal-state
|
(call-interactively (if (featurep 'evil)
|
||||||
'keyboard-escape-quit))
|
'evil-force-normal-state
|
||||||
(doom/popup-close)))
|
'keyboard-escape-quit))
|
||||||
|
(delete-window window))))
|
||||||
|
|
||||||
(defun doom--popup-data (window)
|
(defun doom--popup-data (window)
|
||||||
(let ((buffer (window-buffer window)))
|
(let ((buffer (window-buffer window)))
|
||||||
|
|
|
@ -66,85 +66,97 @@
|
||||||
;; :noesc and :modeline are custom settings and are not part of shackle. See
|
;; :noesc and :modeline are custom settings and are not part of shackle. See
|
||||||
;; `doom*popup-init' and `doom-popup-buffer' for how they're used.
|
;; `doom*popup-init' and `doom-popup-buffer' for how they're used.
|
||||||
(set! :popup
|
(set! :popup
|
||||||
("^ ?\\*doom:.+\\*$" :size 40 :modeline t :regexp t)
|
'("^ ?\\*doom:.+\\*$" :size 40 :modeline t :regexp t)
|
||||||
("^ ?\\*doom .+\\*$" :size 30 :noselect t :regexp t)
|
'("^ ?\\*doom .+\\*$" :size 30 :noselect t :regexp t)
|
||||||
("^\\*.+-Profiler-Report .+\\*$" :size 0.3 :regexp t)
|
'("^\\*.+-Profiler-Report .+\\*$" :size 0.3 :regexp t)
|
||||||
("*esup*" :size 0.4 :noselect t :noesc t)
|
'("*esup*" :size 0.4 :noselect t :noesc t)
|
||||||
("*minor-modes*" :size 0.5 :noselect t)
|
'("*minor-modes*" :size 0.5 :noselect t)
|
||||||
("*eval*" :size 16 :noselect t)
|
'("*eval*" :size 16 :noselect t)
|
||||||
("*Pp Eval Output*" :size 0.3)
|
'("*Pp Eval Output*" :size 0.3)
|
||||||
("*Apropos*" :size 0.3)
|
'("*Apropos*" :size 0.3)
|
||||||
("*Backtrace*" :size 25 :noselect t)
|
'("*Backtrace*" :size 25 :noselect t)
|
||||||
("*Help*" :size 16)
|
'("*Help*" :size 16)
|
||||||
("*Messages*" :size 10)
|
'("*Messages*" :size 10)
|
||||||
("*Warnings*" :size 10 :noselect t)
|
'("*Warnings*" :size 10 :noselect t)
|
||||||
("*command-log*" :size 28 :noselect t :align right)
|
'("*command-log*" :size 28 :noselect t :align right)
|
||||||
("*Shell Command Output*" :size 20 :noselect t)
|
'("*Shell Command Output*" :size 20 :noselect t)
|
||||||
(compilation-mode :size 15 :noselect t :noesc t)
|
'(compilation-mode :size 15 :noselect t :noesc t)
|
||||||
(ivy-occur-grep-mode :size 25 :noesc t)
|
'(ivy-occur-grep-mode :size 25 :noesc t)
|
||||||
(eww-mode :size 30)
|
'(eww-mode :size 30)
|
||||||
(comint-mode :noesc t)
|
'(comint-mode :noesc t)
|
||||||
(tabulated-list-mode :noesc t))
|
'(tabulated-list-mode :noesc t)))
|
||||||
|
|
||||||
(define-minor-mode doom-popup-mode
|
|
||||||
"Minor mode for pop-up windows."
|
|
||||||
:init-value nil
|
|
||||||
:keymap doom-popup-mode-map
|
|
||||||
(if (and (not doom-popup-mode)
|
|
||||||
doom-hide-modeline-mode)
|
|
||||||
(doom-hide-modeline-mode -1)
|
|
||||||
(let ((modeline (plist-get doom-popup-rules :modeline)))
|
|
||||||
(cond ((eq modeline 'nil)
|
|
||||||
(doom-hide-modeline-mode +1))
|
|
||||||
((symbolp modeline)
|
|
||||||
(let ((doom--hidden-modeline-format (+doom-modeline modeline)))
|
|
||||||
(doom-hide-modeline-mode +1))))))
|
|
||||||
(set-window-dedicated-p nil doom-popup-mode))
|
|
||||||
(put 'doom-popup-mode 'permanent-local t)
|
|
||||||
|
|
||||||
;; Tell `window-state-get' and `current-window-configuration' to persist these
|
(define-minor-mode doom-popup-mode
|
||||||
;; custom parameters.
|
"Minor mode for pop-up windows."
|
||||||
(dolist (param '(popup noesc))
|
:init-value nil
|
||||||
(add-to-list 'window-persistent-parameters (cons param 'writable)))
|
:keymap doom-popup-mode-map
|
||||||
|
(if (and (not doom-popup-mode)
|
||||||
|
doom-hide-modeline-mode)
|
||||||
|
(doom-hide-modeline-mode -1)
|
||||||
|
(let ((modeline (plist-get doom-popup-rules :modeline)))
|
||||||
|
(cond ((eq modeline 'nil)
|
||||||
|
(doom-hide-modeline-mode +1))
|
||||||
|
((symbolp modeline)
|
||||||
|
(let ((doom--hidden-modeline-format (+doom-modeline modeline)))
|
||||||
|
(doom-hide-modeline-mode +1))))))
|
||||||
|
(mapc (lambda (cfg) (set-window-parameter nil cfg nil))
|
||||||
|
'(popup no-other-window noesc))
|
||||||
|
(set-window-dedicated-p nil doom-popup-mode))
|
||||||
|
(put 'doom-popup-mode 'permanent-local t)
|
||||||
|
|
||||||
(defun doom*popup-init (orig-fn &rest args)
|
;; Tell `window-state-get' and `current-window-configuration' to persist these
|
||||||
"Enables `doom-popup-mode' in popup windows and returns the window."
|
;; custom parameters.
|
||||||
(unless (doom-popup-p)
|
(dolist (param '(popup noesc))
|
||||||
(setq doom-popup-other-window (selected-window)))
|
(add-to-list 'window-persistent-parameters (cons param 'writable)))
|
||||||
(let ((window (apply orig-fn args))
|
|
||||||
(rules (nth 2 args)))
|
|
||||||
(unless window
|
|
||||||
(error "No window was found (%s)" args))
|
|
||||||
(mapc (lambda (cfg) (set-window-parameter window (car cfg) (cdr cfg)))
|
|
||||||
(append `((popup . ,rules)
|
|
||||||
(no-other-window . ,t))
|
|
||||||
(when (plist-get rules :noesc)
|
|
||||||
`((noesc . ,t)))))
|
|
||||||
(with-selected-window window
|
|
||||||
(setq-local doom-popup-rules rules)
|
|
||||||
(doom-popup-mode +1))
|
|
||||||
;; NOTE orig-fn returns a window, so `doom*popup-init' must too
|
|
||||||
window))
|
|
||||||
|
|
||||||
(defun doom*popup-save (orig-fn &rest args)
|
(defun doom*popup-init (orig-fn &rest args)
|
||||||
"Puts aside all popups before executing the original function, usually to
|
"Enables `doom-popup-mode' in popup windows and returns the window."
|
||||||
|
(unless (doom-popup-p)
|
||||||
|
(setq doom-popup-other-window (selected-window)))
|
||||||
|
(let* ((window (apply orig-fn args))
|
||||||
|
(rules (or (nth 2 args) (shackle-match (window-buffer window)))))
|
||||||
|
(unless window
|
||||||
|
(error "No window was found for %s: %s" (car args) rules))
|
||||||
|
(mapc (lambda (cfg) (set-window-parameter window (car cfg) (cdr cfg)))
|
||||||
|
(append `((popup . ,rules)
|
||||||
|
(no-other-window . ,t))
|
||||||
|
(when (plist-get rules :noesc)
|
||||||
|
`((noesc . ,t)))))
|
||||||
|
(with-selected-window window
|
||||||
|
(setq-local doom-popup-rules rules)
|
||||||
|
(doom-popup-mode +1))
|
||||||
|
;; NOTE orig-fn returns a window, so `doom*popup-init' must too
|
||||||
|
window))
|
||||||
|
(advice-add 'shackle-display-buffer :around 'doom*popup-init)
|
||||||
|
|
||||||
|
(defun doom*popup-save (orig-fn &rest args)
|
||||||
|
"Puts aside all popups before executing the original function, usually to
|
||||||
prevent the popups from interfering (or the other way around)."
|
prevent the popups from interfering (or the other way around)."
|
||||||
(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))
|
||||||
|
(when popups
|
||||||
|
(mapc 'doom/popup-close popups))
|
||||||
|
(unwind-protect (apply orig-fn args)
|
||||||
(when popups
|
(when popups
|
||||||
(mapc 'doom/popup-close popups))
|
(let ((origin (selected-window)))
|
||||||
(unwind-protect (apply orig-fn args)
|
(doom/popup-restore)
|
||||||
(when popups
|
(unless in-popup-p
|
||||||
(let ((origin (selected-window)))
|
(select-window origin)))))))
|
||||||
(doom/popup-restore)
|
;; Don't affect popup windows
|
||||||
(unless in-popup-p
|
(advice-add 'balance-windows :around 'doom*popup-save)
|
||||||
(select-window origin)))))))
|
|
||||||
|
|
||||||
;; There is no shackle-popup hook, so I created one:
|
(defun doom*popup-close (orig-fn &rest args)
|
||||||
(advice-add 'shackle-display-buffer :around 'doom*popup-init)
|
"Ensure that popups are closed properly."
|
||||||
;; Don't affect popup windows
|
(let ((window (car args)))
|
||||||
(advice-add 'balance-windows :around 'doom*popup-save))
|
(when (doom-popup-p window)
|
||||||
|
(with-selected-window window
|
||||||
|
(doom-popup-mode -1)
|
||||||
|
(when doom-popup-remember-history
|
||||||
|
(setq doom-popup-history (list (doom--popup-data window)))))))
|
||||||
|
(apply orig-fn args))
|
||||||
|
(advice-add 'delete-window :around 'doom*popup-close)
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue