emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 5df239f: Support display of line numbers natively


From: Eli Zaretskii
Subject: [Emacs-diffs] master 5df239f: Support display of line numbers natively
Date: Sat, 8 Jul 2017 03:52:28 -0400 (EDT)

branch: master
commit 5df239fc6ffbbb16ea6e5546fbec1508bf2cb4b7
Merge: b8ead34 13786d5
Author: Eli Zaretskii <address@hidden>
Commit: Eli Zaretskii <address@hidden>

    Support display of line numbers natively
    
    This merges branch 'line-numbers'.
    * src/buffer.c (disable_line_numbers_overlay_at_eob): New
    function.
    * src/lisp.h (disable_line_numbers_overlay_at_eob): Add prototype.
    * src/dispextern.h (struct it): New members pt_lnum, lnum,
    lnum_bytepos, lnum_width, and lnum_pixel_width.
    * src/indent.c (line_number_display_width): New function,
    refactored from line-number width calculations in vertical-motion.
    (Fvertical_motion): Call line_number_display_width when the width
    of line-number display is needed.
    (Fline_number_display_width): New defun.
    (syms_of_indent): Defsubr it.
    * src/indent.c (Fvertical_motion): Help C-n/C-p estimate correctly
    the width used up by line numbers by looking near the window-start
    point.  If window-start is outside of the accessible portion,
    temporarily widen the buffer.
    * src/term.c (produce_glyphs): Adjust tab stops for the horizontal
    space taken by the line-number display.
    * src/xdisp.c (display_count_lines_logically)
    (display_count_lines_visually, maybe_produce_line_number)
    (should_produce_line_number, row_text_area_empty): New functions.
    (try_window_reusing_current_matrix): Don't use this method when
    display-line-numbers is in effect.
    (try_window_id, try_cursor_movement): Disable these optimizations
    when the line-number-current-line face is different from
    line-number face and for relative line numbers.
    (try_window_id, redisplay_window, try_cursor_movement): For
    visual line-number display, disable the same redisplay
    optimizations as for relative.
    (x_produce_glyphs): Adjust tab stops for the horizontal
    space taken by the line-number display.
    (hscroll_window_tree): Adjust hscroll calculations to line-number
    display.
    (DISP_INFINITY): Renamed from INFINITY to avoid clashes with
    math.h; all users changed.
    (set_cursor_from_row): Fix calculation of cursor X coordinate in
    R2L rows with display-produced glyphs at the beginning.
    (display_line): Use should_produce_line_number to determine
    whether a line number should be produced for each glyph row, and
    maybe_produce_line_number to produce line numbers.
    Don't display line numbers in the minibuffer and in tooltip
    frames.
    Call row_text_area_empty to verify that a glyph
    row's text area is devoid of any glyphs that came from a buffer or
    a string.  This fixes a bug with empty-lines indication
    disappearing when line numbers or line-prefix are displayed.
    (syms_of_xdisp) <display-line-numbers, display-line-numbers-widen>
    <display-line-number-width>: New buffer-local variables.
    <display-line-numbers-current-absolute>: New variable.
    
    * lisp/cus-start.el (standard): Provide customization forms for
    display-line-numbers and its sub-features.
    * lisp/faces.el (line-number, line-number-current-line): New faces.
    * lisp/frame.el: Add display-line-numbers, display-line-numbers-widen,
    display-line-numbers-current-absolute, and
    display-line-number-width to the list of variables that should
    trigger redisplay of the current buffer.
    * lisp/menu-bar.el (menu-bar-showhide-menu): Add menu-bar item to
    turn display-line-numbers on and off.
    (toggle-display-line-numbers): New function.
    * lisp/simple.el (last--line-number-width): New internal variable.
    (line-move-visual): Use it to adjust temporary-goal-column when
    line-number display changes its width.
    
    * doc/emacs/basic.texi (Position Info): Add cross-reference to
    "Display Custom", for line-number display.
    * doc/emacs/custom.texi (Init Rebinding):
    * doc/emacs/modes.texi (Minor Modes): Remove references to
    linum-mode.
    * doc/emacs/display.texi (Display Custom): Describe the
    line-number display.
    * doc/lispref/display.texi (Size of Displayed Text): Document
    line-number-display-width.
    
    * etc/NEWS: Document display-line-numbers and its customizations.
---
 doc/emacs/basic.texi     |   3 +-
 doc/emacs/custom.texi    |   1 -
 doc/emacs/display.texi   |  62 +++++-
 doc/emacs/modes.texi     |   5 -
 doc/lispref/display.texi |  17 ++
 etc/NEWS                 |  52 ++++-
 lisp/cus-start.el        |  32 +++
 lisp/faces.el            |  27 +++
 lisp/frame.el            |   4 +
 lisp/menu-bar.el         |  19 +-
 lisp/simple.el           |  21 +-
 src/buffer.c             |  27 +++
 src/dispextern.h         |  22 +-
 src/indent.c             |  70 +++++-
 src/lisp.h               |   1 +
 src/term.c               |   8 +-
 src/xdisp.c              | 547 ++++++++++++++++++++++++++++++++++++++++++++---
 17 files changed, 876 insertions(+), 42 deletions(-)

diff --git a/doc/emacs/basic.texi b/doc/emacs/basic.texi
index 6b66c18..5878e7d 100644
--- a/doc/emacs/basic.texi
+++ b/doc/emacs/basic.texi
@@ -630,7 +630,8 @@ Display the line number of point.
 @item M-x line-number-mode
 @itemx M-x column-number-mode
 Toggle automatic display of the current line number or column number.
address@hidden Mode Line}.
address@hidden Mode Line}.  If you want to have a line number
+displayed before each line, see @ref{Display Custom}.
 
 @item M-=
 Display the number of lines, words, and characters that are present in
