mirror of
https://github.com/Llewellynvdm/starship.git
synced 2024-11-28 15:56:28 +00:00
fix(escaping): move escaping to individual variables (#3107)
This commit is contained in:
parent
73277d37c6
commit
c1f2d345aa
@ -3319,6 +3319,19 @@ If you have an interesting example not covered there, feel free to share it ther
|
|||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
::: warning Command output is printed unescaped to the prompt
|
||||||
|
|
||||||
|
Whatever output the command generates is printed unmodified in the prompt. This means if the output
|
||||||
|
contains special sequences that are interpreted by your shell they will be expanded when displayed.
|
||||||
|
These special sequences are shell specific, e.g. you can write a command module that writes bash sequences,
|
||||||
|
e.g. `\h`, but this module will not work in a fish or zsh shell.
|
||||||
|
|
||||||
|
Format strings can also contain shell specific prompt sequences, e.g.
|
||||||
|
[Bash](https://www.gnu.org/software/bash/manual/html_node/Controlling-the-Prompt.html),
|
||||||
|
[Zsh](https://zsh.sourceforge.io/Doc/Release/Prompt-Expansion.html).
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
### Options
|
### Options
|
||||||
|
|
||||||
| Option | Default | Description |
|
| Option | Default | Description |
|
||||||
|
@ -7,6 +7,7 @@ use std::error::Error;
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use crate::config::parse_style_string;
|
use crate::config::parse_style_string;
|
||||||
|
use crate::context::{Context, Shell};
|
||||||
use crate::segment::Segment;
|
use crate::segment::Segment;
|
||||||
|
|
||||||
use super::model::*;
|
use super::model::*;
|
||||||
@ -15,6 +16,7 @@ use super::parser::{parse, Rule};
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
enum VariableValue<'a> {
|
enum VariableValue<'a> {
|
||||||
Plain(Cow<'a, str>),
|
Plain(Cow<'a, str>),
|
||||||
|
NoEscapingPlain(Cow<'a, str>),
|
||||||
Styled(Vec<Segment>),
|
Styled(Vec<Segment>),
|
||||||
Meta(Vec<FormatElement<'a>>),
|
Meta(Vec<FormatElement<'a>>),
|
||||||
}
|
}
|
||||||
@ -123,6 +125,27 @@ impl<'a> StringFormatter<'a> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Maps variable name into a value which is wrapped to prevent escaping later
|
||||||
|
///
|
||||||
|
/// This should be used for variables that should not be escaped before inclusion in the prompt
|
||||||
|
///
|
||||||
|
/// See `StringFormatter::map` for description on the parameters.
|
||||||
|
///
|
||||||
|
pub fn map_no_escaping<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::NoEscapingPlain(var.into())));
|
||||||
|
});
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Maps a meta-variable to a format string containing other variables.
|
/// 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
|
/// This function should be called **before** other map methods so that variables found in
|
||||||
@ -206,11 +229,16 @@ impl<'a> StringFormatter<'a> {
|
|||||||
///
|
///
|
||||||
/// - Format string in meta variables fails to parse
|
/// - Format string in meta variables fails to parse
|
||||||
/// - Variable mapper returns an error.
|
/// - Variable mapper returns an error.
|
||||||
pub fn parse(self, default_style: Option<Style>) -> Result<Vec<Segment>, StringFormatterError> {
|
pub fn parse(
|
||||||
|
self,
|
||||||
|
default_style: Option<Style>,
|
||||||
|
context: Option<&Context>,
|
||||||
|
) -> Result<Vec<Segment>, StringFormatterError> {
|
||||||
fn parse_textgroup<'a>(
|
fn parse_textgroup<'a>(
|
||||||
textgroup: TextGroup<'a>,
|
textgroup: TextGroup<'a>,
|
||||||
variables: &'a VariableMapType<'a>,
|
variables: &'a VariableMapType<'a>,
|
||||||
style_variables: &'a StyleVariableMapType<'a>,
|
style_variables: &'a StyleVariableMapType<'a>,
|
||||||
|
context: Option<&Context>,
|
||||||
) -> Result<Vec<Segment>, StringFormatterError> {
|
) -> Result<Vec<Segment>, StringFormatterError> {
|
||||||
let style = parse_style(textgroup.style, style_variables);
|
let style = parse_style(textgroup.style, style_variables);
|
||||||
parse_format(
|
parse_format(
|
||||||
@ -218,6 +246,7 @@ impl<'a> StringFormatter<'a> {
|
|||||||
style.transpose()?,
|
style.transpose()?,
|
||||||
variables,
|
variables,
|
||||||
style_variables,
|
style_variables,
|
||||||
|
context,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,6 +281,7 @@ impl<'a> StringFormatter<'a> {
|
|||||||
style: Option<Style>,
|
style: Option<Style>,
|
||||||
variables: &'a VariableMapType<'a>,
|
variables: &'a VariableMapType<'a>,
|
||||||
style_variables: &'a StyleVariableMapType<'a>,
|
style_variables: &'a StyleVariableMapType<'a>,
|
||||||
|
context: Option<&Context>,
|
||||||
) -> Result<Vec<Segment>, StringFormatterError> {
|
) -> Result<Vec<Segment>, StringFormatterError> {
|
||||||
let results: Result<Vec<Vec<Segment>>, StringFormatterError> = format
|
let results: Result<Vec<Vec<Segment>>, StringFormatterError> = format
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -263,7 +293,7 @@ impl<'a> StringFormatter<'a> {
|
|||||||
format: textgroup.format,
|
format: textgroup.format,
|
||||||
style: textgroup.style,
|
style: textgroup.style,
|
||||||
};
|
};
|
||||||
parse_textgroup(textgroup, variables, style_variables)
|
parse_textgroup(textgroup, variables, style_variables, context)
|
||||||
}
|
}
|
||||||
FormatElement::Variable(name) => variables
|
FormatElement::Variable(name) => variables
|
||||||
.get(name.as_ref())
|
.get(name.as_ref())
|
||||||
@ -278,14 +308,26 @@ impl<'a> StringFormatter<'a> {
|
|||||||
segment
|
segment
|
||||||
})
|
})
|
||||||
.collect()),
|
.collect()),
|
||||||
VariableValue::Plain(text) => Ok(Segment::from_text(style, text)),
|
VariableValue::Plain(text) => Ok(Segment::from_text(
|
||||||
|
style,
|
||||||
|
shell_prompt_escape(
|
||||||
|
text,
|
||||||
|
match context {
|
||||||
|
None => Shell::Unknown,
|
||||||
|
Some(c) => c.shell,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
VariableValue::NoEscapingPlain(text) => {
|
||||||
|
Ok(Segment::from_text(style, text))
|
||||||
|
}
|
||||||
VariableValue::Meta(format) => {
|
VariableValue::Meta(format) => {
|
||||||
let formatter = StringFormatter {
|
let formatter = StringFormatter {
|
||||||
format,
|
format,
|
||||||
variables: clone_without_meta(variables),
|
variables: clone_without_meta(variables),
|
||||||
style_variables: style_variables.clone(),
|
style_variables: style_variables.clone(),
|
||||||
};
|
};
|
||||||
formatter.parse(style)
|
formatter.parse(style, context)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| Ok(Vec::new())),
|
.unwrap_or_else(|| Ok(Vec::new())),
|
||||||
@ -320,6 +362,9 @@ impl<'a> StringFormatter<'a> {
|
|||||||
VariableValue::Plain(plain_value) => {
|
VariableValue::Plain(plain_value) => {
|
||||||
!plain_value.is_empty()
|
!plain_value.is_empty()
|
||||||
}
|
}
|
||||||
|
VariableValue::NoEscapingPlain(
|
||||||
|
no_escaping_plain_value,
|
||||||
|
) => !no_escaping_plain_value.is_empty(),
|
||||||
VariableValue::Styled(segments) => segments
|
VariableValue::Styled(segments) => segments
|
||||||
.iter()
|
.iter()
|
||||||
.any(|x| !x.value().is_empty()),
|
.any(|x| !x.value().is_empty()),
|
||||||
@ -331,7 +376,7 @@ impl<'a> StringFormatter<'a> {
|
|||||||
let should_show: bool = should_show_elements(&format, variables);
|
let should_show: bool = should_show_elements(&format, variables);
|
||||||
|
|
||||||
if should_show {
|
if should_show {
|
||||||
parse_format(format, style, variables, style_variables)
|
parse_format(format, style, variables, style_variables, context)
|
||||||
} else {
|
} else {
|
||||||
Ok(Vec::new())
|
Ok(Vec::new())
|
||||||
}
|
}
|
||||||
@ -347,6 +392,7 @@ impl<'a> StringFormatter<'a> {
|
|||||||
default_style,
|
default_style,
|
||||||
&self.variables,
|
&self.variables,
|
||||||
&self.style_variables,
|
&self.style_variables,
|
||||||
|
context,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -380,6 +426,28 @@ fn clone_without_meta<'a>(variables: &VariableMapType<'a>) -> VariableMapType<'a
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Escape interpretable characters for the shell prompt
|
||||||
|
pub fn shell_prompt_escape<T>(text: T, shell: Shell) -> String
|
||||||
|
where
|
||||||
|
T: Into<String>,
|
||||||
|
{
|
||||||
|
// Handle other interpretable characters
|
||||||
|
match shell {
|
||||||
|
// Bash might interepret baskslashes, backticks and $
|
||||||
|
// see #658 for more details
|
||||||
|
Shell::Bash => text
|
||||||
|
.into()
|
||||||
|
.replace('\\', r"\\")
|
||||||
|
.replace('$', r"\$")
|
||||||
|
.replace('`', r"\`"),
|
||||||
|
Shell::Zsh => {
|
||||||
|
// % is an escape in zsh, see PROMPT in `man zshmisc`
|
||||||
|
text.into().replace('%', "%%")
|
||||||
|
}
|
||||||
|
_ => text.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -404,7 +472,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).unwrap();
|
let result = formatter.parse(style, None).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);
|
||||||
}
|
}
|
||||||
@ -413,7 +481,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).unwrap();
|
let result = formatter.parse(None, 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()));
|
||||||
}
|
}
|
||||||
@ -428,7 +496,7 @@ mod tests {
|
|||||||
"var1" => Some(Ok("text1".to_owned())),
|
"var1" => Some(Ok("text1".to_owned())),
|
||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
let result = formatter.parse(None).unwrap();
|
let result = formatter.parse(None, 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);
|
||||||
}
|
}
|
||||||
@ -444,7 +512,7 @@ mod tests {
|
|||||||
"style" => Some(Ok("red bold".to_owned())),
|
"style" => Some(Ok("red bold".to_owned())),
|
||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
let result = formatter.parse(None).unwrap();
|
let result = formatter.parse(None, None).unwrap();
|
||||||
let mut result_iter = result.iter();
|
let mut result_iter = result.iter();
|
||||||
match_next!(result_iter, "root", root_style);
|
match_next!(result_iter, "root", root_style);
|
||||||
}
|
}
|
||||||
@ -456,7 +524,7 @@ mod tests {
|
|||||||
let formatter = StringFormatter::new(FORMAT_STR)
|
let formatter = StringFormatter::new(FORMAT_STR)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.map(|variable| Some(Ok(format!("${{{}}}", variable))));
|
.map(|variable| Some(Ok(format!("${{{}}}", variable))));
|
||||||
let result = formatter.parse(None).unwrap();
|
let result = formatter.parse(None, None).unwrap();
|
||||||
let mut result_iter = result.iter();
|
let mut result_iter = result.iter();
|
||||||
match_next!(result_iter, "${env:PWD}", None);
|
match_next!(result_iter, "${env:PWD}", None);
|
||||||
}
|
}
|
||||||
@ -466,7 +534,7 @@ mod tests {
|
|||||||
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).unwrap();
|
let result = formatter.parse(None, 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);
|
||||||
}
|
}
|
||||||
@ -479,7 +547,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).unwrap();
|
let result = formatter.parse(outer_style, None).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);
|
||||||
@ -497,7 +565,7 @@ mod tests {
|
|||||||
"var" => Some(Ok("text".to_owned())),
|
"var" => Some(Ok("text".to_owned())),
|
||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
let result = formatter.parse(None).unwrap();
|
let result = formatter.parse(None, 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);
|
||||||
}
|
}
|
||||||
@ -523,7 +591,7 @@ mod tests {
|
|||||||
"var" => Some(Ok(segments.clone())),
|
"var" => Some(Ok(segments.clone())),
|
||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
let result = formatter.parse(None).unwrap();
|
let result = formatter.parse(None, 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);
|
||||||
@ -546,7 +614,7 @@ mod tests {
|
|||||||
"b" => Some(Ok("$b")),
|
"b" => Some(Ok("$b")),
|
||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
let result = formatter.parse(None).unwrap();
|
let result = formatter.parse(None, None).unwrap();
|
||||||
let mut result_iter = result.iter();
|
let mut result_iter = result.iter();
|
||||||
match_next!(result_iter, "$a", None);
|
match_next!(result_iter, "$a", None);
|
||||||
match_next!(result_iter, "$b", None);
|
match_next!(result_iter, "$b", None);
|
||||||
@ -568,7 +636,7 @@ mod tests {
|
|||||||
"c" => Some(Ok("$c")),
|
"c" => Some(Ok("$c")),
|
||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
let result = formatter.parse(None).unwrap();
|
let result = formatter.parse(None, None).unwrap();
|
||||||
let mut result_iter = result.iter();
|
let mut result_iter = result.iter();
|
||||||
match_next!(result_iter, "$a", None);
|
match_next!(result_iter, "$a", None);
|
||||||
match_next!(result_iter, "$b", None);
|
match_next!(result_iter, "$b", None);
|
||||||
@ -585,7 +653,7 @@ mod tests {
|
|||||||
"some" => Some(Ok("$some")),
|
"some" => Some(Ok("$some")),
|
||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
let result = formatter.parse(None).unwrap();
|
let result = formatter.parse(None, None).unwrap();
|
||||||
let mut result_iter = result.iter();
|
let mut result_iter = result.iter();
|
||||||
match_next!(result_iter, "$some", None);
|
match_next!(result_iter, "$some", None);
|
||||||
match_next!(result_iter, " should render but ", None);
|
match_next!(result_iter, " should render but ", None);
|
||||||
@ -602,7 +670,7 @@ mod tests {
|
|||||||
"empty" => Some(Ok("")),
|
"empty" => Some(Ok("")),
|
||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
let result = formatter.parse(None).unwrap();
|
let result = formatter.parse(None, None).unwrap();
|
||||||
assert_eq!(result.len(), 0);
|
assert_eq!(result.len(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -616,7 +684,7 @@ mod tests {
|
|||||||
"empty" => Some(Ok("")),
|
"empty" => Some(Ok("")),
|
||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
let result = formatter.parse(None).unwrap();
|
let result = formatter.parse(None, None).unwrap();
|
||||||
assert_eq!(result.len(), 0);
|
assert_eq!(result.len(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -630,7 +698,7 @@ mod tests {
|
|||||||
"some" => Some(Ok("$some")),
|
"some" => Some(Ok("$some")),
|
||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
let result = formatter.parse(None).unwrap();
|
let result = formatter.parse(None, None).unwrap();
|
||||||
let mut result_iter = result.iter();
|
let mut result_iter = result.iter();
|
||||||
match_next!(result_iter, "$some", None);
|
match_next!(result_iter, "$some", None);
|
||||||
match_next!(result_iter, " ", None);
|
match_next!(result_iter, " ", None);
|
||||||
@ -649,7 +717,7 @@ mod tests {
|
|||||||
"all" => Some("$some"),
|
"all" => Some("$some"),
|
||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
let result = formatter.parse(None).unwrap();
|
let result = formatter.parse(None, None).unwrap();
|
||||||
let mut result_iter = result.iter();
|
let mut result_iter = result.iter();
|
||||||
match_next!(result_iter, " ", None);
|
match_next!(result_iter, " ", None);
|
||||||
}
|
}
|
||||||
@ -703,8 +771,50 @@ mod tests {
|
|||||||
"never" => Some(Err(never_error.clone())),
|
"never" => Some(Err(never_error.clone())),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, None)
|
||||||
});
|
});
|
||||||
assert!(segments.is_err());
|
assert!(segments.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bash_escape() {
|
||||||
|
let test = "$(echo a)";
|
||||||
|
assert_eq!(
|
||||||
|
shell_prompt_escape(test.to_owned(), Shell::Bash),
|
||||||
|
r"\$(echo a)"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
shell_prompt_escape(test.to_owned(), Shell::PowerShell),
|
||||||
|
test
|
||||||
|
);
|
||||||
|
|
||||||
|
let test = r"\$(echo a)";
|
||||||
|
assert_eq!(
|
||||||
|
shell_prompt_escape(test.to_owned(), Shell::Bash),
|
||||||
|
r"\\\$(echo a)"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
shell_prompt_escape(test.to_owned(), Shell::PowerShell),
|
||||||
|
test
|
||||||
|
);
|
||||||
|
|
||||||
|
let test = r"`echo a`";
|
||||||
|
assert_eq!(
|
||||||
|
shell_prompt_escape(test.to_owned(), Shell::Bash),
|
||||||
|
r"\`echo a\`"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
shell_prompt_escape(test.to_owned(), Shell::PowerShell),
|
||||||
|
test
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_zsh_escape() {
|
||||||
|
let test = "10%";
|
||||||
|
assert_eq!(shell_prompt_escape(test.to_owned(), Shell::Zsh), "10%%");
|
||||||
|
assert_eq!(
|
||||||
|
shell_prompt_escape(test.to_owned(), Shell::PowerShell),
|
||||||
|
test
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ impl<'a> VersionFormatter<'a> {
|
|||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None);
|
.parse(None, None);
|
||||||
|
|
||||||
formatted.map(|segments| {
|
formatted.map(|segments| {
|
||||||
segments
|
segments
|
||||||
|
@ -164,7 +164,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"duration" => duration.as_ref().map(Ok),
|
"duration" => duration.as_ref().map(Ok),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -52,7 +52,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
|
|
||||||
match formatter.parse(None) {
|
match formatter.parse(None, Some(context)) {
|
||||||
Ok(format_string) => {
|
Ok(format_string) => {
|
||||||
module.set_segments(format_string);
|
module.set_segments(format_string);
|
||||||
Some(module)
|
Some(module)
|
||||||
|
@ -53,7 +53,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"symbol" => Some(symbol),
|
"symbol" => Some(symbol),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -43,7 +43,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -37,7 +37,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"duration" => Some(Ok(render_time(elapsed, config.show_milliseconds))),
|
"duration" => Some(Ok(render_time(elapsed, config.show_milliseconds))),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -43,7 +43,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -37,7 +37,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"environment" => Some(Ok(conda_env.as_str())),
|
"environment" => Some(Ok(conda_env.as_str())),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -44,7 +44,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
.map(Ok),
|
.map(Ok),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -56,7 +56,7 @@ pub fn module<'a>(name: &str, context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"style" => Some(Ok(config.style)),
|
"style" => Some(Ok(config.style)),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.map(|variable| match variable {
|
.map_no_escaping(|variable| match variable {
|
||||||
"output" => {
|
"output" => {
|
||||||
let output = exec_command(config.command, &config.shell.0)?;
|
let output = exec_command(config.command, &config.shell.0)?;
|
||||||
let trimmed = output.trim();
|
let trimmed = output.trim();
|
||||||
@ -69,7 +69,7 @@ pub fn module<'a>(name: &str, context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
match parsed {
|
match parsed {
|
||||||
|
@ -43,7 +43,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -42,7 +42,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -113,7 +113,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -71,7 +71,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"context" => Some(Ok(ctx.as_str())),
|
"context" => Some(Ok(ctx.as_str())),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -74,7 +74,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"tfm" => find_current_tfm(&dotnet_files).map(Ok),
|
"tfm" => find_current_tfm(&dotnet_files).map(Ok),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -55,7 +55,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
.map(Ok),
|
.map(Ok),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -42,7 +42,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -68,7 +68,7 @@ fn env_var_module<'a>(module_config_path: Vec<&str>, context: &'a Context) -> Op
|
|||||||
"env_value" => Some(Ok(&env_value)),
|
"env_value" => Some(Ok(&env_value)),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -42,7 +42,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -151,7 +151,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"active" => Some(Ok(gcloud_context.config_name.clone())),
|
"active" => Some(Ok(gcloud_context.config_name.clone())),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -95,7 +95,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -68,7 +68,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"tag" => format_tag(config.tag_symbol, &tag_name),
|
"tag" => format_tag(config.tag_symbol, &tag_name),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -50,7 +50,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"deleted" => GitDiff::get_variable(config.only_nonzero_diffs, stats.deleted),
|
"deleted" => GitDiff::get_variable(config.only_nonzero_diffs, stats.deleted),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -34,7 +34,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"progress_total" => state_description.total.as_ref().map(Ok),
|
"progress_total" => state_description.total.as_ref().map(Ok),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -49,49 +49,52 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
let info = Arc::clone(&info);
|
let info = Arc::clone(&info);
|
||||||
let segments = match variable {
|
let segments = match variable {
|
||||||
"stashed" => info.get_stashed().and_then(|count| {
|
"stashed" => info.get_stashed().and_then(|count| {
|
||||||
format_count(config.stashed, "git_status.stashed", count)
|
format_count(config.stashed, "git_status.stashed", context, count)
|
||||||
}),
|
}),
|
||||||
"ahead_behind" => info.get_ahead_behind().and_then(|(ahead, behind)| {
|
"ahead_behind" => info.get_ahead_behind().and_then(|(ahead, behind)| {
|
||||||
let (ahead, behind) = (ahead?, behind?);
|
let (ahead, behind) = (ahead?, behind?);
|
||||||
if ahead > 0 && behind > 0 {
|
if ahead > 0 && behind > 0 {
|
||||||
format_text(config.diverged, "git_status.diverged", |variable| {
|
format_text(
|
||||||
match variable {
|
config.diverged,
|
||||||
|
"git_status.diverged",
|
||||||
|
context,
|
||||||
|
|variable| match variable {
|
||||||
"ahead_count" => Some(ahead.to_string()),
|
"ahead_count" => Some(ahead.to_string()),
|
||||||
"behind_count" => Some(behind.to_string()),
|
"behind_count" => Some(behind.to_string()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
},
|
||||||
})
|
)
|
||||||
} else if ahead > 0 && behind == 0 {
|
} else if ahead > 0 && behind == 0 {
|
||||||
format_count(config.ahead, "git_status.ahead", ahead)
|
format_count(config.ahead, "git_status.ahead", context, ahead)
|
||||||
} else if behind > 0 && ahead == 0 {
|
} else if behind > 0 && ahead == 0 {
|
||||||
format_count(config.behind, "git_status.behind", behind)
|
format_count(config.behind, "git_status.behind", context, behind)
|
||||||
} else {
|
} else {
|
||||||
format_symbol(config.up_to_date, "git_status.up_to_date")
|
format_symbol(config.up_to_date, "git_status.up_to_date", context)
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
"conflicted" => info.get_conflicted().and_then(|count| {
|
"conflicted" => info.get_conflicted().and_then(|count| {
|
||||||
format_count(config.conflicted, "git_status.conflicted", count)
|
format_count(config.conflicted, "git_status.conflicted", context, count)
|
||||||
}),
|
}),
|
||||||
"deleted" => info.get_deleted().and_then(|count| {
|
"deleted" => info.get_deleted().and_then(|count| {
|
||||||
format_count(config.deleted, "git_status.deleted", count)
|
format_count(config.deleted, "git_status.deleted", context, count)
|
||||||
}),
|
}),
|
||||||
"renamed" => info.get_renamed().and_then(|count| {
|
"renamed" => info.get_renamed().and_then(|count| {
|
||||||
format_count(config.renamed, "git_status.renamed", count)
|
format_count(config.renamed, "git_status.renamed", context, count)
|
||||||
}),
|
}),
|
||||||
"modified" => info.get_modified().and_then(|count| {
|
"modified" => info.get_modified().and_then(|count| {
|
||||||
format_count(config.modified, "git_status.modified", count)
|
format_count(config.modified, "git_status.modified", context, count)
|
||||||
|
}),
|
||||||
|
"staged" => info.get_staged().and_then(|count| {
|
||||||
|
format_count(config.staged, "git_status.staged", context, count)
|
||||||
}),
|
}),
|
||||||
"staged" => info
|
|
||||||
.get_staged()
|
|
||||||
.and_then(|count| format_count(config.staged, "git_status.staged", count)),
|
|
||||||
"untracked" => info.get_untracked().and_then(|count| {
|
"untracked" => info.get_untracked().and_then(|count| {
|
||||||
format_count(config.untracked, "git_status.untracked", count)
|
format_count(config.untracked, "git_status.untracked", context, count)
|
||||||
}),
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
segments.map(Ok)
|
segments.map(Ok)
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
@ -288,14 +291,19 @@ impl RepoStatus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_text<F>(format_str: &str, config_path: &str, mapper: F) -> Option<Vec<Segment>>
|
fn format_text<F>(
|
||||||
|
format_str: &str,
|
||||||
|
config_path: &str,
|
||||||
|
context: &Context,
|
||||||
|
mapper: F,
|
||||||
|
) -> Option<Vec<Segment>>
|
||||||
where
|
where
|
||||||
F: Fn(&str) -> Option<String> + Send + Sync,
|
F: Fn(&str) -> Option<String> + Send + Sync,
|
||||||
{
|
{
|
||||||
if let Ok(formatter) = StringFormatter::new(format_str) {
|
if let Ok(formatter) = StringFormatter::new(format_str) {
|
||||||
formatter
|
formatter
|
||||||
.map(|variable| mapper(variable).map(Ok))
|
.map(|variable| mapper(variable).map(Ok))
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
.ok()
|
.ok()
|
||||||
} else {
|
} else {
|
||||||
log::warn!("Error parsing format string `{}`", &config_path);
|
log::warn!("Error parsing format string `{}`", &config_path);
|
||||||
@ -303,19 +311,29 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_count(format_str: &str, config_path: &str, count: usize) -> Option<Vec<Segment>> {
|
fn format_count(
|
||||||
|
format_str: &str,
|
||||||
|
config_path: &str,
|
||||||
|
context: &Context,
|
||||||
|
count: usize,
|
||||||
|
) -> Option<Vec<Segment>> {
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
format_text(format_str, config_path, |variable| match variable {
|
format_text(
|
||||||
|
format_str,
|
||||||
|
config_path,
|
||||||
|
context,
|
||||||
|
|variable| match variable {
|
||||||
"count" => Some(count.to_string()),
|
"count" => Some(count.to_string()),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_symbol(format_str: &str, config_path: &str) -> Option<Vec<Segment>> {
|
fn format_symbol(format_str: &str, config_path: &str, context: &Context) -> Option<Vec<Segment>> {
|
||||||
format_text(format_str, config_path, |_variable| None)
|
format_text(format_str, config_path, context, |_variable| None)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -43,7 +43,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -46,7 +46,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -60,7 +60,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"branch" => Some(Ok(truncated_and_symbol.as_str())),
|
"branch" => Some(Ok(truncated_and_symbol.as_str())),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -51,7 +51,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"hostname" => Some(Ok(host)),
|
"hostname" => Some(Ok(host)),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -45,7 +45,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -88,7 +88,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"number" => Some(Ok(module_number.clone())),
|
"number" => Some(Ok(module_number.clone())),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -43,7 +43,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -46,7 +46,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -104,7 +104,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"namespace" => kube_ns.as_ref().map(|s| Ok(Cow::Borrowed(s.as_str()))),
|
"namespace" => kube_ns.as_ref().map(|s| Ok(Cow::Borrowed(s.as_str()))),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -45,7 +45,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -86,7 +86,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"swap_pct" if total_swap_kib > 0 => Some(Ok(&swap_pct)),
|
"swap_pct" if total_swap_kib > 0 => Some(Ok(&swap_pct)),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -44,7 +44,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
.map(Ok),
|
.map(Ok),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -46,7 +46,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"name" => shell_name.as_ref().map(Ok),
|
"name" => shell_name.as_ref().map(Ok),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -73,7 +73,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -73,7 +73,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -69,7 +69,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"project" => osp_project.as_ref().map(Ok),
|
"project" => osp_project.as_ref().map(Ok),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -29,7 +29,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"version" => Some(Ok(&module_version)),
|
"version" => Some(Ok(&module_version)),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -43,7 +43,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -42,7 +42,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -43,7 +43,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"stack" => stack_name(&project_file, context).map(Ok),
|
"stack" => stack_name(&project_file, context).map(Ok),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
match parsed {
|
match parsed {
|
||||||
|
@ -41,7 +41,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -61,7 +61,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"pyenv_prefix" => Some(Ok(pyenv_prefix.to_string())),
|
"pyenv_prefix" => Some(Ok(pyenv_prefix.to_string())),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -41,7 +41,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
.map(Ok),
|
.map(Ok),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -43,7 +43,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -41,7 +41,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
.map(Ok),
|
.map(Ok),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -42,7 +42,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"version" => get_module_version(context, &config).map(Ok),
|
"version" => get_module_version(context, &config).map(Ok),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -42,7 +42,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -46,7 +46,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"unknown_indicator" => Some(Ok(config.unknown_indicator)),
|
"unknown_indicator" => Some(Ok(config.unknown_indicator)),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -47,7 +47,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"shlvl" => Some(Ok(shlvl_str)),
|
"shlvl" => Some(Ok(shlvl_str)),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -26,7 +26,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"env" => Some(Ok(&singularity_env)),
|
"env" => Some(Ok(&singularity_env)),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -61,7 +61,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
PipeStatusStatus::Pipe(pipestatus) => pipestatus
|
PipeStatusStatus::Pipe(pipestatus) => pipestatus
|
||||||
.iter()
|
.iter()
|
||||||
.map(
|
.map(
|
||||||
|ec| match format_exit_code(ec.as_str(), config.format, None, &config) {
|
|ec| match format_exit_code(ec.as_str(), config.format, None, &config, context) {
|
||||||
Ok(segments) => segments
|
Ok(segments) => segments
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|s| s.to_string())
|
.map(|s| s.to_string())
|
||||||
@ -79,7 +79,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
PipeStatusStatus::Pipe(_) => config.pipestatus_format,
|
PipeStatusStatus::Pipe(_) => config.pipestatus_format,
|
||||||
_ => config.format,
|
_ => config.format,
|
||||||
};
|
};
|
||||||
let parsed = format_exit_code(exit_code, main_format, Some(&pipestatus), &config);
|
let parsed = format_exit_code(exit_code, main_format, Some(&pipestatus), &config, context);
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
Ok(segments) => segments,
|
Ok(segments) => segments,
|
||||||
@ -96,6 +96,7 @@ fn format_exit_code<'a>(
|
|||||||
format: &'a str,
|
format: &'a str,
|
||||||
pipestatus: Option<&str>,
|
pipestatus: Option<&str>,
|
||||||
config: &'a StatusConfig,
|
config: &'a StatusConfig,
|
||||||
|
context: &'a Context,
|
||||||
) -> Result<Vec<Segment>, StringFormatterError> {
|
) -> Result<Vec<Segment>, StringFormatterError> {
|
||||||
let exit_code_int: ExitCode = match exit_code.parse() {
|
let exit_code_int: ExitCode = match exit_code.parse() {
|
||||||
Ok(i) => i,
|
Ok(i) => i,
|
||||||
@ -164,7 +165,7 @@ fn format_exit_code<'a>(
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -49,7 +49,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"workspace" => get_terraform_workspace(context).map(Ok),
|
"workspace" => get_terraform_workspace(context).map(Ok),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -54,7 +54,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"time" => Some(Ok(&formatted_time_string)),
|
"time" => Some(Ok(&formatted_time_string)),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -48,7 +48,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"user" => Some(Ok(&username)),
|
"user" => Some(Ok(&username)),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
Ok(segments) => segments,
|
Ok(segments) => segments,
|
||||||
|
@ -44,7 +44,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
.map(Ok),
|
.map(Ok),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -30,7 +30,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
"repo" => Some(Ok(&repo)),
|
"repo" => Some(Ok(&repo)),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -42,7 +42,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
.map(Ok),
|
.map(Ok),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -42,7 +42,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.parse(None)
|
.parse(None, Some(context))
|
||||||
});
|
});
|
||||||
|
|
||||||
module.set_segments(match parsed {
|
module.set_segments(match parsed {
|
||||||
|
@ -109,7 +109,7 @@ pub fn get_prompt(context: Context) -> String {
|
|||||||
let mut root_module = Module::new("Starship Root", "The root module", None);
|
let mut root_module = Module::new("Starship Root", "The root module", None);
|
||||||
root_module.set_segments(
|
root_module.set_segments(
|
||||||
formatter
|
formatter
|
||||||
.parse(None)
|
.parse(None, Some(&context))
|
||||||
.expect("Unexpected error returned in root format variables"),
|
.expect("Unexpected error returned in root format variables"),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
62
src/utils.rs
62
src/utils.rs
@ -318,25 +318,8 @@ CMake suite maintained and supported by Kitware (kitware.com/cmake).\n",
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wraps ANSI color escape sequences and other interpretable characters
|
/// Wraps ANSI color escape sequences in the shell-appropriate wrappers.
|
||||||
/// that need to be escaped in the shell-appropriate wrappers.
|
pub fn wrap_colorseq_for_shell(ansi: String, shell: Shell) -> String {
|
||||||
pub fn wrap_colorseq_for_shell(mut ansi: String, shell: Shell) -> String {
|
|
||||||
// Handle other interpretable characters
|
|
||||||
match shell {
|
|
||||||
// Bash might interepret baskslashes, backticks and $
|
|
||||||
// see #658 for more details
|
|
||||||
Shell::Bash => {
|
|
||||||
ansi = ansi.replace('\\', r"\\");
|
|
||||||
ansi = ansi.replace('$', r"\$");
|
|
||||||
ansi = ansi.replace('`', r"\`");
|
|
||||||
}
|
|
||||||
Shell::Zsh => {
|
|
||||||
// % is an escape in zsh, see PROMPT in `man zshmisc`
|
|
||||||
ansi = ansi.replace('%', "%%");
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
const ESCAPE_BEGIN: char = '\u{1b}';
|
const ESCAPE_BEGIN: char = '\u{1b}';
|
||||||
const ESCAPE_END: char = 'm';
|
const ESCAPE_END: char = 'm';
|
||||||
wrap_seq_for_shell(ansi, shell, ESCAPE_BEGIN, ESCAPE_END)
|
wrap_seq_for_shell(ansi, shell, ESCAPE_BEGIN, ESCAPE_END)
|
||||||
@ -674,47 +657,6 @@ mod tests {
|
|||||||
assert_eq!(&bresult5, "");
|
assert_eq!(&bresult5, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_bash_escape() {
|
|
||||||
let test = "$(echo a)";
|
|
||||||
assert_eq!(
|
|
||||||
wrap_colorseq_for_shell(test.to_owned(), Shell::Bash),
|
|
||||||
r"\$(echo a)"
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
wrap_colorseq_for_shell(test.to_owned(), Shell::PowerShell),
|
|
||||||
test
|
|
||||||
);
|
|
||||||
|
|
||||||
let test = r"\$(echo a)";
|
|
||||||
assert_eq!(
|
|
||||||
wrap_colorseq_for_shell(test.to_owned(), Shell::Bash),
|
|
||||||
r"\\\$(echo a)"
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
wrap_colorseq_for_shell(test.to_owned(), Shell::PowerShell),
|
|
||||||
test
|
|
||||||
);
|
|
||||||
|
|
||||||
let test = r"`echo a`";
|
|
||||||
assert_eq!(
|
|
||||||
wrap_colorseq_for_shell(test.to_owned(), Shell::Bash),
|
|
||||||
r"\`echo a\`"
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
wrap_colorseq_for_shell(test.to_owned(), Shell::PowerShell),
|
|
||||||
test
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_zsh_escape() {
|
|
||||||
let test = "10%";
|
|
||||||
assert_eq!(wrap_colorseq_for_shell(test.to_owned(), Shell::Zsh), "10%%");
|
|
||||||
assert_eq!(
|
|
||||||
wrap_colorseq_for_shell(test.to_owned(), Shell::PowerShell),
|
|
||||||
test
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_command_string_output() {
|
fn test_get_command_string_output() {
|
||||||
let case1 = CommandOutput {
|
let case1 = CommandOutput {
|
||||||
|
Loading…
Reference in New Issue
Block a user