From 91357a3e5d8ac065d8bce8af9e59731f956b82e2 Mon Sep 17 00:00:00 2001 From: Henrik Lissner Date: Sat, 6 Jan 2018 01:23:22 -0500 Subject: [PATCH] :boom: Replace core-popup with new feature/popup module This is a breaking change! Update your :popup settings. Old ones will throw errors! Doom's new popup management system casts off its shackles (hur hur) and replaces them with the monster that is `display-buffer-alist`, and window parameters. However, this is highly experimental! Expect edge cases. Particularly with org-mode and magit (or anything that does its own window management). Relevant to #261, #263, #325 --- core/autoload/popups.el | 418 ----------------- core/autoload/scratch.el | 12 +- core/core-popups.el | 544 ---------------------- core/core.el | 1 - init.example.el | 1 + modules/app/regex/config.el | 5 +- modules/app/twitter/config.el | 2 - modules/completion/helm/config.el | 1 - modules/completion/ivy/config.el | 1 - modules/feature/debugger/config.el | 4 +- modules/feature/eval/config.el | 7 +- modules/feature/evil/autoload/evil.el | 8 +- modules/feature/evil/config.el | 5 +- modules/feature/lookup/config.el | 3 +- modules/feature/popup/README.org | 49 ++ modules/feature/popup/autoload.el | 328 +++++++++++++ modules/feature/popup/config.el | 196 ++++++++ modules/feature/version-control/+git.el | 2 +- modules/feature/version-control/config.el | 6 +- modules/lang/clojure/config.el | 2 +- modules/lang/emacs-lisp/config.el | 3 +- modules/lang/haskell/+intero.el | 1 - modules/lang/latex/config.el | 2 +- modules/lang/plantuml/config.el | 2 +- modules/lang/python/config.el | 4 +- modules/lang/rest/config.el | 2 +- modules/private/default/+bindings.el | 14 +- modules/tools/gist/config.el | 1 - modules/tools/imenu/config.el | 26 +- modules/tools/neotree/config.el | 4 + modules/tools/password-store/config.el | 2 +- modules/ui/doom/config.el | 9 +- modules/ui/tabbar/config.el | 4 +- 33 files changed, 631 insertions(+), 1038 deletions(-) delete mode 100644 core/autoload/popups.el delete mode 100644 core/core-popups.el create mode 100644 modules/feature/popup/README.org create mode 100644 modules/feature/popup/autoload.el create mode 100644 modules/feature/popup/config.el diff --git a/core/autoload/popups.el b/core/autoload/popups.el deleted file mode 100644 index 3130e698a..000000000 --- a/core/autoload/popups.el +++ /dev/null @@ -1,418 +0,0 @@ -;;; core/autoload/popups.el -*- lexical-binding: t; -*- - -;;;###autoload -(defun doom-popup-p (&optional target) - "Return t if TARGET (a window or buffer) is a popup. Uses current window if -omitted." - (when-let* ((target (or target (selected-window)))) - (cond ((bufferp target) - (and (buffer-live-p target) - (buffer-local-value 'doom-popup-mode target))) - ((windowp target) - (and (window-live-p target) - (window-parameter target 'popup)))))) - -;;;###autoload -(defun doom-popup-buffer (buffer &optional plist extend-p) - "Display BUFFER in a shackle popup with PLIST rules. See `shackle-rules' for -possible rules. If EXTEND-P is non-nil, don't overwrite the original rules for -this popup, just the specified properties. Returns the new popup window." - (declare (indent defun)) - (unless (bufferp buffer) - (error "%s is not a valid buffer" buffer)) - (shackle-display-buffer - buffer - nil (or (if extend-p - (append plist (shackle-match buffer)) - plist) - (shackle-match buffer)))) - -;;;###autoload -(defun doom-popup-switch-to-buffer (buffer) - "Switch the current (or closest) pop-up window to BUFFER." - (unless (doom-popup-p) - (if-let* ((popups (doom-popup-windows))) - (select-window (car popups)) - (error "No popups to switch to"))) - (set-window-dedicated-p nil nil) - (switch-to-buffer buffer nil t) - (prog1 (selected-window) - (set-window-dedicated-p nil t))) - -;;;###autoload -(defun doom-popup-fit-to-buffer (&optional window max-size) - "Fit WINDOW to the size of its content." - (unless (string-empty-p (buffer-string)) - (let* ((window-size (doom-popup-size window)) - (max-size (or max-size (doom-popup-property :size window))) - (size (+ 2 (if (floatp max-size) (truncate (* max-size window-size)) window-size)))) - (fit-window-to-buffer window size nil size)))) - -;;;###autoload -(defun doom-popup-move (direction) - "Move a popup window to another side of the frame, in DIRECTION, which can be -one of the following: 'left 'right 'above 'below" - (when (doom-popup-p) - (let ((buffer (current-buffer)) - (doom-popup-inhibit-autokill t)) - (doom/popup-close) - (doom-popup-buffer buffer `(:align ,direction) 'extend)))) - -;;;###autoload -(defun doom-popup-file (file &optional plist extend-p) - "Display FILE in a shackle popup, with PLIST rules. See `shackle-rules' for -possible rules." - (unless (file-exists-p file) - (user-error "Can't display file in popup, it doesn't exist: %s" file)) - (doom-popup-buffer (find-file-noselect file t) plist extend-p)) - -;;;###autoload -(defun doom-popup-windows (&optional filter-static-p) - "Get a list of open pop up windows." - (cl-loop for window in doom-popup-windows - if (and (doom-popup-p window) - (not (and filter-static-p - (doom-popup-property :static window)))) - collect window)) - -;;;###autoload -(defun doom-popup-properties (window-or-buffer) - "Returns a window's popup property list, if possible. The buffer-local -`doom-popup-rules' always takes priority, but this will fall back to the popup -window parameter." - (cond ((windowp window-or-buffer) - (or (window-parameter window-or-buffer 'popup) - (doom-popup-properties (window-buffer window-or-buffer)))) - ((bufferp window-or-buffer) - (buffer-local-value 'doom-popup-rules window-or-buffer)))) - -;;;###autoload -(defun doom-popup-property (prop &optional window) - "Returns a `doom-popup-rules' PROPerty from WINDOW." - (or (plist-get (doom-popup-properties (or window (selected-window))) - prop) - (pcase prop - (:size shackle-default-size) - (:align shackle-default-alignment)))) - -;;;###autoload -(defun doom-popup-side (&optional window) - "Return what side a popup WINDOW came from ('left 'right 'above or 'below)." - (let ((align (doom-popup-property :align window))) - (when (eq align t) - (setq align shackle-default-alignment)) - (when (functionp align) - (setq align (funcall align))) - align)) - -;;;###autoload -(defun doom-popup-size (&optional window) - "Return the size of a popup WINDOW." - (pcase (doom-popup-side window) - ((or 'left 'right) (window-width window)) - ((or 'above 'below) (window-height window)))) - -(defun doom--popup-data (window) - (when-let* ((buffer (window-buffer window))) - `(,(buffer-name buffer) - :file ,(buffer-file-name buffer) - :rules ,(window-parameter window 'popup) - :size ,(doom-popup-size window)))) - -;;;###autoload -(defmacro with-popup-rules! (rules &rest body) - "TODO" - (declare (indent defun)) - `(let (shackle-rules) - ,@(cl-loop for rule in rules - collect `(set! :popup ,@rule)) - ,@body)) - -;;;###autoload -(defmacro save-popups! (&rest body) - "Sets aside all popups before executing the original function, usually to -prevent the popup(s) from messing up the UI (or vice versa)." - `(let ((in-popup-p (doom-popup-p)) - (popups (doom-popup-windows)) - (doom-popup-remember-history t) - (doom-popup-inhibit-autokill t)) - (when popups - (mapc #'doom/popup-close popups)) - (unwind-protect - (progn ,@body) - (when popups - (let ((origin (selected-window))) - (doom/popup-restore) - (unless in-popup-p - (select-window origin))))))) - - -;; --- Commands --------------------------- - -;;;###autoload -(defun doom/popup-restore () - "Restore the last open popups. If the buffers have been killed, and -represented real files, they will be restored. Dead special buffers or buffers -with non-nil :autokill properties will not be. - -Returns t if popups were restored, nil otherwise." - (interactive) - (unless doom-popup-history - (error "No popups to restore")) - (let (any-p) - (dolist (spec doom-popup-history) - (let ((buffer (get-buffer (car spec))) - (file (plist-get (cdr spec) :file)) - (rules (plist-get (cdr spec) :rules)) - (size (plist-get (cdr spec) :size))) - (when (and (not buffer) file) - (setq buffer - (if-let* ((buf (get-file-buffer file))) - (clone-indirect-buffer (buffer-name buf) nil t) - (find-file-noselect file t)))) - (when size - (setq rules (plist-put rules :size size))) - (when (and buffer (doom-popup-buffer buffer rules) (not any-p)) - (setq any-p t)))) - (when any-p - (setq doom-popup-history '())) - any-p)) - -;;;###autoload -(defun doom/popup-toggle () - "Toggle popups on and off. If used outside of popups (and popups are -available), it will select the nearest popup window." - (interactive) - (when (doom-popup-p) - (if doom-popup-other-window - (select-window doom-popup-other-window) - (other-window 1))) - (if (doom-popup-windows t) - (let ((doom-popup-inhibit-autokill t)) - (doom/popup-close-all t)) - (doom/popup-restore))) - -;;;###autoload -(defun doom/popup-close (&optional window) - "Find and close WINDOW if it's a popup. If WINDOW is omitted, defaults to -`selected-window'. The contained buffer is buried, unless it has an :autokill -property." - (interactive) - (when (doom-popup-p window) - (delete-window window))) - -;;;###autoload -(defun doom/popup-close-all (&optional force-p) - "Closes most open popups. - -Does not close popups that are :static or don't have an :autoclose property (see -`shackle-rules'). - -If FORCE-P is non-nil (or this function is called interactively), ignore popups' -:autoclose property. This command will never close :static popups." - (interactive - (list (called-interactively-p 'interactive))) - (when-let* ((popups (doom-popup-windows t))) - (let (success doom-popup-remember-history) - (setq doom-popup-history (delq nil (mapcar #'doom--popup-data popups))) - (dolist (window popups success) - (when (or force-p (doom-popup-property :autoclose window)) - (kill-buffer (window-buffer window)) - (setq success t)))))) - -;;;###autoload -(defun doom/popup-close-maybe () - "Close the current popup *if* its window doesn't have a noesc parameter." - (interactive) - (if (doom-popup-property :noesc) - (call-interactively - (if (featurep 'evil) - #'evil-force-normal-state - #'keyboard-quit)) - (kill-this-buffer))) - -;;;###autoload -(defun doom/popup-kill-all () - "Like `doom/popup-close-all', but kill *all* popups, including :static ones, -without leaving any trace behind (muahaha)." - (interactive) - (when-let* ((popups (doom-popup-windows))) - (let (doom-popup-remember-history) - (setq doom-popup-history nil) - (dolist (win popups) - (kill-buffer (window-buffer win)))))) - -;;;###autoload -(defun doom/popup-this-buffer () - "Display currently selected buffer in a popup window." - (interactive) - (doom-popup-buffer (current-buffer) '(:align t :autokill t))) - -;;;###autoload -(defun doom/popup-toggle-messages () - "Toggle *Messages* buffer." - (interactive) - (if-let* ((win (get-buffer-window "*Messages*"))) - (doom/popup-close win) - (doom-popup-buffer (get-buffer "*Messages*")))) - -;;;###autoload -(defun doom/other-popup (count) - "Cycle through popup windows. Like `other-window', but for popups." - (interactive "p") - (if-let* ((popups (if (doom-popup-p) - (cdr (memq (selected-window) doom-popup-windows)) - (setq doom-popup-other-window (selected-window)) - doom-popup-windows))) - (ignore-errors (select-window (nth (mod (1- count) (length popups)) popups))) - (unless (eq (selected-window) doom-popup-other-window) - (when doom-popup-other-window - (select-window doom-popup-other-window t) - (cl-decf count)) - (when (/= count 0) - (other-window count))))) - -;;;###autoload -(defalias 'other-popup #'doom/other-popup) - -;;;###autoload -(defun doom/popup-raise (&optional window) - "Turn a popup window into a normal window." - (interactive) - (let ((window (or window (selected-window)))) - (unless (doom-popup-p window) - (user-error "Not a valid popup to raise")) - (with-selected-window window - (doom-popup-mode -1)))) - -;;;###autoload -(defun doom/popup-move-top () "See `doom-popup-move'." (interactive) (doom-popup-move 'above)) -;;;###autoload -(defun doom/popup-move-bottom () "See `doom-popup-move'." (interactive) (doom-popup-move 'below)) -;;;###autoload -(defun doom/popup-move-left () "See `doom-popup-move'." (interactive) (doom-popup-move 'left)) -;;;###autoload -(defun doom/popup-move-right () "See `doom-popup-move'." (interactive) (doom-popup-move 'right)) - - -;; --- doom-popup-mode -------------------- - -;;;###autoload -(define-minor-mode doom-popup-mode - "Minor mode for popup windows." - :init-value nil - :keymap doom-popup-mode-map - (let ((window (selected-window))) - ;; If `doom-popup-rules' isn't set for some reason, try to set it - (setq-local doom-popup-rules (doom-popup-properties window)) - ;; Ensure that buffer-opening functions/commands (like - ;; `switch-to-buffer-other-window' won't use this window). - (set-window-parameter window 'no-other-window doom-popup-mode) - ;; Makes popup window resist interactively changing its buffer. - (unless (plist-get doom-popup-rules :same) - (set-window-dedicated-p window doom-popup-mode)) - (cond (doom-popup-mode - (when doom-popup-no-fringes - (set-window-fringes window 0 0 fringes-outside-margins)) - ;; 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 - (cl-loop for param in doom-popup-window-parameters - when (plist-get doom-popup-rules param) - do (set-window-parameter window param it)))) - - (t - (when doom-popup-no-fringes - (set-window-fringes window - doom-fringe-size doom-fringe-size - fringes-outside-margins)) - ;; Ensure window parameters are cleaned up - (set-window-parameter window 'popup nil) - (dolist (param doom-popup-window-parameters) - (set-window-parameter window param nil)))))) -(put 'doom-popup-mode 'permanent-local t) - -;;;###autoload -(defun doom|hide-modeline-in-popup () - "Don't show modeline in popup windows without a :modeline rule. If one exists -and it's a symbol, use `doom-modeline' to grab the format. If non-nil, show the -mode-line as normal. If nil (or omitted, by default), then hide the modeline -entirely." - (if doom-popup-mode - (let ((modeline (plist-get doom-popup-rules :modeline))) - (cond ((or (eq modeline 'nil) - (not modeline)) - (doom-hide-modeline-mode +1)) - ((and (symbolp modeline) - (not (eq modeline 't))) - (setq-local doom--modeline-format (doom-modeline modeline)) - (when doom--modeline-format - (doom-hide-modeline-mode +1))))) - (when doom-hide-modeline-mode - (doom-hide-modeline-mode -1)))) - - -;; --- Advice functions ------------------- - -;;;###autoload -(defun doom*shackle-always-align (plist) - "Ensure popups are always aligned and selected by default. Eliminates the need -for :align t on every rule." - (when plist - (unless (or (plist-member plist :align) - (plist-member plist :same) - (plist-member plist :frame)) - (plist-put plist :align t)) - (unless (or (plist-member plist :select) - (plist-member plist :noselect)) - (plist-put plist :select t))) - plist) - -;;;###autoload -(defun doom*popup-init (orig-fn &rest args) - "Initializes a window as a popup window by enabling `doom-popup-mode' in it -and setting `doom-popup-rules' within it. Returns the window." - (unless (doom-popup-p) - (setq doom-popup-other-window (selected-window))) - (let* ((target (car args)) - (plist (or (nth 2 args) - (cond ((windowp target) - (and (window-live-p target) - (shackle-match (window-buffer target)))) - ((bufferp target) - (and (buffer-live-p target) - (shackle-match target)))))) - (buffer (get-buffer target)) - (window-min-height (if (plist-get plist :modeline) 4 2)) - window) - (when (and (doom-real-buffer-p buffer) - (get-buffer-window-list buffer nil t)) - (setq plist (append (list :autokill t) plist)) - (setcar args (clone-indirect-buffer (buffer-name target) nil t))) - (unless (setq window (apply orig-fn args)) - (error "No popup window was found for %s: %s" target plist)) - (cl-pushnew window doom-popup-windows :test #'eq) - (with-selected-window window - (unless (eq plist t) - (setq-local doom-popup-rules plist)) - (doom-popup-mode +1) - (when (plist-get plist :autofit) - (doom-popup-fit-to-buffer window))) - window)) - -;;;###autoload -(defun doom*popups-save (orig-fn &rest args) - "Sets aside all popups before executing the original function, usually to -prevent the popup(s) from messing up the UI (or vice versa)." - (save-popups! (apply orig-fn args))) - -;;;###autoload -(defun doom*delete-popup-window (&optional window) - "Do popup bookkeeping before the popup window is deleted." - (unless window - (setq window (selected-window))) - (when (doom-popup-p window) - (setq doom-popup-windows (delq window doom-popup-windows)) - (when doom-popup-remember-history - (setq doom-popup-history (list (doom--popup-data window)))))) diff --git a/core/autoload/scratch.el b/core/autoload/scratch.el index b0bd510c5..acdca74a9 100644 --- a/core/autoload/scratch.el +++ b/core/autoload/scratch.el @@ -37,11 +37,11 @@ (current-buffer)))) ;;;###autoload -(defun doom/open-scratch-buffer () - "Opens a temporary scratch buffer in a popup window. It is discarded once it -is closed. If a region is active, copy it to the scratch buffer." - (interactive) - (doom-popup-buffer (doom--create-scratch-buffer))) +(defun doom/open-scratch-buffer (&optional in-project-p) + "Opens a temporary scratch buffer. It is discarded once it is closed. If a +region is active, copy it to the scratch buffer." + (interactive "P") + (pop-to-buffer (doom--create-scratch-buffer in-project-p))) ;;;###autoload (defun doom/open-project-scratch-buffer () @@ -49,5 +49,5 @@ is closed. If a region is active, copy it to the scratch buffer." popup window. Scratch buffers are stored in `doom-scratch-files-dir'. If a region is active, copy it to the scratch buffer." (interactive) - (doom-popup-buffer (doom--create-scratch-buffer t))) + (doom/open-scratch-buffer 'in-project)) diff --git a/core/core-popups.el b/core/core-popups.el deleted file mode 100644 index f9ef11bb4..000000000 --- a/core/core-popups.el +++ /dev/null @@ -1,544 +0,0 @@ -;;; core-popups.el -*- lexical-binding: t; -*- - -;; I want a "real"-buffer-first policy in my Emacsian utpoia; popup buffers -;; ought to be second-class citizens to "real" buffers. No need for a wall or -;; controversial immigration policies -- all we need is `shackle' (and it will -;; actually work). -;; -;; The gist is: popups should be displayed on one side of the frame, away from -;; 'real' buffers. They should be easy to dispose of when we don't want to see -;; them and easily brought back in case we change our minds. Also, popups should -;; typically have no mode-line. -;; -;; Be warned, this requires a lot of hackery voodoo that could break with an -;; emacs update or an update to any of the packages it tries to tame (like helm -;; or org-mode). - -(defvar doom-popup-history nil - "A list of popups that were last closed. Used by `doom/popup-restore' and -`doom*popups-save'.") - -(defvar doom-popup-other-window nil - "The last window selected before a popup was opened.") - -(defvar doom-popup-no-fringes t - "If non-nil, disable fringes in popup windows.") - -(defvar doom-popup-windows () - "A list of open popup windows.") - -(defvar-local doom-popup-rules nil - "The shackle rule that caused this buffer to be recognized as a popup. Don't -edit this directly.") -(put 'doom-popup-rules 'permanent-local t) - -(defvar doom-popup-window-parameters - '(:noesc :modeline :autokill :autoclose :autofit :static) - "A list of window parameters that are set (and cleared) when `doom-popup-mode -is enabled/disabled.'") - -(defvar doom-popup-remember-history t - "Don't modify this directly. If non-nil, DOOM will remember the last popup(s) -that was/were open in `doom-popup-history'.") - -(defvar doom-popup-inhibit-autokill nil - "Don't modify this directly. When it is non-nil, no buffers will be killed -when their associated popup windows are closed, despite their :autokill -property.") - -(defvar doom-popup-mode-map (make-sparse-keymap) - "Active keymap in popup windows.") - - -(def-setting! :popup (&rest rules) - "Prepend a new popup rule to `shackle-rules' (see for format details). - -Several custom properties have been added that are not part of shackle, but are -recognized by DOOM's popup system. They are: - -:noesc If non-nil, the popup won't be closed if you press ESC from *inside* - its window. Used by `doom/popup-close-maybe'. - -:modeline By default, mode-lines are hidden in popups unless this is non-nil. - If it is a symbol, it'll use `doom-modeline' to fetch a modeline - config (in `doom-popup-mode'). - -:autokill If non-nil, the popup's buffer will be killed when the popup is - closed. Used by `doom*delete-popup-window'. NOTE - `doom/popup-restore' can't restore non-file popups that have an - :autokill property. - -:autoclose If non-nil, close popup if ESC is pressed from outside the popup - window. - -:autofit If non-nil, resize the popup to fit its content. Uses the value of - the :size property as the maximum height/width. This will not work - if the popup has no content when displayed. - -:static If non-nil, don't treat this window like a popup. This makes it - impervious to being automatically closed or tracked in popup - history. Excellent for permanent sidebars." - (if (cl-every #'listp (mapcar #'doom-unquote rules)) - `(setq shackle-rules (nconc (list ,@rules) shackle-rules)) - `(push (list ,@rules) shackle-rules))) - - -;; -;; -;; - -;; (defvar doom-popup-parameters -;; '(:esc :modeline :transient :fit :align :size) -;; "TODO") - -;; (defvar doom-popup-whitelist -;; '(("^ ?\\*" :size 15 :noselect t :autokill t :autoclose t)) -;; "TODO") - -(defvar doom-popup-blacklist - '("^\\*magit") - "TODO") - - -;; -;; Bootstrap -;; - -(def-package! shackle - :init - (setq shackle-default-alignment 'below - shackle-default-size 8 - shackle-rules - '(("^\\*eww" :regexp t :size 0.5 :select t :autokill t :noesc t) - ("^\\*ftp " :noselect t :autokill t :noesc t) - ;; doom - ("^\\*doom:scratch" :regexp t :size 15 :noesc t :select t :modeline t :autokill t :static t) - ("^\\*doom:" :regexp t :size 0.35 :noesc t :select t) - ("^ ?\\*doom " :regexp t :noselect t :autokill t :autoclose t :autofit t) - ;; built-in (emacs) - ("*compilation*" :size 0.25 :noselect t :autokill t :autoclose t) - ("*ert*" :same t :modeline t) - ("*info*" :size 0.5 :select t :autokill t) - ("*Backtrace*" :size 20 :noselect t) - ("*Warnings*" :size 12 :noselect t :autofit t) - ("*Messages*" :size 12 :noselect t) - ("*Help*" :size 0.3 :autokill t) - ("^\\*.*Shell Command.*\\*$" :regexp t :size 20 :noselect t :autokill t) - (apropos-mode :size 0.3 :autokill t :autoclose t) - (Buffer-menu-mode :size 20 :autokill t) - (comint-mode :noesc t) - (grep-mode :size 25 :noselect t :autokill t) - (profiler-report-mode :size 0.3 :regexp t :autokill t :modeline minimal) - (tabulated-list-mode :noesc t) - ("^ ?\\*" :regexp t :size 15 :noselect t :autokill t :autoclose t))) - - :config - (add-hook 'doom-unreal-buffer-p #'doom-popup-p) - - ;; NOTE This is a temporary fix while I rewrite core-popups - (defun doom-display-buffer-condition (buffer _action) - (and (cl-loop for re in doom-popup-blacklist - when (string-match-p re buffer) - return nil - finally return t) - (shackle-match buffer))) - - (defun doom-display-buffer-action (buffer alist) - (shackle-display-buffer buffer alist (shackle-match buffer))) - - (defun doom|autokill-popups () - "TODO" - (or (not (doom-popup-p)) - (if (and (not doom-popup-inhibit-autokill) - (plist-get doom-popup-rules :autokill)) - (progn - (when-let* ((process (get-buffer-process (current-buffer)))) - (set-process-query-on-exit-flag process nil)) - t) - (doom-popup-mode -1) - (delete-window) - nil))) - - (defun doom|init-popups () - "TODO" - (setq display-buffer-alist - (cons '(doom-display-buffer-condition doom-display-buffer-action) - display-buffer-alist)) - ;; bootstrap popup system - (advice-add #'shackle-display-buffer :around #'doom*popup-init) - (advice-add #'balance-windows :around #'doom*popups-save) - (advice-add #'delete-window :before #'doom*delete-popup-window) - ;; ensure every rule without an :align, :same or :frame property has an - ;; implicit :align (see `shackle-default-alignment') - (advice-add #'shackle--match :filter-return #'doom*shackle-always-align) - ;; autokill popups with a non-nil :autokill property - (add-hook 'kill-buffer-query-functions #'doom|autokill-popups) - ;; no modeline in popups - (add-hook 'doom-popup-mode-hook #'doom|hide-modeline-in-popup) - ;; Tell `window-state-get' and `current-window-configuration' to recognize - ;; these custom parameters. Helpful for `persp-mode' and persisting window - ;; configs that have popups in them. - (dolist (param `(popup ,@doom-popup-window-parameters)) - (push (cons param 'writable) window-persistent-parameters))) - (add-hook 'doom-post-init-hook #'doom|init-popups) - - (let ((map doom-popup-mode-map)) - (define-key map [escape] #'doom/popup-close-maybe) - (define-key map (kbd "ESC") #'doom/popup-close-maybe) - (define-key map [remap quit-window] #'doom/popup-close-maybe) - (define-key map [remap kill-buffer] #'doom/popup-close) - (define-key map [remap split-window-right] #'ignore) - (define-key map [remap split-window-below] #'ignore) - (define-key map [remap split-window-horizontally] #'ignore) - (define-key map [remap split-window-vertically] #'ignore) - (define-key map [remap mouse-split-window-horizontally] #'ignore) - (define-key map [remap mouse-split-window-vertically] #'ignore))) - - -;; -;; Hacks -;; - -(progn ; hacks for built-in functions - (defun doom*suppress-pop-to-buffer-same-window (orig-fn &rest args) - (cl-letf (((symbol-function 'pop-to-buffer-same-window) - (symbol-function 'pop-to-buffer))) - (apply orig-fn args))) - (advice-add #'info :around #'doom*suppress-pop-to-buffer-same-window) - (advice-add #'eww :around #'doom*suppress-pop-to-buffer-same-window) - (advice-add #'eww-browse-url :around #'doom*suppress-pop-to-buffer-same-window) - - (defun doom*popup-buffer-menu (&optional arg) - "Open `buffer-menu' in a popup window." - (interactive "P") - (with-selected-window (doom-popup-buffer (list-buffers-noselect arg)) - (setq mode-line-format "Commands: d, s, x, u; f, o, 1, 2, m, v; ~, %; q to quit; ? for help."))) - (advice-add #'buffer-menu :override #'doom*popup-buffer-menu)) - - -(after! comint - (defun doom|popup-close-comint-buffer () - (when (and (doom-popup-p) - (derived-mode-p 'comint-mode) - (not (process-live-p (get-buffer-process (current-buffer))))) - (delete-window))) - (add-hook '+evil-esc-hook #'doom|popup-close-comint-buffer t)) - - -(after! eshell - ;; By tying buffer life to its process, we ensure that we land back in the - ;; eshell buffer after term dies. May cause problems with short-lived - ;; processes. - ;; FIXME replace with a 'kill buffer' keybinding. - (setq eshell-destroy-buffer-when-process-dies t) - - ;; When eshell runs a visual command (see `eshell-visual-commands'), it spawns - ;; a term buffer to run it in, but where it spawns it is the problem... - (defun doom*eshell-undedicate-popup (orig-fn &rest args) - "Force spawned term buffer to share with the eshell popup (if necessary)." - (when (doom-popup-p) - (set-window-dedicated-p nil nil) - (add-transient-hook! #'eshell-query-kill-processes :after - (set-window-dedicated-p nil t))) - (apply orig-fn args)) - (advice-add #'eshell-exec-visual :around #'doom*eshell-undedicate-popup)) - - -(after! evil - (let ((map doom-popup-mode-map)) - (define-key map [remap evil-window-delete] #'doom/popup-close-maybe) - (define-key map [remap evil-save-modified-and-close] #'doom/popup-close-maybe) - (define-key map [remap evil-window-move-very-bottom] #'doom/popup-move-bottom) - (define-key map [remap evil-window-move-very-top] #'doom/popup-move-top) - (define-key map [remap evil-window-move-far-left] #'doom/popup-move-left) - (define-key map [remap evil-window-move-far-right] #'doom/popup-move-right) - (define-key map [remap evil-window-split] #'ignore) - (define-key map [remap evil-window-vsplit] #'ignore)) - - (defun doom|popup-close-maybe () - "If current window is a popup, close it. If minibuffer is open, close it. If -not in a popup, close all popups with an :autoclose property." - (if (doom-popup-p) - (unless (doom-popup-property :noesc) - (delete-window)) - (doom/popup-close-all))) - (add-hook '+evil-esc-hook #'doom|popup-close-maybe t) - - ;; Make evil-mode cooperate with popups - (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-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." - (when (eq major-mode 'evil-command-window-mode) - (user-error "Cannot recursively open command line window")) - (dolist (win (window-list)) - (when (equal (buffer-name (window-buffer win)) - "*Command Line*") - (kill-buffer (window-buffer win)) - (delete-window win))) - (setq evil-command-window-current-buffer (current-buffer)) - (ignore-errors (kill-buffer "*Command Line*")) - (with-current-buffer (pop-to-buffer "*Command Line*") - (setq-local evil-command-window-execute-fn execute-fn) - (setq-local evil-command-window-cmd-key cmd-key) - (evil-command-window-mode) - (evil-command-window-insert-commands hist))) - - (defun doom*popup-evil-command-window-execute () - "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))) - (execute-fn evil-command-window-execute-fn) - (popup (selected-window))) - (select-window doom-popup-other-window) - (unless (equal evil-command-window-current-buffer (current-buffer)) - (user-error "Originating buffer is no longer active")) - ;; (kill-buffer "*Command Line*") - (doom/popup-close popup) - (funcall execute-fn result) - (setq evil-command-window-current-buffer nil))) - - ;; 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) - (window-in-direction (cond ((eq dir 'up) 'above) - ((eq dir 'down) 'below) - (t dir)) - window t arg windmove-wrap-around t)) - (advice-add #'windmove-find-other-window :override #'doom*ignore-window-parameters-in-popups)) - - -(after! helm - ;; Helm tries to clean up after itself, but shackle has already done this, - ;; causing problems. This fixes that. To reproduce, add a helm rule in - ;; `shackle-rules', open two splits side-by-side, move to the buffer on the - ;; right and invoke helm. It will close all but the left-most buffer. - (setq-default helm-reuse-last-window-split-state t - helm-split-window-in-side-p t) - - (after! helm-swoop - (setq helm-swoop-split-window-function #'pop-to-buffer)) - - (after! helm-ag - ;; This prevents helm-ag from switching between windows and buffers. - (defun doom*helm-ag-edit-done (orig-fn &rest args) - (cl-letf (((symbol-function 'select-window) #'ignore)) - (apply orig-fn args)) - (doom/popup-close)) - (advice-add #'helm-ag--edit-commit :around #'doom*helm-ag-edit-done) - (advice-add #'helm-ag--edit-abort :around #'doom*helm-ag-edit-done) - - (defun doom*helm-ag-edit (orig-fn &rest args) - (cl-letf (((symbol-function 'other-window) #'ignore) - ((symbol-function 'switch-to-buffer) #'doom-popup-buffer)) - (apply orig-fn args) - (with-current-buffer (get-buffer "*helm-ag-edit*") - (use-local-map helm-ag-edit-map)))) - (advice-add #'helm-ag--edit :around #'doom*helm-ag-edit))) - - -(defsubst doom--switch-from-popup (location) - (doom/popup-close) - (switch-to-buffer (car location) nil t) - (if (not (cdr location)) - (message "Unable to find location in file") - (goto-char (cdr location)) - (recenter))) - -(after! help-mode - ;; Help buffers use `other-window' to decide where to open followed links, - ;; which can be unpredictable. It should *only* replace the original buffer we - ;; opened the popup from. To fix this these three button types need to be - ;; redefined to set aside the popup before following a link. - (define-button-type 'help-function-def - :supertype 'help-xref - 'help-function - (lambda (fun file) - (require 'find-func) - (when (eq file 'C-source) - (setq file (help-C-file-name (indirect-function fun) 'fun))) - (doom--switch-from-popup (find-function-search-for-symbol fun nil file)))) - - (define-button-type 'help-variable-def - :supertype 'help-xref - 'help-function - (lambda (var &optional file) - (when (eq file 'C-source) - (setq file (help-C-file-name var 'var))) - (doom--switch-from-popup (find-variable-noselect var file)))) - - (define-button-type 'help-face-def - :supertype 'help-xref - 'help-function - (lambda (fun file) - (require 'find-func) - (doom--switch-from-popup (find-function-search-for-symbol fun 'defface file))))) - - -(after! magit - (add-hook 'magit-mode-hook #'doom-hide-modeline-mode)) - - -(after! mu4e - (defun doom*mu4e-popup-window (buf _height) - (doom-popup-buffer buf '(:size 10 :noselect t)) - buf) - (advice-add #'mu4e~temp-window :override #'doom*mu4e-popup-window)) - - -(after! multi-term - (setq multi-term-buffer-name "doom:terminal")) - - -(after! neotree - ;; Neotree has its own window/popup management built-in, which is difficult to - ;; police. For example, switching perspectives will cause neotree to forget it - ;; is a neotree pane. - ;; - ;; By handing neotree over to shackle, which is better integrated into the - ;; rest of my config (and persp-mode), this is no longer a problem. - (set! :popup " *NeoTree*" :align neo-window-position :size neo-window-width :static t) - - (defun +evil-neotree-display-fn (buf _alist) - "Hand neotree off to shackle." - (let ((win (doom-popup-buffer buf))) - (setq neo-global--buffer (window-buffer win) - neo-global--window win))) - (setq neo-display-action '(+evil-neotree-display-fn)) - - (defun +evil|neotree-fix-popup () - "Repair neotree state whenever its popup state is restored. This ensures -that `doom*popup-save' won't break it." - (when (equal (buffer-name) neo-buffer-name) - (setq neo-global--window (selected-window)) - ;; Fix neotree shrinking when closing nearby vertical splits - (when neo-window-fixed-size - (doom-resize-window neo-global--window neo-window-width t t)))) - (add-hook 'doom-popup-mode-hook #'+evil|neotree-fix-popup)) - - -(after! persp-mode - (defun doom*persp-mode-restore-popups (&rest _) - "Restore popup windows when loading a perspective from file." - (dolist (window (window-list)) - (when-let* ((plist (doom-popup-properties window))) - (with-selected-window window - (unless doom-popup-mode - (setq-local doom-popup-rules plist) - (doom-popup-mode +1)))))) - (advice-add #'persp-load-state-from-file :after #'doom*persp-mode-restore-popups)) - - -(after! quickrun - ;; don't auto-focus quickrun windows, shackle handles that - (setq quickrun-focus-p nil)) - - -(after! twittering-mode - (setq twittering-pop-to-buffer-function #'pop-to-buffer)) - - -(after! wgrep - ;; close the popup after you're done with a wgrep buffer - (advice-add #'wgrep-abort-changes :after #'doom/popup-close) - (advice-add #'wgrep-finish-edit :after #'doom/popup-close)) - - -(after! xref - (defun doom*xref-follow-and-close (orig-fn &rest args) - "Jump to the xref on the current line, select its window and close the popup -you came from." - (interactive) - (let ((popup-p (doom-popup-p)) - (window (selected-window))) - (apply orig-fn args) - (when popup-p (doom/popup-close window)))) - (advice-add #'xref-goto-xref :around #'doom*xref-follow-and-close)) - - -;; -;; Major modes -;; - -(after! plantuml-mode - (defun doom*plantuml-preview-in-popup-window (orig-fn &rest args) - (save-window-excursion - (apply orig-fn args)) - (pop-to-buffer plantuml-preview-buffer)) - (advice-add #'plantuml-preview-string - :around #'doom*plantuml-preview-in-popup-window)) - -;; Ensure these settings are loaded as late as possible, giving other modules a -;; chance to reconfigure org popup settings before the defaults kick in. -(defun doom|init-org-popups () - (add-hook! org-load - (set! :popup - '("*Calendar*" :size 0.4 :noselect t) - '(" *Org todo*" :size 5 :noselect t) - '("*Org Note*" :size 10) - '("*Org Select*" :size 20 :noselect t) - '("*Org Links*" :size 5 :noselect t) - '("*Org Export Dispatcher*" :noselect t) - '(" *Agenda Commands*" :noselect t) - '("^\\*Org Agenda" :regexp t :size 20) - '("*Org Clock*" :noselect t) - '("^\\*Org Src" :regexp t :size 0.35 :noesc t) - '("*Edit Formulas*" :size 10) - '("^\\*Org-Babel" :regexp t :size 25 :noselect t) - '("^CAPTURE.*\\.org$" :regexp t :size 20)) - - ;; Org has a scorched-earth window management system I'm not fond of. i.e. - ;; it kills all windows and monopolizes the frame. No thanks. We can do - ;; better with shackle's help. - (defun doom*suppress-delete-other-windows (orig-fn &rest args) - (cl-letf (((symbol-function 'delete-other-windows) - (symbol-function 'ignore))) - (apply orig-fn args))) - (advice-add #'org-add-log-note :around #'doom*suppress-delete-other-windows) - (advice-add #'org-capture-place-template :around #'doom*suppress-delete-other-windows) - (advice-add #'org-export--dispatch-ui :around #'doom*suppress-delete-other-windows) - - ;; Hand off the src-block window to a shackle popup window. - (defun doom*org-src-pop-to-buffer (buffer _context) - "Open the src-edit in a way that shackle can detect." - (if (eq org-src-window-setup 'switch-invisibly) - (set-buffer buffer) - (pop-to-buffer buffer))) - (advice-add #'org-src-switch-to-buffer :override #'doom*org-src-pop-to-buffer) - - ;; Ensure todo, agenda, and other minor popups are delegated to shackle. - (defun doom*org-pop-to-buffer (&rest args) - "Use `pop-to-buffer' instead of `switch-to-buffer' to open buffer.'" - (let ((buf (car args))) - (pop-to-buffer - (cond ((stringp buf) (get-buffer-create buf)) - ((bufferp buf) buf) - (t (error "Invalid buffer %s" buf)))))) - (advice-add #'org-switch-to-buffer-other-window :override #'doom*org-pop-to-buffer) - - ;; org-agenda - (setq org-agenda-window-setup 'other-window - org-agenda-restore-windows-after-quit nil) - ;; Hide modeline in org-agenda - (add-hook 'org-agenda-finalize-hook #'doom-hide-modeline-mode) - (add-hook 'org-agenda-finalize-hook #'org-fit-window-to-buffer) - ;; Don't monopolize frame! - (advice-add #'org-agenda :around #'doom*suppress-delete-other-windows) - ;; ensure quit keybindings work propertly - (map! :map* org-agenda-mode-map - :m [escape] 'org-agenda-Quit - :m "ESC" 'org-agenda-Quit))) -(add-hook 'doom-init-hook #'doom|init-org-popups) - -(provide 'core-popups) -;;; core-popups.el ends here diff --git a/core/core.el b/core/core.el index 2372c20f9..c61b84233 100644 --- a/core/core.el +++ b/core/core.el @@ -172,7 +172,6 @@ ability to invoke the debugger in debug mode." (unless noninteractive (load! core-ui) ; draw me like one of your French editors - (load! core-popups) ; taming sudden yet inevitable windows (load! core-editor) ; baseline configuration for text editing (load! core-projects) ; making Emacs project-aware (load! core-keybinds)) ; centralized keybind system + which-key diff --git a/init.example.el b/init.example.el index 9cdb36e6c..5de1a7e19 100644 --- a/init.example.el +++ b/init.example.el @@ -30,6 +30,7 @@ (require 'core (concat user-emacs-directory "core/core")) (doom! :feature + popup ; tame sudden yet inevitable temporary windows ;debugger ; FIXME stepping through code, to help you add bugs eval ; run code, run (also, repls) evil ; come to the dark side, we have cookies diff --git a/modules/app/regex/config.el b/modules/app/regex/config.el index cc073013b..64ebebd1a 100644 --- a/modules/app/regex/config.el +++ b/modules/app/regex/config.el @@ -46,7 +46,6 @@ http://regexr.com/foo.html?q=bar https://mediatemple.net" "TODO") -(set! :popup - '("*doom-regex*" :size 4 :select t :noesc t) - '("*doom-regex-groups*" :align left :size 30 :noselect t :noesc t)) +(set! :popup "^\\*doom-regex\\*$" '((size . 4)) '((escape-quit))) +(set! :popup "^\\*doom-regex-groups" '((side . left)) '((select) (escape-quit))) diff --git a/modules/app/twitter/config.el b/modules/app/twitter/config.el index 23aef2356..12385631d 100644 --- a/modules/app/twitter/config.el +++ b/modules/app/twitter/config.el @@ -16,8 +16,6 @@ twittering-initial-timeline-spec-string '(":home" ":mentions" ":direct_messages")) - (set! :popup "*twittering-edit*" :size 12 :select t) - (add-hook! twittering-mode (setq header-line-format (or (doom-modeline 'twitter) mode-line-format) mode-line-format nil)) diff --git a/modules/completion/helm/config.el b/modules/completion/helm/config.el index 116c49c63..a247cc1f2 100644 --- a/modules/completion/helm/config.el +++ b/modules/completion/helm/config.el @@ -42,7 +42,6 @@ (after! helm-mode (add-to-list 'helm-completing-read-handlers-alist '(find-file-at-point . nil))) - (set! :popup "\\` ?\\*[hH]elm.*?\\*\\'" :size 14 :regexp t) (setq projectile-completion-system 'helm) ;;; Helm hacks diff --git a/modules/completion/ivy/config.el b/modules/completion/ivy/config.el index 7ac6ba1b9..139a7dbf0 100644 --- a/modules/completion/ivy/config.el +++ b/modules/completion/ivy/config.el @@ -84,7 +84,6 @@ immediately runs it on the current candidate (ending the ivy session)." (setq counsel-find-file-ignore-regexp "\\(?:^[#.]\\)\\|\\(?:[#~]$\\)\\|\\(?:^Icon?\\)") ;; Configure `counsel-rg', `counsel-ag' & `counsel-pt' - (set! :popup 'ivy-occur-grep-mode :size (+ 2 ivy-height) :regexp t :autokill t) (dolist (cmd '(counsel-ag counsel-rg counsel-pt)) (ivy-add-actions cmd diff --git a/modules/feature/debugger/config.el b/modules/feature/debugger/config.el index 384975d2f..1b7ef587d 100644 --- a/modules/feature/debugger/config.el +++ b/modules/feature/debugger/config.el @@ -3,9 +3,7 @@ (def-package! realgud :commands (realgud:gdb realgud:trepanjs realgud:bashdb realgud:zshdb) :config - (set! :popup - '("^\\*\\(g\\|zsh\\|bash\\)db.*?\\*$" :size 20 :regexp t) - '("^\\*trepanjs.*?\\*$" :size 20 :regexp t)) + (set! :popup "^\\*\\(?trepanjs:\\(?:g\\|zsh\\|bash\\)db\\)" '((size . 20))) ;; TODO Temporary Ex commands for the debugger ;; (def-tmp-excmd! doom:def-debug-on doom:def-debug-off diff --git a/modules/feature/eval/config.el b/modules/feature/eval/config.el index ba954353c..00b2526ed 100644 --- a/modules/feature/eval/config.el +++ b/modules/feature/eval/config.el @@ -16,10 +16,6 @@ function that creates and returns the REPL buffer." `(push (cons ,mode ,command) +eval-repls)) -(set! :popup - '(:custom (lambda (b &rest _) (buffer-local-value '+eval-repl-mode b))) - :size 16 :noesc t) - ;; ;; Evaluation @@ -70,7 +66,8 @@ function that creates and returns the REPL buffer." (unless (boundp 'display-line-numbers) (add-hook 'quickrun--mode-hook #'nlinum-mode)) :config - (set! :popup "*quickrun*" :size 6 :autokill t :autoclose t) + (set! :popup "^\\*\\(?:doom eval\\|Pp Eval Output\\|quickrun\\)" + '((window-height . 10)) '((transient . 0))) (defun +eval*quickrun-auto-close (&rest _) "Allows us to silently re-run quickrun from within the quickrun buffer." diff --git a/modules/feature/evil/autoload/evil.el b/modules/feature/evil/autoload/evil.el index 7e1d6d773..893cf10bc 100644 --- a/modules/feature/evil/autoload/evil.el +++ b/modules/feature/evil/autoload/evil.el @@ -32,14 +32,14 @@ there and there is only one window, split in that direction and place this window there. If there are no windows and this isn't the only window, use evil-window-move-* (e.g. `evil-window-move-far-left')" - (when (doom-popup-p) - (doom/popup-raise)) - (let* ((this-window (get-buffer-window)) + (when (window-dedicated-p) + (user-error "Cannot swap a dedicated window")) + (let* ((this-window (selected-window)) (this-buffer (current-buffer)) (that-window (windmove-find-other-window direction nil this-window)) (that-buffer (window-buffer that-window))) (when (or (minibufferp that-buffer) - (doom-popup-p that-window)) + (window-dedicated-p this-window)) (setq that-buffer nil that-window nil)) (if (not (or that-window (one-window-p t))) (funcall (pcase direction diff --git a/modules/feature/evil/config.el b/modules/feature/evil/config.el index bf0efc808..3c538f20f 100644 --- a/modules/feature/evil/config.el +++ b/modules/feature/evil/config.el @@ -42,9 +42,8 @@ (add-hook 'doom-init-hook #'evil-mode) (evil-select-search-module 'evil-search-module 'evil-search) - (set! :popup - '("*evil-registers*" :size 0.3) - '("*Command Line*" :size 8)) + (set! :popup "^\\*evil-registers" '((size . 0.3))) + (set! :popup "^\\*Command Line" '((size . 8))) ;; Don't interfere with localleader key (define-key evil-motion-state-map "\\" nil) diff --git a/modules/feature/lookup/config.el b/modules/feature/lookup/config.el index b51032a28..6ab555868 100644 --- a/modules/feature/lookup/config.el +++ b/modules/feature/lookup/config.el @@ -91,8 +91,7 @@ properties: (after! xref ;; By default, `etags--xref-backend' is the default xref backend. No need. ;; We'll set these up ourselves in other modules. - (setq-default xref-backend-functions '(t)) - (set! :popup "*xref*" :noselect t :autokill t :autoclose t)) + (setq-default xref-backend-functions '(t))) (defun +lookup|init-xref-backends () "Set `+lookup-current-functions' for the current buffer. diff --git a/modules/feature/popup/README.org b/modules/feature/popup/README.org new file mode 100644 index 000000000..69dbd236a --- /dev/null +++ b/modules/feature/popup/README.org @@ -0,0 +1,49 @@ +#+TITLE: :feature popup + +A short summary about what this module does. + +If necessary, include a longer description below it that goes into more detail. This may be as long as you like. + ++ If possible, include a list of features ++ Include links to major plugins that the module uses, if applicable ++ Use links whenever you can ++ Mention dependencies on other modules here + +* Table of Contents :TOC: +- [[#install][Install]] + - [[#main-dependencies][Main dependencies]] + - [[#extra-dependencies][Extra Dependencies]] +- [[#configuration][Configuration]] +- [[#usage][Usage]] +- [[#appendix][Appendix]] + - [[#commands][Commands]] + - [[#hacks][Hacks]] + +* Install +** Main dependencies +*** MacOS +#+BEGIN_SRC sh :tangle (if (doom-system-os 'macos) "yes") +brew install x +#+END_SRC + +*** Arch Linux +#+BEGIN_SRC sh :dir /sudo:: :tangle (if (doom-system-os 'arch) "yes") +sudo pacman --needed --noconfirm -S X +#+END_SRC + +** Extra Dependencies ++ A ++ B ++ C + +#+BEGIN_SRC sh +Y install A B C +#+END_SRC + +* Configuration + +* Usage + +* Appendix +** Commands +** Hacks diff --git a/modules/feature/popup/autoload.el b/modules/feature/popup/autoload.el new file mode 100644 index 000000000..c0de798f0 --- /dev/null +++ b/modules/feature/popup/autoload.el @@ -0,0 +1,328 @@ +;;; feature/popup/autoload.el -*- lexical-binding: t; -*- + +(defun +popup--cancel-buffer-timer () + "Cancel the current buffer's transient timer." + (when (timerp +popup--timer) + (message "Cancelled timer") + (cancel-timer +popup--timer) + (setq +popup--timer nil)) + t) + +(defun +popup--remember (windows) + "Remember WINDOWS (a list of windows) for later restoration." + (cl-assert (cl-every #'windowp windows) t) + (setq +popup--last + (cl-loop for w in windows + collect (list (window-buffer w) + (window-parameter w 'alist) + (window-state-get w))))) + +(defun +popup--kill-buffer (buffer) + "Tries to kill BUFFER, as was requested by a transient timer. If it fails, eg. +the buffer is visible, then set another timer and try again later." + (when (buffer-live-p buffer) + (if (get-buffer-window buffer) + (with-current-buffer buffer + (setq +popup--timer + (run-at-time (timer--time +popup--timer) + nil #'+popup--kill-buffer buffer))) + (with-demoted-errors "Error killing transient buffer: %s" + (let ((inhibit-message (not doom-debug-mode))) + (message "Cleaned up transient buffer: %s" buffer)) + (kill-buffer buffer))))) + +(defun +popup--init (window alist) + "Initializes a popup window. Run any time a popup is opened. It sets the +default window parameters for popup windows, clears leftover transient timers +and enables `+popup-buffer-mode'." + (with-selected-window window + (set-window-parameter window 'no-other-window t) + (set-window-parameter window 'delete-window #'+popup--destroy) + (set-window-parameter window 'alist alist) + (window-preserve-size + window (memq (window-parameter window 'window-side) '(left right)) t) + (+popup--cancel-buffer-timer) + (+popup-buffer-mode +1))) + +(defun +popup--destroy (window) + "Do housekeeping before destroying a popup window. + ++ Disables `+popup-buffer-mode' so that any hooks attached to it get a chance to + run and do cleanup of its own. ++ Either kills the buffer or sets a transient timer, if the window has a + `transient' window parameter (see `+popup-window-parameters'). ++ And finally deletes the window!" + (let ((ttl (+popup-parameter 'transient window)) + (buffer (window-buffer window))) + (let ((ignore-window-parameters t)) + (delete-window window)) + (unless (window-live-p window) + (with-current-buffer buffer + (+popup-buffer-mode -1) + ;; t = default + ;; integer = ttl + ;; nil = no timer + (when ttl + (when (eq ttl t) + (setq ttl +popup-ttl)) + (cl-assert (integerp ttl) t) + (if (= ttl 0) + (+popup--kill-buffer buffer) + (setq +popup--timer + (run-at-time ttl nil #'+popup--kill-buffer buffer)))))))) + +(defun +popup--normalize-alist (alist) + "Merge `+popup-default-alist' and `+popup-default-parameters' with ALIST." + (if (not alist) + (setq alist +popup-default-alist) + (let* ((alist (map-merge 'list +popup-default-alist alist)) + (params (map-merge 'list + +popup-default-parameters + (cdr (assq 'window-parameters alist))))) + (setq alist (assq-delete-all 'window-parameters alist)) + (push (cons 'window-parameters params) alist) + (nreverse alist)))) + + +;; +;; Public library +;; + +;;;###autoload +(defun +popup-p (&optional target) + "Return t if TARGET is a popup window or buffer. If TARGET is nil, use the +current buffer." + (unless target + (setq target (current-buffer))) + (cond ((windowp target) + (+popup-p (window-buffer target))) + ((bufferp target) + (buffer-local-value '+popup-buffer-mode target)) + (t + (error "Expected a window/buffer, got %s (%s)" + (type-of target) target)))) + +;;;###autoload +(defun +popup-buffer (buffer &optional alist) + "Open BUFFER in a popup window. ALIST describes its features." + (let* ((old-window (selected-window)) + (alist (+popup--normalize-alist alist)) + (new-window (or (display-buffer-reuse-window buffer alist) + (display-buffer-in-side-window buffer alist)))) + (+popup--init new-window alist) + (select-window + (if (+popup-parameter 'select new-window) + new-window + old-window)) + new-window)) + +;;;###autoload +(defun +popup-parameter (parameter &optional window) + "Fetch the window parameter of WINDOW" + (window-parameter (or window (selected-window)) parameter)) + +;;;###autoload +(defun +popup-windows () + "Returns a list of all popup windows." + (cl-remove-if-not #'+popup-p (window-list))) + + +;; +;; Minor mode +;; + +;;;###autoload +(define-minor-mode +popup-mode + "Global minor mode for popups." + :init-value nil + :global t + :keymap +popup-mode-map + (cond (+popup-mode + (add-hook 'doom-unreal-buffer-functions #'+popup-p) + (add-hook '+evil-esc-hook #'+popup|close-on-escape t) + (setq +popup--old-display-buffer-alist display-buffer-alist + display-buffer-alist +popup--display-buffer-alist) + (dolist (prop +popup-window-parameters) + (push (cons prop 'writeable) window-persistent-parameters))) + (t + (remove-hook 'doom-unreal-buffer-functions #'+popup-p) + (remove-hook '+evil-esc-hook #'+popup|close-on-escape) + (setq display-buffer-alist +popup--old-display-buffer-alist) + (dolist (prop +popup-window-parameters) + (assq-delete-all prop window-persistent-parameters))))) + +;;;###autoload +(define-minor-mode +popup-buffer-mode + "Minor mode for popup windows." + :init-value nil + :keymap +popup-buffer-mode-map) + + +;; +;; Hooks +;; + +;;;###autoload +(defun +popup|adjust-fringes () + "Hides the fringe in popup windows, restoring them if `+popup-buffer-mode' is +disabled." + (let ((f (if +popup-buffer-mode 0 doom-fringe-size))) + (set-window-fringes nil f f fringes-outside-margins))) + +;;;###autoload +(defun +popup|set-modeline () + "Don't show modeline in popup windows without a `modeline' window-parameter. + ++ If one exists and it's a symbol, use `doom-modeline' to grab the format. ++ If non-nil, show the mode-line as normal. ++ If nil (or omitted), then hide the modeline entirely (the default)." + (if +popup-buffer-mode + (let ((modeline (+popup-parameter 'modeline))) + (cond ((or (eq modeline 'nil) + (not modeline)) + (doom-hide-modeline-mode +1)) + ((and (symbolp modeline) + (not (eq modeline 't))) + (setq-local doom--modeline-format (doom-modeline modeline)) + (when doom--modeline-format + (doom-hide-modeline-mode +1))))) + (when doom-hide-modeline-mode + (doom-hide-modeline-mode -1)))) + +;;;###autoload +(defun +popup|close-on-escape () + "If called inside a popup, try to close that popup window (see +`+popup/close'). If called outside, try to close all popup windows (see +`+popup/close-all')." + (call-interactively + (if (+popup-p) + #'+popup/close + #'+popup/close-all))) + + +;; +;; Commands +;; + +;;;###autoload +(defalias 'other-popup #'+popup/other) + +;;;###autoload +(defun +popup/other () + "Cycle through popup windows, like `other-window'. Ignores regular windows." + (interactive) + (let ((popups (+popup-windows)) + (window (selected-window))) + (unless popups + (user-error "No popups are open")) + (select-window (if (+popup-p) + (or (car-safe (cdr (memq window popups))) + (car (delq window popups)) + (car popups)) + (car popups))))) + +;;;###autoload +(defun +popup/close (&optional window force-p) + "Close WINDOW, if it's a popup window. + +This will do nothing if the popup's `escape-quit' window parameter is either nil +or 'other. This window parameter is ignored if FORCE-P is non-nil." + (interactive + (list (selected-window) + current-prefix-arg)) + (unless window + (setq window (selected-window))) + (when (and (+popup-p window) + (or force-p + (memq (+popup-parameter 'escape-quit window) + '(t current)))) + (when +popup--remember-last + (+popup--remember (list window))) + (delete-window window) + t)) + +;;;###autoload +(defun +popup/close-all (&optional force-p) + "Close all open popup windows. + +This will ignore popups with an `escape-quit' parameter that is either nil or +'current. This window parameter is ignored if FORCE-P is non-nil." + (interactive "P") + (let (targets +popup--remember-last) + (dolist (window (+popup-windows)) + (when (or force-p + (memq (+popup-parameter 'escape-quit window) + '(t other))) + (push window targets))) + (when targets + (+popup--remember targets) + (mapc #'delete-window targets) + t))) + +;;;###autoload +(defun +popup/toggle () + "If popups are open, close them. If they aren't, restore the last one or open +the message buffer in a popup window." + (interactive) + (cond ((+popup-windows) + (+popup/close-all)) + ((ignore-errors (+popup/restore))) + ((display-buffer (get-buffer "*Messages*"))))) + +;;;###autoload +(defun +popup/restore () + "Restore the last popups that were closed, if any." + (interactive) + (unless +popup--last + (error "No popups to restore")) + (cl-loop for (buffer alist state) in +popup--last + if (and (buffer-live-p buffer) + (+popup-buffer buffer alist)) + do (window-state-put state it)) + (setq +popup--last nil)) + +;;;###autoload +(defun +popup/raise () + "Raise the current popup window into a regular window." + (interactive) + (unless (+popup-p) + (user-error "Cannot raise a non-popup window")) + (let ((window (selected-window)) + (buffer (current-buffer)) + +popup--remember-last) + (set-window-parameter window 'transient nil) + (+popup/close window 'force) + (display-buffer-pop-up-window buffer nil))) + + +;; +;; Macros +;; + +;;;###autoload +(defmacro without-popups! (&rest body) + "Run BODY with a default `display-buffer-alist', ignoring the popup rules set +with the :popup setting." + `(let ((display-buffer-alist +popup--old-display-buffer-alist)) + ,@body)) + +;;;###autoload +(defmacro save-popups! (&rest body) + "Sets aside all popups before executing the original function, usually to +prevent the popup(s) from messing up the UI (or vice versa)." + `(let* ((in-popup-p (+popup-p)) + (popups (+popup-windows)) + (popup-states + (cl-loop for p in popups + collect (cons (window-buffer p) (window-state-get p)))) + +popup--last) + (dolist (p popups) + (+popup/close p 'force)) + (unwind-protect + (progn ,@body) + (when popups + (let ((origin (selected-window))) + (+popup/restore) + (unless in-popup-p + (select-window origin))))))) + diff --git a/modules/feature/popup/config.el b/modules/feature/popup/config.el new file mode 100644 index 000000000..482281c0a --- /dev/null +++ b/modules/feature/popup/config.el @@ -0,0 +1,196 @@ +;;; config.el -*- lexical-binding: t; -*- + +(defconst +popup-window-parameters + '(transient escape-quit select modeline alist) + "A list of custom parameters to be added to `window-persistent-parameters'. +Modifying this has no effect, unless done before feature/popup loads. + +(transient . CDR) + CDR can be t, an integer or nil. It represents the number of seconds before + the buffer belonging to a closed popup window is killed. + + If t, CDR will default to `+popup-ttl'. + If 0, the buffer is immediately killed. + If nil, the buffer won't be killed. + +(escape-quit . CDR) + CDR can be t, 'other, 'current or nil. This determines the behavior of the + escape key in or outside of popup windows. + + If t, close the popup if escape is pressed inside or outside of popups. + If 'other, close this popup if escape is pressed outside of any popup. This is + great for popups you just want to peek at and discard. + If 'current, close the current popup if escape is pressed from inside of + the popup. + If nil, pressing escape will never close this buffer. + +(select . BOOl) + CDR is a boolean that determines whether to focus the popup window after it + opens. + +(modeline . CDR) + CDR can be t (show the default modeline), a symbol representing the name of a + modeline defined with `def-modeline!', or nil (show no modeline). + +(alist . CDR) + This is an internal parameter and should not be set or modified. + +Since I can't find this information anywhere but the Emacs manual, I'll include +a brief description of some native window parameters that Emacs uses: + +(delete-window . CDR) +(delete-other-window . CDR) +(split-window . CDR) +(other-window . CDR) + This applies to all four of the above: CDR can be t or a function. If t, using + those functions on this window will ignore all window parameters. + + If CDR is a function, it will replace the native function when used on this + window. e.g. if CDR is #'ignore (delete-window popup) will run (ignore popup) + instead of deleting the window! +(no-other-window . BOOL) + If CDR is non-nil, this window becomes invisible to `other-window' and + `pop-to-buffer'. Doom popups sets this. The default is nil.") + +(defvar +popup-default-alist + '((slot . 1) + (window-height . 0.14) + (window-width . 26) + (reusable-frames . visible)) + "The default alist for `display-buffer-alist' rules.") + +(defvar +popup-default-parameters + '((transient . t) + (escape-quit . t)) + "The default window parameters to add alists fed to `display-buffer-alist'.") + +(defvar +popup-ttl 10 + "The default time-to-live for transient buffers whose popup buffers have been +deleted.") + +(defvar +popup-mode-map (make-sparse-keymap) + "Active keymap in a session with the popup system enabled. See +`+popup-mode'.") + +(defvar +popup-buffer-mode-map (make-sparse-keymap) + "Active keymap in popup windows. See `+popup-buffer-mode'.") + + +(defvar +popup--display-buffer-alist nil) +(defvar +popup--old-display-buffer-alist nil) +(defvar +popup--remember-last t) +(defvar +popup--last nil) +(defvar-local +popup--timer nil) + + +;; +(def-setting! :popup (condition &optional alist parameters) + "Register a popup rule. + +CONDITION can be a regexp string or a function. See `display-buffer' for a list +of possible entries for ALIST, which tells the display system how to initialize +the popup window. PARAMETERS is an alist of window parameters. See +`+popup-window-parameters' for a list of custom parameters provided by the popup +module." + `(let ((alist ,alist) + (parameters ,parameters)) + ,(when alist + '(when-let* ((size (cdr (assq 'size alist)))) + (setq alist (assq-delete-all 'size alist)) + (push (cons (pcase (cdr (or (assq 'side alist) + (assq 'side +popup-default-alist))) + ((or `left `right) 'window-width) + (_ 'window-height)) + size) + alist))) + (prog1 (push (append (list ,condition '(+popup-buffer)) + alist + (list (cons 'window-parameters parameters))) + +popup--display-buffer-alist) + (when (bound-and-true-p +popup-mode) + (setq display-buffer-alist +popup--display-buffer-alist))))) + + +;; +;; Default popup rules & bootstrap +;; + +(eval-when-compile + (set! :popup "^ \\*") + (set! :popup "^\\*" nil '((select . t))) + (set! :popup "^\\*\\(?:scratch\\|Messages\\)" nil '((transient))) + (set! :popup "^\\*Help" + '((window-height . 0.2)) + '((select . t))) + (set! :+popup "^\\*doom:" + '((window-height . 0.35)) + '((select . t) (escape-quit) (transient)))) + +(setq +popup--display-buffer-alist (eval-when-compile +popup--display-buffer-alist)) +(add-hook 'doom-init-ui-hook #'+popup-mode) + +(add-hook '+popup-buffer-mode-hook #'+popup|adjust-fringes) +(add-hook '+popup-buffer-mode-hook #'+popup|set-modeline) + + +;; +;; Hacks +;; + +(defun doom*ignore-window-parameters (orig-fn &rest args) + "Allow *interactive* window moving commands to traverse popups." + (cl-letf (((symbol-function #'windmove-find-other-window) + (lambda (direction &optional window ignore sign wrap mini) + (window-in-direction + (pcase dir (`up 'above) (`down 'below) (_ dir)) + window (bound-and-true-p +popup-mode) arg windmove-wrap-around t)))) + (apply orig-fn args))) +(advice-add #'windmove-up :around #'doom*ignore-window-parameters) +(advice-add #'windmove-down :around #'doom*ignore-window-parameters) +(advice-add #'windmove-left :around #'doom*ignore-window-parameters) +(advice-add #'windmove-right :around #'doom*ignore-window-parameters) + + +(after! help-mode + (defun doom--switch-from-popup (location) + (let (origin) + (save-popups! + (switch-to-buffer (car location) nil t) + (if (not (cdr location)) + (message "Unable to find location in file") + (goto-char (cdr location)) + (recenter) + (setq origin (selected-window)))) + (+popup/close) + (select-window origin))) + + ;; Help buffers use `pop-to-window' to decide where to open followed links, + ;; which can be unpredictable. It should *only* replace the original buffer we + ;; opened the popup from. To fix this these three button types need to be + ;; redefined to set aside the popup before following a link. + (define-button-type 'help-function-def + :supertype 'help-xref + 'help-function + (lambda (fun file) + (require 'find-func) + (when (eq file 'C-source) + (setq file (help-C-file-name (indirect-function fun) 'fun))) + (doom--switch-from-popup (find-function-search-for-symbol fun nil file)))) + + (define-button-type 'help-variable-def + :supertype 'help-xref + 'help-function + (lambda (var &optional file) + (when (eq file 'C-source) + (setq file (help-C-file-name var 'var))) + (doom--switch-from-popup (find-variable-noselect var file)))) + + (define-button-type 'help-face-def + :supertype 'help-xref + 'help-function + (lambda (fun file) + (require 'find-func) + (doom--switch-from-popup (find-function-search-for-symbol fun 'defface file))))) + +(provide 'config) +;;; config.el ends here diff --git a/modules/feature/version-control/+git.el b/modules/feature/version-control/+git.el index 8a8770880..4adc26ca8 100644 --- a/modules/feature/version-control/+git.el +++ b/modules/feature/version-control/+git.el @@ -24,7 +24,7 @@ (git-gutter-mode +1))) (add-hook! (text-mode prog-mode conf-mode) #'+version-control|git-gutter-maybe) :config - (set! :popup "^\\*git-gutter.+\\*$" :regexp t :size 15 :noselect t) + (set! :popup "^\\*git-gutter" nil '((select))) ;; Update git-gutter on focus (in case I was using git externally) (add-hook 'focus-in-hook #'git-gutter:update-all-windows) diff --git a/modules/feature/version-control/config.el b/modules/feature/version-control/config.el index f13540e2e..b3e72e557 100644 --- a/modules/feature/version-control/config.el +++ b/modules/feature/version-control/config.el @@ -11,10 +11,8 @@ (after! vc-annotate - (set! :popup - '("*vc-diff*" :size 15 :noselect t) - '("*vc-change-log*" :size 15) - '(vc-annotate-mode :same t)) + (set! :popup "^\\vc-d" nil '((select))) ; *vc-diff* + (set! :popup "^\\vc-c" nil '((select . t))) ; *vc-change-log* (set! :evil-state 'vc-annotate-mode 'normal) (set! :evil-state 'vc-git-log-view-mode 'normal)) diff --git a/modules/lang/clojure/config.el b/modules/lang/clojure/config.el index 5dd2ec8c5..d54754467 100644 --- a/modules/lang/clojure/config.el +++ b/modules/lang/clojure/config.el @@ -35,7 +35,7 @@ (setq nrepl-hide-special-buffers t) ;; settings for cider repl as a popup (prevent it from being closed on escape, especially.) - (set! :popup "^\\*cider" :regexp t :noselect t :noesc t) + (set! :popup "^\\*cider" nil '((escape-quit) (select))) ;; Setup cider for clojurescript / figwheel dev. (setq cider-cljs-lein-repl diff --git a/modules/lang/emacs-lisp/config.el b/modules/lang/emacs-lisp/config.el index 4f1e02586..c84354f5f 100644 --- a/modules/lang/emacs-lisp/config.el +++ b/modules/lang/emacs-lisp/config.el @@ -115,8 +115,7 @@ (def-package! overseer - :commands overseer-test - :init (set! :popup "*overseer*" :size 12)) + :commands overseer-test) ;; diff --git a/modules/lang/haskell/+intero.el b/modules/lang/haskell/+intero.el index 9359f6b8c..e3b3ab643 100644 --- a/modules/lang/haskell/+intero.el +++ b/modules/lang/haskell/+intero.el @@ -10,7 +10,6 @@ (add-hook! 'intero-mode-hook #'(flycheck-mode eldoc-mode)) - (set! :popup "^intero:backend:" :regex t :size 12) (set! :lookup 'haskell-mode :definition #'intero-goto-definition)) diff --git a/modules/lang/latex/config.el b/modules/lang/latex/config.el index 2d4fafb04..94e781d82 100644 --- a/modules/lang/latex/config.el +++ b/modules/lang/latex/config.el @@ -33,7 +33,7 @@ LaTeX-section-section LaTeX-section-label)) - (set! :popup " output\\*$" :regexp t :size 15 :noselect t :autoclose t :autokill t) + (set! :popup " output\\*$" '((size . 15))) (map! :map LaTeX-mode-map "C-j" nil)) diff --git a/modules/lang/plantuml/config.el b/modules/lang/plantuml/config.el index 13353d1ab..457f2872d 100644 --- a/modules/lang/plantuml/config.el +++ b/modules/lang/plantuml/config.el @@ -4,7 +4,7 @@ :mode "\\.p\\(lant\\)?uml$" :config (setq plantuml-jar-path (concat doom-etc-dir "plantuml.jar")) - (set! :popup "*PLANTUML Preview*" :size 25 :noselect t :autokill t) + (set! :popup "^\\*PLANTUML" '((size . 0.4)) '((select) (transient . 0))) (unless (executable-find "java") (warn "plantuml-mode: can't find java, preview disabled.")) diff --git a/modules/lang/python/config.el b/modules/lang/python/config.el index 82c20f506..90bf1e83d 100644 --- a/modules/lang/python/config.el +++ b/modules/lang/python/config.el @@ -78,7 +78,7 @@ environment variables." anaconda-mode-eldoc-as-single-line t) :config (add-hook 'anaconda-mode-hook #'anaconda-eldoc-mode) - (set! :popup "*anaconda-mode*" :size 10 :noselect t :autoclose t :autokill t) + (set! :popup "^\\*anaconda-mode" nil '((select))) (map! :map anaconda-mode-map :m "gd" #'anaconda-mode-find-definitions) (advice-add #'anaconda-mode-doc-buffer :after #'doom*anaconda-mode-doc-buffer)) @@ -113,7 +113,7 @@ environment variables." :init (associate! nose-mode :match "/test_.+\\.py$" :modes (python-mode)) :config - (set! :popup "*nosetests*" :size 0.4 :noselect t) + (set! :popup "^\\*nosetests" '((size . 0.4)) '((select))) (set! :yas-minor-mode 'nose-mode) (map! :map nose-mode-map :localleader diff --git a/modules/lang/rest/config.el b/modules/lang/rest/config.el index 4af59d251..79c81c85c 100644 --- a/modules/lang/rest/config.el +++ b/modules/lang/rest/config.el @@ -4,7 +4,7 @@ :commands restclient-mode :mode ("\\.http$" . restclient-mode) :config - (set! :popup "*HTTP Response*" :size 30 :select t :noesc t :autokill t) + (set! :popup "^\\*HTTP Response" '((size . 0.4)) '((escape-quit . other))) (map! :mode restclient-mode :n [M-return] 'restclient-http-send-current :localleader diff --git a/modules/private/default/+bindings.el b/modules/private/default/+bindings.el index 1bfaa4f0c..ca24e00dc 100644 --- a/modules/private/default/+bindings.el +++ b/modules/private/default/+bindings.el @@ -24,8 +24,8 @@ "M--" #'text-scale-decrease ;; Simple window navigation/manipulation - "C-`" #'doom/popup-toggle - "C-~" #'doom/popup-raise + "C-`" #'+popup/toggle + "C-~" #'+popup/raise "M-t" #'+workspace/new "M-T" #'+workspace/display "M-w" #'delete-window @@ -63,7 +63,7 @@ :en "C-k" #'evil-window-up :en "C-l" #'evil-window-right - "C-x p" #'doom/other-popup + "C-x p" #'+popup/other ;; --- ------------------------------------- @@ -78,7 +78,7 @@ :desc "Switch workspace buffer" :n "," #'persp-switch-to-buffer :desc "Switch buffer" :n "<" #'switch-to-buffer :desc "Browse files" :n "." #'find-file - :desc "Toggle last popup" :n "~" #'doom/popup-toggle + :desc "Toggle last popup" :n "~" #'+popup/toggle :desc "Eval expression" :n "`" #'eval-expression :desc "Blink cursor line" :n "DEL" #'+doom/blink-cursor :desc "Jump to bookmark" :n "RET" #'bookmark-jump @@ -195,7 +195,7 @@ :desc "Apropos" :n "a" #'apropos :desc "Reload theme" :n "R" #'doom//reload-theme :desc "Find library" :n "l" #'find-library - :desc "Toggle Emacs log" :n "m" #'doom/popup-toggle-messages + :desc "Toggle Emacs log" :n "m" #'view-echo-area-messages :desc "Command log" :n "L" #'global-command-log-mode :desc "Describe function" :n "f" #'describe-function :desc "Describe key" :n "k" #'describe-key @@ -723,6 +723,10 @@ "M-;" #'eval-expression "A-;" #'eval-expression) + (:when (featurep! :feature popup) + (:map +popup-mode-map + "M-w" #'delete-window)) + (:after tabulated-list (:map tabulated-list-mode-map [remap evil-record-macro] #'quit-window)) diff --git a/modules/tools/gist/config.el b/modules/tools/gist/config.el index cc7837de3..d0864b08f 100644 --- a/modules/tools/gist/config.el +++ b/modules/tools/gist/config.el @@ -7,7 +7,6 @@ (def-package! gist :commands (gist-list gist-region-or-buffer-private gist-region-or-buffer) :config - (set! :popup "*github:gists*" :size 15 :select t :autokill t) (set! :evil-state 'gist-list-mode 'normal) (defun +gist*list-render (orig-fn &rest args) diff --git a/modules/tools/imenu/config.el b/modules/tools/imenu/config.el index cbef99643..5cfb68b59 100644 --- a/modules/tools/imenu/config.el +++ b/modules/tools/imenu/config.el @@ -8,18 +8,16 @@ (def-package! imenu-list :commands imenu-list-minor-mode :config - (setq imenu-list-focus-after-activation t) - (set! :popup imenu-list-buffer-name :size 35 :align 'right) + (set! :popup "^\\*Ilist" + '((side . right) (size . 35)) + '((escape-quit . current) (select) (transient . 0))) - ;; use popups - (defun doom*imenu-list-show () - (doom-popup-buffer (get-buffer imenu-list-buffer-name))) - (advice-add #'imenu-list-show :override #'doom*imenu-list-show) - (advice-add #'imenu-list-show-noselect :override #'doom*imenu-list-show) - - ;; auto kill imenu-list on deactivation - (defun doom|kill-imenu-list () - (when (and (not imenu-list-minor-mode) - (get-buffer imenu-list-buffer-name)) - (kill-buffer (get-buffer imenu-list-buffer-name)))) - (add-hook 'imenu-list-minor-mode-hook #'doom|kill-imenu-list)) + (defun +imenu|cleanup-on-popup-close () + "Clean up after `imenu-list-minor-mode' when killing the list window." + (unless +popup-buffer-mode + (when imenu-list--displayed-buffer + (with-current-buffer imenu-list--displayed-buffer + (imenu-list-minor-mode -1))) + (when (equal (buffer-name) imenu-list-buffer-name) + (kill-buffer (get-buffer imenu-list-buffer-name))))) + (add-hook '+popup-buffer-mode-hook #'+imenu|cleanup-on-popup-close)) diff --git a/modules/tools/neotree/config.el b/modules/tools/neotree/config.el index fb8a88086..988717aba 100644 --- a/modules/tools/neotree/config.el +++ b/modules/tools/neotree/config.el @@ -33,5 +33,9 @@ "~$" "^#.*#$")) + (set! :popup "^ ?\\*NeoTree" + `((side . ,neo-window-position) (width-width . ,neo-window-width)) + '((escape-quit . current) (select . t))) + (when (bound-and-true-p winner-mode) (push neo-buffer-name winner-boring-buffers))) diff --git a/modules/tools/password-store/config.el b/modules/tools/password-store/config.el index 28a69a17a..d63313582 100644 --- a/modules/tools/password-store/config.el +++ b/modules/tools/password-store/config.el @@ -21,7 +21,7 @@ :commands pass :config (set! :evil-state 'pass-mode 'emacs) - (set! :popup "*Password-Store*" :align 'left :size 32 :select t :autokill t :noesc t) + (set! :popup "^\\*Password-Store" '((side . left)) '((escape-quit))) (map! :map pass-mode-map "j" #'pass-next-entry "k" #'pass-prev-entry diff --git a/modules/ui/doom/config.el b/modules/ui/doom/config.el index 55666a769..139328fba 100644 --- a/modules/ui/doom/config.el +++ b/modules/ui/doom/config.el @@ -19,14 +19,7 @@ (add-hook 'doom-init-theme-hook #'doom-themes-neotree-config) (setq doom-neotree-enable-variable-pitch t doom-neotree-file-icons 'simple - doom-neotree-line-spacing 2) - - (after! neotree - (defun +doom|neotree-fix-popup () - "Ensure the fringe settings are maintained on popup restore." - (neo-global--when-window - (doom--neotree-no-fringes))) - (add-hook 'doom-popup-mode-hook #'+doom|neotree-fix-popup))) + doom-neotree-line-spacing 2)) (def-package! solaire-mode diff --git a/modules/ui/tabbar/config.el b/modules/ui/tabbar/config.el index bb694c5c4..296d5d04d 100644 --- a/modules/ui/tabbar/config.el +++ b/modules/ui/tabbar/config.el @@ -10,10 +10,10 @@ (tabbar-mode) (defun +tabbar|disable-in-popups () - (when tabbar-mode + (when (and +popup-buffer-mode tabbar-mode) (tabbar-local-mode -1) (setq-local header-line-format nil))) - (add-hook 'doom-popup-mode-hook #'+tabbar|disable-in-popups) + (add-hook '+popup-buffer-mode-hook #'+tabbar|disable-in-popups) (defun +tabbar-display-tab (tab) "Return a label for TAB that resembles tabs in Atom."