mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-27 07:37:33 +00:00
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.
This commit is contained in:
commit
5df239fc6f
@ -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.
|
||||
@xref{Optional Mode Line}.
|
||||
@xref{Optional 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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
@cindex display of line number
|
||||
@cindex 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.
|
||||
|
||||
@vindex display-line-numbers
|
||||
@cindex number lines in a buffer
|
||||
@cindex display line numbers
|
||||
If you want to have Emacs display line numbers for every line in the
|
||||
buffer, customize the buffer-local variable
|
||||
@code{display-line-numbers}; it is @code{nil} by default. This
|
||||
variable can have several different values to support various modes of
|
||||
line-number display:
|
||||
|
||||
@table @asis
|
||||
@item @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.
|
||||
|
||||
@item @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.
|
||||
|
||||
@item @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.
|
||||
|
||||
@item anything else
|
||||
Any other non-@code{nil} value is treated as @code{t}.
|
||||
@end table
|
||||
|
||||
@vindex 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
|
||||
@code{nil} 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.
|
||||
|
||||
@vindex 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 non-@code{nil}
|
||||
value, line numbers will disregard any narrowing and will start at the
|
||||
first character of the buffer.
|
||||
|
||||
@cindex 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,
|
||||
@code{line-number-current-line}, 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 non-@code{nil}, Emacs attempts
|
||||
to make the whole screen blink when it would normally make an audible bell
|
||||
|
@ -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}.
|
||||
|
||||
@findex linum-mode
|
||||
@cindex Linum mode
|
||||
@item
|
||||
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}.
|
||||
|
@ -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.
|
||||
|
||||
@defun 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
|
||||
non-@code{nil}, means return the value in pixels; otherwise the value
|
||||
is returned in column units of the font defined for the
|
||||
@code{line-number} 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.
|
||||
@end defun
|
||||
|
||||
|
||||
@node Line Height
|
||||
@section Line Height
|
||||
|
52
etc/NEWS
52
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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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]
|
||||
|
@ -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)
|
||||
|
27
src/buffer.c
27
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. */
|
||||
|
@ -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;
|
||||
|
||||
|
70
src/indent.c
70
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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
547
src/xdisp.c
547
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;
|
||||
|
Loading…
Reference in New Issue
Block a user