1
Fork 0

Rollup merge of #89506 - yaymukund:docblock-headings, r=GuillaumeGomez

librustdoc: Use correct heading levels.

Closes #89309

This fixes the `<h#>` header tags throughout the docs to reflect a semantic hierarchy.

- I ran a script to manually check that we don't have any files with multiple `<h1>` tags.
- Also checked that we never incorrectly nest e.g. a `<h2>` under an `<h3>`.
- I also spot-checked a bunch of pages (`trait.Read`, `enum.Ordering`, `primitive.isize`, `trait.Iterator`).
This commit is contained in:
Manish Goregaokar 2021-10-06 12:33:20 -07:00 committed by GitHub
commit 7d6feb421e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 264 additions and 122 deletions

View file

@ -1,4 +1,4 @@
use crate::html::markdown::{ErrorCodes, IdMap, Markdown, Playground};
use crate::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground};
use crate::rustc_span::edition::Edition;
use std::fs;
use std::path::Path;
@ -39,14 +39,32 @@ impl ExternalHtml {
let bc = format!(
"{}{}",
bc,
Markdown(&m_bc, &[], id_map, codes, edition, playground).into_string()
Markdown {
content: &m_bc,
links: &[],
ids: id_map,
error_codes: codes,
edition,
playground,
heading_offset: HeadingOffset::H2,
}
.into_string()
);
let ac = load_external_files(after_content, diag)?;
let m_ac = load_external_files(md_after_content, diag)?;
let ac = format!(
"{}{}",
ac,
Markdown(&m_ac, &[], id_map, codes, edition, playground).into_string()
Markdown {
content: &m_ac,
links: &[],
ids: id_map,
error_codes: codes,
edition,
playground,
heading_offset: HeadingOffset::H2,
}
.into_string()
);
Some(ExternalHtml { in_header: ih, before_content: bc, after_content: ac })
}

View file

