use std::path::{Path, PathBuf};
#[cfg(windows)]
pub fn canonicalize(path: impl AsRef<Path>) -> std::io::Result<PathBuf> {
dunce::canonicalize(path)
}
#[cfg(not(windows))]
pub fn canonicalize(path: impl AsRef<Path>) -> std::io::Result<PathBuf> {
std::fs::canonicalize(path)
}
#[cfg(windows)]
pub fn expand_tilde(path: &str) -> PathBuf {
return PathBuf::from(path);
}
#[cfg(not(windows))]
pub fn expand_tilde(path: &str) -> PathBuf {
if let Some(stripped) = path.strip_prefix("~/")
&& let Some(home_dir) = dirs::home_dir()
{
return home_dir.join(stripped);
}
PathBuf::from(path)
}
pub fn calculate_distance_penalty(current_file: Option<&str>, candidate_dir: &str) -> i32 {
let Some(current_path) = current_file else {
return 0;
};
let current_dir = match current_path.rfind('/') {
Some(pos) => ¤t_path[..pos],
None => "",
};
let candidate_dir = candidate_dir.strip_suffix('/').unwrap_or(candidate_dir);
if current_dir == candidate_dir {
return 0;
}
let mut current_parts = current_dir.split('/').filter(|s| !s.is_empty());
let mut candidate_parts = candidate_dir.split('/').filter(|s| !s.is_empty());
let mut common_len = 0usize;
let mut current_total = 0usize;
loop {
match (current_parts.next(), candidate_parts.next()) {
(Some(a), Some(b)) => {
current_total += 1;
if a == b {
common_len += 1;
} else {
current_total += current_parts.count();
break;
}
}
(Some(_), None) => {
current_total += 1 + current_parts.count();
break;
}
(None, _) => {
break;
}
}
}
let depth_from_common = current_total - common_len;
if depth_from_common == 0 {
return 0;
}
(-(depth_from_common as i32)).max(-20)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg(not(target_family = "windows"))]
fn test_calculate_distance_penalty() {
assert_eq!(calculate_distance_penalty(None, "examples/user/test/"), 0);
assert_eq!(
calculate_distance_penalty(Some("examples/user/test/main.rs"), "examples/user/test/"),
0
);
assert_eq!(
calculate_distance_penalty(
Some("examples/user/test/subdir/file.rs"),
"examples/user/test/"
),
-1
);
assert_eq!(
calculate_distance_penalty(
Some("examples/user/test/dir1/file.rs"),
"examples/user/test/dir2/"
),
-1
);
assert_eq!(
calculate_distance_penalty(
Some("examples/audio-announce/src/lib/audio-announce.rs"),
"examples/audio-announce/src/"
),
-1
);
assert_eq!(
calculate_distance_penalty(
Some("examples/audio-announce/src/audio-announce.rs"),
"examples/pixel/src/"
),
-2
);
assert_eq!(calculate_distance_penalty(Some("main.rs"), ""), 0);
}
#[test]
#[cfg(target_family = "windows")]
fn distance_penalty_works_on_windows() {
assert_eq!(
calculate_distance_penalty(None, "examples\\user\\test\\"),
0
);
assert_eq!(
calculate_distance_penalty(
Some("examples\\user\\test\\main.rs"),
"examples\\user\\test\\"
),
0
);
assert_eq!(
calculate_distance_penalty(
Some("examples\\user\\test\\subdir\\file.rs"),
"examples\\user\\test\\"
),
-1
);
}
}