]> code.delx.au - gnu-emacs/blobdiff - lisp/linum.el
Merge from origin/emacs-25
[gnu-emacs] / lisp / linum.el
index db6e4c49977c6da1dfbf0fa67227926dd23e697f..122f8e31d5726908d20f9063910a0ca625e907d8 100644 (file)
@@ -1,9 +1,9 @@
 ;;; linum.el --- display line numbers in the left margin -*- lexical-binding: t -*-
 
-;; Copyright (C) 2008-2011 Free Software Foundation, Inc.
+;; Copyright (C) 2008-2016 Free Software Foundation, Inc.
 
 ;; Author: Markus Triska <markus.triska@gmx.at>
-;; Maintainer: FSF
+;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: convenience
 ;; Version: 0.9x
 
@@ -44,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
@@ -52,7 +51,9 @@ 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 default)))
@@ -61,7 +62,7 @@ See also `linum-before-numbering-hook'."
 
 (defcustom linum-eager t
   "Whether line numbers should be updated after each command.
-The conservative setting `nil' might miss some buffer changes,
+The conservative setting nil might miss some buffer changes,
 and you have to scroll or press \\[recenter-top-bottom] to update the numbers."
   :group 'linum
   :type 'boolean)
@@ -73,7 +74,12 @@ and you have to scroll or press \\[recenter-top-bottom] to update the numbers."
 
 ;;;###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
@@ -114,7 +120,15 @@ 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 (cdr (window-margins w)))))
+    ;; restore margins if needed FIXME: This still fails if the
+    ;; "other" mode has incidentally set margins to exactly what linum
+    ;; had: see bug#20674 for a similar workaround in nlinum.el
+    (let ((set-margins (window-parameter w 'linum--set-margins))
+          (current-margins (window-margins w)))
+      (when (and set-margins
+                 (equal set-margins current-margins))
+        (set-window-margins w 0 (cdr current-margins))
+        (set-window-parameter w 'linum--set-margins nil)))))
 
 (defun linum-update-current ()
   "Update line numbers for the current buffer."
@@ -132,6 +146,17 @@ and you have to scroll or press \\[recenter-top-bottom] to update the numbers."
       (mapc #'delete-overlay linum-available)
       (setq linum-available nil))))
 
+;; Behind display-graphic-p test.
+(declare-function font-info "font.c" (name &optional frame))
+
+(defun linum--face-width (face)
+  (let ((info (font-info (face-font face)))
+        width)
+    (setq width (aref info 11))
+    (if (<= width 0)
+        (setq width (aref info 10)))
+    width))
+
 (defun linum-update-window (win)
   "Update line numbers for the portion visible in window WIN."
   (goto-char (window-start win))
@@ -146,14 +171,14 @@ and you have to scroll or press \\[recenter-top-bottom] to update the numbers."
     (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))
+    (while (and (not (eobp)) (< (point) limit))
       (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)
+                                 (overlay-get o 'linum-str) str)
                             (unless (memq o linum-overlays)
                               (push o linum-overlays))
                             (setq linum-available (delq o linum-available))
@@ -172,7 +197,16 @@ and you have to scroll or press \\[recenter-top-bottom] to update the numbers."
       (let ((inhibit-point-motion-hooks t))
         (forward-line))
       (setq line (1+ line)))
-    (set-window-margins win width (cdr (window-margins win)))))
+    (when (display-graphic-p)
+      (setq width (ceiling
+                   (/ (* width 1.0 (linum--face-width 'linum))
+                      (frame-char-width)))))
+    ;; open up space in the left margin, if needed, and record that
+    ;; fact as the window-parameter `linum--set-margins'
+    (let ((existing-margins (window-margins win)))
+      (when (> width (or (car existing-margins) 0))
+        (set-window-margins win width (cdr existing-margins))
+        (set-window-parameter win 'linum--set-margins (window-margins win))))))
 
 (defun linum-after-change (beg end _len)
   ;; update overlays on deletions, and after newlines are inserted