use crate::entities::*; use pandoc_types::definition::{Attr, Block, Inline, Meta, MetaValue, Pandoc}; use std::collections::HashMap; pub(crate) fn into_pandoc<'e>( entity: &'e dyn Entity, description: &Description, descriptions: &HashMap, ) -> (Pandoc, HashMap<&'e Usr, &'e DynEntity>) { let mut meta = Meta::null(); let title = vec![Inline::Code(Attr::null(), description.name.clone())]; meta.0.insert( "title".to_string(), MetaValue::MetaString(description.name.clone()), ); let mut content = Vec::new(); content.push(Block::Header(1, Attr::null(), title)); if !description.detailed.is_empty() { content.push(Block::Header( 2, Attr::null(), vec![Inline::Str(String::from("Description"))], )); content.push(Block::Div( Attr(String::new(), vec![String::from("doc")], vec![]), vec![raw_markdown(description.detailed.clone())], )); } let separate_children = entity.separate_children(); let embeddable_children = entity.embeddable_children(); for section in &separate_children { if let Some(members_list) = member_list( section.children.iter().map(|&(usr, _child)| usr), descriptions, ) { content.push(Block::Header( 2, Attr::null(), vec![Inline::Str(String::from(section.name))], )); content.push(members_list); } } let mut embedded_documentation = Vec::new(); for section in &embeddable_children { if let Some(members_list) = member_list( section.children.iter().map(|&(usr, _child)| usr), descriptions, ) { content.push(Block::Header( 2, Attr::null(), vec![Inline::Str(String::from(section.name))], )); content.push(members_list); embedded_documentation.push(Block::Header( 2, Attr::null(), vec![Inline::Str(String::from(section.name) + " Documentation")], )); for (usr, _child) in §ion.children { let child_doc = descriptions.get(usr).unwrap(); embedded_documentation.push(Block::Header( 3, Attr::null(), vec![Inline::Code(Attr::null(), String::from(&child_doc.name))], )); embedded_documentation.push(Block::Div( Attr(String::new(), vec![String::from("doc")], vec![]), vec![raw_markdown(child_doc.detailed.clone())], )); } } } content.append(&mut embedded_documentation); let leftovers = separate_children .iter() .map(|section| section.children.clone()) .flatten() .collect(); (Pandoc(meta, content), leftovers) } fn str_block(content: String) -> Block { Block::Plain(vec![Inline::Str(content)]) } fn entity_link(usr: &Usr, name: String) -> Inline { use pandoc_types::definition::Target; use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS}; use std::iter::once; // https://url.spec.whatwg.org/#fragment-percent-encode-set const FRAGMENT: &AsciiSet = &CONTROLS .add(b' ') .add(b'"') .add(b'<') .add(b'>') .add(b'`') .add(b'#') .add(b'?') .add(b'{') .add(b'}'); Inline::Link( Attr::null(), vec![Inline::Code(Attr::null(), name)], Target( once("./") .chain(utf8_percent_encode(&usr.0, FRAGMENT)) .collect(), String::new(), ), ) } fn raw_markdown(text: String) -> Block { use pandoc_types::definition::Format; Block::RawBlock(Format(String::from("markdown")), text) } fn member_list<'a>( members: impl IntoIterator, descriptions: &HashMap, ) -> Option { let definitions: Vec<(Vec, Vec>)> = members .into_iter() .filter_map(|usr| { let name = &descriptions.get(usr)?.name; Some(( vec![entity_link(usr, name.clone())], vec![vec![str_block( descriptions.get(usr).unwrap().brief.clone(), )]], )) }) .collect(); if definitions.is_empty() { None } else { Some(Block::DefinitionList(definitions)) } }