core-popups: improve popup management stability

This commit is contained in:
Henrik Lissner 2017-02-08 01:58:11 -05:00
parent fdcd3aeee6
commit e342994307
2 changed files with 104 additions and 103 deletions

View file

@ -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)))

View file

@ -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)
;; ;;