feat: added truncation_length/symbol to git_branch (#268)
Git branches can become very long (e.g. gitlab auto-generated branch names), thus it would be nice to be able to truncate them to keep your prompt lenght in line. This patch adds two new options to the git_branch module: * truncation_length: The amount of graphemes to of a gitbranch to truncate to * truncation_symbol: The symbol that should be used to indicate that a branch name was trunctated To be able to correctly work with UTF-8 graphemes, unicode-segmentation was added as a dependency.
This commit is contained in:
parent
f8929c2d7d
commit
59e8b1fc92
|
@ -754,6 +754,7 @@ dependencies = [
|
||||||
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -874,6 +875,11 @@ dependencies = [
|
||||||
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-segmentation"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "unicode-width"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
|
@ -1065,6 +1071,7 @@ dependencies = [
|
||||||
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
|
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
|
||||||
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
||||||
"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426"
|
"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426"
|
||||||
|
"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9"
|
||||||
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
||||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||||
"checksum uom 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "347fe3ff20637a62ab9749a5c90d167302bcbdab77ec961dda7f62a5ca6d368a"
|
"checksum uom 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "347fe3ff20637a62ab9749a5c90d167302bcbdab77ec961dda7f62a5ca6d368a"
|
||||||
|
|
|
@ -39,6 +39,7 @@ log = "0.4.8"
|
||||||
battery = { version = "0.7.4", optional = true }
|
battery = { version = "0.7.4", optional = true }
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
path-slash = "0.1.1"
|
path-slash = "0.1.1"
|
||||||
|
unicode-segmentation = "1.3.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
|
|
|
@ -212,9 +212,11 @@ The `git_branch` module shows the active branch of the repo in your current dire
|
||||||
### Options
|
### Options
|
||||||
|
|
||||||
| Variable | Default | Description |
|
| Variable | Default | Description |
|
||||||
| ---------- | ------- | ----------------------------------------------------------------------------- |
|
| ------------------- | ---------- | ------------------------------------------------------------------------------------- |
|
||||||
| `symbol` | `" "` | The symbol used before the branch name of the repo in your current directory. |
|
| `symbol` | `" "` | The symbol used before the branch name of the repo in your current directory. |
|
||||||
| `disabled` | `false` | Disables the `git_branch` module. |
|
| `disabled` | `false` | Disables the `git_branch` module. |
|
||||||
|
| `truncation_length` | `2^63 - 1` | Truncates a git branch to X graphemes |
|
||||||
|
| `truncation_symbol` | `"…"` | The symbol used to indicate a branch name was truncated. You can use "" for no symbol |
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
|
@ -223,6 +225,8 @@ The `git_branch` module shows the active branch of the repo in your current dire
|
||||||
|
|
||||||
[git_branch]
|
[git_branch]
|
||||||
symbol = "🌱 "
|
symbol = "🌱 "
|
||||||
|
truncation_length = "4"
|
||||||
|
truncation_symbol = ""
|
||||||
```
|
```
|
||||||
|
|
||||||
## Git Status
|
## Git Status
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use ansi_term::Color;
|
use ansi_term::Color;
|
||||||
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
|
|
||||||
use super::{Context, Module};
|
use super::{Context, Module};
|
||||||
|
|
||||||
|
@ -8,15 +9,54 @@ use super::{Context, Module};
|
||||||
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
const GIT_BRANCH_CHAR: &str = " ";
|
const GIT_BRANCH_CHAR: &str = " ";
|
||||||
|
|
||||||
let branch_name = context.branch_name.as_ref()?;
|
|
||||||
let segment_color = Color::Purple.bold();
|
let segment_color = Color::Purple.bold();
|
||||||
|
|
||||||
let mut module = context.new_module("git_branch")?;
|
let mut module = context.new_module("git_branch")?;
|
||||||
module.set_style(segment_color);
|
module.set_style(segment_color);
|
||||||
module.get_prefix().set_value("on ");
|
module.get_prefix().set_value("on ");
|
||||||
|
|
||||||
|
let unsafe_truncation_length = module
|
||||||
|
.config_value_i64("truncation_length")
|
||||||
|
.unwrap_or(std::i64::MAX);
|
||||||
|
let truncation_symbol = get_graphemes(
|
||||||
|
module.config_value_str("truncation_symbol").unwrap_or("…"),
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
|
||||||
module.new_segment("symbol", GIT_BRANCH_CHAR);
|
module.new_segment("symbol", GIT_BRANCH_CHAR);
|
||||||
module.new_segment("name", branch_name);
|
|
||||||
|
// TODO: Once error handling is implemented, warn the user if their config
|
||||||
|
// truncation length is nonsensical
|
||||||
|
let len = if unsafe_truncation_length <= 0 {
|
||||||
|
log::debug!(
|
||||||
|
"[WARN]: \"truncation_length\" should be a positive value, found {}",
|
||||||
|
unsafe_truncation_length
|
||||||
|
);
|
||||||
|
std::usize::MAX
|
||||||
|
} else {
|
||||||
|
unsafe_truncation_length as usize
|
||||||
|
};
|
||||||
|
let branch_name = context.branch_name.as_ref()?;
|
||||||
|
let truncated_graphemes = get_graphemes(&branch_name, len);
|
||||||
|
// The truncation symbol should only be added if we truncated
|
||||||
|
let truncated_and_symbol = if len < graphemes_len(&branch_name) {
|
||||||
|
truncated_graphemes + &truncation_symbol
|
||||||
|
} else {
|
||||||
|
truncated_graphemes
|
||||||
|
};
|
||||||
|
|
||||||
|
module.new_segment("name", &truncated_and_symbol);
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_graphemes(text: &str, length: usize) -> String {
|
||||||
|
UnicodeSegmentation::graphemes(text, true)
|
||||||
|
.take(length)
|
||||||
|
.collect::<Vec<&str>>()
|
||||||
|
.concat()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn graphemes_len(text: &str) -> usize {
|
||||||
|
UnicodeSegmentation::graphemes(&text[..], true).count()
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,168 @@
|
||||||
|
use ansi_term::Color;
|
||||||
|
use git2::Repository;
|
||||||
|
use std::env;
|
||||||
|
use std::io;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
use crate::common::{self, TestCommand};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_changed_truncation_symbol() -> io::Result<()> {
|
||||||
|
test_truncate_length_with_config(
|
||||||
|
"1337_hello_world",
|
||||||
|
15,
|
||||||
|
"1337_hello_worl",
|
||||||
|
"%",
|
||||||
|
"truncation_symbol = \"%\"",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_no_truncation_symbol() -> io::Result<()> {
|
||||||
|
test_truncate_length_with_config(
|
||||||
|
"1337_hello_world",
|
||||||
|
15,
|
||||||
|
"1337_hello_worl",
|
||||||
|
"",
|
||||||
|
"truncation_symbol = \"\"",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_multi_char_truncation_symbol() -> io::Result<()> {
|
||||||
|
test_truncate_length_with_config(
|
||||||
|
"1337_hello_world",
|
||||||
|
15,
|
||||||
|
"1337_hello_worl",
|
||||||
|
"a",
|
||||||
|
"truncation_symbol = \"apple\"",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ascii_boundary_below() -> io::Result<()> {
|
||||||
|
test_truncate_length("1337_hello_world", 15, "1337_hello_worl", "…")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ascii_boundary_on() -> io::Result<()> {
|
||||||
|
test_truncate_length("1337_hello_world", 16, "1337_hello_world", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ascii_boundary_above() -> io::Result<()> {
|
||||||
|
test_truncate_length("1337_hello_world", 17, "1337_hello_world", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_one() -> io::Result<()> {
|
||||||
|
test_truncate_length("1337_hello_world", 1, "1", "…")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_zero() -> io::Result<()> {
|
||||||
|
test_truncate_length("1337_hello_world", 0, "1337_hello_world", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_negative() -> io::Result<()> {
|
||||||
|
test_truncate_length("1337_hello_world", -1, "1337_hello_world", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hindi_truncation() -> io::Result<()> {
|
||||||
|
test_truncate_length("नमस्ते", 3, "नमस्", "…")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hindi_truncation2() -> io::Result<()> {
|
||||||
|
test_truncate_length("नमस्त", 3, "नमस्", "…")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_japanese_truncation() -> io::Result<()> {
|
||||||
|
test_truncate_length("がんばってね", 4, "がんばっ", "…")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_truncate_length(
|
||||||
|
branch_name: &str,
|
||||||
|
truncate_length: i64,
|
||||||
|
expected_name: &str,
|
||||||
|
truncation_symbol: &str,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
return test_truncate_length_with_config(
|
||||||
|
branch_name,
|
||||||
|
truncate_length,
|
||||||
|
expected_name,
|
||||||
|
truncation_symbol,
|
||||||
|
"",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_truncate_length_with_config(
|
||||||
|
branch_name: &str,
|
||||||
|
truncate_length: i64,
|
||||||
|
expected_name: &str,
|
||||||
|
truncation_symbol: &str,
|
||||||
|
config_options: &str,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
let fixture_repo_dir = create_fixture_repo()?;
|
||||||
|
let repo_dir = common::new_tempdir()?.path().join("rocket");
|
||||||
|
|
||||||
|
Repository::clone(fixture_repo_dir.to_str().unwrap(), &repo_dir.as_path()).unwrap();
|
||||||
|
Command::new("git")
|
||||||
|
.args(&["checkout", "-b", branch_name])
|
||||||
|
.current_dir(repo_dir.as_path())
|
||||||
|
.output()?;
|
||||||
|
|
||||||
|
let output = common::render_module("git_branch")
|
||||||
|
.use_config(
|
||||||
|
toml::from_str(&format!(
|
||||||
|
"
|
||||||
|
[git_branch]
|
||||||
|
truncation_length = {}
|
||||||
|
{}
|
||||||
|
",
|
||||||
|
truncate_length, config_options
|
||||||
|
))
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.arg("--path")
|
||||||
|
.arg(repo_dir)
|
||||||
|
.output()?;
|
||||||
|
let actual = String::from_utf8(output.stdout).unwrap();
|
||||||
|
|
||||||
|
let expected = format!(
|
||||||
|
"on {} ",
|
||||||
|
Color::Purple
|
||||||
|
.bold()
|
||||||
|
.paint(format!("\u{e0a0} {}{}", expected_name, truncation_symbol)),
|
||||||
|
);
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_fixture_repo() -> io::Result<std::path::PathBuf> {
|
||||||
|
let fixture_repo_dir = common::new_tempdir()?.path().join("fixture");
|
||||||
|
let fixture = env::current_dir()?.join("tests/fixtures/rocket.bundle");
|
||||||
|
|
||||||
|
Command::new("git")
|
||||||
|
.args(&["config", "--global", "user.email", "starship@example.com"])
|
||||||
|
.output()?;
|
||||||
|
|
||||||
|
Command::new("git")
|
||||||
|
.args(&["config", "--global", "user.name", "starship"])
|
||||||
|
.output()?;
|
||||||
|
|
||||||
|
Command::new("git")
|
||||||
|
.args(&[
|
||||||
|
"clone",
|
||||||
|
"-b",
|
||||||
|
"master",
|
||||||
|
&fixture.to_str().unwrap(),
|
||||||
|
fixture_repo_dir.to_str().unwrap(),
|
||||||
|
])
|
||||||
|
.output()?;
|
||||||
|
|
||||||
|
Ok(fixture_repo_dir)
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ mod cmd_duration;
|
||||||
mod common;
|
mod common;
|
||||||
mod configuration;
|
mod configuration;
|
||||||
mod directory;
|
mod directory;
|
||||||
|
mod git_branch;
|
||||||
mod git_status;
|
mod git_status;
|
||||||
mod golang;
|
mod golang;
|
||||||
mod jobs;
|
mod jobs;
|
||||||
|
|
Loading…
Reference in New Issue