reworked file tree
This commit is contained in:
parent
5f3b199684
commit
297f53198f
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "calcifer"
|
name = "calcifer"
|
||||||
version = "1.3.2"
|
version = "1.4.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"categories":[{"name":"to do","content":[{"name":"bug project","description":"when switching tabs between two project file, if item window is open it crashes","id":1},{"name":"update workflow .yml","description":"make a workflow compiling the calcifer and put the linux in calcifer-{version}\nand the windows in calcifer_windows_{version}\n\nupdate nix\nupdate jiji","id":5},{"name":"open dir in tree ?","description":"// Hello there","id":2},{"name":"fix tab title","description":"// Hello there","id":2}]},{"name":"in progress","content":[{"name":"export copy paste fix","description":"// Hello there","id":1}]},{"name":"done","content":[{"name":"move .project file","description":"// Hello there","id":4},{"name":"move config","description":"config from .calcifer/save.json\nto .config/calcifer/state.json","id":1},{"name":"add id to textarea per tab","description":"to improve undo, make each code area of each tab have a unique id (no more undo into another tab)","id":1},{"name":"file tree id ?","description":"// Hello there","id":1}]},{"name":"+","content":[]}]}
|
{"categories":[{"name":"to do","content":[{"name":"bug project","description":"when switching tabs between two project file, if item window is open it crashes","id":1},{"name":"update workflow .yml","description":"make a workflow compiling the calcifer and put the linux in calcifer-{version}\nand the windows in calcifer_windows_{version}\n\nupdate nix\nupdate jiji","id":5},{"name":"fix tab title","description":"// Hello there","id":2}]},{"name":"in progress","content":[{"name":"export copy paste fix","description":"// Hello there","id":1}]},{"name":"done","content":[{"name":"move .project file","description":"// Hello there","id":4},{"name":"move config","description":"config from .calcifer/save.json\nto .config/calcifer/state.json","id":1},{"name":"add id to textarea per tab","description":"to improve undo, make each code area of each tab have a unique id (no more undo into another tab)","id":1},{"name":"file tree id ?","description":"// Hello there","id":1},{"name":"open dir in tree ?","description":"// Hello there","id":2}]},{"name":"+","content":[]}]}
|
|
@ -209,13 +209,13 @@ impl Calcifer {
|
||||||
|
|
||||||
if let Some(folder_content) = &file.folder_content {
|
if let Some(folder_content) = &file.folder_content {
|
||||||
let mut check_for_update: bool = false;
|
let mut check_for_update: bool = false;
|
||||||
let file_id = panels::get_file_id(&file);
|
let file_path_id = panels::get_file_path_id(&file.path);
|
||||||
|
|
||||||
let collapsing_response = egui::CollapsingHeader::new(&file.name.clone())
|
let collapsing_response = egui::CollapsingHeader::new(file.name.clone())
|
||||||
.id_source(&file_id)
|
.id_source(&file.id)
|
||||||
.default_open(self.tree_dir_opened.contains(&file_id))
|
.default_open(self.tree_dir_opened.contains(&file_path_id))
|
||||||
.show(ui, |ui| {
|
.show(ui, |ui| {
|
||||||
if !self.tree_dir_opened.contains(&file_id) {
|
if !self.tree_dir_opened.contains(&file_path_id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for deeper_file in folder_content {
|
for deeper_file in folder_content {
|
||||||
|
@ -225,9 +225,9 @@ impl Calcifer {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if collapsing_response.fully_closed() {
|
if collapsing_response.fully_closed() {
|
||||||
self.tree_dir_opened.retain(|s| s != &file_id);
|
self.tree_dir_opened.retain(|s| s != &file_path_id);
|
||||||
} else if !self.tree_dir_opened.contains(&file_id) {
|
} else if !self.tree_dir_opened.contains(&file_path_id) {
|
||||||
self.tree_dir_opened.push(file_id);
|
self.tree_dir_opened.push(file_path_id);
|
||||||
return !file.content_checked;
|
return !file.content_checked;
|
||||||
}
|
}
|
||||||
return check_for_update;
|
return check_for_update;
|
||||||
|
|
|
@ -53,19 +53,26 @@ impl Calcifer {
|
||||||
if !self.tree_visible {
|
if !self.tree_visible {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut init_update : bool = false;
|
|
||||||
if self.file_tree.is_none() {
|
|
||||||
self.file_tree = Some(panels::generate_folder_entry(self.home.as_path()));
|
|
||||||
init_update = true
|
|
||||||
}
|
|
||||||
let mut n_files: usize = 0;
|
|
||||||
egui::SidePanel::left("file_tree_panel").show(ctx, |ui| {
|
egui::SidePanel::left("file_tree_panel").show(ctx, |ui| {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label("Bookshelf ");
|
ui.label(format!("Bookshelf ({} files) ", self.n_file_displayed));
|
||||||
|
if ui.button("↺").clicked() {
|
||||||
|
self.file_tree = None;
|
||||||
|
}
|
||||||
|
if ui.button("🗙").clicked() {
|
||||||
|
self.file_tree = None;
|
||||||
|
self.tree_dir_opened = vec![];
|
||||||
|
}
|
||||||
});
|
});
|
||||||
ui.separator();
|
ui.separator();
|
||||||
ui.label(format!("{} files displayed", self.n_file_displayed));
|
|
||||||
ui.separator();
|
let mut init_update : bool = false;
|
||||||
|
if self.file_tree.is_none() {
|
||||||
|
self.file_tree = Some(panels::generate_folder_entry(self.home.as_path()));
|
||||||
|
init_update = true
|
||||||
|
}
|
||||||
|
let mut n_files: usize = 0;
|
||||||
|
|
||||||
egui::ScrollArea::vertical().show(ui, |ui| {
|
egui::ScrollArea::vertical().show(ui, |ui| {
|
||||||
if let Some(file_tree) = self.file_tree.clone() {
|
if let Some(file_tree) = self.file_tree.clone() {
|
||||||
let update_requested = self.list_files(ui, &file_tree, &mut n_files);
|
let update_requested = self.list_files(ui, &file_tree, &mut n_files);
|
||||||
|
@ -80,8 +87,9 @@ impl Calcifer {
|
||||||
}
|
}
|
||||||
ui.separator();
|
ui.separator();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
self.n_file_displayed = n_files;
|
||||||
});
|
});
|
||||||
self.n_file_displayed = n_files;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_bottom_tray(&mut self, ctx: &egui::Context) {
|
pub fn draw_bottom_tray(&mut self, ctx: &egui::Context) {
|
||||||
|
@ -211,7 +219,7 @@ impl Calcifer {
|
||||||
if ui
|
if ui
|
||||||
.add(
|
.add(
|
||||||
egui::Label::new(
|
egui::Label::new(
|
||||||
egui::RichText::new(" X ").color(color),
|
egui::RichText::new(" ❌ ").color(color),
|
||||||
)
|
)
|
||||||
.sense(egui::Sense::click()),
|
.sense(egui::Sense::click()),
|
||||||
)
|
)
|
||||||
|
@ -282,6 +290,25 @@ impl Calcifer {
|
||||||
panels::send_command(format!("cd {}", path.display()));
|
panels::send_command(format!("cd {}", path.display()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ui
|
||||||
|
.add(egui::Button::new("expand tree"))
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
let mut current_path = self.tabs[self.selected_tab].path.clone();
|
||||||
|
current_path.pop();
|
||||||
|
|
||||||
|
while let Some(parent) = current_path.parent() {
|
||||||
|
let dir_id = panels::get_file_path_id(¤t_path);
|
||||||
|
if !self.tree_dir_opened.contains(&dir_id) {
|
||||||
|
self.tree_dir_opened.push(dir_id);
|
||||||
|
}
|
||||||
|
current_path = parent.to_path_buf();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tree_visible = true;
|
||||||
|
self.file_tree = None;
|
||||||
|
}
|
||||||
|
|
||||||
ui.label("Picked file:");
|
ui.label("Picked file:");
|
||||||
ui.monospace(
|
ui.monospace(
|
||||||
self.tabs[self.selected_tab]
|
self.tabs[self.selected_tab]
|
||||||
|
|
|
@ -211,11 +211,6 @@ impl eframe::App for Calcifer {
|
||||||
self.handle_save_file(self.save_tab());
|
self.handle_save_file(self.save_tab());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.input(|i| i.key_pressed(egui::Key::T) && i.modifiers.ctrl) {
|
|
||||||
self.file_tree = None;
|
|
||||||
self.tree_dir_opened = vec![];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ctx.input(|i| i.key_pressed(egui::Key::S) && i.modifiers.ctrl && i.modifiers.shift) {
|
if ctx.input(|i| i.key_pressed(egui::Key::S) && i.modifiers.ctrl && i.modifiers.shift) {
|
||||||
self.handle_save_file(self.save_tab_as());
|
self.handle_save_file(self.save_tab_as());
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,11 @@ use std::{
|
||||||
fs, io,
|
fs, io,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
use std::hash::DefaultHasher;
|
||||||
|
use std::time::UNIX_EPOCH;
|
||||||
|
use std::time::SystemTime;
|
||||||
|
use std::hash::Hasher;
|
||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
//use crate::ALLOWED_FILE_EXTENSIONS;
|
//use crate::ALLOWED_FILE_EXTENSIONS;
|
||||||
|
|
||||||
|
@ -13,53 +18,72 @@ pub struct FileEntry {
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
pub folder_content: Option<Vec<FileEntry>>,
|
pub folder_content: Option<Vec<FileEntry>>,
|
||||||
pub content_checked: bool,
|
pub content_checked: bool,
|
||||||
|
pub id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileEntry {
|
impl FileEntry {
|
||||||
pub fn new_entry(name: String, path: PathBuf) -> Self {
|
pub fn new_entry(name: String, path: PathBuf) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
path,
|
path: path.clone(),
|
||||||
folder_content: None,
|
folder_content: None,
|
||||||
content_checked: true,
|
content_checked: true,
|
||||||
|
id: Self::generate_unique_id(path),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn end_of_branch(name: String, path: PathBuf) -> Self {
|
pub fn end_of_branch(name: String, path: PathBuf) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
path,
|
path: path.clone(),
|
||||||
folder_content: Some(vec![]),
|
folder_content: Some(vec![]),
|
||||||
content_checked: false,
|
content_checked: false,
|
||||||
|
id: Self::generate_unique_id(path),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn generate_unique_id(path: PathBuf) -> String {
|
||||||
|
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
|
||||||
|
|
||||||
|
let mut hasher = DefaultHasher::new();
|
||||||
|
now.hash(&mut hasher);
|
||||||
|
|
||||||
|
let hash = hasher.finish();
|
||||||
|
|
||||||
|
format!("{}#{}", path.display(), hash)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_file_tree(file: FileEntry, opened_dirs: Vec<String>) -> FileEntry {
|
pub fn update_file_tree(file: FileEntry, opened_dirs: Vec<String>) -> FileEntry {
|
||||||
if opened_dirs.contains(&get_file_id(&file)) {
|
if !opened_dirs.contains(&get_file_path_id(&file.path)) {
|
||||||
if let Some(folder_content) = &file.folder_content {
|
return file;
|
||||||
if !file.content_checked {
|
}
|
||||||
return generate_folder_entry(&file.path);
|
|
||||||
}
|
if !file.content_checked {
|
||||||
let updated_content: Vec<FileEntry> = folder_content
|
let folder = generate_folder_entry(&file.path);
|
||||||
.iter()
|
return update_file_tree(folder, opened_dirs);
|
||||||
.map(|entry| update_file_tree(entry.clone(), opened_dirs.clone()))
|
}
|
||||||
.collect();
|
|
||||||
FileEntry {
|
if file.folder_content.is_none() {
|
||||||
name: file.name,
|
return file;
|
||||||
path: file.path,
|
}
|
||||||
folder_content: Some(updated_content),
|
|
||||||
content_checked: true,
|
let folder_content = file.folder_content.expect("should have checked if none");
|
||||||
}
|
|
||||||
} else {
|
let updated_content: Vec<FileEntry> = folder_content
|
||||||
file
|
.iter()
|
||||||
}
|
.map(|entry| update_file_tree(entry.clone(), opened_dirs.clone()))
|
||||||
} else {
|
.collect();
|
||||||
file
|
FileEntry {
|
||||||
|
name: file.name,
|
||||||
|
path: file.path.clone(),
|
||||||
|
folder_content: Some(updated_content),
|
||||||
|
content_checked: true,
|
||||||
|
id: FileEntry::generate_unique_id(file.path),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_file_id(file: &FileEntry) -> String {
|
pub fn get_file_path_id(path: &PathBuf) -> String {
|
||||||
format!("#{}",file.path.clone().display())
|
format!("#{}", path.clone().display())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_folder_entry(path: &Path) -> FileEntry {
|
pub fn generate_folder_entry(path: &Path) -> FileEntry {
|
||||||
|
@ -106,6 +130,7 @@ pub fn generate_folder_entry(path: &Path) -> FileEntry {
|
||||||
path: path.to_path_buf(),
|
path: path.to_path_buf(),
|
||||||
folder_content: Some(folder_content),
|
folder_content: Some(folder_content),
|
||||||
content_checked: true,
|
content_checked: true,
|
||||||
|
id: FileEntry::generate_unique_id(path.to_path_buf()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue