-
Notifications
You must be signed in to change notification settings - Fork 12.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
Replace hoedown with pull in rustdoc #40338
Conversation
(rust_highfive has picked a reviewer for you, use r? to override) |
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 will give this a real review tomorrow, but 🎊
src/librustdoc/html/markdown.rs
Outdated
@@ -179,8 +181,8 @@ extern { | |||
fn hoedown_document_free(md: *mut hoedown_document); | |||
|
|||
fn hoedown_buffer_new(unit: libc::size_t) -> *mut hoedown_buffer; | |||
fn hoedown_buffer_put(b: *mut hoedown_buffer, c: *const libc::c_char, | |||
n: libc::size_t); | |||
/*fn hoedown_buffer_put(b: *mut hoedown_buffer, c: *const libc::c_char, |
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.
Why leave this in but commented out?
src/librustdoc/html/markdown.rs
Outdated
@@ -594,7 +598,7 @@ impl<'a> fmt::Display for MarkdownHtml<'a> { | |||
} | |||
|
|||
pub fn plain_summary_line(md: &str) -> String { | |||
extern fn link(_ob: *mut hoedown_buffer, | |||
/*extern fn link(_ob: *mut hoedown_buffer, |
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.
same here
src/librustdoc/html/markdown.rs
Outdated
let mut register_header = None; | ||
'main: loop { | ||
let next_event = parser.next(); | ||
if let Some(event) = next_event { |
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.
If you made this:
let event = match next_event {
Some(event) => event,
None => break,
};
....
This would reduce the indentation
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.
At that point, couldn't this be a:
while let Some(event) = parser.next() {
...
}
9268ec6
to
2c33d62
Compare
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.
Seems good to me, though I agree with @frewsxcv 's comments about nesting
376b5dd
to
2537b41
Compare
This is now ready to review! |
src/librustdoc/html/markdown.rs
Outdated
let mut content = String::new(); | ||
loop { | ||
let event = parser.next(); | ||
if let Some(event) = event { |
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.
Could this could just be a for
loop?
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.
Agreed, this is for event in parser { match event { … } }
(see main review comment)
src/librustdoc/html/markdown.rs
Outdated
fn link(parser: &mut Parser, buffer: &mut String, url: &str, mut title: String) { | ||
loop { | ||
let event = parser.next(); | ||
if let Some(event) = event { |
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
loop?
src/librustdoc/html/markdown.rs
Outdated
let mut content = String::new(); | ||
loop { | ||
let event = parser.next(); | ||
if let Some(event) = event { |
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
loop?
src/librustdoc/html/markdown.rs
Outdated
use std::fmt::{self, Write}; | ||
use std::slice; | ||
//use std::slice; |
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.
Remove commented out imports
/// A unit struct which has the `fmt::Display` trait implemented. When | ||
/// formatted, this struct will emit the HTML corresponding to the rendered | ||
/// version of the contained markdown string. | ||
pub struct Markdown<'a>(pub &'a str); | ||
// The second parameter is whether we need a shorter version or not. |
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 is a "shorter version"?
Maybe this should be a struct with named fields instead of using unnamed fields
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.
yeah, boolean parameters are usually a code smell
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 I'd prefer an enum MarkdownOutputStyle { Compact, Fancy }
(or some other fitting variant names) instead of bool
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.
@killercup: Good idea!
src/librustdoc/html/markdown.rs
Outdated
@@ -26,13 +26,13 @@ | |||
|
|||
#![allow(non_camel_case_types)] | |||
|
|||
use libc; | |||
//use libc; |
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.
Do we still use the libc crate in rustdoc?
(b'0' <= c && c <= b'9') || | ||
c == b'-' || c == b'_' || c == b'.' || | ||
c == b'~' || c == b'!' || c == b'\'' || | ||
c == b'(' || c == b')' || c == b'*' |
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.
Pull in rust-url for this?
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 is not part of the change, however I can do it next up.
src/librustdoc/html/markdown.rs
Outdated
} | ||
|
||
fn looper<'a>(parser: &'a mut Parser, buffer: &mut String, next_event: Option<Event<'a>>, | ||
toc_builder: &mut Option<TocBuilder>, shorter: bool) -> bool { | ||
if let Some(event) = next_event { |
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.
Could return early here if this is None
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.
Doesn't change much from my point of view... I think this syntax is actually better.
/cc @raphlinus ❤️ |
So, I'm spot-checking some text to find regressions. std::collections module page std::convert module page prelude: some smooshed text std::sync::LockResult std::string that's what i found just now. we may need to tweak some text, and it's probably good to go through the whole entire thing once the technical side is good and clear up these kinds of issues. |
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.
Nice to see some progress here!
One pattern I immediately saw was all the loop
constructs matching the event and tag. I'd:
-
use Event::*
anduse Tag::*;
to reduce the visual noise -
Try to rewrite them as
let events = parser.$filter_relevant_events; for event in events { match event {…} }
, where$filter_relevant_events
are some operations on the iterator to get the events you are interested in (e.g., to usetake_while
instead of addingbreak
arms).FYI, I wrote a macro once for this exact use case to allow
events.take_while(not!(end Tag::Paragraph))
and similar. This may help converting most of these loops into nice iterators.You can find it and example using it here. You'll probably need to extend it to support multiple end tag variants as used below.
I'd also really try to get rid of the shorter: bool
stuff and replace with some semantically meaningful names :)
Switching parser is not something I expect to just work, even when both apparently conform to the CommonMark spec. Before merging this, I'd render a bunch of docs (std and some larger crates), and try to
- set up a script that opens and takes screenshots of all generated html pages to visually diff them with ones generated by the current stable rustdoc,
- or let humans look at the rendered pages,
- or do both 😄
src/Cargo.lock
Outdated
@@ -1203,6 +1203,7 @@ dependencies = [ | |||
"build_helper 0.1.0", | |||
"gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"log 0.0.0", | |||
"pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", |
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.
0.0.8… Another lib we should help get to 1.0
src/librustdoc/html/markdown.rs
Outdated
} | ||
} | ||
buffer.push_str(&format!("<table>{}{}</table>", | ||
content, | ||
if shorter || rows.is_empty() { |
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 this the only place where shorter
is actually used? The name shorter
does not imply "no tbody tag" to me…
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.
In paragraph as well. The point is to display only the first line, so everything that could be on more than one line use it.
/// A unit struct which has the `fmt::Display` trait implemented. When | ||
/// formatted, this struct will emit the HTML corresponding to the rendered | ||
/// version of the contained markdown string. | ||
pub struct Markdown<'a>(pub &'a str); | ||
// The second parameter is whether we need a shorter version or not. |
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 I'd prefer an enum MarkdownOutputStyle { Compact, Fancy }
(or some other fitting variant names) instead of bool
src/librustdoc/html/markdown.rs
Outdated
let mut content = String::new(); | ||
loop { | ||
let event = parser.next(); | ||
if let Some(event) = event { |
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.
Agreed, this is for event in parser { match event { … } }
(see main review comment)
_ => {} | ||
} | ||
} else { | ||
break 'main; |
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.
finally, a good reason not use a for loop ;)
Most problems should be solved now. I'll write a macro next to allow to remove all these loops. |
Is there any reason you're not using |
☔ The latest upstream changes (presumably #40432) made this pull request unmergeable. Please resolve the merge conflicts. |
@ollie27: Unfortunately yes: the generation of urls mainly (for play.rust-lang in blockcodes). |
"<", ">", "&", "'", """]; | ||
for sub in repl_sub { | ||
id = id.replace(sub, ""); | ||
} |
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.
shouldn't this mean the comment above goes away too?
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.
Absolutely!
c132361
to
8b61716
Compare
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.
Code looks nicer with the macro, though I'd probably make it more generic.
Also, why not use Event::*
and use Tag::*
?
@@ -104,6 +104,25 @@ thread_local!(pub static PLAYGROUND: RefCell<Option<(Option<String>, String)>> = | |||
RefCell::new(None) | |||
}); | |||
|
|||
macro_rules! event_loop_break { |
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.
Nice. I'd call it collect_md_events
, though, and make calling it a bit more expressive, e.g.
collect_md_events!(from parser into &mut buf (toc_builder, shorter) until End(Header(_)))
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.
Not sure if this is super useful. Anyone else has an opinion on it?
src/librustdoc/html/markdown.rs
Outdated
shorter: MarkdownOutputStyle) -> fmt::Result { | ||
fn block(parser: &mut Parser, buffer: &mut String, lang: &str) { | ||
let mut origtext = String::new(); | ||
while let Some(event) = parser.next() { |
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.
Could also be using the macro (e.g. when calling without toc builder and shorter)
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 didn't see much interest in expanding the macro to handle this case. But yes it's possible.
3c6a31f
to
7f190fe
Compare
Simply because I like the code being explicit. At least with this syntax, you don't have to think about it, the information is already there. |
You can still use |
83972b3
to
a7c6d3e
Compare
Updated. |
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 have a bunch of nitpicky style things, but they aren't important enough to hold up this PR any longer. Looks good to me!
@frewsxcv, @steveklabnik: Since both of you agreed on the changes, I'll r+ this PR. Don't hesitate to r- if you find anything! @bors: r=frewsxcv,steveklabnik |
📌 Commit a7c6d3e has been approved by |
…veklabnik Replace hoedown with pull in rustdoc cc @rust-lang/docs
☀️ Test successful - status-appveyor, status-travis |
Was this actually finished? It's missing support for horizontal rules, footnotes and images. There are also several bugs like missing the As I previously mentioned, using |
Have you confirmed any of these? I can bring up these concerns during today's Documentation Team meeting. |
Yes. Try rendering the following in the current rustdoc and after this change: /// markdown test
///
/// this is a [link].
///
/// [link]: https://example.com "this is a title"
///
/// hard break:
/// after hard break
///
/// -----------
///
/// a footnote[^footnote].
///
/// [^footnote]: Thing
///
/// ![Rust](https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png)
#[deprecated(note = "Struct<T>")]
pub fn f() {} |
Two things:
I don't think that this missing a few things is the end of the world; now that this has landed, fixing stuff up is much easier. We've still got plenty of time before the release; four weeks until beta, and then we could backport anything catastrophic. Getting this out in the wild sooner rather than later is important IMHO. |
Here is an un-semantic diff steveklabnik/docdiff@5d17061 |
A much prettier diff steveklabnik/docdiff@HEAD~1...master |
I've filed #40912 to track these regressions. 😄 |
Is it really time? Have our months, no, *years* of suffering come to an end? Are we finally able to cast off the pall of Hoedown? The weight which has dragged us down for so long? ----- So, timeline for those who need to catch up: * Way back in December 2016, [we decided we wanted to switch out the markdown renderer](rust-lang#38400). However, this was put on hold because the build system at the time made it difficult to pull in dependencies from crates.io. * A few months later, in March 2017, [the first PR was done, to switch out the renderers entirely](rust-lang#40338). The PR itself was fraught with CI and build system issues, but eventually landed. * However, not all was well in the Rustdoc world. During the PR and shortly after, we noticed [some differences in the way the two parsers handled some things](rust-lang#40912), and some of these differences were major enough to break the docs for some crates. * A couple weeks afterward, [Hoedown was put back in](rust-lang#41290), at this point just to catch tests that Pulldown was "spuriously" running. This would at least provide some warning about spurious tests, rather than just breaking spontaneously. * However, the problems had created enough noise by this point that just a few days after that, [Hoedown was switched back to the default](rust-lang#41431) while we came up with a solution for properly warning about the differences. * That solution came a few weeks later, [as a series of warnings when the HTML emitted by the two parsers was semantically different](rust-lang#41991). But that came at a cost, as now rustdoc needed proc-macro support (the new crate needed some custom derives farther down its dependency tree), and the build system was not equipped to handle it at the time. It was worked on for three months as the issue stumped more and more people. * In that time, [bootstrap was completely reworked](rust-lang#43059) to change how it ordered compilation, and [the method by which it built rustdoc would change](rust-lang#43482), as well. This allowed it to only be built after stage1, when proc-macros would be available, allowing the "rendering differences" PR to finally land. * The warnings were not perfect, and revealed a few [spurious](rust-lang#44368) [differences](rust-lang#45421) between how we handled the renderers. * Once these were handled, [we flipped the switch to turn on the "rendering difference" warnings all the time](rust-lang#45324), in October 2017. This began the "warning cycle" for this change, and landed in stable in 1.23, on 2018-01-04. * Once those warnings hit stable, and after a couple weeks of seeing whether we would get any more reports than what we got from sitting on nightly/beta, [we switched the renderers](rust-lang#47398), making Pulldown the default but still offering the option to use Hoedown. And that brings us to the present. We haven't received more new issues from this in the meantime, and the "switch by default" is now on beta. Our reasoning is that, at this point, anyone who would have been affected by this has run into it already.
cc @rust-lang/docs