declare smobs in alloc.c
[bpt/emacs.git] / lisp / linum.el
CommitLineData
2fbc1934 1;;; linum.el --- display line numbers in the left margin -*- lexical-binding: t -*-
8e54981d 2
ba318903 3;; Copyright (C) 2008-2014 Free Software Foundation, Inc.
8e54981d
JB
4
5;; Author: Markus Triska <markus.triska@gmx.at>
34dc21db 6;; Maintainer: emacs-devel@gnu.org
8e54981d 7;; Keywords: convenience
aad4679e 8;; Version: 0.9x
8e54981d
JB
9
10;; This file is part of GNU Emacs.
11
12;; GNU Emacs is free software: you can redistribute it and/or modify
13;; it under the terms of the GNU General Public License as published by
14;; the Free Software Foundation, either version 3 of the License, or
15;; (at your option) any later version.
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
23;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
24
25;;; Commentary:
26
27;; Display line numbers for the current buffer.
28;;
29;; Toggle display of line numbers with M-x linum-mode. To enable
30;; line numbering in all buffers, use M-x global-linum-mode.
31
32;;; Code:
33
34(defconst linum-version "0.9x")
35
36(defvar linum-overlays nil "Overlays used in this buffer.")
37(defvar linum-available nil "Overlays available for reuse.")
38(defvar linum-before-numbering-hook nil
39 "Functions run in each buffer before line numbering starts.")
40
41(mapc #'make-variable-buffer-local '(linum-overlays linum-available))
42
43(defgroup linum nil
44 "Show line numbers in the left margin."
45 :group 'convenience)
46
8e54981d
JB
47(defcustom linum-format 'dynamic
48 "Format used to display line numbers.
49Either a format string like \"%7d\", `dynamic' to adapt the width
50as needed, or a function that is called with a line number as its
51argument and should evaluate to a string to be shown on that line.
52See also `linum-before-numbering-hook'."
53 :group 'linum
8e5064e5
GM
54 :type '(choice (string :tag "Format string")
55 (const :tag "Dynamic width" dynamic)
56 (function :tag "Function")))
8e54981d
JB
57
58(defface linum
59 '((t :inherit (shadow default)))
60 "Face for displaying line numbers in the display margin."
61 :group 'linum)
62
63(defcustom linum-eager t
64 "Whether line numbers should be updated after each command.
65The conservative setting `nil' might miss some buffer changes,
66and you have to scroll or press \\[recenter-top-bottom] to update the numbers."
67 :group 'linum
68 :type 'boolean)
69
70(defcustom linum-delay nil
71 "Delay updates to give Emacs a chance for other changes."
72 :group 'linum
73 :type 'boolean)
74
75;;;###autoload
76(define-minor-mode linum-mode
06e21633
CY
77 "Toggle display of line numbers in the left margin (Linum mode).
78With a prefix argument ARG, enable Linum mode if ARG is positive,
79and disable it otherwise. If called from Lisp, enable the mode
80if ARG is omitted or nil.
81
82Linum mode is a buffer-local minor mode."
8e54981d
JB
83 :lighter "" ; for desktop.el
84 (if linum-mode
85 (progn
86 (if linum-eager
87 (add-hook 'post-command-hook (if linum-delay
88 'linum-schedule
89 'linum-update-current) nil t)
90 (add-hook 'after-change-functions 'linum-after-change nil t))
91 (add-hook 'window-scroll-functions 'linum-after-scroll nil t)
b932657b
SM
92 ;; Using both window-size-change-functions and
93 ;; window-configuration-change-hook seems redundant. --Stef
94 ;; (add-hook 'window-size-change-functions 'linum-after-size nil t)
8e54981d
JB
95 (add-hook 'change-major-mode-hook 'linum-delete-overlays nil t)
96 (add-hook 'window-configuration-change-hook
b932657b
SM
97 ;; FIXME: If the buffer is shown in N windows, this
98 ;; will be called N times rather than once. We should use
99 ;; something like linum-update-window instead.
100 'linum-update-current nil t)
8e54981d
JB
101 (linum-update-current))
102 (remove-hook 'post-command-hook 'linum-update-current t)
103 (remove-hook 'post-command-hook 'linum-schedule t)
b932657b 104 ;; (remove-hook 'window-size-change-functions 'linum-after-size t)
8e54981d
JB
105 (remove-hook 'window-scroll-functions 'linum-after-scroll t)
106 (remove-hook 'after-change-functions 'linum-after-change t)
b932657b 107 (remove-hook 'window-configuration-change-hook 'linum-update-current t)
8e54981d
JB
108 (remove-hook 'change-major-mode-hook 'linum-delete-overlays t)
109 (linum-delete-overlays)))
110
111;;;###autoload
112(define-globalized-minor-mode global-linum-mode linum-mode linum-on)
113
114(defun linum-on ()
115 (unless (minibufferp)
116 (linum-mode 1)))
117
118(defun linum-delete-overlays ()
119 "Delete all overlays displaying line numbers for this buffer."
120 (mapc #'delete-overlay linum-overlays)
121 (setq linum-overlays nil)
122 (dolist (w (get-buffer-window-list (current-buffer) nil t))
245be23c 123 (set-window-margins w 0 (cdr (window-margins w)))))
8e54981d
JB
124
125(defun linum-update-current ()
126 "Update line numbers for the current buffer."
127 (linum-update (current-buffer)))
128
129(defun linum-update (buffer)
130 "Update line numbers for all windows displaying BUFFER."
131 (with-current-buffer buffer
132 (when linum-mode
133 (setq linum-available linum-overlays)
134 (setq linum-overlays nil)
135 (save-excursion
136 (mapc #'linum-update-window
137 (get-buffer-window-list buffer nil 'visible)))
138 (mapc #'delete-overlay linum-available)
139 (setq linum-available nil))))
140
141(defun linum-update-window (win)
142 "Update line numbers for the portion visible in window WIN."
143 (goto-char (window-start win))
144 (let ((line (line-number-at-pos))
145 (limit (window-end win t))
146 (fmt (cond ((stringp linum-format) linum-format)
147 ((eq linum-format 'dynamic)
148 (let ((w (length (number-to-string
149 (count-lines (point-min) (point-max))))))
150 (concat "%" (number-to-string w) "d")))))
151 (width 0))
152 (run-hooks 'linum-before-numbering-hook)
153 ;; Create an overlay (or reuse an existing one) for each
154 ;; line visible in this window, if necessary.
fdab3d0b 155 (while (and (not (eobp)) (< (point) limit))
8e54981d
JB
156 (let* ((str (if fmt
157 (propertize (format fmt line) 'face 'linum)
158 (funcall linum-format line)))
159 (visited (catch 'visited
160 (dolist (o (overlays-in (point) (point)))
0ca77a92
JB
161 (when (equal-including-properties
162 (overlay-get o 'linum-str) str)
8e54981d
JB
163 (unless (memq o linum-overlays)
164 (push o linum-overlays))
0ca77a92 165 (setq linum-available (delq o linum-available))
8e54981d
JB
166 (throw 'visited t))))))
167 (setq width (max width (length str)))
168 (unless visited
169 (let ((ov (if (null linum-available)
170 (make-overlay (point) (point))
171 (move-overlay (pop linum-available) (point) (point)))))
172 (push ov linum-overlays)
173 (overlay-put ov 'before-string
174 (propertize " " 'display `((margin left-margin) ,str)))
175 (overlay-put ov 'linum-str str))))
d204c46c
SM
176 ;; Text may contain those nasty intangible properties, but that
177 ;; shouldn't prevent us from counting those lines.
178 (let ((inhibit-point-motion-hooks t))
179 (forward-line))
8e54981d 180 (setq line (1+ line)))
245be23c 181 (set-window-margins win width (cdr (window-margins win)))))
8e54981d 182
2fbc1934 183(defun linum-after-change (beg end _len)
8e54981d
JB
184 ;; update overlays on deletions, and after newlines are inserted
185 (when (or (= beg end)
186 (= end (point-max))
187 (string-match-p "\n" (buffer-substring-no-properties beg end)))
188 (linum-update-current)))
189
2fbc1934 190(defun linum-after-scroll (win _start)
8e54981d
JB
191 (linum-update (window-buffer win)))
192
b932657b
SM
193;; (defun linum-after-size (frame)
194;; (linum-after-config))
8e54981d
JB
195
196(defun linum-schedule ()
197 ;; schedule an update; the delay gives Emacs a chance for display changes
198 (run-with-idle-timer 0 nil #'linum-update-current))
199
b932657b
SM
200;; (defun linum-after-config ()
201;; (walk-windows (lambda (w) (linum-update (window-buffer w))) nil 'visible))
8e54981d
JB
202
203(defun linum-unload-function ()
204 "Unload the Linum library."
205 (global-linum-mode -1)
206 ;; continue standard unloading
207 nil)
208
209(provide 'linum)
210
8e54981d 211;;; linum.el ends here