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) (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 (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 ;;;###autoload
(defun doom-popup-buffer (buffer &rest plist) (defun doom-popup-buffer (buffer &rest plist)

View file

@ -17,7 +17,7 @@
(defvar doom-popup-history nil (defvar doom-popup-history nil
"A list of popups that were last closed. Used by `doom/popup-restore' and "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 (defvar doom-popup-remember-history t
"If non-nil, DOOM will remember the last popup(s) that were open in "If non-nil, DOOM will remember the last popup(s) that were open in
@ -92,52 +92,70 @@
'(tabulated-list-mode :noesc t))) '(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 (define-minor-mode doom-popup-mode
"Minor mode for pop-up windows." "Minor mode for popup windows."
:init-value nil :init-value nil
:keymap doom-popup-mode-map :keymap doom-popup-mode-map
(if (and (not doom-popup-mode) (if (and (not doom-popup-mode)
doom-hide-modeline-mode) doom-hide-modeline-mode)
(doom-hide-modeline-mode -1) (doom-hide-modeline-mode -1)
(let ((modeline (plist-get doom-popup-rules :modeline))) (let ((modeline (plist-get doom-popup-rules :modeline)))
(cond ((eq modeline 'nil) (cond ((or (eq modeline 'nil)
(not modeline))
(doom-hide-modeline-mode +1)) (doom-hide-modeline-mode +1))
((symbolp modeline) ((symbolp modeline)
(let ((doom--hidden-modeline-format (+doom-modeline modeline))) (let ((doom--hidden-modeline-format (+doom-modeline modeline)))
(doom-hide-modeline-mode +1)))))) (doom-hide-modeline-mode +1))))))
(mapc (lambda (cfg) (set-window-parameter nil cfg nil)) (unless doom-popup-mode
'(popup no-other-window noesc)) (mapc (lambda (cfg) (set-window-parameter nil cfg nil))
'(popup no-other-window noesc)))
(set-window-dedicated-p nil doom-popup-mode)) (set-window-dedicated-p nil doom-popup-mode))
(put 'doom-popup-mode 'permanent-local t) (put 'doom-popup-mode 'permanent-local t)
;; Tell `window-state-get' and `current-window-configuration' to persist these (defun doom-popup--init (window &optional plist)
;; custom parameters. "Initializes a window as a popup window. Sets custom window parameters and
(dolist (param '(popup noesc)) enables `doom-popup-mode'."
(add-to-list 'window-persistent-parameters (cons param 'writable))) (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)))))
(with-selected-window window
(unless (eq plist t)
(setq-local doom-popup-rules plist))
(doom-popup-mode +1))
window)
(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) (defun doom*popup-init (orig-fn &rest args)
"Enables `doom-popup-mode' in popup windows and returns the window." "Invokes `doom-popup--init' on windows that qualify as popups. 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)))
(let* ((window (apply orig-fn args)) (doom-popup--init (apply orig-fn args) (nth 2 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) (defun doom*popups-save (orig-fn &rest args)
"Puts aside all popups before executing the original function, usually to "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)) (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))
@ -149,11 +167,9 @@ prevent the popups from interfering (or the other way around)."
(doom/popup-restore) (doom/popup-restore)
(unless in-popup-p (unless in-popup-p
(select-window origin))))))) (select-window origin)))))))
;; Don't affect popup windows
(advice-add 'balance-windows :around 'doom*popup-save)
(defun doom*popup-close (orig-fn &rest args) (defun doom*delete-popup-window (orig-fn &rest args)
"Ensure that popups are closed properly." "Ensure that popups are deleted properly."
(let ((window (car args))) (let ((window (car args)))
(when (doom-popup-p window) (when (doom-popup-p window)
(with-selected-window window (with-selected-window window
@ -161,7 +177,6 @@ prevent the popups from interfering (or the other way around)."
(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)))))))
(apply orig-fn args)) (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-window-vsplit] 'ignore)
(define-key map [remap evil-force-normal-state] 'doom/popup-close-maybe)) (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 () (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)) (unless (or (minibuffer-window-active-p (minibuffer-window))
(evil-ex-hl-active-p 'evil-ex-search)) (evil-ex-hl-active-p 'evil-ex-search))
(doom/popup-close-all))) (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) (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 "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." 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) (setq-local evil-command-window-cmd-key cmd-key)
(evil-command-window-mode) (evil-command-window-mode)
(evil-command-window-insert-commands hist))) (evil-command-window-insert-commands hist)))
(advice-add 'evil-command-window :override 'doom*popup-evil-command-window)
(defun doom*popup-evil-command-window-execute () (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) (interactive)
(let ((result (buffer-substring (line-beginning-position) (let ((result (buffer-substring (line-beginning-position)
(line-end-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) (doom/popup-close popup)
(funcall execute-fn result) (funcall execute-fn result)
(setq evil-command-window-current-buffer nil))) (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 ;; Don't mess with popups
(advice-add 'doom-evil-window-move :around 'doom*popup-save) (advice-add 'doom-evil-window-move :around 'doom*popups-save)
(advice-add 'evil-window-move-very-bottom :around 'doom*popup-save) (advice-add 'evil-window-move-very-bottom :around 'doom*popups-save)
(advice-add 'evil-window-move-very-top :around 'doom*popup-save) (advice-add 'evil-window-move-very-top :around 'doom*popups-save)
(advice-add 'evil-window-move-far-left :around 'doom*popup-save) (advice-add 'evil-window-move-far-left :around 'doom*popups-save)
(advice-add 'evil-window-move-far-right :around 'doom*popup-save) (advice-add 'evil-window-move-far-right :around 'doom*popups-save)
;; Don't block moving to/from popup windows ;; Don't block moving to/from popup windows
(defun doom*ignore-window-parameters-in-popups (dir &optional arg window) (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)) window t arg windmove-wrap-around t))
(advice-add 'windmove-find-other-window :override 'doom*ignore-window-parameters-in-popups)) (advice-add 'windmove-find-other-window :override 'doom*ignore-window-parameters-in-popups))
;; (after! magit ;; (after! magit
;; ;; Don't open files (from magit) within the magit popup ;; ;; 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 (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." "Prevents messing up the neotree buffer on window changes."
(let ((neo-p (and (featurep 'neotree) (neo-global--window-exists-p)))) (let ((neo-p (and (featurep 'neotree) (neo-global--window-exists-p))))
(when neo-p (when neo-p
@ -256,18 +275,19 @@ monkey patch it to use pop-to-buffer, and to remember the previous window."
(neotree-show)))))) (neotree-show))))))
;; Prevent neotree from interfering with popups ;; 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 ;; Prevents messing up the neotree buffer on window changes
(advice-add 'doom-evil-window-move :around 'doom*popup-save-neotree) (advice-add 'doom-evil-window-move :around 'doom*popups-save-neotree)
;; (advice-add 'doom-popup-buffer :around 'doom*popup-save-neotree) ;; (advice-add 'doom-popup-buffer :around 'doom*popups-save-neotree)
;; Don't let neotree interfere with moving, splitting or rebalancing windows ;; Don't let neotree interfere with moving, splitting or rebalancing windows
(advice-add 'balance-windows :around 'doom*popup-save-neotree) (advice-add 'balance-windows :around 'doom*popups-save-neotree)
(advice-add 'split-window :around 'doom*popup-save-neotree) (advice-add 'split-window :around 'doom*popups-save-neotree)
(advice-add 'shackle-display-buffer :around 'doom*popup-save-neotree) (advice-add 'shackle-display-buffer :around 'doom*popups-save-neotree)
(advice-add 'evil-window-move-very-bottom :around 'doom*popup-save-neotree) (advice-add 'evil-window-move-very-bottom :around 'doom*popups-save-neotree)
(advice-add 'evil-window-move-very-top :around 'doom*popup-save-neotree) (advice-add 'evil-window-move-very-top :around 'doom*popups-save-neotree)
(advice-add 'evil-window-move-far-left :around 'doom*popup-save-neotree) (advice-add 'evil-window-move-far-left :around 'doom*popups-save-neotree)
(advice-add 'evil-window-move-far-right :around 'doom*popup-save-neotree)) (advice-add 'evil-window-move-far-right :around 'doom*popups-save-neotree))
(add-hook! org-load (add-hook! org-load
;; Ensures org-src-edit yields control of its buffer to shackle. ;; 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)
(define-key map "Q" 'doom/popup-org-agenda-quit)))) (define-key map "Q" 'doom/popup-org-agenda-quit))))
(after! repl-toggle (after! repl-toggle
(add-hook! doom-popup-close (add-hook! doom-popup-close
(setq rtog/--last-buffer nil))) (setq rtog/--last-buffer nil)))

View file

@ -16,9 +16,10 @@
:config :config
;; Ensure unreal/popup buffers aren't saved ;; Ensure unreal/popup buffers aren't saved
(defun +workspaces--filter-unreal (buf) (not (doom-real-buffer-p buf))) (push (lambda (buf) (doom-popup-p (get-buffer-window buf)))
(setq persp-filter-save-buffers-functions (list '+workspaces--filter-unreal)) persp-filter-save-buffers-functions)
(push '+workspaces--filter-unreal persp-common-buffer-filter-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. ;; Auto-add buffers when opening them. Allows a perspective-specific buffer list.
(defun doom*persp-auto-add-buffer (buffer &rest _) (defun doom*persp-auto-add-buffer (buffer &rest _)
@ -35,7 +36,12 @@
;; TODO Test per-frame perspectives ;; 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 (after! ivy
(defun +workspaces|ivy-ignore-non-persp-buffers (b) (defun +workspaces|ivy-ignore-non-persp-buffers (b)