tui-textarea
tui-textarea copied to clipboard
Feature request: Word wrap
This is super cool!
I want to make a little note editor using tui-textarea. But my notes will often use long lines - and ideally rendered with word wrap.
How can I do that? Would it be an easy change to make to tui-textarea? (I'm happy to get my hands dirty)
I was also hoping this was a feature. I'll take a look to see if I can figure out how to implement it.
Here is where a Paragraph widget is created during rendering:
https://github.com/rhysd/tui-textarea/blob/d4bbccbfdbf8c8be933c30c1f7ee61be2f18b6b4/src/widget.rs#L122-L125
Paragraph has a wrap() method to control line wrapping:
https://docs.rs/tui/latest/tui/widgets/struct.Wrap.html
So I think the render function could be changed to something like
let mut inner = Paragraph::new(text)
.style(self.0.style())
.alignment(self.0.alignment())
.wrap(Wrap { trim: false });
Of course a couple things will need to be done like adding a wrap option to the TextArea widget and related methods. I'm not sure if this would interfere with any of the logic for window scrolling and scroll position; perhaps there is an assumption that there is a 1-to-1 relation between a line in the text content and a rendered line in the terminal. I don't fully understand all the scroll position logic in that file.
I'm slowly starting to think about this as a new feature after 0.4.0. This is the biggest missing feature for this crate to be a simple textarea. Since width of each line is repeatedly required on rendering underlying Paragraph widget, lines would need to cache their width. I would need to start with internal refactoring because currently lines are kept as simplest Vec<String> and there is no place for the cache.
Based on my incomplete attempt to implement this before getting too busy to continue (https://github.com/rhysd/tui-textarea/pull/13), there's a couple considerations I'll mention.
In addition to caching line length, the number of rows (wrapped) that a single line occupies based on the area width might be good to cache.
In working out the logic for counting rows and positioning the cursor and viewport, it became quite annoying to try and distinguish between "rows" and "lines", whichever may be which, where one of them refers to a line of text in the text buffer, and one refers to rows in the terminal viewport. I think I have settled on referring to terminal "rows" and text "lines".
Another consideration is support for multiple-byte/char graphemes. Any special characters that are actually composed of multiple characters will change the way line length needs to be computed. I'm not sure if support for those is intended or not.
Another consideration that affects line length and line wrap calculations is whether or not line numbers are active.
I had a decent start to computing row wraps with https://github.com/rhysd/tui-textarea/pull/13/files#diff-4007187965c1fea4fd252a76f5f1007b2ea59f6d86e2f454edee547c5036be24R11
Another consideration that I hadn't yet figured out how to handle is that since text lines do not 1-1 map to terminal rows, and the viewport is positioned based on a text line, it is not possible to position the top edge of the terminal viewport in the middle of a wrapped row. I avoided this complexity with the requirement that scrolling up or down can only be done by an entire text line at a time; it works, but it's not typical expected behavior from a text field.
Perhaps it is necessary to create a buffer of "virtual" lines, that split the source text lines based on line wraps before the terminal renders them, allowing you to set the position in the middle of a wrapped text line.
Another sticky consideration is handling vertical cursor movement properly for wrapped lines. In my implementation, I stuck with a simplified movement that doesn't really consider line wraps. Moving the cursor up and down would not only require considering line wraps, but considering those graphemes that may be composed of multiple characters and affect the counting logic to place the cursor in the right spot.
If you get to this issue and need help, I will try to lend my efforts again.
+1 for this one, would be great to have :pray:
any updates on this one ?
@rhysd is there a way to prioritize this one plz :pray: many users are interested in it