feat(explore): rename file/folder

pull/9/head
wongjiahau 2 years ago
parent 2af8b41007
commit 44b46dda6a

@ -233,6 +233,7 @@ enum PromptAction {
}, },
RemoveDir, RemoveDir,
RemoveFile, RemoveFile,
RenameFile,
Filter, Filter,
} }
@ -289,32 +290,34 @@ impl Explorer {
} }
} }
fn reveal_file(&mut self, cx: &mut Context, path: PathBuf) {
let current_root = &self.state.current_root;
let current_path = path.as_path().to_string_lossy().to_string();
let current_root = current_root.as_path().to_string_lossy().to_string() + "/";
let segments = current_path
.strip_prefix(current_root.as_str())
.expect(
format!(
"Failed to strip prefix '{}' from '{}'",
current_root, current_path
)
.as_str(),
)
.split(std::path::MAIN_SEPARATOR)
.collect::<Vec<_>>();
match self.tree.reveal_item(segments) {
Ok(_) => {
self.focus();
}
Err(error) => cx.editor.set_error(error.to_string()),
}
}
pub fn reveal_current_file(&mut self, cx: &mut Context) { pub fn reveal_current_file(&mut self, cx: &mut Context) {
let current_document_path = doc!(cx.editor).path().cloned(); let current_document_path = doc!(cx.editor).path().cloned();
match current_document_path { match current_document_path {
None => cx.editor.set_error("No opened document."), None => cx.editor.set_error("No opened document."),
Some(current_path) => { Some(current_path) => self.reveal_file(cx, current_path),
let current_root = &self.state.current_root;
let current_path = current_path.as_path().to_string_lossy().to_string();
let current_root = current_root.as_path().to_string_lossy().to_string() + "/";
let segments = current_path
.strip_prefix(current_root.as_str())
.expect(
format!(
"Failed to strip prefix '{}' from '{}'",
current_root, current_path
)
.as_str(),
)
.split(std::path::MAIN_SEPARATOR)
.collect::<Vec<_>>();
match self.tree.reveal_item(segments) {
Ok(_) => {
self.focus();
}
Err(error) => cx.editor.set_error(error.to_string()),
}
}
} }
} }
@ -467,6 +470,20 @@ impl Explorer {
} }
} }
fn new_rename_prompt(&mut self) {
let name = self.tree.current_item().path.to_string_lossy();
self.prompt = Some((
PromptAction::RenameFile,
Prompt::new(
format!(" Rename to ").into(),
None,
ui::completers::none,
|_, _, _| {},
)
.with_line(name.to_string()),
));
}
fn new_remove_file_prompt(&mut self, cx: &mut Context) { fn new_remove_file_prompt(&mut self, cx: &mut Context) {
let item = self.tree.current_item(); let item = self.tree.current_item();
let check = || { let check = || {
@ -807,6 +824,15 @@ impl Explorer {
} }
} }
} }
(PromptAction::RenameFile, key!(Enter)) => {
let item = self.tree.current_item();
if let Err(e) = std::fs::rename(&item.path, line) {
cx.editor.set_error(format!("{e}"));
} else {
self.tree.remove_current();
self.reveal_file(cx, PathBuf::from(line))
}
}
(_, key!(Esc) | ctrl!('c')) => {} (_, key!(Esc) | ctrl!('c')) => {}
_ => { _ => {
prompt.handle_event(Event::Key(event), cx); prompt.handle_event(Event::Key(event), cx);
@ -907,16 +933,7 @@ impl Component for Explorer {
} }
key!(']') => self.change_root(cx, self.tree.current_item().path.clone()), key!(']') => self.change_root(cx, self.tree.current_item().path.clone()),
key!('d') => self.new_remove_prompt(cx), key!('d') => self.new_remove_prompt(cx),
key!('r') => { key!('r') => self.new_rename_prompt(),
self.on_next_key = Some(Box::new(|cx, explorer, event| {
match event.into() {
key!('d') => explorer.new_remove_dir_prompt(cx),
key!('f') => explorer.new_remove_file_prompt(cx),
_ => return EventResult::Ignored(None),
};
EventResult::Consumed(None)
}));
}
_ => { _ => {
self.tree self.tree
.handle_event(Event::Key(key_event), cx, &mut self.state); .handle_event(Event::Key(key_event), cx, &mut self.state);

@ -174,18 +174,61 @@ impl<T: TreeItem> Tree<T> {
} }
Ok(()) Ok(())
} }
fn refresh(&mut self) -> Result<()> {
if !self.is_opened {
return Ok(());
}
let latest_children = vec_to_tree(self.item.get_children()?);
let filtered = std::mem::replace(&mut self.children, vec![])
.into_iter()
// Remove children that does not exists in latest_children
.filter(|tree| {
latest_children
.iter()
.any(|child| tree.item.name().eq(&child.item.name()))
})
.map(|mut tree| {
tree.refresh()?;
Ok(tree)
})
.collect::<Result<Vec<_>>>()?;
// Add new children
let new_nodes = latest_children
.into_iter()
.filter(|child| {
!filtered
.iter()
.any(|child_| child.item.name().eq(&child_.item.name()))
})
.collect::<Vec<_>>();
self.children = filtered.into_iter().chain(new_nodes).collect();
self.sort();
Ok(())
}
fn sort(&mut self) {
self.children
.sort_by(|a, b| tree_item_cmp(&a.item, &b.item))
}
} }
impl<T> Tree<T> { impl<T> Tree<T> {
pub fn new(item: T, children: Vec<Tree<T>>) -> Self { pub fn new(item: T, children: Vec<Tree<T>>) -> Self {
let is_opened = !children.is_empty();
Self { Self {
item, item,
index: 0, index: 0,
parent_index: None, parent_index: None,
children: index_elems(0, children), children: index_elems(0, children),
is_opened: false, is_opened,
} }
} }
fn iter(&self) -> TreeIter<T> { fn iter(&self) -> TreeIter<T> {
TreeIter { TreeIter {
tree: self, tree: self,
@ -352,6 +395,8 @@ impl<T: TreeItem> TreeView<T> {
/// vec!["helix-term", "src", "ui", "tree.rs"] /// vec!["helix-term", "src", "ui", "tree.rs"]
/// ``` /// ```
pub fn reveal_item(&mut self, segments: Vec<&str>) -> Result<()> { pub fn reveal_item(&mut self, segments: Vec<&str>) -> Result<()> {
self.tree.refresh()?;
// Expand the tree // Expand the tree
segments.iter().fold( segments.iter().fold(
Ok(&mut self.tree), Ok(&mut self.tree),

Loading…
Cancel
Save