home

My NixOS systems configurations.
Log | Files | Refs | LICENSE

config-windows.el (7972B)


      1 ;;; config-windows.el ---  -*- lexical-binding: t; -*-
      2 ;; Commentary:
      3 ;;; Windows configuration
      4 ;; Code:
      5 
      6 (setq switch-to-buffer-obey-display-actions t)
      7 
      8 (defun vde/save-desktop-no-ask ()
      9   "Save the desktop without asking questions by modifying the modtime."
     10   (interactive)
     11   (require 'desktop)
     12   (desktop--get-file-modtime)
     13   (desktop-save (concat desktop-dirname)))
     14 (defun vde/desktop-load ()
     15   "Load saved desktop"
     16   (interactive)
     17   (require 'desktop)
     18   (desktop-read desktop-dirname))
     19 
     20 (bind-key "C-c d s" #'vde/save-desktop-no-ask)
     21 (bind-key "C-c d l" #'vde/desktop-load)
     22 
     23 ;; Winner
     24 (use-package winner
     25   :unless noninteractive
     26   :defer 5
     27   :config
     28   (winner-mode 1))
     29 ;; -UseWinner
     30 
     31 (defun toggle-maximize-buffer ()
     32   "Maximize buffer"
     33   (interactive)
     34   (if (one-window-p)
     35       (winner-undo)
     36     (delete-other-windows)))
     37 
     38 ;; UseAceWindow
     39 (use-package ace-window
     40   :unless noninteractive
     41   :commands (ace-window ace-swap-window)
     42   :bind (("C-x o"   . ace-window)
     43          ("C-c w w" . ace-window)
     44          ("C-c w s" . ace-swap-window))
     45   :config
     46   (setq-default aw-keys '(?a ?u ?i ?e ?, ?c ?t ?r ?m)
     47                 aw-scope 'frame
     48                 aw-dispatch-always t
     49                 aw-dispatch-alist
     50                 '((?s aw-swap-window "Swap Windows")
     51                   (?2 aw-split-window-vert "Split Window Vertically")
     52                   (?3 aw-split-window-horz "Split Window Horizontally")
     53                   (?? aw-show-dispatch-help))
     54                 aw-minibuffer-flag t
     55                 aw-ignore-current nil
     56                 aw-display-mode-overlay t
     57                 aw-background t))
     58 ;; -UseAceWindow
     59 
     60 ;; UseWindmove
     61 (use-package windmove
     62   :unless noninteractive
     63   :commands (windmove-left windmove-right windmove-down windmove-up)
     64   :bind (("C-M-<up>" . windmove-up)
     65          ("C-M-<right>" . windmove-right)
     66          ("C-M-<down>" . windmove-down)
     67          ("C-M-<left>" . windmove-left)))
     68 ;; -UseWindmove
     69 
     70 ;; UseWindow
     71 (use-package window
     72   :unless noninteractive
     73   :commands (shrink-window-horizontally shrink-window enlarge-window-horizontally enlarge-window)
     74   :bind (("S-C-<left>" . shrink-window-horizontally)
     75          ("S-C-<right>" . enlarge-window-horizontally)
     76          ("S-C-<down>" . shrink-window)
     77          ("S-C-<up>" . enlarge-window)))
     78 ;; -UseWindow
     79 
     80 ;;;###autoload
     81 (defun prot-common-window-small-p ()
     82   "Return non-nil if window is small.
     83 Check if the `window-width' or `window-height' is less than
     84 `split-width-threshold' and `split-height-threshold',
     85 respectively."
     86   (or (and (numberp split-width-threshold)
     87            (< (window-total-width) split-width-threshold))
     88       (and (numberp split-height-threshold)
     89            (> (window-total-height) split-height-threshold))))
     90 
     91 (defun prot-common-three-or-more-windows-p (&optional frame)
     92   "Return non-nil if three or more windows occupy FRAME.
     93 If FRAME is non-nil, inspect the current frame."
     94   (>= (length (window-list frame :no-minibuffer)) 3))
     95 
     96 (defun prot-window--get-display-buffer-below-or-pop ()
     97   "Return list of functions for `prot-window-display-buffer-below-or-pop'."
     98   (list
     99    #'display-buffer-reuse-mode-window
    100    (if (or (prot-common-window-small-p)
    101            (prot-common-three-or-more-windows-p))
    102        #'display-buffer-below-selected
    103      #'display-buffer-pop-up-window)))
    104 
    105 (defun prot-window-display-buffer-below-or-pop (&rest args)
    106   "Display buffer below current window or pop a new window.
    107 The criterion for choosing to display the buffer below the
    108 current one is a non-nil return value for
    109 `prot-common-window-small-p'.
    110 
    111 Apply ARGS expected by the underlying `display-buffer' functions.
    112 
    113 This as the action function in a `display-buffer-alist' entry."
    114   (let ((functions (prot-window--get-display-buffer-below-or-pop)))
    115     (catch 'success
    116       (dolist (fn functions)
    117         (when (apply fn args)
    118           (throw 'success fn))))))
    119 
    120 (defvar prot-window-window-sizes
    121   '( :max-height (lambda () (floor (frame-height) 3))
    122      :min-height 10
    123      :max-width (lambda () (floor (frame-width) 4))
    124      :min-width 20)
    125   "Property list of maximum and minimum window sizes.
    126 The property keys are `:max-height', `:min-height', `:max-width',
    127 and `:min-width'.  They all accept a value of either a
    128 number (integer or floating point) or a function.")
    129 
    130 (defun prot-window--get-window-size (key)
    131   "Extract the value of KEY from `prot-window-window-sizes'."
    132   (when-let ((value (plist-get prot-window-window-sizes key)))
    133     (cond
    134      ((functionp value)
    135       (funcall value))
    136      ((numberp value)
    137       value)
    138      (t
    139       (error "The value of `%s' is neither a number nor a function" key)))))
    140 
    141 (defun prot-window-select-fit-size (window &rest _)
    142   "Select WINDOW and resize it.
    143 The resize pertains to the maximum and minimum values for height
    144 and width, per `prot-window-window-sizes'.
    145 
    146 Use this as the `body-function' in a `display-buffer-alist' entry."
    147   (select-window window)
    148   (fit-window-to-buffer
    149    window
    150    (prot-window--get-window-size :max-height)
    151    (prot-window--get-window-size :min-height)
    152    (prot-window--get-window-size :max-width)
    153    (prot-window--get-window-size :min-width)))
    154 
    155 (defun prot-window-shell-or-term-p (buffer &rest _)
    156   "Check if BUFFER is a shell or terminal.
    157 This is a predicate function for `buffer-match-p', intended for
    158 use in `display-buffer-alist'."
    159   (when (string-match-p "\\*.*\\(e?shell\\|v?term\\).*" (buffer-name (get-buffer buffer)))
    160     (with-current-buffer buffer
    161       ;; REVIEW 2022-07-14: Is this robust?
    162       (and (not (derived-mode-p 'message-mode 'text-mode))
    163            (derived-mode-p 'eshell-mode 'shell-mode 'comint-mode 'fundamental-mode)))))
    164 
    165 (setq display-buffer-alist
    166       `(;; Default to no window
    167 	("\\`\\*Async Shell Command\\*\\'"
    168 	 (display-buffer-no-window))
    169 	("\\`\\*\\(Warnings\\|Compile-Log\\|Org Links\\)\\*\\'"
    170          (display-buffer-no-window)
    171          (allow-no-window . t))
    172 	;; bottom side window
    173         ("\\*Org \\(Select\\|Note\\)\\*" ; the `org-capture' key selection and `org-add-log-note'
    174          (display-buffer-in-side-window)
    175          (dedicated . t)
    176          (side . bottom)
    177          (slot . 0)
    178          (window-parameters . ((mode-line-format . none))))
    179 	;; bottom buffer (NOT side window)
    180         ((or . ((derived-mode . flymake-diagnostics-buffer-mode)
    181                 (derived-mode . flymake-project-diagnostics-mode)
    182                 (derived-mode . messages-buffer-mode)
    183                 (derived-mode . backtrace-mode)))
    184          (display-buffer-reuse-mode-window display-buffer-at-bottom)
    185          (window-height . 0.3)
    186          (dedicated . t)
    187          (preserve-size . (t . t)))
    188 	;; ((or . ((derived-mode . Man-mode)
    189 	;; 	(derived-mode . woman-mode)
    190 	;; 	"\\*\\(Man\\|woman\\).*"))
    191 	;;  (display-buffer-reuse-mode-window display-buffer-below-selected)
    192         ;;  (window-height . 0.3) ; note this is literal lines, not relative
    193         ;;  (dedicated . t)
    194         ;;  (preserve-size . (t . t)))
    195 	;; below current window
    196 	("\\(\\*Capture\\*\\|CAPTURE-.*\\)"
    197          (display-buffer-reuse-mode-window display-buffer-below-selected))
    198 	((derived-mode . reb-mode) ; M-x re-builder
    199          (display-buffer-reuse-mode-window display-buffer-below-selected)
    200          (window-height . 4) ; note this is literal lines, not relative
    201          (dedicated . t)
    202          (preserve-size . (t . t)))
    203 	((or . ((derived-mode . occur-mode)
    204                 (derived-mode . grep-mode)
    205                 (derived-mode . Buffer-menu-mode)
    206                 (derived-mode . log-view-mode)
    207 		(derived-mode . helpful-mode)
    208                 (derived-mode . help-mode) ; See the hooks for `visual-line-mode'
    209                 "\\*\\(|Buffer List\\|Occur\\|vc-change-log\\).*"
    210                 prot-window-shell-or-term-p
    211                 ,world-clock-buffer-name))
    212          (prot-window-display-buffer-below-or-pop)
    213          (dedicated . t)
    214          (body-function . prot-window-select-fit-size))
    215 	))
    216 
    217 ;; TODO: Move display-buffer-alist here
    218 
    219 (provide 'config-windows)
    220 ;;; config-windows ends here