mirror of
https://github.com/Llewellynvdm/starship.git
synced 2025-01-28 01:28:33 +00:00
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 |
|
| 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. |
|
| `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. |
|
| `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,
|
`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
|
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
|
`/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 crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
use ansi_term::{Color, Style};
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
@ -7,6 +8,7 @@ use starship_module_config_derive::ModuleConfig;
|
|||||||
pub struct DirectoryConfig<'a> {
|
pub struct DirectoryConfig<'a> {
|
||||||
pub truncation_length: i64,
|
pub truncation_length: i64,
|
||||||
pub truncate_to_repo: bool,
|
pub truncate_to_repo: bool,
|
||||||
|
pub substitutions: HashMap<String, &'a str>,
|
||||||
pub fish_style_pwd_dir_length: i64,
|
pub fish_style_pwd_dir_length: i64,
|
||||||
pub use_logical_path: bool,
|
pub use_logical_path: bool,
|
||||||
pub prefix: &'a str,
|
pub prefix: &'a str,
|
||||||
@ -20,6 +22,7 @@ impl<'a> RootModuleConfig<'a> for DirectoryConfig<'a> {
|
|||||||
truncation_length: 3,
|
truncation_length: 3,
|
||||||
truncate_to_repo: true,
|
truncate_to_repo: true,
|
||||||
fish_style_pwd_dir_length: 0,
|
fish_style_pwd_dir_length: 0,
|
||||||
|
substitutions: HashMap::new(),
|
||||||
use_logical_path: true,
|
use_logical_path: true,
|
||||||
prefix: "in ",
|
prefix: "in ",
|
||||||
style: Color::Cyan.bold(),
|
style: Color::Cyan.bold(),
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use path_slash::PathExt;
|
use path_slash::PathExt;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use unicode_segmentation::UnicodeSegmentation;
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
|
|
||||||
@ -10,12 +11,15 @@ use crate::configs::directory::DirectoryConfig;
|
|||||||
|
|
||||||
/// Creates a module with the current directory
|
/// Creates a module with the current directory
|
||||||
///
|
///
|
||||||
/// Will perform path contraction and truncation.
|
/// Will perform path contraction, substitution, and truncation.
|
||||||
/// **Contraction**
|
/// **Contraction**
|
||||||
/// - Paths beginning with the home directory or with a git repo right
|
/// - Paths beginning with the home directory or with a git repo right
|
||||||
/// inside the home directory will be contracted to `~`
|
/// inside the home directory will be contracted to `~`
|
||||||
/// - Paths containing a git repo will contract to begin at the repo root
|
/// - Paths containing a git repo will contract to begin at the repo root
|
||||||
///
|
///
|
||||||
|
/// **Substitution**
|
||||||
|
/// Paths will undergo user-provided substitutions of substrings
|
||||||
|
///
|
||||||
/// **Truncation**
|
/// **Truncation**
|
||||||
/// Paths will be limited in length to `3` path components by default.
|
/// Paths will be limited in length to `3` path components by default.
|
||||||
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
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),
|
_ => contract_path(current_dir, &home_dir, HOME_SYMBOL),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Truncate the dir string to the maximum number of path components
|
let substituted_dir = substitute_path(dir_string, &config.substitutions);
|
||||||
let truncated_dir_string = truncate(dir_string, config.truncation_length as usize);
|
|
||||||
|
|
||||||
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
|
// 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 contracted_home_dir = contract_path(¤t_dir, &home_dir, HOME_SYMBOL);
|
||||||
let fish_style_dir = to_fish_style(
|
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
|
/// 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
|
/// Will take the first letter of each directory before the contracted path and
|
||||||
@ -223,6 +243,17 @@ mod tests {
|
|||||||
assert_eq!(output, "C:/");
|
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]
|
#[test]
|
||||||
fn fish_style_with_user_home_contracted_path() {
|
fn fish_style_with_user_home_contracted_path() {
|
||||||
let path = "~/starship/engines/booster/rocket";
|
let path = "~/starship/engines/booster/rocket";
|
||||||
|
@ -24,6 +24,50 @@ fn home_directory() -> io::Result<()> {
|
|||||||
Ok(())
|
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]
|
#[test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn directory_in_home() -> io::Result<()> {
|
fn directory_in_home() -> io::Result<()> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user