now actually modifies the filesystem. renaming files tbd

main
nick 2024-10-02 16:04:11 -04:00
parent 4f9b52151c
commit 15a2b700cd
3 changed files with 80 additions and 17 deletions

View File

@ -1,6 +1,10 @@
mod display;
mod item;
use std::fs::{remove_dir_all, remove_file, DirBuilder, File};
use std::io::Error;
use std::path::PathBuf;
use tui::widgets::{Block, Borders, List, ListItem};
use tui::style::{Color, Style};
use tui::layout::Rect;
@ -17,12 +21,37 @@ pub struct Directory {
editing: bool,
}
impl Directory {
pub fn new(root: String) -> Self {
Self {
pub fn new(root: String) -> Result<Self, Error> {
DirBuilder::new()
.recursive(true)
.create(&root)?;
Ok(Self {
dirs: vec![Item::new(root, 0, false)],
selection: 0,
editing: false,
})
}
pub fn path(&self) -> PathBuf {
let s = self.selected();
let init = (PathBuf::from(s.name.as_str()), s.depth);
let (result, _) = self.dirs[0..=self.selection()]
.iter()
.rev()
.fold(
init,
|(mut path, mut depth), d| {
if d.depth < depth {
path = PathBuf::from(&d.name).join(path);
depth = d.depth;
}
(path, depth)
}
);
result
}
pub fn select_prev(&mut self) {
@ -47,7 +76,28 @@ impl Directory {
};
let new = Item::new(name, depth, is_file);
self.dirs.insert(self.selection()+1, new);
self.selection += 1;
self.dirs.insert(self.selection(), new);
}
fn create(&self) -> Result<(), Error> {
if self.selected().is_file {
File::create(self.path())?;
} else {
DirBuilder::new()
.recursive(true)
.create(self.path())?;
}
Ok(())
}
fn delete(&self) -> Result<(), Error> {
if self.selected().is_file {
remove_file(self.path())
} else {
remove_dir_all(self.path())
}
}
fn selected(&self) -> &Item {
@ -69,12 +119,10 @@ impl Directory {
match c {
'f' | 'F' => {
self.insert(String::new(), true);
self.select_next();
self.editing = true;
},
'd' | 'D' => {
self.insert(String::new(), false);
self.select_next();
self.editing = true;
},
'x' | 'X' => {
@ -89,12 +137,22 @@ impl Directory {
self.editing = true;
},
KeyCode::Esc => return Message::Exit,
KeyCode::Backspace => {
KeyCode::Backspace if self.selected().depth > 0 => {
self.delete().unwrap();
if self.selected().is_file {
self.dirs.remove(self.selection());
if self.selection() == self.dirs.len() {
self.selection -= 1;
} else {
let target_depth = self.selected().depth;
let end = (self.selection()+1 .. self.dirs.len())
.find(|&i| self.dirs[i].depth <= target_depth)
.unwrap_or(self.dirs.len());
self.dirs.drain(self.selection()..end);
}
if self.selection() >= self.dirs.len() {
self.selection -= 1;
}
}
_ => (),
@ -107,9 +165,12 @@ impl Directory {
match key {
KeyCode::Char(c) => self.selected_mut().name.push(c),
KeyCode::Enter | KeyCode::Esc if !self.selected().name.is_empty() => {
self.create().unwrap();
self.editing = false;
},
KeyCode::Backspace => { self.selected_mut().name.pop(); },
KeyCode::Backspace => {
self.selected_mut().name.pop();
},
_ => (),
}

View File

@ -17,7 +17,7 @@ fn main() -> Result<(), Error> {
let mut terminal = Terminal::new()?;
let area = terminal.size()?;
let mut state = State::new(area);
let mut state = State::new(area)?;
loop {
state.render(&mut terminal)?;

View File

@ -22,13 +22,13 @@ pub struct State {
command: Option<Either<Command, CommandOutput>>
}
impl State {
pub fn new(area: Rect) -> Self {
let dir = Directory::new("root".into());
Self {
pub fn new(area: Rect) -> Result<Self, Error> {
let dir = Directory::new("root".into())?;
Ok(Self {
dir,
size: area,
command: None,
}
})
}
pub fn render(&self, terminal: &mut Terminal) -> Result<(), Error> {
@ -112,11 +112,13 @@ impl State {
else { unsafe { unreachable_unchecked() } };
let mut iter = cmd.buf()
.split(' ');
.split(' ')
.filter(|s| !s.is_empty());
let prog_name = iter.next().unwrap();
let output = Executable::new(prog_name)
.args(iter)
.arg(self.dir.path())
.output();
let command_output = CommandOutput::new(output.map(|o| o.stdout));