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
RFC: Text Wrapping Design #293
Comments
Pinging @lthoerner @TimerErTim @topaxi |
On point Example:
So the indentation would be |
I am interested in this refactor, maybe my use-case can help. I am building a pager (think file-viewer) like My problem is that I have no way of knowing how much |
One approach of solving that is to track both the first (real) line scrolled plus the offset of the line, so the rendering of lines becomes: lines.iter()
.skip(index)
.flat_map(|line| line.wrap(width etc))
.skip(offset)
.take(height)
.enumerate()
.foreach(|(line, y)| buffer.set_line(line, area.x, area.y + y, line.style()); By using a stateful widget rendering, then we can update the scroll position for situations like where we want to scroll up from (index = 100, offset = 0) -> (index = 100, offset = -1) which will be the same as (index = 99, offset = number_of_wrapped_lines_in_line_99_which_only_render_knows) |
This will not really work because the |
Last time I checked |
Yeah, the two versions are incompatible because it has been changed from a field of |
That change to trim is on the PR for wrapping, so It hasn't changed yet. I'm not sure it should be changed given the rationale for it existing (fdehau/tui-rs#327). Briefly stated, the trim option was introduced in order to make it possible to maintain the indentation of lines that will be wrapped to support wrapping e.g.:
to:
instead of:
i.e. it should only effect lines that are wrapped. Not those that don't. I'd suggest that there's a better way of specifying that behavior that would incorporate the indentation as some enum that could have values like: WrapToFirstColumn, WrapToFirstNonWhitespaceColumn, WrapWithPrefix(" |"), WrapWithFunction(fn(Line)->Span) etc. |
Updated with significant amount more links, and better requirements. |
There's an approach that is suggested in https://docs.rs/textwrap/0.16.0/textwrap/wrap_algorithms/fn.wrap_first_fit.html and https://docs.rs/textwrap/0.16.0/textwrap/core/index.html that would be very useful (and would remove most of the actual wrapping code from Ratatui). At a high level, we would need to:
|
While I agree with the sentiment behind this, I think it may be too complicated. I like the |
This is definitely better. @lthoerner do you have any insight into the requirements that are necessary for character based wrapping - perhaps a list of functional requirements like above?. I'd imagine that being able to add indent text would be handy for the terminal like:
|
A few things:
I can't really speak to what implementation I would prefer, but my approach was to implement a trait on text types that allowed them to be wrapped with a method. |
Thanks for these
I think this is probably covered by:
If the implementation of this is at the
That approach is definitely the way for public APIs. If we have tests that cover the same behavior, and can show that it's unchanged by the new implementation (or that changes are reasonable fixes for bugs) do you think we can go faster in removing that code?
Definitely - The way to go with this is to ensure that the tests adequately cover the edge cases of the reflow module by testing from the perspective of paragraph rather than testing the internals. Doing this prior to making any changes to rip out Line Composer is important. That way any change in behavior shows a simultaneous change in a test rather than the implementation being inseparable from the testing.
At a high level that sounds good - can you remind me how the interface would look like for that? For character boundary wrapping, I think there's situations where you want to keep the whitespace always right? Are there any edge cases that you're aware of there? |
Not entirely. FR 7 as written will end up with potentially unexpected or unpredictable behavior when parts of the text are updated, particularly ones that aren't on screen. It would be a good idea to look at how existing editors do this.
All I will say is that I ran into issues with implementing it as a trait where different implementations needed different arguments. |
Got it. That sounds like something that has a part of it out of scope for the wrapping implementation, but the part that matters for wrapping is the interaction with scrolling, so I think you're probably saying that we need to add something like:
Does that sound about right? |
Inspired by https://discord.com/channels/1070692720437383208/1070692720437383211/1200159591107932272 an extra requirement to consider for this is to cache the wrapped lines to avoid duplicating work on each frame. |
I didn't read the entire discussion so sorry if this has been mentioned before. There are two characters(at least that's what I am aware of) that needs to be handled carefully: NBSP(Non breaking white space, U+00A0) and ZWSP(Zero width white space, U+200B, https://unicode-explorer.com/c/200B). My use case is wrapping help text that shows the key binding:
I don't want a key binding be break down in the middle like this: And in the mean while I inserted ZWSP to indicate a possible text wrapping point. It seems for now(ratatui 0.26.2) the wrapping feature of I think my use case is fairly common so I would appreciate it if anyone have existing workaround for such use cases. And note that ZWSP is not a white space character recognized by |
Well, it seems that this is the only reason that blocks ZWSP from being supported. I made a PR to fix it: #1074 |
Request for comment
The intent of this issue is to generate feedback and incorporate that into the design of wrapping. Recently there have been a few PRs that have attempted to tackle the existing state of the reflow module, and in doing so they change the existing behavior in order to implement new functionality. At the same time, we have multiple overlapping feature requests around wrapping (and scrolling).
Problems
reflow
module code is fairly convoluted and difficult to understand, add new functionality to, and to generally maintain. We've recently added some new features, and want to add more.Paragraph
widget.Functional Requirements
Line
s can be wrappedText
can be wrappedText
/Line
s can be wrappedtextwrap
Non-functional requirements
Questions / Tasks
Links
From tui-rs:
From Ratatui:
Paragraph
. #136Paragraph
#193Line
s to be individually truncated/wrapped #201fmt::Write
forText
#202 (maybe)reflow.rs
andLineComposer
logic to be readable #259(The quantity of issues / PRs related to wrapping should hint at why this is non-trivial)
Solution (WIP)
text::Wrap
for configuring the wrappingLine
,Text
, and any widgets that support wrapping to be configured withWrap
Paragraph::wrap()
to takeInto<text::Wrap>
and define a conversion from the existing Wrap type.Line::wrapped_lines(...)
which returns an iterator of lines based on the configuration and any other necessary state (e.g. width / height)Text::wrapped_lines(...)
which does similar, (TBD understand how to pass in scroll info)render_wrapped_lines()
method.Edits
2023-06-05: Added more links, split functional / non-functional and simplified reqs
The text was updated successfully, but these errors were encountered: