feat(fossil_branch): add fossil_branch module (#4806)
Co-authored-by: David Knaack <davidkna@users.noreply.github.com>
This commit is contained in:
parent
3d76a987d6
commit
41eb98b310
|
@ -504,6 +504,21 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"fossil_branch": {
|
||||
"default": {
|
||||
"disabled": true,
|
||||
"format": "on [$symbol$branch]($style) ",
|
||||
"style": "bold purple",
|
||||
"symbol": " ",
|
||||
"truncation_length": 9223372036854775807,
|
||||
"truncation_symbol": "…"
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/FossilBranchConfig"
|
||||
}
|
||||
]
|
||||
},
|
||||
"gcloud": {
|
||||
"default": {
|
||||
"disabled": false,
|
||||
|
@ -2981,6 +2996,37 @@
|
|||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"FossilBranchConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"format": {
|
||||
"default": "on [$symbol$branch]($style) ",
|
||||
"type": "string"
|
||||
},
|
||||
"symbol": {
|
||||
"default": " ",
|
||||
"type": "string"
|
||||
},
|
||||
"style": {
|
||||
"default": "bold purple",
|
||||
"type": "string"
|
||||
},
|
||||
"truncation_length": {
|
||||
"default": 9223372036854775807,
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"truncation_symbol": {
|
||||
"default": "…",
|
||||
"type": "string"
|
||||
},
|
||||
"disabled": {
|
||||
"default": true,
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"GcloudConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
@ -49,6 +49,9 @@ format = '\[[$symbol($version)]($style)\]'
|
|||
[fennel]
|
||||
format = '\[[$symbol($version)]($style)\]'
|
||||
|
||||
[fossil_branch]
|
||||
format = '\[[$symbol$branch]($style)\]'
|
||||
|
||||
[gcloud]
|
||||
format = '\[[$symbol$account(@$domain)(\($region\))]($style)\]'
|
||||
|
||||
|
|
|
@ -25,6 +25,9 @@ symbol = " "
|
|||
[elm]
|
||||
symbol = " "
|
||||
|
||||
[fossil_branch]
|
||||
symbol = " "
|
||||
|
||||
[git_branch]
|
||||
symbol = " "
|
||||
|
||||
|
|
|
@ -61,6 +61,9 @@ symbol = "elm "
|
|||
[fennel]
|
||||
symbol = "fnl "
|
||||
|
||||
[fossil_branch]
|
||||
symbol = "fossil "
|
||||
|
||||
[git_branch]
|
||||
symbol = "git "
|
||||
|
||||
|
|
|
@ -265,6 +265,7 @@ $singularity\
|
|||
$kubernetes\
|
||||
$directory\
|
||||
$vcsh\
|
||||
$fossil_branch\
|
||||
$git_branch\
|
||||
$git_commit\
|
||||
$git_state\
|
||||
|
@ -1556,6 +1557,42 @@ Produces a prompt that looks like:
|
|||
AA -------------------------------------------- BB -------------------------------------------- CC
|
||||
```
|
||||
|
||||
## Fossil Branch
|
||||
|
||||
The `fossil_branch` module shows the name of the active branch of the check-out in your current directory.
|
||||
|
||||
### Options
|
||||
|
||||
| Option | Default | Description |
|
||||
| ------------------- | -------------------------------- | ---------------------------------------------------------------------------------------- |
|
||||
| `format` | `'on [$symbol$branch]($style) '` | The format for the module. Use `'$branch'` to refer to the current branch name. |
|
||||
| `symbol` | `' '` | The symbol used before the branch name of the check-out in your current directory. |
|
||||
| `style` | `'bold purple'` | The style for the module. |
|
||||
| `truncation_length` | `2^63 - 1` | Truncates a Fossil branch name to `N` graphemes |
|
||||
| `truncation_symbol` | `'…'` | The symbol used to indicate a branch name was truncated. You can use `''` for no symbol. |
|
||||
| `disabled` | `true` | Disables the `fossil_branch` module. |
|
||||
|
||||
### Variables
|
||||
|
||||
| Variable | Example | Description |
|
||||
| -------- | ------- | ------------------------------------ |
|
||||
| branch | `trunk` | The active Fossil branch |
|
||||
| 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
|
||||
|
||||
### Example
|
||||
|
||||
```toml
|
||||
# ~/.config/starship.toml
|
||||
|
||||
[fossil_branch]
|
||||
symbol = '🦎 '
|
||||
truncation_length = 4
|
||||
truncation_symbol = ''
|
||||
```
|
||||
|
||||
## Google Cloud (`gcloud`)
|
||||
|
||||
The `gcloud` module shows the current configuration for [`gcloud`](https://cloud.google.com/sdk/gcloud) CLI.
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
#[cfg_attr(
|
||||
feature = "config-schema",
|
||||
derive(schemars::JsonSchema),
|
||||
schemars(deny_unknown_fields)
|
||||
)]
|
||||
#[serde(default)]
|
||||
pub struct FossilBranchConfig<'a> {
|
||||
pub format: &'a str,
|
||||
pub symbol: &'a str,
|
||||
pub style: &'a str,
|
||||
pub truncation_length: i64,
|
||||
pub truncation_symbol: &'a str,
|
||||
pub disabled: bool,
|
||||
}
|
||||
|
||||
impl<'a> Default for FossilBranchConfig<'a> {
|
||||
fn default() -> Self {
|
||||
FossilBranchConfig {
|
||||
format: "on [$symbol$branch]($style) ",
|
||||
symbol: " ",
|
||||
style: "bold purple",
|
||||
truncation_length: std::i64::MAX,
|
||||
truncation_symbol: "…",
|
||||
disabled: true,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ pub mod env_var;
|
|||
pub mod erlang;
|
||||
pub mod fennel;
|
||||
pub mod fill;
|
||||
pub mod fossil_branch;
|
||||
pub mod gcloud;
|
||||
pub mod git_branch;
|
||||
pub mod git_commit;
|
||||
|
@ -155,6 +156,8 @@ pub struct FullConfig<'a> {
|
|||
#[serde(borrow)]
|
||||
fill: fill::FillConfig<'a>,
|
||||
#[serde(borrow)]
|
||||
fossil_branch: fossil_branch::FossilBranchConfig<'a>,
|
||||
#[serde(borrow)]
|
||||
gcloud: gcloud::GcloudConfig<'a>,
|
||||
#[serde(borrow)]
|
||||
git_branch: git_branch::GitBranchConfig<'a>,
|
||||
|
|
|
@ -38,6 +38,7 @@ pub const PROMPT_ORDER: &[&str] = &[
|
|||
"kubernetes",
|
||||
"directory",
|
||||
"vcsh",
|
||||
"fossil_branch",
|
||||
"git_branch",
|
||||
"git_commit",
|
||||
"git_state",
|
||||
|
|
|
@ -34,6 +34,7 @@ pub const ALL_MODULES: &[&str] = &[
|
|||
"erlang",
|
||||
"fennel",
|
||||
"fill",
|
||||
"fossil_branch",
|
||||
"gcloud",
|
||||
"git_branch",
|
||||
"git_commit",
|
||||
|
|
|
@ -0,0 +1,215 @@
|
|||
use super::{Context, Module, ModuleConfig};
|
||||
|
||||
use crate::configs::fossil_branch::FossilBranchConfig;
|
||||
use crate::formatter::StringFormatter;
|
||||
use crate::modules::utils::truncate::truncate_text;
|
||||
|
||||
/// Creates a module with the Fossil branch of the check-out in the current directory
|
||||
///
|
||||
/// Will display the branch name if the current directory is a Fossil check-out
|
||||
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
let mut module = context.new_module("fossil_branch");
|
||||
let config = FossilBranchConfig::try_load(module.config);
|
||||
|
||||
// As we default to disabled=true, we have to check here after loading our config module,
|
||||
// before it was only checking against whatever is in the config starship.toml
|
||||
if config.disabled {
|
||||
return None;
|
||||
};
|
||||
|
||||
let is_checkout = context
|
||||
.try_begin_scan()?
|
||||
.set_files(&[".fslckout"])
|
||||
.is_match();
|
||||
|
||||
if !is_checkout {
|
||||
return None;
|
||||
}
|
||||
|
||||
let len = if config.truncation_length <= 0 {
|
||||
log::warn!(
|
||||
"\"truncation_length\" should be a positive value, found {}",
|
||||
config.truncation_length
|
||||
);
|
||||
std::usize::MAX
|
||||
} else {
|
||||
config.truncation_length as usize
|
||||
};
|
||||
|
||||
let truncated_branch_name = {
|
||||
let output = context.exec_cmd("fossil", &["branch", "current"])?.stdout;
|
||||
truncate_text(output.trim(), len, config.truncation_symbol)
|
||||
};
|
||||
|
||||
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||
formatter
|
||||
.map_meta(|variable, _| match variable {
|
||||
"symbol" => Some(config.symbol),
|
||||
_ => None,
|
||||
})
|
||||
.map_style(|variable| match variable {
|
||||
"style" => Some(Ok(config.style)),
|
||||
_ => None,
|
||||
})
|
||||
.map(|variable| match variable {
|
||||
"branch" => Some(Ok(truncated_branch_name.as_str())),
|
||||
_ => None,
|
||||
})
|
||||
.parse(None, Some(context))
|
||||
});
|
||||
|
||||
module.set_segments(match parsed {
|
||||
Ok(segments) => segments,
|
||||
Err(error) => {
|
||||
log::warn!("Error in module `fossil_branch`:\n{}", error);
|
||||
return None;
|
||||
}
|
||||
});
|
||||
|
||||
Some(module)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
|
||||
use nu_ansi_term::{Color, Style};
|
||||
|
||||
use crate::test::{fixture_repo, FixtureProvider, ModuleRenderer};
|
||||
|
||||
enum Expect<'a> {
|
||||
BranchName(&'a str),
|
||||
Empty,
|
||||
NoTruncation,
|
||||
Symbol(&'a str),
|
||||
Style(Style),
|
||||
TruncationSymbol(&'a str),
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn show_nothing_on_empty_dir() -> io::Result<()> {
|
||||
let checkout_dir = tempfile::tempdir()?;
|
||||
|
||||
let actual = ModuleRenderer::new("fossil_branch")
|
||||
.path(checkout_dir.path())
|
||||
.collect();
|
||||
let expected = None;
|
||||
assert_eq!(expected, actual);
|
||||
|
||||
checkout_dir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fossil_branch_disabled_per_default() -> io::Result<()> {
|
||||
let tempdir = fixture_repo(FixtureProvider::Fossil)?;
|
||||
let checkout_dir = tempdir.path();
|
||||
expect_fossil_branch_with_config(
|
||||
checkout_dir,
|
||||
Some(toml::toml! {
|
||||
// no "disabled=false" in config!
|
||||
[fossil_branch]
|
||||
truncation_length = 14
|
||||
}),
|
||||
&[Expect::Empty],
|
||||
);
|
||||
tempdir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fossil_branch_autodisabled() -> io::Result<()> {
|
||||
let tempdir = tempfile::tempdir()?;
|
||||
expect_fossil_branch_with_config(tempdir.path(), None, &[Expect::Empty]);
|
||||
tempdir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fossil_branch() -> io::Result<()> {
|
||||
let tempdir = fixture_repo(FixtureProvider::Fossil)?;
|
||||
let checkout_dir = tempdir.path();
|
||||
run_fossil(&["branch", "new", "topic-branch", "trunk"], checkout_dir)?;
|
||||
run_fossil(&["update", "topic-branch"], checkout_dir)?;
|
||||
expect_fossil_branch_with_config(
|
||||
checkout_dir,
|
||||
None,
|
||||
&[Expect::BranchName("topic-branch"), Expect::NoTruncation],
|
||||
);
|
||||
tempdir.close()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fossil_branch_configured() -> io::Result<()> {
|
||||
let tempdir = fixture_repo(FixtureProvider::Fossil)?;
|
||||
let checkout_dir = tempdir.path();
|
||||
run_fossil(&["branch", "new", "topic-branch", "trunk"], checkout_dir)?;
|
||||
run_fossil(&["update", "topic-branch"], checkout_dir)?;
|
||||
expect_fossil_branch_with_config(
|
||||
checkout_dir,
|
||||
Some(toml::toml! {
|
||||
[fossil_branch]
|
||||
style = "underline blue"
|
||||
symbol = "F "
|
||||
truncation_length = 10
|
||||
truncation_symbol = "%"
|
||||
disabled = false
|
||||
}),
|
||||
&[
|
||||
Expect::BranchName("topic-bran"),
|
||||
Expect::Style(Color::Blue.underline()),
|
||||
Expect::Symbol("F"),
|
||||
Expect::TruncationSymbol("%"),
|
||||
],
|
||||
);
|
||||
tempdir.close()
|
||||
}
|
||||
|
||||
fn expect_fossil_branch_with_config(
|
||||
checkout_dir: &Path,
|
||||
config: Option<toml::Table>,
|
||||
expectations: &[Expect],
|
||||
) {
|
||||
let actual = ModuleRenderer::new("fossil_branch")
|
||||
.path(checkout_dir.to_str().unwrap())
|
||||
.config(config.unwrap_or_else(|| {
|
||||
toml::toml! {
|
||||
[fossil_branch]
|
||||
disabled = false
|
||||
}
|
||||
}))
|
||||
.collect();
|
||||
|
||||
let mut expect_branch_name = "trunk";
|
||||
let mut expect_style = Color::Purple.bold();
|
||||
let mut expect_symbol = "\u{e0a0}";
|
||||
let mut expect_truncation_symbol = "…";
|
||||
|
||||
for expect in expectations {
|
||||
match expect {
|
||||
Expect::Empty => {
|
||||
assert_eq!(None, actual);
|
||||
return;
|
||||
}
|
||||
Expect::Symbol(symbol) => expect_symbol = symbol,
|
||||
Expect::TruncationSymbol(truncation_symbol) => {
|
||||
expect_truncation_symbol = truncation_symbol
|
||||
}
|
||||
Expect::NoTruncation => expect_truncation_symbol = "",
|
||||
Expect::BranchName(branch_name) => expect_branch_name = branch_name,
|
||||
Expect::Style(style) => expect_style = *style,
|
||||
}
|
||||
}
|
||||
|
||||
let expected = Some(format!(
|
||||
"on {} ",
|
||||
expect_style.paint(format!(
|
||||
"{expect_symbol} {expect_branch_name}{expect_truncation_symbol}"
|
||||
))
|
||||
));
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
fn run_fossil(args: &[&str], _checkout_dir: &Path) -> io::Result<()> {
|
||||
crate::utils::mock_cmd("fossil", args).ok_or(io::ErrorKind::Unsupported)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ mod env_var;
|
|||
mod erlang;
|
||||
mod fennel;
|
||||
mod fill;
|
||||
mod fossil_branch;
|
||||
mod gcloud;
|
||||
mod git_branch;
|
||||
mod git_commit;
|
||||
|
@ -126,6 +127,7 @@ pub fn handle<'a>(module: &str, context: &'a Context) -> Option<Module<'a>> {
|
|||
"env_var" => env_var::module(None, context),
|
||||
"fennel" => fennel::module(context),
|
||||
"fill" => fill::module(context),
|
||||
"fossil_branch" => fossil_branch::module(context),
|
||||
"gcloud" => gcloud::module(context),
|
||||
"git_branch" => git_branch::module(context),
|
||||
"git_commit" => git_commit::module(context),
|
||||
|
@ -239,6 +241,7 @@ pub fn description(module: &str) -> &'static str {
|
|||
"erlang" => "Current OTP version",
|
||||
"fennel" => "The currently installed version of Fennel",
|
||||
"fill" => "Fills the remaining space on the line with a pad string",
|
||||
"fossil_branch" => "The active branch of the check-out in your current directory",
|
||||
"gcloud" => "The current GCP client configuration",
|
||||
"git_branch" => "The active branch of the repo in your current directory",
|
||||
"git_commit" => "The active commit (and tag if any) of the repo in your current directory",
|
||||
|
|
|
@ -167,6 +167,7 @@ impl<'a> ModuleRenderer<'a> {
|
|||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum FixtureProvider {
|
||||
Fossil,
|
||||
Git,
|
||||
Hg,
|
||||
Pijul,
|
||||
|
@ -174,6 +175,15 @@ pub enum FixtureProvider {
|
|||
|
||||
pub fn fixture_repo(provider: FixtureProvider) -> io::Result<TempDir> {
|
||||
match provider {
|
||||
FixtureProvider::Fossil => {
|
||||
let path = tempfile::tempdir()?;
|
||||
fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.open(path.path().join(".fslckout"))?
|
||||
.sync_all()?;
|
||||
Ok(path)
|
||||
}
|
||||
FixtureProvider::Git => {
|
||||
let path = tempfile::tempdir()?;
|
||||
|
||||
|
|
12
src/utils.rs
12
src/utils.rs
|
@ -249,6 +249,18 @@ Elixir 1.10 (compiled with Erlang/OTP 22)\n",
|
|||
stdout: String::from("Fennel 1.2.1 on PUC Lua 5.4\n"),
|
||||
stderr: String::default(),
|
||||
}),
|
||||
"fossil branch current" => Some(CommandOutput{
|
||||
stdout: String::from("topic-branch"),
|
||||
stderr: String::default(),
|
||||
}),
|
||||
"fossil branch new topic-branch trunk" => Some(CommandOutput{
|
||||
stdout: String::default(),
|
||||
stderr: String::default(),
|
||||
}),
|
||||
"fossil update topic-branch" => Some(CommandOutput{
|
||||
stdout: String::default(),
|
||||
stderr: String::default(),
|
||||
}),
|
||||
"go version" => Some(CommandOutput {
|
||||
stdout: String::from("go version go1.12.1 linux/amd64\n"),
|
||||
stderr: String::default(),
|
||||
|
|
Loading…
Reference in New Issue