From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Po Lu Newsgroups: gmane.emacs.devel Subject: Re: Allowing point to be outside the window? Date: Mon, 06 Dec 2021 10:11:47 +0800 Message-ID: <877dcipjmk.fsf@yahoo.com> References: <87ilwd7zaq.fsf.ref@yahoo.com> <87ilwd7zaq.fsf@yahoo.com> <83bl24yaed.fsf@gnu.org> <87sfvg7l51.fsf@yahoo.com> <83zgpowu23.fsf@gnu.org> <87zgpo5tws.fsf@yahoo.com> <83pmqkwi6r.fsf@gnu.org> <87v90c5su6.fsf@yahoo.com> <83o864wg2a.fsf@gnu.org> <87ilwb68ck.fsf@yahoo.com> <83zgpnunfo.fsf@gnu.org> <87fsrf3xmd.fsf@yahoo.com> <83y257ulfp.fsf@gnu.org> <8735ne4e0e.fsf@yahoo.com> <87czmcvcs1.fsf@yahoo.com> <83sfv85y36.fsf@gnu.org> <87v904tsvv.fsf@yahoo.com> <83h7bo5m1x.fsf@gnu.org> <87ilw3ubfp.fsf@yahoo.com> <83h7bn4e55.fsf@gnu.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="13662"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.60 (gnu/linux) Cc: emacs-devel@gnu.org To: Eli Zaretskii Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Mon Dec 06 03:12:55 2021 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mu3Us-0003Pk-8Q for ged-emacs-devel@m.gmane-mx.org; Mon, 06 Dec 2021 03:12:54 +0100 Original-Received: from localhost ([::1]:53860 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mu3Ur-0000LS-75 for ged-emacs-devel@m.gmane-mx.org; Sun, 05 Dec 2021 21:12:53 -0500 Original-Received: from eggs.gnu.org ([209.51.188.92]:38374) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mu3U3-00087k-Fb for emacs-devel@gnu.org; Sun, 05 Dec 2021 21:12:03 -0500 Original-Received: from sonic305-22.consmr.mail.ne1.yahoo.com ([66.163.185.148]:41914) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1mu3Tz-0002tf-Bn for emacs-devel@gnu.org; Sun, 05 Dec 2021 21:12:02 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1638756717; bh=NR4z1t4gTpYC5l4dyxZlxayBjaEPNbe/09ah2/RvpDw=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=ICn9fdYgkMN+4Hm0ZJvvTid/A912eMFd/LTyGGR62yFDXaupjYr2qzgIJKQH+/bQnpEVGnpy8kNfZHQNlAZpaGv4XTnTt8E0cOn/N7oHGJExz78+/AwmVByVd3vKmWybAbfWWtmmu4gT9zFZFSdCOp+D+6ExdsqqKuyT5ut9qT/ADKVVmYduf9nQ6CQO49qHxqlYSlGcl2Lee3bVLE93e1PGROFacorfiqKF3oZ9BQlnZviiMzN84iEW1QX7PY+RVS+LHuVPIKB+laUgemyMQ+xE6mieyTbVZEz1MZUckMsz9QTJoKlwTQt6GfszUIjViGc+CF8l0o8af+tCo02oyQ== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1638756717; bh=Z5KMCp5OM5ESq0HN/w9FRBBBSnOk2z87CZwcdOf7lTe=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=Zjsmxn1Yi7KHCCzYzBOsrl5N2eqRSSSSVrm7E6k3Mfp3rIyWSlTuMVaTez4OAT+8B2Cz8tfB+6ZYvyzfHtg+a7ZjFCqU1YeYN511VIRbcVTiFY3LiSGqMEWd3IY/EMrxHEJPZfFLZBacaaR9SvJGw2mq9NX6k7qR9Zb99eAk0SnYl9gQMmt/3DMokCBPp5ifePu0K3FfJ9T0tqJJUXf+hfzCXJDpHGan6AItdPuKFLuCVg5E1eY52mUOgzkfz8Xe0mjfb9y4fhYs/FQQtCLEWp8+QUCeiPJDvfu6joYLj3qjG9vTvNu47KcL/LxPFfUiTgyy8fBgnijRTKWPioBlTA== X-YMail-OSG: uv.QWiUVM1lmKBiWIfKMl6lOPnCYVmiPDohz5oeVJBvA9WUKmahW2Zz5TNujYFQ eNrJG_7zvS87O5g_.WO216LmiflFK0pMh3XP5YU8YMWM2OvqefGcIcCZoPCAfVei7kHO2LUIk88. BkUQxovkf_XFHzqGyFOTeElhEB2N11ho3GKuozaiVkYbG2EwSi45A.pHBJB5gomyLiADSe5ztcaH S_goPdNah49ovRQO1qnXICUXy9TyWz77UO5h27jORqCFBPudb.HTFFfKsJshAtticU08fpD8_ii5 .Tf86jynMkLuw.wkjaW_tzlqo3Vqk6.2GDGAF0iev6iTwZDuxUdReY7FNqvhkxPqm37UIWyGLxxy WZeQYnTjr0mpLIjxvoynt0SiOc3eS2zHp9V1kIUo2fr0b6241c.LWL3NE7aTXtncyL2I0nvwkAoH fWda3BnFuKJv.2zVDwXYVscW3c8dKFfzQyoRlXBmb5nfCoVc6Vj1KhjDFs8_Rdm5Jk7YIidVgey. 4rejJgEvlq0UJ2YcvKww2FuhopZmXKbJPveof1ZdAR7lODIhQsXQWsqH3Z02Mk_IdrovEkR7dqgd 0Gt0j2iNFMy5uOyPCZMmIVa7aJb39me2U5YfMNEM1MMdrNF6WkNS34JjY3t.F0WgnkzssXlpkBq. gFREtjvNyeg9NeSjoBh3ivrlCdqkeEqn6KewvlQNLV_daArgXRmqCpSxFwa9T3ONNLPl16MmWekL 80_3bAE4SX_07ggSweTuUdNac80gwfNJO2hYaSCHGoZBts03jkeg30y7QaUW0ltsA0DDmcTbDebh HWZei9pm2Ss_gccoKAlzlOHjh1WlyiHnK9UrygfUvg X-Sonic-MF: Original-Received: from sonic.gate.mail.ne1.yahoo.com by sonic305.consmr.mail.ne1.yahoo.com with HTTP; Mon, 6 Dec 2021 02:11:57 +0000 Original-Received: by kubenode512.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 1a5c1a0a07e0bcbcbf63e90d25ba21cf; Mon, 06 Dec 2021 02:11:52 +0000 (UTC) In-Reply-To: <83h7bn4e55.fsf@gnu.org> (Eli Zaretskii's message of "Sun, 05 Dec 2021 11:03:34 +0200") X-Mailer: WebService/1.1.19306 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Received-SPF: pass client-ip=66.163.185.148; envelope-from=luangruo@yahoo.com; helo=sonic305-22.consmr.mail.ne1.yahoo.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:281042 Archived-At: --=-=-= Content-Type: text/plain Eli Zaretskii writes: > That'd cover scrolling a window in a way that leaves point outside of > it. But Emacs also sets the window-start position in other > situations. Moreover, the display engine itself does that, see > redisplay_window. > So some logic and/or flags will be needed to distinguish between the > cases. We should not recenter the display in any case where the start is not forced and point is not moved. >> For instance, we could enable the code that scrolls the window to follow >> point if PT != w->point (if that makes sense). > So any change in the numerical value of point will scroll the window > to bring point into the view? That'd be fine if that's what users > expect. But do they? E.g., what happens if point is below the > window, and you paste (with the mouse) some text into the visible > portion of the window (which doesn't show point)? That's not a problem, as `mouse-yank-primary' and friends already call mouse-set-point. WDYT about the attached patch? It recenters the display whenever PT != w->last_point, and it seems to work very well. It also introduces a new variable `scroll-move-point' that controls if the scrolling commands will try to move point to stay visible. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=diff.diff diff --git a/doc/emacs/display.texi b/doc/emacs/display.texi index 15cad88d59..814f9d0286 100644 --- a/doc/emacs/display.texi +++ b/doc/emacs/display.texi @@ -250,10 +250,18 @@ Auto Scrolling @section Automatic Scrolling @cindex automatic scrolling - Emacs performs @dfn{automatic scrolling} when point moves out of the -visible portion of the text. Normally, automatic scrolling centers -point vertically in the window, but there are several ways to alter -this behavior. + Emacs by default performs @dfn{automatic scrolling} when point moves +out of the visible portion of the text. Normally, automatic scrolling +centers point vertically in the window, but there are several ways to +alter this behavior. + +@vindex keep-point-visible + If @code{keep-point-visible} is nil, redisplay will not move recenter +the display when the window start is changed. + +@vindex scroll-move-point + If @code{scroll-move-point} is nil, scrolling commands will not move +point to keep it inside the visible part of the window. @vindex scroll-conservatively @vindex scroll-minibuffer-conservatively diff --git a/etc/NEWS b/etc/NEWS index a8b7dc56ba..7154f20ade 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -257,6 +257,15 @@ are met. The conditions are given by the argument, which can be * Editing Changes in Emacs 29.1 +** New variable 'keep-point-visible'. +This variable controls if redisplay will try to keep point visible +inside the window. + ++++ +** New variable 'scroll-move-point'. +This variable controls if scrolling moves point to stay inside the +window. + --- ** Indentation of 'cl-flet' and 'cl-labels' has changed. These forms now indent like this: diff --git a/src/window.c b/src/window.c index e801ff821f..c54f8164d3 100644 --- a/src/window.c +++ b/src/window.c @@ -5576,7 +5576,8 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) something like (scroll-down 1) with PT in the line before the partially visible one would recenter. */ - if (!pos_visible_p (w, PT, &x, &y, &rtop, &rbot, &rowh, &vpos)) + if (!pos_visible_p (w, PT, &x, &y, &rtop, &rbot, &rowh, &vpos) + && scroll_move_point) { itdata = bidi_shelve_cache (); /* Move backward half the height of the window. Performance note: @@ -5657,8 +5658,9 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) w->start_at_line_beg = true; wset_update_mode_line (w); /* Set force_start so that redisplay_window will run the - window-scroll-functions. */ - w->force_start = true; + window-scroll-functions, unless scroll_move_point is false, + in which case forcing the start will cause recentering. */ + w->force_start = scroll_move_point; return; } } @@ -5842,8 +5844,9 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) w->start_at_line_beg = (pos == BEGV || FETCH_BYTE (bytepos - 1) == '\n'); wset_update_mode_line (w); /* Set force_start so that redisplay_window will run the - window-scroll-functions. */ - w->force_start = true; + window-scroll-functions, unless scroll_move_point is false, + in which case forcing the start will cause recentering. */ + w->force_start = scroll_move_point; } /* The rest of this function uses current_y in a nonstandard way, @@ -5855,157 +5858,161 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) even if there is a header line. */ this_scroll_margin = window_scroll_margin (w, MARGIN_IN_PIXELS); - if (n > 0) + if (scroll_move_point) { - int last_y = it.last_visible_y - this_scroll_margin - 1; - - /* We moved the window start towards ZV, so PT may be now - in the scroll margin at the top. */ - move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS); - if (IT_CHARPOS (it) == PT - && it.current_y >= this_scroll_margin - && it.current_y <= last_y - WINDOW_TAB_LINE_HEIGHT (w) - - WINDOW_HEADER_LINE_HEIGHT (w) - && (NILP (Vscroll_preserve_screen_position) - || EQ (Vscroll_preserve_screen_position, Qt))) - /* We found PT at a legitimate height. Leave it alone. */ - ; - else + if (n > 0) { - if (window_scroll_pixel_based_preserve_y >= 0) - { - /* Don't enter the scroll margin at the end of the window. */ - int goal_y = min (last_y, window_scroll_pixel_based_preserve_y); - - /* If we have a header line, take account of it. This - is necessary because we set it.current_y to 0, above. */ - move_it_to (&it, -1, - window_scroll_pixel_based_preserve_x, - goal_y - WINDOW_TAB_LINE_HEIGHT (w) - - WINDOW_HEADER_LINE_HEIGHT (w), - -1, MOVE_TO_Y | MOVE_TO_X); - } + int last_y = it.last_visible_y - this_scroll_margin - 1; - /* Get out of the scroll margin at the top of the window. */ - while (it.current_y < this_scroll_margin) + /* We moved the window start towards ZV, so PT may be now + in the scroll margin at the top. */ + move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS); + if (IT_CHARPOS (it) == PT + && it.current_y >= this_scroll_margin + && it.current_y <= last_y - WINDOW_TAB_LINE_HEIGHT (w) + - WINDOW_HEADER_LINE_HEIGHT (w) + && (NILP (Vscroll_preserve_screen_position) + || EQ (Vscroll_preserve_screen_position, Qt))) + /* We found PT at a legitimate height. Leave it alone. */ + ; + else { - int prev = it.current_y; - move_it_by_lines (&it, 1); - if (prev == it.current_y) - break; + if (window_scroll_pixel_based_preserve_y >= 0) + { + /* Don't enter the scroll margin at the end of the window. */ + int goal_y = min (last_y, window_scroll_pixel_based_preserve_y); + + /* If we have a header line, take account of it. This + is necessary because we set it.current_y to 0, above. */ + move_it_to (&it, -1, + window_scroll_pixel_based_preserve_x, + goal_y - WINDOW_TAB_LINE_HEIGHT (w) + - WINDOW_HEADER_LINE_HEIGHT (w), + -1, MOVE_TO_Y | MOVE_TO_X); + } + + /* Get out of the scroll margin at the top of the window. */ + while (it.current_y < this_scroll_margin) + { + int prev = it.current_y; + move_it_by_lines (&it, 1); + if (prev == it.current_y) + break; + } + SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it)); + /* Fix up the Y position to preserve, if it is inside the + scroll margin at the window top. */ + if (window_scroll_pixel_based_preserve_y >= 0 + && window_scroll_pixel_based_preserve_y < this_scroll_margin) + window_scroll_pixel_based_preserve_y = this_scroll_margin; } - SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it)); - /* Fix up the Y position to preserve, if it is inside the - scroll margin at the window top. */ - if (window_scroll_pixel_based_preserve_y >= 0 - && window_scroll_pixel_based_preserve_y < this_scroll_margin) - window_scroll_pixel_based_preserve_y = this_scroll_margin; } - } - else if (n < 0) - { - ptrdiff_t charpos, bytepos; - bool partial_p; - - /* Save our position, for the - window_scroll_pixel_based_preserve_y case. */ - charpos = IT_CHARPOS (it); - bytepos = IT_BYTEPOS (it); - - /* We moved the window start towards BEGV, so PT may be now - in the scroll margin at the bottom. */ - move_it_to (&it, PT, -1, - /* We subtract WINDOW_HEADER_LINE_HEIGHT because - it.y is relative to the bottom of the header - line, see above. */ - (it.last_visible_y - WINDOW_TAB_LINE_HEIGHT (w) - - WINDOW_HEADER_LINE_HEIGHT (w) - - partial_line_height (&it) - this_scroll_margin - 1), - -1, - MOVE_TO_POS | MOVE_TO_Y); - - /* Save our position, in case it's correct. */ - charpos = IT_CHARPOS (it); - bytepos = IT_BYTEPOS (it); - - /* If PT is in the screen line at the last fully visible line, - move_it_to will stop at X = 0 in that line, because the - required Y coordinate is reached there. See if we can get to - PT without descending lower in Y, and if we can, it means we - reached PT before the scroll margin. */ - if (charpos != PT) + else if (n < 0) { - struct it it2; - void *it_data; + ptrdiff_t charpos, bytepos; + bool partial_p; - it2 = it; - it_data = bidi_shelve_cache (); - move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS); - if (IT_CHARPOS (it) == PT && it.current_y == it2.current_y) + /* Save our position, for the + window_scroll_pixel_based_preserve_y case. */ + charpos = IT_CHARPOS (it); + bytepos = IT_BYTEPOS (it); + + /* We moved the window start towards BEGV, so PT may be now + in the scroll margin at the bottom. */ + move_it_to (&it, PT, -1, + /* We subtract WINDOW_HEADER_LINE_HEIGHT because + it.y is relative to the bottom of the header + line, see above. */ + (it.last_visible_y - WINDOW_TAB_LINE_HEIGHT (w) + - WINDOW_HEADER_LINE_HEIGHT (w) + - partial_line_height (&it) - this_scroll_margin - 1), + -1, + MOVE_TO_POS | MOVE_TO_Y); + + /* Save our position, in case it's correct. */ + charpos = IT_CHARPOS (it); + bytepos = IT_BYTEPOS (it); + + /* If PT is in the screen line at the last fully visible line, + move_it_to will stop at X = 0 in that line, because the + required Y coordinate is reached there. See if we can get to + PT without descending lower in Y, and if we can, it means we + reached PT before the scroll margin. */ + if (charpos != PT) { - charpos = IT_CHARPOS (it); - bytepos = IT_BYTEPOS (it); - bidi_unshelve_cache (it_data, true); + struct it it2; + void *it_data; + + it2 = it; + it_data = bidi_shelve_cache (); + move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS); + if (IT_CHARPOS (it) == PT && it.current_y == it2.current_y) + { + charpos = IT_CHARPOS (it); + bytepos = IT_BYTEPOS (it); + bidi_unshelve_cache (it_data, true); + } + else + { + it = it2; + bidi_unshelve_cache (it_data, false); + } } + + /* See if point is on a partially visible line at the end. */ + if (it.what == IT_EOB) + partial_p = + it.current_y + it.ascent + it.descent + > it.last_visible_y - this_scroll_margin + - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w); else { - it = it2; - bidi_unshelve_cache (it_data, false); + move_it_by_lines (&it, 1); + partial_p = + it.current_y + > it.last_visible_y - this_scroll_margin + - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w); } - } - - /* See if point is on a partially visible line at the end. */ - if (it.what == IT_EOB) - partial_p = - it.current_y + it.ascent + it.descent - > it.last_visible_y - this_scroll_margin - - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w); - else - { - move_it_by_lines (&it, 1); - partial_p = - it.current_y - > it.last_visible_y - this_scroll_margin - - WINDOW_TAB_LINE_HEIGHT (w) - WINDOW_HEADER_LINE_HEIGHT (w); - } - if (charpos == PT && !partial_p - && (NILP (Vscroll_preserve_screen_position) - || EQ (Vscroll_preserve_screen_position, Qt))) - /* We found PT before we found the display margin, so PT is ok. */ - ; - else if (window_scroll_pixel_based_preserve_y >= 0) - { - int goal_y = min (it.last_visible_y - this_scroll_margin - 1, - window_scroll_pixel_based_preserve_y); - - /* Don't let the preserved screen Y coordinate put us inside - any of the two margins. */ - if (goal_y < this_scroll_margin) - goal_y = this_scroll_margin; - SET_TEXT_POS_FROM_MARKER (start, w->start); - start_display (&it, w, start); - /* It would be wrong to subtract WINDOW_HEADER_LINE_HEIGHT - here because we called start_display again and did not - alter it.current_y this time. */ - move_it_to (&it, -1, window_scroll_pixel_based_preserve_x, - goal_y, -1, MOVE_TO_Y | MOVE_TO_X); - SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it)); - } - else - { - if (partial_p) - /* The last line was only partially visible, so back up two - lines to make sure we're on a fully visible line. */ + if (charpos == PT && !partial_p + && (NILP (Vscroll_preserve_screen_position) + || EQ (Vscroll_preserve_screen_position, Qt))) + /* We found PT before we found the display margin, so PT is ok. */ + ; + else if (window_scroll_pixel_based_preserve_y >= 0) { - move_it_by_lines (&it, -2); + int goal_y = min (it.last_visible_y - this_scroll_margin - 1, + window_scroll_pixel_based_preserve_y); + + /* Don't let the preserved screen Y coordinate put us inside + any of the two margins. */ + if (goal_y < this_scroll_margin) + goal_y = this_scroll_margin; + SET_TEXT_POS_FROM_MARKER (start, w->start); + start_display (&it, w, start); + /* It would be wrong to subtract WINDOW_HEADER_LINE_HEIGHT + here because we called start_display again and did not + alter it.current_y this time. */ + move_it_to (&it, -1, window_scroll_pixel_based_preserve_x, + goal_y, -1, MOVE_TO_Y | MOVE_TO_X); SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it)); } else - /* No, the position we saved is OK, so use it. */ - SET_PT_BOTH (charpos, bytepos); + { + if (partial_p) + /* The last line was only partially visible, so back up two + lines to make sure we're on a fully visible line. */ + { + move_it_by_lines (&it, -2); + SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it)); + } + else + /* No, the position we saved is OK, so use it. */ + SET_PT_BOTH (charpos, bytepos); + } } } + bidi_unshelve_cache (itdata, false); if (adjust_old_pointm) @@ -8500,6 +8507,10 @@ syms_of_window (void) displayed after a scrolling operation to be somewhat inaccurate. */); fast_but_imprecise_scrolling = false; + DEFVAR_BOOL ("scroll-move-point", scroll_move_point, + doc: /* If nil, don't move point to fit inside the window when scrolling. */); + scroll_move_point = true; + defsubr (&Sselected_window); defsubr (&Sold_selected_window); defsubr (&Sminibuffer_window); diff --git a/src/xdisp.c b/src/xdisp.c index 0ff6286af7..d0d983ca97 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -16118,6 +16118,8 @@ #define AINC(a,i) \ tlbufpos = this_line_start_pos; tlendpos = this_line_end_pos; if (!consider_all_windows_p + /* TODO: enable this optimization. */ + && keep_point_visible && CHARPOS (tlbufpos) > 0 && !w->update_mode_line && !current_buffer->clip_changed @@ -17768,6 +17770,9 @@ try_scrolling (Lisp_Object window, bool just_this_one_p, else scroll_max = 0; + if (!keep_point_visible) + goto out; + too_near_end: /* Decide whether to scroll down. */ @@ -18004,6 +18009,8 @@ try_scrolling (Lisp_Object window, bool just_this_one_p, /* Run window scroll functions. */ startp = run_window_scroll_functions (window, startp); + out: + /* Display the window. Give up if new fonts are loaded, or if point doesn't appear. */ if (!try_window (window, startp, 0)) @@ -18183,6 +18190,10 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, return rc; #endif + /* TODO: enable this optimization. */ + if (!keep_point_visible) + return CURSOR_MOVEMENT_CANNOT_BE_USED; + /* Previously, there was a check for Lisp integer in the if-statement below. Now, this field is converted to ptrdiff_t, thus zero means invalid position in a buffer. */ @@ -18770,6 +18781,8 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) clear_glyph_matrix (w->desired_matrix); } + debug_method_add (w, "real redisplay starts"); + /* Otherwise set up data on this window; select its buffer and point value. */ /* Really select the buffer, for the sake of buffer-local @@ -18992,6 +19005,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) new_vpos = MATRIX_ROW_BOTTOM_Y (r); else /* Give up and just move to the middle of the window. */ new_vpos = window_box_height (w) / 2; + } if (!cursor_row_fully_visible_p (w, false, false, false)) @@ -19223,10 +19237,12 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) IF_DEBUG (debug_method_add (w, "1")); clear_glyph_matrix (w->desired_matrix); if (try_window (window, startp, TRY_WINDOW_CHECK_MARGINS) < 0) - /* -1 means we need to scroll. - 0 means we need new matrices, but fonts_changed - is set in that case, so we will detect it below. */ - goto try_to_scroll; + { + /* -1 means we need to scroll. + 0 means we need new matrices, but fonts_changed + is set in that case, so we will detect it below. */ + goto try_to_scroll; + } } if (f->fonts_changed) @@ -19255,7 +19271,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) try_to_scroll: - /* Redisplay the mode line. Select the buffer properly for that. */ + /* Redisplay the mode line. Select the buffer properly for that. */ if (!update_mode_line) { update_mode_line = true; @@ -19301,6 +19317,9 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) } } + if (!keep_point_visible && PT == w->last_point) + goto maybe_try_window; + /* Finally, just choose a place to start which positions point according to user preferences. */ @@ -19317,6 +19336,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) /* Determine the window start relative to point. */ init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID); it.current_y = it.last_visible_y; + if (centering_position < 0) { ptrdiff_t margin_pos = CHARPOS (startp); @@ -19584,6 +19604,53 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) centering_position = 0; goto recenter; } + goto done; + + maybe_try_window: + + /* Set the window start position here explicitly if it is outside + the accessible portion of the buffer. */ + + if (CHARPOS (startp) < BEGV + || CHARPOS (startp) > ZV) + { + if (CHARPOS (startp) < BEGV) + set_marker_both (w->start, Qnil, BEGV, BEGV_BYTE); + else + set_marker_both (w->start, Qnil, ZV, ZV_BYTE); + + SET_TEXT_POS_FROM_MARKER (startp, w->start); + + /* Run scroll hooks. */ + startp = run_window_scroll_functions (window, startp); + } + + /* We invoke try_window and try_window_reusing_current_matrix below, + and they manipulate the bidi cache. Save and restore the cache + state of our iterator, so we could continue using it after that. */ + itdata = bidi_shelve_cache (); + + /* Redisplay the window. */ + use_desired_matrix = false; + if (!current_matrix_up_to_date_p + || windows_or_buffers_changed + || f->cursor_type_changed + /* Don't use try_window_reusing_current_matrix in this case + because it can have changed the buffer. */ + || !NILP (Vwindow_scroll_functions) + || !just_this_one_p + || MINI_WINDOW_P (w) + || !(used_current_matrix_p + = try_window_reusing_current_matrix (w))) + use_desired_matrix = (try_window (window, startp, 0) == 1); + + bidi_unshelve_cache (itdata, false); + + /* If new fonts have been loaded (due to fontsets), give up. We + have to start a new redisplay since we need to re-adjust glyph + matrices. */ + if (f->fonts_changed) + goto need_larger_matrices; done: @@ -19591,6 +19658,11 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) w->start_at_line_beg = (CHARPOS (startp) == BEGV || FETCH_BYTE (BYTEPOS (startp) - 1) == '\n'); + if (!keep_point_visible + && (w->cursor.vpos == -1) + && w->phys_cursor_on_p) + erase_phys_cursor (w); + /* Display the mode line, header line, and tab-line, if we must. */ if ((update_mode_line /* If window not full width, must redo its mode line @@ -19801,6 +19873,8 @@ try_window (Lisp_Object window, struct text_pos pos, int flags) struct frame *f = XFRAME (w->frame); int cursor_vpos = w->cursor.vpos; + debug_method_add (w, "try_window"); + /* Make POS the new window start. */ set_marker_both (w->start, Qnil, CHARPOS (pos), BYTEPOS (pos)); @@ -19960,6 +20034,10 @@ try_window_reusing_current_matrix (struct window *w) return false; #endif + /* TODO: enable this optimization. */ + if (!keep_point_visible) + 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); @@ -32389,6 +32467,9 @@ display_and_set_cursor (struct window *w, bool on, && new_cursor_width != w->phys_cursor_width))) erase_phys_cursor (w); + if (w->cursor.vpos == -1) + return; + /* Don't check phys_cursor_on_p here because that flag is only set to false in some cases where we know that the cursor has been completely erased, to avoid the extra work of erasing the cursor @@ -32749,6 +32830,9 @@ cursor_in_mouse_face_p (struct window *w) int vpos = w->phys_cursor.vpos; struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos); + if (vpos == -1) + return false; + /* When the window is hscrolled, cursor hpos can legitimately be out of bounds, but we draw the cursor at the corresponding window margin in that case. */ @@ -35493,6 +35577,10 @@ syms_of_xdisp (void) x_stretch_cursor_p = 0; #endif + DEFVAR_BOOL ("keep-point-visible", keep_point_visible, + doc: /* Non-nil means to keep the point visible. */); + keep_point_visible = 1; + DEFVAR_LISP ("show-trailing-whitespace", Vshow_trailing_whitespace, doc: /* Non-nil means highlight trailing whitespace. The face used for trailing whitespace is `trailing-whitespace'. */); --=-=-= Content-Type: text/plain Thanks. --=-=-=--