summaryrefslogtreecommitdiffstats
path: root/src/tree
diff options
context:
space:
mode:
authorCanop <cano.petrole@gmail.com>2021-09-17 21:08:55 +0200
committerCanop <cano.petrole@gmail.com>2021-09-17 21:08:55 +0200
commit21671ef69a92e562ccbf5a2521243663819e065c (patch)
treed17e75bd47cd818518525b2bca7188f661655abe /src/tree
parentb45bb00dbb4b1df306faa32cd5d943bdd75f0610 (diff)
fix special-path/Enter for sym links
Fix #448
Diffstat (limited to 'src/tree')
-rw-r--r--src/tree/tree.rs70
-rw-r--r--src/tree/tree_line.rs54
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))
- }
-}