file tree lazy update
This commit is contained in:
parent
df18044c64
commit
28bc4b4823
|
@ -190,30 +190,35 @@ impl Calcifer {
|
|||
&mut self,
|
||||
ui: &mut egui::Ui,
|
||||
file: &panels::FileEntry,
|
||||
depth: isize,
|
||||
n_files: &mut usize,
|
||||
) {
|
||||
) -> bool {
|
||||
*n_files += 1;
|
||||
|
||||
if let Some(folder_content) = &file.folder_content {
|
||||
let mut check_for_update: bool = false;
|
||||
let collapsing_response = egui::CollapsingHeader::new(file.name.clone())
|
||||
.default_open(depth > 0)
|
||||
.default_open(self.tree_dir_opened.contains(&file.name))
|
||||
.show(ui, |ui| {
|
||||
if !self.tree_dir_opened.contains(&file.name) {
|
||||
return;
|
||||
}
|
||||
for deeper_file in folder_content {
|
||||
self.list_files(ui, deeper_file, depth - 1, n_files);
|
||||
if self.list_files(ui, deeper_file, n_files) {
|
||||
check_for_update = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
if collapsing_response.fully_closed() {
|
||||
self.tree_dir_opened.retain(|s| s != &file.name);
|
||||
} else if !self.tree_dir_opened.contains(&file.name) {
|
||||
self.tree_dir_opened.push(file.name.clone());
|
||||
return !file.content_checked;
|
||||
}
|
||||
return check_for_update;
|
||||
} else if ui.button(&file.name).clicked() {
|
||||
self.open_file(Some(&file.path));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,20 +54,28 @@ impl Calcifer {
|
|||
if !self.tree_visible {
|
||||
return;
|
||||
}
|
||||
if self.file_tree.is_none() {
|
||||
self.file_tree = Some(panels::generate_folder_entry(self.home.as_path()));
|
||||
}
|
||||
let mut n_files: usize = 0;
|
||||
egui::SidePanel::left("file_tree_panel").show(ctx, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Bookshelf ");
|
||||
if ui.add(egui::Button::new("📖")).clicked() {
|
||||
self.file_tree = panels::generate_file_tree(self.home.as_path(), 7);
|
||||
}
|
||||
});
|
||||
ui.separator();
|
||||
let mut n_files: usize = 0;
|
||||
if let Some(file_tree) = self.file_tree.clone() {
|
||||
self.list_files(ui, &file_tree, 1, &mut n_files);
|
||||
} else {
|
||||
ui.label("No book on the Bookshelf");
|
||||
}
|
||||
egui::ScrollArea::vertical().show(ui, |ui| {
|
||||
if let Some(file_tree) = self.file_tree.clone() {
|
||||
let update_requested = self.list_files(ui, &file_tree, &mut n_files);
|
||||
if update_requested {
|
||||
self.file_tree = Some(panels::update_file_tree(
|
||||
file_tree,
|
||||
self.tree_dir_opened.clone(),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
ui.label("No book on the Bookshelf");
|
||||
}
|
||||
});
|
||||
ui.separator();
|
||||
ui.label(format!("{} files displayed", n_files));
|
||||
});
|
||||
|
|
|
@ -12,7 +12,7 @@ pub struct FileEntry {
|
|||
pub name: String,
|
||||
pub path: PathBuf,
|
||||
pub folder_content: Option<Vec<FileEntry>>,
|
||||
pub folder_open: bool,
|
||||
pub content_checked: bool,
|
||||
}
|
||||
|
||||
impl FileEntry {
|
||||
|
@ -21,7 +21,15 @@ impl FileEntry {
|
|||
name,
|
||||
path,
|
||||
folder_content: None,
|
||||
folder_open: false,
|
||||
content_checked: true,
|
||||
}
|
||||
}
|
||||
pub fn end_of_branch(name: String, path: PathBuf) -> Self {
|
||||
Self {
|
||||
name,
|
||||
path,
|
||||
folder_content: Some(vec![]),
|
||||
content_checked: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,10 +53,14 @@ pub fn generate_file_tree(path: &Path, depth: isize) -> Option<FileEntry> {
|
|||
.to_string_lossy()
|
||||
.into_owned();
|
||||
|
||||
if !path.is_dir() || depth < 0 {
|
||||
if !path.is_dir() {
|
||||
return Some(FileEntry::new_entry(name, path.to_path_buf()));
|
||||
}
|
||||
|
||||
if depth < 0 {
|
||||
return Some(FileEntry::end_of_branch(name, path.to_path_buf()));
|
||||
}
|
||||
|
||||
match fs::read_dir(path) {
|
||||
Err(err) => Some(FileEntry::new_entry(
|
||||
format!("Error reading directory: {}", err),
|
||||
|
@ -92,12 +104,113 @@ pub fn generate_file_tree(path: &Path, depth: isize) -> Option<FileEntry> {
|
|||
name,
|
||||
path: path.to_path_buf(),
|
||||
folder_content: Some(folder_content),
|
||||
folder_open: false,
|
||||
content_checked: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_file_tree(file: FileEntry, opened_dirs: Vec<String>) -> FileEntry {
|
||||
if opened_dirs.contains(&file.name) {
|
||||
if let Some(folder_content) = &file.folder_content {
|
||||
if !file.content_checked {
|
||||
return generate_folder_entry(&file.path);
|
||||
}
|
||||
let updated_content: Vec<FileEntry> = folder_content
|
||||
.iter()
|
||||
.map(|entry| update_file_tree(entry.clone(), opened_dirs.clone()))
|
||||
.collect();
|
||||
return FileEntry {
|
||||
name: file.name,
|
||||
path: file.path,
|
||||
folder_content: Some(updated_content),
|
||||
content_checked: true,
|
||||
};
|
||||
} else {
|
||||
return file;
|
||||
}
|
||||
} else {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_folder_entry(path: &Path) -> FileEntry {
|
||||
if let Some(file_name) = path.file_name() {
|
||||
let name = file_name.to_string_lossy().into_owned();
|
||||
|
||||
match fs::read_dir(path) {
|
||||
Err(err) => FileEntry::new_entry(
|
||||
format!("Error reading directory: {}", err),
|
||||
path.to_path_buf(),
|
||||
),
|
||||
Ok(entries) => {
|
||||
let mut paths: Vec<Result<fs::DirEntry, io::Error>> = entries
|
||||
.map(|r| r.map_err(|e| io::Error::new(io::ErrorKind::Other, e)))
|
||||
.collect();
|
||||
|
||||
paths.sort_by(|a, b| match (a, b) {
|
||||
(Ok(entry_a), Ok(entry_b)) => sort_directories_first(entry_a, entry_b),
|
||||
(Err(_), Ok(_)) => std::cmp::Ordering::Greater,
|
||||
(Ok(_), Err(_)) => std::cmp::Ordering::Less,
|
||||
(Err(_), Err(_)) => std::cmp::Ordering::Equal,
|
||||
});
|
||||
|
||||
let mut folder_content = Vec::new();
|
||||
|
||||
for result in paths {
|
||||
match result {
|
||||
Ok(entry) => {
|
||||
if let Some(file) = generate_entry(&entry.path()) {
|
||||
folder_content.push(file);
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
folder_content.push(FileEntry::new_entry(
|
||||
format!("Error reading entry: {}", err),
|
||||
path.to_path_buf(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FileEntry {
|
||||
name,
|
||||
path: path.to_path_buf(),
|
||||
folder_content: Some(folder_content),
|
||||
content_checked: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
FileEntry::new_entry(format!("Error reading directory name"), path.to_path_buf())
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_entry(path: &Path) -> Option<FileEntry> {
|
||||
if let Some(file_name) = path.file_name() {
|
||||
if file_name.to_string_lossy().starts_with('.') {
|
||||
return None;
|
||||
}
|
||||
let extension = path.extension().and_then(|ext| ext.to_str());
|
||||
if !ALLOWED_FILE_EXTENSIONS.contains(&extension.unwrap_or_default()) {
|
||||
return None;
|
||||
}
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
|
||||
let name = path
|
||||
.file_name()
|
||||
.unwrap_or_else(|| OsStr::new(""))
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
|
||||
if !path.is_dir() {
|
||||
return Some(FileEntry::new_entry(name, path.to_path_buf()));
|
||||
}
|
||||
return Some(FileEntry::end_of_branch(name, path.to_path_buf()));
|
||||
}
|
||||
|
||||
fn sort_directories_first(a: &std::fs::DirEntry, b: &std::fs::DirEntry) -> Ordering {
|
||||
let a_is_dir = a.path().is_dir();
|
||||
let b_is_dir = b.path().is_dir();
|
||||
|
|
Loading…
Reference in a new issue