Add vim bindings and directory expand/collapse
- Replace arrow keys with j/k for navigation - Add h/l for collapse/expand directories - Remove emoji icons, use clean text markers - Show directories with [-]/[+] expand markers - Track expanded state per directory path - Add directory suffix (/) for clarity - Update help text with vim bindings
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
use crate::cache::{Cache, FileTreeNode};
|
||||
use crate::config::Config;
|
||||
use std::collections::HashSet;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -21,6 +22,7 @@ pub struct AppState {
|
||||
pub volume: i64,
|
||||
pub should_quit: bool,
|
||||
pub flattened_items: Vec<FlattenedItem>,
|
||||
pub expanded_dirs: HashSet<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -32,7 +34,11 @@ pub struct FlattenedItem {
|
||||
|
||||
impl AppState {
|
||||
pub fn new(cache: Cache, config: Config) -> Self {
|
||||
let flattened_items = flatten_tree(&cache.file_tree, 0);
|
||||
let mut expanded_dirs = HashSet::new();
|
||||
// Start with all directories expanded
|
||||
collect_all_dirs(&cache.file_tree, &mut expanded_dirs);
|
||||
|
||||
let flattened_items = flatten_tree(&cache.file_tree, 0, &expanded_dirs);
|
||||
|
||||
Self {
|
||||
cache,
|
||||
@@ -46,6 +52,7 @@ impl AppState {
|
||||
volume: 100,
|
||||
should_quit: false,
|
||||
flattened_items,
|
||||
expanded_dirs,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,28 +72,79 @@ impl AppState {
|
||||
self.flattened_items.get(self.selected_index)
|
||||
}
|
||||
|
||||
pub fn toggle_expand(&mut self) {
|
||||
if let Some(item) = self.get_selected_item() {
|
||||
if item.node.is_dir {
|
||||
let path = item.node.path.clone();
|
||||
if self.expanded_dirs.contains(&path) {
|
||||
self.expanded_dirs.remove(&path);
|
||||
} else {
|
||||
self.expanded_dirs.insert(path);
|
||||
}
|
||||
self.rebuild_flattened_items();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn collapse_selected(&mut self) {
|
||||
if let Some(item) = self.get_selected_item() {
|
||||
if item.node.is_dir {
|
||||
let path = item.node.path.clone();
|
||||
self.expanded_dirs.remove(&path);
|
||||
self.rebuild_flattened_items();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expand_selected(&mut self) {
|
||||
if let Some(item) = self.get_selected_item() {
|
||||
if item.node.is_dir {
|
||||
let path = item.node.path.clone();
|
||||
self.expanded_dirs.insert(path);
|
||||
self.rebuild_flattened_items();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn refresh_flattened_items(&mut self) {
|
||||
self.flattened_items = flatten_tree(&self.cache.file_tree, 0);
|
||||
self.expanded_dirs.clear();
|
||||
collect_all_dirs(&self.cache.file_tree, &mut self.expanded_dirs);
|
||||
self.rebuild_flattened_items();
|
||||
}
|
||||
|
||||
fn rebuild_flattened_items(&mut self) {
|
||||
self.flattened_items = flatten_tree(&self.cache.file_tree, 0, &self.expanded_dirs);
|
||||
if self.selected_index >= self.flattened_items.len() {
|
||||
self.selected_index = self.flattened_items.len().saturating_sub(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flatten_tree(nodes: &[FileTreeNode], depth: usize) -> Vec<FlattenedItem> {
|
||||
fn flatten_tree(nodes: &[FileTreeNode], depth: usize, expanded_dirs: &HashSet<PathBuf>) -> Vec<FlattenedItem> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
for node in nodes {
|
||||
let is_expanded = expanded_dirs.contains(&node.path);
|
||||
|
||||
result.push(FlattenedItem {
|
||||
node: node.clone(),
|
||||
depth,
|
||||
is_expanded: true, // For now, all directories are expanded
|
||||
is_expanded,
|
||||
});
|
||||
|
||||
if node.is_dir && !node.children.is_empty() {
|
||||
result.extend(flatten_tree(&node.children, depth + 1));
|
||||
if node.is_dir && !node.children.is_empty() && is_expanded {
|
||||
result.extend(flatten_tree(&node.children, depth + 1, expanded_dirs));
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn collect_all_dirs(nodes: &[FileTreeNode], dirs: &mut HashSet<PathBuf>) {
|
||||
for node in nodes {
|
||||
if node.is_dir {
|
||||
dirs.insert(node.path.clone());
|
||||
collect_all_dirs(&node.children, dirs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user