From 1c305c9de7c7e02e60496833107cbff3fbda98c3 Mon Sep 17 00:00:00 2001 From: Segev Finer Date: Thu, 30 Dec 2021 10:57:13 +0200 Subject: [PATCH] feat(directory): Windows path formatting via path_slash::PathBufExt (#3157) * feat: Experimental Windows path formatting via path_slash::PathBufExt * Rework the slash path conversion into a real PR * Add a test for convert_slash = false * Attempt fixing CI failures * Fix lint and fmt * Fix docs/config/README.md getting messed up * Rename convert_slash/from_slash * Move convert_path_sep calls in tests * Keep path_vec immutable * Run rustfmt --- docs/config/README.md | 3 +- src/configs/directory.rs | 2 + src/modules/directory.rs | 229 ++++++++++++++++++++++++++++----------- 3 files changed, 170 insertions(+), 64 deletions(-) diff --git a/docs/config/README.md b/docs/config/README.md index ca96bbc1..1a08e8c7 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -806,7 +806,8 @@ it would have been `nixpkgs/pkgs`. | `read_only_style` | `"red"` | The style for the read only symbol. | | `truncation_symbol` | `""` | The symbol to prefix to truncated paths. eg: "…/" | | `repo_root_style` | `None` | The style for the root of the git repo when `truncate_to_repo` option is set to false.| -| `home_symbol` | `"~"` | The symbol indicating home directory. | +| `home_symbol` | `"~"` | The symbol indicating home directory. | +| `use_os_path_sep` | `true` | Use the OS specific path seperator instead of always using `/` (e.g. `\` on Windows) |
This module has a few advanced configuration options that control how the directory is displayed. diff --git a/src/configs/directory.rs b/src/configs/directory.rs index 566ae439..0d1d9217 100644 --- a/src/configs/directory.rs +++ b/src/configs/directory.rs @@ -20,6 +20,7 @@ pub struct DirectoryConfig<'a> { pub read_only_style: &'a str, pub truncation_symbol: &'a str, pub home_symbol: &'a str, + pub use_os_path_sep: bool, } impl<'a> Default for DirectoryConfig<'a> { @@ -39,6 +40,7 @@ impl<'a> Default for DirectoryConfig<'a> { read_only_style: "red", truncation_symbol: "", home_symbol: "~", + use_os_path_sep: true, } } } diff --git a/src/modules/directory.rs b/src/modules/directory.rs index d140f545..d0ea7315 100644 --- a/src/modules/directory.rs +++ b/src/modules/directory.rs @@ -4,7 +4,7 @@ use super::utils::directory_nix as directory_utils; use super::utils::directory_win as directory_utils; use super::utils::path::PathExt as SPathExt; use indexmap::IndexMap; -use path_slash::PathExt; +use path_slash::{PathBufExt, PathExt}; use std::iter::FromIterator; use std::path::{Path, PathBuf}; use unicode_segmentation::UnicodeSegmentation; @@ -117,6 +117,12 @@ pub fn module<'a>(context: &'a Context) -> Option> { _ => ["".to_string(), "".to_string(), prefix + &dir_string], }; + let path_vec = if config.use_os_path_sep { + path_vec.map(|i| convert_path_sep(&i)) + } else { + path_vec + }; + let lock_symbol = String::from(config.read_only); let display_format = if path_vec[0].is_empty() && path_vec[1].is_empty() { config.format @@ -321,6 +327,11 @@ fn to_fish_style(pwd_dir_length: usize, dir_string: String, truncated_dir_string .join("/") } +/// Convert the path seperators in `path` to the OS specific path seperators. +fn convert_path_sep(path: &str) -> String { + return PathBuf::from_slash(path).to_string_lossy().into_owned(); +} + #[cfg(test)] mod tests { use super::*; @@ -573,7 +584,10 @@ mod tests { home_symbol = "🚀" }) .collect(); - let expected = Some(format!("{} ", Color::Cyan.bold().paint("🚀"))); + let expected = Some(format!( + "{} ", + Color::Cyan.bold().paint(convert_path_sep("🚀")) + )); assert_eq!(expected, actual); } @@ -587,7 +601,12 @@ mod tests { home_symbol = "🚀" }) .collect(); - let expected = Some(format!("{} ", Color::Cyan.bold().paint("🚀/path/subpath"))); + let expected = Some(format!( + "{} ", + Color::Cyan + .bold() + .paint(convert_path_sep("🚀/path/subpath")) + )); assert_eq!(expected, actual); } @@ -606,7 +625,9 @@ mod tests { .collect(); let expected = Some(format!( "{} ", - Color::Cyan.bold().paint("net/workspace/d/dev") + Color::Cyan + .bold() + .paint(convert_path_sep("net/workspace/d/dev")) )); assert_eq!(expected, actual); @@ -622,7 +643,10 @@ mod tests { "/to/sub" = "/wrong/order" }) .collect(); - let expected = Some(format!("{} ", Color::Cyan.bold().paint("/correct/order"))); + let expected = Some(format!( + "{} ", + Color::Cyan.bold().paint(convert_path_sep("/correct/order")) + )); assert_eq!(expected, actual); } @@ -644,7 +668,7 @@ mod tests { "{} ", Color::Cyan .bold() - .paint(format!("/foo/bar/{}/path", strange_sub)) + .paint(convert_path_sep(&format!("/foo/bar/{}/path", strange_sub))) )); assert_eq!(expected, actual); @@ -659,7 +683,9 @@ mod tests { let actual = ModuleRenderer::new("directory").path(dir).collect(); let expected = Some(format!( "{} ", - Color::Cyan.bold().paint(format!("~/{}/starship", name)) + Color::Cyan + .bold() + .paint(convert_path_sep(&format!("~/{}/starship", name))) )); assert_eq!(expected, actual); @@ -677,7 +703,7 @@ mod tests { "{} ", Color::Cyan .bold() - .paint(format!("{}/engine/schematics", name)) + .paint(convert_path_sep(&format!("{}/engine/schematics", name))) )); assert_eq!(expected, actual); @@ -700,9 +726,10 @@ mod tests { .collect(); let expected = Some(format!( "{} ", - Color::Cyan - .bold() - .paint(format!("~/{}/st/schematics", name.split_at(3).0)) + Color::Cyan.bold().paint(convert_path_sep(&format!( + "~/{}/st/schematics", + name.split_at(3).0 + ))) )); assert_eq!(expected, actual); @@ -721,7 +748,10 @@ mod tests { }) .path("/") .collect(); - let expected = Some(format!("{} ", Color::Cyan.bold().paint("/"))); + let expected = Some(format!( + "{} ", + Color::Cyan.bold().paint(convert_path_sep("/")) + )); assert_eq!(expected, actual); } @@ -737,7 +767,7 @@ mod tests { "{} ", Color::Cyan .bold() - .paint(format!("{}/thrusters/rocket", name)) + .paint(convert_path_sep(&format!("{}/thrusters/rocket", name))) )); assert_eq!(expected, actual); @@ -760,9 +790,9 @@ mod tests { let dir_str = dir.to_slash_lossy(); let expected = Some(format!( "{} ", - Color::Cyan - .bold() - .paint(truncate(&dir_str, 100).unwrap_or(dir_str)) + Color::Cyan.bold().paint(convert_path_sep( + &truncate(&dir_str, 100).unwrap_or(dir_str) + )) )); assert_eq!(expected, actual); @@ -785,9 +815,11 @@ mod tests { .collect(); let expected = Some(format!( "{} ", - Color::Cyan - .bold() - .paint(to_fish_style(100, dir.to_slash_lossy(), "")) + Color::Cyan.bold().paint(convert_path_sep(&to_fish_style( + 100, + dir.to_slash_lossy(), + "" + ))) )); assert_eq!(expected, actual); @@ -809,7 +841,9 @@ mod tests { .collect(); let expected = Some(format!( "{} ", - Color::Cyan.bold().paint(format!("{}/rocket", name)) + Color::Cyan + .bold() + .paint(convert_path_sep(&format!("{}/rocket", name))) )); assert_eq!(expected, actual); @@ -832,10 +866,10 @@ mod tests { .collect(); let expected = Some(format!( "{} ", - Color::Cyan.bold().paint(format!( + Color::Cyan.bold().paint(convert_path_sep(&format!( "{}/thrusters/rocket", to_fish_style(1, dir.to_slash_lossy(), "/thrusters/rocket") - )) + ))) )); assert_eq!(expected, actual); @@ -851,7 +885,12 @@ mod tests { init_repo(&repo_dir).unwrap(); let actual = ModuleRenderer::new("directory").path(repo_dir).collect(); - let expected = Some(format!("{} ", Color::Cyan.bold().paint("rocket-controls"))); + let expected = Some(format!( + "{} ", + Color::Cyan + .bold() + .paint(convert_path_sep("rocket-controls")) + )); assert_eq!(expected, actual); tmp_dir.close() @@ -869,7 +908,9 @@ mod tests { let actual = ModuleRenderer::new("directory").path(dir).collect(); let expected = Some(format!( "{} ", - Color::Cyan.bold().paint("rocket-controls/src") + Color::Cyan + .bold() + .paint(convert_path_sep("rocket-controls/src")) )); assert_eq!(expected, actual); @@ -888,7 +929,9 @@ mod tests { let actual = ModuleRenderer::new("directory").path(dir).collect(); let expected = Some(format!( "{} ", - Color::Cyan.bold().paint("src/meters/fuel-gauge") + Color::Cyan + .bold() + .paint(convert_path_sep("src/meters/fuel-gauge")) )); assert_eq!(expected, actual); @@ -915,9 +958,9 @@ mod tests { .collect(); let expected = Some(format!( "{} ", - Color::Cyan - .bold() - .paint("above-repo/rocket-controls/src/meters/fuel-gauge") + Color::Cyan.bold().paint(convert_path_sep( + "above-repo/rocket-controls/src/meters/fuel-gauge" + )) )); assert_eq!(expected, actual); @@ -945,10 +988,10 @@ mod tests { .collect(); let expected = Some(format!( "{} ", - Color::Cyan.bold().paint(format!( + Color::Cyan.bold().paint(convert_path_sep(&format!( "{}/above-repo/rocket-controls/src/meters/fuel-gauge", to_fish_style(1, tmp_dir.path().to_slash_lossy(), "") - )) + ))) )); assert_eq!(expected, actual); @@ -976,10 +1019,10 @@ mod tests { .collect(); let expected = Some(format!( "{} ", - Color::Cyan.bold().paint(format!( + Color::Cyan.bold().paint(convert_path_sep(&format!( "{}/rocket-controls/src/meters/fuel-gauge", to_fish_style(1, tmp_dir.path().join("above-repo").to_slash_lossy(), "") - )) + ))) )); assert_eq!(expected, actual); @@ -1008,7 +1051,7 @@ mod tests { "{} ", Color::Cyan .bold() - .paint("rocket-controls/src/meters/fuel-gauge") + .paint(convert_path_sep("rocket-controls/src/meters/fuel-gauge")) )); assert_eq!(expected, actual); @@ -1028,7 +1071,9 @@ mod tests { let actual = ModuleRenderer::new("directory").path(symlink_dir).collect(); let expected = Some(format!( "{} ", - Color::Cyan.bold().paint("rocket-controls-symlink") + Color::Cyan + .bold() + .paint(convert_path_sep("rocket-controls-symlink")) )); assert_eq!(expected, actual); @@ -1052,7 +1097,9 @@ mod tests { .collect(); let expected = Some(format!( "{} ", - Color::Cyan.bold().paint("rocket-controls-symlink/src") + Color::Cyan + .bold() + .paint(convert_path_sep("rocket-controls-symlink/src")) )); assert_eq!(expected, actual); @@ -1076,7 +1123,9 @@ mod tests { .collect(); let expected = Some(format!( "{} ", - Color::Cyan.bold().paint("src/meters/fuel-gauge") + Color::Cyan + .bold() + .paint(convert_path_sep("src/meters/fuel-gauge")) )); assert_eq!(expected, actual); @@ -1109,9 +1158,9 @@ mod tests { .collect(); let expected = Some(format!( "{} ", - Color::Cyan - .bold() - .paint("above-repo/rocket-controls-symlink/src/meters/fuel-gauge") + Color::Cyan.bold().paint(convert_path_sep( + "above-repo/rocket-controls-symlink/src/meters/fuel-gauge" + )) )); assert_eq!(expected, actual); @@ -1145,10 +1194,10 @@ mod tests { .collect(); let expected = Some(format!( "{} ", - Color::Cyan.bold().paint(format!( + Color::Cyan.bold().paint(convert_path_sep(&format!( "{}/above-repo/rocket-controls-symlink/src/meters/fuel-gauge", to_fish_style(1, tmp_dir.path().to_slash_lossy(), "") - )) + ))) )); assert_eq!(expected, actual); @@ -1182,10 +1231,10 @@ mod tests { .collect(); let expected = Some(format!( "{} ", - Color::Cyan.bold().paint(format!( + Color::Cyan.bold().paint(convert_path_sep(&format!( "{}/rocket-controls-symlink/src/meters/fuel-gauge", to_fish_style(1, tmp_dir.path().join("above-repo").to_slash_lossy(), "") - )) + ))) )); assert_eq!(expected, actual); @@ -1218,9 +1267,9 @@ mod tests { .collect(); let expected = Some(format!( "{} ", - Color::Cyan - .bold() - .paint("rocket-controls-symlink/src/meters/fuel-gauge") + Color::Cyan.bold().paint(convert_path_sep( + "rocket-controls-symlink/src/meters/fuel-gauge" + )) )); assert_eq!(expected, actual); @@ -1248,7 +1297,9 @@ mod tests { .collect(); let expected = Some(format!( "{} ", - Color::Cyan.bold().paint("rocket-controls/src/loop/loop") + Color::Cyan + .bold() + .paint(convert_path_sep("rocket-controls/src/loop/loop")) )); assert_eq!(expected, actual); @@ -1267,7 +1318,9 @@ mod tests { .collect(); let expected = Some(format!( "{} ", - Color::Cyan.bold().paint("…/four/element/path") + Color::Cyan + .bold() + .paint(convert_path_sep("…/four/element/path")) )); assert_eq!(expected, actual); } @@ -1284,7 +1337,9 @@ mod tests { .collect(); let expected = Some(format!( "{} ", - Color::Cyan.bold().paint("/a/four/element/path") + Color::Cyan + .bold() + .paint(convert_path_sep("/a/four/element/path")) )); assert_eq!(expected, actual); } @@ -1305,7 +1360,9 @@ mod tests { .collect(); let expected = Some(format!( "{} ", - Color::Cyan.bold().paint(format!("…/{}/a/subpath", name)) + Color::Cyan + .bold() + .paint(convert_path_sep(&format!("…/{}/a/subpath", name))) )); assert_eq!(expected, actual); tmp_dir.close() @@ -1328,7 +1385,9 @@ mod tests { .collect(); let expected = Some(format!( "{} ", - Color::Cyan.bold().paint(format!("~/{}/a/subpath", name)) + Color::Cyan + .bold() + .paint(convert_path_sep(&format!("~/{}/a/subpath", name))) )); assert_eq!(expected, actual); tmp_dir.close() @@ -1350,7 +1409,10 @@ mod tests { }) .path(dir) .collect(); - let expected = Some(format!("{} ", Color::Cyan.bold().paint("…/src/sub/path"))); + let expected = Some(format!( + "{} ", + Color::Cyan.bold().paint(convert_path_sep("…/src/sub/path")) + )); assert_eq!(expected, actual); tmp_dir.close() } @@ -1374,7 +1436,9 @@ mod tests { .collect(); let expected = Some(format!( "{} ", - Color::Cyan.bold().paint("…/repo/src/sub/path") + Color::Cyan + .bold() + .paint(convert_path_sep("…/repo/src/sub/path")) )); assert_eq!(expected, actual); tmp_dir.close() @@ -1392,7 +1456,10 @@ mod tests { }) .path(dir) .collect(); - let expected = Some(format!("{} ", Color::Cyan.bold().paint("C:/temp"))); + let expected = Some(format!( + "{} ", + Color::Cyan.bold().paint(convert_path_sep("C:/temp")) + )); assert_eq!(expected, actual); } @@ -1408,7 +1475,10 @@ mod tests { }) .path(dir) .collect(); - let expected = Some(format!("{} ", Color::Cyan.bold().paint("…/temp"))); + let expected = Some(format!( + "{} ", + Color::Cyan.bold().paint(convert_path_sep("…/temp")) + )); assert_eq!(expected, actual); } @@ -1424,7 +1494,10 @@ mod tests { }) .path(dir) .collect(); - let expected = Some(format!("{} ", Color::Cyan.bold().paint("…\\temp"))); + let expected = Some(format!( + "{} ", + Color::Cyan.bold().paint(convert_path_sep("…\\temp")) + )); assert_eq!(expected, actual); } @@ -1437,7 +1510,9 @@ mod tests { let expected = Some(format!( "{} ", - Color::Cyan.bold().paint("Logical:/fuel-gauge") + Color::Cyan + .bold() + .paint(convert_path_sep("Logical:/fuel-gauge")) )); let actual = ModuleRenderer::new("directory") @@ -1463,7 +1538,9 @@ mod tests { let expected = Some(format!( "{} ", - Color::Cyan.bold().paint("src/meters/fuel-gauge") + Color::Cyan + .bold() + .paint(convert_path_sep("src/meters/fuel-gauge")) )); let actual = ModuleRenderer::new("directory") @@ -1489,7 +1566,9 @@ mod tests { let expected = Some(format!( "{} ", - Color::Cyan.bold().paint("C:/Windows/System32") + Color::Cyan + .bold() + .paint(convert_path_sep("C:/Windows/System32")) )); // Note: We have disable the read_only settings here due to false positives when running @@ -1519,7 +1598,9 @@ mod tests { // which is why the first part of this string still includes backslashes let expected = Some(format!( "{} ", - Color::Cyan.bold().paint(r"\\server\share/a/b/c") + Color::Cyan + .bold() + .paint(convert_path_sep(r"\\server\share/a/b/c")) )); let actual = ModuleRenderer::new("directory") @@ -1555,7 +1636,7 @@ mod tests { "{}{}repo{} ", Color::Cyan.bold().prefix(), Color::Red.prefix(), - Color::Cyan.paint("/src/sub/path") + Color::Cyan.paint(convert_path_sep("/src/sub/path")) )); assert_eq!(expected, actual); tmp_dir.close() @@ -1581,9 +1662,9 @@ mod tests { .collect(); let expected = Some(format!( "{}{}repo{} ", - Color::Cyan.bold().paint("…/above/"), + Color::Cyan.bold().paint(convert_path_sep("…/above/")), Color::Green.prefix(), - Color::Cyan.bold().paint("/src/sub/path") + Color::Cyan.bold().paint(convert_path_sep("/src/sub/path")) )); assert_eq!(expected, actual); tmp_dir.close() @@ -1630,4 +1711,26 @@ mod tests { assert_eq!(expected, actual); } + + #[test] + fn use_os_path_sep_false() -> io::Result<()> { + let (tmp_dir, name) = make_known_tempdir(home_dir().unwrap().as_path())?; + let dir = tmp_dir.path().join("starship"); + fs::create_dir_all(&dir)?; + + let actual = ModuleRenderer::new("directory") + .config(toml::toml! { + [directory] + use_os_path_sep = false + }) + .path(dir) + .collect(); + let expected = Some(format!( + "{} ", + Color::Cyan.bold().paint(format!("~/{}/starship", name)) + )); + + assert_eq!(expected, actual); + tmp_dir.close() + } }