clide/src/tui/app.rs

134 lines
4.4 KiB
Rust
Raw Normal View History

2026-01-17 17:09:42 -05:00
use crate::tui::component::{Action, ClideComponent};
use crate::tui::explorer::Explorer;
2026-01-17 14:04:02 -05:00
use ratatui::buffer::Buffer;
use ratatui::layout::{Constraint, Direction, Layout, Rect};
use ratatui::prelude::{Color, Style, Widget};
use ratatui::widgets::{Block, Borders, Padding, Paragraph, Tabs, Wrap};
use ratatui::{DefaultTerminal, symbols};
2026-01-17 17:09:42 -05:00
#[derive(Debug, Clone)]
2026-01-17 14:04:02 -05:00
pub struct App<'a> {
explorer: Explorer<'a>,
2026-01-17 14:04:02 -05:00
}
impl<'a> App<'a> {
pub(crate) fn new(root_path: &'a std::path::Path) -> Self {
Self {
explorer: Explorer::new(root_path),
}
2026-01-17 14:04:02 -05:00
}
pub fn run(mut self, mut terminal: DefaultTerminal) -> anyhow::Result<()> {
loop {
2026-01-17 17:09:42 -05:00
terminal.draw(|f| {
f.render_widget(&self, f.area());
})?;
// TODO: Handle events based on which component is active.
// match self.explorer.handle_events() { ... }
match self.handle_events() {
Action::Quit => break,
_ => {}
2026-01-17 14:04:02 -05:00
}
}
Ok(())
}
2026-01-17 17:09:42 -05:00
fn draw_status(&self, area: Rect, buf: &mut Buffer) {
// TODO: Status bar should have drop down menus
2026-01-17 14:04:02 -05:00
Tabs::new(["File", "Edit", "View", "Help"])
.style(Style::default())
.block(Block::default().borders(Borders::ALL))
.render(area, buf);
}
2026-01-17 17:09:42 -05:00
fn draw_tabs(&self, area: Rect, buf: &mut Buffer) {
2026-01-17 14:04:02 -05:00
// TODO: Tabs should be opened from file explorer
Tabs::new(["file.md", "file.cpp"])
.divider(symbols::DOT)
.block(
Block::default()
.borders(Borders::NONE)
.padding(Padding::new(0, 0, 0, 0)),
)
.highlight_style(Style::default().fg(Color::LightRed))
.render(area, buf);
}
2026-01-17 17:09:42 -05:00
fn draw_editor(&self, area: Rect, buf: &mut Buffer) {
2026-01-17 14:04:02 -05:00
// TODO: Title should be detected programming language name
// TODO: Content should be file contents
// TODO: Contents should use vim in rendered TTY
// TODO: Vimrc should be used
Paragraph::new("This is an example of the TUI interface (press 'q' to quit)")
.style(Style::default())
.block(
Block::default()
.title("Rust")
.title_style(Style::default().fg(Color::Yellow))
.borders(Borders::ALL)
.padding(Padding::new(0, 0, 0, 1)),
)
.wrap(Wrap { trim: false })
.render(area, buf);
}
2026-01-17 17:09:42 -05:00
fn draw_terminal(&self, area: Rect, buf: &mut Buffer) {
2026-01-17 14:04:02 -05:00
// TODO: Title should be detected shell name
// TODO: Contents should be shell output
Paragraph::new("shaun@pc:~/Code/clide$ ")
2026-01-17 14:04:02 -05:00
.style(Style::default())
.block(
Block::default()
.title("Bash")
.title_style(Style::default().fg(Color::DarkGray))
.borders(Borders::ALL),
)
.wrap(Wrap { trim: false })
.render(area, buf);
}
}
// TODO: Separate complex components into their own widgets.
2026-01-17 17:09:42 -05:00
impl<'a> Widget for &App<'a> {
2026-01-17 14:04:02 -05:00
fn render(self, area: Rect, buf: &mut Buffer)
where
Self: Sized,
{
let vertical = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Length(3), // status bar
Constraint::Percentage(70), // horizontal layout
Constraint::Percentage(30), // terminal
])
.split(area);
let horizontal = Layout::default()
.direction(Direction::Horizontal)
.constraints([
Constraint::Max(30), // File explorer with a max width of 30 characters.
Constraint::Fill(1), // Editor fills the remaining space.
])
.split(vertical[1]);
let editor_layout = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Length(1), // Editor tabs.
2026-01-17 17:09:42 -05:00
Constraint::Fill(1), // Editor contents.
2026-01-17 14:04:02 -05:00
])
.split(horizontal[1]);
self.draw_status(vertical[0], buf);
self.draw_terminal(vertical[2], buf);
2026-01-17 17:09:42 -05:00
self.explorer.render(horizontal[0], buf);
2026-01-17 14:04:02 -05:00
self.draw_tabs(editor_layout[0], buf);
self.draw_editor(editor_layout[1], buf);
}
}
2026-01-17 17:09:42 -05:00
impl<'a> ClideComponent for App<'a> {}