1+ use std:: path:: Path ;
2+ use regex:: Regex ;
3+
14use errors:: * ;
25
36use 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