diff --git a/src/book/mod.rs b/src/book/mod.rs index 939dc67b..a0a244f4 100644 --- a/src/book/mod.rs +++ b/src/book/mod.rs @@ -430,11 +430,11 @@ impl MDBook { .map(|item| { match *item { TocItem::Numbered(ref i) => - TocItem::Numbered(self.set_translation_links(i)), + TocItem::Numbered(self.set_translation_links(i, key.to_owned())), TocItem::Unnumbered(ref i) => - TocItem::Unnumbered(self.set_translation_links(i)), + TocItem::Unnumbered(self.set_translation_links(i, key.to_owned())), TocItem::Unlisted(ref i) => - TocItem::Unlisted(self.set_translation_links(i)), + TocItem::Unlisted(self.set_translation_links(i, key.to_owned())), TocItem::Spacer => TocItem::Spacer, } @@ -475,7 +475,7 @@ impl MDBook { Some(default_links) } - fn set_translation_links(&mut self, content: &TocContent) -> TocContent { + fn set_translation_links(&mut self, content: &TocContent, key: String) -> TocContent { let mut final_links: BTreeMap = BTreeMap::new(); let mut newcontent: TocContent = content.clone(); @@ -498,6 +498,9 @@ impl MDBook { // Find a translation for the links that are still None + let orig_book: &Book = self.translations.get(&key).unwrap(); + let orig_toc_id = toc::toc_node_count_id(&orig_book.toc); + for (key, trl) in final_links.clone().iter() { match trl.link { Some(_) => { continue; }, @@ -507,6 +510,8 @@ impl MDBook { let b: &Book = self.translations.get(key).unwrap(); let flat_toc = toc::flat_toc(&b.toc); + let by_section: bool = toc::toc_node_count_id(&b.toc) == orig_toc_id; + for item in flat_toc.iter() { match *item { TocItem::Numbered(ref i) | @@ -515,7 +520,7 @@ impl MDBook { // Note that this will also add a link to itself, which is good. - if content.is_it_a_translation_of(i) { + if content.is_it_a_translation_of(i, true, true, by_section) { if let Some(mut a) = i.chapter.get_dest_path() { // Join the path to the language code, i.e. en/tears.html a = PathBuf::from(key.to_string()).join(a); diff --git a/src/book/toc.rs b/src/book/toc.rs index d7510b8b..08d3ea6b 100644 --- a/src/book/toc.rs +++ b/src/book/toc.rs @@ -55,21 +55,45 @@ impl TocContent { } } - pub fn is_it_a_translation_of(&self, checking: &TocContent) -> bool { + pub fn is_it_a_translation_of(&self, + checking: &TocContent, + by_tr_id: bool, + by_src_path: bool, + by_section: bool) -> bool { + // if the user has set the same translation_id on them - if let Some(ref a) = self.chapter.translation_id { - if let Some(ref b) = checking.chapter.translation_id { - if a == b { - return true; + if by_tr_id { + if let Some(ref a) = self.chapter.translation_id { + if let Some(ref b) = checking.chapter.translation_id { + if a == b { + return true; + } } } } // if src_path matches - if let Some(ref a) = self.chapter.get_src_path() { - if let Some(ref b) = checking.chapter.get_src_path() { - if a == b { - return true; + if by_src_path { + if let Some(ref a) = self.chapter.get_src_path() { + if let Some(ref b) = checking.chapter.get_src_path() { + if a == b { + return true; + } + } + } + } + + // if section string matches, useful when TOC structure matches but + // titles and paths are translated. Can test that with + // toc_node_count_id(). + if by_section { + if let Some(_) = self.section { + let a = self.section_as_string(); + if let Some(_) = checking.section { + let b = checking.section_as_string(); + if a == b { + return true; + } } } } @@ -115,3 +139,34 @@ pub fn flat_toc(toc: &Vec) -> Vec { } flattened } + +/// Produces a String that can be used to check if two TOCs have the same +/// structure. It recursively counts the items at each level, ignoring Spacer +/// items. +pub fn toc_node_count_id(toc: &Vec) -> String { + let mut counters = String::new(); + + let c = toc.iter().filter(|x| { + match **x { + TocItem::Spacer => { false }, + _ => { true }, + }}).count(); + + counters.push_str(&format!("{}", c)); + + for i in toc.iter() { + match *i { + TocItem::Numbered(ref x) | + TocItem::Unnumbered(ref x) | + TocItem::Unlisted(ref x) => { + if let Some(ref subs) = x.sub_items { + let a = toc_node_count_id(subs); + counters.push_str(&a); + } + }, + TocItem::Spacer => {}, + } + } + + counters +} diff --git a/src/tests/hbs_renderer_multilang.rs b/src/tests/hbs_renderer_multilang.rs index 5ce7ca5a..a9d58e28 100644 --- a/src/tests/hbs_renderer_multilang.rs +++ b/src/tests/hbs_renderer_multilang.rs @@ -64,32 +64,28 @@ fn it_renders_multilanguage_book() { assert!(s.contains("hu")); assert!(s.contains("fr")); - // Test if translation links given in the TOML header were rendered + // Test if translation links are found book_path = proj.translations.get("en").unwrap().config.get_dest(); + chapter_path = book_path.join("rabbit-hole.html"); s = utils::fs::file_to_string(&chapter_path).unwrap(); + assert!(s.contains("en")); assert!(s.contains("hu")); assert!(s.contains("fr")); - // Test if translation links by translation_id were found - - book_path = proj.translations.get("en").unwrap().config.get_dest(); - chapter_path = book_path.join("long-tale.html"); - s = utils::fs::file_to_string(&chapter_path).unwrap(); - assert!(s.contains("en")); - assert!(s.contains("fr")); - assert!(s.contains("hu")); - - // Test if translation links by src_path were found - - book_path = proj.translations.get("en").unwrap().config.get_dest(); chapter_path = book_path.join("tears.html"); s = utils::fs::file_to_string(&chapter_path).unwrap(); assert!(s.contains("en")); assert!(s.contains("fr")); assert!(s.contains("hu")); + chapter_path = book_path.join("long-tale.html"); + s = utils::fs::file_to_string(&chapter_path).unwrap(); + assert!(s.contains("en")); + assert!(s.contains("fr")); + assert!(s.contains("hu")); + // Test if print.html is produced for each translations book_path = proj.translations.get("en").unwrap().config.get_dest(); diff --git a/src/tests/toc_test.rs b/src/tests/toc_test.rs index a8fac14b..d4372fab 100644 --- a/src/tests/toc_test.rs +++ b/src/tests/toc_test.rs @@ -1,7 +1,7 @@ #[cfg(test)] use book::chapter::Chapter; -use book::toc::{TocItem, TocContent, flat_toc}; +use book::toc::{TocItem, TocContent, flat_toc, toc_node_count_id}; use parse::summary::parse_level; #[test] @@ -77,3 +77,37 @@ fn it_flattens_toc() { assert_eq!(format!("{:#?}", result), expected); } + +#[test] +fn it_counts_toc_id_string() { + let text = r#" +# Summary + +[Introduction](misc/introduction.md) + +- [mdBook](README.md) +- [Command Line Tool](cli/cli-tool.md) + - [init](cli/init.md) + - [build](cli/build.md) + - [watch](cli/watch.md) + - [serve](cli/serve.md) + - [test](cli/test.md) +- [Format](format/format.md) + - [SUMMARY.md](format/summary.md) + - [Configuration](format/config.md) + - [Theme](format/theme/theme.md) + - [index.hbs](format/theme/index-hbs.md) + - [Syntax highlighting](format/theme/syntax-highlighting.md) + - [MathJax Support](format/mathjax.md) + - [Rust code specific features](format/rust.md) +- [Rust Library](lib/lib.md) +----------- +[Contributors](misc/contributors.md) +"#; + + let toc = parse_level(&mut text.split('\n').collect(), 0, vec![0], true).unwrap(); + + let counters = toc_node_count_id(&toc); + + assert_eq!(counters, "6552".to_string()); +}