From d654bbf512560ad4701becac46a6e8f6aa52b4be Mon Sep 17 00:00:00 2001 From: videogame hacker Date: Sun, 12 Sep 2021 23:24:51 +0100 Subject: [PATCH] Matrix: Implement code and code-block parsing --- src/message_ast/convert_matrix.rs | 67 ++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/src/message_ast/convert_matrix.rs b/src/message_ast/convert_matrix.rs index 2fff3fd..2b29ac3 100644 --- a/src/message_ast/convert_matrix.rs +++ b/src/message_ast/convert_matrix.rs @@ -12,6 +12,7 @@ pub fn convert_matrix(message: &str) -> MessageContent { let mut parents = vec![]; let mut components = vec![]; + let mut skip_text = false; for edge in dom.traverse() { match edge { @@ -39,6 +40,10 @@ pub fn convert_matrix(message: &str) -> MessageContent { } } + local_name!("code") => { + skip_text = true; + } + _ => {} } } @@ -47,7 +52,9 @@ pub fn convert_matrix(message: &str) -> MessageContent { NodeEdge::End(node) => match node.data() { NodeData::Text(text) => { - components.push(MessageComponent::Plain(text.borrow().clone())); + if !skip_text { + components.push(MessageComponent::Plain(text.borrow().clone())); + } } NodeData::Element(element) => { macro_rules! construct_component { @@ -105,6 +112,37 @@ pub fn convert_matrix(message: &str) -> MessageContent { }) } } + local_name!("code") => { + // is_code_block = whether we are the child of a
 tag
+                                let is_code_block = node
+                                    .parent()
+                                    .as_ref()
+                                    .map(|p| p.data())
+                                    .and_then(|d| match d {
+                                        NodeData::Element(e) => {
+                                            Some(e.name.local == local_name!("pre"))
+                                        }
+                                        _ => None,
+                                    })
+                                    .unwrap_or(false);
+
+                                components.push(if is_code_block {
+                                    let attrs = element.attributes.borrow();
+                                    let lang = attrs
+                                        .get(local_name!("class"))
+                                        .and_then(|lang| lang.strip_prefix("language-"))
+                                        .map(|s| s.to_string());
+
+                                    MessageComponent::CodeBlock {
+                                        lang,
+                                        source: node.text_contents(),
+                                    }
+                                } else {
+                                    MessageComponent::Code(node.text_contents())
+                                });
+
+                                skip_text = false;
+                            }
                             _ => {}
                         }
                     }
@@ -168,7 +206,7 @@ pub fn format_matrix(message_content: &[MessageComponent]) -> String {
 }
 
 #[test]
-fn simple_matrix_parsing() {
+fn simple_parsing() {
     use MessageComponent::*;
 
     let html =
@@ -208,3 +246,28 @@ fn spoiler_parsing() {
         }]
     );
 }
+
+#[test]
+fn code_parsing() {
+    use MessageComponent::*;
+
+    let html = r#"hello_world();"#;
+
+    assert_eq!(
+        convert_matrix(html),
+        vec![Code("hello_world();".to_string())]
+    );
+
+    let html = r#"
console.log("hello, world!");
+console.table({ a: 1, b: 2, c: 3 });
+
"#; + + assert_eq!( + convert_matrix(html), + vec![CodeBlock { + lang: Some("javascript".to_string()), + source: "console.log(\"hello, world!\");\nconsole.table({ a: 1, b: 2, c: 3 });\n" + .to_string(), + }] + ); +}