mirror of
https://github.com/starship/starship.git
synced 2025-02-23 05:41:44 +01:00
Merge branch 'master' into conditional-style
This commit is contained in:
commit
34e141d9f1
16
.github/config-schema.json
vendored
16
.github/config-schema.json
vendored
@ -996,10 +996,12 @@
|
|||||||
"default": {
|
"default": {
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
"format": "via [$symbol$state( \\($name\\))]($style) ",
|
"format": "via [$symbol$state( \\($name\\))]($style) ",
|
||||||
|
"heuristic": false,
|
||||||
"impure_msg": "impure",
|
"impure_msg": "impure",
|
||||||
"pure_msg": "pure",
|
"pure_msg": "pure",
|
||||||
"style": "bold blue",
|
"style": "bold blue",
|
||||||
"symbol": "❄️ "
|
"symbol": "❄️ ",
|
||||||
|
"unknown_msg": ""
|
||||||
},
|
},
|
||||||
"allOf": [
|
"allOf": [
|
||||||
{
|
{
|
||||||
@ -2914,6 +2916,10 @@
|
|||||||
"disabled": {
|
"disabled": {
|
||||||
"default": false,
|
"default": false,
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"default": "<env_var module>",
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
@ -4148,9 +4154,17 @@
|
|||||||
"default": "pure",
|
"default": "pure",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"unknown_msg": {
|
||||||
|
"default": "",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"disabled": {
|
"disabled": {
|
||||||
"default": false,
|
"default": false,
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"heuristic": {
|
||||||
|
"default": false,
|
||||||
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
|
33
Cargo.lock
generated
33
Cargo.lock
generated
@ -1030,9 +1030,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "git-features"
|
name = "git-features"
|
||||||
version = "0.25.0"
|
version = "0.25.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "510591428bb22671eb60f56430975718af88fdae55a1489d403005f74c0d3c25"
|
checksum = "0f98e6ede7b790dfba16bf3c62861ae75c3719485d675b522cf7d7e748a4011c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crc32fast",
|
"crc32fast",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
@ -1146,9 +1146,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "git-odb"
|
name = "git-odb"
|
||||||
version = "0.38.0"
|
version = "0.38.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a30a069e4c30d8aeabe41235f9a1595b60186a3cdfae73a7f3c89054e3e0d0ad"
|
checksum = "55333419bbb25aa6d39e29155f747ad8e1777fe385f70f447be9d680824d23dd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"git-features",
|
"git-features",
|
||||||
@ -1256,9 +1256,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "git-repository"
|
name = "git-repository"
|
||||||
version = "0.30.1"
|
version = "0.30.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5dbc1d1d0c346c66f18ea3c1393e8441f0729f759ec91965606b9f9ae6f2545c"
|
checksum = "1925a65a9fea6587e969a7a85cb239c8e1e438cf6dc520406df1b4c9d0e83bdc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"git-actor",
|
"git-actor",
|
||||||
"git-attributes",
|
"git-attributes",
|
||||||
@ -1352,9 +1352,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "git-url"
|
name = "git-url"
|
||||||
version = "0.12.1"
|
version = "0.12.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7cc3a878147b2cc4bb3011ef7a290ecf4d6ab11c36e50fedd99ec52702dea98c"
|
checksum = "8651924c9692a778f09141ca44d1bf2dada229fe9b240f1ff1bdecd9621a1a93"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bstr",
|
"bstr",
|
||||||
"git-features",
|
"git-features",
|
||||||
@ -1839,12 +1839,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nom8"
|
name = "nom8"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "75d908f0297c3526d34e478d438b07eefe3d7b0416494d7ffccb17f1c7f7262c"
|
checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
"minimal-lexical",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2619,18 +2618,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.151"
|
version = "1.0.152"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0"
|
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.151"
|
version = "1.0.152"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8"
|
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -3104,9 +3103,9 @@ checksum = "808b51e57d0ef8f71115d8f3a01e7d3750d01c79cac4b3eda910f4389fdf92fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
version = "0.16.0"
|
version = "0.16.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dcd65b83c7473af53e3fd994eb2888dfddfeb28cac9a82825ec5803c233c882c"
|
checksum = "dd30deba9a1cd7153c22aecf93e86df639e7b81c622b0af8d9255e989991a7b7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
@ -48,9 +48,9 @@ clap_complete = "4.0.7"
|
|||||||
dirs-next = "2.0.0"
|
dirs-next = "2.0.0"
|
||||||
dunce = "1.0.3"
|
dunce = "1.0.3"
|
||||||
gethostname = "0.4.1"
|
gethostname = "0.4.1"
|
||||||
git-features = { version = "0.25.0", optional = true }
|
git-features = { version = "0.25.1", optional = true }
|
||||||
# default feature restriction addresses https://github.com/starship/starship/issues/4251
|
# default feature restriction addresses https://github.com/starship/starship/issues/4251
|
||||||
git-repository = { version = "0.30.1", default-features = false, features = ["max-performance-safe"] }
|
git-repository = { version = "0.30.2", default-features = false, features = ["max-performance-safe"] }
|
||||||
indexmap = { version = "1.9.2", features = ["serde"] }
|
indexmap = { version = "1.9.2", features = ["serde"] }
|
||||||
log = { version = "0.4.17", features = ["std"] }
|
log = { version = "0.4.17", features = ["std"] }
|
||||||
# nofity-rust is optional (on by default) because the crate doesn't currently build for darwin with nix
|
# nofity-rust is optional (on by default) because the crate doesn't currently build for darwin with nix
|
||||||
@ -70,7 +70,7 @@ rayon = "1.6.1"
|
|||||||
regex = "1.7.0"
|
regex = "1.7.0"
|
||||||
rust-ini = "0.18.0"
|
rust-ini = "0.18.0"
|
||||||
semver = "1.0.16"
|
semver = "1.0.16"
|
||||||
serde = { version = "1.0.151", features = ["derive"] }
|
serde = { version = "1.0.152", features = ["derive"] }
|
||||||
serde_json = "1.0.91"
|
serde_json = "1.0.91"
|
||||||
sha1 = "0.10.5"
|
sha1 = "0.10.5"
|
||||||
shadow-rs = { version = "0.19.0", default-features = false }
|
shadow-rs = { version = "0.19.0", default-features = false }
|
||||||
@ -81,7 +81,7 @@ strsim = "0.10.0"
|
|||||||
systemstat = "=0.2.2"
|
systemstat = "=0.2.2"
|
||||||
terminal_size = "0.2.3"
|
terminal_size = "0.2.3"
|
||||||
toml = { version = "0.5.10", features = ["preserve_order"] }
|
toml = { version = "0.5.10", features = ["preserve_order"] }
|
||||||
toml_edit = "0.16.0"
|
toml_edit = "0.16.2"
|
||||||
unicode-segmentation = "1.10.0"
|
unicode-segmentation = "1.10.0"
|
||||||
unicode-width = "0.1.10"
|
unicode-width = "0.1.10"
|
||||||
urlencoding = "2.1.2"
|
urlencoding = "2.1.2"
|
||||||
|
@ -1380,6 +1380,14 @@ The module will be shown only if any of the following conditions are met:
|
|||||||
|
|
||||||
::: tip
|
::: tip
|
||||||
|
|
||||||
|
The order in which env_var modules are shown can be individually set by including
|
||||||
|
`${env_var.foo}` in the top level `format` (as it includes a dot, you need to use `${...}`).
|
||||||
|
By default, the `env_var` module will simply show all env_var modules in the order they were defined.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: tip
|
||||||
|
|
||||||
Multiple environmental variables can be displayed by using a `.`. (see example)
|
Multiple environmental variables can be displayed by using a `.`. (see example)
|
||||||
If the `variable` configuration option is not set, the module will display value of variable under the name of text after the `.` character.
|
If the `variable` configuration option is not set, the module will display value of variable under the name of text after the `.` character.
|
||||||
|
|
||||||
@ -1397,11 +1405,12 @@ default = 'unknown user'
|
|||||||
### Options
|
### Options
|
||||||
|
|
||||||
| Option | Default | Description |
|
| Option | Default | Description |
|
||||||
| ---------- | ------------------------------ | ---------------------------------------------------------------------------- |
|
| ------------- | ------------------------------ | ---------------------------------------------------------------------------- |
|
||||||
| `symbol` | `''` | The symbol used before displaying the variable value. |
|
| `symbol` | `""` | The symbol used before displaying the variable value. |
|
||||||
| `variable` | | The environment variable to be displayed. |
|
| `variable` | | The environment variable to be displayed. |
|
||||||
| `default` | | The default value to be displayed when the selected variable is not defined. |
|
| `default` | | The default value to be displayed when the selected variable is not defined. |
|
||||||
| `format` | `'with [$env_value]($style) '` | The format for the module. |
|
| `format` | `"with [$env_value]($style) "` | The format for the module. |
|
||||||
|
| `description` | `"<env_var module>"` | The description of the module that is shown when running `starship explain`. |
|
||||||
| `disabled` | `false` | Disables the `env_var` module. |
|
| `disabled` | `false` | Disables the `env_var` module. |
|
||||||
|
|
||||||
### Variables
|
### Variables
|
||||||
@ -2719,13 +2728,15 @@ The module will be shown when inside a nix-shell environment.
|
|||||||
### Options
|
### Options
|
||||||
|
|
||||||
| Option | Default | Description |
|
| Option | Default | Description |
|
||||||
| ------------ | -------------------------------------------- | ----------------------------------------------------- |
|
| ------------- | -------------------------------------------- | --------------------------------------------------------------------- |
|
||||||
| `format` | `'via [$symbol$state( \($name\))]($style) '` | The format for the module. |
|
| `format` | `'via [$symbol$state( \($name\))]($style) '` | The format for the module. |
|
||||||
| `symbol` | `'❄️ '` | A format string representing the symbol of nix-shell. |
|
| `symbol` | `'❄️ '` | A format string representing the symbol of nix-shell. |
|
||||||
| `style` | `'bold blue'` | The style for the module. |
|
| `style` | `'bold blue'` | The style for the module. |
|
||||||
| `impure_msg` | `'impure'` | A format string shown when the shell is impure. |
|
| `impure_msg` | `'impure'` | A format string shown when the shell is impure. |
|
||||||
| `pure_msg` | `'pure'` | A format string shown when the shell is pure. |
|
| `pure_msg` | `'pure'` | A format string shown when the shell is pure. |
|
||||||
|
| `unknown_msg` | `''` | A format string shown when it is unknown if the shell is pure/impure. |
|
||||||
| `disabled` | `false` | Disables the `nix_shell` module. |
|
| `disabled` | `false` | Disables the `nix_shell` module. |
|
||||||
|
| `heuristic` | `false` | Attempts to detect new `nix shell`-style shells with a heuristic. |
|
||||||
|
|
||||||
### Variables
|
### Variables
|
||||||
|
|
||||||
@ -2747,6 +2758,7 @@ The module will be shown when inside a nix-shell environment.
|
|||||||
disabled = true
|
disabled = true
|
||||||
impure_msg = '[impure shell](bold red)'
|
impure_msg = '[impure shell](bold red)'
|
||||||
pure_msg = '[pure shell](bold green)'
|
pure_msg = '[pure shell](bold green)'
|
||||||
|
unknown_msg = '[unknown shell](bold yellow)'
|
||||||
format = 'via [☃️ $state( \($name\))](bold blue) '
|
format = 'via [☃️ $state( \($name\))](bold blue) '
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ pub struct EnvVarConfig<'a> {
|
|||||||
pub default: Option<&'a str>,
|
pub default: Option<&'a str>,
|
||||||
pub format: &'a str,
|
pub format: &'a str,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
|
pub description: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Default for EnvVarConfig<'a> {
|
impl<'a> Default for EnvVarConfig<'a> {
|
||||||
@ -27,6 +28,7 @@ impl<'a> Default for EnvVarConfig<'a> {
|
|||||||
default: None,
|
default: None,
|
||||||
format: "with [$env_value]($style) ",
|
format: "with [$env_value]($style) ",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
|
description: "<env_var module>",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
4
src/configs/nix_shell.rs
Normal file → Executable file
4
src/configs/nix_shell.rs
Normal file → Executable file
@ -13,7 +13,9 @@ pub struct NixShellConfig<'a> {
|
|||||||
pub style: &'a str,
|
pub style: &'a str,
|
||||||
pub impure_msg: &'a str,
|
pub impure_msg: &'a str,
|
||||||
pub pure_msg: &'a str,
|
pub pure_msg: &'a str,
|
||||||
|
pub unknown_msg: &'a str,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
|
pub heuristic: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The trailing double spaces in `symbol` are needed to work around issues with
|
/* The trailing double spaces in `symbol` are needed to work around issues with
|
||||||
@ -27,7 +29,9 @@ impl<'a> Default for NixShellConfig<'a> {
|
|||||||
style: "bold blue",
|
style: "bold blue",
|
||||||
impure_msg: "impure",
|
impure_msg: "impure",
|
||||||
pure_msg: "pure",
|
pure_msg: "pure",
|
||||||
|
unknown_msg: "",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
|
heuristic: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -238,15 +238,6 @@ impl<'a> Context<'a> {
|
|||||||
disabled == Some(true)
|
disabled == Some(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return whether the specified custom module has a `disabled` option set to true.
|
|
||||||
/// If it doesn't exist, `None` is returned.
|
|
||||||
pub fn is_custom_module_disabled_in_config(&self, name: &str) -> Option<bool> {
|
|
||||||
let config = self.config.get_custom_module_config(name)?;
|
|
||||||
let disabled = Some(config).and_then(|table| table.as_table()?.get("disabled")?.as_bool());
|
|
||||||
|
|
||||||
Some(disabled == Some(true))
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns a new ScanDir struct with reference to current dir_files of context
|
// returns a new ScanDir struct with reference to current dir_files of context
|
||||||
// see ScanDir for methods
|
// see ScanDir for methods
|
||||||
pub fn try_begin_scan(&'a self) -> Option<ScanDir<'a>> {
|
pub fn try_begin_scan(&'a self) -> Option<ScanDir<'a>> {
|
||||||
|
@ -31,7 +31,6 @@ pub const ALL_MODULES: &[&str] = &[
|
|||||||
"dotnet",
|
"dotnet",
|
||||||
"elixir",
|
"elixir",
|
||||||
"elm",
|
"elm",
|
||||||
"env_var",
|
|
||||||
"erlang",
|
"erlang",
|
||||||
"fennel",
|
"fennel",
|
||||||
"fill",
|
"fill",
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
|
use std::fmt::{self, Debug};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
use process_control::{ChildExt, Control, Output};
|
use process_control::{ChildExt, Control, Output};
|
||||||
|
|
||||||
@ -22,11 +22,11 @@ use crate::{
|
|||||||
///
|
///
|
||||||
/// Finally, the content of the module itself is also set by a command.
|
/// Finally, the content of the module itself is also set by a command.
|
||||||
pub fn module<'a>(name: &str, context: &'a Context) -> Option<Module<'a>> {
|
pub fn module<'a>(name: &str, context: &'a Context) -> Option<Module<'a>> {
|
||||||
let start: Instant = Instant::now();
|
let toml_config = get_config(name, context)?;
|
||||||
let toml_config = context.config.get_custom_module_config(name).expect(
|
|
||||||
"modules::custom::module should only be called after ensuring that the module exists",
|
|
||||||
);
|
|
||||||
let config = CustomConfig::load(toml_config);
|
let config = CustomConfig::load(toml_config);
|
||||||
|
if config.disabled {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(os) = config.os {
|
if let Some(os) = config.os {
|
||||||
if os != env::consts::OS && !(os == "unix" && cfg!(unix)) {
|
if os != env::consts::OS && !(os == "unix" && cfg!(unix)) {
|
||||||
@ -34,7 +34,8 @@ pub fn module<'a>(name: &str, context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut module = Module::new(name, config.description, Some(toml_config));
|
// Note: Forward config if `Module` ends up needing `config`
|
||||||
|
let mut module = Module::new(&format!("custom.{name}"), config.description, None);
|
||||||
|
|
||||||
let mut is_match = context
|
let mut is_match = context
|
||||||
.try_begin_scan()?
|
.try_begin_scan()?
|
||||||
@ -48,9 +49,12 @@ pub fn module<'a>(name: &str, context: &'a Context) -> Option<Module<'a>> {
|
|||||||
Either::First(b) => b,
|
Either::First(b) => b,
|
||||||
Either::Second(s) => exec_when(s, &config, context),
|
Either::Second(s) => exec_when(s, &config, context),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if !is_match {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_match {
|
|
||||||
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
formatter
|
formatter
|
||||||
.map_meta(|var, _| match var {
|
.map_meta(|var, _| match var {
|
||||||
@ -83,13 +87,36 @@ pub fn module<'a>(name: &str, context: &'a Context) -> Option<Module<'a>> {
|
|||||||
log::warn!("Error in module `custom.{}`:\n{}", name, error);
|
log::warn!("Error in module `custom.{}`:\n{}", name, error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
let elapsed = start.elapsed();
|
|
||||||
log::trace!("Took {:?} to compute custom module {:?}", elapsed, name);
|
|
||||||
module.duration = elapsed;
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the TOML config for the custom module, handling the case where the module is not defined
|
||||||
|
fn get_config<'a>(module_name: &str, context: &'a Context<'a>) -> Option<&'a toml::Value> {
|
||||||
|
struct DebugCustomModules<'tmp>(&'tmp toml::value::Table);
|
||||||
|
|
||||||
|
impl Debug for DebugCustomModules<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
f.debug_list().entries(self.0.keys()).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let config = context.config.get_custom_module_config(module_name);
|
||||||
|
|
||||||
|
if config.is_some() {
|
||||||
|
return config;
|
||||||
|
} else if let Some(modules) = context.config.get_custom_modules() {
|
||||||
|
log::debug!(
|
||||||
|
"top level format contains custom module {module_name:?}, but no configuration was provided. Configuration for the following modules were provided: {:?}",
|
||||||
|
DebugCustomModules(modules),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
log::debug!(
|
||||||
|
"top level format contains custom module {module_name:?}, but no configuration was provided.",
|
||||||
|
);
|
||||||
|
};
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the invoking shell, using `shell` and fallbacking in order to `STARSHIP_SHELL` and "sh"/"cmd"
|
/// Return the invoking shell, using `shell` and fallbacking in order to `STARSHIP_SHELL` and "sh"/"cmd"
|
||||||
fn get_shell<'a, 'b>(
|
fn get_shell<'a, 'b>(
|
||||||
shell_args: &'b [&'a str],
|
shell_args: &'b [&'a str],
|
||||||
@ -680,4 +707,18 @@ mod tests {
|
|||||||
|
|
||||||
dir.close()
|
dir.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn disabled() {
|
||||||
|
let actual = ModuleRenderer::new("custom.test")
|
||||||
|
.config(toml::toml! {
|
||||||
|
[custom.test]
|
||||||
|
disabled = true
|
||||||
|
when = true
|
||||||
|
format = "test"
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let expected = None;
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,38 +1,9 @@
|
|||||||
use super::{Context, Module};
|
use super::{Context, Module};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::config::ModuleConfig;
|
use crate::config::ModuleConfig;
|
||||||
use crate::configs::env_var::EnvVarConfig;
|
use crate::configs::env_var::EnvVarConfig;
|
||||||
use crate::formatter::StringFormatter;
|
use crate::formatter::StringFormatter;
|
||||||
use crate::segment::Segment;
|
|
||||||
|
|
||||||
/// Creates `env_var_module` displayer which displays all configured environmental variables
|
|
||||||
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|
||||||
let config_table = context.config.get_env_var_modules()?;
|
|
||||||
let mut env_modules = config_table
|
|
||||||
.iter()
|
|
||||||
.filter(|(_, config)| config.is_table())
|
|
||||||
.filter_map(|(variable, _)| env_var_module(vec!["env_var", variable], context))
|
|
||||||
.collect::<Vec<Module>>();
|
|
||||||
// Old configuration is present in starship configuration
|
|
||||||
if config_table.iter().any(|(_, config)| !config.is_table()) {
|
|
||||||
if let Some(fallback_env_var_module) = env_var_module(vec!["env_var"], context) {
|
|
||||||
env_modules.push(fallback_env_var_module);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(env_var_displayer(env_modules, context))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A utility module to display multiple `env_variable` modules
|
|
||||||
fn env_var_displayer<'a>(modules: Vec<Module>, context: &'a Context) -> Module<'a> {
|
|
||||||
let mut module = context.new_module("env_var_displayer");
|
|
||||||
|
|
||||||
let module_segments = modules
|
|
||||||
.into_iter()
|
|
||||||
.flat_map(|module| module.segments)
|
|
||||||
.collect::<Vec<Segment>>();
|
|
||||||
module.set_segments(module_segments);
|
|
||||||
module
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a module with the value of the chosen environment variable
|
/// Creates a module with the value of the chosen environment variable
|
||||||
///
|
///
|
||||||
@ -40,20 +11,36 @@ fn env_var_displayer<'a>(modules: Vec<Module>, context: &'a Context) -> Module<'
|
|||||||
/// - `env_var.disabled` is absent or false
|
/// - `env_var.disabled` is absent or false
|
||||||
/// - `env_var.variable` is defined
|
/// - `env_var.variable` is defined
|
||||||
/// - a variable named as the value of `env_var.variable` is defined
|
/// - a variable named as the value of `env_var.variable` is defined
|
||||||
fn env_var_module<'a>(module_config_path: Vec<&str>, context: &'a Context) -> Option<Module<'a>> {
|
pub fn module<'a>(name: Option<&str>, context: &'a Context) -> Option<Module<'a>> {
|
||||||
let mut module = context.new_module(&module_config_path.join("."));
|
let toml_config = match name {
|
||||||
let config_value = context.config.get_config(&module_config_path);
|
Some(name) => context
|
||||||
let config = EnvVarConfig::load(config_value.expect(
|
.config
|
||||||
"modules::env_var::module should only be called after ensuring that the module exists",
|
.get_config(&["env_var", name])
|
||||||
));
|
.map(Cow::Borrowed),
|
||||||
|
None => context
|
||||||
|
.config
|
||||||
|
.get_module_config("env_var")
|
||||||
|
.and_then(filter_config)
|
||||||
|
.map(Cow::Owned)
|
||||||
|
.map(Some)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mod_name = match name {
|
||||||
|
Some(name) => format!("env_var.{}", name),
|
||||||
|
None => "env_var".to_owned(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let config = EnvVarConfig::try_load(toml_config.as_deref());
|
||||||
|
// Note: Forward config if `Module` ends up needing `config`
|
||||||
|
let mut module = Module::new(&mod_name, config.description, None);
|
||||||
if config.disabled {
|
if config.disabled {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
let variable_name = get_variable_name(module_config_path, &config);
|
let variable_name = config.variable.or(name)?;
|
||||||
|
|
||||||
let env_value = get_env_value(context, variable_name?, config.default)?;
|
let env_value = context.get_env(variable_name);
|
||||||
|
let env_value = env_value.as_deref().or(config.default)?;
|
||||||
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
formatter
|
formatter
|
||||||
.map_meta(|var, _| match var {
|
.map_meta(|var, _| match var {
|
||||||
@ -65,7 +52,7 @@ fn env_var_module<'a>(module_config_path: Vec<&str>, context: &'a Context) -> Op
|
|||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.map(|variable| match variable {
|
.map(|variable| match variable {
|
||||||
"env_value" => Some(Ok(&env_value)),
|
"env_value" => Some(Ok(env_value)),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None, Some(context))
|
.parse(None, Some(context))
|
||||||
@ -82,24 +69,22 @@ fn env_var_module<'a>(module_config_path: Vec<&str>, context: &'a Context) -> Op
|
|||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_variable_name<'a>(
|
/// Filter `config` to only includes non-table values
|
||||||
module_config_path: Vec<&'a str>,
|
/// This filters the top-level table to only include its specific configuation
|
||||||
config: &'a EnvVarConfig,
|
fn filter_config(config: &toml::Value) -> Option<toml::Value> {
|
||||||
) -> Option<&'a str> {
|
let o = config
|
||||||
match config.variable {
|
.as_table()
|
||||||
Some(v) => Some(v),
|
.map(|table| {
|
||||||
None => {
|
table
|
||||||
let last_element = module_config_path.last()?;
|
.iter()
|
||||||
Some(*last_element)
|
.filter(|(_key, val)| !val.is_table())
|
||||||
}
|
.map(|(key, val)| (key.to_owned(), val.to_owned()))
|
||||||
}
|
.collect::<toml::value::Table>()
|
||||||
}
|
})
|
||||||
|
.filter(|table| !table.is_empty())
|
||||||
fn get_env_value(context: &Context, name: &str, default: Option<&str>) -> Option<String> {
|
.map(toml::Value::Table);
|
||||||
match context.get_env(name) {
|
log::trace!("Filtered top-level env_var config: {o:?}");
|
||||||
Some(value) => Some(value),
|
o
|
||||||
None => default.map(std::borrow::ToOwned::to_owned),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -133,7 +118,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn defined_variable() {
|
fn defined_variable() {
|
||||||
let actual = ModuleRenderer::new("env_var")
|
let actual = ModuleRenderer::new("env_var.TEST_VAR")
|
||||||
.config(toml::toml! {
|
.config(toml::toml! {
|
||||||
[env_var.TEST_VAR]
|
[env_var.TEST_VAR]
|
||||||
})
|
})
|
||||||
@ -146,7 +131,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn undefined_variable() {
|
fn undefined_variable() {
|
||||||
let actual = ModuleRenderer::new("env_var")
|
let actual = ModuleRenderer::new("env_var.TEST_VAR")
|
||||||
.config(toml::toml! {
|
.config(toml::toml! {
|
||||||
[env_var.TEST_VAR]
|
[env_var.TEST_VAR]
|
||||||
})
|
})
|
||||||
@ -158,7 +143,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn default_has_no_effect() {
|
fn default_has_no_effect() {
|
||||||
let actual = ModuleRenderer::new("env_var")
|
let actual = ModuleRenderer::new("env_var.TEST_VAR")
|
||||||
.config(toml::toml! {
|
.config(toml::toml! {
|
||||||
[env_var.TEST_VAR]
|
[env_var.TEST_VAR]
|
||||||
default = "N/A"
|
default = "N/A"
|
||||||
@ -172,7 +157,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn default_takes_effect() {
|
fn default_takes_effect() {
|
||||||
let actual = ModuleRenderer::new("env_var")
|
let actual = ModuleRenderer::new("env_var.UNDEFINED_TEST_VAR")
|
||||||
.config(toml::toml! {
|
.config(toml::toml! {
|
||||||
[env_var.UNDEFINED_TEST_VAR]
|
[env_var.UNDEFINED_TEST_VAR]
|
||||||
default = "N/A"
|
default = "N/A"
|
||||||
@ -185,7 +170,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn symbol() {
|
fn symbol() {
|
||||||
let actual = ModuleRenderer::new("env_var")
|
let actual = ModuleRenderer::new("env_var.TEST_VAR")
|
||||||
.config(toml::toml! {
|
.config(toml::toml! {
|
||||||
[env_var.TEST_VAR]
|
[env_var.TEST_VAR]
|
||||||
format = "with [■ $env_value](black bold dimmed) "
|
format = "with [■ $env_value](black bold dimmed) "
|
||||||
@ -202,7 +187,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn prefix() {
|
fn prefix() {
|
||||||
let actual = ModuleRenderer::new("env_var")
|
let actual = ModuleRenderer::new("env_var.TEST_VAR")
|
||||||
.config(toml::toml! {
|
.config(toml::toml! {
|
||||||
[env_var.TEST_VAR]
|
[env_var.TEST_VAR]
|
||||||
format = "with [_$env_value](black bold dimmed) "
|
format = "with [_$env_value](black bold dimmed) "
|
||||||
@ -219,7 +204,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn suffix() {
|
fn suffix() {
|
||||||
let actual = ModuleRenderer::new("env_var")
|
let actual = ModuleRenderer::new("env_var.TEST_VAR")
|
||||||
.config(toml::toml! {
|
.config(toml::toml! {
|
||||||
[env_var.TEST_VAR]
|
[env_var.TEST_VAR]
|
||||||
format = "with [${env_value}_](black bold dimmed) "
|
format = "with [${env_value}_](black bold dimmed) "
|
||||||
@ -236,7 +221,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn display_few() {
|
fn display_few() {
|
||||||
let actual = ModuleRenderer::new("env_var")
|
let actual1 = ModuleRenderer::new("env_var.TEST_VAR")
|
||||||
.config(toml::toml! {
|
.config(toml::toml! {
|
||||||
[env_var.TEST_VAR]
|
[env_var.TEST_VAR]
|
||||||
[env_var.TEST_VAR2]
|
[env_var.TEST_VAR2]
|
||||||
@ -244,11 +229,103 @@ mod test {
|
|||||||
.env("TEST_VAR", TEST_VAR_VALUE)
|
.env("TEST_VAR", TEST_VAR_VALUE)
|
||||||
.env("TEST_VAR2", TEST_VAR_VALUE)
|
.env("TEST_VAR2", TEST_VAR_VALUE)
|
||||||
.collect();
|
.collect();
|
||||||
let expected = Some(format!(
|
let actual2 = ModuleRenderer::new("env_var.TEST_VAR2")
|
||||||
"with {} with {} ",
|
.config(toml::toml! {
|
||||||
style().paint(TEST_VAR_VALUE),
|
[env_var.TEST_VAR]
|
||||||
style().paint(TEST_VAR_VALUE)
|
[env_var.TEST_VAR2]
|
||||||
));
|
})
|
||||||
|
.env("TEST_VAR", TEST_VAR_VALUE)
|
||||||
|
.env("TEST_VAR2", TEST_VAR_VALUE)
|
||||||
|
.collect();
|
||||||
|
let expected = Some(format!("with {} ", style().paint(TEST_VAR_VALUE)));
|
||||||
|
|
||||||
|
assert_eq!(expected, actual1);
|
||||||
|
assert_eq!(expected, actual2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mixed() {
|
||||||
|
let cfg = toml::toml! {
|
||||||
|
[env_var]
|
||||||
|
variable = "TEST_VAR_OUTER"
|
||||||
|
format = "$env_value"
|
||||||
|
[env_var.TEST_VAR_INNER]
|
||||||
|
format = "$env_value"
|
||||||
|
};
|
||||||
|
let actual_inner = ModuleRenderer::new("env_var.TEST_VAR_INNER")
|
||||||
|
.config(cfg.clone())
|
||||||
|
.env("TEST_VAR_OUTER", "outer")
|
||||||
|
.env("TEST_VAR_INNER", "inner")
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
actual_inner.as_deref(),
|
||||||
|
Some("inner"),
|
||||||
|
"inner module should be rendered"
|
||||||
|
);
|
||||||
|
|
||||||
|
let actual_outer = ModuleRenderer::new("env_var")
|
||||||
|
.config(cfg)
|
||||||
|
.env("TEST_VAR_OUTER", "outer")
|
||||||
|
.env("TEST_VAR_INNER", "inner")
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
actual_outer.as_deref(),
|
||||||
|
Some("outer"),
|
||||||
|
"outer module should be rendered"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_config() {
|
||||||
|
let actual = ModuleRenderer::new("env_var.TEST_VAR")
|
||||||
|
.env("TEST_VAR", TEST_VAR_VALUE)
|
||||||
|
.collect();
|
||||||
|
let expected = Some(format!("with {} ", style().paint(TEST_VAR_VALUE)));
|
||||||
|
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn disabled_child() {
|
||||||
|
let actual = ModuleRenderer::new("env_var.TEST_VAR")
|
||||||
|
.config(toml::toml! {
|
||||||
|
[env_var.TEST_VAR]
|
||||||
|
disabled = true
|
||||||
|
})
|
||||||
|
.env("TEST_VAR", TEST_VAR_VALUE)
|
||||||
|
.collect();
|
||||||
|
let expected = None;
|
||||||
|
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn disabled_root() {
|
||||||
|
let actual = ModuleRenderer::new("env_var")
|
||||||
|
.config(toml::toml! {
|
||||||
|
[env_var]
|
||||||
|
disabled = true
|
||||||
|
})
|
||||||
|
.env("TEST_VAR", TEST_VAR_VALUE)
|
||||||
|
.collect();
|
||||||
|
let expected = None;
|
||||||
|
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn variable_override() {
|
||||||
|
let actual = ModuleRenderer::new("env_var.TEST_VAR")
|
||||||
|
.config(toml::toml! {
|
||||||
|
[env_var.TEST_VAR]
|
||||||
|
variable = "TEST_VAR2"
|
||||||
|
})
|
||||||
|
.env("TEST_VAR", "implicit name")
|
||||||
|
.env("TEST_VAR2", "explicit name")
|
||||||
|
.collect();
|
||||||
|
let expected = Some(format!("with {} ", style().paint("explicit name")));
|
||||||
|
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
}
|
}
|
||||||
|
@ -122,8 +122,8 @@ pub fn handle<'a>(module: &str, context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"elixir" => elixir::module(context),
|
"elixir" => elixir::module(context),
|
||||||
"elm" => elm::module(context),
|
"elm" => elm::module(context),
|
||||||
"erlang" => erlang::module(context),
|
"erlang" => erlang::module(context),
|
||||||
|
"env_var" => env_var::module(None, context),
|
||||||
"fennel" => fennel::module(context),
|
"fennel" => fennel::module(context),
|
||||||
"env_var" => env_var::module(context),
|
|
||||||
"fill" => fill::module(context),
|
"fill" => fill::module(context),
|
||||||
"gcloud" => gcloud::module(context),
|
"gcloud" => gcloud::module(context),
|
||||||
"git_branch" => git_branch::module(context),
|
"git_branch" => git_branch::module(context),
|
||||||
@ -183,8 +183,9 @@ pub fn handle<'a>(module: &str, context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"vagrant" => vagrant::module(context),
|
"vagrant" => vagrant::module(context),
|
||||||
"vcsh" => vcsh::module(context),
|
"vcsh" => vcsh::module(context),
|
||||||
"zig" => zig::module(context),
|
"zig" => zig::module(context),
|
||||||
// Added for tests, avoid potential side effects in production code.
|
env if env.starts_with("env_var.") => {
|
||||||
#[cfg(test)]
|
env_var::module(env.strip_prefix("env_var."), context)
|
||||||
|
}
|
||||||
custom if custom.starts_with("custom.") => {
|
custom if custom.starts_with("custom.") => {
|
||||||
// SAFETY: We just checked that the module starts with "custom."
|
// SAFETY: We just checked that the module starts with "custom."
|
||||||
custom::module(custom.strip_prefix("custom.").unwrap(), context)
|
custom::module(custom.strip_prefix("custom.").unwrap(), context)
|
||||||
@ -233,7 +234,6 @@ pub fn description(module: &str) -> &'static str {
|
|||||||
"dotnet" => "The relevant version of the .NET Core SDK for the current directory",
|
"dotnet" => "The relevant version of the .NET Core SDK for the current directory",
|
||||||
"elixir" => "The currently installed versions of Elixir and OTP",
|
"elixir" => "The currently installed versions of Elixir and OTP",
|
||||||
"elm" => "The currently installed version of Elm",
|
"elm" => "The currently installed version of Elm",
|
||||||
"env_var" => "Displays the current value of a selected environment variable",
|
|
||||||
"erlang" => "Current OTP version",
|
"erlang" => "Current OTP version",
|
||||||
"fennel" => "The currently installed version of Fennel",
|
"fennel" => "The currently installed version of Fennel",
|
||||||
"fill" => "Fills the remaining space on the line with a pad string",
|
"fill" => "Fills the remaining space on the line with a pad string",
|
||||||
|
@ -3,6 +3,43 @@ use super::{Context, Module, ModuleConfig};
|
|||||||
use crate::configs::nix_shell::NixShellConfig;
|
use crate::configs::nix_shell::NixShellConfig;
|
||||||
use crate::formatter::StringFormatter;
|
use crate::formatter::StringFormatter;
|
||||||
|
|
||||||
|
enum NixShellType {
|
||||||
|
Pure,
|
||||||
|
Impure,
|
||||||
|
/// We're in a Nix shell, but we don't know which type.
|
||||||
|
/// This can only happen in a `nix shell` shell (not a `nix-shell` one).
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NixShellType {
|
||||||
|
fn detect_shell_type(use_heuristic: bool, context: &Context) -> Option<NixShellType> {
|
||||||
|
use NixShellType::*;
|
||||||
|
|
||||||
|
let shell_type = context.get_env("IN_NIX_SHELL");
|
||||||
|
match shell_type.as_deref() {
|
||||||
|
Some("pure") => return Some(Pure),
|
||||||
|
Some("impure") => return Some(Impure),
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
if use_heuristic {
|
||||||
|
Self::in_new_nix_shell(context).map(|_| Unknown)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hack to detect if we're in a `nix shell` (in constrast to a `nix-shell`).
|
||||||
|
// A better way to do this will be enabled by https://github.com/NixOS/nix/issues/6677.
|
||||||
|
fn in_new_nix_shell(context: &Context) -> Option<()> {
|
||||||
|
let path = context.get_env("PATH")?;
|
||||||
|
|
||||||
|
std::env::split_paths(&path)
|
||||||
|
.any(|path| path.starts_with("/nix/store"))
|
||||||
|
.then_some(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a module showing if inside a nix-shell
|
/// Creates a module showing if inside a nix-shell
|
||||||
///
|
///
|
||||||
/// The module will use the `$IN_NIX_SHELL` and `$name` environment variable to
|
/// The module will use the `$IN_NIX_SHELL` and `$name` environment variable to
|
||||||
@ -11,24 +48,25 @@ use crate::formatter::StringFormatter;
|
|||||||
/// The following options are availables:
|
/// The following options are availables:
|
||||||
/// - `impure_msg` (string) // change the impure msg
|
/// - `impure_msg` (string) // change the impure msg
|
||||||
/// - `pure_msg` (string) // change the pure msg
|
/// - `pure_msg` (string) // change the pure msg
|
||||||
|
/// - `unknown_msg` (string) // change the unknown message
|
||||||
///
|
///
|
||||||
/// Will display the following:
|
/// Will display the following:
|
||||||
/// - pure (name) // $name == "name" in a pure nix-shell
|
/// - pure (name) // $name == "name" in a pure nix-shell
|
||||||
/// - impure (name) // $name == "name" in an impure nix-shell
|
/// - impure (name) // $name == "name" in an impure nix-shell
|
||||||
/// - pure // $name == "" in a pure nix-shell
|
/// - pure // $name == "" in a pure nix-shell
|
||||||
/// - impure // $name == "" in an impure nix-shell
|
/// - impure // $name == "" in an impure nix-shell
|
||||||
|
/// - unknown (name) // $name == "name" in an unknown nix-shell
|
||||||
|
/// - unknown // $name == "" in an unknown nix-shell
|
||||||
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
let mut module = context.new_module("nix_shell");
|
let mut module = context.new_module("nix_shell");
|
||||||
let config: NixShellConfig = NixShellConfig::try_load(module.config);
|
let config: NixShellConfig = NixShellConfig::try_load(module.config);
|
||||||
|
|
||||||
let shell_name = context.get_env("name");
|
let shell_name = context.get_env("name");
|
||||||
let shell_type = context.get_env("IN_NIX_SHELL")?;
|
let shell_type = NixShellType::detect_shell_type(config.heuristic, context)?;
|
||||||
let shell_type_format = match shell_type.as_ref() {
|
let shell_type_format = match shell_type {
|
||||||
"impure" => config.impure_msg,
|
NixShellType::Pure => config.pure_msg,
|
||||||
"pure" => config.pure_msg,
|
NixShellType::Impure => config.impure_msg,
|
||||||
_ => {
|
NixShellType::Unknown => config.unknown_msg,
|
||||||
return None;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
@ -130,4 +168,62 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn new_nix_shell() {
|
||||||
|
let actual = ModuleRenderer::new("nix_shell")
|
||||||
|
.env(
|
||||||
|
"PATH",
|
||||||
|
"/nix/store/v7qvqv81jp0cajvrxr9x072jgqc01yhi-nix-info/bin:/Users/user/.cargo/bin",
|
||||||
|
)
|
||||||
|
.config(toml::toml! {
|
||||||
|
[nix_shell]
|
||||||
|
heuristic = true
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let expected = Some(format!("via {} ", Color::Blue.bold().paint("❄️ ")));
|
||||||
|
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_new_nix_shell() {
|
||||||
|
let actual = ModuleRenderer::new("nix_shell")
|
||||||
|
.env("PATH", "/Users/user/.cargo/bin")
|
||||||
|
.config(toml::toml! {
|
||||||
|
[nix_shell]
|
||||||
|
heuristic = true
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let expected = None;
|
||||||
|
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_new_nix_shell_with_nix_store_subdirectory() {
|
||||||
|
let actual = ModuleRenderer::new("nix_shell")
|
||||||
|
.env("PATH", "/Users/user/some/nix/store/subdirectory")
|
||||||
|
.config(toml::toml! {
|
||||||
|
[nix_shell]
|
||||||
|
heuristic = true
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let expected = None;
|
||||||
|
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_new_nix_shell_when_heuristic_is_disabled() {
|
||||||
|
let actual = ModuleRenderer::new("nix_shell")
|
||||||
|
.env(
|
||||||
|
"PATH",
|
||||||
|
"/nix/store/v7qvqv81jp0cajvrxr9x072jgqc01yhi-nix-info/bin:/Users/user/.cargo/bin",
|
||||||
|
)
|
||||||
|
.collect();
|
||||||
|
let expected = None;
|
||||||
|
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ fn get_gradle_version(context: &Context, config: &PackageConfig) -> Option<Strin
|
|||||||
context
|
context
|
||||||
.read_file_from_pwd("gradle.properties")
|
.read_file_from_pwd("gradle.properties")
|
||||||
.and_then(|contents| {
|
.and_then(|contents| {
|
||||||
let re = Regex::new(r"version=(?P<version>.*)").unwrap();
|
let re = Regex::new(r"(?m)^\s*version\s*=\s*(?P<version>.*)").unwrap();
|
||||||
let caps = re.captures(&contents)?;
|
let caps = re.captures(&contents)?;
|
||||||
format_version(&caps["version"], config.version_format)
|
format_version(&caps["version"], config.version_format)
|
||||||
}).or_else(|| {
|
}).or_else(|| {
|
||||||
@ -979,6 +979,18 @@ java {
|
|||||||
expect_output(&project_dir, Some("v1.2.3"), None);
|
expect_output(&project_dir, Some("v1.2.3"), None);
|
||||||
project_dir.close()
|
project_dir.close()
|
||||||
}
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_extract_grade_version_from_properties_with_comment_and_whitespace() -> io::Result<()> {
|
||||||
|
let config_name = "gradle.properties";
|
||||||
|
let config_content = "
|
||||||
|
# or use -Pversion=0.0.1
|
||||||
|
version = 1.2.3
|
||||||
|
";
|
||||||
|
let project_dir = create_project_dir()?;
|
||||||
|
fill_config(&project_dir, config_name, Some(config_content))?;
|
||||||
|
expect_output(&project_dir, Some("v1.2.3"), None);
|
||||||
|
project_dir.close()
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_extract_mix_version() -> io::Result<()> {
|
fn test_extract_mix_version() -> io::Result<()> {
|
||||||
|
213
src/print.rs
213
src/print.rs
@ -2,7 +2,7 @@ use clap::{builder::PossibleValue, ValueEnum};
|
|||||||
use nu_ansi_term::AnsiStrings;
|
use nu_ansi_term::AnsiStrings;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::fmt::{self, Debug, Write as FmtWrite};
|
use std::fmt::{Debug, Write as FmtWrite};
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use terminal_size::terminal_size;
|
use terminal_size::terminal_size;
|
||||||
@ -313,14 +313,6 @@ fn handle_module<'a>(
|
|||||||
context: &'a Context,
|
context: &'a Context,
|
||||||
module_list: &BTreeSet<String>,
|
module_list: &BTreeSet<String>,
|
||||||
) -> Vec<Module<'a>> {
|
) -> Vec<Module<'a>> {
|
||||||
struct DebugCustomModules<'tmp>(&'tmp toml::value::Table);
|
|
||||||
|
|
||||||
impl Debug for DebugCustomModules<'_> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.debug_list().entries(self.0.keys()).finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut modules: Vec<Module> = Vec::new();
|
let mut modules: Vec<Module> = Vec::new();
|
||||||
|
|
||||||
if ALL_MODULES.contains(&module) {
|
if ALL_MODULES.contains(&module) {
|
||||||
@ -328,34 +320,29 @@ fn handle_module<'a>(
|
|||||||
if !context.is_module_disabled_in_config(module) {
|
if !context.is_module_disabled_in_config(module) {
|
||||||
modules.extend(modules::handle(module, context));
|
modules.extend(modules::handle(module, context));
|
||||||
}
|
}
|
||||||
} else if module == "custom" {
|
} else if module.starts_with("custom.") || module.starts_with("env_var.") {
|
||||||
|
// custom.<name> and env_var.<name> are special cases and handle disabled modules themselves
|
||||||
|
modules.extend(modules::handle(module, context));
|
||||||
|
} else if matches!(module, "custom" | "env_var") {
|
||||||
|
// env var is a spacial case and may contain a top-level module definition
|
||||||
|
if module == "env_var" {
|
||||||
|
modules.extend(modules::handle(module, context));
|
||||||
|
}
|
||||||
|
|
||||||
// Write out all custom modules, except for those that are explicitly set
|
// Write out all custom modules, except for those that are explicitly set
|
||||||
if let Some(custom_modules) = context.config.get_custom_modules() {
|
for (child, config) in context
|
||||||
let custom_modules = custom_modules.iter().filter_map(|(custom_module, config)| {
|
.config
|
||||||
if should_add_implicit_custom_module(custom_module, config, module_list) {
|
.get_config(&[module])
|
||||||
modules::custom::module(custom_module, context)
|
.and_then(|config| config.as_table().map(|t| t.iter()))
|
||||||
} else {
|
.into_iter()
|
||||||
None
|
.flatten()
|
||||||
|
{
|
||||||
|
// Some env var keys may be part of a top-level module definition
|
||||||
|
if module == "env_var" && !config.is_table() {
|
||||||
|
continue;
|
||||||
|
} else if should_add_implicit_module(module, child, config, module_list) {
|
||||||
|
modules.extend(modules::handle(&format!("{module}.{child}"), context));
|
||||||
}
|
}
|
||||||
});
|
|
||||||
modules.extend(custom_modules);
|
|
||||||
}
|
|
||||||
} else if let Some(module) = module.strip_prefix("custom.") {
|
|
||||||
// Write out a custom module if it isn't disabled (and it exists...)
|
|
||||||
match context.is_custom_module_disabled_in_config(module) {
|
|
||||||
Some(true) => (), // Module is disabled, we don't add it to the prompt
|
|
||||||
Some(false) => modules.extend(modules::custom::module(module, context)),
|
|
||||||
None => match context.config.get_custom_modules() {
|
|
||||||
Some(modules) => log::debug!(
|
|
||||||
"top level format contains custom module \"{}\", but no configuration was provided. Configuration for the following modules were provided: {:?}",
|
|
||||||
module,
|
|
||||||
DebugCustomModules(modules),
|
|
||||||
),
|
|
||||||
None => log::debug!(
|
|
||||||
"top level format contains custom module \"{}\", but no configuration was provided.",
|
|
||||||
module,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log::debug!(
|
log::debug!(
|
||||||
@ -368,12 +355,13 @@ fn handle_module<'a>(
|
|||||||
modules
|
modules
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_add_implicit_custom_module(
|
fn should_add_implicit_module(
|
||||||
custom_module: &str,
|
parent_module: &str,
|
||||||
|
child_module: &str,
|
||||||
config: &toml::Value,
|
config: &toml::Value,
|
||||||
module_list: &BTreeSet<String>,
|
module_list: &BTreeSet<String>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let explicit_module_name = format!("custom.{custom_module}");
|
let explicit_module_name = format!("{parent_module}.{child_module}");
|
||||||
let is_explicitly_specified = module_list.contains(&explicit_module_name);
|
let is_explicitly_specified = module_list.contains(&explicit_module_name);
|
||||||
|
|
||||||
if is_explicitly_specified {
|
if is_explicitly_specified {
|
||||||
@ -539,4 +527,153 @@ mod test {
|
|||||||
fn print_schema_does_not_panic() {
|
fn print_schema_does_not_panic() {
|
||||||
print_schema();
|
print_schema();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn custom_expands() -> std::io::Result<()> {
|
||||||
|
let dir = tempfile::tempdir()?;
|
||||||
|
let mut context = default_context();
|
||||||
|
context.current_dir = dir.path().to_path_buf();
|
||||||
|
context.config = StarshipConfig {
|
||||||
|
config: Some(toml::toml! {
|
||||||
|
format="$custom"
|
||||||
|
[custom.a]
|
||||||
|
when=true
|
||||||
|
format="a"
|
||||||
|
[custom.b]
|
||||||
|
when=true
|
||||||
|
format="b"
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
context.root_config.format = "$custom".to_string();
|
||||||
|
|
||||||
|
let expected = String::from("\nab");
|
||||||
|
let actual = get_prompt(context);
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
dir.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn env_expands() {
|
||||||
|
let mut context = default_context();
|
||||||
|
context.config = StarshipConfig {
|
||||||
|
config: Some(toml::toml! {
|
||||||
|
format="$env_var"
|
||||||
|
[env_var]
|
||||||
|
format="$env_value"
|
||||||
|
variable = "a"
|
||||||
|
[env_var.b]
|
||||||
|
format="$env_value"
|
||||||
|
[env_var.c]
|
||||||
|
format="$env_value"
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
context.root_config.format = "$env_var".to_string();
|
||||||
|
context.env.insert("a", "a".to_string());
|
||||||
|
context.env.insert("b", "b".to_string());
|
||||||
|
context.env.insert("c", "c".to_string());
|
||||||
|
|
||||||
|
let expected = String::from("\nabc");
|
||||||
|
let actual = get_prompt(context);
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn custom_mixed() -> std::io::Result<()> {
|
||||||
|
let dir = tempfile::tempdir()?;
|
||||||
|
let mut context = default_context();
|
||||||
|
context.current_dir = dir.path().to_path_buf();
|
||||||
|
context.config = StarshipConfig {
|
||||||
|
config: Some(toml::toml! {
|
||||||
|
format="${custom.c}$custom${custom.b}"
|
||||||
|
[custom.a]
|
||||||
|
when=true
|
||||||
|
format="a"
|
||||||
|
[custom.b]
|
||||||
|
when=true
|
||||||
|
format="b"
|
||||||
|
[custom.c]
|
||||||
|
when=true
|
||||||
|
format="c"
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
context.root_config.format = "${custom.c}$custom${custom.b}".to_string();
|
||||||
|
|
||||||
|
let expected = String::from("\ncab");
|
||||||
|
let actual = get_prompt(context);
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
dir.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn env_mixed() {
|
||||||
|
let mut context = default_context();
|
||||||
|
context.config = StarshipConfig {
|
||||||
|
config: Some(toml::toml! {
|
||||||
|
format="${env_var.c}$env_var${env_var.b}"
|
||||||
|
[env_var]
|
||||||
|
format="$env_value"
|
||||||
|
variable = "d"
|
||||||
|
[env_var.a]
|
||||||
|
format="$env_value"
|
||||||
|
[env_var.b]
|
||||||
|
format="$env_value"
|
||||||
|
[env_var.c]
|
||||||
|
format="$env_value"
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
context.root_config.format = "${env_var.c}$env_var${env_var.b}".to_string();
|
||||||
|
context.env.insert("a", "a".to_string());
|
||||||
|
context.env.insert("b", "b".to_string());
|
||||||
|
context.env.insert("c", "c".to_string());
|
||||||
|
context.env.insert("d", "d".to_string());
|
||||||
|
|
||||||
|
let expected = String::from("\ncdab");
|
||||||
|
let actual = get_prompt(context);
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn custom_subset() -> std::io::Result<()> {
|
||||||
|
let dir = tempfile::tempdir()?;
|
||||||
|
let mut context = default_context();
|
||||||
|
context.current_dir = dir.path().to_path_buf();
|
||||||
|
context.config = StarshipConfig {
|
||||||
|
config: Some(toml::toml! {
|
||||||
|
format="${custom.b}"
|
||||||
|
[custom.a]
|
||||||
|
when=true
|
||||||
|
format="a"
|
||||||
|
[custom.b]
|
||||||
|
when=true
|
||||||
|
format="b"
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
context.root_config.format = "${custom.b}".to_string();
|
||||||
|
|
||||||
|
let expected = String::from("\nb");
|
||||||
|
let actual = get_prompt(context);
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
dir.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn custom_missing() -> std::io::Result<()> {
|
||||||
|
let dir = tempfile::tempdir()?;
|
||||||
|
let mut context = default_context();
|
||||||
|
context.current_dir = dir.path().to_path_buf();
|
||||||
|
context.config = StarshipConfig {
|
||||||
|
config: Some(toml::toml! {
|
||||||
|
format="${custom.b}"
|
||||||
|
[custom.a]
|
||||||
|
when=true
|
||||||
|
format="a"
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
context.root_config.format = "${custom.b}".to_string();
|
||||||
|
|
||||||
|
let expected = String::from("\n");
|
||||||
|
let actual = get_prompt(context);
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
dir.close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user