winure/path-convert/src/main.rs

124 lines
3.3 KiB
Rust

use std::path::{ Path, PathBuf };
use pico_args::Arguments;
// - HELPER -
const DRIVE: &str = "/mnt/c/";
// - ENV -
const DISTRO: &str = "WSL_DISTRO_NAME";
// - FLAGS -
const HELP: [&str;2] = [ "-h", "--help" ];
const NET_PATH: [&str;2] = [ "-n", "--network" ];
const NO_SPACES: [&str;2] = [ "-s", "--no-space" ];
const QUOTED: [&str;2] = [ "-q", "--quotes" ];
pub fn main() {
let mut args = Arguments::from_env();
// handle help flag
if args.contains(HELP) {
help_text();
return;
}
// handle quote flag
let quotes: &str =
if args.contains(QUOTED) {
if args.contains(QUOTED) { "\"" } // -qq -> "..." (output with double quotes)
else { "'" } // -q -> '...' (output with single quotes)
} else { "" }; // _ -> ... (output with no quotes)
// consume simple flags
let no_spaces = args.contains(NO_SPACES);
let network_path = args.contains(NET_PATH);
let mut targets = args.finish();
// for empty args, just do cwd
if targets.len() == 0 { targets.push(".".into()) ; }
for target in targets {
let target = target.to_string_lossy().to_string();
// canonicalize; windows doesn't recognize symlinks
let path = Path::new(&target).canonicalize();
let mut output =
if let Ok(canonical) = path {
canonical.to_string_lossy().to_string()
} else {
target
};
// handle no-space flag
if no_spaces {
let tmp = output.clone();
let parts = tmp.split('/');
let mut current = PathBuf::new();
current.push("/");
for part in parts {
if part.is_empty() { continue; }
let space = part.chars().position(|c| c == ' ');
let len = part.len();
// if a space is found, use short version
if let Some(index) = space {
// find cut point and slice
let cut = usize::min(len, index).min(6);
let replace = &(part[..cut]);
// determine shortened index
let mut index = 0;
let children = current.read_dir();
if !children.is_ok() { continue; }
for child in children.unwrap() {
if let Ok(child) = child {
let name: String = child.file_name().to_string_lossy().to_string();
// matching names increment index
if name.to_lowercase().starts_with(&replace.to_lowercase()) { index += 1; }
// ... and break when we hit the target
if name == part { break; }
}
}
output = output.replacen(part, &format!("{replace}~{index}"), 1);
}
current.push(part);
}
}
// very basic C-drive substitution
if output.starts_with(DRIVE) {
output = output.replace(DRIVE, "C:\\");
} else if network_path {
let name = std::env::var(DISTRO);
if let Ok(name) = name {
output = format!("//wsl.localhost/{name}{output}");
}
}
// switch out separators
output = output.replace("/", "\\");
// emit to stdout
println!("{quotes}{output}{quotes}");
}
}
pub fn help_text() {
println!("path-convert v{}
Valerie Wolfe <sleeplessval@gmail.com>
Canonicalize and convert Unix paths for DOS programs.
usage: path-convert [flags] <paths...>
args:
<paths...> One or more paths to convert
flags:
-h, --help Show this help text
-n, --network Add the network path where appropriate
-q, --quotes Surround the output strings with quotes (-qq for double quotes)
-s, --no-space Don't allow paths to have spaces
", env!("CARGO_PKG_VERSION"));
}