From 3958260353a7721049a4a9ada97b83394db9d570 Mon Sep 17 00:00:00 2001 From: Martin Geisler Date: Sun, 11 Sep 2022 00:46:26 +0200 Subject: [PATCH 1/4] Simplify the use of `Option::and_then` I found a few places where `Option::and_then` could be simplified (in my opinion) with `?` or with `match`. --- src/cmd/serve.rs | 3 +- .../html_handlebars/helpers/navigation.rs | 15 +++--- src/renderer/html_handlebars/helpers/toc.rs | 50 +++++++++---------- 3 files changed, 32 insertions(+), 36 deletions(-) diff --git a/src/cmd/serve.rs b/src/cmd/serve.rs index bafbfd52..00eaa46b 100644 --- a/src/cmd/serve.rs +++ b/src/cmd/serve.rs @@ -89,8 +89,7 @@ pub fn execute(args: &ArgMatches) -> Result<()> { let input_404 = book .config .get("output.html.input-404") - .map(toml::Value::as_str) - .and_then(std::convert::identity) // flatten + .and_then(toml::Value::as_str) .map(ToString::to_string); let file_404 = get_404_output_file(&input_404); diff --git a/src/renderer/html_handlebars/helpers/navigation.rs b/src/renderer/html_handlebars/helpers/navigation.rs index f57e9ae9..b184c441 100644 --- a/src/renderer/html_handlebars/helpers/navigation.rs +++ b/src/renderer/html_handlebars/helpers/navigation.rs @@ -148,15 +148,12 @@ fn render( trace!("Render template"); - _h.template() - .ok_or_else(|| RenderError::new("Error with the handlebars template")) - .and_then(|t| { - let local_ctx = Context::wraps(&context)?; - let mut local_rc = rc.clone(); - t.render(r, &local_ctx, &mut local_rc, out) - })?; - - Ok(()) + let t = _h + .template() + .ok_or_else(|| RenderError::new("Error with the handlebars template"))?; + let local_ctx = Context::wraps(&context)?; + let mut local_rc = rc.clone(); + t.render(r, &local_ctx, &mut local_rc, out) } pub fn previous( diff --git a/src/renderer/html_handlebars/helpers/toc.rs b/src/renderer/html_handlebars/helpers/toc.rs index 0884d30a..e96e6ef6 100644 --- a/src/renderer/html_handlebars/helpers/toc.rs +++ b/src/renderer/html_handlebars/helpers/toc.rs @@ -117,35 +117,35 @@ impl HelperDef for RenderToc { } // Link - let path_exists = if let Some(path) = - item.get("path") - .and_then(|p| if p.is_empty() { None } else { Some(p) }) - { - out.write(" { + out.write("")?; + path_exists = true; } - - out.write(">")?; - true - } else { - out.write("
")?; - false - }; + _ => { + out.write("
")?; + path_exists = false; + } + } if !self.no_section_label { // Section does not necessarily exist From 75857fbf739905bd6eac53751ac945bab33b0c99 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 23 Sep 2022 06:05:39 +0800 Subject: [PATCH 2/4] feat: use once_cell instead of lazy_static (#1894) --- Cargo.lock | 8 ++++- Cargo.toml | 2 +- src/preprocess/index.rs | 7 ++--- src/preprocess/links.rs | 25 +++++++-------- src/renderer/html_handlebars/hbs_renderer.rs | 24 ++++++--------- src/renderer/html_handlebars/search.rs | 32 +++++++++----------- src/utils/mod.rs | 23 +++++--------- src/utils/string.rs | 10 +++--- 8 files changed, 61 insertions(+), 70 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 10fae527..90b8073f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -809,10 +809,10 @@ dependencies = [ "futures-util", "gitignore", "handlebars", - "lazy_static", "log", "memchr", "notify", + "once_cell", "opener", "predicates", "pretty_assertions", @@ -997,6 +997,12 @@ dependencies = [ "libc", ] +[[package]] +name = "once_cell" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" + [[package]] name = "opaque-debug" version = "0.2.3" diff --git a/Cargo.toml b/Cargo.toml index b1c095d3..07b2ed78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,9 +20,9 @@ anyhow = "1.0.28" chrono = "0.4" clap = { version = "3.0", features = ["cargo"] } clap_complete = "3.0" +once_cell = "1" env_logger = "0.9.0" handlebars = "4.0" -lazy_static = "1.0" log = "0.4" memchr = "2.0" opener = "0.5" diff --git a/src/preprocess/index.rs b/src/preprocess/index.rs index d8a4e375..004b7eda 100644 --- a/src/preprocess/index.rs +++ b/src/preprocess/index.rs @@ -4,8 +4,8 @@ use std::path::Path; use super::{Preprocessor, PreprocessorContext}; use crate::book::{Book, BookItem}; use crate::errors::*; -use lazy_static::lazy_static; use log::warn; +use once_cell::sync::Lazy; /// A preprocessor for converting file name `README.md` to `index.md` since /// `README.md` is the de facto index file in markdown-based documentation. @@ -68,9 +68,8 @@ fn warn_readme_name_conflict>(readme_path: P, index_path: P) { } fn is_readme_file>(path: P) -> bool { - lazy_static! { - static ref RE: Regex = Regex::new(r"(?i)^readme$").unwrap(); - } + static RE: Lazy = Lazy::new(|| Regex::new(r"(?i)^readme$").unwrap()); + RE.is_match( path.as_ref() .file_stem() diff --git a/src/preprocess/links.rs b/src/preprocess/links.rs index 81575e86..c2c81f52 100644 --- a/src/preprocess/links.rs +++ b/src/preprocess/links.rs @@ -10,8 +10,8 @@ use std::path::{Path, PathBuf}; use super::{Preprocessor, PreprocessorContext}; use crate::book::{Book, BookItem}; -use lazy_static::lazy_static; use log::{error, warn}; +use once_cell::sync::Lazy; const ESCAPE_CHAR: char = '\\'; const MAX_LINK_NESTED_DEPTH: usize = 10; @@ -410,19 +410,20 @@ impl<'a> Iterator for LinkIter<'a> { fn find_links(contents: &str) -> LinkIter<'_> { // lazily compute following regex // r"\\\{\{#.*\}\}|\{\{#([a-zA-Z0-9]+)\s*([^}]+)\}\}")?; - lazy_static! { - static ref RE: Regex = Regex::new( + static RE: Lazy = Lazy::new(|| { + Regex::new( r"(?x) # insignificant whitespace mode - \\\{\{\#.*\}\} # match escaped link - | # or - \{\{\s* # link opening parens and whitespace - \#([a-zA-Z0-9_]+) # link type - \s+ # separating whitespace - ([^}]+) # link target path and space separated properties - \}\} # link closing parens" + \\\{\{\#.*\}\} # match escaped link + | # or + \{\{\s* # link opening parens and whitespace + \#([a-zA-Z0-9_]+) # link type + \s+ # separating whitespace + ([^}]+) # link target path and space separated properties + \}\} # link closing parens", ) - .unwrap(); - } + .unwrap() + }); + LinkIter(RE.captures_iter(contents)) } diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index 9c126feb..710449af 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -14,8 +14,8 @@ use std::path::{Path, PathBuf}; use crate::utils::fs::get_404_output_file; use handlebars::Handlebars; -use lazy_static::lazy_static; use log::{debug, trace, warn}; +use once_cell::sync::Lazy; use regex::{Captures, Regex}; use serde_json::json; @@ -767,9 +767,8 @@ fn make_data( /// Goes through the rendered HTML, making sure all header tags have /// an anchor respectively so people can link to sections directly. fn build_header_links(html: &str) -> String { - lazy_static! { - static ref BUILD_HEADER_LINKS: Regex = Regex::new(r"(.*?)").unwrap(); - } + static BUILD_HEADER_LINKS: Lazy = + Lazy::new(|| Regex::new(r"(.*?)").unwrap()); let mut id_counter = HashMap::new(); @@ -810,10 +809,8 @@ fn insert_link_into_header( // ``` // This function replaces all commas by spaces in the code block classes fn fix_code_blocks(html: &str) -> String { - lazy_static! { - static ref FIX_CODE_BLOCKS: Regex = - Regex::new(r##"]+)class="([^"]+)"([^>]*)>"##).unwrap(); - } + static FIX_CODE_BLOCKS: Lazy = + Lazy::new(|| Regex::new(r##"]+)class="([^"]+)"([^>]*)>"##).unwrap()); FIX_CODE_BLOCKS .replace_all(html, |caps: &Captures<'_>| { @@ -836,10 +833,9 @@ fn add_playground_pre( playground_config: &Playground, edition: Option, ) -> String { - lazy_static! { - static ref ADD_PLAYGROUND_PRE: Regex = - Regex::new(r##"((?s)]?class="([^"]+)".*?>(.*?))"##).unwrap(); - } + static ADD_PLAYGROUND_PRE: Lazy = + Lazy::new(|| Regex::new(r##"((?s)]?class="([^"]+)".*?>(.*?))"##).unwrap()); + ADD_PLAYGROUND_PRE .replace_all(html, |caps: &Captures<'_>| { let text = &caps[1]; @@ -902,9 +898,7 @@ fn add_playground_pre( } fn hide_lines(content: &str) -> String { - lazy_static! { - static ref BORING_LINES_REGEX: Regex = Regex::new(r"^(\s*)#(.?)(.*)$").unwrap(); - } + static BORING_LINES_REGEX: Lazy = Lazy::new(|| Regex::new(r"^(\s*)#(.?)(.*)$").unwrap()); let mut result = String::with_capacity(content.len()); let mut lines = content.lines().peekable(); diff --git a/src/renderer/html_handlebars/search.rs b/src/renderer/html_handlebars/search.rs index f88893a0..a9e2f5ca 100644 --- a/src/renderer/html_handlebars/search.rs +++ b/src/renderer/html_handlebars/search.rs @@ -3,6 +3,7 @@ use std::collections::{HashMap, HashSet}; use std::path::Path; use elasticlunr::{Index, IndexBuilder}; +use once_cell::sync::Lazy; use pulldown_cmark::*; use crate::book::{Book, BookItem}; @@ -10,7 +11,6 @@ use crate::config::Search; use crate::errors::*; use crate::theme::searcher; use crate::utils; -use lazy_static::lazy_static; use log::{debug, warn}; use serde::Serialize; @@ -267,21 +267,19 @@ fn write_to_json(index: Index, search_config: &Search, doc_urls: Vec) -> } fn clean_html(html: &str) -> String { - lazy_static! { - static ref AMMONIA: ammonia::Builder<'static> = { - let mut clean_content = HashSet::new(); - clean_content.insert("script"); - clean_content.insert("style"); - let mut builder = ammonia::Builder::new(); - builder - .tags(HashSet::new()) - .tag_attributes(HashMap::new()) - .generic_attributes(HashSet::new()) - .link_rel(None) - .allowed_classes(HashMap::new()) - .clean_content_tags(clean_content); - builder - }; - } + static AMMONIA: Lazy> = Lazy::new(|| { + let mut clean_content = HashSet::new(); + clean_content.insert("script"); + clean_content.insert("style"); + let mut builder = ammonia::Builder::new(); + builder + .tags(HashSet::new()) + .tag_attributes(HashMap::new()) + .generic_attributes(HashSet::new()) + .link_rel(None) + .allowed_classes(HashMap::new()) + .clean_content_tags(clean_content); + builder + }); AMMONIA.clean(html).to_string() } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index ab1a1bcd..9f67deda 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -4,8 +4,8 @@ pub mod fs; mod string; pub(crate) mod toml_ext; use crate::errors::Error; -use lazy_static::lazy_static; use log::error; +use once_cell::sync::Lazy; use pulldown_cmark::{html, CodeBlockKind, CowStr, Event, Options, Parser, Tag}; use regex::Regex; @@ -21,9 +21,7 @@ pub use self::string::{ /// Replaces multiple consecutive whitespace characters with a single space character. pub fn collapse_whitespace(text: &str) -> Cow<'_, str> { - lazy_static! { - static ref RE: Regex = Regex::new(r"\s\s+").unwrap(); - } + static RE: Lazy = Lazy::new(|| Regex::new(r"\s\s+").unwrap()); RE.replace_all(text, " ") } @@ -52,9 +50,7 @@ pub fn id_from_content(content: &str) -> String { let mut content = content.to_string(); // Skip any tags or html-encoded stuff - lazy_static! { - static ref HTML: Regex = Regex::new(r"(<.*?>)").unwrap(); - } + static HTML: Lazy = Lazy::new(|| Regex::new(r"(<.*?>)").unwrap()); content = HTML.replace_all(&content, "").into(); const REPL_SUB: &[&str] = &["<", ">", "&", "'", """]; for sub in REPL_SUB { @@ -97,10 +93,9 @@ pub fn unique_id_from_content(content: &str, id_counter: &mut HashMap(event: Event<'a>, path: Option<&Path>) -> Event<'a> { - lazy_static! { - static ref SCHEME_LINK: Regex = Regex::new(r"^[a-z][a-z0-9+.-]*:").unwrap(); - static ref MD_LINK: Regex = Regex::new(r"(?P.*)\.md(?P#.*)?").unwrap(); - } + static SCHEME_LINK: Lazy = Lazy::new(|| Regex::new(r"^[a-z][a-z0-9+.-]*:").unwrap()); + static MD_LINK: Lazy = + Lazy::new(|| Regex::new(r"(?P.*)\.md(?P#.*)?").unwrap()); fn fix<'a>(dest: CowStr<'a>, path: Option<&Path>) -> CowStr<'a> { if dest.starts_with('#') { @@ -153,10 +148,8 @@ fn adjust_links<'a>(event: Event<'a>, path: Option<&Path>) -> Event<'a> { // There are dozens of HTML tags/attributes that contain paths, so // feel free to add more tags if desired; these are the only ones I // care about right now. - lazy_static! { - static ref HTML_LINK: Regex = - Regex::new(r#"(<(?:a|img) [^>]*?(?:src|href)=")([^"]+?)""#).unwrap(); - } + static HTML_LINK: Lazy = + Lazy::new(|| Regex::new(r#"(<(?:a|img) [^>]*?(?:src|href)=")([^"]+?)""#).unwrap()); HTML_LINK .replace_all(&html, |caps: ®ex::Captures<'_>| { diff --git a/src/utils/string.rs b/src/utils/string.rs index bc854347..6dafe260 100644 --- a/src/utils/string.rs +++ b/src/utils/string.rs @@ -1,4 +1,4 @@ -use lazy_static::lazy_static; +use once_cell::sync::Lazy; use regex::Regex; use std::ops::Bound::{Excluded, Included, Unbounded}; use std::ops::RangeBounds; @@ -24,10 +24,10 @@ pub fn take_lines>(s: &str, range: R) -> String { } } -lazy_static! { - static ref ANCHOR_START: Regex = Regex::new(r"ANCHOR:\s*(?P[\w_-]+)").unwrap(); - static ref ANCHOR_END: Regex = Regex::new(r"ANCHOR_END:\s*(?P[\w_-]+)").unwrap(); -} +static ANCHOR_START: Lazy = + Lazy::new(|| Regex::new(r"ANCHOR:\s*(?P[\w_-]+)").unwrap()); +static ANCHOR_END: Lazy = + Lazy::new(|| Regex::new(r"ANCHOR_END:\s*(?P[\w_-]+)").unwrap()); /// Take anchored lines from a string. /// Lines containing anchor are ignored. From 7aaa84853d8991d895f53d27630a2a1c10bd9531 Mon Sep 17 00:00:00 2001 From: Noritada Kobayashi Date: Sun, 25 Sep 2022 06:32:41 +0900 Subject: [PATCH 3/4] Add test code to show preprocessor developers what the interface data looks like (#1897) This test code will show preprocessor developers what the input data looks like and how to test the preprocessing results. --- Cargo.toml | 4 +++ examples/nop-preprocessor.rs | 54 ++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 07b2ed78..5b564ec9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,3 +65,7 @@ search = ["elasticlunr-rs", "ammonia"] [[bin]] doc = false name = "mdbook" + +[[example]] +name = "nop-preprocessor" +test = true diff --git a/examples/nop-preprocessor.rs b/examples/nop-preprocessor.rs index ace40093..a5e47daa 100644 --- a/examples/nop-preprocessor.rs +++ b/examples/nop-preprocessor.rs @@ -101,4 +101,58 @@ mod nop_lib { renderer != "not-supported" } } + + #[cfg(test)] + mod test { + use super::*; + + #[test] + fn nop_preprocessor_run() { + let input_json = r##"[ + { + "root": "/path/to/book", + "config": { + "book": { + "authors": ["AUTHOR"], + "language": "en", + "multilingual": false, + "src": "src", + "title": "TITLE" + }, + "preprocessor": { + "nop": {} + } + }, + "renderer": "html", + "mdbook_version": "0.4.21" + }, + { + "sections": [ + { + "Chapter": { + "name": "Chapter 1", + "content": "# Chapter 1\n", + "number": [1], + "sub_items": [], + "path": "chapter_1.md", + "source_path": "chapter_1.md", + "parent_names": [] + } + } + ], + "__non_exhaustive": null + } + ]"##; + let input_json = input_json.as_bytes(); + + let (ctx, book) = mdbook::preprocess::CmdPreprocessor::parse_input(input_json).unwrap(); + let expected_book = book.clone(); + let result = Nop::new().run(&ctx, book); + assert!(result.is_ok()); + + // The nop-preprocessor should not have made any changes to the book content. + let actual_book = result.unwrap(); + assert_eq!(actual_book, expected_book); + } + } } From cb01f11ad100db49d5b1995a6852623feaa29eae Mon Sep 17 00:00:00 2001 From: Kian-Meng Ang Date: Thu, 29 Sep 2022 22:41:12 +0800 Subject: [PATCH 4/4] Fix typos Found via `codespell -S ./src/theme -L crate,nam,varius,phasis` --- CONTRIBUTING.md | 2 +- src/book/summary.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 72010ad2..23f90c7a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -116,7 +116,7 @@ If possible, do your best to avoid breaking older browser releases. Any change to the HTML or styling is encouraged to manually check on as many browsers and platforms that you can. Unfortunately at this time we don't have any automated UI or browser testing, so your assistance in testing is appreciated. -## Updating higlight.js +## Updating highlight.js The following are instructions for updating [highlight.js](https://highlightjs.org/). diff --git a/src/book/summary.rs b/src/book/summary.rs index 02f67c6f..b2784ce5 100644 --- a/src/book/summary.rs +++ b/src/book/summary.rs @@ -454,7 +454,7 @@ impl<'a> SummaryParser<'a> { items.push(item); } Some(Event::Start(Tag::List(..))) => { - // Skip this tag after comment bacause it is not nested. + // Skip this tag after comment because it is not nested. if items.is_empty() { continue; }