2026-01-19 09:23:12 -05:00
|
|
|
use crate::tui::component::Component;
|
2026-01-17 17:09:42 -05:00
|
|
|
use anyhow::Result;
|
2026-01-17 15:07:05 -05:00
|
|
|
use ratatui::buffer::Buffer;
|
2026-01-17 17:39:13 -05:00
|
|
|
use ratatui::layout::{Alignment, Rect};
|
2026-01-17 15:07:05 -05:00
|
|
|
use ratatui::prelude::Style;
|
2026-01-17 17:39:13 -05:00
|
|
|
use ratatui::style::Color;
|
2026-01-17 15:07:05 -05:00
|
|
|
use ratatui::widgets::{Block, Borders, Widget};
|
2026-01-17 17:09:42 -05:00
|
|
|
use std::fs;
|
2026-01-17 15:07:05 -05:00
|
|
|
use tui_tree_widget::{Tree, TreeItem};
|
|
|
|
|
use uuid::Uuid;
|
|
|
|
|
|
2026-01-17 17:09:42 -05:00
|
|
|
#[derive(Clone, Debug)]
|
2026-01-17 15:07:05 -05:00
|
|
|
pub struct Explorer<'a> {
|
2026-01-19 09:23:12 -05:00
|
|
|
root_path: std::path::PathBuf,
|
2026-01-17 17:09:42 -05:00
|
|
|
tree_items: TreeItem<'a, String>,
|
2026-01-17 15:07:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> Explorer<'a> {
|
2026-01-19 15:03:50 -05:00
|
|
|
pub fn new(path: &std::path::PathBuf) -> Self {
|
2026-01-18 10:09:28 -05:00
|
|
|
let explorer = Explorer {
|
2026-01-19 09:23:12 -05:00
|
|
|
root_path: path.to_owned(),
|
2026-01-19 15:03:50 -05:00
|
|
|
tree_items: Self::build_tree_from_path(path.to_owned()),
|
2026-01-17 17:09:42 -05:00
|
|
|
};
|
|
|
|
|
explorer
|
2026-01-17 15:07:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn build_tree_from_path(path: std::path::PathBuf) -> TreeItem<'static, String> {
|
|
|
|
|
let mut children = vec![];
|
|
|
|
|
if let Ok(entries) = fs::read_dir(&path) {
|
|
|
|
|
let mut paths = entries
|
|
|
|
|
.map(|res| res.map(|e| e.path()))
|
|
|
|
|
.collect::<Result<Vec<_>, std::io::Error>>()
|
|
|
|
|
.expect("");
|
|
|
|
|
paths.sort();
|
|
|
|
|
for path in paths {
|
|
|
|
|
if path.is_dir() {
|
|
|
|
|
children.push(Self::build_tree_from_path(path));
|
|
|
|
|
} else {
|
|
|
|
|
children.push(TreeItem::new_leaf(
|
|
|
|
|
Uuid::new_v4().to_string(),
|
2026-01-19 09:23:12 -05:00
|
|
|
path.file_name()
|
|
|
|
|
.expect("Failed to get file name from path.")
|
|
|
|
|
.to_string_lossy()
|
|
|
|
|
.to_string(),
|
2026-01-17 15:07:05 -05:00
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TreeItem::new(
|
|
|
|
|
Uuid::new_v4().to_string(),
|
|
|
|
|
path.file_name()
|
2026-01-19 09:23:12 -05:00
|
|
|
.expect("Failed to get file name from path.")
|
2026-01-17 15:07:05 -05:00
|
|
|
.to_string_lossy()
|
|
|
|
|
.to_string(),
|
|
|
|
|
children,
|
|
|
|
|
)
|
2026-01-17 17:09:42 -05:00
|
|
|
.expect("Failed to build tree from path.")
|
2026-01-17 15:07:05 -05:00
|
|
|
}
|
|
|
|
|
}
|
2026-01-17 17:09:42 -05:00
|
|
|
|
|
|
|
|
impl<'a> Widget for &Explorer<'a> {
|
|
|
|
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
|
|
|
|
Tree::new(&self.tree_items.children())
|
|
|
|
|
.expect("Failed to build tree.")
|
|
|
|
|
.style(Style::default())
|
2026-01-17 17:39:13 -05:00
|
|
|
.block(
|
|
|
|
|
Block::default()
|
|
|
|
|
.borders(Borders::ALL)
|
|
|
|
|
.title(
|
|
|
|
|
self.root_path
|
|
|
|
|
.file_name()
|
|
|
|
|
.expect("Failed to get file name from path.")
|
|
|
|
|
.to_string_lossy(),
|
|
|
|
|
)
|
|
|
|
|
.title_style(Style::default().fg(Color::Green))
|
|
|
|
|
.title_alignment(Alignment::Center),
|
|
|
|
|
)
|
2026-01-17 17:09:42 -05:00
|
|
|
.render(area, buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-19 15:03:50 -05:00
|
|
|
impl<'a> Component for Explorer<'a> {
|
|
|
|
|
fn id(&self) -> &str {
|
|
|
|
|
"explorer"
|
|
|
|
|
}
|
|
|
|
|
}
|