1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-12-27 10:54:40 +00:00

Finish up native display of line numbers

* src/xdisp.c (maybe_produce_line_number): Produce a blank before
the number, for R2L rows.  Increment 'g' in the loop even if
glyph_row is NULL.  Accept 2nd argument FORCE and produce the
line-number glyphs if it is non-zero.
(move_it_in_display_line_to): Account for the space taken by the
line-number glyphs.  Call maybe_produce_line_number with 2nd
argument non-zero.
(set_cursor_from_row): Fix calculation of cursor X coordinate in
R2L rows with display-produced glyphs at the beginning.
(syms_of_xdisp) <line-number>: New face symbol.
<relative, display-line-width>: New symbols.
(maybe_produce_line_number): Use the line-number face for
displaying line numbers.  Support relative line-number display.
Support user-defined width for displaying line numbers.
(try_cursor_movement, try_window_id): Disable these optimizations
when displaying relative line numbers.
* src/dispextern.h (struct it): New member 'pt_lnum'.

* lisp/faces.el (line-number): New face.
* lisp/cus-start.el (standard): Provide customization forms for
display-line-numbers and display-line-width.
* lisp/menu-bar.el (menu-bar-showhide-menu): Add menu-bar item to
turn display-line-numbers on and off.

* etc/NEWS: Document the new feature.
This commit is contained in:
Eli Zaretskii 2017-06-17 17:42:44 +03:00
parent daf78963ee
commit 7277c0fca7
6 changed files with 162 additions and 31 deletions

View File

@ -377,6 +377,27 @@ 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".
** 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. The default is nil, which
doesn't display the line numbers.
You can also customize the new variable 'display-lines-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 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 keep the line-number display area of constant 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

View File

@ -584,6 +584,22 @@ 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))
"26.1")
(display-line-width display
(choice
(const :tag "Dynamically computed"
:value nil)
(integer :menu-tag "Fixed number of columns"
:value 2
:format "%v"))
"26.1")
;; xfaces.c
(scalable-fonts-allowed display boolean "22.1")
;; xfns.c

View File

@ -2465,6 +2465,14 @@ 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."
:version "26.1"
:group 'basic-faces)
(defface escape-glyph
'((((background dark)) :foreground "cyan")
;; See the comment in minibuffer-prompt for

View File

@ -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]

View File

@ -2671,6 +2671,9 @@ struct it
zero if not computed. */
int lnum_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;

View File

