Implement TUI colon command mode
This commit is contained in:
@@ -160,6 +160,47 @@ impl Sidebar {
|
||||
self.selected.as_ref()
|
||||
}
|
||||
|
||||
pub fn select_path(&mut self, path: &str, directory: bool) -> bool {
|
||||
let target = collect_ids(&self.full)
|
||||
.into_iter()
|
||||
.find(|id| id.path() == path && id.is_directory() == directory);
|
||||
let Some(target) = target else {
|
||||
return false;
|
||||
};
|
||||
if !path.is_empty() {
|
||||
let mut prefix = String::new();
|
||||
for component in path
|
||||
.split('/')
|
||||
.take(path.split('/').count().saturating_sub(1))
|
||||
{
|
||||
if !prefix.is_empty() {
|
||||
prefix.push('/');
|
||||
}
|
||||
prefix.push_str(component);
|
||||
self.expanded.insert(NodeId {
|
||||
path: prefix.clone(),
|
||||
directory: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
self.selected = Some(target);
|
||||
self.ensure_selected_visible();
|
||||
true
|
||||
}
|
||||
|
||||
pub fn completion_paths(&self) -> Vec<String> {
|
||||
fn visit(nodes: &[SidebarNode], paths: &mut Vec<String>) {
|
||||
for node in nodes {
|
||||
paths.push(node.id.path.clone());
|
||||
visit(&node.children, paths);
|
||||
}
|
||||
}
|
||||
|
||||
let mut paths = Vec::new();
|
||||
visit(&self.full, &mut paths);
|
||||
paths
|
||||
}
|
||||
|
||||
pub fn set_viewport_height(&mut self, height: usize) {
|
||||
self.viewport_height = height.max(1);
|
||||
self.ensure_selected_visible();
|
||||
@@ -574,6 +615,31 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn command_selection_expands_ancestors_and_completion_uses_the_full_tree() {
|
||||
let mut sidebar = sidebar();
|
||||
assert!(sidebar.select_path("personal", true));
|
||||
assert!(sidebar.select_path("personal/咖啡", false));
|
||||
assert_eq!(sidebar.selected().map(NodeId::path), Some("personal/咖啡"));
|
||||
assert!(
|
||||
sidebar
|
||||
.visible_rows()
|
||||
.iter()
|
||||
.any(|row| row.id.path() == "personal/咖啡")
|
||||
);
|
||||
assert_eq!(
|
||||
sidebar.completion_paths(),
|
||||
vec![
|
||||
"personal",
|
||||
"personal/email",
|
||||
"personal/咖啡",
|
||||
"work",
|
||||
"work/server"
|
||||
]
|
||||
);
|
||||
assert!(!sidebar.select_path("personal/咖啡", true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_tree_has_no_stale_selection() {
|
||||
let mut sidebar = Sidebar::default();
|
||||
|
||||
Reference in New Issue
Block a user