diff --git a/utils/mdhtml/lib.rs b/utils/mdhtml/lib.rs index 490212e..29fc2b4 100644 --- a/utils/mdhtml/lib.rs +++ b/utils/mdhtml/lib.rs @@ -1,5 +1,53 @@ use html5ever::{tendril::SliceExt, tokenizer::{BufferQueue, TagKind, Token, TokenSink, TokenSinkResult, Tokenizer}}; -use comrak::{markdown_to_html, Options}; + +// TODO this drives me so mad!!! The #[non_exhaustive] attr on the underlying ___Options structs +// makes it impossible to construct them with struct syntax! I need to use this BULLSHIT +// builder pattern. And it's NOT CONST!!! I have to keep this shit heap allocated somewhere +// because this thing is #[non_exhaustive]... oh i hate this so much +fn options() -> &'static comrak::Options { + static OPTIONS: std::sync::OnceLock = std::sync::OnceLock::new(); + OPTIONS.get_or_init(|| + comrak::Options { + extension: comrak::ExtensionOptionsBuilder::default() + .autolink(true) + .strikethrough(true) + .description_lists(false) + .tagfilter(true) + .table(true) + .tasklist(false) + .superscript(true) + .header_ids(None) + .footnotes(false) + .front_matter_delimiter(None) + .multiline_block_quotes(true) + .math_dollars(true) + .math_code(true) + .build() + .expect("error creating default markdown extension options"), + + parse: comrak::ParseOptionsBuilder::default() + .smart(false) + .default_info_string(None) + .relaxed_tasklist_matching(true) + .relaxed_autolinks(false) + .build() + .expect("erropr creating default markdown parse options"), + + render: comrak::RenderOptionsBuilder::default() + .hardbreaks(true) + .github_pre_lang(true) + .full_info_string(false) + .width(120) + .unsafe_(false) + .escape(true) + .list_style(comrak::ListStyleType::Dash) + .sourcepos(false) + .escaped_char_spans(true) + .build() + .expect("error creating default markdown render options"), + } + ) +} pub type Cloaker = Box String>; @@ -26,7 +74,7 @@ impl Sanitizer { } pub fn markdown(self, text: &str) -> String { - self.html(&markdown_to_html(text, &Options::default())) + self.html(&comrak::markdown_to_html(text, options())) } pub fn html(self, text: &str) -> String { @@ -54,12 +102,17 @@ impl TokenSink for Sanitizer { Token::TagToken(tag) => { if !matches!( tag.name.as_ref(), - "h1" | "h2" | "h3" - | "hr" | "br" | "p" | "b" | "i" | "s" - | "blockquote" | "pre" | "code" - | "ul" | "ol" | "li" - | "img" | "a" - ) { return TokenSinkResult::Continue } // skip this tag + "h1" | "h2" | "h3" // allow titles, up to 3 depth + | "sup" | "sub" // allow superscript/subscript + | "hr" | "br" // allow horizontal rules and linebreaks + | "p" | "span" // allow placing paragraphs and spans + | "b" | "i" | "s" | "del" // allow simple formatting: bold, italic and strikethrough, but not underlined as it can look like a link! + | "blockquote" | "pre" | "code" // allow code blocks + | "ul" | "ol" | "li" // allow lists + | "img" | "a" // allow images and links, but will get sanitized later + ) { + return TokenSinkResult::Continue; // skip this tag + } self.buffer.push('<');