Merge remote-tracking branch 'upstream/master' into include-ident
This commit is contained in:
commit
16e38ab0b3
|
@ -28,9 +28,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
@ -228,10 +228,10 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "difference"
|
||||
version = "2.0.0"
|
||||
name = "diff"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
|
||||
checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
|
||||
|
||||
[[package]]
|
||||
name = "difflib"
|
||||
|
@ -283,9 +283,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.7.1"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
|
||||
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"humantime",
|
||||
|
@ -382,25 +382,11 @@ dependencies = [
|
|||
"new_debug_unreachable",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1adc00f486adfc9ce99f77d717836f0c5aa84965eb0b4f051f4e83f7cab53f8b"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.16"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74ed2411805f6e4e3d9bc904c95d5d423b89b3b25dc0250aa74729de20629ff9"
|
||||
checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
|
@ -408,15 +394,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.16"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af51b1b4a7fdff033703db39de8802c673eb91855f2e0d47dcf3bf2c0ef01f99"
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b0e06c393068f3a6ef246c75cdca793d6a46347e75286933e5e75fd2fd11582"
|
||||
checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
|
@ -433,9 +413,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.16"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0f30aaa67363d119812743aa5f33c201a7a66329f97d1a887022971feea4b53"
|
||||
checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
|
@ -545,7 +525,7 @@ dependencies = [
|
|||
"log",
|
||||
"pest",
|
||||
"pest_derive",
|
||||
"quick-error 2.0.1",
|
||||
"quick-error",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
@ -640,12 +620,9 @@ checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440"
|
|||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "1.3.0"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
|
||||
dependencies = [
|
||||
"quick-error 1.2.3",
|
||||
]
|
||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
|
@ -712,15 +689,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "input_buffer"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f97967975f448f1a7ddb12b0bc41069d09ed6a1c161a92687e057325db35d413"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iovec"
|
||||
version = "0.1.4"
|
||||
|
@ -1232,13 +1200,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pretty_assertions"
|
||||
version = "0.6.1"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
|
||||
checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"ctor",
|
||||
"difference",
|
||||
"diff",
|
||||
"output_vt100",
|
||||
]
|
||||
|
||||
|
@ -1274,12 +1242,6 @@ dependencies = [
|
|||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "2.0.1"
|
||||
|
@ -1643,6 +1605,26 @@ version = "0.14.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.43"
|
||||
|
@ -1670,11 +1652,10 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.10.0"
|
||||
version = "1.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01cf844b23c6131f624accf65ce0e4e9956a8bb329400ea5bcc26ae3a5c20b0b"
|
||||
checksum = "0c27a64b625de6d309e8c57716ba93021dccf1b3b5c97edd6d3dd2d2135afc0a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bytes",
|
||||
"libc",
|
||||
"memchr",
|
||||
|
@ -1687,9 +1668,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "1.3.0"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54473be61f4ebe4efd09cec9bd5d16fa51d70ea0192213d754d2d500457db110"
|
||||
checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1709,9 +1690,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tokio-tungstenite"
|
||||
version = "0.13.0"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1a5f475f1b9d077ea1017ecbc60890fda8e54942d680ca0b1d2b47cfa2d861b"
|
||||
checksum = "511de3f85caf1c98983545490c3d09685fa8eb634e57eec22bb4db271f46cbd8"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"log",
|
||||
|
@ -1790,19 +1771,19 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
|
|||
|
||||
[[package]]
|
||||
name = "tungstenite"
|
||||
version = "0.12.0"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ada8297e8d70872fa9a551d93250a9f407beb9f37ef86494eb20012a2ff7c24"
|
||||
checksum = "a0b2d8558abd2e276b0a8df5c05a2ec762609344191e5fd23e292c910e9165b5"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"http",
|
||||
"httparse",
|
||||
"input_buffer",
|
||||
"log",
|
||||
"rand 0.8.4",
|
||||
"sha-1 0.9.7",
|
||||
"thiserror",
|
||||
"url",
|
||||
"utf-8",
|
||||
]
|
||||
|
@ -1905,12 +1886,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "warp"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "332d47745e9a0c38636dbd454729b147d16bd1ed08ae67b3ab281c4506771054"
|
||||
checksum = "3cef4e1e9114a4b7f1ac799f16ce71c14de5778500c5450ec6b7b920c55b587e"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"headers",
|
||||
"http",
|
||||
"hyper",
|
||||
|
|
|
@ -20,7 +20,7 @@ anyhow = "1.0.28"
|
|||
chrono = "0.4"
|
||||
clap = { version = "3.0", features = ["cargo"] }
|
||||
clap_complete = "3.0"
|
||||
env_logger = "0.7.1"
|
||||
env_logger = "0.9.0"
|
||||
handlebars = "4.0"
|
||||
lazy_static = "1.0"
|
||||
log = "0.4"
|
||||
|
@ -42,7 +42,7 @@ gitignore = { version = "1.0", optional = true }
|
|||
# Serve feature
|
||||
futures-util = { version = "0.3.4", optional = true }
|
||||
tokio = { version = "1", features = ["macros", "rt-multi-thread"], optional = true }
|
||||
warp = { version = "0.3.1", default-features = false, features = ["websocket"], optional = true }
|
||||
warp = { version = "0.3.2", default-features = false, features = ["websocket"], optional = true }
|
||||
|
||||
# Search feature
|
||||
elasticlunr-rs = { version = "3.0.0", optional = true }
|
||||
|
@ -53,7 +53,7 @@ assert_cmd = "1"
|
|||
predicates = "2"
|
||||
select = "0.5"
|
||||
semver = "1.0"
|
||||
pretty_assertions = "0.6"
|
||||
pretty_assertions = "1.2.1"
|
||||
walkdir = "2.0"
|
||||
|
||||
[features]
|
||||
|
|
|
@ -30,6 +30,8 @@ cargo install mdbook
|
|||
|
||||
This will automatically download mdBook from [crates.io], build it, and install it in Cargo's global binary directory (`~/.cargo/bin/` by default).
|
||||
|
||||
To uninstall, run the command `cargo uninstall mdbook`.
|
||||
|
||||
[Rust installation page]: https://www.rust-lang.org/tools/install
|
||||
[crates.io]: https://crates.io/
|
||||
|
||||
|
|
|
@ -386,7 +386,7 @@ fn determine_renderers(config: &Config) -> Vec<Box<dyn Renderer>> {
|
|||
renderers
|
||||
}
|
||||
|
||||
const DEFAULT_PREPROCESSORS: &[&'static str] = &["links", "index"];
|
||||
const DEFAULT_PREPROCESSORS: &[&str] = &["links", "index"];
|
||||
|
||||
fn is_default_preprocessor(pre: &dyn Preprocessor) -> bool {
|
||||
let name = pre.name();
|
||||
|
@ -756,10 +756,9 @@ mod tests {
|
|||
|
||||
let preprocessors = determine_preprocessors(&cfg).unwrap();
|
||||
|
||||
assert!(preprocessors
|
||||
assert!(!preprocessors
|
||||
.iter()
|
||||
.find(|preprocessor| preprocessor.name() == "random")
|
||||
.is_none());
|
||||
.any(|preprocessor| preprocessor.name() == "random"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -776,10 +775,9 @@ mod tests {
|
|||
|
||||
let preprocessors = determine_preprocessors(&cfg).unwrap();
|
||||
|
||||
assert!(preprocessors
|
||||
assert!(!preprocessors
|
||||
.iter()
|
||||
.find(|preprocessor| preprocessor.name() == "links")
|
||||
.is_none());
|
||||
.any(|preprocessor| preprocessor.name() == "links"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -122,8 +122,5 @@ fn confirm() -> bool {
|
|||
io::stdout().flush().unwrap();
|
||||
let mut s = String::new();
|
||||
io::stdin().read_line(&mut s).ok();
|
||||
match &*s.trim() {
|
||||
"Y" | "y" | "yes" | "Yes" => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(&*s.trim(), "Y" | "y" | "yes" | "Yes")
|
||||
}
|
||||
|
|
|
@ -227,10 +227,10 @@ impl Config {
|
|||
let value = Value::try_from(value)
|
||||
.with_context(|| "Unable to represent the item as a JSON Value")?;
|
||||
|
||||
if index.starts_with("book.") {
|
||||
self.book.update_value(&index[5..], value);
|
||||
} else if index.starts_with("build.") {
|
||||
self.build.update_value(&index[6..], value);
|
||||
if let Some(key) = index.strip_prefix("book.") {
|
||||
self.book.update_value(key, value);
|
||||
} else if let Some(key) = index.strip_prefix("build.") {
|
||||
self.build.update_value(key, value);
|
||||
} else {
|
||||
self.rest.insert(index, value);
|
||||
}
|
||||
|
@ -371,15 +371,8 @@ impl Serialize for Config {
|
|||
}
|
||||
|
||||
fn parse_env(key: &str) -> Option<String> {
|
||||
const PREFIX: &str = "MDBOOK_";
|
||||
|
||||
if key.starts_with(PREFIX) {
|
||||
let key = &key[PREFIX.len()..];
|
||||
|
||||
Some(key.to_lowercase().replace("__", ".").replace("_", "-"))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
key.strip_prefix("MDBOOK_")
|
||||
.map(|key| key.to_lowercase().replace("__", ".").replace('_', "-"))
|
||||
}
|
||||
|
||||
fn is_legacy_format(table: &Value) -> bool {
|
||||
|
@ -828,7 +821,7 @@ mod tests {
|
|||
"#;
|
||||
|
||||
let got = Config::from_str(src).unwrap();
|
||||
assert_eq!(got.html_config().unwrap().playground.runnable, false);
|
||||
assert!(!got.html_config().unwrap().playground.runnable);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1037,7 +1030,7 @@ mod tests {
|
|||
fn encode_env_var(key: &str) -> String {
|
||||
format!(
|
||||
"MDBOOK_{}",
|
||||
key.to_uppercase().replace('.', "__").replace("-", "_")
|
||||
key.to_uppercase().replace('.', "__").replace('-', "_")
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1061,11 +1054,10 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::approx_constant)]
|
||||
fn update_config_using_env_var_and_complex_value() {
|
||||
let mut cfg = Config::default();
|
||||
let key = "foo-bar.baz";
|
||||
let value = json!({"array": [1, 2, 3], "number": 3.14});
|
||||
let value = json!({"array": [1, 2, 3], "number": 13.37});
|
||||
let value_str = serde_json::to_string(&value).unwrap();
|
||||
|
||||
assert!(cfg.get(key).is_none());
|
||||
|
@ -1184,15 +1176,15 @@ mod tests {
|
|||
"#;
|
||||
let got = Config::from_str(src).unwrap();
|
||||
let html_config = got.html_config().unwrap();
|
||||
assert_eq!(html_config.print.enable, false);
|
||||
assert_eq!(html_config.print.page_break, true);
|
||||
assert!(!html_config.print.enable);
|
||||
assert!(html_config.print.page_break);
|
||||
let src = r#"
|
||||
[output.html.print]
|
||||
page-break = false
|
||||
"#;
|
||||
let got = Config::from_str(src).unwrap();
|
||||
let html_config = got.html_config().unwrap();
|
||||
assert_eq!(html_config.print.enable, true);
|
||||
assert_eq!(html_config.print.page_break, false);
|
||||
assert!(html_config.print.enable);
|
||||
assert!(!html_config.print.page_break);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,7 +82,6 @@
|
|||
|
||||
#![deny(missing_docs)]
|
||||
#![deny(rust_2018_idioms)]
|
||||
#![allow(clippy::comparison_chain)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
|
|
@ -153,6 +153,7 @@ enum RangeOrAnchor {
|
|||
}
|
||||
|
||||
// A range of lines specified with some include directive.
|
||||
#[allow(clippy::enum_variant_names)] // The prefix can't be removed, and is meant to mirror the contained type
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
enum LineRange {
|
||||
Range(Range<usize>),
|
||||
|
|
|
@ -116,7 +116,7 @@ impl HtmlHandlebars {
|
|||
if ctx.is_index {
|
||||
ctx.data.insert("path".to_owned(), json!("index.md"));
|
||||
ctx.data.insert("path_to_root".to_owned(), json!(""));
|
||||
ctx.data.insert("is_index".to_owned(), json!("true"));
|
||||
ctx.data.insert("is_index".to_owned(), json!(true));
|
||||
let rendered_index = ctx.handlebars.render("index", &ctx.data)?;
|
||||
let rendered_index =
|
||||
self.post_process(rendered_index, &ctx.html_config.playground, ctx.edition);
|
||||
|
@ -540,7 +540,8 @@ impl Renderer for HtmlHandlebars {
|
|||
chapter_titles: &ctx.chapter_titles,
|
||||
};
|
||||
self.render_item(item, ctx, &mut print_content)?;
|
||||
is_index = false;
|
||||
// Only the first non-draft chapter item should be treated as the "index"
|
||||
is_index &= !matches!(item, BookItem::Chapter(ch) if !ch.is_draft_chapter());
|
||||
}
|
||||
|
||||
// Render 404 page
|
||||
|
@ -814,7 +815,7 @@ fn fix_code_blocks(html: &str) -> String {
|
|||
FIX_CODE_BLOCKS
|
||||
.replace_all(html, |caps: &Captures<'_>| {
|
||||
let before = &caps[1];
|
||||
let classes = &caps[2].replace(",", " ");
|
||||
let classes = &caps[2].replace(',', " ");
|
||||
let after = &caps[3];
|
||||
|
||||
format!(
|
||||
|
@ -880,11 +881,8 @@ fn add_playground_pre(
|
|||
// we need to inject our own main
|
||||
let (attrs, code) = partition_source(code);
|
||||
|
||||
format!(
|
||||
"\n# #![allow(unused)]\n{}#fn main() {{\n{}#}}",
|
||||
attrs, code
|
||||
)
|
||||
.into()
|
||||
format!("# #![allow(unused)]\n{}#fn main() {{\n{}#}}", attrs, code)
|
||||
.into()
|
||||
};
|
||||
hide_lines(&content)
|
||||
}
|
||||
|
@ -1007,7 +1005,7 @@ mod tests {
|
|||
fn add_playground() {
|
||||
let inputs = [
|
||||
("<code class=\"language-rust\">x()</code>",
|
||||
"<pre class=\"playground\"><code class=\"language-rust\">\n<span class=\"boring\">#![allow(unused)]\n</span><span class=\"boring\">fn main() {\n</span>x()\n<span class=\"boring\">}\n</span></code></pre>"),
|
||||
"<pre class=\"playground\"><code class=\"language-rust\"><span class=\"boring\">#![allow(unused)]\n</span><span class=\"boring\">fn main() {\n</span>x()\n<span class=\"boring\">}\n</span></code></pre>"),
|
||||
("<code class=\"language-rust\">fn main() {}</code>",
|
||||
"<pre class=\"playground\"><code class=\"language-rust\">fn main() {}\n</code></pre>"),
|
||||
("<code class=\"language-rust editable\">let s = \"foo\n # bar\n\";</code>",
|
||||
|
@ -1037,7 +1035,7 @@ mod tests {
|
|||
fn add_playground_edition2015() {
|
||||
let inputs = [
|
||||
("<code class=\"language-rust\">x()</code>",
|
||||
"<pre class=\"playground\"><code class=\"language-rust edition2015\">\n<span class=\"boring\">#![allow(unused)]\n</span><span class=\"boring\">fn main() {\n</span>x()\n<span class=\"boring\">}\n</span></code></pre>"),
|
||||
"<pre class=\"playground\"><code class=\"language-rust edition2015\"><span class=\"boring\">#![allow(unused)]\n</span><span class=\"boring\">fn main() {\n</span>x()\n<span class=\"boring\">}\n</span></code></pre>"),
|
||||
("<code class=\"language-rust\">fn main() {}</code>",
|
||||
"<pre class=\"playground\"><code class=\"language-rust edition2015\">fn main() {}\n</code></pre>"),
|
||||
("<code class=\"language-rust edition2015\">fn main() {}</code>",
|
||||
|
@ -1061,7 +1059,7 @@ mod tests {
|
|||
fn add_playground_edition2018() {
|
||||
let inputs = [
|
||||
("<code class=\"language-rust\">x()</code>",
|
||||
"<pre class=\"playground\"><code class=\"language-rust edition2018\">\n<span class=\"boring\">#![allow(unused)]\n</span><span class=\"boring\">fn main() {\n</span>x()\n<span class=\"boring\">}\n</span></code></pre>"),
|
||||
"<pre class=\"playground\"><code class=\"language-rust edition2018\"><span class=\"boring\">#![allow(unused)]\n</span><span class=\"boring\">fn main() {\n</span>x()\n<span class=\"boring\">}\n</span></code></pre>"),
|
||||
("<code class=\"language-rust\">fn main() {}</code>",
|
||||
"<pre class=\"playground\"><code class=\"language-rust edition2018\">fn main() {}\n</code></pre>"),
|
||||
("<code class=\"language-rust edition2015\">fn main() {}</code>",
|
||||
|
@ -1085,7 +1083,7 @@ mod tests {
|
|||
fn add_playground_edition2021() {
|
||||
let inputs = [
|
||||
("<code class=\"language-rust\">x()</code>",
|
||||
"<pre class=\"playground\"><code class=\"language-rust edition2021\">\n<span class=\"boring\">#![allow(unused)]\n</span><span class=\"boring\">fn main() {\n</span>x()\n<span class=\"boring\">}\n</span></code></pre>"),
|
||||
"<pre class=\"playground\"><code class=\"language-rust edition2021\"><span class=\"boring\">#![allow(unused)]\n</span><span class=\"boring\">fn main() {\n</span>x()\n<span class=\"boring\">}\n</span></code></pre>"),
|
||||
("<code class=\"language-rust\">fn main() {}</code>",
|
||||
"<pre class=\"playground\"><code class=\"language-rust edition2021\">fn main() {}\n</code></pre>"),
|
||||
("<code class=\"language-rust edition2015\">fn main() {}</code>",
|
||||
|
|
|
@ -61,7 +61,7 @@ fn find_chapter(
|
|||
.as_json()
|
||||
.as_str()
|
||||
.ok_or_else(|| RenderError::new("Type error for `path`, string expected"))?
|
||||
.replace("\"", "");
|
||||
.replace('\"', "");
|
||||
|
||||
if !rc.evaluate(ctx, "@root/is_index")?.is_missing() {
|
||||
// Special case for index.md which may be a synthetic page.
|
||||
|
@ -121,7 +121,7 @@ fn render(
|
|||
.as_json()
|
||||
.as_str()
|
||||
.ok_or_else(|| RenderError::new("Type error for `path`, string expected"))?
|
||||
.replace("\"", "");
|
||||
.replace('\"', "");
|
||||
|
||||
context.insert(
|
||||
"path_to_root".to_owned(),
|
||||
|
@ -141,7 +141,7 @@ fn render(
|
|||
.with_extension("html")
|
||||
.to_str()
|
||||
.ok_or_else(|| RenderError::new("Link could not be converted to str"))
|
||||
.map(|p| context.insert("link".to_owned(), json!(p.replace("\\", "/"))))
|
||||
.map(|p| context.insert("link".to_owned(), json!(p.replace('\\', "/"))))
|
||||
})?;
|
||||
|
||||
trace!("Render template");
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use std::collections::BTreeMap;
|
||||
use std::path::Path;
|
||||
use std::{cmp::Ordering, collections::BTreeMap};
|
||||
|
||||
use crate::utils;
|
||||
use crate::utils::bracket_escape;
|
||||
|
@ -33,7 +33,7 @@ impl HelperDef for RenderToc {
|
|||
.as_json()
|
||||
.as_str()
|
||||
.ok_or_else(|| RenderError::new("Type error for `path`, string expected"))?
|
||||
.replace("\"", "");
|
||||
.replace('\"', "");
|
||||
|
||||
let current_section = rc
|
||||
.evaluate(ctx, "@root/section")?
|
||||
|
@ -57,6 +57,11 @@ impl HelperDef for RenderToc {
|
|||
out.write("<ol class=\"chapter\">")?;
|
||||
|
||||
let mut current_level = 1;
|
||||
// The "index" page, which has this attribute set, is supposed to alias the first chapter in
|
||||
// the book, i.e. the first link. There seems to be no easy way to determine which chapter
|
||||
// the "index" is aliasing from within the renderer, so this is used instead to force the
|
||||
// first link to be active. See further below.
|
||||
let mut is_first_chapter = ctx.data().get("is_index").is_some();
|
||||
|
||||
for item in chapters {
|
||||
// Spacer
|
||||
|
@ -81,22 +86,26 @@ impl HelperDef for RenderToc {
|
|||
level - 1 < fold_level as usize
|
||||
};
|
||||
|
||||
if level > current_level {
|
||||
while level > current_level {
|
||||
out.write("<li>")?;
|
||||
out.write("<ol class=\"section\">")?;
|
||||
current_level += 1;
|
||||
match level.cmp(¤t_level) {
|
||||
Ordering::Greater => {
|
||||
while level > current_level {
|
||||
out.write("<li>")?;
|
||||
out.write("<ol class=\"section\">")?;
|
||||
current_level += 1;
|
||||
}
|
||||
write_li_open_tag(out, is_expanded, false)?;
|
||||
}
|
||||
write_li_open_tag(out, is_expanded, false)?;
|
||||
} else if level < current_level {
|
||||
while level < current_level {
|
||||
out.write("</ol>")?;
|
||||
out.write("</li>")?;
|
||||
current_level -= 1;
|
||||
Ordering::Less => {
|
||||
while level < current_level {
|
||||
out.write("</ol>")?;
|
||||
out.write("</li>")?;
|
||||
current_level -= 1;
|
||||
}
|
||||
write_li_open_tag(out, is_expanded, false)?;
|
||||
}
|
||||
Ordering::Equal => {
|
||||
write_li_open_tag(out, is_expanded, item.get("section").is_none())?;
|
||||
}
|
||||
write_li_open_tag(out, is_expanded, false)?;
|
||||
} else {
|
||||
write_li_open_tag(out, is_expanded, item.get("section").is_none())?;
|
||||
}
|
||||
|
||||
// Part title
|
||||
|
@ -119,14 +128,15 @@ impl HelperDef for RenderToc {
|
|||
.to_str()
|
||||
.unwrap()
|
||||
// Hack for windows who tends to use `\` as separator instead of `/`
|
||||
.replace("\\", "/");
|
||||
.replace('\\', "/");
|
||||
|
||||
// Add link
|
||||
out.write(&utils::fs::path_to_root(¤t_path))?;
|
||||
out.write(&tmp)?;
|
||||
out.write("\"")?;
|
||||
|
||||
if path == ¤t_path {
|
||||
if path == ¤t_path || is_first_chapter {
|
||||
is_first_chapter = false;
|
||||
out.write(" class=\"active\"")?;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::borrow::Cow;
|
|||
use std::collections::{HashMap, HashSet};
|
||||
use std::path::Path;
|
||||
|
||||
use elasticlunr::Index;
|
||||
use elasticlunr::{Index, IndexBuilder};
|
||||
use pulldown_cmark::*;
|
||||
|
||||
use crate::book::{Book, BookItem};
|
||||
|
@ -13,9 +13,25 @@ use crate::utils;
|
|||
|
||||
use serde::Serialize;
|
||||
|
||||
const MAX_WORD_LENGTH_TO_INDEX: usize = 80;
|
||||
|
||||
/// Tokenizes in the same way as elasticlunr-rs (for English), but also drops long tokens.
|
||||
fn tokenize(text: &str) -> Vec<String> {
|
||||
text.split(|c: char| c.is_whitespace() || c == '-')
|
||||
.filter(|s| !s.is_empty())
|
||||
.map(|s| s.trim().to_lowercase())
|
||||
.filter(|s| s.len() <= MAX_WORD_LENGTH_TO_INDEX)
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Creates all files required for search.
|
||||
pub fn create_files(search_config: &Search, destination: &Path, book: &Book) -> Result<()> {
|
||||
let mut index = Index::new(&["title", "body", "breadcrumbs"]);
|
||||
let mut index = IndexBuilder::new()
|
||||
.add_field_with_tokenizer("title", Box::new(&tokenize))
|
||||
.add_field_with_tokenizer("body", Box::new(&tokenize))
|
||||
.add_field_with_tokenizer("breadcrumbs", Box::new(&tokenize))
|
||||
.build();
|
||||
|
||||
let mut doc_urls = Vec::with_capacity(book.sections.len());
|
||||
|
||||
for item in book.iter() {
|
||||
|
@ -211,12 +227,13 @@ fn write_to_json(index: Index, search_config: &Search, doc_urls: Vec<String>) ->
|
|||
|
||||
let mut fields = BTreeMap::new();
|
||||
let mut opt = SearchOptionsField::default();
|
||||
opt.boost = Some(search_config.boost_title);
|
||||
fields.insert("title".into(), opt);
|
||||
opt.boost = Some(search_config.boost_paragraph);
|
||||
fields.insert("body".into(), opt);
|
||||
opt.boost = Some(search_config.boost_hierarchy);
|
||||
fields.insert("breadcrumbs".into(), opt);
|
||||
let mut insert_boost = |key: &str, boost| {
|
||||
opt.boost = Some(boost);
|
||||
fields.insert(key.into(), opt);
|
||||
};
|
||||
insert_boost("title", search_config.boost_title);
|
||||
insert_boost("body", search_config.boost_paragraph);
|
||||
insert_boost("breadcrumbs", search_config.boost_hierarchy);
|
||||
|
||||
let search_options = SearchOptions {
|
||||
bool: if search_config.use_boolean_and {
|
||||
|
|
|
@ -8,7 +8,6 @@ Original by Dempfi (https://github.com/dempfi/ayu)
|
|||
overflow-x: auto;
|
||||
background: #191f26;
|
||||
color: #e6e1cf;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
|
|
|
@ -208,24 +208,63 @@ pre {
|
|||
pre > .buttons {
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
right: 0px;
|
||||
top: 2px;
|
||||
margin: 0px;
|
||||
padding: 2px 0px;
|
||||
|
||||
color: var(--sidebar-fg);
|
||||
cursor: pointer;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: visibility 0.1s linear, opacity 0.1s linear;
|
||||
}
|
||||
pre:hover > .buttons {
|
||||
visibility: visible;
|
||||
opacity: 1
|
||||
}
|
||||
pre > .buttons :hover {
|
||||
color: var(--sidebar-active);
|
||||
border-color: var(--icons-hover);
|
||||
background-color: var(--theme-hover);
|
||||
}
|
||||
pre > .buttons i {
|
||||
margin-left: 8px;
|
||||
}
|
||||
pre > .buttons button {
|
||||
color: inherit;
|
||||
background: transparent;
|
||||
border: none;
|
||||
cursor: inherit;
|
||||
margin: 0px 5px;
|
||||
padding: 3px 5px;
|
||||
font-size: 14px;
|
||||
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-radius: 4px;
|
||||
border-color: var(--icons);
|
||||
background-color: var(--theme-popup-bg);
|
||||
transition: 100ms;
|
||||
transition-property: color,border-color,background-color;
|
||||
color: var(--icons);
|
||||
}
|
||||
@media (pointer: coarse) {
|
||||
pre > .buttons button {
|
||||
/* On mobile, make it easier to tap buttons. */
|
||||
padding: 0.3rem 1rem;
|
||||
}
|
||||
}
|
||||
code {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
/* FIXME: ACE editors overlap their buttons because ACE does absolute
|
||||
positioning within the code block which breaks padding. The only solution I
|
||||
can think of is to move the padding to the outer pre tag (or insert a div
|
||||
wrapper), but that would require fixing a whole bunch of CSS rules.
|
||||
*/
|
||||
.hljs.ace_editor {
|
||||
padding: 0rem 0rem;
|
||||
}
|
||||
|
||||
pre > .result {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,16 @@ code {
|
|||
font-size: 0.875em; /* please adjust the ace font size accordingly in editor.js */
|
||||
}
|
||||
|
||||
/* make long words/inline code not x overflow */
|
||||
main {
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
/* make wide tables scroll if they overflow */
|
||||
.table-wrapper {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
/* Don't change font size in headers. */
|
||||
h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
|
||||
font-size: unset;
|
||||
|
@ -80,8 +90,7 @@ h6:target::before {
|
|||
|
||||
.content {
|
||||
overflow-y: auto;
|
||||
padding: 0 15px;
|
||||
padding-bottom: 50px;
|
||||
padding: 0 5px 50px 5px;
|
||||
}
|
||||
.content main {
|
||||
margin-left: auto;
|
||||
|
|
|
@ -61,7 +61,6 @@
|
|||
overflow-x: auto;
|
||||
background: #f6f7f6;
|
||||
color: #000;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
.hljs-emphasis {
|
||||
|
|
|
@ -81,8 +81,6 @@
|
|||
overflow-x: auto;
|
||||
background: #1d1f21;
|
||||
color: #c5c8c6;
|
||||
padding: 0.5em;
|
||||
-webkit-text-size-adjust: none;
|
||||
}
|
||||
|
||||
.coffeescript .javascript,
|
||||
|
|
|
@ -200,12 +200,28 @@ pub fn render_markdown_with_path(text: &str, curly_quotes: bool, path: Option<&P
|
|||
let p = new_cmark_parser(text, curly_quotes);
|
||||
let events = p
|
||||
.map(clean_codeblock_headers)
|
||||
.map(|event| adjust_links(event, path));
|
||||
.map(|event| adjust_links(event, path))
|
||||
.flat_map(|event| {
|
||||
let (a, b) = wrap_tables(event);
|
||||
a.into_iter().chain(b)
|
||||
});
|
||||
|
||||
html::push_html(&mut s, events);
|
||||
s
|
||||
}
|
||||
|
||||
/// Wraps tables in a `.table-wrapper` class to apply overflow-x rules to.
|
||||
fn wrap_tables(event: Event<'_>) -> (Option<Event<'_>>, Option<Event<'_>>) {
|
||||
match event {
|
||||
Event::Start(Tag::Table(_)) => (
|
||||
Some(Event::Html(r#"<div class="table-wrapper">"#.into())),
|
||||
Some(event),
|
||||
),
|
||||
Event::End(Tag::Table(_)) => (Some(event), Some(Event::Html(r#"</div>"#.into()))),
|
||||
_ => (Some(event), None),
|
||||
}
|
||||
}
|
||||
|
||||
fn clean_codeblock_headers(event: Event<'_>) -> Event<'_> {
|
||||
match event {
|
||||
Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(ref info))) => {
|
||||
|
@ -282,6 +298,22 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_can_wrap_tables() {
|
||||
let src = r#"
|
||||
| Original | Punycode | Punycode + Encoding |
|
||||
|-----------------|-----------------|---------------------|
|
||||
| føø | f-5gaa | f_5gaa |
|
||||
"#;
|
||||
let out = r#"
|
||||
<div class="table-wrapper"><table><thead><tr><th>Original</th><th>Punycode</th><th>Punycode + Encoding</th></tr></thead><tbody>
|
||||
<tr><td>føø</td><td>f-5gaa</td><td>f_5gaa</td></tr>
|
||||
</tbody></table>
|
||||
</div>
|
||||
"#.trim();
|
||||
assert_eq!(render_markdown(src, false), out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_can_keep_quotes_straight() {
|
||||
assert_eq!(render_markdown("'one'", false), "<p>'one'</p>\n");
|
||||
|
|
|
@ -122,6 +122,7 @@ mod tests {
|
|||
};
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::reversed_empty_ranges)] // Intentionally checking that those are correctly handled
|
||||
fn take_lines_test() {
|
||||
let s = "Lorem\nipsum\ndolor\nsit\namet";
|
||||
assert_eq!(take_lines(s, 1..3), "ipsum\ndolor");
|
||||
|
@ -163,6 +164,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::reversed_empty_ranges)] // Intentionally checking that those are correctly handled
|
||||
fn take_rustdoc_include_lines_test() {
|
||||
let s = "Lorem\nipsum\ndolor\nsit\namet";
|
||||
assert_eq!(
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
# Summary
|
||||
|
||||
---
|
||||
|
||||
- [None of these should be treated as the "index chapter"]()
|
||||
|
||||
# Part 1
|
||||
|
||||
- [Not this either]()
|
||||
- [Chapter 1](./chapter_1.md)
|
||||
- [And not this]()
|
|
@ -0,0 +1 @@
|
|||
# Chapter 1
|
|
@ -1,3 +1,5 @@
|
|||
Capybara capybara capybara.
|
||||
|
||||
Capybara capybara capybara.
|
||||
Capybara capybara capybara.
|
||||
|
||||
ThisLongWordIsIncludedSoWeCanCheckThatSufficientlyLongWordsAreOmittedFromTheSearchIndex.
|
||||
|
|
|
@ -467,6 +467,21 @@ fn by_default_mdbook_use_index_preprocessor_to_convert_readme_to_index() {
|
|||
assert_doesnt_contain_strings(&second_index, &unexpected_strings);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn first_chapter_is_copied_as_index_even_if_not_first_elem() {
|
||||
let temp = DummyBook::new().build().unwrap();
|
||||
let mut cfg = Config::default();
|
||||
cfg.set("book.src", "index_html_test")
|
||||
.expect("Couldn't set config.book.src to \"index_html_test\"");
|
||||
let md = MDBook::load_with_config(temp.path(), cfg).unwrap();
|
||||
md.build().unwrap();
|
||||
|
||||
let root = temp.path().join("book");
|
||||
let chapter = fs::read_to_string(root.join("chapter_1.html")).expect("read chapter 1");
|
||||
let index = fs::read_to_string(root.join("index.html")).expect("read index");
|
||||
pretty_assertions::assert_eq!(chapter, index);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn theme_dir_overrides_work_correctly() {
|
||||
let book_dir = dummy_book::new_copy_of_example_book().unwrap();
|
||||
|
@ -772,7 +787,7 @@ mod search {
|
|||
);
|
||||
assert_eq!(
|
||||
docs[&no_headers]["body"],
|
||||
"Capybara capybara capybara. Capybara capybara capybara."
|
||||
"Capybara capybara capybara. Capybara capybara capybara. ThisLongWordIsIncludedSoWeCanCheckThatSufficientlyLongWordsAreOmittedFromTheSearchIndex."
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -241,7 +241,7 @@
|
|||
"title": "Unicode stress tests"
|
||||
},
|
||||
"19": {
|
||||
"body": "Capybara capybara capybara. Capybara capybara capybara.",
|
||||
"body": "Capybara capybara capybara. Capybara capybara capybara. ThisLongWordIsIncludedSoWeCanCheckThatSufficientlyLongWordsAreOmittedFromTheSearchIndex.",
|
||||
"breadcrumbs": "First Chapter » No Headers",
|
||||
"id": "19",
|
||||
"title": "First Chapter"
|
||||
|
|
Loading…
Reference in New Issue