mirror of
https://github.com/Llewellynvdm/starship.git
synced 2024-12-01 01:04:00 +00:00
feat: refactor modules to use format strings (#1374)
This commit is contained in:
parent
0f52b7b12e
commit
ec76fafff0
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -867,6 +867,15 @@ version = "1.2.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quick-xml"
|
||||||
|
version = "0.18.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3cc440ee4802a86e357165021e3e255a9143724da31db1e2ea540214c96a0f82"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
@ -1151,6 +1160,7 @@ dependencies = [
|
|||||||
"pest",
|
"pest",
|
||||||
"pest_derive",
|
"pest_derive",
|
||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
|
"quick-xml",
|
||||||
"rayon",
|
"rayon",
|
||||||
"regex",
|
"regex",
|
||||||
"remove_dir_all",
|
"remove_dir_all",
|
||||||
|
@ -59,6 +59,7 @@ open = "1.4.0"
|
|||||||
unicode-width = "0.1.8"
|
unicode-width = "0.1.8"
|
||||||
textwrap = "0.12.1"
|
textwrap = "0.12.1"
|
||||||
term_size = "0.3.2"
|
term_size = "0.3.2"
|
||||||
|
quick-xml = "0.18.1"
|
||||||
|
|
||||||
# Optional/http:
|
# Optional/http:
|
||||||
attohttpc = { version = "0.15.0", optional = true, default-features = false, features = ["tls", "form"] }
|
attohttpc = { version = "0.15.0", optional = true, default-features = false, features = ["tls", "form"] }
|
||||||
|
File diff suppressed because it is too large
Load Diff
130
src/config.rs
130
src/config.rs
@ -235,37 +235,84 @@ impl StarshipConfig {
|
|||||||
|
|
||||||
/// Get the subset of the table for a module by its name
|
/// Get the subset of the table for a module by its name
|
||||||
pub fn get_module_config(&self, module_name: &str) -> Option<&Value> {
|
pub fn get_module_config(&self, module_name: &str) -> Option<&Value> {
|
||||||
let module_config = self.config.as_ref()?.as_table()?.get(module_name);
|
let module_config = self.get_config(&[module_name]);
|
||||||
if module_config.is_some() {
|
if module_config.is_some() {
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"Config found for \"{}\": \n{:?}",
|
"Config found for \"{}\": \n{:?}",
|
||||||
&module_name,
|
&module_name,
|
||||||
&module_config
|
&module_config
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
log::trace!("No config found for \"{}\"", &module_name);
|
|
||||||
}
|
}
|
||||||
module_config
|
module_config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the value of the config in a specific path
|
||||||
|
pub fn get_config(&self, path: &[&str]) -> Option<&Value> {
|
||||||
|
let mut prev_table = self.config.as_ref()?.as_table()?;
|
||||||
|
|
||||||
|
assert_ne!(
|
||||||
|
path.len(),
|
||||||
|
0,
|
||||||
|
"Starship::get_config called with an empty path"
|
||||||
|
);
|
||||||
|
|
||||||
|
let (table_options, _) = path.split_at(path.len() - 1);
|
||||||
|
|
||||||
|
// Assumes all keys except the last in path has a table
|
||||||
|
for option in table_options {
|
||||||
|
match prev_table.get(*option) {
|
||||||
|
Some(value) => match value.as_table() {
|
||||||
|
Some(value) => {
|
||||||
|
prev_table = value;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
log::trace!(
|
||||||
|
"No config found for \"{}\": \"{}\" is not a table",
|
||||||
|
path.join("."),
|
||||||
|
&option
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
log::trace!(
|
||||||
|
"No config found for \"{}\": Option \"{}\" not found",
|
||||||
|
path.join("."),
|
||||||
|
&option
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let last_option = path.last().unwrap();
|
||||||
|
let value = prev_table.get(*last_option);
|
||||||
|
if value.is_none() {
|
||||||
|
log::trace!(
|
||||||
|
"No config found for \"{}\": Option \"{}\" not found",
|
||||||
|
path.join("."),
|
||||||
|
&last_option
|
||||||
|
);
|
||||||
|
};
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the subset of the table for a custom module by its name
|
/// Get the subset of the table for a custom module by its name
|
||||||
pub fn get_custom_module_config(&self, module_name: &str) -> Option<&Value> {
|
pub fn get_custom_module_config(&self, module_name: &str) -> Option<&Value> {
|
||||||
let module_config = self.get_custom_modules()?.get(module_name);
|
let module_config = self.get_config(&["custom", module_name]);
|
||||||
if module_config.is_some() {
|
if module_config.is_some() {
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"Custom config found for \"{}\": \n{:?}",
|
"Custom config found for \"{}\": \n{:?}",
|
||||||
&module_name,
|
&module_name,
|
||||||
&module_config
|
&module_config
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
log::trace!("No custom config found for \"{}\"", &module_name);
|
|
||||||
}
|
}
|
||||||
module_config
|
module_config
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the table of all the registered custom modules, if any
|
/// Get the table of all the registered custom modules, if any
|
||||||
pub fn get_custom_modules(&self) -> Option<&toml::value::Table> {
|
pub fn get_custom_modules(&self) -> Option<&toml::value::Table> {
|
||||||
self.config.as_ref()?.as_table()?.get("custom")?.as_table()
|
self.get_config(&["custom"])?.as_table()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_root_config(&self) -> StarshipRootConfig {
|
pub fn get_root_config(&self) -> StarshipRootConfig {
|
||||||
@ -277,75 +324,6 @@ impl StarshipConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct SegmentConfig<'a> {
|
|
||||||
pub value: &'a str,
|
|
||||||
pub style: Option<Style>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ModuleConfig<'a> for SegmentConfig<'a> {
|
|
||||||
fn from_config(config: &'a Value) -> Option<Self> {
|
|
||||||
match config {
|
|
||||||
Value::String(ref config_str) => Some(Self {
|
|
||||||
value: config_str,
|
|
||||||
style: None,
|
|
||||||
}),
|
|
||||||
Value::Table(ref config_table) => Some(Self {
|
|
||||||
value: config_table.get("value")?.as_str()?,
|
|
||||||
style: config_table.get("style").and_then(<Style>::from_config),
|
|
||||||
}),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_config(&self, config: &'a Value) -> Self {
|
|
||||||
let mut new_config = self.clone();
|
|
||||||
match config {
|
|
||||||
Value::String(ref config_str) => {
|
|
||||||
new_config.value = config_str;
|
|
||||||
}
|
|
||||||
Value::Table(ref config_table) => {
|
|
||||||
if let Some(Value::String(value)) = config_table.get("value") {
|
|
||||||
new_config.value = value;
|
|
||||||
};
|
|
||||||
if let Some(style) = config_table.get("style") {
|
|
||||||
new_config.style = <Style>::from_config(style);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
new_config
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> SegmentConfig<'a> {
|
|
||||||
pub fn new(value: &'a str) -> Self {
|
|
||||||
Self { value, style: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Immutably set value
|
|
||||||
pub fn with_value(&self, value: &'a str) -> Self {
|
|
||||||
Self {
|
|
||||||
value,
|
|
||||||
style: self.style,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Immutably set style
|
|
||||||
pub fn with_style(&self, style: Option<Style>) -> Self {
|
|
||||||
Self {
|
|
||||||
value: self.value,
|
|
||||||
style,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for SegmentConfig<'static> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new("")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Parse a style string which represents an ansi style. Valid tokens in the style
|
/** Parse a style string which represents an ansi style. Valid tokens in the style
|
||||||
string include the following:
|
string include the following:
|
||||||
- 'fg:<color>' (specifies that the color read should be a foreground color)
|
- 'fg:<color>' (specifies that the color read should be a foreground color)
|
||||||
|
@ -1,48 +1,24 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
use std::collections::HashMap;
|
||||||
#[derive(Clone, PartialEq)]
|
|
||||||
pub enum AwsItems {
|
|
||||||
All,
|
|
||||||
Region,
|
|
||||||
Profile,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct AwsConfig<'a> {
|
pub struct AwsConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
pub profile: SegmentConfig<'a>,
|
pub symbol: &'a str,
|
||||||
pub region: SegmentConfig<'a>,
|
pub style: &'a str,
|
||||||
pub style: Style,
|
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
pub displayed_items: AwsItems,
|
|
||||||
pub region_aliases: HashMap<String, &'a str>,
|
pub region_aliases: HashMap<String, &'a str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for AwsConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for AwsConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
AwsConfig {
|
AwsConfig {
|
||||||
symbol: SegmentConfig::new("☁️ "),
|
format: "on [$symbol$profile(\\($region\\))]($style) ",
|
||||||
profile: SegmentConfig::default(),
|
symbol: "☁️ ",
|
||||||
region: SegmentConfig::default(),
|
style: "bold yellow",
|
||||||
style: Color::Yellow.bold(),
|
|
||||||
disabled: false,
|
disabled: false,
|
||||||
displayed_items: AwsItems::All,
|
|
||||||
region_aliases: HashMap::new(),
|
region_aliases: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ModuleConfig<'a> for AwsItems {
|
|
||||||
fn from_config(config: &toml::Value) -> Option<Self> {
|
|
||||||
match config.as_str()? {
|
|
||||||
"all" => Some(AwsItems::All),
|
|
||||||
"region" => Some(AwsItems::Region),
|
|
||||||
"profile" => Some(AwsItems::Profile),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,40 +1,39 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct BatteryConfig<'a> {
|
pub struct BatteryConfig<'a> {
|
||||||
pub full_symbol: SegmentConfig<'a>,
|
pub full_symbol: &'a str,
|
||||||
pub charging_symbol: SegmentConfig<'a>,
|
pub charging_symbol: &'a str,
|
||||||
pub discharging_symbol: SegmentConfig<'a>,
|
pub discharging_symbol: &'a str,
|
||||||
pub unknown_symbol: Option<SegmentConfig<'a>>,
|
pub unknown_symbol: Option<&'a str>,
|
||||||
pub empty_symbol: Option<SegmentConfig<'a>>,
|
pub empty_symbol: Option<&'a str>,
|
||||||
pub display: Vec<BatteryDisplayConfig>,
|
pub display: Vec<BatteryDisplayConfig<'a>>,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
pub percentage: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for BatteryConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for BatteryConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
BatteryConfig {
|
BatteryConfig {
|
||||||
full_symbol: SegmentConfig::new("•"),
|
full_symbol: "•",
|
||||||
charging_symbol: SegmentConfig::new("↑"),
|
charging_symbol: "↑",
|
||||||
discharging_symbol: SegmentConfig::new("↓"),
|
discharging_symbol: "↓",
|
||||||
unknown_symbol: None,
|
unknown_symbol: None,
|
||||||
empty_symbol: None,
|
empty_symbol: None,
|
||||||
|
format: "[$symbol$percentage]($style) ",
|
||||||
display: vec![BatteryDisplayConfig {
|
display: vec![BatteryDisplayConfig {
|
||||||
threshold: 10,
|
threshold: 10,
|
||||||
style: Color::Red.bold(),
|
style: "red bold",
|
||||||
}],
|
}],
|
||||||
disabled: false,
|
disabled: false,
|
||||||
percentage: SegmentConfig::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct BatteryDisplayConfig {
|
pub struct BatteryDisplayConfig<'a> {
|
||||||
pub threshold: i64,
|
pub threshold: i64,
|
||||||
pub style: Style,
|
pub style: &'a str,
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,23 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct CharacterConfig<'a> {
|
pub struct CharacterConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
pub error_symbol: SegmentConfig<'a>,
|
pub success_symbol: &'a str,
|
||||||
pub vicmd_symbol: SegmentConfig<'a>,
|
pub error_symbol: &'a str,
|
||||||
pub use_symbol_for_status: bool,
|
pub vicmd_symbol: &'a str,
|
||||||
pub style_success: Style,
|
|
||||||
pub style_failure: Style,
|
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for CharacterConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for CharacterConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
CharacterConfig {
|
CharacterConfig {
|
||||||
symbol: SegmentConfig::new("❯"),
|
format: "$symbol ",
|
||||||
error_symbol: SegmentConfig::new("✖"),
|
success_symbol: "[❯](bold green)",
|
||||||
vicmd_symbol: SegmentConfig::new("❮"),
|
error_symbol: "[❯](bold red)",
|
||||||
use_symbol_for_status: false,
|
vicmd_symbol: "[❮](bold green)",
|
||||||
style_success: Color::Green.bold(),
|
|
||||||
style_failure: Color::Red.bold(),
|
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct CmdDurationConfig<'a> {
|
pub struct CmdDurationConfig<'a> {
|
||||||
pub min_time: i64,
|
pub min_time: i64,
|
||||||
pub prefix: &'a str,
|
pub format: &'a str,
|
||||||
pub style: Style,
|
pub style: &'a str,
|
||||||
pub show_milliseconds: bool,
|
pub show_milliseconds: bool,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
@ -16,9 +15,9 @@ impl<'a> RootModuleConfig<'a> for CmdDurationConfig<'a> {
|
|||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
CmdDurationConfig {
|
CmdDurationConfig {
|
||||||
min_time: 2_000,
|
min_time: 2_000,
|
||||||
prefix: "took ",
|
format: "took [$duration]($style) ",
|
||||||
show_milliseconds: false,
|
show_milliseconds: false,
|
||||||
style: Color::Yellow.bold(),
|
style: "yellow bold",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct CondaConfig<'a> {
|
pub struct CondaConfig<'a> {
|
||||||
pub truncation_length: usize,
|
pub truncation_length: usize,
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
pub environment: SegmentConfig<'a>,
|
pub symbol: &'a str,
|
||||||
pub style: Style,
|
pub style: &'a str,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,15 +15,9 @@ impl<'a> RootModuleConfig<'a> for CondaConfig<'a> {
|
|||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
CondaConfig {
|
CondaConfig {
|
||||||
truncation_length: 1,
|
truncation_length: 1,
|
||||||
symbol: SegmentConfig {
|
format: "via [$symbol$environment]($style) ",
|
||||||
value: "C ",
|
symbol: "🅒 ",
|
||||||
style: None,
|
style: "green bold",
|
||||||
},
|
|
||||||
environment: SegmentConfig {
|
|
||||||
value: "",
|
|
||||||
style: None,
|
|
||||||
},
|
|
||||||
style: Color::Green.bold(),
|
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,21 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct CrystalConfig<'a> {
|
pub struct CrystalConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
pub style: Style,
|
pub symbol: &'a str,
|
||||||
|
pub style: &'a str,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for CrystalConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for CrystalConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
CrystalConfig {
|
CrystalConfig {
|
||||||
symbol: SegmentConfig::new("🔮 "),
|
format: "via [$symbol$version]($style) ",
|
||||||
style: Color::Red.bold(),
|
symbol: "🔮 ",
|
||||||
|
style: "bold red",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig, VecOr};
|
use crate::config::{ModuleConfig, RootModuleConfig, VecOr};
|
||||||
|
|
||||||
use ansi_term::Style;
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, Default, PartialEq)]
|
#[derive(Clone, Default, PartialEq)]
|
||||||
@ -14,15 +13,14 @@ pub struct Directories<'a>(pub Vec<&'a str>);
|
|||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct CustomConfig<'a> {
|
pub struct CustomConfig<'a> {
|
||||||
pub symbol: Option<SegmentConfig<'a>>,
|
pub format: &'a str,
|
||||||
|
pub symbol: &'a str,
|
||||||
pub command: &'a str,
|
pub command: &'a str,
|
||||||
pub when: Option<&'a str>,
|
pub when: Option<&'a str>,
|
||||||
pub shell: VecOr<&'a str>,
|
pub shell: VecOr<&'a str>,
|
||||||
pub description: &'a str,
|
pub description: &'a str,
|
||||||
pub style: Option<Style>,
|
pub style: &'a str,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
pub prefix: Option<&'a str>,
|
|
||||||
pub suffix: Option<&'a str>,
|
|
||||||
pub files: Files<'a>,
|
pub files: Files<'a>,
|
||||||
pub extensions: Extensions<'a>,
|
pub extensions: Extensions<'a>,
|
||||||
pub directories: Directories<'a>,
|
pub directories: Directories<'a>,
|
||||||
@ -31,15 +29,14 @@ pub struct CustomConfig<'a> {
|
|||||||
impl<'a> RootModuleConfig<'a> for CustomConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for CustomConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
CustomConfig {
|
CustomConfig {
|
||||||
symbol: None,
|
format: "[$symbol$output]($style) ",
|
||||||
|
symbol: "",
|
||||||
command: "",
|
command: "",
|
||||||
when: None,
|
when: None,
|
||||||
shell: VecOr::default(),
|
shell: VecOr::default(),
|
||||||
description: "<custom config>",
|
description: "<custom config>",
|
||||||
style: None,
|
style: "green bold",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
prefix: None,
|
|
||||||
suffix: None,
|
|
||||||
files: Files::default(),
|
files: Files::default(),
|
||||||
extensions: Extensions::default(),
|
extensions: Extensions::default(),
|
||||||
directories: Directories::default(),
|
directories: Directories::default(),
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
@ -11,8 +10,8 @@ pub struct DirectoryConfig<'a> {
|
|||||||
pub substitutions: HashMap<String, &'a str>,
|
pub substitutions: HashMap<String, &'a str>,
|
||||||
pub fish_style_pwd_dir_length: i64,
|
pub fish_style_pwd_dir_length: i64,
|
||||||
pub use_logical_path: bool,
|
pub use_logical_path: bool,
|
||||||
pub prefix: &'a str,
|
pub format: &'a str,
|
||||||
pub style: Style,
|
pub style: &'a str,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,8 +23,8 @@ impl<'a> RootModuleConfig<'a> for DirectoryConfig<'a> {
|
|||||||
fish_style_pwd_dir_length: 0,
|
fish_style_pwd_dir_length: 0,
|
||||||
substitutions: HashMap::new(),
|
substitutions: HashMap::new(),
|
||||||
use_logical_path: true,
|
use_logical_path: true,
|
||||||
prefix: "in ",
|
format: "[$path]($style) ",
|
||||||
style: Color::Cyan.bold(),
|
style: "cyan bold",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct DockerContextConfig<'a> {
|
pub struct DockerContextConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub symbol: &'a str,
|
||||||
pub context: SegmentConfig<'a>,
|
pub style: &'a str,
|
||||||
pub style: Style,
|
pub format: &'a str,
|
||||||
pub only_with_files: bool,
|
pub only_with_files: bool,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
@ -15,9 +14,9 @@ pub struct DockerContextConfig<'a> {
|
|||||||
impl<'a> RootModuleConfig<'a> for DockerContextConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for DockerContextConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
DockerContextConfig {
|
DockerContextConfig {
|
||||||
symbol: SegmentConfig::new("🐳 "),
|
symbol: "🐳 ",
|
||||||
context: SegmentConfig::default(),
|
style: "blue bold",
|
||||||
style: Color::Blue.bold(),
|
format: "via [$symbol$context]($style) ",
|
||||||
only_with_files: true,
|
only_with_files: true,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,24 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
use starship_module_config_derive::ModuleConfig;
|
||||||
use starship_module_config_derive::ModuleConfig;
|
|
||||||
|
#[derive(Clone, ModuleConfig)]
|
||||||
#[derive(Clone, ModuleConfig)]
|
pub struct DotnetConfig<'a> {
|
||||||
pub struct DotnetConfig<'a> {
|
pub format: &'a str,
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub symbol: &'a str,
|
||||||
pub version: SegmentConfig<'a>,
|
pub style: &'a str,
|
||||||
pub style: Style,
|
pub heuristic: bool,
|
||||||
pub heuristic: bool,
|
pub disabled: bool,
|
||||||
pub disabled: bool,
|
}
|
||||||
}
|
|
||||||
|
impl<'a> RootModuleConfig<'a> for DotnetConfig<'a> {
|
||||||
impl<'a> RootModuleConfig<'a> for DotnetConfig<'a> {
|
fn new() -> Self {
|
||||||
fn new() -> Self {
|
DotnetConfig {
|
||||||
DotnetConfig {
|
format: "[$symbol$version( 🎯 $tfm)]($style) ",
|
||||||
symbol: SegmentConfig::new("•NET "),
|
symbol: "•NET ",
|
||||||
version: SegmentConfig::default(),
|
style: "blue bold",
|
||||||
style: Color::Blue.bold(),
|
heuristic: true,
|
||||||
heuristic: true,
|
disabled: false,
|
||||||
disabled: false,
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -1,24 +1,21 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct ElixirConfig<'a> {
|
pub struct ElixirConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
pub version: SegmentConfig<'a>,
|
pub symbol: &'a str,
|
||||||
pub otp_version: SegmentConfig<'a>,
|
pub style: &'a str,
|
||||||
pub style: Style,
|
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for ElixirConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for ElixirConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
ElixirConfig {
|
ElixirConfig {
|
||||||
symbol: SegmentConfig::new("💧 "),
|
format: "via [$symbol$version \\(OTP $otp_version\\)]($style) ",
|
||||||
version: SegmentConfig::default(),
|
symbol: "💧 ",
|
||||||
otp_version: SegmentConfig::default(),
|
style: "bold purple",
|
||||||
style: Color::Purple.bold(),
|
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,21 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct ElmConfig<'a> {
|
pub struct ElmConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
pub version: SegmentConfig<'a>,
|
pub symbol: &'a str,
|
||||||
pub style: Style,
|
pub style: &'a str,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for ElmConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for ElmConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
ElmConfig {
|
ElmConfig {
|
||||||
symbol: SegmentConfig::new("🌳 "),
|
format: "via [$symbol$version]($style) ",
|
||||||
version: SegmentConfig::default(),
|
symbol: "🌳 ",
|
||||||
style: Color::Cyan.bold(),
|
style: "cyan bold",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,25 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct EnvVarConfig<'a> {
|
pub struct EnvVarConfig<'a> {
|
||||||
pub symbol: Option<SegmentConfig<'a>>,
|
pub symbol: &'a str,
|
||||||
|
pub style: &'a str,
|
||||||
pub variable: Option<&'a str>,
|
pub variable: Option<&'a str>,
|
||||||
pub default: Option<&'a str>,
|
pub default: Option<&'a str>,
|
||||||
pub prefix: &'a str,
|
pub format: &'a str,
|
||||||
pub suffix: &'a str,
|
|
||||||
pub style: Style,
|
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for EnvVarConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for EnvVarConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
EnvVarConfig {
|
EnvVarConfig {
|
||||||
symbol: None,
|
symbol: "",
|
||||||
|
style: "black bold dimmed",
|
||||||
variable: None,
|
variable: None,
|
||||||
default: None,
|
default: None,
|
||||||
prefix: "",
|
format: "with [$env_value]($style) ",
|
||||||
suffix: "",
|
|
||||||
style: Color::Black.bold().dimmed(),
|
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,21 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct ErlangConfig<'a> {
|
pub struct ErlangConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
pub version: SegmentConfig<'a>,
|
pub symbol: &'a str,
|
||||||
pub style: Style,
|
pub style: &'a str,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for ErlangConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for ErlangConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
ErlangConfig {
|
ErlangConfig {
|
||||||
symbol: SegmentConfig::new("🖧 "),
|
format: "via [$symbol$version]($style) ",
|
||||||
version: SegmentConfig::default(),
|
symbol: "🖧 ",
|
||||||
style: Color::Red.bold(),
|
style: "bold red",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,25 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct GitBranchConfig<'a> {
|
pub struct GitBranchConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
|
pub symbol: &'a str,
|
||||||
|
pub style: &'a str,
|
||||||
pub truncation_length: i64,
|
pub truncation_length: i64,
|
||||||
pub truncation_symbol: &'a str,
|
pub truncation_symbol: &'a str,
|
||||||
pub branch_name: SegmentConfig<'a>,
|
|
||||||
pub style: Style,
|
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for GitBranchConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for GitBranchConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
GitBranchConfig {
|
GitBranchConfig {
|
||||||
symbol: SegmentConfig::new(" "),
|
format: "on [$symbol$branch]($style) ",
|
||||||
|
symbol: " ",
|
||||||
|
style: "bold purple",
|
||||||
truncation_length: std::i64::MAX,
|
truncation_length: std::i64::MAX,
|
||||||
truncation_symbol: "…",
|
truncation_symbol: "…",
|
||||||
branch_name: SegmentConfig::default(),
|
|
||||||
style: Color::Purple.bold(),
|
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct GitCommitConfig<'a> {
|
pub struct GitCommitConfig<'a> {
|
||||||
pub commit_hash_length: usize,
|
pub commit_hash_length: usize,
|
||||||
pub hash: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
pub prefix: &'a str,
|
pub style: &'a str,
|
||||||
pub suffix: &'a str,
|
|
||||||
pub style: Style,
|
|
||||||
pub only_detached: bool,
|
pub only_detached: bool,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
@ -19,10 +16,8 @@ impl<'a> RootModuleConfig<'a> for GitCommitConfig<'a> {
|
|||||||
GitCommitConfig {
|
GitCommitConfig {
|
||||||
// be consistent with git by default, which has DEFAULT_ABBREV set to 7
|
// be consistent with git by default, which has DEFAULT_ABBREV set to 7
|
||||||
commit_hash_length: 7,
|
commit_hash_length: 7,
|
||||||
hash: SegmentConfig::default(),
|
format: "[\\($hash\\)]($style) ",
|
||||||
prefix: "(",
|
style: "green bold",
|
||||||
suffix: ") ",
|
|
||||||
style: Color::Green.bold(),
|
|
||||||
only_detached: true,
|
only_detached: true,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
|
@ -1,34 +1,33 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct GitStateConfig<'a> {
|
pub struct GitStateConfig<'a> {
|
||||||
pub rebase: SegmentConfig<'a>,
|
pub rebase: &'a str,
|
||||||
pub merge: SegmentConfig<'a>,
|
pub merge: &'a str,
|
||||||
pub revert: SegmentConfig<'a>,
|
pub revert: &'a str,
|
||||||
pub cherry_pick: SegmentConfig<'a>,
|
pub cherry_pick: &'a str,
|
||||||
pub bisect: SegmentConfig<'a>,
|
pub bisect: &'a str,
|
||||||
pub am: SegmentConfig<'a>,
|
pub am: &'a str,
|
||||||
pub am_or_rebase: SegmentConfig<'a>,
|
pub am_or_rebase: &'a str,
|
||||||
pub progress_divider: SegmentConfig<'a>,
|
pub style: &'a str,
|
||||||
pub style: Style,
|
pub format: &'a str,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for GitStateConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for GitStateConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
GitStateConfig {
|
GitStateConfig {
|
||||||
rebase: SegmentConfig::new("REBASING"),
|
rebase: "REBASING",
|
||||||
merge: SegmentConfig::new("MERGING"),
|
merge: "MERGING",
|
||||||
revert: SegmentConfig::new("REVERTING"),
|
revert: "REVERTING",
|
||||||
cherry_pick: SegmentConfig::new("CHERRY-PICKING"),
|
cherry_pick: "CHERRY-PICKING",
|
||||||
bisect: SegmentConfig::new("BISECTING"),
|
bisect: "BISECTING",
|
||||||
am: SegmentConfig::new("AM"),
|
am: "AM",
|
||||||
am_or_rebase: SegmentConfig::new("AM/REBASE"),
|
am_or_rebase: "AM/REBASE",
|
||||||
progress_divider: SegmentConfig::new("/"),
|
style: "bold yellow",
|
||||||
style: Color::Yellow.bold(),
|
format: "[\\($state( $progress_current/$progress_total)\\)]($style) ",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,65 +1,40 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct GitStatusConfig<'a> {
|
pub struct GitStatusConfig<'a> {
|
||||||
pub stashed: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
pub stashed_count: CountConfig,
|
pub style: &'a str,
|
||||||
pub ahead: SegmentConfig<'a>,
|
pub stashed: &'a str,
|
||||||
pub behind: SegmentConfig<'a>,
|
pub ahead: &'a str,
|
||||||
pub diverged: SegmentConfig<'a>,
|
pub behind: &'a str,
|
||||||
pub show_sync_count: bool,
|
pub diverged: &'a str,
|
||||||
pub conflicted: SegmentConfig<'a>,
|
pub conflicted: &'a str,
|
||||||
pub conflicted_count: CountConfig,
|
pub deleted: &'a str,
|
||||||
pub deleted: SegmentConfig<'a>,
|
pub renamed: &'a str,
|
||||||
pub deleted_count: CountConfig,
|
pub modified: &'a str,
|
||||||
pub renamed: SegmentConfig<'a>,
|
pub staged: &'a str,
|
||||||
pub renamed_count: CountConfig,
|
pub untracked: &'a str,
|
||||||
pub modified: SegmentConfig<'a>,
|
|
||||||
pub modified_count: CountConfig,
|
|
||||||
pub staged: SegmentConfig<'a>,
|
|
||||||
pub staged_count: CountConfig,
|
|
||||||
pub untracked: SegmentConfig<'a>,
|
|
||||||
pub untracked_count: CountConfig,
|
|
||||||
pub prefix: &'a str,
|
|
||||||
pub suffix: &'a str,
|
|
||||||
pub style: Style,
|
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for GitStatusConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for GitStatusConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
GitStatusConfig {
|
GitStatusConfig {
|
||||||
stashed: SegmentConfig::new("$"),
|
format: "([\\[$all_status$ahead_behind\\]]($style) )",
|
||||||
stashed_count: CountConfig::default(),
|
style: "red bold",
|
||||||
ahead: SegmentConfig::new("⇡"),
|
stashed: "\\$",
|
||||||
behind: SegmentConfig::new("⇣"),
|
ahead: "⇡",
|
||||||
diverged: SegmentConfig::new("⇕"),
|
behind: "⇣",
|
||||||
conflicted: SegmentConfig::new("="),
|
diverged: "⇕",
|
||||||
show_sync_count: false,
|
conflicted: "=",
|
||||||
conflicted_count: CountConfig::default(),
|
deleted: "✘",
|
||||||
deleted: SegmentConfig::new("✘"),
|
renamed: "»",
|
||||||
deleted_count: CountConfig::default(),
|
modified: "!",
|
||||||
renamed: SegmentConfig::new("»"),
|
staged: "+",
|
||||||
renamed_count: CountConfig::default(),
|
untracked: "?",
|
||||||
modified: SegmentConfig::new("!"),
|
|
||||||
modified_count: CountConfig::default(),
|
|
||||||
staged: SegmentConfig::new("+"),
|
|
||||||
staged_count: CountConfig::default(),
|
|
||||||
untracked: SegmentConfig::new("?"),
|
|
||||||
untracked_count: CountConfig::default(),
|
|
||||||
prefix: "[",
|
|
||||||
suffix: "] ",
|
|
||||||
style: Color::Red.bold(),
|
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, ModuleConfig, Default)]
|
|
||||||
pub struct CountConfig {
|
|
||||||
pub enabled: bool,
|
|
||||||
pub style: Option<Style>,
|
|
||||||
}
|
|
||||||
|
@ -1,22 +1,21 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct GoConfig<'a> {
|
pub struct GoConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
pub version: SegmentConfig<'a>,
|
pub symbol: &'a str,
|
||||||
pub style: Style,
|
pub style: &'a str,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for GoConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for GoConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
GoConfig {
|
GoConfig {
|
||||||
symbol: SegmentConfig::new("🐹 "),
|
format: "via [$symbol$version]($style) ",
|
||||||
version: SegmentConfig::default(),
|
symbol: "🐹 ",
|
||||||
style: Color::Cyan.bold(),
|
style: "bold cyan",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,25 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct HgBranchConfig<'a> {
|
pub struct HgBranchConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub symbol: &'a str,
|
||||||
|
pub style: &'a str,
|
||||||
|
pub format: &'a str,
|
||||||
pub truncation_length: i64,
|
pub truncation_length: i64,
|
||||||
pub truncation_symbol: &'a str,
|
pub truncation_symbol: &'a str,
|
||||||
pub branch_name: SegmentConfig<'a>,
|
|
||||||
pub style: Style,
|
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for HgBranchConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for HgBranchConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
HgBranchConfig {
|
HgBranchConfig {
|
||||||
symbol: SegmentConfig::new(" "),
|
symbol: " ",
|
||||||
|
style: "bold purple",
|
||||||
|
format: "on [$symbol$branch]($style) ",
|
||||||
truncation_length: std::i64::MAX,
|
truncation_length: std::i64::MAX,
|
||||||
truncation_symbol: "…",
|
truncation_symbol: "…",
|
||||||
branch_name: SegmentConfig::default(),
|
|
||||||
style: Color::Purple.bold(),
|
|
||||||
disabled: true,
|
disabled: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct HostnameConfig<'a> {
|
pub struct HostnameConfig<'a> {
|
||||||
pub ssh_only: bool,
|
pub ssh_only: bool,
|
||||||
pub prefix: &'a str,
|
|
||||||
pub suffix: &'a str,
|
|
||||||
pub trim_at: &'a str,
|
pub trim_at: &'a str,
|
||||||
pub style: Style,
|
pub format: &'a str,
|
||||||
|
pub style: &'a str,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,10 +15,9 @@ impl<'a> RootModuleConfig<'a> for HostnameConfig<'a> {
|
|||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
HostnameConfig {
|
HostnameConfig {
|
||||||
ssh_only: true,
|
ssh_only: true,
|
||||||
prefix: "",
|
|
||||||
suffix: "",
|
|
||||||
trim_at: ".",
|
trim_at: ".",
|
||||||
style: Color::Green.bold().dimmed(),
|
format: "on [$hostname]($style) ",
|
||||||
|
style: "green dimmed bold",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,22 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct JavaConfig<'a> {
|
pub struct JavaConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
|
||||||
pub style: Style,
|
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
|
pub format: &'a str,
|
||||||
|
pub style: &'a str,
|
||||||
|
pub symbol: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for JavaConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for JavaConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
JavaConfig {
|
JavaConfig {
|
||||||
symbol: SegmentConfig::new("☕ "),
|
format: "via [$symbol$version]($style) ",
|
||||||
style: Color::Red.dimmed(),
|
|
||||||
disabled: false,
|
disabled: false,
|
||||||
|
style: "red dimmed",
|
||||||
|
symbol: "☕ ",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,23 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct JobsConfig<'a> {
|
pub struct JobsConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
|
||||||
pub threshold: i64,
|
pub threshold: i64,
|
||||||
pub style: Style,
|
pub format: &'a str,
|
||||||
|
pub symbol: &'a str,
|
||||||
|
pub style: &'a str,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for JobsConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for JobsConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
JobsConfig {
|
JobsConfig {
|
||||||
symbol: SegmentConfig::new("✦"),
|
|
||||||
threshold: 1,
|
threshold: 1,
|
||||||
style: Color::Blue.bold(),
|
format: "[$symbol$number]($style) ",
|
||||||
|
symbol: "✦",
|
||||||
|
style: "bold blue",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,21 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct JuliaConfig<'a> {
|
pub struct JuliaConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
pub version: SegmentConfig<'a>,
|
pub symbol: &'a str,
|
||||||
pub style: Style,
|
pub style: &'a str,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for JuliaConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for JuliaConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
JuliaConfig {
|
JuliaConfig {
|
||||||
symbol: SegmentConfig::new("ஃ "),
|
format: "via [$symbol$version]($style) ",
|
||||||
version: SegmentConfig::default(),
|
symbol: "ஃ ",
|
||||||
style: Color::Purple.bold(),
|
style: "bold purple",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct KubernetesConfig<'a> {
|
pub struct KubernetesConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub symbol: &'a str,
|
||||||
pub context: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
pub namespace: SegmentConfig<'a>,
|
pub style: &'a str,
|
||||||
pub style: Style,
|
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
pub context_aliases: HashMap<String, &'a str>,
|
pub context_aliases: HashMap<String, &'a str>,
|
||||||
}
|
}
|
||||||
@ -17,10 +15,9 @@ pub struct KubernetesConfig<'a> {
|
|||||||
impl<'a> RootModuleConfig<'a> for KubernetesConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for KubernetesConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
KubernetesConfig {
|
KubernetesConfig {
|
||||||
symbol: SegmentConfig::new("☸ "),
|
symbol: "☸ ",
|
||||||
context: SegmentConfig::default(),
|
format: "on [$symbol$context( \\($namespace\\))]($style) ",
|
||||||
namespace: SegmentConfig::default(),
|
style: "cyan bold",
|
||||||
style: Color::Cyan.bold(),
|
|
||||||
disabled: true,
|
disabled: true,
|
||||||
context_aliases: HashMap::new(),
|
context_aliases: HashMap::new(),
|
||||||
}
|
}
|
||||||
|
@ -1,32 +1,23 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct MemoryConfig<'a> {
|
pub struct MemoryConfig<'a> {
|
||||||
pub show_percentage: bool,
|
|
||||||
pub show_swap: bool,
|
|
||||||
pub threshold: i64,
|
pub threshold: i64,
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
pub separator: SegmentConfig<'a>,
|
pub style: &'a str,
|
||||||
pub ram: SegmentConfig<'a>,
|
pub symbol: &'a str,
|
||||||
pub swap: SegmentConfig<'a>,
|
|
||||||
pub style: Style,
|
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for MemoryConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for MemoryConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
MemoryConfig {
|
MemoryConfig {
|
||||||
show_percentage: false,
|
|
||||||
show_swap: true,
|
|
||||||
threshold: 75,
|
threshold: 75,
|
||||||
symbol: SegmentConfig::new("🐏 "),
|
format: "via $symbol[$ram( | $swap)]($style) ",
|
||||||
separator: SegmentConfig::new(" | "),
|
style: "white bold dimmed",
|
||||||
ram: SegmentConfig::default(),
|
symbol: "🐏 ",
|
||||||
swap: SegmentConfig::default(),
|
|
||||||
style: Color::White.bold().dimmed(),
|
|
||||||
disabled: true,
|
disabled: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,21 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct NimConfig<'a> {
|
pub struct NimConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
pub version: SegmentConfig<'a>,
|
pub symbol: &'a str,
|
||||||
pub style: Style,
|
pub style: &'a str,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for NimConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for NimConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
NimConfig {
|
NimConfig {
|
||||||
symbol: SegmentConfig::new("👑 "),
|
format: "via [$symbol$version]($style) ",
|
||||||
version: SegmentConfig::default(),
|
symbol: "👑 ",
|
||||||
style: Color::Yellow.bold(),
|
style: "yellow bold",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,25 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct NixShellConfig<'a> {
|
pub struct NixShellConfig<'a> {
|
||||||
pub use_name: bool,
|
pub format: &'a str,
|
||||||
pub impure_msg: SegmentConfig<'a>,
|
pub symbol: &'a str,
|
||||||
pub pure_msg: SegmentConfig<'a>,
|
pub style: &'a str,
|
||||||
pub style: Style,
|
pub impure_msg: &'a str,
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub pure_msg: &'a str,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for NixShellConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for NixShellConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
NixShellConfig {
|
NixShellConfig {
|
||||||
use_name: false,
|
format: "via [$symbol$state( \\($name\\))]($style) ",
|
||||||
impure_msg: SegmentConfig::new("impure"),
|
symbol: "❄️ ",
|
||||||
pure_msg: SegmentConfig::new("pure"),
|
style: "bold blue",
|
||||||
style: Color::Blue.bold(),
|
impure_msg: "impure",
|
||||||
symbol: SegmentConfig::new("❄️ "),
|
pure_msg: "pure",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,21 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct NodejsConfig<'a> {
|
pub struct NodejsConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
pub style: Style,
|
pub symbol: &'a str,
|
||||||
|
pub style: &'a str,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for NodejsConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for NodejsConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
NodejsConfig {
|
NodejsConfig {
|
||||||
symbol: SegmentConfig::new("⬢ "),
|
format: "via [$symbol$version]($style) ",
|
||||||
style: Color::Green.bold(),
|
symbol: "⬢ ",
|
||||||
|
style: "bold green",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,21 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct OCamlConfig<'a> {
|
pub struct OCamlConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
pub version: SegmentConfig<'a>,
|
pub symbol: &'a str,
|
||||||
pub style: Style,
|
pub style: &'a str,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for OCamlConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for OCamlConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
OCamlConfig {
|
OCamlConfig {
|
||||||
symbol: SegmentConfig::new("🐫 "),
|
format: "via [$symbol$version]($style) ",
|
||||||
version: SegmentConfig::default(),
|
symbol: "🐫 ",
|
||||||
style: Color::Yellow.bold(),
|
style: "bold yellow",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct PackageConfig<'a> {
|
pub struct PackageConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
pub style: Style,
|
pub symbol: &'a str,
|
||||||
|
pub style: &'a str,
|
||||||
pub display_private: bool,
|
pub display_private: bool,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
@ -14,8 +14,9 @@ pub struct PackageConfig<'a> {
|
|||||||
impl<'a> RootModuleConfig<'a> for PackageConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for PackageConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
PackageConfig {
|
PackageConfig {
|
||||||
symbol: SegmentConfig::new("📦 "),
|
format: "is [$symbol$version]($style) ",
|
||||||
style: Color::Fixed(208).bold(),
|
symbol: "📦 ",
|
||||||
|
style: "208 bold",
|
||||||
display_private: false,
|
display_private: false,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,21 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct PhpConfig<'a> {
|
pub struct PhpConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub symbol: &'a str,
|
||||||
pub style: Style,
|
pub style: &'a str,
|
||||||
|
pub format: &'a str,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for PhpConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for PhpConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
PhpConfig {
|
PhpConfig {
|
||||||
symbol: SegmentConfig::new("🐘 "),
|
symbol: "🐘 ",
|
||||||
style: Color::Fixed(147).bold(),
|
style: "147 bold",
|
||||||
|
format: "via [$symbol$version]($style) ",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,21 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct PureScriptConfig<'a> {
|
pub struct PureScriptConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
pub version: SegmentConfig<'a>,
|
pub symbol: &'a str,
|
||||||
pub style: Style,
|
pub style: &'a str,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for PureScriptConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for PureScriptConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
PureScriptConfig {
|
PureScriptConfig {
|
||||||
symbol: SegmentConfig::new("<=> "),
|
format: "via [$symbol$version]($style) ",
|
||||||
version: SegmentConfig::default(),
|
symbol: "<=> ",
|
||||||
style: Color::White.bold(),
|
style: "bold white",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,27 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct PythonConfig<'a> {
|
pub struct PythonConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
|
||||||
pub version: SegmentConfig<'a>,
|
|
||||||
pub pyenv_prefix: SegmentConfig<'a>,
|
|
||||||
pub pyenv_version_name: bool,
|
pub pyenv_version_name: bool,
|
||||||
pub python_binary: &'a str,
|
pub python_binary: &'a str,
|
||||||
pub scan_for_pyfiles: bool,
|
pub scan_for_pyfiles: bool,
|
||||||
pub style: Style,
|
pub format: &'a str,
|
||||||
|
pub style: &'a str,
|
||||||
|
pub symbol: &'a str,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for PythonConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for PythonConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
PythonConfig {
|
PythonConfig {
|
||||||
symbol: SegmentConfig::new("🐍 "),
|
|
||||||
version: SegmentConfig::default(),
|
|
||||||
pyenv_prefix: SegmentConfig::new("pyenv "),
|
|
||||||
pyenv_version_name: false,
|
pyenv_version_name: false,
|
||||||
python_binary: "python",
|
python_binary: "python",
|
||||||
scan_for_pyfiles: true,
|
scan_for_pyfiles: true,
|
||||||
style: Color::Yellow.bold(),
|
format: "via [$symbol$version( \\($virtualenv\\))]($style) ",
|
||||||
|
style: "yellow bold",
|
||||||
|
symbol: "🐍 ",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,21 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct RubyConfig<'a> {
|
pub struct RubyConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
pub style: Style,
|
pub symbol: &'a str,
|
||||||
|
pub style: &'a str,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for RubyConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for RubyConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
RubyConfig {
|
RubyConfig {
|
||||||
symbol: SegmentConfig::new("💎 "),
|
format: "via [$symbol$version]($style) ",
|
||||||
style: Color::Red.bold(),
|
symbol: "💎 ",
|
||||||
|
style: "bold red",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,21 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct RustConfig<'a> {
|
pub struct RustConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
pub version: SegmentConfig<'a>,
|
pub symbol: &'a str,
|
||||||
pub style: Style,
|
pub style: &'a str,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for RustConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for RustConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
RustConfig {
|
RustConfig {
|
||||||
symbol: SegmentConfig::new("🦀 "),
|
format: "via [$symbol$version]($style) ",
|
||||||
version: SegmentConfig::default(),
|
symbol: "🦀 ",
|
||||||
style: Color::Red.bold(),
|
style: "bold red",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,21 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct SingularityConfig<'a> {
|
pub struct SingularityConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub symbol: &'a str,
|
||||||
pub label: &'a str,
|
pub format: &'a str,
|
||||||
pub prefix: &'a str,
|
pub style: &'a str,
|
||||||
pub suffix: &'a str,
|
|
||||||
pub style: Style,
|
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for SingularityConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for SingularityConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
SingularityConfig {
|
SingularityConfig {
|
||||||
symbol: SegmentConfig::default(),
|
format: "[$symbol\\[$env\\]]($style) ",
|
||||||
label: "",
|
symbol: "",
|
||||||
prefix: "[",
|
style: "blue bold dimmed",
|
||||||
suffix: "]",
|
|
||||||
style: Color::Blue.bold().dimmed(),
|
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,66 +4,66 @@ use starship_module_config_derive::ModuleConfig;
|
|||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct StarshipRootConfig<'a> {
|
pub struct StarshipRootConfig<'a> {
|
||||||
pub add_newline: bool,
|
pub format: &'a str,
|
||||||
pub prompt_order: Vec<&'a str>,
|
|
||||||
pub scan_timeout: u64,
|
pub scan_timeout: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// List of default prompt order
|
||||||
|
// NOTE: If this const value is changed then Default prompt order subheading inside
|
||||||
|
// prompt heading of config docs needs to be updated according to changes made here.
|
||||||
|
pub const PROMPT_ORDER: [&str; 42] = [
|
||||||
|
"username",
|
||||||
|
"hostname",
|
||||||
|
"singularity",
|
||||||
|
"kubernetes",
|
||||||
|
"directory",
|
||||||
|
"git_branch",
|
||||||
|
"git_commit",
|
||||||
|
"git_state",
|
||||||
|
"git_status",
|
||||||
|
"hg_branch",
|
||||||
|
"docker_context",
|
||||||
|
"package",
|
||||||
|
// ↓ Toolchain version modules ↓
|
||||||
|
// (Let's keep these sorted alphabetically)
|
||||||
|
"dotnet",
|
||||||
|
"elixir",
|
||||||
|
"elm",
|
||||||
|
"erlang",
|
||||||
|
"golang",
|
||||||
|
"java",
|
||||||
|
"julia",
|
||||||
|
"nim",
|
||||||
|
"nodejs",
|
||||||
|
"ocaml",
|
||||||
|
"php",
|
||||||
|
"purescript",
|
||||||
|
"python",
|
||||||
|
"ruby",
|
||||||
|
"rust",
|
||||||
|
"terraform",
|
||||||
|
"zig",
|
||||||
|
// ↑ Toolchain version modules ↑
|
||||||
|
"nix_shell",
|
||||||
|
"conda",
|
||||||
|
"memory_usage",
|
||||||
|
"aws",
|
||||||
|
"env_var",
|
||||||
|
"crystal",
|
||||||
|
"cmd_duration",
|
||||||
|
"custom",
|
||||||
|
"line_break",
|
||||||
|
"jobs",
|
||||||
|
#[cfg(feature = "battery")]
|
||||||
|
"battery",
|
||||||
|
"time",
|
||||||
|
"character",
|
||||||
|
];
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for StarshipRootConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for StarshipRootConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
StarshipRootConfig {
|
StarshipRootConfig {
|
||||||
add_newline: true,
|
format: "\n$all",
|
||||||
// List of default prompt order
|
|
||||||
// NOTE: If this const value is changed then Default prompt order subheading inside
|
|
||||||
// prompt heading of config docs needs to be updated according to changes made here.
|
|
||||||
prompt_order: vec![
|
|
||||||
"username",
|
|
||||||
"hostname",
|
|
||||||
"singularity",
|
|
||||||
"kubernetes",
|
|
||||||
"directory",
|
|
||||||
"git_branch",
|
|
||||||
"git_commit",
|
|
||||||
"git_state",
|
|
||||||
"git_status",
|
|
||||||
"hg_branch",
|
|
||||||
"docker_context",
|
|
||||||
"package",
|
|
||||||
// ↓ Toolchain version modules ↓
|
|
||||||
// (Let's keep these sorted alphabetically)
|
|
||||||
"dotnet",
|
|
||||||
"elixir",
|
|
||||||
"elm",
|
|
||||||
"erlang",
|
|
||||||
"golang",
|
|
||||||
"java",
|
|
||||||
"julia",
|
|
||||||
"nim",
|
|
||||||
"nodejs",
|
|
||||||
"ocaml",
|
|
||||||
"php",
|
|
||||||
"purescript",
|
|
||||||
"python",
|
|
||||||
"ruby",
|
|
||||||
"rust",
|
|
||||||
"terraform",
|
|
||||||
"zig",
|
|
||||||
// ↑ Toolchain version modules ↑
|
|
||||||
"nix_shell",
|
|
||||||
"conda",
|
|
||||||
"memory_usage",
|
|
||||||
"aws",
|
|
||||||
"env_var",
|
|
||||||
"crystal",
|
|
||||||
"cmd_duration",
|
|
||||||
"custom",
|
|
||||||
"line_break",
|
|
||||||
"jobs",
|
|
||||||
#[cfg(feature = "battery")]
|
|
||||||
"battery",
|
|
||||||
"time",
|
|
||||||
"character",
|
|
||||||
],
|
|
||||||
scan_timeout: 30,
|
scan_timeout: 30,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,21 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct TerraformConfig<'a> {
|
pub struct TerraformConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
pub workspace: SegmentConfig<'a>,
|
pub symbol: &'a str,
|
||||||
pub version: SegmentConfig<'a>,
|
pub style: &'a str,
|
||||||
pub show_version: bool,
|
|
||||||
pub style: Style,
|
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for TerraformConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for TerraformConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
TerraformConfig {
|
TerraformConfig {
|
||||||
symbol: SegmentConfig::new("💠 "),
|
format: "via [$symbol$workspace]($style) ",
|
||||||
workspace: SegmentConfig::default(),
|
symbol: "💠 ",
|
||||||
version: SegmentConfig::default(),
|
style: "bold 105",
|
||||||
show_version: false,
|
|
||||||
style: Color::Fixed(105).bold(),
|
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct TimeConfig<'a> {
|
pub struct TimeConfig<'a> {
|
||||||
|
pub format: &'a str,
|
||||||
|
pub style: &'a str,
|
||||||
pub use_12hr: bool,
|
pub use_12hr: bool,
|
||||||
pub format: Option<&'a str>,
|
pub time_format: Option<&'a str>,
|
||||||
pub style: Style,
|
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
pub utc_time_offset: &'a str,
|
pub utc_time_offset: &'a str,
|
||||||
pub time_range: &'a str,
|
pub time_range: &'a str,
|
||||||
@ -16,9 +16,10 @@ pub struct TimeConfig<'a> {
|
|||||||
impl<'a> RootModuleConfig<'a> for TimeConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for TimeConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
TimeConfig {
|
TimeConfig {
|
||||||
|
format: "at [$time]($style) ",
|
||||||
|
style: "bold yellow",
|
||||||
use_12hr: false,
|
use_12hr: false,
|
||||||
format: None,
|
time_format: None,
|
||||||
style: Color::Yellow.bold(),
|
|
||||||
disabled: true,
|
disabled: true,
|
||||||
utc_time_offset: "local",
|
utc_time_offset: "local",
|
||||||
time_range: "-",
|
time_range: "-",
|
||||||
|
@ -1,21 +1,22 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct UsernameConfig {
|
pub struct UsernameConfig<'a> {
|
||||||
pub style_root: Style,
|
pub format: &'a str,
|
||||||
pub style_user: Style,
|
pub style_root: &'a str,
|
||||||
|
pub style_user: &'a str,
|
||||||
pub show_always: bool,
|
pub show_always: bool,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for UsernameConfig {
|
impl<'a> RootModuleConfig<'a> for UsernameConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
UsernameConfig {
|
UsernameConfig {
|
||||||
style_root: Color::Red.bold(),
|
format: "via [$user]($style) ",
|
||||||
style_user: Color::Yellow.bold(),
|
style_root: "red bold",
|
||||||
|
style_user: "yellow bold",
|
||||||
show_always: false,
|
show_always: false,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,21 @@
|
|||||||
use crate::config::{ModuleConfig, RootModuleConfig, SegmentConfig};
|
use crate::config::{ModuleConfig, RootModuleConfig};
|
||||||
|
|
||||||
use ansi_term::{Color, Style};
|
|
||||||
use starship_module_config_derive::ModuleConfig;
|
use starship_module_config_derive::ModuleConfig;
|
||||||
|
|
||||||
#[derive(Clone, ModuleConfig)]
|
#[derive(Clone, ModuleConfig)]
|
||||||
pub struct ZigConfig<'a> {
|
pub struct ZigConfig<'a> {
|
||||||
pub symbol: SegmentConfig<'a>,
|
pub format: &'a str,
|
||||||
pub version: SegmentConfig<'a>,
|
pub symbol: &'a str,
|
||||||
pub style: Style,
|
pub style: &'a str,
|
||||||
pub disabled: bool,
|
pub disabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RootModuleConfig<'a> for ZigConfig<'a> {
|
impl<'a> RootModuleConfig<'a> for ZigConfig<'a> {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
ZigConfig {
|
ZigConfig {
|
||||||
symbol: SegmentConfig::new("↯ "),
|
format: "via [$symbol$version]($style) ",
|
||||||
version: SegmentConfig::default(),
|
symbol: "↯ ",
|
||||||
style: Color::Yellow.bold(),
|
style: "bold yellow",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,4 +2,5 @@ pub mod model;
|
|||||||
mod parser;
|
mod parser;
|
||||||
pub mod string_formatter;
|
pub mod string_formatter;
|
||||||
|
|
||||||
|
pub use model::{StyleVariableHolder, VariableHolder};
|
||||||
pub use string_formatter::StringFormatter;
|
pub use string_formatter::StringFormatter;
|
||||||
|
@ -1,17 +1,103 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
|
/// Type that holds a number of variables of type `T`
|
||||||
|
pub trait VariableHolder<T> {
|
||||||
|
fn get_variables(&self) -> BTreeSet<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Type that holds a number of style variables of type `T`
|
||||||
|
pub trait StyleVariableHolder<T> {
|
||||||
|
fn get_style_variables(&self) -> BTreeSet<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct TextGroup<'a> {
|
pub struct TextGroup<'a> {
|
||||||
pub format: Vec<FormatElement<'a>>,
|
pub format: Vec<FormatElement<'a>>,
|
||||||
pub style: Vec<StyleElement<'a>>,
|
pub style: Vec<StyleElement<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub enum FormatElement<'a> {
|
pub enum FormatElement<'a> {
|
||||||
Text(Cow<'a, str>),
|
Text(Cow<'a, str>),
|
||||||
Variable(Cow<'a, str>),
|
Variable(Cow<'a, str>),
|
||||||
TextGroup(TextGroup<'a>),
|
TextGroup(TextGroup<'a>),
|
||||||
|
Conditional(Vec<FormatElement<'a>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub enum StyleElement<'a> {
|
pub enum StyleElement<'a> {
|
||||||
Text(Cow<'a, str>),
|
Text(Cow<'a, str>),
|
||||||
Variable(Cow<'a, str>),
|
Variable(Cow<'a, str>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> VariableHolder<Cow<'a, str>> for FormatElement<'a> {
|
||||||
|
fn get_variables(&self) -> BTreeSet<Cow<'a, str>> {
|
||||||
|
match self {
|
||||||
|
FormatElement::Variable(var) => {
|
||||||
|
let mut variables = BTreeSet::new();
|
||||||
|
variables.insert(var.clone());
|
||||||
|
variables
|
||||||
|
}
|
||||||
|
FormatElement::TextGroup(textgroup) => textgroup.format.get_variables(),
|
||||||
|
FormatElement::Conditional(format) => format.get_variables(),
|
||||||
|
_ => Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> VariableHolder<Cow<'a, str>> for Vec<FormatElement<'a>> {
|
||||||
|
fn get_variables(&self) -> BTreeSet<Cow<'a, str>> {
|
||||||
|
self.iter().fold(BTreeSet::new(), |mut acc, el| {
|
||||||
|
acc.extend(el.get_variables());
|
||||||
|
acc
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> VariableHolder<Cow<'a, str>> for &[FormatElement<'a>] {
|
||||||
|
fn get_variables(&self) -> BTreeSet<Cow<'a, str>> {
|
||||||
|
self.iter().fold(BTreeSet::new(), |mut acc, el| {
|
||||||
|
acc.extend(el.get_variables());
|
||||||
|
acc
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> StyleVariableHolder<Cow<'a, str>> for StyleElement<'a> {
|
||||||
|
fn get_style_variables(&self) -> BTreeSet<Cow<'a, str>> {
|
||||||
|
match self {
|
||||||
|
StyleElement::Variable(var) => {
|
||||||
|
let mut variables = BTreeSet::new();
|
||||||
|
variables.insert(var.clone());
|
||||||
|
variables
|
||||||
|
}
|
||||||
|
_ => Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> StyleVariableHolder<Cow<'a, str>> for Vec<StyleElement<'a>> {
|
||||||
|
fn get_style_variables(&self) -> BTreeSet<Cow<'a, str>> {
|
||||||
|
self.iter().fold(BTreeSet::new(), |mut acc, el| {
|
||||||
|
acc.extend(el.get_style_variables());
|
||||||
|
acc
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> StyleVariableHolder<Cow<'a, str>> for Vec<FormatElement<'a>> {
|
||||||
|
fn get_style_variables(&self) -> BTreeSet<Cow<'a, str>> {
|
||||||
|
self.iter().fold(BTreeSet::new(), |mut acc, el| match el {
|
||||||
|
FormatElement::TextGroup(textgroup) => {
|
||||||
|
acc.extend(textgroup.style.get_style_variables());
|
||||||
|
acc
|
||||||
|
}
|
||||||
|
FormatElement::Conditional(format) => {
|
||||||
|
acc.extend(format.get_style_variables());
|
||||||
|
acc
|
||||||
|
}
|
||||||
|
_ => acc,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,6 +6,18 @@ use super::model::*;
|
|||||||
#[grammar = "formatter/spec.pest"]
|
#[grammar = "formatter/spec.pest"]
|
||||||
struct IdentParser;
|
struct IdentParser;
|
||||||
|
|
||||||
|
fn _parse_value(value: Pair<Rule>) -> FormatElement {
|
||||||
|
match value.as_rule() {
|
||||||
|
Rule::text => FormatElement::Text(_parse_text(value).into()),
|
||||||
|
Rule::variable => FormatElement::Variable(_parse_variable(value).into()),
|
||||||
|
Rule::textgroup => FormatElement::TextGroup(_parse_textgroup(value)),
|
||||||
|
Rule::conditional => {
|
||||||
|
FormatElement::Conditional(_parse_format(value.into_inner().next().unwrap()))
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn _parse_textgroup(textgroup: Pair<Rule>) -> TextGroup {
|
fn _parse_textgroup(textgroup: Pair<Rule>) -> TextGroup {
|
||||||
let mut inner_rules = textgroup.into_inner();
|
let mut inner_rules = textgroup.into_inner();
|
||||||
let format = inner_rules.next().unwrap();
|
let format = inner_rules.next().unwrap();
|
||||||
@ -22,55 +34,32 @@ fn _parse_variable(variable: Pair<Rule>) -> &str {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn _parse_text(text: Pair<Rule>) -> String {
|
fn _parse_text(text: Pair<Rule>) -> String {
|
||||||
let mut result = String::new();
|
text.into_inner()
|
||||||
for pair in text.into_inner() {
|
.map(|pair| pair.as_str().chars())
|
||||||
result.push_str(pair.as_str());
|
.flatten()
|
||||||
}
|
.collect()
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _parse_format(format: Pair<Rule>) -> Vec<FormatElement> {
|
fn _parse_format(format: Pair<Rule>) -> Vec<FormatElement> {
|
||||||
let mut result: Vec<FormatElement> = Vec::new();
|
format.into_inner().map(_parse_value).collect()
|
||||||
|
|
||||||
for pair in format.into_inner() {
|
|
||||||
match pair.as_rule() {
|
|
||||||
Rule::text => result.push(FormatElement::Text(_parse_text(pair).into())),
|
|
||||||
Rule::variable => result.push(FormatElement::Variable(_parse_variable(pair).into())),
|
|
||||||
Rule::textgroup => result.push(FormatElement::TextGroup(_parse_textgroup(pair))),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _parse_style(style: Pair<Rule>) -> Vec<StyleElement> {
|
fn _parse_style(style: Pair<Rule>) -> Vec<StyleElement> {
|
||||||
let mut result: Vec<StyleElement> = Vec::new();
|
style
|
||||||
|
.into_inner()
|
||||||
for pair in style.into_inner() {
|
.map(|pair| match pair.as_rule() {
|
||||||
match pair.as_rule() {
|
Rule::string => StyleElement::Text(pair.as_str().into()),
|
||||||
Rule::text => result.push(StyleElement::Text(_parse_text(pair).into())),
|
Rule::variable => StyleElement::Variable(_parse_variable(pair).into()),
|
||||||
Rule::variable => result.push(StyleElement::Variable(_parse_variable(pair).into())),
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
})
|
||||||
}
|
.collect()
|
||||||
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(format: &str) -> Result<Vec<FormatElement>, Error<Rule>> {
|
pub fn parse(format: &str) -> Result<Vec<FormatElement>, Error<Rule>> {
|
||||||
let pairs = IdentParser::parse(Rule::expression, format)?;
|
IdentParser::parse(Rule::expression, format).map(|pairs| {
|
||||||
let mut result: Vec<FormatElement> = Vec::new();
|
pairs
|
||||||
|
.take_while(|pair| pair.as_rule() != Rule::EOI)
|
||||||
// Lifetime of Segment is the same as result
|
.map(_parse_value)
|
||||||
for pair in pairs.take_while(|pair| pair.as_rule() != Rule::EOI) {
|
.collect()
|
||||||
match pair.as_rule() {
|
})
|
||||||
Rule::text => result.push(FormatElement::Text(_parse_text(pair).into())),
|
|
||||||
Rule::variable => result.push(FormatElement::Variable(_parse_variable(pair).into())),
|
|
||||||
Rule::textgroup => result.push(FormatElement::TextGroup(_parse_textgroup(pair))),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(result)
|
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,51 @@
|
|||||||
|
// Expression
|
||||||
|
//
|
||||||
|
// The expression of the format string.
|
||||||
|
//
|
||||||
|
// Should be started with SOI and ended with EOI, with a format string in it.
|
||||||
expression = _{ SOI ~ value* ~ EOI }
|
expression = _{ SOI ~ value* ~ EOI }
|
||||||
value = _{ text | variable | textgroup }
|
value = _{ text | variable | textgroup | conditional }
|
||||||
|
|
||||||
variable = { "$" ~ variable_name }
|
// Variable
|
||||||
variable_name = @{ char+ }
|
//
|
||||||
|
// A variable is defined as one of the following:
|
||||||
|
//
|
||||||
|
// - A valid variable name followed by a `$` character (`$[a-zA-Z_][a-zA-Z0-9_]*`),
|
||||||
|
// e.g. `$variable`.
|
||||||
|
//
|
||||||
|
// - Some texts wrapped in a curly bracket (`${[^\(\)\[\]\\\${}]+}`),
|
||||||
|
// e.g. `${env:HOST}`.
|
||||||
|
variable = { "$" ~ (variable_name | variable_scope) }
|
||||||
|
variable_name = @{ ('a'..'z' | 'A'..'Z' | "_") ~ char* }
|
||||||
char = _{ 'a'..'z' | 'A'..'Z' | '0'..'9' | "_" }
|
char = _{ 'a'..'z' | 'A'..'Z' | '0'..'9' | "_" }
|
||||||
|
|
||||||
text = { text_inner+ }
|
variable_scope = _{ "{" ~ variable_scoped_name ~ "}" }
|
||||||
text_inner = _{ text_inner_char | escape }
|
variable_scoped_name = { scoped_char+ }
|
||||||
text_inner_char = { !("[" | "]" | "(" | ")" | "$" | "\\") ~ ANY }
|
scoped_char = _{ !(escaped_char | "{" | "}") ~ ANY }
|
||||||
|
|
||||||
|
// Text
|
||||||
|
//
|
||||||
|
// Texts can be one of `string` or `escaped_char`, where string is one or more of
|
||||||
|
// unescapable chars.
|
||||||
|
//
|
||||||
|
// This is implemented so as to ensure all functional characters are escaped.
|
||||||
|
text = { (string | escape)+ }
|
||||||
|
string = @{ text_inner_char+ }
|
||||||
|
text_inner_char = { !escaped_char ~ ANY }
|
||||||
escape = _{ "\\" ~ escaped_char }
|
escape = _{ "\\" ~ escaped_char }
|
||||||
escaped_char = { "[" | "]" | "(" | ")" | "\\" | "$" }
|
escaped_char = { "[" | "]" | "(" | ")" | "\\" | "$" }
|
||||||
|
|
||||||
|
// TextGroup
|
||||||
|
//
|
||||||
|
// A textgroup is a pair of `format` and `style` (`[format](style)`)
|
||||||
|
//
|
||||||
|
// - `format`: A format string, can contain any number of variables, texts or textgroups.
|
||||||
|
// - `style`: A style string, can contain any number of variables or texts.
|
||||||
textgroup = { "[" ~ format ~ "]" ~ "(" ~ style ~ ")" }
|
textgroup = { "[" ~ format ~ "]" ~ "(" ~ style ~ ")" }
|
||||||
format = { (variable | text | textgroup)* }
|
format = { value* }
|
||||||
style = { (variable | text)* }
|
style = { (variable | string)* }
|
||||||
|
|
||||||
|
// Conditional
|
||||||
|
//
|
||||||
|
// A conditional format string that won't render if all the containing variables are empty.
|
||||||
|
conditional = { "(" ~ format ~ ")" }
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
use ansi_term::Style;
|
use ansi_term::Style;
|
||||||
use pest::error::Error;
|
use pest::error::Error as PestError;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use std::collections::BTreeMap;
|
use std::borrow::Cow;
|
||||||
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fmt;
|
||||||
|
use std::iter::FromIterator;
|
||||||
|
|
||||||
use crate::config::parse_style_string;
|
use crate::config::parse_style_string;
|
||||||
use crate::segment::Segment;
|
use crate::segment::Segment;
|
||||||
@ -10,109 +14,263 @@ use super::model::*;
|
|||||||
use super::parser::{parse, Rule};
|
use super::parser::{parse, Rule};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
enum VariableValue {
|
enum VariableValue<'a> {
|
||||||
Plain(String),
|
Plain(Cow<'a, str>),
|
||||||
Styled(Vec<Segment>),
|
Styled(Vec<Segment>),
|
||||||
|
Meta(Vec<FormatElement<'a>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for VariableValue {
|
impl<'a> Default for VariableValue<'a> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
VariableValue::Plain(String::new())
|
VariableValue::Plain(Cow::Borrowed(""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type VariableMapType = BTreeMap<String, Option<VariableValue>>;
|
type VariableMapType<'a> =
|
||||||
|
BTreeMap<String, Option<Result<VariableValue<'a>, StringFormatterError>>>;
|
||||||
|
type StyleVariableMapType<'a> =
|
||||||
|
BTreeMap<String, Option<Result<Cow<'a, str>, StringFormatterError>>>;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum StringFormatterError {
|
||||||
|
Custom(String),
|
||||||
|
Parse(PestError<Rule>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for StringFormatterError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Custom(error) => write!(f, "{}", error),
|
||||||
|
Self::Parse(error) => write!(f, "{}", error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for StringFormatterError {}
|
||||||
|
|
||||||
|
impl From<String> for StringFormatterError {
|
||||||
|
fn from(error: String) -> Self {
|
||||||
|
StringFormatterError::Custom(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct StringFormatter<'a> {
|
pub struct StringFormatter<'a> {
|
||||||
format: Vec<FormatElement<'a>>,
|
format: Vec<FormatElement<'a>>,
|
||||||
variables: VariableMapType,
|
variables: VariableMapType<'a>,
|
||||||
|
style_variables: StyleVariableMapType<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> StringFormatter<'a> {
|
impl<'a> StringFormatter<'a> {
|
||||||
/// Creates an instance of StringFormatter from a format string
|
/// Creates an instance of StringFormatter from a format string
|
||||||
pub fn new(format: &'a str) -> Result<Self, Error<Rule>> {
|
///
|
||||||
|
/// This method will throw an Error when the given format string fails to parse.
|
||||||
|
pub fn new(format: &'a str) -> Result<Self, StringFormatterError> {
|
||||||
parse(format)
|
parse(format)
|
||||||
.map(|format| {
|
.map(|format| {
|
||||||
let variables = _get_variables(&format);
|
// Cache all variables
|
||||||
(format, variables)
|
let variables = VariableMapType::from_iter(
|
||||||
|
format
|
||||||
|
.get_variables()
|
||||||
|
.into_iter()
|
||||||
|
.map(|key| (key.to_string(), None))
|
||||||
|
.collect::<Vec<(String, Option<_>)>>(),
|
||||||
|
);
|
||||||
|
let style_variables = StyleVariableMapType::from_iter(
|
||||||
|
format
|
||||||
|
.get_style_variables()
|
||||||
|
.into_iter()
|
||||||
|
.map(|key| (key.to_string(), None))
|
||||||
|
.collect::<Vec<(String, Option<_>)>>(),
|
||||||
|
);
|
||||||
|
(format, variables, style_variables)
|
||||||
})
|
})
|
||||||
.map(|(format, variables)| Self { format, variables })
|
.map(|(format, variables, style_variables)| Self {
|
||||||
|
format,
|
||||||
|
variables,
|
||||||
|
style_variables,
|
||||||
|
})
|
||||||
|
.map_err(StringFormatterError::Parse)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Maps variable name to its value
|
/// Maps variable name to its value
|
||||||
pub fn map(mut self, mapper: impl Fn(&str) -> Option<String> + Sync) -> Self {
|
///
|
||||||
self.variables.par_iter_mut().for_each(|(key, value)| {
|
/// You should provide a function or closure that accepts the variable name `name: &str` as a
|
||||||
*value = mapper(key).map(VariableValue::Plain);
|
/// parameter and returns the one of the following values:
|
||||||
});
|
///
|
||||||
|
/// - `None`: This variable will be reserved for further mappers. If it is `None` when
|
||||||
|
/// `self.parse()` is called, it will be dropped.
|
||||||
|
///
|
||||||
|
/// - `Some(Err(StringFormatterError))`: This variable will throws `StringFormatterError` when
|
||||||
|
/// `self.parse()` is called. Return this if some fatal error occurred and the format string
|
||||||
|
/// should not be rendered.
|
||||||
|
///
|
||||||
|
/// - `Some(Ok(_))`: The value of this variable will be displayed in the format string.
|
||||||
|
///
|
||||||
|
pub fn map<T, M>(mut self, mapper: M) -> Self
|
||||||
|
where
|
||||||
|
T: Into<Cow<'a, str>>,
|
||||||
|
M: Fn(&str) -> Option<Result<T, StringFormatterError>> + Sync,
|
||||||
|
{
|
||||||
|
self.variables
|
||||||
|
.par_iter_mut()
|
||||||
|
.filter(|(_, value)| value.is_none())
|
||||||
|
.for_each(|(key, value)| {
|
||||||
|
*value = mapper(key).map(|var| var.map(|var| VariableValue::Plain(var.into())));
|
||||||
|
});
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Maps a meta-variable to a format string containing other variables.
|
||||||
|
///
|
||||||
|
/// This function should be called **before** other map methods so that variables found in
|
||||||
|
/// the format strings of meta-variables can be cached properly.
|
||||||
|
///
|
||||||
|
/// See `StringFormatter::map` for description on the parameters.
|
||||||
|
pub fn map_meta<M>(mut self, mapper: M) -> Self
|
||||||
|
where
|
||||||
|
M: Fn(&str, &BTreeSet<String>) -> Option<&'a str> + Sync,
|
||||||
|
{
|
||||||
|
let variables = self.get_variables();
|
||||||
|
let (variables, style_variables) = self
|
||||||
|
.variables
|
||||||
|
.iter_mut()
|
||||||
|
.filter(|(_, value)| value.is_none())
|
||||||
|
.fold(
|
||||||
|
(VariableMapType::new(), StyleVariableMapType::new()),
|
||||||
|
|(mut v, mut sv), (key, value)| {
|
||||||
|
*value = mapper(key, &variables).map(|format| {
|
||||||
|
StringFormatter::new(format).map(|formatter| {
|
||||||
|
let StringFormatter {
|
||||||
|
format,
|
||||||
|
mut variables,
|
||||||
|
mut style_variables,
|
||||||
|
} = formatter;
|
||||||
|
|
||||||
|
// Add variables in meta variables to self
|
||||||
|
v.append(&mut variables);
|
||||||
|
sv.append(&mut style_variables);
|
||||||
|
|
||||||
|
VariableValue::Meta(format)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
(v, sv)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
self.variables.extend(variables);
|
||||||
|
self.style_variables.extend(style_variables);
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Maps variable name to an array of segments
|
/// Maps variable name to an array of segments
|
||||||
pub fn map_variables_to_segments(
|
///
|
||||||
mut self,
|
/// See `StringFormatter::map` for description on the parameters.
|
||||||
mapper: impl Fn(&str) -> Option<Vec<Segment>> + Sync,
|
pub fn map_variables_to_segments<M>(mut self, mapper: M) -> Self
|
||||||
) -> Self {
|
where
|
||||||
self.variables.par_iter_mut().for_each(|(key, value)| {
|
M: Fn(&str) -> Option<Result<Vec<Segment>, StringFormatterError>> + Sync,
|
||||||
*value = mapper(key).map(VariableValue::Styled);
|
{
|
||||||
});
|
self.variables
|
||||||
|
.par_iter_mut()
|
||||||
|
.filter(|(_, value)| value.is_none())
|
||||||
|
.for_each(|(key, value)| {
|
||||||
|
*value = mapper(key).map(|var| var.map(VariableValue::Styled));
|
||||||
|
});
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Maps variable name in a style string to its value
|
||||||
|
///
|
||||||
|
/// See `StringFormatter::map` for description on the parameters.
|
||||||
|
pub fn map_style<T, M>(mut self, mapper: M) -> Self
|
||||||
|
where
|
||||||
|
T: Into<Cow<'a, str>>,
|
||||||
|
M: Fn(&str) -> Option<Result<T, StringFormatterError>> + Sync,
|
||||||
|
{
|
||||||
|
self.style_variables
|
||||||
|
.par_iter_mut()
|
||||||
|
.filter(|(_, value)| value.is_none())
|
||||||
|
.for_each(|(key, value)| {
|
||||||
|
*value = mapper(key).map(|var| var.map(|var| var.into()));
|
||||||
|
});
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse the format string and consume self.
|
/// Parse the format string and consume self.
|
||||||
pub fn parse(self, default_style: Option<Style>) -> Vec<Segment> {
|
///
|
||||||
|
/// This method will throw an Error in the following conditions:
|
||||||
|
///
|
||||||
|
/// - Format string in meta variables fails to parse
|
||||||
|
/// - Variable mapper returns an error.
|
||||||
|
pub fn parse(self, default_style: Option<Style>) -> Result<Vec<Segment>, StringFormatterError> {
|
||||||
fn _parse_textgroup<'a>(
|
fn _parse_textgroup<'a>(
|
||||||
textgroup: TextGroup<'a>,
|
textgroup: TextGroup<'a>,
|
||||||
variables: &'a VariableMapType,
|
variables: &'a VariableMapType<'a>,
|
||||||
) -> Vec<Segment> {
|
style_variables: &'a StyleVariableMapType<'a>,
|
||||||
let style = _parse_style(textgroup.style);
|
) -> Result<Vec<Segment>, StringFormatterError> {
|
||||||
_parse_format(textgroup.format, style, &variables)
|
let style = _parse_style(textgroup.style, style_variables);
|
||||||
|
_parse_format(
|
||||||
|
textgroup.format,
|
||||||
|
style.transpose()?,
|
||||||
|
&variables,
|
||||||
|
&style_variables,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _parse_style(style: Vec<StyleElement>) -> Option<Style> {
|
fn _parse_style<'a>(
|
||||||
let style_string = style
|
style: Vec<StyleElement>,
|
||||||
.iter()
|
variables: &'a StyleVariableMapType<'a>,
|
||||||
.flat_map(|style| match style {
|
) -> Option<Result<Style, StringFormatterError>> {
|
||||||
StyleElement::Text(text) => text.as_ref().chars(),
|
let style_strings = style
|
||||||
StyleElement::Variable(variable) => {
|
.into_iter()
|
||||||
log::warn!(
|
.map(|style| match style {
|
||||||
"Variable `{}` monitored in style string, which is not allowed",
|
StyleElement::Text(text) => Ok(text),
|
||||||
&variable
|
StyleElement::Variable(name) => {
|
||||||
);
|
let variable = variables.get(name.as_ref()).unwrap_or(&None);
|
||||||
"".chars()
|
match variable {
|
||||||
|
Some(style_string) => style_string.clone().map(|string| string),
|
||||||
|
None => Ok("".into()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<String>();
|
.collect::<Result<Vec<Cow<str>>, StringFormatterError>>();
|
||||||
parse_style_string(&style_string)
|
style_strings
|
||||||
|
.map(|style_strings| {
|
||||||
|
let style_string: String =
|
||||||
|
style_strings.iter().flat_map(|s| s.chars()).collect();
|
||||||
|
parse_style_string(&style_string)
|
||||||
|
})
|
||||||
|
.transpose()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _parse_format<'a>(
|
fn _parse_format<'a>(
|
||||||
mut format: Vec<FormatElement<'a>>,
|
format: Vec<FormatElement<'a>>,
|
||||||
style: Option<Style>,
|
style: Option<Style>,
|
||||||
variables: &'a VariableMapType,
|
variables: &'a VariableMapType<'a>,
|
||||||
) -> Vec<Segment> {
|
style_variables: &'a StyleVariableMapType<'a>,
|
||||||
let mut result: Vec<Segment> = Vec::new();
|
) -> Result<Vec<Segment>, StringFormatterError> {
|
||||||
|
let results: Result<Vec<Vec<Segment>>, StringFormatterError> = format
|
||||||
format.reverse();
|
.into_iter()
|
||||||
while let Some(el) = format.pop() {
|
.map(|el| {
|
||||||
let mut segments = match el {
|
match el {
|
||||||
FormatElement::Text(text) => {
|
FormatElement::Text(text) => Ok(vec![_new_segment("_text", text, style)]),
|
||||||
vec![_new_segment("_text".into(), text.into_owned(), style)]
|
FormatElement::TextGroup(textgroup) => {
|
||||||
}
|
let textgroup = TextGroup {
|
||||||
FormatElement::TextGroup(textgroup) => {
|
format: textgroup.format,
|
||||||
let textgroup = TextGroup {
|
style: textgroup.style,
|
||||||
format: textgroup.format,
|
};
|
||||||
style: textgroup.style,
|
_parse_textgroup(textgroup, &variables, &style_variables)
|
||||||
};
|
}
|
||||||
_parse_textgroup(textgroup, &variables)
|
FormatElement::Variable(name) => variables
|
||||||
}
|
.get(name.as_ref())
|
||||||
FormatElement::Variable(name) => variables
|
.expect("Uncached variable found")
|
||||||
.get(name.as_ref())
|
.as_ref()
|
||||||
.map(|segments| {
|
.map(|segments| match segments.clone()? {
|
||||||
let value = segments.clone().unwrap_or_default();
|
VariableValue::Styled(segments) => Ok(segments
|
||||||
match value {
|
|
||||||
VariableValue::Styled(segments) => segments
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|mut segment| {
|
.map(|mut segment| {
|
||||||
|
// Derive upper style if the style of segments are none.
|
||||||
if !segment.has_style() {
|
if !segment.has_style() {
|
||||||
if let Some(style) = style {
|
if let Some(style) = style {
|
||||||
segment.set_style(style);
|
segment.set_style(style);
|
||||||
@ -120,80 +278,124 @@ impl<'a> StringFormatter<'a> {
|
|||||||
}
|
}
|
||||||
segment
|
segment
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect()),
|
||||||
VariableValue::Plain(text) => {
|
VariableValue::Plain(text) => {
|
||||||
vec![_new_segment(name.to_string(), text, style)]
|
Ok(vec![_new_segment(name, text, style)])
|
||||||
}
|
}
|
||||||
|
VariableValue::Meta(format) => {
|
||||||
|
let formatter = StringFormatter {
|
||||||
|
format,
|
||||||
|
variables: _clone_without_meta(variables),
|
||||||
|
style_variables: style_variables.clone(),
|
||||||
|
};
|
||||||
|
formatter.parse(style)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| Ok(Vec::new())),
|
||||||
|
FormatElement::Conditional(format) => {
|
||||||
|
// Show the conditional format string if all the variables inside are not
|
||||||
|
// none.
|
||||||
|
fn _should_show_elements<'a>(
|
||||||
|
format_elements: &[FormatElement],
|
||||||
|
variables: &'a VariableMapType<'a>,
|
||||||
|
) -> bool {
|
||||||
|
format_elements.get_variables().iter().any(|var| {
|
||||||
|
variables
|
||||||
|
.get(var.as_ref())
|
||||||
|
.map(|map_result| {
|
||||||
|
let map_result = map_result.as_ref();
|
||||||
|
map_result
|
||||||
|
.and_then(|result| result.as_ref().ok())
|
||||||
|
.map(|result| match result {
|
||||||
|
// If the variable is a meta variable, also
|
||||||
|
// check the format string inside it.
|
||||||
|
VariableValue::Meta(meta_elements) => {
|
||||||
|
let meta_variables =
|
||||||
|
_clone_without_meta(variables);
|
||||||
|
_should_show_elements(
|
||||||
|
&meta_elements,
|
||||||
|
&meta_variables,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => true,
|
||||||
|
})
|
||||||
|
// The variable is None or Err, or a meta variable
|
||||||
|
// that shouldn't show
|
||||||
|
.unwrap_or(false)
|
||||||
|
})
|
||||||
|
// Can't find the variable in format string
|
||||||
|
.unwrap_or(false)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.unwrap_or_default(),
|
|
||||||
};
|
|
||||||
result.append(&mut segments);
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
let should_show: bool = _should_show_elements(&format, variables);
|
||||||
|
|
||||||
|
if should_show {
|
||||||
|
_parse_format(format, style, variables, style_variables)
|
||||||
|
} else {
|
||||||
|
Ok(Vec::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
Ok(results?.into_iter().flatten().collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
_parse_format(self.format, default_style, &self.variables)
|
_parse_format(
|
||||||
|
self.format,
|
||||||
|
default_style,
|
||||||
|
&self.variables,
|
||||||
|
&self.style_variables,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract variable names from an array of `FormatElement` into a `BTreeMap`
|
impl<'a> VariableHolder<String> for StringFormatter<'a> {
|
||||||
fn _get_variables<'a>(format: &[FormatElement<'a>]) -> VariableMapType {
|
fn get_variables(&self) -> BTreeSet<String> {
|
||||||
let mut variables: VariableMapType = Default::default();
|
BTreeSet::from_iter(self.variables.keys().cloned())
|
||||||
|
|
||||||
fn _push_variables_from_textgroup<'a>(
|
|
||||||
variables: &mut VariableMapType,
|
|
||||||
textgroup: &'a TextGroup<'a>,
|
|
||||||
) {
|
|
||||||
for el in &textgroup.format {
|
|
||||||
match el {
|
|
||||||
FormatElement::Variable(name) => _push_variable(variables, name.as_ref()),
|
|
||||||
FormatElement::TextGroup(textgroup) => {
|
|
||||||
_push_variables_from_textgroup(variables, &textgroup)
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for el in &textgroup.style {
|
|
||||||
if let StyleElement::Variable(name) = el {
|
|
||||||
_push_variable(variables, name.as_ref())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn _push_variable<'a>(variables: &mut VariableMapType, name: &'a str) {
|
impl<'a> StyleVariableHolder<String> for StringFormatter<'a> {
|
||||||
variables.insert(name.to_owned(), None);
|
fn get_style_variables(&self) -> BTreeSet<String> {
|
||||||
|
BTreeSet::from_iter(self.style_variables.keys().cloned())
|
||||||
}
|
}
|
||||||
|
|
||||||
for el in format {
|
|
||||||
match el {
|
|
||||||
FormatElement::Variable(name) => _push_variable(&mut variables, name.as_ref()),
|
|
||||||
FormatElement::TextGroup(textgroup) => {
|
|
||||||
_push_variables_from_textgroup(&mut variables, &textgroup)
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
variables
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to create a new segment
|
/// Helper function to create a new segment
|
||||||
fn _new_segment(name: String, value: String, style: Option<Style>) -> Segment {
|
fn _new_segment(
|
||||||
|
name: impl Into<String>,
|
||||||
|
value: impl Into<String>,
|
||||||
|
style: Option<Style>,
|
||||||
|
) -> Segment {
|
||||||
Segment {
|
Segment {
|
||||||
_name: name,
|
_name: name.into(),
|
||||||
value,
|
value: value.into(),
|
||||||
style,
|
style,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn _clone_without_meta<'a>(variables: &VariableMapType<'a>) -> VariableMapType<'a> {
|
||||||
|
VariableMapType::from_iter(variables.iter().map(|(key, value)| {
|
||||||
|
let value = match value {
|
||||||
|
Some(Ok(value)) => match value {
|
||||||
|
VariableValue::Meta(_) => None,
|
||||||
|
other => Some(Ok(other.clone())),
|
||||||
|
},
|
||||||
|
Some(Err(e)) => Some(Err(e.clone())),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
(key.clone(), value)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use ansi_term::Color;
|
use ansi_term::Color;
|
||||||
|
|
||||||
// match_next(result: Iter<Segment>, value, style)
|
// match_next(result: IterMut<Segment>, value, style)
|
||||||
macro_rules! match_next {
|
macro_rules! match_next {
|
||||||
($iter:ident, $value:literal, $($style:tt)+) => {
|
($iter:ident, $value:literal, $($style:tt)+) => {
|
||||||
let _next = $iter.next().unwrap();
|
let _next = $iter.next().unwrap();
|
||||||
@ -202,7 +404,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn empty_mapper(_: &str) -> Option<String> {
|
fn empty_mapper(_: &str) -> Option<Result<String, StringFormatterError>> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,7 +414,7 @@ mod tests {
|
|||||||
let style = Some(Color::Red.bold());
|
let style = Some(Color::Red.bold());
|
||||||
|
|
||||||
let formatter = StringFormatter::new(FORMAT_STR).unwrap().map(empty_mapper);
|
let formatter = StringFormatter::new(FORMAT_STR).unwrap().map(empty_mapper);
|
||||||
let result = formatter.parse(style);
|
let result = formatter.parse(style).unwrap();
|
||||||
let mut result_iter = result.iter();
|
let mut result_iter = result.iter();
|
||||||
match_next!(result_iter, "text", style);
|
match_next!(result_iter, "text", style);
|
||||||
}
|
}
|
||||||
@ -221,7 +423,7 @@ mod tests {
|
|||||||
fn test_textgroup_text_only() {
|
fn test_textgroup_text_only() {
|
||||||
const FORMAT_STR: &str = "[text](red bold)";
|
const FORMAT_STR: &str = "[text](red bold)";
|
||||||
let formatter = StringFormatter::new(FORMAT_STR).unwrap().map(empty_mapper);
|
let formatter = StringFormatter::new(FORMAT_STR).unwrap().map(empty_mapper);
|
||||||
let result = formatter.parse(None);
|
let result = formatter.parse(None).unwrap();
|
||||||
let mut result_iter = result.iter();
|
let mut result_iter = result.iter();
|
||||||
match_next!(result_iter, "text", Some(Color::Red.bold()));
|
match_next!(result_iter, "text", Some(Color::Red.bold()));
|
||||||
}
|
}
|
||||||
@ -233,20 +435,48 @@ mod tests {
|
|||||||
let formatter = StringFormatter::new(FORMAT_STR)
|
let formatter = StringFormatter::new(FORMAT_STR)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.map(|variable| match variable {
|
.map(|variable| match variable {
|
||||||
"var1" => Some("text1".to_owned()),
|
"var1" => Some(Ok("text1".to_owned())),
|
||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
let result = formatter.parse(None);
|
let result = formatter.parse(None).unwrap();
|
||||||
let mut result_iter = result.iter();
|
let mut result_iter = result.iter();
|
||||||
match_next!(result_iter, "text1", None);
|
match_next!(result_iter, "text1", None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_variable_in_style() {
|
||||||
|
const FORMAT_STR: &str = "[root]($style)";
|
||||||
|
let root_style = Some(Color::Red.bold());
|
||||||
|
|
||||||
|
let formatter = StringFormatter::new(FORMAT_STR)
|
||||||
|
.unwrap()
|
||||||
|
.map_style(|variable| match variable {
|
||||||
|
"style" => Some(Ok("red bold".to_owned())),
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
let result = formatter.parse(None).unwrap();
|
||||||
|
let mut result_iter = result.iter();
|
||||||
|
match_next!(result_iter, "root", root_style);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_scoped_variable() {
|
||||||
|
const FORMAT_STR: &str = "${env:PWD}";
|
||||||
|
|
||||||
|
let formatter = StringFormatter::new(FORMAT_STR)
|
||||||
|
.unwrap()
|
||||||
|
.map(|variable| Some(Ok(format!("${{{}}}", variable))));
|
||||||
|
let result = formatter.parse(None).unwrap();
|
||||||
|
let mut result_iter = result.iter();
|
||||||
|
match_next!(result_iter, "${env:PWD}", None);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_escaped_chars() {
|
fn test_escaped_chars() {
|
||||||
const FORMAT_STR: &str = r#"\\\[\$text\]\(red bold\)"#;
|
const FORMAT_STR: &str = r#"\\\[\$text\]\(red bold\)"#;
|
||||||
|
|
||||||
let formatter = StringFormatter::new(FORMAT_STR).unwrap().map(empty_mapper);
|
let formatter = StringFormatter::new(FORMAT_STR).unwrap().map(empty_mapper);
|
||||||
let result = formatter.parse(None);
|
let result = formatter.parse(None).unwrap();
|
||||||
let mut result_iter = result.iter();
|
let mut result_iter = result.iter();
|
||||||
match_next!(result_iter, r#"\[$text](red bold)"#, None);
|
match_next!(result_iter, r#"\[$text](red bold)"#, None);
|
||||||
}
|
}
|
||||||
@ -259,7 +489,7 @@ mod tests {
|
|||||||
let inner_style = Some(Color::Blue.normal());
|
let inner_style = Some(Color::Blue.normal());
|
||||||
|
|
||||||
let formatter = StringFormatter::new(FORMAT_STR).unwrap().map(empty_mapper);
|
let formatter = StringFormatter::new(FORMAT_STR).unwrap().map(empty_mapper);
|
||||||
let result = formatter.parse(outer_style);
|
let result = formatter.parse(outer_style).unwrap();
|
||||||
let mut result_iter = result.iter();
|
let mut result_iter = result.iter();
|
||||||
match_next!(result_iter, "outer ", outer_style);
|
match_next!(result_iter, "outer ", outer_style);
|
||||||
match_next!(result_iter, "middle ", middle_style);
|
match_next!(result_iter, "middle ", middle_style);
|
||||||
@ -274,10 +504,10 @@ mod tests {
|
|||||||
let formatter = StringFormatter::new(FORMAT_STR)
|
let formatter = StringFormatter::new(FORMAT_STR)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.map(|variable| match variable {
|
.map(|variable| match variable {
|
||||||
"var" => Some("text".to_owned()),
|
"var" => Some(Ok("text".to_owned())),
|
||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
let result = formatter.parse(None);
|
let result = formatter.parse(None).unwrap();
|
||||||
let mut result_iter = result.iter();
|
let mut result_iter = result.iter();
|
||||||
match_next!(result_iter, "text", var_style);
|
match_next!(result_iter, "text", var_style);
|
||||||
}
|
}
|
||||||
@ -292,7 +522,7 @@ mod tests {
|
|||||||
let formatter = StringFormatter::new(FORMAT_STR)
|
let formatter = StringFormatter::new(FORMAT_STR)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.map_variables_to_segments(|variable| match variable {
|
.map_variables_to_segments(|variable| match variable {
|
||||||
"var" => Some(vec![
|
"var" => Some(Ok(vec![
|
||||||
_new_segment("_1".to_owned(), "styless".to_owned(), None),
|
_new_segment("_1".to_owned(), "styless".to_owned(), None),
|
||||||
_new_segment("_2".to_owned(), "styled".to_owned(), styled_style),
|
_new_segment("_2".to_owned(), "styled".to_owned(), styled_style),
|
||||||
_new_segment(
|
_new_segment(
|
||||||
@ -300,16 +530,133 @@ mod tests {
|
|||||||
"styled_no_modifier".to_owned(),
|
"styled_no_modifier".to_owned(),
|
||||||
styled_no_modifier_style,
|
styled_no_modifier_style,
|
||||||
),
|
),
|
||||||
]),
|
])),
|
||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
let result = formatter.parse(None);
|
let result = formatter.parse(None).unwrap();
|
||||||
let mut result_iter = result.iter();
|
let mut result_iter = result.iter();
|
||||||
match_next!(result_iter, "styless", var_style);
|
match_next!(result_iter, "styless", var_style);
|
||||||
match_next!(result_iter, "styled", styled_style);
|
match_next!(result_iter, "styled", styled_style);
|
||||||
match_next!(result_iter, "styled_no_modifier", styled_no_modifier_style);
|
match_next!(result_iter, "styled_no_modifier", styled_no_modifier_style);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_meta_variable() {
|
||||||
|
const FORMAT_STR: &str = "$all";
|
||||||
|
const FORMAT_STR__ALL: &str = "$a$b";
|
||||||
|
|
||||||
|
let formatter = StringFormatter::new(FORMAT_STR)
|
||||||
|
.unwrap()
|
||||||
|
.map_meta(|var, _| match var {
|
||||||
|
"all" => Some(FORMAT_STR__ALL),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|var| match var {
|
||||||
|
"a" => Some(Ok("$a")),
|
||||||
|
"b" => Some(Ok("$b")),
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
let result = formatter.parse(None).unwrap();
|
||||||
|
let mut result_iter = result.iter();
|
||||||
|
match_next!(result_iter, "$a", None);
|
||||||
|
match_next!(result_iter, "$b", None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_multiple_mapper() {
|
||||||
|
const FORMAT_STR: &str = "$a$b$c";
|
||||||
|
|
||||||
|
let formatter = StringFormatter::new(FORMAT_STR)
|
||||||
|
.unwrap()
|
||||||
|
.map(|var| match var {
|
||||||
|
"a" => Some(Ok("$a")),
|
||||||
|
"b" => Some(Ok("$b")),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|var| match var {
|
||||||
|
"b" => Some(Ok("$B")),
|
||||||
|
"c" => Some(Ok("$c")),
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
let result = formatter.parse(None).unwrap();
|
||||||
|
let mut result_iter = result.iter();
|
||||||
|
match_next!(result_iter, "$a", None);
|
||||||
|
match_next!(result_iter, "$b", None);
|
||||||
|
match_next!(result_iter, "$c", None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_conditional() {
|
||||||
|
const FORMAT_STR: &str = "($some) should render but ($none) shouldn't";
|
||||||
|
|
||||||
|
let formatter = StringFormatter::new(FORMAT_STR)
|
||||||
|
.unwrap()
|
||||||
|
.map(|var| match var {
|
||||||
|
"some" => Some(Ok("$some")),
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
let result = formatter.parse(None).unwrap();
|
||||||
|
let mut result_iter = result.iter();
|
||||||
|
match_next!(result_iter, "$some", None);
|
||||||
|
match_next!(result_iter, " should render but ", None);
|
||||||
|
match_next!(result_iter, " shouldn't", None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_nested_conditional() {
|
||||||
|
const FORMAT_STR: &str = "($some ($none)) and ($none ($some))";
|
||||||
|
|
||||||
|
let formatter = StringFormatter::new(FORMAT_STR)
|
||||||
|
.unwrap()
|
||||||
|
.map(|var| match var {
|
||||||
|
"some" => Some(Ok("$some")),
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
let result = formatter.parse(None).unwrap();
|
||||||
|
let mut result_iter = result.iter();
|
||||||
|
match_next!(result_iter, "$some", None);
|
||||||
|
match_next!(result_iter, " ", None);
|
||||||
|
match_next!(result_iter, " and ", None);
|
||||||
|
match_next!(result_iter, " ", None);
|
||||||
|
match_next!(result_iter, "$some", None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_conditional_meta_variable() {
|
||||||
|
const FORMAT_STR: &str = r"(\[$all\]) ";
|
||||||
|
|
||||||
|
let formatter = StringFormatter::new(FORMAT_STR)
|
||||||
|
.unwrap()
|
||||||
|
.map_meta(|var, _| match var {
|
||||||
|
"all" => Some("$some"),
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
let result = formatter.parse(None).unwrap();
|
||||||
|
let mut result_iter = result.iter();
|
||||||
|
match_next!(result_iter, " ", None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_variable_holder() {
|
||||||
|
const FORMAT_STR: &str = "($a [($b) $c](none $s)) $d [t]($t)";
|
||||||
|
let expected_variables =
|
||||||
|
BTreeSet::from_iter(vec!["a", "b", "c", "d"].into_iter().map(String::from));
|
||||||
|
|
||||||
|
let formatter = StringFormatter::new(FORMAT_STR).unwrap().map(empty_mapper);
|
||||||
|
let variables = formatter.get_variables();
|
||||||
|
assert_eq!(variables, expected_variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_style_variable_holder() {
|
||||||
|
const FORMAT_STR: &str = "($a [($b) $c](none $s)) $d [t]($t)";
|
||||||
|
let expected_variables = BTreeSet::from_iter(vec!["s", "t"].into_iter().map(String::from));
|
||||||
|
|
||||||
|
let formatter = StringFormatter::new(FORMAT_STR).unwrap().map(empty_mapper);
|
||||||
|
let variables = formatter.get_style_variables();
|
||||||
|
assert_eq!(variables, expected_variables);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_error() {
|
fn test_parse_error() {
|
||||||
// brackets without escape
|
// brackets without escape
|
||||||
@ -323,4 +670,21 @@ mod tests {
|
|||||||
assert!(StringFormatter::new(FORMAT_STR).is_err());
|
assert!(StringFormatter::new(FORMAT_STR).is_err());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_variable_error() {
|
||||||
|
const FORMAT_STR: &str = "$never$some";
|
||||||
|
let never_error = StringFormatterError::Custom("NEVER".to_owned());
|
||||||
|
|
||||||
|
let segments = StringFormatter::new(FORMAT_STR).and_then(|formatter| {
|
||||||
|
formatter
|
||||||
|
.map(|var| match var {
|
||||||
|
"some" => Some(Ok("some")),
|
||||||
|
"never" => Some(Err(never_error.clone())),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
assert!(segments.is_err());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
130
src/module.rs
130
src/module.rs
@ -1,8 +1,6 @@
|
|||||||
use crate::config::SegmentConfig;
|
|
||||||
use crate::context::Shell;
|
use crate::context::Shell;
|
||||||
use crate::segment::Segment;
|
use crate::segment::Segment;
|
||||||
use crate::utils::wrap_colorseq_for_shell;
|
use crate::utils::wrap_colorseq_for_shell;
|
||||||
use ansi_term::Style;
|
|
||||||
use ansi_term::{ANSIString, ANSIStrings};
|
use ansi_term::{ANSIString, ANSIStrings};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
@ -66,17 +64,8 @@ pub struct Module<'a> {
|
|||||||
/// The module's description
|
/// The module's description
|
||||||
description: String,
|
description: String,
|
||||||
|
|
||||||
/// The styling to be inherited by all segments contained within this module.
|
|
||||||
style: Style,
|
|
||||||
|
|
||||||
/// The prefix used to separate the current module from the previous one.
|
|
||||||
prefix: Affix,
|
|
||||||
|
|
||||||
/// The collection of segments that compose this module.
|
/// The collection of segments that compose this module.
|
||||||
segments: Vec<Segment>,
|
pub segments: Vec<Segment>,
|
||||||
|
|
||||||
/// The suffix used to separate the current module from the next one.
|
|
||||||
suffix: Affix,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Module<'a> {
|
impl<'a> Module<'a> {
|
||||||
@ -86,23 +75,10 @@ impl<'a> Module<'a> {
|
|||||||
config,
|
config,
|
||||||
_name: name.to_string(),
|
_name: name.to_string(),
|
||||||
description: desc.to_string(),
|
description: desc.to_string(),
|
||||||
style: Style::default(),
|
|
||||||
prefix: Affix::default_prefix(name),
|
|
||||||
segments: Vec::new(),
|
segments: Vec::new(),
|
||||||
suffix: Affix::default_suffix(name),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a reference to a newly created segment in the module
|
|
||||||
pub fn create_segment(&mut self, name: &str, segment_config: &SegmentConfig) -> &mut Segment {
|
|
||||||
let mut segment = Segment::new(name);
|
|
||||||
segment.set_style(segment_config.style.unwrap_or(self.style));
|
|
||||||
segment.set_value(segment_config.value);
|
|
||||||
self.segments.push(segment);
|
|
||||||
|
|
||||||
self.segments.last_mut().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set segments in module
|
/// Set segments in module
|
||||||
pub fn set_segments(&mut self, segments: Vec<Segment>) {
|
pub fn set_segments(&mut self, segments: Vec<Segment>) {
|
||||||
self.segments = segments;
|
self.segments = segments;
|
||||||
@ -123,31 +99,11 @@ impl<'a> Module<'a> {
|
|||||||
self.segments.iter().all(|segment| segment.is_empty())
|
self.segments.iter().all(|segment| segment.is_empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get values of the module's segments
|
||||||
pub fn get_segments(&self) -> Vec<&str> {
|
pub fn get_segments(&self) -> Vec<&str> {
|
||||||
self.segments.iter().map(Segment::get_value).collect()
|
self.segments.iter().map(Segment::get_value).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the module's prefix
|
|
||||||
pub fn get_prefix(&mut self) -> &mut Affix {
|
|
||||||
&mut self.prefix
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the module's suffix
|
|
||||||
pub fn get_suffix(&mut self) -> &mut Affix {
|
|
||||||
&mut self.suffix
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the style of the segment.
|
|
||||||
///
|
|
||||||
/// Accepts either `Color` or `Style`.
|
|
||||||
pub fn set_style<T>(&mut self, style: T) -> &mut Module<'a>
|
|
||||||
where
|
|
||||||
T: Into<Style>,
|
|
||||||
{
|
|
||||||
self.style = style.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a vector of colored ANSIString elements to be later used with
|
/// Returns a vector of colored ANSIString elements to be later used with
|
||||||
/// `ANSIStrings()` to optimize ANSI codes
|
/// `ANSIStrings()` to optimize ANSI codes
|
||||||
pub fn ansi_strings(&self) -> Vec<ANSIString> {
|
pub fn ansi_strings(&self) -> Vec<ANSIString> {
|
||||||
@ -155,26 +111,17 @@ impl<'a> Module<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn ansi_strings_for_shell(&self, shell: Shell) -> Vec<ANSIString> {
|
pub fn ansi_strings_for_shell(&self, shell: Shell) -> Vec<ANSIString> {
|
||||||
let mut ansi_strings = self
|
let ansi_strings = self
|
||||||
.segments
|
.segments
|
||||||
.iter()
|
.iter()
|
||||||
.map(Segment::ansi_string)
|
.map(Segment::ansi_string)
|
||||||
.collect::<Vec<ANSIString>>();
|
.collect::<Vec<ANSIString>>();
|
||||||
|
|
||||||
ansi_strings.insert(0, self.prefix.ansi_string());
|
match shell {
|
||||||
ansi_strings.push(self.suffix.ansi_string());
|
|
||||||
|
|
||||||
ansi_strings = match shell {
|
|
||||||
Shell::Bash => ansi_strings_modified(ansi_strings, shell),
|
Shell::Bash => ansi_strings_modified(ansi_strings, shell),
|
||||||
Shell::Zsh => ansi_strings_modified(ansi_strings, shell),
|
Shell::Zsh => ansi_strings_modified(ansi_strings, shell),
|
||||||
_ => ansi_strings,
|
_ => ansi_strings,
|
||||||
};
|
}
|
||||||
|
|
||||||
ansi_strings
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_string_without_prefix(&self, shell: Shell) -> String {
|
|
||||||
ANSIStrings(&self.ansi_strings_for_shell(shell)[1..]).to_string()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,67 +142,6 @@ fn ansi_strings_modified(ansi_strings: Vec<ANSIString>, shell: Shell) -> Vec<ANS
|
|||||||
.collect::<Vec<ANSIString>>()
|
.collect::<Vec<ANSIString>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Module affixes are to be used for the prefix or suffix of a module.
|
|
||||||
pub struct Affix {
|
|
||||||
/// The affix's name, to be used in configuration and logging.
|
|
||||||
_name: String,
|
|
||||||
|
|
||||||
/// The affix's style.
|
|
||||||
style: Style,
|
|
||||||
|
|
||||||
/// The string value of the affix.
|
|
||||||
value: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Affix {
|
|
||||||
pub fn default_prefix(name: &str) -> Self {
|
|
||||||
Self {
|
|
||||||
_name: format!("{}_prefix", name),
|
|
||||||
style: Style::default(),
|
|
||||||
value: "via ".to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn default_suffix(name: &str) -> Self {
|
|
||||||
Self {
|
|
||||||
_name: format!("{}_suffix", name),
|
|
||||||
style: Style::default(),
|
|
||||||
value: " ".to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the style of the module.
|
|
||||||
///
|
|
||||||
/// Accepts either `Color` or `Style`.
|
|
||||||
pub fn set_style<T>(&mut self, style: T) -> &mut Self
|
|
||||||
where
|
|
||||||
T: Into<Style>,
|
|
||||||
{
|
|
||||||
self.style = style.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the value of the module.
|
|
||||||
pub fn set_value<T>(&mut self, value: T) -> &mut Self
|
|
||||||
where
|
|
||||||
T: Into<String>,
|
|
||||||
{
|
|
||||||
self.value = value.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generates the colored ANSIString output.
|
|
||||||
pub fn ansi_string(&self) -> ANSIString {
|
|
||||||
self.style.paint(&self.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Affix {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.ansi_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -268,10 +154,7 @@ mod tests {
|
|||||||
config: None,
|
config: None,
|
||||||
_name: name.to_string(),
|
_name: name.to_string(),
|
||||||
description: desc.to_string(),
|
description: desc.to_string(),
|
||||||
style: Style::default(),
|
|
||||||
prefix: Affix::default_prefix(name),
|
|
||||||
segments: Vec::new(),
|
segments: Vec::new(),
|
||||||
suffix: Affix::default_suffix(name),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(module.is_empty());
|
assert!(module.is_empty());
|
||||||
@ -285,10 +168,7 @@ mod tests {
|
|||||||
config: None,
|
config: None,
|
||||||
_name: name.to_string(),
|
_name: name.to_string(),
|
||||||
description: desc.to_string(),
|
description: desc.to_string(),
|
||||||
style: Style::default(),
|
|
||||||
prefix: Affix::default_prefix(name),
|
|
||||||
segments: vec![Segment::new("test_segment")],
|
segments: vec![Segment::new("test_segment")],
|
||||||
suffix: Affix::default_suffix(name),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(module.is_empty());
|
assert!(module.is_empty());
|
||||||
|
@ -7,7 +7,8 @@ use std::str::FromStr;
|
|||||||
|
|
||||||
use super::{Context, Module, RootModuleConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::configs::aws::{AwsConfig, AwsItems};
|
use crate::configs::aws::AwsConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
|
|
||||||
type Profile = String;
|
type Profile = String;
|
||||||
type Region = String;
|
type Region = String;
|
||||||
@ -51,73 +52,64 @@ fn get_aws_profile_and_region() -> (Option<Profile>, Option<Region>) {
|
|||||||
env::var("AWS_VAULT")
|
env::var("AWS_VAULT")
|
||||||
.or_else(|_| env::var("AWS_PROFILE"))
|
.or_else(|_| env::var("AWS_PROFILE"))
|
||||||
.ok(),
|
.ok(),
|
||||||
env::var("AWS_REGION").ok(),
|
env::var("AWS_DEFAULT_REGION")
|
||||||
env::var("AWS_DEFAULT_REGION").ok(),
|
.or_else(|_| env::var("AWS_REGION"))
|
||||||
|
.ok(),
|
||||||
) {
|
) {
|
||||||
(Some(p), Some(_), Some(dr)) => (Some(p), Some(dr)),
|
(Some(p), Some(r)) => (Some(p), Some(r)),
|
||||||
(Some(p), Some(r), None) => (Some(p), Some(r)),
|
(None, Some(r)) => (None, Some(r)),
|
||||||
(None, Some(r), None) => (None, Some(r)),
|
(Some(ref p), None) => (Some(p.to_owned()), get_aws_region_from_config(Some(p))),
|
||||||
(Some(p), None, Some(dr)) => (Some(p), Some(dr)),
|
(None, None) => (None, get_aws_region_from_config(None)),
|
||||||
(Some(ref p), None, None) => (Some(p.to_owned()), get_aws_region_from_config(Some(p))),
|
|
||||||
(None, None, Some(dr)) => (None, Some(dr)),
|
|
||||||
(None, Some(_), Some(dr)) => (None, Some(dr)),
|
|
||||||
(None, None, None) => (None, get_aws_region_from_config(None)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_aws_region() -> Option<Region> {
|
fn alias_region(region: String, aliases: &HashMap<String, &str>) -> String {
|
||||||
match (
|
match aliases.get(®ion) {
|
||||||
env::var("AWS_REGION").ok(),
|
None => region,
|
||||||
env::var("AWS_DEFAULT_REGION").ok(),
|
|
||||||
) {
|
|
||||||
(Some(r), None) => Some(r),
|
|
||||||
(None, Some(dr)) => Some(dr),
|
|
||||||
(Some(_), Some(dr)) => Some(dr),
|
|
||||||
(None, None) => get_aws_region_from_config(None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn alias_region(region: &str, aliases: &HashMap<String, &str>) -> String {
|
|
||||||
match aliases.get(region) {
|
|
||||||
None => region.to_string(),
|
|
||||||
Some(alias) => (*alias).to_string(),
|
Some(alias) => (*alias).to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
const AWS_PREFIX: &str = "on ";
|
|
||||||
|
|
||||||
let mut module = context.new_module("aws");
|
let mut module = context.new_module("aws");
|
||||||
let config: AwsConfig = AwsConfig::try_load(module.config);
|
let config: AwsConfig = AwsConfig::try_load(module.config);
|
||||||
|
|
||||||
module.set_style(config.style);
|
let (aws_profile, aws_region) = get_aws_profile_and_region();
|
||||||
|
if aws_profile.is_none() && aws_region.is_none() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
module.get_prefix().set_value(AWS_PREFIX);
|
let mapped_region = if let Some(aws_region) = aws_region {
|
||||||
|
Some(alias_region(aws_region, &config.region_aliases))
|
||||||
module.create_segment("symbol", &config.symbol);
|
} else {
|
||||||
match config.displayed_items {
|
None
|
||||||
AwsItems::All => {
|
|
||||||
let (aws_profile, aws_region) = get_aws_profile_and_region();
|
|
||||||
|
|
||||||
let aws_segment = match (&aws_profile, &aws_region) {
|
|
||||||
(None, None) => return None,
|
|
||||||
(Some(p), Some(r)) => format!("{}({})", p, alias_region(r, &config.region_aliases)),
|
|
||||||
(Some(p), None) => p.to_string(),
|
|
||||||
(None, Some(r)) => alias_region(r, &config.region_aliases),
|
|
||||||
};
|
|
||||||
module.create_segment("all", &config.region.with_value(&aws_segment));
|
|
||||||
}
|
|
||||||
AwsItems::Profile => {
|
|
||||||
let aws_profile = env::var("AWS_PROFILE").ok()?;
|
|
||||||
|
|
||||||
module.create_segment("profile", &config.profile.with_value(&aws_profile));
|
|
||||||
}
|
|
||||||
AwsItems::Region => {
|
|
||||||
let aws_region = alias_region(&get_aws_region()?, &config.region_aliases);
|
|
||||||
|
|
||||||
module.create_segment("region", &config.region.with_value(&aws_region));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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 {
|
||||||
|
"profile" => aws_profile.as_ref().map(Ok),
|
||||||
|
"region" => mapped_region.as_ref().map(Ok),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
|
module.set_segments(match parsed {
|
||||||
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::error!("Error in module `aws`: \n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
use super::{Context, Module, RootModuleConfig, Shell};
|
use super::{Context, Module, RootModuleConfig, Shell};
|
||||||
use crate::configs::battery::BatteryConfig;
|
use crate::configs::battery::BatteryConfig;
|
||||||
|
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
|
|
||||||
/// Creates a module for the battery percentage and charging state
|
/// Creates a module for the battery percentage and charging state
|
||||||
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
// TODO: Update when v1.0 printing refactor is implemented to only
|
// TODO: Update when v1.0 printing refactor is implemented to only
|
||||||
@ -14,60 +16,58 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
let BatteryStatus { state, percentage } = battery_status;
|
let BatteryStatus { state, percentage } = battery_status;
|
||||||
|
|
||||||
let mut module = context.new_module("battery");
|
let mut module = context.new_module("battery");
|
||||||
let battery_config: BatteryConfig = BatteryConfig::try_load(module.config);
|
let config: BatteryConfig = BatteryConfig::try_load(module.config);
|
||||||
|
|
||||||
// Parse config under `display`
|
// Parse config under `display`.
|
||||||
let display_styles = &battery_config.display;
|
// Select the first style that match the threshold,
|
||||||
let display_style = display_styles
|
// if all thresholds are lower do not display battery module.
|
||||||
|
let display_style = config
|
||||||
|
.display
|
||||||
.iter()
|
.iter()
|
||||||
.find(|display_style| percentage <= display_style.threshold as f32);
|
.find(|display_style| percentage <= display_style.threshold as f32)?;
|
||||||
|
|
||||||
if let Some(display_style) = display_style {
|
// Parse the format string and build the module
|
||||||
// Set style based on percentage
|
match StringFormatter::new(config.format) {
|
||||||
module.set_style(display_style.style);
|
Ok(formatter) => {
|
||||||
module.get_prefix().set_value("");
|
let formatter = formatter
|
||||||
|
.map_meta(|variable, _| match variable {
|
||||||
|
"symbol" => match state {
|
||||||
|
battery::State::Full => Some(config.full_symbol),
|
||||||
|
battery::State::Charging => Some(config.charging_symbol),
|
||||||
|
battery::State::Discharging => Some(config.discharging_symbol),
|
||||||
|
battery::State::Unknown => config.unknown_symbol,
|
||||||
|
battery::State::Empty => config.empty_symbol,
|
||||||
|
_ => {
|
||||||
|
log::debug!("Unhandled battery state `{}`", state);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map_style(|style| match style {
|
||||||
|
"style" => Some(Ok(display_style.style)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"percentage" => Some(Ok(format!("{}{}", percentage.round(), percentage_char))),
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
|
||||||
match state {
|
match formatter.parse(None) {
|
||||||
battery::State::Full => {
|
Ok(format_string) => {
|
||||||
module.create_segment("full_symbol", &battery_config.full_symbol);
|
module.set_segments(format_string);
|
||||||
}
|
Some(module)
|
||||||
battery::State::Charging => {
|
|
||||||
module.create_segment("charging_symbol", &battery_config.charging_symbol);
|
|
||||||
}
|
|
||||||
battery::State::Discharging => {
|
|
||||||
module.create_segment("discharging_symbol", &battery_config.discharging_symbol);
|
|
||||||
}
|
|
||||||
battery::State::Unknown => {
|
|
||||||
log::debug!("Unknown detected");
|
|
||||||
if let Some(unknown_symbol) = battery_config.unknown_symbol {
|
|
||||||
module.create_segment("unknown_symbol", &unknown_symbol);
|
|
||||||
}
|
}
|
||||||
}
|
Err(e) => {
|
||||||
battery::State::Empty => {
|
log::warn!("Cannot parse `battery.format`: {}", e);
|
||||||
if let Some(empty_symbol) = battery_config.empty_symbol {
|
None
|
||||||
module.create_segment("empty_symbol", &empty_symbol);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
|
||||||
log::debug!("Unhandled battery state `{}`", state);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Err(e) => {
|
||||||
let mut percent_string = Vec::<String>::with_capacity(2);
|
log::warn!("Cannot load `battery.format`: {}", e);
|
||||||
// Round the percentage to a whole number
|
None
|
||||||
percent_string.push(percentage.round().to_string());
|
}
|
||||||
percent_string.push(percentage_char.to_string());
|
|
||||||
module.create_segment(
|
|
||||||
"percentage",
|
|
||||||
&battery_config
|
|
||||||
.percentage
|
|
||||||
.with_value(percent_string.join("").as_ref()),
|
|
||||||
);
|
|
||||||
|
|
||||||
Some(module)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
use super::{Context, Module, RootModuleConfig, Shell};
|
use super::{Context, Module, RootModuleConfig, Shell};
|
||||||
use crate::configs::character::CharacterConfig;
|
use crate::configs::character::CharacterConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
|
|
||||||
/// Creates a module for the prompt character
|
/// Creates a module for the prompt character
|
||||||
///
|
///
|
||||||
/// The character segment prints an arrow character in a color dependant on the exit-
|
/// The character segment prints an arrow character in a color dependant on the
|
||||||
/// code of the last executed command:
|
/// exit-code of the last executed command:
|
||||||
/// - If the exit-code was "0", the arrow will be formatted with `style_success`
|
/// - If the exit-code was "0", it will be formatted with `success_symbol`
|
||||||
/// (green by default)
|
/// (green arrow by default)
|
||||||
/// - If the exit-code was anything else, the arrow will be formatted with
|
/// - If the exit-code was anything else, it will be formatted with
|
||||||
/// `style_failure` (red by default)
|
/// `error_symbol` (red arrow by default)
|
||||||
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
enum ShellEditMode {
|
enum ShellEditMode {
|
||||||
Normal,
|
Normal,
|
||||||
@ -19,12 +20,11 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
|
|
||||||
let mut module = context.new_module("character");
|
let mut module = context.new_module("character");
|
||||||
let config: CharacterConfig = CharacterConfig::try_load(module.config);
|
let config: CharacterConfig = CharacterConfig::try_load(module.config);
|
||||||
module.get_prefix().set_value("");
|
|
||||||
|
|
||||||
let props = &context.properties;
|
let props = &context.properties;
|
||||||
let exit_code_default = std::string::String::from("0");
|
let exit_code_default = String::from("0");
|
||||||
let exit_code = props.get("status_code").unwrap_or(&exit_code_default);
|
let exit_code = props.get("status_code").unwrap_or(&exit_code_default);
|
||||||
let keymap_default = std::string::String::from("viins");
|
let keymap_default = String::from("viins");
|
||||||
let keymap = props.get("keymap").unwrap_or(&keymap_default);
|
let keymap = props.get("keymap").unwrap_or(&keymap_default);
|
||||||
let exit_success = exit_code == "0";
|
let exit_success = exit_code == "0";
|
||||||
|
|
||||||
@ -38,22 +38,33 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
_ => ASSUMED_MODE,
|
_ => ASSUMED_MODE,
|
||||||
};
|
};
|
||||||
|
|
||||||
if exit_success {
|
let symbol = match mode {
|
||||||
module.set_style(config.style_success);
|
ShellEditMode::Normal => config.vicmd_symbol,
|
||||||
} else {
|
ShellEditMode::Insert => {
|
||||||
module.set_style(config.style_failure);
|
if exit_success {
|
||||||
};
|
config.success_symbol
|
||||||
|
} else {
|
||||||
/* If an error symbol is set in the config, use symbols to indicate
|
config.error_symbol
|
||||||
success/failure, in addition to color */
|
}
|
||||||
if config.use_symbol_for_status && !exit_success {
|
|
||||||
module.create_segment("error_symbol", &config.error_symbol)
|
|
||||||
} else {
|
|
||||||
match mode {
|
|
||||||
ShellEditMode::Normal => module.create_segment("vicmd_symbol", &config.vicmd_symbol),
|
|
||||||
ShellEditMode::Insert => module.create_segment("symbol", &config.symbol),
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
|
formatter
|
||||||
|
.map_meta(|variable, _| match variable {
|
||||||
|
"symbol" => Some(symbol),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
|
module.set_segments(match parsed {
|
||||||
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `character`:\n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::{Context, Module, SegmentConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::config::RootModuleConfig;
|
|
||||||
use crate::configs::cmd_duration::CmdDurationConfig;
|
use crate::configs::cmd_duration::CmdDurationConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
|
|
||||||
/// Outputs the time it took the last command to execute
|
/// Outputs the time it took the last command to execute
|
||||||
///
|
///
|
||||||
@ -28,19 +28,30 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let config_min = config.min_time as u128;
|
if elapsed < config.min_time as u128 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let module_color = match elapsed {
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
time if time < config_min => return None,
|
formatter
|
||||||
_ => config.style,
|
.map_style(|variable| match variable {
|
||||||
};
|
"style" => Some(Ok(config.style)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"duration" => Some(Ok(render_time(elapsed, config.show_milliseconds))),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
module.set_style(module_color);
|
module.set_segments(match parsed {
|
||||||
module.create_segment(
|
Ok(segments) => segments,
|
||||||
"cmd_duration",
|
Err(error) => {
|
||||||
&SegmentConfig::new(&render_time(elapsed, config.show_milliseconds)),
|
log::warn!("Error in module `cmd_duration`: \n{}", error);
|
||||||
);
|
return None;
|
||||||
module.get_prefix().set_value(config.prefix);
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use super::{Context, Module};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use super::utils::directory::truncate;
|
use super::utils::directory::truncate;
|
||||||
use crate::config::RootModuleConfig;
|
|
||||||
use crate::configs::conda::CondaConfig;
|
use crate::configs::conda::CondaConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
|
|
||||||
/// Creates a module with the current Conda environment
|
/// Creates a module with the current Conda environment
|
||||||
///
|
///
|
||||||
@ -17,14 +17,34 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut module = context.new_module("conda");
|
let mut module = context.new_module("conda");
|
||||||
let config = CondaConfig::try_load(module.config);
|
let config: CondaConfig = CondaConfig::try_load(module.config);
|
||||||
|
|
||||||
let conda_env = truncate(conda_env, config.truncation_length);
|
let conda_env = truncate(conda_env, config.truncation_length);
|
||||||
|
|
||||||
module.set_style(config.style);
|
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 {
|
||||||
|
"environment" => Some(Ok(conda_env.as_str())),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
module.create_segment("symbol", &config.symbol);
|
module.set_segments(match parsed {
|
||||||
module.create_segment("environment", &config.environment.with_value(&conda_env));
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `conda`:\n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use super::{Context, Module, RootModuleConfig, SegmentConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::configs::crystal::CrystalConfig;
|
use crate::configs::crystal::CrystalConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
/// Creates a module with the current Crystal version
|
/// Creates a module with the current Crystal version
|
||||||
@ -20,14 +21,34 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let crystal_version = utils::exec_cmd("crystal", &["--version"])?.stdout;
|
let crystal_version = utils::exec_cmd("crystal", &["--version"])?.stdout;
|
||||||
let formatted_version = format_crystal_version(&crystal_version)?;
|
|
||||||
|
|
||||||
let mut module = context.new_module("crystal");
|
let mut module = context.new_module("crystal");
|
||||||
let config: CrystalConfig = CrystalConfig::try_load(module.config);
|
let config: CrystalConfig = CrystalConfig::try_load(module.config);
|
||||||
module.set_style(config.style);
|
|
||||||
|
|
||||||
module.create_segment("symbol", &config.symbol);
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
module.create_segment("version", &SegmentConfig::new(&formatted_version));
|
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 {
|
||||||
|
"version" => format_crystal_version(&crystal_version).map(Ok),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
|
module.set_segments(match parsed {
|
||||||
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `crystal`:\n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
use ansi_term::Color;
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::process::{Command, Output, Stdio};
|
use std::process::{Command, Output, Stdio};
|
||||||
|
|
||||||
use super::{Context, Module, RootModuleConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::{config::SegmentConfig, configs::custom::CustomConfig};
|
use crate::{configs::custom::CustomConfig, formatter::StringFormatter};
|
||||||
|
|
||||||
/// Creates a custom module with some configuration
|
/// Creates a custom module with some configuration
|
||||||
///
|
///
|
||||||
@ -13,7 +12,7 @@ use crate::{config::SegmentConfig, configs::custom::CustomConfig};
|
|||||||
/// command can be run -- if its result is 0, the module will be shown.
|
/// command can be run -- if its result is 0, the module will be shown.
|
||||||
///
|
///
|
||||||
/// 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: &'a str, context: &'a Context) -> Option<Module<'a>> {
|
pub fn module<'a>(name: &str, context: &'a Context) -> Option<Module<'a>> {
|
||||||
let toml_config = context.config.get_custom_module_config(name).expect(
|
let toml_config = context.config.get_custom_module_config(name).expect(
|
||||||
"modules::custom::module should only be called after ensuring that the module exists",
|
"modules::custom::module should only be called after ensuring that the module exists",
|
||||||
);
|
);
|
||||||
@ -44,35 +43,42 @@ pub fn module<'a>(name: &'a str, context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut module = Module::new(name, config.description, Some(toml_config));
|
let mut module = Module::new(name, config.description, Some(toml_config));
|
||||||
let style = config.style.unwrap_or_else(|| Color::Green.bold());
|
|
||||||
|
|
||||||
if let Some(prefix) = config.prefix {
|
let output = exec_command(config.command, &config.shell.0)?;
|
||||||
module.get_prefix().set_value(prefix);
|
|
||||||
}
|
let trimmed = output.trim();
|
||||||
if let Some(suffix) = config.suffix {
|
if trimmed.is_empty() {
|
||||||
module.get_suffix().set_value(suffix);
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(symbol) = config.symbol {
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
module.create_segment("symbol", &symbol);
|
formatter
|
||||||
}
|
.map_meta(|var, _| match var {
|
||||||
|
"symbol" => Some(config.symbol),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map_style(|variable| match variable {
|
||||||
|
"style" => Some(Ok(config.style)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
// This may result in multiple calls to `get_module_version` when a user have
|
||||||
|
// multiple `$version` variables defined in `format`.
|
||||||
|
"output" => Some(Ok(trimmed)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
if let Some(output) = exec_command(config.command, &config.shell.0) {
|
module.set_segments(match parsed {
|
||||||
let trimmed = output.trim();
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
if trimmed.is_empty() {
|
log::warn!("Error in module `custom.{}`:\n{}", name, error);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
module.create_segment(
|
Some(module)
|
||||||
"output",
|
|
||||||
&SegmentConfig::new(&trimmed).with_style(Some(style)),
|
|
||||||
);
|
|
||||||
|
|
||||||
Some(module)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the invoking shell, using `shell` and fallbacking in order to STARSHIP_SHELL and "sh"
|
/// Return the invoking shell, using `shell` and fallbacking in order to STARSHIP_SHELL and "sh"
|
||||||
|
@ -7,8 +7,9 @@ use unicode_segmentation::UnicodeSegmentation;
|
|||||||
use super::{Context, Module};
|
use super::{Context, Module};
|
||||||
|
|
||||||
use super::utils::directory::truncate;
|
use super::utils::directory::truncate;
|
||||||
use crate::config::{RootModuleConfig, SegmentConfig};
|
use crate::config::RootModuleConfig;
|
||||||
use crate::configs::directory::DirectoryConfig;
|
use crate::configs::directory::DirectoryConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
|
|
||||||
/// Creates a module with the current directory
|
/// Creates a module with the current directory
|
||||||
///
|
///
|
||||||
@ -29,8 +30,6 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
let mut module = context.new_module("directory");
|
let mut module = context.new_module("directory");
|
||||||
let config: DirectoryConfig = DirectoryConfig::try_load(module.config);
|
let config: DirectoryConfig = DirectoryConfig::try_load(module.config);
|
||||||
|
|
||||||
module.set_style(config.style);
|
|
||||||
|
|
||||||
// Using environment PWD is the standard approach for determining logical path
|
// Using environment PWD is the standard approach for determining logical path
|
||||||
// If this is None for any reason, we fall back to reading the os-provided path
|
// If this is None for any reason, we fall back to reading the os-provided path
|
||||||
let physical_current_dir = if config.use_logical_path {
|
let physical_current_dir = if config.use_logical_path {
|
||||||
@ -80,33 +79,39 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
|
|
||||||
// Substitutions could have changed the prefix, so don't allow them and
|
// Substitutions could have changed the prefix, so don't allow them and
|
||||||
// fish-style path contraction together
|
// fish-style path contraction together
|
||||||
if config.fish_style_pwd_dir_length > 0 && config.substitutions.is_empty() {
|
let fish_prefix = if config.fish_style_pwd_dir_length > 0 && config.substitutions.is_empty() {
|
||||||
// If user is using fish style path, we need to add the segment first
|
// If user is using fish style path, we need to add the segment first
|
||||||
let contracted_home_dir = contract_path(¤t_dir, &home_dir, HOME_SYMBOL);
|
let contracted_home_dir = contract_path(¤t_dir, &home_dir, HOME_SYMBOL);
|
||||||
let fish_style_dir = to_fish_style(
|
to_fish_style(
|
||||||
config.fish_style_pwd_dir_length as usize,
|
config.fish_style_pwd_dir_length as usize,
|
||||||
contracted_home_dir,
|
contracted_home_dir,
|
||||||
&truncated_dir_string,
|
&truncated_dir_string,
|
||||||
);
|
)
|
||||||
|
} else {
|
||||||
|
String::from("")
|
||||||
|
};
|
||||||
|
let final_dir_string = format!("{}{}", fish_prefix, truncated_dir_string);
|
||||||
|
|
||||||
module.create_segment(
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
"path",
|
formatter
|
||||||
&SegmentConfig {
|
.map_style(|variable| match variable {
|
||||||
value: &fish_style_dir,
|
"style" => Some(Ok(config.style)),
|
||||||
style: None,
|
_ => None,
|
||||||
},
|
})
|
||||||
);
|
.map(|variable| match variable {
|
||||||
}
|
"path" => Some(Ok(&final_dir_string)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
module.create_segment(
|
module.set_segments(match parsed {
|
||||||
"path",
|
Ok(segments) => segments,
|
||||||
&SegmentConfig {
|
Err(error) => {
|
||||||
value: &truncated_dir_string,
|
log::warn!("Error in module `directory`:\n{}", error);
|
||||||
style: None,
|
return None;
|
||||||
},
|
}
|
||||||
);
|
});
|
||||||
|
|
||||||
module.get_prefix().set_value(config.prefix);
|
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
|
use std::env;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use super::{Context, Module, RootModuleConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::configs::docker_context::DockerContextConfig;
|
use crate::configs::docker_context::DockerContextConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
const DOCKER_CONFIG_FILE: &str = ".docker/config.json";
|
|
||||||
|
|
||||||
/// Creates a module with the currently active Docker context
|
/// Creates a module with the currently active Docker context
|
||||||
///
|
///
|
||||||
/// Will display the Docker context if the following criteria are met:
|
/// Will display the Docker context if the following criteria are met:
|
||||||
/// - There is a file named `$HOME/.docker/config.json`
|
/// - There is a file named `$HOME/.docker/config.json`
|
||||||
|
/// - Or a file named `$DOCKER_CONFIG/config.json`
|
||||||
/// - The file is JSON and contains a field named `currentContext`
|
/// - The file is JSON and contains a field named `currentContext`
|
||||||
/// - The value of `currentContext` is not `default`
|
/// - The value of `currentContext` is not `default`
|
||||||
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
@ -23,9 +26,17 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
let docker_config = PathBuf::from(
|
||||||
|
&env::var_os("DOCKER_CONFIG")
|
||||||
|
.unwrap_or(dirs_next::home_dir()?.join(".docker").into_os_string()),
|
||||||
|
)
|
||||||
|
.join("config.json");
|
||||||
|
|
||||||
let config_path = dirs_next::home_dir()?.join(DOCKER_CONFIG_FILE);
|
if !docker_config.exists() {
|
||||||
let json = utils::read_file(config_path).ok()?;
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let json = utils::read_file(docker_config).ok()?;
|
||||||
let parsed_json = serde_json::from_str(&json).ok()?;
|
let parsed_json = serde_json::from_str(&json).ok()?;
|
||||||
|
|
||||||
match parsed_json {
|
match parsed_json {
|
||||||
@ -33,9 +44,31 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
let current_context = root.get("currentContext")?;
|
let current_context = root.get("currentContext")?;
|
||||||
match current_context {
|
match current_context {
|
||||||
serde_json::Value::String(ctx) => {
|
serde_json::Value::String(ctx) => {
|
||||||
module.set_style(config.style);
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
module.create_segment("symbol", &config.symbol);
|
formatter
|
||||||
module.create_segment("context", &config.context.with_value(&ctx));
|
.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 {
|
||||||
|
"context" => Some(Ok(ctx)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
|
module.set_segments(match parsed {
|
||||||
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `docker_context`:\n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use quick_xml::events::Event;
|
||||||
|
use quick_xml::Reader;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::iter::Iterator;
|
use std::iter::Iterator;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
@ -6,6 +8,7 @@ use std::str;
|
|||||||
|
|
||||||
use super::{Context, Module, RootModuleConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
use crate::configs::dotnet::DotnetConfig;
|
use crate::configs::dotnet::DotnetConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
type JValue = serde_json::Value;
|
type JValue = serde_json::Value;
|
||||||
@ -48,20 +51,90 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
// Internally, this module uses its own mechanism for version detection.
|
// Internally, this module uses its own mechanism for version detection.
|
||||||
// Typically it is twice as fast as running `dotnet --version`.
|
// Typically it is twice as fast as running `dotnet --version`.
|
||||||
let enable_heuristic = config.heuristic;
|
let enable_heuristic = config.heuristic;
|
||||||
let version = if enable_heuristic {
|
|
||||||
let repo_root = context.get_repo().ok().and_then(|r| r.root.as_deref());
|
|
||||||
estimate_dotnet_version(&dotnet_files, &context.current_dir, repo_root)?
|
|
||||||
} else {
|
|
||||||
get_version_from_cli()?
|
|
||||||
};
|
|
||||||
|
|
||||||
module.set_style(config.style);
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
module.create_segment("symbol", &config.symbol);
|
formatter
|
||||||
module.create_segment("version", &config.version.with_value(&version.0));
|
.map_style(|variable| match variable {
|
||||||
|
"style" => Some(Ok(config.style)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"symbol" => Some(Ok(config.symbol)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"version" => {
|
||||||
|
let version = if enable_heuristic {
|
||||||
|
let repo_root = context.get_repo().ok().and_then(|r| r.root.as_deref());
|
||||||
|
estimate_dotnet_version(&dotnet_files, &context.current_dir, repo_root)
|
||||||
|
} else {
|
||||||
|
get_version_from_cli()
|
||||||
|
};
|
||||||
|
version.map(|v| Ok(v.0))
|
||||||
|
}
|
||||||
|
"tfm" => find_current_tfm(&dotnet_files).map(Ok),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
|
module.set_segments(match parsed {
|
||||||
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `dotnet`:\n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_current_tfm<'a>(files: &[DotNetFile<'a>]) -> Option<String> {
|
||||||
|
let get_file_of_type = |t: FileType| files.iter().find(|f| f.file_type == t);
|
||||||
|
|
||||||
|
let relevant_file = get_file_of_type(FileType::ProjectFile)?;
|
||||||
|
|
||||||
|
get_tfm_from_project_file(relevant_file.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_tfm_from_project_file(path: &Path) -> Option<String> {
|
||||||
|
let project_file = utils::read_file(path).ok()?;
|
||||||
|
let mut reader = Reader::from_str(&project_file);
|
||||||
|
reader.trim_text(true);
|
||||||
|
|
||||||
|
let mut in_tfm = false;
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match reader.read_event(&mut buf) {
|
||||||
|
// for triggering namespaced events, use this instead:
|
||||||
|
// match reader.read_namespaced_event(&mut buf) {
|
||||||
|
Ok(Event::Start(ref e)) => {
|
||||||
|
// for namespaced:
|
||||||
|
// Ok((ref namespace_value, Event::Start(ref e)))
|
||||||
|
match e.name() {
|
||||||
|
b"TargetFrameworks" => in_tfm = true,
|
||||||
|
b"TargetFramework" => in_tfm = true,
|
||||||
|
_ => in_tfm = false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// unescape and decode the text event using the reader encoding
|
||||||
|
Ok(Event::Text(e)) => {
|
||||||
|
if in_tfm {
|
||||||
|
return e.unescape_and_decode(&reader).ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Event::Eof) => break, // exits the loop when reaching end of file
|
||||||
|
Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
|
||||||
|
_ => (), // There are several other `Event`s we do not consider here
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we don't keep a borrow elsewhere, we can clear the buffer to keep memory usage low
|
||||||
|
buf.clear();
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn estimate_dotnet_version<'a>(
|
fn estimate_dotnet_version<'a>(
|
||||||
files: &[DotNetFile<'a>],
|
files: &[DotNetFile<'a>],
|
||||||
current_dir: &Path,
|
current_dir: &Path,
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
use regex::Regex;
|
|
||||||
|
|
||||||
use super::{Context, Module, RootModuleConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::configs::elixir::ElixirConfig;
|
use crate::configs::elixir::ElixirConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
|
use crate::utils;
|
||||||
|
|
||||||
|
use regex::Regex;
|
||||||
const ELIXIR_VERSION_PATTERN: &str = "\
|
const ELIXIR_VERSION_PATTERN: &str = "\
|
||||||
Erlang/OTP (?P<otp>\\d+)[^\\n]+
|
Erlang/OTP (?P<otp>\\d+)[^\\n]+
|
||||||
|
|
||||||
@ -11,7 +12,7 @@ Elixir (?P<elixir>\\d[.\\d]+).*";
|
|||||||
|
|
||||||
/// Create a module with the current Elixir version
|
/// Create a module with the current Elixir version
|
||||||
///
|
///
|
||||||
/// Will display the Rust version if any of the following criteria are met:
|
/// Will display the Elixir version if any of the following criteria are met:
|
||||||
/// - Current directory contains a `mix.exs` file
|
/// - Current directory contains a `mix.exs` file
|
||||||
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
let is_elixir_project = context.try_begin_scan()?.set_files(&["mix.exs"]).is_match();
|
let is_elixir_project = context.try_begin_scan()?.set_files(&["mix.exs"]).is_match();
|
||||||
@ -24,23 +25,36 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
|
|
||||||
let mut module = context.new_module("elixir");
|
let mut module = context.new_module("elixir");
|
||||||
let config = ElixirConfig::try_load(module.config);
|
let config = ElixirConfig::try_load(module.config);
|
||||||
module.set_style(config.style);
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
|
formatter
|
||||||
|
.map_meta(|var, _| match var {
|
||||||
|
"symbol" => Some(config.symbol),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map_style(|variable| match variable {
|
||||||
|
"style" => Some(Ok(config.style)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"version" => Some(Ok(&elixir_version)),
|
||||||
|
"otp_version" => Some(Ok(&otp_version)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
module.create_segment("symbol", &config.symbol);
|
module.set_segments(match parsed {
|
||||||
module.create_segment("version", &config.version.with_value(&elixir_version));
|
Ok(segments) => segments,
|
||||||
module.create_segment(
|
Err(error) => {
|
||||||
"otp_version",
|
log::warn!("Error in module `elixir`:\n{}", error);
|
||||||
&config
|
return None;
|
||||||
.otp_version
|
}
|
||||||
.with_value(&format!(" (OTP {})", otp_version)),
|
});
|
||||||
);
|
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_elixir_version() -> Option<(String, String)> {
|
fn get_elixir_version() -> Option<(String, String)> {
|
||||||
use crate::utils;
|
|
||||||
|
|
||||||
let output = utils::exec_cmd("elixir", &["--version"])?.stdout;
|
let output = utils::exec_cmd("elixir", &["--version"])?.stdout;
|
||||||
|
|
||||||
parse_elixir_version(&output)
|
parse_elixir_version(&output)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use super::{Context, Module, RootModuleConfig, SegmentConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::configs::elm::ElmConfig;
|
use crate::configs::elm::ElmConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
/// Creates a module with the current Elm version
|
/// Creates a module with the current Elm version
|
||||||
@ -24,14 +25,35 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let elm_version = utils::exec_cmd("elm", &["--version"])?.stdout;
|
let elm_version = utils::exec_cmd("elm", &["--version"])?.stdout;
|
||||||
let formatted_version = Some(format!("v{}", elm_version.trim()))?;
|
let module_version = Some(format!("v{}", elm_version.trim()))?;
|
||||||
|
|
||||||
let mut module = context.new_module("elm");
|
let mut module = context.new_module("elm");
|
||||||
let config: ElmConfig = ElmConfig::try_load(module.config);
|
let config: ElmConfig = ElmConfig::try_load(module.config);
|
||||||
module.set_style(config.style);
|
|
||||||
|
|
||||||
module.create_segment("symbol", &config.symbol);
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
module.create_segment("version", &SegmentConfig::new(&formatted_version));
|
formatter
|
||||||
|
.map_meta(|var, _| match var {
|
||||||
|
"symbol" => Some(config.symbol),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map_style(|variable| match variable {
|
||||||
|
"style" => Some(Ok(config.style)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"version" => Some(Ok(&module_version)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
|
module.set_segments(match parsed {
|
||||||
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `elm`:\n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use super::{Context, Module, SegmentConfig};
|
use super::{Context, Module};
|
||||||
|
|
||||||
use crate::config::RootModuleConfig;
|
use crate::config::RootModuleConfig;
|
||||||
use crate::configs::env_var::EnvVarConfig;
|
use crate::configs::env_var::EnvVarConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
|
|
||||||
/// Creates a module with the value of the chosen environment variable
|
/// Creates a module with the value of the chosen environment variable
|
||||||
///
|
///
|
||||||
@ -16,17 +17,30 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
let config: EnvVarConfig = EnvVarConfig::try_load(module.config);
|
let config: EnvVarConfig = EnvVarConfig::try_load(module.config);
|
||||||
|
|
||||||
let env_value = get_env_value(config.variable?, config.default)?;
|
let env_value = get_env_value(config.variable?, config.default)?;
|
||||||
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
|
formatter
|
||||||
|
.map_meta(|var, _| match var {
|
||||||
|
"symbol" => Some(config.symbol),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map_style(|variable| match variable {
|
||||||
|
"style" => Some(Ok(config.style)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"env_value" => Some(Ok(&env_value)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
module.set_style(config.style);
|
module.set_segments(match parsed {
|
||||||
module.get_prefix().set_value("with ");
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
if let Some(symbol) = config.symbol {
|
log::warn!("Error in module `env_var`:\n{}", error);
|
||||||
module.create_segment("symbol", &symbol);
|
return None;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
// TODO: Use native prefix and suffix instead of stacking custom ones together with env_value.
|
|
||||||
let env_var_stacked = format!("{}{}{}", config.prefix, env_value, config.suffix);
|
|
||||||
module.create_segment("env_var", &SegmentConfig::new(&env_var_stacked));
|
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use super::{Context, Module, RootModuleConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::configs::erlang::ErlangConfig;
|
use crate::configs::erlang::ErlangConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
|
|
||||||
/// Create a module with the current Erlang version
|
/// Create a module with the current Erlang version
|
||||||
///
|
///
|
||||||
@ -17,14 +18,33 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let erlang_version = get_erlang_version()?;
|
|
||||||
|
|
||||||
let mut module = context.new_module("erlang");
|
let mut module = context.new_module("erlang");
|
||||||
let config = ErlangConfig::try_load(module.config);
|
let config = ErlangConfig::try_load(module.config);
|
||||||
module.set_style(config.style);
|
|
||||||
|
|
||||||
module.create_segment("symbol", &config.symbol);
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
module.create_segment("version", &config.version.with_value(&erlang_version));
|
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 {
|
||||||
|
"version" => get_erlang_version().map(Ok),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
|
module.set_segments(match parsed {
|
||||||
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `erlang`:\n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ use unicode_segmentation::UnicodeSegmentation;
|
|||||||
use super::{Context, Module, RootModuleConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::configs::git_branch::GitBranchConfig;
|
use crate::configs::git_branch::GitBranchConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
|
|
||||||
/// Creates a module with the Git branch in the current directory
|
/// Creates a module with the Git branch in the current directory
|
||||||
///
|
///
|
||||||
@ -10,15 +11,11 @@ use crate::configs::git_branch::GitBranchConfig;
|
|||||||
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("git_branch");
|
let mut module = context.new_module("git_branch");
|
||||||
let config = GitBranchConfig::try_load(module.config);
|
let config = GitBranchConfig::try_load(module.config);
|
||||||
module.set_style(config.style);
|
|
||||||
|
|
||||||
module.get_prefix().set_value("on ");
|
let truncation_symbol = get_first_grapheme(config.truncation_symbol);
|
||||||
|
|
||||||
let truncation_symbol = get_graphemes(config.truncation_symbol, 1);
|
|
||||||
module.create_segment("symbol", &config.symbol);
|
|
||||||
|
|
||||||
// TODO: Once error handling is implemented, warn the user if their config
|
// TODO: Once error handling is implemented, warn the user if their config
|
||||||
// truncation length is nonsensical
|
// truncation length is nonsensical
|
||||||
let len = if config.truncation_length <= 0 {
|
let len = if config.truncation_length <= 0 {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"\"truncation_length\" should be a positive value, found {}",
|
"\"truncation_length\" should be a positive value, found {}",
|
||||||
@ -31,29 +28,50 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
|
|
||||||
let repo = context.get_repo().ok()?;
|
let repo = context.get_repo().ok()?;
|
||||||
let branch_name = repo.branch.as_ref()?;
|
let branch_name = repo.branch.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.create_segment(
|
let mut graphemes = get_graphemes(&branch_name);
|
||||||
"name",
|
let trunc_len = len.min(graphemes.len());
|
||||||
&config.branch_name.with_value(&truncated_and_symbol),
|
|
||||||
);
|
if trunc_len < graphemes.len() {
|
||||||
|
// The truncation symbol should only be added if we truncate
|
||||||
|
graphemes[trunc_len] = truncation_symbol;
|
||||||
|
graphemes.truncate(trunc_len + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
|
formatter
|
||||||
|
.map_meta(|var, _| match var {
|
||||||
|
"symbol" => Some(config.symbol),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map_style(|variable| match variable {
|
||||||
|
"style" => Some(Ok(config.style)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"branch" => Some(Ok(graphemes.concat())),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
|
module.set_segments(match parsed {
|
||||||
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `git_branch`: \n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_graphemes(text: &str, length: usize) -> String {
|
fn get_first_grapheme(text: &str) -> &str {
|
||||||
UnicodeSegmentation::graphemes(text, true)
|
UnicodeSegmentation::graphemes(text, true)
|
||||||
.take(length)
|
.next()
|
||||||
.collect::<Vec<&str>>()
|
.unwrap_or("")
|
||||||
.concat()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn graphemes_len(text: &str) -> usize {
|
fn get_graphemes(text: &str) -> Vec<&str> {
|
||||||
UnicodeSegmentation::graphemes(&text[..], true).count()
|
UnicodeSegmentation::graphemes(text, true).collect()
|
||||||
}
|
}
|
||||||
|
@ -2,23 +2,14 @@ use super::{Context, Module, RootModuleConfig};
|
|||||||
use git2::Repository;
|
use git2::Repository;
|
||||||
|
|
||||||
use crate::configs::git_commit::GitCommitConfig;
|
use crate::configs::git_commit::GitCommitConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
|
|
||||||
/// Creates a module with the Git commit in the current directory
|
/// Creates a module with the Git commit in the current directory
|
||||||
///
|
///
|
||||||
/// Will display the commit hash if the current directory is a git repo
|
/// Will display the commit hash if the current directory is a git repo
|
||||||
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("git_commit");
|
let mut module = context.new_module("git_commit");
|
||||||
let config = GitCommitConfig::try_load(module.config);
|
let config: GitCommitConfig = GitCommitConfig::try_load(module.config);
|
||||||
|
|
||||||
module
|
|
||||||
.get_prefix()
|
|
||||||
.set_value(config.prefix)
|
|
||||||
.set_style(config.style);
|
|
||||||
module
|
|
||||||
.get_suffix()
|
|
||||||
.set_value(config.suffix)
|
|
||||||
.set_style(config.style);
|
|
||||||
module.set_style(config.style);
|
|
||||||
|
|
||||||
let repo = context.get_repo().ok()?;
|
let repo = context.get_repo().ok()?;
|
||||||
let repo_root = repo.root.as_ref()?;
|
let repo_root = repo.root.as_ref()?;
|
||||||
@ -32,13 +23,30 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
let git_head = git_repo.head().ok()?;
|
let git_head = git_repo.head().ok()?;
|
||||||
let head_commit = git_head.peel_to_commit().ok()?;
|
let head_commit = git_head.peel_to_commit().ok()?;
|
||||||
let commit_oid = head_commit.id();
|
let commit_oid = head_commit.id();
|
||||||
module.create_segment(
|
|
||||||
"hash",
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
&config.hash.with_value(&id_to_hex_abbrev(
|
formatter
|
||||||
commit_oid.as_bytes(),
|
.map_style(|variable| match variable {
|
||||||
config.commit_hash_length,
|
"style" => Some(Ok(config.style)),
|
||||||
)),
|
_ => None,
|
||||||
);
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"hash" => Some(Ok(id_to_hex_abbrev(
|
||||||
|
commit_oid.as_bytes(),
|
||||||
|
config.commit_hash_length,
|
||||||
|
))),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
|
module.set_segments(match parsed {
|
||||||
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `git_commit`:\n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use git2::RepositoryState;
|
use git2::RepositoryState;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use super::{Context, Module, RootModuleConfig, SegmentConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
use crate::configs::git_state::GitStateConfig;
|
use crate::configs::git_state::GitStateConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
|
|
||||||
/// Creates a module with the state of the git repository at the current directory
|
/// Creates a module with the state of the git repository at the current directory
|
||||||
///
|
///
|
||||||
@ -12,37 +13,37 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
let mut module = context.new_module("git_state");
|
let mut module = context.new_module("git_state");
|
||||||
let config: GitStateConfig = GitStateConfig::try_load(module.config);
|
let config: GitStateConfig = GitStateConfig::try_load(module.config);
|
||||||
|
|
||||||
module.set_style(config.style);
|
|
||||||
module.get_prefix().set_value("(");
|
|
||||||
module.get_suffix().set_value(") ");
|
|
||||||
|
|
||||||
let repo = context.get_repo().ok()?;
|
let repo = context.get_repo().ok()?;
|
||||||
let repo_root = repo.root.as_ref()?;
|
let repo_root = repo.root.as_ref()?;
|
||||||
let repo_state = repo.state?;
|
let repo_state = repo.state?;
|
||||||
|
|
||||||
let state_description = get_state_description(repo_state, repo_root, config);
|
let state_description = get_state_description(repo_state, repo_root, &config)?;
|
||||||
|
|
||||||
let label = match &state_description {
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
StateDescription::Label(label) => label,
|
formatter
|
||||||
StateDescription::LabelAndProgress(label, _) => label,
|
.map_meta(|variable, _| match variable {
|
||||||
StateDescription::Clean => {
|
"state" => Some(state_description.label),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map_style(|variable| match variable {
|
||||||
|
"style" => Some(Ok(config.style)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"progress_current" => state_description.current.as_ref().map(Ok),
|
||||||
|
"progress_total" => state_description.total.as_ref().map(Ok),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
|
module.set_segments(match parsed {
|
||||||
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `git_state`:\n{}", error);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
module.create_segment(label.name, &label.segment);
|
|
||||||
|
|
||||||
if let StateDescription::LabelAndProgress(_, progress) = &state_description {
|
|
||||||
module.create_segment(
|
|
||||||
"progress_current",
|
|
||||||
&SegmentConfig::new(&format!(" {}", progress.current)),
|
|
||||||
);
|
|
||||||
module.create_segment("progress_divider", &SegmentConfig::new("/"));
|
|
||||||
module.create_segment(
|
|
||||||
"progress_total",
|
|
||||||
&SegmentConfig::new(&format!("{}", progress.total)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
@ -53,40 +54,57 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
fn get_state_description<'a>(
|
fn get_state_description<'a>(
|
||||||
state: RepositoryState,
|
state: RepositoryState,
|
||||||
root: &'a std::path::PathBuf,
|
root: &'a std::path::PathBuf,
|
||||||
config: GitStateConfig<'a>,
|
config: &GitStateConfig<'a>,
|
||||||
) -> StateDescription<'a> {
|
) -> Option<StateDescription<'a>> {
|
||||||
match state {
|
match state {
|
||||||
RepositoryState::Clean => StateDescription::Clean,
|
RepositoryState::Clean => None,
|
||||||
RepositoryState::Merge => StateDescription::Label(StateLabel::new("merge", config.merge)),
|
RepositoryState::Merge => Some(StateDescription {
|
||||||
RepositoryState::Revert => {
|
label: config.merge,
|
||||||
StateDescription::Label(StateLabel::new("revert", config.revert))
|
current: None,
|
||||||
}
|
total: None,
|
||||||
RepositoryState::RevertSequence => {
|
}),
|
||||||
StateDescription::Label(StateLabel::new("revert", config.revert))
|
RepositoryState::Revert => Some(StateDescription {
|
||||||
}
|
label: config.revert,
|
||||||
RepositoryState::CherryPick => {
|
current: None,
|
||||||
StateDescription::Label(StateLabel::new("cherry_pick", config.cherry_pick))
|
total: None,
|
||||||
}
|
}),
|
||||||
RepositoryState::CherryPickSequence => {
|
RepositoryState::RevertSequence => Some(StateDescription {
|
||||||
StateDescription::Label(StateLabel::new("cherry_pick", config.cherry_pick))
|
label: config.revert,
|
||||||
}
|
current: None,
|
||||||
RepositoryState::Bisect => {
|
total: None,
|
||||||
StateDescription::Label(StateLabel::new("bisect", config.bisect))
|
}),
|
||||||
}
|
RepositoryState::CherryPick => Some(StateDescription {
|
||||||
RepositoryState::ApplyMailbox => StateDescription::Label(StateLabel::new("am", config.am)),
|
label: config.cherry_pick,
|
||||||
RepositoryState::ApplyMailboxOrRebase => {
|
current: None,
|
||||||
StateDescription::Label(StateLabel::new("am_or_rebase", config.am_or_rebase))
|
total: None,
|
||||||
}
|
}),
|
||||||
RepositoryState::Rebase => describe_rebase(root, config.rebase),
|
RepositoryState::CherryPickSequence => Some(StateDescription {
|
||||||
RepositoryState::RebaseInteractive => describe_rebase(root, config.rebase),
|
label: config.cherry_pick,
|
||||||
RepositoryState::RebaseMerge => describe_rebase(root, config.rebase),
|
current: None,
|
||||||
|
total: None,
|
||||||
|
}),
|
||||||
|
RepositoryState::Bisect => Some(StateDescription {
|
||||||
|
label: config.bisect,
|
||||||
|
current: None,
|
||||||
|
total: None,
|
||||||
|
}),
|
||||||
|
RepositoryState::ApplyMailbox => Some(StateDescription {
|
||||||
|
label: config.am,
|
||||||
|
current: None,
|
||||||
|
total: None,
|
||||||
|
}),
|
||||||
|
RepositoryState::ApplyMailboxOrRebase => Some(StateDescription {
|
||||||
|
label: config.am_or_rebase,
|
||||||
|
current: None,
|
||||||
|
total: None,
|
||||||
|
}),
|
||||||
|
RepositoryState::Rebase => Some(describe_rebase(root, config.rebase)),
|
||||||
|
RepositoryState::RebaseInteractive => Some(describe_rebase(root, config.rebase)),
|
||||||
|
RepositoryState::RebaseMerge => Some(describe_rebase(root, config.rebase)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn describe_rebase<'a>(
|
fn describe_rebase<'a>(root: &'a PathBuf, rebase_config: &'a str) -> StateDescription<'a> {
|
||||||
root: &'a PathBuf,
|
|
||||||
rebase_config: SegmentConfig<'a>,
|
|
||||||
) -> StateDescription<'a> {
|
|
||||||
/*
|
/*
|
||||||
* Sadly, libgit2 seems to have some issues with reading the state of
|
* Sadly, libgit2 seems to have some issues with reading the state of
|
||||||
* interactive rebases. So, instead, we'll poke a few of the .git files
|
* interactive rebases. So, instead, we'll poke a few of the .git files
|
||||||
@ -98,12 +116,12 @@ fn describe_rebase<'a>(
|
|||||||
let dot_git = root.join(".git");
|
let dot_git = root.join(".git");
|
||||||
|
|
||||||
let has_path = |relative_path: &str| {
|
let has_path = |relative_path: &str| {
|
||||||
let path = dot_git.join(Path::new(relative_path));
|
let path = dot_git.join(PathBuf::from(relative_path));
|
||||||
path.exists()
|
path.exists()
|
||||||
};
|
};
|
||||||
|
|
||||||
let file_to_usize = |relative_path: &str| {
|
let file_to_usize = |relative_path: &str| {
|
||||||
let path = dot_git.join(Path::new(relative_path));
|
let path = dot_git.join(PathBuf::from(relative_path));
|
||||||
let contents = crate::utils::read_file(path).ok()?;
|
let contents = crate::utils::read_file(path).ok()?;
|
||||||
let quantity = contents.trim().parse::<usize>().ok()?;
|
let quantity = contents.trim().parse::<usize>().ok()?;
|
||||||
Some(quantity)
|
Some(quantity)
|
||||||
@ -112,7 +130,7 @@ fn describe_rebase<'a>(
|
|||||||
let paths_to_progress = |current_path: &str, total_path: &str| {
|
let paths_to_progress = |current_path: &str, total_path: &str| {
|
||||||
let current = file_to_usize(current_path)?;
|
let current = file_to_usize(current_path)?;
|
||||||
let total = file_to_usize(total_path)?;
|
let total = file_to_usize(total_path)?;
|
||||||
Some(StateProgress { current, total })
|
Some((current, total))
|
||||||
};
|
};
|
||||||
|
|
||||||
let progress = if has_path("rebase-merge") {
|
let progress = if has_path("rebase-merge") {
|
||||||
@ -123,32 +141,15 @@ fn describe_rebase<'a>(
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
match progress {
|
StateDescription {
|
||||||
None => StateDescription::Label(StateLabel::new("rebase", rebase_config)),
|
label: rebase_config,
|
||||||
Some(progress) => {
|
current: Some(format!("{}", progress.unwrap().0)),
|
||||||
StateDescription::LabelAndProgress(StateLabel::new("rebase", rebase_config), progress)
|
total: Some(format!("{}", progress.unwrap().1)),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum StateDescription<'a> {
|
struct StateDescription<'a> {
|
||||||
Clean,
|
label: &'a str,
|
||||||
Label(StateLabel<'a>),
|
current: Option<String>,
|
||||||
LabelAndProgress(StateLabel<'a>, StateProgress),
|
total: Option<String>,
|
||||||
}
|
|
||||||
|
|
||||||
struct StateLabel<'a> {
|
|
||||||
name: &'static str,
|
|
||||||
segment: SegmentConfig<'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct StateProgress {
|
|
||||||
current: usize,
|
|
||||||
total: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> StateLabel<'a> {
|
|
||||||
fn new(name: &'static str, segment: SegmentConfig<'a>) -> Self {
|
|
||||||
Self { name, segment }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,13 @@ use git2::{Repository, Status};
|
|||||||
|
|
||||||
use super::{Context, Module, RootModuleConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::config::SegmentConfig;
|
use crate::configs::git_status::GitStatusConfig;
|
||||||
use crate::configs::git_status::{CountConfig, GitStatusConfig};
|
use crate::context::Repo;
|
||||||
use std::borrow::BorrowMut;
|
use crate::formatter::StringFormatter;
|
||||||
use std::collections::HashMap;
|
use crate::segment::Segment;
|
||||||
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
|
const ALL_STATUS_FORMAT: &str = "$conflicted$stashed$deleted$renamed$modified$staged$untracked";
|
||||||
|
|
||||||
/// Creates a module with the Git branch in the current directory
|
/// Creates a module with the Git branch in the current directory
|
||||||
///
|
///
|
||||||
@ -23,174 +26,233 @@ use std::collections::HashMap;
|
|||||||
/// - `✘` — A file's deletion has been added to the staging area
|
/// - `✘` — A file's deletion has been added to the staging area
|
||||||
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
let repo = context.get_repo().ok()?;
|
let repo = context.get_repo().ok()?;
|
||||||
let branch_name = repo.branch.as_ref()?;
|
let info = Arc::new(GitStatusInfo::load(repo));
|
||||||
let repo_root = repo.root.as_ref()?;
|
|
||||||
let mut repository = Repository::open(repo_root).ok()?;
|
|
||||||
|
|
||||||
let mut module = context.new_module("git_status");
|
let mut module = context.new_module("git_status");
|
||||||
let config: GitStatusConfig = GitStatusConfig::try_load(module.config);
|
let config: GitStatusConfig = GitStatusConfig::try_load(module.config);
|
||||||
|
|
||||||
module
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
.get_prefix()
|
formatter
|
||||||
.set_value(config.prefix)
|
.map_meta(|variable, _| match variable {
|
||||||
.set_style(config.style);
|
"all_status" => Some(ALL_STATUS_FORMAT),
|
||||||
module
|
_ => None,
|
||||||
.get_suffix()
|
})
|
||||||
.set_value(config.suffix)
|
.map_style(|variable: &str| match variable {
|
||||||
.set_style(config.style);
|
"style" => Some(Ok(config.style)),
|
||||||
module.set_style(config.style);
|
_ => None,
|
||||||
|
})
|
||||||
|
.map_variables_to_segments(|variable: &str| {
|
||||||
|
let info = Arc::clone(&info);
|
||||||
|
let segments = match variable {
|
||||||
|
"stashed" => info.get_stashed().and_then(|count| {
|
||||||
|
format_count(config.stashed, "git_status.stashed", count)
|
||||||
|
}),
|
||||||
|
"ahead_behind" => info.get_ahead_behind().and_then(|(ahead, behind)| {
|
||||||
|
if ahead > 0 && behind > 0 {
|
||||||
|
format_text(config.diverged, "git_status.diverged", |variable| {
|
||||||
|
match variable {
|
||||||
|
"ahead_count" => Some(ahead.to_string()),
|
||||||
|
"behind_count" => Some(behind.to_string()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if ahead > 0 && behind == 0 {
|
||||||
|
format_count(config.ahead, "git_status.ahead", ahead)
|
||||||
|
} else if behind > 0 && ahead == 0 {
|
||||||
|
format_count(config.behind, "git_status.behind", behind)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
"conflicted" => info.get_conflicted().and_then(|count| {
|
||||||
|
format_count(config.conflicted, "git_status.conflicted", count)
|
||||||
|
}),
|
||||||
|
"deleted" => info.get_deleted().and_then(|count| {
|
||||||
|
format_count(config.deleted, "git_status.deleted", count)
|
||||||
|
}),
|
||||||
|
"renamed" => info.get_renamed().and_then(|count| {
|
||||||
|
format_count(config.renamed, "git_status.renamed", count)
|
||||||
|
}),
|
||||||
|
"modified" => info.get_modified().and_then(|count| {
|
||||||
|
format_count(config.modified, "git_status.modified", count)
|
||||||
|
}),
|
||||||
|
"staged" => info
|
||||||
|
.get_staged()
|
||||||
|
.and_then(|count| format_count(config.staged, "git_status.staged", count)),
|
||||||
|
"untracked" => info.get_untracked().and_then(|count| {
|
||||||
|
format_count(config.untracked, "git_status.untracked", count)
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
segments.map(Ok)
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
let repo_status = get_repo_status(repository.borrow_mut());
|
module.set_segments(match parsed {
|
||||||
log::debug!("Repo status: {:?}", repo_status);
|
Ok(segments) => {
|
||||||
|
if segments.is_empty() {
|
||||||
let ahead_behind = get_ahead_behind(&repository, branch_name);
|
return None;
|
||||||
if ahead_behind == Ok((0, 0)) {
|
} else {
|
||||||
log::trace!("No ahead/behind found");
|
segments
|
||||||
} else {
|
|
||||||
log::debug!("Repo ahead/behind: {:?}", ahead_behind);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the conflicted segment
|
|
||||||
if let Ok(repo_status) = repo_status {
|
|
||||||
create_segment_with_count(
|
|
||||||
&mut module,
|
|
||||||
"conflicted",
|
|
||||||
repo_status.conflicted,
|
|
||||||
&config.conflicted,
|
|
||||||
config.conflicted_count,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the ahead/behind segment
|
|
||||||
if let Ok((ahead, behind)) = ahead_behind {
|
|
||||||
let add_ahead = |m: &mut Module<'a>| {
|
|
||||||
create_segment_with_count(
|
|
||||||
m,
|
|
||||||
"ahead",
|
|
||||||
ahead,
|
|
||||||
&config.ahead,
|
|
||||||
CountConfig {
|
|
||||||
enabled: config.show_sync_count,
|
|
||||||
style: None,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
let add_behind = |m: &mut Module<'a>| {
|
|
||||||
create_segment_with_count(
|
|
||||||
m,
|
|
||||||
"behind",
|
|
||||||
behind,
|
|
||||||
&config.behind,
|
|
||||||
CountConfig {
|
|
||||||
enabled: config.show_sync_count,
|
|
||||||
style: None,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
if ahead > 0 && behind > 0 {
|
|
||||||
module.create_segment("diverged", &config.diverged);
|
|
||||||
|
|
||||||
if config.show_sync_count {
|
|
||||||
add_ahead(&mut module);
|
|
||||||
add_behind(&mut module);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Err(error) => {
|
||||||
if ahead > 0 && behind == 0 {
|
log::warn!("Error in module `git_status`:\n{}", error);
|
||||||
add_ahead(&mut module);
|
return None;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
if behind > 0 && ahead == 0 {
|
|
||||||
add_behind(&mut module);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the stashed segment
|
|
||||||
if let Ok(repo_status) = repo_status {
|
|
||||||
create_segment_with_count(
|
|
||||||
&mut module,
|
|
||||||
"stashed",
|
|
||||||
repo_status.stashed,
|
|
||||||
&config.stashed,
|
|
||||||
config.stashed_count,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add all remaining status segments
|
|
||||||
if let Ok(repo_status) = repo_status {
|
|
||||||
create_segment_with_count(
|
|
||||||
&mut module,
|
|
||||||
"deleted",
|
|
||||||
repo_status.deleted,
|
|
||||||
&config.deleted,
|
|
||||||
config.deleted_count,
|
|
||||||
);
|
|
||||||
|
|
||||||
create_segment_with_count(
|
|
||||||
&mut module,
|
|
||||||
"renamed",
|
|
||||||
repo_status.renamed,
|
|
||||||
&config.renamed,
|
|
||||||
config.renamed_count,
|
|
||||||
);
|
|
||||||
|
|
||||||
create_segment_with_count(
|
|
||||||
&mut module,
|
|
||||||
"modified",
|
|
||||||
repo_status.modified,
|
|
||||||
&config.modified,
|
|
||||||
config.modified_count,
|
|
||||||
);
|
|
||||||
|
|
||||||
create_segment_with_count(
|
|
||||||
&mut module,
|
|
||||||
"staged",
|
|
||||||
repo_status.staged,
|
|
||||||
&config.staged,
|
|
||||||
config.staged_count,
|
|
||||||
);
|
|
||||||
|
|
||||||
create_segment_with_count(
|
|
||||||
&mut module,
|
|
||||||
"untracked",
|
|
||||||
repo_status.untracked,
|
|
||||||
&config.untracked,
|
|
||||||
config.untracked_count,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if module.is_empty() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_segment_with_count<'a>(
|
struct GitStatusInfo<'a> {
|
||||||
module: &mut Module<'a>,
|
repo: &'a Repo,
|
||||||
name: &str,
|
ahead_behind: RwLock<Option<Result<(usize, usize), git2::Error>>>,
|
||||||
count: usize,
|
repo_status: RwLock<Option<Result<RepoStatus, git2::Error>>>,
|
||||||
config: &SegmentConfig<'a>,
|
stashed_count: RwLock<Option<Result<usize, git2::Error>>>,
|
||||||
count_config: CountConfig,
|
}
|
||||||
) {
|
|
||||||
if count > 0 {
|
|
||||||
module.create_segment(name, &config);
|
|
||||||
|
|
||||||
if count_config.enabled {
|
impl<'a> GitStatusInfo<'a> {
|
||||||
module.create_segment(
|
pub fn load(repo: &'a Repo) -> Self {
|
||||||
&format!("{}_count", name),
|
Self {
|
||||||
&SegmentConfig::new(&count.to_string()).with_style(count_config.style),
|
repo,
|
||||||
);
|
ahead_behind: RwLock::new(None),
|
||||||
|
repo_status: RwLock::new(None),
|
||||||
|
stashed_count: RwLock::new(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_branch_name(&self) -> String {
|
||||||
|
self.repo
|
||||||
|
.branch
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_else(|| String::from("master"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_repository(&self) -> Option<Repository> {
|
||||||
|
// bare repos don't have a branch name, so `repo.branch.as_ref` would return None,
|
||||||
|
// but git treats "master" as the default branch name
|
||||||
|
let repo_root = self.repo.root.as_ref()?;
|
||||||
|
Repository::open(repo_root).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_ahead_behind(&self) -> Option<(usize, usize)> {
|
||||||
|
{
|
||||||
|
let data = self.ahead_behind.read().unwrap();
|
||||||
|
if let Some(result) = data.as_ref() {
|
||||||
|
return match result.as_ref() {
|
||||||
|
Ok(ahead_behind) => Some(*ahead_behind),
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Warn: get_ahead_behind: {}", error);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let repo = self.get_repository()?;
|
||||||
|
let branch_name = self.get_branch_name();
|
||||||
|
let mut data = self.ahead_behind.write().unwrap();
|
||||||
|
*data = Some(get_ahead_behind(&repo, &branch_name));
|
||||||
|
match data.as_ref().unwrap() {
|
||||||
|
Ok(ahead_behind) => Some(*ahead_behind),
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Warn: get_ahead_behind: {}", error);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_repo_status(&self) -> Option<RepoStatus> {
|
||||||
|
{
|
||||||
|
let data = self.repo_status.read().unwrap();
|
||||||
|
if let Some(result) = data.as_ref() {
|
||||||
|
return match result.as_ref() {
|
||||||
|
Ok(repo_status) => Some(*repo_status),
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Warn: get_repo_status: {}", error);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut repo = self.get_repository()?;
|
||||||
|
let mut data = self.repo_status.write().unwrap();
|
||||||
|
*data = Some(get_repo_status(&mut repo));
|
||||||
|
match data.as_ref().unwrap() {
|
||||||
|
Ok(repo_status) => Some(*repo_status),
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Warn: get_repo_status: {}", error);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_stashed(&self) -> Option<usize> {
|
||||||
|
{
|
||||||
|
let data = self.stashed_count.read().unwrap();
|
||||||
|
if let Some(result) = data.as_ref() {
|
||||||
|
return match result.as_ref() {
|
||||||
|
Ok(stashed_count) => Some(*stashed_count),
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Warn: get_stashed_count: {}", error);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut repo = self.get_repository()?;
|
||||||
|
let mut data = self.stashed_count.write().unwrap();
|
||||||
|
*data = Some(get_stashed_count(&mut repo));
|
||||||
|
match data.as_ref().unwrap() {
|
||||||
|
Ok(stashed_count) => Some(*stashed_count),
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Warn: get_stashed_count: {}", error);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_conflicted(&self) -> Option<usize> {
|
||||||
|
self.get_repo_status().map(|data| data.conflicted)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_deleted(&self) -> Option<usize> {
|
||||||
|
self.get_repo_status().map(|data| data.deleted)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_renamed(&self) -> Option<usize> {
|
||||||
|
self.get_repo_status().map(|data| data.renamed)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_modified(&self) -> Option<usize> {
|
||||||
|
self.get_repo_status().map(|data| data.modified)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_staged(&self) -> Option<usize> {
|
||||||
|
self.get_repo_status().map(|data| data.staged)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_untracked(&self) -> Option<usize> {
|
||||||
|
self.get_repo_status().map(|data| data.untracked)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the number of files in various git states (staged, modified, deleted, etc...)
|
/// Gets the number of files in various git states (staged, modified, deleted, etc...)
|
||||||
fn get_repo_status(repository: &mut Repository) -> Result<RepoStatus, git2::Error> {
|
fn get_repo_status(repository: &mut Repository) -> Result<RepoStatus, git2::Error> {
|
||||||
let mut status_options = git2::StatusOptions::new();
|
let mut status_options = git2::StatusOptions::new();
|
||||||
|
|
||||||
|
let mut repo_status = RepoStatus::default();
|
||||||
|
|
||||||
match repository.config()?.get_entry("status.showUntrackedFiles") {
|
match repository.config()?.get_entry("status.showUntrackedFiles") {
|
||||||
Ok(entry) => status_options.include_untracked(entry.value() != Some("no")),
|
Ok(entry) => status_options.include_untracked(entry.value() != Some("no")),
|
||||||
_ => status_options.include_untracked(true),
|
_ => status_options.include_untracked(true),
|
||||||
@ -201,76 +263,21 @@ fn get_repo_status(repository: &mut Repository) -> Result<RepoStatus, git2::Erro
|
|||||||
.renames_index_to_workdir(true)
|
.renames_index_to_workdir(true)
|
||||||
.include_unmodified(true);
|
.include_unmodified(true);
|
||||||
|
|
||||||
let statuses: Vec<Status> = repository
|
let statuses = repository.statuses(Some(&mut status_options))?;
|
||||||
.statuses(Some(&mut status_options))?
|
|
||||||
.iter()
|
|
||||||
.map(|s| s.status())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
if statuses.is_empty() {
|
if statuses.is_empty() {
|
||||||
return Err(git2::Error::from_str("Repo has no status"));
|
return Err(git2::Error::from_str("Repo has no status"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let statuses_count = count_statuses(statuses);
|
statuses
|
||||||
|
.iter()
|
||||||
let repo_status: RepoStatus = RepoStatus {
|
.map(|s| s.status())
|
||||||
conflicted: *statuses_count.get("conflicted").unwrap_or(&0),
|
.for_each(|status| repo_status.add(status));
|
||||||
deleted: *statuses_count.get("deleted").unwrap_or(&0),
|
|
||||||
renamed: *statuses_count.get("renamed").unwrap_or(&0),
|
|
||||||
modified: *statuses_count.get("modified").unwrap_or(&0),
|
|
||||||
staged: *statuses_count.get("staged").unwrap_or(&0),
|
|
||||||
untracked: *statuses_count.get("untracked").unwrap_or(&0),
|
|
||||||
stashed: stashed_count(repository)?,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(repo_status)
|
Ok(repo_status)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn count_statuses(statuses: Vec<Status>) -> HashMap<&'static str, usize> {
|
fn get_stashed_count(repository: &mut Repository) -> Result<usize, git2::Error> {
|
||||||
let mut predicates: HashMap<&'static str, fn(git2::Status) -> bool> = HashMap::new();
|
|
||||||
predicates.insert("conflicted", is_conflicted);
|
|
||||||
predicates.insert("deleted", is_deleted);
|
|
||||||
predicates.insert("renamed", is_renamed);
|
|
||||||
predicates.insert("modified", is_modified);
|
|
||||||
predicates.insert("staged", is_staged);
|
|
||||||
predicates.insert("untracked", is_untracked);
|
|
||||||
|
|
||||||
statuses.iter().fold(HashMap::new(), |mut map, status| {
|
|
||||||
for (key, predicate) in predicates.iter() {
|
|
||||||
if predicate(*status) {
|
|
||||||
let entry = map.entry(key).or_insert(0);
|
|
||||||
*entry += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
map
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_conflicted(status: Status) -> bool {
|
|
||||||
status.is_conflicted()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_deleted(status: Status) -> bool {
|
|
||||||
status.is_wt_deleted() || status.is_index_deleted()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_renamed(status: Status) -> bool {
|
|
||||||
status.is_wt_renamed() || status.is_index_renamed()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_modified(status: Status) -> bool {
|
|
||||||
status.is_wt_modified()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_staged(status: Status) -> bool {
|
|
||||||
status.is_index_modified() || status.is_index_new()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_untracked(status: Status) -> bool {
|
|
||||||
status.is_wt_new()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stashed_count(repository: &mut Repository) -> Result<usize, git2::Error> {
|
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
repository.stash_foreach(|_, _, _| {
|
repository.stash_foreach(|_, _, _| {
|
||||||
count += 1;
|
count += 1;
|
||||||
@ -303,5 +310,65 @@ struct RepoStatus {
|
|||||||
modified: usize,
|
modified: usize,
|
||||||
staged: usize,
|
staged: usize,
|
||||||
untracked: usize,
|
untracked: usize,
|
||||||
stashed: usize,
|
}
|
||||||
|
|
||||||
|
impl RepoStatus {
|
||||||
|
fn is_conflicted(status: Status) -> bool {
|
||||||
|
status.is_conflicted()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_deleted(status: Status) -> bool {
|
||||||
|
status.is_wt_deleted() || status.is_index_deleted()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_renamed(status: Status) -> bool {
|
||||||
|
status.is_wt_renamed() || status.is_index_renamed()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_modified(status: Status) -> bool {
|
||||||
|
status.is_wt_modified()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_staged(status: Status) -> bool {
|
||||||
|
status.is_index_modified() || status.is_index_new()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_untracked(status: Status) -> bool {
|
||||||
|
status.is_wt_new()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add(&mut self, s: Status) {
|
||||||
|
self.conflicted += RepoStatus::is_conflicted(s) as usize;
|
||||||
|
self.deleted += RepoStatus::is_deleted(s) as usize;
|
||||||
|
self.renamed += RepoStatus::is_renamed(s) as usize;
|
||||||
|
self.modified += RepoStatus::is_modified(s) as usize;
|
||||||
|
self.staged += RepoStatus::is_staged(s) as usize;
|
||||||
|
self.untracked += RepoStatus::is_untracked(s) as usize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_text<F>(format_str: &str, config_path: &str, mapper: F) -> Option<Vec<Segment>>
|
||||||
|
where
|
||||||
|
F: Fn(&str) -> Option<String> + Send + Sync,
|
||||||
|
{
|
||||||
|
if let Ok(formatter) = StringFormatter::new(format_str) {
|
||||||
|
formatter
|
||||||
|
.map(|variable| mapper(variable).map(Ok))
|
||||||
|
.parse(None)
|
||||||
|
.ok()
|
||||||
|
} else {
|
||||||
|
log::error!("Error parsing format string `{}`", &config_path);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_count(format_str: &str, config_path: &str, count: usize) -> Option<Vec<Segment>> {
|
||||||
|
if count == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
format_text(format_str, config_path, |variable| match variable {
|
||||||
|
"count" => Some(count.to_string()),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use super::{Context, Module, RootModuleConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::configs::go::GoConfig;
|
use crate::configs::go::GoConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
/// Creates a module with the current Go version
|
/// Creates a module with the current Go version
|
||||||
@ -34,14 +35,33 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut module = context.new_module("golang");
|
let mut module = context.new_module("golang");
|
||||||
let config: GoConfig = GoConfig::try_load(module.config);
|
let config = GoConfig::try_load(module.config);
|
||||||
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
|
formatter
|
||||||
|
.map_meta(|var, _| match var {
|
||||||
|
"symbol" => Some(config.symbol),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map_style(|variable| match variable {
|
||||||
|
"style" => Some(Ok(config.style)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"version" => {
|
||||||
|
format_go_version(&utils::exec_cmd("go", &["version"])?.stdout.as_str()).map(Ok)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
module.set_style(config.style);
|
module.set_segments(match parsed {
|
||||||
module.create_segment("symbol", &config.symbol);
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
let formatted_version =
|
log::warn!("Error in module `golang`:\n{}", error);
|
||||||
format_go_version(&utils::exec_cmd("go", &["version"])?.stdout.as_str())?;
|
return None;
|
||||||
module.create_segment("version", &config.version.with_value(&formatted_version));
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ use unicode_segmentation::UnicodeSegmentation;
|
|||||||
use super::{Context, Module, RootModuleConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::configs::hg_branch::HgBranchConfig;
|
use crate::configs::hg_branch::HgBranchConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
|
|
||||||
/// 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
|
||||||
///
|
///
|
||||||
@ -15,12 +16,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut module = context.new_module("hg_branch");
|
let mut module = context.new_module("hg_branch");
|
||||||
let config = HgBranchConfig::try_load(module.config);
|
let config: HgBranchConfig = HgBranchConfig::try_load(module.config);
|
||||||
module.set_style(config.style);
|
|
||||||
|
|
||||||
module.get_prefix().set_value("on ");
|
|
||||||
|
|
||||||
module.create_segment("symbol", &config.symbol);
|
|
||||||
|
|
||||||
// TODO: Once error handling is implemented, warn the user if their config
|
// TODO: Once error handling is implemented, warn the user if their config
|
||||||
// truncation length is nonsensical
|
// truncation length is nonsensical
|
||||||
@ -46,10 +42,30 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
truncated_graphemes
|
truncated_graphemes
|
||||||
};
|
};
|
||||||
|
|
||||||
module.create_segment(
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
"name",
|
formatter
|
||||||
&config.branch_name.with_value(&truncated_and_symbol),
|
.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_and_symbol.as_str())),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
|
module.set_segments(match parsed {
|
||||||
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `hg_branch`:\n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use super::{Context, Module, SegmentConfig};
|
use super::{Context, Module};
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
|
|
||||||
use crate::config::RootModuleConfig;
|
use crate::config::RootModuleConfig;
|
||||||
use crate::configs::hostname::HostnameConfig;
|
use crate::configs::hostname::HostnameConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
|
|
||||||
/// Creates a module with the system hostname
|
/// Creates a module with the system hostname
|
||||||
///
|
///
|
||||||
@ -42,10 +43,26 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
host.as_ref()
|
host.as_ref()
|
||||||
};
|
};
|
||||||
|
|
||||||
module.set_style(config.style);
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
let hostname_stacked = format!("{}{}{}", config.prefix, host, config.suffix);
|
formatter
|
||||||
module.create_segment("hostname", &SegmentConfig::new(&hostname_stacked));
|
.map_style(|variable| match variable {
|
||||||
module.get_prefix().set_value("on ");
|
"style" => Some(Ok(config.style)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"hostname" => Some(Ok(host)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
|
module.set_segments(match parsed {
|
||||||
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `hostname`:\n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::configs::java::JavaConfig;
|
use crate::configs::java::JavaConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
|
|
||||||
use super::{Context, Module, RootModuleConfig, SegmentConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::modules::utils::java_version_parser;
|
use crate::modules::utils::java_version_parser;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
@ -25,12 +26,31 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
Some(java_version) => {
|
Some(java_version) => {
|
||||||
let mut module = context.new_module("java");
|
let mut module = context.new_module("java");
|
||||||
let config: JavaConfig = JavaConfig::try_load(module.config);
|
let config: JavaConfig = JavaConfig::try_load(module.config);
|
||||||
module.set_style(config.style);
|
|
||||||
|
|
||||||
let formatted_version = format_java_version(java_version)?;
|
let formatted_version = format_java_version(java_version)?;
|
||||||
module.create_segment("symbol", &config.symbol);
|
|
||||||
module.create_segment("version", &SegmentConfig::new(&formatted_version));
|
|
||||||
|
|
||||||
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
|
formatter
|
||||||
|
.map_meta(|var, _| match var {
|
||||||
|
"symbol" => Some(config.symbol),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map_style(|variable| match variable {
|
||||||
|
"style" => Some(Ok(config.style)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"version" => Some(Ok(&formatted_version)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
module.set_segments(match parsed {
|
||||||
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `java`:\n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
None => None,
|
None => None,
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
use super::{Context, Module};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::config::{RootModuleConfig, SegmentConfig};
|
|
||||||
use crate::configs::jobs::JobsConfig;
|
use crate::configs::jobs::JobsConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
|
|
||||||
/// Creates a segment to show if there are any active jobs running
|
/// Creates a segment to show if there are any active jobs running
|
||||||
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("jobs");
|
let mut module = context.new_module("jobs");
|
||||||
let config: JobsConfig = JobsConfig::try_load(module.config);
|
let config = JobsConfig::try_load(module.config);
|
||||||
|
|
||||||
module.set_style(config.style);
|
|
||||||
|
|
||||||
let props = &context.properties;
|
let props = &context.properties;
|
||||||
let num_of_jobs = props
|
let num_of_jobs = props
|
||||||
@ -20,11 +18,37 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
if num_of_jobs == 0 {
|
if num_of_jobs == 0 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
module.create_segment("symbol", &config.symbol);
|
|
||||||
if num_of_jobs > config.threshold {
|
let module_number = if num_of_jobs > config.threshold {
|
||||||
module.create_segment("number", &SegmentConfig::new(&num_of_jobs.to_string()));
|
num_of_jobs.to_string()
|
||||||
}
|
} else {
|
||||||
module.get_prefix().set_value("");
|
"".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
|
formatter
|
||||||
|
.map_meta(|var, _| match var {
|
||||||
|
"symbol" => Some(config.symbol),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map_style(|variable| match variable {
|
||||||
|
"style" => Some(Ok(config.style)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"number" => Some(Ok(module_number.clone())),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
|
module.set_segments(match parsed {
|
||||||
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `jobs`:\n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use super::{Context, Module, RootModuleConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::configs::julia::JuliaConfig;
|
use crate::configs::julia::JuliaConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
/// Creates a module with the current Julia version
|
/// Creates a module with the current Julia version
|
||||||
@ -21,14 +22,34 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut module = context.new_module("julia");
|
let mut module = context.new_module("julia");
|
||||||
let config: JuliaConfig = JuliaConfig::try_load(module.config);
|
let config = JuliaConfig::try_load(module.config);
|
||||||
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
|
formatter
|
||||||
|
.map_meta(|var, _| match var {
|
||||||
|
"symbol" => Some(config.symbol),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map_style(|variable| match variable {
|
||||||
|
"style" => Some(Ok(config.style)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"version" => {
|
||||||
|
format_julia_version(&utils::exec_cmd("julia", &["--version"])?.stdout.as_str())
|
||||||
|
.map(Ok)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
module.set_style(config.style);
|
module.set_segments(match parsed {
|
||||||
module.create_segment("symbol", &config.symbol);
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
let formatted_version =
|
log::warn!("Error in module `julia`:\n{}", error);
|
||||||
format_julia_version(&utils::exec_cmd("julia", &["--version"])?.stdout.as_str())?;
|
return None;
|
||||||
module.create_segment("version", &config.version.with_value(&formatted_version));
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,9 @@ use std::path;
|
|||||||
use super::{Context, Module, RootModuleConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::configs::kubernetes::KubernetesConfig;
|
use crate::configs::kubernetes::KubernetesConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
const KUBERNETES_PREFIX: &str = "on ";
|
|
||||||
|
|
||||||
fn get_kube_context(contents: &str) -> Option<(String, String)> {
|
fn get_kube_context(contents: &str) -> Option<(String, String)> {
|
||||||
let yaml_docs = YamlLoader::load_from_str(&contents).ok()?;
|
let yaml_docs = YamlLoader::load_from_str(&contents).ok()?;
|
||||||
if yaml_docs.is_empty() {
|
if yaml_docs.is_empty() {
|
||||||
@ -63,23 +62,44 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
module.set_style(config.style);
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
module.get_prefix().set_value(KUBERNETES_PREFIX);
|
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 {
|
||||||
|
"context" => match config.context_aliases.get(&kube_ctx) {
|
||||||
|
None => Some(Ok(kube_ctx.as_str())),
|
||||||
|
Some(&alias) => Some(Ok(alias)),
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"namespace" => {
|
||||||
|
if kube_ns != "" {
|
||||||
|
Some(Ok(kube_ns.as_str()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
module.create_segment("symbol", &config.symbol);
|
module.set_segments(match parsed {
|
||||||
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `kubernetes`: \n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let displayed_context = match config.context_aliases.get(&kube_ctx) {
|
|
||||||
None => &kube_ctx,
|
|
||||||
Some(&alias) => alias,
|
|
||||||
};
|
|
||||||
|
|
||||||
module.create_segment("context", &config.context.with_value(&displayed_context));
|
|
||||||
if kube_ns != "" {
|
|
||||||
module.create_segment(
|
|
||||||
"namespace",
|
|
||||||
&config.namespace.with_value(&format!(" ({})", kube_ns)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
None => None,
|
None => None,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use super::{Context, Module};
|
use super::{Context, Module};
|
||||||
use crate::config::SegmentConfig;
|
use crate::segment::Segment;
|
||||||
|
|
||||||
/// Creates a module for the line break
|
/// Creates a module for the line break
|
||||||
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
@ -7,10 +7,11 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
|
|
||||||
let mut module = context.new_module("line_break");
|
let mut module = context.new_module("line_break");
|
||||||
|
|
||||||
module.get_prefix().set_value("");
|
module.set_segments(vec![Segment {
|
||||||
module.get_suffix().set_value("");
|
_name: "line_break".to_string(),
|
||||||
|
style: None,
|
||||||
module.create_segment("character", &SegmentConfig::new(LINE_ENDING));
|
value: LINE_ENDING.to_string(),
|
||||||
|
}]);
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ use sysinfo::{RefreshKind, SystemExt};
|
|||||||
use super::{Context, Module, RootModuleConfig, Shell};
|
use super::{Context, Module, RootModuleConfig, Shell};
|
||||||
|
|
||||||
use crate::configs::memory_usage::MemoryConfig;
|
use crate::configs::memory_usage::MemoryConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
|
|
||||||
fn format_kib(n_kib: u64) -> String {
|
fn format_kib(n_kib: u64) -> String {
|
||||||
let byte = Byte::from_unit(n_kib as f64, ByteUnit::KiB).unwrap_or_else(|_| Byte::from_bytes(0));
|
let byte = Byte::from_unit(n_kib as f64, ByteUnit::KiB).unwrap_or_else(|_| Byte::from_bytes(0));
|
||||||
@ -12,6 +13,14 @@ fn format_kib(n_kib: u64) -> String {
|
|||||||
display_bytes
|
display_bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn format_pct(pct_number: f64, pct_sign: &str) -> String {
|
||||||
|
format!("{:.0}{}", pct_number, pct_sign)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_usage_total(usage: u64, total: u64) -> String {
|
||||||
|
format!("{}/{}", format_kib(usage), format_kib(total))
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a module with system memory usage information
|
/// Creates a module with system memory usage information
|
||||||
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("memory_usage");
|
let mut module = context.new_module("memory_usage");
|
||||||
@ -19,7 +28,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
|
|
||||||
// TODO: Update when v1.0 printing refactor is implemented to only
|
// TODO: Update when v1.0 printing refactor is implemented to only
|
||||||
// print escapes in a prompt context.
|
// print escapes in a prompt context.
|
||||||
let percent_sign = match context.shell {
|
let pct_sign = match context.shell {
|
||||||
Shell::Zsh => "%%", // % is an escape in zsh, see PROMPT in `man zshmisc`
|
Shell::Zsh => "%%", // % is an escape in zsh, see PROMPT in `man zshmisc`
|
||||||
_ => "%",
|
_ => "%",
|
||||||
};
|
};
|
||||||
@ -28,54 +37,52 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.set_style(config.style);
|
|
||||||
module.create_segment("symbol", &config.symbol);
|
|
||||||
|
|
||||||
let system = sysinfo::System::new_with_specifics(RefreshKind::new().with_memory());
|
let system = sysinfo::System::new_with_specifics(RefreshKind::new().with_memory());
|
||||||
|
|
||||||
let used_memory_kib = system.get_used_memory();
|
let used_memory_kib = system.get_used_memory();
|
||||||
let total_memory_kib = system.get_total_memory();
|
let total_memory_kib = system.get_total_memory();
|
||||||
|
let ram_used = (used_memory_kib as f64 / total_memory_kib as f64) * 100.;
|
||||||
let percent_mem_used = (used_memory_kib as f64 / total_memory_kib as f64) * 100.;
|
let ram_pct = format_pct(ram_used, pct_sign);
|
||||||
|
|
||||||
let threshold = config.threshold;
|
let threshold = config.threshold;
|
||||||
|
if ram_used.round() < threshold as f64 {
|
||||||
if percent_mem_used.round() < threshold as f64 {
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let show_percentage = config.show_percentage;
|
let ram = format_usage_total(used_memory_kib, total_memory_kib);
|
||||||
|
|
||||||
let ram = if show_percentage {
|
|
||||||
format!("{:.0}{}", percent_mem_used, percent_sign)
|
|
||||||
} else {
|
|
||||||
format!(
|
|
||||||
"{}/{}",
|
|
||||||
format_kib(used_memory_kib),
|
|
||||||
format_kib(total_memory_kib)
|
|
||||||
)
|
|
||||||
};
|
|
||||||
module.create_segment("ram", &config.ram.with_value(&ram));
|
|
||||||
|
|
||||||
// swap only shown if enabled and there is swap on the system
|
|
||||||
let total_swap_kib = system.get_total_swap();
|
let total_swap_kib = system.get_total_swap();
|
||||||
if config.show_swap && total_swap_kib > 0 {
|
let used_swap_kib = system.get_used_swap();
|
||||||
let used_swap_kib = system.get_used_swap();
|
let percent_swap_used = (used_swap_kib as f64 / total_swap_kib as f64) * 100.;
|
||||||
let percent_swap_used = (used_swap_kib as f64 / total_swap_kib as f64) * 100.;
|
let swap_pct = format_pct(percent_swap_used, pct_sign);
|
||||||
|
let swap = format_usage_total(used_swap_kib, total_swap_kib);
|
||||||
|
|
||||||
let swap = if show_percentage {
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
format!("{:.0}{}", percent_swap_used, percent_sign)
|
formatter
|
||||||
} else {
|
.map_meta(|var, _| match var {
|
||||||
format!(
|
"symbol" => Some(config.symbol),
|
||||||
"{}/{}",
|
_ => None,
|
||||||
format_kib(used_swap_kib),
|
})
|
||||||
format_kib(total_swap_kib)
|
.map_style(|variable| match variable {
|
||||||
)
|
"style" => Some(Ok(config.style)),
|
||||||
};
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"ram" => Some(Ok(&ram)),
|
||||||
|
"ram_pct" => Some(Ok(&ram_pct)),
|
||||||
|
// swap only shown if there is swap on the system
|
||||||
|
"swap" if total_swap_kib > 0 => Some(Ok(&swap)),
|
||||||
|
"swap_pct" if total_swap_kib > 0 => Some(Ok(&swap_pct)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
module.create_segment("separator", &config.separator);
|
module.set_segments(match parsed {
|
||||||
module.create_segment("swap", &config.swap.with_value(&swap));
|
Ok(segments) => segments,
|
||||||
}
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `memory_usage`:\n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ mod zig;
|
|||||||
#[cfg(feature = "battery")]
|
#[cfg(feature = "battery")]
|
||||||
mod battery;
|
mod battery;
|
||||||
|
|
||||||
use crate::config::{RootModuleConfig, SegmentConfig};
|
use crate::config::RootModuleConfig;
|
||||||
use crate::context::{Context, Shell};
|
use crate::context::{Context, Shell};
|
||||||
use crate::module::Module;
|
use crate::module::Module;
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use super::{Context, Module, RootModuleConfig, SegmentConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::configs::nim::NimConfig;
|
use crate::configs::nim::NimConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
/// Creates a module with the current Nim version
|
/// Creates a module with the current Nim version
|
||||||
@ -19,16 +20,38 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let nim_version_output = utils::exec_cmd("nim", &["--version"])?.stdout;
|
|
||||||
let formatted_nim_version = format!("v{}", parse_nim_version(&nim_version_output)?);
|
|
||||||
|
|
||||||
let mut module = context.new_module("nim");
|
let mut module = context.new_module("nim");
|
||||||
let config = NimConfig::try_load(module.config);
|
let config = NimConfig::try_load(module.config);
|
||||||
|
|
||||||
module.set_style(config.style);
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
|
formatter
|
||||||
|
.map_meta(|var, _| match var {
|
||||||
|
"symbol" => Some(config.symbol),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map_style(|variable| match variable {
|
||||||
|
"style" => Some(Ok(config.style)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"version" => utils::exec_cmd("nim", &["--version"])
|
||||||
|
.map(|command_output| command_output.stdout)
|
||||||
|
.and_then(|nim_version_output| {
|
||||||
|
Some(format!("v{}", parse_nim_version(&nim_version_output)?))
|
||||||
|
})
|
||||||
|
.map(Ok),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
module.create_segment("symbol", &config.symbol);
|
module.set_segments(match parsed {
|
||||||
module.create_segment("version", &SegmentConfig::new(&formatted_nim_version));
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `nim`:\n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use super::{Context, Module, RootModuleConfig, SegmentConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::configs::nix_shell::NixShellConfig;
|
use crate::configs::nix_shell::NixShellConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
// IN_NIX_SHELL should be "pure" or "impure" but lorri uses "1" for "impure"
|
|
||||||
// https://github.com/target/lorri/issues/140
|
|
||||||
|
|
||||||
/// Creates a module showing if inside a nix-shell
|
/// Creates a module showing if inside a nix-shell
|
||||||
///
|
///
|
||||||
@ -13,43 +11,53 @@ use crate::configs::nix_shell::NixShellConfig;
|
|||||||
/// determine if it's inside a nix-shell and the name of it.
|
/// determine if it's inside a nix-shell and the name of it.
|
||||||
///
|
///
|
||||||
/// The following options are availables:
|
/// The following options are availables:
|
||||||
/// - use_name (bool) // print the name of the nix-shell
|
|
||||||
/// - 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
|
||||||
///
|
///
|
||||||
/// Will display the following:
|
/// Will display the following:
|
||||||
/// - name (pure) // use_name == true in a pure nix-shell
|
/// - pure (name) // $name == "name" in a pure nix-shell
|
||||||
/// - name (impure) // use_name == true in an impure nix-shell
|
/// - impure (name) // $name == "name" in an impure nix-shell
|
||||||
/// - pure // use_name == false in a pure nix-shell
|
/// - pure // $name == "" in a pure nix-shell
|
||||||
/// - impure // use_name == false in an impure nix-shell
|
/// - impure // $name == "" in an impure 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);
|
||||||
|
|
||||||
module.set_style(config.style);
|
let shell_name = env::var("name").ok();
|
||||||
module.create_segment("symbol", &config.symbol);
|
|
||||||
|
|
||||||
let shell_type = env::var("IN_NIX_SHELL").ok()?;
|
let shell_type = env::var("IN_NIX_SHELL").ok()?;
|
||||||
let shell_type_segment: SegmentConfig = match shell_type.as_ref() {
|
let shell_type_format = match shell_type.as_ref() {
|
||||||
"1" | "impure" => config.impure_msg,
|
"impure" => config.impure_msg,
|
||||||
"pure" => config.pure_msg,
|
"pure" => config.pure_msg,
|
||||||
_ => {
|
_ => {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if config.use_name {
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
if let Ok(name) = env::var("name") {
|
formatter
|
||||||
module.create_segment(
|
.map_meta(|variable, _| match variable {
|
||||||
"nix_shell",
|
"symbol" => Some(config.symbol),
|
||||||
&shell_type_segment.with_value(&format!("{} ({})", name, shell_type_segment.value)),
|
"state" => Some(shell_type_format),
|
||||||
);
|
_ => None,
|
||||||
} else {
|
})
|
||||||
module.create_segment("nix_shell", &shell_type_segment);
|
.map_style(|variable| match variable {
|
||||||
|
"style" => Some(Ok(config.style)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"name" => shell_name.as_ref().map(Ok),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
|
module.set_segments(match parsed {
|
||||||
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `nix_shell`:\n{}", error);
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
} else {
|
});
|
||||||
module.create_segment("nix_shell", &shell_type_segment);
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use super::{Context, Module, RootModuleConfig, SegmentConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::configs::nodejs::NodejsConfig;
|
use crate::configs::nodejs::NodejsConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
/// Creates a module with the current Node.js version
|
/// Creates a module with the current Node.js version
|
||||||
@ -27,16 +28,32 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let node_version = utils::exec_cmd("node", &["--version"])?.stdout;
|
|
||||||
|
|
||||||
let mut module = context.new_module("nodejs");
|
let mut module = context.new_module("nodejs");
|
||||||
let config: NodejsConfig = NodejsConfig::try_load(module.config);
|
let config = NodejsConfig::try_load(module.config);
|
||||||
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
|
formatter
|
||||||
|
.map_meta(|var, _| match var {
|
||||||
|
"symbol" => Some(config.symbol),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map_style(|variable| match variable {
|
||||||
|
"style" => Some(Ok(config.style)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"version" => Some(Ok(utils::exec_cmd("node", &["--version"])?.stdout)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
module.set_style(config.style);
|
module.set_segments(match parsed {
|
||||||
|
Ok(segments) => segments,
|
||||||
let formatted_version = node_version.trim();
|
Err(error) => {
|
||||||
module.create_segment("symbol", &config.symbol);
|
log::warn!("Error in module `nodejs`:\n{}", error);
|
||||||
module.create_segment("version", &SegmentConfig::new(formatted_version));
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use super::{Context, Module, RootModuleConfig, SegmentConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::configs::ocaml::OCamlConfig;
|
use crate::configs::ocaml::OCamlConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
/// Creates a module with the current OCaml version
|
/// Creates a module with the current OCaml version
|
||||||
@ -35,14 +36,33 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
utils::exec_cmd("ocaml", &["-vnum"])?.stdout
|
utils::exec_cmd("ocaml", &["-vnum"])?.stdout
|
||||||
};
|
};
|
||||||
|
|
||||||
let formatted_version = format!("v{}", &ocaml_version.trim());
|
|
||||||
|
|
||||||
let mut module = context.new_module("ocaml");
|
let mut module = context.new_module("ocaml");
|
||||||
let config = OCamlConfig::try_load(module.config);
|
let config: OCamlConfig = OCamlConfig::try_load(module.config);
|
||||||
module.set_style(config.style);
|
|
||||||
|
|
||||||
module.create_segment("symbol", &config.symbol);
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
module.create_segment("version", &SegmentConfig::new(&formatted_version));
|
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 {
|
||||||
|
"version" => Some(Ok(format!("v{}", &ocaml_version))),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
|
module.set_segments(match parsed {
|
||||||
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `ocaml`: \n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -1,33 +1,47 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use super::{Context, Module};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
use crate::configs::package::PackageConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde_json as json;
|
use serde_json as json;
|
||||||
|
|
||||||
use super::{RootModuleConfig, SegmentConfig};
|
|
||||||
use crate::configs::package::PackageConfig;
|
|
||||||
|
|
||||||
/// Creates a module with the current package version
|
/// Creates a module with the current package version
|
||||||
///
|
///
|
||||||
/// Will display if a version is defined for your Node.js or Rust project (if one exists)
|
/// Will display if a version is defined for your Node.js or Rust project (if one exists)
|
||||||
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("package");
|
let mut module = context.new_module("package");
|
||||||
let config: PackageConfig = PackageConfig::try_load(module.config);
|
let config: PackageConfig = PackageConfig::try_load(module.config);
|
||||||
|
let module_version = get_package_version(&context.current_dir, &config)?;
|
||||||
|
|
||||||
match get_package_version(&context.current_dir, &config) {
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
Some(package_version) => {
|
formatter
|
||||||
module.set_style(config.style);
|
.map_meta(|var, _| match var {
|
||||||
module.get_prefix().set_value("is ");
|
"symbol" => Some(config.symbol),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map_style(|variable| match variable {
|
||||||
|
"style" => Some(Ok(config.style)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"version" => Some(Ok(&module_version)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
module.create_segment("symbol", &config.symbol);
|
module.set_segments(match parsed {
|
||||||
module.create_segment("version", &SegmentConfig::new(&package_version));
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
Some(module)
|
log::warn!("Error in module `package`:\n{}", error);
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
None => None,
|
});
|
||||||
}
|
|
||||||
|
Some(module)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_cargo_version(file_contents: &str) -> Option<String> {
|
fn extract_cargo_version(file_contents: &str) -> Option<String> {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use super::{Context, Module, RootModuleConfig, SegmentConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::configs::php::PhpConfig;
|
use crate::configs::php::PhpConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
/// Creates a module with the current PHP version
|
/// Creates a module with the current PHP version
|
||||||
@ -27,16 +28,33 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
],
|
],
|
||||||
) {
|
) {
|
||||||
Some(php_cmd_output) => {
|
Some(php_cmd_output) => {
|
||||||
let php_version = php_cmd_output.stdout;
|
|
||||||
|
|
||||||
let mut module = context.new_module("php");
|
let mut module = context.new_module("php");
|
||||||
let config: PhpConfig = PhpConfig::try_load(module.config);
|
let config: PhpConfig = PhpConfig::try_load(module.config);
|
||||||
|
|
||||||
module.set_style(config.style);
|
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 {
|
||||||
|
"version" => format_php_version(&php_cmd_output.stdout).map(Ok),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
let formatted_version = format_php_version(&php_version)?;
|
module.set_segments(match parsed {
|
||||||
module.create_segment("symbol", &config.symbol);
|
Ok(segments) => segments,
|
||||||
module.create_segment("version", &SegmentConfig::new(&formatted_version));
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `php`:\n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use super::{Context, Module, RootModuleConfig, SegmentConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::configs::purescript::PureScriptConfig;
|
use crate::configs::purescript::PureScriptConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
/// Creates a module with the current PureScript version
|
/// Creates a module with the current PureScript version
|
||||||
@ -20,14 +21,34 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let purs_version = utils::exec_cmd("purs", &["--version"])?.stdout;
|
let purs_version = utils::exec_cmd("purs", &["--version"])?.stdout;
|
||||||
let formatted_version = Some(format!("v{}", purs_version.trim()))?;
|
|
||||||
|
|
||||||
let mut module = context.new_module("purescript");
|
let mut module = context.new_module("purescript");
|
||||||
let config: PureScriptConfig = PureScriptConfig::try_load(module.config);
|
let config: PureScriptConfig = PureScriptConfig::try_load(module.config);
|
||||||
module.set_style(config.style);
|
|
||||||
|
|
||||||
module.create_segment("symbol", &config.symbol);
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
module.create_segment("version", &SegmentConfig::new(&formatted_version));
|
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 {
|
||||||
|
"version" => Some(Ok(format!("v{}", purs_version.trim()))),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
|
module.set_segments(match parsed {
|
||||||
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `purescript`:\n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use super::{Context, Module, RootModuleConfig, SegmentConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
use crate::configs::python::PythonConfig;
|
use crate::configs::python::PythonConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
/// Creates a module with the current Python version
|
/// Creates a module with the current Python version
|
||||||
@ -41,25 +42,39 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.set_style(config.style);
|
let python_version = if config.pyenv_version_name {
|
||||||
module.create_segment("symbol", &config.symbol);
|
utils::exec_cmd("pyenv", &["version-name"])?.stdout
|
||||||
|
|
||||||
if config.pyenv_version_name {
|
|
||||||
let python_version = utils::exec_cmd("pyenv", &["version-name"])?.stdout;
|
|
||||||
module.create_segment("pyenv_prefix", &config.pyenv_prefix);
|
|
||||||
module.create_segment("version", &SegmentConfig::new(&python_version.trim()));
|
|
||||||
} else {
|
} else {
|
||||||
let python_version = get_python_version(&config.python_binary)?;
|
let version = get_python_version(&config.python_binary)?;
|
||||||
let formatted_version = format_python_version(&python_version);
|
format_python_version(&version)
|
||||||
module.create_segment("version", &SegmentConfig::new(&formatted_version));
|
|
||||||
};
|
};
|
||||||
|
let virtual_env = get_python_virtual_env();
|
||||||
|
|
||||||
if let Some(virtual_env) = get_python_virtual_env() {
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
module.create_segment(
|
formatter
|
||||||
"virtualenv",
|
.map_meta(|var, _| match var {
|
||||||
&SegmentConfig::new(&format!(" ({})", virtual_env)),
|
"symbol" => Some(config.symbol),
|
||||||
);
|
_ => None,
|
||||||
};
|
})
|
||||||
|
.map_style(|variable| match variable {
|
||||||
|
"style" => Some(Ok(config.style)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"version" => Some(Ok(python_version.trim())),
|
||||||
|
"virtualenv" => virtual_env.as_ref().map(|e| Ok(e.trim())),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
|
module.set_segments(match parsed {
|
||||||
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `python`:\n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use super::{Context, Module, RootModuleConfig, SegmentConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::configs::ruby::RubyConfig;
|
use crate::configs::ruby::RubyConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
/// Creates a module with the current Ruby version
|
/// Creates a module with the current Ruby version
|
||||||
@ -19,15 +20,34 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ruby_version = utils::exec_cmd("ruby", &["-v"])?.stdout;
|
|
||||||
let formatted_version = format_ruby_version(&ruby_version)?;
|
|
||||||
|
|
||||||
let mut module = context.new_module("ruby");
|
let mut module = context.new_module("ruby");
|
||||||
let config: RubyConfig = RubyConfig::try_load(module.config);
|
let config = RubyConfig::try_load(module.config);
|
||||||
module.set_style(config.style);
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
|
formatter
|
||||||
|
.map_meta(|var, _| match var {
|
||||||
|
"symbol" => Some(config.symbol),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map_style(|variable| match variable {
|
||||||
|
"style" => Some(Ok(config.style)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"version" => {
|
||||||
|
format_ruby_version(&utils::exec_cmd("ruby", &["-v"])?.stdout.as_str()).map(Ok)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
module.create_segment("symbol", &config.symbol);
|
module.set_segments(match parsed {
|
||||||
module.create_segment("version", &SegmentConfig::new(&formatted_version));
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `ruby`:\n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ use std::{env, fs};
|
|||||||
use super::{Context, Module, RootModuleConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::configs::rust::RustConfig;
|
use crate::configs::rust::RustConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
|
|
||||||
/// Creates a module with the current Rust version
|
/// Creates a module with the current Rust version
|
||||||
///
|
///
|
||||||
@ -22,6 +23,39 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut module = context.new_module("rust");
|
||||||
|
let config = RustConfig::try_load(module.config);
|
||||||
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
|
formatter
|
||||||
|
.map_meta(|var, _| match var {
|
||||||
|
"symbol" => Some(config.symbol),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map_style(|variable| match variable {
|
||||||
|
"style" => Some(Ok(config.style)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
// This may result in multiple calls to `get_module_version` when a user have
|
||||||
|
// multiple `$version` variables defined in `format`.
|
||||||
|
"version" => get_module_version(context).map(Ok),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
|
module.set_segments(match parsed {
|
||||||
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `rust`:\n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Some(module)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_module_version(context: &Context) -> Option<String> {
|
||||||
// `$CARGO_HOME/bin/rustc(.exe) --version` may attempt installing a rustup toolchain.
|
// `$CARGO_HOME/bin/rustc(.exe) --version` may attempt installing a rustup toolchain.
|
||||||
// https://github.com/starship/starship/issues/417
|
// https://github.com/starship/starship/issues/417
|
||||||
//
|
//
|
||||||
@ -56,14 +90,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
format_rustc_version(execute_rustc_version()?)
|
format_rustc_version(execute_rustc_version()?)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut module = context.new_module("rust");
|
Some(module_version)
|
||||||
let config = RustConfig::try_load(module.config);
|
|
||||||
module.set_style(config.style);
|
|
||||||
|
|
||||||
module.create_segment("symbol", &config.symbol);
|
|
||||||
module.create_segment("version", &config.version.with_value(&module_version));
|
|
||||||
|
|
||||||
Some(module)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn env_rustup_toolchain() -> Option<String> {
|
fn env_rustup_toolchain() -> Option<String> {
|
||||||
|
@ -1,28 +1,44 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use super::{Context, Module, SegmentConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::config::RootModuleConfig;
|
|
||||||
use crate::configs::singularity::SingularityConfig;
|
use crate::configs::singularity::SingularityConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
|
|
||||||
/// Creates a module with the current Singularity image
|
/// Creates a module with the current Singularity image
|
||||||
///
|
///
|
||||||
/// Will display the Singularity image if `$SINGULARITY_NAME` is set.
|
/// Will display the Singularity image if `$SINGULARITY_NAME` is set.
|
||||||
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
let singularity_env = env::var("SINGULARITY_NAME").unwrap_or_else(|_| "".into());
|
let singularity_env = env::var("SINGULARITY_NAME").ok();
|
||||||
if singularity_env.trim().is_empty() {
|
singularity_env.as_ref()?;
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut module = context.new_module("singularity");
|
let mut module = context.new_module("singularity");
|
||||||
let config = SingularityConfig::try_load(module.config);
|
let config: SingularityConfig = SingularityConfig::try_load(module.config);
|
||||||
|
|
||||||
module.get_prefix().set_value(config.label);
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
module.set_style(config.style);
|
formatter
|
||||||
module.create_segment("symbol", &config.symbol);
|
.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 {
|
||||||
|
"env" => singularity_env.as_ref().map(Ok),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
let env_var_stacked = format!("{}{}{}", config.prefix, singularity_env, config.suffix);
|
module.set_segments(match parsed {
|
||||||
module.create_segment("singularity", &SegmentConfig::new(&env_var_stacked));
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `singularity`: \n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use super::{Context, Module, RootModuleConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::configs::terraform::TerraformConfig;
|
use crate::configs::terraform::TerraformConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@ -25,20 +27,34 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
let mut module = context.new_module("terraform");
|
let mut module = context.new_module("terraform");
|
||||||
let config: TerraformConfig = TerraformConfig::try_load(module.config);
|
let config: TerraformConfig = TerraformConfig::try_load(module.config);
|
||||||
|
|
||||||
module.set_style(config.style);
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
module.create_segment("symbol", &config.symbol);
|
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 {
|
||||||
|
"version" => format_terraform_version(
|
||||||
|
&utils::exec_cmd("terraform", &["version"])?.stdout.as_str(),
|
||||||
|
)
|
||||||
|
.map(Ok),
|
||||||
|
"workspace" => get_terraform_workspace(&context.current_dir).map(Ok),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
if config.show_version {
|
module.set_segments(match parsed {
|
||||||
let terraform_version =
|
Ok(segments) => segments,
|
||||||
format_terraform_version(&utils::exec_cmd("terraform", &["version"])?.stdout.as_str())?;
|
Err(error) => {
|
||||||
module.create_segment("version", &config.version.with_value(&terraform_version));
|
log::warn!("Error in module `terraform`:\n{}", error);
|
||||||
}
|
return None;
|
||||||
|
}
|
||||||
let terraform_workspace = &get_terraform_workspace(&context.current_dir)?;
|
});
|
||||||
module.create_segment(
|
|
||||||
"workspace",
|
|
||||||
&config.workspace.with_value(&terraform_workspace),
|
|
||||||
);
|
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
use chrono::{DateTime, FixedOffset, Local, NaiveTime, Utc};
|
use chrono::{DateTime, FixedOffset, Local, NaiveTime, Utc};
|
||||||
|
|
||||||
use super::{Context, Module};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::config::{RootModuleConfig, SegmentConfig};
|
|
||||||
use crate::configs::time::TimeConfig;
|
use crate::configs::time::TimeConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
|
|
||||||
/// Outputs the current time
|
/// Outputs the current time
|
||||||
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
const TIME_PREFIX: &str = "at ";
|
|
||||||
|
|
||||||
let mut module = context.new_module("time");
|
let mut module = context.new_module("time");
|
||||||
let config: TimeConfig = TimeConfig::try_load(module.config);
|
let config: TimeConfig = TimeConfig::try_load(module.config);
|
||||||
if config.disabled {
|
if config.disabled {
|
||||||
@ -23,7 +20,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let default_format = if config.use_12hr { "%r" } else { "%T" };
|
let default_format = if config.use_12hr { "%r" } else { "%T" };
|
||||||
let time_format = config.format.unwrap_or(default_format);
|
let time_format = config.time_format.unwrap_or(default_format);
|
||||||
|
|
||||||
log::trace!(
|
log::trace!(
|
||||||
"Timer module is enabled with format string: {}",
|
"Timer module is enabled with format string: {}",
|
||||||
@ -44,17 +41,26 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
format_time(&time_format, Local::now())
|
format_time(&time_format, Local::now())
|
||||||
};
|
};
|
||||||
|
|
||||||
module.set_style(config.style);
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
|
formatter
|
||||||
|
.map_style(|variable| match variable {
|
||||||
|
"style" => Some(Ok(config.style)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"time" => Some(Ok(&formatted_time_string)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
module.get_prefix().set_value(TIME_PREFIX);
|
module.set_segments(match parsed {
|
||||||
|
Ok(segments) => segments,
|
||||||
module.create_segment(
|
Err(error) => {
|
||||||
"time",
|
log::warn!("Error in module `time`: \n{}", error);
|
||||||
&SegmentConfig {
|
return None;
|
||||||
value: &formatted_time_string,
|
}
|
||||||
style: None,
|
});
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use super::{Context, Module, RootModuleConfig, SegmentConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::configs::username::UsernameConfig;
|
use crate::configs::username::UsernameConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
/// Creates a module with the current user's username
|
/// Creates a module with the current user's username
|
||||||
@ -23,13 +24,32 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
let config: UsernameConfig = UsernameConfig::try_load(module.config);
|
let config: UsernameConfig = UsernameConfig::try_load(module.config);
|
||||||
|
|
||||||
if user != logname || ssh_connection.is_some() || user_uid == ROOT_UID || config.show_always {
|
if user != logname || ssh_connection.is_some() || user_uid == ROOT_UID || config.show_always {
|
||||||
let module_style = match user_uid {
|
let username = user?;
|
||||||
Some(0) => config.style_root,
|
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||||
_ => config.style_user,
|
formatter
|
||||||
};
|
.map_style(|variable| match variable {
|
||||||
|
"style" => {
|
||||||
module.set_style(module_style);
|
let module_style = match user_uid {
|
||||||
module.create_segment("username", &SegmentConfig::new(&user?));
|
Some(0) => config.style_root,
|
||||||
|
_ => config.style_user,
|
||||||
|
};
|
||||||
|
Some(Ok(module_style))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|variable| match variable {
|
||||||
|
"user" => Some(Ok(&username)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
module.set_segments(match parsed {
|
||||||
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `username`:\n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use super::{Context, Module, RootModuleConfig};
|
use super::{Context, Module, RootModuleConfig};
|
||||||
|
|
||||||
use crate::configs::zig::ZigConfig;
|
use crate::configs::zig::ZigConfig;
|
||||||
|
use crate::formatter::StringFormatter;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
/// Creates a module with the current Zig version
|
/// Creates a module with the current Zig version
|
||||||
@ -26,10 +27,30 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
let mut module = context.new_module("zig");
|
let mut module = context.new_module("zig");
|
||||||
let config = ZigConfig::try_load(module.config);
|
let config = ZigConfig::try_load(module.config);
|
||||||
|
|
||||||
module.set_style(config.style);
|
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 {
|
||||||
|
"version" => Some(Ok(zig_version.clone())),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.parse(None)
|
||||||
|
});
|
||||||
|
|
||||||
module.create_segment("symbol", &config.symbol);
|
module.set_segments(match parsed {
|
||||||
module.create_segment("version", &config.version.with_value(&zig_version));
|
Ok(segments) => segments,
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("Error in module `zig`:\n{}", error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
|
204
src/print.rs
204
src/print.rs
@ -1,14 +1,18 @@
|
|||||||
use ansi_term::ANSIStrings;
|
use ansi_term::ANSIStrings;
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
|
use std::collections::BTreeSet;
|
||||||
use std::fmt::{self, Debug, Write as FmtWrite};
|
use std::fmt::{self, Debug, Write as FmtWrite};
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use unicode_width::UnicodeWidthChar;
|
use unicode_width::UnicodeWidthChar;
|
||||||
|
|
||||||
|
use crate::configs::PROMPT_ORDER;
|
||||||
use crate::context::{Context, Shell};
|
use crate::context::{Context, Shell};
|
||||||
|
use crate::formatter::{StringFormatter, VariableHolder};
|
||||||
use crate::module::Module;
|
use crate::module::Module;
|
||||||
use crate::module::ALL_MODULES;
|
use crate::module::ALL_MODULES;
|
||||||
use crate::modules;
|
use crate::modules;
|
||||||
|
use crate::segment::Segment;
|
||||||
|
|
||||||
pub fn prompt(args: ArgMatches) {
|
pub fn prompt(args: ArgMatches) {
|
||||||
let context = Context::new(args);
|
let context = Context::new(args);
|
||||||
@ -21,34 +25,53 @@ pub fn get_prompt(context: Context) -> String {
|
|||||||
let config = context.config.get_root_config();
|
let config = context.config.get_root_config();
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
|
|
||||||
// Write a new line before the prompt
|
|
||||||
if config.add_newline {
|
|
||||||
writeln!(buf).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
// A workaround for a fish bug (see #739,#279). Applying it to all shells
|
// A workaround for a fish bug (see #739,#279). Applying it to all shells
|
||||||
// breaks things (see #808,#824,#834). Should only be printed in fish.
|
// breaks things (see #808,#824,#834). Should only be printed in fish.
|
||||||
if let Shell::Fish = context.shell {
|
if let Shell::Fish = context.shell {
|
||||||
buf.push_str("\x1b[J"); // An ASCII control code to clear screen
|
buf.push_str("\x1b[J"); // An ASCII control code to clear screen
|
||||||
}
|
}
|
||||||
|
|
||||||
let modules = compute_modules(&context);
|
let formatter = if let Ok(formatter) = StringFormatter::new(config.format) {
|
||||||
|
formatter
|
||||||
let mut print_without_prefix = true;
|
} else {
|
||||||
let printable = modules.iter();
|
log::error!("Error parsing `format`");
|
||||||
|
buf.push_str(">");
|
||||||
for module in printable {
|
return buf;
|
||||||
// Skip printing the prefix of a module after the line_break
|
};
|
||||||
if print_without_prefix {
|
let modules = formatter.get_variables();
|
||||||
let module_without_prefix = module.to_string_without_prefix(context.shell);
|
let formatter = formatter.map_variables_to_segments(|module| {
|
||||||
write!(buf, "{}", module_without_prefix).unwrap()
|
// Make $all display all modules
|
||||||
|
if module == "all" {
|
||||||
|
Some(Ok(PROMPT_ORDER
|
||||||
|
.par_iter()
|
||||||
|
.flat_map(|module| {
|
||||||
|
handle_module(module, &context, &modules)
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|module| module.segments)
|
||||||
|
.collect::<Vec<Segment>>()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()))
|
||||||
|
} else if context.is_module_disabled_in_config(&module) {
|
||||||
|
None
|
||||||
} else {
|
} else {
|
||||||
let module = module.ansi_strings_for_shell(context.shell);
|
// Get segments from module
|
||||||
write!(buf, "{}", ANSIStrings(&module)).unwrap();
|
Some(Ok(handle_module(module, &context, &modules)
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|module| module.segments)
|
||||||
|
.collect::<Vec<Segment>>()))
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
print_without_prefix = module.get_name() == "line_break"
|
// Creates a root module and prints it.
|
||||||
}
|
let mut root_module = Module::new("Starship Root", "The root module", None);
|
||||||
|
root_module.set_segments(
|
||||||
|
formatter
|
||||||
|
.parse(None)
|
||||||
|
.expect("Unexpected error returned in root format variables"),
|
||||||
|
);
|
||||||
|
|
||||||
|
let module_strings = root_module.ansi_strings_for_shell(context.shell);
|
||||||
|
write!(buf, "{}", ANSIStrings(&module_strings)).unwrap();
|
||||||
|
|
||||||
buf
|
buf
|
||||||
}
|
}
|
||||||
@ -72,16 +95,15 @@ pub fn explain(args: ArgMatches) {
|
|||||||
desc: String,
|
desc: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
let dont_print = vec!["line_break", "character"];
|
let dont_print = vec!["line_break"];
|
||||||
|
|
||||||
let modules = compute_modules(&context)
|
let modules = compute_modules(&context)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|module| !dont_print.contains(&module.get_name().as_str()))
|
.filter(|module| !dont_print.contains(&module.get_name().as_str()))
|
||||||
.map(|module| {
|
.map(|module| {
|
||||||
let ansi_strings = module.ansi_strings();
|
|
||||||
let value = module.get_segments().join("");
|
let value = module.get_segments().join("");
|
||||||
ModuleInfo {
|
ModuleInfo {
|
||||||
value: ansi_term::ANSIStrings(&ansi_strings[1..ansi_strings.len() - 1]).to_string(),
|
value: ansi_term::ANSIStrings(&module.ansi_strings()).to_string(),
|
||||||
value_len: value.chars().count() + count_wide_chars(&value),
|
value_len: value.chars().count() + count_wide_chars(&value),
|
||||||
desc: module.get_description().to_owned(),
|
desc: module.get_description().to_owned(),
|
||||||
}
|
}
|
||||||
@ -132,11 +154,38 @@ pub fn explain(args: ArgMatches) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn compute_modules<'a>(context: &'a Context) -> Vec<Module<'a>> {
|
fn compute_modules<'a>(context: &'a Context) -> Vec<Module<'a>> {
|
||||||
enum Mod<'a> {
|
let mut prompt_order: Vec<Module<'a>> = Vec::new();
|
||||||
Builtin(&'a str),
|
|
||||||
Custom(&'a str),
|
let config = context.config.get_root_config();
|
||||||
|
let formatter = if let Ok(formatter) = StringFormatter::new(config.format) {
|
||||||
|
formatter
|
||||||
|
} else {
|
||||||
|
log::error!("Error parsing `format`");
|
||||||
|
return Vec::new();
|
||||||
|
};
|
||||||
|
let modules = formatter.get_variables();
|
||||||
|
|
||||||
|
for module in &modules {
|
||||||
|
// Manually add all modules if `$all` is encountered
|
||||||
|
if module == "all" {
|
||||||
|
for module in PROMPT_ORDER.iter() {
|
||||||
|
let modules = handle_module(module, &context, &modules);
|
||||||
|
prompt_order.extend(modules.into_iter());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let modules = handle_module(module, &context, &modules);
|
||||||
|
prompt_order.extend(modules.into_iter());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prompt_order
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_module<'a>(
|
||||||
|
module: &str,
|
||||||
|
context: &'a Context,
|
||||||
|
module_list: &BTreeSet<String>,
|
||||||
|
) -> Vec<Module<'a>> {
|
||||||
struct DebugCustomModules<'tmp>(&'tmp toml::value::Table);
|
struct DebugCustomModules<'tmp>(&'tmp toml::value::Table);
|
||||||
|
|
||||||
impl Debug for DebugCustomModules<'_> {
|
impl Debug for DebugCustomModules<'_> {
|
||||||
@ -145,74 +194,63 @@ fn compute_modules<'a>(context: &'a Context) -> Vec<Module<'a>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut prompt_order: Vec<Mod> = Vec::new();
|
let mut modules: Vec<Option<Module>> = Vec::new();
|
||||||
|
|
||||||
// Write out a custom prompt order
|
if ALL_MODULES.contains(&module) {
|
||||||
let config_prompt_order = context.config.get_root_config().prompt_order;
|
// Write out a module if it isn't disabled
|
||||||
|
if !context.is_module_disabled_in_config(module) {
|
||||||
for module in &config_prompt_order {
|
modules.push(modules::handle(module, &context));
|
||||||
if ALL_MODULES.contains(module) {
|
|
||||||
// Write out a module if it isn't disabled
|
|
||||||
if !context.is_module_disabled_in_config(*module) {
|
|
||||||
prompt_order.push(Mod::Builtin(module));
|
|
||||||
}
|
|
||||||
} else if *module == "custom" {
|
|
||||||
// Write out all custom modules, except for those that are explicitly set
|
|
||||||
if let Some(custom_modules) = context.config.get_custom_modules() {
|
|
||||||
for (custom_module, config) in custom_modules {
|
|
||||||
if should_add_implicit_custom_module(
|
|
||||||
custom_module,
|
|
||||||
config,
|
|
||||||
&config_prompt_order,
|
|
||||||
) {
|
|
||||||
prompt_order.push(Mod::Custom(custom_module));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if module.starts_with("custom.") {
|
|
||||||
// Write out a custom module if it isn't disabled (and it exists...)
|
|
||||||
match context.is_custom_module_disabled_in_config(&module[7..]) {
|
|
||||||
Some(true) => (), // Module is disabled, we don't add it to the prompt
|
|
||||||
Some(false) => prompt_order.push(Mod::Custom(&module[7..])),
|
|
||||||
None => match context.config.get_custom_modules() {
|
|
||||||
Some(modules) => log::debug!(
|
|
||||||
"prompt_order contains custom module \"{}\", but no configuration was provided. Configuration for the following modules were provided: {:?}",
|
|
||||||
module,
|
|
||||||
DebugCustomModules(modules),
|
|
||||||
),
|
|
||||||
None => log::debug!(
|
|
||||||
"prompt_order contains custom module \"{}\", but no configuration was provided.",
|
|
||||||
module,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log::debug!(
|
|
||||||
"Expected prompt_order to contain value from {:?}. Instead received {}",
|
|
||||||
ALL_MODULES,
|
|
||||||
module,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
} else if module == "custom" {
|
||||||
|
// Write out all custom modules, except for those that are explicitly set
|
||||||
|
if let Some(custom_modules) = context.config.get_custom_modules() {
|
||||||
|
let custom_modules = custom_modules
|
||||||
|
.iter()
|
||||||
|
.map(|(custom_module, config)| {
|
||||||
|
if should_add_implicit_custom_module(custom_module, config, &module_list) {
|
||||||
|
modules::custom::module(custom_module, &context)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<Option<Module<'a>>>>();
|
||||||
|
modules.extend(custom_modules)
|
||||||
|
}
|
||||||
|
} else if module.starts_with("custom.") {
|
||||||
|
// Write out a custom module if it isn't disabled (and it exists...)
|
||||||
|
match context.is_custom_module_disabled_in_config(&module[7..]) {
|
||||||
|
Some(true) => (), // Module is disabled, we don't add it to the prompt
|
||||||
|
Some(false) => modules.push(modules::custom::module(&module[7..], &context)),
|
||||||
|
None => match context.config.get_custom_modules() {
|
||||||
|
Some(modules) => log::debug!(
|
||||||
|
"prompt_order contains custom module \"{}\", but no configuration was provided. Configuration for the following modules were provided: {:?}",
|
||||||
|
module,
|
||||||
|
DebugCustomModules(modules),
|
||||||
|
),
|
||||||
|
None => log::debug!(
|
||||||
|
"prompt_order contains custom module \"{}\", but no configuration was provided.",
|
||||||
|
module,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log::debug!(
|
||||||
|
"Expected prompt_order to contain value from {:?}. Instead received {}",
|
||||||
|
ALL_MODULES,
|
||||||
|
module,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
prompt_order
|
modules.into_iter().flatten().collect()
|
||||||
.par_iter()
|
|
||||||
.map(|module| match module {
|
|
||||||
Mod::Builtin(builtin) => modules::handle(builtin, context),
|
|
||||||
Mod::Custom(custom) => modules::custom::module(custom, context),
|
|
||||||
}) // Compute segments
|
|
||||||
.flatten() // Remove segments set to `None`
|
|
||||||
.collect::<Vec<Module<'a>>>()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_add_implicit_custom_module(
|
fn should_add_implicit_custom_module(
|
||||||
custom_module: &str,
|
custom_module: &str,
|
||||||
config: &toml::Value,
|
config: &toml::Value,
|
||||||
config_prompt_order: &[&str],
|
module_list: &BTreeSet<String>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let is_explicitly_specified = config_prompt_order.iter().any(|x| {
|
let explicit_module_name = format!("custom.{}", custom_module);
|
||||||
x.len() == 7 + custom_module.len() && &x[..7] == "custom." && &x[7..] == custom_module
|
let is_explicitly_specified = module_list.contains(&explicit_module_name);
|
||||||
});
|
|
||||||
|
|
||||||
if is_explicitly_specified {
|
if is_explicitly_specified {
|
||||||
// The module is already specified explicitly, so we skip it
|
// The module is already specified explicitly, so we skip it
|
||||||
|
@ -22,7 +22,7 @@ fn region_set() -> io::Result<()> {
|
|||||||
let output = common::render_module("aws")
|
let output = common::render_module("aws")
|
||||||
.env("AWS_REGION", "ap-northeast-2")
|
.env("AWS_REGION", "ap-northeast-2")
|
||||||
.output()?;
|
.output()?;
|
||||||
let expected = format!("on {} ", Color::Yellow.bold().paint("☁️ ap-northeast-2"));
|
let expected = format!("on {} ", Color::Yellow.bold().paint("☁️ (ap-northeast-2)"));
|
||||||
let actual = String::from_utf8(output.stdout).unwrap();
|
let actual = String::from_utf8(output.stdout).unwrap();
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -37,7 +37,7 @@ fn region_set_with_alias() -> io::Result<()> {
|
|||||||
ap-southeast-2 = "au"
|
ap-southeast-2 = "au"
|
||||||
})
|
})
|
||||||
.output()?;
|
.output()?;
|
||||||
let expected = format!("on {} ", Color::Yellow.bold().paint("☁️ au"));
|
let expected = format!("on {} ", Color::Yellow.bold().paint("☁️ (au)"));
|
||||||
let actual = String::from_utf8(output.stdout).unwrap();
|
let actual = String::from_utf8(output.stdout).unwrap();
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -49,7 +49,7 @@ fn default_region_set() -> io::Result<()> {
|
|||||||
.env("AWS_REGION", "ap-northeast-2")
|
.env("AWS_REGION", "ap-northeast-2")
|
||||||
.env("AWS_DEFAULT_REGION", "ap-northeast-1")
|
.env("AWS_DEFAULT_REGION", "ap-northeast-1")
|
||||||
.output()?;
|
.output()?;
|
||||||
let expected = format!("on {} ", Color::Yellow.bold().paint("☁️ ap-northeast-1"));
|
let expected = format!("on {} ", Color::Yellow.bold().paint("☁️ (ap-northeast-1)"));
|
||||||
let actual = String::from_utf8(output.stdout).unwrap();
|
let actual = String::from_utf8(output.stdout).unwrap();
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -112,7 +112,7 @@ region = us-east-2
|
|||||||
let output = common::render_module("aws")
|
let output = common::render_module("aws")
|
||||||
.env("AWS_CONFIG_FILE", config_path.to_string_lossy().as_ref())
|
.env("AWS_CONFIG_FILE", config_path.to_string_lossy().as_ref())
|
||||||
.output()?;
|
.output()?;
|
||||||
let expected = format!("on {} ", Color::Yellow.bold().paint("☁️ us-east-1"));
|
let expected = format!("on {} ", Color::Yellow.bold().paint("☁️ (us-east-1)"));
|
||||||
let actual = String::from_utf8(output.stdout).unwrap();
|
let actual = String::from_utf8(output.stdout).unwrap();
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
dir.close()
|
dir.close()
|
||||||
@ -155,10 +155,6 @@ fn profile_and_region_set_with_display_all() -> io::Result<()> {
|
|||||||
let output = common::render_module("aws")
|
let output = common::render_module("aws")
|
||||||
.env("AWS_PROFILE", "astronauts")
|
.env("AWS_PROFILE", "astronauts")
|
||||||
.env("AWS_REGION", "ap-northeast-1")
|
.env("AWS_REGION", "ap-northeast-1")
|
||||||
.use_config(toml::toml! {
|
|
||||||
[aws]
|
|
||||||
displayed_items = "all"
|
|
||||||
})
|
|
||||||
.output()?;
|
.output()?;
|
||||||
let expected = format!(
|
let expected = format!(
|
||||||
"on {} ",
|
"on {} ",
|
||||||
@ -173,10 +169,6 @@ fn profile_and_region_set_with_display_all() -> io::Result<()> {
|
|||||||
fn profile_set_with_display_all() -> io::Result<()> {
|
fn profile_set_with_display_all() -> io::Result<()> {
|
||||||
let output = common::render_module("aws")
|
let output = common::render_module("aws")
|
||||||
.env("AWS_PROFILE", "astronauts")
|
.env("AWS_PROFILE", "astronauts")
|
||||||
.use_config(toml::toml! {
|
|
||||||
[aws]
|
|
||||||
displayed_items = "all"
|
|
||||||
})
|
|
||||||
.output()?;
|
.output()?;
|
||||||
let expected = format!("on {} ", Color::Yellow.bold().paint("☁️ astronauts"));
|
let expected = format!("on {} ", Color::Yellow.bold().paint("☁️ astronauts"));
|
||||||
let actual = String::from_utf8(output.stdout).unwrap();
|
let actual = String::from_utf8(output.stdout).unwrap();
|
||||||
@ -188,12 +180,8 @@ fn profile_set_with_display_all() -> io::Result<()> {
|
|||||||
fn region_set_with_display_all() -> io::Result<()> {
|
fn region_set_with_display_all() -> io::Result<()> {
|
||||||
let output = common::render_module("aws")
|
let output = common::render_module("aws")
|
||||||
.env("AWS_REGION", "ap-northeast-1")
|
.env("AWS_REGION", "ap-northeast-1")
|
||||||
.use_config(toml::toml! {
|
|
||||||
[aws]
|
|
||||||
displayed_items = "all"
|
|
||||||
})
|
|
||||||
.output()?;
|
.output()?;
|
||||||
let expected = format!("on {} ", Color::Yellow.bold().paint("☁️ ap-northeast-1"));
|
let expected = format!("on {} ", Color::Yellow.bold().paint("☁️ (ap-northeast-1)"));
|
||||||
let actual = String::from_utf8(output.stdout).unwrap();
|
let actual = String::from_utf8(output.stdout).unwrap();
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -206,7 +194,7 @@ fn profile_and_region_set_with_display_region() -> io::Result<()> {
|
|||||||
.env("AWS_DEFAULT_REGION", "ap-northeast-1")
|
.env("AWS_DEFAULT_REGION", "ap-northeast-1")
|
||||||
.use_config(toml::toml! {
|
.use_config(toml::toml! {
|
||||||
[aws]
|
[aws]
|
||||||
displayed_items = "region"
|
format = "on [$symbol$region]($style) "
|
||||||
})
|
})
|
||||||
.output()?;
|
.output()?;
|
||||||
let expected = format!("on {} ", Color::Yellow.bold().paint("☁️ ap-northeast-1"));
|
let expected = format!("on {} ", Color::Yellow.bold().paint("☁️ ap-northeast-1"));
|
||||||
@ -222,7 +210,7 @@ fn profile_and_region_set_with_display_profile() -> io::Result<()> {
|
|||||||
.env("AWS_REGION", "ap-northeast-1")
|
.env("AWS_REGION", "ap-northeast-1")
|
||||||
.use_config(toml::toml! {
|
.use_config(toml::toml! {
|
||||||
[aws]
|
[aws]
|
||||||
displayed_items = "profile"
|
format = "on [$symbol$profile]($style) "
|
||||||
})
|
})
|
||||||
.output()?;
|
.output()?;
|
||||||
let expected = format!("on {} ", Color::Yellow.bold().paint("☁️ astronauts"));
|
let expected = format!("on {} ", Color::Yellow.bold().paint("☁️ astronauts"));
|
||||||
@ -237,10 +225,10 @@ fn region_set_with_display_profile() -> io::Result<()> {
|
|||||||
.env("AWS_REGION", "ap-northeast-1")
|
.env("AWS_REGION", "ap-northeast-1")
|
||||||
.use_config(toml::toml! {
|
.use_config(toml::toml! {
|
||||||
[aws]
|
[aws]
|
||||||
displayed_items = "profile"
|
format = "on [$symbol$profile]($style) "
|
||||||
})
|
})
|
||||||
.output()?;
|
.output()?;
|
||||||
let expected = "";
|
let expected = format!("on {} ", Color::Yellow.bold().paint("☁️ "));
|
||||||
let actual = String::from_utf8(output.stdout).unwrap();
|
let actual = String::from_utf8(output.stdout).unwrap();
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -252,7 +240,7 @@ fn region_not_set_with_display_region() -> io::Result<()> {
|
|||||||
let output = common::render_module("aws")
|
let output = common::render_module("aws")
|
||||||
.use_config(toml::toml! {
|
.use_config(toml::toml! {
|
||||||
[aws]
|
[aws]
|
||||||
displayed_items = "region"
|
format = "on [$symbol$region]($style) "
|
||||||
})
|
})
|
||||||
.output()?;
|
.output()?;
|
||||||
let expected = "";
|
let expected = "";
|
||||||
|
@ -4,7 +4,7 @@ use std::io;
|
|||||||
use crate::common::{self, TestCommand};
|
use crate::common::{self, TestCommand};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn char_module_success_status() -> io::Result<()> {
|
fn success_status() -> io::Result<()> {
|
||||||
let expected = format!("{} ", Color::Green.bold().paint("❯"));
|
let expected = format!("{} ", Color::Green.bold().paint("❯"));
|
||||||
|
|
||||||
// Status code 0
|
// Status code 0
|
||||||
@ -23,7 +23,7 @@ fn char_module_success_status() -> io::Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn char_module_failure_status() -> io::Result<()> {
|
fn failure_status() -> io::Result<()> {
|
||||||
let expected = format!("{} ", Color::Red.bold().paint("❯"));
|
let expected = format!("{} ", Color::Red.bold().paint("❯"));
|
||||||
|
|
||||||
let exit_values = ["1", "54321", "-5000"];
|
let exit_values = ["1", "54321", "-5000"];
|
||||||
@ -39,9 +39,9 @@ fn char_module_failure_status() -> io::Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn char_module_symbolyes_status() -> io::Result<()> {
|
fn custom_symbol() -> io::Result<()> {
|
||||||
let expected_fail = format!("{} ", Color::Red.bold().paint("✖"));
|
let expected_fail = format!("{} ", Color::Red.bold().paint("✖"));
|
||||||
let expected_success = format!("{} ", Color::Green.bold().paint("❯"));
|
let expected_success = format!("{} ", Color::Green.bold().paint("➜"));
|
||||||
|
|
||||||
let exit_values = ["1", "54321", "-5000"];
|
let exit_values = ["1", "54321", "-5000"];
|
||||||
|
|
||||||
@ -51,7 +51,9 @@ fn char_module_symbolyes_status() -> io::Result<()> {
|
|||||||
let output = common::render_module("character")
|
let output = common::render_module("character")
|
||||||
.use_config(toml::toml! {
|
.use_config(toml::toml! {
|
||||||
[character]
|
[character]
|
||||||
use_symbol_for_status = true
|
success_symbol = "[➜](bold green)"
|
||||||
|
error_symbol = "[✖](bold red)"
|
||||||
|
|
||||||
})
|
})
|
||||||
.arg(arg)
|
.arg(arg)
|
||||||
.output()?;
|
.output()?;
|
||||||
@ -63,7 +65,8 @@ fn char_module_symbolyes_status() -> io::Result<()> {
|
|||||||
let output = common::render_module("character")
|
let output = common::render_module("character")
|
||||||
.use_config(toml::toml! {
|
.use_config(toml::toml! {
|
||||||
[character]
|
[character]
|
||||||
use_symbol_for_status = true
|
success_symbol = "[➜](bold green)"
|
||||||
|
error_symbol = "[✖](bold red)"
|
||||||
})
|
})
|
||||||
.arg("--status=0")
|
.arg("--status=0")
|
||||||
.output()?;
|
.output()?;
|
||||||
@ -74,11 +77,10 @@ fn char_module_symbolyes_status() -> io::Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn char_module_zsh_keymap() -> io::Result<()> {
|
fn zsh_keymap() -> io::Result<()> {
|
||||||
let expected_vicmd = "❮";
|
let expected_vicmd = format!("{} ", Color::Green.bold().paint("❮"));
|
||||||
// TODO make this less... well, stupid when ANSI escapes can be mocked out
|
let expected_specified = format!("{} ", Color::Green.bold().paint("V"));
|
||||||
let expected_specified = "I HIGHLY DOUBT THIS WILL SHOW UP IN OTHER OUTPUT";
|
let expected_other = format!("{} ", Color::Green.bold().paint("❯"));
|
||||||
let expected_other = "❯";
|
|
||||||
|
|
||||||
// zle keymap is vicmd
|
// zle keymap is vicmd
|
||||||
let output = common::render_module("character")
|
let output = common::render_module("character")
|
||||||
@ -86,19 +88,19 @@ fn char_module_zsh_keymap() -> io::Result<()> {
|
|||||||
.arg("--keymap=vicmd")
|
.arg("--keymap=vicmd")
|
||||||
.output()?;
|
.output()?;
|
||||||
let actual = String::from_utf8(output.stdout).unwrap();
|
let actual = String::from_utf8(output.stdout).unwrap();
|
||||||
assert!(actual.contains(&expected_vicmd));
|
assert_eq!(expected_vicmd, actual);
|
||||||
|
|
||||||
// specified vicmd character
|
// specified vicmd character
|
||||||
let output = common::render_module("character")
|
let output = common::render_module("character")
|
||||||
.use_config(toml::toml! {
|
.use_config(toml::toml! {
|
||||||
[character]
|
[character]
|
||||||
vicmd_symbol = "I HIGHLY DOUBT THIS WILL SHOW UP IN OTHER OUTPUT"
|
vicmd_symbol = "[V](bold green)"
|
||||||
})
|
})
|
||||||
.env("STARSHIP_SHELL", "zsh")
|
.env("STARSHIP_SHELL", "zsh")
|
||||||
.arg("--keymap=vicmd")
|
.arg("--keymap=vicmd")
|
||||||
.output()?;
|
.output()?;
|
||||||
let actual = String::from_utf8(output.stdout).unwrap();
|
let actual = String::from_utf8(output.stdout).unwrap();
|
||||||
assert!(actual.contains(&expected_specified));
|
assert_eq!(expected_specified, actual);
|
||||||
|
|
||||||
// zle keymap is other
|
// zle keymap is other
|
||||||
let output = common::render_module("character")
|
let output = common::render_module("character")
|
||||||
@ -106,17 +108,16 @@ fn char_module_zsh_keymap() -> io::Result<()> {
|
|||||||
.arg("--keymap=visual")
|
.arg("--keymap=visual")
|
||||||
.output()?;
|
.output()?;
|
||||||
let actual = String::from_utf8(output.stdout).unwrap();
|
let actual = String::from_utf8(output.stdout).unwrap();
|
||||||
assert!(actual.contains(&expected_other));
|
assert_eq!(expected_other, actual);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn char_module_fish_keymap() -> io::Result<()> {
|
fn fish_keymap() -> io::Result<()> {
|
||||||
let expected_vicmd = "❮";
|
let expected_vicmd = format!("{} ", Color::Green.bold().paint("❮"));
|
||||||
// TODO make this less... well, stupid when ANSI escapes can be mocked out
|
let expected_specified = format!("{} ", Color::Green.bold().paint("V"));
|
||||||
let expected_specified = "I HIGHLY DOUBT THIS WILL SHOW UP IN OTHER OUTPUT";
|
let expected_other = format!("{} ", Color::Green.bold().paint("❯"));
|
||||||
let expected_other = "❯";
|
|
||||||
|
|
||||||
// fish keymap is default
|
// fish keymap is default
|
||||||
let output = common::render_module("character")
|
let output = common::render_module("character")
|
||||||
@ -124,19 +125,19 @@ fn char_module_fish_keymap() -> io::Result<()> {
|
|||||||
.arg("--keymap=default")
|
.arg("--keymap=default")
|
||||||
.output()?;
|
.output()?;
|
||||||
let actual = String::from_utf8(output.stdout).unwrap();
|
let actual = String::from_utf8(output.stdout).unwrap();
|
||||||
assert!(actual.contains(&expected_vicmd));
|
assert_eq!(expected_vicmd, actual);
|
||||||
|
|
||||||
// specified vicmd character
|
// specified vicmd character
|
||||||
let output = common::render_module("character")
|
let output = common::render_module("character")
|
||||||
.use_config(toml::toml! {
|
.use_config(toml::toml! {
|
||||||
[character]
|
[character]
|
||||||
vicmd_symbol = "I HIGHLY DOUBT THIS WILL SHOW UP IN OTHER OUTPUT"
|
vicmd_symbol = "[V](bold green)"
|
||||||
})
|
})
|
||||||
.env("STARSHIP_SHELL", "fish")
|
.env("STARSHIP_SHELL", "fish")
|
||||||
.arg("--keymap=default")
|
.arg("--keymap=default")
|
||||||
.output()?;
|
.output()?;
|
||||||
let actual = String::from_utf8(output.stdout).unwrap();
|
let actual = String::from_utf8(output.stdout).unwrap();
|
||||||
assert!(actual.contains(&expected_specified));
|
assert_eq!(expected_specified, actual);
|
||||||
|
|
||||||
// fish keymap is other
|
// fish keymap is other
|
||||||
let output = common::render_module("character")
|
let output = common::render_module("character")
|
||||||
@ -144,7 +145,7 @@ fn char_module_fish_keymap() -> io::Result<()> {
|
|||||||
.arg("--keymap=visual")
|
.arg("--keymap=visual")
|
||||||
.output()?;
|
.output()?;
|
||||||
let actual = String::from_utf8(output.stdout).unwrap();
|
let actual = String::from_utf8(output.stdout).unwrap();
|
||||||
assert!(actual.contains(&expected_other));
|
assert_eq!(expected_other, actual);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ fn config_1s_duration_prefix_underwent() -> io::Result<()> {
|
|||||||
let output = common::render_module("cmd_duration")
|
let output = common::render_module("cmd_duration")
|
||||||
.use_config(toml::toml! {
|
.use_config(toml::toml! {
|
||||||
[cmd_duration]
|
[cmd_duration]
|
||||||
prefix = "underwent "
|
format = "underwent [$duration]($style) "
|
||||||
})
|
})
|
||||||
.arg("--cmd-duration=1000")
|
.arg("--cmd-duration=1000")
|
||||||
.output()?;
|
.output()?;
|
||||||
@ -80,7 +80,7 @@ fn config_5s_duration_prefix_underwent() -> io::Result<()> {
|
|||||||
let output = common::render_module("cmd_duration")
|
let output = common::render_module("cmd_duration")
|
||||||
.use_config(toml::toml! {
|
.use_config(toml::toml! {
|
||||||
[cmd_duration]
|
[cmd_duration]
|
||||||
prefix = "underwent "
|
format = "underwent [$duration]($style) "
|
||||||
})
|
})
|
||||||
.arg("--cmd-duration=5000")
|
.arg("--cmd-duration=5000")
|
||||||
.output()?;
|
.output()?;
|
||||||
|
@ -16,7 +16,7 @@ const EXE_PATH: &str = "./target/debug/starship.exe";
|
|||||||
const EXE_PATH: &str = "./target/debug/starship";
|
const EXE_PATH: &str = "./target/debug/starship";
|
||||||
|
|
||||||
/// Render the full starship prompt
|
/// Render the full starship prompt
|
||||||
pub fn render_prompt() -> process::Command {
|
pub fn _render_prompt() -> process::Command {
|
||||||
let mut command = process::Command::new(EXE_PATH);
|
let mut command = process::Command::new(EXE_PATH);
|
||||||
|
|
||||||
command
|
command
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user