ratatui-org / ratatui

Rust library that's all about cooking up terminal user interfaces (TUIs) 👨‍🍳🐀
https://ratatui.rs
MIT License
8.86k stars 269 forks source link

Consistent examples in ratatui #1157

Open kdheepak opened 1 month ago

kdheepak commented 1 month ago

Problem

On discord, we mentioned there was an issue with examples being inconsistent. I wanted to open an issue to track it.

Some of my thoughts are below. I think we need a few different kinds of examples:

  1. Examples of features used in a widget
  2. Examples of how to build more complicated applications on top of widgets / patterns one can follow etc
  3. Examples of how to structure applications

As an example, compare examples/paragraph.rs and examples/list.rs. IMO,

There's a complexity difference between these two categories.

Suggestions:

Perhaps the list.rs example works better as a tutorial than an example?

Examples that fall into category 1 should make it extremely easy for anyone to experiment with different features offered by said widget in Ratatui. To debug a problem on discord, I tried to start with the list.rs example but found it was too complicated to experiment with, and it was faster to write the following from scratch:

use crossterm::{
    event::{self, Event, KeyCode, KeyEventKind},
    execute,
    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use ratatui::{backend::CrosstermBackend, Terminal};

fn main() -> Result<(), color_eyre::eyre::Error> {
    let original_hook = std::panic::take_hook();

    std::panic::set_hook(Box::new(move |panic| {
        disable_raw_mode().unwrap();
        let mut terminal = Terminal::new(CrosstermBackend::new(std::io::stdout())).unwrap();
        execute!(terminal.backend_mut(), LeaveAlternateScreen).unwrap();
        original_hook(panic);
    }));

    let mut terminal = Terminal::new(CrosstermBackend::new(std::io::stdout()))?;
    enable_raw_mode()?;
    execute!(terminal.backend_mut(), EnterAlternateScreen)?;

    loop {
        let mut list_state = ratatui::widgets::ListState::default();

        list_state.select(Some(1));

        terminal.draw(|frame| {
            let area = frame.size();

            let items = ["Item 1", "Item 2", "Item 3"]
                .into_iter()
                .map(|s| ratatui::text::Text::from(s).centered());

            let list = ratatui::widgets::List::new(items)
                .highlight_symbol(" > ")
                .highlight_style(
                    ratatui::style::Style::default()
                        .fg(ratatui::style::Color::Black)
                        .bg(ratatui::style::Color::White),
                );

            frame.render_stateful_widget(list, area, &mut list_state)
        })?;

        if let Event::Key(key) = event::read()? {
            if key.kind == KeyEventKind::Press {
                match key.code {
                    KeyCode::Char('q') => break,
                    KeyCode::Char('j') => list_state.next(), // TODO implement .next()
                    KeyCode::Char('k') => list_state.previous(), // TODO implement .previous()
                    _ => (),
                }
            }
        }
    }

    disable_raw_mode()?;
    execute!(terminal.backend_mut(), LeaveAlternateScreen)?;
    Ok(())
}

We should solicit more input from users on what kinds of examples they find useful.

joshka commented 1 month ago

We should solicit more input from users on what kinds of examples they find useful.

I was thinking about the same today - a good place for this might be to add a small comment box on the website - e.g. if we move the examples to the website (https://github.com/ratatui-org/ratatui-website/issues/619) then that becomes a good place to solicit info. A simple thumbs up / down / with a textbox that posts to a kv store on cloudflare might be enough for this. There were also some suggestions just today on hn about feedback form approaches https://news.ycombinator.com/item?id=40524501

joshka commented 1 month ago

I refactored the list example in #1159 quite a bit.

I've been reading the bevy docs, and examples quite a bit recently, one thing I noted was that they have a bunch of examples on the same topic, some simple, some more advanced. I'd caution against making everything simple or converting it into a tutorial, as there's a lot of work going from example to tutorial well. I'd say a good middle ground would be webpages that have