rename and clippy

This commit is contained in:
2025-08-24 01:13:17 -05:00
parent 5b283ae40d
commit b329ba8261
2 changed files with 102 additions and 62 deletions
+34 -22
View File
@@ -1,24 +1,23 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::fs; use std::fs;
use std::io::Error; use std::path::{Path, PathBuf};
use std::path::PathBuf;
use std::process::Command; use std::process::Command;
use thiserror::Error; use thiserror::Error;
use crate::fleen_app::FleenError::{RootDirNonexistenceError, RootDirPopulatedError}; use crate::fleen_app::FleenError::{RootDirNonexistence, RootDirPopulated};
use crate::fleen_app::TreeEntry::{CloseDir, Dir}; use crate::fleen_app::TreeEntry::{CloseDir, Dir};
#[derive(Error, Debug, Clone)] #[derive(Error, Debug, Clone)]
pub enum FleenError { pub enum FleenError {
#[error("Can't reach root dir {0}")] #[error("Can't reach root dir {0}")]
RootDirNonexistenceError(PathBuf), RootDirNonexistence(PathBuf),
#[error("Root dir is nonempty, you probably don't want to create an app here: {0}")] #[error("Root dir is nonempty, you probably don't want to create an app here: {0}")]
RootDirPopulatedError(PathBuf), RootDirPopulated(PathBuf),
#[error("Failed to open {0}: {1}")] #[error("IO error on {0}: {1}")]
FileIoError(String, String), FileIo(String, String),
#[error("Can't create {0} because it already exists")] #[error("Can't create {0} because it already exists")]
FileExistsError(PathBuf), FileExists(PathBuf),
#[error("Can't create {0}: {1}")] #[error("Can't create {0}: {1}")]
FileCreateError(PathBuf, String) FileCreate(PathBuf, String)
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@@ -42,7 +41,7 @@ impl FleenApp {
pub fn open(root: PathBuf) -> Result<Self, FleenError> { pub fn open(root: PathBuf) -> Result<Self, FleenError> {
match root.try_exists() { match root.try_exists() {
Ok(true) => Ok(Self { root, files_cache: RefCell::new(None) }), Ok(true) => Ok(Self { root, files_cache: RefCell::new(None) }),
_ => Err(RootDirNonexistenceError(root)) _ => Err(RootDirNonexistence(root))
} }
} }
@@ -50,13 +49,13 @@ impl FleenApp {
match root.read_dir() { match root.read_dir() {
Ok(mut iter) => { Ok(mut iter) => {
if iter.next().is_some() { if iter.next().is_some() {
Err(RootDirPopulatedError(root)) Err(RootDirPopulated(root))
} else { } else {
Ok(Self { root, files_cache: RefCell::new(None) }) Ok(Self { root, files_cache: RefCell::new(None) })
} }
} }
Err(_) => { Err(_) => {
Err(RootDirNonexistenceError(root)) Err(RootDirNonexistence(root))
} }
} }
} }
@@ -66,7 +65,7 @@ impl FleenApp {
if self.files_cache.borrow().is_none() || force { if self.files_cache.borrow().is_none() || force {
let mut entries = vec![]; let mut entries = vec![];
fn visit_dir(dir: &PathBuf, entries: &mut Vec<TreeEntry>) { fn visit_dir(dir: &Path, entries: &mut Vec<TreeEntry>) {
for entry in dir.read_dir().unwrap() { for entry in dir.read_dir().unwrap() {
let path = entry.unwrap().path(); let path = entry.unwrap().path();
if path.is_file() && !path.file_name().unwrap().to_str().unwrap().starts_with('.') { if path.is_file() && !path.file_name().unwrap().to_str().unwrap().starts_with('.') {
@@ -92,31 +91,31 @@ impl FleenApp {
self.files_cache.borrow().clone().expect("Can't happen because we just refreshed the cache") self.files_cache.borrow().clone().expect("Can't happen because we just refreshed the cache")
} }
pub fn open_filename(&self, filename: &String) -> Result<(), FleenError> { pub fn open_filename(&self, filename: &str) -> Result<(), FleenError> {
Command::new("open").arg(filename.clone()).spawn().map_err(|err| { Command::new("open").arg(filename).spawn().map_err(|err| {
FleenError::FileIoError(filename.clone(), err.to_string()) FleenError::FileIo(filename.to_owned(), err.to_string())
})?; })?;
Ok(()) Ok(())
} }
pub fn create_page(&self, file_type: FileType, name: &String, parent: Option<&String>) -> Result<(), FleenError> { pub fn create_page(&self, file_type: FileType, name: &str, parent: Option<&String>) -> Result<(), FleenError> {
let mut target = match parent { let mut target = match parent {
Some(s) => PathBuf::from(s), Some(s) => PathBuf::from(s),
None => self.root.clone() None => self.root.clone()
}; };
target.push(name.clone()); target.push(name);
if target.exists() { if target.exists() {
return Err(FleenError::FileExistsError(target)) return Err(FleenError::FileExists(target))
} }
match file_type { match file_type {
FileType::File => std::fs::write(target.clone(), []), FileType::File => std::fs::write(target.clone(), []),
FileType::Dir => std::fs::create_dir(target.clone()) FileType::Dir => std::fs::create_dir(target.clone())
}.map_err(|err| FleenError::FileCreateError(target.clone(), err.to_string()))?; }.map_err(|err| FleenError::FileCreate(target.clone(), err.to_string()))?;
self.refresh_file_cache(true); self.refresh_file_cache(true);
if file_type == FileType::File { if file_type == FileType::File {
self.open_filename(&target.to_string_lossy().to_string())? self.open_filename(target.to_string_lossy().as_ref())?
} }
Ok(()) Ok(())
} }
@@ -127,8 +126,21 @@ impl FleenApp {
fs::remove_dir_all(target) fs::remove_dir_all(target)
} else { } else {
fs::remove_file(target) fs::remove_file(target)
}.map_err(|err| FleenError::FileIoError(path.clone(), err.to_string()))?; }.map_err(|err| FleenError::FileIo(path.clone(), err.to_string()))?;
self.refresh_file_cache(true); self.refresh_file_cache(true);
Ok(()) Ok(())
} }
pub fn rename_page(&self, target: &String, new_name: &str) -> Result<(), FleenError> {
let path = PathBuf::from(target);
let mut new_path = path.clone();
new_path.set_file_name(new_name);
fs::rename(path, new_path).map_err(|err| FleenError::FileIo(target.clone(), err.to_string()))?;
self.refresh_file_cache(true);
Ok(())
}
pub fn root_path(&self) -> String {
self.root.to_string_lossy().to_string()
}
} }
+68 -40
View File
@@ -1,7 +1,7 @@
mod fleen_app; mod fleen_app;
use std::path::PathBuf; use std::path::{Path, PathBuf};
use eframe::egui::{Color32, Context, Id, Stroke}; use eframe::egui::{Color32, Context, Id, RichText};
use eframe::{egui, Frame}; use eframe::{egui, Frame};
use egui_ltreeview::Action; use egui_ltreeview::Action;
use crate::fleen_app::{FileType, FleenApp, FleenError, TreeEntry}; use crate::fleen_app::{FileType, FleenApp, FleenError, TreeEntry};
@@ -19,6 +19,7 @@ enum DialogMode {
RenameFile(String) RenameFile(String)
} }
#[derive(Default)]
struct FleenUi { struct FleenUi {
app: Option<FleenApp>, app: Option<FleenApp>,
error: Option<FleenError>, error: Option<FleenError>,
@@ -26,77 +27,67 @@ struct FleenUi {
dialog_mode: Option<DialogMode> dialog_mode: Option<DialogMode>
} }
impl Default for FleenUi {
fn default() -> Self {
Self {
app: None,
error: None,
selected_file: None,
dialog_mode: None
}
}
}
impl FleenUi { impl FleenUi {
fn site_chooser(&mut self, ctx: &Context) { fn site_chooser(&mut self, ctx: &Context) {
egui::CentralPanel::default().show(ctx, |ui| { egui::CentralPanel::default().show(ctx, |ui| {
ui.label("No site selected!"); ui.label("No site selected!");
if ui.button("Open site...").clicked() { if ui.button("Open site...").clicked() && let Some(path) = rfd::FileDialog::new().pick_folder() {
if let Some(path) = rfd::FileDialog::new().pick_folder() { match FleenApp::open(path) {
match FleenApp::open(path) { Ok(app) => { self.app = Some(app) }
Ok(app) => { self.app = Some(app) } Err(err) => { self.error = Some(err) }
Err(err) => { self.error = Some(err) }
}
} }
} }
if ui.button("New site...").clicked() { if ui.button("New site...").clicked() && let Some(path) = rfd::FileDialog::new().pick_folder() {
if let Some(path) = rfd::FileDialog::new().pick_folder() { match FleenApp::create(path) {
match FleenApp::create(path) { Ok(app) => { self.app = Some(app) }
Ok(app) => { self.app = Some(app) } Err(err) => { self.error = Some(err) }
Err(err) => { self.error = Some(err) }
}
} }
} }
}); });
} }
fn display(&mut self, ctx: &Context) { fn display(&mut self, ctx: &Context) {
let mut new_clicked = false; let mut just_clicked = false;
egui::CentralPanel::default().show(ctx, |ui| { egui::CentralPanel::default().show(ctx, |ui| {
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.vertical(|ui| { ui.vertical(|ui| {
self.tree_view(ui); self.tree_view(ui);
if ui.add(egui::Button::new("Open")).clicked() { if ui.add(egui::Button::new("Open")).clicked() &&
if let Some(fname) = &self.selected_file { let Some(fname) = &self.selected_file {
self.handle_error(self.app.as_ref().unwrap().open_filename(fname)) self.handle_error(self.app.as_ref().unwrap().open_filename(fname))
}
} }
if ui.add(egui::Button::new("New page")).clicked() { let new_btn = egui::Button::new(RichText::new("New page").color(Color32::WHITE)).fill(Color32::DARK_GREEN);
new_clicked = true; if ui.add(new_btn).clicked() {
just_clicked = true;
self.dialog_mode = Some(DialogMode::NewFile(String::new())); self.dialog_mode = Some(DialogMode::NewFile(String::new()));
} }
let rename_btn = egui::Button::new("Rename");
let delete_btn = egui::Button::new("Delete").fill(Color32::DARK_RED); let delete_btn = egui::Button::new("Delete").fill(Color32::DARK_RED);
if let Some(selected) = &self.selected_file { if self.root_selected() || self.selected_file.is_none() {
ui.add_enabled(false, rename_btn);
ui.add_enabled(false, delete_btn);
} else if let Some(selected) = &self.selected_file {
if ui.add(rename_btn).clicked() {
self.dialog_mode = Some(DialogMode::RenameFile(label_for_path(&PathBuf::from(&selected))));
just_clicked = true;
}
if ui.add(delete_btn).clicked() { if ui.add(delete_btn).clicked() {
self.dialog_mode = Some(DialogMode::ConfirmDelete(selected.clone())); self.dialog_mode = Some(DialogMode::ConfirmDelete(selected.clone()));
} }
} else {
ui.add_enabled(false, delete_btn);
} }
}); });
}) })
}); });
match self.dialog_mode { match self.dialog_mode {
Some(DialogMode::NewFile(_)) => self.new_file_dialog(ctx, new_clicked), Some(DialogMode::NewFile(_)) => self.new_file_dialog(ctx, just_clicked),
Some(DialogMode::ConfirmDelete(_)) => self.confirm_delete_dialog(ctx), Some(DialogMode::ConfirmDelete(_)) => self.confirm_delete_dialog(ctx),
Some(DialogMode::RenameFile(_)) => todo!(), Some(DialogMode::RenameFile(_)) => self.rename_dialog(ctx, just_clicked),
None => {} None => {}
} }
} }
@@ -118,7 +109,7 @@ impl FleenUi {
for action in actions { for action in actions {
match action { match action {
Action::SetSelected(files) => { Action::SetSelected(files) => {
self.selected_file = files.first().map(String::clone) self.selected_file = files.first().cloned()
} }
Action::Activate(activate) => { Action::Activate(activate) => {
for fname in activate.selected { for fname in activate.selected {
@@ -173,6 +164,35 @@ impl FleenUi {
}); });
} }
fn rename_dialog(&mut self, ctx: &Context, just_clicked: bool) {
egui::Window::new("Rename").collapsible(false).resizable(false).show(ctx, |ui| {
ui.label("New name");
let Some(DialogMode::RenameFile(fname)) = &mut self.dialog_mode else { unreachable!() };
let name_field = egui::TextEdit::singleline(fname);
let resp = ui.add(name_field);
let enter_key = resp.lost_focus();
if just_clicked { resp.request_focus() } // See new_file_dialog
ui.horizontal(|ui| {
let btn = ui.button("Rename");
if enter_key { btn.request_focus() }
if btn.clicked() {
let Some(DialogMode::RenameFile(fname)) = &self.dialog_mode else { unreachable!() };
let app = self.app.as_ref().unwrap();
let r = app.rename_page(self.selected_file.as_ref().unwrap(), fname);
if r.is_err() {
self.handle_error(r);
} else {
self.dialog_mode = None; // Close the dialog, we're done
}
}
if ui.button("Cancel").clicked() {
self.dialog_mode = None
}
})
});
}
fn confirm_delete_dialog(&mut self, ctx: &Context) { fn confirm_delete_dialog(&mut self, ctx: &Context) {
let (mut del, mut cancel) = (false, false); let (mut del, mut cancel) = (false, false);
let Some(DialogMode::ConfirmDelete(fname)) = &self.dialog_mode else { unreachable!() }; let Some(DialogMode::ConfirmDelete(fname)) = &self.dialog_mode else { unreachable!() };
@@ -201,6 +221,14 @@ impl FleenUi {
self.error = Some(e) self.error = Some(e)
} }
} }
fn root_selected(&self) -> bool {
if let Some(path) = &self.selected_file {
path == &self.app.as_ref().unwrap().root_path()
} else {
false
}
}
} }
impl eframe::App for FleenUi { impl eframe::App for FleenUi {
@@ -222,10 +250,10 @@ impl eframe::App for FleenUi {
} }
} }
fn label_for_path(path: &PathBuf) -> String { fn label_for_path(path: &Path) -> String {
path.file_name().unwrap().to_string_lossy().to_string() path.file_name().unwrap().to_string_lossy().to_string()
} }
fn id_for_path(path: &PathBuf) -> String { fn id_for_path(path: &Path) -> String {
path.to_string_lossy().to_string() path.to_string_lossy().to_string()
} }