Refactor core-popups; improve popups/persp-mode integration

This commit is contained in:
Henrik Lissner 2017-02-08 17:56:27 -05:00
parent 55e4434d77
commit 5d5c3bf92e
3 changed files with 91 additions and 62 deletions

View file

@ -5,7 +5,9 @@
(defun doom-popup-p (&optional window)
"Return t if WINDOW is a popup. Uses current window if WINDOW is omitted."
(let ((window (or window (selected-window))))
(and window (buffer-local-value 'doom-popup-mode (window-buffer window)))))
(and window
(or (window-parameter window 'popup)
(buffer-local-value 'doom-popup-mode (window-buffer window))))))
;;;###autoload
(defun doom-popup-buffer (buffer &rest plist)

View file

@ -17,7 +17,7 @@
(defvar doom-popup-history nil
"A list of popups that were last closed. Used by `doom/popup-restore' and
`doom*popup-save'.")
`doom*popups-save'.")
(defvar doom-popup-remember-history t
"If non-nil, DOOM will remember the last popup(s) that were open in
@ -92,52 +92,70 @@
'(tabulated-list-mode :noesc t)))
;;
;; Modifications
;;
;; Tell `window-state-get' and `current-window-configuration' to persist these
;; custom parameters. Allows `persp-mode' to remember popup states.
(setq window-persistent-parameters
(append '((popup . writable)
(noesc . writable))
window-persistent-parameters))
(define-minor-mode doom-popup-mode
"Minor mode for pop-up windows."
"Minor mode for popup 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)
(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))))))
(unless doom-popup-mode
(mapc (lambda (cfg) (set-window-parameter nil cfg nil))
'(popup no-other-window noesc))
'(popup no-other-window noesc)))
(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
;; custom parameters.
(dolist (param '(popup noesc))
(add-to-list 'window-persistent-parameters (cons param 'writable)))
(defun doom*popup-init (orig-fn &rest args)
"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)))))
(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) rules))
(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 . ,rules)
(append `((popup . ,plist)
(no-other-window . ,t))
(when (plist-get rules :noesc)
(when (plist-get plist :noesc)
`((noesc . ,t)))))
(with-selected-window window
(setq-local doom-popup-rules rules)
(unless (eq plist t)
(setq-local doom-popup-rules plist))
(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)
window)
(defun doom*popup-save (orig-fn &rest args)
(advice-add 'shackle-display-buffer :around 'doom*popup-init)
(advice-add 'balance-windows :around 'doom*popups-save)
(advice-add 'delete-window :around 'doom*delete-popup-window)
(defun doom*popup-init (orig-fn &rest args)
"Invokes `doom-popup--init' on windows that qualify as popups. Returns the window."
(unless (doom-popup-p)
(setq doom-popup-other-window (selected-window)))
(doom-popup--init (apply orig-fn args) (nth 2 args)))
(defun doom*popups-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 popups from messaging up the UI (or vice versa)."
(let ((in-popup-p (doom-popup-p))
(popups (doom-popup-windows))
(doom-popup-remember-history t))
@ -149,11 +167,9 @@ prevent the popups from interfering (or the other way around)."
(doom/popup-restore)
(unless in-popup-p
(select-window origin)))))))
;; Don't affect popup windows
(advice-add 'balance-windows :around 'doom*popup-save)
(defun doom*popup-close (orig-fn &rest args)
"Ensure that popups are closed properly."
(defun doom*delete-popup-window (orig-fn &rest args)
"Ensure that popups are deleted properly."
(let ((window (car args)))
(when (doom-popup-p window)
(with-selected-window window
@ -161,7 +177,6 @@ prevent the popups from interfering (or the other way around)."
(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)
;;
@ -179,15 +194,18 @@ prevent the popups from interfering (or the other way around)."
(define-key map [remap evil-window-vsplit] 'ignore)
(define-key map [remap evil-force-normal-state] 'doom/popup-close-maybe))
;; Close popups when you press ESC in normal mode, in any buffer
;; Make evil-mode cooperate with popups
(advice-add 'evil-force-normal-state :before 'doom*popup-evil-close-on-esc)
(advice-add 'evil-command-window :override 'doom*popup-evil-command-window)
(advice-add 'evil-command-window-execute :override 'doom*popup-evil-command-window-execute)
(defun doom*popup-evil-close-on-esc ()
"Close non-repl popups and clean up `doom-popup-windows'."
"Close non-repl popups and clean up `doom-popup-windows' when you press ESC
from normal mode in any buffer."
(unless (or (minibuffer-window-active-p (minibuffer-window))
(evil-ex-hl-active-p 'evil-ex-search))
(doom/popup-close-all)))
(advice-add 'evil-force-normal-state :after 'doom*popup-evil-close-on-esc)
;; Tame the command window
(defun doom*popup-evil-command-window (hist cmd-key execute-fn)
"The evil command window has a mind of its own (uses `switch-to-buffer'). We
monkey patch it to use pop-to-buffer, and to remember the previous window."
@ -205,10 +223,10 @@ monkey patch it to use pop-to-buffer, and to remember the previous window."
(setq-local evil-command-window-cmd-key cmd-key)
(evil-command-window-mode)
(evil-command-window-insert-commands hist)))
(advice-add 'evil-command-window :override 'doom*popup-evil-command-window)
(defun doom*popup-evil-command-window-execute ()
"Execute the command under the cursor in the appropriate buffer."
"Execute the command under the cursor in the appropriate buffer, rather than
the command buffer."
(interactive)
(let ((result (buffer-substring (line-beginning-position)
(line-end-position)))
@ -221,14 +239,13 @@ monkey patch it to use pop-to-buffer, and to remember the previous window."
(doom/popup-close popup)
(funcall execute-fn result)
(setq evil-command-window-current-buffer nil)))
(advice-add 'evil-command-window-execute :override 'doom*popup-evil-command-window-execute)
;; Tell these functions not to mess with popups
(advice-add 'doom-evil-window-move :around 'doom*popup-save)
(advice-add 'evil-window-move-very-bottom :around 'doom*popup-save)
(advice-add 'evil-window-move-very-top :around 'doom*popup-save)
(advice-add 'evil-window-move-far-left :around 'doom*popup-save)
(advice-add 'evil-window-move-far-right :around 'doom*popup-save)
;; Don't mess with popups
(advice-add 'doom-evil-window-move :around 'doom*popups-save)
(advice-add 'evil-window-move-very-bottom :around 'doom*popups-save)
(advice-add 'evil-window-move-very-top :around 'doom*popups-save)
(advice-add 'evil-window-move-far-left :around 'doom*popups-save)
(advice-add 'evil-window-move-far-right :around 'doom*popups-save)
;; Don't block moving to/from popup windows
(defun doom*ignore-window-parameters-in-popups (dir &optional arg window)
@ -239,12 +256,14 @@ monkey patch it to use pop-to-buffer, and to remember the previous window."
window t arg windmove-wrap-around t))
(advice-add 'windmove-find-other-window :override 'doom*ignore-window-parameters-in-popups))
;; (after! magit
;; ;; Don't open files (from magit) within the magit popup
;; (advice-add 'magit-display-file-buffer-traditional :around 'doom*popup-save))
;; (advice-add 'magit-display-file-buffer-traditional :around 'doom*popups-save))
(after! neotree
(defun doom*popup-save-neotree (orig-fun &rest args)
(defun doom*popups-save-neotree (orig-fun &rest args)
"Prevents messing up the neotree buffer on window changes."
(let ((neo-p (and (featurep 'neotree) (neo-global--window-exists-p))))
(when neo-p
@ -256,18 +275,19 @@ monkey patch it to use pop-to-buffer, and to remember the previous window."
(neotree-show))))))
;; Prevent neotree from interfering with popups
(advice-add 'shackle-display-buffer :around 'doom*popup-save-neotree)
(advice-add 'shackle-display-buffer :around 'doom*popups-save-neotree)
;; Prevents messing up the neotree buffer on window changes
(advice-add 'doom-evil-window-move :around 'doom*popup-save-neotree)
;; (advice-add 'doom-popup-buffer :around 'doom*popup-save-neotree)
(advice-add 'doom-evil-window-move :around 'doom*popups-save-neotree)
;; (advice-add 'doom-popup-buffer :around 'doom*popups-save-neotree)
;; Don't let neotree interfere with moving, splitting or rebalancing windows
(advice-add 'balance-windows :around 'doom*popup-save-neotree)
(advice-add 'split-window :around 'doom*popup-save-neotree)
(advice-add 'shackle-display-buffer :around 'doom*popup-save-neotree)
(advice-add 'evil-window-move-very-bottom :around 'doom*popup-save-neotree)
(advice-add 'evil-window-move-very-top :around 'doom*popup-save-neotree)
(advice-add 'evil-window-move-far-left :around 'doom*popup-save-neotree)
(advice-add 'evil-window-move-far-right :around 'doom*popup-save-neotree))
(advice-add 'balance-windows :around 'doom*popups-save-neotree)
(advice-add 'split-window :around 'doom*popups-save-neotree)
(advice-add 'shackle-display-buffer :around 'doom*popups-save-neotree)
(advice-add 'evil-window-move-very-bottom :around 'doom*popups-save-neotree)
(advice-add 'evil-window-move-very-top :around 'doom*popups-save-neotree)
(advice-add 'evil-window-move-far-left :around 'doom*popups-save-neotree)
(advice-add 'evil-window-move-far-right :around 'doom*popups-save-neotree))
(add-hook! org-load
;; Ensures org-src-edit yields control of its buffer to shackle.
@ -311,6 +331,7 @@ monkey patch it to use pop-to-buffer, and to remember the previous window."
(define-key map "q" 'doom/popup-org-agenda-quit)
(define-key map "Q" 'doom/popup-org-agenda-quit))))
(after! repl-toggle
(add-hook! doom-popup-close
(setq rtog/--last-buffer nil)))

View file

@ -16,9 +16,10 @@
:config
;; Ensure unreal/popup buffers aren't saved
(defun +workspaces--filter-unreal (buf) (not (doom-real-buffer-p buf)))
(setq persp-filter-save-buffers-functions (list '+workspaces--filter-unreal))
(push '+workspaces--filter-unreal persp-common-buffer-filter-functions)
(push (lambda (buf) (doom-popup-p (get-buffer-window buf)))
persp-filter-save-buffers-functions)
(push (lambda (buf) (not (doom-real-buffer-p buf)))
persp-common-buffer-filter-functions)
;; Auto-add buffers when opening them. Allows a perspective-specific buffer list.
(defun doom*persp-auto-add-buffer (buffer &rest _)
@ -35,7 +36,12 @@
;; TODO Test per-frame perspectives
(persp-mode 1))
;; Restore popups on load
(defun +workspaces*reinit-popups ()
(dolist (window (window-list))
(let ((plist (window-parameter window 'popup)))
(when plist (doom-popup--init window plist)))))
(advice-add 'persp-load-state-from-file :after '+workspaces*reinit-popups))
(after! ivy
(defun +workspaces|ivy-ignore-non-persp-buffers (b)