feat(directory): Add directory substitutions (#1183)
Adds an option to provide a table of strings to substitute in the directory string. Fixes #1065. Co-authored-by: Radu Butoi <butoi@google.com>
This commit is contained in:
parent
329b3c791d
commit
ab1c3d1c54
|
@ -399,9 +399,19 @@ it would have been `nixpkgs/pkgs`.
|
|||
|
||||
| Variable | Default | Description |
|
||||
| --------------------------- | ------- | ---------------------------------------------------------------------------------------- |
|
||||
| `substitutions` | | A table of substitutions to be made to the path. |
|
||||
| `fish_style_pwd_dir_length` | `0` | The number of characters to use when applying fish shell pwd path logic. |
|
||||
| `use_logical_path` | `true` | Displays the logical path provided by the shell (`PWD`) instead of the path from the OS. |
|
||||
|
||||
`substitutions` allows you to define arbitrary replacements for literal strings that occur in the path, for example long network
|
||||
prefixes or development directories (i.e. Java). Note that this will disable the fish style PWD.
|
||||
|
||||
```toml
|
||||
[directory.substitutions]
|
||||
"/Volumes/network/path" = "/net"
|
||||
"src/com/long/java/path" = "mypath"
|
||||
```
|
||||
|
||||
`fish_style_pwd_dir_length` interacts with the standard truncation options in a way that can be surprising at first: if it's non-zero,
|
||||
the components of the path that would normally be truncated are instead displayed with that many characters. For example, the path
|
||||
`/built/this/city/on/rock/and/roll`, which would normally be displayed as as `rock/and/roll`, would be displayed as
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use ansi_term::{Color, Style};
|
||||
use starship_module_config_derive::ModuleConfig;
|
||||
|
@ -7,6 +8,7 @@ use starship_module_config_derive::ModuleConfig;
|
|||
pub struct DirectoryConfig<'a> {
|
||||
pub truncation_length: i64,
|
||||
pub truncate_to_repo: bool,
|
||||
pub substitutions: HashMap<String, &'a str>,
|
||||
pub fish_style_pwd_dir_length: i64,
|
||||
pub use_logical_path: bool,
|
||||
pub prefix: &'a str,
|
||||
|
@ -20,6 +22,7 @@ impl<'a> RootModuleConfig<'a> for DirectoryConfig<'a> {
|
|||
truncation_length: 3,
|
||||
truncate_to_repo: true,
|
||||
fish_style_pwd_dir_length: 0,
|
||||
substitutions: HashMap::new(),
|
||||
use_logical_path: true,
|
||||
prefix: "in ",
|
||||
style: Color::Cyan.bold(),
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use path_slash::PathExt;
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
|
@ -10,12 +11,15 @@ use crate::configs::directory::DirectoryConfig;
|
|||
|
||||
/// Creates a module with the current directory
|
||||
///
|
||||
/// Will perform path contraction and truncation.
|
||||
/// Will perform path contraction, substitution, and truncation.
|
||||
/// **Contraction**
|
||||
/// - Paths beginning with the home directory or with a git repo right
|
||||
/// inside the home directory will be contracted to `~`
|
||||
/// - Paths containing a git repo will contract to begin at the repo root
|
||||
///
|
||||
/// **Substitution**
|
||||
/// Paths will undergo user-provided substitutions of substrings
|
||||
///
|
||||
/// **Truncation**
|
||||
/// Paths will be limited in length to `3` path components by default.
|
||||
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
|
@ -67,10 +71,14 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||
_ => contract_path(current_dir, &home_dir, HOME_SYMBOL),
|
||||
};
|
||||
|
||||
// Truncate the dir string to the maximum number of path components
|
||||
let truncated_dir_string = truncate(dir_string, config.truncation_length as usize);
|
||||
let substituted_dir = substitute_path(dir_string, &config.substitutions);
|
||||
|
||||
if config.fish_style_pwd_dir_length > 0 {
|
||||
// Truncate the dir string to the maximum number of path components
|
||||
let truncated_dir_string = truncate(substituted_dir, config.truncation_length as usize);
|
||||
|
||||
// Substitutions could have changed the prefix, so don't allow them and
|
||||
// fish-style path contraction together
|
||||
if config.fish_style_pwd_dir_length > 0 && config.substitutions.is_empty() {
|
||||
// If user is using fish style path, we need to add the segment first
|
||||
let contracted_home_dir = contract_path(¤t_dir, &home_dir, HOME_SYMBOL);
|
||||
let fish_style_dir = to_fish_style(
|
||||
|
@ -126,6 +134,18 @@ fn contract_path(full_path: &Path, top_level_path: &Path, top_level_replacement:
|
|||
)
|
||||
}
|
||||
|
||||
/// Perform a list of string substitutions on the path
|
||||
///
|
||||
/// Given a list of (from, to) pairs, this will perform the string
|
||||
/// substitutions, in order, on the path. Any non-pair of strings is ignored.
|
||||
fn substitute_path(dir_string: String, substitutions: &HashMap<String, &str>) -> String {
|
||||
let mut substituted_dir = dir_string;
|
||||
for substitution_pair in substitutions.iter() {
|
||||
substituted_dir = substituted_dir.replace(substitution_pair.0, substitution_pair.1);
|
||||
}
|
||||
substituted_dir
|
||||
}
|
||||
|
||||
/// Takes part before contracted path and replaces it with fish style path
|
||||
///
|
||||
/// Will take the first letter of each directory before the contracted path and
|
||||
|
@ -223,6 +243,17 @@ mod tests {
|
|||
assert_eq!(output, "C:/");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn substitute_prefix_and_middle() {
|
||||
let full_path = "/absolute/path/foo/bar/baz";
|
||||
let mut substitutions = HashMap::new();
|
||||
substitutions.insert("/absolute/path".to_string(), "");
|
||||
substitutions.insert("/bar/".to_string(), "/");
|
||||
|
||||
let output = substitute_path(full_path.to_string(), &substitutions);
|
||||
assert_eq!(output, "/foo/baz");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fish_style_with_user_home_contracted_path() {
|
||||
let path = "~/starship/engines/booster/rocket";
|
||||
|
|
|
@ -24,6 +24,50 @@ fn home_directory() -> io::Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn substituted_truncated_path() -> io::Result<()> {
|
||||
let output = common::render_module("directory")
|
||||
.arg("--path=/some/long/network/path/workspace/a/b/c/dev")
|
||||
.use_config(toml::toml! {
|
||||
[directory]
|
||||
truncation_length = 4
|
||||
[directory.substitutions]
|
||||
"/some/long/network/path" = "/some/net"
|
||||
"a/b/c" = "d"
|
||||
})
|
||||
.output()?;
|
||||
let actual = String::from_utf8(output.stdout).unwrap();
|
||||
|
||||
let expected = format!("in {} ", Color::Cyan.bold().paint("net/workspace/d/dev"));
|
||||
assert_eq!(expected, actual);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn strange_substitution() -> io::Result<()> {
|
||||
let strange_sub = "/\\/;,!";
|
||||
let output = common::render_module("directory")
|
||||
.arg("--path=/foo/bar/regular/path")
|
||||
.use_config(toml::toml! {
|
||||
[directory]
|
||||
truncation_length = 0
|
||||
fish_style_pwd_dir_length = 2 // Overridden by substitutions
|
||||
[directory.substitutions]
|
||||
"regular" = strange_sub
|
||||
})
|
||||
.output()?;
|
||||
let actual = String::from_utf8(output.stdout).unwrap();
|
||||
|
||||
let expected = format!(
|
||||
"in {} ",
|
||||
Color::Cyan
|
||||
.bold()
|
||||
.paint(format!("/foo/bar/{}/path", strange_sub))
|
||||
);
|
||||
assert_eq!(expected, actual);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn directory_in_home() -> io::Result<()> {
|
||||
|
|
Loading…
Reference in New Issue