From daf78963ee96484df1ecb0c10e7c0040d7b544a5 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 16 Jun 2017 22:44:48 +0300 Subject: 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(-) (limited to 'src') 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; -- cgit v1.2.1 From 7277c0fca7dab9f1b311c3eba5c42fd17acc3593 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 17 Jun 2017 17:42:44 +0300 Subject: 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. --- src/dispextern.h | 3 ++ src/xdisp.c | 126 ++++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 100 insertions(+), 29 deletions(-) (limited to 'src') 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. */); -- cgit v1.2.1 From d4eddb08e505ff9b4d956f00f225e3baf0d15462 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 23 Jun 2017 17:13:01 +0300 Subject: 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 | 298 ++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 158 insertions(+), 140 deletions(-) (limited to 'src') 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); - } + 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) + 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 { - 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; + /* 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 = ' '; + 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 - 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; - } + 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; + /* 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++) + 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) { - 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)++; - } + *p++ = *g; + (*u)++; } + } - /* Update IT->glyph_row's metrics. */ - if (it->glyph_row) - { - struct glyph_row *row = it->glyph_row; + /* 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); - } + 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); + 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); -- cgit v1.2.1 From bbaf2f3d529ac3f8d72b671ee3a8a0c3347c5510 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 23 Jun 2017 18:13:53 +0300 Subject: 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(-) (limited to 'src') 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) -- cgit v1.2.1 From 77f8b86e405cc0ff9c49aea5d98097212755b832 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 11:34:52 +0300 Subject: 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(-) (limited to 'src') 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); -- cgit v1.2.1 From 5b648ac7a2b2e1b77eb59573db59019d5068476c Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 12:37:30 +0300 Subject: 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. --- src/xdisp.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src') 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) - { - /* pre-redisplay-function made changes (e.g. move the region) - that require another round of redisplay. */ + if (w->redisplay || XBUFFER (w->contents)->text->redisplay + || (EQ (Vdisplay_line_numbers, Qrelative) + && row != MATRIX_FIRST_TEXT_ROW (w->desired_matrix))) + { + /* 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; -- cgit v1.2.1 From 9776d7bcf044722909c10c9395d18c81641f27d0 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 13:01:30 +0300 Subject: Don't display line numbers in the minibuffer and in tooltip frames. --- src/xdisp.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'src') 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; -- cgit v1.2.1 From 7d7602cea09692eddb6a8d16f7786b5086a01091 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 13:26:01 +0300 Subject: Fix crashes on TTY frames due to negative lnum_width. --- src/xdisp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') 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); -- cgit v1.2.1 From 55a9298d63121578cd66ef7f14c14b2160aae77d Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 14:29:32 +0300 Subject: 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(+) (limited to 'src') 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 -- cgit v1.2.1 From efedb664666563da6455500ade488fd9726be83a Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 14:53:35 +0300 Subject: 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. --- src/xdisp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') 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. */); -- cgit v1.2.1 From fa5e84cccd31cf94074255180d6ff3a44d4f8f89 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 15:15:02 +0300 Subject: 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(-) (limited to 'src') 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. */ -- cgit v1.2.1 From 71a7294d0a775a8969ec077eb3633da6bdad7c62 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 15:45:23 +0300 Subject: 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. --- src/xdisp.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) (limited to 'src') 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"); -- cgit v1.2.1 From 6e18841b17c9b7ca9f38b923db4195cade05da2e Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 16:58:01 +0300 Subject: 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. --- src/xdisp.c | 52 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 19 deletions(-) (limited to 'src') 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"); -- cgit v1.2.1 From 13cc19a0a3685ceade4a5a560475ee47165f3bbc Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 19:03:39 +0300 Subject: 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(-) (limited to 'src') 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 -- cgit v1.2.1 From 0d5c713a6b21cd3bd8a232ff35924c65cd3cce6b Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 24 Jun 2017 19:40:41 +0300 Subject: 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(-) (limited to 'src') 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; + } } } -- cgit v1.2.1 From 540669cda984f64964d7baeb7369d3eea424a34c Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 25 Jun 2017 19:33:04 +0300 Subject: 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(-) (limited to 'src') 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; -- cgit v1.2.1 From 5d1025e7162db46b3c8d7c19facd8f9b9eff6f49 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 25 Jun 2017 20:53:05 +0300 Subject: 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(-) (limited to 'src') 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; } -- cgit v1.2.1 From 33073d5629ca44f0d5db6fb29d1229da74e0e3c1 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 25 Jun 2017 20:55:58 +0300 Subject: Minor aesthetic fix of last change. --- src/xdisp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') 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 -- cgit v1.2.1 From 67c8a219e670eed317acdffc68a2888e2c557e79 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 26 Jun 2017 19:38:17 +0300 Subject: 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(+) (limited to 'src') 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); } -- cgit v1.2.1 From beb95a8f890da611acc1a4422211deafe512d87d Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 26 Jun 2017 23:20:49 +0300 Subject: 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. --- src/xdisp.c | 116 ++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 82 insertions(+), 34 deletions(-) (limited to 'src') 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. */); -- cgit v1.2.1 From 71e31ac839b05d01486d728d4da9a8daaf1ae240 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Tue, 27 Jun 2017 19:46:50 +0300 Subject: 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(-) (limited to 'src') 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; } -- cgit v1.2.1 From 5b9b49492b9c024bd07b83ef6e5d095af6b8fdd0 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Thu, 29 Jun 2017 21:09:55 +0300 Subject: 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(-) (limited to 'src') 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)) { -- cgit v1.2.1 From dfe1c820d3dca6673aba911a4a37969bbabd0486 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 30 Jun 2017 11:43:49 +0300 Subject: 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(-) (limited to 'src') 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 -- cgit v1.2.1 From a06dd3b9187489b61f08256d9e9a07745302dc4e Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 30 Jun 2017 12:24:13 +0300 Subject: 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(-) (limited to 'src') 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 -- cgit v1.2.1 From 0e4f2e01af1f4c51b958057d86e28c04cdefddb4 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 30 Jun 2017 15:55:51 +0300 Subject: 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(-) (limited to 'src') 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. */ -- cgit v1.2.1 From 7a762fbbfc1c05be8de3d253251f5e7b32da2c73 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 30 Jun 2017 16:37:57 +0300 Subject: 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. --- src/xdisp.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'src') 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; -- cgit v1.2.1 From e83b128a8195e5c63f12832decf70c2953821dc0 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 30 Jun 2017 17:33:06 +0300 Subject: 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. --- src/xdisp.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src') 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); -- cgit v1.2.1 From a9be5a768b6c06e74a386c474aba8125dfc8ed86 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 30 Jun 2017 22:48:36 +0300 Subject: 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(-) (limited to 'src') 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); + + /* 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 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_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)) -- cgit v1.2.1 From fb62728b7afa7024d4ca01e6f89b0267231cf607 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 1 Jul 2017 10:22:45 +0300 Subject: 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(-) (limited to 'src') 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; } -- cgit v1.2.1 From b5ce3100a8549df519d6f2b577fe7c3acf90cb40 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 1 Jul 2017 16:00:18 +0300 Subject: 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(-) (limited to 'src') 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; -- cgit v1.2.1 From 4c9353a5840b285631a86a5bad2b48ea6276abf3 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 2 Jul 2017 18:01:39 +0300 Subject: 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(-) (limited to 'src') 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); -- cgit v1.2.1 From 52bfb7d4d6595302b5261ff810951e0b3281352c Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 3 Jul 2017 18:57:01 +0300 Subject: 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(+) (limited to 'src') 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); -- cgit v1.2.1 From d5f8a3d03f6c0c98f3280d55a2d88ddb40aa1f3e Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Tue, 4 Jul 2017 18:43:03 +0300 Subject: 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(-) (limited to 'src') 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; -- cgit v1.2.1 From 25bc3911615d1160d47287c023545c6e0587739f Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Thu, 6 Jul 2017 20:22:16 +0300 Subject: 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. --- src/xdisp.c | 49 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 11 deletions(-) (limited to 'src') 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; -- cgit v1.2.1 From 4caf65d4de591089c82ccf542a31ea5009a3c717 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 7 Jul 2017 12:21:10 +0300 Subject: 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. --- src/indent.c | 84 ++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 22 deletions(-) (limited to 'src') 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); } -- cgit v1.2.1 From 13786d5e7d0aa0a37d7f81d1a1b82eddd3472796 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 7 Jul 2017 17:30:06 +0300 Subject: 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(-) (limited to 'src') 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 -- cgit v1.2.1