Skip to content

Commit 92487a3

Browse files
committed
Match file stem case-insensitively for IndexPreprocessor
1 parent 45fe346 commit 92487a3

1 file changed

Lines changed: 59 additions & 2 deletions

File tree

src/preprocess/index.rs

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
use std::path::Path;
2+
use regex::Regex;
3+
14
use errors::*;
25

36
use super::{Preprocessor, PreprocessorContext};
@@ -19,10 +22,17 @@ impl Preprocessor for IndexPreprocessor {
1922
"index"
2023
}
2124

22-
fn run(&self, _ctx: &PreprocessorContext, book: &mut Book) -> Result<()> {
25+
fn run(&self, ctx: &PreprocessorContext, book: &mut Book) -> Result<()> {
26+
let source_dir = ctx.root.join(&ctx.config.book.src);
2327
book.for_each_mut(|section: &mut BookItem| {
2428
if let BookItem::Chapter(ref mut ch) = *section {
25-
if ch.path.file_name().unwrap_or_default() == "README.md" {
29+
if is_readme_file(&ch.path) {
30+
let index_md = source_dir
31+
.join(ch.path.with_file_name("index.md"));
32+
if index_md.exists() {
33+
warn_readme_name_conflict(&ch.path, &index_md);
34+
}
35+
2636
ch.path.set_file_name("index.md");
2737
}
2838
}
@@ -32,3 +42,50 @@ impl Preprocessor for IndexPreprocessor {
3242
}
3343
}
3444

45+
fn warn_readme_name_conflict<P: AsRef<Path>>(readme_path: P, index_path: P) {
46+
let file_name = readme_path.as_ref().file_name().unwrap_or_default();
47+
let parent_dir = index_path.as_ref().parent().unwrap_or(index_path.as_ref());
48+
warn!("It seems that there are both {:?} and index.md under \"{}\".", file_name, parent_dir.display());
49+
warn!("mdbook converts {:?} into index.html by default. It may cause", file_name);
50+
warn!("unexpected behavior if putting both files under the same directory.");
51+
warn!("To solve the warning, try to rearrange the book structure or disable");
52+
warn!("\"index\" preprocessor to stop the conversion.");
53+
}
54+
55+
fn is_readme_file<P: AsRef<Path>>(path: P) -> bool {
56+
lazy_static! {
57+
static ref RE: Regex = Regex::new(r"(?i)^readme$").unwrap();
58+
}
59+
RE.is_match(
60+
path.as_ref()
61+
.file_stem()
62+
.and_then(|s| s.to_str())
63+
.unwrap_or_default()
64+
)
65+
}
66+
67+
#[cfg(test)]
68+
mod tests {
69+
use super::*;
70+
71+
#[test]
72+
fn file_stem_exactly_matches_readme_case_insensitively() {
73+
let path = "path/to/Readme.md";
74+
assert!(is_readme_file(path));
75+
76+
let path = "path/to/README.md";
77+
assert!(is_readme_file(path));
78+
79+
let path = "path/to/rEaDmE.md";
80+
assert!(is_readme_file(path));
81+
82+
let path = "path/to/README.markdown";
83+
assert!(is_readme_file(path));
84+
85+
let path = "path/to/README";
86+
assert!(is_readme_file(path));
87+
88+
let path = "path/to/README-README.md";
89+
assert!(!is_readme_file(path));
90+
}
91+
}

0 commit comments

Comments
 (0)