Auto merge of #142910 - yotamofek:pr/rustdoc/markdown-lazy-to-string, r=GuillaumeGomez
Lazy-ify some markdown rendering
Seems to have a positive effect in my local perf runs 😍
r? `@GuillaumeGomez` if you're interested, otherwise feel free to reassign
(would also love a perf run)
This commit is contained in:
commit
9e64506923
5 changed files with 83 additions and 86 deletions
|
|
@ -35,10 +35,9 @@ impl ExternalHtml {
|
|||
) -> Option<ExternalHtml> {
|
||||
let codes = ErrorCodes::from(nightly_build);
|
||||
let ih = load_external_files(in_header, dcx)?;
|
||||
let bc = load_external_files(before_content, dcx)?;
|
||||
let m_bc = load_external_files(md_before_content, dcx)?;
|
||||
let bc = format!(
|
||||
"{bc}{}",
|
||||
let bc = {
|
||||
let mut bc = load_external_files(before_content, dcx)?;
|
||||
let m_bc = load_external_files(md_before_content, dcx)?;
|
||||
Markdown {
|
||||
content: &m_bc,
|
||||
links: &[],
|
||||
|
|
@ -48,12 +47,13 @@ impl ExternalHtml {
|
|||
playground,
|
||||
heading_offset: HeadingOffset::H2,
|
||||
}
|
||||
.into_string()
|
||||
);
|
||||
let ac = load_external_files(after_content, dcx)?;
|
||||
let m_ac = load_external_files(md_after_content, dcx)?;
|
||||
let ac = format!(
|
||||
"{ac}{}",
|
||||
.write_into(&mut bc)
|
||||
.unwrap();
|
||||
bc
|
||||
};
|
||||
let ac = {
|
||||
let mut ac = load_external_files(after_content, dcx)?;
|
||||
let m_ac = load_external_files(md_after_content, dcx)?;
|
||||
Markdown {
|
||||
content: &m_ac,
|
||||
links: &[],
|
||||
|
|
@ -63,8 +63,10 @@ impl ExternalHtml {
|
|||
playground,
|
||||
heading_offset: HeadingOffset::H2,
|
||||
}
|
||||
.into_string()
|
||||
);
|
||||
.write_into(&mut ac)
|
||||
.unwrap();
|
||||
ac
|
||||
};
|
||||
Some(ExternalHtml { in_header: ih, before_content: bc, after_content: ac })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,13 +21,14 @@
|
|||
//! playground: &None,
|
||||
//! heading_offset: HeadingOffset::H2,
|
||||
//! };
|
||||
//! let html = md.into_string();
|
||||
//! let mut html = String::new();
|
||||
//! md.write_into(&mut html).unwrap();
|
||||
//! // ... something using html
|
||||
//! ```
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::collections::VecDeque;
|
||||
use std::fmt::Write;
|
||||
use std::fmt::{self, Write};
|
||||
use std::iter::Peekable;
|
||||
use std::ops::{ControlFlow, Range};
|
||||
use std::path::PathBuf;
|
||||
|
|
@ -1328,16 +1329,13 @@ impl LangString {
|
|||
}
|
||||
|
||||
impl<'a> Markdown<'a> {
|
||||
pub fn into_string(self) -> String {
|
||||
pub fn write_into(self, f: impl fmt::Write) -> fmt::Result {
|
||||
// This is actually common enough to special-case
|
||||
if self.content.is_empty() {
|
||||
return String::new();
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut s = String::with_capacity(self.content.len() * 3 / 2);
|
||||
html::push_html(&mut s, self.into_iter());
|
||||
|
||||
s
|
||||
html::write_html_fmt(f, self.into_iter())
|
||||
}
|
||||
|
||||
fn into_iter(self) -> CodeBlocks<'a, 'a, impl Iterator<Item = Event<'a>>> {
|
||||
|
|
@ -1453,19 +1451,20 @@ impl MarkdownWithToc<'_> {
|
|||
|
||||
(toc.into_toc(), s)
|
||||
}
|
||||
pub(crate) fn into_string(self) -> String {
|
||||
|
||||
pub(crate) fn write_into(self, mut f: impl fmt::Write) -> fmt::Result {
|
||||
let (toc, s) = self.into_parts();
|
||||
format!("<nav id=\"rustdoc\">{toc}</nav>{s}", toc = toc.print())
|
||||
write!(f, "<nav id=\"rustdoc\">{toc}</nav>{s}", toc = toc.print())
|
||||
}
|
||||
}
|
||||
|
||||
impl MarkdownItemInfo<'_> {
|
||||
pub(crate) fn into_string(self) -> String {
|
||||
pub(crate) fn write_into(self, mut f: impl fmt::Write) -> fmt::Result {
|
||||
let MarkdownItemInfo(md, ids) = self;
|
||||
|
||||
// This is actually common enough to special-case
|
||||
if md.is_empty() {
|
||||
return String::new();
|
||||
return Ok(());
|
||||
}
|
||||
let p = Parser::new_ext(md, main_body_opts()).into_offset_iter();
|
||||
|
||||
|
|
@ -1475,8 +1474,6 @@ impl MarkdownItemInfo<'_> {
|
|||
_ => event,
|
||||
});
|
||||
|
||||
let mut s = String::with_capacity(md.len() * 3 / 2);
|
||||
|
||||
ids.handle_footnotes(|ids, existing_footnotes| {
|
||||
let p = HeadingLinks::new(p, None, ids, HeadingOffset::H1);
|
||||
let p = footnotes::Footnotes::new(p, existing_footnotes);
|
||||
|
|
@ -1484,10 +1481,8 @@ impl MarkdownItemInfo<'_> {
|
|||
let p = p.filter(|event| {
|
||||
!matches!(event, Event::Start(Tag::Paragraph) | Event::End(TagEnd::Paragraph))
|
||||
});
|
||||
html::push_html(&mut s, p);
|
||||
});
|
||||
|
||||
s
|
||||
html::write_html_fmt(&mut f, p)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -297,7 +297,8 @@ fn test_lang_string_tokenizer() {
|
|||
fn test_header() {
|
||||
fn t(input: &str, expect: &str) {
|
||||
let mut map = IdMap::new();
|
||||
let output = Markdown {
|
||||
let mut output = String::new();
|
||||
Markdown {
|
||||
content: input,
|
||||
links: &[],
|
||||
ids: &mut map,
|
||||
|
|
@ -306,7 +307,8 @@ fn test_header() {
|
|||
playground: &None,
|
||||
heading_offset: HeadingOffset::H2,
|
||||
}
|
||||
.into_string();
|
||||
.write_into(&mut output)
|
||||
.unwrap();
|
||||
assert_eq!(output, expect, "original: {}", input);
|
||||
}
|
||||
|
||||
|
|
@ -348,7 +350,8 @@ fn test_header() {
|
|||
fn test_header_ids_multiple_blocks() {
|
||||
let mut map = IdMap::new();
|
||||
fn t(map: &mut IdMap, input: &str, expect: &str) {
|
||||
let output = Markdown {
|
||||
let mut output = String::new();
|
||||
Markdown {
|
||||
content: input,
|
||||
links: &[],
|
||||
ids: map,
|
||||
|
|
@ -357,7 +360,8 @@ fn test_header_ids_multiple_blocks() {
|
|||
playground: &None,
|
||||
heading_offset: HeadingOffset::H2,
|
||||
}
|
||||
.into_string();
|
||||
.write_into(&mut output)
|
||||
.unwrap();
|
||||
assert_eq!(output, expect, "original: {}", input);
|
||||
}
|
||||
|
||||
|
|
@ -466,7 +470,8 @@ fn test_plain_text_summary() {
|
|||
fn test_markdown_html_escape() {
|
||||
fn t(input: &str, expect: &str) {
|
||||
let mut idmap = IdMap::new();
|
||||
let output = MarkdownItemInfo(input, &mut idmap).into_string();
|
||||
let mut output = String::new();
|
||||
MarkdownItemInfo(input, &mut idmap).write_into(&mut output).unwrap();
|
||||
assert_eq!(output, expect, "original: {}", input);
|
||||
}
|
||||
|
||||
|
|
@ -496,7 +501,8 @@ fn test_find_testable_code_line() {
|
|||
fn test_ascii_with_prepending_hashtag() {
|
||||
fn t(input: &str, expect: &str) {
|
||||
let mut map = IdMap::new();
|
||||
let output = Markdown {
|
||||
let mut output = String::new();
|
||||
Markdown {
|
||||
content: input,
|
||||
links: &[],
|
||||
ids: &mut map,
|
||||
|
|
@ -505,7 +511,8 @@ fn test_ascii_with_prepending_hashtag() {
|
|||
playground: &None,
|
||||
heading_offset: HeadingOffset::H2,
|
||||
}
|
||||
.into_string();
|
||||
.write_into(&mut output)
|
||||
.unwrap();
|
||||
assert_eq!(output, expect, "original: {}", input);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -508,22 +508,21 @@ fn scrape_examples_help(shared: &SharedContext<'_>) -> String {
|
|||
the Rustdoc book]({DOC_RUST_LANG_ORG_VERSION}/rustdoc/scraped-examples.html)."
|
||||
));
|
||||
|
||||
let mut ids = IdMap::default();
|
||||
format!(
|
||||
"<div class=\"main-heading\">\
|
||||
<h1>About scraped examples</h1>\
|
||||
</div>\
|
||||
<div>{}</div>",
|
||||
Markdown {
|
||||
fmt::from_fn(|f| Markdown {
|
||||
content: &content,
|
||||
links: &[],
|
||||
ids: &mut ids,
|
||||
ids: &mut IdMap::default(),
|
||||
error_codes: shared.codes,
|
||||
edition: shared.edition(),
|
||||
playground: &shared.playground,
|
||||
heading_offset: HeadingOffset::H1,
|
||||
}
|
||||
.into_string()
|
||||
.write_into(f))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -555,20 +554,18 @@ fn render_markdown(
|
|||
heading_offset: HeadingOffset,
|
||||
) -> impl fmt::Display {
|
||||
fmt::from_fn(move |f| {
|
||||
write!(
|
||||
f,
|
||||
"<div class=\"docblock\">{}</div>",
|
||||
Markdown {
|
||||
content: md_text,
|
||||
links: &links,
|
||||
ids: &mut cx.id_map.borrow_mut(),
|
||||
error_codes: cx.shared.codes,
|
||||
edition: cx.shared.edition(),
|
||||
playground: &cx.shared.playground,
|
||||
heading_offset,
|
||||
}
|
||||
.into_string()
|
||||
)
|
||||
f.write_str("<div class=\"docblock\">")?;
|
||||
Markdown {
|
||||
content: md_text,
|
||||
links: &links,
|
||||
ids: &mut cx.id_map.borrow_mut(),
|
||||
error_codes: cx.shared.codes,
|
||||
edition: cx.shared.edition(),
|
||||
playground: &cx.shared.playground,
|
||||
heading_offset,
|
||||
}
|
||||
.write_into(&mut *f)?;
|
||||
f.write_str("</div>")
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -752,7 +749,7 @@ fn short_item_info(
|
|||
let mut id_map = cx.id_map.borrow_mut();
|
||||
let html = MarkdownItemInfo(note, &mut id_map);
|
||||
message.push_str(": ");
|
||||
message.push_str(&html.into_string());
|
||||
html.write_into(&mut message).unwrap();
|
||||
}
|
||||
extra_info.push(ShortItemInfo::Deprecation { message });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
//!
|
||||
//! [docs]: https://doc.rust-lang.org/stable/rustdoc/#using-standalone-markdown-files
|
||||
|
||||
use std::fmt::Write as _;
|
||||
use std::fmt::{self, Write as _};
|
||||
use std::fs::{File, create_dir_all, read_to_string};
|
||||
use std::io::prelude::*;
|
||||
use std::path::Path;
|
||||
|
|
@ -77,32 +77,33 @@ pub(crate) fn render_and_write<P: AsRef<Path>>(
|
|||
}
|
||||
let title = metadata[0];
|
||||
|
||||
let mut ids = IdMap::new();
|
||||
let error_codes = ErrorCodes::from(options.unstable_features.is_nightly_build());
|
||||
let text = if !options.markdown_no_toc {
|
||||
MarkdownWithToc {
|
||||
content: text,
|
||||
links: &[],
|
||||
ids: &mut ids,
|
||||
error_codes,
|
||||
edition,
|
||||
playground: &playground,
|
||||
let text = fmt::from_fn(|f| {
|
||||
if !options.markdown_no_toc {
|
||||
MarkdownWithToc {
|
||||
content: text,
|
||||
links: &[],
|
||||
ids: &mut IdMap::new(),
|
||||
error_codes,
|
||||
edition,
|
||||
playground: &playground,
|
||||
}
|
||||
.write_into(f)
|
||||
} else {
|
||||
Markdown {
|
||||
content: text,
|
||||
links: &[],
|
||||
ids: &mut IdMap::new(),
|
||||
error_codes,
|
||||
edition,
|
||||
playground: &playground,
|
||||
heading_offset: HeadingOffset::H1,
|
||||
}
|
||||
.write_into(f)
|
||||
}
|
||||
.into_string()
|
||||
} else {
|
||||
Markdown {
|
||||
content: text,
|
||||
links: &[],
|
||||
ids: &mut ids,
|
||||
error_codes,
|
||||
edition,
|
||||
playground: &playground,
|
||||
heading_offset: HeadingOffset::H1,
|
||||
}
|
||||
.into_string()
|
||||
};
|
||||
});
|
||||
|
||||
let err = write!(
|
||||
let res = write!(
|
||||
&mut out,
|
||||
r#"<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
|
@ -130,15 +131,10 @@ pub(crate) fn render_and_write<P: AsRef<Path>>(
|
|||
</body>
|
||||
</html>"#,
|
||||
title = Escape(title),
|
||||
css = css,
|
||||
in_header = options.external_html.in_header,
|
||||
before_content = options.external_html.before_content,
|
||||
text = text,
|
||||
after_content = options.external_html.after_content,
|
||||
);
|
||||
|
||||
match err {
|
||||
Err(e) => Err(format!("cannot write to `{output}`: {e}", output = output.display())),
|
||||
Ok(_) => Ok(()),
|
||||
}
|
||||
res.map_err(|e| format!("cannot write to `{output}`: {e}", output = output.display()))
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue