mirror of
https://github.com/nushell/nushell.git
synced 2024-11-22 00:13:21 +01:00
add ability to specify an ansi style (#595)
* add ability to specify an ansi style * remove comments * remove more debug code * some cleanup and refactoring
This commit is contained in:
parent
1dbf351425
commit
1837acfc70
@ -2,13 +2,13 @@ use nu_ansi_term::{Color, Style};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
struct NuStyle {
|
||||
fg: Option<String>,
|
||||
bg: Option<String>,
|
||||
attr: Option<String>,
|
||||
pub struct NuStyle {
|
||||
pub fg: Option<String>,
|
||||
pub bg: Option<String>,
|
||||
pub attr: Option<String>,
|
||||
}
|
||||
|
||||
fn parse_nustyle(nu_style: NuStyle) -> Style {
|
||||
pub fn parse_nustyle(nu_style: NuStyle) -> Style {
|
||||
// get the nu_ansi_term::Color foreground color
|
||||
let fg_color = match nu_style.fg {
|
||||
Some(fg) => color_from_hex(&fg).expect("error with foreground color"),
|
||||
|
@ -193,7 +193,7 @@ impl Command for AnsiCommand {
|
||||
Signature::build("ansi")
|
||||
.optional(
|
||||
"code",
|
||||
SyntaxShape::String,
|
||||
SyntaxShape::Any,
|
||||
"the name of the code to use like 'green' or 'reset' to reset the color",
|
||||
)
|
||||
.switch(
|
||||
@ -222,17 +222,17 @@ Example: 1;31m for bold red or 2;37;41m for dimmed white fg with red bg
|
||||
There can be multiple text formatting sequence numbers
|
||||
separated by a ; and ending with an m where the # is of the
|
||||
following values:
|
||||
attributes
|
||||
0 reset / normal display
|
||||
1 bold or increased intensity
|
||||
2 faint or decreased intensity
|
||||
3 italic on (non-mono font)
|
||||
4 underline on
|
||||
5 slow blink on
|
||||
6 fast blink on
|
||||
7 reverse video on
|
||||
8 nondisplayed (invisible) on
|
||||
9 strike-through on
|
||||
attribute_number, abbreviation, description
|
||||
0 reset / normal display
|
||||
1 b bold or increased intensity
|
||||
2 d faint or decreased intensity
|
||||
3 i italic on (non-mono font)
|
||||
4 u underline on
|
||||
5 l slow blink on
|
||||
6 fast blink on
|
||||
7 r reverse video on
|
||||
8 h nondisplayed (invisible) on
|
||||
9 s strike-through on
|
||||
|
||||
foreground/bright colors background/bright colors
|
||||
30/90 black 40/100 black
|
||||
@ -273,17 +273,23 @@ Format: #
|
||||
Example {
|
||||
description:
|
||||
"Use ansi to color text (rb = red bold, gb = green bold, pb = purple bold)",
|
||||
example: r#"echo [(ansi rb) Hello " " (ansi gb) Nu " " (ansi pb) World] | str collect"#,
|
||||
example: r#"echo [(ansi rb) Hello " " (ansi gb) Nu " " (ansi pb) World (ansi reset)] | str collect"#,
|
||||
result: Some(Value::test_string(
|
||||
"\u{1b}[1;31mHello \u{1b}[1;32mNu \u{1b}[1;35mWorld",
|
||||
"\u{1b}[1;31mHello \u{1b}[1;32mNu \u{1b}[1;35mWorld\u{1b}[0m",
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description:
|
||||
"Use ansi to color text (rb = red bold, gb = green bold, pb = purple bold)",
|
||||
example: r#"echo [(ansi -e '3;93;41m') Hello (ansi reset) " " (ansi gb) Nu " " (ansi pb) World] | str collect"#,
|
||||
description: "Use ansi to color text (italic bright yellow on red 'Hello' with green bold 'Nu' and purble bold 'World')",
|
||||
example: r#"echo [(ansi -e '3;93;41m') Hello (ansi reset) " " (ansi gb) Nu " " (ansi pb) World (ansi reset)] | str collect"#,
|
||||
result: Some(Value::test_string(
|
||||
"\u{1b}[3;93;41mHello\u{1b}[0m \u{1b}[1;32mNu \u{1b}[1;35mWorld",
|
||||
"\u{1b}[3;93;41mHello\u{1b}[0m \u{1b}[1;32mNu \u{1b}[1;35mWorld\u{1b}[0m",
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
description: "Use ansi to color text with a style (blue on red in bold)",
|
||||
example: r#"$"(ansi -e { fg: '#0000ff' bg: '#ff0000' attr: b })Hello Nu World(ansi reset)""#,
|
||||
result: Some(Value::test_string(
|
||||
"\u{1b}[1;48;2;255;0;0;38;2;0;0;255mHello Nu World\u{1b}[0m",
|
||||
)),
|
||||
},
|
||||
]
|
||||
@ -299,15 +305,21 @@ Format: #
|
||||
let list: bool = call.has_flag("list");
|
||||
let escape: bool = call.has_flag("escape");
|
||||
let osc: bool = call.has_flag("osc");
|
||||
|
||||
if list {
|
||||
return generate_ansi_code_list(engine_state, call.head);
|
||||
}
|
||||
let code: String = match call.opt::<String>(engine_state, stack, 0)? {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
return Err(ShellError::MissingParameter("code".into(), call.head));
|
||||
}
|
||||
|
||||
// The code can now be one of the ansi abbreviations like green_bold
|
||||
// or it can be a record like this: { fg: "#ff0000" bg: "#00ff00" attr: bli }
|
||||
// this record is defined in nu-color-config crate
|
||||
let code: Value = match call.opt(engine_state, stack, 0)? {
|
||||
Some(c) => c,
|
||||
None => return Err(ShellError::MissingParameter("code".into(), call.head)),
|
||||
};
|
||||
|
||||
let param_is_string = matches!(code, Value::String { val: _, span: _ });
|
||||
|
||||
if escape && osc {
|
||||
return Err(ShellError::IncompatibleParameters {
|
||||
left_message: "escape".into(),
|
||||
@ -322,8 +334,17 @@ Format: #
|
||||
.span,
|
||||
});
|
||||
}
|
||||
if escape || osc {
|
||||
let code_vec: Vec<char> = code.chars().collect();
|
||||
|
||||
let code_string = if param_is_string {
|
||||
code.as_string().expect("error getting code as string")
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
|
||||
let param_is_valid_string = param_is_string && !code_string.is_empty();
|
||||
|
||||
if (escape || osc) && (param_is_valid_string) {
|
||||
let code_vec: Vec<char> = code_string.chars().collect();
|
||||
if code_vec[0] == '\\' {
|
||||
return Err(ShellError::UnsupportedInput(
|
||||
String::from("no need for escape characters"),
|
||||
@ -333,14 +354,15 @@ Format: #
|
||||
));
|
||||
}
|
||||
}
|
||||
let output = if escape {
|
||||
format!("\x1b[{}", code)
|
||||
} else if osc {
|
||||
//Operating system command aka osc ESC ] <- note the right brace, not left brace for osc
|
||||
|
||||
let output = if escape && param_is_valid_string {
|
||||
format!("\x1b[{}", code_string)
|
||||
} else if osc && param_is_valid_string {
|
||||
// Operating system command aka osc ESC ] <- note the right brace, not left brace for osc
|
||||
// OCS's need to end with a bell '\x07' char
|
||||
format!("\x1b]{};", code)
|
||||
} else {
|
||||
match str_to_ansi(&code) {
|
||||
format!("\x1b]{};", code_string)
|
||||
} else if param_is_valid_string {
|
||||
match str_to_ansi(&code_string) {
|
||||
Some(c) => c,
|
||||
None => {
|
||||
return Err(ShellError::UnsupportedInput(
|
||||
@ -349,7 +371,36 @@ Format: #
|
||||
))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// This is a record that should look like
|
||||
// { fg: "#ff0000" bg: "#00ff00" attr: bli }
|
||||
let record = code.as_record()?;
|
||||
// create a NuStyle to parse the information into
|
||||
let mut nu_style = nu_color_config::NuStyle {
|
||||
fg: None,
|
||||
bg: None,
|
||||
attr: None,
|
||||
};
|
||||
// Iterate and populate NuStyle with real values
|
||||
for (k, v) in record.0.iter().zip(record.1) {
|
||||
match k.as_str() {
|
||||
"fg" => nu_style.fg = Some(v.as_string()?),
|
||||
"bg" => nu_style.bg = Some(v.as_string()?),
|
||||
"attr" => nu_style.attr = Some(v.as_string()?),
|
||||
_ => {
|
||||
return Err(ShellError::IncompatibleParametersSingle(
|
||||
format!("problem with key: {}", k.to_string()),
|
||||
code.span().expect("error with span"),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now create a nu_ansi_term::Style from the NuStyle
|
||||
let style = nu_color_config::parse_nustyle(nu_style);
|
||||
// Return the prefix string. The prefix is the Ansi String. The suffix would be 0m, reset/stop coloring.
|
||||
style.prefix().to_string()
|
||||
};
|
||||
|
||||
Ok(Value::string(output, call.head).into_pipeline_data())
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user