Skip to content

WIP: Add support for virtual chapters #592

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions book-example/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- [clean](cli/clean.md)
- [Format](format/format.md)
- [SUMMARY.md](format/summary.md)
- [Virtual Chapter]()
- [Configuration](format/config.md)
- [Theme](format/theme/theme.md)
- [index.hbs](format/theme/index-hbs.md)
Expand Down
1 change: 0 additions & 1 deletion src/bin/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use std::process::Command;
use clap::{App, ArgMatches, SubCommand};
use mdbook::MDBook;
use mdbook::errors::Result;
use mdbook::utils;
use mdbook::config;
use get_book_dir;

Expand Down
73 changes: 67 additions & 6 deletions src/book/book.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::collections::VecDeque;
use std::fs::{self, File};
use std::io::{Read, Write};

use super::summary::{parse_summary, Link, SectionNumber, Summary, SummaryItem};
use super::summary::{parse_summary, Link, SectionNumber, Summary, SummaryItem, VirtualLink};
use config::BuildConfig;
use errors::*;

Expand Down Expand Up @@ -129,16 +129,27 @@ where
pub enum BookItem {
/// A nested chapter.
Chapter(Chapter),
/// A nested virtual chapter.
VirtualChapter(VirtualChapter),
/// A section separator.
Separator,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While we're making breaking changes, it may be a good idea to add a variant:

// To make sure clients have a `_ =>` case
#[doc(hidden)]
__NonExhaustive,

to ensure client libraries can handle new enum variants.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. I will do that!

// To make sure clients have a `_ =>` case
#[doc(hidden)]
__NonExhaustive,
}

impl From<Chapter> for BookItem {
fn from(other: Chapter) -> BookItem {
fn from(other: Chapter) -> Self {
BookItem::Chapter(other)
}
}

impl From<VirtualChapter> for BookItem {
fn from(other: VirtualChapter) -> Self {
BookItem::VirtualChapter(other)
}
}

/// The representation of a "chapter", usually mapping to a single file on
/// disk however it may contain multiple sub-chapters.
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
Expand Down Expand Up @@ -175,6 +186,28 @@ impl Chapter {
}
}

/// The representation of a "virtual chapter", available for namespacing
/// purposes and not mapping to a file on disk.
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct VirtualChapter {
/// The chapter's name.
pub name: String,
/// The chapter's section number, if it has one.
pub number: Option<SectionNumber>,
/// Nested items.
pub sub_items: Vec<BookItem>,
}

impl VirtualChapter {
/// Create a new virtual chapter with the given name.
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
..Default::default()
}
}
}

/// Use the provided `Summary` to load a `Book` from disk.
///
/// You need to pass in the book's source directory because all the links in
Expand Down Expand Up @@ -212,6 +245,8 @@ fn load_summary_item<P: AsRef<Path>>(
SummaryItem::Link(ref link) => {
load_chapter(link, src_dir, parent_names).map(|c| BookItem::Chapter(c))
}
SummaryItem::VirtualLink(ref link) =>
load_virtual_chapter(link, src_dir, parent_names).map(VirtualChapter::into),
}
}

Expand Down Expand Up @@ -255,6 +290,23 @@ fn load_chapter<P: AsRef<Path>>(
Ok(ch)
}

fn load_virtual_chapter<P: AsRef<Path>>(link: &VirtualLink, src_dir: P, parent_names: Vec<String>) -> Result<VirtualChapter> {
debug!("Loading {}", link.name);
let src_dir = src_dir.as_ref();

let mut ch = VirtualChapter::new(&link.name);
ch.number = link.number.clone();

let sub_items = link.nested_items
.iter()
.map(|i| load_summary_item(i, src_dir, parent_names.clone()))
.collect::<Result<Vec<_>>>()?;

ch.sub_items = sub_items;

Ok(ch)
}

/// A depth-first iterator over the items in a book.
///
/// # Note
Expand All @@ -273,11 +325,20 @@ impl<'a> Iterator for BookItems<'a> {
fn next(&mut self) -> Option<Self::Item> {
let item = self.items.pop_front();

if let Some(&BookItem::Chapter(ref ch)) = item {
// if we wanted a breadth-first iterator we'd `extend()` here
for sub_item in ch.sub_items.iter().rev() {
self.items.push_front(sub_item);
match item {
Some(&BookItem::Chapter(ref ch)) => {
// if we wanted a breadth-first iterator we'd `extend()` here
for sub_item in ch.sub_items.iter().rev() {
self.items.push_front(sub_item);
}
},
Some(&BookItem::VirtualChapter(ref ch)) => {
// if we wanted a breadth-first iterator we'd `extend()` here
for sub_item in ch.sub_items.iter().rev() {
self.items.push_front(sub_item);
}
}
_ => {},
}

item
Expand Down
2 changes: 2 additions & 0 deletions src/book/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,9 @@ impl MDBook {
/// for item in book.iter() {
/// match *item {
/// BookItem::Chapter(ref chapter) => {},
/// BookItem::VirtualChapter(ref virtual_chapter) => {},
/// BookItem::Separator => {},
/// _ => {},
/// }
/// }
///
Expand Down
Loading