diff --git a/doc/emacs/custom.texi b/doc/emacs/custom.texi
index c84f4a9..a756a89 100644
--- a/doc/emacs/custom.texi
+++ b/doc/emacs/custom.texi
@@ -1701,7 +1701,6 @@ and mouse events:
 (global-set-key (kbd "C-c y") 'clipboard-yank)
 (global-set-key (kbd "C-M-q") 'query-replace)
 (global-set-key (kbd "<f5>") 'flyspell-mode)
-(global-set-key (kbd "C-<f5>") 'linum-mode)
 (global-set-key (kbd "C-<right>") 'forward-sentence)
 (global-set-key (kbd "<mouse-2>") 'mouse-save-then-kill)
 @end example
diff --git a/doc/emacs/display.texi b/doc/emacs/display.texi
index c4554eb..083fcdf 100644
--- a/doc/emacs/display.texi
+++ b/doc/emacs/display.texi
@@ -1333,7 +1333,7 @@ characters in the buffer, which means that @samp{k} for 
10^3, @samp{M}
 for 10^6, @samp{G} for 10^9, etc., are used to abbreviate.
 
 @cindex line number display
address@hidden display of line number
address@hidden display of current line number
 @findex line-number-mode
   The current line number of point appears in the mode line when Line
 Number mode is enabled.  Use the command @kbd{M-x line-number-mode} to
@@ -1710,6 +1710,66 @@ variable @code{visual-line-fringe-indicators}.
   This section describes variables that control miscellaneous aspects
 of the appearance of the Emacs screen.  Beginning users can skip it.
 
address@hidden display-line-numbers
address@hidden number lines in a buffer
address@hidden display line numbers
+  If you want to have Emacs display line numbers for every line in the
+buffer, customize the buffer-local variable
address@hidden; it is @code{nil} by default.  This
+variable can have several different values to support various modes of
+line-number display:
+
address@hidden @asis
address@hidden @code{t}
+Display (an absolute) line number before each non-continuation screen
+line that displays buffer text.  If the line is a continuation line,
+or if the entire screen line displays a display or an overlay string,
+that line will not be numbered.
+
address@hidden @code{relative}
+Display relative line numbers before non-continuation lines which show
+buffer text.  The line numbers are relative to the line showing point,
+so the numbers grow both up and down as lines become farther from the
+current line.
+
address@hidden @code{visual}
+This value causes Emacs to count lines visually: only lines actually
+shown on the display will be counted (disregarding any lines in
+invisible parts of text), and lines which wrap to consume more than
+one screen line will be numbered that many times.  The displayed
+numbers are relative, as with @code{relative} value above.  This is
+handy in modes that fold text, such as Outline mode (@pxref{Outline
+Mode}), and need to move by exact number of screen lines.
+
address@hidden anything else
+Any other address@hidden value is treated as @code{t}.
address@hidden table
+
address@hidden display-line-numbers-current-absolute
+When Emacs displays relative line numbers, you can control the number
+displayed before the current line, the line showing point.  By
+default, Emacs displays the absolute number of the current line there,
+even though all the other line numbers are relative.  If you customize
+the variable @code{display-line-numbers-current-absolute} to a
address@hidden value, the number displayed for the current line will be
+zero.  This is handy if you don't care about the number of the current
+line, and want to leave more horizontal space for text in large
+buffers.
+
address@hidden display-line-numbers-widen
+In a narrowed buffer (@pxref{Narrowing}) lines are normally numbered
+starting at the beginning of the narrowing.  However, if you customize
+the variable @code{display-line-numbers-widen} to a address@hidden
+value, line numbers will disregard any narrowing and will start at the
+first character of the buffer.
+
address@hidden line-number face
+The line numbers are displayed in a special face @code{line-number}.
+The current line number is displayed in a different face,
address@hidden, so you can make the current line's
+number have a distinct appearance, which will help locating the line
+showing point.
+
 @vindex visible-bell
   If the variable @code{visible-bell} is address@hidden, Emacs attempts
 to make the whole screen blink when it would normally make an audible bell
diff --git a/doc/emacs/modes.texi b/doc/emacs/modes.texi
index be89340..eb0c88b 100644
--- a/doc/emacs/modes.texi
+++ b/doc/emacs/modes.texi
@@ -225,11 +225,6 @@ Font-Lock mode automatically highlights certain textual 
units found in
 programs.  It is enabled globally by default, but you can disable it
 in individual buffers.  @xref{Faces}.
 
address@hidden linum-mode
address@hidden Linum mode
address@hidden
-Linum mode displays each line's line number in the window's left margin.
-
 @item
 Outline minor mode provides similar facilities to the major mode
 called Outline mode.  @xref{Outline Mode}.
diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi
index 2ebe872..005d31a 100644
--- a/doc/lispref/display.texi
+++ b/doc/lispref/display.texi
@@ -2045,6 +2045,23 @@ selected window.  The value includes the line spacing of 
the line
 (@pxref{Line Height}).
 @end defun
 
+When a buffer is displayed with line numbers (@pxref{Display Custom,,,
+emacs, The GNU Emacs Manual}), it is sometimes useful to know the
+width taken for displaying the line numbers.  The following function
+is for Lisp programs which need this information for layout
+calculations.
+
address@hidden line-number-display-width &optional pixelwise
+This function returns the width used for displaying the line numbers
+in the selected window.  Optional argument @var{pixelwise}, if
address@hidden, means return the value in pixels; otherwise the value
+is returned in column units of the font defined for the
address@hidden face.  If line numbers are not displayed in the
+selected window, the value is zero.  Use @code{with-selected-window}
+(@pxref{Selecting Windows}) if you need this information about another
+window.
address@hidden defun
+
 
 @node Line Height
 @section Line Height
diff --git a/etc/NEWS b/etc/NEWS
index 13805ce..15c3009 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -405,10 +405,60 @@ display of raw bytes from octal to hex.
 ** You can now provide explicit field numbers in format specifiers.
 For example, '(format "%2$s %1$s" "X" "Y")' produces "Y X".
 
-+++
 ** 'comment-indent-function' values may now return a cons to specify a
 range of indentation.
 
++++
+** Emacs now supports optional display of line numbers in the buffer.
+This is similar to what linum-mode provides, but much faster and
+doesn't usurp the display margin for the line numbers.  Customize the
+buffer-local variable 'display-line-numbers' to activate this optional
+display.  If set to t, Emacs will display the number of each line
+before the line.  If set to 'relative', Emacs will display the line
+number relative to the line showing point, with that line's number
+displayed as absolute.  If set to 'visual', Emacs will display a
+relative number for every screen line, i.e. it will count screen lines
+rather than buffer lines.  The default is nil, which doesn't display
+the line numbers.
+
+In 'relative' and 'visual' modes, the variable
+'display-line-numbers-current-absolute' controls what number is
+displayed for the line showing point.  By default, this variable's
+value is t, which means display the absolute line number for the line
+showing point.  Customizing this variable to a nil value will cause
+Emacs to show zero instead, which preserves horizontal space of the
+window in large buffers.
+
+Line numbers are not displayed at all in minibuffer windows and in
+tooltips, as they are not useful there.
+
+The new face 'line-number' is used to display the line numbers.  The
+new face 'line-number-current-line' can be customized to display the
+current line's number differently from all the other line numbers; by
+default these two faces are identical.
+
+You can also customize the new variable 'display-line-number-width' to
+specify a fixed minimal with of the area allocated to line-number
+display.  The default is nil, meaning that Emacs will dynamically
+calculate the area width, enlarging or shrinking it as needed.
+Setting it to a non-negative integer specifies that as the minimal
+width; selecting a value  that is large enough to display all line
+numbers in a buffer will then keep the line-number display area of
+constant width at all times, if that is desired.
+
+Lisp programs can disable line-number display for a particular screen
+line by putting the 'display-line-numbers-disable' text property or
+overlay property on the first character of that screen line.  This is
+intended for add-on packages that need a finer control of the display.
+
+Lisp programs that need to know how much screen estate is used up for
+line-number display in a window can use the new function
+'line-number-display-width'.
+
+Linum mode and all similar packages are henceforth becoming obsolete.
+Users and developers are encouraged to switch to this new feature
+instead.
+
 
 * Editing Changes in Emacs 26.1
 
diff --git a/lisp/cus-start.el b/lisp/cus-start.el
index 744fe7f..017e7f9 100644
--- a/lisp/cus-start.el
+++ b/lisp/cus-start.el
@@ -584,6 +584,38 @@ since it could result in memory overflow and make Emacs 
crash."
                       (const :tag "Grow only" :value grow-only))
              "25.1")
             (display-raw-bytes-as-hex display boolean "26.1")
+             (display-line-numbers display
+                                   (choice
+                                    (const :tag "Off (nil)" :value nil)
+                                    (const :tag "Absolute line numbers"
+                                           :value t)
+                                    (const :tag "Relative line numbers"
+                                           :value relative)
+                                    (const :tag "Visually relative line 
numbers"
+                                           :value visual))
+                                   "26.1")
+             (display-line-number-width display
+                                 (choice
+                                  (const :tag "Dynamically computed"
+                                         :value nil)
+                                  (integer :menu-tag "Fixed number of columns"
+                                           :value 2
+                                           :format "%v"))
+                                 "26.1")
+             (display-line-numbers-current-absolute display
+                                 (choice
+                                  (const :tag "Display actual number of 
current line"
+                                         :value t)
+                                  (const :tag "Display zero as number of 
current line"
+                                         :value nil))
+                                 "26.1")
+             (display-line-numbers-widen display
+                                 (choice
+                                  (const :tag "Disregard narrowing when 
calculating line numbers"
+                                         :value t)
+                                  (const :tag "Count lines from beinning of 
narrowed region"
+                                         :value nil))
+                                 "26.1")
             ;; xfaces.c
             (scalable-fonts-allowed display boolean "22.1")
             ;; xfns.c
diff --git a/lisp/faces.el b/lisp/faces.el
index 9a8a134..c3693d1 100644
--- a/lisp/faces.el
+++ b/lisp/faces.el
@@ -2465,6 +2465,33 @@ If you set `term-file-prefix' to nil, this function does 
nothing."
   :version "21.1"
   :group 'basic-faces)
 
+;; Definition stolen from linum.el.
+(defface line-number
+  '((t :inherit (shadow default)))
+  "Face for displaying line numbers.
+This face is used when `display-line-numbers' is non-nil.
+
+If you customize the font of this face, make sure it is a
+monospaced font, otherwise line numbers will not line up,
+and text lines might move horizontally as you move through
+the buffer."
+  :version "26.1"
+  :group 'basic-faces)
+
+(defface line-number-current-line
+  '((t :inherit line-number))
+  "Face for displaying the current line number.
+This face is used when `display-line-numbers' is non-nil.
+
+If you customize the font of this face, make sure it is a
+monospaced font, otherwise line numbers will not line up,
+and text lines might move horizontally as you move through
+the buffer.  Similarly, making this face's font different
+from that of the `line-number' face could produce such
+unwanted effects."
+  :version "26.1"
+  :group 'basic-faces)
+
 (defface escape-glyph
   '((((background dark)) :foreground "cyan")
     ;; See the comment in minibuffer-prompt for
diff --git a/lisp/frame.el b/lisp/frame.el
index b54df6f..c629a94 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -2466,6 +2466,10 @@ See also `toggle-frame-maximized'."
         line-prefix
         wrap-prefix
         truncate-lines
+        display-line-numbers
+        display-line-number-width
+        display-line-numbers-current-absolute
+        display-line-numbers-widen
         bidi-paragraph-direction
         bidi-display-reordering))
 
diff --git a/lisp/menu-bar.el b/lisp/menu-bar.el
index 9c7bcff..06f8c78 100644
--- a/lisp/menu-bar.el
+++ b/lisp/menu-bar.el
@@ -1101,17 +1101,32 @@ The selected font will be the default on both the 
existing and future frames."
                     :button (:radio . (eq tool-bar-mode nil))))
       menu)))
 
+(defun toggle-display-line-numbers ()
+  (interactive)
+  (if display-line-numbers
+      (setq display-line-numbers nil)
+    (setq display-line-numbers t))
+  (force-mode-line-update))
+
 (defvar menu-bar-showhide-menu
   (let ((menu (make-sparse-keymap "Show/Hide")))
 
+    (bindings--define-key menu [display-line-numbers]
+      `(menu-item "Line Numbers for all lines"
+                  ,(lambda ()
+                     (interactive)
+                     (toggle-display-line-numbers))
+                  :help "Show the line number alongside each line"
+                  :button (:toggle . display-line-numbers)))
+
     (bindings--define-key menu [column-number-mode]
       (menu-bar-make-mm-toggle column-number-mode
-                               "Column Numbers"
+                               "Column Numbers in Mode Line"
                                "Show the current column number in the mode 
line"))
 
     (bindings--define-key menu [line-number-mode]
       (menu-bar-make-mm-toggle line-number-mode
-                               "Line Numbers"
+                               "Line Numbers in Mode Line"
                                "Show the current line number in the mode 
line"))
 
     (bindings--define-key menu [size-indication-mode]
diff --git a/lisp/simple.el b/lisp/simple.el
index 1db14a8..3d23fc3 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -5942,6 +5942,10 @@ columns by which window is scrolled from left margin.
 When the `track-eol' feature is doing its job, the value is
 `most-positive-fixnum'.")
 
+(defvar last--line-number-width 0
+  "Last value of width used for displaying line numbers.
+Used internally by `line-move-visual'.")
+
 (defcustom line-move-ignore-invisible t
   "Non-nil means commands that move by lines ignore invisible newlines.
 When this option is non-nil, \\[next-line], \\[previous-line], 
\\[move-end-of-line], and \\[move-beginning-of-line] behave
@@ -6212,6 +6216,7 @@ not vscroll."
 If NOERROR, don't signal an error if we can't move that many lines."
   (let ((opoint (point))
        (hscroll (window-hscroll))
+        (lnum-width (line-number-display-width t))
        target-hscroll)
     ;; Check if the previous command was a line-motion command, or if
     ;; we were called from some other command.
@@ -6219,9 +6224,19 @@ If NOERROR, don't signal an error if we can't move that 
many lines."
             (memq last-command `(next-line previous-line ,this-command)))
        ;; If so, there's no need to reset `temporary-goal-column',
        ;; but we may need to hscroll.
-       (if (or (/= (cdr temporary-goal-column) hscroll)
-               (>  (cdr temporary-goal-column) 0))
-           (setq target-hscroll (cdr temporary-goal-column)))
+        (progn
+          (if (or (/= (cdr temporary-goal-column) hscroll)
+                  (>  (cdr temporary-goal-column) 0))
+              (setq target-hscroll (cdr temporary-goal-column)))
+          ;; Update the COLUMN part of temporary-goal-column if the
+          ;; line-number display changed its width since the last
+          ;; time.
+          (setq temporary-goal-column
+                (cons (+ (car temporary-goal-column)
+                         (/ (float (- lnum-width last--line-number-width))
+                            (frame-char-width)))
+                      (cdr temporary-goal-column)))
+          (setq last--line-number-width lnum-width))
       ;; Otherwise, we should reset `temporary-goal-column'.
       (let ((posn (posn-at-point))
            x-pos)
diff --git a/src/buffer.c b/src/buffer.c
index 80dbd33..780e4d7 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -3054,6 +3054,33 @@ mouse_face_overlay_overlaps (Lisp_Object overlay)
   return i < n;
 }
 
+/* Return the value of the 'display-line-numbers-disable' property at
+   EOB, if there's an overlay at ZV with a non-nil value of that property.  */
+Lisp_Object
+disable_line_numbers_overlay_at_eob (void)
+{
+  ptrdiff_t n, i, size;
+  Lisp_Object *v, tem = Qnil;
+  Lisp_Object vbuf[10];
+  USE_SAFE_ALLOCA;
+
+  size = ARRAYELTS (vbuf);
+  v = vbuf;
+  n = overlays_in (ZV, ZV, 0, &v, &size, NULL, NULL);
+  if (n > size)
+    {
+      SAFE_NALLOCA (v, 1, n);
+      overlays_in (ZV, ZV, 0, &v, &n, NULL, NULL);
+    }
+
+  for (i = 0; i < n; ++i)
+    if ((tem = Foverlay_get (v[i], Qdisplay_line_numbers_disable),
+        !NILP (tem)))
+      break;
+
+  SAFE_FREE ();
+  return tem;
+}
 
 
 /* Fast function to just test if we're at an overlay boundary.  */
diff --git a/src/dispextern.h b/src/dispextern.h
index 8644ce2..1df769a 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -384,6 +384,7 @@ struct glyph
       glyph standing for newline at end of line    0
       empty space after the end of the line       -1
       overlay arrow on a TTY                      -1
+      glyph displaying line number                -1
       glyph at EOB that ends in a newline         -1
       left truncation glyphs:                     -1
       right truncation/continuation glyphs        next buffer position
@@ -2537,7 +2538,12 @@ struct it
      Do NOT use !BUFFERP (it.object) as a test whether we are
      iterating over a string; use STRINGP (it.string) instead.
 
-     Position is the current iterator position in object.  */
+     Position is the current iterator position in object.
+
+     The 'position's CHARPOS is copied to glyph->charpos of the glyph
+     produced by PRODUCE_GLYPHS, so any artificial value documented
+     under 'struct glyph's 'charpos' member can also be found in the
+     'position' member here.  */
   Lisp_Object object;
   struct text_pos position;
 
@@ -2621,6 +2627,20 @@ struct it
      coordinate is past first_visible_x.  */
   int hpos;
 
+  /* Current line number, zero-based.  */
+  ptrdiff_t lnum;
+
+  /* The byte position corresponding to lnum.  */
+  ptrdiff_t lnum_bytepos;
+
+  /* The width, in columns and in pixels, needed for display of the
+     line numbers, or zero if not computed.  */
+  int lnum_width;
+  int lnum_pixel_width;
+
+  /* The line number of point's line, or zero if not computed yet.  */
+  ptrdiff_t pt_lnum;
+
   /* Left fringe bitmap number (enum fringe_bitmap_type).  */
   unsigned left_user_fringe_bitmap : FRINGE_ID_BITS;
 
diff --git a/src/indent.c b/src/indent.c
index adecc36..4c6dacd 100644
--- a/src/indent.c
+++ b/src/indent.c
@@ -1947,6 +1947,57 @@ vmotion (register ptrdiff_t from, register ptrdiff_t 
from_byte,
                         -1, hscroll, 0, w);
 }
 
+/* Return the width taken by line-number display in window W.  */
+static void
+line_number_display_width (struct window *w, int *width, int *pixel_width)
+{
+  if (NILP (Vdisplay_line_numbers))
+    {
+      *width = 0;
+      *pixel_width = 0;
+    }
+  else
+    {
+      struct it it;
+      struct text_pos wstart;
+      bool saved_restriction = false;
+      ptrdiff_t count = SPECPDL_INDEX ();
+      SET_TEXT_POS_FROM_MARKER (wstart, w->start);
+      void *itdata = bidi_shelve_cache ();
+      /* We must start from window's start point, but it could be
+        outside the accessible region.  */
+      if (wstart.charpos < BEGV || wstart.charpos > ZV)
+       {
+         record_unwind_protect (save_restriction_restore,
+                                save_restriction_save ());
+         Fwiden ();
+         saved_restriction = true;
+       }
+      start_display (&it, w, wstart);
+      move_it_by_lines (&it, 1);
+      *width = it.lnum_width;
+      *pixel_width = it.lnum_pixel_width;
+      if (saved_restriction)
+       unbind_to (count, Qnil);
+      bidi_unshelve_cache (itdata, 0);
+    }
+}
+
+DEFUN ("line-number-display-width", Fline_number_display_width,
+       Sline_number_display_width, 0, 1, 0,
+       doc: /* Return the width used for displaying line numbers in the 
selected window.
+If optional argument PIXELWISE is non-nil, return the width in pixels,
+otherwise return the width in columns of the face used to display
+line numbers, `line-number'.  */)
+  (Lisp_Object pixelwise)
+{
+  int width, pixel_width;
+  line_number_display_width (XWINDOW (selected_window), &width, &pixel_width);
+  if (!NILP (pixelwise))
+    return make_number (pixel_width);
+  return make_number (width);
+}
+
 /* In window W (derived from WINDOW), return x coordinate for column
    COL (derived from COLUMN).  */
 static int
@@ -2068,9 +2119,19 @@ whether or not it is currently displayed in some window. 
 */)
          start_x = window_column_x (w, window, start_col, cur_col);
        }
 
-      itdata = bidi_shelve_cache ();
+      /* When displaying line numbers, we need to prime IT's
+        lnum_width with the value calculated at window's start, since
+        that's what normal window redisplay does.  Otherwise C-n/C-p
+        will sometimes err by one column.  */
+      int lnum_width = 0;
+      int lnum_pixel_width = 0;
+      if (!NILP (Vdisplay_line_numbers)
+         && !EQ (Vdisplay_line_numbers, Qvisual))
+       line_number_display_width (w, &lnum_width, &lnum_pixel_width);
       SET_TEXT_POS (pt, PT, PT_BYTE);
+      itdata = bidi_shelve_cache ();
       start_display (&it, w, pt);
+      it.lnum_width = lnum_width;
       first_x = it.first_visible_x;
       it_start = IT_CHARPOS (it);
 
@@ -2247,6 +2308,12 @@ whether or not it is currently displayed in some window. 
 */)
         an addition to the hscroll amount.  */
       if (lcols_given)
        {
+         /* If we are displaying line numbers, we could cross the
+            line where the width of the line-number display changes,
+            in which case we need to fix up the pixel coordinate
+            accordingly.  */
+         if (lnum_pixel_width > 0)
+           to_x += it.lnum_pixel_width - lnum_pixel_width;
          move_it_in_display_line (&it, ZV, first_x + to_x, MOVE_TO_X);
          /* If we find ourselves in the middle of an overlay string
             which includes a newline after current string position,
@@ -2292,6 +2359,7 @@ syms_of_indent (void)
   defsubr (&Sindent_to);
   defsubr (&Scurrent_column);
   defsubr (&Smove_to_column);
+  defsubr (&Sline_number_display_width);
   defsubr (&Svertical_motion);
   defsubr (&Scompute_motion);
 }
diff --git a/src/lisp.h b/src/lisp.h
index ff8dde2..f5cb6c7 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3965,6 +3965,7 @@ extern void syms_of_editfns (void);
 
 /* Defined in buffer.c.  */
 extern bool mouse_face_overlay_overlaps (Lisp_Object);
+extern Lisp_Object disable_line_numbers_overlay_at_eob (void);
 extern _Noreturn void nsberror (Lisp_Object);
 extern void adjust_overlays_for_insert (ptrdiff_t, ptrdiff_t);
 extern void adjust_overlays_for_delete (ptrdiff_t, ptrdiff_t);
diff --git a/src/term.c b/src/term.c
index 3d7f4ad..87a4126 100644
--- a/src/term.c
+++ b/src/term.c
@@ -1585,10 +1585,16 @@ produce_glyphs (struct it *it)
     {
       int absolute_x = (it->current_x
                        + it->continuation_lines_width);
+      int x0 = absolute_x;
+      /* Adjust for line numbers.  */
+      if (!NILP (Vdisplay_line_numbers))
+       absolute_x -= it->lnum_pixel_width;
       int next_tab_x
        = (((1 + absolute_x + it->tab_width - 1)
            / it->tab_width)
           * it->tab_width);
+      if (!NILP (Vdisplay_line_numbers))
+       next_tab_x += it->lnum_pixel_width;
       int nspaces;
 
       /* If part of the TAB has been displayed on the previous line
@@ -1596,7 +1602,7 @@ produce_glyphs (struct it *it)
         been incremented already by the part that fitted on the
         continued line.  So, we will get the right number of spaces
         here.  */
-      nspaces = next_tab_x - absolute_x;
+      nspaces = next_tab_x - x0;
 
       if (it->glyph_row)
        {
diff --git a/src/xdisp.c b/src/xdisp.c
index 1c316fa..fad23bf 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -290,6 +290,7 @@ along with GNU Emacs.  If not, see 
<http://www.gnu.org/licenses/>.  */
 #include <stdio.h>
 #include <stdlib.h>
 #include <limits.h>
+#include <math.h>
 
 #include "lisp.h"
 #include "atimer.h"
@@ -324,7 +325,7 @@ along with GNU Emacs.  If not, see 
<http://www.gnu.org/licenses/>.  */
 #define FRAME_X_OUTPUT(f) ((f)->output_data.x)
 #endif
 
-#define INFINITY 10000000
+#define DISP_INFINITY 10000000
 
 /* Holds the list (error).  */
 static Lisp_Object list_of_error;
@@ -832,6 +833,8 @@ static bool cursor_row_fully_visible_p (struct window *, 
bool, bool);
 static bool update_menu_bar (struct frame *, bool, bool);
 static bool try_window_reusing_current_matrix (struct window *);
 static int try_window_id (struct window *);
+static void maybe_produce_line_number (struct it *);
+static bool should_produce_line_number (struct it *);
 static bool display_line (struct it *, int);
 static int display_mode_lines (struct window *);
 static int display_mode_line (struct window *, enum face_id, Lisp_Object);
@@ -843,6 +846,8 @@ static const char *decode_mode_spec (struct window *, int, 
int, Lisp_Object *);
 static void display_menu_bar (struct window *);
 static ptrdiff_t display_count_lines (ptrdiff_t, ptrdiff_t, ptrdiff_t,
                                      ptrdiff_t *);
+static void pint2str (register char *, register int, register ptrdiff_t);
+
 static int display_string (const char *, Lisp_Object, Lisp_Object,
                            ptrdiff_t, ptrdiff_t, struct it *, int, int, int, 
int);
 static void compute_line_metrics (struct it *);
@@ -6764,7 +6769,7 @@ reseat_to_string (struct it *it, const char *s, 
Lisp_Object string,
      FIELD_WIDTH < 0 means infinite field width.  This is useful for
      padding with `-' at the end of a mode line.  */
   if (field_width < 0)
-    field_width = INFINITY;
+    field_width = DISP_INFINITY;
   /* Implementation note: We deliberately don't enlarge
      it->bidi_it.string.schars here to fit it->end_charpos, because
      the bidi iterator cannot produce characters out of thin air.  */
@@ -8661,9 +8666,16 @@ move_it_in_display_line_to (struct it *it,
        || (it->method == GET_FROM_DISPLAY_VECTOR               \
           && it->dpvec + it->current.dpvec_index + 1 >= it->dpend)))
 
-  /* If there's a line-/wrap-prefix, handle it.  */
-  if (it->hpos == 0 && it->method == GET_FROM_BUFFER)
-    handle_line_prefix (it);
+  if (it->hpos == 0)
+    {
+      /* If line numbers are being displayed, produce a line number.  */
+      if (should_produce_line_number (it)
+         && it->current_x == it->first_visible_x)
+       maybe_produce_line_number (it);
+      /* If there's a line-/wrap-prefix, handle it.  */
+      if (it->method == GET_FROM_BUFFER)
+       handle_line_prefix (it);
+    }
 
   if (IT_CHARPOS (*it) < CHARPOS (this_line_min_pos))
     SET_TEXT_POS (this_line_min_pos, IT_CHARPOS (*it), IT_BYTEPOS (*it));
@@ -13069,6 +13081,43 @@ hscroll_window_tree (Lisp_Object window)
            }
          bool row_r2l_p = cursor_row->reversed_p;
          bool hscl = hscrolling_current_line_p (w);
+         int x_offset = 0;
+         /* When line numbers are displayed, we need to account for
+            the horizontal space they consume.  */
+         if (!NILP (Vdisplay_line_numbers))
+           {
+             struct glyph *g;
+             if (!row_r2l_p)
+               {
+                 for (g = cursor_row->glyphs[TEXT_AREA];
+                      g < cursor_row->glyphs[TEXT_AREA]
+                        + cursor_row->used[TEXT_AREA];
+                      g++)
+                   {
+                     if (!(NILP (g->object) && g->charpos < 0))
+                       break;
+                     x_offset += g->pixel_width;
+                   }
+               }
+             else
+               {
+                 for (g = cursor_row->glyphs[TEXT_AREA]
+                        + cursor_row->used[TEXT_AREA];
+                      g > cursor_row->glyphs[TEXT_AREA];
+                      g--)
+                   {
+                     if (!(NILP ((g - 1)->object) && (g - 1)->charpos < 0))
+                       break;
+                     x_offset += (g - 1)->pixel_width;
+                   }
+               }
+           }
+         if (cursor_row->truncated_on_left_p)
+           {
+             /* On TTY frames, don't count the left truncation glyph.  */
+             struct frame *f = XFRAME (WINDOW_FRAME (w));
+             x_offset -= (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f));
+           }
 
          text_area_width = window_box_width (w, TEXT_AREA);
 
@@ -13101,7 +13150,7 @@ hscroll_window_tree (Lisp_Object window)
                 inside the left margin and the window is already
                 hscrolled.  */
              && ((!row_r2l_p
-                  && ((w->hscroll && w->cursor.x <= h_margin)
+                  && ((w->hscroll && w->cursor.x <= h_margin + x_offset)
                       || (cursor_row->enabled_p
                           && cursor_row->truncated_on_right_p
                           && (w->cursor.x >= text_area_width - h_margin))))
@@ -13119,7 +13168,8 @@ hscroll_window_tree (Lisp_Object window)
                           && cursor_row->truncated_on_right_p
                           && w->cursor.x <= h_margin)
                          || (w->hscroll
-                             && (w->cursor.x >= text_area_width - h_margin))))
+                             && (w->cursor.x >= (text_area_width - h_margin
+                                                 - x_offset)))))
                  /* This last condition is needed when moving
                     vertically from an hscrolled line to a short line
                     that doesn't need to be hscrolled.  If we omit
@@ -13150,7 +13200,7 @@ hscroll_window_tree (Lisp_Object window)
              if (hscl)
                it.first_visible_x = window_hscroll_limited (w, it.f)
                                     * FRAME_COLUMN_WIDTH (it.f);
-             it.last_visible_x = INFINITY;
+             it.last_visible_x = DISP_INFINITY;
              move_it_in_display_line_to (&it, pt, -1, MOVE_TO_POS);
              /* If the line ends in an overlay string with a newline,
                 we might infloop, because displaying the window will
@@ -14796,15 +14846,12 @@ set_cursor_from_row (struct window *w, struct 
glyph_row *row,
          while (glyph > end + 1
                 && NILP (glyph->object)
                 && glyph->charpos < 0)
-           {
-             --glyph;
-             x -= glyph->pixel_width;
-           }
+           --glyph;
          if (NILP (glyph->object) && glyph->charpos < 0)
            --glyph;
          /* By default, in reversed rows we put the cursor on the
             rightmost (first in the reading order) glyph.  */
-         for (g = end + 1; g < glyph; g++)
+         for (x = 0, g = end + 1; g < glyph; g++)
            x += g->pixel_width;
          while (end < glyph
                 && NILP ((end + 1)->object)
@@ -15835,7 +15882,7 @@ compute_window_start_on_continuation_line (struct 
window *w)
             So, we're looking for the display line start with the
             minimum distance from the old window start.  */
          pos_before_pt = pos = it.current.pos;
-         min_distance = INFINITY;
+         min_distance = DISP_INFINITY;
          while ((distance = eabs (CHARPOS (start_pos) - IT_CHARPOS (it))),
                 distance < min_distance)
            {
@@ -15941,6 +15988,17 @@ try_cursor_movement (Lisp_Object window, struct 
text_pos startp,
       && !windows_or_buffers_changed
       && !f->cursor_type_changed
       && NILP (Vshow_trailing_whitespace)
+      /* When display-line-numbers is in relative mode, moving point
+        requires to redraw the entire window.  */
+      && !EQ (Vdisplay_line_numbers, Qrelative)
+      && !EQ (Vdisplay_line_numbers, Qvisual)
+      /* When the current line number should be displayed in a
+        distinct face, moving point cannot be handled in optimized
+        way as below.  */
+      && !(!NILP (Vdisplay_line_numbers)
+          && NILP (Finternal_lisp_face_equal_p (Qline_number,
+                                                Qline_number_current_line,
+                                                w->frame)))
       /* This code is not used for mini-buffer for the sake of the case
         of redisplaying to replace an echo area message; since in
         that case the mini-buffer contents per se are usually
@@ -16788,10 +16846,15 @@ redisplay_window (Lisp_Object window, bool 
just_this_one_p)
          XBUFFER (w->contents)->text->redisplay = false;
          safe__call1 (true, Vpre_redisplay_function, Fcons (window, Qnil));
 
-         if (w->redisplay || XBUFFER (w->contents)->text->redisplay)
+         if (w->redisplay || XBUFFER (w->contents)->text->redisplay
+             || ((EQ (Vdisplay_line_numbers, Qrelative)
+                  || EQ (Vdisplay_line_numbers, Qvisual))
+                 && row != MATRIX_FIRST_TEXT_ROW (w->desired_matrix)))
            {
-             /* pre-redisplay-function made changes (e.g. move the region)
-                that require another round of redisplay.  */
+             /* Either pre-redisplay-function made changes (e.g. move
+                the region), or we moved point in a window that is
+                under display-line-numbers = relative mode.  We need
+                another round of redisplay.  */
              clear_glyph_matrix (w->desired_matrix);
              if (!try_window (window, startp, 0))
                goto need_larger_matrices;
@@ -17592,6 +17655,12 @@ try_window_reusing_current_matrix (struct window *w)
   if (w->vscroll || MATRIX_ROW_PARTIALLY_VISIBLE_P (w, start_row))
     return false;
 
+  /* Give up if line numbers are being displayed, because reusing the
+     current matrix might use the wrong width for line-number
+     display.  */
+  if (!NILP (Vdisplay_line_numbers))
+    return false;
+
   /* The variable new_start now holds the new window start.  The old
      start `start' can be determined from the current matrix.  */
   SET_TEXT_POS_FROM_MARKER (new_start, w->start);
@@ -18423,6 +18492,16 @@ try_window_id (struct window *w)
   if (!NILP (BVAR (XBUFFER (w->contents), extra_line_spacing)))
     GIVE_UP (23);
 
+  /* Give up if display-line-numbers is in relative mode, or when the
+     current line's number needs to be displayed in a distinct face.  */
+  if (EQ (Vdisplay_line_numbers, Qrelative)
+      || EQ (Vdisplay_line_numbers, Qvisual)
+      || (!NILP (Vdisplay_line_numbers)
+         && NILP (Finternal_lisp_face_equal_p (Qline_number,
+                                               Qline_number_current_line,
+                                               w->frame))))
+    GIVE_UP (24);
+
   /* Make sure beg_unchanged and end_unchanged are up to date.  Do it
      only if buffer has really changed.  The reason is that the gap is
      initially at Z for freshly visited files.  The code below would
@@ -20669,6 +20748,352 @@ find_row_edges (struct it *it, struct glyph_row *row,
     row->maxpos = it->current.pos;
 }
 
+/* Like display_count_lines, but capable of counting outside of the
+   current narrowed region.  */
+static ptrdiff_t
+display_count_lines_logically (ptrdiff_t start_byte, ptrdiff_t limit_byte,
+                              ptrdiff_t count, ptrdiff_t *byte_pos_ptr)
+{
+  if (!display_line_numbers_widen || (BEGV == BEG && ZV == Z))
+    return display_count_lines (start_byte, limit_byte, count, byte_pos_ptr);
+
+  ptrdiff_t val;
+  ptrdiff_t pdl_count = SPECPDL_INDEX ();
+  record_unwind_protect (save_restriction_restore, save_restriction_save ());
+  Fwiden ();
+  val = display_count_lines (start_byte, limit_byte, count, byte_pos_ptr);
+  unbind_to (pdl_count, Qnil);
+  return val;
+}
+
+/* Count the number of screen lines in window IT->w between character
+   position IT_CHARPOS(*IT) and the line showing that window's point.  */
+static ptrdiff_t
+display_count_lines_visually (struct it *it)
+{
+  struct it tem_it;
+  ptrdiff_t to;
+  struct text_pos from;
+
+  /* If we already calculated a relative line number, use that.  This
+     trick relies on the fact that visual lines (a.k.a. "glyph rows")
+     are laid out sequentially, one by one, for each sequence of calls
+     to display_line or other similar function that follows a call to
+     init_iterator.  */
+  if (it->lnum_bytepos > 0)
+    return it->lnum + 1;
+  else
+    {
+      ptrdiff_t count = SPECPDL_INDEX ();
+
+      if (IT_CHARPOS (*it) <= PT)
+       {
+         from = it->current.pos;
+         to = PT;
+       }
+      else
+       {
+         SET_TEXT_POS (from, PT, PT_BYTE);
+         to = IT_CHARPOS (*it);
+       }
+      start_display (&tem_it, it->w, from);
+      /* Need to disable visual mode temporarily, since otherwise the
+        call to move_it_to will cause infinite recursion.  */
+      specbind (Qdisplay_line_numbers, Qrelative);
+      /* Some redisplay optimizations could invoke us very far from
+        PT, which will make the caller painfully slow.  There should
+        be no need to go too far beyond the window's bottom, as any
+        such optimization will fail to show point anyway.  */
+      move_it_to (&tem_it, to, -1,
+                 tem_it.last_visible_y
+                 + (SCROLL_LIMIT + 10) * FRAME_LINE_HEIGHT (tem_it.f),
+                 -1, MOVE_TO_POS | MOVE_TO_Y);
+      unbind_to (count, Qnil);
+      return IT_CHARPOS (*it) <= PT ? -tem_it.vpos : tem_it.vpos;
+    }
+}
+
+/* Produce the line-number glyphs for the current glyph_row.  If
+   IT->glyph_row is non-NULL, populate the row with the produced
+   glyphs.  */
+static void
+maybe_produce_line_number (struct it *it)
+{
+  ptrdiff_t last_line = it->lnum;
+  ptrdiff_t start_from, bytepos;
+  ptrdiff_t this_line;
+  bool first_time = false;
+  ptrdiff_t beg = display_line_numbers_widen ? BEG : BEGV;
+  ptrdiff_t beg_byte = display_line_numbers_widen ? BEG_BYTE : BEGV_BYTE;
+  ptrdiff_t z_byte = display_line_numbers_widen ? Z_BYTE : ZV_BYTE;
+  void *itdata = bidi_shelve_cache ();
+
+  if (EQ (Vdisplay_line_numbers, Qvisual))
+    this_line = display_count_lines_visually (it);
+  else
+    {
+      if (!last_line)
+       {
+         /* FIXME: Maybe reuse the data in it->w->base_line_number.  */
+         start_from = beg;
+         if (!it->lnum_bytepos)
+           first_time = true;
+       }
+      else
+       start_from = it->lnum_bytepos;
+
+      /* Paranoia: what if someone changes the narrowing since the
+        last time display_line was called?  Shouldn't really happen,
+        but who knows what some crazy Lisp invoked by :eval could do?  */
+      if (!(beg_byte <= start_from && start_from < z_byte))
+       {
+         last_line = 0;
+         start_from = beg_byte;
+       }
+
+      this_line =
+       last_line + display_count_lines_logically (start_from,
+                                                  IT_BYTEPOS (*it),
+                                                  IT_CHARPOS (*it), &bytepos);
+      eassert (this_line > 0 || (this_line == 0 && start_from == beg_byte));
+      eassert (bytepos == IT_BYTEPOS (*it));
+    }
+
+  /* Record the line number information.  */
+  if (this_line != last_line || !it->lnum_bytepos)
+    {
+      it->lnum = this_line;
+      it->lnum_bytepos = IT_BYTEPOS (*it);
+    }
+
+  /* Produce the glyphs for the line number.  */
+  struct it tem_it;
+  char lnum_buf[INT_STRLEN_BOUND (ptrdiff_t) + 1];
+  bool beyond_zv = IT_BYTEPOS (*it) >= ZV_BYTE ? true : false;
+  ptrdiff_t lnum_offset = -1; /* to produce 1-based line numbers */
+  int lnum_face_id = merge_faces (it->f, Qline_number, 0, DEFAULT_FACE_ID);
+  int current_lnum_face_id
+    = merge_faces (it->f, Qline_number_current_line, 0, DEFAULT_FACE_ID);
+  /* Compute point's line number if needed.  */
+  if ((EQ (Vdisplay_line_numbers, Qrelative)
+       || EQ (Vdisplay_line_numbers, Qvisual)
+       || lnum_face_id != current_lnum_face_id)
+      && !it->pt_lnum)
+    {
+      ptrdiff_t ignored;
+      if (PT_BYTE > it->lnum_bytepos && !EQ (Vdisplay_line_numbers, Qvisual))
+       it->pt_lnum =
+         this_line + display_count_lines_logically (it->lnum_bytepos, PT_BYTE,
+                                                    PT, &ignored);
+      else
+       it->pt_lnum = display_count_lines_logically (beg_byte, PT_BYTE, PT,
+                                                    &ignored);
+    }
+  /* Compute the required width if needed.  */
+  if (!it->lnum_width)
+    {
+      if (NATNUMP (Vdisplay_line_number_width))
+       it->lnum_width = XFASTINT (Vdisplay_line_number_width);
+
+      /* Max line number to be displayed cannot be more than the one
+        corresponding to the last row of the desired matrix.  */
+      ptrdiff_t max_lnum;
+
+      if (NILP (Vdisplay_line_numbers_current_absolute)
+         && (EQ (Vdisplay_line_numbers, Qrelative)
+             || EQ (Vdisplay_line_numbers, Qvisual)))
+       /* We subtract one more because the current line is always
+          zero in this mode.  */
+       max_lnum = it->w->desired_matrix->nrows - 2;
+      else if (EQ (Vdisplay_line_numbers, Qvisual))
+       max_lnum = it->pt_lnum + it->w->desired_matrix->nrows - 1;
+      else
+       max_lnum = this_line + it->w->desired_matrix->nrows - 1 - it->vpos;
+      max_lnum = max (1, max_lnum);
+      it->lnum_width = max (it->lnum_width, log10 (max_lnum) + 1);
+      eassert (it->lnum_width > 0);
+    }
+  if (EQ (Vdisplay_line_numbers, Qrelative))
+    lnum_offset = it->pt_lnum;
+  else if (EQ (Vdisplay_line_numbers, Qvisual))
+    lnum_offset = 0;
+
+  /* Under 'relative', display the absolute line number for the
+     current line, unless the user requests otherwise.  */
+  ptrdiff_t lnum_to_display = eabs (this_line - lnum_offset);
+  if ((EQ (Vdisplay_line_numbers, Qrelative)
+       || EQ (Vdisplay_line_numbers, Qvisual))
+      && lnum_to_display == 0
+      && !NILP (Vdisplay_line_numbers_current_absolute))
+    lnum_to_display = it->pt_lnum + 1;
+  /* In L2R rows we need to append the blank separator, in R2L
+     rows we need to prepend it.  But this function is usually
+     called when no display elements were produced from the
+     following line, so the paragraph direction might be unknown.
+     Therefore we cheat and add 2 blanks, one on either side.  */
+  pint2str (lnum_buf, it->lnum_width + 1, lnum_to_display);
+  strcat (lnum_buf, " ");
+
+  /* Setup for producing the glyphs.  */
+  init_iterator (&tem_it, it->w, -1, -1, &scratch_glyph_row,
+                /* FIXME: Use specialized face.  */
+                DEFAULT_FACE_ID);
+  scratch_glyph_row.reversed_p = false;
+  scratch_glyph_row.used[TEXT_AREA] = 0;
+  SET_TEXT_POS (tem_it.position, 0, 0);
+  tem_it.avoid_cursor_p = true;
+  tem_it.bidi_p = true;
+  tem_it.bidi_it.type = WEAK_EN;
+  /* According to UAX#9, EN goes up 2 levels in L2R paragraph and
+     1 level in R2L paragraphs.  Emulate that, assuming we are in
+     an L2R paragraph.  */
+  tem_it.bidi_it.resolved_level = 2;
+
+  /* Produce glyphs for the line number in a scratch glyph_row.  */
+  int n_glyphs_before;
+  for (const char *p = lnum_buf; *p; p++)
+    {
+      /* For continuation lines and lines after ZV, instead of a line
+        number, produce a blank prefix of the same width.  Use the
+        default face for the blank field beyond ZV.  */
+      if (beyond_zv)
+       tem_it.face_id = it->base_face_id;
+      else if (lnum_face_id != current_lnum_face_id
+              && (EQ (Vdisplay_line_numbers, Qvisual)
+                  ? this_line == 0
+                  : this_line == it->pt_lnum))
+       tem_it.face_id = current_lnum_face_id;
+      else
+       tem_it.face_id = lnum_face_id;
+      if (beyond_zv
+         /* Don't display the same line number more than once.  */
+         || (!EQ (Vdisplay_line_numbers, Qvisual)
+             && (it->continuation_lines_width > 0
+                 || (this_line == last_line && !first_time))))
+       tem_it.c = tem_it.char_to_display = ' ';
+      else
+       tem_it.c = tem_it.char_to_display = *p;
+      tem_it.len = 1;
+      n_glyphs_before = scratch_glyph_row.used[TEXT_AREA];
+      /* Make sure these glyphs will have a "position" of -1.  */
+      SET_TEXT_POS (tem_it.position, -1, -1);
+      PRODUCE_GLYPHS (&tem_it);
+
+      /* Stop producing glyphs if we don't have enough space on
+        this line.  FIXME: should we refrain from producing the
+        line number at all in that case?  */
+      if (tem_it.current_x > tem_it.last_visible_x)
+       {
+         scratch_glyph_row.used[TEXT_AREA] = n_glyphs_before;
+         break;
+       }
+    }
+
+  /* Record the width in pixels we need for the line number display.  */
+  it->lnum_pixel_width = tem_it.current_x;
+  /* Copy the produced glyphs into IT's glyph_row.  */
+  struct glyph *g = scratch_glyph_row.glyphs[TEXT_AREA];
+  struct glyph *e = g + scratch_glyph_row.used[TEXT_AREA];
+  struct glyph *p = it->glyph_row ? it->glyph_row->glyphs[TEXT_AREA] : NULL;
+  short *u = it->glyph_row ? &it->glyph_row->used[TEXT_AREA] : NULL;
+
+  for ( ; g < e; g++)
+    {
+      it->current_x += g->pixel_width;
+      /* The following is important when this function is called
+        from move_it_in_display_line_to: HPOS is incremented only
+        when we are in the visible portion of the glyph row.  */
+      if (it->current_x > it->first_visible_x)
+       it->hpos++;
+      if (p)
+       {
+         *p++ = *g;
+         (*u)++;
+       }
+    }
+
+  /* Update IT's metrics due to glyphs produced for line numbers.  */
+  if (it->glyph_row)
+    {
+      struct glyph_row *row = it->glyph_row;
+
+      it->max_ascent = max (row->ascent, tem_it.max_ascent);
+      it->max_descent = max (row->height - row->ascent, tem_it.max_descent);
+      it->max_phys_ascent = max (row->phys_ascent, tem_it.max_phys_ascent);
+      it->max_phys_descent = max (row->phys_height - row->phys_ascent,
+                                 tem_it.max_phys_descent);
+    }
+  else
+    {
+      it->max_ascent = max (it->max_ascent, tem_it.max_ascent);
+      it->max_descent = max (it->max_descent, tem_it.max_descent);
+      it->max_phys_ascent = max (it->max_phys_ascent, tem_it.max_phys_ascent);
+      it->max_phys_descent = max (it->max_phys_descent, 
tem_it.max_phys_descent);
+    }
+
+  bidi_unshelve_cache (itdata, false);
+}
+
+/* Return true if this glyph row needs a line number to be produced
+   for it.  */
+static bool
+should_produce_line_number (struct it *it)
+{
+  if (NILP (Vdisplay_line_numbers))
+    return false;
+
+  /* Don't display line numbers in minibuffer windows.  */
+  if (MINI_WINDOW_P (it->w))
+    return false;
+
+#ifdef HAVE_WINDOW_SYSTEM
+  /* Don't display line number in tooltip frames.  */
+  if (FRAMEP (tip_frame) && EQ (WINDOW_FRAME (it->w), tip_frame))
+    return false;
+#endif
+
+  /* If the character at current position has a non-nil special
+     property, disable line numbers for this row.  This is for
+     packages such as company-mode, which need this for their tricky
+     layout, where line numbers get in the way.  */
+  Lisp_Object val = Fget_char_property (make_number (IT_CHARPOS (*it)),
+                                       Qdisplay_line_numbers_disable,
+                                       it->window);
+  /* For ZV, we need to also look in empty overlays at that point,
+     because get-char-property always returns nil for ZV, except if
+     the property is in 'default-text-properties'.  */
+  if (NILP (val) && IT_CHARPOS (*it) >= ZV)
+    val = disable_line_numbers_overlay_at_eob ();
+  return NILP (val) ? true : false;
+}
+
+/* Return true if ROW has no glyphs except those inserted by the
+   display engine.  This is needed for indicate-empty-lines and
+   similar features when the glyph row starts with glyphs which didn't
+   come from buffer or string.  */
+static bool
+row_text_area_empty (struct glyph_row *row)
+{
+  if (!row->reversed_p)
+    {
+      for (struct glyph *g = row->glyphs[TEXT_AREA];
+          g < row->glyphs[TEXT_AREA] + row->used[TEXT_AREA];
+          g++)
+       if (!NILP (g->object) || g->charpos > 0)
+         return false;
+    }
+  else
+    {
+      for (struct glyph *g = row->glyphs[TEXT_AREA] + row->used[TEXT_AREA] - 1;
+          g > row->glyphs[TEXT_AREA];
+          g--)
+       if (!NILP ((g - 1)->object) || (g - 1)->charpos > 0)
+         return false;
+    }
+
+  return true;
+}
+
 /* Construct the glyph row IT->glyph_row in the desired matrix of
    IT->w from text at the current position of IT.  See dispextern.h
    for an overview of struct it.  Value is true if
@@ -20739,6 +21164,8 @@ display_line (struct it *it, int cursor_vpos)
       (window_hscroll_limited (it->w, it->f) - it->w->min_hscroll)
       * FRAME_COLUMN_WIDTH (it->f);
 
+  bool line_number_needed = should_produce_line_number (it);
+
   /* Move over display elements that are not visible because we are
      hscrolled.  This may stop at an x-position < first_visible_x
      if the first glyph is partially visible or if we hit a line end.  */
@@ -20774,9 +21201,17 @@ display_line (struct it *it, int cursor_vpos)
         are hscrolled to the left of the left edge of the window.  */
       min_pos = CHARPOS (this_line_min_pos);
       min_bpos = BYTEPOS (this_line_min_pos);
+
+      /* Produce line number, if needed.  */
+      if (line_number_needed)
+       maybe_produce_line_number (it);
     }
   else if (it->area == TEXT_AREA)
     {
+      /* Line numbers should precede the line-prefix or wrap-prefix.  */
+      if (line_number_needed)
+       maybe_produce_line_number (it);
+
       /* We only do this when not calling move_it_in_display_line_to
         above, because that function calls itself handle_line_prefix.  */
       handle_line_prefix (it);
@@ -20838,6 +21273,7 @@ display_line (struct it *it, int cursor_vpos)
         buffer reached.  */
       if (!get_next_display_element (it))
        {
+         bool row_has_glyphs = false;
          /* Maybe add a space at the end of this line that is used to
             display the cursor there under X.  Set the charpos of the
             first glyph of blank lines not corresponding to any text
@@ -20846,14 +21282,17 @@ display_line (struct it *it, int cursor_vpos)
            row->exact_window_width_line_p = true;
          else if ((append_space_for_newline (it, true)
                    && row->used[TEXT_AREA] == 1)
-                  || row->used[TEXT_AREA] == 0)
+                  || row->used[TEXT_AREA] == 0
+                  || (row_has_glyphs = row_text_area_empty (row)))
            {
              row->glyphs[TEXT_AREA]->charpos = -1;
-             row->displays_text_p = false;
+             /* Don't reset the displays_text_p flag if we are
+                displaying line numbers or line-prefix.  */
+             if (!row_has_glyphs)
+               row->displays_text_p = false;
 
              if (!NILP (BVAR (XBUFFER (it->w->contents), indicate_empty_lines))
-                 && (!MINI_WINDOW_P (it->w)
-                     || (minibuf_level && EQ (it->window, minibuf_window))))
+                 && (!MINI_WINDOW_P (it->w)))
                row->indicate_empty_line_p = true;
            }
 
@@ -20935,6 +21374,10 @@ display_line (struct it *it, int cursor_vpos)
             process the prefix now.  */
          if (it->area == TEXT_AREA && pending_handle_line_prefix)
            {
+             /* Line numbers should precede the line-prefix or wrap-prefix.  */
+             if (line_number_needed)
+               maybe_produce_line_number (it);
+
              pending_handle_line_prefix = false;
              handle_line_prefix (it);
            }
@@ -22006,7 +22449,7 @@ Value is the new character position of point.  */)
         reach point, in order to start from its X coordinate.  So we
         need to disregard the window's horizontal extent in that case.  */
       if (it.line_wrap == TRUNCATE)
-       it.last_visible_x = INFINITY;
+       it.last_visible_x = DISP_INFINITY;
 
       if (it.cmp_it.id < 0
          && it.method == GET_FROM_STRING
@@ -22099,7 +22542,7 @@ Value is the new character position of point.  */)
            {
              start_display (&it, w, pt);
              if (it.line_wrap == TRUNCATE)
-               it.last_visible_x = INFINITY;
+               it.last_visible_x = DISP_INFINITY;
              reseat_at_previous_visible_line_start (&it);
              it.current_x = it.current_y = it.hpos = 0;
              if (pt_vpos != 0)
@@ -27616,15 +28059,23 @@ x_produce_glyphs (struct it *it)
            {
              int tab_width = it->tab_width * font->space_width;
              int x = it->current_x + it->continuation_lines_width;
+             int x0 = x;
+             /* Adjust for line numbers, if needed.   */
+             if (!NILP (Vdisplay_line_numbers) && x0 >= it->lnum_pixel_width)
+               x -= it->lnum_pixel_width;
              int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * 
tab_width;
 
              /* If the distance from the current position to the next tab
                 stop is less than a space character width, use the
                 tab stop after that.  */
-             if (next_tab_x - x < font->space_width)
+             if (next_tab_x - x0 < font->space_width)
                next_tab_x += tab_width;
+             if (!NILP (Vdisplay_line_numbers) && x0 >= it->lnum_pixel_width)
+               next_tab_x += (it->lnum_pixel_width
+                              - ((it->w->hscroll * font->space_width)
+                                 % tab_width));
 
-             it->pixel_width = next_tab_x - x;
+             it->pixel_width = next_tab_x - x0;
              it->nglyphs = 1;
              if (FONT_TOO_HIGH (font))
                {
@@ -31708,6 +32159,12 @@ They are still logged to the *Messages* buffer.  */);
   /* Name of the face used to highlight trailing whitespace.  */
   DEFSYM (Qtrailing_whitespace, "trailing-whitespace");
 
+  /* Names of the faces used to display line numbers.  */
+  DEFSYM (Qline_number, "line-number");
+  DEFSYM (Qline_number_current_line, "line-number-current-line");
+  /* Name of a text property which disables line-number display.  */
+  DEFSYM (Qdisplay_line_numbers_disable, "display-line-numbers-disable");
+
   /* Name and number of the face used to highlight escape glyphs.  */
   DEFSYM (Qescape_glyph, "escape-glyph");
 
@@ -32215,6 +32672,46 @@ To add a prefix to continuation lines, use 
`wrap-prefix'.  */);
   DEFSYM (Qline_prefix, "line-prefix");
   Fmake_variable_buffer_local (Qline_prefix);
 
+  DEFVAR_LISP ("display-line-numbers", Vdisplay_line_numbers,
+    doc: /* Non-nil means display line numbers.
+By default, line numbers are displayed before each non-continuation
+line that displays buffer text, i.e. after each newline that came
+from buffer text.  However, if the value is `visual', every screen
+line will have a number.
+
+Lisp programs can disable display of a line number of a particular
+screen line by putting the `display-line-numbers-disable' text
+property or overlay property on the first visible character of
+that line.  */);
+  Vdisplay_line_numbers = Qnil;
+  DEFSYM (Qdisplay_line_numbers, "display-line-numbers");
+  Fmake_variable_buffer_local (Qdisplay_line_numbers);
+  DEFSYM (Qrelative, "relative");
+  DEFSYM (Qvisual, "visual");
+
+  DEFVAR_LISP ("display-line-number-width", Vdisplay_line_number_width,
+    doc: /* Minimum width of space reserved for line number display.
+A positive number means reserve that many columns for line numbers,
+even if the actual number needs less space.
+The default value of nil means compute the space dynamically.
+Any other value is treated as nil.  */);
+  Vdisplay_line_number_width = Qnil;
+  DEFSYM (Qdisplay_line_number_width, "display-line-number-width");
+  Fmake_variable_buffer_local (Qdisplay_line_number_width);
+
+  DEFVAR_LISP ("display-line-numbers-current-absolute",
+              Vdisplay_line_numbers_current_absolute,
+    doc: /* Non-nil means display absolute number of current line.
+This variable has effect only when `display-line-numbers' is
+either `relative' or `visual'.  */);
+  Vdisplay_line_numbers_current_absolute = Qt;
+
+  DEFVAR_BOOL ("display-line-numbers-widen", display_line_numbers_widen,
+    doc: /* Non-nil means display line numbers disregarding any narrowing.  
*/);
+  display_line_numbers_widen = false;
+  DEFSYM (Qdisplay_line_numbers_widen, "display-line-numbers-widen");
+  Fmake_variable_buffer_local (Qdisplay_line_numbers_widen);
+
   DEFVAR_BOOL ("inhibit-eval-during-redisplay", inhibit_eval_during_redisplay,
     doc: /* Non-nil means don't eval Lisp during redisplay.  */);
   inhibit_eval_during_redisplay = false;



reply via email to

[Prev in Thread] Current Thread [Next in Thread]