diff options
| author | Eli Zaretskii | 2017-06-16 22:44:48 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2017-06-16 22:44:48 +0300 |
| commit | daf78963ee96484df1ecb0c10e7c0040d7b544a5 (patch) | |
| tree | 645bebe8802594002507f2d71dbd25ccded9cc24 /src | |
| parent | 7a2038d7c887e4fa08a91950a7494d1dd20c39e1 (diff) | |
| download | emacs-daf78963ee96484df1ecb0c10e7c0040d7b544a5.tar.gz emacs-daf78963ee96484df1ecb0c10e7c0040d7b544a5.zip | |
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'.
Diffstat (limited to 'src')
| -rw-r--r-- | src/dispextern.h | 18 | ||||
| -rw-r--r-- | src/xdisp.c | 176 |
2 files changed, 187 insertions, 7 deletions
diff --git a/src/dispextern.h b/src/dispextern.h index d1e4715c329..050c68b8e08 100644 --- a/src/dispextern.h +++ b/src/dispextern.h | |||
| @@ -384,6 +384,7 @@ struct glyph | |||
| 384 | glyph standing for newline at end of line 0 | 384 | glyph standing for newline at end of line 0 |
| 385 | empty space after the end of the line -1 | 385 | empty space after the end of the line -1 |
| 386 | overlay arrow on a TTY -1 | 386 | overlay arrow on a TTY -1 |
| 387 | glyph displaying line number -1 | ||
| 387 | glyph at EOB that ends in a newline -1 | 388 | glyph at EOB that ends in a newline -1 |
| 388 | left truncation glyphs: -1 | 389 | left truncation glyphs: -1 |
| 389 | right truncation/continuation glyphs next buffer position | 390 | right truncation/continuation glyphs next buffer position |
| @@ -2571,7 +2572,12 @@ struct it | |||
| 2571 | Do NOT use !BUFFERP (it.object) as a test whether we are | 2572 | Do NOT use !BUFFERP (it.object) as a test whether we are |
| 2572 | iterating over a string; use STRINGP (it.string) instead. | 2573 | iterating over a string; use STRINGP (it.string) instead. |
| 2573 | 2574 | ||
| 2574 | Position is the current iterator position in object. */ | 2575 | Position is the current iterator position in object. |
| 2576 | |||
| 2577 | The 'position's CHARPOS is copied to glyph->charpos of the glyph | ||
| 2578 | produced by PRODUCE_GLYPHS, so any artificial value documented | ||
| 2579 | under 'struct glyph's 'charpos' member can also be found in the | ||
| 2580 | 'position' member here. */ | ||
| 2575 | Lisp_Object object; | 2581 | Lisp_Object object; |
| 2576 | struct text_pos position; | 2582 | struct text_pos position; |
| 2577 | 2583 | ||
| @@ -2655,6 +2661,16 @@ struct it | |||
| 2655 | coordinate is past first_visible_x. */ | 2661 | coordinate is past first_visible_x. */ |
| 2656 | int hpos; | 2662 | int hpos; |
| 2657 | 2663 | ||
| 2664 | /* Current line number, zero-based. */ | ||
| 2665 | ptrdiff_t lnum; | ||
| 2666 | |||
| 2667 | /* The byte position corresponding to lnum. */ | ||
| 2668 | ptrdiff_t lnum_bytepos; | ||
| 2669 | |||
| 2670 | /* The width in columns needed for display of the line numbers, or | ||
| 2671 | zero if not computed. */ | ||
| 2672 | int lnum_width; | ||
| 2673 | |||
| 2658 | /* Left fringe bitmap number (enum fringe_bitmap_type). */ | 2674 | /* Left fringe bitmap number (enum fringe_bitmap_type). */ |
| 2659 | unsigned left_user_fringe_bitmap : FRINGE_ID_BITS; | 2675 | unsigned left_user_fringe_bitmap : FRINGE_ID_BITS; |
| 2660 | 2676 | ||
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 <http://www.gnu.org/licenses/>. */ | |||
| 290 | #include <stdio.h> | 290 | #include <stdio.h> |
| 291 | #include <stdlib.h> | 291 | #include <stdlib.h> |
| 292 | #include <limits.h> | 292 | #include <limits.h> |
| 293 | #include <math.h> | ||
| 293 | 294 | ||
| 294 | #include "lisp.h" | 295 | #include "lisp.h" |
| 295 | #include "atimer.h" | 296 | #include "atimer.h" |
| @@ -324,7 +325,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 324 | #define FRAME_X_OUTPUT(f) ((f)->output_data.x) | 325 | #define FRAME_X_OUTPUT(f) ((f)->output_data.x) |
| 325 | #endif | 326 | #endif |
| 326 | 327 | ||
| 327 | #define INFINITY 10000000 | 328 | #define DISP_INFINITY 10000000 |
| 328 | 329 | ||
| 329 | /* Holds the list (error). */ | 330 | /* Holds the list (error). */ |
| 330 | static Lisp_Object list_of_error; | 331 | static Lisp_Object list_of_error; |
| @@ -843,6 +844,8 @@ static const char *decode_mode_spec (struct window *, int, int, Lisp_Object *); | |||
| 843 | static void display_menu_bar (struct window *); | 844 | static void display_menu_bar (struct window *); |
| 844 | static ptrdiff_t display_count_lines (ptrdiff_t, ptrdiff_t, ptrdiff_t, | 845 | static ptrdiff_t display_count_lines (ptrdiff_t, ptrdiff_t, ptrdiff_t, |
| 845 | ptrdiff_t *); | 846 | ptrdiff_t *); |
| 847 | static void pint2str (register char *, register int, register ptrdiff_t); | ||
| 848 | |||
| 846 | static int display_string (const char *, Lisp_Object, Lisp_Object, | 849 | static int display_string (const char *, Lisp_Object, Lisp_Object, |
| 847 | ptrdiff_t, ptrdiff_t, struct it *, int, int, int, int); | 850 | ptrdiff_t, ptrdiff_t, struct it *, int, int, int, int); |
| 848 | static void compute_line_metrics (struct it *); | 851 | static void compute_line_metrics (struct it *); |
| @@ -6751,7 +6754,7 @@ reseat_to_string (struct it *it, const char *s, Lisp_Object string, | |||
| 6751 | FIELD_WIDTH < 0 means infinite field width. This is useful for | 6754 | FIELD_WIDTH < 0 means infinite field width. This is useful for |
| 6752 | padding with `-' at the end of a mode line. */ | 6755 | padding with `-' at the end of a mode line. */ |
| 6753 | if (field_width < 0) | 6756 | if (field_width < 0) |
| 6754 | field_width = INFINITY; | 6757 | field_width = DISP_INFINITY; |
| 6755 | /* Implementation note: We deliberately don't enlarge | 6758 | /* Implementation note: We deliberately don't enlarge |
| 6756 | it->bidi_it.string.schars here to fit it->end_charpos, because | 6759 | it->bidi_it.string.schars here to fit it->end_charpos, because |
| 6757 | the bidi iterator cannot produce characters out of thin air. */ | 6760 | the bidi iterator cannot produce characters out of thin air. */ |
| @@ -13138,7 +13141,7 @@ hscroll_window_tree (Lisp_Object window) | |||
| 13138 | if (hscl) | 13141 | if (hscl) |
| 13139 | it.first_visible_x = window_hscroll_limited (w, it.f) | 13142 | it.first_visible_x = window_hscroll_limited (w, it.f) |
| 13140 | * FRAME_COLUMN_WIDTH (it.f); | 13143 | * FRAME_COLUMN_WIDTH (it.f); |
| 13141 | it.last_visible_x = INFINITY; | 13144 | it.last_visible_x = DISP_INFINITY; |
| 13142 | move_it_in_display_line_to (&it, pt, -1, MOVE_TO_POS); | 13145 | move_it_in_display_line_to (&it, pt, -1, MOVE_TO_POS); |
| 13143 | /* If the line ends in an overlay string with a newline, | 13146 | /* If the line ends in an overlay string with a newline, |
| 13144 | we might infloop, because displaying the window will | 13147 | we might infloop, because displaying the window will |
| @@ -15823,7 +15826,7 @@ compute_window_start_on_continuation_line (struct window *w) | |||
| 15823 | So, we're looking for the display line start with the | 15826 | So, we're looking for the display line start with the |
| 15824 | minimum distance from the old window start. */ | 15827 | minimum distance from the old window start. */ |
| 15825 | pos_before_pt = pos = it.current.pos; | 15828 | pos_before_pt = pos = it.current.pos; |
| 15826 | min_distance = INFINITY; | 15829 | min_distance = DISP_INFINITY; |
| 15827 | while ((distance = eabs (CHARPOS (start_pos) - IT_CHARPOS (it))), | 15830 | while ((distance = eabs (CHARPOS (start_pos) - IT_CHARPOS (it))), |
| 15828 | distance < min_distance) | 15831 | distance < min_distance) |
| 15829 | { | 15832 | { |
| @@ -17593,6 +17596,12 @@ try_window_reusing_current_matrix (struct window *w) | |||
| 17593 | if (w->vscroll || MATRIX_ROW_PARTIALLY_VISIBLE_P (w, start_row)) | 17596 | if (w->vscroll || MATRIX_ROW_PARTIALLY_VISIBLE_P (w, start_row)) |
| 17594 | return false; | 17597 | return false; |
| 17595 | 17598 | ||
| 17599 | /* Give up if line numbers are being displayed, because reusing the | ||
| 17600 | current matrix might use the wrong width for line-number | ||
| 17601 | display. */ | ||
| 17602 | if (!NILP (Vdisplay_line_numbers)) | ||
| 17603 | return false; | ||
| 17604 | |||
| 17596 | /* The variable new_start now holds the new window start. The old | 17605 | /* The variable new_start now holds the new window start. The old |
| 17597 | start `start' can be determined from the current matrix. */ | 17606 | start `start' can be determined from the current matrix. */ |
| 17598 | SET_TEXT_POS_FROM_MARKER (new_start, w->start); | 17607 | SET_TEXT_POS_FROM_MARKER (new_start, w->start); |
| @@ -20670,6 +20679,141 @@ find_row_edges (struct it *it, struct glyph_row *row, | |||
| 20670 | row->maxpos = it->current.pos; | 20679 | row->maxpos = it->current.pos; |
| 20671 | } | 20680 | } |
| 20672 | 20681 | ||
| 20682 | static void | ||
| 20683 | maybe_produce_line_number (struct it *it) | ||
| 20684 | { | ||
| 20685 | ptrdiff_t last_line = it->lnum; | ||
| 20686 | ptrdiff_t start_from, bytepos; | ||
| 20687 | |||
| 20688 | /* FIXME: Maybe reuse the data in it->w->base_line_number. */ | ||
| 20689 | if (!last_line) | ||
| 20690 | start_from = BEGV; | ||
| 20691 | else | ||
| 20692 | start_from = it->lnum_bytepos; | ||
| 20693 | |||
| 20694 | /* Paranoia: what if someone changes the narrowing since the last | ||
| 20695 | time display_line was called? Shouldn't really happen, but who | ||
| 20696 | knows what some crazy Lisp invoked by :eval could do? */ | ||
| 20697 | if (!(BEGV_BYTE <= start_from && start_from < ZV_BYTE)) | ||
| 20698 | { | ||
| 20699 | last_line = 0; | ||
| 20700 | start_from = BEGV_BYTE; | ||
| 20701 | } | ||
| 20702 | |||
| 20703 | ptrdiff_t this_line; | ||
| 20704 | |||
| 20705 | this_line = | ||
| 20706 | last_line + display_count_lines (start_from, | ||
| 20707 | IT_BYTEPOS (*it), IT_CHARPOS (*it), | ||
| 20708 | &bytepos); | ||
| 20709 | eassert (this_line > 0 || (this_line == 0 && start_from == BEGV_BYTE)); | ||
| 20710 | eassert (bytepos == IT_BYTEPOS (*it)); | ||
| 20711 | |||
| 20712 | /* If this is a new logical line, produce the glyphs for the line | ||
| 20713 | number. */ | ||
| 20714 | if (this_line != last_line || !last_line || it->continuation_lines_width > 0) | ||
| 20715 | { | ||
| 20716 | if (this_line != last_line || !last_line) | ||
| 20717 | { | ||
| 20718 | it->lnum = this_line; | ||
| 20719 | it->lnum_bytepos = IT_BYTEPOS (*it); | ||
| 20720 | } | ||
| 20721 | |||
| 20722 | void *itdata = bidi_shelve_cache (); | ||
| 20723 | struct it tem_it; | ||
| 20724 | char lnum_buf[INT_STRLEN_BOUND (ptrdiff_t) + 1]; | ||
| 20725 | bool beyond_zv = IT_BYTEPOS (*it) >= ZV_BYTE ? true : false; | ||
| 20726 | /* Compute the required width if needed. */ | ||
| 20727 | if (!it->lnum_width) | ||
| 20728 | { | ||
| 20729 | /* Max line number to be displayed cannot be more than the | ||
| 20730 | one corresponding to the last row of the desired | ||
| 20731 | matrix. */ | ||
| 20732 | ptrdiff_t max_lnum = | ||
| 20733 | this_line + it->w->desired_matrix->nrows - 1 - it->vpos; | ||
| 20734 | it->lnum_width = log10 (max_lnum) + 1; | ||
| 20735 | eassert (it->lnum_width > 0); | ||
| 20736 | } | ||
| 20737 | pint2str (lnum_buf, it->lnum_width, this_line + 1); | ||
| 20738 | /* Append a blank. */ | ||
| 20739 | strcat (lnum_buf, " "); | ||
| 20740 | |||
| 20741 | /* Setup for producing the glyphs. */ | ||
| 20742 | init_iterator (&tem_it, it->w, -1, -1, &scratch_glyph_row, | ||
| 20743 | /* FIXME: Use specialized face. */ | ||
| 20744 | DEFAULT_FACE_ID); | ||
| 20745 | scratch_glyph_row.reversed_p = false; | ||
| 20746 | scratch_glyph_row.used[TEXT_AREA] = 0; | ||
| 20747 | SET_TEXT_POS (tem_it.position, 0, 0); | ||
| 20748 | tem_it.bidi_it.type = WEAK_EN; | ||
| 20749 | /* According to UAX#9, EN goes up 2 levels in L2R paragraph and | ||
| 20750 | 1 level in R2L paragraphs. Emulate that. */ | ||
| 20751 | tem_it.bidi_it.resolved_level = 2; | ||
| 20752 | if (it->glyph_row && it->glyph_row->reversed_p) | ||
| 20753 | tem_it.bidi_it.resolved_level = 1; | ||
| 20754 | |||
| 20755 | /* Produce glyphs for the line number in a scratch glyph_row. */ | ||
| 20756 | int n_glyphs_before; | ||
| 20757 | for (const char *p = lnum_buf; *p; p++) | ||
| 20758 | { | ||
| 20759 | /* For continuation lines and lines after ZV, instead of a | ||
| 20760 | line number, produce a blank prefix of the same width. */ | ||
| 20761 | if (beyond_zv || it->continuation_lines_width > 0) | ||
| 20762 | tem_it.c = tem_it.char_to_display = ' '; | ||
| 20763 | else | ||
| 20764 | tem_it.c = tem_it.char_to_display = *p; | ||
| 20765 | tem_it.len = 1; | ||
| 20766 | n_glyphs_before = scratch_glyph_row.used[TEXT_AREA]; | ||
| 20767 | /* Make sure these glyphs will have a "position" of -1. */ | ||
| 20768 | SET_TEXT_POS (tem_it.position, -1, -1); | ||
| 20769 | PRODUCE_GLYPHS (&tem_it); | ||
| 20770 | |||
| 20771 | /* Stop producing glyphs if we don't have enough space on | ||
| 20772 | this line. FIXME: should we refrain from producing the | ||
| 20773 | line number at all in that case? */ | ||
| 20774 | if (tem_it.current_x > tem_it.last_visible_x) | ||
| 20775 | { | ||
| 20776 | scratch_glyph_row.used[TEXT_AREA] = n_glyphs_before; | ||
| 20777 | break; | ||
| 20778 | } | ||
| 20779 | } | ||
| 20780 | |||
| 20781 | /* Copy the produced glyphs into IT's glyph_row. */ | ||
| 20782 | struct glyph *g = scratch_glyph_row.glyphs[TEXT_AREA]; | ||
| 20783 | struct glyph *e = g + scratch_glyph_row.used[TEXT_AREA]; | ||
| 20784 | struct glyph *p = it->glyph_row ? it->glyph_row->glyphs[TEXT_AREA] : NULL; | ||
| 20785 | short *u = it->glyph_row ? &it->glyph_row->used[TEXT_AREA] : NULL; | ||
| 20786 | |||
| 20787 | while (g < e) | ||
| 20788 | { | ||
| 20789 | it->current_x += g->pixel_width; | ||
| 20790 | it->hpos++; | ||
| 20791 | if (p) | ||
| 20792 | { | ||
| 20793 | *p++ = *g++; | ||
| 20794 | (*u)++; | ||
| 20795 | } | ||
| 20796 | } | ||
| 20797 | |||
| 20798 | /* Update IT->glyph_row's metrics. */ | ||
| 20799 | if (it->glyph_row) | ||
| 20800 | { | ||
| 20801 | struct glyph_row *row = it->glyph_row; | ||
| 20802 | |||
| 20803 | row->ascent = max (row->ascent, tem_it.max_ascent); | ||
| 20804 | row->height = max (row->height, | ||
| 20805 | tem_it.max_ascent + tem_it.max_descent); | ||
| 20806 | row->phys_ascent = max (row->phys_ascent, tem_it.max_phys_ascent); | ||
| 20807 | row->phys_height = max (row->phys_height, | ||
| 20808 | tem_it.max_phys_ascent + tem_it.max_phys_descent); | ||
| 20809 | row->extra_line_spacing = max (row->extra_line_spacing, | ||
| 20810 | tem_it.max_extra_line_spacing); | ||
| 20811 | } | ||
| 20812 | |||
| 20813 | bidi_unshelve_cache (itdata, false); | ||
| 20814 | } | ||
| 20815 | } | ||
| 20816 | |||
| 20673 | /* Construct the glyph row IT->glyph_row in the desired matrix of | 20817 | /* Construct the glyph row IT->glyph_row in the desired matrix of |
| 20674 | IT->w from text at the current position of IT. See dispextern.h | 20818 | IT->w from text at the current position of IT. See dispextern.h |
| 20675 | for an overview of struct it. Value is true if | 20819 | for an overview of struct it. Value is true if |
| @@ -20775,9 +20919,17 @@ display_line (struct it *it, int cursor_vpos) | |||
| 20775 | are hscrolled to the left of the left edge of the window. */ | 20919 | are hscrolled to the left of the left edge of the window. */ |
| 20776 | min_pos = CHARPOS (this_line_min_pos); | 20920 | min_pos = CHARPOS (this_line_min_pos); |
| 20777 | min_bpos = BYTEPOS (this_line_min_pos); | 20921 | min_bpos = BYTEPOS (this_line_min_pos); |
| 20922 | |||
| 20923 | /* Produce line number, if needed. */ | ||
| 20924 | if (!NILP (Vdisplay_line_numbers)) | ||
| 20925 | maybe_produce_line_number (it); | ||
| 20778 | } | 20926 | } |
| 20779 | else if (it->area == TEXT_AREA) | 20927 | else if (it->area == TEXT_AREA) |
| 20780 | { | 20928 | { |
| 20929 | /* Line numbers should precede the line-prefix or wrap-prefix. */ | ||
| 20930 | if (!NILP (Vdisplay_line_numbers)) | ||
| 20931 | maybe_produce_line_number (it); | ||
| 20932 | |||
| 20781 | /* We only do this when not calling move_it_in_display_line_to | 20933 | /* We only do this when not calling move_it_in_display_line_to |
| 20782 | above, because that function calls itself handle_line_prefix. */ | 20934 | above, because that function calls itself handle_line_prefix. */ |
| 20783 | handle_line_prefix (it); | 20935 | handle_line_prefix (it); |
| @@ -20936,6 +21088,10 @@ display_line (struct it *it, int cursor_vpos) | |||
| 20936 | process the prefix now. */ | 21088 | process the prefix now. */ |
| 20937 | if (it->area == TEXT_AREA && pending_handle_line_prefix) | 21089 | if (it->area == TEXT_AREA && pending_handle_line_prefix) |
| 20938 | { | 21090 | { |
| 21091 | /* Line numbers should precede the line-prefix or wrap-prefix. */ | ||
| 21092 | if (!NILP (Vdisplay_line_numbers)) | ||
| 21093 | maybe_produce_line_number (it); | ||
| 21094 | |||
| 20939 | pending_handle_line_prefix = false; | 21095 | pending_handle_line_prefix = false; |
| 20940 | handle_line_prefix (it); | 21096 | handle_line_prefix (it); |
| 20941 | } | 21097 | } |
| @@ -22007,7 +22163,7 @@ Value is the new character position of point. */) | |||
| 22007 | reach point, in order to start from its X coordinate. So we | 22163 | reach point, in order to start from its X coordinate. So we |
| 22008 | need to disregard the window's horizontal extent in that case. */ | 22164 | need to disregard the window's horizontal extent in that case. */ |
| 22009 | if (it.line_wrap == TRUNCATE) | 22165 | if (it.line_wrap == TRUNCATE) |
| 22010 | it.last_visible_x = INFINITY; | 22166 | it.last_visible_x = DISP_INFINITY; |
| 22011 | 22167 | ||
| 22012 | if (it.cmp_it.id < 0 | 22168 | if (it.cmp_it.id < 0 |
| 22013 | && it.method == GET_FROM_STRING | 22169 | && it.method == GET_FROM_STRING |
| @@ -22100,7 +22256,7 @@ Value is the new character position of point. */) | |||
| 22100 | { | 22256 | { |
| 22101 | start_display (&it, w, pt); | 22257 | start_display (&it, w, pt); |
| 22102 | if (it.line_wrap == TRUNCATE) | 22258 | if (it.line_wrap == TRUNCATE) |
| 22103 | it.last_visible_x = INFINITY; | 22259 | it.last_visible_x = DISP_INFINITY; |
| 22104 | reseat_at_previous_visible_line_start (&it); | 22260 | reseat_at_previous_visible_line_start (&it); |
| 22105 | it.current_x = it.current_y = it.hpos = 0; | 22261 | it.current_x = it.current_y = it.hpos = 0; |
| 22106 | if (pt_vpos != 0) | 22262 | if (pt_vpos != 0) |
| @@ -32134,6 +32290,14 @@ To add a prefix to continuation lines, use `wrap-prefix'. */); | |||
| 32134 | DEFSYM (Qline_prefix, "line-prefix"); | 32290 | DEFSYM (Qline_prefix, "line-prefix"); |
| 32135 | Fmake_variable_buffer_local (Qline_prefix); | 32291 | Fmake_variable_buffer_local (Qline_prefix); |
| 32136 | 32292 | ||
| 32293 | DEFVAR_LISP ("display-line-numbers", Vdisplay_line_numbers, | ||
| 32294 | doc: /* Non-nil means display line numbers. | ||
| 32295 | Line numbers are displayed before each non-continuation line, i.e. | ||
| 32296 | after each newline that comes from buffer text. */); | ||
| 32297 | Vdisplay_line_numbers = Qnil; | ||
| 32298 | DEFSYM (Qdisplay_line_numbers, "display-line-numbers"); | ||
| 32299 | Fmake_variable_buffer_local (Qdisplay_line_numbers); | ||
| 32300 | |||
| 32137 | DEFVAR_BOOL ("inhibit-eval-during-redisplay", inhibit_eval_during_redisplay, | 32301 | DEFVAR_BOOL ("inhibit-eval-during-redisplay", inhibit_eval_during_redisplay, |
| 32138 | doc: /* Non-nil means don't eval Lisp during redisplay. */); | 32302 | doc: /* Non-nil means don't eval Lisp during redisplay. */); |
| 32139 | inhibit_eval_during_redisplay = false; | 32303 | inhibit_eval_during_redisplay = false; |