@ -8,11 +8,19 @@
//! extern crate rustc_span;
//!
//! use rustc_span::edition::Edition;
//! use rustdoc::html::markdown::{IdMap, Markdown, ErrorCodes};
//! use rustdoc::html::markdown::{HeadingOffset, IdMap, Markdown, ErrorCodes};
//!
//! let s = "My *markdown* _text_";
//! let mut id_map = IdMap::new();
//! let md = Markdown(s, &[], &mut id_map, ErrorCodes::Yes, Edition::Edition2015, &None);
//! let md = Markdown {
//! content: s,
//! links: &[],
//! ids: &mut id_map,
//! error_codes: ErrorCodes::Yes,
//! edition: Edition::Edition2015,
//! playground: &None,
//! heading_offset: HeadingOffset::H2,
//! };
//! let html = md.into_string();
//! // ... something using html
//! ```
@ -47,6 +55,8 @@ use pulldown_cmark::{
#[cfg(test)]
mod tests;
const MAX_HEADER_LEVEL: u32 = 6;
/// Options for rendering Markdown in the main body of documentation.
pub(crate) fn main_body_opts() -> Options {
Options::ENABLE_TABLES
@ -65,20 +75,33 @@ pub(crate) fn summary_opts() -> Options {
| Options::ENABLE_SMART_PUNCTUATION
}
#[derive(Debug, Clone, Copy)]
pub enum HeadingOffset {
H1 = 0,
H2,
H3,
H4,
H5,
H6,
}
/// When `to_string` is called, this struct will emit the HTML corresponding to
/// the rendered version of the contained markdown string.
pub struct Markdown<'a>(
pub &'a str,
pub struct Markdown<'a> {
pub content: &'a str,
/// A list of link replacements.
pub &'a [RenderedLink],
pub links: &'a [RenderedLink],
/// The current list of used header IDs.
pub &'a mut IdMap,
pub ids: &'a mut IdMap,
/// Whether to allow the use of explicit error codes in doctest lang strings.
pub ErrorCodes,
pub error_codes: ErrorCodes,
/// Default edition to use when parsing doctests (to add a `fn main`).
pub Edition,
pub &'a Option<Playground>,
);
pub edition: Edition,
pub playground: &'a Option<Playground>,
/// Offset at which we render headings.
/// E.g. if `heading_offset: HeadingOffset::H2`, then `# something` renders an `<h2>`.
pub heading_offset: HeadingOffset,
}
/// A tuple struct like `Markdown` that renders the markdown with a table of contents.
crate struct MarkdownWithToc<'a>(
crate &'a str,
@ -489,11 +512,17 @@ struct HeadingLinks<'a, 'b, 'ids, I> {
toc: Option<&'b mut TocBuilder>,
buf: VecDeque<SpannedEvent<'a>>,
id_map: &'ids mut IdMap,
heading_offset: HeadingOffset,
}
impl<'a, 'b, 'ids, I> HeadingLinks<'a, 'b, 'ids, I> {
fn new(iter: I, toc: Option<&'b mut TocBuilder>, ids: &'ids mut IdMap) -> Self {
HeadingLinks { inner: iter, toc, buf: VecDeque::new(), id_map: ids }
fn new(
iter: I,
toc: Option<&'b mut TocBuilder>,
ids: &'ids mut IdMap,
heading_offset: HeadingOffset,
) -> Self {
HeadingLinks { inner: iter, toc, buf: VecDeque::new(), id_map: ids, heading_offset }
}
}
@ -530,6 +559,7 @@ impl<'a, 'b, 'ids, I: Iterator<Item = SpannedEvent<'a>>> Iterator
self.buf.push_front((Event::Html(format!("{} ", sec).into()), 0..0));
}
let level = std::cmp::min(level + (self.heading_offset as u32), MAX_HEADER_LEVEL);
self.buf.push_back((Event::Html(format!("</a></h{}>", level).into()), 0..0));
let start_tags = format!(
@ -1005,7 +1035,15 @@ impl LangString {
impl Markdown<'_> {
pub fn into_string(self) -> String {
let Markdown(md, links, mut ids, codes, edition, playground) = self;
let Markdown {
content: md,
links,
mut ids,
error_codes: codes,
edition,
playground,
heading_offset,
} = self;
// This is actually common enough to special-case
if md.is_empty() {
@ -1026,7 +1064,7 @@ impl Markdown<'_> {
let mut s = String::with_capacity(md.len() * 3 / 2);
let p = HeadingLinks::new(p, None, &mut ids);
let p = HeadingLinks::new(p, None, &mut ids, heading_offset);
let p = Footnotes::new(p);
let p = LinkReplacer::new(p.map(|(ev, _)| ev), links);
let p = TableWrapper::new(p);
@ -1048,7 +1086,7 @@ impl MarkdownWithToc<'_> {
let mut toc = TocBuilder::new();
{
let p = HeadingLinks::new(p, Some(&mut toc), &mut ids);
let p = HeadingLinks::new(p, Some(&mut toc), &mut ids, HeadingOffset::H1);
let p = Footnotes::new(p);
let p = TableWrapper::new(p.map(|(ev, _)| ev));
let p = CodeBlocks::new(p, codes, edition, playground);
@ -1077,7 +1115,7 @@ impl MarkdownHtml<'_> {
let mut s = String::with_capacity(md.len() * 3 / 2);
let p = HeadingLinks::new(p, None, &mut ids);
let p = HeadingLinks::new(p, None, &mut ids, HeadingOffset::H1);
let p = Footnotes::new(p);
let p = TableWrapper::new(p.map(|(ev, _)| ev));
let p = CodeBlocks::new(p, codes, edition, playground);
@ -1295,7 +1333,7 @@ crate fn markdown_links(md: &str) -> Vec<MarkdownLink> {
// There's no need to thread an IdMap through to here because
// the IDs generated aren't going to be emitted anywhere.
let mut ids = IdMap::new();
let iter = Footnotes::new(HeadingLinks::new(p, None, &mut ids));
let iter = Footnotes::new(HeadingLinks::new(p, None, &mut ids, HeadingOffset::H1));
for ev in iter {
if let Event::Start(Tag::Link(kind, dest, _)) = ev.0 {

View file

@ -1,5 +1,5 @@
use super::{find_testable_code, plain_text_summary, short_markdown_summary};
use super::{ErrorCodes, IdMap, Ignore, LangString, Markdown, MarkdownHtml};
use super::{ErrorCodes, HeadingOffset, IdMap, Ignore, LangString, Markdown, MarkdownHtml};
use rustc_span::edition::{Edition, DEFAULT_EDITION};
#[test]
@ -147,33 +147,41 @@ fn test_lang_string_tokenizer() {
fn test_header() {
fn t(input: &str, expect: &str) {
let mut map = IdMap::new();
let output =
Markdown(input, &[], &mut map, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string();
let output = Markdown {
content: input,
links: &[],
ids: &mut map,
error_codes: ErrorCodes::Yes,
edition: DEFAULT_EDITION,
playground: &None,
heading_offset: HeadingOffset::H2,
}
.into_string();
assert_eq!(output, expect, "original: {}", input);
}
t(
"# Foo bar",
"<h1 id=\"foo-bar\" class=\"section-header\"><a href=\"#foo-bar\">Foo bar</a></h1>",
"<h2 id=\"foo-bar\" class=\"section-header\"><a href=\"#foo-bar\">Foo bar</a></h2>",
);
t(
"## Foo-bar_baz qux",
"<h2 id=\"foo-bar_baz-qux\" class=\"section-header\">\
<a href=\"#foo-bar_baz-qux\">Foo-bar_baz qux</a></h2>",
"<h3 id=\"foo-bar_baz-qux\" class=\"section-header\">\
<a href=\"#foo-bar_baz-qux\">Foo-bar_baz qux</a></h3>",
);
t(
"### **Foo** *bar* baz!?!& -_qux_-%",
"<h3 id=\"foo-bar-baz--qux-\" class=\"section-header\">\
"<h4 id=\"foo-bar-baz--qux-\" class=\"section-header\">\
<a href=\"#foo-bar-baz--qux-\"><strong>Foo</strong> \
<em>bar</em> baz!?!&amp; -<em>qux</em>-%</a>\
</h3>",
</h4>",
);
t(
"#### **Foo?** & \\*bar?!* _`baz`_ ❤ #qux",
"<h4 id=\"foo--bar--baz--qux\" class=\"section-header\">\
"<h5 id=\"foo--bar--baz--qux\" class=\"section-header\">\
<a href=\"#foo--bar--baz--qux\"><strong>Foo?</strong> &amp; *bar?!* \
<em><code>baz</code></em> #qux</a>\
</h4>",
</h5>",
);
}
@ -181,40 +189,48 @@ 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(input, &[], map, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string();
let output = Markdown {
content: input,
links: &[],
ids: map,
error_codes: ErrorCodes::Yes,
edition: DEFAULT_EDITION,
playground: &None,
heading_offset: HeadingOffset::H2,
}
.into_string();
assert_eq!(output, expect, "original: {}", input);
}
t(
&mut map,
"# Example",
"<h1 id=\"example\" class=\"section-header\"><a href=\"#example\">Example</a></h1>",
"<h2 id=\"example\" class=\"section-header\"><a href=\"#example\">Example</a></h2>",
);
t(
&mut map,
"# Panics",
"<h1 id=\"panics\" class=\"section-header\"><a href=\"#panics\">Panics</a></h1>",
"<h2 id=\"panics\" class=\"section-header\"><a href=\"#panics\">Panics</a></h2>",
);
t(
&mut map,
"# Example",
"<h1 id=\"example-1\" class=\"section-header\"><a href=\"#example-1\">Example</a></h1>",
"<h2 id=\"example-1\" class=\"section-header\"><a href=\"#example-1\">Example</a></h2>",
);
t(
&mut map,
"# Main",
"<h1 id=\"main-1\" class=\"section-header\"><a href=\"#main-1\">Main</a></h1>",
"<h2 id=\"main-1\" class=\"section-header\"><a href=\"#main-1\">Main</a></h2>",
);
t(
&mut map,
"# Example",
"<h1 id=\"example-2\" class=\"section-header\"><a href=\"#example-2\">Example</a></h1>",
"<h2 id=\"example-2\" class=\"section-header\"><a href=\"#example-2\">Example</a></h2>",
);
t(
&mut map,
"# Panics",
"<h1 id=\"panics-1\" class=\"section-header\"><a href=\"#panics-1\">Panics</a></h1>",
"<h2 id=\"panics-1\" class=\"section-header\"><a href=\"#panics-1\">Panics</a></h2>",
);
}

View file

@ -67,7 +67,7 @@ use crate::html::format::{
href, print_abi_with_space, print_constness_with_space, print_default_space,
print_generic_bounds, print_where_clause, Buffer, HrefError, PrintWithSpace,
};
use crate::html::markdown::{Markdown, MarkdownHtml, MarkdownSummaryLine};
use crate::html::markdown::{HeadingOffset, Markdown, MarkdownHtml, MarkdownSummaryLine};
/// A pair of name and its optional document.
crate type NameDoc = (String, Option<String>);
@ -470,32 +470,45 @@ fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result<Strin
))
}
fn document(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, parent: Option<&clean::Item>) {
fn document(
w: &mut Buffer,
cx: &Context<'_>,
item: &clean::Item,
parent: Option<&clean::Item>,
heading_offset: HeadingOffset,
) {
if let Some(ref name) = item.name {
info!("Documenting {}", name);
}
document_item_info(w, cx, item, parent);
if parent.is_none() {
document_full_collapsible(w, item, cx);
document_full_collapsible(w, item, cx, heading_offset);
} else {
document_full(w, item, cx);
document_full(w, item, cx, heading_offset);
}
}
/// Render md_text as markdown.
fn render_markdown(w: &mut Buffer, cx: &Context<'_>, md_text: &str, links: Vec<RenderedLink>) {
fn render_markdown(
w: &mut Buffer,
cx: &Context<'_>,
md_text: &str,
links: Vec<RenderedLink>,
heading_offset: HeadingOffset,
) {
let mut ids = cx.id_map.borrow_mut();
write!(
w,
"<div class=\"docblock\">{}</div>",
Markdown(
md_text,
&links,
&mut ids,
cx.shared.codes,
cx.shared.edition(),
&cx.shared.playground
)
Markdown {
content: md_text,
links: &links,
ids: &mut ids,
error_codes: cx.shared.codes,
edition: cx.shared.edition(),
playground: &cx.shared.playground,
heading_offset,
}
.into_string()
)
}
@ -531,15 +544,31 @@ fn document_short(
}
}
fn document_full_collapsible(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>) {
document_full_inner(w, item, cx, true);
fn document_full_collapsible(
w: &mut Buffer,
item: &clean::Item,
cx: &Context<'_>,
heading_offset: HeadingOffset,
) {
document_full_inner(w, item, cx, true, heading_offset);
}
fn document_full(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>) {
document_full_inner(w, item, cx, false);
fn document_full(
w: &mut Buffer,
item: &clean::Item,
cx: &Context<'_>,
heading_offset: HeadingOffset,
) {
document_full_inner(w, item, cx, false, heading_offset);
}
fn document_full_inner(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>, is_collapsible: bool) {
fn document_full_inner(
w: &mut Buffer,
item: &clean::Item,
cx: &Context<'_>,
is_collapsible: bool,
heading_offset: HeadingOffset,
) {
if let Some(s) = cx.shared.maybe_collapsed_doc_value(item) {
debug!("Doc block: =====\n{}\n=====", s);
if is_collapsible {
@ -549,10 +578,10 @@ fn document_full_inner(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>, is_
<span>Expand description</span>\
</summary>",
);
render_markdown(w, cx, &s, item.links(cx));
render_markdown(w, cx, &s, item.links(cx), heading_offset);
w.write_str("</details>");
} else {
render_markdown(w, cx, &s, item.links(cx));
render_markdown(w, cx, &s, item.links(cx), heading_offset);
}
}
}
@ -1321,7 +1350,7 @@ fn render_impl(
// because impls can't have a stability.
if item.doc_value().is_some() {
document_item_info(&mut info_buffer, cx, it, Some(parent));
document_full(&mut doc_buffer, item, cx);
document_full(&mut doc_buffer, item, cx, HeadingOffset::H5);
short_documented = false;
} else {
// In case the item isn't documented,
@ -1339,7 +1368,7 @@ fn render_impl(
} else {
document_item_info(&mut info_buffer, cx, item, Some(parent));
if rendering_params.show_def_docs {
document_full(&mut doc_buffer, item, cx);
document_full(&mut doc_buffer, item, cx, HeadingOffset::H5);
short_documented = false;
}
}
@ -1573,14 +1602,15 @@ fn render_impl(
write!(
w,
"<div class=\"docblock\">{}</div>",
Markdown(
&*dox,
&i.impl_item.links(cx),
&mut ids,
cx.shared.codes,
cx.shared.edition(),
&cx.shared.playground
)
Markdown {
content: &*dox,
links: &i.impl_item.links(cx),
ids: &mut ids,
error_codes: cx.shared.codes,
edition: cx.shared.edition(),
playground: &cx.shared.playground,
heading_offset: HeadingOffset::H2
}
.into_string()
);
}

View file

@ -30,7 +30,7 @@ use crate::html::format::{
};
use crate::html::highlight;
use crate::html::layout::Page;
use crate::html::markdown::MarkdownSummaryLine;
use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
const ITEM_TABLE_OPEN: &'static str = "<div class=\"item-table\">";
const ITEM_TABLE_CLOSE: &'static str = "</div>";
@ -175,7 +175,7 @@ fn toggle_close(w: &mut Buffer) {
}
fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) {
document(w, cx, item, None);
document(w, cx, item, None, HeadingOffset::H2);
let mut indices = (0..items.len()).filter(|i| !items[*i].is_stripped()).collect::<Vec<usize>>();
@ -482,7 +482,7 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::
notable_traits = notable_traits_decl(&f.decl, cx),
);
});
document(w, cx, it, None)
document(w, cx, it, None, HeadingOffset::H2)
}
fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) {
@ -605,7 +605,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
});
// Trait documentation
document(w, cx, it, None);
document(w, cx, it, None, HeadingOffset::H2);
fn write_small_section_header(w: &mut Buffer, id: &str, title: &str, extra_content: &str) {
write!(
@ -623,7 +623,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
let item_type = m.type_();
let id = cx.derive_id(format!("{}.{}", item_type, name));
let mut content = Buffer::empty_from(w);
document(&mut content, cx, m, Some(t));
document(&mut content, cx, m, Some(t), HeadingOffset::H5);
let toggled = !content.is_empty();
if toggled {
write!(w, "<details class=\"rustdoc-toggle\" open><summary>");
@ -837,7 +837,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clea
);
});
document(w, cx, it, None);
document(w, cx, it, None, HeadingOffset::H2);
// Render any items associated directly to this alias, as otherwise they
// won't be visible anywhere in the docs. It would be nice to also show
@ -859,7 +859,7 @@ fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean:
);
});
document(w, cx, it, None);
document(w, cx, it, None, HeadingOffset::H2);
// Render any items associated directly to this alias, as otherwise they
// won't be visible anywhere in the docs. It would be nice to also show
@ -890,7 +890,7 @@ fn item_typedef(
);
});
document(w, cx, it, None);
document(w, cx, it, None, HeadingOffset::H2);
let def_id = it.def_id.expect_def_id();
// Render any items associated directly to this alias, as otherwise they
@ -908,7 +908,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
});
});
document(w, cx, it, None);
document(w, cx, it, None, HeadingOffset::H2);
let mut fields = s
.fields
@ -941,7 +941,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
if let Some(stability_class) = field.stability_class(cx.tcx()) {
write!(w, "<span class=\"stab {stab}\"></span>", stab = stability_class);
}
document(w, cx, field, Some(it));
document(w, cx, field, Some(it), HeadingOffset::H2);
}
}
let def_id = it.def_id.expect_def_id();
@ -1023,7 +1023,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
});
});
document(w, cx, it, None);
document(w, cx, it, None, HeadingOffset::H2);
if !e.variants.is_empty() {
write!(
@ -1052,7 +1052,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
w.write_str("</code>");
render_stability_since(w, variant, it, cx.tcx());
w.write_str("</div>");
document(w, cx, variant, Some(it));
document(w, cx, variant, Some(it), HeadingOffset::H2);
document_non_exhaustive(w, variant);
use crate::clean::Variant;
@ -1092,7 +1092,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
f = field.name.as_ref().unwrap(),
t = ty.print(cx)
);
document(w, cx, field, Some(variant));
document(w, cx, field, Some(variant), HeadingOffset::H2);
}
_ => unreachable!(),
}
@ -1119,7 +1119,7 @@ fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Mac
None,
);
});
document(w, cx, it, None)
document(w, cx, it, None, HeadingOffset::H2)
}
fn item_proc_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, m: &clean::ProcMacro) {
@ -1149,11 +1149,11 @@ fn item_proc_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, m: &clean
});
}
}
document(w, cx, it, None)
document(w, cx, it, None, HeadingOffset::H2)
}
fn item_primitive(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
document(w, cx, it, None);
document(w, cx, it, None, HeadingOffset::H2);
render_assoc_items(w, cx, it, it.def_id.expect_def_id(), AssocItemRender::All)
}
@ -1192,7 +1192,7 @@ fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean::
}
});
document(w, cx, it, None)
document(w, cx, it, None, HeadingOffset::H2)
}
fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) {
@ -1203,7 +1203,7 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
});
});
document(w, cx, it, None);
document(w, cx, it, None, HeadingOffset::H2);
let mut fields = s
.fields
@ -1239,7 +1239,7 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
name = field_name,
ty = ty.print(cx)
);
document(w, cx, field, Some(it));
document(w, cx, field, Some(it), HeadingOffset::H2);
}
}
}
@ -1260,7 +1260,7 @@ fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
typ = s.type_.print(cx)
);
});
document(w, cx, it, None)
document(w, cx, it, None, HeadingOffset::H2)
}
fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
@ -1275,13 +1275,13 @@ fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
);
});
document(w, cx, it, None);
document(w, cx, it, None, HeadingOffset::H2);
render_assoc_items(w, cx, it, it.def_id.expect_def_id(), AssocItemRender::All)
}
fn item_keyword(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
document(w, cx, it, None)
document(w, cx, it, None, HeadingOffset::H2)
}
/// Compare two strings treating multi-digit numbers as single units (i.e. natural sort order).

