emacs-winum icon indicating copy to clipboard operation
emacs-winum copied to clipboard

Window numbers for Emacs - Navigate windows and frames using numbers

#+TITLE: Window numbers for Emacs !

[[https://github.com/syl20bnr/spacemacs][file:https://cdn.rawgit.com/syl20bnr/spacemacs/442d025779da2f62fc86c2082703697714db6514/assets/spacemacs-badge.svg]] [[https://melpa.org/#/winum][file:https://melpa.org/packages/winum-badge.svg]] [[https://stable.melpa.org/#/winum][file:https://stable.melpa.org/packages/winum-badge.svg]]

  • Contents :TOC:noexport:
  • [[#introduction][Introduction]]
  • [[#changelog][Changelog]]
    • [[#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]]
  • [[#installation][Installation]]
    • [[#using-melpa][Using Melpa]]
    • [[#manual-installation][Manual installation]]
  • [[#how-to-use][How to use]]
  • [[#configuration][Configuration]]
    • [[#keybindings][Keybindings]]
    • [[#customize-options][Customize options]]
    • [[#configuration-file-example][Configuration file example]]
  • [[#future-developments][Future developments]]
  • Introduction Window numbers for Emacs: Navigate your windows and frames using numbers !

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]].

This version brings, among other things, support for number sets across multiple frames, giving the user a smoother experience of multi-screen Emacs.

  • Changelog ** Sep. 11 2019
  • Added customize variable =winum-ignored-buffers-regexp= to ignored buffers based on regexps. ** Nov. 15 2018
  • Added customize variable =winum-format=, a format string to configure how the window number appears in the mode-line

** Initial release: what's changed since window-numbering This package brings a lot of additions to the old window-numbering:

  • Number sets across multiple frames, giving a smoother experience of multi-screen Emacs
  • 3 possible scopes: frame-local, visible frames or all frames
  • =get-window-by-number= public function, needed in Spacemacs and for future developments.
  • Unlimited window numbers
  • =select-window-by-number= can now be used interactively to select a window using prefix arg or =read-from-minibuffer=, allowing the selection of an unlimited number.
  • Ignore buffers by name
  • =;;;###autoload= all functions that should have public visibility
  • Improved =customize= integration
  • Removed =window-numbering-before-assign-hook=, which just duplicated =window-numbering-assign-func= in a more complicated fashion
  • New default key bindings under the ~C-x w~ prefix, to be compliant with Emacs key bindings conventions and native Emacs key bindings
  • =winum-set-keymap-prefix= helper function to change the prefix more easily
  • More detailed README.org
  • Improved docstrings
  • Simplified implementation for better readability
  • Installation ** Using Melpa The recommended way of installing =winum= is from the [[https://melpa.org/#/winum][Melpa]] package repository:

#+BEGIN_SRC emacs-lisp M-x package-install RET winum RET #+END_SRC

You will find instructions to setup Melpa [[https://github.com/melpa/melpa#usage][here]] if you don't have it setup yet.

Once the package is installed, you need to load and activate =winum-mode= in your Emacs configuration:

#+BEGIN_SRC emacs-lisp (require 'winum)

(winum-mode) #+END_SRC

** Manual installation

  • Clone the repo:

#+BEGIN_SRC shell cd /path/to/install/folder git clone https://github.com/deb0ch/emacs-winum #+END_SRC

  • Add the following to your Emacs configuration:

#+BEGIN_SRC emacs-lisp (add-to-list 'load-path "/path/to/install/folder/emacs-winum/")

(require 'winum)

(winum-mode) #+END_SRC

  • How to use | Key binding | Description | |-------------+---------------------------------------------------------------------------------------------| | ~C-x w ~ | select window , where ranges from 0 to 9. A negative argument deletes the window. | | ~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=

    By default, ~C-x w 0~ is bound to =select-window-0-or-10=. If window 0 is not assigned, it will act on the window 10 instead.

    You can rebind this to the more straightforward =select-window-0= if you prefer.

  • =select-window-by-number=

    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 ig given, a number is read from minibuffer. A negative input will delete the window instead of selecting it.
  • Configuration ** Keybindings The default prefix for key bindings is ~C-x w~ for compatibility with native Emacs bindings.

If you don't like ~C-x w~, you can set a prefix of your choosing using the function =winum-set-keymap-prefix=:

#+BEGIN_SRC elisp (winum-set-keymap-prefix (kbd "C-c")) #+END_SRC

This function overrides the value of =winum-keymap=, so you should call it before customization of =winum-keymap= and/or after customization of =winum-base-map=. Its argument must be a key sequence, like the ones returned by =kbd=.

If you prefer no to use a prefix and have even shorter bindings, you can also 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-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) (define-key map (kbd "M-3") 'winum-select-window-3) (define-key map (kbd "M-4") 'winum-select-window-4) (define-key map (kbd "M-5") 'winum-select-window-5) (define-key map (kbd "M-6") 'winum-select-window-6) (define-key map (kbd "M-7") 'winum-select-window-7) (define-key map (kbd "M-8") 'winum-select-window-8) map))

(require 'winum)

(winum-mode) #+END_SRC

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-number) #+END_SRC

NB: Both ~`~ and ~²~ are mapped to =winum-select-window-by-number= by default to handle both =qwerty= and =azerty= keyboard layouts. If you are using a different kind of layout, the recommended place to map it is the key beside ~1~.

** Customize options Several options are available through Emacs' Customize interface under =convenience= > =winum=:

  • =winum-scope=

    Frames affected by a number set. Choices are 'frame-local 'visible or 'global.

    Default: 'global

  • =winum-reverse-frame-list=

    If t, order frames by reverse order of creation. Has effect only when =winum-scope= is not 'frame-local.

    Default: =nil=

  • =winum-auto-assign-0-to-minibuffer=

    If non-nil, =winum-mode= assigns 0 to the minibuffer if active.

    Default: =t=

  • =winum-assign-functions=

    List of functions called for each window by `winum-mode'.

    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 more than 1 function assigns a number a warning will be logged in the messages buffer).

    If the list is empty or if every function returns nil for a given window winum 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 and NeoTree the number 0:

    #+BEGIN_SRC emacs-lisp (defun winum-assign-9-to-calculator-8-to-flycheck-errors () (cond ((equal (buffer-name) "Calculator") 9) ((equal (buffer-name) "Flycheck errors") 8)))

    (defun winum-assign-0-to-neotree () (when (string-match-p (buffer-name) ".\NeoTree\.") 10))

    (add-to-list 'winum-assign-functions #'winum-assign-9-to-calculator-8-to-flycheck-errors) (add-to-list 'winum-assign-functions #'winum-assign-0-to-neotree) #+END_SRC

    Default: =nil=

  • =winum-auto-setup-mode-line=

    When nil, =winum-mode= will not display window numbers in the mode-line. You might want this to be nil if you use a package that already manages window numbers in the mode-line.

    Default: =t=

  • =winum-format=

    Format string defining how the window number looks like in the mode-line. This string is passed to the =format= function along with the result of =winum-get-number-string=.

    Default: =" %s "=

  • =winum-mode-line-position=

    The position in the mode-line =winum-mode= displays the number.

    Default: =1=

  • =winum-ignored-buffers=

    List of buffers to ignore when assigning numbers.

    Default: '(" which-key")

  • =winum-ignored-buffers-regexp=

    List of regexps for buffer names. Matching buffers will be ignored when assigning numbers. See [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Regexps.html][Emacs' documentation on regexps]] for syntax.

    Default: '()

  • face: =winum-face=

    Face used for the number in the mode-line.

** Configuration file example Here is an example that you could put in your =.emacs=, which includes all available winum options.

#+BEGIN_SRC emacs-lisp (setq winum-keymap (let ((map (make-sparse-keymap))) (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) (define-key map (kbd "M-3") 'winum-select-window-3) (define-key map (kbd "M-4") 'winum-select-window-4) (define-key map (kbd "M-5") 'winum-select-window-5) (define-key map (kbd "M-6") 'winum-select-window-6) (define-key map (kbd "M-7") 'winum-select-window-7) (define-key map (kbd "M-8") 'winum-select-window-8) map))

(require 'winum)

(defun winum-assign-9-to-calculator-8-to-flycheck-errors () (cond ((equal (buffer-name) "Calculator") 9) ((equal (buffer-name) "Flycheck errors") 8)))

(defun winum-assign-0-to-neotree () (when (string-match-p (buffer-name) ".\NeoTree\.") 10))

(add-to-list 'winum-assign-functions #'winum-assign-9-to-calculator-8-to-flycheck-errors) (add-to-list 'winum-assign-functions #'winum-assign-0-to-neotree)

(set-face-attribute 'winum-face nil :weight 'bold)

(setq window-numbering-scope 'global winum-reverse-frame-list nil winum-auto-assign-0-to-minibuffer t winum-assign-func 'my-winum-assign-func winum-auto-setup-mode-line t winum-format " %s " winum-mode-line-position 1 winum-ignored-buffers '(" which-key") winum-ignored-buffers-regexp '(" \Treemacs-."))

(winum-mode) #+END_SRC

  • Future developments
  • send buffer to numbered window

    Send current window's buffer to window N. With prefix argument focus will follow.

  • swap buffer with numbered window

    Same as previous, but will swap buffers instead of just sending them.

  • Evilify

    Adapt the package to the famous evil-mode and use a leader key.

  • Override native =other-window= (~C-x o~) to use window numbers

  • Autocomplete read-from-minibuffer

  • Things that you have thought of and I haven't :smile_cat: