* Allowing point to be outside the window? [not found] <87ilwd7zaq.fsf.ref@yahoo.com> @ 2021-11-28 3:07 ` Po Lu 2021-11-28 8:03 ` Eli Zaretskii 0 siblings, 1 reply; 111+ messages in thread From: Po Lu @ 2021-11-28 3:07 UTC (permalink / raw) To: emacs-devel I wonder what would be involved in allowing point to be outside a window's visible area. It would make pixel scrolling much less confusing for many people who are used to other editors, such as gedit. Thanks. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-28 3:07 ` Allowing point to be outside the window? Po Lu @ 2021-11-28 8:03 ` Eli Zaretskii 2021-11-28 8:13 ` Po Lu 0 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-11-28 8:03 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Date: Sun, 28 Nov 2021 11:07:57 +0800 > > I wonder what would be involved in allowing point to be outside a > window's visible area. Two steps: 1. Design the feature: how would it work? which operations would bring point back into the viewport, and which won't? For example, a simple question: if point is outside of the viewport, what is the effect of C-f or C-n on display? 2. Go over the display-related code and modify all the places which assume point is or must be visible. Source files involved are xdisp.c, dispnew.c, window.c, fringe.c, probably also indent.c. IMO, it's a large job if done cleanly. Patches welcome. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-28 8:03 ` Eli Zaretskii @ 2021-11-28 8:13 ` Po Lu 2021-11-28 8:41 ` Eli Zaretskii 2021-11-28 14:03 ` Alan Mackenzie 0 siblings, 2 replies; 111+ messages in thread From: Po Lu @ 2021-11-28 8:13 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: >> From: Po Lu <luangruo@yahoo.com> >> Date: Sun, 28 Nov 2021 11:07:57 +0800 >> >> I wonder what would be involved in allowing point to be outside a >> window's visible area. > > Two steps: > > 1. Design the feature: how would it work? which operations would > bring point back into the viewport, and which won't? For > example, a simple question: if point is outside of the viewport, > what is the effect of C-f or C-n on display? The effect would be move point forward, or to the next line, and then to recenter the window, so point is at the center of the window. Inserting text should probably recenter the window as well, if point is outside the visible area (this is also how other programs behave). This is how other programs behave as well. > IMO, it's a large job if done cleanly. Patches welcome. Thanks, I will take a look at it. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-28 8:13 ` Po Lu @ 2021-11-28 8:41 ` Eli Zaretskii 2021-11-28 12:47 ` Po Lu 2021-11-28 14:03 ` Alan Mackenzie 1 sibling, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-11-28 8:41 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Sun, 28 Nov 2021 16:13:46 +0800 > > Eli Zaretskii <eliz@gnu.org> writes: > > >> From: Po Lu <luangruo@yahoo.com> > >> Date: Sun, 28 Nov 2021 11:07:57 +0800 > >> > >> I wonder what would be involved in allowing point to be outside a > >> window's visible area. > > > > Two steps: > > > > 1. Design the feature: how would it work? which operations would > > bring point back into the viewport, and which won't? For > > example, a simple question: if point is outside of the viewport, > > what is the effect of C-f or C-n on display? > > The effect would be move point forward, or to the next line, and then to > recenter the window, so point is at the center of the window. That's one possibility, perhaps the most obvious one. But it isn't the only one, and we should understand well what we want in this regard, because Emacs sometimes moves point by itself, without the user's say-so. > Inserting text should probably recenter the window as well, if point is > outside the visible area (this is also how other programs behave). This is IMO less obvious, especially if you keep in mind that text can be inserted by some Emacs command other than an explicit text insertion by the user (via self-insert-command, C-y, etc.). It is quite possible we will need some finer granularity here, where not _every_ insertion will bring point into the viewport. > This is how other programs behave as well. Emacs is much more complex than "other programs", and many commands/functions are invoked in different contexts, where user expectations regarding this aspect could be different. Moreover, we have a lot of code that disregards the context because the assumption is that point is always visible, something that is obtained by a coordinated effort of many parts of Emacs code (so if one of them doesn't make point visible, some other one will). Making this well-orchestrated effort do something different (let alone do it optionally, since I expect quite a few users to want not to have this new behavior) will probably require some new protocol. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-28 8:41 ` Eli Zaretskii @ 2021-11-28 12:47 ` Po Lu 2021-11-28 12:58 ` Eli Zaretskii 0 siblings, 1 reply; 111+ messages in thread From: Po Lu @ 2021-11-28 12:47 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: > Emacs is much more complex than "other programs", and many > commands/functions are invoked in different contexts, where user > expectations regarding this aspect could be different. Moreover, we > have a lot of code that disregards the context because the assumption > is that point is always visible, something that is obtained by a > coordinated effort of many parts of Emacs code (so if one of them > doesn't make point visible, some other one will). Making this > well-orchestrated effort do something different (let alone do it > optionally, since I expect quite a few users to want not to have this > new behavior) will probably require some new protocol. Hmm, thanks. One small question though: what should I do in order to make a window's cursor invisible? I want to detect if PT is before window start, and in that case refrain from displaying the phys cursor. Right now, I test for that condition in redisplay_window, and the test seems to work, but I have no idea how to mark the window's cursor as invisible, so to speak. Or perhaps this is an X/Y question, but I'm not sure. Thanks in advance. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-28 12:47 ` Po Lu @ 2021-11-28 12:58 ` Eli Zaretskii 2021-11-28 13:10 ` Po Lu 0 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-11-28 12:58 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Sun, 28 Nov 2021 20:47:15 +0800 > > Hmm, thanks. One small question though: what should I do in order to > make a window's cursor invisible? Prevent display_and_set_cursor from being called, I presume? There's also set_cursor_from_row, which calculates where to display the cursor, and something should be done about that to indicate that the cursor is not shown at all. > I want to detect if PT is before window start, and in that case refrain > from displaying the phys cursor. Right now, I test for that condition > in redisplay_window, and the test seems to work display_and_set_cursor is also called from dispnew.c, so I'm not sure redisplay_window alone will be enough. And why only "before window start"? what about beyond window's end? > but I have no idea how to mark the window's cursor as invisible, so > to speak. I think you need to add something to the struct window's 'cursor' and 'phys_cursor' members. > Or perhaps this is an X/Y question, but I'm not sure. You cannot express coordinates outside of the window as X/Y. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-28 12:58 ` Eli Zaretskii @ 2021-11-28 13:10 ` Po Lu 2021-11-28 13:44 ` Eli Zaretskii 0 siblings, 1 reply; 111+ messages in thread From: Po Lu @ 2021-11-28 13:10 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: >> Hmm, thanks. One small question though: what should I do in order to >> make a window's cursor invisible? > Prevent display_and_set_cursor from being called, I presume? What if the cursor is already displayed? Is it OK to call erase_phys_cursor from redisplay_window? > There's also set_cursor_from_row, which calculates where to display > the cursor, and something should be done about that to indicate that > the cursor is not shown at all. set_cursor_from_row can just immediately return if I indicate that the cursor is invisible because point is before or after window start, correct? > display_and_set_cursor is also called from dispnew.c, so I'm not sure > redisplay_window alone will be enough. Hmm, thanks, I think I might put that logic in display_and_set_cursor instead. > And why only "before window start"? what about beyond window's end? I don't know how to get that information inside redisplay_window. AFAIU, it's not available until redisplay completes. > I think you need to add something to the struct window's 'cursor' and > 'phys_cursor' members. Okay, I'll do that. > You cannot express coordinates outside of the window as X/Y. I meant "X/Y" question as in a question that goes somewhat like this: - User wants to do X. - User doesn't know how to do X, but thinks they can fumble their way to a solution if they can just manage to do Y. - User doesn't know how to do Y either. - User asks for help with Y. - Others try to help user with Y, but are confused because Y seems like a strange problem to want to solve. - After much interaction and wasted time, it finally becomes clear that the user really wants help with X, and that Y wasn't even a suitable solution for X. I hope this isn't the case here, but I can't explain what the "X" here is in terms more specific than "I want the ability to have point outside the window". Thanks in advance. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-28 13:10 ` Po Lu @ 2021-11-28 13:44 ` Eli Zaretskii 2021-11-29 1:47 ` Po Lu 0 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-11-28 13:44 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Sun, 28 Nov 2021 21:10:25 +0800 > > Eli Zaretskii <eliz@gnu.org> writes: > > >> Hmm, thanks. One small question though: what should I do in order to > >> make a window's cursor invisible? > > > Prevent display_and_set_cursor from being called, I presume? > > What if the cursor is already displayed? Is it OK to call > erase_phys_cursor from redisplay_window? Hmm... I guess it would be better to modify display_and_set_cursor so that it only erases the cursor if needed, but doesn't display it. > > There's also set_cursor_from_row, which calculates where to display > > the cursor, and something should be done about that to indicate that > > the cursor is not shown at all. > > set_cursor_from_row can just immediately return if I indicate that the > cursor is invisible because point is before or after window start, > correct? Yes, but that function is the one that sets the data in window's 'cursor' member, so in this case set_cursor_from_row should somehow indicate there that the cursor is not visible or something. I think. There are several places in the display code which look at that data and rely on it. > > And why only "before window start"? what about beyond window's end? > > I don't know how to get that information inside redisplay_window. > AFAIU, it's not available until redisplay completes. So you will have to add code somewhere that produces this information and records it somewhere, right? It would be not very useful to support "point outside window, but only before the window" feature. You will find in try_scrolling code that finds whether point is beyond the window end. You can do something similar where you need this information. > I hope this isn't the case here, but I can't explain what the "X" here > is in terms more specific than "I want the ability to have point outside > the window". I don't see any way around carefully reading the code and finding all the places where we assume that point is visible, or make it visible if it isn't. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-28 13:44 ` Eli Zaretskii @ 2021-11-29 1:47 ` Po Lu 2021-11-29 13:00 ` Eli Zaretskii 0 siblings, 1 reply; 111+ messages in thread From: Po Lu @ 2021-11-29 1:47 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: Hmm, thanks. Another question: is the only code that moves either point or window start in order to constrain point into the window in redisplay_window, under `recenter' and `try_to_scroll'? Thanks. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-29 1:47 ` Po Lu @ 2021-11-29 13:00 ` Eli Zaretskii 2021-11-29 13:22 ` Po Lu 0 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-11-29 13:00 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Mon, 29 Nov 2021 09:47:39 +0800 > > Eli Zaretskii <eliz@gnu.org> writes: > > Hmm, thanks. Another question: is the only code that moves either point > or window start in order to constrain point into the window in > redisplay_window, under `recenter' and `try_to_scroll'? A $64M question ;-) Your opinion about my memory is too good. But in general, I think you are looking at a too-narrow aspect of this behavior. First, even in xdisp.c there are several places where we attempt to redisplay a window, and then reject the results because point is not fully visible in the window. "Reject" here sometimes mean another, fresh attempt of redisplaying the window with some conditions or variables modified to yield a success. These places should be audited in order to decide whether the rejection is justified under this new feature. Second, look at the scrolling code in window.c: under some conditions, it decides up front that point will be invisible, and then either moves point or modifies the scroll (i.e. the window-start). That, too, will have to be revisited and carefully audited. And there could be other places as well, I simply don't remember. So I think the answer to your question is, unfortunately, NO. The problem is wider and more complex than just the scrolling code in redisplay_window in these two places. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-29 13:00 ` Eli Zaretskii @ 2021-11-29 13:22 ` Po Lu 2021-11-29 13:43 ` Eli Zaretskii 0 siblings, 1 reply; 111+ messages in thread From: Po Lu @ 2021-11-29 13:22 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: > A $64M question ;-) Your opinion about my memory is too good. > > But in general, I think you are looking at a too-narrow aspect of this > behavior. First, even in xdisp.c there are several places where we > attempt to redisplay a window, and then reject the results because > point is not fully visible in the window. "Reject" here sometimes > mean another, fresh attempt of redisplaying the window with some > conditions or variables modified to yield a success. These places > should be audited in order to decide whether the rejection is > justified under this new feature. Thanks, I will look at it. One last question though: > Second, look at the scrolling code in window.c: under some conditions, > it decides up front that point will be invisible, and then either > moves point or modifies the scroll (i.e. the window-start). That, > too, will have to be revisited and carefully audited. Is any of that scrolling code used during redisplay (for instance, if the window start is changed?) The main use I have for this feature will be in the pixel scrolling code, which doesn't use any of the normal scrolling commands. Thanks. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-29 13:22 ` Po Lu @ 2021-11-29 13:43 ` Eli Zaretskii 2021-11-30 1:40 ` Po Lu 0 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-11-29 13:43 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Mon, 29 Nov 2021 21:22:18 +0800 > > > Second, look at the scrolling code in window.c: under some conditions, > > it decides up front that point will be invisible, and then either > > moves point or modifies the scroll (i.e. the window-start). That, > > too, will have to be revisited and carefully audited. > > Is any of that scrolling code used during redisplay (for instance, if > the window start is changed?) It certainly affects redisplay. It might also be called by redisplay, I don't remember. However, ... > The main use I have for this feature will be in the pixel scrolling > code, which doesn't use any of the normal scrolling commands. ... it makes very little sense to me to introduce such a feature only for the sake of pixel-wise scrolling. We should allow such a mode with all the Emacs commands, not just in pixel-wise scrolling. And anyway, Emacs might call scrolling commands as part of other commands, not just because the user types C-v. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-29 13:43 ` Eli Zaretskii @ 2021-11-30 1:40 ` Po Lu 2021-11-30 16:49 ` [External] : " Drew Adams 2021-12-04 11:18 ` Po Lu 0 siblings, 2 replies; 111+ messages in thread From: Po Lu @ 2021-11-30 1:40 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: > It might also be called by redisplay, That is what I'm worried about, thanks. > ... it makes very little sense to me to introduce such a feature only > for the sake of pixel-wise scrolling. We should allow such a mode > with all the Emacs commands, not just in pixel-wise scrolling. And > anyway, Emacs might call scrolling commands as part of other commands, > not just because the user types C-v. Makes sense, I will work on it. ^ permalink raw reply [flat|nested] 111+ messages in thread
* RE: [External] : Re: Allowing point to be outside the window? 2021-11-30 1:40 ` Po Lu @ 2021-11-30 16:49 ` Drew Adams 2021-11-30 17:26 ` Eli Zaretskii 2021-12-04 11:18 ` Po Lu 1 sibling, 1 reply; 111+ messages in thread From: Drew Adams @ 2021-11-30 16:49 UTC (permalink / raw) To: Po Lu, Eli Zaretskii; +Cc: emacs-devel@gnu.org A probably OT question that occurred to me. Ignore if not relevant/helpful. If we add the ability (as an option) to let point be off-window, I'm guessing it might entail the risk that someone uses `C-w' and is not aware of perhaps killing a chunk of text (perhaps a big chunk). Should we maybe consider an (optional) warning message or an optional confirmation requirement? A wild guess is that other editors, which allow this off-window behavior, somehow don't have such a risk of cutting lots of text more or less silently. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: [External] : Re: Allowing point to be outside the window? 2021-11-30 16:49 ` [External] : " Drew Adams @ 2021-11-30 17:26 ` Eli Zaretskii 2021-11-30 18:10 ` Lars Ingebrigtsen 2021-11-30 23:20 ` Stefan Monnier 0 siblings, 2 replies; 111+ messages in thread From: Eli Zaretskii @ 2021-11-30 17:26 UTC (permalink / raw) To: Drew Adams; +Cc: luangruo, emacs-devel > From: Drew Adams <drew.adams@oracle.com> > CC: "emacs-devel@gnu.org" <emacs-devel@gnu.org> > Date: Tue, 30 Nov 2021 16:49:46 +0000 > > If we add the ability (as an option) to > let point be off-window, I'm guessing it > might entail the risk that someone uses > `C-w' and is not aware of perhaps killing > a chunk of text (perhaps a big chunk). > > Should we maybe consider an (optional) > warning message or an optional confirmation > requirement? I think kill commands that use point should be disabled when point is outside of the viewport. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: [External] : Re: Allowing point to be outside the window? 2021-11-30 17:26 ` Eli Zaretskii @ 2021-11-30 18:10 ` Lars Ingebrigtsen 2021-11-30 18:32 ` Eli Zaretskii ` (2 more replies) 2021-11-30 23:20 ` Stefan Monnier 1 sibling, 3 replies; 111+ messages in thread From: Lars Ingebrigtsen @ 2021-11-30 18:10 UTC (permalink / raw) To: Eli Zaretskii; +Cc: luangruo, Drew Adams, emacs-devel Eli Zaretskii <eliz@gnu.org> writes: > I think kill commands that use point should be disabled when point is > outside of the viewport. Perhaps all (well, most) commands should be disabled in this case? I.e., all commands do nothing except display point? It's not what (say) Libreoffice does, though -- if you've marked some text, scroll away with the scroll bar, and then hit DEL, it'll delete the marked text... -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: [External] : Re: Allowing point to be outside the window? 2021-11-30 18:10 ` Lars Ingebrigtsen @ 2021-11-30 18:32 ` Eli Zaretskii 2021-11-30 18:49 ` Stefan Kangas 2021-11-30 23:41 ` Daniel Martín 2 siblings, 0 replies; 111+ messages in thread From: Eli Zaretskii @ 2021-11-30 18:32 UTC (permalink / raw) To: Lars Ingebrigtsen; +Cc: luangruo, drew.adams, emacs-devel > From: Lars Ingebrigtsen <larsi@gnus.org> > Cc: Drew Adams <drew.adams@oracle.com>, luangruo@yahoo.com, > emacs-devel@gnu.org > Date: Tue, 30 Nov 2021 19:10:13 +0100 > > Eli Zaretskii <eliz@gnu.org> writes: > > > I think kill commands that use point should be disabled when point is > > outside of the viewport. > > Perhaps all (well, most) commands should be disabled in this case? > I.e., all commands do nothing except display point? I don't know. I'd need to think about this. But "all commands" sounds too many ;-) > It's not what (say) Libreoffice does, though -- if you've marked some > text, scroll away with the scroll bar, and then hit DEL, it'll delete > the marked text... Those "other applications" only support region operations on highlighted text, which avoids using (the equivalent of) point. Emacs could do that as well (but it will have to preserve point in this hypothetical mode when highlighting text with point outside of the viewport). ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: [External] : Re: Allowing point to be outside the window? 2021-11-30 18:10 ` Lars Ingebrigtsen 2021-11-30 18:32 ` Eli Zaretskii @ 2021-11-30 18:49 ` Stefan Kangas 2021-11-30 19:21 ` Eli Zaretskii 2021-11-30 23:41 ` Daniel Martín 2 siblings, 1 reply; 111+ messages in thread From: Stefan Kangas @ 2021-11-30 18:49 UTC (permalink / raw) To: Lars Ingebrigtsen, Eli Zaretskii; +Cc: luangruo, Drew Adams, emacs-devel Lars Ingebrigtsen <larsi@gnus.org> writes: > Perhaps all (well, most) commands should be disabled in this case? > I.e., all commands do nothing except display point? Why? We don't do anything like that when mark is not in the window. The benefit of this feature for me would be to be able to look around and then immediately edit where I left point/mark, as I can do in other text editors. > It's not what (say) Libreoffice does, though -- if you've marked some > text, scroll away with the scroll bar, and then hit DEL, it'll delete > the marked text... AFAIK, pretty much all graphical text editor and word processors behaves like LibreOffice in this regard. Maybe there are some exceptions, but I can't think of any. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: [External] : Re: Allowing point to be outside the window? 2021-11-30 18:49 ` Stefan Kangas @ 2021-11-30 19:21 ` Eli Zaretskii 2021-11-30 20:57 ` Drew Adams 0 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-11-30 19:21 UTC (permalink / raw) To: Stefan Kangas; +Cc: luangruo, larsi, drew.adams, emacs-devel > From: Stefan Kangas <stefankangas@gmail.com> > Date: Tue, 30 Nov 2021 10:49:06 -0800 > Cc: luangruo@yahoo.com, Drew Adams <drew.adams@oracle.com>, emacs-devel@gnu.org > > Lars Ingebrigtsen <larsi@gnus.org> writes: > > > Perhaps all (well, most) commands should be disabled in this case? > > I.e., all commands do nothing except display point? > > Why? We don't do anything like that when mark is not in the window. What if neither mark nor point are visible? Anyway, an alternative would be to warp point back into view if some editing command is invoked. ^ permalink raw reply [flat|nested] 111+ messages in thread
* RE: [External] : Re: Allowing point to be outside the window? 2021-11-30 19:21 ` Eli Zaretskii @ 2021-11-30 20:57 ` Drew Adams 0 siblings, 0 replies; 111+ messages in thread From: Drew Adams @ 2021-11-30 20:57 UTC (permalink / raw) To: Eli Zaretskii, Stefan Kangas Cc: luangruo@yahoo.com, larsi@gnus.org, emacs-devel@gnu.org My main purpose in raising this possible gotcha was just to point to it. And yes, the potential problem is wider than just `C-w'. ___ As for possible remedies - 1. A user option, to specify preferred behavior, for sure. This could even be per-command, either by way of the option value or via a command-symbol property - see below, at the end. 2. Some possible choices for the behavior: a. Do nothing special (just act, silently). b. Show a message that point is off-window. (Could also do it even for mark off-window). c. Require y/n confirmation, to act. d. Don't allow the command (raise an error). ___ For 2c, it might be good, while waiting for confirmation, to let you use a key to indicate the region in some way. Here's one way (similar to `C-x C-x' behavior): Move temporarily to point - and when repeated, move to mark, i.e., toggle between them. And highlight the region text, to make clear on which side of the boundaries the text to be operated on lies. Another possibility would be to automatically bounce to show you the off-window point location. But I think letting you do that on demand makes more sense. IOW, let me tell Emacs to show me point, before I decide whether to confirm, but also let me just confirm or not, without showing me point. ___ In any case, by default the feature should be off: no off-window point. ___ Another possibility might be to force users who want the ability to act on the region when point is off-window to use different commands for that. That is, bind particular (new) commands that allow it. This would let you, say, permit some operations but not others. You could even be able to make a _per-command_ choice like what the user-option allows. And each command that lets you act on a region when point is off-window would be disabled, by default. E.g., (put 'kill-region-maybe-offscreen 'disabled) ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: [External] : Re: Allowing point to be outside the window? 2021-11-30 18:10 ` Lars Ingebrigtsen 2021-11-30 18:32 ` Eli Zaretskii 2021-11-30 18:49 ` Stefan Kangas @ 2021-11-30 23:41 ` Daniel Martín 2021-12-01 8:30 ` martin rudalics 2 siblings, 1 reply; 111+ messages in thread From: Daniel Martín @ 2021-11-30 23:41 UTC (permalink / raw) To: Lars Ingebrigtsen; +Cc: Eli Zaretskii, luangruo, Drew Adams, emacs-devel Lars Ingebrigtsen <larsi@gnus.org> writes: > > It's not what (say) Libreoffice does, though -- if you've marked some > text, scroll away with the scroll bar, and then hit DEL, it'll delete > the marked text... It's also how other text editors that implement this feature work; the text is killed and the window is scrolled to make the point visible again. So perhaps users of this feature would not be surprised if Emacs does the same thing. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: [External] : Re: Allowing point to be outside the window? 2021-11-30 23:41 ` Daniel Martín @ 2021-12-01 8:30 ` martin rudalics 2021-12-01 9:10 ` Juri Linkov 0 siblings, 1 reply; 111+ messages in thread From: martin rudalics @ 2021-12-01 8:30 UTC (permalink / raw) To: Daniel Martín, Lars Ingebrigtsen Cc: luangruo, Eli Zaretskii, Drew Adams, emacs-devel >> It's not what (say) Libreoffice does, though -- if you've marked some >> text, scroll away with the scroll bar, and then hit DEL, it'll delete >> the marked text... > > It's also how other text editors that implement this feature work; the > text is killed and the window is scrolled to make the point visible > again. > > So perhaps users of this feature would not be surprised if Emacs does > the same thing. A GUI Emacs does that already. With emacs -Q do (setq truncate-lines t) (toggle-horizontal-scroll-bar t) C-x 3 Now put the region on say "To create", use the mouse on the horizontal scroll bar to drag that region completely out of view and type C-w. martin ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: [External] : Re: Allowing point to be outside the window? 2021-12-01 8:30 ` martin rudalics @ 2021-12-01 9:10 ` Juri Linkov 0 siblings, 0 replies; 111+ messages in thread From: Juri Linkov @ 2021-12-01 9:10 UTC (permalink / raw) To: martin rudalics Cc: emacs-devel, luangruo, Lars Ingebrigtsen, Daniel Martín, Eli Zaretskii, Drew Adams > A GUI Emacs does that already. With emacs -Q do > > (setq truncate-lines t) > (toggle-horizontal-scroll-bar t) > C-x 3 > > Now put the region on say "To create", use the mouse on the horizontal > scroll bar to drag that region completely out of view and type C-w. Interesting, it works even without the horizontal scroll bar, after typing 'C-x <' (scroll-left). But it automatically scrolls back only when using the horizontal scroll bar. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: [External] : Re: Allowing point to be outside the window? 2021-11-30 17:26 ` Eli Zaretskii 2021-11-30 18:10 ` Lars Ingebrigtsen @ 2021-11-30 23:20 ` Stefan Monnier 1 sibling, 0 replies; 111+ messages in thread From: Stefan Monnier @ 2021-11-30 23:20 UTC (permalink / raw) To: Eli Zaretskii; +Cc: Drew Adams, luangruo, emacs-devel > I think kill commands that use point should be disabled when point is > outside of the viewport. I suspect this would not be worth the trouble and could be annoying in some cases where the users know very well what they're doing. Let the users shoot themselves in the foot if they want. There's `undo` to reattach the foot anyway. Stefan ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-30 1:40 ` Po Lu 2021-11-30 16:49 ` [External] : " Drew Adams @ 2021-12-04 11:18 ` Po Lu 2021-12-04 12:55 ` Eli Zaretskii 2021-12-04 13:00 ` dick 1 sibling, 2 replies; 111+ messages in thread From: Po Lu @ 2021-12-04 11:18 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel [-- Attachment #1: Type: text/plain, Size: 743 bytes --] Po Lu <luangruo@yahoo.com> writes: > Eli Zaretskii <eliz@gnu.org> writes: > >> It might also be called by redisplay, > > That is what I'm worried about, thanks. > >> ... it makes very little sense to me to introduce such a feature only >> for the sake of pixel-wise scrolling. We should allow such a mode >> with all the Emacs commands, not just in pixel-wise scrolling. And >> anyway, Emacs might call scrolling commands as part of other commands, >> not just because the user types C-v. > > Makes sense, I will work on it. I haven't figured out most of the user level command things, but here's a patch that allows point to be outside a window. Some redisplay optimizations are disabled, but I hope to solve that soon. WDYT? Thanks. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Make-it-possible-for-point-to-appear-outside-a-windo.patch --] [-- Type: text/x-patch, Size: 13173 bytes --] From f2295fbfceff3ef0db91c9c5b9e5155fefe12697 Mon Sep 17 00:00:00 2001 From: Po Lu <luangruo@yahoo.com> Date: Sat, 4 Dec 2021 18:33:53 +0800 Subject: [PATCH] Make it possible for point to appear outside a window * src/window.h (struct window): New field `cursor_visible_p'. * src/xdisp.c (redisplay_internal, redisplay_window): Allow point to appear outside the window. (set_cursor_from_row): Set cursor_visible_p appropriately. (try_window_id) (try_cursor_movement): Disable optimization when point is allowed to be invisible. (display_and_set_cursor): Erase cursor if invisible. (try_window): Allow some things. (syms_of_xdisp) <keep-point-visible>: New variable. --- src/window.h | 4 ++ src/xdisp.c | 194 ++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 150 insertions(+), 48 deletions(-) diff --git a/src/window.h b/src/window.h index 2400c422c1..e9528ff02f 100644 --- a/src/window.h +++ b/src/window.h @@ -445,6 +445,10 @@ #define WINDOW_H_INCLUDED window. */ bool_bf suspend_auto_hscroll : 1; + /* True if the cursor is supposed to be visible in this + window. */ + bool_bf cursor_visible_p : 1; + /* Amount by which lines of this window are scrolled in y-direction (smooth scrolling). */ int vscroll; diff --git a/src/xdisp.c b/src/xdisp.c index 7ca3977200..7a0949d514 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 @@ -16989,6 +16991,8 @@ set_cursor_from_row (struct window *w, struct glyph_row *row, comes from a text property, not from an overlay. */ bool string_from_text_prop = false; + w->cursor_visible_p = false; + /* Don't even try doing anything if called for a mode-line or header-line or tab-line row, since the rest of the code isn't prepared to deal with such calamities. */ @@ -17575,6 +17579,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row, CHARPOS (this_line_start_pos) = 0; } + w->cursor_visible_p = true; return true; } @@ -18183,6 +18188,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 +18779,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 @@ -18964,34 +18975,39 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) if (w->cursor.vpos < 0) { - /* If point does not appear, try to move point so it does - appear. The desired matrix has been built above, so we - can use it here. First see if point is in invisible - text, and if so, move it to the first visible buffer - position past that. */ - struct glyph_row *r = NULL; - Lisp_Object invprop = - get_char_property_and_overlay (make_fixnum (PT), Qinvisible, - Qnil, NULL); - - if (TEXT_PROP_MEANS_INVISIBLE (invprop) != 0) + if (!keep_point_visible) + w->cursor_visible_p = false; + else { - ptrdiff_t alt_pt; - Lisp_Object invprop_end = - Fnext_single_char_property_change (make_fixnum (PT), Qinvisible, - Qnil, Qnil); + /* If point does not appear, try to move point so it does + appear. The desired matrix has been built above, so we + can use it here. First see if point is in invisible + text, and if so, move it to the first visible buffer + position past that. */ + struct glyph_row *r = NULL; + Lisp_Object invprop = + get_char_property_and_overlay (make_fixnum (PT), Qinvisible, + Qnil, NULL); + + if (TEXT_PROP_MEANS_INVISIBLE (invprop) != 0) + { + ptrdiff_t alt_pt; + Lisp_Object invprop_end = + Fnext_single_char_property_change (make_fixnum (PT), Qinvisible, + Qnil, Qnil); - if (FIXNATP (invprop_end)) - alt_pt = XFIXNAT (invprop_end); - else - alt_pt = ZV; - r = row_containing_pos (w, alt_pt, w->desired_matrix->rows, - NULL, 0); + if (FIXNATP (invprop_end)) + alt_pt = XFIXNAT (invprop_end); + else + alt_pt = ZV; + r = row_containing_pos (w, alt_pt, w->desired_matrix->rows, + NULL, 0); + } + if (r) + 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 (r) - 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 +19239,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) @@ -19253,9 +19271,12 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) clear_glyph_matrix (w->desired_matrix); } + if (!keep_point_visible) + goto maybe_try_window; + 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; @@ -19317,6 +19338,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 +19606,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 +19660,12 @@ 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_visible_p + || 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 +19876,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 +20037,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); @@ -20875,6 +20956,8 @@ #define GIVE_UP(X) return 0 row = row_containing_pos (w, PT, r0, NULL, 0); if (row) set_cursor_from_row (w, row, current_matrix, 0, 0, 0, 0); + else + w->cursor_visible_p = false; return 1; } } @@ -20915,6 +20998,8 @@ #define GIVE_UP(X) return 0 row = row_containing_pos (w, PT, r0, NULL, 0); if (row) set_cursor_from_row (w, row, current_matrix, 0, 0, 0, 0); + else + w->cursor_visible_p = false; return 2; } } @@ -21152,6 +21237,8 @@ #define GIVE_UP(X) return 0 last_unchanged_at_beg_row + 1, 0); if (row) set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0); + else + w->cursor_visible_p = false; } /* Start from first_unchanged_at_end_row looking for PT. */ @@ -21162,6 +21249,8 @@ #define GIVE_UP(X) return 0 if (row) set_cursor_from_row (w, row, w->current_matrix, delta, delta_bytes, dy, dvpos); + else + w->cursor_visible_p = false; } /* Give up if cursor was not found. */ @@ -21173,24 +21262,25 @@ #define GIVE_UP(X) return 0 } /* Don't let the cursor end in the scroll margins. */ - { - int this_scroll_margin = window_scroll_margin (w, MARGIN_IN_PIXELS); - int cursor_height = MATRIX_ROW (w->desired_matrix, w->cursor.vpos)->height; - - if ((w->cursor.y < this_scroll_margin - && 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 - + (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); - return -1; - } - } + if (w->cursor_visible_p) + { + int this_scroll_margin = window_scroll_margin (w, MARGIN_IN_PIXELS); + int cursor_height = MATRIX_ROW (w->desired_matrix, w->cursor.vpos)->height; + + if ((w->cursor.y < this_scroll_margin + && 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 + + (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); + return -1; + } + } /* Scroll the display. Do it before changing the current matrix so that xterm.c doesn't get confused about where the cursor glyph is @@ -32387,6 +32477,10 @@ display_and_set_cursor (struct window *w, bool on, && new_cursor_width != w->phys_cursor_width))) erase_phys_cursor (w); + if (!w->cursor_visible_p + || 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 @@ -35491,6 +35585,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'. */); -- 2.33.1 ^ permalink raw reply related [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-04 11:18 ` Po Lu @ 2021-12-04 12:55 ` Eli Zaretskii 2021-12-04 13:13 ` Po Lu 2021-12-04 13:00 ` dick 1 sibling, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-12-04 12:55 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Sat, 04 Dec 2021 19:18:38 +0800 > > I haven't figured out most of the user level command things, but here's > a patch that allows point to be outside a window. > > Some redisplay optimizations are disabled, but I hope to solve that > soon. > > WDYT? Thanks. This "allows point to be outside a window" in what situations? In general, it's hard to provide useful feedback without understanding the main ideas of the changes. And you didn't add any comments to help in that. So I'm left to wonder whether some changes I don't think I understand are just my misunderstanding of your ideas, or your misunderstanding of the code. So just a few random thoughts I had while reading the changes: > @@ -16989,6 +16991,8 @@ set_cursor_from_row (struct window *w, struct glyph_row *row, > comes from a text property, not from an overlay. */ > bool string_from_text_prop = false; > > + w->cursor_visible_p = false; > + > /* Don't even try doing anything if called for a mode-line or > header-line or tab-line row, since the rest of the code isn't > prepared to deal with such calamities. */ > @@ -17575,6 +17579,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row, > CHARPOS (this_line_start_pos) = 0; > } > > + w->cursor_visible_p = true; > return true; > } Shouldn't set_cursor_from_row be disabled/bypassed in this mode? And I don't understand the dance with the cursor_visible_p flag: why do you reset it at entry and set back before exiting? Isn't the value of w->cursor enough to tell whether the cursor position was computed or not? > + if (!keep_point_visible) > + goto maybe_try_window; > + > try_to_scroll: I don't understand this change. Are you forcibly trying to avoid calling try_scrolling? If so, why? That function is only loosely related to scrolling commands; in fact, if you type C-v in "emacs -Q", you will never see it called. This function is an optimization of a window's redisplay, and that is needed even in this new mode you are implementing. > + 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 (); This and the rest of this hunk is a copy of code we have elsewhere, and I'm not sure I understand why you needed that. > @@ -20875,6 +20956,8 @@ #define GIVE_UP(X) return 0 > row = row_containing_pos (w, PT, r0, NULL, 0); > if (row) > set_cursor_from_row (w, row, current_matrix, 0, 0, 0, 0); > + else > + w->cursor_visible_p = false; > return 1; > } > } > @@ -20915,6 +20998,8 @@ #define GIVE_UP(X) return 0 > row = row_containing_pos (w, PT, r0, NULL, 0); > if (row) > set_cursor_from_row (w, row, current_matrix, 0, 0, 0, 0); > + else > + w->cursor_visible_p = false; > return 2; > } > } > @@ -21152,6 +21237,8 @@ #define GIVE_UP(X) return 0 > last_unchanged_at_beg_row + 1, 0); > if (row) > set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0); > + else > + w->cursor_visible_p = false; > } > > /* Start from first_unchanged_at_end_row looking for PT. */ > @@ -21162,6 +21249,8 @@ #define GIVE_UP(X) return 0 > if (row) > set_cursor_from_row (w, row, w->current_matrix, delta, > delta_bytes, dy, dvpos); > + else > + w->cursor_visible_p = false; > } Are these really needed? why? > + if (w->cursor_visible_p) > + { > + int this_scroll_margin = window_scroll_margin (w, MARGIN_IN_PIXELS); > + int cursor_height = MATRIX_ROW (w->desired_matrix, w->cursor.vpos)->height; The condition above doesn't check the keep_point_visible flag, why? Thanks. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-04 12:55 ` Eli Zaretskii @ 2021-12-04 13:13 ` Po Lu 2021-12-04 16:24 ` Eli Zaretskii 2021-12-04 17:15 ` Eli Zaretskii 0 siblings, 2 replies; 111+ messages in thread From: Po Lu @ 2021-12-04 13:13 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: > This "allows point to be outside a window" in what situations? If you move point out of the visible area of the window (such as with `goto-char') or if you set the window start but do not force it. > In general, it's hard to provide useful feedback without understanding > the main ideas of the changes. And you didn't add any comments to > help in that. So I'm left to wonder whether some changes I don't > think I understand are just my misunderstanding of your ideas, or your > misunderstanding of the code. I will work on that, sorry. > So just a few random thoughts I had while reading the changes: > Shouldn't set_cursor_from_row be disabled/bypassed in this mode? > > And I don't understand the dance with the cursor_visible_p flag: why > do you reset it at entry and set back before exiting? Isn't the value > of w->cursor enough to tell whether the cursor position was computed > or not? The idea is that if `set_cursor_from_row' returns false (say if the cursor was not found to be in the row), w->cursor_visible will also be set to false. I don't understand why set_cursor_from_row should be disabled though: isn't it responsible for placing the cursor on the display (and as such, isn't it required for the cursor to be displayed when point is _inside_ the window?). >> + if (!keep_point_visible) >> + goto maybe_try_window; >> + >> try_to_scroll: > I don't understand this change. Are you forcibly trying to avoid > calling try_scrolling? If so, why? That function is only loosely > related to scrolling commands; in fact, if you type C-v in "emacs -Q", > you will never see it called. This function is an optimization of a > window's redisplay, and that is needed even in this new mode you are > implementing. Doesn't `try_scrolling' try to constrain point inside if it is too near the end of the window? (And isn't the optimization that tries to decide whether or not to blit the display if appropriate `scrolling_window' in dispextern.c?) >> + 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 (); > This and the rest of this hunk is a copy of code we have elsewhere, > and I'm not sure I understand why you needed that. I think I can keep it underneath the recenter label, thanks. >> @@ -20875,6 +20956,8 @@ #define GIVE_UP(X) return 0 >> row = row_containing_pos (w, PT, r0, NULL, 0); >> if (row) >> set_cursor_from_row (w, row, current_matrix, 0, 0, 0, 0); >> + else >> + w->cursor_visible_p = false; >> return 1; >> } >> } >> @@ -20915,6 +20998,8 @@ #define GIVE_UP(X) return 0 >> row = row_containing_pos (w, PT, r0, NULL, 0); >> if (row) >> set_cursor_from_row (w, row, current_matrix, 0, 0, 0, 0); >> + else >> + w->cursor_visible_p = false; >> return 2; >> } >> } >> @@ -21152,6 +21237,8 @@ #define GIVE_UP(X) return 0 >> last_unchanged_at_beg_row + 1, 0); >> if (row) >> set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0); >> + else >> + w->cursor_visible_p = false; >> } >> >> /* Start from first_unchanged_at_end_row looking for PT. */ >> @@ -21162,6 +21249,8 @@ #define GIVE_UP(X) return 0 >> if (row) >> set_cursor_from_row (w, row, w->current_matrix, delta, >> delta_bytes, dy, dvpos); >> + else >> + w->cursor_visible_p = false; >> } > Are these really needed? why? I think that's not needed anymore. I will delete it. >> + if (w->cursor_visible_p) >> + { >> + int this_scroll_margin = window_scroll_margin (w, MARGIN_IN_PIXELS); >> + int cursor_height = MATRIX_ROW (w->desired_matrix, w->cursor.vpos)->height; > The condition above doesn't check the keep_point_visible flag, why? w->cursor_visible_p should always be true if keep_point_visible is not nil by the time we get there. Thanks. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-04 13:13 ` Po Lu @ 2021-12-04 16:24 ` Eli Zaretskii 2021-12-05 0:40 ` Po Lu 2021-12-04 17:15 ` Eli Zaretskii 1 sibling, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-12-04 16:24 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Sat, 04 Dec 2021 21:13:40 +0800 > > > This "allows point to be outside a window" in what situations? > > If you move point out of the visible area of the window (such as with > `goto-char') or if you set the window start but do not force it. Which commands did you try in addition to goto-char? What about scrolling commands? > > Shouldn't set_cursor_from_row be disabled/bypassed in this mode? > > > > And I don't understand the dance with the cursor_visible_p flag: why > > do you reset it at entry and set back before exiting? Isn't the value > > of w->cursor enough to tell whether the cursor position was computed > > or not? > > The idea is that if `set_cursor_from_row' returns false (say if the > cursor was not found to be in the row), w->cursor_visible will also be > set to false. But you are just wasting cycles that way. When it is known that point is outside of the window, that function will end up being called for every screen line we lay out. Instead, just set the result without calling it in those cases. > I don't understand why set_cursor_from_row should be disabled though: > isn't it responsible for placing the cursor on the display (and as such, > isn't it required for the cursor to be displayed when point is _inside_ > the window?). Yes. I meant when you know that point is outside of the window. > > I don't understand this change. Are you forcibly trying to avoid > > calling try_scrolling? If so, why? That function is only loosely > > related to scrolling commands; in fact, if you type C-v in "emacs -Q", > > you will never see it called. This function is an optimization of a > > window's redisplay, and that is needed even in this new mode you are > > implementing. > > Doesn't `try_scrolling' try to constrain point inside if it is too near > the end of the window? Among other things, yes. But its main purpose is not to move point, it's to find a suitable window-start position. > (And isn't the optimization that tries to decide whether or not to > blit the display if appropriate `scrolling_window' in dispextern.c?) scrolling_window belongs to the second phase of a redisplay cycle, where we actually deliver glyphs to the glass. try_scrolling is from the first phase, where we decide what should be on the glass. In any case, both try_scrolling and scrolling_window are not about bringing point back into view, they are about redrawing the window so that it correctly reflects the buffer contents. So these functions cannot and shouldn't be bypassed, even in this mode. > > The condition above doesn't check the keep_point_visible flag, why? > > w->cursor_visible_p should always be true if keep_point_visible is not > nil by the time we get there. There should be a comment there about this, and perhaps also an assertion. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-04 16:24 ` Eli Zaretskii @ 2021-12-05 0:40 ` Po Lu 0 siblings, 0 replies; 111+ messages in thread From: Po Lu @ 2021-12-05 0:40 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: > Which commands did you try in addition to goto-char? What about > scrolling commands? I haven't worked on any of the scrolling commands yet: they still keep point inside the window. >> The idea is that if `set_cursor_from_row' returns false (say if the >> cursor was not found to be in the row), w->cursor_visible will also be >> set to false. > But you are just wasting cycles that way. When it is known that point > is outside of the window, that function will end up being called for > every screen line we lay out. Instead, just set the result without > calling it in those cases. >> I don't understand why set_cursor_from_row should be disabled though: >> isn't it responsible for placing the cursor on the display (and as such, >> isn't it required for the cursor to be displayed when point is _inside_ >> the window?). > Yes. I meant when you know that point is outside of the window. Thanks, I understand your point now. >> Doesn't `try_scrolling' try to constrain point inside if it is too near >> the end of the window? > Among other things, yes. But its main purpose is not to move point, > it's to find a suitable window-start position. Thanks. >> (And isn't the optimization that tries to decide whether or not to >> blit the display if appropriate `scrolling_window' in dispextern.c?) > scrolling_window belongs to the second phase of a redisplay cycle, > where we actually deliver glyphs to the glass. try_scrolling is from > the first phase, where we decide what should be on the glass. > > In any case, both try_scrolling and scrolling_window are not about > bringing point back into view, they are about redrawing the window so > that it correctly reflects the buffer contents. So these functions > cannot and shouldn't be bypassed, even in this mode. > >> > The condition above doesn't check the keep_point_visible flag, why? >> w->cursor_visible_p should always be true if keep_point_visible is not >> nil by the time we get there. > There should be a comment there about this, and perhaps also an > assertion. Okay, I will do that. Thanks. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-04 13:13 ` Po Lu 2021-12-04 16:24 ` Eli Zaretskii @ 2021-12-04 17:15 ` Eli Zaretskii 2021-12-05 0:45 ` Po Lu 1 sibling, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-12-04 17:15 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Sat, 04 Dec 2021 21:13:40 +0800 > > Eli Zaretskii <eliz@gnu.org> writes: > > > In general, it's hard to provide useful feedback without understanding > > the main ideas of the changes. And you didn't add any comments to > > help in that. So I'm left to wonder whether some changes I don't > > think I understand are just my misunderstanding of your ideas, or your > > misunderstanding of the code. > > I will work on that, sorry. Btw, one issue that I couldn't figure out from reading the patch is how do you intend to distinguish between point going out of the viewport by an explicit user command (which AFAIU is what we want to support in this new mode), and point going out of the viewport for some other reason, for example text insertion before point? Specifically, the bother is this: if we just disable/bypass all the places where Emacs brings point back into the window, we could find point outside of the window without the user meaning that to happen, and the disabled/bypassed code will then leave point invisible. So I think a single variable set by the user once and globally is not enough to control the changes in the display code to support this mode. We need some variable that is per window and is set dynamically depending on what caused point to go out of the viewport. This will quite naturally lead to defining the command that we will allow to create such a situation, because only those commands will be able to set that dynamic variable, and only for a window where those commands were invoked. (I guess some of the scrolling commands will be in that group.) ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-04 17:15 ` Eli Zaretskii @ 2021-12-05 0:45 ` Po Lu 2021-12-05 9:03 ` Eli Zaretskii 0 siblings, 1 reply; 111+ messages in thread From: Po Lu @ 2021-12-05 0:45 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: > Btw, one issue that I couldn't figure out from reading the patch is > how do you intend to distinguish between point going out of the > viewport by an explicit user command (which AFAIU is what we want to > support in this new mode), and point going out of the viewport for > some other reason, for example text insertion before point? > Specifically, the bother is this: if we just disable/bypass all the > places where Emacs brings point back into the window, we could find > point outside of the window without the user meaning that to happen, > and the disabled/bypassed code will then leave point invisible. Hmm, how about not allowing point to _move_ out of the window, instead only allowing window start to move so that point becomes invisible? For instance, we could enable the code that scrolls the window to follow point if PT != w->point (if that makes sense). ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-05 0:45 ` Po Lu @ 2021-12-05 9:03 ` Eli Zaretskii 2021-12-06 2:11 ` Po Lu 0 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-12-05 9:03 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Sun, 05 Dec 2021 08:45:14 +0800 > > Eli Zaretskii <eliz@gnu.org> writes: > > > Btw, one issue that I couldn't figure out from reading the patch is > > how do you intend to distinguish between point going out of the > > viewport by an explicit user command (which AFAIU is what we want to > > support in this new mode), and point going out of the viewport for > > some other reason, for example text insertion before point? > > Specifically, the bother is this: if we just disable/bypass all the > > places where Emacs brings point back into the window, we could find > > point outside of the window without the user meaning that to happen, > > and the disabled/bypassed code will then leave point invisible. > > Hmm, how about not allowing point to _move_ out of the window, instead > only allowing window start to move so that point becomes invisible? 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. > 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)? ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-05 9:03 ` Eli Zaretskii @ 2021-12-06 2:11 ` Po Lu 2021-12-06 14:13 ` Eli Zaretskii 2021-12-09 11:45 ` Eli Zaretskii 0 siblings, 2 replies; 111+ messages in thread From: Po Lu @ 2021-12-06 2:11 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel [-- Attachment #1: Type: text/plain, Size: 1240 bytes --] Eli Zaretskii <eliz@gnu.org> 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. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: diff.diff --] [-- Type: text/x-patch, Size: 22133 bytes --] 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'. */); [-- Attachment #3: Type: text/plain, Size: 9 bytes --] Thanks. ^ permalink raw reply related [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-06 2:11 ` Po Lu @ 2021-12-06 14:13 ` Eli Zaretskii 2021-12-07 2:18 ` Po Lu 2021-12-09 11:45 ` Eli Zaretskii 1 sibling, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-12-06 14:13 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Mon, 06 Dec 2021 10:11:47 +0800 > > > 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. Again, what do you mean by "start is forced"? Emacs sometimes forces the window-start upon itself, you can clearly see that in the code. And if point is outside of the window, recentering makes no sense anyway, because there's nothing to recenter about, there's no point of reference for it. > > 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. "Not a problem" because point will be brought back into the window before pasting? But is that what users want? > 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. Thanks, I will look into this later. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-06 14:13 ` Eli Zaretskii @ 2021-12-07 2:18 ` Po Lu 2021-12-07 13:42 ` Eli Zaretskii 0 siblings, 1 reply; 111+ messages in thread From: Po Lu @ 2021-12-07 2:18 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: > Again, what do you mean by "start is forced"? Emacs sometimes forces > the window-start upon itself, you can clearly see that in the code. Whenever w->force_start is true. > And if point is outside of the window, recentering makes no sense > anyway, because there's nothing to recenter about, there's no point of > reference for it. The window start is moved to a suitable location which will cause point to be displayed in the center of the screen. If that isn't possible, the closest location to that is set as window start. > "not a problem" because point will be brought back into the window > before pasting? But is that what users want? Yes, that's what users want. > Thanks, I will look into this later. Thanks. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-07 2:18 ` Po Lu @ 2021-12-07 13:42 ` Eli Zaretskii 2021-12-08 1:17 ` Po Lu 0 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-12-07 13:42 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Tue, 07 Dec 2021 10:18:37 +0800 > > Eli Zaretskii <eliz@gnu.org> writes: > > > Again, what do you mean by "start is forced"? Emacs sometimes forces > > the window-start upon itself, you can clearly see that in the code. > > Whenever w->force_start is true. This is sometimes set for Emacs itself, regardless of the user commands. So all such uses should be audited. > > And if point is outside of the window, recentering makes no sense > > anyway, because there's nothing to recenter about, there's no point of > > reference for it. > > The window start is moved to a suitable location which will cause point > to be displayed in the center of the screen. > > If that isn't possible, the closest location to that is set as window > start. Yes. I'm saying that if point is allowed to be outside of the window during some redisplay cycle, we'd need a different criteria for when and how to change w->start. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-07 13:42 ` Eli Zaretskii @ 2021-12-08 1:17 ` Po Lu 2021-12-08 17:14 ` Eli Zaretskii 0 siblings, 1 reply; 111+ messages in thread From: Po Lu @ 2021-12-08 1:17 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: > This is sometimes set for Emacs itself, regardless of the user > commands. So all such uses should be audited. Most of the uses seem fine to me (mostly in the scrolling commands, which I've already modified as appropriate, and also when the cursor is obscured and make-cursor-line-fully-visible is non-nil), but I have one question about the following code: /* We used to issue a CHECK_MARGINS argument to try_window here, but this causes scrolling to fail when point begins inside the scroll margin (bug#148) -- cyd */ clear_glyph_matrix (w->desired_matrix); if (!try_window (window, startp, 0)) { w->force_start = true; clear_glyph_matrix (w->desired_matrix); goto need_larger_matrices; } Why does it have to force start? Doesn't need_larger_matrices take care of resizing the matrix when, for instance, fonts change? Thanks. > Yes. I'm saying that if point is allowed to be outside of the window > during some redisplay cycle, we'd need a different criteria for when > and how to change w->start. Why is that so (for the "how to change w->start" part)? Making point display in the center of the screen in that case will be intuitive for most users. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-08 1:17 ` Po Lu @ 2021-12-08 17:14 ` Eli Zaretskii 2021-12-09 0:23 ` Po Lu 0 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-12-08 17:14 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Wed, 08 Dec 2021 09:17:13 +0800 > > /* We used to issue a CHECK_MARGINS argument to try_window here, > but this causes scrolling to fail when point begins inside > the scroll margin (bug#148) -- cyd */ > clear_glyph_matrix (w->desired_matrix); > if (!try_window (window, startp, 0)) > { > w->force_start = true; > clear_glyph_matrix (w->desired_matrix); > goto need_larger_matrices; > } > > Why does it have to force start? Because the place for the window-start was given to us (this code is under the 'if (w->force_start)' condition), but we've reset the flag after checking the condition, so now we are putting the flag back, for the next redisplay cycle -- since we are abandoning this cycle. > Doesn't need_larger_matrices take care of resizing the matrix when, > for instance, fonts change? need_larger_matrices indeed resizes the glyph matrices, after aborting the redisplay cycle with the old matrices, but that doesn't mean that window-start is invalid, it just means the previous glyph matrices were not large enough, e.g., because some part of the displayed text now has a different face that uses a smaller font. Basically, the strategy of redisplay_window, after some initial bookkeeping, is to go through a series of steps, whereby if a step succeeds, we are done, otherwise we go to the next step. The steps are: . if nothing's changed except point, and point is still inside the same window, no need to do anything except redisplay the cursor; . try using the window-start that someone else told us to use . try using the same window-start as the previous redisplay, reusing as much of the current glyph matrix as possible . try using the same window-start as the previous redisplay, after correcting it in small ways (like, for example, to move point out of the scroll margin) . recompute the window-start anew using point as the reference . in each case, redisplay the parts of the window using the window-start we found So, as you see, a lot of the processing is dedicated to finding a good window-start point, which is why if someone told us where to put it, we prefer to stick to that. Besides, that someone could be the user via one of the scroll commands, and in that case the window-start we were given is mandatory. > > Yes. I'm saying that if point is allowed to be outside of the window > > during some redisplay cycle, we'd need a different criteria for when > > and how to change w->start. > > Why is that so (for the "how to change w->start" part)? Making point > display in the center of the screen in that case will be intuitive for > most users. That's not what I had in mind. What I had in mind was the situation where point is outside of the window, and the portion of the buffer shown in the window changes due to something that Emacs does. If you are saying that in all such situation we will bring point back into the window, then my concern is addressed; but if not, we will not be able to use the final fallback of recentering the window around point, because that would move the window instead of redrawing the visible portion of the buffer. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-08 17:14 ` Eli Zaretskii @ 2021-12-09 0:23 ` Po Lu 2021-12-09 8:02 ` Eli Zaretskii 0 siblings, 1 reply; 111+ messages in thread From: Po Lu @ 2021-12-09 0:23 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: >> From: Po Lu <luangruo@yahoo.com> >> Cc: emacs-devel@gnu.org >> Date: Wed, 08 Dec 2021 09:17:13 +0800 >> >> /* We used to issue a CHECK_MARGINS argument to try_window here, >> but this causes scrolling to fail when point begins inside >> the scroll margin (bug#148) -- cyd */ >> clear_glyph_matrix (w->desired_matrix); >> if (!try_window (window, startp, 0)) >> { >> w->force_start = true; >> clear_glyph_matrix (w->desired_matrix); >> goto need_larger_matrices; >> } >> >> Why does it have to force start? > > Because the place for the window-start was given to us (this code is > under the 'if (w->force_start)' condition), but we've reset the flag > after checking the condition, so now we are putting the flag back, for > the next redisplay cycle -- since we are abandoning this cycle. > >> Doesn't need_larger_matrices take care of resizing the matrix when, >> for instance, fonts change? > > need_larger_matrices indeed resizes the glyph matrices, after aborting > the redisplay cycle with the old matrices, but that doesn't mean that > window-start is invalid, it just means the previous glyph matrices > were not large enough, e.g., because some part of the displayed text > now has a different face that uses a smaller font. > > Basically, the strategy of redisplay_window, after some initial > bookkeeping, is to go through a series of steps, whereby if a step > succeeds, we are done, otherwise we go to the next step. The steps > are: > > . if nothing's changed except point, and point is still inside the > same window, no need to do anything except redisplay the cursor; > . try using the window-start that someone else told us to use > . try using the same window-start as the previous redisplay, reusing > as much of the current glyph matrix as possible > . try using the same window-start as the previous redisplay, after > correcting it in small ways (like, for example, to move point out > of the scroll margin) > . recompute the window-start anew using point as the reference > . in each case, redisplay the parts of the window using the > window-start we found > > So, as you see, a lot of the processing is dedicated to finding a good > window-start point, which is why if someone told us where to put it, > we prefer to stick to that. Besides, that someone could be the user > via one of the scroll commands, and in that case the window-start we > were given is mandatory. > That's not what I had in mind. What I had in mind was the situation > where point is outside of the window, and the portion of the buffer > shown in the window changes due to something that Emacs does. If you > are saying that in all such situation we will bring point back into > the window, then my concern is addressed; but if not, we will not be > able to use the final fallback of recentering the window around point, > because that would move the window instead of redrawing the visible > portion of the buffer. If point doesn't change, but something in the visible part of the buffer does, that part will be redrawn, keeping point and window start in their original locations. But maybe we should make it move point back into the window under this situation. WDYT? ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-09 0:23 ` Po Lu @ 2021-12-09 8:02 ` Eli Zaretskii 2021-12-09 9:22 ` Po Lu 2021-12-25 6:45 ` Po Lu 0 siblings, 2 replies; 111+ messages in thread From: Eli Zaretskii @ 2021-12-09 8:02 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Thu, 09 Dec 2021 08:23:28 +0800 > > Eli Zaretskii <eliz@gnu.org> writes: > > > That's not what I had in mind. What I had in mind was the situation > > where point is outside of the window, and the portion of the buffer > > shown in the window changes due to something that Emacs does. If you > > are saying that in all such situation we will bring point back into > > the window, then my concern is addressed; but if not, we will not be > > able to use the final fallback of recentering the window around point, > > because that would move the window instead of redrawing the visible > > portion of the buffer. > > If point doesn't change, but something in the visible part of the buffer > does, that part will be redrawn, keeping point and window start in their > original locations. I'm saying that if some part of the window needs to be redrawn, "the last line of defense" we have there now, which is to center point in the window, will not necessarily be available, and we need to do something else if all the other methods in redisplay_window fail to find a good window-start point. > But maybe we should make it move point back into the window under this > situation. WDYT? I already provided an example where this could not be what users expect: some command inserts text before the window-start, which causes the text shown in the window to move if we use the same window-start position. Now, window-start is a marker, so theoretically we could use the same marker with the buffer position updated due to the insertion, in which case the stuff displayed in the window may stay unchanged. But is this what users will expect? And if this is not what users expect, i.e. if we will need to recompute window-start anew in that case, we cannot use the "recenter around point" fallback. Likewise with bringing point into the view: will this be what users expect in the described situation? ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-09 8:02 ` Eli Zaretskii @ 2021-12-09 9:22 ` Po Lu 2021-12-09 10:02 ` Eli Zaretskii 2021-12-25 6:45 ` Po Lu 1 sibling, 1 reply; 111+ messages in thread From: Po Lu @ 2021-12-09 9:22 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: > Now, window-start is a marker, so theoretically we could use the same > marker with the buffer position updated due to the insertion, in which > case the stuff displayed in the window may stay unchanged. I don't know, because I can't think of what other programs do in this situation, as they generally don't have commands that insert text outside the visible area. Perhaps someone else can chime in at this point. > But is this what users will expect? And if this is not what users > expect, i.e. if we will need to recompute window-start anew in that > case, we cannot use the "recenter around point" fallback. Likewise > with bringing point into the view: will this be what users expect in > the described situation? I see what you mean now. We could have a user option that says one of the following: - If the text before the window start changes, use the current value of the window start marker. - If the text before the window start changes, bring point into view. - If the text before the window start changes, try to move window start so that point appears in the middle of the window. If that is not possible, move window start to the location that will cause point to appear closest to the middle of the window. BTW, how would you recommend to determine inside redisplay whether the text before the start of the window has changed? Thanks. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-09 9:22 ` Po Lu @ 2021-12-09 10:02 ` Eli Zaretskii 0 siblings, 0 replies; 111+ messages in thread From: Eli Zaretskii @ 2021-12-09 10:02 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Thu, 09 Dec 2021 17:22:52 +0800 > > BTW, how would you recommend to determine inside redisplay whether the > text before the start of the window has changed? We already do that when needed: /* The position of the first and last character that has been changed. */ first_changed_charpos = BEG + BEG_UNCHANGED; last_changed_charpos = Z - END_UNCHANGED; /* If window starts after a line end, and the last change is in front of that newline, then changes don't affect the display. This case happens with stealth-fontification. Note that although the display is unchanged, glyph positions in the matrix have to be adjusted, of course. */ row = MATRIX_ROW (w->current_matrix, w->window_end_vpos); if (MATRIX_ROW_DISPLAYS_TEXT_P (row) && ((last_changed_charpos < CHARPOS (start) && CHARPOS (start) == BEGV) || (last_changed_charpos < CHARPOS (start) - 1 && FETCH_BYTE (BYTEPOS (start) - 1) == '\n'))) The BEG_UNCHANGED and END_UNCHANGED positions are tracked by all the functions that modify the buffer. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-09 8:02 ` Eli Zaretskii 2021-12-09 9:22 ` Po Lu @ 2021-12-25 6:45 ` Po Lu 2021-12-25 7:07 ` Eli Zaretskii 2022-02-06 7:22 ` Po Lu 1 sibling, 2 replies; 111+ messages in thread From: Po Lu @ 2021-12-25 6:45 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: > I already provided an example where this could not be what users > expect: some command inserts text before the window-start, which > causes the text shown in the window to move if we use the same > window-start position. Now, window-start is a marker, so > theoretically we could use the same marker with the buffer position > updated due to the insertion, in which case the stuff displayed in the > window may stay unchanged. > But is this what users will expect? And if this is not what users > expect, i.e. if we will need to recompute window-start anew in that > case, we cannot use the "recenter around point" fallback. Likewise > with bringing point into the view: will this be what users expect in > the described situation? To be completely clear, the "recenter around point" fallback you allude to is the code under the `recenter' label in `redisplay_window', correct? Please forgive me if this has been answered before, but I haven't been working on this in a while, and my memory is already getting rusty. Thanks. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-25 6:45 ` Po Lu @ 2021-12-25 7:07 ` Eli Zaretskii 2022-02-06 7:22 ` Po Lu 1 sibling, 0 replies; 111+ messages in thread From: Eli Zaretskii @ 2021-12-25 7:07 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Sat, 25 Dec 2021 14:45:59 +0800 > > Eli Zaretskii <eliz@gnu.org> writes: > > > I already provided an example where this could not be what users > > expect: some command inserts text before the window-start, which > > causes the text shown in the window to move if we use the same > > window-start position. Now, window-start is a marker, so > > theoretically we could use the same marker with the buffer position > > updated due to the insertion, in which case the stuff displayed in the > > window may stay unchanged. > > > But is this what users will expect? And if this is not what users > > expect, i.e. if we will need to recompute window-start anew in that > > case, we cannot use the "recenter around point" fallback. Likewise > > with bringing point into the view: will this be what users expect in > > the described situation? > > To be completely clear, the "recenter around point" fallback you allude > to is the code under the `recenter' label in `redisplay_window', > correct? Yes. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-25 6:45 ` Po Lu 2021-12-25 7:07 ` Eli Zaretskii @ 2022-02-06 7:22 ` Po Lu 2022-02-06 11:34 ` Eli Zaretskii 1 sibling, 1 reply; 111+ messages in thread From: Po Lu @ 2022-02-06 7:22 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel [-- Attachment #1: Type: text/plain, Size: 484 bytes --] Po Lu <luangruo@yahoo.com> writes: > To be completely clear, the "recenter around point" fallback you allude > to is the code under the `recenter' label in `redisplay_window', > correct? > > Please forgive me if this has been answered before, but I haven't been > working on this in a while, and my memory is already getting rusty. > > Thanks. How about this: we recenter around the position of the first modified character? Point isn't moved at all during that process. Thanks. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: test.diff --] [-- Type: text/x-patch, Size: 29096 bytes --] diff --git a/doc/emacs/display.texi b/doc/emacs/display.texi index 4fcd2a3f7d..fabb53bb3d 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 6c5aeacb7b..a696a1dffc 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -392,6 +392,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/lisp/pixel-scroll.el b/lisp/pixel-scroll.el index 54724ca328..8f07e58428 100644 --- a/lisp/pixel-scroll.el +++ b/lisp/pixel-scroll.el @@ -507,20 +507,22 @@ pixel-scroll-precision-scroll-down-page (edges (window-edges nil t)) (usable-height (- (nth 3 edges) (nth 1 edges))) - (next-pos (save-excursion - (goto-char desired-start) - (when (zerop (vertical-motion (1+ scroll-margin))) - (set-window-start nil desired-start) - (signal 'end-of-buffer nil)) - (while (when-let ((posn (posn-at-point))) - (< (cdr (posn-x-y posn)) delta)) - (when (zerop (vertical-motion 1)) + (next-pos (when keep-point-visible + (save-excursion + (goto-char desired-start) + (when (zerop (vertical-motion (1+ scroll-margin))) (set-window-start nil desired-start) - (signal 'end-of-buffer nil))) - (point))) + (signal 'end-of-buffer nil)) + (while (when-let ((posn (posn-at-point))) + (< (cdr (posn-x-y posn)) delta)) + (when (zerop (vertical-motion 1)) + (set-window-start nil desired-start) + (signal 'end-of-buffer nil))) + (point)))) (scroll-preserve-screen-position nil) (auto-window-vscroll nil)) - (when (and (or (< (point) next-pos)) + (when (and keep-point-visible + (or (< (point) next-pos)) (let ((pos-visibility (pos-visible-in-window-p next-pos nil t))) (and pos-visibility (or (eq (length pos-visibility) 2) @@ -554,15 +556,17 @@ pixel-scroll-precision-scroll-up-page (max-y (- (nth 3 edges) (nth 1 edges))) (usable-height max-y) - (posn (posn-at-x-y 0 (+ (window-tab-line-height) - (window-header-line-height) - (- max-y delta)))) - (point (posn-point posn)) - (up-point (save-excursion - (goto-char point) - (vertical-motion (- (1+ scroll-margin))) - (point)))) - (when (> (point) up-point) + (posn (when keep-point-visible + (posn-at-x-y 0 (+ (window-tab-line-height) + (window-header-line-height) + (- max-y delta))))) + (point (when posn (posn-point posn))) + (up-point (when point + (save-excursion + (goto-char point) + (vertical-motion (- (1+ scroll-margin))) + (point))))) + (when (and keep-point-visible (> (point) up-point)) (when (let ((pos-visible (pos-visible-in-window-p up-point nil t))) (or (eq (length pos-visible) 2) (when-let* ((posn (posn-at-point up-point)) diff --git a/src/window.c b/src/window.c index 449f2b0cc5..b2fd76652f 100644 --- a/src/window.c +++ b/src/window.c @@ -5578,7 +5578,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: @@ -5659,8 +5660,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; } } @@ -5844,8 +5846,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, @@ -5857,7 +5860,7 @@ 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; @@ -5873,142 +5876,159 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror) || EQ (Vscroll_preserve_screen_position, Qt))) /* We found PT at a legitimate height. Leave it alone. */ ; - else + 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) @@ -8513,6 +8533,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 db9bc512a9..1f882f6996 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -16224,6 +16224,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 @@ -17874,6 +17876,9 @@ try_scrolling (Lisp_Object window, bool just_this_one_p, else scroll_max = 0; + if (!keep_point_visible && PT == w->last_point) + goto out; + too_near_end: /* Decide whether to scroll down. */ @@ -18110,6 +18115,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)) @@ -18844,6 +18851,9 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) int frame_line_height, margin; bool use_desired_matrix; void *itdata = NULL; + bool need_recenter_even_if_point_can_be_invisible = false; + ptrdiff_t that_recentering_position; + ptrdiff_t that_recentering_byte; SET_TEXT_POS (lpoint, PT, PT_BYTE); opoint = lpoint; @@ -19022,6 +19032,36 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) SET_TEXT_POS_FROM_MARKER (startp, w->start); + if (!keep_point_visible && window_outdated (w)) + { + /* If some text changed between window start, then recenter the + display around the first character that changed, to avoid + confusing the user by not updating the display to reflect the + changes. */ + ptrdiff_t last_changed_charpos, first_changed_charpos; + + /* Make sure beg_unchanged and end_unchanged are up to date. Do it + only if buffer has really changed. The reason is that the gap is + initially at Z for freshly visited files. The code below would + set end_unchanged to 0 in that case. */ + if (GPT - BEG < BEG_UNCHANGED) + BEG_UNCHANGED = GPT - BEG; + if (Z - GPT < END_UNCHANGED) + END_UNCHANGED = Z - GPT; + + /* The position of the first and last character that has been changed. */ + first_changed_charpos = BEG + BEG_UNCHANGED; + last_changed_charpos = Z - END_UNCHANGED; + + if (last_changed_charpos < CHARPOS (startp)) + { + that_recentering_position = first_changed_charpos; + that_recentering_byte = buf_charpos_to_bytepos (current_buffer, + first_changed_charpos); + need_recenter_even_if_point_can_be_invisible = true; + } + } + /* If someone specified a new starting point but did not insist, check whether it can be used. */ if ((w->optional_new_start || window_frozen_p (w)) @@ -19146,6 +19186,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)) @@ -19393,10 +19434,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) @@ -19425,7 +19468,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; @@ -19471,6 +19514,13 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) } } + if (!keep_point_visible + && !need_recenter_even_if_point_can_be_invisible) + { + if (PT == w->last_point) + goto maybe_try_window; + } + /* Finally, just choose a place to start which positions point according to user preferences. */ @@ -19484,9 +19534,16 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) if (!buffer_unchanged_p) w->base_line_number = 0; - /* Determine the window start relative to point. */ - init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID); + /* Determine the window start relative to where we want to recenter + to. */ + + if (need_recenter_even_if_point_can_be_invisible) + init_iterator (&it, w, that_recentering_position, + that_recentering_byte, NULL, DEFAULT_FACE_ID); + else + 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); @@ -19513,7 +19570,9 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) margin_pos = IT_CHARPOS (it1); RESTORE_IT (&it, &it, it1data); } - scrolling_up = PT > margin_pos; + scrolling_up = (need_recenter_even_if_point_can_be_invisible + ? that_recentering_position + : PT) > margin_pos; aggressive = scrolling_up ? BVAR (current_buffer, scroll_up_aggressively) @@ -19754,6 +19813,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: @@ -19761,6 +19867,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 @@ -28638,6 +28749,7 @@ fill_composite_glyph_string (struct glyph_string *s, struct face *base_face, if (s->hl == DRAW_MOUSE_FACE || (s->hl == DRAW_CURSOR + && s->w->phys_cursor.vpos != -1 && MATRIX_ROW (s->w->current_matrix, s->w->phys_cursor.vpos)->mouse_face_p && cursor_in_mouse_face_p (s->w))) @@ -28690,6 +28802,7 @@ fill_gstring_glyph_string (struct glyph_string *s, int face_id, s->cmp_to = glyph->slice.cmp.to + 1; if (s->hl == DRAW_MOUSE_FACE || (s->hl == DRAW_CURSOR + && s->w->phys_cursor.vpos != -1 && MATRIX_ROW (s->w->current_matrix, s->w->phys_cursor.vpos)->mouse_face_p && cursor_in_mouse_face_p (s->w))) @@ -28759,6 +28872,7 @@ fill_glyphless_glyph_string (struct glyph_string *s, int face_id, s->font = s->face->font ? s->face->font : FRAME_FONT (s->f); if (s->hl == DRAW_MOUSE_FACE || (s->hl == DRAW_CURSOR + && s->w->phys_cursor.vpos != -1 && MATRIX_ROW (s->w->current_matrix, s->w->phys_cursor.vpos)->mouse_face_p && cursor_in_mouse_face_p (s->w))) @@ -28834,6 +28948,7 @@ fill_glyph_string (struct glyph_string *s, int face_id, if (s->hl == DRAW_MOUSE_FACE || (s->hl == DRAW_CURSOR + && s->w->phys_cursor.vpos != -1 && MATRIX_ROW (s->w->current_matrix, s->w->phys_cursor.vpos)->mouse_face_p && cursor_in_mouse_face_p (s->w))) @@ -28879,6 +28994,7 @@ fill_image_glyph_string (struct glyph_string *s) s->font = s->face->font; if (s->hl == DRAW_MOUSE_FACE || (s->hl == DRAW_CURSOR + && s->w->phys_cursor.vpos != -1 && MATRIX_ROW (s->w->current_matrix, s->w->phys_cursor.vpos)->mouse_face_p && cursor_in_mouse_face_p (s->w))) @@ -28905,6 +29021,7 @@ fill_xwidget_glyph_string (struct glyph_string *s) s->font = s->face->font; if (s->hl == DRAW_MOUSE_FACE || (s->hl == DRAW_CURSOR + && s->w->phys_cursor.vpos != -1 && MATRIX_ROW (s->w->current_matrix, s->w->phys_cursor.vpos)->mouse_face_p && cursor_in_mouse_face_p (s->w))) @@ -28942,6 +29059,7 @@ fill_stretch_glyph_string (struct glyph_string *s, int start, int end) s->font = s->face->font; if (s->hl == DRAW_MOUSE_FACE || (s->hl == DRAW_CURSOR + && s->w->phys_cursor.vpos != -1 && MATRIX_ROW (s->w->current_matrix, s->w->phys_cursor.vpos)->mouse_face_p && cursor_in_mouse_face_p (s->w))) @@ -29231,6 +29349,7 @@ set_glyph_string_background_width (struct glyph_string *s, int start, int last_x #ifdef HAVE_WINDOW_SYSTEM if (FRAME_WINDOW_P (s->f) && s->hl == DRAW_CURSOR + && s->w->phys_cursor.vpos != -1 && MATRIX_ROW (s->w->current_matrix, s->w->phys_cursor.vpos)->mouse_face_p && cursor_in_mouse_face_p (s->w)) @@ -32608,6 +32727,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 @@ -32968,6 +33090,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. */ @@ -35717,6 +35842,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'. */); ^ permalink raw reply related [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2022-02-06 7:22 ` Po Lu @ 2022-02-06 11:34 ` Eli Zaretskii 2022-02-06 11:46 ` Po Lu 0 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2022-02-06 11:34 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Sun, 06 Feb 2022 15:22:57 +0800 > > Po Lu <luangruo@yahoo.com> writes: > > > To be completely clear, the "recenter around point" fallback you allude > > to is the code under the `recenter' label in `redisplay_window', > > correct? > > > > Please forgive me if this has been answered before, but I haven't been > > working on this in a while, and my memory is already getting rusty. > > > > Thanks. > > How about this: we recenter around the position of the first modified > character? Point isn't moved at all during that process. It's very hard to keep a discussion with such long pauses. I don't even remember what we were discussing the last time and what issues remained unresolved. > +@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. Why do we need 2 flags? Are they indeed orthogonal, or can we have a single variable (perhaps with more than 2 states)? > +** 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. This is waaaay too terse for such a significant change... > --- a/lisp/pixel-scroll.el > +++ b/lisp/pixel-scroll.el Why do we need to have changes in pixel-scroll.el be part of this changeset? It makes the changes harder to review, and is not really related to the changes in the display code. > --- a/src/window.c > +++ b/src/window.c > @@ -5578,7 +5578,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) Don't you need to test keep_point_visible as well here? If not, why not? > @@ -5659,8 +5660,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; Should the logic of whether and how to obey the force_start flag be confined to the display code, instead of having part of it here? What does it mean when you set the w->start point, but do NOT set the w->force_start flag? > @@ -5844,8 +5846,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; Same here. > @@ -5857,7 +5860,7 @@ 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) This and the rest of changes in window_scroll_pixel_based are impossible to review: you replaced the "n > 0" condition with a different one, and now the rest of the diffs are completely unreadable. I also don't understand how come the exact same code which was previously run only for n > 0 is now run for any value of 'n', and _by_default_ (since scroll_move_point is non-zero by default)? How can that be TRT?? > + if (!keep_point_visible && window_outdated (w)) > + { > + /* If some text changed between window start, then recenter the > + display around the first character that changed, to avoid > + confusing the user by not updating the display to reflect the > + changes. */ > + ptrdiff_t last_changed_charpos, first_changed_charpos; > + > + /* Make sure beg_unchanged and end_unchanged are up to date. Do it > + only if buffer has really changed. The reason is that the gap is > + initially at Z for freshly visited files. The code below would > + set end_unchanged to 0 in that case. */ > + if (GPT - BEG < BEG_UNCHANGED) > + BEG_UNCHANGED = GPT - BEG; > + if (Z - GPT < END_UNCHANGED) > + END_UNCHANGED = Z - GPT; I'm not sure I understand this part. Why do you need to change the values of BEG_UNCHANGED and END_UNCHANGED -- those are supposed to be changed only by code that modifies the buffer text. > - /* -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; > + } These braces are redundant. > + /* Determine the window start relative to where we want to recenter > + to. */ > + > + if (need_recenter_even_if_point_can_be_invisible) > + init_iterator (&it, w, that_recentering_position, > + that_recentering_byte, NULL, DEFAULT_FACE_ID); > + else > + init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID); > it.current_y = it.last_visible_y; > + You want to display window around the change, but not bring point there? Is that a good idea? > + maybe_try_window: Why do we need this maybe_try_window stuff? It seems to repeat existing code, doesn't it? Thanks. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2022-02-06 11:34 ` Eli Zaretskii @ 2022-02-06 11:46 ` Po Lu 2022-02-06 11:55 ` Eli Zaretskii 0 siblings, 1 reply; 111+ messages in thread From: Po Lu @ 2022-02-06 11:46 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: > It's very hard to keep a discussion with such long pauses. I don't > even remember what we were discussing the last time and what issues > remained unresolved. Sorry for that, and I don't quite remember the problems either. IIRC, the one problem that remained unsolved was to find a better solution for the case where some text changed behind window start than to recenter the window around point, which I think I've found. >> +@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. > Why do we need 2 flags? Are they indeed orthogonal, or can we have a > single variable (perhaps with more than 2 states)? The first flag controls the behaviour of redisplay, while the second controls that of the scrolling commands, so I think they are orthogonal. > This is waaaay too terse for such a significant change... Agreed, though I can't think of anything better. > Why do we need to have changes in pixel-scroll.el be part of this > changeset? It makes the changes harder to review, and is not really > related to the changes in the display code. It allows pixel-scroll to take advantage of the new feature. You can just ignore it for now, I simply forgot to remove it. >> - 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) > Don't you need to test keep_point_visible as well here? If not, why > not? Thanks for catching that. >> @@ -5659,8 +5660,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; > What does it mean when you set the w->start point, but do NOT set the > w->force_start flag? w->force_start will result in point being constrained inside window start by the code under force_start: in redisplay_window. >> @@ -5857,7 +5860,7 @@ 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) > This and the rest of changes in window_scroll_pixel_based are > impossible to review: you replaced the "n > 0" condition with a > different one, and now the rest of the diffs are completely > unreadable. > I also don't understand how come the exact same code which was > previously run only for n > 0 is now run for any value of 'n', and > _by_default_ (since scroll_move_point is non-zero by default)? How > can that be TRT?? ??? That seems to be a problem which came up after I rebased the changes onto master from some version of master around late December, not before. Thanks for catching it. >> + if (!keep_point_visible && window_outdated (w)) >> + { >> + /* If some text changed between window start, then recenter the >> + display around the first character that changed, to avoid >> + confusing the user by not updating the display to reflect the >> + changes. */ >> + ptrdiff_t last_changed_charpos, first_changed_charpos; >> + >> + /* Make sure beg_unchanged and end_unchanged are up to date. Do it >> + only if buffer has really changed. The reason is that the gap is >> + initially at Z for freshly visited files. The code below would >> + set end_unchanged to 0 in that case. */ >> + if (GPT - BEG < BEG_UNCHANGED) >> + BEG_UNCHANGED = GPT - BEG; >> + if (Z - GPT < END_UNCHANGED) >> + END_UNCHANGED = Z - GPT; > I'm not sure I understand this part. Why do you need to change the > values of BEG_UNCHANGED and END_UNCHANGED -- those are supposed to be > changed only by code that modifies the buffer text. I saw the code do that in try_window_id, so even though I didn't really understand it I thought it would be safer to do that here as well. >> - /* -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; >> + } > > These braces are redundant. Thanks. >> + /* Determine the window start relative to where we want to recenter >> + to. */ >> + >> + if (need_recenter_even_if_point_can_be_invisible) >> + init_iterator (&it, w, that_recentering_position, >> + that_recentering_byte, NULL, DEFAULT_FACE_ID); >> + else >> + init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID); >> it.current_y = it.last_visible_y; >> + > You want to display window around the change, but not bring point > there? Is that a good idea? Yes, IMO. If the change is actually at point, then the window will be recentered around point by the `PT != w->last_point' conditional. Otherwise, such surprising changes to point would be unwanted. > Why do we need this maybe_try_window stuff? It seems to repeat > existing code, doesn't it? It does. There was a reason I put it there last December, but I can't remember it right now. Thanks. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2022-02-06 11:46 ` Po Lu @ 2022-02-06 11:55 ` Eli Zaretskii 2022-02-06 12:21 ` Po Lu 0 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2022-02-06 11:55 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Sun, 06 Feb 2022 19:46:15 +0800 > > >> +@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. > > > Why do we need 2 flags? Are they indeed orthogonal, or can we have a > > single variable (perhaps with more than 2 states)? > > The first flag controls the behaviour of redisplay, while the second > controls that of the scrolling commands, so I think they are orthogonal. Since scrolling is basically implemented in redisplay, I don't think this answers my question. Let's look at this from another aspect: which combinations of values of these two variables make sense, and what would be the behavior under each one of these reasonable combinations? > >> @@ -5659,8 +5660,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; > > > What does it mean when you set the w->start point, but do NOT set the > > w->force_start flag? > > w->force_start will result in point being constrained inside window > start by the code under force_start: in redisplay_window. That doesn't really answer my question. I was asking what is the semantics of setting the window-start, but not the force_start flag? What is expected from redisplay in this case? should it obey window-start? > >> + /* Make sure beg_unchanged and end_unchanged are up to date. Do it > >> + only if buffer has really changed. The reason is that the gap is > >> + initially at Z for freshly visited files. The code below would > >> + set end_unchanged to 0 in that case. */ > >> + if (GPT - BEG < BEG_UNCHANGED) > >> + BEG_UNCHANGED = GPT - BEG; > >> + if (Z - GPT < END_UNCHANGED) > >> + END_UNCHANGED = Z - GPT; > > > I'm not sure I understand this part. Why do you need to change the > > values of BEG_UNCHANGED and END_UNCHANGED -- those are supposed to be > > changed only by code that modifies the buffer text. > > I saw the code do that in try_window_id, so even though I didn't really > understand it I thought it would be safer to do that here as well. But you aren't going to do anything that try_window_id does, are you? > > You want to display window around the change, but not bring point > > there? Is that a good idea? > > Yes, IMO. If the change is actually at point, then the window will be > recentered around point by the `PT != w->last_point' conditional. > > Otherwise, such surprising changes to point would be unwanted. No, I mean don't we want to force point to move to the locus of these changes? I thought other applications did that. > > Why do we need this maybe_try_window stuff? It seems to repeat > > existing code, doesn't it? > > It does. There was a reason I put it there last December, but I can't > remember it right now. Too bad. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2022-02-06 11:55 ` Eli Zaretskii @ 2022-02-06 12:21 ` Po Lu 2022-02-06 16:15 ` Eli Zaretskii 0 siblings, 1 reply; 111+ messages in thread From: Po Lu @ 2022-02-06 12:21 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: > Since scrolling is basically implemented in redisplay, I don't think > this answers my question. > > Let's look at this from another aspect: which combinations of values > of these two variables make sense, and what would be the behavior > under each one of these reasonable combinations? It makes sense to have `scroll-move-point' to t, and `keep-point-visible' set to nil or t, and `scroll-move-point' set to nil when `keep-point-visible' is nil. The behaviour under the first and combinations would be that scrolling moves point to fit inside the visible portion of the buffer. With the third, scrolling will not move the point at all. >> >> @@ -5659,8 +5660,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; > That doesn't really answer my question. I was asking what is the > semantics of setting the window-start, but not the force_start flag? > What is expected from redisplay in this case? should it obey > window-start? It's expected that it will obey window-start (unless some text changed before it, in which case it will recenter around the first change position.) > But you aren't going to do anything that try_window_id does, are you? No, so it's probably safe to remove then. Thanks. > No, I mean don't we want to force point to move to the locus of these > changes? I thought other applications did that. They provide no way to make changes without point already being at the locus of the change. (In which case it will be caught either by the `PT != w->last_point' conditional, and redisplay will recenter around point as usual, or if point did not move, then it will recenter around the change, which would be near the point in that case.) IOW, there's no way in most other editors to do something like this: (save-excursion (goto-char (point-min)) (insert "foo")) ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2022-02-06 12:21 ` Po Lu @ 2022-02-06 16:15 ` Eli Zaretskii 2022-02-07 1:21 ` Po Lu 0 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2022-02-06 16:15 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Sun, 06 Feb 2022 20:21:11 +0800 > > Eli Zaretskii <eliz@gnu.org> writes: > > > Since scrolling is basically implemented in redisplay, I don't think > > this answers my question. > > > > Let's look at this from another aspect: which combinations of values > > of these two variables make sense, and what would be the behavior > > under each one of these reasonable combinations? > > It makes sense to have `scroll-move-point' to t, and > `keep-point-visible' set to nil or t, and `scroll-move-point' set to nil > when `keep-point-visible' is nil. > > The behaviour under the first and combinations would be that scrolling > moves point to fit inside the visible portion of the buffer. With the > third, scrolling will not move the point at all. So we have at most 3 states, and could have a single tri-state variable. And I question the validity of the combination scroll-move-point = nil with keep-point-visible = t. The problem with your implementation is that scroll-move-point = nil disables scrolling in redisplay_window, but scrolling there is used not necessarily as result of scrolling commands, but also when redisplay_window decides that the optimal method of updating a window is to scroll its previous contents. Thus, disabling scrolling on that level will cause confusing results, because users will expect that to affect only scrolling commands: they are unaware that redisplay sometimes scrolls the window for other reasons. > >> >> @@ -5659,8 +5660,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; > > > That doesn't really answer my question. I was asking what is the > > semantics of setting the window-start, but not the force_start flag? > > What is expected from redisplay in this case? should it obey > > window-start? > > It's expected that it will obey window-start (unless some text changed > before it, in which case it will recenter around the first change > position.) For that, you must set the force_start flag. If you don't set it, redisplay cannot know whether the value of w->start is just the result of the previous redisplay cycle or was set by some user command which wants to scroll the window. Perhaps you want to explore using w->optional_new_start instead? > > No, I mean don't we want to force point to move to the locus of these > > changes? I thought other applications did that. > > They provide no way to make changes without point already being at the > locus of the change. (In which case it will be caught either by the `PT > != w->last_point' conditional, and redisplay will recenter around point > as usual, or if point did not move, then it will recenter around the > change, which would be near the point in that case.) > > IOW, there's no way in most other editors to do something like this: > > (save-excursion > (goto-char (point-min)) > (insert "foo")) Maybe so should we, at least as an option. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2022-02-06 16:15 ` Eli Zaretskii @ 2022-02-07 1:21 ` Po Lu 2022-02-07 7:21 ` Po Lu 0 siblings, 1 reply; 111+ messages in thread From: Po Lu @ 2022-02-07 1:21 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: > So we have at most 3 states, and could have a single tri-state > variable. Indeed. > And I question the validity of the combination scroll-move-point = nil > with keep-point-visible = t. The problem with your implementation is > that scroll-move-point = nil disables scrolling in redisplay_window, > but scrolling there is used not necessarily as result of scrolling > commands, but also when redisplay_window decides that the optimal > method of updating a window is to scroll its previous contents. Thus, > disabling scrolling on that level will cause confusing results, > because users will expect that to affect only scrolling commands: they > are unaware that redisplay sometimes scrolls the window for other > reasons. Perhaps we could have redisplay bind `scroll-move-point' to a reasonable value before calling the scrolling commands? > For that, you must set the force_start flag. If you don't set it, > redisplay cannot know whether the value of w->start is just the result > of the previous redisplay cycle or was set by some user command which > wants to scroll the window. > > Perhaps you want to explore using w->optional_new_start instead? Yes, it seems to be perfect for what I need. Thanks. > Maybe so should we, at least as an option. Sure, an option would be nice. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2022-02-07 1:21 ` Po Lu @ 2022-02-07 7:21 ` Po Lu 2022-02-07 13:41 ` Eli Zaretskii 0 siblings, 1 reply; 111+ messages in thread From: Po Lu @ 2022-02-07 7:21 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Po Lu <luangruo@yahoo.com> writes: > Eli Zaretskii <eliz@gnu.org> writes: > >> So we have at most 3 states, and could have a single tri-state >> variable. > > Indeed. > >> And I question the validity of the combination scroll-move-point = nil >> with keep-point-visible = t. The problem with your implementation is >> that scroll-move-point = nil disables scrolling in redisplay_window, >> but scrolling there is used not necessarily as result of scrolling >> commands, but also when redisplay_window decides that the optimal >> method of updating a window is to scroll its previous contents. Thus, >> disabling scrolling on that level will cause confusing results, >> because users will expect that to affect only scrolling commands: they >> are unaware that redisplay sometimes scrolls the window for other >> reasons. > > Perhaps we could have redisplay bind `scroll-move-point' to a reasonable > value before calling the scrolling commands? I don't see where the scrolling commands in window.c get called from `redisplay_window'. Is it try_scrolling? If so, I see nothing there. Thanks. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2022-02-07 7:21 ` Po Lu @ 2022-02-07 13:41 ` Eli Zaretskii 2022-02-07 13:57 ` Po Lu 0 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2022-02-07 13:41 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Mon, 07 Feb 2022 15:21:49 +0800 > > Po Lu <luangruo@yahoo.com> writes: > > > Eli Zaretskii <eliz@gnu.org> writes: > > > >> So we have at most 3 states, and could have a single tri-state > >> variable. > > > > Indeed. > > > >> And I question the validity of the combination scroll-move-point = nil > >> with keep-point-visible = t. The problem with your implementation is > >> that scroll-move-point = nil disables scrolling in redisplay_window, > >> but scrolling there is used not necessarily as result of scrolling > >> commands, but also when redisplay_window decides that the optimal > >> method of updating a window is to scroll its previous contents. Thus, > >> disabling scrolling on that level will cause confusing results, > >> because users will expect that to affect only scrolling commands: they > >> are unaware that redisplay sometimes scrolls the window for other > >> reasons. > > > > Perhaps we could have redisplay bind `scroll-move-point' to a reasonable > > value before calling the scrolling commands? > > I don't see where the scrolling commands in window.c get called from > `redisplay_window'. I didn't say redisplay calls the scrolling commands: you did. The truth is that redisplay doesn't call any scrolling commands. > Is it try_scrolling? try_scrolling is not a scrolling command, it's one of the methods used by redisplay to update a window's display by reusing parts of the existing display. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2022-02-07 13:41 ` Eli Zaretskii @ 2022-02-07 13:57 ` Po Lu 2022-02-07 14:24 ` Eli Zaretskii 0 siblings, 1 reply; 111+ messages in thread From: Po Lu @ 2022-02-07 13:57 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: >> >> And I question the validity of the combination scroll-move-point = nil >> >> with keep-point-visible = t. The problem with your implementation is >> >> that scroll-move-point = nil disables scrolling in redisplay_window, >> >> but scrolling there is used not necessarily as result of scrolling >> >> commands, but also when redisplay_window decides that the optimal >> >> method of updating a window is to scroll its previous contents. Thus, >> >> disabling scrolling on that level will cause confusing results, >> >> because users will expect that to affect only scrolling commands: they >> >> are unaware that redisplay sometimes scrolls the window for other >> >> reasons. > I didn't say redisplay calls the scrolling commands: you did. > > The truth is that redisplay doesn't call any scrolling commands. `scroll-move-point' doesn't affect redisplay; it only affects the scrolling commands in window.c. I thought what you wrote was a typo, and that you meant to say "disables scrolling in window.c" or something else similar. Thanks. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2022-02-07 13:57 ` Po Lu @ 2022-02-07 14:24 ` Eli Zaretskii 2022-02-08 0:58 ` Po Lu 0 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2022-02-07 14:24 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Mon, 07 Feb 2022 21:57:50 +0800 > > Eli Zaretskii <eliz@gnu.org> writes: > > >> >> And I question the validity of the combination scroll-move-point = nil > >> >> with keep-point-visible = t. The problem with your implementation is > >> >> that scroll-move-point = nil disables scrolling in redisplay_window, > >> >> but scrolling there is used not necessarily as result of scrolling > >> >> commands, but also when redisplay_window decides that the optimal > >> >> method of updating a window is to scroll its previous contents. Thus, > >> >> disabling scrolling on that level will cause confusing results, > >> >> because users will expect that to affect only scrolling commands: they > >> >> are unaware that redisplay sometimes scrolls the window for other > >> >> reasons. > > > I didn't say redisplay calls the scrolling commands: you did. > > > > The truth is that redisplay doesn't call any scrolling commands. > > `scroll-move-point' doesn't affect redisplay; it only affects the > scrolling commands in window.c. It does affect redisplay: by not setting the force_start flag of the window. > I thought what you wrote was a typo, and that you meant to say "disables > scrolling in window.c" or something else similar. No, the problematic word was "scrolling": I meant the large block in redisplay_window conditioned by w->force_start being non-zero. That includes the code under try_to_scroll. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2022-02-07 14:24 ` Eli Zaretskii @ 2022-02-08 0:58 ` Po Lu 2022-02-08 17:08 ` Eli Zaretskii 0 siblings, 1 reply; 111+ messages in thread From: Po Lu @ 2022-02-08 0:58 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: >> `scroll-move-point' doesn't affect redisplay; it only affects the >> scrolling commands in window.c. > > It does affect redisplay: by not setting the force_start flag of the > window. What about modifying the code under force_start to not move point if `keep-point-visible' is nil? Since the point isn't required to be visible anymore, there is no need to move the cursor there, I think. > No, the problematic word was "scrolling": I meant the large block in > redisplay_window conditioned by w->force_start being non-zero. That > includes the code under try_to_scroll. Thanks for explaining that. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2022-02-08 0:58 ` Po Lu @ 2022-02-08 17:08 ` Eli Zaretskii 2022-02-09 1:57 ` Po Lu 0 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2022-02-08 17:08 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Tue, 08 Feb 2022 08:58:22 +0800 > > Eli Zaretskii <eliz@gnu.org> writes: > > >> `scroll-move-point' doesn't affect redisplay; it only affects the > >> scrolling commands in window.c. > > > > It does affect redisplay: by not setting the force_start flag of the > > window. > > What about modifying the code under force_start to not move point if > `keep-point-visible' is nil? Since the point isn't required to be > visible anymore, there is no need to move the cursor there, I think. I don't think you can do that indiscriminately, because some of the places that set the window's force_start flag are unrelated to this feature. One example is set_window_buffer and its callers. Another example is the code in redisplay_window that ends with "goto force_start". And there are probably more. So if you want to do that, you'll need to carefully audit all those places, and make sure you avoid moving point only when force_start was set by scrolling commands or in some similar situations. Otherwise, users will complain that point goes out of view when they didn't expect it to. For example, "C-x 2" goes through that code, and I'm quite sure we don't want point to be left outside of the window in that case. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2022-02-08 17:08 ` Eli Zaretskii @ 2022-02-09 1:57 ` Po Lu 2022-02-10 13:04 ` Eli Zaretskii 0 siblings, 1 reply; 111+ messages in thread From: Po Lu @ 2022-02-09 1:57 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: > I don't think you can do that indiscriminately, because some of the > places that set the window's force_start flag are unrelated to this > feature. One example is set_window_buffer and its callers. Another > example is the code in redisplay_window that ends with "goto > force_start". And there are probably more. > > So if you want to do that, you'll need to carefully audit all those > places, and make sure you avoid moving point only when force_start was > set by scrolling commands or in some similar situations. Otherwise, > users will complain that point goes out of view when they didn't > expect it to. For example, "C-x 2" goes through that code, and I'm > quite sure we don't want point to be left outside of the window in > that case. Would it make sense to introduce a new flag that split-window-below and other such commands set that makes force_start move point regardless of the value of `keep-point-visible'? ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2022-02-09 1:57 ` Po Lu @ 2022-02-10 13:04 ` Eli Zaretskii 2022-02-10 13:09 ` Po Lu 0 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2022-02-10 13:04 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Wed, 09 Feb 2022 09:57:45 +0800 > > Eli Zaretskii <eliz@gnu.org> writes: > > > I don't think you can do that indiscriminately, because some of the > > places that set the window's force_start flag are unrelated to this > > feature. One example is set_window_buffer and its callers. Another > > example is the code in redisplay_window that ends with "goto > > force_start". And there are probably more. > > > > So if you want to do that, you'll need to carefully audit all those > > places, and make sure you avoid moving point only when force_start was > > set by scrolling commands or in some similar situations. Otherwise, > > users will complain that point goes out of view when they didn't > > expect it to. For example, "C-x 2" goes through that code, and I'm > > quite sure we don't want point to be left outside of the window in > > that case. > > Would it make sense to introduce a new flag that split-window-below and > other such commands set that makes force_start move point regardless of > the value of `keep-point-visible'? Commands cannot bind variables to force redisplay do something, because redisplay runs when the command already exited. So what you mean is probably a flag in the window object. Is that the intent? ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2022-02-10 13:04 ` Eli Zaretskii @ 2022-02-10 13:09 ` Po Lu 0 siblings, 0 replies; 111+ messages in thread From: Po Lu @ 2022-02-10 13:09 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: > Commands cannot bind variables to force redisplay do something, > because redisplay runs when the command already exited. > > So what you mean is probably a flag in the window object. Is that the > intent? Yes, I should have been clearer. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-06 2:11 ` Po Lu 2021-12-06 14:13 ` Eli Zaretskii @ 2021-12-09 11:45 ` Eli Zaretskii 2021-12-09 12:19 ` Po Lu 1 sibling, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-12-09 11:45 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Mon, 06 Dec 2021 10:11:47 +0800 > > 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. Once again, it's hard to understand the main ideas behind the feature. You explained above when it brings point into the view, but what I'm looking for is an explanation for how to modify redisplay_window when this feature is turned ON, without losing too much of the existing redisplay functionality. Also, a large part of the patch seems to change mainly whitespace, so please use the -w switch to show diffs ignoring the whitespace changes, because otherwise it's very hard to spot the real changes. A couple of comments below: > --- 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) It seems you made changes for GUI scrolling, but not for TTY scrolling? Is this feature supposed to be disabled on TTY frames? > @@ -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: I'm confused here. This bypasses all of try_scrolling's code, which can select a new window-start because, for example, point moved out of the visible portion of the window. Does this mean that when this feature is turned ON, scrolling of the window in these cases is no longer supported? For example, let's say I pressed C-n and that moved point below the window's end (with the default zero value of scroll-margin) -- does it mean the window will not scroll, leaving point invisible in this case? That brings me back to a question I already asked: how do users tell Emacs when they deliberately want to move point outside of the window and when they want Emacs to scroll the window to make point visible, as before? > @@ -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; Likewise here: you are disabling one of the more important redisplay optimizations, which minimizes redisplay work when the user just move point a little ways. Can you tell why this needs to be disabled under the new behavior? it seems to be unrelated, because the optimization only does its thing when point didn't leave the window. > + debug_method_add (w, "real redisplay starts"); This will have to go eventually, as this trace is not useful in general. > + /* TODO: enable this optimization. */ > + if (!keep_point_visible) > + return false; This optimization also doesn't necessarily have anything to do with point being outside of the window. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-09 11:45 ` Eli Zaretskii @ 2021-12-09 12:19 ` Po Lu 2021-12-09 12:45 ` Eli Zaretskii 0 siblings, 1 reply; 111+ messages in thread From: Po Lu @ 2021-12-09 12:19 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: > Once again, it's hard to understand the main ideas behind the > feature. You explained above when it brings point into the view, but > what I'm looking for is an explanation for how to modify > redisplay_window when this feature is turned ON, without losing too > much of the existing redisplay functionality. The idea is to prevent redisplay_window from entering `recenter' unless `w->force_start' or a few other conditions are true, and to not display the phys cursor if its position is unknown. A large part of `try_scrolling' is also disabled, but I think I know how to turn it on now. > Also, a large part of the patch seems to change mainly whitespace, so > please use the -w switch to show diffs ignoring the whitespace > changes, because otherwise it's very hard to spot the real changes. Thanks, I will keep that in mind in the future. > A couple of comments below: >> --- 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) > It seems you made changes for GUI scrolling, but not for TTY > scrolling? Is this feature supposed to be disabled on TTY frames? No, it's something I plan to do in a while, but not yet. >> @@ -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: > I'm confused here. This bypasses all of try_scrolling's code, which > can select a new window-start because, for example, point moved out of > the visible portion of the window. Does this mean that when > this feature is turned ON, scrolling of the window in these cases is > no longer supported? For example, let's say I pressed C-n and that > moved point below the window's end (with the default zero value of > scroll-margin) -- does it mean the window will not scroll, leaving > point invisible in this case? It does not: it enters the code under the `recenter' label instead, which causes point to be displayed at the center of the screen. But the behavior is very different between that and the code in try_scrolling, so I think it should be turned on if the numeric value of point has changed, as we do with the recenter label. >> @@ -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; > Likewise here: you are disabling one of the more important redisplay > optimizations, which minimizes redisplay work when the user just move > point a little ways. Can you tell why this needs to be disabled under > the new behavior? it seems to be unrelated, because the optimization > only does its thing when point didn't leave the window. I disabled all the redisplay optimizations when first developing this feature, so I could turn them on one-by-one to see if they would cause any problems. This optimization works fine however, so it can be enabled. > This will have to go eventually, as this trace is not useful in > general. Thanks, I'll keep that in mind. > This optimization also doesn't necessarily have anything to do with > point being outside of the window. That's because I haven't tested to see if it works yet. Thanks. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-09 12:19 ` Po Lu @ 2021-12-09 12:45 ` Eli Zaretskii 0 siblings, 0 replies; 111+ messages in thread From: Eli Zaretskii @ 2021-12-09 12:45 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org > Date: Thu, 09 Dec 2021 20:19:13 +0800 > > > Likewise here: you are disabling one of the more important redisplay > > optimizations, which minimizes redisplay work when the user just move > > point a little ways. Can you tell why this needs to be disabled under > > the new behavior? it seems to be unrelated, because the optimization > > only does its thing when point didn't leave the window. > > I disabled all the redisplay optimizations when first developing this > feature, so I could turn them on one-by-one to see if they would cause > any problems. You can disable each of these optimizations individually without changing any code, by using the corresponding inhibit-* variables (inhibit-try-window-id etc.). ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-04 11:18 ` Po Lu 2021-12-04 12:55 ` Eli Zaretskii @ 2021-12-04 13:00 ` dick 2021-12-04 13:14 ` tomas 2021-12-04 13:19 ` Po Lu 1 sibling, 2 replies; 111+ messages in thread From: dick @ 2021-12-04 13:00 UTC (permalink / raw) Cc: emacs-devel PL> + if (!keep_point_visible PL> + && (!w->cursor_visible_p PL> + || w->cursor.vpos == -1) PL> + && w->phys_cursor_on_p) The display code is already rife with a hundred state variables, all of which invite laborious combinations of if-clauses to accommodate (something EZ is rather expert at), all of them sources of FUD and puzzlement. cursor_visible_p is yet another state indicator that multiplies the state space by 2. I can't oppose it (I can't seem to oppose anything) if it will revive emacs's fortunes, but the state profileration really galls. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-04 13:00 ` dick @ 2021-12-04 13:14 ` tomas 2021-12-04 13:19 ` Po Lu 1 sibling, 0 replies; 111+ messages in thread From: tomas @ 2021-12-04 13:14 UTC (permalink / raw) To: emacs-devel [-- Attachment #1: Type: text/plain, Size: 457 bytes --] On Sat, Dec 04, 2021 at 08:00:16AM -0500, dick wrote: > PL> + if (!keep_point_visible > PL> + && (!w->cursor_visible_p > PL> + || w->cursor.vpos == -1) > PL> + && w->phys_cursor_on_p) > > The display code is already rife [...] > [...] FUD [...] > [...] I can't oppose it [...] You can oppose, as anyone else. Have you considered working your tone? Perhaps your opposition might be taken more seriously, then. Cheers -- t [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 195 bytes --] ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-04 13:00 ` dick 2021-12-04 13:14 ` tomas @ 2021-12-04 13:19 ` Po Lu 2021-12-04 13:41 ` Eli Zaretskii 2021-12-04 14:17 ` dick 1 sibling, 2 replies; 111+ messages in thread From: Po Lu @ 2021-12-04 13:19 UTC (permalink / raw) To: dick; +Cc: emacs-devel dick <dick.r.chiang@gmail.com> writes: > PL> + if (!keep_point_visible > PL> + && (!w->cursor_visible_p > PL> + || w->cursor.vpos == -1) > PL> + && w->phys_cursor_on_p) > The display code is already rife with a hundred state variables, all of > which invite laborious combinations of if-clauses to accommodate I am aware of that. > (something EZ is rather expert at), all of them sources of FUD and > puzzlement. Why FUD? What is the fear, and where is the uncertainty and doubt? > cursor_visible_p is yet another state indicator that multiplies the > state space by 2. I can't oppose it (I can't seem to oppose anything) > if it will revive emacs's fortunes You, personally, are free to work on other things that interest you, just as I will with my interests. Emacs is free software after all. If anything, adding the ability to have point outside a window will only serve positively towards Emacs's fortunes, as this has been a feature many people have wanted for a while now. cursor_visible_p is also conceptually simple: if it is false, the cursor is not inside the window. I fail to see how it can multiply the state space by any significant amount. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-04 13:19 ` Po Lu @ 2021-12-04 13:41 ` Eli Zaretskii 2021-12-05 0:46 ` Po Lu 2021-12-04 14:17 ` dick 1 sibling, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-12-04 13:41 UTC (permalink / raw) To: emacs-devel, Po Lu, dick On December 4, 2021 3:19:57 PM GMT+02:00, Po Lu <luangruo@yahoo.com> wrote: > dick <dick.r.chiang@gmail.com> writes: > > > PL> + if (!keep_point_visible > > PL> + && (!w->cursor_visible_p > > PL> + || w->cursor.vpos == -1) > > PL> + && w->phys_cursor_on_p) > > > The display code is already rife with a hundred state variables, all of > > which invite laborious combinations of if-clauses to accommodate > > I am aware of that. But you could perhaps avoid a separate flag if you'd set w->cursor.vpos to a negative value when the cursor is outside of the window. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-04 13:41 ` Eli Zaretskii @ 2021-12-05 0:46 ` Po Lu 2021-12-05 7:12 ` Eli Zaretskii 0 siblings, 1 reply; 111+ messages in thread From: Po Lu @ 2021-12-05 0:46 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel, dick Eli Zaretskii <eliz@gnu.org> writes: > But you could perhaps avoid a separate flag if you'd set > w->cursor.vpos to a negative value when the cursor is outside of the > window. Actually, it now seems that cursor_visible_p is currently totally redundant: cursor.vpos is already -1 when the cursor is supposed to be invisible. Can that value be relied on? ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-05 0:46 ` Po Lu @ 2021-12-05 7:12 ` Eli Zaretskii 2021-12-05 7:16 ` Po Lu 0 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-12-05 7:12 UTC (permalink / raw) To: Po Lu; +Cc: dick.r.chiang, emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: emacs-devel@gnu.org, dick <dick.r.chiang@gmail.com> > Date: Sun, 05 Dec 2021 08:46:52 +0800 > > Eli Zaretskii <eliz@gnu.org> writes: > > > But you could perhaps avoid a separate flag if you'd set > > w->cursor.vpos to a negative value when the cursor is outside of the > > window. > > Actually, it now seems that cursor_visible_p is currently totally > redundant: cursor.vpos is already -1 when the cursor is supposed to be > invisible. > > Can that value be relied on? Depends what for and how you want to rely on it. It basically says that the cursor position inside the window is unknown. The "normal" redisplay must always calculate some reasonable coordinates and put them there, otherwise the cursor will not be visible, which is a display bug. If that is enough for you, then yes, you can rely on it. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-05 7:12 ` Eli Zaretskii @ 2021-12-05 7:16 ` Po Lu 2021-12-05 8:48 ` Eli Zaretskii 0 siblings, 1 reply; 111+ messages in thread From: Po Lu @ 2021-12-05 7:16 UTC (permalink / raw) To: Eli Zaretskii; +Cc: dick.r.chiang, emacs-devel Eli Zaretskii <eliz@gnu.org> writes: >> From: Po Lu <luangruo@yahoo.com> >> Cc: emacs-devel@gnu.org, dick <dick.r.chiang@gmail.com> >> Date: Sun, 05 Dec 2021 08:46:52 +0800 >> >> Eli Zaretskii <eliz@gnu.org> writes: >> >> > But you could perhaps avoid a separate flag if you'd set >> > w->cursor.vpos to a negative value when the cursor is outside of the >> > window. >> >> Actually, it now seems that cursor_visible_p is currently totally >> redundant: cursor.vpos is already -1 when the cursor is supposed to be >> invisible. >> >> Can that value be relied on? > > Depends what for and how you want to rely on it. It basically says > that the cursor position inside the window is unknown. The "normal" > redisplay must always calculate some reasonable coordinates and put > them there, otherwise the cursor will not be visible, which is a > display bug. If that is enough for you, then yes, you can rely on it. I meant to ask whether or not I can forgo calculating whether point is outside the window, and just test whether or not cursor.vpos is -1 to determine if the cursor should be displayed, when point is allowed to be outside the window. Thanks. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-05 7:16 ` Po Lu @ 2021-12-05 8:48 ` Eli Zaretskii 2021-12-05 9:15 ` Po Lu 0 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-12-05 8:48 UTC (permalink / raw) To: Po Lu; +Cc: dick.r.chiang, emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: dick.r.chiang@gmail.com, emacs-devel@gnu.org > Date: Sun, 05 Dec 2021 15:16:13 +0800 > > >> Can that value be relied on? > > > > Depends what for and how you want to rely on it. It basically says > > that the cursor position inside the window is unknown. The "normal" > > redisplay must always calculate some reasonable coordinates and put > > them there, otherwise the cursor will not be visible, which is a > > display bug. If that is enough for you, then yes, you can rely on it. > > I meant to ask whether or not I can forgo calculating whether point is > outside the window, and just test whether or not cursor.vpos is -1 to > determine if the cursor should be displayed, when point is allowed to be > outside the window. No. I think it should be the other way around: first see if point is outside of the window, then force cursor.vpos to be negative. That's because redisplay resets that value to -1 whenever it isn't sure the cursor will stay in its old position. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-05 8:48 ` Eli Zaretskii @ 2021-12-05 9:15 ` Po Lu 2021-12-05 9:25 ` Eli Zaretskii 0 siblings, 1 reply; 111+ messages in thread From: Po Lu @ 2021-12-05 9:15 UTC (permalink / raw) To: Eli Zaretskii; +Cc: dick.r.chiang, emacs-devel Eli Zaretskii <eliz@gnu.org> writes: >> From: Po Lu <luangruo@yahoo.com> >> Cc: dick.r.chiang@gmail.com, emacs-devel@gnu.org >> Date: Sun, 05 Dec 2021 15:16:13 +0800 >> >> >> Can that value be relied on? >> > >> > Depends what for and how you want to rely on it. It basically says >> > that the cursor position inside the window is unknown. The "normal" >> > redisplay must always calculate some reasonable coordinates and put >> > them there, otherwise the cursor will not be visible, which is a >> > display bug. If that is enough for you, then yes, you can rely on it. >> >> I meant to ask whether or not I can forgo calculating whether point is >> outside the window, and just test whether or not cursor.vpos is -1 to >> determine if the cursor should be displayed, when point is allowed to be >> outside the window. > > No. I think it should be the other way around: first see if point is > outside of the window, then force cursor.vpos to be negative. That's > because redisplay resets that value to -1 whenever it isn't sure the > cursor will stay in its old position. Thanks. Another question or two: I can't use the value "-1" for cursor.vpos to indicate that point is outside the window, as it's already treated specially by redisplay, correct? Also, where should I put the code to test if cursor is invisible? I think it should be after the label force_start, as forcing the start could potentially adjust point to be inside the window. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-05 9:15 ` Po Lu @ 2021-12-05 9:25 ` Eli Zaretskii 2021-12-05 9:31 ` Po Lu 0 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-12-05 9:25 UTC (permalink / raw) To: Po Lu; +Cc: dick.r.chiang, emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: dick.r.chiang@gmail.com, emacs-devel@gnu.org > Date: Sun, 05 Dec 2021 17:15:25 +0800 > > >> I meant to ask whether or not I can forgo calculating whether point is > >> outside the window, and just test whether or not cursor.vpos is -1 to > >> determine if the cursor should be displayed, when point is allowed to be > >> outside the window. > > > > No. I think it should be the other way around: first see if point is > > outside of the window, then force cursor.vpos to be negative. That's > > because redisplay resets that value to -1 whenever it isn't sure the > > cursor will stay in its old position. > > Thanks. Another question or two: I can't use the value "-1" for > cursor.vpos to indicate that point is outside the window, as it's > already treated specially by redisplay, correct? No, you can't. But the question is why do you need to? -1 there means the cursor position is unknown. Why do you need to know more than that, plus the fact that point is _allowed_ to be outside of the window? > Also, where should I put the code to test if cursor is invisible? I > think it should be after the label force_start, as forcing the start > could potentially adjust point to be inside the window. It goes back to the same question I asked above: why do you need to know that point is outside of the window? for what purposes? IOW, why not just let redisplay do its thing, without bothering to bring point into the window, when that is allowed? ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-05 9:25 ` Eli Zaretskii @ 2021-12-05 9:31 ` Po Lu 2021-12-05 10:34 ` Eli Zaretskii 0 siblings, 1 reply; 111+ messages in thread From: Po Lu @ 2021-12-05 9:31 UTC (permalink / raw) To: Eli Zaretskii; +Cc: dick.r.chiang, emacs-devel Eli Zaretskii <eliz@gnu.org> writes: >> From: Po Lu <luangruo@yahoo.com> >> Cc: dick.r.chiang@gmail.com, emacs-devel@gnu.org >> Date: Sun, 05 Dec 2021 17:15:25 +0800 >> >> >> I meant to ask whether or not I can forgo calculating whether point is >> >> outside the window, and just test whether or not cursor.vpos is -1 to >> >> determine if the cursor should be displayed, when point is allowed to be >> >> outside the window. >> > >> > No. I think it should be the other way around: first see if point is >> > outside of the window, then force cursor.vpos to be negative. That's >> > because redisplay resets that value to -1 whenever it isn't sure the >> > cursor will stay in its old position. >> >> Thanks. Another question or two: I can't use the value "-1" for >> cursor.vpos to indicate that point is outside the window, as it's >> already treated specially by redisplay, correct? > > No, you can't. But the question is why do you need to? -1 there > means the cursor position is unknown. Why do you need to know more > than that, plus the fact that point is _allowed_ to be outside of the > window? > >> Also, where should I put the code to test if cursor is invisible? I >> think it should be after the label force_start, as forcing the start >> could potentially adjust point to be inside the window. > > It goes back to the same question I asked above: why do you need to > know that point is outside of the window? for what purposes? > > IOW, why not just let redisplay do its thing, without bothering to > bring point into the window, when that is allowed? I need to erase the phys cursor and to tell display_and_set_cursor to not draw it: otherwise, the ghost of the cursor remains on-screen even after point is moved out. Thanks. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-05 9:31 ` Po Lu @ 2021-12-05 10:34 ` Eli Zaretskii 2021-12-05 10:37 ` Po Lu 0 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-12-05 10:34 UTC (permalink / raw) To: Po Lu; +Cc: dick.r.chiang, emacs-devel > From: Po Lu <luangruo@yahoo.com> > Cc: dick.r.chiang@gmail.com, emacs-devel@gnu.org > Date: Sun, 05 Dec 2021 17:31:03 +0800 > > >> Also, where should I put the code to test if cursor is invisible? I > >> think it should be after the label force_start, as forcing the start > >> could potentially adjust point to be inside the window. > > > > It goes back to the same question I asked above: why do you need to > > know that point is outside of the window? for what purposes? > > > > IOW, why not just let redisplay do its thing, without bothering to > > bring point into the window, when that is allowed? > > I need to erase the phys cursor and to tell display_and_set_cursor to > not draw it: otherwise, the ghost of the cursor remains on-screen even > after point is moved out. Which probably means you need to put the code which determines whether point is inside or outside of the window in update_window or thereabouts? ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-05 10:34 ` Eli Zaretskii @ 2021-12-05 10:37 ` Po Lu 0 siblings, 0 replies; 111+ messages in thread From: Po Lu @ 2021-12-05 10:37 UTC (permalink / raw) To: Eli Zaretskii; +Cc: dick.r.chiang, emacs-devel Eli Zaretskii <eliz@gnu.org> writes: >> From: Po Lu <luangruo@yahoo.com> >> Cc: dick.r.chiang@gmail.com, emacs-devel@gnu.org >> Date: Sun, 05 Dec 2021 17:31:03 +0800 >> >> >> Also, where should I put the code to test if cursor is invisible? I >> >> think it should be after the label force_start, as forcing the start >> >> could potentially adjust point to be inside the window. >> > >> > It goes back to the same question I asked above: why do you need to >> > know that point is outside of the window? for what purposes? >> > >> > IOW, why not just let redisplay do its thing, without bothering to >> > bring point into the window, when that is allowed? >> >> I need to erase the phys cursor and to tell display_and_set_cursor to >> not draw it: otherwise, the ghost of the cursor remains on-screen even >> after point is moved out. > Which probably means you need to put the code which determines whether > point is inside or outside of the window in update_window or > thereabouts? Thanks. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-04 13:19 ` Po Lu 2021-12-04 13:41 ` Eli Zaretskii @ 2021-12-04 14:17 ` dick 2021-12-04 16:33 ` Eli Zaretskii 1 sibling, 1 reply; 111+ messages in thread From: dick @ 2021-12-04 14:17 UTC (permalink / raw) To: Po Lu; +Cc: emacs-devel > Why FUD? What is the fear, and where is the uncertainty and doubt? When you bypass large state-heavy stanzas via "if allow-point-outside" in central functions like try_cursor_movement() and redisplay_window(), people (not you or EZ apparently) get scared. What will likely happen is you'll palm off the new flag "allow-point-outside" (i.e., !keep-point-visible), which will default off such that none of your state changes will ever take. You will be content with having tallied additional slocs. The not-so-hidden cost of your change however is obfuscation, which I suppose is par for the course in the emacs code base. > just as I will with my interests You gotta do what you gotta do. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-04 14:17 ` dick @ 2021-12-04 16:33 ` Eli Zaretskii 2021-12-04 17:13 ` dick 0 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-12-04 16:33 UTC (permalink / raw) To: dick; +Cc: luangruo, emacs-devel > From: dick <dick.r.chiang@gmail.com> > Date: Sat, 04 Dec 2021 09:17:41 -0500 > Cc: emacs-devel@gnu.org > > When you bypass large state-heavy stanzas via "if allow-point-outside" > in central functions like try_cursor_movement() and redisplay_window(), > people (not you or EZ apparently) get scared. Only people who have no clear idea about the overall structure of redisplay_window can become nervous when they see such bypasses, as a matter of principle, without considering what exactly is bypassed and why. A place to begin is by figuring out what does that "try" in "try_cursor_movement" means. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-04 16:33 ` Eli Zaretskii @ 2021-12-04 17:13 ` dick 2021-12-05 0:48 ` Po Lu 0 siblings, 1 reply; 111+ messages in thread From: dick @ 2021-12-04 17:13 UTC (permalink / raw) To: Eli Zaretskii; +Cc: luangruo, emacs-devel > Only people who have no clear idea about the overall structure of Having spent the last month trying to fix longlines, I believe I'm among the top five people in the world most entitled to be nervous. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-04 17:13 ` dick @ 2021-12-05 0:48 ` Po Lu 0 siblings, 0 replies; 111+ messages in thread From: Po Lu @ 2021-12-05 0:48 UTC (permalink / raw) To: dick; +Cc: Eli Zaretskii, emacs-devel dick <dick.r.chiang@gmail.com> writes: >> Only people who have no clear idea about the overall structure of > > Having spent the last month trying to fix longlines, I believe > I'm among the top five people in the world most entitled to be nervous. Why are you looking at redisplay_window to solve that problem? AFAIU, it's caused by the move_it_* functions scanning backwards for newline characters. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-28 8:13 ` Po Lu 2021-11-28 8:41 ` Eli Zaretskii @ 2021-11-28 14:03 ` Alan Mackenzie 2021-11-28 14:28 ` Eric S Fraga ` (3 more replies) 1 sibling, 4 replies; 111+ messages in thread From: Alan Mackenzie @ 2021-11-28 14:03 UTC (permalink / raw) To: Po Lu; +Cc: Eli Zaretskii, emacs-devel Hello, Po. On Sun, Nov 28, 2021 at 16:13:46 +0800, Po Lu wrote: > Eli Zaretskii <eliz@gnu.org> writes: > >> From: Po Lu <luangruo@yahoo.com> > >> Date: Sun, 28 Nov 2021 11:07:57 +0800 > >> I wonder what would be involved in allowing point to be outside a > >> window's visible area. Why would anybody want this? Why do you want this? This isn't a rhetorical question. Because other programs do it isn't a satisfactory reason. I detest this behaviour, and that Emacs doesn't (currently) do it is a large part of the reason why I use Emacs. With these other programs I experience a constant background stress, that the careless or accidental depression of a key causes BANG!!! and the text I was reading disappears for ever, being overwritten by the text around point. Also, as Eli has asked, how would you bring point back into the currently displayed window position? Please assume the user doesn't have a mouse, or dislikes using it. It would also be good to have some means of setting the mark there. > > Two steps: > > 1. Design the feature: how would it work? which operations would > > bring point back into the viewport, and which won't? For > > example, a simple question: if point is outside of the viewport, > > what is the effect of C-f or C-n on display? > The effect would be move point forward, or to the next line, and then to > recenter the window, so point is at the center of the window. In other words, a complete replacement of the window's previously displayed text by other text some arbitrary distance away. This is what I dislike so much, so hopefully this part of the feature would be optional. > Inserting text should probably recenter the window as well, if point is > outside the visible area (this is also how other programs behave). Again, this doesn't seem a good reason. > This is how other programs behave as well. > > IMO, it's a large job if done cleanly. Patches welcome. > Thanks, I will take a look at it. I think Eli was underestimating when he said it would be a large job. ;-) -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-28 14:03 ` Alan Mackenzie @ 2021-11-28 14:28 ` Eric S Fraga 2021-11-28 14:39 ` Eli Zaretskii 2021-11-28 14:42 ` dick ` (2 subsequent siblings) 3 siblings, 1 reply; 111+ messages in thread From: Eric S Fraga @ 2021-11-28 14:28 UTC (permalink / raw) To: emacs-devel On Sunday, 28 Nov 2021 at 14:03, Alan Mackenzie wrote: > I detest this behaviour [...] so hopefully this part of the feature > would be optional. +1 Invisible cursor is probably the one aspect of some other editors/word processors that I hate the most. And the one aspect of org mode's folding approach that I dislike. I would prefer for point to always be on text that is visible. -- Eric S Fraga with org 9.5 in Emacs 29.0.50 on Debian 11.1 ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-28 14:28 ` Eric S Fraga @ 2021-11-28 14:39 ` Eli Zaretskii 2021-11-28 16:55 ` Eric S Fraga 0 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-11-28 14:39 UTC (permalink / raw) To: Eric S Fraga; +Cc: emacs-devel > From: Eric S Fraga <e.fraga@ucl.ac.uk> > Date: Sun, 28 Nov 2021 14:28:39 +0000 > > On Sunday, 28 Nov 2021 at 14:03, Alan Mackenzie wrote: > > I detest this behaviour [...] so hopefully this part of the feature > > would be optional. > > +1 Don't worry, this will never be anything _but_ an optional feature. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-28 14:39 ` Eli Zaretskii @ 2021-11-28 16:55 ` Eric S Fraga 0 siblings, 0 replies; 111+ messages in thread From: Eric S Fraga @ 2021-11-28 16:55 UTC (permalink / raw) To: emacs-devel On Sunday, 28 Nov 2021 at 16:39, Eli Zaretskii wrote: > Don't worry, this will never be anything _but_ an optional feature. Not worried really; just letting Alan know he's not alone! ;-) Thank you in any case! -- Eric S Fraga with org 9.5 in Emacs 29.0.50 on Debian 11.1 ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-28 14:03 ` Alan Mackenzie 2021-11-28 14:28 ` Eric S Fraga @ 2021-11-28 14:42 ` dick 2021-11-28 15:39 ` Kévin Le Gouguec 2021-11-29 0:34 ` Po Lu 3 siblings, 0 replies; 111+ messages in thread From: dick @ 2021-11-28 14:42 UTC (permalink / raw) To: emacs-devel AM> Why would anybody want this? Why do you want this? This isn't a AM> rhetorical question. Because other programs do it isn't a AM> satisfactory reason. I used to be involved in a poker game where sometimes I'd split the pot in a stupid way. One player would complain, and another player would say, "Just let him do it the dumb way." Hundreds of bad ideas float through emacs-devel per year, and for whatever inexplicable reason, the maintainer entertains them all. Most if not all those ideas never see the light of day, or get compartmentalized in a module never exercised in practice. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-28 14:03 ` Alan Mackenzie 2021-11-28 14:28 ` Eric S Fraga 2021-11-28 14:42 ` dick @ 2021-11-28 15:39 ` Kévin Le Gouguec 2021-11-28 15:45 ` Eli Zaretskii 2021-11-28 16:59 ` Eric S Fraga 2021-11-29 0:34 ` Po Lu 3 siblings, 2 replies; 111+ messages in thread From: Kévin Le Gouguec @ 2021-11-28 15:39 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Po Lu, Eli Zaretskii, emacs-devel Alan Mackenzie <acm@muc.de> writes: >> >> From: Po Lu <luangruo@yahoo.com> >> >> Date: Sun, 28 Nov 2021 11:07:57 +0800 > >> >> I wonder what would be involved in allowing point to be outside a >> >> window's visible area. > > Why would anybody want this? Why do you want this? This isn't a > rhetorical question. Because other programs do it isn't a satisfactory > reason. I'll bite: because a user could want to peek a few screenfuls ahead/behind, while keeping the cursor at a point of interest, where they can come back with any point movement (e.g. arrow keys) or by just typing in ("Greetings Mister… *scrolls back up* Mackenzie, RET RET I trust this Sunday afternoon finds you well…"). Granted, IME I rarely want to check out an arbitrary "full screenfuls"; I usually want to check out the end of the current function (C-M-e) or look for a pattern (C-s); if that takes me off-screen, C-u C-SPC brings me right back where I was. I wouldn't begrudge users who'd prefer the behaviour Po suggests, though. > I detest this behaviour, and that Emacs doesn't (currently) do it is a > large part of the reason why I use Emacs. With these other programs I > experience a constant background stress, that the careless or accidental > depression of a key causes BANG!!! and the text I was reading > disappears for ever, being overwritten by the text around point. I don't see how (what I understand of) Po's proposition could lead to such catastrophic text Armageddon. And in any case, Emacs's trusty undo would surely come and save the day. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-28 15:39 ` Kévin Le Gouguec @ 2021-11-28 15:45 ` Eli Zaretskii 2021-11-28 17:14 ` Kévin Le Gouguec 2021-11-28 16:59 ` Eric S Fraga 1 sibling, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-11-28 15:45 UTC (permalink / raw) To: Kévin Le Gouguec; +Cc: luangruo, acm, emacs-devel > From: Kévin Le Gouguec <kevin.legouguec@gmail.com> > Cc: Po Lu <luangruo@yahoo.com>, Eli Zaretskii <eliz@gnu.org>, > emacs-devel@gnu.org > Date: Sun, 28 Nov 2021 16:39:01 +0100 > > > I detest this behaviour, and that Emacs doesn't (currently) do it is a > > large part of the reason why I use Emacs. With these other programs I > > experience a constant background stress, that the careless or accidental > > depression of a key causes BANG!!! and the text I was reading > > disappears for ever, being overwritten by the text around point. > > I don't see how (what I understand of) Po's proposition could lead to > such catastrophic text Armageddon. And in any case, Emacs's trusty undo > would surely come and save the day. Undo doesn't undo display operations, only editing operations. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-28 15:45 ` Eli Zaretskii @ 2021-11-28 17:14 ` Kévin Le Gouguec 0 siblings, 0 replies; 111+ messages in thread From: Kévin Le Gouguec @ 2021-11-28 17:14 UTC (permalink / raw) To: Eli Zaretskii; +Cc: luangruo, acm, emacs-devel Eli Zaretskii <eliz@gnu.org> writes: >> From: Kévin Le Gouguec <kevin.legouguec@gmail.com> >> Cc: Po Lu <luangruo@yahoo.com>, Eli Zaretskii <eliz@gnu.org>, >> emacs-devel@gnu.org >> Date: Sun, 28 Nov 2021 16:39:01 +0100 >> >> > I detest this behaviour, and that Emacs doesn't (currently) do it is a >> > large part of the reason why I use Emacs. With these other programs I >> > experience a constant background stress, that the careless or accidental >> > depression of a key causes BANG!!! and the text I was reading >> > disappears for ever, being overwritten by the text around point. >> >> I don't see how (what I understand of) Po's proposition could lead to >> such catastrophic text Armageddon. And in any case, Emacs's trusty undo >> would surely come and save the day. > > Undo doesn't undo display operations, only editing operations. Right; on my first read (and second, and third… I did try to understand Alan's problem scenario and its consequences, but I obviously failed), I interpreted "[disappearing] forever, being overwritten" as describing an editing hazard (akin to erasing the selection in a single keystroke when delete-selection-mode is on) rather than a "sudden shift of viewport" issue. FWIW I find the absence of a blinking cursor conspicuous enough to remind me that the cursor is actually somewhere else (and that typing in text or moving around will bring me back to this cursor), but I understand the concern. "Keep the feature opt-in" sounds like a good way to avoid surprises; even for people who might enable the feature, maybe having a fringe indicator at the top or the bottom of the window (to indicate in which direction point lies) would help? (Especially if it blinks according to blink-cursor-mode) ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-28 15:39 ` Kévin Le Gouguec 2021-11-28 15:45 ` Eli Zaretskii @ 2021-11-28 16:59 ` Eric S Fraga 2021-11-28 17:30 ` Kévin Le Gouguec 2021-11-29 0:34 ` Dmitry Gutov 1 sibling, 2 replies; 111+ messages in thread From: Eric S Fraga @ 2021-11-28 16:59 UTC (permalink / raw) To: emacs-devel On Sunday, 28 Nov 2021 at 16:39, Kévin Le Gouguec wrote: > I'll bite: because a user could want to peek a few screenfuls > ahead/behind, while keeping the cursor at a point of interest, where That's what C-x 2 M-C-v is for? ;-) Seriously, it's what Emacs does so well that other editors do not: being able to have multiple views into the same file/buffer. or, alternatively, set a mark, scroll away, and jump back... -- Eric S Fraga with org 9.5 in Emacs 29.0.50 on Debian 11.1 ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-28 16:59 ` Eric S Fraga @ 2021-11-28 17:30 ` Kévin Le Gouguec 2021-11-29 0:34 ` Dmitry Gutov 1 sibling, 0 replies; 111+ messages in thread From: Kévin Le Gouguec @ 2021-11-28 17:30 UTC (permalink / raw) To: Eric S Fraga; +Cc: emacs-devel Eric S Fraga <e.fraga@ucl.ac.uk> writes: > On Sunday, 28 Nov 2021 at 16:39, Kévin Le Gouguec wrote: >> I'll bite: because a user could want to peek a few screenfuls >> ahead/behind, while keeping the cursor at a point of interest, where > > That's what C-x 2 M-C-v is for? ;-) > > Seriously, it's what Emacs does so well that other editors do not: being > able to have multiple views into the same file/buffer. Sure, although off the top of my head I can't see a faster way to delete the temporary window than "C-x o C-x 0" (granted, that's not the most awkward sequence ever). (Assuming the user has other windows of interest, so dismissing C-x 1) > or, alternatively, set a mark, scroll away, and jump back... Yes, as I described. As I said, I personally find C-u C-SPC enough for my purposes, but I can imagine other people liking the proposed behaviour better. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-28 16:59 ` Eric S Fraga 2021-11-28 17:30 ` Kévin Le Gouguec @ 2021-11-29 0:34 ` Dmitry Gutov 1 sibling, 0 replies; 111+ messages in thread From: Dmitry Gutov @ 2021-11-29 0:34 UTC (permalink / raw) To: Eric S Fraga, emacs-devel On 28.11.2021 19:59, Eric S Fraga wrote: > On Sunday, 28 Nov 2021 at 16:39, Kévin Le Gouguec wrote: >> I'll bite: because a user could want to peek a few screenfuls >> ahead/behind, while keeping the cursor at a point of interest, where > That's what C-x 2 M-C-v is for?;-) And with the feature in question you would just scroll with the mouse however far you like, and then return to the original location with e.g. 'C-f'. Far fewer keypresses. I've used this kind of approach often back in another (non-Emacser) life, and I've missed that ability for a number of years afterward. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-28 14:03 ` Alan Mackenzie ` (2 preceding siblings ...) 2021-11-28 15:39 ` Kévin Le Gouguec @ 2021-11-29 0:34 ` Po Lu 2021-12-08 1:45 ` John Ankarström 3 siblings, 1 reply; 111+ messages in thread From: Po Lu @ 2021-11-29 0:34 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, emacs-devel Alan Mackenzie <acm@muc.de> writes: > Why would anybody want this? Why do you want this? This isn't a > rhetorical question. Because other programs do it isn't a satisfactory > reason. > I detest this behaviour, and that Emacs doesn't (currently) do it is a > large part of the reason why I use Emacs. With these other programs I > experience a constant background stress, that the careless or accidental > depression of a key causes BANG!!! and the text I was reading > disappears for ever, being overwritten by the text around point. > Also, as Eli has asked, how would you bring point back into the > currently displayed window position? Please assume the user doesn't > have a mouse, or dislikes using it. It would also be good to have some > means of setting the mark there. The feature will be optional, of course. And it will certainly be disabled by default, because I don't want it either. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-11-29 0:34 ` Po Lu @ 2021-12-08 1:45 ` John Ankarström 2021-12-08 12:45 ` Eli Zaretskii 0 siblings, 1 reply; 111+ messages in thread From: John Ankarström @ 2021-12-08 1:45 UTC (permalink / raw) To: emacs-devel Po Lu <luangruo@yahoo.com> writes: > Alan Mackenzie <acm@muc.de> writes: > >> Why would anybody want this? Why do you want this? This isn't a >> rhetorical question. Because other programs do it isn't a satisfactory >> reason. [...] > > The feature will be optional, of course. And it will certainly be > disabled by default, because I don't want it either. For what it's worth, I think that it would be a good idea to limit this feature to mouse-based scrolling. That's what I've been doing in my own Elisp emulation of this kind of thing [1]. I agree with Alan that, if you primarily use the keyboard for scrolling, it is very jarring if editing/movement commands bring the window view back to the original position. But the mouse provdides an easy way of overriding the original position (by left-clicking on a new position). [1] http://ankarstrom.se/~john/emacs/scroll-without-point.el ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-08 1:45 ` John Ankarström @ 2021-12-08 12:45 ` Eli Zaretskii 2021-12-08 13:33 ` John Ankarström 0 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-12-08 12:45 UTC (permalink / raw) To: John Ankarström; +Cc: emacs-devel > From: John Ankarström <john@ankarstrom.se> > Date: Wed, 08 Dec 2021 02:45:02 +0100 > > For what it's worth, I think that it would be a good idea to limit this > feature to mouse-based scrolling. The display engine doesn't know what kind of user gestures (or even Lisp program) caused the scroll, so doing that cleanly won't be easy, if at all feasible. And Emacs users are likely to dislike a solution that makes such a distinction, since many of them don't use the mouse. > I agree with Alan that, if you primarily use the keyboard for scrolling, > it is very jarring if editing/movement commands bring the window view > back to the original position. You'd prefer to have the editing command change the buffer in the portion that stays invisible? IMNSHO, that'd be not just more jarring, it would be appalling. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-08 12:45 ` Eli Zaretskii @ 2021-12-08 13:33 ` John Ankarström 2021-12-08 13:38 ` Po Lu ` (3 more replies) 0 siblings, 4 replies; 111+ messages in thread From: John Ankarström @ 2021-12-08 13:33 UTC (permalink / raw) To: emacs-devel Eli Zaretskii <eliz@gnu.org> writes: >> From: John Ankarström <john@ankarstrom.se> >> Date: Wed, 08 Dec 2021 02:45:02 +0100 >> >> For what it's worth, I think that it would be a good idea to limit this >> feature to mouse-based scrolling. > > The display engine doesn't know what kind of user gestures (or even > Lisp program) caused the scroll, so doing that cleanly won't be easy, > if at all feasible. And Emacs users are likely to dislike a solution > that makes such a distinction, since many of them don't use the mouse. > >> I agree with Alan that, if you primarily use the keyboard for scrolling, >> it is very jarring if editing/movement commands bring the window view >> back to the original position. > > You'd prefer to have the editing command change the buffer in the > portion that stays invisible? IMNSHO, that'd be not just more > jarring, it would be appalling. No. What I meant is this: "Point-detached" scrolling is only useful if there is a way to move the point to the current view. Let's say the point is at the beginning of the buffer. I scroll down to look for a specific definition. I find it in the middle of the buffer. Now, I want to edit that definition. But how do I get the point to the currently viewed position? In (all?) "modern" editors, the only way to do this is by left-clicking. That's why I suggested limiting the whole feature to mouse-based scrolling. If you are scrolling with the mouse, it is natural to click to set a new position for the point. But if you are scrolling with, say, Page Up and Page Down, you would need to move your hand to the mouse to set a new position for the point. This makes the whole feature quite useless for any scrolling that isn't mouse-based. When scrolling with the keyboard, it is annoying if the only way to move the point to the scrolled-to position is by clicking the mouse. The alternative is to provide a keyboard-based way to move the point to the currently viewed portion of the buffer -- like a reverse C-l. Come to think of it, that is probably a better solution than limiting the feature to mouse-based scrolling. I adjust my opinion! ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-08 13:33 ` John Ankarström @ 2021-12-08 13:38 ` Po Lu 2021-12-08 13:52 ` John Ankarström 2021-12-08 14:26 ` Eli Zaretskii ` (2 subsequent siblings) 3 siblings, 1 reply; 111+ messages in thread From: Po Lu @ 2021-12-08 13:38 UTC (permalink / raw) To: John Ankarström; +Cc: emacs-devel John Ankarström <john@ankarstrom.se> writes: > No. What I meant is this: > "Point-detached" scrolling is only useful if there is a way to move the > point to the current view. > Let's say the point is at the beginning of the buffer. I scroll down to > look for a specific definition. I find it in the middle of the buffer. > Now, I want to edit that definition. But how do I get the point to the > currently viewed position? > In (all?) "modern" editors, the only way to do this is by left-clicking. > That's why I suggested limiting the whole feature to mouse-based > scrolling. If you are scrolling with the mouse, it is natural to click > to set a new position for the point. But if you are scrolling with, say, > Page Up and Page Down, you would need to move your hand to the mouse to > set a new position for the point. I'm not saying we shouldn't provide all the knobs to _allow_ limiting the scope of this feature to mouse wheel (or precision) scrolling, if that is what you mean by mouse scrolling, but I see no reason to limit the feature to that by default. > This makes the whole feature quite useless for any scrolling that isn't > mouse-based. When scrolling with the keyboard, it is annoying if the > only way to move the point to the scrolled-to position is by clicking > the mouse. If you don't like that behaviour, you will be able to turn it off by setting `scroll-move-point' to nil. In fact, it's off by default. Thanks. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-08 13:38 ` Po Lu @ 2021-12-08 13:52 ` John Ankarström 0 siblings, 0 replies; 111+ messages in thread From: John Ankarström @ 2021-12-08 13:52 UTC (permalink / raw) To: emacs-devel Po Lu <luangruo@yahoo.com> writes: >> That's why I suggested limiting the whole feature to mouse-based >> scrolling. If you are scrolling with the mouse, it is natural to click >> to set a new position for the point. But if you are scrolling with, say, >> Page Up and Page Down, you would need to move your hand to the mouse to >> set a new position for the point. > > I'm not saying we shouldn't provide all the knobs to _allow_ limiting > the scope of this feature to mouse wheel (or precision) scrolling, if > that is what you mean by mouse scrolling, but I see no reason to limit > the feature to that by default. Sounds good -- although I think that there should be an included command, like C-l, that moves the point to the currently viewed portion. >> This makes the whole feature quite useless for any scrolling that isn't >> mouse-based. When scrolling with the keyboard, it is annoying if the >> only way to move the point to the scrolled-to position is by clicking >> the mouse. > > If you don't like that behaviour, you will be able to turn it off by > setting `scroll-move-point' to nil. > > In fact, it's off by default. Which behavior do you mean? If you're referring to the point-detached scrolling, I *do* like that behavior. I would just dislike it if, again, there weren't any way (such as the reverse C-l I suggested) to move the point to the currently viewed portion. > Thanks. Thank you very much for working on this! I have wanted such a feature in Emacs for a long time :-) ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-08 13:33 ` John Ankarström 2021-12-08 13:38 ` Po Lu @ 2021-12-08 14:26 ` Eli Zaretskii 2021-12-08 16:57 ` Stefan Monnier 2021-12-08 19:21 ` Rudolf Schlatte 2021-12-08 22:25 ` Kévin Le Gouguec 3 siblings, 1 reply; 111+ messages in thread From: Eli Zaretskii @ 2021-12-08 14:26 UTC (permalink / raw) To: John Ankarström; +Cc: emacs-devel > From: John Ankarström <john@ankarstrom.se> > Date: Wed, 08 Dec 2021 14:33:01 +0100 > > The alternative is to provide a keyboard-based way to move the point to > the currently viewed portion of the buffer -- like a reverse C-l. > > Come to think of it, that is probably a better solution than limiting > the feature to mouse-based scrolling. I adjust my opinion! I think I agree with your adjusted opinion. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-08 14:26 ` Eli Zaretskii @ 2021-12-08 16:57 ` Stefan Monnier 2021-12-08 19:29 ` Yuri Khan 2021-12-09 0:16 ` Po Lu 0 siblings, 2 replies; 111+ messages in thread From: Stefan Monnier @ 2021-12-08 16:57 UTC (permalink / raw) To: Eli Zaretskii; +Cc: John Ankarström, emacs-devel IIUC the way this new feature is expected to work is that it prevents "scroll to bring point into view" under some conditions. I'm not sure exactly what are those conditions, but I'd expect it's something like: - point was not moved since last time we redisplayed this buffer. - the buffer was not modified since last time we redisplayed it. - window-start was set explicitly. So it should be easy to provide a "move point to view" with something like: (goto-char (window-start)) -- Stefan ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-08 16:57 ` Stefan Monnier @ 2021-12-08 19:29 ` Yuri Khan 2021-12-09 0:16 ` Po Lu 1 sibling, 0 replies; 111+ messages in thread From: Yuri Khan @ 2021-12-08 19:29 UTC (permalink / raw) To: Stefan Monnier; +Cc: Eli Zaretskii, John Ankarström, Emacs developers On Wed, 8 Dec 2021 at 23:58, Stefan Monnier <monnier@iro.umontreal.ca> wrote: > So it should be easy to provide a "move point to view" with something > like: > > (goto-char (window-start)) A better implementation would bring the point to the line of (window-start) when point is before (window-start), or to the line of (window-end) when after (window-end), while striving to keep the column unchanged or to move to goal-column, as if by (previous-line) or (next-line). ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-08 16:57 ` Stefan Monnier 2021-12-08 19:29 ` Yuri Khan @ 2021-12-09 0:16 ` Po Lu 1 sibling, 0 replies; 111+ messages in thread From: Po Lu @ 2021-12-09 0:16 UTC (permalink / raw) To: Stefan Monnier; +Cc: Eli Zaretskii, John Ankarström, emacs-devel Stefan Monnier <monnier@iro.umontreal.ca> writes: > IIUC the way this new feature is expected to work is that it prevents > "scroll to bring point into view" under some conditions. > I'm not sure exactly what are those conditions, but I'd expect it's > something like: > - point was not moved since last time we redisplayed this buffer. > - window-start was set explicitly. Yes. > - the buffer was not modified since last time we redisplayed it. This might not be necessary. > So it should be easy to provide a "move point to view" with something > like: > (goto-char (window-start)) It would probably have to take into account vscroll, as the cursor appearing in a partially visible row would be confusing. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-08 13:33 ` John Ankarström 2021-12-08 13:38 ` Po Lu 2021-12-08 14:26 ` Eli Zaretskii @ 2021-12-08 19:21 ` Rudolf Schlatte 2021-12-08 19:56 ` Juri Linkov 2021-12-09 0:17 ` Allowing point to be outside the window? Po Lu 2021-12-08 22:25 ` Kévin Le Gouguec 3 siblings, 2 replies; 111+ messages in thread From: Rudolf Schlatte @ 2021-12-08 19:21 UTC (permalink / raw) To: emacs-devel John Ankarström <john@ankarstrom.se> writes: > Eli Zaretskii <eliz@gnu.org> writes: > >>> From: John Ankarström <john@ankarstrom.se> >>> Date: Wed, 08 Dec 2021 02:45:02 +0100 >>> >>> For what it's worth, I think that it would be a good idea to limit this >>> feature to mouse-based scrolling. [...] > > That's why I suggested limiting the whole feature to mouse-based > scrolling. If you are scrolling with the mouse, it is natural to click > to set a new position for the point. But if you are scrolling with, say, > Page Up and Page Down, you would need to move your hand to the mouse to > set a new position for the point. > > This makes the whole feature quite useless for any scrolling that isn't > mouse-based. When scrolling with the keyboard, it is annoying if the > only way to move the point to the scrolled-to position is by clicking > the mouse. I briefly tested with two contemporary editors (Atom and VS Code), and their behavior indeed differs between mouse-based and keyboard-based scrolling: in the former case (scrolling via mouse), the cursor stays put and moves out of view, while in the latter case (scrolling via the PgDn key), the cursor changes position to stay on screen. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-08 19:21 ` Rudolf Schlatte @ 2021-12-08 19:56 ` Juri Linkov 2021-12-08 20:05 ` André A. Gomes 2021-12-08 20:31 ` Linux console scrollback [ Was: Allowing point to be outside the window? ] Alan Mackenzie 2021-12-09 0:17 ` Allowing point to be outside the window? Po Lu 1 sibling, 2 replies; 111+ messages in thread From: Juri Linkov @ 2021-12-08 19:56 UTC (permalink / raw) To: Rudolf Schlatte; +Cc: emacs-devel > I briefly tested with two contemporary editors (Atom and VS Code), and > their behavior indeed differs between mouse-based and keyboard-based > scrolling: in the former case (scrolling via mouse), the cursor stays > put and moves out of view, while in the latter case (scrolling via the > PgDn key), the cursor changes position to stay on screen. Linux console supported keyboard-based scrolling with Shift-PageDown/PageUp where the cursor stays on the command line and it scrolls back on a key press, but recently this feature was removed. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-08 19:56 ` Juri Linkov @ 2021-12-08 20:05 ` André A. Gomes 2021-12-08 20:31 ` Linux console scrollback [ Was: Allowing point to be outside the window? ] Alan Mackenzie 1 sibling, 0 replies; 111+ messages in thread From: André A. Gomes @ 2021-12-08 20:05 UTC (permalink / raw) To: Juri Linkov; +Cc: Rudolf Schlatte, emacs-devel Juri Linkov <juri@linkov.net> writes: >> I briefly tested with two contemporary editors (Atom and VS Code), and >> their behavior indeed differs between mouse-based and keyboard-based >> scrolling: in the former case (scrolling via mouse), the cursor stays >> put and moves out of view, while in the latter case (scrolling via the >> PgDn key), the cursor changes position to stay on screen. > > Linux console supported keyboard-based scrolling with Shift-PageDown/PageUp > where the cursor stays on the command line and it scrolls back on a key press, > but recently this feature was removed. Off-topic: I noticed it in the linux console recently. Is there a workaround? Thanks. -- André A. Gomes "Free Thought, Free World" ^ permalink raw reply [flat|nested] 111+ messages in thread
* Linux console scrollback [ Was: Allowing point to be outside the window? ] 2021-12-08 19:56 ` Juri Linkov 2021-12-08 20:05 ` André A. Gomes @ 2021-12-08 20:31 ` Alan Mackenzie 1 sibling, 0 replies; 111+ messages in thread From: Alan Mackenzie @ 2021-12-08 20:31 UTC (permalink / raw) To: Juri Linkov; +Cc: Rudolf Schlatte, emacs-devel Hello, Juri. On Wed, Dec 08, 2021 at 21:56:47 +0200, Juri Linkov wrote: > > I briefly tested with two contemporary editors (Atom and VS Code), and > > their behavior indeed differs between mouse-based and keyboard-based > > scrolling: in the former case (scrolling via mouse), the cursor stays > > put and moves out of view, while in the latter case (scrolling via the > > PgDn key), the cursor changes position to stay on screen. > Linux console supported keyboard-based scrolling with > Shift-PageDown/PageUp where the cursor stays on the command line and it > scrolls back on a key press, but recently this feature was removed. Just as a matter of interest, I've hacked the Linux sources to put this essential feature back again, in an improved fashion. Where previously one scrollback buffer was shared by all the tty's, causing the scrollback to be lost on moving to a different tty, now each tty has its own buffer which does not lose its contents by such a move. I've published the patch on the Gentoo user's list. It is slightly different for different kernel major versions. If anybody is interested in this patch, and can't be bothered to dig it out of the Gentoo list archive, feel free to send me an email, and I will reply with the patch and (short) directions for its use. -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-08 19:21 ` Rudolf Schlatte 2021-12-08 19:56 ` Juri Linkov @ 2021-12-09 0:17 ` Po Lu 1 sibling, 0 replies; 111+ messages in thread From: Po Lu @ 2021-12-09 0:17 UTC (permalink / raw) To: Rudolf Schlatte; +Cc: emacs-devel Rudolf Schlatte <rudi@constantly.at> writes: > I briefly tested with two contemporary editors (Atom and VS Code), and > their behavior indeed differs between mouse-based and keyboard-based > scrolling: in the former case (scrolling via mouse), the cursor stays > put and moves out of view, while in the latter case (scrolling via the > PgDn key), the cursor changes position to stay on screen. Then I think we would do well to replicate this change. ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-08 13:33 ` John Ankarström ` (2 preceding siblings ...) 2021-12-08 19:21 ` Rudolf Schlatte @ 2021-12-08 22:25 ` Kévin Le Gouguec 2021-12-08 23:17 ` John Ankarström 3 siblings, 1 reply; 111+ messages in thread From: Kévin Le Gouguec @ 2021-12-08 22:25 UTC (permalink / raw) To: John Ankarström; +Cc: emacs-devel John Ankarström <john@ankarstrom.se> writes: > The alternative is to provide a keyboard-based way to move the point to > the currently viewed portion of the buffer -- like a reverse C-l. Wouldn't the existing M-r (move-to-window-line-top-bottom) fit the bill? ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-08 22:25 ` Kévin Le Gouguec @ 2021-12-08 23:17 ` John Ankarström 0 siblings, 0 replies; 111+ messages in thread From: John Ankarström @ 2021-12-08 23:17 UTC (permalink / raw) To: emacs-devel Kévin Le Gouguec <kevin.legouguec@gmail.com> writes: > John Ankarström <john@ankarstrom.se> writes: > >> The alternative is to provide a keyboard-based way to move the point to >> the currently viewed portion of the buffer -- like a reverse C-l. > > Wouldn't the existing M-r (move-to-window-line-top-bottom) fit the bill? Ah, yes, good point! I've added support for it in my Elisp implementation and it works well. ^ permalink raw reply [flat|nested] 111+ messages in thread
[parent not found: <9603C99D-97E7-4285-A1C1-022191B6F5CC@univie.ac.at>]
* Re: Allowing point to be outside the window? [not found] <9603C99D-97E7-4285-A1C1-022191B6F5CC@univie.ac.at> @ 2021-12-08 18:43 ` Konrad Podczeck 2021-12-08 20:47 ` John Ankarström 0 siblings, 1 reply; 111+ messages in thread From: Konrad Podczeck @ 2021-12-08 18:43 UTC (permalink / raw) To: john; +Cc: emacs-devel Hi John, congratulations, the code works great! Do you allow to use it? If yes, what could I try so that, with hl-line-mode on, also the actually highlighted line scrolls out and in of the window, instead of dancing around? In any case, thanks for your effort, Konrad ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? 2021-12-08 18:43 ` Konrad Podczeck @ 2021-12-08 20:47 ` John Ankarström 0 siblings, 0 replies; 111+ messages in thread From: John Ankarström @ 2021-12-08 20:47 UTC (permalink / raw) To: emacs-devel Konrad Podczeck <konrad.podczeck@univie.ac.at> writes: > Hi John, > > congratulations, the code works great! Do you allow to use it? Of course! > If yes, what could I try so that, with hl-line-mode on, also the > actually highlighted line scrolls out and in of the window, instead of > dancing around? I've uploaded an updated version that supports hl-line-mode [1]. It adds an advice around hl-line-move that disables it while scrolling. The new version also supports inactive windows. [1] http://ankarstrom.se/~john/emacs/scroll-without-point.el ^ permalink raw reply [flat|nested] 111+ messages in thread
* Re: Allowing point to be outside the window? @ 2021-12-09 15:34 Konrad Podczeck 0 siblings, 0 replies; 111+ messages in thread From: Konrad Podczeck @ 2021-12-09 15:34 UTC (permalink / raw) To: john; +Cc: emacs-devel Hi John, the update concerning hl-line-mode works fine. However, I observe a spill-over between different frames. E.g., suppose I have open two buffers, say A and B, in two different frames. Do M-x scroll-without-point-mode, say in the frame showing A. Scroll in this frame so as to make the cursor there invisible. As soon as I use the mouse to make the frame showing B active, there is a jump back in the frame showing A. Now suppose the frame showing B is the active one, but the mouse is still over the other frame and scroll. Now any command in the frame showing B leads to a jump in frame A. Cam these be avoided? Konrad ^ permalink raw reply [flat|nested] 111+ messages in thread
end of thread, other threads:[~2022-02-10 13:09 UTC | newest] Thread overview: 111+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- [not found] <87ilwd7zaq.fsf.ref@yahoo.com> 2021-11-28 3:07 ` Allowing point to be outside the window? Po Lu 2021-11-28 8:03 ` Eli Zaretskii 2021-11-28 8:13 ` Po Lu 2021-11-28 8:41 ` Eli Zaretskii 2021-11-28 12:47 ` Po Lu 2021-11-28 12:58 ` Eli Zaretskii 2021-11-28 13:10 ` Po Lu 2021-11-28 13:44 ` Eli Zaretskii 2021-11-29 1:47 ` Po Lu 2021-11-29 13:00 ` Eli Zaretskii 2021-11-29 13:22 ` Po Lu 2021-11-29 13:43 ` Eli Zaretskii 2021-11-30 1:40 ` Po Lu 2021-11-30 16:49 ` [External] : " Drew Adams 2021-11-30 17:26 ` Eli Zaretskii 2021-11-30 18:10 ` Lars Ingebrigtsen 2021-11-30 18:32 ` Eli Zaretskii 2021-11-30 18:49 ` Stefan Kangas 2021-11-30 19:21 ` Eli Zaretskii 2021-11-30 20:57 ` Drew Adams 2021-11-30 23:41 ` Daniel Martín 2021-12-01 8:30 ` martin rudalics 2021-12-01 9:10 ` Juri Linkov 2021-11-30 23:20 ` Stefan Monnier 2021-12-04 11:18 ` Po Lu 2021-12-04 12:55 ` Eli Zaretskii 2021-12-04 13:13 ` Po Lu 2021-12-04 16:24 ` Eli Zaretskii 2021-12-05 0:40 ` Po Lu 2021-12-04 17:15 ` Eli Zaretskii 2021-12-05 0:45 ` Po Lu 2021-12-05 9:03 ` Eli Zaretskii 2021-12-06 2:11 ` Po Lu 2021-12-06 14:13 ` Eli Zaretskii 2021-12-07 2:18 ` Po Lu 2021-12-07 13:42 ` Eli Zaretskii 2021-12-08 1:17 ` Po Lu 2021-12-08 17:14 ` Eli Zaretskii 2021-12-09 0:23 ` Po Lu 2021-12-09 8:02 ` Eli Zaretskii 2021-12-09 9:22 ` Po Lu 2021-12-09 10:02 ` Eli Zaretskii 2021-12-25 6:45 ` Po Lu 2021-12-25 7:07 ` Eli Zaretskii 2022-02-06 7:22 ` Po Lu 2022-02-06 11:34 ` Eli Zaretskii 2022-02-06 11:46 ` Po Lu 2022-02-06 11:55 ` Eli Zaretskii 2022-02-06 12:21 ` Po Lu 2022-02-06 16:15 ` Eli Zaretskii 2022-02-07 1:21 ` Po Lu 2022-02-07 7:21 ` Po Lu 2022-02-07 13:41 ` Eli Zaretskii 2022-02-07 13:57 ` Po Lu 2022-02-07 14:24 ` Eli Zaretskii 2022-02-08 0:58 ` Po Lu 2022-02-08 17:08 ` Eli Zaretskii 2022-02-09 1:57 ` Po Lu 2022-02-10 13:04 ` Eli Zaretskii 2022-02-10 13:09 ` Po Lu 2021-12-09 11:45 ` Eli Zaretskii 2021-12-09 12:19 ` Po Lu 2021-12-09 12:45 ` Eli Zaretskii 2021-12-04 13:00 ` dick 2021-12-04 13:14 ` tomas 2021-12-04 13:19 ` Po Lu 2021-12-04 13:41 ` Eli Zaretskii 2021-12-05 0:46 ` Po Lu 2021-12-05 7:12 ` Eli Zaretskii 2021-12-05 7:16 ` Po Lu 2021-12-05 8:48 ` Eli Zaretskii 2021-12-05 9:15 ` Po Lu 2021-12-05 9:25 ` Eli Zaretskii 2021-12-05 9:31 ` Po Lu 2021-12-05 10:34 ` Eli Zaretskii 2021-12-05 10:37 ` Po Lu 2021-12-04 14:17 ` dick 2021-12-04 16:33 ` Eli Zaretskii 2021-12-04 17:13 ` dick 2021-12-05 0:48 ` Po Lu 2021-11-28 14:03 ` Alan Mackenzie 2021-11-28 14:28 ` Eric S Fraga 2021-11-28 14:39 ` Eli Zaretskii 2021-11-28 16:55 ` Eric S Fraga 2021-11-28 14:42 ` dick 2021-11-28 15:39 ` Kévin Le Gouguec 2021-11-28 15:45 ` Eli Zaretskii 2021-11-28 17:14 ` Kévin Le Gouguec 2021-11-28 16:59 ` Eric S Fraga 2021-11-28 17:30 ` Kévin Le Gouguec 2021-11-29 0:34 ` Dmitry Gutov 2021-11-29 0:34 ` Po Lu 2021-12-08 1:45 ` John Ankarström 2021-12-08 12:45 ` Eli Zaretskii 2021-12-08 13:33 ` John Ankarström 2021-12-08 13:38 ` Po Lu 2021-12-08 13:52 ` John Ankarström 2021-12-08 14:26 ` Eli Zaretskii 2021-12-08 16:57 ` Stefan Monnier 2021-12-08 19:29 ` Yuri Khan 2021-12-09 0:16 ` Po Lu 2021-12-08 19:21 ` Rudolf Schlatte 2021-12-08 19:56 ` Juri Linkov 2021-12-08 20:05 ` André A. Gomes 2021-12-08 20:31 ` Linux console scrollback [ Was: Allowing point to be outside the window? ] Alan Mackenzie 2021-12-09 0:17 ` Allowing point to be outside the window? Po Lu 2021-12-08 22:25 ` Kévin Le Gouguec 2021-12-08 23:17 ` John Ankarström [not found] <9603C99D-97E7-4285-A1C1-022191B6F5CC@univie.ac.at> 2021-12-08 18:43 ` Konrad Podczeck 2021-12-08 20:47 ` John Ankarström 2021-12-09 15:34 Konrad Podczeck
Code repositories for project(s) associated with this external index https://git.savannah.gnu.org/cgit/emacs.git https://git.savannah.gnu.org/cgit/emacs/org-mode.git This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.