-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
WIP: Add support for virtual chapters #592
Conversation
src/book/book.rs
Outdated
/// The chapter's name. | ||
pub name: String, | ||
/// The chapter's contents. | ||
pub content: String, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any content in a virtual chapter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't believe so. A virtual chapter just has a name, maybe a number, and a bunch of sub-items.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any content in a virtual chapter?
This was actually a question somewhere else in a // TODO
. I will remove the field.
src/book/book.rs
Outdated
Ok(ch) | ||
/* TODO Open question: Do we really want to return a `Result<_>` here? | ||
* Pro: Function would have almost signature as load_chapter() | ||
* Con: We do not use it! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But we do use it. When you call load_summary_item
recursively on the sub-items you return an error if any of the sub-items error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. I overlooked the ?
-operator in line 284. Thanks!
/// | ||
/// This is roughly the equivalent of `- Some virtual section`. | ||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] | ||
pub struct VirtualLink { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would the difference be between a normal link and a virtual one? My understanding is you'd write a normal link as - [Some Chapter](./chapter.md)
and a virtual link as - [Some Chapter]()
(i.e. virtual chapters have no link in SUMMARY.md
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think, that is an important design decision to make!
I propose that a user can write
- [Some Chapter](./chapter.md)
for a link and- both
- Some virtual chapter
and- [Some virtual chapter]()
for a virtual link.
Maybe, we could add a lint for - [Some virtual chapter]()
but I would rather not do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the moment, I've only implemented parsing - [Some virtual chapter]()
. - Some virtual chapter
seems to be more tricky, therefore I would like to have a decision before going on... ;-)
The parser seems to work -- at least for syntax A. Unfortunately, I have no idea where to start with the renderer. Can someone mentor me through? |
last_link.nested_items = sub_items; | ||
}, | ||
SummaryItem::Separator => unreachable!(), | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't really like this match because of the code duplication. Some ideas on how to make it nicer?
link.number = Some(number); | ||
}, | ||
SummaryItem::Separator => panic!(), | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another match. Same problem.
You mentioned there are a lot of redundant |
I believe the main thing we need to do on the renderer side is update the I think the navigation helpers should skip over a virtual chapter when you hit next/previous, although I'd have to have another look at the code to see how you are meant to do that. |
My thoughts are:
I am really unsure which solution is better. @azerupi What do you think? |
Yeah I think we should definitely have a separate item in the enum to represent those empty chapters. I am not up to date with the summary loading code however, so I don't have an opinion there. |
@@ -128,16 +128,24 @@ where | |||
pub enum BookItem { | |||
/// A nested chapter. | |||
Chapter(Chapter), | |||
/// A nested virtual chapter. | |||
VirtualChapter(VirtualChapter), | |||
/// A section separator. | |||
Separator, |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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!
Hey @teiesti, were you wanting any help with the rendering side of things? |
@Michael-F-Bryan: Yes. By the way: Sorry for being inactive. I was busy learning for some university exams. |
Status of this PR? (If it stays inactive, I'll try to complete it myself. This feature is important) |
I am still waiting for help on the rendering side. If you want to give it a try, don't hesitate. Your work is appreciated... :-) |
@teiesti, what do you think you'll need help with from the rendering side? I believe it should be enough to update the You'll probably want to write a test or two in either the TOC helper or as part of the integration test suite to make sure virtual chapters get added to the TOC but don't contain links to anywhere. |
I was thinking about this pull request again, and it seems that I won't have time for it soon. So, if anyone wants to take over, your welcome. Otherwise, I'll keep this open and try to complete my work when time is less rare. But this won't be in near future. Sorry... |
Hm. It finds out, I have to deal with that 100 lines long How unfortunate. |
This includes: - Use 'Self' instead of '<type name>' where possible. - Match enums in order of their variants.
This includes - a modification to parse_a_link() since parse_link() was modified and renamed to parse_item(), - a new test parse_a_virtual_link() and - the removal of an_empty_link_location_is_an_error() since an empty link location is parsed into a 'VirtualLink' from now on.
parse_nested_item() had to be adapted.
I rebased this PR onto the latest master. The renderer actually still had support for "virtual chapters" from before. So I just added virtual chapters as chapters without a path when making the context for handlebars and it just worked as before. I am sure it can be improved to make it more robust, but I propose that we merge this as is and improve it in further PRs. Edit: I found a bug testing this. If the first chapter is a virtual chapter, the index.html will not be created. We should probably create an empty landing page only containing the TOC. |
@Michael-F-Bryan could you review this when you have some time? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the changes, I believe we've covered everything necessary to add virtual chapters. @azerupi have you tried using this branch for your project?
When I get time I might come back and tidy up the parsing. The initial recursive descent approach gets the job done, but it can lead to some pretty confusing code and lots of redundant match statements. Since then I've gotten a lot better at parsing and we can probably feed the output from pulldown-cmark
into lalrpop
to make it all a lot nicer.
BookItem::Separator => { | ||
chapter.insert("spacer".to_owned(), json!("_spacer_")); | ||
} | ||
_ => unimplemented!(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of a catch-all _
we should probably change it to __NonExhaustive => unreachable!()
, that way we can't accidentally forget to update this match statement when the BookItem
enum gets updated.
|
||
link.number = Some(number); | ||
}, | ||
SummaryItem::Separator => panic!(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For consistency with the previous SummaryItem::Separator
(line 438) , this should probably be changed to unreachable!()
.
.filter_map(|(i, item)| item.maybe_link_mut().map(|l| (i, l))) | ||
.filter(|&(_, ref item)| { | ||
match **item { | ||
SummaryItem::Link(_) => true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can actually be condensed a bit.
SummaryItem::Link(_) | SummaryItem::VirtualLink(_) => true,
SummaryItem::Separator => false,
|
||
let href = match parser.stream.next() { | ||
Some(Event::Start(Tag::Link(href, _))) => href, | ||
other => panic!("Unreachable, {:?}", other), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you mean unreachable!()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose it has been written like this to offer more context in case the test fails.
Thanks for the review!
I have, it works great on the books I tried it on :) |
@teiesti do you want to continue with this? else it will be a good idea to close it and open a new PR when you feel like doing it again. Thanks for contributing |
@Dylan-DPC I think, it was way overdue to close this PR, cause it was laying around bitrotting. I still want to finish this work but in fact I won't have time anytime soon. |
Beware: This is currently WIP.
This pull request introduces virtual chapters which do not correspondent to a file on disk. Virtual chapters can be used for namespacing purposes since they have an entry in the
SUMMARY.md
and the rendered navigation on the left side.Work to be done:
BookItem
andSummaryItem
.- [Some virtual chapter]()
- Some virtual chapter
if desired (Design decision pending!)Closes #483.
Closes #576.