Skip to content

Commit 19579c6

Browse files
committed
Auto merge of #84834 - GuillaumeGomez:sidebar-unification, r=jsha
Sidebar unification This PR does a few things: * Put crates list at all levels (before, it was only on the "top" items) * Fix bug in module sidebar: the list of items was from the parent module. The other changes (on bootstrap mostly) were to allow to generate multiple crates in a same folder so that we can ensure that clicking on the crates in the sidebar works as expected. I added a rustdoc-gui test to ensure everything is where it should be. r? `@jyn514`
2 parents da86509 + 9b637fa commit 19579c6

File tree

14 files changed

+173
-99
lines changed

14 files changed

+173
-99
lines changed

src/librustdoc/clean/types.rs

-1
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,6 @@ impl Item {
526526
crate fn is_crate(&self) -> bool {
527527
self.is_mod() && self.def_id.as_real().map_or(false, |did| did.index == CRATE_DEF_INDEX)
528528
}
529-
530529
crate fn is_mod(&self) -> bool {
531530
self.type_() == ItemType::Module
532531
}

src/librustdoc/html/layout.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ crate fn render<T: Print, S: Print>(
119119
{after_content}\
120120
<div id=\"rustdoc-vars\" data-root-path=\"{root_path}\" data-current-crate=\"{krate}\" \
121121
data-search-index-js=\"{root_path}search-index{suffix}.js\" \
122-
data-search-js=\"{static_root_path}search{suffix}.js\"></div>
122+
data-search-js=\"{static_root_path}search{suffix}.js\"></div>\
123123
<script src=\"{static_root_path}main{suffix}.js\"></script>\
124124
{extra_scripts}\
125125
</body>\

src/librustdoc/html/render/context.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,15 @@ impl<'tcx> Context<'tcx> {
200200
)
201201
};
202202
let keywords = make_item_keywords(it);
203+
let name;
204+
let tyname_s = if it.is_crate() {
205+
name = format!("{} crate", tyname);
206+
name.as_str()
207+
} else {
208+
tyname.as_str()
209+
};
203210
let page = layout::Page {
204-
css_class: tyname.as_str(),
211+
css_class: tyname_s,
205212
root_path: &self.root_path(),
206213
static_root_path: self.shared.static_root_path.as_deref(),
207214
title: &title,

src/librustdoc/html/render/mod.rs

+30-37
Original file line numberDiff line numberDiff line change
@@ -1713,7 +1713,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
17131713
"<div class=\"block version\">\
17141714
<p>Version {}</p>\
17151715
</div>",
1716-
Escape(version)
1716+
Escape(version),
17171717
);
17181718
}
17191719
}
@@ -1723,9 +1723,10 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
17231723
write!(
17241724
buffer,
17251725
"<a id=\"all-types\" href=\"all.html\"><p>See all {}'s items</p></a>",
1726-
it.name.as_ref().expect("crates always have a name")
1726+
it.name.as_ref().expect("crates always have a name"),
17271727
);
17281728
}
1729+
17291730
match *it.kind {
17301731
clean::StructItem(ref s) => sidebar_struct(cx, buffer, it, s),
17311732
clean::TraitItem(ref t) => sidebar_trait(cx, buffer, it, t),
@@ -1735,7 +1736,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
17351736
clean::TypedefItem(_, _) => sidebar_typedef(cx, buffer, it),
17361737
clean::ModuleItem(ref m) => sidebar_module(buffer, &m.items),
17371738
clean::ForeignTypeItem => sidebar_foreign_type(cx, buffer, it),
1738-
_ => (),
1739+
_ => {}
17391740
}
17401741

17411742
// The sidebar is designed to display sibling functions, modules and
@@ -1746,22 +1747,24 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
17461747
// as much HTML as possible in order to allow non-JS-enabled browsers
17471748
// to navigate the documentation (though slightly inefficiently).
17481749

