From e034253a5eea764b20ab601f71bf84903d80e8d6 Mon Sep 17 00:00:00 2001 From: Neil Kistner Date: Mon, 26 Aug 2019 20:52:45 -0500 Subject: feat: Add ability to use an alternate directory truncation style (#239) * Add ability to use an alternate directory truncation style --- src/modules/directory.rs | 95 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 85 insertions(+), 10 deletions(-) (limited to 'src/modules/directory.rs') diff --git a/src/modules/directory.rs b/src/modules/directory.rs index ee3924b98..8c12db59a 100644 --- a/src/modules/directory.rs +++ b/src/modules/directory.rs @@ -16,6 +16,7 @@ use super::{Context, Module}; pub fn module<'a>(context: &'a Context) -> Option> { const HOME_SYMBOL: &str = "~"; const DIR_TRUNCATION_LENGTH: i64 = 3; + const FISH_STYLE_PWD_DIR_LENGTH: i64 = 0; let module_color = Color::Cyan.bold(); let mut module = context.new_module("directory")?; @@ -25,28 +26,40 @@ pub fn module<'a>(context: &'a Context) -> Option> { .config_value_i64("truncation_length") .unwrap_or(DIR_TRUNCATION_LENGTH); let truncate_to_repo = module.config_value_bool("truncate_to_repo").unwrap_or(true); + let fish_style_pwd_dir_length = module + .config_value_i64("fish_style_pwd_dir_length") + .unwrap_or(FISH_STYLE_PWD_DIR_LENGTH); + let home_dir = dirs::home_dir().unwrap(); let current_dir = &context.current_dir; log::debug!("Current directory: {:?}", current_dir); - let dir_string; - match &context.repo_root { + let dir_string = match &context.repo_root { Some(repo_root) if truncate_to_repo => { - // Contract the path to the git repo root let repo_folder_name = repo_root.file_name().unwrap().to_str().unwrap(); - dir_string = contract_path(current_dir, repo_root, repo_folder_name); - } - _ => { - // Contract the path to the home directory - let home_dir = dirs::home_dir().unwrap(); - - dir_string = contract_path(current_dir, &home_dir, HOME_SYMBOL); + // Contract the path to the git repo root + contract_path(current_dir, repo_root, repo_folder_name) } + // Contract the path to the home directory + _ => 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, truncation_length as usize); + + if fish_style_pwd_dir_length > 0 { + // If user is using fish style path, we need to add the segment first + let contracted_home_dir = contract_path(current_dir, &home_dir, HOME_SYMBOL); + let fish_style_dir = to_fish_style( + fish_style_pwd_dir_length as usize, + contracted_home_dir, + &truncated_dir_string, + ); + + module.new_segment("path", &fish_style_dir); + } + module.new_segment("path", &truncated_dir_string); module.get_prefix().set_value("in "); @@ -115,6 +128,38 @@ fn truncate(dir_string: String, length: usize) -> String { truncated_components.join("/") } +/// 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 +/// use that in the path instead. See the following example. +/// +/// Absolute Path: `/Users/Bob/Projects/work/a_repo` +/// Contracted Path: `a_repo` +/// With Fish Style: `~/P/w/a_repo` +/// +/// Absolute Path: `/some/Path/not/in_a/repo/but_nested` +/// Contracted Path: `in_a/repo/but_nested` +/// With Fish Style: `/s/P/n/in_a/repo/but_nested` +fn to_fish_style(pwd_dir_length: usize, dir_string: String, truncated_dir_string: &str) -> String { + let replaced_dir_string = dir_string.replace(truncated_dir_string, ""); + let components = replaced_dir_string.split('/').collect::>(); + + if components.is_empty() { + return replaced_dir_string; + } + + components + .into_iter() + .map(|word| match word { + "" => "", + _ if word.len() <= pwd_dir_length => word, + _ if word.starts_with('.') => &word[..=pwd_dir_length], + _ => &word[..pwd_dir_length], + }) + .collect::>() + .join("/") +} + #[cfg(test)] mod tests { use super::*; @@ -204,4 +249,34 @@ mod tests { let output = truncate(path.to_string(), 3); assert_eq!(output, "engines/booster/rocket") } + + #[test] + fn fish_style_with_user_home_contracted_path() { + let path = "~/starship/engines/booster/rocket"; + let output = to_fish_style(1, path.to_string(), "engines/booster/rocket"); + assert_eq!(output, "~/s/"); + } + + #[test] + fn fish_style_with_user_home_contracted_path_and_dot_dir() { + let path = "~/.starship/engines/booster/rocket"; + let output = to_fish_style(1, path.to_string(), "engines/booster/rocket"); + assert_eq!(output, "~/.s/"); + } + + #[test] + fn fish_style_with_no_contracted_path() { + // `truncatation_length = 2` + let path = "/absolute/Path/not/in_a/repo/but_nested"; + let output = to_fish_style(1, path.to_string(), "repo/but_nested"); + assert_eq!(output, "/a/P/n/i/"); + } + + #[test] + fn fish_style_with_pwd_dir_len_no_contracted_path() { + // `truncatation_length = 2` + let path = "/absolute/Path/not/in_a/repo/but_nested"; + let output = to_fish_style(2, path.to_string(), "repo/but_nested"); + assert_eq!(output, "/ab/Pa/no/in/"); + } } -- cgit v1.2.3