feat: coloration syntaxique via CSS classes (themeable)
Remplace les styles inline syntect par des classes CSS. Le CSS est généré côté Rust (base16-ocean.dark) et injecté au démarrage via get_syntax_highlight_css. Les thèmes peuvent surcharger .syntax-highlighting et les classes de tokens. Supprime le lien CDN highlight.js inutilisé. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,19 +1,16 @@
|
||||
use comrak::plugins::syntect::SyntectAdapterBuilder;
|
||||
use comrak::{markdown_to_html_with_plugins, Options, Plugins};
|
||||
use syntect::highlighting::ThemeSet;
|
||||
use syntect::html::{css_for_theme_with_class_style, ClassStyle};
|
||||
|
||||
use crate::domain::MarkdownRenderer;
|
||||
|
||||
pub struct ComrakRenderer {
|
||||
pub theme: String,
|
||||
}
|
||||
|
||||
pub struct ComrakPreviewRenderer {
|
||||
pub theme: String,
|
||||
}
|
||||
pub struct ComrakRenderer;
|
||||
pub struct ComrakPreviewRenderer;
|
||||
|
||||
impl MarkdownRenderer for ComrakRenderer {
|
||||
fn render(&self, content: &str) -> String {
|
||||
let adapter = SyntectAdapterBuilder::new().theme(&self.theme).build();
|
||||
let adapter = SyntectAdapterBuilder::new().css().build();
|
||||
let mut options = Options::default();
|
||||
options.extension.table = true;
|
||||
options.extension.strikethrough = true;
|
||||
@@ -27,10 +24,60 @@ impl MarkdownRenderer for ComrakRenderer {
|
||||
|
||||
impl MarkdownRenderer for ComrakPreviewRenderer {
|
||||
fn render(&self, content: &str) -> String {
|
||||
let adapter = SyntectAdapterBuilder::new().theme(&self.theme).build();
|
||||
let adapter = SyntectAdapterBuilder::new().css().build();
|
||||
let options = Options::default();
|
||||
let mut plugins = Plugins::default();
|
||||
plugins.render.codefence_syntax_highlighter = Some(&adapter);
|
||||
markdown_to_html_with_plugins(content, &options, &plugins)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn syntax_css_for_theme(syntect_theme_name: &str) -> String {
|
||||
let ts = ThemeSet::load_defaults();
|
||||
let theme = match ts.themes.get(syntect_theme_name) {
|
||||
Some(t) => t,
|
||||
None => return String::new(),
|
||||
};
|
||||
match css_for_theme_with_class_style(theme, ClassStyle::Spaced) {
|
||||
Ok(css) => css.replace(".code {", ".syntax-highlighting {"),
|
||||
Err(_) => String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn render_outputs_syntax_highlighting_class() {
|
||||
let r = ComrakRenderer;
|
||||
let html = r.render("```rust\nfn main() {}\n```\n");
|
||||
assert!(html.contains("syntax-highlighting"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_outputs_classed_spans() {
|
||||
let r = ComrakRenderer;
|
||||
let html = r.render("```rust\nfn main() {}\n```\n");
|
||||
assert!(html.contains("<span class="));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn syntax_css_known_theme_contains_wrapper() {
|
||||
let css = syntax_css_for_theme("base16-ocean.dark");
|
||||
assert!(!css.is_empty());
|
||||
assert!(css.contains(".syntax-highlighting {"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn syntax_css_known_theme_contains_token_rules() {
|
||||
let css = syntax_css_for_theme("base16-ocean.dark");
|
||||
assert!(css.contains("color:") || css.contains("color :"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn syntax_css_unknown_theme_returns_empty() {
|
||||
let css = syntax_css_for_theme("nonexistent-theme-xyz");
|
||||
assert!(css.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user