-
Notifications
You must be signed in to change notification settings - Fork 863
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Widget.refresh
Method Not Cropping To Region
Start Correctly
#5625
Comments
You should consider this to be an implementation detail. When you add a region to refresh, you are informing Textual which regions have changed. You aren't saying exactly which characters to update. It's up to Textual to decide which segments / characters to build in to the next update. This means that your render_line should always return the up-to-date state of your widget. i.e. it should never make assumptions about how it is called. The currently implementation does update more than is needed. It is generally more efficient to do this, as it requires less cropping of segments (which is expensive), and it avoids issues where double width characters may be broken in half (which doesn't render well). So updating more on the screen can be a performance win. This may change in the future. As long as your |
Hi @willmcgugan, this came up in the context of https://github.com/davidfokkema/textual-hires-canvas. It works, but is not very fast. The Line API introduction reads:
So we were hoping to implement that. But it appears that even in the case of Segments containing only single characters, Textual refuses to update only the Region that was passed to refresh. With the proposed change there is no change in the number of calls to Phrased another way: is it, or is it currently not, possible to update single characters in the middle of the widget? |
...but I see that in the case of textual-plot, which uses textual-hires-canvas, that particular section of code is hardly ever executed. So changing it might not get us anything it seems. I'll have to dig deeper. |
It is possible in a sense. Rather than write the segments up to the place we want to update, Textual could simply move the cursor up to the start. That would reduce the amount of data sent to the terminal, and may be something worth doing. Although reducing the amount of data sent to the terminal is unlikely to have a material impact on performance here. Looking at your Let me suggest a different approach which I think will be faster. Rather than two 2D arrays, store the canvas as essentially a 2D array of Segment instances. Something like the following: BLANK = Segment(" ", Style())
lines = [[BLANK] * width for y in range(height)] Note that creates multiple references to the same blank segment, which will help caching. Your When you set a "pixel" you would update a single segment, and call refresh with a region that covers that segment. Bonus point if you cache those lines. So if BTW I'm loving the work you are doing on textual-hires-canvas. It's a terrific addition! |
Thanks! I'll set up a proper performance testing application to work on that. Right now I find it hard to interpret pyinstrument output from run to run because I run the app for a bit and then quit it and get only wall clock times, but the app did not render the same number of frames.
I think the code @ddkasa posted above implements just that. After some testing, and maybe tweaking it a bit, that could be turned into a PR. So if you think it's worth doing, although it wouldn't help textual-hires-canvas much, we could proceed with a PR. If you think it's not worth it, you can close the issue, ;-). |
It's worth doing in principle. Conceptually that's exactly what we need to do, but I'll leave this issue open, to tackle when I get back. Although I'm happy to elaborate on the solution I have in mind, if either of you want to give it a go... |
Sure, if that saves you time, we can look at it in more detail! No rush, though. |
The Bug
When supplying explicit regions with the
Widget.refresh
command Textual does not crop the region correctly. It will crop the end of the region correctly, but refresh everything before that instead of cropping to the start.Video
Current
region_refresh.webm
Expected
expected_refresh.webm
MRE
Possible Cause/Solution
Through some exploration of the
_compositor.py
module, I find that theChopsUpdate.render_segments
method is not cropping up to the start of the region, but to the start of theStrip
instead.textual/src/textual/_compositor.py
Lines 266 to 268 in dd36b69
Changing the above to the code below leads to the expected outcome.
A side note is that the Rich console repr has a todo comment leftover in it which mentions it, so it might have been forgotten in the
ChopsUpdate.render_segments
method as well.textual/src/textual/_compositor.py
Line 198 in 732c6b9
Accounting for the previous
Compositor
logic, this step makes most sense in terms of the problem source. Might be wrong though, so getting extra pairs of eyes on this would great.Textual Diagnostics
Versions
Python
Operating System
Terminal
Rich Console options
The text was updated successfully, but these errors were encountered: