wayver's git archive


an obsidian renderer
git clone https://git.wayver.dev/sable

sable-markdown/src/render/highlighter.rs@main

raw
Date Commit Message Author Files + -
2026-02-23 01:55 initial mvp wayverd 139 17808 0
...

1use crate::ast::{CodeBlock, CodeBlockKind};
2
3// TODO: maybe combine the support lang tokens for all highlighters
4
5#[cfg(feature = "highlighting-inkjet")]
6pub(super) fn highlight(block: &CodeBlock) -> String {
7    use std::cell::RefCell;
8
9    use inkjet::{Highlighter, Language, formatter::Html};
10
11    let language = match &block.kind {
12        CodeBlockKind::Indented => Language::Plaintext,
13        CodeBlockKind::Fenced { info } => info
14            .as_deref()
15            .and_then(Language::from_token)
16            .unwrap_or(Language::Plaintext),
17    };
18
19    let mut buf = String::new();
20
21    thread_local! {
22        static HIGHLIGHTER: RefCell<Highlighter> = RefCell::new(Highlighter::new());
23    }
24
25    // TODO: return error probably
26    HIGHLIGHTER.with(|this| {
27        this.borrow_mut()
28            .highlight_to_fmt(language, &Html, &block.literal, &mut buf)
29            .expect("failed to write highlighted code");
30    });
31
32    buf
33}
34
35#[cfg(feature = "highlighting-syntect")]
36pub fn highlight(block: &CodeBlock) -> String {
37    use std::sync::LazyLock;
38
39    use syntect::{
40        html::{ClassStyle, ClassedHTMLGenerator},
41        parsing::SyntaxSet,
42        util::LinesWithEndings,
43    };
44
45    static SET: LazyLock<SyntaxSet> = LazyLock::new(SyntaxSet::load_defaults_newlines);
46
47    let syntax_ref = match &block.kind {
48        CodeBlockKind::Indented => SET.find_syntax_plain_text(),
49        CodeBlockKind::Fenced { info } => info
50            .as_deref()
51            .and_then(|token| SET.find_syntax_by_token(token))
52            .unwrap_or_else(|| SET.find_syntax_plain_text()),
53    };
54
55    let mut rs_html_generator =
56        ClassedHTMLGenerator::new_with_class_style(syntax_ref, &SET, ClassStyle::Spaced);
57
58    for line in LinesWithEndings::from(&block.literal) {
59        rs_html_generator
60            .parse_html_for_line_which_includes_newline(line)
61            .unwrap();
62    }
63
64    rs_html_generator.finalize()
65}
66
67#[cfg(not(any(feature = "highlighting-inkjet", feature = "highlighting-syntect")))]
68pub fn highlight(block: &CodeBlock) -> String {
69    crate::util::escape(&block.literal)
70}
71