1749-
buffer.write_str("<p class=\"location\">");
1750-
for (i, name) in cx.current.iter().take(parentlen).enumerate() {
1751-
if i > 0 {
1752-
buffer.write_str("::<wbr>");
1750+
if !it.is_mod() {
1751+
buffer.write_str("<p class=\"location\">Other items in<br>");
1752+
for (i, name) in cx.current.iter().take(parentlen).enumerate() {
1753+
if i > 0 {
1754+
buffer.write_str("::<wbr>");
1755+
}
1756+
write!(
1757+
buffer,
1758+
"<a href=\"{}index.html\">{}</a>",
1759+
&cx.root_path()[..(cx.current.len() - i - 1) * 3],
1760+
*name
1761+
);
17531762
}
1754-
write!(
1755-
buffer,
1756-
"<a href=\"{}index.html\">{}</a>",
1757-
&cx.root_path()[..(cx.current.len() - i - 1) * 3],
1758-
*name
1759-
);
1763+
buffer.write_str("</p>");
17601764
}
1761-
buffer.write_str("</p>");
17621765

17631766
// Sidebar refers to the enclosing module, not this module.
1764-
let relpath = if it.is_mod() { "../" } else { "" };
1767+
let relpath = if it.is_mod() && parentlen != 0 { "./" } else { "" };
17651768
write!(
17661769
buffer,
17671770
"<div id=\"sidebar-vars\" data-name=\"{name}\" data-ty=\"{ty}\" data-relpath=\"{path}\">\
@@ -1770,17 +1773,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
17701773
ty = it.type_(),
17711774
path = relpath
17721775
);
1773-
1774-
if parentlen == 0 {
1775-
write!(
1776-
buffer,
1777-
"<script defer src=\"{}sidebar-items{}.js\"></script>",
1778-
relpath, cx.shared.resource_suffix
1779-
);
1780-
} else {
1781-
write!(buffer, "<script defer src=\"{}sidebar-items.js\"></script>", relpath);
1782-
}
1783-
1776+
write!(buffer, "<script defer src=\"{}sidebar-items.js\"></script>", relpath);
17841777
// Closes sidebar-elems div.
17851778
buffer.write_str("</div>");
17861779
}
@@ -2288,8 +2281,8 @@ fn sidebar_enum(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, e: &clean:
22882281
}
22892282
}
22902283

