diff --git a/crates/nu-cli/src/commands/to_html.rs b/crates/nu-cli/src/commands/to_html.rs
index c6de43506d..41b3a96632 100644
--- a/crates/nu-cli/src/commands/to_html.rs
+++ b/crates/nu-cli/src/commands/to_html.rs
@@ -5,9 +5,17 @@ use futures::StreamExt;
use nu_errors::ShellError;
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
use nu_source::AnchorLocation;
+use regex::Regex;
+use std::collections::HashMap;
pub struct ToHTML;
+#[derive(Deserialize)]
+pub struct ToHTMLArgs {
+ html_color: bool,
+ no_color: bool,
+}
+
#[async_trait]
impl WholeStreamCommand for ToHTML {
fn name(&self) -> &str {
@@ -16,6 +24,8 @@ impl WholeStreamCommand for ToHTML {
fn signature(&self) -> Signature {
Signature::build("to html")
+ .switch("html_color", "change ansi colors to html colors", Some('t'))
+ .switch("no_color", "remove all ansi colors in output", Some('n'))
}
fn usage(&self) -> &str {
@@ -36,16 +46,34 @@ async fn to_html(
registry: &CommandRegistry,
) -> Result {
let registry = registry.clone();
- let args = args.evaluate_once(®istry).await?;
- let name_tag = args.name_tag();
- let input: Vec = args.input.collect().await;
+ let name_tag = args.call_info.name_tag.clone();
+ let (
+ ToHTMLArgs {
+ html_color,
+ no_color,
+ },
+ input,
+ ) = args.process(®istry).await?;
+ let input: Vec = input.collect().await;
let headers = nu_protocol::merge_descriptors(&input);
- let mut output_string = "".to_string();
+ let mut output_string = "".to_string();
+ output_string.push_str("");
+ // change the body background color
+ // output_string.push_str("");
+ let mut hm = HashMap::new();
+
+ // Add grid lines to html
+ // let mut output_string = "");
if !headers.is_empty() && (headers.len() > 1 || headers[0] != "") {
output_string.push_str("");
output_string.push_str("");
+ // change the background of tables
+ // output_string.push_str("
");
+
for header in &headers {
output_string.push_str("");
output_string.push_str(&htmlescape::encode_minimal(&header));
@@ -124,14 +152,211 @@ async fn to_html(
}
output_string.push_str("");
+ // Check to see if we want to remove all color or change ansi to html colors
+ if html_color {
+ setup_html_color_regexes(&mut hm);
+ output_string = run_regexes(&hm, &output_string);
+ } else if no_color {
+ setup_no_color_regexes(&mut hm);
+ output_string = run_regexes(&hm, &output_string);
+ }
+
Ok(OutputStream::one(ReturnSuccess::value(
UntaggedValue::string(output_string).into_value(name_tag),
)))
}
+fn setup_html_color_regexes(hash: &mut HashMap) {
+ // All the bold colors
+ hash.insert(
+ 0,
+ (
+ r"(?P\[0m)(?P[[:alnum:][:space:][:punct:]]*)",
+ // Since this is a reset, reset to black, normal weight font
+ r"$word",
+ ),
+ );
+ hash.insert(
+ 1,
+ (
+ // Bold Black
+ // r"(?P\[1;30m)(?P[A-Za-z0-9\-'!/_~ &;|=\+\*\.#%:\]$`\(\)]+)",
+ r"(?P\[1;30m)(?P[[:alnum:][:space:][:punct:]]*)",
+ r"$word",
+ ),
+ );
+ hash.insert(
+ 2,
+ (
+ // Bold Red
+ // r"(?P \[1;31m)(?P[A-Za-z0-9\-'!/_~ &;|=\+\*\.#%:\]$`\(\)]+)",
+ r"(?P \[1;31m)(?P[[:alnum:][:space:][:punct:]]*)",
+ r"$word",
+ ),
+ );
+ hash.insert(
+ 3,
+ (
+ // Bold Green
+ // r"(?P\[1;32m)(?P[A-Za-z0-9\-'!/_~ &;|=\+\*\.#%:\]$`\(\)]+)",
+ r"(?P\[1;32m)(?P[[:alnum:][:space:][:punct:]]*)",
+ r"$word",
+ ),
+ );
+ hash.insert(
+ 4,
+ (
+ // Bold Yellow
+ // r"(?P\[1;33m)(?P[A-Za-z0-9\-'!/_~ &;|=\+\*\.#%:\]$`\(\)]+)",
+ r"(?P\[1;33m)(?P[[:alnum:][:space:][:punct:]]*)",
+ r"$word",
+ ),
+ );
+ hash.insert(
+ 5,
+ (
+ // Bold Blue
+ // r"(?P\[1;34m)(?P[A-Za-z0-9\-'!/_~ &;|=\+\*\.#%:\]$`\(\)]+)",
+ r"(?P\[1;34m)(?P[[:alnum:][:space:][:punct:]]*)",
+ r"$word",
+ ),
+ );
+ hash.insert(
+ 6,
+ (
+ // Bold Magenta
+ // r"(?P\[1;35m)(?P[A-Za-z0-9\-'!/_~ &;|=\+\*\.#%:\]$`\(\)]+)",
+ r"(?P\[1;35m)(?P[[:alnum:][:space:][:punct:]]*)",
+ r"$word",
+ ),
+ );
+ hash.insert(
+ 7,
+ (
+ // Bold Cyan
+ // r"(?P\[1;36m)(?P[A-Za-z0-9\-'!/_~ &;|=\+\*\.#%:\]$`\(\)]+)",
+ r"(?P\[1;36m)(?P[[:alnum:][:space:][:punct:]]*)",
+ r"$word",
+ ),
+ );
+ hash.insert(
+ 8,
+ (
+ // Bold White
+ // Let's change this to black since the html background
+ // is white. White on white = no bueno.
+ // r"(?P\[1;37m)(?P[A-Za-z0-9\-'!/_~ &;|=\+\*\.#%:\]$`\(\)]+)",
+ r"(?P\[1;37m)(?P[[:alnum:][:space:][:punct:]]*)",
+ r"$word",
+ ),
+ );
+ // All the normal colors
+ hash.insert(
+ 9,
+ (
+ // Black
+ // r"(?P\[30m)(?P[A-Za-z0-9\-'!/_~ &;|=\+\*\.#%:\]$`\(\)]+)",
+ r"(?P\[30m)(?P[[:alnum:][:space:][:punct:]]*)",
+ r"$word",
+ ),
+ );
+ hash.insert(
+ 10,
+ (
+ // Red
+ // r"(?P\[31m)(?P[A-Za-z0-9\-'!/_~ &;|=\+\*\.#%:\]$`\(\)]+)",
+ r"(?P\[31m)(?P[[:alnum:][:space:][:punct:]]*)",
+ r"$word",
+ ),
+ );
+ hash.insert(
+ 11,
+ (
+ // Green
+ // r"(?P\[32m)(?P[A-Za-z0-9\-'!/_~ &;|=\+\*\.#%:\]$`\(\)]+)",
+ r"(?P\[32m)(?P[[:alnum:][:space:][:punct:]]*)",
+ r"$word",
+ ),
+ );
+ hash.insert(
+ 12,
+ (
+ // Yellow
+ // r"(?P\[33m)(?P[A-Za-z0-9\-'!/_~ &;|=\+\*\.#%:\]$`\(\)]+)",
+ r"(?P\[33m)(?P[[:alnum:][:space:][:punct:]]*)",
+ r"$word",
+ ),
+ );
+ hash.insert(
+ 13,
+ (
+ // Blue
+ // r"(?P\[34m)(?P[A-Za-z0-9\-'!/_~ &;|=\+\*\.#%:\]$`\(\)]+)",
+ r"(?P\[34m)(?P[[:alnum:][:space:][:punct:]]*)",
+ r"$word",
+ ),
+ );
+ hash.insert(
+ 14,
+ (
+ // Magenta
+ // r"(?P\[35m)(?P[A-Za-z0-9\-'!/_~ &;|=\+\*\.#%:\]$`\(\)]+)",
+ r"(?P\[35m)(?P[[:alnum:][:space:][:punct:]]*)",
+ r"$word",
+ ),
+ );
+ hash.insert(
+ 15,
+ (
+ // Cyan
+ // r"(?P\[36m)(?P[A-Za-z0-9\-'!/_~ &;|=\+\*\.#%:\]$`\(\)]+)",
+ r"(?P\[36m)(?P[[:alnum:][:space:][:punct:]]*)",
+ r"$word",
+ ),
+ );
+ hash.insert(
+ 16,
+ (
+ // White
+ // Let's change this to black since the html background
+ // is white. White on white = no bueno.
+ // r"(?P\[37m)(?P[A-Za-z0-9\-'!/_~ &;|=\+\*\.#%:\]$`\(\)]+)",
+ r"(?P\[37m)(?P[[:alnum:][:space:][:punct:]]*)",
+ r"$word",
+ ),
+ );
+}
+
+fn setup_no_color_regexes(hash: &mut HashMap) {
+ // We can just use one regex here because we're just removing ansi sequences
+ // and not replacing them with html colors.
+ // attribution: https://stackoverflow.com/questions/14693701/how-can-i-remove-the-ansi-escape-sequences-from-a-string-in-python
+ hash.insert(
+ 0,
+ (
+ r"(?:\x1B[@-Z\\-_]|[\x80-\x9A\x9C-\x9F]|(?:\x1B\[|\x9B)[0-?]*[ -/]*[@-~])",
+ r"$name_group_doesnt_exist",
+ ),
+ );
+}
+
+fn run_regexes(hash: &HashMap, contents: &str) -> String {
+ let mut working_string = contents.to_owned();
+ let hash_count: u32 = hash.len() as u32;
+ for n in 0..hash_count {
+ let value = hash.get(&n).expect("error getting hash at index");
+ //println!("{},{}", value.0, value.1);
+ let re = Regex::new(value.0).expect("problem with color regex");
+ let after = re.replace_all(&working_string, value.1).to_string();
+ working_string = after.clone();
+ }
+ working_string
+}
+
#[cfg(test)]
mod tests {
- use super::ToHTML;
+ use super::*;
+ use std::collections::HashMap;
#[test]
fn examples_work_as_expected() {
@@ -139,4 +364,31 @@ mod tests {
test_examples(ToHTML {})
}
+
+ #[test]
+ fn test_html_color_flag() {
+ let mut hm = HashMap::new();
+ let cd_help = r"Change to a new path.
Usage: > cd (directory) {flags}
Parameters: (directory) the directory to change to
Flags: -h, --help: Display this help message
Examples: Change to a new directory called 'dirname' > [1;36mcd[0m[37m [0m[36mdirname[0m
Change to your home directory > [1;36mcd[0m
Change to your home directory (alternate version) > [1;36mcd[0m[37m [0m[36m~[0m
Change to the previous directory > [1;36mcd[0m[37m [0m[36m-[0m
".to_string();
+ let cd_help_expected_result = r"Change to a new path.
Usage: > cd (directory) {flags}
Parameters: (directory) the directory to change to
Flags: -h, --help: Display this help message
Examples: Change to a new directory called 'dirname' > cd dirname
Change to your home directory > cd
Change to your home directory (alternate version) > cd ~
Change to the previous directory > cd -
".to_string();
+ setup_html_color_regexes(&mut hm);
+ assert_eq!(cd_help_expected_result, run_regexes(&hm, &cd_help));
+ }
+
+ #[test]
+ fn test_no_color_flag() {
+ let mut hm = HashMap::new();
+ let cd_help = r"Change to a new path.
Usage: > cd (directory) {flags}
Parameters: (directory) the directory to change to
Flags: -h, --help: Display this help message
Examples: Change to a new directory called 'dirname' > [1;36mcd[0m[37m [0m[36mdirname[0m
Change to your home directory > [1;36mcd[0m
Change to your home directory (alternate version) > [1;36mcd[0m[37m [0m[36m~[0m
Change to the previous directory > [1;36mcd[0m[37m [0m[36m-[0m
".to_string();
+ let cd_help_expected_result = r"Change to a new path.
Usage: > cd (directory) {flags}
Parameters: (directory) the directory to change to
Flags: -h, --help: Display this help message
Examples: Change to a new directory called 'dirname' > cd dirname
Change to your home directory > cd
Change to your home directory (alternate version) > cd ~
Change to the previous directory > cd -
".to_string();
+ setup_no_color_regexes(&mut hm);
+ assert_eq!(cd_help_expected_result, run_regexes(&hm, &cd_help));
+ }
+
+ #[test]
+ fn test_html_color_where_flag() {
+ let mut hm = HashMap::new();
+ let where_help = r"Filter table to match the condition.
Usage: > where <condition> {flags}
Parameters: <condition> the condition that must match
Flags: -h, --help: Display this help message
Examples: List all files in the current directory with sizes greater than 2kb > [1;36mls[0m[37m | [0m[1;36mwhere[0m[37m [0m[1;33msize[0m[37m [0m[33m>[0m[37m [0m[1;35m2[0m[1;36mkb[0m
List only the files in the current directory > [1;36mls[0m[37m | [0m[1;36mwhere[0m[37m [0m[1;33mtype[0m[37m [0m[33m==[0m[37m [0m[32mFile[0m
List all files with names that contain "Car" > [1;36mls[0m[37m | [0m[1;36mwhere[0m[37m [0m[1;33mname[0m[37m [0m[33m=~[0m[37m [0m[32m"Car"[0m
List all files that were modified in the last two months > [1;36mls[0m[37m | [0m[1;36mwhere[0m[37m [0m[1;33mmodified[0m[37m [0m[33m<=[0m[37m [0m[1;35m2[0m[1;36mM[0m
".to_string();
+ let where_help_exptected_results = r"Filter table to match the condition.
Usage: > where <condition> {flags}
Parameters: <condition> the condition that must match
Flags: -h, --help: Display this help message
Examples: List all files in the current directory with sizes greater than 2kb > ls | where size > 2kb
List only the files in the current directory > ls | where type == File
List all files with names that contain "Car" > ls | where name =~ "Car"
List all files that were modified in the last two months > ls | where modified <= 2M
".to_string();
+ setup_html_color_regexes(&mut hm);
+ assert_eq!(where_help_exptected_results, run_regexes(&hm, &where_help));
+ }
}
|