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.
This commit is contained in:
parent
25bc391161
commit
4caf65d4de
4 changed files with 101 additions and 25 deletions
|
@ -1980,6 +1980,23 @@ selected window. The value includes the line spacing of the line
|
|||
(@pxref{Line Height}).
|
||||
@end defun
|
||||
|
||||
When a buffer is displayed with line numbers (@pxref{Display Custom,,,
|
||||
emacs, The GNU Emacs Manual}), it is sometimes useful to know the
|
||||
width taken for displaying the line numbers. The following function
|
||||
is for Lisp programs which need this information for layout
|
||||
calculations.
|
||||
|
||||
@defun line-number-display-width &optional pixelwise
|
||||
This function returns the width used for displaying the line numbers
|
||||
in the selected window. Optional argument @var{pixelwise}, if
|
||||
non-@code{nil}, means return the value in pixels; otherwise the value
|
||||
is returned in column units of the font defined for the
|
||||
@code{line-number} face. If line numbers are not displayed in the
|
||||
selected window, the value is zero. Use @code{with-selected-window}
|
||||
(@pxref{Selecting Windows}) if you need this information about another
|
||||
window.
|
||||
@end defun
|
||||
|
||||
|
||||
@node Line Height
|
||||
@section Line Height
|
||||
|
|
4
etc/NEWS
4
etc/NEWS
|
@ -420,6 +420,10 @@ line by putting the 'display-line-numbers-disable' text property or
|
|||
overlay property on the first character of that screen line. This is
|
||||
intended for add-on packages that need a finer control of the display.
|
||||
|
||||
Lisp programs that need to know how much screen estate is used up for
|
||||
line-number display in a window can use the new function
|
||||
'line-number-display-width'.
|
||||
|
||||
Linum mode and all similar packages are henceforth becoming obsolete.
|
||||
Users and developers are encouraged to switch to this new feature
|
||||
instead.
|
||||
|
|
|
@ -5931,6 +5931,10 @@ columns by which window is scrolled from left margin.
|
|||
When the `track-eol' feature is doing its job, the value is
|
||||
`most-positive-fixnum'.")
|
||||
|
||||
(defvar last--line-number-width 0
|
||||
"Last value of width used for displaying line numbers.
|
||||
Used internally by `line-move-visual'.")
|
||||
|
||||
(defcustom line-move-ignore-invisible t
|
||||
"Non-nil means commands that move by lines ignore invisible newlines.
|
||||
When this option is non-nil, \\[next-line], \\[previous-line], \\[move-end-of-line], and \\[move-beginning-of-line] behave
|
||||
|
@ -6201,6 +6205,7 @@ not vscroll."
|
|||
If NOERROR, don't signal an error if we can't move that many lines."
|
||||
(let ((opoint (point))
|
||||
(hscroll (window-hscroll))
|
||||
(lnum-width (line-number-display-width t))
|
||||
target-hscroll)
|
||||
;; Check if the previous command was a line-motion command, or if
|
||||
;; we were called from some other command.
|
||||
|
@ -6208,9 +6213,19 @@ If NOERROR, don't signal an error if we can't move that many lines."
|
|||
(memq last-command `(next-line previous-line ,this-command)))
|
||||
;; If so, there's no need to reset `temporary-goal-column',
|
||||
;; but we may need to hscroll.
|
||||
(if (or (/= (cdr temporary-goal-column) hscroll)
|
||||
(> (cdr temporary-goal-column) 0))
|
||||
(setq target-hscroll (cdr temporary-goal-column)))
|
||||
(progn
|
||||
(if (or (/= (cdr temporary-goal-column) hscroll)
|
||||
(> (cdr temporary-goal-column) 0))
|
||||
(setq target-hscroll (cdr temporary-goal-column)))
|
||||
;; Update the COLUMN part of temporary-goal-column if the
|
||||
;; line-number display changed its width since the last
|
||||
;; time.
|
||||
(setq temporary-goal-column
|
||||
(cons (+ (car temporary-goal-column)
|
||||
(/ (float (- lnum-width last--line-number-width))
|
||||
(frame-char-width)))
|
||||
(cdr temporary-goal-column)))
|
||||
(setq last--line-number-width lnum-width))
|
||||
;; Otherwise, we should reset `temporary-goal-column'.
|
||||
(let ((posn (posn-at-point))
|
||||
x-pos)
|
||||
|
|
84
src/indent.c
84
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);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue