@@ -2,7 +2,8 @@ use std::path::Path;
22use syntect:: easy:: HighlightLines ;
33use syntect:: highlighting:: ThemeSet ;
44use syntect:: html:: {
5- IncludeBackground , append_highlighted_html_for_styled_line, start_highlighted_html_snippet,
5+ ClassStyle , ClassedHTMLGenerator , IncludeBackground , append_highlighted_html_for_styled_line,
6+ css_for_theme_with_class_style, start_highlighted_html_snippet,
67} ;
78use syntect:: parsing:: { SyntaxReference , SyntaxSet } ;
89use syntect:: util:: LinesWithEndings ;
@@ -16,6 +17,8 @@ pub struct Syntax {
1617 default_theme : Option < String > ,
1718}
1819
20+ const CSS_THEME : & str = "css" ;
21+
1922impl Syntax {
2023 pub fn new ( ) -> Self {
2124 Self {
@@ -31,12 +34,30 @@ impl Syntax {
3134 self . syntax_set = builder. build ( ) ;
3235 }
3336
37+ pub fn css_theme_name ( ) -> & ' static str {
38+ CSS_THEME
39+ }
40+
3441 pub fn has_theme ( & self , name : & str ) -> bool {
35- self . theme_set . themes . contains_key ( name)
42+ name == CSS_THEME || self . theme_set . themes . contains_key ( name)
3643 }
3744
3845 pub fn themes ( & self ) -> impl Iterator < Item = String > + ' _ {
39- self . theme_set . themes . keys ( ) . cloned ( )
46+ let mut themes: Vec < _ > = self . theme_set . themes . keys ( ) . cloned ( ) . collect ( ) ;
47+ themes. push ( CSS_THEME . to_string ( ) ) ;
48+ themes. sort_by_key ( |a| a. to_ascii_lowercase ( ) ) ;
49+
50+ themes. into_iter ( )
51+ }
52+
53+ fn css_class_style ( ) -> ClassStyle {
54+ ClassStyle :: SpacedPrefixed { prefix : "c-" }
55+ }
56+
57+ /// Get the content of a css file to apply the specified color theme when using the 'css' theme
58+ pub fn css_for_theme ( & self , name : & str ) -> String {
59+ let theme = & self . theme_set . themes [ name] ;
60+ css_for_theme_with_class_style ( theme, Self :: css_class_style ( ) ) . unwrap ( )
4061 }
4162
4263 pub fn syntaxes ( & self ) -> impl Iterator < Item = String > + ' _ {
@@ -66,32 +87,63 @@ impl Syntax {
6687 self . default_theme = Some ( theme. into ( ) ) ;
6788 }
6889
90+ fn format_inline_theme ( & self , code : & str , theme : & str , syntax : & SyntaxReference ) -> String {
91+ let theme = & self . theme_set . themes [ theme] ;
92+
93+ // Essentially the same as `syntect::html::highlighted_html_for_string`,
94+ // but adding <code> tags between the <pre> tags
95+ // See: https://docs.rs/syntect/5.0.0/src/syntect/html.rs.html#269
96+ let mut highlighter = HighlightLines :: new ( syntax, theme) ;
97+ let ( mut output, bg) = start_highlighted_html_snippet ( theme) ;
98+ output. push_str ( "<code>" ) ;
99+
100+ for line in LinesWithEndings :: from ( code) {
101+ let regions = highlighter. highlight_line ( line, & self . syntax_set ) . unwrap ( ) ;
102+ append_highlighted_html_for_styled_line (
103+ & regions[ ..] ,
104+ IncludeBackground :: IfDifferent ( bg) ,
105+ & mut output,
106+ )
107+ . unwrap ( ) ;
108+ }
109+
110+ output. push_str ( "</code></pre>\n " ) ;
111+ output
112+ }
113+
114+ fn format_css_theme ( & self , code : & str , lang : Option < & str > , syntax : & SyntaxReference ) -> String {
115+ let mut html_generator = ClassedHTMLGenerator :: new_with_class_style (
116+ syntax,
117+ & self . syntax_set ,
118+ Self :: css_class_style ( ) ,
119+ ) ;
120+
121+ for line in LinesWithEndings :: from ( code) {
122+ html_generator
123+ . parse_html_for_line_which_includes_newline ( line)
124+ . unwrap ( ) ;
125+ }
126+
127+ let language_class = lang. map ( |l| format ! ( "language-{l} " ) ) . unwrap_or_default ( ) ;
128+ let mut output = format ! ( "<pre class=\" {language_class}highlighter-syntect\" >" ) ;
129+ output. push_str ( "<code class=\" highlight\" >" ) ;
130+ output. push_str ( & html_generator. finalize ( ) ) ;
131+ output. push_str ( "</code></pre>" ) ;
132+
133+ output
134+ }
135+
69136 pub fn format ( & self , code : & str , lang : Option < & str > , theme : Option < & str > ) -> String {
70137 if let Some ( theme) = theme. or_else ( || self . default_theme ( ) ) {
71- let theme = & self . theme_set . themes [ theme] ;
72-
73138 let syntax = lang
74139 . and_then ( |l| self . syntax_set . find_syntax_by_token ( l) )
75140 . unwrap_or_else ( || self . syntax_set . find_syntax_plain_text ( ) ) ;
76141
77- // Essentially the same as `syntect::html::highlighted_html_for_string`,
78- // but adding <code> tags between the <pre> tags
79- // See: https://docs.rs/syntect/5.0.0/src/syntect/html.rs.html#269
80- let mut highlighter = HighlightLines :: new ( syntax, theme) ;
81- let ( mut output, bg) = start_highlighted_html_snippet ( theme) ;
82- output. push_str ( "<code>" ) ;
83-
84- for line in LinesWithEndings :: from ( code) {
85- let regions = highlighter. highlight_line ( line, & self . syntax_set ) . unwrap ( ) ;
86- append_highlighted_html_for_styled_line (
87- & regions[ ..] ,
88- IncludeBackground :: IfDifferent ( bg) ,
89- & mut output,
90- )
91- . unwrap ( ) ;
142+ if theme == CSS_THEME {
143+ self . format_css_theme ( code, lang, syntax)
144+ } else {
145+ self . format_inline_theme ( code, theme, syntax)
92146 }
93- output. push_str ( "</code></pre>\n " ) ;
94- output
95147 } else {
96148 crate :: Raw :: new ( ) . format ( code, lang, theme)
97149 }
0 commit comments