From 8bd48212020ee206b782477ac32b918861bcaf08 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 30 Sep 2018 14:14:59 +0300 Subject: [PATCH] Allow 'make-cursor-line-fully-visible' name a function * src/xdisp.c (cursor_row_fully_visible_p): Handle the case of make-cursor-line-fully-visible being a function. Accept a 3rd argument; if non-zero, assume the caller already tested the conditions for the cursor being fully-visible, and don't recheck them. All callers changed. (try_cursor_movement, try_window_id): Call cursor_row_fully_visible_p instead of testing the value of make-cursor-line-fully-visible directly. (syms_of_xdisp) : Update the doc string. Define a symbol Qmake_cursor_line_fully_visible. (Bug#32848) * lisp/cus-start.el (standard): Update the Custom form. * etc/NEWS: Mention the change in possible values of 'make-cursor-line-fully-visible'. --- etc/NEWS | 6 +++++ lisp/cus-start.el | 7 ++++- src/xdisp.c | 69 +++++++++++++++++++++++++++++++++++------------ 3 files changed, 64 insertions(+), 18 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 7e7de165ec1..155394ef68f 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -220,6 +220,12 @@ This triggers to search the program on the remote host as indicated by When set to t, no message will be shown when auto-saving (default value: nil). +--- +** The value of 'make-cursor-line-fully-visible' can now be a function. +In addition to nil or non-nil, the value can now be a predicate +function. Follow mode uses this to control scrolling of its windows +when the last screen line in a window is not fully visible. + * Editing Changes in Emacs 27.1 diff --git a/lisp/cus-start.el b/lisp/cus-start.el index 88a61753f25..e33fe6e5ecf 100644 --- a/lisp/cus-start.el +++ b/lisp/cus-start.el @@ -547,7 +547,12 @@ since it could result in memory overflow and make Emacs crash." (const :tag "Respect `truncate-lines'" nil) (other :tag "Truncate if not full-width" t)) "23.1") - (make-cursor-line-fully-visible windows boolean) + (make-cursor-line-fully-visible + windows + (choice + (const :tag "Make cursor always fully visible" t) + (const :tag "Allow cursor to be partially-visible" nil) + (function :tag "User-defined function"))) (mode-line-in-non-selected-windows mode-line boolean "22.1") (line-number-display-limit display (choice integer diff --git a/src/xdisp.c b/src/xdisp.c index 93cd54a3240..d61d421f08a 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -842,7 +842,7 @@ static Lisp_Object redisplay_window_1 (Lisp_Object); static bool set_cursor_from_row (struct window *, struct glyph_row *, struct glyph_matrix *, ptrdiff_t, ptrdiff_t, int, int); -static bool cursor_row_fully_visible_p (struct window *, bool, bool); +static bool cursor_row_fully_visible_p (struct window *, bool, 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 *); @@ -14346,7 +14346,7 @@ redisplay_internal (void) eassert (this_line_vpos == it.vpos); eassert (this_line_y == it.current_y); set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0); - if (cursor_row_fully_visible_p (w, false, true)) + if (cursor_row_fully_visible_p (w, false, true, false)) { #ifdef GLYPH_DEBUG *w->desired_matrix->method = 0; @@ -15628,19 +15628,46 @@ run_window_scroll_functions (Lisp_Object window, struct text_pos startp) window's current glyph matrix; otherwise use the desired glyph matrix. + If JUST_TEST_USER_PREFERENCE_P, just test what the value of + make-cursor-row-fully-visible requires, don't test the actual + cursor position. The assumption is that in that case the caller + performs the necessary testing of the cursor position. + A value of false means the caller should do scrolling as if point had gone off the screen. */ static bool cursor_row_fully_visible_p (struct window *w, bool force_p, - bool current_matrix_p) + bool current_matrix_p, + bool just_test_user_preference_p) { struct glyph_matrix *matrix; struct glyph_row *row; int window_height; + Lisp_Object mclfv_p = + buffer_local_value (Qmake_cursor_line_fully_visible, w->contents); - if (!make_cursor_line_fully_visible_p) + /* If no local binding, use the global value. */ + if (EQ (mclfv_p, Qunbound)) + mclfv_p = Vmake_cursor_line_fully_visible; + /* Follow mode sets the variable to a Lisp function in buffers that + are under Follow mode. */ + if (FUNCTIONP (mclfv_p)) + { + Lisp_Object window; + XSETWINDOW (window, w); + /* Implementation note: if the function we call here signals an + error, we will NOT scroll when the cursor is partially-visible. */ + Lisp_Object val = safe_call1 (mclfv_p, window); + if (NILP (val)) + return true; + else if (just_test_user_preference_p) + return false; + } + else if (NILP (mclfv_p)) return true; + else if (just_test_user_preference_p) + return false; /* It's not always possible to find the cursor, e.g, when a window is full of overlay strings. Don't do anything in that case. */ @@ -16002,7 +16029,7 @@ try_scrolling (Lisp_Object window, bool just_this_one_p, /* If cursor ends up on a partially visible line, treat that as being off the bottom of the screen. */ if (! cursor_row_fully_visible_p (w, extra_scroll_margin_lines <= 1, - false) + false, false) /* It's possible that the cursor is on the first line of the buffer, which is partially obscured due to a vscroll (Bug#7537). In that case, avoid looping forever. */ @@ -16367,7 +16394,7 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, /* Make sure this isn't a header line by any chance, since then MATRIX_ROW_PARTIALLY_VISIBLE_P might yield true. */ && !row->mode_line_p - && make_cursor_line_fully_visible_p) + && !cursor_row_fully_visible_p (w, true, true, true)) { if (PT == MATRIX_ROW_END_CHARPOS (row) && !row->ends_at_zv_p @@ -16385,7 +16412,7 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, else { set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0); - if (!cursor_row_fully_visible_p (w, false, true)) + if (!cursor_row_fully_visible_p (w, false, true, false)) rc = CURSOR_MOVEMENT_MUST_SCROLL; else rc = CURSOR_MOVEMENT_SUCCESS; @@ -16964,7 +16991,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) new_vpos = window_box_height (w) / 2; } - if (!cursor_row_fully_visible_p (w, false, false)) + if (!cursor_row_fully_visible_p (w, false, false, false)) { /* Point does appear, but on a line partly visible at end of window. Move it back to a fully-visible line. */ @@ -17059,7 +17086,8 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) goto need_larger_matrices; } } - if (w->cursor.vpos < 0 || !cursor_row_fully_visible_p (w, false, false)) + if (w->cursor.vpos < 0 + || !cursor_row_fully_visible_p (w, false, false, false)) { clear_glyph_matrix (w->desired_matrix); goto try_to_scroll; @@ -17206,7 +17234,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) /* Forget any recorded base line for line number display. */ w->base_line_number = 0; - if (!cursor_row_fully_visible_p (w, true, false)) + if (!cursor_row_fully_visible_p (w, true, false, false)) { clear_glyph_matrix (w->desired_matrix); last_line_misfit = true; @@ -17502,7 +17530,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) set_cursor_from_row (w, row, matrix, 0, 0, 0, 0); } - if (!cursor_row_fully_visible_p (w, false, false)) + if (!cursor_row_fully_visible_p (w, false, false, false)) { /* If vscroll is enabled, disable it and try again. */ if (w->vscroll) @@ -19068,9 +19096,10 @@ try_window_id (struct window *w) && CHARPOS (start) > BEGV) /* Old redisplay didn't take scroll margin into account at the bottom, but then global-hl-line-mode doesn't scroll. KFS 2004-06-14 */ - || (w->cursor.y + (make_cursor_line_fully_visible_p - ? cursor_height + this_scroll_margin - : 1)) > it.last_visible_y) + || (w->cursor.y + + (cursor_row_fully_visible_p (w, false, true, true) + ? 1 + : cursor_height + this_scroll_margin)) > it.last_visible_y) { w->cursor.vpos = -1; clear_glyph_matrix (w->desired_matrix); @@ -32903,9 +32932,15 @@ automatically; to decrease the tool-bar height, use \\[recenter]. */); doc: /* Non-nil means raise tool-bar buttons when the mouse moves over them. */); auto_raise_tool_bar_buttons_p = true; - DEFVAR_BOOL ("make-cursor-line-fully-visible", make_cursor_line_fully_visible_p, - doc: /* Non-nil means to scroll (recenter) cursor line if it is not fully visible. */); - make_cursor_line_fully_visible_p = true; + DEFVAR_LISP ("make-cursor-line-fully-visible", Vmake_cursor_line_fully_visible, + doc: /* Whether to scroll the window if the cursor line is not fully visible. +If the value is non-nil, Emacs scrolls or recenters the window to make +the cursor line fully visible. The value could also be a function, which +is called with a single argument, the window to be scrolled, and should +return non-nil if the partially-visible cursor requires scrolling the +window, nil if it's okay to leave the cursor partially-visible. */); + Vmake_cursor_line_fully_visible = Qt; + DEFSYM (Qmake_cursor_line_fully_visible, "make-cursor-line-fully-visible"); DEFVAR_LISP ("tool-bar-border", Vtool_bar_border, doc: /* Border below tool-bar in pixels. -- 2.39.5