simple_ls_controller/
simple_ls_controller.rs

1use std::io;
2
3use crossterm::event::{self, Event, KeyCode, KeyEventKind};
4use portable_pty::CommandBuilder;
5use ratatui::{
6    layout::Alignment,
7    style::{Modifier, Style},
8    text::Line,
9    widgets::{Block, Borders, Paragraph},
10    DefaultTerminal, Frame,
11};
12use tui_term::{controller::Controller, widget::PseudoTerminal};
13use vt100::Screen;
14
15fn main() -> std::io::Result<()> {
16    let mut terminal = ratatui::init();
17    let result = run_app(&mut terminal);
18    ratatui::restore();
19    result
20}
21
22fn run_app(terminal: &mut DefaultTerminal) -> std::io::Result<()> {
23    let terminal_size = terminal.size()?;
24    let size = Size {
25        rows: terminal_size.height,
26        cols: terminal_size.width,
27    };
28
29    // Subtract the borders from the size
30    let size = tui_term::controller::Size::new(size.cols - 2, size.rows, 0, 0);
31
32    let mut cmd = CommandBuilder::new("ls");
33    if let Ok(cwd) = std::env::current_dir() {
34        cmd.cwd(cwd);
35    }
36
37    let mut controller = Controller::new(cmd, Some(size));
38    controller.run();
39    let screen = controller.screen();
40
41    run(terminal, screen)
42}
43
44fn run(terminal: &mut DefaultTerminal, screen: Option<vt100::Screen>) -> io::Result<()> {
45    loop {
46        if let Some(ref screen) = screen {
47            terminal.draw(|f| ui(f, &screen))?;
48        }
49
50        if let Event::Key(key) = event::read()? {
51            if key.kind == KeyEventKind::Press {
52                if let KeyCode::Char('q') = key.code {
53                    return Ok(());
54                }
55            }
56        }
57    }
58}
59
60fn ui(f: &mut Frame, screen: &Screen) {
61    let chunks = ratatui::layout::Layout::default()
62        .direction(ratatui::layout::Direction::Vertical)
63        .margin(1)
64        .constraints(
65            [
66                ratatui::layout::Constraint::Percentage(100),
67                ratatui::layout::Constraint::Min(1),
68            ]
69            .as_ref(),
70        )
71        .split(f.area());
72    let title = Line::from("[ Running: ls ]");
73    let block = Block::default()
74        .borders(Borders::ALL)
75        .title(title)
76        .style(Style::default().add_modifier(Modifier::BOLD));
77    let pseudo_term = PseudoTerminal::new(screen)
78        .cursor(tui_term::widget::Cursor::default().visibility(false))
79        .block(block.clone());
80    f.render_widget(pseudo_term, chunks[0]);
81    let explanation = "Press q to exit";
82    let explanation = Paragraph::new(explanation)
83        .style(Style::default().add_modifier(Modifier::BOLD | Modifier::REVERSED))
84        .alignment(Alignment::Center);
85    f.render_widget(explanation, chunks[1]);
86}
87
88#[derive(Debug, Clone)]
89struct Size {
90    cols: u16,
91    rows: u16,
92}