2018-01-06 01:23:22 -05:00
|
|
|
;;; config.el -*- lexical-binding: t; -*-
|
|
|
|
|
|
|
|
(defconst +popup-window-parameters
|
2018-01-06 04:56:12 -05:00
|
|
|
'(transient quit select modeline popup)
|
2018-01-06 01:23:22 -05:00
|
|
|
"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)
|
2018-01-07 02:33:57 -05:00
|
|
|
CDR can be t, an integer, nil or a function that returns one of these. It
|
|
|
|
represents the number of seconds before the buffer belonging to a closed popup
|
|
|
|
window is killed.
|
2018-01-06 01:23:22 -05:00
|
|
|
|
|
|
|
If t, CDR will default to `+popup-ttl'.
|
|
|
|
If 0, the buffer is immediately killed.
|
|
|
|
If nil, the buffer won't be killed.
|
2018-01-07 02:33:57 -05:00
|
|
|
If a function, it must return one of the other possible values above. It takes
|
|
|
|
the popup buffer as its sole argument.
|
2018-01-06 01:23:22 -05:00
|
|
|
|
2018-01-06 02:42:53 -05:00
|
|
|
(quit . CDR)
|
2018-01-07 02:33:57 -05:00
|
|
|
CDR can be t, 'other, 'current, nil, or a function that returns one of these.
|
|
|
|
This determines the behavior of the ESC/C-g keys in or outside of popup
|
|
|
|
windows.
|
2018-01-06 01:23:22 -05:00
|
|
|
|
2018-01-06 02:42:53 -05:00
|
|
|
If t, close the popup if ESC/C-g is pressed inside or outside of popups.
|
|
|
|
If 'other, close this popup if ESC/C-g is pressed outside of any popup. This
|
2018-01-07 00:08:30 -05:00
|
|
|
is great for popups you just want to peek at and discard, but might also
|
|
|
|
want to poke around in, without the risk of closing it from the inside.
|
2018-01-06 02:42:53 -05:00
|
|
|
If 'current, close the current popup if ESC/C-g is pressed from inside of the
|
|
|
|
popup.
|
|
|
|
If nil, pressing ESC/C-g will never close this buffer.
|
2018-01-07 02:33:57 -05:00
|
|
|
If a function, it is checked each time ESC/C-g is pressed to determine the
|
|
|
|
fate of the popup window. This function takes one argument: the popup
|
|
|
|
window and must return one of the other possible values.
|
2018-01-06 01:23:22 -05:00
|
|
|
|
2018-01-07 02:33:57 -05:00
|
|
|
(select . CDR)
|
|
|
|
CDR can be a boolean or function. The boolean determines whether to focus the
|
|
|
|
popup window after it opens (non-nil) or focus the origin window (nil).
|
|
|
|
|
|
|
|
If a function, it takes two arguments: the popup window and the source window
|
|
|
|
(where you were before the popup was opened). It does nothing else, and
|
|
|
|
ignores its return value.
|
2018-01-06 01:23:22 -05:00
|
|
|
|
|
|
|
(modeline . CDR)
|
|
|
|
CDR can be t (show the default modeline), a symbol representing the name of a
|
2018-01-07 02:33:57 -05:00
|
|
|
modeline defined with `def-modeline!', nil (show no modeline) or a function
|
|
|
|
that returns one of these. The function takes one argument: the popup buffer.
|
2018-01-06 01:23:22 -05:00
|
|
|
|
2018-01-06 13:30:59 -05:00
|
|
|
(popup . t)
|
|
|
|
This is for internal use, do not change this. It simply marks a window as a
|
|
|
|
popup window.
|
2018-01-06 01:23:22 -05:00
|
|
|
|
|
|
|
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)
|
2018-01-06 02:42:53 -05:00
|
|
|
(quit . t))
|
2018-01-07 00:08:30 -05:00
|
|
|
"The default window parameters.")
|
2018-01-06 01:23:22 -05:00
|
|
|
|
|
|
|
(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'.")
|
|
|
|
|
|
|
|
|
2018-01-06 16:37:31 -05:00
|
|
|
(defvar +popup--inhibit-transient nil)
|
2018-01-06 01:23:22 -05:00
|
|
|
(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
|
2018-01-06 03:09:15 -05:00
|
|
|
module.
|
|
|
|
|
|
|
|
ALIST supports one custom parameter: `size', which will resolve to
|
|
|
|
`window-height' or `window-width' depending on `side'."
|
2018-01-06 01:23:22 -05:00
|
|
|
`(let ((alist ,alist)
|
|
|
|
(parameters ,parameters))
|
|
|
|
,(when alist
|
2018-01-06 23:54:12 -05:00
|
|
|
`(when-let* ((size (cdr (assq 'size alist)))
|
|
|
|
(side (cdr (assq 'side (append alist +popup-default-alist)))))
|
|
|
|
(map-delete alist 'size)
|
|
|
|
(map-put alist (if (memq side '(left right))
|
|
|
|
'window-width
|
|
|
|
'window-height)
|
|
|
|
size)))
|
2018-01-06 01:23:22 -05:00
|
|
|
(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"
|
2018-01-06 03:09:15 -05:00
|
|
|
'((size . 0.2))
|
2018-01-06 01:23:22 -05:00
|
|
|
'((select . t)))
|
|
|
|
(set! :+popup "^\\*doom:"
|
2018-01-06 03:09:15 -05:00
|
|
|
'((size . 0.35))
|
2018-01-06 02:42:53 -05:00
|
|
|
'((select . t) (quit) (transient))))
|
2018-01-06 01:23:22 -05:00
|
|
|
|
|
|
|
(setq +popup--display-buffer-alist (eval-when-compile +popup--display-buffer-alist))
|
|
|
|
(add-hook 'doom-init-ui-hook #'+popup-mode)
|
|
|
|
|
2018-01-07 00:08:30 -05:00
|
|
|
(add-hook! '+popup-buffer-mode-hook #'(+popup|adjust-fringes +popup|set-modeline))
|
2018-01-06 01:23:22 -05:00
|
|
|
|
|
|
|
|
|
|
|
;;
|
|
|
|
;; Hacks
|
|
|
|
;;
|
|
|
|
|
2018-01-06 04:56:39 -05:00
|
|
|
(advice-add #'balance-windows :around #'+popup*save)
|
|
|
|
|
2018-01-06 01:23:22 -05:00
|
|
|
(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)
|
2018-01-06 04:24:37 -05:00
|
|
|
(lambda (dir &optional arg window)
|
2018-01-06 01:23:22 -05:00
|
|
|
(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)
|
|
|
|
|
2018-01-06 04:56:39 -05:00
|
|
|
;; `help-mode'
|
2018-01-06 01:23:22 -05:00
|
|
|
(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)))))
|
|
|
|
|
2018-01-06 16:40:16 -05:00
|
|
|
;; `neotree'
|
|
|
|
(after! neotree
|
|
|
|
(advice-remove #'balance-windows #'ad-Advice-balance-windows))
|
|
|
|
|
2018-01-06 04:56:39 -05:00
|
|
|
;; `wgrep'
|
|
|
|
(after! wgrep
|
|
|
|
;; close the popup after you're done with a wgrep buffer
|
|
|
|
(advice-add #'wgrep-abort-changes :after #'+popup*close)
|
|
|
|
(advice-add #'wgrep-finish-edit :after #'+popup*close))
|
|
|
|
|
|
|
|
;; `org'
|
|
|
|
(after! org
|
|
|
|
(set! :popup "^ \\*Org todo" '((size . 5)) '((transient . 0)))
|
|
|
|
(set! :popup "^\\*Org Agenda" '((size . 20)))
|
|
|
|
|
2018-01-07 00:08:30 -05:00
|
|
|
;; 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
|
|
|
|
;; ourselves.
|
2018-01-06 04:56:39 -05:00
|
|
|
(defun +popup*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 #'+popup*suppress-delete-other-windows)
|
|
|
|
(advice-add #'org-capture-place-template :around #'+popup*suppress-delete-other-windows)
|
|
|
|
(advice-add #'org-export--dispatch-ui :around #'+popup*suppress-delete-other-windows)
|
|
|
|
|
|
|
|
(defun +popup*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 #'+popup*org-pop-to-buffer)
|
|
|
|
|
|
|
|
;; `org-agenda'
|
|
|
|
(setq org-agenda-window-setup 'other-window
|
|
|
|
org-agenda-restore-windows-after-quit nil)
|
|
|
|
(add-hook 'org-agenda-finalize-hook #'org-fit-window-to-buffer)
|
|
|
|
;; Don't monopolize frame!
|
|
|
|
(advice-add #'org-agenda :around #'+popup*suppress-delete-other-windows))
|
|
|
|
|
|
|
|
;; `persp-mode'
|
|
|
|
(after! persp-mode
|
|
|
|
(defun +popup*persp-mode-restore-popups (&rest _)
|
|
|
|
"Restore popup windows when loading a perspective from file."
|
|
|
|
(dolist (window (window-list))
|
|
|
|
(when (+popup-parameter 'popup window)
|
|
|
|
(with-selected-window window
|
|
|
|
(+popup-buffer-mode +1)))))
|
|
|
|
(advice-add #'persp-load-state-from-file :after #'+popup*persp-mode-restore-popups))
|
|
|
|
|
2018-01-06 01:23:22 -05:00
|
|
|
(provide 'config)
|
|
|
|
;;; config.el ends here
|