Compare commits

..

No commits in common. "aca0f74f3a442b1b1a6f4315303c340f7c1005b8" and "c5455e866e8a5f7eab6a7263e2057aff5f1118b9" have entirely different histories.

2 changed files with 228 additions and 249 deletions

View file

@ -5,7 +5,6 @@
* Contents :TOC:noexport:
- [[#introduction][Introduction]]
- [[#changelog][Changelog]]
- [[#aug-26-2024][Aug. 26 2024]]
- [[#sep-11-2019][Sep. 11 2019]]
- [[#nov-15-2018][Nov. 15 2018]]
- [[#initial-release-whats-changed-since-window-numbering][Initial release: what's changed since window-numbering]]
@ -20,18 +19,16 @@
- [[#future-developments][Future developments]]
* Introduction
Window numbers for Emacs: Navigate your windows and frames using numbers !
This package is a fork of the [[https://github.com/deb0ch/emacs-winum][winum]] package, which is itself a fork of the
[[https://github.com/nschum/window-numbering.el][window-numbering]] package.
This package is an extended and actively maintained version of the
[[https://github.com/nschum/window-numbering.el][window-numbering]] package by Nikolaj Schumacher, with some ideas and code taken
from [[https://github.com/abo-abo/ace-window][ace-window]].
Compared to winum, this fork adds support for windows having arbitrary Lisp values
as identifiers, as opposed to strictly increasing numbers. The public
API is largely the same, however, and simple numbers are still the default.
This version brings, among other things, support for number sets across multiple
frames, giving the user a smoother experience of multi-screen Emacs.
* Changelog
** Aug. 26 2024
- Added support for arbitrary Lisp objects (non-nil, compared with =equal=) as indices.
- Added customize variable =winum-auto-assign-function= to control auto-assigning behavior.
** Sep. 11 2019
- Added customize variable =winum-ignored-buffers-regexp= to ignored buffers
based on regexps.
@ -104,7 +101,7 @@ your Emacs configuration:
| Key binding | Description |
|-------------+---------------------------------------------------------------------------------------------|
| ~C-x w <n>~ | select window <n>, where <n> ranges from 0 to 9. A negative argument deletes the window. |
| ~C-x w `~ | select window by index. Integer indices can be given as prefix arg, or the index will be read from minibuffer. |
| ~C-x w `~ | select window by number. Number can be given as prefix arg or will be read from minibuffer. |
- =select-window-0-or-10=
@ -114,19 +111,23 @@ your Emacs configuration:
You can rebind this to the more straightforward =select-window-0= if you
prefer.
- =select-window-by-index=
- =select-window-by-number=
If you happen to have more than 10 windows, or if you want to select a window that
doesn't have an integer index, you can use the =select-window-by-index= function, bound
by default to ~C-x w `~.
If you happen to have more than 10 windows, you can use the
=select-window-by-number= function, bound by default to ~C-x w `~.
This function allows several ways to input the window number:
- Use a numbered prefix argument.\\
*Ex:* ~C-1 C-2 C-x w `~ to select window 12.
- Use a negative prefix argument to delete the window.\\
*Ex:* ~C-- C-1 C-2 C-x w `~ to delete window 12.
- Use the negative prefix argument to delete window 0.\\
*Ex:* ~C-- C-x w `~ to delete window 0.
- Use the default prefix argument to delete current window.\\
*Ex:* ~C-u C-x w `~ to delete current window.
- If no prefix argument is given, an un-evaluated Lisp value is read from minibuffer.
- If no prefix argument ig given, a number is read from minibuffer. A negative
input will delete the window instead of selecting it.
* Configuration
** Keybindings
@ -151,8 +152,8 @@ override =winum-keymap= in the minor mode bindings table:
#+BEGIN_SRC emacs-lisp
(setq winum-keymap
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-`") 'winum-select-window-by-index)
(define-key map (kbd "C-²") 'winum-select-window-by-index)
(define-key map (kbd "C-`") 'winum-select-window-by-number)
(define-key map (kbd "C-²") 'winum-select-window-by-number)
(define-key map (kbd "M-0") 'winum-select-window-0-or-10)
(define-key map (kbd "M-1") 'winum-select-window-1)
(define-key map (kbd "M-2") 'winum-select-window-2)
@ -174,7 +175,7 @@ Note that it is important to set =winum-keymap= /before/ the =require=.
You can also use the more conventional =define-key= on =winum-keymap=:
#+BEGIN_SRC emacs-lisp
(define-key winum-keymap (kbd "C-x y o l o") 'winum-select-window-by-index)
(define-key winum-keymap (kbd "C-x y o l o") 'winum-select-window-by-number)
#+END_SRC
*NB:* Both ~`~ and ~²~ are mapped to =winum-select-window-by-number= by default
@ -200,11 +201,11 @@ Several options are available through Emacs' Customize interface under
Default: =nil=
- =winum-minibuffer-auto-assign=
- =winum-auto-assign-0-to-minibuffer=
If non-nil, =winum-mode= automatically assigns this index to the minibuffer.
If non-nil, =winum-mode= assigns 0 to the minibuffer if active.
Default: =0=
Default: =t=
- =winum-assign-functions=
@ -243,18 +244,6 @@ Several options are available through Emacs' Customize interface under
Default: =nil=
- =winum-auto-assign-function=
The function called to auto-assign indices to windows.
This function is called after =winum-assign-functions= to automatically assign
indices to the remaining windows. It must take in a list of windows and call
the function =winum--assign= to assign an index to each, while avoiding
assigning any indices already taken (stored in =winum--assigned-indices=).
Members of this list should be tested for using `equal'.
Default: =#'winum--auto-assign=
- =winum-auto-setup-mode-line=
When nil, =winum-mode= will not display window numbers in the mode-line. You
@ -301,8 +290,8 @@ available winum options.
#+BEGIN_SRC emacs-lisp
(setq winum-keymap
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-`") 'winum-select-window-by-index)
(define-key map (kbd "C-²") 'winum-select-window-by-index)
(define-key map (kbd "C-`") 'winum-select-window-by-number)
(define-key map (kbd "C-²") 'winum-select-window-by-number)
(define-key map (kbd "M-0") 'winum-select-window-0-or-10)
(define-key map (kbd "M-1") 'winum-select-window-1)
(define-key map (kbd "M-2") 'winum-select-window-2)
@ -331,7 +320,7 @@ available winum options.
(setq window-numbering-scope 'global
winum-reverse-frame-list nil
winum-minibuffer-auto-assign 0
winum-auto-assign-0-to-minibuffer t
winum-assign-func 'my-winum-assign-func
winum-auto-setup-mode-line t
winum-format " %s "

400
winum.el
View file

@ -1,8 +1,7 @@
;;; winum.el --- Navigate windows and frames using numbers.
;;
;; Copyright (c) 2006-2015 Nikolaj Schumacher
;; Copyright (c) 2016-2019 Thomas Chauvot de Beauchêne
;; Copyright (c) 2024 Kiana Sheibani
;; Copyright (c) 2016 Thomas Chauvot de Beauchêne
;;
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
@ -17,8 +16,8 @@
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;
;; Author: Kiana Sheibani <kiana.a.sheibani@gmail.com>
;; Version: 3.0.0
;; Author: Thomas de Beauchêne <thomas.de.beauchene@gmail.com>
;; Version: 2.2.0
;; Keywords: convenience, frames, windows, multi-screen
;; URL: http://github.com/deb0ch/winum.el
;; Created: 2016
@ -39,6 +38,9 @@
;; frames, giving the user a smoother experience of multi-screen Emacs.
;;
;;; Code:
;;
;; FIXME: The mode-line's window number is not always up to date in all frames.
;;
(eval-when-compile (require 'cl-lib))
(require 'dash)
@ -63,15 +65,18 @@ Has effect only when `winum-scope' is not 'frame-local."
:group 'winum
:type 'boolean)
(defcustom winum-minibuffer-auto-assign 0
"If non-nil, `winum-mode' automatically assigns this index to the minibuffer."
(defcustom winum-auto-assign-0-to-minibuffer t
"If non-nil, `winum-mode' assigns 0 to the minibuffer when active."
:group 'winum
:type 'sexp)
:type 'boolean)
(defcustom winum-assign-func nil
"Function called for each window by `winum-mode'.
This is called before automatic assignment begins. The function should
return an index to have it assigned to the current-window, nil otherwise.
return a number to have it assigned to the current-window, nil otherwise.
This function along with `winum-auto-assign-0-to-minibuffer' are the only
ways to have 0 assigned to a window.
Example: always assign *Calculator* the number 9 and *NeoTree* the number 0:
@ -93,18 +98,21 @@ Example: always assign *Calculator* the number 9 and *NeoTree* the number 0:
(defcustom winum-assign-functions nil
"List of functions called for each window by `winum-mode'.
These functions allow for deterministic assignment of indices to windows. Each
function is called for every window. A function should return the index to be
assigned to a window or nil. The *first* function to output a value for a
given window will determine this window's number.
These functions allow for deterministic assignment of numbers to windows. Each
function is called for every window. A function should return the number to be
assigned to a window or nil. The *first* function to output a number for
a given window will determine this window's number.
If the list is empty or if every functions returns nil for a given window winum
will proceed to automatic assignment.
will proceed to automatic number assignment.
Since this list is meant to allow custom window assignment for *mutiple*
packages at once it should never be directly set, only added to and removed
from.
These functions, along with `winum-auto-assign-0-to-minibuffer', are the only
way to have 0 assigned to a window.
Example: always assign *Calculator* the number 9, *Flycheck-errors* the number 8
and *NeoTree* the number 0:
@ -121,21 +129,7 @@ and *NeoTree* the number 0:
(add-to-list
'winum-assign-functions #'winum-assign-0-to-neotree)"
:group 'winum
:type '(repeat function))
(defcustom winum-auto-assign-function #'winum--auto-assign
"The function called to auto-assign indices to windows.
This function is called after `winum-assign-functions' to automatically assign
indices to the remaining windows. It must take in a list of windows and call
the function `winum--assign' to assign an index to each, while avoiding
assigning any indices already taken (stored in `winum--assigned-indices').
Members of this list should be tested for using `equal'.
The default auto-assign function is `winum--auto-assign', which assigns strictly
increasing integers to each window."
:group 'winum
:type 'function)
:type 'list)
(defcustom winum-auto-setup-mode-line t
"When nil, `winum-mode' will not display window numbers in the mode-line.
@ -149,38 +143,33 @@ numbers in the mode-line."
:group 'winum
:type 'integer)
(defcustom winum-mode-line-p #'integerp
"A predicate that determines when to display a window index on the mode-line.
By default, only integers are displayed."
:group 'winum
:type 'function)
(defcustom winum-format " %s "
"Format string defining how the window number looks like in the mode-line.
This string is passed to the `format' function along with the index."
This string is passed to the `format' function along with the
result of `winum-get-number-string'."
:group 'winum
:type 'string)
(defcustom winum-ignored-buffers '(" *which-key*")
"List of buffers to ignore when assigning indices."
"List of buffers to ignore when assigning numbers."
:group 'winum
:type '(repeat string))
(defcustom winum-ignored-buffers-regexp '()
"List of regexps for buffer names to ignore when assigning indices.
"List of regexps for buffer names to ignore when assigning numbers.
See Info node `(emacs) Regexps' or Info node `(elisp) Regular Expressions'"
:group 'winum
:type '(repeat string)
:risky t)
(defface winum-face '()
"Face used for the index in the mode-line."
"Face used for the number in the mode-line."
:group 'winum)
(defvar winum-base-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "`") 'winum-select-window-by-index)
(define-key map (kbd "²") 'winum-select-window-by-index)
(define-key map (kbd "`") 'winum-select-window-by-number)
(define-key map (kbd "²") 'winum-select-window-by-number)
(define-key map (kbd "0") 'winum-select-window-0-or-10)
(define-key map (kbd "1") 'winum-select-window-1)
(define-key map (kbd "2") 'winum-select-window-2)
@ -194,7 +183,7 @@ See Info node `(emacs) Regexps' or Info node `(elisp) Regular Expressions'"
map)
"Keymap to be used under the prefix provided by `winum-keymap-prefix'.")
(defvar winum-mode-map (let ((map (make-sparse-keymap)))
(defvar winum-keymap (let ((map (make-sparse-keymap)))
(define-key map (kbd "C-x w") winum-base-map)
map)
"Keymap used for `winum-mode'.")
@ -204,36 +193,37 @@ See Info node `(emacs) Regexps' or Info node `(elisp) Regular Expressions'"
(defvar winum--max-frames 16
"Maximum number of frames that can be numbered.")
(defvar winum--assigned-indices nil
"List of indices that have already been assigned by `winum-assign-functions'.")
(defvar winum--window-count nil
"Current count of windows to be numbered.")
(defvar winum--window-table nil
"Hash table with indices as keys and windows as values.
Used internally by winum to get a window provided an index.")
(defvar winum--remaining nil
"A list of window numbers to assign.")
(defvar winum--index-table nil
"Hash table with windows as keys and indices as values.
Used internally by winum to get an index provided a window.")
(defvar winum--window-vector nil
"Vector of windows indexed by their number.
Used internally by winum to get a window provided a number.")
(defvar winum--numbers-table nil
"Hash table of numbers indexed by their window.
Used internally by winum to get a number provided a window.")
(defvar winum--frames-table nil
"Table linking windows to indices and indices to windows for each frame.
"Table linking windows to numbers and numbers to windows for each frame.
Used only when `winum-scope' is 'frame-local to keep track of
separate window index sets in every frame.
separate window numbers sets in every frame.
It is a hash table using Emacs frames as keys and cons of the form
\(`winum--window-table' . `winum--index-table')
\(`winum--window-vector' . `winum--numbers-table')
as values.
To get a window given an index, use the `car' of a value.
To get an index given a window, use the `cdr' of a value.
To get a window given a number, use the `car' of a value.
To get a number given a window, use the `cdr' of a value.
Such a structure allows for per-frame bidirectional fast access.")
(defvar winum--mode-line-segment
'(:eval (let ((index (winum-get-index)))
(when (funcall winum-mode-line-p index)
(propertize (format winum-format index) 'face 'winum-face))))
'(:eval (format winum-format (winum-get-number-string)))
"What is pushed into `mode-line-format' when setting it up automatically.")
(defvar winum--last-used-scope winum-scope
@ -245,7 +235,9 @@ Needed to detect scope changes at runtime.")
;;;###autoload
(define-minor-mode winum-mode
"A minor mode that allows for managing windows based on window numbers."
:lighter nil
nil
nil
winum-keymap
:global t
(if winum-mode
(winum--init)
@ -253,145 +245,115 @@ Needed to detect scope changes at runtime.")
;;;###autoload
(defun winum-select-window-0-or-10 (&optional arg)
"Jump to window 0, or window 10 if 0 is not assigned.
"Jump to window 0 if assigned or 10 if exists.
If prefix ARG is given, delete the window instead of selecting it."
(interactive "P")
(let ((n (if (winum-get-window-by-index 0) 0 10)))
(if arg
(winum-delete-window-by-index n)
(winum-select-window-by-index n))))
(let ((n (if (winum-get-window-by-number 0)
(if arg '- 0)
(if arg -10 10))))
(winum-select-window-by-number n)))
;;;###autoload
(defun winum-select-window-0 (&optional arg)
"Jump to window 0.
If prefix ARG is given, delete the window instead of selecting it."
(interactive "P")
(if arg
(winum-delete-window-by-index 0)
(winum-select-window-by-index 0)))
(winum-select-window-by-number (if arg '- 0)))
;;;###autoload
(defun winum-select-window-1 (&optional arg)
"Jump to window 1.
If prefix ARG is given, delete the window instead of selecting it."
(interactive "P")
(if arg
(winum-delete-window-by-index 1)
(winum-select-window-by-index 1)))
(winum-select-window-by-number (if arg -1 1)))
;;;###autoload
(defun winum-select-window-2 (&optional arg)
"Jump to window 2.
If prefix ARG is given, delete the window instead of selecting it."
(interactive "P")
(if arg
(winum-delete-window-by-index 2)
(winum-select-window-by-index 2)))
(winum-select-window-by-number (if arg -2 2)))
;;;###autoload
(defun winum-select-window-3 (&optional arg)
"Jump to window 3.
If prefix ARG is given, delete the window instead of selecting it."
(interactive "P")
(if arg
(winum-delete-window-by-index 3)
(winum-select-window-by-index 3)))
(winum-select-window-by-number (if arg -3 3)))
;;;###autoload
(defun winum-select-window-4 (&optional arg)
"Jump to window 4.
If prefix ARG is given, delete the window instead of selecting it."
(interactive "P")
(if arg
(winum-delete-window-by-index 4)
(winum-select-window-by-index 4)))
(winum-select-window-by-number (if arg -4 4)))
;;;###autoload
(defun winum-select-window-5 (&optional arg)
"Jump to window 5.
If prefix ARG is given, delete the window instead of selecting it."
(interactive "P")
(if arg
(winum-delete-window-by-index 5)
(winum-select-window-by-index 5)))
(winum-select-window-by-number (if arg -5 5)))
;;;###autoload
(defun winum-select-window-6 (&optional arg)
"Jump to window 6.
If prefix ARG is given, delete the window instead of selecting it."
(interactive "P")
(if arg
(winum-delete-window-by-index 6)
(winum-select-window-by-index 6)))
(winum-select-window-by-number (if arg -6 6)))
;;;###autoload
(defun winum-select-window-7 (&optional arg)
"Jump to window 7.
If prefix ARG is given, delete the window instead of selecting it."
(interactive "P")
(if arg
(winum-delete-window-by-index 7)
(winum-select-window-by-index 7)))
(winum-select-window-by-number (if arg -7 7)))
;;;###autoload
(defun winum-select-window-8 (&optional arg)
"Jump to window 8.
If prefix ARG is given, delete the window instead of selecting it."
(interactive "P")
(if arg
(winum-delete-window-by-index 8)
(winum-select-window-by-index 8)))
(winum-select-window-by-number (if arg -8 8)))
;;;###autoload
(defun winum-select-window-9 (&optional arg)
"Jump to window 9.
If prefix ARG is given, delete the window instead of selecting it."
(interactive "P")
(if arg
(winum-delete-window-by-index 9)
(winum-select-window-by-index 9)))
(winum-select-window-by-number (if arg -9 9)))
;;;###autoload
(defun winum-select-window-by-index (&optional arg)
"Select window whose index is specified by ARG.
There are several ways to provide the value:
(defun winum-select-window-by-number (&optional arg)
"Select or delete window which number is specified by ARG.
If the number is negative, delete the window instead of selecting it.
There are several ways to provide the number:
- if called from elisp with an argument, use it.
- if called from elisp without an argument, use current window.
- if called interactively with a numeric prefix argument, use it.
- if called interactively with the default prefix argument, use current window.
- if called interactively and no argument is provided, read from minibuffer."
- if prefix argument is the negative argument, delete window 0.
- if prefix argument is the default prefix argument, delete current window.
- if called interactively and no valid argument is provided, read from
minibuffer."
(interactive "P")
(let* ((i (if (called-interactively-p 'any)
(cond
(let* ((n (cond
((integerp arg) arg)
(arg (winum-get-index))
(t (read--expression "Window: ")))
(or arg (winum-get-index))))
(w (winum-get-window-by-index i)))
(if w
(winum--switch-to-window w)
(user-error "No window with index %S" i))))
;;;###autoload
(defun winum-delete-window-by-index (&optional arg)
"Delete window whose index is specified by ARG.
There are several ways to provide the value:
- if called from elisp with an argument, use it.
- if called from elisp without an argument, use current window.
- if called interactively with a numeric prefix argument, use it.
- if called interactively with the default prefix argument, use current window.
- if called interactively and no argument is provided, read from minibuffer."
(interactive "P")
(let* ((i (if (called-interactively-p 'any)
(cond
((integerp arg) arg)
(arg (winum-get-index))
(t (read--expression "Window: ")))
(or arg (winum-get-index))))
(w (winum-get-window-by-index i)))
((eq arg '-) 0) ; the negative argument
(arg (winum-get-number))
((called-interactively-p 'any)
(let ((user-input-str (read-from-minibuffer "Window: ")))
(if (not (string-match-p "[+-]?[0-9]+\.*" user-input-str))
(winum-get-number)
(string-to-number user-input-str))))
(t (winum-get-number))))
(w (winum-get-window-by-number (abs n)))
(delete (and arg
(or (not (integerp arg))
(> 0 n)))))
(if w
(if delete
(delete-window w)
(user-error "No window with index %S" i))))
(winum--switch-to-window w))
(error "No window numbered %d" n))))
;; Public API ------------------------------------------------------------------
@ -409,38 +371,41 @@ PREFIX must be a key sequence, like the ones returned by `kbd'."
winum-keymap))
;;;###autoload
(defun winum-get-window-by-index (index)
"Return window INDEX if exists, nil otherwise."
(let ((window-table (winum--get-window-table)))
(gethash index window-table)))
(defun winum-get-window-by-number (n)
"Return window numbered N if exists, nil otherwise."
(let ((window-vector (winum--get-window-vector)))
(when (and (>= n 0) (< n (length window-vector)))
(aref window-vector n))))
;;;###autoload
(defun winum-get-index (&optional window)
"Get the index of WINDOW or the current window."
(let ((w (or window (selected-window))))
(gethash w (winum--get-index-table))))
;; For backwards compatibility
;;;###autoload
(defun winum-get-number-string (&optional window)
"Get the current or specified window's current number as a propertized string.
WINDOW: if specified, the window of which we want to know the number.
If not specified, the number of the currently selected window is
returned."
(let* ((n (winum-get-index window))
(s (if (funcall winum-mode-line-p n)
(format "%s" n)
(let* ((n (winum-get-number window))
(s (if (numberp n)
(int-to-string n)
"")))
(propertize s 'face 'winum-face)))
;;;###autoload
(defun winum-get-number (&optional window)
"Get the current or specified window's current number.
WINDOW: if specified, the window of which we want to know the number.
If not specified, the number of the currently selected window is
returned."
(let ((w (or window (selected-window))))
(gethash w (winum--get-numbers-table))))
;; Internal functions ----------------------------------------------------------
(defun winum--init ()
"Initialize winum-mode."
(setq winum--window-count (length (winum--window-list)))
(if (eq winum-scope 'frame-local)
(setq winum--frames-table (make-hash-table :size winum--max-frames))
(setq winum--window-table (make-hash-table :test 'equal)
winum--index-table (make-hash-table :test 'equal)))
(setq winum--numbers-table (make-hash-table :size winum--window-count)))
(when winum-auto-setup-mode-line
(winum--install-mode-line))
(add-hook 'minibuffer-setup-hook 'winum--update)
@ -458,7 +423,7 @@ WINDOW: if specified, the window of which we want to know the number.
(setq winum--frames-table nil))
(defun winum--install-mode-line (&optional position)
"Install the window index from `winum-mode' to the mode-line.
"Install the window number from `winum-mode' to the mode-line.
POSITION: position in the mode-line."
(let ((mode-line (default-value 'mode-line-format))
res)
@ -475,7 +440,7 @@ POSITION: position in the mode-line."
(force-mode-line-update t))
(defun winum--clear-mode-line ()
"Remove the window index of `winum-mode' from the mode-line."
"Remove the window number of `winum-mode' from the mode-line."
(let ((mode-line (default-value 'mode-line-format))
res)
(while mode-line
@ -488,63 +453,71 @@ POSITION: position in the mode-line."
(force-mode-line-update t))
(defun winum--update ()
"Update window indices."
"Update window numbers."
(let ((windows (winum--window-list)))
(setq winum--assigned-indices nil)
(clrhash (winum--get-window-table))
(clrhash (winum--get-index-table))
(setq winum--window-count (length windows)
winum--remaining (winum--available-numbers))
(winum--set-window-vector (make-vector (1+ winum--window-count) nil))
(clrhash (winum--get-numbers-table))
(when winum-assign-functions
(--each (-copy windows) (when (winum--try-to-find-custom-index it)
(setq windows (delq it windows)))))
(when (and winum-minibuffer-auto-assign
(-each windows #'winum--try-to-find-custom-number))
(when (and winum-auto-assign-0-to-minibuffer
(active-minibuffer-window)
(not (winum-get-window-by-index winum-minibuffer-auto-assign)))
(winum--assign (active-minibuffer-window) winum-minibuffer-auto-assign)
(push winum-minibuffer-auto-assign winum--assigned-indices))
;; Auto-assign remaining windows
(when windows
(funcall winum-auto-assign-function windows))))
(defun winum--auto-assign (windows)
"The default auto-assign function for assigning indices to windows.
Takes in the list of windows WINDOWS and uses `winum--assign' to assign
increasing integers to it."
(let ((index 1))
(not (winum-get-window-by-number 0)))
(winum--assign (active-minibuffer-window) 0))
(dolist (w windows)
(while (member index winum--assigned-indices)
(setq index (1+ index)))
(winum--assign w index)
(setq index (1+ index)))))
(winum--assign w))))
(defun winum--try-to-find-custom-index (window)
"Try to find and assign a custom index for WINDOW.
(defun winum--try-to-find-custom-number (window)
"Try to find and assign a custom number for WINDOW.
Do so by trying every function in `winum-assign-functions' and assign the
*first* non nil value.
When multiple functions assign an index to a window log a warning and use the
first index anyway."
*first* non nil integer.
When multiple functions assign a number to a window log a warning and use the
first number anyway."
(with-selected-window window
(with-current-buffer (window-buffer window)
(when-let* ((inds (->> winum-assign-functions
(let* ((nums (->> winum-assign-functions
(--map (cons it (funcall it)))
(--remove (null (cdr it)))))
(ind (-> inds (cl-first) (cdr))))
(when (> (length inds) 1)
(message "Winum conflict - window %s was assigned an index by multiple custom assign functions: '%s'"
window (--map (format "%s -> %S" (car it) (cdr it)) inds)))
(winum--assign window ind)
(push ind winum--assigned-indices)))))
(num (-> nums (cl-first) (cdr))))
(when (> (length nums) 1)
(message "Winum conflict - window %s was assigned a number by multiple custom assign functions: '%s'"
window (--map (format "%s -> %s" (car it) (cdr it)) nums)))
(when (integerp num) (winum--assign window num))))))
(defun winum--assign (window index)
"Assign to window WINDOW the index INDEX.
Returns the assigned index, or nil on error."
(if (gethash index (winum--get-window-table))
(defun winum--assign (window &optional number)
"Assign to window WINDOW the number NUMBER.
If NUMBER is not specified, determine it first based on `winum--remaining'.
Returns the assigned number, or nil on error."
(if number
(progn
(message "Index %S already assigned to %s, can't assign to %s"
index (gethash index (winum--get-window-table)) window)
(winum--maybe-expand-window-vector number)
(if (aref (winum--get-window-vector) number)
(progn
(message "Number %s already assigned to %s, can't assign to %s"
number (aref (winum--get-window-vector) number) window)
nil)
(puthash index window (winum--get-window-table))
(puthash window index (winum--get-index-table))
index))
(setf (aref (winum--get-window-vector) number) window)
(puthash window number (winum--get-numbers-table))
(setq winum--remaining (delq number winum--remaining))
number))
;; else determine number and assign
(when winum--remaining
(unless (gethash window (winum--get-numbers-table))
(let ((number (car winum--remaining)))
(winum--assign window number))))))
(defun winum--maybe-expand-window-vector (number)
"Expand `winum--window-vector' if NUMBER is bigger than its size.
The size of `winum--window-vector' is normally based on the number of live
windows, however a higher number can be reserved by the user-defined
`winum-assign-func'."
(let* ((window-vector (winum--get-window-vector))
(window-vector-length (length window-vector)))
(when (> number window-vector-length)
(winum--set-window-vector
(vconcat window-vector
(make-vector (1+ (- number window-vector-length)) nil))))))
(defun winum--window-list ()
"Return a list of interesting windows."
@ -564,10 +537,10 @@ Returns the assigned index, or nil on error."
(frame-local
(winum--list-windows-in-frame))
(t
(user-error "Invalid `winum-scope': %S" winum-scope)))))
(error "Invalid `winum-scope': %S" winum-scope)))))
(defun winum--ignore-window-p (window)
"Non-nil if WINDOW should be ignored for indexing."
"Non-nil if WINDOW should be ignored for numbering."
(let ((f (window-frame window)))
(or (not (and (frame-live-p f)
(frame-visible-p f)))
@ -581,25 +554,33 @@ Returns the assigned index, or nil on error."
"List windows in frame F using natural Emacs ordering."
(window-list f 0 (frame-first-window f)))
(defun winum--get-window-table ()
"Return the window table used to get a window given an index.
This hashtable is not stored the same way depending on the value of
`winum-scope'."
(defun winum--set-window-vector (window-vector)
"Set WINDOW-VECTOR according to the current `winum-scope'."
(winum--check-for-scope-change)
(if (eq winum-scope 'frame-local)
(puthash (selected-frame)
(cons window-vector
(make-hash-table :size winum--window-count))
winum--frames-table)
(setq winum--window-vector window-vector)))
(defun winum--get-window-vector ()
"Return the window vector used to get a window given a number.
This vector is not stored the same way depending on the value of `winum-scope'."
(winum--check-for-scope-change)
(winum--check-frames-table)
(if (eq winum-scope 'frame-local)
(car (gethash (selected-frame) winum--frames-table))
winum--window-table))
winum--window-vector))
(defun winum--get-index-table ()
"Return the index hashtable used to get an index given a window.
(defun winum--get-numbers-table ()
"Return the numbers hashtable used to get a number given a window.
This hashtable is not stored the same way depending on the value of
`winum-scope'."
`winum-scope'"
(winum--check-for-scope-change)
(winum--check-frames-table)
(if (eq winum-scope 'frame-local)
(cdr (gethash (selected-frame) winum--frames-table))
winum--index-table))
winum--numbers-table))
(defun winum--check-frames-table ()
"Make sure `winum--frames-table' exists and is correctly equipped.
@ -612,12 +593,17 @@ Verifies 2 things (when `winum-scope' is frame local):
(unless winum--frames-table
(setq winum--frames-table (make-hash-table :size winum--max-frames)))
(unless (gethash (selected-frame) winum--frames-table)
(puthash (selected-frame) (cons
(make-hash-table :test 'equal)
(make-hash-table :test 'equal))
winum--frames-table)
(winum--update))))
(defun winum--available-numbers ()
"Return a list of numbers from 1 to `winum--window-count'.
0 is is not part of the list as its assignment is either manual
using the `winum-assign-func', or using `winum-auto-assign-0-to-minibuffer'."
(let ((numbers))
(dotimes (i winum--window-count)
(push (1+ i) numbers))
(nreverse numbers)))
(defun winum--switch-to-window (window)
"Switch to the window WINDOW and switch input focus if on a different frame."
(let ((frame (window-frame window)))
@ -643,6 +629,10 @@ internal data structures according to the new scope."
(add-hook 'delete-frame-functions #'winum--remove-deleted-frame-from-frames-table)
(push "^No window numbered .$" debug-ignored-errors)
(push "^Got a dead window .$" debug-ignored-errors)
(push "^Invalid `winum-scope': .$" debug-ignored-errors)
(provide 'winum)
;;; winum.el ends here