Skip to content

Commit 166a972

Browse files
authored
Merge pull request #2833 from ehuss/static-regex
Add a helper for defining a regex
2 parents f2db034 + e3bb655 commit 166a972

File tree

6 files changed

+50
-49
lines changed

6 files changed

+50
-49
lines changed

crates/mdbook-core/src/utils/mod.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
//! Various helpers and utilities.
22
33
use anyhow::Error;
4-
use regex::Regex;
54
use std::borrow::Cow;
65
use std::collections::HashMap;
76
use std::fmt::Write;
8-
use std::sync::LazyLock;
97
use tracing::error;
108

119
pub mod fs;
@@ -19,10 +17,23 @@ pub use self::string::{
1917
take_rustdoc_include_lines,
2018
};
2119

20+
/// Defines a `static` with a [`regex::Regex`].
21+
#[macro_export]
22+
macro_rules! static_regex {
23+
($name:ident, $regex:literal) => {
24+
static $name: std::sync::LazyLock<regex::Regex> =
25+
std::sync::LazyLock::new(|| regex::Regex::new($regex).unwrap());
26+
};
27+
($name:ident, bytes, $regex:literal) => {
28+
static $name: std::sync::LazyLock<regex::bytes::Regex> =
29+
std::sync::LazyLock::new(|| regex::bytes::Regex::new($regex).unwrap());
30+
};
31+
}
32+
2233
/// Replaces multiple consecutive whitespace characters with a single space character.
2334
pub fn collapse_whitespace(text: &str) -> Cow<'_, str> {
24-
static RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"\s\s+").unwrap());
25-
RE.replace_all(text, " ")
35+
static_regex!(WS, r"\s\s+");
36+
WS.replace_all(text, " ")
2637
}
2738