@ -833,6 +833,7 @@ 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 *, bool);
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);
@ -8652,9 +8653,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 (!NILP (Vdisplay_line_numbers)
&& it->current_x == it->first_visible_x)
maybe_produce_line_number (it, true);
/* 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));
@ -14787,15 +14795,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)
@ -15932,6 +15937,9 @@ 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)
/* 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
@ -18433,6 +18441,10 @@ 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. */
if (EQ (Vdisplay_line_numbers, Qrelative))
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
@ -20679,8 +20691,13 @@ find_row_edges (struct it *it, struct glyph_row *row,
row->maxpos = it->current.pos;
}
/* Produce the line-number glyphs for the current glyph_row. If
IT->glyph_row is non-NULL, populate the row with the produced
glyphs. FORCE non-zero means produce the glyphs even if the line
number didn't change since the last time this function was called;
this is used by move_it_in_display_line_to. */
static void
maybe_produce_line_number (struct it *it)
maybe_produce_line_number (struct it *it, bool force)
{
ptrdiff_t last_line = it->lnum;
ptrdiff_t start_from, bytepos;
@ -20709,9 +20726,12 @@ maybe_produce_line_number (struct it *it)
eassert (this_line > 0 || (this_line == 0 && start_from == BEGV_BYTE));
eassert (bytepos == IT_BYTEPOS (*it));
/* If this is a new logical line, produce the glyphs for the line
number. */
if (this_line != last_line || !last_line || it->continuation_lines_width > 0)
/* Produce the glyphs for the line number if needed. */
if (force
|| !last_line
|| this_line != last_line
|| it->continuation_lines_width > 0
|| (EQ (Vdisplay_line_numbers, Qrelative) && PT != it->w->last_point))
{
if (this_line != last_line || !last_line)
{
@ -20723,19 +20743,51 @@ maybe_produce_line_number (struct it *it)
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 */
/* Compute point's line number if needed. */
if (EQ (Vdisplay_line_numbers, Qrelative) && !it->pt_lnum)
{
ptrdiff_t ignored;
if (PT_BYTE > it->lnum_bytepos)
it->pt_lnum =
this_line + display_count_lines (it->lnum_bytepos, PT_BYTE, PT,
&ignored);
else
it->pt_lnum = display_count_lines (BEGV_BYTE, PT_BYTE, PT,
&ignored);
}
/* Compute the required width if needed. */
if (!it->lnum_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 =
this_line + it->w->desired_matrix->nrows - 1 - it->vpos;
it->lnum_width = log10 (max_lnum) + 1;
if (NATNUMP (Vdisplay_line_width))
it->lnum_width = XFASTINT (Vdisplay_line_width);
else
{
/* 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 (EQ (Vdisplay_line_numbers, Qrelative))
/* We subtract one more because the current line is
always zero under relative line-number display. */
max_lnum = it->w->desired_matrix->nrows - 2;
else
max_lnum =
this_line + it->w->desired_matrix->nrows - 1 - it->vpos;
it->lnum_width = log10 (max_lnum) + 1;
}
eassert (it->lnum_width > 0);
}
pint2str (lnum_buf, it->lnum_width, this_line + 1);
/* Append a blank. */
if (EQ (Vdisplay_line_numbers, Qrelative))
lnum_offset = it->pt_lnum;
/* 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, eabs (this_line - lnum_offset));
strcat (lnum_buf, " ");
/* Setup for producing the glyphs. */
@ -20745,12 +20797,12 @@ maybe_produce_line_number (struct it *it)
scratch_glyph_row.reversed_p = false;
scratch_glyph_row.used[TEXT_AREA] = 0;
SET_TEXT_POS (tem_it.position, 0, 0);
tem_it.face_id = merge_faces (it->f, Qline_number, 0, DEFAULT_FACE_ID);
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. */
1 level in R2L paragraphs. Emulate that, assuming we are in
an L2R paragraph. */
tem_it.bidi_it.resolved_level = 2;
if (it->glyph_row && it->glyph_row->reversed_p)
tem_it.bidi_it.resolved_level = 1;
/* Produce glyphs for the line number in a scratch glyph_row. */
int n_glyphs_before;
@ -20784,13 +20836,17 @@ maybe_produce_line_number (struct it *it)
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;
while (g < e)
for ( ; g < e; g++)
{
it->current_x += g->pixel_width;
it->hpos++;
/* 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++;
*p++ = *g;
(*u)++;
}
}
@ -20922,13 +20978,13 @@ display_line (struct it *it, int cursor_vpos)
/* Produce line number, if needed. */
if (!NILP (Vdisplay_line_numbers))
maybe_produce_line_number (it);
maybe_produce_line_number (it, false);
}
else if (it->area == TEXT_AREA)
{
/* Line numbers should precede the line-prefix or wrap-prefix. */
if (!NILP (Vdisplay_line_numbers))
maybe_produce_line_number (it);
maybe_produce_line_number (it, false);
/* We only do this when not calling move_it_in_display_line_to
above, because that function calls itself handle_line_prefix. */
@ -21090,7 +21146,7 @@ display_line (struct it *it, int cursor_vpos)
{
/* Line numbers should precede the line-prefix or wrap-prefix. */
if (!NILP (Vdisplay_line_numbers))
maybe_produce_line_number (it);
maybe_produce_line_number (it, false);
pending_handle_line_prefix = false;
handle_line_prefix (it);
@ -31778,6 +31834,9 @@ They are still logged to the *Messages* buffer. */);
/* Name of the face used to highlight trailing whitespace. */
DEFSYM (Qtrailing_whitespace, "trailing-whitespace");
/* Name of the face used to display line numbers. */
DEFSYM (Qline_number, "line-number");
/* Name and number of the face used to highlight escape glyphs. */
DEFSYM (Qescape_glyph, "escape-glyph");
@ -32297,6 +32356,15 @@ after each newline that comes from buffer text. */);
Vdisplay_line_numbers = Qnil;
DEFSYM (Qdisplay_line_numbers, "display-line-numbers");
Fmake_variable_buffer_local (Qdisplay_line_numbers);
DEFSYM (Qrelative, "relative");
DEFVAR_LISP ("display-line-width", Vdisplay_line_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_width = Qnil;
DEFVAR_BOOL ("inhibit-eval-during-redisplay", inhibit_eval_during_redisplay,
doc: /* Non-nil means don't eval Lisp during redisplay. */);