View file

@ -126,7 +126,7 @@ h2 {
h3 {
font-size: 1.3em;
}
h1, h2, h3, h4 {
h1, h2, h3, h4, h5, h6 {
font-weight: 500;
margin: 20px 0 15px 0;
padding-bottom: 6px;
@ -179,7 +179,7 @@ div.impl-items > div {
padding-left: 0;
}
h1, h2, h3, h4,
h1, h2, h3, h4, h5, h6,
.sidebar, a.source, .search-input, .search-results .result-name,
.content table td:first-child > a,
.item-left > a,
@ -501,21 +501,20 @@ nav.sub {
white-space: pre-wrap;
}
.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 {
.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 {
border-bottom: 1px solid;
}
.top-doc .docblock h1 { font-size: 1.3em; }
.top-doc .docblock h2 { font-size: 1.15em; }
.top-doc .docblock h3,
.top-doc .docblock h2 { font-size: 1.3em; }
.top-doc .docblock h3 { font-size: 1.15em; }
.top-doc .docblock h4,
.top-doc .docblock h5 {
.top-doc .docblock h5,
.top-doc .docblock h6 {
font-size: 1em;
}
.docblock h1 { font-size: 1em; }
.docblock h2 { font-size: 0.95em; }
.docblock h3, .docblock h4, .docblock h5 { font-size: 0.9em; }
.docblock h5 { font-size: 1em; }
.docblock h6 { font-size: 0.95em; }
.docblock {
margin-left: 24px;

View file

@ -136,7 +136,7 @@ pre, .rustdoc.source .example-wrap {
border-right: 1px solid #ffb44c;
}
.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 {
.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 {
border-bottom-color: #5c6773;
}

View file

@ -93,7 +93,7 @@ pre, .rustdoc.source .example-wrap {
background-color: #0a042f !important;
}
.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 {
.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 {
border-bottom-color: #DDD;
}

View file

@ -93,7 +93,7 @@ pre, .rustdoc.source .example-wrap {
background-color: #f6fdb0 !important;
}
.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 {
.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 {
border-bottom-color: #ddd;
}

View file

@ -10,7 +10,9 @@ use crate::config::{Options, RenderOptions};
use crate::doctest::{Collector, TestOptions};
use crate::html::escape::Escape;
use crate::html::markdown;
use crate::html::markdown::{find_testable_code, ErrorCodes, IdMap, Markdown, MarkdownWithToc};
use crate::html::markdown::{
find_testable_code, ErrorCodes, HeadingOffset, IdMap, Markdown, MarkdownWithToc,
};
/// Separate any lines at the start of the file that begin with `# ` or `%`.
fn extract_leading_metadata(s: &str) -> (Vec<&str>, &str) {
@ -70,7 +72,16 @@ crate fn render<P: AsRef<Path>>(
let text = if !options.markdown_no_toc {
MarkdownWithToc(text, &mut ids, error_codes, edition, &playground).into_string()
} else {
Markdown(text, &[], &mut ids, error_codes, edition, &playground).into_string()
Markdown {
content: text,
links: &[],
ids: &mut ids,
error_codes,
edition,
playground: &playground,
heading_offset: HeadingOffset::H1,
}
.into_string()
};
let err = write!(

View file

@ -6,5 +6,5 @@
extern crate external_cross;
// @has host/struct.NeedMoreDocs.html
// @has - '//h1' 'Cross-crate imported docs'
// @has - '//h2' 'Cross-crate imported docs'
pub use external_cross::NeedMoreDocs;

View file

@ -1,6 +1,6 @@
// @has external_doc/struct.IncludeStrDocs.html
// @has - '//h1' 'External Docs'
// @has - '//h2' 'Inline Docs'
// @has - '//h2' 'External Docs'
// @has - '//h3' 'Inline Docs'
#[doc = include_str!("auxiliary/external-doc.md")]
/// ## Inline Docs
pub struct IncludeStrDocs;
@ -8,7 +8,7 @@ pub struct IncludeStrDocs;
macro_rules! dir { () => { "auxiliary" } }
// @has external_doc/struct.EagerExpansion.html
// @has - '//h1' 'External Docs'
// @has - '//h2' 'External Docs'
#[doc = include_str!(concat!(dir!(), "/external-doc.md"))]
/// ## Inline Docs
pub struct EagerExpansion;

View file

@ -1,5 +1,5 @@
// @has issue_42760/struct.NonGen.html
// @has - '//h1' 'Example'
// @has - '//h2' 'Example'
/// Item docs.
///

View file

@ -0,0 +1,29 @@
#![crate_name = "foo"]
// @has foo/trait.Read.html
// @has - '//h2' 'Trait examples'
/// # Trait examples
pub trait Read {
// @has - '//h5' 'Function examples'
/// # Function examples
fn read(&mut self, buf: &mut [u8]) -> Result<usize, ()>;
}
pub struct Foo;
// @has foo/struct.Foo.html
impl Foo {
// @has - '//h5' 'Implementation header'
/// # Implementation header
pub fn bar(&self) -> usize {
1
}
}
impl Read for Foo {
// @has - '//h5' 'Trait implementation header'
/// # Trait implementation header
fn read(&mut self, buf: &mut [u8]) -> Result<usize, ()> {
Ok(1)
}
}

View file

@ -2,7 +2,7 @@
// @has foo/index.html '//*[@class="item-right docblock-short"]/p' 'fooo'
// @!has foo/index.html '//*[@class="item-right docblock-short"]/p/h1' 'fooo'
// @has foo/fn.foo.html '//h1[@id="fooo"]/a[@href="#fooo"]' 'fooo'
// @has foo/fn.foo.html '//h2[@id="fooo"]/a[@href="#fooo"]' 'fooo'
/// # fooo
///
@ -11,7 +11,7 @@ pub fn foo() {}
// @has foo/index.html '//*[@class="item-right docblock-short"]/p' 'mooood'
// @!has foo/index.html '//*[@class="item-right docblock-short"]/p/h2' 'mooood'
// @has foo/foo/index.html '//h2[@id="mooood"]/a[@href="#mooood"]' 'mooood'
// @has foo/foo/index.html '//h3[@id="mooood"]/a[@href="#mooood"]' 'mooood'
/// ## mooood
///

View file

@ -21,7 +21,7 @@
//! ```
// @has "foo/index.html" "//p" "This is the “start” of the document! Howd you know that “its” the start?"
// @has "foo/index.html" "//h1" "Header with “smart punct”"
// @has "foo/index.html" "//h2" "Header with “smart punct”"
// @has "foo/index.html" '//a[@href="https://www.rust-lang.org"]' "link with “smart punct yessiree!"
// @has "foo/index.html" '//code' "this inline code -- it shouldn't have \"smart punct\""
// @has "foo/index.html" '//pre' "let x = \"don't smart-punct me -- please!\";"

View file

@ -14,7 +14,7 @@ use std::path::PathBuf;
use rustc_span::edition::DEFAULT_EDITION;
use rustdoc::html::markdown::{ErrorCodes, IdMap, Markdown, Playground};
use rustdoc::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground};
pub struct ErrorMetadata {
pub description: Option<String>,
@ -119,14 +119,15 @@ impl Formatter for HTMLFormatter {
write!(
output,
"{}",
Markdown(
desc,
&[],
&mut id_map,
ErrorCodes::Yes,
DEFAULT_EDITION,
&Some(playground)
)
Markdown {
content: desc,
links: &[],
ids: &mut id_map,
error_codes: ErrorCodes::Yes,
edition: DEFAULT_EDITION,
playground: &Some(playground),
heading_offset: HeadingOffset::H1,
}
.into_string()
)?
}