html: render lists, list items
This commit is contained in:
		
					parent
					
						
							
								2f616c41b7
							
						
					
				
			
			
				commit
				
					
						1f71df82ef
					
				
			
		
					 1 changed files with 63 additions and 25 deletions
				
			
		
							
								
								
									
										92
									
								
								src/html.rs
									
										
									
									
									
								
							
							
						
						
									
										92
									
								
								src/html.rs
									
										
									
									
									
								
							| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
use crate::Atom;
 | 
					use crate::Atom;
 | 
				
			||||||
use crate::Container;
 | 
					use crate::Container;
 | 
				
			||||||
use crate::Event;
 | 
					use crate::Event;
 | 
				
			||||||
 | 
					use crate::List;
 | 
				
			||||||
 | 
					use crate::OrderedListNumbering::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Generate HTML from parsed events and push it to a unicode-accepting buffer or stream.
 | 
					/// Generate HTML from parsed events and push it to a unicode-accepting buffer or stream.
 | 
				
			||||||
pub fn push<'s, I: Iterator<Item = Event<'s>>, W: std::fmt::Write>(out: W, events: I) {
 | 
					pub fn push<'s, I: Iterator<Item = Event<'s>>, W: std::fmt::Write>(out: W, events: I) {
 | 
				
			||||||
| 
						 | 
					@ -99,9 +101,29 @@ impl<'s, I: Iterator<Item = Event<'s>>, W: std::fmt::Write> Writer<'s, I, W> {
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    match &c {
 | 
					                    match &c {
 | 
				
			||||||
                        Container::Blockquote => self.out.write_str("<blockquote")?,
 | 
					                        Container::Blockquote => self.out.write_str("<blockquote")?,
 | 
				
			||||||
                        Container::List(..) => todo!(),
 | 
					                        Container::List(List::Unordered | List::Task) => {
 | 
				
			||||||
                        Container::ListItem => self.out.write_str("<li")?,
 | 
					                            self.out.write_str("<ul")?;
 | 
				
			||||||
                        Container::TaskListItem { .. } => todo!(),
 | 
					                        }
 | 
				
			||||||
 | 
					                        Container::List(List::Ordered {
 | 
				
			||||||
 | 
					                            numbering, start, ..
 | 
				
			||||||
 | 
					                        }) => {
 | 
				
			||||||
 | 
					                            self.out.write_str("<ol")?;
 | 
				
			||||||
 | 
					                            if *start > 1 {
 | 
				
			||||||
 | 
					                                write!(self.out, r#" start="{}""#, start)?;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            if let Some(ty) = match numbering {
 | 
				
			||||||
 | 
					                                Decimal => None,
 | 
				
			||||||
 | 
					                                AlphaLower => Some('a'),
 | 
				
			||||||
 | 
					                                AlphaUpper => Some('A'),
 | 
				
			||||||
 | 
					                                RomanLower => Some('i'),
 | 
				
			||||||
 | 
					                                RomanUpper => Some('I'),
 | 
				
			||||||
 | 
					                            } {
 | 
				
			||||||
 | 
					                                write!(self.out, r#" type="{}""#, ty)?;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        Container::ListItem | Container::TaskListItem { .. } => {
 | 
				
			||||||
 | 
					                            self.out.write_str("<li")?;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
                        Container::DescriptionDetails => self.out.write_str("<dd")?,
 | 
					                        Container::DescriptionDetails => self.out.write_str("<dd")?,
 | 
				
			||||||
                        Container::Footnote { number, .. } => {
 | 
					                        Container::Footnote { number, .. } => {
 | 
				
			||||||
                            assert!(self.footnote_number.is_none());
 | 
					                            assert!(self.footnote_number.is_none());
 | 
				
			||||||
| 
						 | 
					@ -153,42 +175,53 @@ impl<'s, I: Iterator<Item = Event<'s>>, W: std::fmt::Write> Writer<'s, I, W> {
 | 
				
			||||||
                        Container::Mark => self.out.write_str("<mark")?,
 | 
					                        Container::Mark => self.out.write_str("<mark")?,
 | 
				
			||||||
                        Container::SingleQuoted => self.out.write_str("‘")?,
 | 
					                        Container::SingleQuoted => self.out.write_str("‘")?,
 | 
				
			||||||
                        Container::DoubleQuoted => self.out.write_str("“")?,
 | 
					                        Container::DoubleQuoted => self.out.write_str("“")?,
 | 
				
			||||||
 | 
					                        _ => panic!(),
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if matches!(c, Container::SingleQuoted | Container::DoubleQuoted) {
 | 
					                    if matches!(c, Container::SingleQuoted | Container::DoubleQuoted) {
 | 
				
			||||||
                        continue; // TODO add span to allow attributes?
 | 
					                        continue; // TODO add span to allow attributes?
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    for (a, v) in attrs.iter().filter(|(a, _)| *a != "class") {
 | 
				
			||||||
 | 
					                        write!(self.out, r#" {}="{}""#, a, v)?;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if attrs.iter().any(|(a, _)| a == "class")
 | 
					                    if attrs.iter().any(|(a, _)| a == "class")
 | 
				
			||||||
                        || matches!(
 | 
					                        || matches!(
 | 
				
			||||||
                            c,
 | 
					                            c,
 | 
				
			||||||
                            Container::Div { class: Some(_) } | Container::Math { .. }
 | 
					                            Container::Div { class: Some(_) }
 | 
				
			||||||
 | 
					                                | Container::Math { .. }
 | 
				
			||||||
 | 
					                                | Container::List(List::Task)
 | 
				
			||||||
 | 
					                                | Container::TaskListItem { .. }
 | 
				
			||||||
                        )
 | 
					                        )
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        self.out.write_str(r#" class=""#)?;
 | 
					                        self.out.write_str(r#" class=""#)?;
 | 
				
			||||||
                        let mut classes = attrs
 | 
					                        let mut first_written = false;
 | 
				
			||||||
                            .iter()
 | 
					                        if let Some(cls) = match c {
 | 
				
			||||||
                            .filter(|(a, _)| a == &"class")
 | 
					                            Container::List(List::Task) => Some("task-list"),
 | 
				
			||||||
                            .map(|(_, cls)| cls);
 | 
					                            Container::TaskListItem { checked: false } => Some("unchecked"),
 | 
				
			||||||
                        let has_attr = if let Container::Math { display } = c {
 | 
					                            Container::TaskListItem { checked: true } => Some("checked"),
 | 
				
			||||||
                            self.out.write_str(if display {
 | 
					                            Container::Math { display: false } => Some("math inline"),
 | 
				
			||||||
                                "math display"
 | 
					                            Container::Math { display: true } => Some("math display"),
 | 
				
			||||||
                            } else {
 | 
					                            _ => None,
 | 
				
			||||||
                                "math inline"
 | 
					                        } {
 | 
				
			||||||
                            })?;
 | 
					                            first_written = true;
 | 
				
			||||||
                            true
 | 
					 | 
				
			||||||
                        } else if let Some(cls) = classes.next() {
 | 
					 | 
				
			||||||
                            self.out.write_str(cls)?;
 | 
					 | 
				
			||||||
                            for cls in classes {
 | 
					 | 
				
			||||||
                                self.out.write_char(' ')?;
 | 
					 | 
				
			||||||
                            self.out.write_str(cls)?;
 | 
					                            self.out.write_str(cls)?;
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                            true
 | 
					                        for cls in attrs
 | 
				
			||||||
                        } else {
 | 
					                            .iter()
 | 
				
			||||||
                            false
 | 
					                            .filter(|(a, _)| a == &"class")
 | 
				
			||||||
                        };
 | 
					                            .map(|(_, cls)| cls)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            if first_written {
 | 
				
			||||||
 | 
					                                self.out.write_char(' ')?;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            first_written = true;
 | 
				
			||||||
 | 
					                            self.out.write_str(cls)?;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        // div class goes after classes from attrs
 | 
				
			||||||
                        if let Container::Div { class: Some(cls) } = c {
 | 
					                        if let Container::Div { class: Some(cls) } = c {
 | 
				
			||||||
                            if has_attr {
 | 
					                            if first_written {
 | 
				
			||||||
                                self.out.write_char(' ')?;
 | 
					                                self.out.write_char(' ')?;
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            self.out.write_str(cls)?;
 | 
					                            self.out.write_str(cls)?;
 | 
				
			||||||
| 
						 | 
					@ -223,9 +256,13 @@ impl<'s, I: Iterator<Item = Event<'s>>, W: std::fmt::Write> Writer<'s, I, W> {
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    match c {
 | 
					                    match c {
 | 
				
			||||||
                        Container::Blockquote => self.out.write_str("</blockquote>")?,
 | 
					                        Container::Blockquote => self.out.write_str("</blockquote>")?,
 | 
				
			||||||
                        Container::List(..) => todo!(),
 | 
					                        Container::List(List::Unordered | List::Task) => {
 | 
				
			||||||
                        Container::ListItem => self.out.write_str("</li>")?,
 | 
					                            self.out.write_str("</ul>")?;
 | 
				
			||||||
                        Container::TaskListItem { .. } => todo!(),
 | 
					                        }
 | 
				
			||||||
 | 
					                        Container::List(List::Ordered { .. }) => self.out.write_str("</ol>")?,
 | 
				
			||||||
 | 
					                        Container::ListItem | Container::TaskListItem { .. } => {
 | 
				
			||||||
 | 
					                            self.out.write_str("</li>")?;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
                        Container::DescriptionDetails => self.out.write_str("</dd>")?,
 | 
					                        Container::DescriptionDetails => self.out.write_str("</dd>")?,
 | 
				
			||||||
                        Container::Footnote { number, .. } => {
 | 
					                        Container::Footnote { number, .. } => {
 | 
				
			||||||
                            if !self.footnote_backlink_written {
 | 
					                            if !self.footnote_backlink_written {
 | 
				
			||||||
| 
						 | 
					@ -291,6 +328,7 @@ impl<'s, I: Iterator<Item = Event<'s>>, W: std::fmt::Write> Writer<'s, I, W> {
 | 
				
			||||||
                        Container::Mark => self.out.write_str("</mark>")?,
 | 
					                        Container::Mark => self.out.write_str("</mark>")?,
 | 
				
			||||||
                        Container::SingleQuoted => self.out.write_str("’")?,
 | 
					                        Container::SingleQuoted => self.out.write_str("’")?,
 | 
				
			||||||
                        Container::DoubleQuoted => self.out.write_str("”")?,
 | 
					                        Container::DoubleQuoted => self.out.write_str("”")?,
 | 
				
			||||||
 | 
					                        _ => panic!(),
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                Event::Str(s) => {
 | 
					                Event::Str(s) => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue