Skip to content

Commit f55535b

Browse files
authored
Add support for class-based highlighting
1 parent 2d7c085 commit f55535b

File tree

1 file changed

+38
-6
lines changed

1 file changed

+38
-6
lines changed

src/plugins/extra/syntect.rs

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
//! Syntax highlighting for code blocks
22
use syntect::highlighting::ThemeSet;
3-
use syntect::html::highlighted_html_for_string;
3+
use syntect::html::{highlighted_html_for_string, ClassedHtmlGenerator};
4+
pub use syntect::html::ClassStyle;
45
use syntect::parsing::SyntaxSet;
6+
use syntect::util::LinesWithEndings;
57

68
use crate::parser::core::CoreRule;
79
use crate::parser::extset::MarkdownItExt;
@@ -21,29 +23,50 @@ impl NodeValue for SyntectSnippet {
2123
}
2224

2325
#[derive(Debug, Clone, Copy)]
24-
struct SyntectSettings(&'static str);
26+
enum SyntectMode {
27+
InlineStyles { theme: &'static str },
28+
CssClasses { class_style: ClassStyle }
29+
}
30+
31+
#[derive(Debug, Clone, Copy)]
32+
struct SyntectSettings(SyntectMode);
2533
impl MarkdownItExt for SyntectSettings {}
2634

2735
impl Default for SyntectSettings {
2836
fn default() -> Self {
29-
Self("InspiredGitHub")
37+
Self(SyntectMode::InlineStyles { theme: "InspiredGitHub" })
3038
}
3139
}
3240

3341
pub fn add(md: &mut MarkdownIt) {
3442
md.add_rule::<SyntectRule>();
3543
}
3644

45+
/// Use inline styles with the given theme
3746
pub fn set_theme(md: &mut MarkdownIt, theme: &'static str) {
38-
md.ext.insert(SyntectSettings(theme));
47+
md.ext.insert(SyntectSettings(
48+
SyntectMode::InlineStyles { theme }
49+
));
50+
}
51+
52+
/// Generate spans with css classes applied
53+
///
54+
/// This is an alternative to using a theme. You are responsible for including a style sheet.
55+
pub fn use_css_classes(md: &mut MarkdownIt, class_style: ClassStyle) {
56+
md.ext_insert(SyntectSettings(
57+
SyntectMode::CssClasses { class_style }
58+
));
3959
}
4060

4161
pub struct SyntectRule;
4262
impl CoreRule for SyntectRule {
4363
fn run(root: &mut Node, md: &MarkdownIt) {
4464
let ss = SyntaxSet::load_defaults_newlines();
4565
let ts = ThemeSet::load_defaults();
46-
let theme = &ts.themes[md.ext.get::<SyntectSettings>().copied().unwrap_or_default().0];
66+
let mode = match md.ext.get::<SyntectSettings>().copied().unwrap_or_default().0 {
67+
SyntectMode::InlineStyles {theme} => Some(&ts.themes[theme]),
68+
SyntectMode::CssClasses => None
69+
};
4770

4871
root.walk_mut(|node, _| {
4972
let mut content = None;
@@ -63,7 +86,16 @@ impl CoreRule for SyntectRule {
6386
}
6487
let syntax = syntax.unwrap_or_else(|| ss.find_syntax_plain_text());
6588

66-
let html = highlighted_html_for_string(content, &ss, syntax, theme);
89+
let html = match mode {
90+
SyntectMode::InlineStyles { theme } => highlighted_html_for_string(content, &ss, syntax, &ts.themes[theme]),
91+
SyntectMode::CssClasses { class_style } => {
92+
let mut html_generator = ClassedHTMLGenerator::new_with_class_style(syntax, &ss, class_style);
93+
for line in LinesWithEndings::from(content) {
94+
html_generator.parse_html_for_line_which_includes_newline(line);
95+
}
96+
Ok(html_generator.finalize())
97+
}
98+
};
6799

68100
if let Ok(html) = html {
69101
node.replace(SyntectSnippet { html });

0 commit comments

Comments
 (0)