Skip to content

rustdoc: simplify handling of plain text output #109246

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 5 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
678 changes: 295 additions & 383 deletions src/librustdoc/html/format.rs

Large diffs are not rendered by default.

99 changes: 52 additions & 47 deletions src/librustdoc/html/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -809,7 +809,7 @@ fn assoc_method(
) {
let tcx = cx.tcx();
let header = meth.fn_header(tcx).expect("Trying to get header from a non-function item");
let name = meth.name.as_ref().unwrap();
let name = meth.name.as_ref().unwrap().as_str();
let vis = visibility_print_with_space(meth.visibility(tcx), meth.item_id, cx).to_string();
// FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
// this condition.
Expand All @@ -825,48 +825,53 @@ fn assoc_method(
let abi = print_abi_with_space(header.abi).to_string();
let href = assoc_href_attr(meth, link, cx);

// NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
let generics_len = format!("{:#}", g.print(cx)).len();
let mut header_len = "fn ".len()
+ vis.len()
+ constness.len()
+ asyncness.len()
+ unsafety.len()
+ defaultness.len()
+ abi.len()
+ name.as_str().len()
+ generics_len;

let notable_traits = d.output.as_return().and_then(|output| notable_traits_button(output, cx));
let notable_traits = d
.output
.as_return()
.and_then(|output| notable_traits_button(output, cx))
.unwrap_or_default();

let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
header_len += 4;
let indent_str = " ";
render_attributes_in_pre(w, meth, indent_str);
(4, indent_str, Ending::NoNewline)
} else {
render_attributes_in_code(w, meth);
(0, "", Ending::Newline)
};
w.reserve(header_len + "<a href=\"\" class=\"fn\">{".len() + "</a>".len());
write!(
w,
"{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn <a{href} class=\"fn\">{name}</a>\
{generics}{decl}{notable_traits}{where_clause}",
indent = indent_str,
vis = vis,
constness = constness,
asyncness = asyncness,
unsafety = unsafety,
defaultness = defaultness,
abi = abi,
href = href,
name = name,
generics = g.print(cx),
decl = d.full_print(header_len, indent, cx),
notable_traits = notable_traits.unwrap_or_default(),
where_clause = print_where_clause(g, cx, indent, end_newline),
);

let fn_header = FunctionHeader {
indent_str,
vis,
constness,
asyncness,
unsafety,
defaultness,
abi,
href,
name,
generics: g.print(cx).to_string(),
};

let decl = d.full_print(&fn_header, indent, cx);
let where_clause = print_where_clause(g, cx, indent, end_newline);

write!(w, "{fn_header}{decl}{notable_traits}{where_clause}");
}

#[derive(Template)]
#[template(path = "function_header.html")]
struct FunctionHeader<'a> {
indent_str: &'static str,
vis: String,
constness: &'a str,
asyncness: &'a str,
unsafety: &'a str,
defaultness: &'a str,
abi: String,
href: String,
name: &'a str,
generics: String,
}

/// Writes a span containing the versions at which an item became stable and/or const-stable. For
Expand Down Expand Up @@ -1141,8 +1146,10 @@ fn render_assoc_items_inner(
(RenderMode::Normal, "implementations-list".to_owned())
}
AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
let id =
cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx))));
let id = cx.derive_id(small_url_encode(format!(
"deref-methods-{}",
type_.print_plain(cx)
)));
if let Some(def_id) = type_.def_id(cx.cache()) {
cx.deref_id_map.insert(def_id, id.clone());
}
Expand Down Expand Up @@ -1314,7 +1321,7 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> O
cx.types_with_notable_traits.insert(ty.clone());
Some(format!(
" <a href=\"#\" class=\"tooltip\" data-notable-ty=\"{ty}\">ⓘ</a>",
ty = Escape(&format!("{:#}", ty.print(cx))),
ty = Escape(&ty.print_plain(cx).to_string()),
))
} else {
None
Expand Down Expand Up @@ -1379,7 +1386,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
write!(&mut out, "</code></pre>",);
}

(format!("{:#}", ty.print(cx)), out.into_inner())
(ty.print_plain(cx).to_string(), out.into_inner())
}

