1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
// Copyright (c) 2022 FernOfSigma.
// This software is licensed under the MIT license.
//! Shortens UNIX-like paths.
use std::path::{Path, PathBuf};
use itertools::Itertools;
/// Takes a reference to a [`Path`] and shortens all but its last component to their
/// first characters. Dots (`.`) are left as is since they might refer to hidden or
/// relative paths.
///
/// [`Path`]: https://doc.rust-lang.org/std/path/struct.Path.html
///
/// # Example
/// ```rust
/// use spat::shorten;
///
/// fn main() {
/// let shortened = shorten("/path/to/something");
/// assert_eq!(shortened.as_os_str(), "/p/t/something");
/// }
/// ```
pub fn shorten(path: impl AsRef<Path>) -> PathBuf{
let mut components = path.as_ref().components().collect::<Vec<_>>();
let basename = components.pop();
let mut shortened = components.into_iter()
.map(|component| component.as_os_str().to_string_lossy())
.map(|s| s.chars().take_while_inclusive(|c| c == &'.').collect::<String>())
.collect::<PathBuf>();
shortened.extend(basename);
shortened
}
#[cfg(test)]
mod tests {
use super::*;
fn compare(s1: &str, s2: &str) {
assert_eq!(shorten(s1).as_os_str(), s2);
}
#[test]
fn symbols() {
compare("~", "~");
compare("/", "/");
compare(".", ".");
}
#[test]
fn standard() {
compare("~/sigma/dev/rust/", "~/s/d/rust");
compare("/home/sigma/dev/rust/", "/h/s/d/rust");
compare("home/sigma/dev/rust/", "h/s/d/rust");
}
#[test]
fn hidden() {
compare("~/.cargo/bin/", "~/.c/bin");
}
#[test]
fn dots() {
compare("./music/../videos/1.mkv", "./m/../v/1.mkv");
}
}