5

From the doc of window-end function:

Even if update is non-nil, window-end does not attempt to scroll the display if point has moved off the screen, the way real redisplay would do. It does not alter the window-start value. In effect, it reports where the displayed text will end if scrolling is not required.

Since the window-end only reports where the displayed text will end if scrolling is not required, what should I do to get the correct window-end after I call next-line at the end of the current window, which causes the window to scroll by one line? Do I need something like forcing the window to redisplay before calling window-end function?

7
  • IIUC you just can't (except maybe by forcing a redisplay first, e.g. with (redisplay). Most likely if you explain more of what it is you're trying to do, we can give you a better answer.
    – Stefan
    Feb 27, 2016 at 14:39
  • @Stefan I am trying to implement some function in the package. The problem is that I need to know the up-to-date window-start and window-end to get all the visible lines, but when next-line causes the window to scroll, these window bounds are not correct.
    – cutejumper
    Feb 27, 2016 at 19:06
  • I don't know what "some function" is, and neither do I know why it needs to know the window-start/end and even less why it needs it during the execution of next-line.
    – Stefan
    Feb 27, 2016 at 20:45
  • It needs to know the window-start and window-end because I want to label the visual lines. When next-line cause the window to scroll, the visual lines are changed, so we need to change the overlay accordingly.
    – cutejumper
    Feb 27, 2016 at 21:07
  • Then you don't need to know window-start and window-end for that. Instead, you want to use fontification-functions which will be called on every part of the buffer that is displayed. Typically this is not used directly but instead it's done via jit-lock-register.
    – Stefan
    Feb 28, 2016 at 23:41

1 Answer 1

3

The best a user can achieve -- without forcing a redisplay or without modifying the C-source code -- is use the window-end function with the optional second argument set to t in conjunction with the window-scroll-functions hook that takes two arguments -- https://www.gnu.org/software/emacs/manual/html_node/elisp/Window-Hooks.html#Window-Hooks [NOTE: Forcing a redisplay may reveal to the naked eye (for a split second) an unfinished product -- e.g., perhaps the new overlays have not yet been removed/placed.]

CAVEAT:  Beware that the window-scroll-functions hook fires sometimes more than once during each command loop (while redisplay performs its job), and the first values for window-start and window-end win t are not always correct, and the last values are not always correct either -- e.g., when inserting/yanking, or when using goto. [Fn 1.] When the window-scroll-functions hook runs multiple times, the function attached to the hook can cause significant performance issues depending upon the complexity of said function. And, as mentioned, sometimes the user is simply out of luck -- i.e., correct values can never be obtained. Using pos-visible-in-window-p can be helpful as a workaround to set up some checks to prevent the function attached to the hook from fully running its course if point is not yet fully visible; and, a variable can be set up to test for whether the function has already fully run one time during that command loop (so that it doesn't keep running).

I have written a draft proof concept patch to the C-source code that I am using for my own personal setup to always get the correct window-start and window-end during redisplay; however, it may never make its way into the mainstream since I'm not a programmer and am the only person really motivated: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22404 It is called the window-start-end-hook -- but it's only available if a user wants to experiment with the draft patch and build Emacs from source. My draft patch works irrespective of window scrolling, e.g., it works when moving point within the visible window; it works when using goto; it works when inserting/yanking; and, it works when scrolling. Anyone interested in developing that concept should please feel free to submit a post to feature request 22404.


See also these related threads:

How to update window-start without calling redisplay?

https://stackoverflow.com/questions/23923371/emacs-calculating-new-window-start-end-without-redisplay/24216247#24216247


NOTE:  Debugging functions that run during redisplay may require using a feature called trace-redisplay (after launching Emacs from the command line) that is available when building Emacs from source with options such as: ./configure --enable-checking='glyphs'.


[Fn. 1.]:  When working with Bug #22637, Eli Z. on the Emacs development team explained that the reason the window-scroll-functions hook does not yield correct results for inserting/yanking or goto is because it was never designed for those scenarios: "The reason window-scroll-functions aren't run in both of these test cases is that what happens there is not considered 'scrolling'. Scrolling is informally defined as either an explicit call to a function that scrolls the window, or a pseudo-scroll done by the display engine when it detects that some part of the window's previous display is still present, but in a different vertical position. Moving point to an arbitrary location is neither." https://debbugs.gnu.org/cgi/bugreport.cgi?bug=22637#35

12
  • I don't aware of that @abo-abo has already asked a similar question! Basically I have the same question as him. I've read your post in that thread, and it seems there is no elegant solution yet. window-start-end-hook is good, but how can we push forward the feature request?
    – cutejumper
    Feb 27, 2016 at 19:15
  • Eli Z. is concerned that permitting a user to introduce Lisp into redisplay could cause Emacs to hang or crash; however, he also guided me towards using safe_call which I believe resolves that concern because the Lisp function will be canceled if there is an error during redisplay. Eli Z. would prefer a final hook that he calls the proposed post-redisplay-hook; however, I believe my solution is better because it permits a user to introduce Lisp that alters the layout (e.g., moves point or increases a font size) and redisplay will recheck the tentative result and do more work if needed.
    – lawlist
    Feb 27, 2016 at 19:34
  • Other than submitting a contemporaneous e-mail to Eli Z. and also feature 22404 voicing your input, I don't know what else can be done to make the feature a reality. John said he doesn't need to be carbon-copied directly because he reads all the bug e-mail. [I would certainly appreciate receiving a carbon-copy of feature 22404 related emails, if you wouldn't mind (since I don't regularly peruse the latest happenings).]
    – lawlist
    Feb 27, 2016 at 19:37
  • The window-start-end-hook fires completely (i.e., runs all of the code) when point is fully visible, but it has some built-in code that can be altered to fire completely when point is partially visible. Some users may want that partially visible ability -- see the doc-string for the built-in variable make-cursor-line-fully-visible which can be set to nil, but the default value is t. In other words, my draft proof concept is not a final product (it could still use some TLC) -- but I've been using it for a couple of weeks in my own setup and am very happy with it.
    – lawlist
    Feb 27, 2016 at 19:49
  • From a developer's point of view, I can't see what is blocking this issue to be solved. We should expect the window-start and window-end can always return the right values -- that is what these functions are supposed to do. I'll try the methods you've mentioned as well as @abo-abo 's approach.
    – cutejumper
    Feb 27, 2016 at 19:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.