pub(crate) fn notable_traits_json<'a>(
Expand Down Expand Up @@ -1947,20 +1954,18 @@ pub(crate) fn small_url_encode(s: String) -> String {

fn get_id_for_impl(for_: &clean::Type, trait_: Option<&clean::Path>, cx: &Context<'_>) -> String {
match trait_ {
Some(t) => small_url_encode(format!("impl-{:#}-for-{:#}", t.print(cx), for_.print(cx))),
None => small_url_encode(format!("impl-{:#}", for_.print(cx))),
Some(t) => {
small_url_encode(format!("impl-{}-for-{}", t.print_plain(cx), for_.print_plain(cx)))
}
None => small_url_encode(format!("impl-{}", for_.print_plain(cx))),
}
}

fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> {
match *item.kind {
clean::ItemKind::ImplItem(ref i) => {
i.trait_.as_ref().map(|trait_| {
// Alternative format produces no URLs,
// so this parameter does nothing.
(format!("{:#}", i.for_.print(cx)), get_id_for_impl(&i.for_, Some(trait_), cx))
})
}
clean::ItemKind::ImplItem(ref i) => i.trait_.as_ref().map(|trait_| {
(i.for_.print_plain(cx).to_string(), get_id_for_impl(&i.for_, Some(trait_), cx))
}),
_ => None,
}
}
Expand Down
53 changes: 24 additions & 29 deletions src/librustdoc/html/render/print_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -528,39 +528,34 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
let abi = print_abi_with_space(header.abi).to_string();
let asyncness = header.asyncness.print_with_space();
let visibility = visibility_print_with_space(it.visibility(tcx), it.item_id, cx).to_string();
let name = it.name.unwrap();

let generics_len = format!("{:#}", f.generics.print(cx)).len();
let header_len = "fn ".len()
+ visibility.len()
+ constness.len()
+ asyncness.len()
+ unsafety.len()
+ abi.len()
+ name.as_str().len()
+ generics_len;
let name = it.name.as_ref().unwrap().as_str();

let fn_header = super::FunctionHeader {
indent_str: "",
vis: visibility,
constness,
asyncness,
unsafety,
// standalone functions are never default, only associated functions.
defaultness: "",
abi,
href: "".to_string(),
name,
generics: f.generics.print(cx).to_string(),
};

let notable_traits =
f.decl.output.as_return().and_then(|output| notable_traits_button(output, cx));
let notable_traits = f
.decl
.output
.as_return()
.and_then(|output| notable_traits_button(output, cx))
.unwrap_or_default();

wrap_item(w, |w| {
render_attributes_in_pre(w, it, "");
w.reserve(header_len);
write!(
w,
"{vis}{constness}{asyncness}{unsafety}{abi}fn \
{name}{generics}{decl}{notable_traits}{where_clause}",
vis = visibility,
constness = constness,
asyncness = asyncness,
unsafety = unsafety,
abi = abi,
name = name,
generics = f.generics.print(cx),
where_clause = print_where_clause(&f.generics, cx, 0, Ending::Newline),
decl = f.decl.full_print(header_len, 0, cx),
notable_traits = notable_traits.unwrap_or_default(),
);
let decl = f.decl.full_print(&fn_header, 0, cx);
let where_clause = print_where_clause(&f.generics, cx, 0, Ending::Newline);
write!(w, "{fn_header}{decl}{notable_traits}{where_clause}");
});
document(w, cx, it, None, HeadingOffset::H2);
}
Expand Down
8 changes: 4 additions & 4 deletions src/librustdoc/html/render/sidebar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,9 +378,9 @@ fn sidebar_deref_methods<'a>(
Cow::Borrowed("deref-methods")
};
let title = format!(
"Methods from {:#}<Target={:#}>",
impl_.inner_impl().trait_.as_ref().unwrap().print(cx),
real_target.print(cx),
"Methods from {}<Target={}>",
impl_.inner_impl().trait_.as_ref().unwrap().print_plain(cx),
real_target.print_plain(cx),
);
// We want links' order to be reproducible so we don't use unstable sort.
ret.sort();
Expand Down Expand Up @@ -487,7 +487,7 @@ fn sidebar_render_assoc_items(
ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
ty::ImplPolarity::Negative => "!",
};
let generated = Link::new(encoded, format!("{prefix}{:#}", trait_.print(cx)));
let generated = Link::new(encoded, format!("{prefix}{}", trait_.print_plain(cx)));
if links.insert(generated.clone()) { Some(generated) } else { None }
})
.collect::<Vec<Link<'static>>>();
Expand Down
11 changes: 11 additions & 0 deletions src/librustdoc/html/templates/function_header.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{# All of the parts of a function or method declaration that
come before the parameters and return value #}
{{indent_str}}
{{vis|safe}}
{{constness}}
{{asyncness}}
{{unsafety}}
{{defaultness}}
{{abi|safe}}
fn <a{{href|safe +}} class="fn">{{name}}</a>
{{generics|safe}}
34 changes: 34 additions & 0 deletions src/librustdoc/html/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,37 @@ fn href_relative_parts_root() {
let fqp = &[sym::std];
assert_relative_path(&[sym::std], relative_to_fqp, fqp);
}

#[test]
fn test_html_remover() {
use super::format::HtmlRemover;
use std::fmt::Write;

fn assert_removed_eq(input: &str, output: &str) {
let mut remover = HtmlRemover::new(String::new());
write!(&mut remover, "{}", input).unwrap();
assert_eq!(&remover.into_inner(), output);
}

assert_removed_eq("a<a href='https://example.com'>b", "ab");
assert_removed_eq("alpha &lt;bet&gt;", "alpha <bet>");
assert_removed_eq("<a href=\"&quot;\">", "");
assert_removed_eq("<tag>&gt;</tag>text&lt;<tag>", ">text<");
assert_removed_eq("&quot;&#39;", "\"'");

let mut remover = HtmlRemover::new(String::new());
assert!(write!(&mut remover, "&ent;").is_err());

let mut remover = HtmlRemover::new(String::new());
assert!(write!(&mut remover, "&longentity").is_err());

let mut remover = HtmlRemover::new(String::new());
assert!(write!(&mut remover, "<open <tag").is_err());
}

#[test]
fn test_plain() {
use super::format::Plain;
let d = Plain("<strong>alpha</strong> &lt;bet&gt;");
assert_eq!(&d.to_string(), "alpha <bet>");
}
2 changes: 1 addition & 1 deletion tests/rustdoc/array-links.link_box_generic.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<code>pub fn delta&lt;T&gt;() -&gt; <a class="struct" href="struct.MyBox.html" title="struct foo::MyBox">MyBox</a>&lt;<a class="primitive" href="{{channel}}/core/primitive.array.html">[T; 1]</a>&gt;</code>
<code>pub fn <a class="fn">delta</a>&lt;T&gt;() -&gt; <a class="struct" href="struct.MyBox.html" title="struct foo::MyBox">MyBox</a>&lt;<a class="primitive" href="{{channel}}/core/primitive.array.html">[T; 1]</a>&gt;</code>
2 changes: 1 addition & 1 deletion tests/rustdoc/array-links.link_box_u32.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<code>pub fn gamma() -&gt; <a class="struct" href="struct.MyBox.html" title="struct foo::MyBox">MyBox</a>&lt;[<a class="primitive" href="{{channel}}/core/primitive.u32.html">u32</a>; <a class="primitive" href="{{channel}}/core/primitive.array.html">1</a>]&gt;</code>
<code>pub fn <a class="fn">gamma</a>() -&gt; <a class="struct" href="struct.MyBox.html" title="struct foo::MyBox">MyBox</a>&lt;[<a class="primitive" href="{{channel}}/core/primitive.u32.html">u32</a>; <a class="primitive" href="{{channel}}/core/primitive.array.html">1</a>]&gt;</code>
2 changes: 1 addition & 1 deletion tests/rustdoc/array-links.link_slice_generic.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<code>pub fn beta&lt;T&gt;() -&gt; &amp;'static <a class="primitive" href="{{channel}}/core/primitive.array.html">[T; 1]</a></code>
<code>pub fn <a class="fn">beta</a>&lt;T&gt;() -&gt; &amp;'static <a class="primitive" href="{{channel}}/core/primitive.array.html">[T; 1]</a></code>
2 changes: 1 addition & 1 deletion tests/rustdoc/array-links.link_slice_u32.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<code>pub fn alpha() -&gt; &amp;'static [<a class="primitive" href="{{channel}}/core/primitive.u32.html">u32</a>; <a class="primitive" href="{{channel}}/core/primitive.array.html">1</a>]</code>
<code>pub fn <a class="fn">alpha</a>() -&gt; &amp;'static [<a class="primitive" href="{{channel}}/core/primitive.u32.html">u32</a>; <a class="primitive" href="{{channel}}/core/primitive.array.html">1</a>]</code>
4 changes: 2 additions & 2 deletions tests/rustdoc/nested-modules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ mod a_module {

pub mod a_nested_module {
// @has aCrate/a_nested_module/index.html '//a[@href="fn.a_nested_public_function.html"]' 'a_nested_public_function'
// @hasraw aCrate/a_nested_module/fn.a_nested_public_function.html 'pub fn a_nested_public_function()'
// @has aCrate/a_nested_module/fn.a_nested_public_function.html '//' 'pub fn a_nested_public_function()'
pub fn a_nested_public_function() {}

// @has aCrate/a_nested_module/index.html '//a[@href="fn.another_nested_public_function.html"]' 'another_nested_public_function'
// @hasraw aCrate/a_nested_module/fn.another_nested_public_function.html 'pub fn another_nested_public_function()'
// @has aCrate/a_nested_module/fn.another_nested_public_function.html '//' 'pub fn another_nested_public_function()'
pub use a_nested_module::a_nested_public_function as another_nested_public_function;
}

Expand Down
2 changes: 1 addition & 1 deletion tests/rustdoc/reexports-priv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ pub mod outer {
pub use reexports::foo;
// @has 'foo/outer/inner/fn.foo_crate.html' '//pre[@class="rust item-decl"]' 'pub(crate) fn foo_crate()'
pub(crate) use reexports::foo_crate;
// @has 'foo/outer/inner/fn.foo_super.html' '//pre[@class="rust item-decl"]' 'pub(in outer) fn foo_super( )'
// @has 'foo/outer/inner/fn.foo_super.html' '//pre[@class="rust item-decl"]' 'pub(in outer) fn foo_super()'
pub(super) use::reexports::foo_super;
// @!has 'foo/outer/inner/fn.foo_self.html'
pub(self) use reexports::foo_self;
Expand Down
2 changes: 1 addition & 1 deletion tests/rustdoc/slice-links.link_box_generic.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<code>pub fn delta&lt;T&gt;() -&gt; <a class="struct" href="struct.MyBox.html" title="struct foo::MyBox">MyBox</a>&lt;<a class="primitive" href="{{channel}}/core/primitive.slice.html">[T]</a>&gt;</code>
<code>pub fn <a class="fn">delta</a>&lt;T&gt;() -&gt; <a class="struct" href="struct.MyBox.html" title="struct foo::MyBox">MyBox</a>&lt;<a class="primitive" href="{{channel}}/core/primitive.slice.html">[T]</a>&gt;</code>
2 changes: 1 addition & 1 deletion tests/rustdoc/slice-links.link_box_u32.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<code>pub fn gamma() -&gt; <a class="struct" href="struct.MyBox.html" title="struct foo::MyBox">MyBox</a>&lt;[<a class="primitive" href="{{channel}}/core/primitive.u32.html">u32</a>]&gt;</code>
<code>pub fn <a class="fn">gamma</a>() -&gt; <a class="struct" href="struct.MyBox.html" title="struct foo::MyBox">MyBox</a>&lt;[<a class="primitive" href="{{channel}}/core/primitive.u32.html">u32</a>]&gt;</code>
2 changes: 1 addition & 1 deletion tests/rustdoc/slice-links.link_slice_generic.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<code>pub fn beta&lt;T&gt;() -&gt; &amp;'static <a class="primitive" href="{{channel}}/core/primitive.slice.html">[T]</a></code>
<code>pub fn <a class="fn">beta</a>&lt;T&gt;() -&gt; &amp;'static <a class="primitive" href="{{channel}}/core/primitive.slice.html">[T]</a></code>
2 changes: 1 addition & 1 deletion tests/rustdoc/slice-links.link_slice_u32.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<code>pub fn alpha() -&gt; &amp;'static [<a class="primitive" href="{{channel}}/core/primitive.u32.html">u32</a>]</code>
<code>pub fn <a class="fn">alpha</a>() -&gt; &amp;'static [<a class="primitive" href="{{channel}}/core/primitive.u32.html">u32</a>]</code>
2 changes: 1 addition & 1 deletion tests/rustdoc/tuples.link1_i32.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<code>pub fn tuple1(x: (<a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>,)) -&gt; (<a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>,)</code>
<code>pub fn <a class="fn">tuple1</a>(x: (<a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>,)) -&gt; (<a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>,)</code>
2 changes: 1 addition & 1 deletion tests/rustdoc/tuples.link1_t.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<code>pub fn tuple1_t&lt;T&gt;(x: <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T,)</a>) -&gt; <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T,)</a></code>
<code>pub fn <a class="fn">tuple1_t</a>&lt;T&gt;(x: <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T,)</a>) -&gt; <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T,)</a></code>
2 changes: 1 addition & 1 deletion tests/rustdoc/tuples.link2_i32.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<code>pub fn tuple2(x: (<a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>, <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>)) -&gt; (<a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>, <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>)</code>
<code>pub fn <a class="fn">tuple2</a>(x: (<a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>, <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>)) -&gt; (<a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>, <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>)</code>
2 changes: 1 addition & 1 deletion tests/rustdoc/tuples.link2_t.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<code>pub fn tuple2_t&lt;T&gt;(x: <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T, T)</a>) -&gt; <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T, T)</a></code>
<code>pub fn <a class="fn">tuple2_t</a>&lt;T&gt;(x: <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T, T)</a>) -&gt; <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T, T)</a></code>
2 changes: 1 addition & 1 deletion tests/rustdoc/tuples.link2_tu.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<code>pub fn tuple2_tu&lt;T, U&gt;(x: <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T, U)</a>) -&gt; <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T, U)</a></code>
<code>pub fn <a class="fn">tuple2_tu</a>&lt;T, U&gt;(x: <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T, U)</a>) -&gt; <a class="primitive" href="{{channel}}/std/primitive.tuple.html">(T, U)</a></code>
2 changes: 1 addition & 1 deletion tests/rustdoc/tuples.link_unit.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<code>pub fn tuple0(x: <a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>)</code>
<code>pub fn <a class="fn">tuple0</a>(x: <a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>)</code>