summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Zaretskii <eliz@gnu.org>2017-06-17 17:42:44 +0300
committerEli Zaretskii <eliz@gnu.org>2017-06-17 17:42:44 +0300
commit7277c0fca7dab9f1b311c3eba5c42fd17acc3593 (patch)
tree6426512a85cc8a16bd274bb93eaf857f440e40db
parentdaf78963ee96484df1ecb0c10e7c0040d7b544a5 (diff)
downloademacs-7277c0fca7dab9f1b311c3eba5c42fd17acc3593.tar.gz
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.
-rw-r--r--etc/NEWS21
-rw-r--r--lisp/cus-start.el16
-rw-r--r--lisp/faces.el8
-rw-r--r--lisp/menu-bar.el19
-rw-r--r--src/dispextern.h3
-rw-r--r--src/xdisp.c126
6 files changed, 162 insertions, 31 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 2fb8daab101..856ebfe35e7 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -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
diff --git a/lisp/cus-start.el b/lisp/cus-start.el
index 744fe7f69ee..0fe41d7c3ea 100644
--- a/lisp/cus-start.el
+++ b/lisp/cus-start.el
@@ -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
diff --git a/lisp/faces.el b/lisp/faces.el
index 9a8a1344caf..ac2d210a32f 100644
--- a/lisp/faces.el
+++ b/lisp/faces.el
@@ -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
diff --git a/lisp/menu-bar.el b/lisp/menu-bar.el
index 9c7bcffbaab..06f8c7872b7 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/src/dispextern.h b/src/dispextern.h
index 050c68b8e08..08e5caa893b 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -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;
diff --git a/src/xdisp.c b/src/xdisp.c
index dcef242966e..ebf5edc4d05 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -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. */);