dirbuilder/src/state.rs

139 lines
3.7 KiB
Rust
Raw Normal View History

2024-10-02 14:56:07 -04:00
use std::hint::unreachable_unchecked;
2024-10-02 12:28:14 -04:00
use std::io::Error;
2024-10-02 14:56:07 -04:00
use std::process::Command as Executable;
2024-10-02 12:28:14 -04:00
use crossterm::event::KeyCode;
use tui::layout::Rect;
2024-10-02 14:56:07 -04:00
use crate::command::Command;
use crate::command_output::CommandOutput;
2024-10-02 12:28:14 -04:00
use crate::directory::Directory;
2024-10-02 14:56:07 -04:00
use crate::pane::{Message, Pane};
2024-10-02 12:28:14 -04:00
use crate::terminal::Terminal;
2024-10-02 14:56:07 -04:00
enum Either<T, U> {
Cmd(T),
CmdOut(U),
}
2024-10-02 12:28:14 -04:00
pub struct State {
2024-10-02 14:56:07 -04:00
dir: Directory,
size: Rect,
command: Option<Either<Command, CommandOutput>>
2024-10-02 12:28:14 -04:00
}
impl State {
2024-10-03 12:30:23 -04:00
pub fn new(root: String, area: Rect) -> Result<Self, Error> {
let dir = Directory::new(root)?;
Ok(Self {
2024-10-02 14:56:07 -04:00
dir,
size: area,
command: None,
})
2024-10-02 12:28:14 -04:00
}
2024-10-02 14:56:07 -04:00
pub fn render(&self, terminal: &mut Terminal) -> Result<(), Error> {
let command_size = match &self.command {
None => 0,
Some(e) => match e {
Either::Cmd(c) => c.lines_hint(),
Either::CmdOut(o) => o.lines_hint(),
}
};
let (dir_area, bottom_area) = if command_size > 0 {
(Rect {
height: self.size.height - command_size as u16 - 2,
..self.size
}, Rect {
y: self.size.height - command_size as u16 - 2,
height: command_size as u16 + 2,
..self.size
})
} else {
(self.size, self.size)
};
2024-10-02 12:28:14 -04:00
terminal.draw(
2024-10-02 14:56:07 -04:00
|output| {
self.dir.display(output, dir_area);
if let Some(command) = self.command.as_ref() {
match command {
Either::Cmd(cmd) => cmd.display(output, bottom_area),
Either::CmdOut(cmd) => cmd.display(output, bottom_area),
}
}
}
2024-10-02 12:28:14 -04:00
)?;
Ok(())
}
2024-10-02 14:56:07 -04:00
const fn current_pane(&self) -> &dyn Pane {
match self.command.as_ref() {
None => &self.dir,
Some(either) => match either {
Either::Cmd(c) => c,
Either::CmdOut(o) => o,
}
}
}
2024-10-02 12:28:14 -04:00
pub fn cursor_position(&self) -> Option<(u16, u16)> {
2024-10-02 14:56:07 -04:00
let pane = self.current_pane();
let (x, y) = pane.cursor_position()?;
let new_x = x + 1;
let dy = if let Some(Either::Cmd(c)) = &self.command {
self.size.height - c.lines_hint() as u16 - 2
} else {
self.size.y
};
let new_y = y + dy + 1;
Some((new_x, new_y))
2024-10-02 12:28:14 -04:00
}
pub fn update(&mut self, key: KeyCode) -> Message {
2024-10-02 14:56:07 -04:00
match self.command.as_mut() {
None => self.dir.update(key),
Some(either) => match either {
Either::Cmd(c) => c.update(key),
Either::CmdOut(_) => { self.close_window(); Message::Nothing },
}
}
}
pub fn begin_command(&mut self) {
self.command = Some(Either::Cmd(Command::new()));
}
pub fn execute_command(&mut self) {
let Some(Either::Cmd(cmd)) = self.command.take()
else { unsafe { unreachable_unchecked() } };
let mut iter = cmd.buf()
.split(' ')
.filter(|s| !s.is_empty());
2024-10-02 14:56:07 -04:00
let prog_name = iter.next().unwrap();
let output = Executable::new(prog_name)
.args(iter)
.arg(self.dir.path())
2024-10-02 14:56:07 -04:00
.output();
let command_output = CommandOutput::new(output.map(|o| o.stdout));
if !command_output.should_display() {
return;
}
self.command = Some(Either::CmdOut(command_output));
}
pub fn cancel_command(&mut self) {
self.command = None;
}
pub fn close_window(&mut self) {
self.command = None;
2024-10-02 12:28:14 -04:00
}
}