From daf78963ee96484df1ecb0c10e7c0040d7b544a5 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 16 Jun 2017 22:44:48 +0300 Subject: [PATCH 01/39] Initial version of native display of line numbers * src/xdisp.c (syms_of_xdisp) : New buffer-local variable. Include . (maybe_produce_line_number): New function. (DISP_INFINITY): Rename from INFINITY, since math.h defines INFINITY. (try_window_reusing_current_matrix): Don't use this method when display-line-numbers is in effect. * src/dispextern.h (struct it): New members 'lnum'. --- src/dispextern.h | 18 ++++- src/xdisp.c | 176 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 187 insertions(+), 7 deletions(-) diff --git a/src/dispextern.h b/src/dispextern.h index d1e4715c329..050c68b8e08 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 @@ -2571,7 +2572,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; @@ -2655,6 +2661,16 @@ 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 needed for display of the line numbers, or + zero if not computed. */ + int lnum_width; + /* 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 34ee877e6be..dcef242966e 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -290,6 +290,7 @@ along with GNU Emacs. If not, see . */ #include #include #include +#include #include "lisp.h" #include "atimer.h" @@ -324,7 +325,7 @@ along with GNU Emacs. If not, see . */ #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; @@ -843,6 +844,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 *); @@ -6751,7 +6754,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. */ @@ -13138,7 +13141,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 @@ -15823,7 +15826,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) { @@ -17593,6 +17596,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); @@ -20670,6 +20679,141 @@ find_row_edges (struct it *it, struct glyph_row *row, row->maxpos = it->current.pos; } +static void +maybe_produce_line_number (struct it *it) +{ + ptrdiff_t last_line = it->lnum; + ptrdiff_t start_from, bytepos; + + /* FIXME: Maybe reuse the data in it->w->base_line_number. */ + if (!last_line) + start_from = BEGV; + 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 (!(BEGV_BYTE <= start_from && start_from < ZV_BYTE)) + { + last_line = 0; + start_from = BEGV_BYTE; + } + + ptrdiff_t this_line; + + this_line = + last_line + display_count_lines (start_from, + IT_BYTEPOS (*it), IT_CHARPOS (*it), + &bytepos); + 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) + { + if (this_line != last_line || !last_line) + { + it->lnum = this_line; + it->lnum_bytepos = IT_BYTEPOS (*it); + } + + void *itdata = bidi_shelve_cache (); + struct it tem_it; + char lnum_buf[INT_STRLEN_BOUND (ptrdiff_t) + 1]; + bool beyond_zv = IT_BYTEPOS (*it) >= ZV_BYTE ? true : false; + /* 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; + eassert (it->lnum_width > 0); + } + pint2str (lnum_buf, it->lnum_width, this_line + 1); + /* Append a blank. */ + 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.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. */ + 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; + 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. */ + if (beyond_zv || it->continuation_lines_width > 0) + 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; + } + } + + /* 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; + + while (g < e) + { + it->current_x += g->pixel_width; + it->hpos++; + if (p) + { + *p++ = *g++; + (*u)++; + } + } + + /* Update IT->glyph_row's metrics. */ + if (it->glyph_row) + { + struct glyph_row *row = it->glyph_row; + + row->ascent = max (row->ascent, tem_it.max_ascent); + row->height = max (row->height, + tem_it.max_ascent + tem_it.max_descent); + row->phys_ascent = max (row->phys_ascent, tem_it.max_phys_ascent); + row->phys_height = max (row->phys_height, + tem_it.max_phys_ascent + tem_it.max_phys_descent); + row->extra_line_spacing = max (row->extra_line_spacing, + tem_it.max_extra_line_spacing); + } + + bidi_unshelve_cache (itdata, false); + } +} + /* 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 @@ -20775,9 +20919,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 (!NILP (Vdisplay_line_numbers)) + maybe_produce_line_number (it); } 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); + /* 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); @@ -20936,6 +21088,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 (!NILP (Vdisplay_line_numbers)) + maybe_produce_line_number (it); + pending_handle_line_prefix = false; handle_line_prefix (it); } @@ -22007,7 +22163,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 @@ -22100,7 +22256,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) @@ -32134,6 +32290,14 @@ 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. +Line numbers are displayed before each non-continuation line, i.e. +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); + 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; From 7277c0fca7dab9f1b311c3eba5c42fd17acc3593 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 17 Jun 2017 17:42:44 +0300 Subject: [PATCH 02/39] 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) : New face symbol. : 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. --- etc/NEWS | 21 ++++++++ lisp/cus-start.el | 16 ++++++ lisp/faces.el | 8 +++ lisp/menu-bar.el | 19 ++++++- src/dispextern.h | 3 ++ src/xdisp.c | 126 +++++++++++++++++++++++++++++++++++----------- 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. */); From d4eddb08e505ff9b4d956f00f225e3baf0d15462 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 23 Jun 2017 17:13:01 +0300 Subject: [PATCH 03/39] Fix display of indicate-empty-lines when line numbers are displayed * src/xdisp.c (row_text_area_empty): New function. (display_line): 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. (display_line): Delete the argument FORCE; all callers changed. Remove the condition for actually producing the glyphs for the line number, as even if the number didn't change we need to produce empty space. --- src/xdisp.c | 322 +++++++++++++++++++++++++++------------------------- 1 file changed, 170 insertions(+), 152 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index ebf5edc4d05..136e8391d46 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -833,7 +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 void maybe_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); @@ -8658,7 +8658,7 @@ move_it_in_display_line_to (struct it *it, /* 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); + maybe_produce_line_number (it); /* If there's a line-/wrap-prefix, handle it. */ if (it->method == GET_FROM_BUFFER) handle_line_prefix (it); @@ -20693,14 +20693,13 @@ find_row_edges (struct it *it, struct glyph_row *row, /* 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. */ + glyphs. */ static void -maybe_produce_line_number (struct it *it, bool force) +maybe_produce_line_number (struct it *it) { ptrdiff_t last_line = it->lnum; ptrdiff_t start_from, bytepos; + ptrdiff_t this_line; /* FIXME: Maybe reuse the data in it->w->base_line_number. */ if (!last_line) @@ -20717,8 +20716,6 @@ maybe_produce_line_number (struct it *it, bool force) start_from = BEGV_BYTE; } - ptrdiff_t this_line; - this_line = last_line + display_count_lines (start_from, IT_BYTEPOS (*it), IT_CHARPOS (*it), @@ -20726,148 +20723,168 @@ maybe_produce_line_number (struct it *it, bool force) eassert (this_line > 0 || (this_line == 0 && start_from == BEGV_BYTE)); eassert (bytepos == IT_BYTEPOS (*it)); - /* 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)) + /* Produce the glyphs for the line number. */ + if (this_line != last_line || !last_line) { - if (this_line != last_line || !last_line) - { - it->lnum = this_line; - it->lnum_bytepos = IT_BYTEPOS (*it); - } - - void *itdata = bidi_shelve_cache (); - 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) - { - 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); - } - 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. */ - 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.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, 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. */ - if (beyond_zv || it->continuation_lines_width > 0) - 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; - } - } - - /* 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->glyph_row's metrics. */ - if (it->glyph_row) - { - struct glyph_row *row = it->glyph_row; - - row->ascent = max (row->ascent, tem_it.max_ascent); - row->height = max (row->height, - tem_it.max_ascent + tem_it.max_descent); - row->phys_ascent = max (row->phys_ascent, tem_it.max_phys_ascent); - row->phys_height = max (row->phys_height, - tem_it.max_phys_ascent + tem_it.max_phys_descent); - row->extra_line_spacing = max (row->extra_line_spacing, - tem_it.max_extra_line_spacing); - } - - bidi_unshelve_cache (itdata, false); + it->lnum = this_line; + it->lnum_bytepos = IT_BYTEPOS (*it); } + + void *itdata = bidi_shelve_cache (); + 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) + { + 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); + } + 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. */ + 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.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, 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. */ + if (beyond_zv || it->continuation_lines_width > 0) + 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; + } + } + + /* 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->glyph_row's metrics. */ + if (it->glyph_row) + { + struct glyph_row *row = it->glyph_row; + + row->ascent = max (row->ascent, tem_it.max_ascent); + row->height = max (row->height, + tem_it.max_ascent + tem_it.max_descent); + row->phys_ascent = max (row->phys_ascent, tem_it.max_phys_ascent); + row->phys_height = max (row->phys_height, + tem_it.max_phys_ascent + tem_it.max_phys_descent); + row->extra_line_spacing = max (row->extra_line_spacing, + tem_it.max_extra_line_spacing); + } + + bidi_unshelve_cache (itdata, 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 @@ -20978,13 +20995,13 @@ display_line (struct it *it, int cursor_vpos) /* Produce line number, if needed. */ if (!NILP (Vdisplay_line_numbers)) - maybe_produce_line_number (it, false); + maybe_produce_line_number (it); } 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, false); + 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. */ @@ -21055,7 +21072,8 @@ 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_text_area_empty (row)) { row->glyphs[TEXT_AREA]->charpos = -1; row->displays_text_p = false; @@ -21146,7 +21164,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, false); + maybe_produce_line_number (it); pending_handle_line_prefix = false; handle_line_prefix (it); From bbaf2f3d529ac3f8d72b671ee3a8a0c3347c5510 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 23 Jun 2017 18:13:53 +0300 Subject: [PATCH 04/39] Fix background color beyond EOB and cursor display * src/xdisp.c: (maybe_produce_line_number): Use the default face for background of the blank glyphs in the line-number area which are drawn beyond EOB. (display_line): Reset the glyph row's displays_text_p flag only on empty lines that don't display line numbers. This fixes cursor display beyond EOB. Fix the bidi information in the glyphs produced for line numbers. Set the avoid_cursor_p flag of glyphs produced for line numbers. --- src/xdisp.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index 136e8391d46..f4e8aeee390 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -20788,7 +20788,8 @@ 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.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 @@ -20797,10 +20798,16 @@ maybe_produce_line_number (struct it *it) /* Produce glyphs for the line number in a scratch glyph_row. */ int n_glyphs_before; + int lnum_face_id = merge_faces (it->f, Qline_number, 0, DEFAULT_FACE_ID); 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. */ + /* 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 + tem_it.face_id = lnum_face_id; if (beyond_zv || it->continuation_lines_width > 0) tem_it.c = tem_it.char_to_display = ' '; else @@ -21064,6 +21071,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 @@ -21073,10 +21081,13 @@ display_line (struct it *it, int cursor_vpos) else if ((append_space_for_newline (it, true) && row->used[TEXT_AREA] == 1) || row->used[TEXT_AREA] == 0 - || row_text_area_empty (row)) + || (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) From 77f8b86e405cc0ff9c49aea5d98097212755b832 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 11:34:52 +0300 Subject: [PATCH 05/39] Fix display of line numbers with fonts larger than the default * src/xdisp.c (maybe_produce_line_number): Update the metrics in IT, not in IT->glyph_row, since the latter gets overwritten in display_line. Fixes display of line numbers when the font used for them is larger than that of the default face. --- src/xdisp.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index f4e8aeee390..39176e0e675 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -20849,19 +20849,16 @@ maybe_produce_line_number (struct it *it) } } - /* Update IT->glyph_row's metrics. */ + /* Update IT's metrics due to glyphs produced for line numbers. */ if (it->glyph_row) { struct glyph_row *row = it->glyph_row; - row->ascent = max (row->ascent, tem_it.max_ascent); - row->height = max (row->height, - tem_it.max_ascent + tem_it.max_descent); - row->phys_ascent = max (row->phys_ascent, tem_it.max_phys_ascent); - row->phys_height = max (row->phys_height, - tem_it.max_phys_ascent + tem_it.max_phys_descent); - row->extra_line_spacing = max (row->extra_line_spacing, - tem_it.max_extra_line_spacing); + 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); } bidi_unshelve_cache (itdata, false); From 5b648ac7a2b2e1b77eb59573db59019d5068476c Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 12:37:30 +0300 Subject: [PATCH 06/39] Fix problems with line-number updates in Follow mode * src/xdisp.c (redisplay_window): If forced window-start requires to move a window's point, and the window is under relative line-number display, force another round of redisplay to update the relative line numbers. This fixes follow-mode "redisplay" of its window group. * lisp/frame.el: Add display-line-numbers to the list of variables that should trigger redisplay of the current buffer. --- lisp/frame.el | 1 + src/xdisp.c | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lisp/frame.el b/lisp/frame.el index b7a55169281..8f51afa2a9a 100644 --- a/lisp/frame.el +++ b/lisp/frame.el @@ -2434,6 +2434,7 @@ See also `toggle-frame-maximized'." line-prefix wrap-prefix truncate-lines + display-line-numbers bidi-paragraph-direction bidi-display-reordering)) diff --git a/src/xdisp.c b/src/xdisp.c index 39176e0e675..9b5762550d7 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -16800,10 +16800,14 @@ 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) + && 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; From 9776d7bcf044722909c10c9395d18c81641f27d0 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 13:01:30 +0300 Subject: [PATCH 07/39] Don't display line numbers in the minibuffer and in tooltip frames. --- src/xdisp.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index 9b5762550d7..19e3efb2f3d 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -21002,13 +21002,23 @@ display_line (struct it *it, int cursor_vpos) min_bpos = BYTEPOS (this_line_min_pos); /* Produce line number, if needed. */ - if (!NILP (Vdisplay_line_numbers)) + if (!NILP (Vdisplay_line_numbers) +#ifdef HAVE_WINDOW_SYSTEM + && !(FRAMEP (tip_frame) + && EQ (WINDOW_FRAME (it->w), tip_frame)) +#endif + && (!MINI_WINDOW_P (it->w))) maybe_produce_line_number (it); } else if (it->area == TEXT_AREA) { /* Line numbers should precede the line-prefix or wrap-prefix. */ - if (!NILP (Vdisplay_line_numbers)) + if (!NILP (Vdisplay_line_numbers) +#ifdef HAVE_WINDOW_SYSTEM + && !(FRAMEP (tip_frame) + && EQ (WINDOW_FRAME (it->w), tip_frame)) +#endif + && (!MINI_WINDOW_P (it->w))) maybe_produce_line_number (it); /* We only do this when not calling move_it_in_display_line_to @@ -21091,8 +21101,7 @@ display_line (struct it *it, int cursor_vpos) 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; } @@ -21175,7 +21184,13 @@ display_line (struct it *it, int cursor_vpos) if (it->area == TEXT_AREA && pending_handle_line_prefix) { /* Line numbers should precede the line-prefix or wrap-prefix. */ - if (!NILP (Vdisplay_line_numbers)) + if (!NILP (Vdisplay_line_numbers) +#ifdef HAVE_WINDOW_SYSTEM + && !(FRAMEP (tip_frame) + && EQ (WINDOW_FRAME (it->w), tip_frame)) +#endif + && (!MINI_WINDOW_P (it->w) + || (minibuf_level && EQ (it->window, minibuf_window)))) maybe_produce_line_number (it); pending_handle_line_prefix = false; From 7d7602cea09692eddb6a8d16f7786b5086a01091 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 13:26:01 +0300 Subject: [PATCH 08/39] Fix crashes on TTY frames due to negative lnum_width. --- src/xdisp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xdisp.c b/src/xdisp.c index 19e3efb2f3d..f98e7a9ac7e 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -20770,6 +20770,7 @@ maybe_produce_line_number (struct it *it) else max_lnum = this_line + it->w->desired_matrix->nrows - 1 - it->vpos; + max_lnum = max (1, max_lnum); it->lnum_width = log10 (max_lnum) + 1; } eassert (it->lnum_width > 0); From 55a9298d63121578cd66ef7f14c14b2160aae77d Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 14:29:32 +0300 Subject: [PATCH 09/39] Fix tab stops when line numbers are displayed * src/xdisp.c (x_produce_glyphs): * src/term.c (produce_glyphs): Adjust tab stops for the horizontal space taken by the line-number display. --- src/term.c | 4 ++++ src/xdisp.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/term.c b/src/term.c index 8770aff8a92..b0e7e052e51 100644 --- a/src/term.c +++ b/src/term.c @@ -1584,6 +1584,10 @@ produce_glyphs (struct it *it) { int absolute_x = (it->current_x + it->continuation_lines_width); + /* Adjust for line numbers. Kludge alert: the "2" below is + because we add 2 blanks to the actual line number. */ + if (!NILP (Vdisplay_line_numbers)) + absolute_x -= it->lnum_width + 2; int next_tab_x = (((1 + absolute_x + it->tab_width - 1) / it->tab_width) diff --git a/src/xdisp.c b/src/xdisp.c index f98e7a9ac7e..5f86f0bfde6 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -27865,6 +27865,10 @@ x_produce_glyphs (struct it *it) { int tab_width = it->tab_width * font->space_width; int x = it->current_x + it->continuation_lines_width; + /* Adjust for line numbers. Kludge alert: the "2" below + is because we add 2 blanks to the actual line number. */ + if (!NILP (Vdisplay_line_numbers)) + x -= (it->lnum_width + 2) * font->space_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 From efedb664666563da6455500ade488fd9726be83a Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 14:53:35 +0300 Subject: [PATCH 10/39] Rename display-line-width * etc/NEWS: * src/xdisp.c (syms_of_xdisp, maybe_produce_line_number): * lisp/cus-start.el: Rename display-line-width to display-line-number-width. --- etc/NEWS | 6 ++++-- lisp/cus-start.el | 2 +- src/xdisp.c | 8 ++++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 856ebfe35e7..03204beb9ee 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -386,8 +386,10 @@ 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 +The new face 'line-number' is used to display the line numbers. + +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 it as needed. Setting it to a non-negative integer specifies that as the minimal width; selecting a diff --git a/lisp/cus-start.el b/lisp/cus-start.el index 0fe41d7c3ea..773520c64f2 100644 --- a/lisp/cus-start.el +++ b/lisp/cus-start.el @@ -592,7 +592,7 @@ since it could result in memory overflow and make Emacs crash." (const :tag "Relative line numbers" :value relative)) "26.1") - (display-line-width display + (display-line-number-width display (choice (const :tag "Dynamically computed" :value nil) diff --git a/src/xdisp.c b/src/xdisp.c index 5f86f0bfde6..d23b1768d68 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -20754,8 +20754,8 @@ maybe_produce_line_number (struct it *it) /* Compute the required width if needed. */ if (!it->lnum_width) { - if (NATNUMP (Vdisplay_line_width)) - it->lnum_width = XFASTINT (Vdisplay_line_width); + if (NATNUMP (Vdisplay_line_number_width)) + it->lnum_width = XFASTINT (Vdisplay_line_number_width); else { /* Max line number to be displayed cannot be more than @@ -32408,13 +32408,13 @@ after each newline that comes from buffer text. */); Fmake_variable_buffer_local (Qdisplay_line_numbers); DEFSYM (Qrelative, "relative"); - DEFVAR_LISP ("display-line-width", Vdisplay_line_width, + 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_width = Qnil; + Vdisplay_line_number_width = Qnil; DEFVAR_BOOL ("inhibit-eval-during-redisplay", inhibit_eval_during_redisplay, doc: /* Non-nil means don't eval Lisp during redisplay. */); From fa5e84cccd31cf94074255180d6ff3a44d4f8f89 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 15:15:02 +0300 Subject: [PATCH 11/39] Change display of current line in relative mode * src/xdisp.c (maybe_produce_line_number): In relative mode display the current line number as its absolute value, not as zero. --- src/xdisp.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index d23b1768d68..8acba259d2f 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -20763,13 +20763,7 @@ maybe_produce_line_number (struct it *it) 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; + max_lnum = this_line + it->w->desired_matrix->nrows - 1 - it->vpos; max_lnum = max (1, max_lnum); it->lnum_width = log10 (max_lnum) + 1; } @@ -20778,12 +20772,18 @@ maybe_produce_line_number (struct it *it) if (EQ (Vdisplay_line_numbers, Qrelative)) lnum_offset = it->pt_lnum; + /* Under 'relative', display the absolute line number for the + current line, as displaying zero gives zero useful information. */ + ptrdiff_t lnum_to_display = eabs (this_line - lnum_offset); + if (EQ (Vdisplay_line_numbers, Qrelative) + && lnum_to_display == 0) + 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, eabs (this_line - lnum_offset)); + pint2str (lnum_buf, it->lnum_width + 1, lnum_to_display); strcat (lnum_buf, " "); /* Setup for producing the glyphs. */ From 71a7294d0a775a8969ec077eb3633da6bdad7c62 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 15:45:23 +0300 Subject: [PATCH 12/39] Support a separate face for displaying the current line's number * lisp/faces.el (line-number-current-line): New face. * src/xdisp.c (syms_of_xdisp) : New symbol. (try_window_id, try_cursor_movement): Disable these optimizations when the line-number-current-line face is different from line-number face. (maybe_produce_line_number): Display the current line in the line-number-current-line face, if it's different from line-number. --- lisp/faces.el | 7 +++++++ src/xdisp.c | 29 ++++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/lisp/faces.el b/lisp/faces.el index ac2d210a32f..3a40dc90081 100644 --- a/lisp/faces.el +++ b/lisp/faces.el @@ -2473,6 +2473,13 @@ This face is used when `display-line-numbers' is non-nil." :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." + :version "26.1" + :group 'basic-faces) + (defface escape-glyph '((((background dark)) :foreground "cyan") ;; See the comment in minibuffer-prompt for diff --git a/src/xdisp.c b/src/xdisp.c index 8acba259d2f..cf396de203e 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -15940,6 +15940,13 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, /* When display-line-numbers is in relative mode, moving point requires to redraw the entire window. */ && !EQ (Vdisplay_line_numbers, Qrelative) + /* 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 @@ -18445,8 +18452,13 @@ 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 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) + || (!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 @@ -20739,8 +20751,13 @@ maybe_produce_line_number (struct it *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) && !it->pt_lnum) + if ((EQ (Vdisplay_line_numbers, Qrelative) + || lnum_face_id != current_lnum_face_id) + && !it->pt_lnum) { ptrdiff_t ignored; if (PT_BYTE > it->lnum_bytepos) @@ -20803,7 +20820,6 @@ maybe_produce_line_number (struct it *it) /* Produce glyphs for the line number in a scratch glyph_row. */ int n_glyphs_before; - int lnum_face_id = merge_faces (it->f, Qline_number, 0, DEFAULT_FACE_ID); for (const char *p = lnum_buf; *p; p++) { /* For continuation lines and lines after ZV, instead of a line @@ -20811,6 +20827,8 @@ maybe_produce_line_number (struct it *it) 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 && this_line == it->pt_lnum) + tem_it.face_id = current_lnum_face_id; else tem_it.face_id = lnum_face_id; if (beyond_zv || it->continuation_lines_width > 0) @@ -31884,8 +31902,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. */ + /* Names of the faces used to display line numbers. */ DEFSYM (Qline_number, "line-number"); + DEFSYM (Qline_number_current_line, "line-number-current-line"); /* Name and number of the face used to highlight escape glyphs. */ DEFSYM (Qescape_glyph, "escape-glyph"); From 6e18841b17c9b7ca9f38b923db4195cade05da2e Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 16:58:01 +0300 Subject: [PATCH 13/39] Allow Lisp program to disable line-number display for specific lines * etc/NEWS: Update the documentation. * src/xdisp.c (syms_of_xdisp) : New symbol. (should_produce_line_number): New function. (display_line): Use should_produce_line_number to determine whether a line number should be produced for each glyph row. --- etc/NEWS | 9 ++++++++- src/xdisp.c | 52 +++++++++++++++++++++++++++++++++------------------- 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 03204beb9ee..b125b89370f 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -386,7 +386,10 @@ 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. -The new face 'line-number' is used to display the line numbers. +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 @@ -396,6 +399,10 @@ 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. +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. + Linum mode and all similar packages are henceforth becoming obsolete. Users and developers are encouraged to switch to this new feature instead. diff --git a/src/xdisp.c b/src/xdisp.c index cf396de203e..d35170ed43e 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -20887,6 +20887,32 @@ maybe_produce_line_number (struct it *it) 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. */ + Lisp_Object val = Fget_char_property (make_number (IT_CHARPOS (*it)), + Qdisplay_line_numbers_disable, + it->window); + 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 @@ -20984,6 +21010,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. */ @@ -21021,23 +21049,13 @@ display_line (struct it *it, int cursor_vpos) min_bpos = BYTEPOS (this_line_min_pos); /* Produce line number, if needed. */ - if (!NILP (Vdisplay_line_numbers) -#ifdef HAVE_WINDOW_SYSTEM - && !(FRAMEP (tip_frame) - && EQ (WINDOW_FRAME (it->w), tip_frame)) -#endif - && (!MINI_WINDOW_P (it->w))) + 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 (!NILP (Vdisplay_line_numbers) -#ifdef HAVE_WINDOW_SYSTEM - && !(FRAMEP (tip_frame) - && EQ (WINDOW_FRAME (it->w), tip_frame)) -#endif - && (!MINI_WINDOW_P (it->w))) + if (line_number_needed) maybe_produce_line_number (it); /* We only do this when not calling move_it_in_display_line_to @@ -21203,13 +21221,7 @@ display_line (struct it *it, int cursor_vpos) if (it->area == TEXT_AREA && pending_handle_line_prefix) { /* Line numbers should precede the line-prefix or wrap-prefix. */ - if (!NILP (Vdisplay_line_numbers) -#ifdef HAVE_WINDOW_SYSTEM - && !(FRAMEP (tip_frame) - && EQ (WINDOW_FRAME (it->w), tip_frame)) -#endif - && (!MINI_WINDOW_P (it->w) - || (minibuf_level && EQ (it->window, minibuf_window)))) + if (line_number_needed) maybe_produce_line_number (it); pending_handle_line_prefix = false; @@ -31905,6 +31917,8 @@ They are still logged to the *Messages* buffer. */); /* 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"); From 13cc19a0a3685ceade4a5a560475ee47165f3bbc Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 19:03:39 +0300 Subject: [PATCH 14/39] Partial fix of hscroll of truncated lines with line numbers * src/xdisp.c (x_produce_glyphs, hscroll_window_tree): Adjust hscroll calculations to line-number display. * src/term.c (produce_glyphs): Adjust tab stop to window's hscroll. These two changes fix horizontal scrolling when line numbers are displayed. But there's still a bug: the horizontal shift of lines that begin with a TAB is different from the rest. * src/xdisp.c (move_it_in_display_line_to): Call should_produce_line_number to determine whether a line number should be produced for this screen line. --- src/term.c | 2 +- src/xdisp.c | 34 ++++++++++++++++++++++++++++++---- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/term.c b/src/term.c index b0e7e052e51..46d8bff73cc 100644 --- a/src/term.c +++ b/src/term.c @@ -1587,7 +1587,7 @@ produce_glyphs (struct it *it) /* Adjust for line numbers. Kludge alert: the "2" below is because we add 2 blanks to the actual line number. */ if (!NILP (Vdisplay_line_numbers)) - absolute_x -= it->lnum_width + 2; + absolute_x -= it->lnum_width + 2 - it->w->hscroll; int next_tab_x = (((1 + absolute_x + it->tab_width - 1) / it->tab_width) diff --git a/src/xdisp.c b/src/xdisp.c index d35170ed43e..d0673595390 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -834,6 +834,7 @@ 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); @@ -8656,7 +8657,7 @@ move_it_in_display_line_to (struct it *it, if (it->hpos == 0) { /* If line numbers are being displayed, produce a line number. */ - if (!NILP (Vdisplay_line_numbers) + 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. */ @@ -13068,6 +13069,30 @@ 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; + 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; + } + } text_area_width = window_box_width (w, TEXT_AREA); @@ -13100,7 +13125,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)))) @@ -13118,7 +13143,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 @@ -27898,7 +27924,7 @@ x_produce_glyphs (struct it *it) /* Adjust for line numbers. Kludge alert: the "2" below is because we add 2 blanks to the actual line number. */ if (!NILP (Vdisplay_line_numbers)) - x -= (it->lnum_width + 2) * font->space_width; + x -= (it->lnum_width + 2 - it->w->hscroll) * font->space_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 From 0d5c713a6b21cd3bd8a232ff35924c65cd3cce6b Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 19:40:41 +0300 Subject: [PATCH 15/39] Move additional hscrolling code into a suitable 'if' * src/xdisp.c (hscroll_window_tree): Make additional calculations regarding glyphs produced for line numbers conditional on line-number display. --- src/xdisp.c | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index d0673595390..6fa1d841ee2 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -13070,27 +13070,34 @@ 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; - struct glyph *g; - if (!row_r2l_p) + /* When line numbers are displayed, we need to account for + the horizontal space they consume. */ + if (!NILP (Vdisplay_line_numbers)) { - for (g = cursor_row->glyphs[TEXT_AREA]; - g < cursor_row->glyphs[TEXT_AREA] + cursor_row->used[TEXT_AREA]; - g++) + struct glyph *g; + if (!row_r2l_p) { - if (!(NILP (g->object) && g->charpos < 0)) - break; - x_offset += g->pixel_width; + 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--) + else { - if (!(NILP ((g - 1)->object) && (g - 1)->charpos < 0)) - break; - x_offset += (g - 1)->pixel_width; + 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; + } } } From ead4ab635989c85a860d99b9005bc5d16635731f Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 20:11:56 +0300 Subject: [PATCH 16/39] Improve documentation in NEWS. --- etc/NEWS | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index b125b89370f..845ab382297 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -383,25 +383,28 @@ 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. +number relative to the line showing point, with that line's number +displayed as absolute. The default is nil, which doesn't display the +line numbers. 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 +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 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. +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. +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. Linum mode and all similar packages are henceforth becoming obsolete. Users and developers are encouraged to switch to this new feature From 16d2695674a4c8abbec846c427fe8abef97e07ef Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 21:10:04 +0300 Subject: [PATCH 17/39] Minor change in NEWS. --- etc/NEWS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/etc/NEWS b/etc/NEWS index 845ab382297..e201d88a098 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -387,6 +387,9 @@ number relative to the line showing point, with that line's number displayed as absolute. The default is nil, which doesn't display the line numbers. +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 From 540669cda984f64964d7baeb7369d3eea424a34c Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 25 Jun 2017 19:33:04 +0300 Subject: [PATCH 18/39] Fix line number display for overlay/display strings with newlines * src/xdisp.c (maybe_produce_line_number): Fix the condition for producing space glyphs instead of a line number to include the case of display strings and overlays. --- src/xdisp.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index 6fa1d841ee2..c318a6954c4 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -20749,10 +20749,15 @@ 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; /* FIXME: Maybe reuse the data in it->w->base_line_number. */ if (!last_line) - start_from = BEGV; + { + start_from = BEGV; + if (!it->lnum_bytepos) + first_time = true; + } else start_from = it->lnum_bytepos; @@ -20772,13 +20777,14 @@ maybe_produce_line_number (struct it *it) eassert (this_line > 0 || (this_line == 0 && start_from == BEGV_BYTE)); eassert (bytepos == IT_BYTEPOS (*it)); - /* Produce the glyphs for the line number. */ + /* Record the line number information. */ if (this_line != last_line || !last_line) { it->lnum = this_line; it->lnum_bytepos = IT_BYTEPOS (*it); } + /* Produce the glyphs for the line number. */ void *itdata = bidi_shelve_cache (); struct it tem_it; char lnum_buf[INT_STRLEN_BOUND (ptrdiff_t) + 1]; @@ -20864,7 +20870,10 @@ maybe_produce_line_number (struct it *it) tem_it.face_id = current_lnum_face_id; else tem_it.face_id = lnum_face_id; - if (beyond_zv || it->continuation_lines_width > 0) + if (beyond_zv + /* Don't display the same line number more than once. */ + || 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; From 5d1025e7162db46b3c8d7c19facd8f9b9eff6f49 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 25 Jun 2017 20:53:05 +0300 Subject: [PATCH 19/39] Allow to disable display of line numbers beyond EOB * src/buffer.c (disable_line_numbers_overlay_at_eob): New function. * src/lisp.h (disable_line_numbers_overlay_at_eob): Add prototype. * src/xdisp.c (should_produce_line_number): When at ZV, call disable_line_numbers_overlay_at_eob to determine whether line numbers should be displayed beyond ZV. --- src/buffer.c | 27 +++++++++++++++++++++++++++ src/lisp.h | 1 + src/xdisp.c | 13 +++++++++---- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/buffer.c b/src/buffer.c index 80dbd3318dc..780e4d7a7d6 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/lisp.h b/src/lisp.h index ff8dde2b825..f5cb6c75706 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/xdisp.c b/src/xdisp.c index c318a6954c4..7649b16e974 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -20948,10 +20948,15 @@ should_produce_line_number (struct it *it) #endif /* If the character at current position has a non-nil special - property, disable line numbers for this row. */ - Lisp_Object val = Fget_char_property (make_number (IT_CHARPOS (*it)), - Qdisplay_line_numbers_disable, - it->window); + property, disable line numbers for this row. For ZV, we need to + use a special algorithm that only supports empty overlays at that + point, because get-char-property always returns nil for ZV. */ + Lisp_Object val = Qnil; + if (IT_CHARPOS (*it) >= ZV) + val = disable_line_numbers_overlay_at_eob (); + else + val = Fget_char_property (make_number (IT_CHARPOS (*it)), + Qdisplay_line_numbers_disable, it->window); return NILP (val) ? true : false; } From 33073d5629ca44f0d5db6fb29d1229da74e0e3c1 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 25 Jun 2017 20:55:58 +0300 Subject: [PATCH 20/39] Minor aesthetic fix of last change. --- src/xdisp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xdisp.c b/src/xdisp.c index 7649b16e974..aa75fcaf77c 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -20951,7 +20951,7 @@ should_produce_line_number (struct it *it) property, disable line numbers for this row. For ZV, we need to use a special algorithm that only supports empty overlays at that point, because get-char-property always returns nil for ZV. */ - Lisp_Object val = Qnil; + Lisp_Object val; if (IT_CHARPOS (*it) >= ZV) val = disable_line_numbers_overlay_at_eob (); else From 67c8a219e670eed317acdffc68a2888e2c557e79 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 26 Jun 2017 19:38:17 +0300 Subject: [PATCH 21/39] Update IT's metrics while simulating display * src/xdisp.c (maybe_produce_line_number): Update IT's metrics also when glyph_row is NULL. This is important for move_it_* functions. --- src/xdisp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/xdisp.c b/src/xdisp.c index aa75fcaf77c..3283f9ee971 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -20925,6 +20925,13 @@ maybe_produce_line_number (struct it *it) 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); } From beb95a8f890da611acc1a4422211deafe512d87d Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 26 Jun 2017 23:20:49 +0300 Subject: [PATCH 22/39] Initial support for visually-relative line numbers Works very slowly. * src/xdisp.c (display_count_lines_visually): New function. (maybe_produce_line_number): Support 'visual' mode of line-number display. * src/xdisp.c (maybe_produce_line_number): Update IT's metrics also when glyph_row is NULL. This is important for move_it_* functions. (syms_of_xdisp) : Now buffer-local. (try_window_id, redisplay_window, try_cursor_movement): For 'visual' line-number display, disable the same redisplay optimizations as for 'relative'. * lisp/cus-start.el (standard): Add new value for the customization form of display-line-numbers. --- lisp/cus-start.el | 4 +- src/xdisp.c | 116 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 85 insertions(+), 35 deletions(-) diff --git a/lisp/cus-start.el b/lisp/cus-start.el index 773520c64f2..599e7e57f32 100644 --- a/lisp/cus-start.el +++ b/lisp/cus-start.el @@ -590,7 +590,9 @@ since it could result in memory overflow and make Emacs crash." (const :tag "Absolute line numbers" :value t) (const :tag "Relative line numbers" - :value relative)) + :value relative) + (const :tag "Visually relative line numbers" + :value visual)) "26.1") (display-line-number-width display (choice diff --git a/src/xdisp.c b/src/xdisp.c index 3283f9ee971..67266fdf315 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -15973,6 +15973,7 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, /* 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. */ @@ -16841,7 +16842,8 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) safe__call1 (true, Vpre_redisplay_function, Fcons (window, Qnil)); if (w->redisplay || XBUFFER (w->contents)->text->redisplay - || (EQ (Vdisplay_line_numbers, Qrelative) + || ((EQ (Vdisplay_line_numbers, Qrelative) + || EQ (Vdisplay_line_numbers, Qvisual)) && row != MATRIX_FIRST_TEXT_ROW (w->desired_matrix))) { /* Either pre-redisplay-function made changes (e.g. move @@ -18488,6 +18490,7 @@ try_window_id (struct window *w) /* 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, @@ -20740,6 +20743,35 @@ find_row_edges (struct it *it, struct glyph_row *row, row->maxpos = it->current.pos; } +/* Count the number of screen lines in window W between character + position CHARPOS and the line showing that window's point. */ +static ptrdiff_t +display_count_lines_visually (struct window *w, struct text_pos pos) +{ + struct it tem_it; + ptrdiff_t to; + struct text_pos from; + ptrdiff_t count = SPECPDL_INDEX (); + + if (CHARPOS (pos) <= PT) + { + from = pos; + to = PT; + } + else + { + SET_TEXT_POS (from, PT, PT_BYTE); + to = CHARPOS (pos); + } + start_display (&tem_it, w, from); + /* Need to disable visual mode temporarily, since otherwise the call + to move_it_to will cause infionite recursion. */ + specbind (Qdisplay_line_numbers, Qrelative); + move_it_to (&tem_it, to, -1, -1, -1, MOVE_TO_POS); + unbind_to (count, Qnil); + return CHARPOS (pos) <= 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. */ @@ -20750,42 +20782,47 @@ maybe_produce_line_number (struct it *it) ptrdiff_t start_from, bytepos; ptrdiff_t this_line; bool first_time = false; + void *itdata = bidi_shelve_cache (); - /* FIXME: Maybe reuse the data in it->w->base_line_number. */ - if (!last_line) - { - start_from = BEGV; - if (!it->lnum_bytepos) - first_time = true; - } + if (EQ (Vdisplay_line_numbers, Qvisual)) + this_line = display_count_lines_visually (it->w, it->current.pos); 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 (!(BEGV_BYTE <= start_from && start_from < ZV_BYTE)) { - last_line = 0; - start_from = BEGV_BYTE; - } + if (!last_line) + { + /* FIXME: Maybe reuse the data in it->w->base_line_number. */ + start_from = BEGV; + if (!it->lnum_bytepos) + first_time = true; + } + else + start_from = it->lnum_bytepos; - this_line = - last_line + display_count_lines (start_from, - IT_BYTEPOS (*it), IT_CHARPOS (*it), - &bytepos); - eassert (this_line > 0 || (this_line == 0 && start_from == BEGV_BYTE)); - eassert (bytepos == IT_BYTEPOS (*it)); + /* 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 (!(BEGV_BYTE <= start_from && start_from < ZV_BYTE)) + { + last_line = 0; + start_from = BEGV_BYTE; + } - /* Record the line number information. */ - if (this_line != last_line || !last_line) - { - it->lnum = this_line; - it->lnum_bytepos = IT_BYTEPOS (*it); + this_line = + last_line + display_count_lines (start_from, + IT_BYTEPOS (*it), IT_CHARPOS (*it), + &bytepos); + eassert (this_line > 0 || (this_line == 0 && start_from == BEGV_BYTE)); + eassert (bytepos == IT_BYTEPOS (*it)); + + /* Record the line number information. */ + if (this_line != last_line || !last_line) + { + it->lnum = this_line; + it->lnum_bytepos = IT_BYTEPOS (*it); + } } /* Produce the glyphs for the line number. */ - void *itdata = bidi_shelve_cache (); struct it tem_it; char lnum_buf[INT_STRLEN_BOUND (ptrdiff_t) + 1]; bool beyond_zv = IT_BYTEPOS (*it) >= ZV_BYTE ? true : false; @@ -20795,11 +20832,12 @@ maybe_produce_line_number (struct it *it) = 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) + if (PT_BYTE > it->lnum_bytepos && !EQ (Vdisplay_line_numbers, Qvisual)) it->pt_lnum = this_line + display_count_lines (it->lnum_bytepos, PT_BYTE, PT, &ignored); @@ -20819,7 +20857,10 @@ maybe_produce_line_number (struct it *it) matrix. */ ptrdiff_t max_lnum; - max_lnum = this_line + it->w->desired_matrix->nrows - 1 - it->vpos; + 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 = log10 (max_lnum) + 1; } @@ -20827,11 +20868,14 @@ maybe_produce_line_number (struct it *it) } 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, as displaying zero gives zero useful information. */ ptrdiff_t lnum_to_display = eabs (this_line - lnum_offset); - if (EQ (Vdisplay_line_numbers, Qrelative) + if ((EQ (Vdisplay_line_numbers, Qrelative) + || EQ (Vdisplay_line_numbers, Qvisual)) && lnum_to_display == 0) lnum_to_display = it->pt_lnum + 1; /* In L2R rows we need to append the blank separator, in R2L @@ -20872,8 +20916,9 @@ maybe_produce_line_number (struct it *it) tem_it.face_id = lnum_face_id; if (beyond_zv /* Don't display the same line number more than once. */ - || it->continuation_lines_width > 0 - || (this_line == last_line && !first_time)) + && (!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; @@ -32494,6 +32539,7 @@ after each newline that comes from buffer text. */); 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. @@ -32502,6 +32548,8 @@ 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_BOOL ("inhibit-eval-during-redisplay", inhibit_eval_during_redisplay, doc: /* Non-nil means don't eval Lisp during redisplay. */); From 71e31ac839b05d01486d728d4da9a8daaf1ae240 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Tue, 27 Jun 2017 19:46:50 +0300 Subject: [PATCH 23/39] Support default-text-properties * src/xdisp.c (should_produce_line_number): Call get-char-property at ZV as well, to support default-text-properties. --- src/xdisp.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index 67266fdf315..ef2e2646b2c 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -21000,15 +21000,17 @@ should_produce_line_number (struct it *it) #endif /* If the character at current position has a non-nil special - property, disable line numbers for this row. For ZV, we need to - use a special algorithm that only supports empty overlays at that - point, because get-char-property always returns nil for ZV. */ - Lisp_Object val; - if (IT_CHARPOS (*it) >= ZV) + 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 (); - else - val = Fget_char_property (make_number (IT_CHARPOS (*it)), - Qdisplay_line_numbers_disable, it->window); return NILP (val) ? true : false; } From 5b9b49492b9c024bd07b83ef6e5d095af6b8fdd0 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Thu, 29 Jun 2017 21:09:55 +0300 Subject: [PATCH 24/39] Minor fixes * src/xdisp.c (maybe_produce_line_number): Fix bug that caused line numbers to be displayed in empty lines beyond ZV. (x_produce_glyphs): Start fixing TAB display in truncated lines. --- src/xdisp.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index ef2e2646b2c..bbf30504844 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -20916,7 +20916,7 @@ maybe_produce_line_number (struct it *it) 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) + || (!EQ (Vdisplay_line_numbers, Qvisual) && (it->continuation_lines_width > 0 || (this_line == last_line && !first_time)))) tem_it.c = tem_it.char_to_display = ' '; @@ -27996,19 +27996,22 @@ 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. Kludge alert: the "2" below is because we add 2 blanks to the actual line number. */ if (!NILP (Vdisplay_line_numbers)) - x -= (it->lnum_width + 2 - it->w->hscroll) * font->space_width; + x -= (it->lnum_width + 2) * font->space_width; int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width; + if (!NILP (Vdisplay_line_numbers)) + next_tab_x += (it->lnum_width + 2) * font->space_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; - it->pixel_width = next_tab_x - x; + it->pixel_width = next_tab_x - x0; it->nglyphs = 1; if (FONT_TOO_HIGH (font)) { From dfe1c820d3dca6673aba911a4a37969bbabd0486 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 30 Jun 2017 11:43:49 +0300 Subject: [PATCH 25/39] Fix TAB display when the line-number face uses a smaller/larger font * src/dispextern.h (struct it): New member lnum_pixel_width. * src/xdisp.c (maybe_produce_line_number): Compute the width of the line-number display in pixels. (x_produce_glyphs): Use it->lnum_pixel_width instead of a kludge that used it->lnum_width and made assumptions about pixel width. --- src/dispextern.h | 5 +++-- src/xdisp.c | 9 +++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/dispextern.h b/src/dispextern.h index 08e5caa893b..84a27169ea1 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -2667,9 +2667,10 @@ struct it /* The byte position corresponding to lnum. */ ptrdiff_t lnum_bytepos; - /* The width in columns needed for display of the line numbers, or - zero if not computed. */ + /* 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; diff --git a/src/xdisp.c b/src/xdisp.c index bbf30504844..3fc5f29d0c4 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -20938,6 +20938,8 @@ maybe_produce_line_number (struct it *it) } } + /* 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]; @@ -27997,13 +27999,12 @@ 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. Kludge alert: the "2" below - is because we add 2 blanks to the actual line number. */ + /* Adjust for line numbers, if needed. */ if (!NILP (Vdisplay_line_numbers)) - x -= (it->lnum_width + 2) * font->space_width; + x -= it->lnum_pixel_width; int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width; if (!NILP (Vdisplay_line_numbers)) - next_tab_x += (it->lnum_width + 2) * font->space_width; + next_tab_x += it->lnum_pixel_width; /* If the distance from the current position to the next tab stop is less than a space character width, use the From a06dd3b9187489b61f08256d9e9a07745302dc4e Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 30 Jun 2017 12:24:13 +0300 Subject: [PATCH 26/39] Fix hscrolling with line numbers on TTY frames * src/xdisp.c (hscroll_window_tree): Correct the X offset calculations on TTY frames. * src/term.c (produce_glyphs): Use it->lnum_pixel_width instead of a kludge using it->lnum_width. --- src/term.c | 10 ++++++---- src/xdisp.c | 9 ++++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/term.c b/src/term.c index 46d8bff73cc..00a272c3b0b 100644 --- a/src/term.c +++ b/src/term.c @@ -1584,14 +1584,16 @@ produce_glyphs (struct it *it) { int absolute_x = (it->current_x + it->continuation_lines_width); - /* Adjust for line numbers. Kludge alert: the "2" below is - because we add 2 blanks to the actual line number. */ + int x0 = absolute_x; + /* Adjust for line numbers. */ if (!NILP (Vdisplay_line_numbers)) - absolute_x -= it->lnum_width + 2 - it->w->hscroll; + 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 @@ -1599,7 +1601,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 3fc5f29d0c4..26b19eb44fb 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -13100,6 +13100,12 @@ hscroll_window_tree (Lisp_Object window) } } } + 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); @@ -28004,7 +28010,8 @@ x_produce_glyphs (struct it *it) x -= it->lnum_pixel_width; int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width; if (!NILP (Vdisplay_line_numbers)) - next_tab_x += it->lnum_pixel_width; + next_tab_x += (it->lnum_pixel_width + - it->w->hscroll * font->space_width); /* If the distance from the current position to the next tab stop is less than a space character width, use the From 0e4f2e01af1f4c51b958057d86e28c04cdefddb4 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 30 Jun 2017 15:55:51 +0300 Subject: [PATCH 27/39] Speed up the visual-mode relative line numbers * src/xdisp.c (display_count_lines_visually): Introduce a shortcut: if a relative line number was already calculated for this iterator object, just increase it instead of the expensive call to move_it_to. Argument list changed to pass a pointer to the iterator object. (maybe_produce_line_number): Adjust for change in signature of display_count_lines_visually. Record the relative line number and the corresponding byte position in the iterator object also in the 'visual' mode. --- src/xdisp.c | 61 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index 26b19eb44fb..5c6aea19697 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -20749,33 +20749,44 @@ find_row_edges (struct it *it, struct glyph_row *row, row->maxpos = it->current.pos; } -/* Count the number of screen lines in window W between character - position CHARPOS and the line showing that window's point. */ +/* 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 window *w, struct text_pos pos) +display_count_lines_visually (struct it *it) { struct it tem_it; ptrdiff_t to; struct text_pos from; - ptrdiff_t count = SPECPDL_INDEX (); - if (CHARPOS (pos) <= PT) - { - from = pos; - to = PT; - } + /* 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 { - SET_TEXT_POS (from, PT, PT_BYTE); - to = CHARPOS (pos); + 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); + move_it_to (&tem_it, to, -1, -1, -1, MOVE_TO_POS); + unbind_to (count, Qnil); + return IT_CHARPOS (*it) <= PT ? -tem_it.vpos : tem_it.vpos; } - start_display (&tem_it, w, from); - /* Need to disable visual mode temporarily, since otherwise the call - to move_it_to will cause infionite recursion. */ - specbind (Qdisplay_line_numbers, Qrelative); - move_it_to (&tem_it, to, -1, -1, -1, MOVE_TO_POS); - unbind_to (count, Qnil); - return CHARPOS (pos) <= PT ? -tem_it.vpos : tem_it.vpos; } /* Produce the line-number glyphs for the current glyph_row. If @@ -20791,7 +20802,7 @@ maybe_produce_line_number (struct it *it) void *itdata = bidi_shelve_cache (); if (EQ (Vdisplay_line_numbers, Qvisual)) - this_line = display_count_lines_visually (it->w, it->current.pos); + this_line = display_count_lines_visually (it); else { if (!last_line) @@ -20819,13 +20830,13 @@ maybe_produce_line_number (struct it *it) &bytepos); eassert (this_line > 0 || (this_line == 0 && start_from == BEGV_BYTE)); eassert (bytepos == IT_BYTEPOS (*it)); + } - /* Record the line number information. */ - if (this_line != last_line || !last_line) - { - it->lnum = this_line; - it->lnum_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. */ From 7a762fbbfc1c05be8de3d253251f5e7b32da2c73 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 30 Jun 2017 16:37:57 +0300 Subject: [PATCH 28/39] Support displaying zero as the number of the current line * src/xdisp.c (syms_of_xdisp) : New variable. : Doc fix. (maybe_produce_line_number): Support nil value of display-line-numbers-current-absolute. * lisp/cus-start.el (standard): Add customization form for display-line-numbers-current-absolute. * etc/NEWS: Document recently introduced features. --- etc/NEWS | 14 ++++++++++++-- lisp/cus-start.el | 7 +++++++ src/xdisp.c | 26 +++++++++++++++++++++----- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index e201d88a098..9f4c3bbb3e0 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -384,8 +384,18 @@ 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. The default is nil, which doesn't display the -line numbers. +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. diff --git a/lisp/cus-start.el b/lisp/cus-start.el index 599e7e57f32..ed17113c784 100644 --- a/lisp/cus-start.el +++ b/lisp/cus-start.el @@ -602,6 +602,13 @@ since it could result in memory overflow and make Emacs crash." :value 2 :format "%v")) "26.1") + (display-line-numbers-current-absolute + (choice + (const :tag "Display actual number of current line" + :value t) + (const :tag "Display zero as number of current line" + :value nil)) + "26.1") ;; xfaces.c (scalable-fonts-allowed display boolean "22.1") ;; xfns.c diff --git a/src/xdisp.c b/src/xdisp.c index 5c6aea19697..7851487e74e 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -20874,7 +20874,13 @@ maybe_produce_line_number (struct it *it) matrix. */ ptrdiff_t max_lnum; - if (EQ (Vdisplay_line_numbers, Qvisual)) + 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; @@ -20889,11 +20895,12 @@ maybe_produce_line_number (struct it *it) lnum_offset = 0; /* Under 'relative', display the absolute line number for the - current line, as displaying zero gives zero useful information. */ + 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) + && 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 @@ -32557,8 +32564,10 @@ To add a prefix to continuation lines, use `wrap-prefix'. */); DEFVAR_LISP ("display-line-numbers", Vdisplay_line_numbers, doc: /* Non-nil means display line numbers. -Line numbers are displayed before each non-continuation line, i.e. -after each newline that comes from buffer text. */); +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. */); Vdisplay_line_numbers = Qnil; DEFSYM (Qdisplay_line_numbers, "display-line-numbers"); Fmake_variable_buffer_local (Qdisplay_line_numbers); @@ -32575,6 +32584,13 @@ Any other value is treated as nil. */); 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 ("inhibit-eval-during-redisplay", inhibit_eval_during_redisplay, doc: /* Non-nil means don't eval Lisp during redisplay. */); inhibit_eval_during_redisplay = false; From e83b128a8195e5c63f12832decf70c2953821dc0 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 30 Jun 2017 17:33:06 +0300 Subject: [PATCH 29/39] Add documentation for display-line-numbers * 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. (Optional Mode Line): Fix the index entry to not conflict with that in "Display Custom". * doc/emacs/basic.texi (Position Info): Add cross-reference to "Display Custom", for line-number display. * src/xdisp.c (syms_of_xdisp): : Mention display-line-numbers-disable in the doc string. * lisp/cus-start.el (standard): Fix lst change. --- doc/emacs/basic.texi | 3 ++- doc/emacs/custom.texi | 1 - doc/emacs/display.texi | 54 +++++++++++++++++++++++++++++++++++++++++- doc/emacs/modes.texi | 5 ---- etc/NEWS | 3 ++- lisp/cus-start.el | 2 +- src/xdisp.c | 7 +++++- 7 files changed, 64 insertions(+), 11 deletions(-) diff --git a/doc/emacs/basic.texi b/doc/emacs/basic.texi index 6b66c18016b..5878e7da256 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. -@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 diff --git a/doc/emacs/custom.texi b/doc/emacs/custom.texi index c84f4a975d8..a756a89e3f8 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 "") 'flyspell-mode) -(global-set-key (kbd "C-") 'linum-mode) (global-set-key (kbd "C-") 'forward-sentence) (global-set-key (kbd "") 'mouse-save-then-kill) @end example diff --git a/doc/emacs/display.texi b/doc/emacs/display.texi index c4554eb3187..61ca7e24f84 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 -@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,58 @@ 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. + +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 diff --git a/doc/emacs/modes.texi b/doc/emacs/modes.texi index be893403012..eb0c88b2901 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}. -@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}. diff --git a/etc/NEWS b/etc/NEWS index 9f4c3bbb3e0..b50c770c505 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -377,6 +377,7 @@ 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 @@ -410,7 +411,7 @@ 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 +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. diff --git a/lisp/cus-start.el b/lisp/cus-start.el index ed17113c784..a89d5dff0cd 100644 --- a/lisp/cus-start.el +++ b/lisp/cus-start.el @@ -602,7 +602,7 @@ since it could result in memory overflow and make Emacs crash." :value 2 :format "%v")) "26.1") - (display-line-numbers-current-absolute + (display-line-numbers-current-absolute display (choice (const :tag "Display actual number of current line" :value t) diff --git a/src/xdisp.c b/src/xdisp.c index 7851487e74e..bcd7d33332f 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -32567,7 +32567,12 @@ To add a prefix to continuation lines, use `wrap-prefix'. */); 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. */); +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); From a9be5a768b6c06e74a386c474aba8125dfc8ed86 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 30 Jun 2017 22:48:36 +0300 Subject: [PATCH 30/39] Fix relative-number display with non-nil display-line-number-width * src/xdisp.c (maybe_produce_line_number): Don't treat a zero value of display-line-number-width as acceptable. Handle the case of 'relative' with display-line-number-width non-nil and smaller than the absolute line number requires. Reported by Alex . --- src/xdisp.c | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index bcd7d33332f..aeccac2cb16 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -20867,26 +20867,23 @@ maybe_produce_line_number (struct it *it) { if (NATNUMP (Vdisplay_line_number_width)) it->lnum_width = XFASTINT (Vdisplay_line_number_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 (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 = log10 (max_lnum) + 1; - } + /* 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)) From 1174e53ebb9610dc352c4a5c533d24c935cc1ed9 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 30 Jun 2017 23:19:53 +0300 Subject: [PATCH 31/39] Improve documentation of faces related to display-line-numbers * lisp/faces.el (line-number, line-number-current-line): Warn against using non-monospaced fonts. --- lisp/faces.el | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/lisp/faces.el b/lisp/faces.el index 3a40dc90081..c3693d16631 100644 --- a/lisp/faces.el +++ b/lisp/faces.el @@ -2469,14 +2469,26 @@ If you set `term-file-prefix' to nil, this function does nothing." (defface line-number '((t :inherit (shadow default))) "Face for displaying line numbers. -This face is used when `display-line-numbers' is non-nil." +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." +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) From fb62728b7afa7024d4ca01e6f89b0267231cf607 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 1 Jul 2017 10:22:45 +0300 Subject: [PATCH 32/39] Avoid slow redisplay under 'visual' mode of line numbers * src/xdisp.c (display_count_lines_visually): Avoid very slow redisplay when this function is invoked very far from point. Reported by Alex . --- src/xdisp.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/xdisp.c b/src/xdisp.c index aeccac2cb16..7bbe9d9ca3e 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -20783,7 +20783,14 @@ display_count_lines_visually (struct it *it) /* Need to disable visual mode temporarily, since otherwise the call to move_it_to will cause infinite recursion. */ specbind (Qdisplay_line_numbers, Qrelative); - move_it_to (&tem_it, to, -1, -1, -1, MOVE_TO_POS); + /* 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; } From b5ce3100a8549df519d6f2b577fe7c3acf90cb40 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 1 Jul 2017 16:00:18 +0300 Subject: [PATCH 33/39] Improve display of tabs with line numbers * src/xdisp.c (x_produce_glyphs): Improve calculation of next tab stop in hscrolled lines. Prevent aborts in compute_line_metrics. --- src/xdisp.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index 7bbe9d9ca3e..47b81414630 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -28028,18 +28028,19 @@ x_produce_glyphs (struct it *it) int x = it->current_x + it->continuation_lines_width; int x0 = x; /* Adjust for line numbers, if needed. */ - if (!NILP (Vdisplay_line_numbers)) + 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 (!NILP (Vdisplay_line_numbers)) - next_tab_x += (it->lnum_pixel_width - - it->w->hscroll * font->space_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 - 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 - x0; it->nglyphs = 1; From 4c9353a5840b285631a86a5bad2b48ea6276abf3 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 2 Jul 2017 18:01:39 +0300 Subject: [PATCH 34/39] Avoid off-by-one errors in column C-n/C-p calculations * 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. --- src/indent.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/indent.c b/src/indent.c index adecc3622a8..2cacfbbe3c0 100644 --- a/src/indent.c +++ b/src/indent.c @@ -2068,9 +2068,26 @@ 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; + if (!NILP (Vdisplay_line_numbers) + && !EQ (Vdisplay_line_numbers, Qvisual)) + { + struct text_pos wstart; + SET_TEXT_POS_FROM_MARKER (wstart, w->start); + itdata = bidi_shelve_cache (); + start_display (&it, w, wstart); + move_it_by_lines (&it, 1); + lnum_width = it.lnum_width; + bidi_unshelve_cache (itdata, 0); + } 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); From 52bfb7d4d6595302b5261ff810951e0b3281352c Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 3 Jul 2017 18:57:01 +0300 Subject: [PATCH 35/39] Avoid errors in vertical-motion when buffer is narrowed * src/indent.c (Fvertical_motion): If need to start from window-start, and it is outside of the accessible portion, temporarily widen the buffer. This avoids errors in evil-mode. Reported by James Nguyen . --- src/indent.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/indent.c b/src/indent.c index 2cacfbbe3c0..70351f90466 100644 --- a/src/indent.c +++ b/src/indent.c @@ -2077,11 +2077,24 @@ whether or not it is currently displayed in some window. */) && !EQ (Vdisplay_line_numbers, Qvisual)) { struct text_pos wstart; + bool saved_restriction = false; + ptrdiff_t count1 = SPECPDL_INDEX (); SET_TEXT_POS_FROM_MARKER (wstart, w->start); 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); lnum_width = it.lnum_width; + if (saved_restriction) + unbind_to (count1, Qnil); bidi_unshelve_cache (itdata, 0); } SET_TEXT_POS (pt, PT, PT_BYTE); From d5f8a3d03f6c0c98f3280d55a2d88ddb40aa1f3e Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Tue, 4 Jul 2017 18:43:03 +0300 Subject: [PATCH 36/39] Fix display of current line number in visual mode * src/xdisp.c (maybe_produce_line_number): Fix visual-mode display of current line when line-number-current-line face was customized. Reported by Filipe Silva . --- src/xdisp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/xdisp.c b/src/xdisp.c index 47b81414630..312ee10f280 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -20938,7 +20938,10 @@ maybe_produce_line_number (struct it *it) 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 && this_line == it->pt_lnum) + 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; From 25bc3911615d1160d47287c023545c6e0587739f Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Thu, 6 Jul 2017 20:22:16 +0300 Subject: [PATCH 37/39] Implement line numbers that disregard narrowing * src/xdisp.c (display_count_lines_logically): New function, counts line numbers disregarding narrowing. Suggested by Andy Moreton . (maybe_produce_line_number): Call display_count_lines_logically instead of display_count_lines. Adapt BEGV, ZV, etc. to display-line-numbers-widen. (syms_of_xdisp) : New buffer-local variable. * lisp/cus-start.el (standard): Provide a customization form for display-line-numbers-widen. * lisp/frame.el: Add 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. * doc/emacs/display.texi (Display Custom): Document display-line-numbers-widen. --- doc/emacs/display.texi | 8 +++++++ lisp/cus-start.el | 9 +++++++- lisp/frame.el | 3 +++ src/xdisp.c | 49 ++++++++++++++++++++++++++++++++---------- 4 files changed, 57 insertions(+), 12 deletions(-) diff --git a/doc/emacs/display.texi b/doc/emacs/display.texi index 61ca7e24f84..083fcdf97a6 100644 --- a/doc/emacs/display.texi +++ b/doc/emacs/display.texi @@ -1756,6 +1756,14 @@ 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 diff --git a/lisp/cus-start.el b/lisp/cus-start.el index a89d5dff0cd..017e7f9fa55 100644 --- a/lisp/cus-start.el +++ b/lisp/cus-start.el @@ -608,7 +608,14 @@ since it could result in memory overflow and make Emacs crash." :value t) (const :tag "Display zero as number of current line" :value nil)) - "26.1") + "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/frame.el b/lisp/frame.el index 8f51afa2a9a..f3e59edb2f5 100644 --- a/lisp/frame.el +++ b/lisp/frame.el @@ -2435,6 +2435,9 @@ See also `toggle-frame-maximized'." 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/src/xdisp.c b/src/xdisp.c index 312ee10f280..92ce1451867 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -20749,6 +20749,24 @@ 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 @@ -20806,6 +20824,9 @@ maybe_produce_line_number (struct it *it) 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)) @@ -20815,7 +20836,7 @@ maybe_produce_line_number (struct it *it) if (!last_line) { /* FIXME: Maybe reuse the data in it->w->base_line_number. */ - start_from = BEGV; + start_from = beg; if (!it->lnum_bytepos) first_time = true; } @@ -20825,17 +20846,17 @@ maybe_produce_line_number (struct it *it) /* 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 (!(BEGV_BYTE <= start_from && start_from < ZV_BYTE)) + if (!(beg_byte <= start_from && start_from < z_byte)) { last_line = 0; - start_from = BEGV_BYTE; + start_from = beg_byte; } this_line = - last_line + display_count_lines (start_from, - IT_BYTEPOS (*it), IT_CHARPOS (*it), - &bytepos); - eassert (this_line > 0 || (this_line == 0 && start_from == BEGV_BYTE)); + 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)); } @@ -20863,11 +20884,11 @@ maybe_produce_line_number (struct it *it) ptrdiff_t ignored; if (PT_BYTE > it->lnum_bytepos && !EQ (Vdisplay_line_numbers, Qvisual)) it->pt_lnum = - this_line + display_count_lines (it->lnum_bytepos, PT_BYTE, PT, - &ignored); + this_line + display_count_lines_logically (it->lnum_bytepos, PT_BYTE, + PT, &ignored); else - it->pt_lnum = display_count_lines (BEGV_BYTE, PT_BYTE, PT, - &ignored); + it->pt_lnum = display_count_lines_logically (beg_byte, PT_BYTE, PT, + &ignored); } /* Compute the required width if needed. */ if (!it->lnum_width) @@ -32604,6 +32625,12 @@ 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; From 4caf65d4de591089c82ccf542a31ea5009a3c717 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 7 Jul 2017 12:21:10 +0300 Subject: [PATCH 38/39] Fix vertical-motion across the place where line-number width changes * 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. * doc/lispref/display.texi (Size of Displayed Text): Document line-number-display-width. * etc/NEWS: Mention line-number-display-width. * 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/lispref/display.texi | 17 ++++++++ etc/NEWS | 4 ++ lisp/simple.el | 21 ++++++++-- src/indent.c | 84 +++++++++++++++++++++++++++++----------- 4 files changed, 101 insertions(+), 25 deletions(-) diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 4de55fd3fb2..08b2b4671de 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -1980,6 +1980,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 diff --git a/etc/NEWS b/etc/NEWS index b50c770c505..79eb3919e6d 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -420,6 +420,10 @@ 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. diff --git a/lisp/simple.el b/lisp/simple.el index df664fc0503..5d1a6dbfb84 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -5931,6 +5931,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 @@ -6201,6 +6205,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. @@ -6208,9 +6213,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/indent.c b/src/indent.c index 70351f90466..ba936509934 100644 --- a/src/indent.c +++ b/src/indent.c @@ -1947,6 +1947,59 @@ 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); + /* FIXME: The "+ 2" part knows that we add a blank on each side of + the line number when producing glyphs for display. */ + return make_number (width + 2); +} + /* In window W (derived from WINDOW), return x coordinate for column COL (derived from COLUMN). */ static int @@ -2073,30 +2126,10 @@ whether or not it is currently displayed in some window. */) 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)) - { - struct text_pos wstart; - bool saved_restriction = false; - ptrdiff_t count1 = SPECPDL_INDEX (); - SET_TEXT_POS_FROM_MARKER (wstart, w->start); - 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); - lnum_width = it.lnum_width; - if (saved_restriction) - unbind_to (count1, Qnil); - bidi_unshelve_cache (itdata, 0); - } + 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); @@ -2277,6 +2310,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, @@ -2322,6 +2361,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); } From 13786d5e7d0aa0a37d7f81d1a1b82eddd3472796 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 7 Jul 2017 17:30:06 +0300 Subject: [PATCH 39/39] Exclude blank columns from value of line-number-display-width * src/indent.c (Fline_number_display_width): Don't add 2 to the number of columns we return, to make this consistent with display-line-number-width. --- src/indent.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/indent.c b/src/indent.c index ba936509934..4c6dacd2042 100644 --- a/src/indent.c +++ b/src/indent.c @@ -1995,9 +1995,7 @@ line numbers, `line-number'. */) line_number_display_width (XWINDOW (selected_window), &width, &pixel_width); if (!NILP (pixelwise)) return make_number (pixel_width); - /* FIXME: The "+ 2" part knows that we add a blank on each side of - the line number when producing glyphs for display. */ - return make_number (width + 2); + return make_number (width); } /* In window W (derived from WINDOW), return x coordinate for column