From 403cb178c75a80603dbd8ed23e342d2109645401 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 9 Feb 2015 18:24:46 +0200 Subject: [PATCH] Speed up vertical-motion when screen coordinates are known src/indent.c (Fvertical_motion): Accept an additional argument CUR-COL and use it as the starting screen coordinate. src/window.c (window_scroll_line_based, Fmove_to_window_line): All callers of vertical-motion changed. doc/lispref/positions.texi (Screen Lines): Update the documentation of vertical-motion to document the new additional argument. --- doc/lispref/ChangeLog | 5 ++++ doc/lispref/positions.texi | 10 ++++++- src/ChangeLog | 7 +++++ src/indent.c | 55 +++++++++++++++++++++++++++++--------- src/window.c | 21 ++++++++------- 5 files changed, 74 insertions(+), 24 deletions(-) diff --git a/doc/lispref/ChangeLog b/doc/lispref/ChangeLog index 3fe3d6fd6a0..0c76a6b8b34 100644 --- a/doc/lispref/ChangeLog +++ b/doc/lispref/ChangeLog @@ -1,3 +1,8 @@ +2015-02-09 Eli Zaretskii + + * positions.texi (Screen Lines): Update the documentation of + vertical-motion to document the new additional argument. + 2015-02-06 Nicolas Petton * sequences.texi (Sequence Functions): Add documentation for diff --git a/doc/lispref/positions.texi b/doc/lispref/positions.texi index 317b9d64a5c..b74116ebf1d 100644 --- a/doc/lispref/positions.texi +++ b/doc/lispref/positions.texi @@ -493,7 +493,7 @@ If you intend to use them heavily, Emacs provides caches which may improve the performance of your code. @xref{Truncation, cache-long-scans}. @end ignore -@defun vertical-motion count &optional window +@defun vertical-motion count &optional window cur-col This function moves point to the start of the screen line @var{count} screen lines down from the screen line containing point. If @var{count} is negative, it moves up instead. @@ -515,6 +515,14 @@ The window @var{window} is used for obtaining parameters such as the width, the horizontal scrolling, and the display table. But @code{vertical-motion} always operates on the current buffer, even if @var{window} currently displays some other buffer. + +The optional argument @var{cur-col} specifies the current column when +the function is called. This is the window-relative horizontal +coordinate of point, measured in units of font width of the frame's +default face. Providing it speeds up the function, especially in very +long lines, because it doesn't have to go back in the buffer in order +to determine the current column. Note that @var{cur-col} is also +counted from the visual start of the line. @end defun @defun count-screen-lines &optional beg end count-final-newline window diff --git a/src/ChangeLog b/src/ChangeLog index 2a702a29a7d..4afcdcf0711 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,10 @@ +2015-02-09 Eli Zaretskii + + * indent.c (Fvertical_motion): Accept an additional argument + CUR-COL and use it as the starting screen coordinate. + * window.c (window_scroll_line_based, Fmove_to_window_line): All + callers of vertical-motion changed. + 2015-02-09 Dima Kogan * font.c (font_score): Remove unused variable assignment. diff --git a/src/indent.c b/src/indent.c index 8660400e1ce..f0aea002fd2 100644 --- a/src/indent.c +++ b/src/indent.c @@ -1928,7 +1928,7 @@ vmotion (register ptrdiff_t from, register ptrdiff_t from_byte, -1, hscroll, 0, w); } -DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 2, 0, +DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 3, 0, doc: /* Move point to start of the screen line LINES lines down. If LINES is negative, this means moving up. @@ -1951,12 +1951,18 @@ is). If the line is scrolled horizontally, COLS is interpreted visually, i.e., as addition to the columns of text beyond the left edge of the window. +The optional third argument CUR-COL specifies the horizontal +window-relative coordinate of point, in units of frame's canonical +character width, where the function is invoked. If this argument is +omitted or nil, the function will determine the point coordinate by +going back to the beginning of the line. + `vertical-motion' always uses the current buffer, regardless of which buffer is displayed in WINDOW. This is consistent with other cursor motion functions and makes it possible to use `vertical-motion' in any buffer, whether or not it is currently displayed in some window. */) - (Lisp_Object lines, Lisp_Object window) + (Lisp_Object lines, Lisp_Object window, Lisp_Object cur_col) { struct it it; struct text_pos pt; @@ -2006,6 +2012,22 @@ whether or not it is currently displayed in some window. */) bool disp_string_at_start_p = 0; ptrdiff_t nlines = XINT (lines); int vpos_init = 0; + double start_col; + int start_x; + bool start_x_given = false; + int to_x = -1; + + if (!NILP (cur_col)) + { + CHECK_NUMBER_OR_FLOAT (cur_col); + start_col = + INTEGERP (cur_col) + ? (double) XINT (cur_col) + : XFLOAT_DATA (cur_col); + start_x = + (int)(start_col * FRAME_COLUMN_WIDTH (XFRAME (w->frame)) + 0.5); + start_x_given = true; + } itdata = bidi_shelve_cache (); SET_TEXT_POS (pt, PT, PT_BYTE); @@ -2042,11 +2064,19 @@ whether or not it is currently displayed in some window. */) it_overshoot_count = !(it.method == GET_FROM_IMAGE || it.method == GET_FROM_STRETCH); - /* Scan from the start of the line containing PT. If we don't - do this, we start moving with IT->current_x == 0, while PT is - really at some x > 0. */ - reseat_at_previous_visible_line_start (&it); - it.current_x = it.hpos = 0; + if (start_x_given) + { + it.hpos = (int) start_col; + it.current_x = start_x; + } + else + { + /* Scan from the start of the line containing PT. If we don't + do this, we start moving with IT->current_x == 0, while PT is + really at some x > 0. */ + reseat_at_previous_visible_line_start (&it); + it.current_x = it.hpos = 0; + } if (IT_CHARPOS (it) != PT) /* We used to temporarily disable selective display here; the comment said this is "so we don't move too far" (2005-01-19 @@ -2108,12 +2138,15 @@ whether or not it is currently displayed in some window. */) return the correct value to the caller. */ vpos_init = -1; } + if (!NILP (lcols)) + to_x = (int)(cols * FRAME_COLUMN_WIDTH (XFRAME (w->frame)) + 0.5); if (nlines <= 0) { it.vpos = vpos_init; /* Do this even if LINES is 0, so that we move back to the beginning of the current line as we ought. */ - if (nlines == 0 || IT_CHARPOS (it) > 0) + if ((nlines < 0 && IT_CHARPOS (it) > 0) + || (nlines == 0 && !(start_x_given && start_x <= to_x))) move_it_by_lines (&it, max (PTRDIFF_MIN, nlines)); } else if (overshoot_handled) @@ -2153,11 +2186,7 @@ whether or not it is currently displayed in some window. */) was originally hscrolled, the goal column is interpreted as an addition to the hscroll amount. */ if (!NILP (lcols)) - { - int to_x = (int)(cols * FRAME_COLUMN_WIDTH (XFRAME (w->frame)) + 0.5); - - move_it_in_display_line (&it, ZV, first_x + to_x, MOVE_TO_X); - } + move_it_in_display_line (&it, ZV, first_x + to_x, MOVE_TO_X); SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it)); bidi_unshelve_cache (itdata, 0); diff --git a/src/window.c b/src/window.c index 293140041a9..d59616d0545 100644 --- a/src/window.c +++ b/src/window.c @@ -5350,14 +5350,14 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, int noerror) if (NILP (tem)) { - Fvertical_motion (make_number (- (ht / 2)), window); + Fvertical_motion (make_number (- (ht / 2)), window, Qnil); startpos = PT; startbyte = PT_BYTE; } SET_PT_BOTH (startpos, startbyte); lose = n < 0 && PT == BEGV; - Fvertical_motion (make_number (n), window); + Fvertical_motion (make_number (n), window, Qnil); pos = PT; pos_byte = PT_BYTE; bolp = Fbolp (); @@ -5389,7 +5389,7 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, int noerror) && (whole || !EQ (Vscroll_preserve_screen_position, Qt))) { SET_PT_BOTH (pos, pos_byte); - Fvertical_motion (original_pos, window); + Fvertical_motion (original_pos, window, Qnil); } /* If we scrolled forward, put point enough lines down that it is outside the scroll margin. */ @@ -5400,7 +5400,7 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, int noerror) if (this_scroll_margin > 0) { SET_PT_BOTH (pos, pos_byte); - Fvertical_motion (make_number (this_scroll_margin), window); + Fvertical_motion (make_number (this_scroll_margin), window, Qnil); top_margin = PT; } else @@ -5412,7 +5412,7 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, int noerror) else if (!NILP (Vscroll_preserve_screen_position)) { SET_PT_BOTH (pos, pos_byte); - Fvertical_motion (original_pos, window); + Fvertical_motion (original_pos, window, Qnil); } else SET_PT (top_margin); @@ -5424,7 +5424,8 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, int noerror) /* If we scrolled backward, put point near the end of the window but not within the scroll margin. */ SET_PT_BOTH (pos, pos_byte); - tem = Fvertical_motion (make_number (ht - this_scroll_margin), window); + tem = Fvertical_motion (make_number (ht - this_scroll_margin), window, + Qnil); if (XFASTINT (tem) == ht - this_scroll_margin) bottom_margin = PT; else @@ -5438,10 +5439,10 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, int noerror) if (!NILP (Vscroll_preserve_screen_position)) { SET_PT_BOTH (pos, pos_byte); - Fvertical_motion (original_pos, window); + Fvertical_motion (original_pos, window, Qnil); } else - Fvertical_motion (make_number (-1), window); + Fvertical_motion (make_number (-1), window, Qnil); } } } @@ -5999,7 +6000,7 @@ zero means top of window, negative means relative to bottom of window. */) if (start < BEGV || start > ZV) { int height = window_internal_height (w); - Fvertical_motion (make_number (- (height / 2)), window); + Fvertical_motion (make_number (- (height / 2)), window, Qnil); set_marker_both (w->start, w->contents, PT, PT_BYTE); w->start_at_line_beg = !NILP (Fbolp ()); w->force_start = 1; @@ -6040,7 +6041,7 @@ zero means top of window, negative means relative to bottom of window. */) if (w->vscroll) XSETINT (arg, XINT (arg) + 1); - return Fvertical_motion (arg, window); + return Fvertical_motion (arg, window, Qnil); } -- 2.39.2