Compare commits
	
		
			No commits in common. "25c4d83d4dc19480e1da85011466f06605a5eff0" and "122f9d120b8f5abf599bdf305b07ce1615145239" have entirely different histories. 
		
	
	
		
			25c4d83d4d
			...
			122f9d120b
		
	
		
							
								
								
									
										95
									
								
								src/lib.rs
								
								
								
								
							
							
						
						
									
										95
									
								
								src/lib.rs
								
								
								
								
							| 
						 | 
					@ -19,7 +19,7 @@ pub fn convert(markdown_text: &str) -> String {
 | 
				
			||||||
            md::Event::Start(md::Tag::Heading(level)) => state.start_heading(level),
 | 
					            md::Event::Start(md::Tag::Heading(level)) => state.start_heading(level),
 | 
				
			||||||
            md::Event::Start(md::Tag::BlockQuote) => state.start_block_quote(),
 | 
					            md::Event::Start(md::Tag::BlockQuote) => state.start_block_quote(),
 | 
				
			||||||
            md::Event::Start(md::Tag::CodeBlock(_)) => state.start_code_block(),
 | 
					            md::Event::Start(md::Tag::CodeBlock(_)) => state.start_code_block(),
 | 
				
			||||||
            md::Event::Start(md::Tag::List(_)) => state.start_list(),
 | 
					            md::Event::Start(md::Tag::List(_)) => (),
 | 
				
			||||||
            md::Event::Start(md::Tag::Item) => state.start_list_item(),
 | 
					            md::Event::Start(md::Tag::Item) => state.start_list_item(),
 | 
				
			||||||
            md::Event::Start(md::Tag::FootnoteDefinition(_)) => {
 | 
					            md::Event::Start(md::Tag::FootnoteDefinition(_)) => {
 | 
				
			||||||
                unimplemented!("footnotes disabled")
 | 
					                unimplemented!("footnotes disabled")
 | 
				
			||||||
| 
						 | 
					@ -39,7 +39,7 @@ pub fn convert(markdown_text: &str) -> String {
 | 
				
			||||||
            md::Event::End(md::Tag::BlockQuote) => (),
 | 
					            md::Event::End(md::Tag::BlockQuote) => (),
 | 
				
			||||||
            md::Event::End(md::Tag::CodeBlock(_)) => state.finish_node(),
 | 
					            md::Event::End(md::Tag::CodeBlock(_)) => state.finish_node(),
 | 
				
			||||||
            md::Event::End(md::Tag::List(_)) => state.finish_list(),
 | 
					            md::Event::End(md::Tag::List(_)) => state.finish_list(),
 | 
				
			||||||
            md::Event::End(md::Tag::Item) => state.finish_item(),
 | 
					            md::Event::End(md::Tag::Item) => state.finish_node(),
 | 
				
			||||||
            md::Event::End(md::Tag::FootnoteDefinition(_)) => unimplemented!("footnotes disabled"),
 | 
					            md::Event::End(md::Tag::FootnoteDefinition(_)) => unimplemented!("footnotes disabled"),
 | 
				
			||||||
            md::Event::End(md::Tag::Table(_)) => state.finish_table_building(),
 | 
					            md::Event::End(md::Tag::Table(_)) => state.finish_table_building(),
 | 
				
			||||||
            md::Event::End(md::Tag::TableHead) => (),
 | 
					            md::Event::End(md::Tag::TableHead) => (),
 | 
				
			||||||
| 
						 | 
					@ -118,8 +118,6 @@ struct State {
 | 
				
			||||||
    link_text_stack: Vec<String>,
 | 
					    link_text_stack: Vec<String>,
 | 
				
			||||||
    table: Vec<Vec<String>>,
 | 
					    table: Vec<Vec<String>>,
 | 
				
			||||||
    building_table: bool,
 | 
					    building_table: bool,
 | 
				
			||||||
    nested_list_level: Option<u8>,
 | 
					 | 
				
			||||||
    list_items: Vec<String>,
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl State {
 | 
					impl State {
 | 
				
			||||||
| 
						 | 
					@ -132,8 +130,6 @@ impl State {
 | 
				
			||||||
            link_text_stack: vec![],
 | 
					            link_text_stack: vec![],
 | 
				
			||||||
            table: vec![],
 | 
					            table: vec![],
 | 
				
			||||||
            building_table: false,
 | 
					            building_table: false,
 | 
				
			||||||
            nested_list_level: None,
 | 
					 | 
				
			||||||
            list_items: vec![],
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -170,16 +166,8 @@ impl State {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn start_list(&mut self) {
 | 
					 | 
				
			||||||
        let level = match self.nested_list_level {
 | 
					 | 
				
			||||||
            Some(n) => n + 1,
 | 
					 | 
				
			||||||
            None => 0,
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        self.nested_list_level = Some(level);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn start_list_item(&mut self) {
 | 
					    fn start_list_item(&mut self) {
 | 
				
			||||||
        self.list_items.push(String::new());
 | 
					        self.pending_node_type = NodeType::ListItem;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn toggle_emphasis(&mut self) {
 | 
					    fn toggle_emphasis(&mut self) {
 | 
				
			||||||
| 
						 | 
					@ -203,12 +191,6 @@ impl State {
 | 
				
			||||||
        self.pending_node_content += "[image: ";
 | 
					        self.pending_node_content += "[image: ";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn finish_item(&mut self) {
 | 
					 | 
				
			||||||
        if self.nested_list_level.is_none() {
 | 
					 | 
				
			||||||
            self.finish_node();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn finish_table_building(&mut self) {
 | 
					    fn finish_table_building(&mut self) {
 | 
				
			||||||
        let mut table = Table::new();
 | 
					        let mut table = Table::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -227,31 +209,14 @@ impl State {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn finish_list(&mut self) {
 | 
					    fn finish_list(&mut self) {
 | 
				
			||||||
        let level = match self.nested_list_level {
 | 
					        self.nodes.push(vec![]);
 | 
				
			||||||
            Some(0) => {
 | 
					 | 
				
			||||||
                for item in self.list_items.clone() {
 | 
					 | 
				
			||||||
                    self.pending_node_type = NodeType::ListItem;
 | 
					 | 
				
			||||||
                    self.pending_node_content = item;
 | 
					 | 
				
			||||||
                    self.finish_node();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                self.list_items.clear();
 | 
					 | 
				
			||||||
                self.force_links();
 | 
					 | 
				
			||||||
                None
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            Some(n) => Some(n - 1),
 | 
					 | 
				
			||||||
            None => unreachable!("How can you finish a list without level?"),
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        self.nested_list_level = level;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn end_link(&mut self, href: &str) {
 | 
					    fn end_link(&mut self, href: &str) {
 | 
				
			||||||
        let text = if self.nested_list_level.is_some() {
 | 
					        let text = self
 | 
				
			||||||
            href.to_string()
 | 
					            .link_text_stack
 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            self.link_text_stack
 | 
					 | 
				
			||||||
            .pop()
 | 
					            .pop()
 | 
				
			||||||
                .unwrap_or_else(|| href.to_string())
 | 
					            .unwrap_or_else(|| href.to_string());
 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        self.pending_other.push(gemtext::Node::Link {
 | 
					        self.pending_other.push(gemtext::Node::Link {
 | 
				
			||||||
            to: href.to_string(),
 | 
					            to: href.to_string(),
 | 
				
			||||||
            name: Some(text),
 | 
					            name: Some(text),
 | 
				
			||||||
| 
						 | 
					@ -271,11 +236,6 @@ impl State {
 | 
				
			||||||
        self.pending_node_content += "]";
 | 
					        self.pending_node_content += "]";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn force_links(&mut self) {
 | 
					 | 
				
			||||||
        let last_cluster = self.nodes.last_mut().expect("empty cluster list??");
 | 
					 | 
				
			||||||
        last_cluster.extend(self.pending_other.drain(..));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // will create an empty paragraph if pending_text is empty
 | 
					    // will create an empty paragraph if pending_text is empty
 | 
				
			||||||
    fn finish_node(&mut self) {
 | 
					    fn finish_node(&mut self) {
 | 
				
			||||||
        match (
 | 
					        match (
 | 
				
			||||||
| 
						 | 
					@ -285,23 +245,17 @@ impl State {
 | 
				
			||||||
            (NodeType::ListItem, Some(gemtext::Node::ListItem(_))) => (),
 | 
					            (NodeType::ListItem, Some(gemtext::Node::ListItem(_))) => (),
 | 
				
			||||||
            _ => self.nodes.push(vec![]),
 | 
					            _ => self.nodes.push(vec![]),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        let node_text = self.pending_node_content.trim_end().to_string();
 | 
					        let node_text = self.pending_node_content.trim().to_string();
 | 
				
			||||||
        let new_node = self.pending_node_type.take().construct(node_text);
 | 
					        let new_node = self.pending_node_type.take().construct(node_text);
 | 
				
			||||||
        let last_cluster = self.nodes.last_mut().expect("empty cluster list??");
 | 
					        let last_cluster = self.nodes.last_mut().expect("empty cluster list??");
 | 
				
			||||||
        last_cluster.push(new_node);
 | 
					        last_cluster.push(new_node);
 | 
				
			||||||
        if self.nested_list_level.is_none() {
 | 
					 | 
				
			||||||
        last_cluster.extend(self.pending_other.drain(..));
 | 
					        last_cluster.extend(self.pending_other.drain(..));
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.pending_node_content = String::new();
 | 
					        self.pending_node_content = String::new();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn add_text(&mut self, text: &str) {
 | 
					    fn add_text(&mut self, text: &str) {
 | 
				
			||||||
        if self.nested_list_level.is_some() {
 | 
					        if self.building_table {
 | 
				
			||||||
            if let Some(last) = self.list_items.last_mut() {
 | 
					 | 
				
			||||||
                last.push_str(text);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } else if self.building_table {
 | 
					 | 
				
			||||||
            if let Some(last_row) = self.table.last_mut() {
 | 
					            if let Some(last_row) = self.table.last_mut() {
 | 
				
			||||||
                if let Some(last_cell) = last_row.last_mut() {
 | 
					                if let Some(last_cell) = last_row.last_mut() {
 | 
				
			||||||
                    last_cell.push_str(&text.split("<br>").collect::<Vec<&str>>().join("\n"));
 | 
					                    last_cell.push_str(&text.split("<br>").collect::<Vec<&str>>().join("\n"));
 | 
				
			||||||
| 
						 | 
					@ -328,12 +282,6 @@ impl State {
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else if self.nested_list_level.is_some() {
 | 
					 | 
				
			||||||
            if let Some(last) = self.list_items.last_mut() {
 | 
					 | 
				
			||||||
                last.push_str("`");
 | 
					 | 
				
			||||||
                last.push_str(code);
 | 
					 | 
				
			||||||
                last.push_str("`");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            self.pending_node_content += "`";
 | 
					            self.pending_node_content += "`";
 | 
				
			||||||
            self.pending_node_content += code;
 | 
					            self.pending_node_content += code;
 | 
				
			||||||
| 
						 | 
					@ -483,28 +431,3 @@ fn test_multi_tables() {
 | 
				
			||||||
"#;
 | 
					"#;
 | 
				
			||||||
    assert_eq!(convert(markdown).trim(), gemtext.trim());
 | 
					    assert_eq!(convert(markdown).trim(), gemtext.trim());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
#[cfg(test)]
 | 
					 | 
				
			||||||
#[test]
 | 
					 | 
				
			||||||
fn test_nested_list() {
 | 
					 | 
				
			||||||
    let markdown = r#"
 | 
					 | 
				
			||||||
- item 1
 | 
					 | 
				
			||||||
- item 2
 | 
					 | 
				
			||||||
  - subitem 2.1
 | 
					 | 
				
			||||||
  - subitem [2.2](https://example.com)
 | 
					 | 
				
			||||||
  - subitem [2.3](https://example.com)
 | 
					 | 
				
			||||||
- item 3
 | 
					 | 
				
			||||||
"#;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let gemtext = r#"
 | 
					 | 
				
			||||||
* item 1
 | 
					 | 
				
			||||||
* item 2
 | 
					 | 
				
			||||||
* subitem 2.1
 | 
					 | 
				
			||||||
* subitem 2.2
 | 
					 | 
				
			||||||
* subitem 2.3
 | 
					 | 
				
			||||||
* item 3
 | 
					 | 
				
			||||||
=> https://example.com https://example.com
 | 
					 | 
				
			||||||
=> https://example.com https://example.com
 | 
					 | 
				
			||||||
"#;
 | 
					 | 
				
			||||||
    assert_eq!(convert(markdown).trim(), gemtext.trim());
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue