From 8dce7c9c4aa0457f5f921cb6f7af8ca681da5467 Mon Sep 17 00:00:00 2001 From: Trust me I am a doctor Date: Tue, 8 Jun 2021 11:44:54 +0200 Subject: [PATCH] User option to choose a function triggered by windmove-create * lisp/windmove.el (windmove-create-window): Add a defcustom choice. (windmove-do-window-select): Trigger custom functions, update the docstring. Commentary: document the usage of this user option with a basic 'display-buffer-alist', a dispatcher function for 'windmove-create-window' and an alist to hold the dispatch. --- lisp/windmove.el | 90 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 6 deletions(-) diff --git a/lisp/windmove.el b/lisp/windmove.el index f558903681..0ef20fb498 100644 --- a/lisp/windmove.el +++ b/lisp/windmove.el @@ -110,6 +110,72 @@ ;; (setq windmove-wrap-around t) ;; +;; Configuring windmove to display side windows : +;; +;; Assuming you have customized your 'display-buffer-alist' to +;; uses side-windows, see (info "(elisp) Choosing Window") +;; +;; Or refer to this basic example : +;; +;; (customize-set-variable 'display-buffer-alist +;; '(("\\*Ibuffer\\*" +;; (display-buffer-in-side-window) +;; (side . left) (window-width . 42)) +;; ("\\*Info.*" +;; (display-buffer-in-side-window) +;; (side . right) (window-width . 80)) +;; ("\\*e?shell.*" +;; (display-buffer-in-side-window) +;; (side . top)) +;; ("\\*Messages.*" +;; (display-buffer-in-side-window) +;; (side . bottom)))) +;; +;; You can create a function that will dispatch the calls by direction : +;; +;; (defun windmove-create-side-window (dir arg window) +;; "Intermedary function choosing what to call on direction DIR. +;; If the selected-window is a side-window, delete it, otherwise, +;; select the relevant function from `windmove-dispatch-sides-functions'. +;; Only pass ARG and WINDOW to the childs functions." +;; ;; normalise the direction +;; (let ((dir (pcase dir (`up 'top) (`down 'bottom) (_ dir)))) +;; (funcall (if (eq dir (window-parameter window 'window-side)) +;; (lambda (_dir _arg window) +;; (prog1 (get-mru-window) (delete-window window))) +;; (alist-get dir windmove-dispatch-sides-functions)) +;; dir arg window))) +;; +;; Then assign it to 'windmove-create-window' +;; +;; (customize-set-variable 'windmove-create-window +;; #'windmove-create-side-window) +;; +;; You can then specify an alist to actually hold the functions +;; to be called with their directions : +;; +;; (defvar windmove-dispatch-sides-functions +;; '((left . (lambda (_dir _arg _window) +;; (ibuffer 'other-window) +;; (get-buffer-window "*Ibuffer*"))) +;; (right . (lambda (_dir _arg _window) +;; (let ((buffer (get-buffer "*info*"))) +;; (if buffer +;; (display-buffer buffer) +;; (info)) +;; (get-buffer-window "*info*")))) +;; (top . (lambda (_dir _arg _window) +;; (shell) +;; (get-buffer-window "*shell*"))) +;; (bottom . (lambda (_arg _dir _window) +;; (view-echo-area-messages) +;; 'no-select))) +;; "Alist to dispatch by direction the calls of `windmove-create-side-window'") +;; +;; And also activate this recommended setting : +;; +;; (customize-set-variable 'windmove-allow-all-windows t) + ;; Acknowledgments: ;; ;; Special thanks to Julian Assange (proff@iq.org), whose @@ -145,10 +211,18 @@ windmove-create-window "Whether movement off the edge of the frame creates a new window. If this variable is set to t, moving left from the leftmost window in a frame will create a new window on the left, and similarly for the other -directions." - :type 'boolean - :group 'windmove - :version "27.1") +directions. +This variable may also be a function to be called in this circumstance +by `windmove-do-window-select'. The function should accept then as +argument the DIRECTION targeted, an interactive ARG and a WINDOW +corresponding to the currently selected window. It should also return +or a valid window that `windmove-do-window-select' will select, +or the symbol 'no-select to ignore that final selection. +The commentary section of windmove.el show an example of this utilisation." + :type '(choice (const :tag "Don't create new windows" nil) + (const :tag "Create new windows" t) + (function :tag "Provide a function")) + :version "28.1") ;; If your Emacs sometimes places an empty column between two adjacent ;; windows, you may wish to set this delta to 2. @@ -350,19 +424,23 @@ windmove-do-window-select "Move to the window at direction DIR as seen from WINDOW. DIR, ARG, and WINDOW are handled as by `windmove-find-other-window'. If no window is at direction DIR, an error is signaled. -If `windmove-create-window' is non-nil, try to create a new window +If `windmove-create-window' is a function, call that function with +DIR, ARG and WINDOW, if it is non-nil, try to create a new window in direction DIR instead." (let ((other-window (windmove-find-other-window dir arg window))) (when (and windmove-create-window (or (null other-window) (and (window-minibuffer-p other-window) (not (minibuffer-window-active-p other-window))))) - (setq other-window (split-window window nil dir))) + (setq other-window (if (functionp windmove-create-window) + (funcall windmove-create-window dir arg window) + (split-window window nil dir)))) (cond ((null other-window) (user-error "No window %s from selected window" dir)) ((and (window-minibuffer-p other-window) (not (minibuffer-window-active-p other-window))) (user-error "Minibuffer is inactive")) + ((eq other-window 'no-select)) (t (select-window other-window))))) -- 2.20.1