From 7fcacf3386f9f953b342a2584e086b71098d778f Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 20 Sep 2025 17:55:12 -0700 Subject: [PATCH] Move theme copy to the Theme type and reduce visibility This moves the code for copying the theme to the theme directory to the Theme type so that the code lives closer to the data definition. This also then reduces the public API surface of the Theme to give a little more flexibility for updating it in the future. --- crates/mdbook-driver/src/init.rs | 34 +---- crates/mdbook-html/src/theme/fonts.rs | 8 +- crates/mdbook-html/src/theme/mod.rs | 121 +++++++++++------- .../src/theme/playground_editor.rs | 12 +- crates/mdbook-html/src/theme/searcher.rs | 7 +- 5 files changed, 95 insertions(+), 87 deletions(-) diff --git a/crates/mdbook-driver/src/init.rs b/crates/mdbook-driver/src/init.rs index 83785cef..badd24c5 100644 --- a/crates/mdbook-driver/src/init.rs +++ b/crates/mdbook-driver/src/init.rs @@ -4,7 +4,7 @@ use super::MDBook; use anyhow::{Context, Result}; use mdbook_core::config::Config; use mdbook_core::utils::fs; -use mdbook_html::theme; +use mdbook_html::theme::Theme; use std::path::PathBuf; use tracing::{debug, error, info, trace}; @@ -109,37 +109,7 @@ impl BookBuilder { debug!("Copying theme"); let html_config = self.config.html_config().unwrap_or_default(); - let themedir = html_config.theme_dir(&self.root); - - fs::write(themedir.join("book.js"), theme::JS)?; - fs::write(themedir.join("favicon.png"), theme::FAVICON_PNG)?; - fs::write(themedir.join("favicon.svg"), theme::FAVICON_SVG)?; - fs::write(themedir.join("highlight.css"), theme::HIGHLIGHT_CSS)?; - fs::write(themedir.join("highlight.js"), theme::HIGHLIGHT_JS)?; - fs::write(themedir.join("index.hbs"), theme::INDEX)?; - - let cssdir = themedir.join("css"); - - fs::write(cssdir.join("general.css"), theme::GENERAL_CSS)?; - fs::write(cssdir.join("chrome.css"), theme::CHROME_CSS)?; - fs::write(cssdir.join("variables.css"), theme::VARIABLES_CSS)?; - if html_config.print.enable { - fs::write(cssdir.join("print.css"), theme::PRINT_CSS)?; - } - - let fonts_dir = themedir.join("fonts"); - fs::write(fonts_dir.join("fonts.css"), theme::fonts::CSS)?; - for (file_name, contents) in theme::fonts::LICENSES { - fs::write(themedir.join(file_name), contents)?; - } - for (file_name, contents) in theme::fonts::OPEN_SANS.iter() { - fs::write(themedir.join(file_name), contents)?; - } - fs::write( - themedir.join(theme::fonts::SOURCE_CODE_PRO.0), - theme::fonts::SOURCE_CODE_PRO.1, - )?; - + Theme::copy_theme(&html_config, &self.root)?; Ok(()) } diff --git a/crates/mdbook-html/src/theme/fonts.rs b/crates/mdbook-html/src/theme/fonts.rs index dc8c8c08..3cf13d3a 100644 --- a/crates/mdbook-html/src/theme/fonts.rs +++ b/crates/mdbook-html/src/theme/fonts.rs @@ -1,6 +1,6 @@ -pub static CSS: &[u8] = include_bytes!("../../front-end/fonts/fonts.css"); +pub(crate) static CSS: &[u8] = include_bytes!("../../front-end/fonts/fonts.css"); // An array of (file_name, file_contents) pairs -pub static LICENSES: [(&str, &[u8]); 2] = [ +pub(crate) static LICENSES: [(&str, &[u8]); 2] = [ ( "fonts/OPEN-SANS-LICENSE.txt", include_bytes!("../../front-end/fonts/OPEN-SANS-LICENSE.txt"), @@ -11,7 +11,7 @@ pub static LICENSES: [(&str, &[u8]); 2] = [ ), ]; // An array of (file_name, file_contents) pairs -pub static OPEN_SANS: [(&str, &[u8]); 10] = [ +pub(crate) static OPEN_SANS: [(&str, &[u8]); 10] = [ ( "fonts/open-sans-v17-all-charsets-300.woff2", include_bytes!("../../front-end/fonts/open-sans-v17-all-charsets-300.woff2"), @@ -55,7 +55,7 @@ pub static OPEN_SANS: [(&str, &[u8]); 10] = [ ]; // A (file_name, file_contents) pair -pub static SOURCE_CODE_PRO: (&str, &[u8]) = ( +pub(crate) static SOURCE_CODE_PRO: (&str, &[u8]) = ( "fonts/source-code-pro-v11-all-charsets-500.woff2", include_bytes!("../../front-end/fonts/source-code-pro-v11-all-charsets-500.woff2"), ); diff --git a/crates/mdbook-html/src/theme/mod.rs b/crates/mdbook-html/src/theme/mod.rs index f40fbb6b..c55a30ef 100644 --- a/crates/mdbook-html/src/theme/mod.rs +++ b/crates/mdbook-html/src/theme/mod.rs @@ -1,32 +1,34 @@ -#![allow(missing_docs)] +//! Support for theme files. use anyhow::Result; +use mdbook_core::config::HtmlConfig; +use mdbook_core::utils::fs; use std::path::{Path, PathBuf}; use tracing::{info, warn}; -pub mod fonts; -pub mod playground_editor; +pub(crate) mod fonts; +pub(crate) mod playground_editor; #[cfg(feature = "search")] -pub mod searcher; +pub(crate) mod searcher; -pub static INDEX: &[u8] = include_bytes!("../../front-end/templates/index.hbs"); -pub static HEAD: &[u8] = include_bytes!("../../front-end/templates/head.hbs"); -pub static REDIRECT: &[u8] = include_bytes!("../../front-end/templates/redirect.hbs"); -pub static HEADER: &[u8] = include_bytes!("../../front-end/templates/header.hbs"); -pub static TOC_JS: &[u8] = include_bytes!("../../front-end/templates/toc.js.hbs"); -pub static TOC_HTML: &[u8] = include_bytes!("../../front-end/templates/toc.html.hbs"); -pub static CHROME_CSS: &[u8] = include_bytes!("../../front-end/css/chrome.css"); -pub static GENERAL_CSS: &[u8] = include_bytes!("../../front-end/css/general.css"); -pub static PRINT_CSS: &[u8] = include_bytes!("../../front-end/css/print.css"); -pub static VARIABLES_CSS: &[u8] = include_bytes!("../../front-end/css/variables.css"); -pub static FAVICON_PNG: &[u8] = include_bytes!("../../front-end/images/favicon.png"); -pub static FAVICON_SVG: &[u8] = include_bytes!("../../front-end/images/favicon.svg"); -pub static JS: &[u8] = include_bytes!("../../front-end/js/book.js"); -pub static HIGHLIGHT_JS: &[u8] = include_bytes!("../../front-end/js/highlight.js"); -pub static TOMORROW_NIGHT_CSS: &[u8] = include_bytes!("../../front-end/css/tomorrow-night.css"); -pub static HIGHLIGHT_CSS: &[u8] = include_bytes!("../../front-end/css/highlight.css"); -pub static AYU_HIGHLIGHT_CSS: &[u8] = include_bytes!("../../front-end/css/ayu-highlight.css"); -pub static CLIPBOARD_JS: &[u8] = include_bytes!("../../front-end/js/clipboard.min.js"); +static INDEX: &[u8] = include_bytes!("../../front-end/templates/index.hbs"); +static HEAD: &[u8] = include_bytes!("../../front-end/templates/head.hbs"); +static REDIRECT: &[u8] = include_bytes!("../../front-end/templates/redirect.hbs"); +static HEADER: &[u8] = include_bytes!("../../front-end/templates/header.hbs"); +static TOC_JS: &[u8] = include_bytes!("../../front-end/templates/toc.js.hbs"); +static TOC_HTML: &[u8] = include_bytes!("../../front-end/templates/toc.html.hbs"); +static CHROME_CSS: &[u8] = include_bytes!("../../front-end/css/chrome.css"); +static GENERAL_CSS: &[u8] = include_bytes!("../../front-end/css/general.css"); +static PRINT_CSS: &[u8] = include_bytes!("../../front-end/css/print.css"); +static VARIABLES_CSS: &[u8] = include_bytes!("../../front-end/css/variables.css"); +static FAVICON_PNG: &[u8] = include_bytes!("../../front-end/images/favicon.png"); +static FAVICON_SVG: &[u8] = include_bytes!("../../front-end/images/favicon.svg"); +static JS: &[u8] = include_bytes!("../../front-end/js/book.js"); +static HIGHLIGHT_JS: &[u8] = include_bytes!("../../front-end/js/highlight.js"); +static TOMORROW_NIGHT_CSS: &[u8] = include_bytes!("../../front-end/css/tomorrow-night.css"); +static HIGHLIGHT_CSS: &[u8] = include_bytes!("../../front-end/css/highlight.css"); +static AYU_HIGHLIGHT_CSS: &[u8] = include_bytes!("../../front-end/css/ayu-highlight.css"); +static CLIPBOARD_JS: &[u8] = include_bytes!("../../front-end/js/clipboard.min.js"); /// The `Theme` struct should be used instead of the static variables because /// the `new()` method will look if the user has a theme directory in their @@ -35,28 +37,27 @@ pub static CLIPBOARD_JS: &[u8] = include_bytes!("../../front-end/js/clipboard.mi /// You should only ever use the static variables directly if you want to /// override the user's theme with the defaults. #[derive(Debug, PartialEq)] -#[non_exhaustive] pub struct Theme { - pub index: Vec, - pub head: Vec, - pub redirect: Vec, - pub header: Vec, - pub toc_js: Vec, - pub toc_html: Vec, - pub chrome_css: Vec, - pub general_css: Vec, - pub print_css: Vec, - pub variables_css: Vec, - pub fonts_css: Option>, - pub font_files: Vec, - pub favicon_png: Option>, - pub favicon_svg: Option>, - pub js: Vec, - pub highlight_css: Vec, - pub tomorrow_night_css: Vec, - pub ayu_highlight_css: Vec, - pub highlight_js: Vec, - pub clipboard_js: Vec, + pub(crate) index: Vec, + pub(crate) head: Vec, + pub(crate) redirect: Vec, + pub(crate) header: Vec, + pub(crate) toc_js: Vec, + pub(crate) toc_html: Vec, + pub(crate) chrome_css: Vec, + pub(crate) general_css: Vec, + pub(crate) print_css: Vec, + pub(crate) variables_css: Vec, + pub(crate) fonts_css: Option>, + pub(crate) font_files: Vec, + pub(crate) favicon_png: Option>, + pub(crate) favicon_svg: Option>, + pub(crate) js: Vec, + pub(crate) highlight_css: Vec, + pub(crate) tomorrow_night_css: Vec, + pub(crate) ayu_highlight_css: Vec, + pub(crate) highlight_js: Vec, + pub(crate) clipboard_js: Vec, } impl Theme { @@ -160,6 +161,40 @@ impl Theme { theme } + + /// Copies the default theme files to the theme directory. + pub fn copy_theme(html_config: &HtmlConfig, root: &Path) -> Result<()> { + let themedir = html_config.theme_dir(root); + + fs::write(themedir.join("book.js"), JS)?; + fs::write(themedir.join("favicon.png"), FAVICON_PNG)?; + fs::write(themedir.join("favicon.svg"), FAVICON_SVG)?; + fs::write(themedir.join("highlight.css"), HIGHLIGHT_CSS)?; + fs::write(themedir.join("highlight.js"), HIGHLIGHT_JS)?; + fs::write(themedir.join("index.hbs"), INDEX)?; + + let cssdir = themedir.join("css"); + + fs::write(cssdir.join("general.css"), GENERAL_CSS)?; + fs::write(cssdir.join("chrome.css"), CHROME_CSS)?; + fs::write(cssdir.join("variables.css"), VARIABLES_CSS)?; + if html_config.print.enable { + fs::write(cssdir.join("print.css"), PRINT_CSS)?; + } + + fs::write(themedir.join("fonts").join("fonts.css"), fonts::CSS)?; + for (file_name, contents) in fonts::LICENSES { + fs::write(themedir.join(file_name), contents)?; + } + for (file_name, contents) in fonts::OPEN_SANS.iter() { + fs::write(themedir.join(file_name), contents)?; + } + fs::write( + themedir.join(fonts::SOURCE_CODE_PRO.0), + fonts::SOURCE_CODE_PRO.1, + )?; + Ok(()) + } } impl Default for Theme { diff --git a/crates/mdbook-html/src/theme/playground_editor.rs b/crates/mdbook-html/src/theme/playground_editor.rs index c2462e2f..2fd385ac 100644 --- a/crates/mdbook-html/src/theme/playground_editor.rs +++ b/crates/mdbook-html/src/theme/playground_editor.rs @@ -1,8 +1,10 @@ //! Theme dependencies for the playground editor. -pub static JS: &[u8] = include_bytes!("../../front-end/playground_editor/editor.js"); -pub static ACE_JS: &[u8] = include_bytes!("../../front-end/playground_editor/ace.js"); -pub static MODE_RUST_JS: &[u8] = include_bytes!("../../front-end/playground_editor/mode-rust.js"); -pub static THEME_DAWN_JS: &[u8] = include_bytes!("../../front-end/playground_editor/theme-dawn.js"); -pub static THEME_TOMORROW_NIGHT_JS: &[u8] = +pub(crate) static JS: &[u8] = include_bytes!("../../front-end/playground_editor/editor.js"); +pub(crate) static ACE_JS: &[u8] = include_bytes!("../../front-end/playground_editor/ace.js"); +pub(crate) static MODE_RUST_JS: &[u8] = + include_bytes!("../../front-end/playground_editor/mode-rust.js"); +pub(crate) static THEME_DAWN_JS: &[u8] = + include_bytes!("../../front-end/playground_editor/theme-dawn.js"); +pub(crate) static THEME_TOMORROW_NIGHT_JS: &[u8] = include_bytes!("../../front-end/playground_editor/theme-tomorrow_night.js"); diff --git a/crates/mdbook-html/src/theme/searcher.rs b/crates/mdbook-html/src/theme/searcher.rs index f1a839b2..79ba6f2d 100644 --- a/crates/mdbook-html/src/theme/searcher.rs +++ b/crates/mdbook-html/src/theme/searcher.rs @@ -1,6 +1,7 @@ //! Theme dependencies for in-browser search. Not included in mdbook when //! the "search" cargo feature is disabled. -pub static JS: &[u8] = include_bytes!("../../front-end/searcher/searcher.js"); -pub static MARK_JS: &[u8] = include_bytes!("../../front-end/searcher/mark.min.js"); -pub static ELASTICLUNR_JS: &[u8] = include_bytes!("../../front-end/searcher/elasticlunr.min.js"); +pub(crate) static JS: &[u8] = include_bytes!("../../front-end/searcher/searcher.js"); +pub(crate) static MARK_JS: &[u8] = include_bytes!("../../front-end/searcher/mark.min.js"); +pub(crate) static ELASTICLUNR_JS: &[u8] = + include_bytes!("../../front-end/searcher/elasticlunr.min.js");