diff --git a/docs/authoring.md b/docs/authoring.md index a465309c8..3c28dd035 100644 --- a/docs/authoring.md +++ b/docs/authoring.md @@ -180,9 +180,15 @@ Admonitions use a style similar to GitHub-flavored markdown, where the style nam > [!NOTE] > This is a note. + +> [!EDITION-2024] +> This is an edition-specific difference. + +> [!EXAMPLE] +> This is an example. ``` -The color and styling is defined in [`theme/reference.css`](https://github.com/rust-lang/reference/blob/master/theme/reference.css) and the transformation and icons are in [`mdbook-spec/src/lib.rs`](https://github.com/rust-lang/reference/blob/HEAD/mdbook-spec/src/lib.rs). +The color and styling is defined in [`theme/reference.css`](https://github.com/rust-lang/reference/blob/master/theme/reference.css) and the transformation and icons are in [`mdbook-spec/src/admonitions.rs`](https://github.com/rust-lang/reference/blob/HEAD/mdbook-spec/src/admonitions.rs). ## Style diff --git a/mdbook-spec/src/admonitions.rs b/mdbook-spec/src/admonitions.rs new file mode 100644 index 000000000..8aaf6cf66 --- /dev/null +++ b/mdbook-spec/src/admonitions.rs @@ -0,0 +1,106 @@ +//! Support for admonitions using markdown blockquotes. +//! +//! To add support for a new admonition: +//! +//! 1. Modify the [`admonitions`] function below to include an icon. +//! 2. Modify `theme/reference.css` to set the color for the different themes. +//! Look at one of the other admonitions as a guide. +//! 3. Update `src/introduction.md` and describe what this new block is for +//! with an example. +//! 4. Update `docs/authoring.md` to show an example of your new admonition. + +use crate::{Diagnostics, warn_or_err}; +use mdbook::book::Chapter; +use regex::{Captures, Regex}; +use std::sync::LazyLock; + +/// The Regex for the syntax for blockquotes that have a specific CSS class, +/// like `> [!WARNING]`. +static ADMONITION_RE: LazyLock = LazyLock::new(|| { + Regex::new(r"(?m)^ *> \[!(?[^]]+)\]\n(?
(?: *>.*\n)+)").unwrap() +}); + +// This icon is from GitHub, MIT License, see https://github.com/primer/octicons +const ICON_NOTE: &str = r#""#; + +// This icon is from GitHub, MIT License, see https://github.com/primer/octicons +const ICON_WARNING: &str = r#""#; + +// This icon is from GitHub, MIT License, see https://github.com/primer/octicons +const ICON_EXAMPLE: &str = r#""#; + +/// Converts blockquotes with special headers into admonitions. +/// +/// The blockquote should look something like: +/// +/// ```markdown +/// > [!WARNING] +/// > ... +/// ``` +/// +/// This will add a `
` around the +/// blockquote so that it can be styled differently, and injects an icon. +/// The actual styling needs to be added in the `reference.css` CSS file. +pub fn admonitions(chapter: &Chapter, diag: &mut Diagnostics) -> String { + ADMONITION_RE + .replace_all(&chapter.content, |caps: &Captures<'_>| { + let lower = caps["admon"].to_lowercase(); + let term = to_initial_case(&caps["admon"]); + let blockquote = &caps["blockquote"]; + let initial_spaces = blockquote.chars().position(|ch| ch != ' ').unwrap_or(0); + let space = &blockquote[..initial_spaces]; + + let format_div = |class, content| { + format!( + "{space}
\n\ + \n\ + {space}>

\ + {content}

\n\ + {space} >\n\ + {blockquote}\n\ + \n\ + {space}
\n", + ) + }; + + if lower.starts_with("edition-") { + let edition = &lower[8..]; + return format_div( + "edition", + format!( + "{edition} Edition differences" + ), + ); + } + + let svg = match lower.as_str() { + "note" => ICON_NOTE, + "warning" => ICON_WARNING, + "example" => ICON_EXAMPLE, + _ => { + warn_or_err!( + diag, + "admonition `{lower}` in {:?} is incorrect or not yet supported", + chapter.path.as_ref().unwrap() + ); + "" + } + }; + format_div( + &lower, + format!( + "\ + {svg}\ + {term}" + ), + ) + }) + .to_string() +} + +fn to_initial_case(s: &str) -> String { + let mut chars = s.chars(); + let first = chars.next().expect("not empty").to_uppercase(); + let rest = chars.as_str().to_lowercase(); + format!("{first}{rest}") +} diff --git a/mdbook-spec/src/lib.rs b/mdbook-spec/src/lib.rs index 0f14819fc..f5799ae0f 100644 --- a/mdbook-spec/src/lib.rs +++ b/mdbook-spec/src/lib.rs @@ -14,17 +14,12 @@ use std::io; use std::ops::Range; use std::path::PathBuf; +mod admonitions; pub mod grammar; mod rules; mod std_links; mod test_links; -/// The Regex for the syntax for blockquotes that have a specific CSS class, -/// like `> [!WARNING]`. -static ADMONITION_RE: Lazy = Lazy::new(|| { - Regex::new(r"(?m)^ *> \[!(?[^]]+)\]\n(?
(?: *>.*\n)+)").unwrap() -}); - /// A primitive regex to find link reference definitions. static MD_LINK_REFERENCE_DEFINITION: Lazy = Lazy::new(|| Regex::new(r"(?m)^\[(?