diff --git a/crates/nu-cli/src/commands/to_html.rs b/crates/nu-cli/src/commands/to_html.rs index b42986d519..2ec54d8d44 100644 --- a/crates/nu-cli/src/commands/to_html.rs +++ b/crates/nu-cli/src/commands/to_html.rs @@ -250,6 +250,8 @@ async fn to_html( ) = args.process(®istry).await?; let input: Vec = input.collect().await; let headers = nu_protocol::merge_descriptors(&input); + let headers = Some(headers) + .filter(|headers| !headers.is_empty() && (headers.len() > 1 || headers[0] != "")); let mut output_string = "".to_string(); let mut regex_hm: HashMap = HashMap::new(); let color_hm = get_colors(dark, &theme); @@ -266,115 +268,22 @@ async fn to_html( .expect("Error getting foreground color") )); - // Add grid lines to html - // let mut output_string = ""); - - if !headers.is_empty() && (headers.len() > 1 || headers[0] != "") { - // output_string.push_str(""); - - // change the color of tables - output_string.push_str(&format!( - r"
", - color_hm - .get("background") - .expect("Error getting background color"), - color_hm - .get("foreground") - .expect("Error getting foreground color") - )); - - output_string.push_str(""); - - for header in &headers { - output_string.push_str(""); - } - output_string.push_str(""); - } - - for row in input { - match row.value { - UntaggedValue::Primitive(Primitive::Binary(b)) => { - // This might be a bit much, but it's fun :) - match row.tag.anchor { - Some(AnchorLocation::Url(f)) | Some(AnchorLocation::File(f)) => { - let extension = f.split('.').last().map(String::from); - match extension { - Some(s) - if ["png", "jpg", "bmp", "gif", "tiff", "jpeg"] - .contains(&s.to_lowercase().as_str()) => - { - output_string.push_str(""); - } - _ => { - let output = pretty_hex::pretty_hex(&b); - - output_string.push_str("
");
-                                output_string.push_str(&output);
-                                output_string.push_str("
"); - } - } - } - _ => { - let output = pretty_hex::pretty_hex(&b); - - output_string.push_str("
");
-                        output_string.push_str(&output);
-                        output_string.push_str("
"); - } - } + let inner_value = match input.len() { + 0 => String::default(), + 1 => match headers { + Some(headers) => html_table(input, headers, color_hm), + None => { + let value = &input[0]; + html_value(value) } - UntaggedValue::Primitive(Primitive::String(ref b)) => { - // This might be a bit much, but it's fun :) - match row.tag.anchor { - Some(AnchorLocation::Url(f)) | Some(AnchorLocation::File(f)) => { - let extension = f.split('.').last().map(String::from); - match extension { - Some(s) if s.to_lowercase() == "svg" => { - output_string.push_str(""); - continue; - } - _ => {} - } - } - _ => {} - } - output_string.push_str( - &(htmlescape::encode_minimal(&format_leaf(&row.value).plain_string(100_000)) - .replace("\n", "
")), - ); - } - UntaggedValue::Row(row) => { - output_string.push_str(""); - for header in &headers { - let data = row.get_data(header); - output_string.push_str(""); - } - output_string.push_str(""); - } - p => { - output_string.push_str( - &(htmlescape::encode_minimal(&format_leaf(&p).plain_string(100_000)) - .replace("\n", "
")), - ); - } - } - } + }, + _ => match headers { + Some(headers) => html_table(input, headers, color_hm), + None => html_list(input), + }, + }; - if !headers.is_empty() && (headers.len() > 1 || headers[0] != "") { - output_string.push_str("
"); - output_string.push_str(&htmlescape::encode_minimal(&header)); - output_string.push_str("
"); - output_string.push_str(&format_leaf(data.borrow()).plain_string(100_000)); - output_string.push_str("
"); - } + output_string.push_str(&inner_value); output_string.push_str(""); // Check to see if we want to remove all color or change ansi to html colors @@ -391,6 +300,130 @@ async fn to_html( ))) } +fn html_list(list: Vec) -> String { + let mut output_string = String::new(); + output_string.push_str("
    "); + for value in list { + output_string.push_str("
  1. "); + output_string.push_str(&html_value(&value)); + output_string.push_str("
  2. "); + } + output_string.push_str("
"); + output_string +} + +fn html_table(table: Vec, headers: Vec, color_hm: HashMap<&str, String>) -> String { + let mut output_string = String::new(); + // Add grid lines to html + // let mut output_string = ""); + + // output_string.push_str(""); + + // change the color of tables + output_string.push_str(&format!( + r"
", + color_hm + .get("background") + .expect("Error getting background color"), + color_hm + .get("foreground") + .expect("Error getting foreground color") + )); + + output_string.push_str(""); + for header in &headers { + output_string.push_str(""); + } + output_string.push_str(""); + + for row in table { + if let UntaggedValue::Row(row) = row.value { + output_string.push_str(""); + for header in &headers { + let data = row.get_data(header); + output_string.push_str(""); + } + output_string.push_str(""); + } + } + output_string.push_str("
"); + output_string.push_str(&htmlescape::encode_minimal(&header)); + output_string.push_str("
"); + output_string.push_str(&html_value(data.borrow())); + output_string.push_str("
"); + + output_string +} + +fn html_value(value: &Value) -> String { + let mut output_string = String::new(); + match &value.value { + UntaggedValue::Primitive(Primitive::Binary(b)) => { + // This might be a bit much, but it's fun :) + match &value.tag.anchor { + Some(AnchorLocation::Url(f)) | Some(AnchorLocation::File(f)) => { + let extension = f.split('.').last().map(String::from); + match extension { + Some(s) + if ["png", "jpg", "bmp", "gif", "tiff", "jpeg"] + .contains(&s.to_lowercase().as_str()) => + { + output_string.push_str(""); + } + _ => { + let output = pretty_hex::pretty_hex(&b); + + output_string.push_str("
");
+                            output_string.push_str(&output);
+                            output_string.push_str("
"); + } + } + } + _ => { + let output = pretty_hex::pretty_hex(&b); + + output_string.push_str("
");
+                    output_string.push_str(&output);
+                    output_string.push_str("
"); + } + } + } + UntaggedValue::Primitive(Primitive::String(ref b)) => { + // This might be a bit much, but it's fun :) + match &value.tag.anchor { + Some(AnchorLocation::Url(f)) | Some(AnchorLocation::File(f)) => { + let extension = f.split('.').last().map(String::from); + match extension { + Some(s) if s.to_lowercase() == "svg" => { + output_string.push_str(""); + return output_string; + } + _ => {} + } + } + _ => {} + } + output_string.push_str( + &htmlescape::encode_minimal(&format_leaf(&value.value).plain_string(100_000)) + .replace("\n", "
"), + ); + } + other => output_string.push_str( + &htmlescape::encode_minimal(&format_leaf(other).plain_string(100_000)) + .replace("\n", "
"), + ), + } + output_string +} + fn setup_html_color_regexes( hash: &mut HashMap, is_dark: bool, diff --git a/crates/nu-protocol/src/value.rs b/crates/nu-protocol/src/value.rs index 48e398d4aa..7c70f06184 100644 --- a/crates/nu-protocol/src/value.rs +++ b/crates/nu-protocol/src/value.rs @@ -28,6 +28,7 @@ use serde::{Deserialize, Serialize}; use std::hash::{Hash, Hasher}; use std::path::PathBuf; use std::time::SystemTime; + /// The core structured values that flow through a pipeline #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)] pub enum UntaggedValue {