2291-
fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) {
2292-
match *ty {
2284+
fn item_ty_to_strs(ty: ItemType) -> (&'static str, &'static str) {
2285+
match ty {
22932286
ItemType::ExternCrate | ItemType::Import => ("reexports", "Re-exports"),
22942287
ItemType::Module => ("modules", "Modules"),
22952288
ItemType::Struct => ("structs", "Structs"),
@@ -2321,10 +2314,14 @@ fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) {
23212314
fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) {
23222315
let mut sidebar = String::new();
23232316

2317+
// Re-exports are handled a bit differently because they can be extern crates or imports.
23242318
if items.iter().any(|it| {
2325-
it.type_() == ItemType::ExternCrate || (it.type_() == ItemType::Import && !it.is_stripped())
2319+
it.name.is_some()
2320+
&& (it.type_() == ItemType::ExternCrate
2321+
|| (it.type_() == ItemType::Import && !it.is_stripped()))
23262322
}) {
2327-
sidebar.push_str("<li><a href=\"#reexports\">Re-exports</a></li>");
2323+
let (id, name) = item_ty_to_strs(ItemType::Import);
2324+
sidebar.push_str(&format!("<li><a href=\"#{}\">{}</a></li>", id, name));
23282325
}
23292326

23302327
// ordering taken from item_module, reorder, where it prioritized elements in a certain order
@@ -2351,13 +2348,9 @@ fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) {
23512348
ItemType::ForeignType,
23522349
ItemType::Keyword,
23532350
] {
2354-
if items.iter().any(|it| !it.is_stripped() && it.type_() == myty) {
2355-
let (short, name) = item_ty_to_strs(&myty);
2356-
sidebar.push_str(&format!(
2357-
"<li><a href=\"#{id}\">{name}</a></li>",
2358-
id = short,
2359-
name = name
2360-
));
2351+
if items.iter().any(|it| !it.is_stripped() && it.type_() == myty && it.name.is_some()) {
2352+
let (id, name) = item_ty_to_strs(myty);
2353+
sidebar.push_str(&format!("<li><a href=\"#{}\">{}</a></li>", id, name));
23612354
}
23622355
}
23632356

src/librustdoc/html/render/print_item.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
263263
w.write_str("</table>");
264264
}
265265
curty = myty;
266-
let (short, name) = item_ty_to_strs(&myty.unwrap());
266+
let (short, name) = item_ty_to_strs(myty.unwrap());
267267
write!(
268268
w,
269269
"<h2 id=\"{id}\" class=\"section-header\">\

src/librustdoc/html/render/write_shared.rs

-1
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,6 @@ pub(super) fn write_shared(
227227
)?;
228228
write_minify("search.js", static_files::SEARCH_JS)?;
229229
write_minify("settings.js", static_files::SETTINGS_JS)?;
230-
write_minify("sidebar-items.js", static_files::sidebar::ITEMS)?;
231230

232231
if cx.shared.include_sources {
233232
write_minify("source-script.js", static_files::sidebar::SOURCE_SCRIPT)?;

src/librustdoc/html/static/main.js

+53-50
Original file line numberDiff line numberDiff line change
@@ -561,41 +561,40 @@ function hideThemeButtonState() {
561561
}
562562
}());
563563

564-
function addSidebarCrates(crates) {
565-
// Draw a convenient sidebar of known crates if we have a listing
566-
if (window.rootPath === "../" || window.rootPath === "./") {
567-
var sidebar = document.getElementsByClassName("sidebar-elems")[0];
568-
if (sidebar) {
569-
var div = document.createElement("div");
570-
div.className = "block crate";
571-
div.innerHTML = "<h3>Crates</h3>";
572-
var ul = document.createElement("ul");
573-
div.appendChild(ul);
574-
575-
for (var i = 0; i < crates.length; ++i) {
576-
var klass = "crate";
577-
if (window.rootPath !== "./" && crates[i] === window.currentCrate) {
578-
klass += " current";
579-
}
580-
var link = document.createElement("a");
581-
link.href = window.rootPath + crates[i] + "/index.html";
582-
link.className = klass;
583-
link.textContent = crates[i];
584-
585-
var li = document.createElement("li");
586-
li.appendChild(link);
587-
ul.appendChild(li);
588-
}
589-
sidebar.appendChild(div);
590-
}
591-
}
592-
}
593-
594564
// delayed sidebar rendering.
595565
window.initSidebarItems = function(items) {
596566
var sidebar = document.getElementsByClassName("sidebar-elems")[0];
597567
var current = window.sidebarCurrent;
598568

569+
function addSidebarCrates(crates) {
570+
if (!hasClass(document.body, "crate")) {
571+
// We only want to list crates on the crate page.
572+
return;
573+
}
574+
// Draw a convenient sidebar of known crates if we have a listing
575+
var div = document.createElement("div");
576+
div.className = "block crate";
577+
div.innerHTML = "<h3>Crates</h3>";
578+
var ul = document.createElement("ul");
579+
div.appendChild(ul);
580+
581+
for (var i = 0; i < crates.length; ++i) {
582+
var klass = "crate";
583+
if (window.rootPath !== "./" && crates[i] === window.currentCrate) {
584+
klass += " current";
585+
}
586+
var link = document.createElement("a");
587+
link.href = window.rootPath + crates[i] + "/index.html";
588+
link.className = klass;
589+
link.textContent = crates[i];
590+
591+
var li = document.createElement("li");
592+
li.appendChild(link);
593+
ul.appendChild(li);
594+
}
595+
sidebar.appendChild(div);
596+
}
597+
599598
function block(shortty, longty) {
600599
var filtered = items[shortty];
601600
if (!filtered) {
@@ -634,28 +633,32 @@ function hideThemeButtonState() {
634633
ul.appendChild(li);
635634
}
636635
div.appendChild(ul);
637-
if (sidebar) {
638-
sidebar.appendChild(div);
639-
}
636+
sidebar.appendChild(div);
640637
}
641638

642-
block("primitive", "Primitive Types");
643-
block("mod", "Modules");
644-
block("macro", "Macros");
645-
block("struct", "Structs");
646-
block("enum", "Enums");
647-
block("union", "Unions");
648-
block("constant", "Constants");
649-
block("static", "Statics");
650-
block("trait", "Traits");
651-
block("fn", "Functions");
652-
block("type", "Type Definitions");
653-
block("foreigntype", "Foreign Types");
654-
block("keyword", "Keywords");
655-
block("traitalias", "Trait Aliases");
656-
657-
// `crates{version}.js` should always be loaded before this script, so we can use it safely.
658-
addSidebarCrates(window.ALL_CRATES);
639+
if (sidebar) {
640+
var isModule = hasClass(document.body, "mod");
641+
if (!isModule) {
642+
block("primitive", "Primitive Types");
643+
block("mod", "Modules");
644+
block("macro", "Macros");
645+
block("struct", "Structs");
646+
block("enum", "Enums");
647+
block("union", "Unions");
648+
block("constant", "Constants");
649+
block("static", "Statics");
650+
block("trait", "Traits");
651+
block("fn", "Functions");
652+
block("type", "Type Definitions");
653+
block("foreigntype", "Foreign Types");
654+
block("keyword", "Keywords");
655+
block("traitalias", "Trait Aliases");
656+
}
657+
658+
// `crates{version}.js` should always be loaded before this script, so we can use
659+
// it safely.
660+
addSidebarCrates(window.ALL_CRATES);
661+
}
659662
};
660663

661664
window.register_implementors = function(imp) {

src/librustdoc/html/static/rustdoc.css

+4-1
Original file line numberDiff line numberDiff line change
@@ -311,9 +311,12 @@ nav.sub {
311311
border: none;
312312
}
313313

314-
.location a:first-child {
314+
.location a:first-of-type {
315315
font-weight: 500;
316316
}
317+
.location a:hover {
318+
text-decoration: underline;
319+
}
317320

318321
.block {
319322
padding: 0;

src/librustdoc/html/static/sidebar-items.js

-2
This file was deleted.

src/librustdoc/html/static_files.rs

-3
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,4 @@ crate mod noto_sans_kr {
141141
crate mod sidebar {
142142
/// File script to handle sidebar.
143143
crate static SOURCE_SCRIPT: &str = include_str!("static/source-script.js");
144-
145-
/// Top Level sidebar items script which will load a sidebar without items.
146-
crate static ITEMS: &str = include_str!("static/sidebar-items.js");
147144
}

src/test/rustdoc-gui/sidebar.goml

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
goto: file://|DOC_PATH|/test_docs/index.html
2+
assert: (".sidebar > .location", "Crate test_docs")
3+
// In modules, we only have one "location" element.
4+
assert: (".sidebar .location", 1)
5+
assert: (".sidebar-elems > #all-types", "See all test_docs's items")
6+
// We check that we have the crates list and that the "current" on is "test_docs".
7+
assert: (".sidebar-elems > .crate > ul > li > a.current", "test_docs")
8+
// And we're also supposed to have the list of items in the current module.
9+
assert: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules")
10+
assert: (".sidebar-elems > .items > ul > li:nth-child(2)", "Structs")
11+
assert: (".sidebar-elems > .items > ul > li:nth-child(3)", "Enums")
12+
assert: (".sidebar-elems > .items > ul > li:nth-child(4)", "Traits")
13+
assert: (".sidebar-elems > .items > ul > li:nth-child(5)", "Functions")
14+
assert: (".sidebar-elems > .items > ul > li:nth-child(6)", "Keywords")
15+
assert: ("#structs + table td > a", "Foo")
16+
click: "#structs + table td > a"
17+
18+
// PAGE: struct.Foo.html
19+
assert: (".sidebar .location", 2)
20+
// We check that there is no crate listed outside of the top level.
21+
assert-false: ".sidebar-elems > .crate"
22+
// We now go back to the crate page to click on the "lib2" crate link.
23+
goto: file://|DOC_PATH|/test_docs/index.html
24+
click: ".sidebar-elems > .crate > ul > li:first-child > a"
25+
26+
// PAGE: lib2/index.html
27+
goto: file://|DOC_PATH|/lib2/index.html
28+
assert: (".sidebar > .location", "Crate lib2")
29+
// We check that we have the crates list and that the "current" on is now "lib2".
30+
assert: (".sidebar-elems > .crate > ul > li > a.current", "lib2")
31+
// We now go to the "foobar" function page.
32+
assert: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules")
33+
assert: (".sidebar-elems > .items > ul > li:nth-child(2)", "Functions")
34+
assert: ("#functions + table td > a", "foobar")
35+
click: "#functions + table td > a"
36+
37+
// PAGE: fn.foobar.html
38+
// In items containing no items (like functions or constants) and in modules, we have one
39+
// "location" elements.
40+
assert: (".sidebar .location", 1)
41+
// There is a "<br>" tag between "in" and "lib2", but it doesn't count as a space.
42+
assert: (".sidebar .sidebar-elems .location", "Other items inlib2")
43+
// We check that we don't have the crate list.
44+
assert-false: ".sidebar-elems > .crate"
45+
46+
goto: ./module/index.html
47+
assert: (".sidebar > .location", "Module module")
48+
// We check that we don't have the crate list.
49+
assert-false: ".sidebar-elems > .crate"
50+
51+
goto: ./sub_module/sub_sub_module/index.html
52+
assert: (".sidebar > .location", "Module sub_sub_module")
53+
// We check that we don't have the crate list.
54+
assert-false: ".sidebar-elems > .crate"
55+
assert: (".sidebar-elems > .items > ul > li:nth-child(1)", "Functions")
56+
assert: ("#functions + table td > a", "foo")

src/test/rustdoc-gui/src/lib2.rs

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
pub mod module {
2+
pub mod sub_module {
3+
pub mod sub_sub_module {
4+
pub fn foo() {}
5+
}
6+
pub fn bar() {}
7+
}
8+
pub fn whatever() {}
9+
}
10+
11+
pub fn foobar() {}

0 commit comments

Comments
 (0)