window-numbering.el 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. ;;; window-numbering.el --- Numbered window shortcuts
  2. ;;
  3. ;; Copyright (C) 2006-2007, 2013, 2015 Nikolaj Schumacher <bugs * nschum , de>
  4. ;;
  5. ;; Author: Nikolaj Schumacher <bugs * nschum de>
  6. ;; Version: 1.1.2
  7. ;; Keywords: faces, matching
  8. ;; URL: http://nschum.de/src/emacs/window-numbering-mode/
  9. ;; Compatibility: GNU Emacs 22.x, GNU Emacs 23.x, GNU Emacs 24.x
  10. ;;
  11. ;; This file is NOT part of GNU Emacs.
  12. ;;
  13. ;; This program is free software; you can redistribute it and/or
  14. ;; modify it under the terms of the GNU General Public License
  15. ;; as published by the Free Software Foundation; either version 2
  16. ;; of the License, or (at your option) any later version.
  17. ;;
  18. ;; This program is distributed in the hope that it will be useful,
  19. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. ;; GNU General Public License for more details.
  22. ;;
  23. ;; You should have received a copy of the GNU General Public License
  24. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  25. ;;
  26. ;;; Commentary:
  27. ;;
  28. ;; Enable window-numbering-mode and use M-1 through M-0 to navigate.
  29. ;;
  30. ;; If you want to affect the numbers, use window-numbering-before-hook or
  31. ;; window-numbering-assign-func.
  32. ;; For instance, to always assign the calculator window the number 9, add the
  33. ;; following to your .emacs:
  34. ;;
  35. ;; (setq window-numbering-assign-func
  36. ;; (lambda () (when (equal (buffer-name) "*Calculator*") 9)))
  37. ;;
  38. ;;; Changes Log:
  39. ;;
  40. ;; Fix numbering of minibuffer for recent Emacs versions.
  41. ;;
  42. ;; 2013-03-23 (1.1.2)
  43. ;; Fix numbering in terminal mode with menu bar visible.
  44. ;; Add face for window number. (thanks to Chen Bin)
  45. ;;
  46. ;; 2008-04-11 (1.1.1)
  47. ;; Added possibility to delete window with prefix arg.
  48. ;; Cleaned up code and migrated to `defcustom'.
  49. ;;
  50. ;; 2007-02-18 (1.1)
  51. ;; Added window-numbering-before-hook, window-numbering-assign-func.
  52. ;;
  53. ;;; Code:
  54. (eval-when-compile (require 'cl))
  55. (push "^No window numbered .$" debug-ignored-errors)
  56. (defgroup window-numbering nil
  57. "Numbered window shortcuts"
  58. :group 'convenience)
  59. (defcustom window-numbering-auto-assign-0-to-minibuffer t
  60. "*If non-nil, `window-numbering-mode' assigns 0 to the minibuffer if active."
  61. :group 'window-numbering
  62. :type '(choice (const :tag "Off" nil)
  63. (const :tag "On" t)))
  64. (defcustom window-numbering-before-hook nil
  65. "*Hook called before `window-numbering-mode' starts assigning numbers.
  66. The number of windows that will be numbered is passed as a parameter.
  67. Use `window-numbering-assign' to manually assign some of them a number.
  68. If you want to assign a number to just one buffer, use
  69. `window-numbering-assign-func' instead."
  70. :group 'window-numbering
  71. :type 'hook)
  72. (defcustom window-numbering-assign-func nil
  73. "*Function called for each window by `window-numbering-mode'.
  74. This is called before automatic assignment begins. The function should
  75. return a number to have it assigned to the current-window, nil otherwise."
  76. :group 'window-numbering
  77. :type 'function)
  78. (defconst window-numbering-mode-line-position 1
  79. "The position in the mode-line `window-numbering-mode' displays the number.")
  80. (defface window-numbering-face
  81. '()
  82. "Face used for the number in the mode-line."
  83. :group 'window-numbering)
  84. (defvar window-numbering-table nil
  85. "table -> (window vector . number table)")
  86. (defun select-window-by-number (i &optional arg)
  87. "Select window given number I by `window-numbering-mode'.
  88. If prefix ARG is given, delete the window instead of selecting it."
  89. (interactive "P")
  90. (let ((windows (car (gethash (selected-frame) window-numbering-table)))
  91. window)
  92. (if (and (>= i 0) (< i 10)
  93. (setq window (aref windows i)))
  94. (if arg
  95. (delete-window window)
  96. (select-window window))
  97. (error "No window numbered %s" i))))
  98. ;; define interactive functions for keymap
  99. (dotimes (i 10)
  100. (eval `(defun ,(intern (format "select-window-%s" i)) (&optional arg)
  101. ,(format "Select the window with number %i." i)
  102. (interactive "P")
  103. (select-window-by-number ,i arg))))
  104. (defun window-numbering-calculate-left (windows)
  105. (let ((i 9) left)
  106. (while (>= i 0)
  107. (let ((window (aref windows i)))
  108. (unless window
  109. (push (% (1+ i) 10) left)))
  110. (decf i))
  111. left))
  112. (defvar window-numbering-windows nil
  113. "A vector listing the window for each number.")
  114. (defvar window-numbering-numbers
  115. "A hash map containing each window's number.")
  116. (defvar window-numbering-left
  117. "A list of unused window numbers.")
  118. (defun window-numbering-assign (window &optional number)
  119. (if number
  120. (if (aref window-numbering-windows number)
  121. (progn (message "Number %s assigned to two buffers (%s and %s)"
  122. number window (aref window-numbering-windows number))
  123. nil)
  124. (setf (aref window-numbering-windows number) window)
  125. (puthash window number window-numbering-numbers)
  126. (setq window-numbering-left (delq number window-numbering-left))
  127. t)
  128. ;; else default adding
  129. (when window-numbering-left
  130. (unless (gethash window window-numbering-numbers)
  131. (let ((number (car window-numbering-left)))
  132. (window-numbering-assign window number)
  133. number)))))
  134. (defun window-numbering-update ()
  135. "Update the window numbering for the current frame.
  136. Optional parameter PREASSIGNED-WINDOWS is a hashmap already mapping some
  137. windows to numbers."
  138. (setq window-numbering-windows (make-vector 10 nil)
  139. window-numbering-numbers (make-hash-table :size 10)
  140. window-numbering-left
  141. (window-numbering-calculate-left window-numbering-windows))
  142. (puthash (selected-frame)
  143. (cons window-numbering-windows window-numbering-numbers)
  144. window-numbering-table)
  145. (when (and window-numbering-auto-assign-0-to-minibuffer
  146. (active-minibuffer-window))
  147. (window-numbering-assign (active-minibuffer-window) 0))
  148. (let ((windows (window-list nil 0 (frame-first-window))))
  149. (run-hook-with-args 'window-numbering-before-hook windows)
  150. (when window-numbering-assign-func
  151. (mapc (lambda (window)
  152. (with-selected-window window
  153. (with-current-buffer (window-buffer window)
  154. (let ((num (funcall window-numbering-assign-func)))
  155. (when num
  156. (window-numbering-assign window num))))))
  157. windows))
  158. (dolist (window windows)
  159. (window-numbering-assign window))))
  160. (defun window-numbering-get-number-string (&optional window)
  161. (let ((s (int-to-string (window-numbering-get-number window))))
  162. (propertize s 'face 'window-numbering-face)))
  163. (defun window-numbering-get-number (&optional window)
  164. (gethash (or window (selected-window))
  165. (cdr (gethash (selected-frame) window-numbering-table))))
  166. (defvar window-numbering-keymap
  167. (let ((map (make-sparse-keymap)))
  168. (define-key map "\M-0" 'select-window-0)
  169. (define-key map "\M-1" 'select-window-1)
  170. (define-key map "\M-2" 'select-window-2)
  171. (define-key map "\M-3" 'select-window-3)
  172. (define-key map "\M-4" 'select-window-4)
  173. (define-key map "\M-5" 'select-window-5)
  174. (define-key map "\M-6" 'select-window-6)
  175. (define-key map "\M-7" 'select-window-7)
  176. (define-key map "\M-8" 'select-window-8)
  177. (define-key map "\M-9" 'select-window-9)
  178. map)
  179. "Keymap used in by `window-numbering-mode'.")
  180. ;;;###autoload
  181. (define-minor-mode window-numbering-mode
  182. "A minor mode that assigns a number to each window."
  183. nil nil window-numbering-keymap :global t
  184. (if window-numbering-mode
  185. (unless window-numbering-table
  186. (save-excursion
  187. (setq window-numbering-table (make-hash-table :size 16))
  188. (window-numbering-install-mode-line)
  189. (add-hook 'minibuffer-setup-hook 'window-numbering-update)
  190. (add-hook 'window-configuration-change-hook
  191. 'window-numbering-update)
  192. (dolist (frame (frame-list))
  193. (select-frame frame)
  194. (window-numbering-update))))
  195. (window-numbering-clear-mode-line)
  196. (remove-hook 'minibuffer-setup-hook 'window-numbering-update)
  197. (remove-hook 'window-configuration-change-hook
  198. 'window-numbering-update)
  199. (setq window-numbering-table nil)))
  200. (defun window-numbering-install-mode-line (&optional position)
  201. "Install the window number from `window-numbering-mode' to the mode-line."
  202. (let ((mode-line (default-value 'mode-line-format))
  203. (res))
  204. (dotimes (i (min (or position window-numbering-mode-line-position)
  205. (length mode-line)))
  206. (push (car mode-line) res)
  207. (pop mode-line))
  208. (push '(:eval (window-numbering-get-number-string)) res)
  209. (while mode-line
  210. (push (car mode-line) res)
  211. (pop mode-line))
  212. (setq-default mode-line-format (nreverse res)))
  213. (force-mode-line-update t))
  214. (defun window-numbering-clear-mode-line ()
  215. "Remove the window number of `window-numbering-mode' from the mode-line."
  216. (let ((mode-line (default-value 'mode-line-format))
  217. (res))
  218. (while mode-line
  219. (let ((item (car mode-line)))
  220. (unless (equal item '(:eval (window-numbering-get-number-string)))
  221. (push item res)))
  222. (pop mode-line))
  223. (setq-default mode-line-format (nreverse res)))
  224. (force-mode-line-update t))
  225. (provide 'window-numbering)
  226. ;;; window-numbering.el ends here