at main 87 lines 2.9 kB view raw
1use markdown_weaver_escape::StrWrite; 2// use syntect::highlighting::ThemeSet; 3// use syntect::html::css_for_theme_with_class_style; 4use syntect::html::{ClassStyle, ClassedHTMLGenerator}; 5use syntect::parsing::SyntaxSet; 6use syntect::util::LinesWithEndings; 7 8/// Perform syntax highlighting on a code block. 9/// This requires an external stylesheet, also generated by syntect to be loaded by the page. 10/// The syntect SyntaxSet is also provided, so that it is not re-created on every call. 11pub fn highlight<M>( 12 syn_set: &SyntaxSet, 13 lang: Option<&str>, 14 code: impl AsRef<str>, 15 writer: &mut M, 16) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> 17where 18 M: StrWrite, 19 <M as StrWrite>::Error: std::error::Error + Send + Sync + 'static, 20{ 21 let lang_syn = if let Some(lang) = lang { 22 syn_set 23 .find_syntax_by_token(lang) 24 .unwrap_or_else(|| syn_set.find_syntax_plain_text()) 25 } else { 26 syn_set 27 .find_syntax_by_first_line(code.as_ref()) 28 .unwrap_or_else(|| syn_set.find_syntax_plain_text()) 29 }; 30 writer.write_str("<pre><code class=\"wvc-code language-")?; 31 writer.write_str(&lang_syn.name)?; 32 writer.write_str("\">")?; 33 34 let mut html_gen = ClassedHTMLGenerator::new_with_class_style( 35 lang_syn, 36 syn_set, 37 ClassStyle::SpacedPrefixed { prefix: CSS_PREFIX }, 38 ); 39 for line in LinesWithEndings::from(code.as_ref()) { 40 html_gen 41 .parse_html_for_line_which_includes_newline(line) 42 .unwrap(); 43 } 44 writer.write_str(&html_gen.finalize())?; 45 writer.write_str("</code></pre>")?; 46 Ok(()) 47} 48 49pub const CSS_PREFIX: &str = "wvc-"; 50 51pub fn highlight_code<M>( 52 lang: Option<&str>, 53 code: impl AsRef<str>, 54 writer: &mut M, 55) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> 56where 57 M: StrWrite, 58 <M as StrWrite>::Error: std::error::Error + Send + Sync + 'static, 59{ 60 let syn_set = SyntaxSet::load_defaults_newlines(); 61 let lang_syn = if let Some(lang) = lang { 62 syn_set 63 .find_syntax_by_token(lang) 64 .unwrap_or_else(|| syn_set.find_syntax_plain_text()) 65 } else { 66 syn_set 67 .find_syntax_by_first_line(code.as_ref()) 68 .unwrap_or_else(|| syn_set.find_syntax_plain_text()) 69 }; 70 writer.write_str("<pre><code class=\"wvc-code language-")?; 71 writer.write_str(&lang_syn.name)?; 72 writer.write_str("\">")?; 73 74 let mut html_gen = ClassedHTMLGenerator::new_with_class_style( 75 lang_syn, 76 &syn_set, 77 ClassStyle::SpacedPrefixed { prefix: CSS_PREFIX }, 78 ); 79 for line in LinesWithEndings::from(code.as_ref()) { 80 html_gen 81 .parse_html_for_line_which_includes_newline(line) 82 .unwrap(); 83 } 84 writer.write_str(&html_gen.finalize())?; 85 writer.write_str("</code></pre>")?; 86 Ok(()) 87}