feat(explore): rename file/folder

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

@ -233,6 +233,7 @@ enum PromptAction {
},
RemoveDir,
RemoveFile,
RenameFile,
Filter,
}
@ -289,13 +290,9 @@ impl Explorer {
}
}
pub fn reveal_current_file(&mut self, cx: &mut Context) {
let current_document_path = doc!(cx.editor).path().cloned();
match current_document_path {
None => cx.editor.set_error("No opened document."),
Some(current_path) => {
fn reveal_file(&mut self, cx: &mut Context, path: PathBuf) {
let current_root = &self.state.current_root;
let current_path = current_path.as_path().to_string_lossy().to_string();
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())
@ -315,6 +312,12 @@ impl Explorer {
Err(error) => cx.editor.set_error(error.to_string()),
}
}
pub fn reveal_current_file(&mut self, cx: &mut Context) {
let current_document_path = doc!(cx.editor).path().cloned();
match current_document_path {
None => cx.editor.set_error("No opened document."),
Some(current_path) => self.reveal_file(cx, current_path),
}
}
@ -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) {
let item = self.tree.current_item();
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')) => {}
_ => {
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!('d') => self.new_remove_prompt(cx),
key!('r') => {
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)
}));
}
key!('r') => self.new_rename_prompt(),
_ => {
self.tree
.handle_event(Event::Key(key_event), cx, &mut self.state);

@ -174,18 +174,61 @@ impl<T: TreeItem> Tree<T> {
}
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> {
pub fn new(item: T, children: Vec<Tree<T>>) -> Self {
let is_opened = !children.is_empty();
Self {
item,
index: 0,
parent_index: None,
children: index_elems(0, children),
is_opened: false,
is_opened,
}
}
fn iter(&self) -> TreeIter<T> {
TreeIter {
tree: self,
@ -352,6 +395,8 @@ impl<T: TreeItem> TreeView<T> {
/// vec!["helix-term", "src", "ui", "tree.rs"]
/// ```
pub fn reveal_item(&mut self, segments: Vec<&str>) -> Result<()> {
self.tree.refresh()?;
// Expand the tree
segments.iter().fold(
Ok(&mut self.tree),

Loading…
Cancel
Save