mirror of
https://github.com/Llewellynvdm/starship.git
synced 2024-11-28 07:46:28 +00:00
feat(hg_branch): Add support for mercurial topics and find hg root dir (#4771)
* feat(hg_branch): Add support for mercurial topics and find hg root dir * Fix clippy errors * Use crate::utils::read_file * Update config-schema.json * Extend PathExt to retrieve device ID of Path * Break hg root search when switching to another device * Fix clippy and formatting errors * Update docs/config/README.md Co-authored-by: David Knaack <davidkna@users.noreply.github.com> * Update src/modules/utils/path.rs Co-authored-by: David Knaack <davidkna@users.noreply.github.com> * Update src/configs/hg_branch.rs Co-authored-by: David Knaack <davidkna@users.noreply.github.com> * Update hg_branch description * Revert to lazy loading, use truncate_text from utils and use fake topic * Format code and fix clippy error * Revert to previous test string as topic is optional in the config * Fix doc formatting * Stub device_id for windows * Update config-schema.json * Update src/modules/hg_branch.rs Co-authored-by: David Knaack <davidkna@users.noreply.github.com> * Do not use unwrap in device_id * Fix formatter error * Use dev under non linux unixes Co-authored-by: David Knaack <davidkna@users.noreply.github.com>
This commit is contained in:
parent
8a8e09dd50
commit
8d2256ab1d
4
.github/config-schema.json
vendored
4
.github/config-schema.json
vendored
@ -750,7 +750,7 @@
|
|||||||
"hg_branch": {
|
"hg_branch": {
|
||||||
"default": {
|
"default": {
|
||||||
"disabled": true,
|
"disabled": true,
|
||||||
"format": "on [$symbol$branch]($style) ",
|
"format": "on [$symbol$branch(:$topic)]($style) ",
|
||||||
"style": "bold purple",
|
"style": "bold purple",
|
||||||
"symbol": " ",
|
"symbol": " ",
|
||||||
"truncation_length": 9223372036854775807,
|
"truncation_length": 9223372036854775807,
|
||||||
@ -3537,7 +3537,7 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"format": {
|
"format": {
|
||||||
"default": "on [$symbol$branch]($style) ",
|
"default": "on [$symbol$branch(:$topic)]($style) ",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"truncation_length": {
|
"truncation_length": {
|
||||||
|
@ -2643,26 +2643,27 @@ style = 'bold dimmed green'
|
|||||||
|
|
||||||
## Mercurial Branch
|
## Mercurial Branch
|
||||||
|
|
||||||
The `hg_branch` module shows the active branch of the repo in your current directory.
|
The `hg_branch` module shows the active branch and topic of the repo in your current directory.
|
||||||
|
|
||||||
### Options
|
### Options
|
||||||
|
|
||||||
| Option | Default | Description |
|
| Option | Default | Description |
|
||||||
| ------------------- | -------------------------------- | -------------------------------------------------------------------------------------------- |
|
| ------------------- | ----------------------------------------- | -------------------------------------------------------------------------------------------- |
|
||||||
| `symbol` | `' '` | The symbol used before the hg bookmark or branch name of the repo in your current directory. |
|
| `symbol` | `' '` | The symbol used before the hg bookmark or branch name of the repo in your current directory. |
|
||||||
| `style` | `'bold purple'` | The style for the module. |
|
| `style` | `'bold purple'` | The style for the module. |
|
||||||
| `format` | `'on [$symbol$branch]($style) '` | The format for the module. |
|
| `format` | `'on [$symbol$branch(:$topic)]($style) '` | The format for the module. |
|
||||||
| `truncation_length` | `2^63 - 1` | Truncates the hg branch name to `N` graphemes |
|
| `truncation_length` | `2^63 - 1` | Truncates the hg branch / topic name to `N` graphemes |
|
||||||
| `truncation_symbol` | `'…'` | The symbol used to indicate a branch name was truncated. |
|
| `truncation_symbol` | `'…'` | The symbol used to indicate a branch name was truncated. |
|
||||||
| `disabled` | `true` | Disables the `hg_branch` module. |
|
| `disabled` | `true` | Disables the `hg_branch` module. |
|
||||||
|
|
||||||
### Variables
|
### Variables
|
||||||
|
|
||||||
| Variable | Example | Description |
|
| Variable | Example | Description |
|
||||||
| -------- | -------- | ------------------------------------ |
|
| -------- | --------- | ------------------------------------ |
|
||||||
| branch | `master` | The active mercurial branch |
|
| branch | `master` | The active mercurial branch |
|
||||||
| symbol | | Mirrors the value of option `symbol` |
|
| topic | `feature` | The active mercurial topic |
|
||||||
| style\* | | Mirrors the value of option `style` |
|
| symbol | | Mirrors the value of option `symbol` |
|
||||||
|
| style\* | | Mirrors the value of option `style` |
|
||||||
|
|
||||||
*: This variable can only be used as a part of a style string
|
*: This variable can only be used as a part of a style string
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ impl<'a> Default for HgBranchConfig<'a> {
|
|||||||
HgBranchConfig {
|
HgBranchConfig {
|
||||||
symbol: " ",
|
symbol: " ",
|
||||||
style: "bold purple",
|
style: "bold purple",
|
||||||
format: "on [$symbol$branch]($style) ",
|
format: "on [$symbol$branch(:$topic)]($style) ",
|
||||||
truncation_length: std::i64::MAX,
|
truncation_length: std::i64::MAX,
|
||||||
truncation_symbol: "…",
|
truncation_symbol: "…",
|
||||||
disabled: true,
|
disabled: true,
|
||||||
|
@ -1,20 +1,18 @@
|
|||||||
use unicode_segmentation::UnicodeSegmentation;
|
use std::io::{Error, ErrorKind};
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use super::utils::truncate::truncate_text;
|
||||||
use super::{Context, Module, ModuleConfig};
|
use super::{Context, Module, ModuleConfig};
|
||||||
|
|
||||||
use crate::configs::hg_branch::HgBranchConfig;
|
use crate::configs::hg_branch::HgBranchConfig;
|
||||||
use crate::formatter::StringFormatter;
|
use crate::formatter::StringFormatter;
|
||||||
|
use crate::modules::utils::path::PathExt;
|
||||||
|
use crate::utils::read_file;
|
||||||
|
|
||||||
/// Creates a module with the Hg bookmark or branch in the current directory
|
/// Creates a module with the Hg bookmark or branch in the current directory
|
||||||
///
|
///
|
||||||
/// Will display the bookmark or branch name if the current directory is an hg repo
|
/// Will display the bookmark or branch name if the current directory is an hg repo
|
||||||
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
let is_hg_repo = context.try_begin_scan()?.set_folders(&[".hg"]).is_match();
|
|
||||||
|
|
||||||
if !is_hg_repo {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut module = context.new_module("hg_branch");
|
let mut module = context.new_module("hg_branch");
|
||||||
let config: HgBranchConfig = HgBranchConfig::try_load(module.config);
|
let config: HgBranchConfig = HgBranchConfig::try_load(module.config);
|
||||||
|
|
||||||
@ -34,16 +32,16 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
config.truncation_length as usize
|
config.truncation_length as usize
|
||||||
};
|
};
|
||||||
|
|
||||||
let branch_name =
|
let repo_root = get_hg_repo_root(context).ok()?;
|
||||||
get_hg_current_bookmark(context).unwrap_or_else(|| get_hg_branch_name(context));
|
let branch_name = get_hg_current_bookmark(repo_root).unwrap_or_else(|_| {
|
||||||
|
get_hg_branch_name(repo_root).unwrap_or_else(|_| String::from("default"))
|
||||||
|
});
|
||||||
|
|
||||||
let truncated_graphemes = get_graphemes(&branch_name, len);
|
let branch_graphemes = truncate_text(&branch_name, len, config.truncation_symbol);
|
||||||
// The truncation symbol should only be added if we truncated
|
let topic_graphemes = if let Ok(topic) = get_hg_topic_name(repo_root) {
|
||||||
let truncated_and_symbol = if len < graphemes_len(&branch_name) {
|
truncate_text(&topic, len, config.truncation_symbol)
|
||||||
let truncation_symbol = get_graphemes(config.truncation_symbol, 1);
|
|
||||||
truncated_graphemes + truncation_symbol.as_str()
|
|
||||||
} else {
|
} else {
|
||||||
truncated_graphemes
|
String::from("")
|
||||||
};
|
};
|
||||||
|
|
||||||
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
@ -57,7 +55,8 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.map(|variable| match variable {
|
.map(|variable| match variable {
|
||||||
"branch" => Some(Ok(truncated_and_symbol.as_str())),
|
"branch" => Some(Ok(branch_graphemes.as_str())),
|
||||||
|
"topic" => Some(Ok(topic_graphemes.as_str())),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None, Some(context))
|
.parse(None, Some(context))
|
||||||
@ -74,26 +73,33 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_hg_branch_name(ctx: &Context) -> String {
|
fn get_hg_repo_root<'a>(ctx: &'a Context) -> Result<&'a Path, Error> {
|
||||||
std::fs::read_to_string(ctx.current_dir.join(".hg").join("branch"))
|
let dir = ctx.current_dir.as_path();
|
||||||
.map_or_else(|_| "default".to_string(), |s| s.trim().into())
|
let dev_id = dir.device_id();
|
||||||
|
for root_dir in dir.ancestors() {
|
||||||
|
if dev_id != root_dir.device_id() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if root_dir.join(".hg").is_dir() {
|
||||||
|
return Ok(root_dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(Error::new(ErrorKind::Other, "No .hg found!"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_hg_current_bookmark(ctx: &Context) -> Option<String> {
|
fn get_hg_branch_name(hg_root: &Path) -> Result<String, Error> {
|
||||||
std::fs::read_to_string(ctx.current_dir.join(".hg").join("bookmarks.current"))
|
match read_file(hg_root.join(".hg").join("branch")) {
|
||||||
.map(|s| s.trim().into())
|
Ok(b) => Ok(b.trim().to_string()),
|
||||||
.ok()
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_graphemes(text: &str, length: usize) -> String {
|
fn get_hg_current_bookmark(hg_root: &Path) -> Result<String, Error> {
|
||||||
UnicodeSegmentation::graphemes(text, true)
|
read_file(hg_root.join(".hg").join("bookmarks.current"))
|
||||||
.take(length)
|
|
||||||
.collect::<Vec<&str>>()
|
|
||||||
.concat()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn graphemes_len(text: &str) -> usize {
|
fn get_hg_topic_name(hg_root: &Path) -> Result<String, Error> {
|
||||||
UnicodeSegmentation::graphemes(text, true).count()
|
read_file(hg_root.join(".hg").join("topic"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -186,6 +192,26 @@ mod tests {
|
|||||||
tempdir.close()
|
tempdir.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn test_hg_topic() -> io::Result<()> {
|
||||||
|
let tempdir = fixture_repo(FixtureProvider::Hg)?;
|
||||||
|
let repo_dir = tempdir.path();
|
||||||
|
fs::write(repo_dir.join(".hg").join("topic"), "feature")?;
|
||||||
|
|
||||||
|
let actual = ModuleRenderer::new("hg_branch")
|
||||||
|
.path(repo_dir.to_str().unwrap())
|
||||||
|
.config(toml::toml! {
|
||||||
|
[hg_branch]
|
||||||
|
format = "$topic"
|
||||||
|
disabled = false
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
assert_eq!(Some(String::from("feature")), actual);
|
||||||
|
tempdir.close()
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn test_default_truncation_symbol() -> io::Result<()> {
|
fn test_default_truncation_symbol() -> io::Result<()> {
|
||||||
|
@ -249,7 +249,7 @@ pub fn description(module: &str) -> &'static str {
|
|||||||
"haskell" => "The selected version of the Haskell toolchain",
|
"haskell" => "The selected version of the Haskell toolchain",
|
||||||
"haxe" => "The currently installed version of Haxe",
|
"haxe" => "The currently installed version of Haxe",
|
||||||
"helm" => "The currently installed version of Helm",
|
"helm" => "The currently installed version of Helm",
|
||||||
"hg_branch" => "The active branch of the repo in your current directory",
|
"hg_branch" => "The active branch and topic of the repo in your current directory",
|
||||||
"hostname" => "The system hostname",
|
"hostname" => "The system hostname",
|
||||||
"java" => "The currently installed version of Java",
|
"java" => "The currently installed version of Java",
|
||||||
"jobs" => "The current number of jobs running",
|
"jobs" => "The current number of jobs running",
|
||||||
|
@ -13,6 +13,8 @@ pub trait PathExt {
|
|||||||
/// E.g. `\\?\UNC\server\share\foo` => `\foo`
|
/// E.g. `\\?\UNC\server\share\foo` => `\foo`
|
||||||
/// E.g. `/foo/bar` => `/foo/bar`
|
/// E.g. `/foo/bar` => `/foo/bar`
|
||||||
fn without_prefix(&self) -> &Path;
|
fn without_prefix(&self) -> &Path;
|
||||||
|
/// Get device / volume info
|
||||||
|
fn device_id(&self) -> Option<u64>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -80,6 +82,11 @@ impl PathExt for Path {
|
|||||||
let (_, path) = normalize::normalize_path(self);
|
let (_, path) = normalize::normalize_path(self);
|
||||||
path
|
path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn device_id(&self) -> Option<u64> {
|
||||||
|
// Maybe it should use unimplemented!
|
||||||
|
Some(42u64)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Windows path prefixes are only parsed on Windows.
|
// NOTE: Windows path prefixes are only parsed on Windows.
|
||||||
@ -100,6 +107,24 @@ impl PathExt for Path {
|
|||||||
fn without_prefix(&self) -> &Path {
|
fn without_prefix(&self) -> &Path {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
fn device_id(&self) -> Option<u64> {
|
||||||
|
use std::os::linux::fs::MetadataExt;
|
||||||
|
match self.metadata() {
|
||||||
|
Ok(m) => Some(m.st_dev()),
|
||||||
|
Err(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(unix, not(target_os = "linux")))]
|
||||||
|
fn device_id(&self) -> Option<u64> {
|
||||||
|
use std::os::unix::fs::MetadataExt;
|
||||||
|
match self.metadata() {
|
||||||
|
Ok(m) => Some(m.dev()),
|
||||||
|
Err(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
Loading…
Reference in New Issue
Block a user