[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] scratch/line-numbers daf7896 1/2: Initial version of nativ
From: |
Eli Zaretskii |
Subject: |
[Emacs-diffs] scratch/line-numbers daf7896 1/2: Initial version of native display of line numbers |
Date: |
Sat, 17 Jun 2017 10:52:20 -0400 (EDT) |
branch: scratch/line-numbers
commit daf78963ee96484df1ecb0c10e7c0040d7b544a5
Author: Eli Zaretskii <address@hidden>
Commit: Eli Zaretskii <address@hidden>
Initial version of native display of line numbers
* src/xdisp.c (syms_of_xdisp) <display-line-numbers>: New
buffer-local variable.
Include <math.h>.
(maybe_produce_line_number): New function.
(DISP_INFINITY): Rename from INFINITY, since math.h defines INFINITY.
(try_window_reusing_current_matrix): Don't use this method when
display-line-numbers is in effect.
* src/dispextern.h (struct it): New members 'lnum'.
---
src/dispextern.h | 18 +++++-
src/xdisp.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 187 insertions(+), 7 deletions(-)
diff --git a/src/dispextern.h b/src/dispextern.h
index d1e4715..050c68b 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 34ee877..dcef242 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -290,6 +290,7 @@ along with GNU Emacs. If not, see
<http://www.gnu.org/licenses/>. */
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
+#include <math.h>
#include "lisp.h"
#include "atimer.h"
@@ -324,7 +325,7 @@ along with GNU Emacs. If not, see
<http://www.gnu.org/licenses/>. */
#define FRAME_X_OUTPUT(f) ((f)->output_data.x)
#endif
-#define INFINITY 10000000
+#define DISP_INFINITY 10000000
/* Holds the list (error). */
static Lisp_Object list_of_error;
@@ -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;