diff options
author | Canop <cano.petrole@gmail.com> | 2021-09-17 21:08:55 +0200 |
---|---|---|
committer | Canop <cano.petrole@gmail.com> | 2021-09-17 21:08:55 +0200 |
commit | 21671ef69a92e562ccbf5a2521243663819e065c (patch) | |
tree | d17e75bd47cd818518525b2bca7188f661655abe /src/tree | |
parent | b45bb00dbb4b1df306faa32cd5d943bdd75f0610 (diff) |
fix special-path/Enter for sym links
Fix #448
Diffstat (limited to 'src/tree')
-rw-r--r-- | src/tree/tree.rs | 70 | ||||
-rw-r--r-- | src/tree/tree_line.rs | 54 |
2 files changed, 55 insertions, 69 deletions
diff --git a/src/tree/tree.rs b/src/tree/tree.rs index b1d2ab0..b147490 100644 --- a/src/tree/tree.rs +++ b/src/tree/tree.rs @@ -7,8 +7,9 @@ use { git::TreeGitStatus, task_sync::ComputationResult, task_sync::Dam, - tree_build::TreeBuilder, + tree_build::{BId, TreeBuilder}, }, + fnv::FnvHashMap, std::{ cmp::Ord, mem, @@ -68,8 +69,44 @@ impl Tree { /// - sort the lines /// - compute left branchs pub fn after_lines_changed(&mut self) { - // we sort the lines (this is mandatory to avoid crashes) - self.lines[1..].sort(); + + // we need to order the lines to build the tree. + // It's a little complicated because + // - we want a case insensitive sort + // - we still don't want to confuse the children of AA and Aa + // - a node can come from a not parent node, when we followed a link + let mut bid_parents: FnvHashMap<BId, BId> = FnvHashMap::default(); + let mut bid_lines: FnvHashMap<BId, &TreeLine> = FnvHashMap::default(); + for line in self.lines[..].iter() { + if let Some(parent_bid) = line.parent_bid { + bid_parents.insert(line.bid, parent_bid); + } + bid_lines.insert(line.bid, &line); + } + let mut sort_paths: FnvHashMap<BId, String> = FnvHashMap::default(); + for line in self.lines[1..].iter() { + let mut sort_path = String::new(); + let mut bid = line.bid; + loop { + if let Some(l) = bid_lines.get(&bid) { + sort_path = format!( + "{}-{}/{}", + l.path.to_string_lossy().to_lowercase(), + bid.index(), // to be sure to separate paths having the same lowercase + sort_path, + ); + } else { + break; + } + if let Some(&parent_bid) = bid_parents.get(&bid) { + bid = parent_bid; + } else { + break; + } + } + sort_paths.insert(line.bid, sort_path); + } + self.lines[1..].sort_by_key(|line| sort_paths.get(&line.bid).unwrap()); let mut best_index = 0; // index of the line with the best score for i in 1..self.lines.len() { @@ -86,24 +123,21 @@ impl Tree { for end_index in (1..self.lines.len()).rev() { let depth = (self.lines[end_index].depth - 1) as usize; let start_index = { - let parent_index = { - let parent_path = &self.lines[end_index].path.parent(); - match parent_path { - Some(parent_path) => { - let mut index = end_index; - loop { - index -= 1; - if self.lines[index].path == *parent_path { - break; - } - if index == 0 { - break; - } + let parent_index = match self.lines[end_index].parent_bid { + Some(parent_bid) => { + let mut index = end_index; + loop { + index -= 1; + if self.lines[index].bid == parent_bid { + break; + } + if index == 0 { + break; } - index } - None => end_index, // Should not happen + index } + None => end_index, // Should not happen }; if parent_index != last_parent_index { // the line at end_index is the last listed child of the line at parent_index diff --git a/src/tree/tree_line.rs b/src/tree/tree_line.rs index 3742f53..612e271 100644 --- a/src/tree/tree_line.rs +++ b/src/tree/tree_line.rs @@ -4,10 +4,10 @@ use { app::{Selection, SelectionType}, file_sum::FileSum, git::LineGitStatus, + tree_build::BId, }, lazy_regex::regex_captures, std::{ - cmp::{self, Ord, Ordering, PartialOrd}, fs, path::{Path, PathBuf}, }, @@ -22,6 +22,8 @@ use is_executable::IsExecutable; /// a line in the representation of the file hierarchy #[derive(Debug, Clone)] pub struct TreeLine { + pub bid: BId, + pub parent_bid: Option<BId>, pub left_branchs: Box<[bool]>, // a depth-sized array telling whether a branch pass pub depth: u16, pub path: PathBuf, @@ -133,55 +135,5 @@ impl TreeLine { } } } -impl PartialEq for TreeLine { - fn eq(&self, other: &TreeLine) -> bool { - self.path == other.path - } -} - -impl Eq for TreeLine {} -impl Ord for TreeLine { - // paths are sorted in a complete ignore case way - // (A<a<B<b) - fn cmp(&self, other: &TreeLine) -> Ordering { - let mut sci = self.path.components(); - let mut oci = other.path.components(); - loop { - match sci.next() { - Some(sc) => { - match oci.next() { - Some(oc) => { - let scs = sc.as_os_str().to_string_lossy(); - let ocs = oc.as_os_str().to_string_lossy(); - let lower_ordering = scs.to_lowercase().cmp(&ocs.to_lowercase()); - if lower_ordering != Ordering::Equal { - return lower_ordering; - } - let ordering = scs.cmp(&ocs); - if ordering != Ordering::Equal { - return ordering; - } - } - None => { - return Ordering::Greater; - } - }; - } - None => { - if oci.next().is_some() { - return Ordering::Less; - } else { - return Ordering::Equal; - } - } - }; - } - } -} -impl PartialOrd for TreeLine { - fn partial_cmp(&self, other: &TreeLine) -> Option<cmp::Ordering> { - Some(self.cmp(other)) - } -} |