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
This commit is contained in:
Segev Finer 2021-12-30 10:57:13 +02:00 committed by GitHub
parent f48c7a26cf
commit 1c305c9de7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 170 additions and 64 deletions

View File

@ -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) |
<details>
<summary>This module has a few advanced configuration options that control how the directory is displayed.</summary>

View File

@ -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,
}
}
}

View File

@ -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<Module<'a>> {
_ => ["".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()
}
}