2839
/// Convert the given string to a valid HTML element ID.
@@ -48,7 +59,7 @@ fn id_from_content(content: &str) -> String {
4859
let mut content = content.to_string();
4960

5061
// Skip any tags or html-encoded stuff
51-
static HTML: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(<.*?>)").unwrap());
62+
static_regex!(HTML, r"(<.*?>)");
5263
content = HTML.replace_all(&content, "").into();
5364
const REPL_SUB: &[&str] = &["&lt;", "&gt;", "&amp;", "&#39;", "&quot;"];
5465
for sub in REPL_SUB {

crates/mdbook-core/src/utils/string.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
use regex::Regex;
1+
use crate::static_regex;
22
use std::ops::Bound::{Excluded, Included, Unbounded};
33
use std::ops::RangeBounds;
4-
use std::sync::LazyLock;
54

65
/// Take a range of lines from a string.
76
pub fn take_lines<R: RangeBounds<usize>>(s: &str, range: R) -> String {
@@ -24,10 +23,8 @@ pub fn take_lines<R: RangeBounds<usize>>(s: &str, range: R) -> String {
2423
}
2524
}
2625

27-
static ANCHOR_START: LazyLock<Regex> =
28-
LazyLock::new(|| Regex::new(r"ANCHOR:\s*(?P<anchor_name>[\w_-]+)").unwrap());
29-
static ANCHOR_END: LazyLock<Regex> =
30-
LazyLock::new(|| Regex::new(r"ANCHOR_END:\s*(?P<anchor_name>[\w_-]+)").unwrap());
26+
static_regex!(ANCHOR_START, r"ANCHOR:\s*(?P<anchor_name>[\w_-]+)");
27+
static_regex!(ANCHOR_END, r"ANCHOR_END:\s*(?P<anchor_name>[\w_-]+)");
3128

3229
/// Take anchored lines from a string.
3330
/// Lines containing anchor are ignored.

crates/mdbook-driver/src/builtin_preprocessors/index.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use anyhow::Result;
22
use mdbook_core::book::{Book, BookItem};
3+
use mdbook_core::static_regex;
34
use mdbook_preprocessor::{Preprocessor, PreprocessorContext};
4-
use regex::Regex;
5-
use std::{path::Path, sync::LazyLock};
5+
use std::path::Path;
66
use tracing::warn;
77

88
/// A preprocessor for converting file name `README.md` to `index.md` since
@@ -68,9 +68,9 @@ fn warn_readme_name_conflict<P: AsRef<Path>>(readme_path: P, index_path: P) {
6868
}
6969

7070
fn is_readme_file<P: AsRef<Path>>(path: P) -> bool {
71-
static RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(?i)^readme$").unwrap());
71+
static_regex!(README, r"(?i)^readme$");
7272

73-
RE.is_match(
73+
README.is_match(
7474
path.as_ref()
7575
.file_stem()
7676
.and_then(std::ffi::OsStr::to_str)

crates/mdbook-driver/src/builtin_preprocessors/links.rs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
use anyhow::{Context, Result};
22
use mdbook_core::book::{Book, BookItem};
3+
use mdbook_core::static_regex;
34
use mdbook_core::utils::{
45
take_anchored_lines, take_lines, take_rustdoc_include_anchored_lines,
56
take_rustdoc_include_lines,
67
};
78
use mdbook_preprocessor::{Preprocessor, PreprocessorContext};
8-
use regex::{CaptureMatches, Captures, Regex};
9+
use regex::{CaptureMatches, Captures};
910
use std::fs;
1011
use std::ops::{Bound, Range, RangeBounds, RangeFrom, RangeFull, RangeTo};
1112
use std::path::{Path, PathBuf};
12-
use std::sync::LazyLock;
1313
use tracing::{error, warn};
1414

1515
const ESCAPE_CHAR: char = '\\';
@@ -408,23 +408,19 @@ impl<'a> Iterator for LinkIter<'a> {
408408
}
409409

410410
fn find_links(contents: &str) -> LinkIter<'_> {
411-
// lazily compute following regex
412-
// r"\\\{\{#.*\}\}|\{\{#([a-zA-Z0-9]+)\s*([^}]+)\}\}")?;
413-
static RE: LazyLock<Regex> = LazyLock::new(|| {
414-
Regex::new(
415-
r"(?x) # insignificant whitespace mode
411+
static_regex!(
412+
LINK,
413+
r"(?x) # insignificant whitespace mode
416414
\\\{\{\#.*\}\} # match escaped link
417415
| # or
418416
\{\{\s* # link opening parens and whitespace
419417
\#([a-zA-Z0-9_]+) # link type
420418
\s+ # separating whitespace
421419
([^}]+) # link target path and space separated properties
422-
\}\} # link closing parens",
423-
)
424-
.unwrap()
425-
});
420+
\}\} # link closing parens"
421+
);
426422

427-
LinkIter(RE.captures_iter(contents))
423+
LinkIter(LINK.captures_iter(contents))
428424
}
429425

430426
#[cfg(test)]

crates/mdbook-html/src/html_handlebars/hbs_renderer.rs

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,17 @@ use anyhow::{Context, Result, bail};
55
use handlebars::Handlebars;
66
use mdbook_core::book::{Book, BookItem, Chapter};
77
use mdbook_core::config::{BookConfig, Code, Config, HtmlConfig, Playground, RustEdition};
8-
use mdbook_core::utils;
98
use mdbook_core::utils::fs::get_404_output_file;
9+
use mdbook_core::{static_regex, utils};
1010
use mdbook_markdown::render_markdown;
1111
use mdbook_renderer::{RenderContext, Renderer};
12-
use regex::{Captures, Regex};
12+
use regex::Captures;
1313
use serde_json::json;
1414
use std::borrow::Cow;
1515
use std::collections::BTreeMap;
1616
use std::collections::HashMap;
1717
use std::fs::{self, File};
1818
use std::path::{Path, PathBuf};
19-
use std::sync::LazyLock;
2019
use tracing::error;
2120
use tracing::{debug, info, trace, warn};
2221

@@ -702,9 +701,10 @@ fn make_data(
702701
/// Goes through the rendered HTML, making sure all header tags have
703702
/// an anchor respectively so people can link to sections directly.
704703
fn build_header_links(html: &str) -> String {
705-
static BUILD_HEADER_LINKS: LazyLock<Regex> = LazyLock::new(|| {
706-
Regex::new(r#"<h(\d)(?: id="([^"]+)")?(?: class="([^"]+)")?>(.*?)</h\d>"#).unwrap()
707-
});
704+
static_regex!(
705+
BUILD_HEADER_LINKS,
706+
r#"<h(\d)(?: id="([^"]+)")?(?: class="([^"]+)")?>(.*?)</h\d>"#
707+
);
708708
static IGNORE_CLASS: &[&str] = &["menu-title", "mdbook-help-title"];
709709

710710
let mut id_counter = HashMap::new();
@@ -758,8 +758,8 @@ fn insert_link_into_header(
758758
fn convert_fontawesome(html: &str) -> String {
759759
use font_awesome_as_a_crate as fa;
760760

761-
let regex = Regex::new(r##"<i([^>]+)class="([^"]+)"([^>]*)></i>"##).unwrap();
762-
regex
761+
static_regex!(FA_RE, r#"<i([^>]+)class="([^"]+)"([^>]*)></i>"#);
762+
FA_RE
763763
.replace_all(html, |caps: &Captures<'_>| {
764764
let text = &caps[0];
765765
let before = &caps[1];
@@ -811,8 +811,7 @@ fn convert_fontawesome(html: &str) -> String {
811811
// ```
812812
// This function replaces all commas by spaces in the code block classes
813813
fn fix_code_blocks(html: &str) -> String {
814-
static FIX_CODE_BLOCKS: LazyLock<Regex> =
815-
LazyLock::new(|| Regex::new(r##"<code([^>]+)class="([^"]+)"([^>]*)>"##).unwrap());
814+
static_regex!(FIX_CODE_BLOCKS, r#"<code([^>]+)class="([^"]+)"([^>]*)>"#);
816815

817816
FIX_CODE_BLOCKS
818817
.replace_all(html, |caps: &Captures<'_>| {
@@ -825,8 +824,10 @@ fn fix_code_blocks(html: &str) -> String {
825824
.into_owned()
826825
}
827826

828-
static CODE_BLOCK_RE: LazyLock<Regex> =
829-
LazyLock::new(|| Regex::new(r##"((?s)<code[^>]?class="([^"]+)".*?>(.*?)</code>)"##).unwrap());
827+
static_regex!(
828+
CODE_BLOCK_RE,
829+
r#"((?s)<code[^>]?class="([^"]+)".*?>(.*?)</code>)"#
830+
);
830831

831832
fn add_playground_pre(
832833
html: &str,
@@ -895,10 +896,8 @@ fn add_playground_pre(
895896
/// Modifies all `<code>` blocks to convert "hidden" lines and to wrap them in
896897
/// a `<span class="boring">`.
897898
fn hide_lines(html: &str, code_config: &Code) -> String {
898-
static LANGUAGE_REGEX: LazyLock<Regex> =
899-
LazyLock::new(|| Regex::new(r"\blanguage-(\w+)\b").unwrap());
900-
static HIDELINES_REGEX: LazyLock<Regex> =
901-
LazyLock::new(|| Regex::new(r"\bhidelines=(\S+)").unwrap());
899+
static_regex!(LANGUAGE_REGEX, r"\blanguage-(\w+)\b");
900+
static_regex!(HIDELINES_REGEX, r"\bhidelines=(\S+)");
902901

903902
CODE_BLOCK_RE
904903
.replace_all(html, |caps: &Captures<'_>| {
@@ -939,8 +938,7 @@ fn hide_lines(html: &str, code_config: &Code) -> String {
939938
}
940939

941940
fn hide_lines_rust(content: &str) -> String {
942-
static BORING_LINES_REGEX: LazyLock<Regex> =
943-
LazyLock::new(|| Regex::new(r"^(\s*)#(.?)(.*)$").unwrap());
941+
static_regex!(BORING_LINES_REGEX, r"^(\s*)#(.?)(.*)$");
944942

945943
let mut result = String::with_capacity(content.len());
946944
let mut lines = content.lines().peekable();

crates/mdbook-html/src/html_handlebars/static_files.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ use super::helpers::resources::ResourceHelper;
44
use crate::theme::{self, Theme, playground_editor};
55
use anyhow::{Context, Result};
66
use mdbook_core::config::HtmlConfig;
7+
use mdbook_core::static_regex;
78
use mdbook_core::utils;
89
use std::borrow::Cow;
910
use std::collections::HashMap;
1011
use std::fs::{self, File};
1112
use std::path::{Path, PathBuf};
12-
use std::sync::LazyLock;
1313
use tracing::debug;
1414

1515
/// Map static files to their final names and contents.
@@ -191,11 +191,10 @@ impl StaticFiles {
191191

192192
pub(super) fn write_files(self, destination: &Path) -> Result<ResourceHelper> {
193193
use mdbook_core::utils::fs::write_file;
194-
use regex::bytes::{Captures, Regex};
194+
use regex::bytes::Captures;
195195
// The `{{ resource "name" }}` directive in static resources look like
196196
// handlebars syntax, even if they technically aren't.
197-
static RESOURCE: LazyLock<Regex> =
198-
LazyLock::new(|| Regex::new(r#"\{\{ resource "([^"]+)" \}\}"#).unwrap());
197+
static_regex!(RESOURCE, bytes, r#"\{\{ resource "([^"]+)" \}\}"#);
199198
fn replace_all<'a>(
200199
hash_map: &HashMap<String, String>,
201200
data: &'a [u8],

0 commit comments

Comments
 (0)