mod.rs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. use std::process::exit;
  2. use dioxus_rsx::{BodyNode, CallBody};
  3. use super::*;
  4. /// Build the Rust WASM app and all of its assets.
  5. #[derive(Clone, Debug, Parser)]
  6. #[clap(name = "translate")]
  7. pub struct Translate {
  8. /// Activate debug mode
  9. // short and long flags (-d, --debug) will be deduced from the field's name
  10. #[clap(short, long)]
  11. pub component: bool,
  12. /// Input file
  13. #[clap(short, long)]
  14. pub file: Option<String>,
  15. /// Input file
  16. #[clap(short, long)]
  17. pub raw: Option<String>,
  18. /// Output file, stdout if not present
  19. #[arg(short, long)]
  20. pub output: Option<PathBuf>,
  21. }
  22. impl Translate {
  23. pub fn translate(self) -> Result<()> {
  24. // Get the right input for the translation
  25. let contents = determine_input(self.file, self.raw)?;
  26. // Ensure we're loading valid HTML
  27. let dom = html_parser::Dom::parse(&contents)?;
  28. // Convert the HTML to RSX
  29. let out = convert_html_to_formatted_rsx(&dom, self.component);
  30. // Write the output
  31. match self.output {
  32. Some(output) => std::fs::write(&output, out)?,
  33. None => print!("{}", out),
  34. }
  35. Ok(())
  36. }
  37. }
  38. pub fn convert_html_to_formatted_rsx(dom: &Dom, component: bool) -> String {
  39. let callbody = rsx_rosetta::rsx_from_html(&dom);
  40. match component {
  41. true => write_callbody_with_icon_section(callbody),
  42. false => dioxus_autofmt::write_block_out(callbody).unwrap(),
  43. }
  44. }
  45. fn write_callbody_with_icon_section(mut callbody: CallBody) -> String {
  46. let mut svgs = vec![];
  47. rsx_rosetta::collect_svgs(&mut callbody.roots, &mut svgs);
  48. let mut out = write_component_body(dioxus_autofmt::write_block_out(callbody).unwrap());
  49. if !svgs.is_empty() {
  50. write_svg_section(&mut out, svgs);
  51. }
  52. out
  53. }
  54. fn write_component_body(raw: String) -> String {
  55. let mut out = String::from("fn component(cx: Scope) -> Element {\n cx.render(rsx! {");
  56. indent_and_write(&raw, 1, &mut out);
  57. out.push_str(" })\n}");
  58. out
  59. }
  60. fn write_svg_section(out: &mut String, svgs: Vec<BodyNode>) {
  61. out.push_str("\n\nmod icons {");
  62. out.push_str("\n use super::*;");
  63. for (idx, icon) in svgs.into_iter().enumerate() {
  64. let raw = dioxus_autofmt::write_block_out(CallBody { roots: vec![icon] }).unwrap();
  65. out.push_str("\n\n pub fn icon_");
  66. out.push_str(&idx.to_string());
  67. out.push_str("(cx: Scope) -> Element {\n cx.render(rsx! {");
  68. indent_and_write(&raw, 2, out);
  69. out.push_str(" })\n }");
  70. }
  71. out.push_str("\n}");
  72. }
  73. fn indent_and_write(raw: &str, idx: usize, out: &mut String) {
  74. for line in raw.lines() {
  75. for _ in 0..idx {
  76. out.push_str(" ");
  77. }
  78. out.push_str(line);
  79. out.push('\n');
  80. }
  81. }
  82. fn determine_input(file: Option<String>, raw: Option<String>) -> Result<String> {
  83. // Make sure not both are specified
  84. if file.is_some() && raw.is_some() {
  85. log::error!("Only one of --file or --raw should be specified.");
  86. exit(0);
  87. }
  88. if let Some(raw) = raw {
  89. return Ok(raw);
  90. }
  91. if let Some(file) = file {
  92. return Ok(std::fs::read_to_string(&file)?);
  93. }
  94. // If neither exist, we try to read from stdin
  95. if atty::is(atty::Stream::Stdin) {
  96. return custom_error!("No input file, source, or stdin to translate from.");
  97. }
  98. let mut buffer = String::new();
  99. std::io::stdin().read_to_string(&mut buffer).unwrap();
  100. Ok(buffer.trim().to_string())
  101. }
  102. #[test]
  103. fn generates_svgs() {
  104. let st = include_str!("../../../tests/svg.html");
  105. let out = convert_html_to_formatted_rsx(&html_parser::Dom::parse(st).unwrap(), true);
  106. println!("{}", out);
  107. }