cross-link by section number if TOC are structurally the same

This commit is contained in:
Gambhiro 2017-01-16 21:01:34 +00:00
parent badc921429
commit aa54d95a23
4 changed files with 118 additions and 28 deletions

View File

@ -430,11 +430,11 @@ impl MDBook {
.map(|item| { .map(|item| {
match *item { match *item {
TocItem::Numbered(ref i) => 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(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(ref i) =>
TocItem::Unlisted(self.set_translation_links(i)), TocItem::Unlisted(self.set_translation_links(i, key.to_owned())),
TocItem::Spacer => TocItem::Spacer =>
TocItem::Spacer, TocItem::Spacer,
} }
@ -475,7 +475,7 @@ impl MDBook {
Some(default_links) 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<String, TranslationLink> = BTreeMap::new(); let mut final_links: BTreeMap<String, TranslationLink> = BTreeMap::new();
let mut newcontent: TocContent = content.clone(); let mut newcontent: TocContent = content.clone();
@ -498,6 +498,9 @@ impl MDBook {
// Find a translation for the links that are still None // 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() { for (key, trl) in final_links.clone().iter() {
match trl.link { match trl.link {
Some(_) => { continue; }, Some(_) => { continue; },
@ -507,6 +510,8 @@ impl MDBook {
let b: &Book = self.translations.get(key).unwrap(); let b: &Book = self.translations.get(key).unwrap();
let flat_toc = toc::flat_toc(&b.toc); 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() { for item in flat_toc.iter() {
match *item { match *item {
TocItem::Numbered(ref i) | TocItem::Numbered(ref i) |
@ -515,7 +520,7 @@ impl MDBook {
// Note that this will also add a link to itself, which is good. // 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() { if let Some(mut a) = i.chapter.get_dest_path() {
// Join the path to the language code, i.e. en/tears.html // Join the path to the language code, i.e. en/tears.html
a = PathBuf::from(key.to_string()).join(a); a = PathBuf::from(key.to_string()).join(a);

View File

@ -55,8 +55,14 @@ 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 the user has set the same translation_id on them
if by_tr_id {
if let Some(ref a) = self.chapter.translation_id { if let Some(ref a) = self.chapter.translation_id {
if let Some(ref b) = checking.chapter.translation_id { if let Some(ref b) = checking.chapter.translation_id {
if a == b { if a == b {
@ -64,8 +70,10 @@ impl TocContent {
} }
} }
} }
}
// if src_path matches // if src_path matches
if by_src_path {
if let Some(ref a) = self.chapter.get_src_path() { if let Some(ref a) = self.chapter.get_src_path() {
if let Some(ref b) = checking.chapter.get_src_path() { if let Some(ref b) = checking.chapter.get_src_path() {
if a == b { if a == b {
@ -73,6 +81,22 @@ impl TocContent {
} }
} }
} }
}
// 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;
}
}
}
}
false false
} }
@ -115,3 +139,34 @@ pub fn flat_toc(toc: &Vec<TocItem>) -> Vec<TocItem> {
} }
flattened 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<TocItem>) -> 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
}

View File

@ -64,32 +64,28 @@ fn it_renders_multilanguage_book() {
assert!(s.contains("<a href=\"hu/index.html\">hu</a>")); assert!(s.contains("<a href=\"hu/index.html\">hu</a>"));
assert!(s.contains("<a href=\"fr/index.html\">fr</a>")); assert!(s.contains("<a href=\"fr/index.html\">fr</a>"));
// 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(); book_path = proj.translations.get("en").unwrap().config.get_dest();
chapter_path = book_path.join("rabbit-hole.html"); chapter_path = book_path.join("rabbit-hole.html");
s = utils::fs::file_to_string(&chapter_path).unwrap(); s = utils::fs::file_to_string(&chapter_path).unwrap();
assert!(s.contains("<a href=\"en/rabbit-hole.html\">en</a>"));
assert!(s.contains("<a href=\"hu/nyuszi.html\">hu</a>")); assert!(s.contains("<a href=\"hu/nyuszi.html\">hu</a>"));
assert!(s.contains("<a href=\"fr/terrier.html\">fr</a>")); assert!(s.contains("<a href=\"fr/terrier.html\">fr</a>"));
// 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("<a href=\"en/long-tale.html\">en</a>"));
assert!(s.contains("<span>fr</span>"));
assert!(s.contains("<a href=\"hu/tarka-farka.html\">hu</a>"));
// 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"); chapter_path = book_path.join("tears.html");
s = utils::fs::file_to_string(&chapter_path).unwrap(); s = utils::fs::file_to_string(&chapter_path).unwrap();
assert!(s.contains("<a href=\"en/tears.html\">en</a>")); assert!(s.contains("<a href=\"en/tears.html\">en</a>"));
assert!(s.contains("<a href=\"fr/tears.html\">fr</a>")); assert!(s.contains("<a href=\"fr/tears.html\">fr</a>"));
assert!(s.contains("<a href=\"hu/tears.html\">hu</a>")); assert!(s.contains("<a href=\"hu/tears.html\">hu</a>"));
chapter_path = book_path.join("long-tale.html");
s = utils::fs::file_to_string(&chapter_path).unwrap();
assert!(s.contains("<a href=\"en/long-tale.html\">en</a>"));
assert!(s.contains("<a href=\"fr/cocasse.html\">fr</a>"));
assert!(s.contains("<a href=\"hu/tarka-farka.html\">hu</a>"));
// Test if print.html is produced for each translations // Test if print.html is produced for each translations
book_path = proj.translations.get("en").unwrap().config.get_dest(); book_path = proj.translations.get("en").unwrap().config.get_dest();

View File

@ -1,7 +1,7 @@
#[cfg(test)] #[cfg(test)]
use book::chapter::Chapter; 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; use parse::summary::parse_level;
#[test] #[test]
@ -77,3 +77,37 @@ fn it_flattens_toc() {
assert_eq!(format!("{:#?}", result), expected); 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());
}