Paragraph
Demonstrates the Paragraph
widget.
git clone https://github.com/ratatui/ratatui.git --branch latestcd ratatuicargo run --example=paragraph --features=crossterm
//! # [Ratatui] Paragraph example//!//! The latest version of this example is available in the [examples] folder in the repository.//!//! Please note that the examples are designed to be run against the `main` branch of the Github//! repository. This means that you may not be able to compile with the latest release version on//! crates.io, or the one that you have installed locally.//!//! See the [examples readme] for more information on finding examples that match the version of the//! library you are using.//!//! [Ratatui]: https://github.com/ratatui/ratatui//! [examples]: https://github.com/ratatui/ratatui/blob/main/examples//! [examples readme]: https://github.com/ratatui/ratatui/blob/main/examples/README.md
use std::{    io::{self},    time::{Duration, Instant},};
use color_eyre::Result;use ratatui::{    buffer::Buffer,    crossterm::event::{self, Event, KeyCode, KeyEventKind},    layout::{Constraint, Layout, Rect},    style::{Color, Stylize},    text::{Line, Masked, Span},    widgets::{Block, Paragraph, Widget, Wrap},    DefaultTerminal,};
fn main() -> Result<()> {    color_eyre::install()?;    let terminal = ratatui::init();    let app_result = App::new().run(terminal);    ratatui::restore();    app_result}
#[derive(Debug)]struct App {    should_exit: bool,    scroll: u16,    last_tick: Instant,}
impl App {    /// The duration between each tick.    const TICK_RATE: Duration = Duration::from_millis(250);
    /// Create a new instance of the app.    fn new() -> Self {        Self {            should_exit: false,            scroll: 0,            last_tick: Instant::now(),        }    }
    /// Run the app until the user exits.    fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {        while !self.should_exit {            terminal.draw(|frame| frame.render_widget(&self, frame.area()))?;            self.handle_events()?;            if self.last_tick.elapsed() >= Self::TICK_RATE {                self.on_tick();                self.last_tick = Instant::now();            }        }        Ok(())    }
    /// Handle events from the terminal.    fn handle_events(&mut self) -> io::Result<()> {        let timeout = Self::TICK_RATE.saturating_sub(self.last_tick.elapsed());        while event::poll(timeout)? {            if let Event::Key(key) = event::read()? {                if key.kind == KeyEventKind::Press && key.code == KeyCode::Char('q') {                    self.should_exit = true;                }            }        }        Ok(())    }
    /// Update the app state on each tick.    fn on_tick(&mut self) {        self.scroll = (self.scroll + 1) % 10;    }}
impl Widget for &App {    fn render(self, area: Rect, buf: &mut Buffer) {        let areas = Layout::vertical([Constraint::Max(9); 4]).split(area);        Paragraph::new(create_lines(area))            .block(title_block("Default alignment (Left), no wrap"))            .gray()            .render(areas[0], buf);        Paragraph::new(create_lines(area))            .block(title_block("Default alignment (Left), with wrap"))            .gray()            .wrap(Wrap { trim: true })            .render(areas[1], buf);        Paragraph::new(create_lines(area))            .block(title_block("Right alignment, with wrap"))            .gray()            .right_aligned()            .wrap(Wrap { trim: true })            .render(areas[2], buf);        Paragraph::new(create_lines(area))            .block(title_block("Center alignment, with wrap, with scroll"))            .gray()            .centered()            .wrap(Wrap { trim: true })            .scroll((self.scroll, 0))            .render(areas[3], buf);    }}
/// Create a bordered block with a title.fn title_block(title: &str) -> Block {    Block::bordered()        .gray()        .title(title.bold().into_centered_line())}
/// Create some lines to display in the paragraph.fn create_lines(area: Rect) -> Vec<Line<'static>> {    let short_line = "A long line to demonstrate line wrapping. ";    let long_line = short_line.repeat(usize::from(area.width) / short_line.len() + 4);    let mut styled_spans = vec![];    for span in [        "Styled".blue(),        "Spans".red().on_white(),        "Bold".bold(),        "Italic".italic(),        "Underlined".underlined(),        "Strikethrough".crossed_out(),    ] {        styled_spans.push(span);        styled_spans.push(" ".into());    }    vec![        Line::raw("Unstyled Line"),        Line::raw("Styled Line").black().on_red().bold().italic(),        Line::from(styled_spans),        Line::from(long_line.green().italic()),        Line::from_iter([            "Masked text: ".into(),            Span::styled(Masked::new("my secret password", '*'), Color::Red),        ]),    ]}