toss/examples/text_wrapping.rs
Joscha 26a8936cf5 Store Styled with contiguous string
The previous implementation of Styled used chunks that consisted of a
String and a ContentStyle. The current implementation instead stores a
single String and chunks consisting of a ContentStyle and an ending
index.

This implementation may reduce allocations and makes width-related
operations easier, for example getting the width of a Styled with its
whitespace trimmed.
2022-08-01 19:02:57 +02:00

74 lines
2.4 KiB
Rust

use crossterm::event::Event;
use toss::frame::{Frame, Pos};
use toss::styled::Styled;
use toss::terminal::Terminal;
fn draw(f: &mut Frame) {
let text = concat!(
"This is a short paragraph in order to demonstrate unicode-aware word wrapping. ",
"Resize your terminal to different widths to try it out. ",
"After this sentence come two newlines, so it should always break here.\n",
"\n",
"Since the wrapping algorithm is aware of the Unicode Standard Annex #14, ",
"it understands things like non-breaking spaces and word joiners: ",
"This\u{00a0}sentence\u{00a0}is\u{00a0}separated\u{00a0}by\u{00a0}non-\u{2060}breaking\u{00a0}spaces.\n",
"\n",
"It can also properly handle wide graphemes (like emoji 🤔), ",
"including ones usually displayed incorrectly by terminal emulators, like 👩‍🔬 (a female scientist emoji).\n",
"\n",
"Finally, tabs are supported as well. ",
"The following text is rendered with a tab width of 4:\n",
"\tx\n",
"1\tx\n",
"12\tx\n",
"123\tx\n",
"1234\tx\n",
"12345\tx\n",
"123456\tx\n",
"1234567\tx\n",
"12345678\tx\n",
"123456789\tx\n",
);
let breaks = f.wrap(text, f.size().width.into());
let lines = Styled::new_plain(text).split_at_indices(&breaks);
for (i, mut line) in lines.into_iter().enumerate() {
line.trim_end();
f.write(Pos::new(0, i as i32), line);
}
}
fn render_frame(term: &mut Terminal) {
loop {
// Must be called before rendering, otherwise the terminal has out-of-date
// size information and will present garbage.
term.autoresize().unwrap();
draw(term.frame());
term.present().unwrap();
if term.measuring_required() {
term.measure_widths().unwrap();
} else {
break;
}
}
}
fn main() {
// Automatically enters alternate screen and enables raw mode
let mut term = Terminal::new().unwrap();
term.set_measuring(true);
term.set_tab_width(4);
loop {
// Render and display a frame. A full frame is displayed on the terminal
// once this function exits.
render_frame(&mut term);
// Exit if the user presses any buttons
if !matches!(crossterm::event::read().unwrap(), Event::Resize(_, _)) {
break;
}
}
}