atproto blogging
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}