PrettyPrompt/src/indicators/pwd.rs
2024-11-30 12:22:49 +05:30

98 lines
3.4 KiB
Rust

use crate::indicators::git::{repo_name, MAIN_COL};
use ansi_term::ANSIGenericString;
use ansi_term::Colour::RGB;
use std::env::current_dir;
pub const UNKNOWN_PATH: &str = "\u{2248}"; // "≈"
pub const PATH_COL: ansi_term::Colour = RGB(82, 82, 82);
pub const REPO_COL: ansi_term::Colour = RGB(55, 120, 130);
/// Find the current user's home directory.
fn home_dir() -> String {
std::env::var("HOME").map_or_else(|_| String::new(), |path| path.to_string())
}
/// Returns the full path of the current directory as a string.
fn full_path() -> String {
current_dir().map_or_else(
|_| UNKNOWN_PATH.to_string(),
|path| path.display().to_string(),
)
}
/// Remove the path of the repo's root from the path, to replace it with the repo's name.
fn remove_repo(pwd_path: &str, repo_path: &str) -> String {
pwd_path.replacen(repo_path, "", 1)
}
/// Replace the 'home directory' part of the path with a the '~' symbol
fn replace_home(path: &str) -> String {
path.replacen(&home_dir(), "~", 1)
}
fn short(path: &str, slash_limit: u8) -> String {
let slashes = path.matches('/').count(); // Get the number of slashes
if slashes <= slash_limit.into() {
return path.to_string(); // Short path, return without changes
}
// Else: Long path, shorten it
let parts: Vec<&str> = path.split('/').collect(); // Split the path into parts
let first = if path.starts_with('~') { "~" } else { "" }; // Determine the first part correctly
let last = parts[parts.len() - 1]; // The last part
// Abbreviate middle parts (take the first character of each)
let abbreviated_middle = parts[1..parts.len() - 1] // Skip the first and last part
.iter()
.filter(|&&part| !part.is_empty()) // Avoid empty parts (like "//")
.map(|&part| part.chars().next().unwrap().to_string()) // Take the first letter
.collect::<Vec<_>>() // Collect the parts as a Vec
.join("/"); // Join them with a "/" separator
format!("{first}/{abbreviated_middle}/{last}") // Final
}
pub fn pwd(
abbrev_home: bool,
shorten_path: bool,
replace_repo: bool,
git_repo: Option<String>,
) -> ANSIGenericString<'static, str> {
let mut slash_limit: u8 = 3; // Max number of slashes
let mut path = full_path(); // Get the full path of he current directory
// Replace a git repo root path with the repo's name
if replace_repo && git_repo.is_some() {
if let Some(repo_path) = git_repo {
path = remove_repo(&path, &repo_path);
let repo_name = repo_name(&repo_path);
if shorten_path {
slash_limit = 2; // Max number of slashes
path = short(&path, slash_limit);
}
return if path.is_empty() {
REPO_COL.paint(repo_name) // In the root dir of the repo
} else {
// In a subdir inside the repo
format!(
"{}{}{}",
REPO_COL.paint(repo_name), // Repo name
MAIN_COL.paint(" \u{F02A2} "), // Seperator
PATH_COL.italic().paint(path) // Sub-directory
)
.into()
};
}
}
// Replace the home directory path with the 'home symbol': ~
if abbrev_home {
path = replace_home(&path);
}
if shorten_path {
path = short(&path, slash_limit);
}
PATH_COL.italic().paint(path)
}