feat: edit working-checkout comparisons with normal editor actions
This commit is contained in:
+67
-58
@@ -165,10 +165,10 @@ impl FilePicker {
|
||||
Ok(Self::from_nodes(root, nodes, presentation, view, warning))
|
||||
}
|
||||
|
||||
/// Builds the changed-path catalog without consulting the working tree.
|
||||
pub fn from_paths(root: PathBuf, paths: impl IntoIterator<Item = PathBuf>) -> Self {
|
||||
/// Builds a changed-path catalog, retaining each path's comparison index.
|
||||
pub fn from_paths(root: PathBuf, paths: impl IntoIterator<Item = (usize, PathBuf)>) -> Self {
|
||||
let mut catalog = HashMap::new();
|
||||
for (index, path) in paths.into_iter().enumerate() {
|
||||
for (index, path) in paths {
|
||||
for parent in path
|
||||
.ancestors()
|
||||
.skip(1)
|
||||
@@ -719,63 +719,69 @@ impl FilePicker {
|
||||
|
||||
pub(crate) fn refresh(&mut self) {
|
||||
match Self::scan(self.root.clone(), self.presentation, self.view) {
|
||||
Ok(mut replacement) => {
|
||||
let by_path: HashMap<_, _> = replacement
|
||||
.nodes
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, node)| (node.path.clone(), index))
|
||||
.collect();
|
||||
let surviving = |node: usize| {
|
||||
let mut path = self.nodes[node].path.as_path();
|
||||
loop {
|
||||
if let Some(&node) = by_path.get(path) {
|
||||
return Some(node);
|
||||
}
|
||||
path = path.parent()?;
|
||||
}
|
||||
};
|
||||
replacement.expanded = self
|
||||
.expanded
|
||||
.iter()
|
||||
.filter_map(|&node| {
|
||||
by_path
|
||||
.get(&self.nodes[node].path)
|
||||
.copied()
|
||||
.filter(|&node| replacement.nodes[node].is_dir)
|
||||
})
|
||||
.collect();
|
||||
replacement.filter_collapsed = self
|
||||
.filter_collapsed
|
||||
.iter()
|
||||
.filter_map(|&node| {
|
||||
by_path
|
||||
.get(&self.nodes[node].path)
|
||||
.copied()
|
||||
.filter(|&node| replacement.nodes[node].is_dir)
|
||||
})
|
||||
.collect();
|
||||
replacement.saved_selection =
|
||||
self.saved_selection.map(|node| node.and_then(surviving));
|
||||
replacement.filtered_selection =
|
||||
self.filtered_selection.map(|node| node.and_then(surviving));
|
||||
replacement.query = self.query.clone();
|
||||
replacement.focused = self.focused;
|
||||
replacement.view = self.view;
|
||||
replacement.searching = self.searching;
|
||||
replacement.tree_searching = self.tree_searching;
|
||||
let selected = self
|
||||
.selected_node()
|
||||
.or(self.filtered_selection[self.view.index()])
|
||||
.or(self.saved_selection[self.view.index()])
|
||||
.and_then(surviving);
|
||||
replacement.project(selected, false);
|
||||
replacement.remember_selection(false);
|
||||
*self = replacement;
|
||||
}
|
||||
Ok(replacement) => self.replace_catalog(replacement),
|
||||
Err(error) => self.error = Some(format!("Refresh failed: {error}")),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn replace_paths(&mut self, paths: impl IntoIterator<Item = (usize, PathBuf)>) {
|
||||
self.replace_catalog(Self::from_paths(self.root.clone(), paths));
|
||||
}
|
||||
|
||||
fn replace_catalog(&mut self, mut replacement: Self) {
|
||||
replacement.presentation = self.presentation;
|
||||
let by_path: HashMap<_, _> = replacement
|
||||
.nodes
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, node)| (node.path.clone(), index))
|
||||
.collect();
|
||||
let surviving = |node: usize| {
|
||||
let mut path = self.nodes[node].path.as_path();
|
||||
loop {
|
||||
if let Some(&node) = by_path.get(path) {
|
||||
return Some(node);
|
||||
}
|
||||
path = path.parent()?;
|
||||
}
|
||||
};
|
||||
replacement.expanded = self
|
||||
.expanded
|
||||
.iter()
|
||||
.filter_map(|&node| {
|
||||
by_path
|
||||
.get(&self.nodes[node].path)
|
||||
.copied()
|
||||
.filter(|&node| replacement.nodes[node].is_dir)
|
||||
})
|
||||
.collect();
|
||||
replacement.filter_collapsed = self
|
||||
.filter_collapsed
|
||||
.iter()
|
||||
.filter_map(|&node| {
|
||||
by_path
|
||||
.get(&self.nodes[node].path)
|
||||
.copied()
|
||||
.filter(|&node| replacement.nodes[node].is_dir)
|
||||
})
|
||||
.collect();
|
||||
replacement.saved_selection = self.saved_selection.map(|node| node.and_then(surviving));
|
||||
replacement.filtered_selection =
|
||||
self.filtered_selection.map(|node| node.and_then(surviving));
|
||||
replacement.query = self.query.clone();
|
||||
replacement.focused = self.focused;
|
||||
replacement.view = self.view;
|
||||
replacement.searching = self.searching;
|
||||
replacement.tree_searching = self.tree_searching;
|
||||
let selected = self
|
||||
.selected_node()
|
||||
.or(self.filtered_selection[self.view.index()])
|
||||
.or(self.saved_selection[self.view.index()])
|
||||
.and_then(surviving);
|
||||
replacement.project(selected, false);
|
||||
replacement.remember_selection(false);
|
||||
*self = replacement;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -786,7 +792,10 @@ mod tests {
|
||||
fn virtual_catalog_compacts_and_retains_file_directory_collisions() {
|
||||
let mut picker = FilePicker::from_paths(
|
||||
PathBuf::new(),
|
||||
["x", "x/y", "src/deep/deleted.rs", "src/deep/deleted.rs"].map(PathBuf::from),
|
||||
["x", "x/y", "src/deep/deleted.rs", "src/deep/deleted.rs"]
|
||||
.map(PathBuf::from)
|
||||
.into_iter()
|
||||
.enumerate(),
|
||||
);
|
||||
assert_eq!(
|
||||
picker
|
||||
|
||||
Reference in New Issue
Block a user