declare smobs in alloc.c
[bpt/emacs.git] / lisp / linum.el
index 41fe2de..bbf7ebe 100644 (file)
@@ -1,10 +1,11 @@
-;;; linum.el --- display line numbers in the left margin
+;;; linum.el --- display line numbers in the left margin -*- lexical-binding: t -*-
 
-;; Copyright (C) 2008 Free Software Foundation, Inc.
+;; Copyright (C) 2008-2014 Free Software Foundation, Inc.
 
 ;; Author: Markus Triska <markus.triska@gmx.at>
-;; Maintainer: FSF
+;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: convenience
+;; Version: 0.9x
 
 ;; This file is part of GNU Emacs.
 
@@ -30,7 +31,7 @@
 
 ;;; Code:
 
-(defconst linum-version "0.9wx")
+(defconst linum-version "0.9x")
 
 (defvar linum-overlays nil "Overlays used in this buffer.")
 (defvar linum-available nil "Overlays available for reuse.")
@@ -43,7 +44,6 @@
   "Show line numbers in the left margin."
   :group 'convenience)
 
-;;;###autoload
 (defcustom linum-format 'dynamic
   "Format used to display line numbers.
 Either a format string like \"%7d\", `dynamic' to adapt the width
@@ -51,10 +51,12 @@ as needed, or a function that is called with a line number as its
 argument and should evaluate to a string to be shown on that line.
 See also `linum-before-numbering-hook'."
   :group 'linum
-  :type 'sexp)
+  :type '(choice (string :tag "Format string")
+                 (const :tag "Dynamic width" dynamic)
+                 (function :tag "Function")))
 
 (defface linum
-  '((t :inherit shadow))
+  '((t :inherit (shadow default)))
   "Face for displaying line numbers in the display margin."
   :group 'linum)
 
@@ -65,14 +67,19 @@ and you have to scroll or press \\[recenter-top-bottom] to update the numbers."
   :group 'linum
   :type 'boolean)
 
-(defcustom linum-delay t
+(defcustom linum-delay nil
   "Delay updates to give Emacs a chance for other changes."
   :group 'linum
   :type 'boolean)
 
 ;;;###autoload
 (define-minor-mode linum-mode
-  "Toggle display of line numbers in the left margin."
+  "Toggle display of line numbers in the left margin (Linum mode).
+With a prefix argument ARG, enable Linum mode if ARG is positive,
+and disable it otherwise.  If called from Lisp, enable the mode
+if ARG is omitted or nil.
+
+Linum mode is a buffer-local minor mode."
   :lighter ""                           ; for desktop.el
   (if linum-mode
       (progn
@@ -82,18 +89,22 @@ and you have to scroll or press \\[recenter-top-bottom] to update the numbers."
                                            'linum-update-current) nil t)
           (add-hook 'after-change-functions 'linum-after-change nil t))
         (add-hook 'window-scroll-functions 'linum-after-scroll nil t)
-        ;; mistake in Emacs: window-size-change-functions cannot be local
-        (add-hook 'window-size-change-functions 'linum-after-size)
+        ;; Using both window-size-change-functions and
+        ;; window-configuration-change-hook seems redundant. --Stef
+        ;; (add-hook 'window-size-change-functions 'linum-after-size nil t)
         (add-hook 'change-major-mode-hook 'linum-delete-overlays nil t)
         (add-hook 'window-configuration-change-hook
-                  'linum-after-config nil t)
+                  ;; FIXME: If the buffer is shown in N windows, this
+                  ;; will be called N times rather than once.  We should use
+                  ;; something like linum-update-window instead.
+                  'linum-update-current nil t)
         (linum-update-current))
     (remove-hook 'post-command-hook 'linum-update-current t)
     (remove-hook 'post-command-hook 'linum-schedule t)
-    (remove-hook 'window-size-change-functions 'linum-after-size)
+    ;; (remove-hook 'window-size-change-functions 'linum-after-size t)
     (remove-hook 'window-scroll-functions 'linum-after-scroll t)
     (remove-hook 'after-change-functions 'linum-after-change t)
-    (remove-hook 'window-configuration-change-hook 'linum-after-config t)
+    (remove-hook 'window-configuration-change-hook 'linum-update-current t)
     (remove-hook 'change-major-mode-hook 'linum-delete-overlays t)
     (linum-delete-overlays)))
 
@@ -109,7 +120,7 @@ and you have to scroll or press \\[recenter-top-bottom] to update the numbers."
   (mapc #'delete-overlay linum-overlays)
   (setq linum-overlays nil)
   (dolist (w (get-buffer-window-list (current-buffer) nil t))
-    (set-window-margins w 0)))
+    (set-window-margins w 0 (cdr (window-margins w)))))
 
 (defun linum-update-current ()
   "Update line numbers for the current buffer."
@@ -131,62 +142,63 @@ and you have to scroll or press \\[recenter-top-bottom] to update the numbers."
   "Update line numbers for the portion visible in window WIN."
   (goto-char (window-start win))
   (let ((line (line-number-at-pos))
-        (limit (1+ (window-end win t)))
+        (limit (window-end win t))
         (fmt (cond ((stringp linum-format) linum-format)
                    ((eq linum-format 'dynamic)
                     (let ((w (length (number-to-string
                                       (count-lines (point-min) (point-max))))))
                       (concat "%" (number-to-string w) "d")))))
-        (width 0)
-        visited
-        ov)
+        (width 0))
     (run-hooks 'linum-before-numbering-hook)
     ;; Create an overlay (or reuse an existing one) for each
     ;; line visible in this window, if necessary.
     (while (and (not (eobp)) (< (point) limit))
-      (setq visited nil)
-      (dolist (o (overlays-in (point) (point)))
-        (when (eq (overlay-get o 'linum-line) line)
-          (unless (memq o linum-overlays)
-            (push o linum-overlays))
-          (setq linum-available (delete o linum-available))
-          (setq visited t)))
-      (let ((str (if fmt
-                     (propertize (format fmt line) 'face 'linum)
-                   (funcall linum-format line))))
+      (let* ((str (if fmt
+                      (propertize (format fmt line) 'face 'linum)
+                    (funcall linum-format line)))
+             (visited (catch 'visited
+                        (dolist (o (overlays-in (point) (point)))
+                          (when (equal-including-properties
+                                (overlay-get o 'linum-str) str)
+                            (unless (memq o linum-overlays)
+                              (push o linum-overlays))
+                            (setq linum-available (delq o linum-available))
+                            (throw 'visited t))))))
         (setq width (max width (length str)))
         (unless visited
-          (if (null linum-available)
-              (setq ov (make-overlay (point) (point)))
-            (setq ov (pop linum-available))
-            (move-overlay ov (point) (point)))
-          (push ov linum-overlays)
-          (setq str (propertize " " 'display `((margin left-margin) ,str)))
-          (overlay-put ov 'before-string str)
-          (overlay-put ov 'linum-line line)))
-      (forward-line)
+          (let ((ov (if (null linum-available)
+                        (make-overlay (point) (point))
+                      (move-overlay (pop linum-available) (point) (point)))))
+            (push ov linum-overlays)
+            (overlay-put ov 'before-string
+                         (propertize " " 'display `((margin left-margin) ,str)))
+            (overlay-put ov 'linum-str str))))
+      ;; Text may contain those nasty intangible properties, but that
+      ;; shouldn't prevent us from counting those lines.
+      (let ((inhibit-point-motion-hooks t))
+        (forward-line))
       (setq line (1+ line)))
-    (set-window-margins win width)))
+    (set-window-margins win width (cdr (window-margins win)))))
 
-(defun linum-after-change (beg end len)
+(defun linum-after-change (beg end _len)
   ;; update overlays on deletions, and after newlines are inserted
   (when (or (= beg end)
             (= end (point-max))
             (string-match-p "\n" (buffer-substring-no-properties beg end)))
     (linum-update-current)))
 
-(defun linum-after-scroll (win start)
+(defun linum-after-scroll (win _start)
   (linum-update (window-buffer win)))
 
-(defun linum-after-size (frame)
-  (linum-after-config))
+;; (defun linum-after-size (frame)
+;;   (linum-after-config))
 
 (defun linum-schedule ()
   ;; schedule an update; the delay gives Emacs a chance for display changes
   (run-with-idle-timer 0 nil #'linum-update-current))
 
-(defun linum-after-config ()
-  (walk-windows (lambda (w) (linum-update (window-buffer w))) nil 'visible))
+;; (defun linum-after-config ()
+;;   (walk-windows (lambda (w) (linum-update (window-buffer w))) nil 'visible))
 
 (defun linum-unload-function ()
   "Unload the Linum library."
@@ -196,5 +208,4 @@ and you have to scroll or press \\[recenter-top-bottom] to update the numbers."
 
 (provide 'linum)
 
-;; arch-tag: dea45631-ed3c-4867-8b49-1c41c80aec6a
 ;;; linum.el ends here