11//! Syntax highlighting for code blocks
22use 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 ;
45use syntect:: parsing:: SyntaxSet ;
6+ use syntect:: util:: LinesWithEndings ;
57
68use crate :: parser:: core:: CoreRule ;
79use 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 ) ;
2533impl MarkdownItExt for SyntectSettings { }
2634
2735impl Default for SyntectSettings {
2836 fn default ( ) -> Self {
29- Self ( "InspiredGitHub" )
37+ Self ( SyntectMode :: InlineStyles { theme : "InspiredGitHub" } )
3038 }
3139}
3240
3341pub fn add ( md : & mut MarkdownIt ) {
3442 md. add_rule :: < SyntectRule > ( ) ;
3543}
3644
45+ /// Use inline styles with the given theme
3746pub 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
4161pub struct SyntectRule ;
4262impl 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