use crate::path_info::PathInfo;
fn comparable_text(text: &str) -> &str {
if text.starts_with('.') && text.len() > 1 {
&text[1..]
} else {
text
}
}
fn unique_prefix_len(target: &str, others: &[&str]) -> Option<usize> {
let target_cmp = comparable_text(target);
let other_cmps: Vec<&str> = others.iter().map(|o| comparable_text(o)).collect();
if other_cmps.contains(&target_cmp) {
return None;
}
let target_chars: Vec<char> = target_cmp.chars().collect();
for len in 1..=target_chars.len() {
let prefix: String = target_chars[..len].iter().collect();
let is_unique = other_cmps.iter().all(|other| {
let other_chars: Vec<char> = other.chars().collect();
if other_chars.len() < len {
true
} else {
let other_prefix: String = other_chars[..len].iter().collect();
prefix != other_prefix
}
});
if is_unique {
return Some(len);
}
}
Some(target_chars.len())
}
fn abbreviate_with_len(text: &str, prefix_len: usize) -> String {
if text.starts_with('.') && text.len() > 1 {
let after_dot: String = text[1..].chars().take(prefix_len).collect();
format!(".{after_dot}")
} else {
text.chars().take(prefix_len).collect()
}
}
pub fn shrink_unique(info: &PathInfo, anchors: &[String]) -> String {
let texts: Vec<&str> = info.segments.iter().map(|s| s.text.as_str()).collect();
let abbreviated: Vec<String> = texts
.iter()
.enumerate()
.map(|(i, &text)| {
if anchors.iter().any(|a| a == text) {
return text.to_string();
}
let others: Vec<&str> = texts
.iter()
.enumerate()
.filter(|(j, _)| *j != i)
.map(|(_, &t)| t)
.collect();
match unique_prefix_len(text, &others) {
Some(len) => abbreviate_with_len(text, len),
None => text.to_string(), }
})
.collect();
let refs: Vec<&str> = abbreviated.iter().map(|s| s.as_str()).collect();
info.reassemble(&refs)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::path_info::PathInfo;
#[test]
fn all_unique_first_chars() {
let info = PathInfo::parse("/home/john/projects/rust/lib.rs", None);
let result = shrink_unique(&info, &[]);
assert_eq!(result, "/h/j/p/r/lib.rs");
}
#[test]
fn identical_segments_kept_full() {
let info = PathInfo::parse("/dev/dev/dev/file.txt", None);
let result = shrink_unique(&info, &[]);
assert_eq!(result, "/dev/dev/dev/file.txt");
}
#[test]
fn partial_disambiguation() {
let info = PathInfo::parse("/home/documents/downloads/file.txt", None);
let result = shrink_unique(&info, &[]);
assert_eq!(result, "/h/doc/dow/file.txt");
}
#[test]
fn dot_prefixed_disambiguation() {
let info = PathInfo::parse("/home/user/.config/.cache/file.txt", None);
let result = shrink_unique(&info, &[]);
assert_eq!(result, "/h/u/.co/.ca/file.txt");
}
#[test]
fn windows_unique() {
let info = PathInfo::parse("C:\\Users\\Admin\\AppData\\Application\\file.txt", None);
let result = shrink_unique(&info, &[]);
assert_eq!(result, "C:\\U\\Ad\\AppD\\Appl\\file.txt");
}
#[test]
fn single_segment() {
let info = PathInfo::parse("/home/file.txt", None);
let result = shrink_unique(&info, &[]);
assert_eq!(result, "/h/file.txt");
}
#[test]
fn anchored_segment_preserved() {
let info = PathInfo::parse("/home/john/src/lib.rs", None);
let anchors = vec!["src".to_string()];
let result = shrink_unique(&info, &anchors);
assert_eq!(result, "/h/j/src/lib.rs");
}
}