about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-02-17 23:00:57 +0100
committerGitHub <noreply@github.com>2022-02-17 23:00:57 +0100
commit6a2b612590284f2e8fc08117c976e017ddd79d81 (patch)
tree5fdbb9a781c515fbfd626380bb239fd7f77b9b0a
parent98c54c8cad638e703b631a5ff64630e5e55eb5dc (diff)
parent0d928b6ed01ec66b4f6c4ea07d838bdcc5db4f23 (diff)
Rollup merge of #93780 - GuillaumeGomez:links-in-sidebar, r=jsha
Generate list instead of div items in sidebar

Fixes #92986.

Surprisingly, we didn't have much CSS for this...

[Demo](https://rustdoc.crud.net/imperio/links-in-sidebar/std/index.html).

r? `@jsha`
-rw-r--r--src/librustdoc/html/render/mod.rs225
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css11
-rw-r--r--src/test/rustdoc-gui/hash-item-expansion.goml4
-rw-r--r--src/test/rustdoc-gui/sidebar-mobile.goml2
-rw-r--r--src/test/rustdoc-gui/sidebar.goml34
-rw-r--r--src/test/rustdoc-gui/trait-sidebar-item-order.goml12
-rw-r--r--src/test/rustdoc/associated-consts.rs4
-rw-r--r--src/test/rustdoc/deref-mut-methods.rs2
-rw-r--r--src/test/rustdoc/deref-recursive-pathbuf.rs4
-rw-r--r--src/test/rustdoc/deref-recursive.rs4
-rw-r--r--src/test/rustdoc/deref-typedef.rs8
-rw-r--r--src/test/rustdoc/double-quote-escape.rs2
-rw-r--r--src/test/rustdoc/generic-impl.rs2
-rw-r--r--src/test/rustdoc/method-list.rs4
-rw-r--r--src/test/rustdoc/negative-impl-sidebar.rs2
-rw-r--r--src/test/rustdoc/recursive-deref-sidebar.rs4
-rw-r--r--src/test/rustdoc/sidebar-items.rs24
-rw-r--r--src/test/rustdoc/sidebar-link-generation.rs2
-rw-r--r--src/test/rustdoc/sidebar-links-to-foreign-impl.rs4
19 files changed, 168 insertions, 186 deletions
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 1c3f9b56b47..3e3302f8f4d 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1963,16 +1963,12 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
                 // We want links' order to be reproducible so we don't use unstable sort.
                 assoc_consts.sort();
 
-                out.push_str(
-                    "<h3 class=\"sidebar-title\">\
-                        <a href=\"#implementations\">Associated Constants</a>\
-                     </h3>\
-                     <div class=\"sidebar-links\">",
+                print_sidebar_block(
+                    out,
+                    "implementations",
+                    "Associated Constants",
+                    assoc_consts.iter(),
                 );
-                for line in assoc_consts {
-                    write!(out, "{}", line);
-                }
-                out.push_str("</div>");
             }
             let mut methods = v
                 .iter()
@@ -1983,14 +1979,7 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
                 // We want links' order to be reproducible so we don't use unstable sort.
                 methods.sort();
 
-                out.push_str(
-                    "<h3 class=\"sidebar-title\"><a href=\"#implementations\">Methods</a></h3>\
-                     <div class=\"sidebar-links\">",
-                );
-                for line in methods {
-                    write!(out, "{}", line);
-                }
-                out.push_str("</div>");
+                print_sidebar_block(out, "implementations", "Methods", methods.iter());
             }
         }
 
@@ -2029,14 +2018,6 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
                 ret
             };
 
-            let write_sidebar_links = |out: &mut Buffer, links: Vec<String>| {
-                out.push_str("<div class=\"sidebar-links\">");
-                for link in links {
-                    out.push_str(&link);
-                }
-                out.push_str("</div>");
-            };
-
             let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
                 v.iter().partition::<Vec<_>, _>(|i| i.inner_impl().kind.is_auto());
             let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) =
@@ -2047,27 +2028,30 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
             let blanket_format = format_impls(blanket_impl);
 
             if !concrete_format.is_empty() {
-                out.push_str(
-                    "<h3 class=\"sidebar-title\"><a href=\"#trait-implementations\">\
-                        Trait Implementations</a></h3>",
+                print_sidebar_block(
+                    out,
+                    "trait-implementations",
+                    "Trait Implementations",
+                    concrete_format.iter(),
                 );
-                write_sidebar_links(out, concrete_format);
             }
 
             if !synthetic_format.is_empty() {
-                out.push_str(
-                    "<h3 class=\"sidebar-title\"><a href=\"#synthetic-implementations\">\
-                        Auto Trait Implementations</a></h3>",
+                print_sidebar_block(
+                    out,
+                    "synthetic-implementations",
+                    "Auto Trait Implementations",
+                    synthetic_format.iter(),
                 );
-                write_sidebar_links(out, synthetic_format);
             }
 
             if !blanket_format.is_empty() {
-                out.push_str(
-                    "<h3 class=\"sidebar-title\"><a href=\"#blanket-implementations\">\
-                        Blanket Implementations</a></h3>",
+                print_sidebar_block(
+                    out,
+                    "blanket-implementations",
+                    "Blanket Implementations",
+                    blanket_format.iter(),
                 );
-                write_sidebar_links(out, blanket_format);
             }
         }
     }
@@ -2127,20 +2111,14 @@ fn sidebar_deref_methods(
                 } else {
                     "deref-methods"
                 };
-                write!(
-                    out,
-                    "<h3 class=\"sidebar-title\"><a href=\"#{}\">Methods from {}&lt;Target={}&gt;</a></h3>",
-                    id,
+                let title = format!(
+                    "Methods from {}&lt;Target={}&gt;",
                     Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print(cx))),
                     Escape(&format!("{:#}", real_target.print(cx))),
                 );
                 // We want links' order to be reproducible so we don't use unstable sort.
                 ret.sort();
-                out.push_str("<div class=\"sidebar-links\">");
-                for link in ret {
-                    write!(out, "{}", link);
-                }
-                out.push_str("</div>");
+                print_sidebar_block(out, id, &title, ret.iter());
             }
         }
 
@@ -2166,27 +2144,19 @@ fn sidebar_struct(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, s: &clea
     let fields = get_struct_fields_name(&s.fields);
 
     if !fields.is_empty() {
-        if let CtorKind::Fictive = s.struct_type {
-            sidebar.push_str(
-                "<h3 class=\"sidebar-title\"><a href=\"#fields\">Fields</a></h3>\
-                <div class=\"sidebar-links\">",
-            );
-
-            for field in fields {
-                sidebar.push_str(&field);
+        match s.struct_type {
+            CtorKind::Fictive => {
+                print_sidebar_block(&mut sidebar, "fields", "Fields", fields.iter());
             }
-
-            sidebar.push_str("</div>");
-        } else if let CtorKind::Fn = s.struct_type {
-            sidebar
-                .push_str("<h3 class=\"sidebar-title\"><a href=\"#fields\">Tuple Fields</a></h3>");
+            CtorKind::Fn => print_sidebar_title(&mut sidebar, "fields", "Tuple Fields"),
+            CtorKind::Const => {}
         }
     }
 
     sidebar_assoc_items(cx, &mut sidebar, it);
 
     if !sidebar.is_empty() {
-        write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
+        write!(buf, "<section>{}</section>", sidebar.into_inner());
     }
 }
 
@@ -2214,18 +2184,50 @@ fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String
     }
 }
 
+/// Don't call this function directly!!! Use `print_sidebar_title` or `print_sidebar_block` instead!
+fn print_sidebar_title_inner(buf: &mut Buffer, id: &str, title: &str) {
+    write!(
+        buf,
+        "<h3 class=\"sidebar-title\">\
+             <a href=\"#{}\">{}</a>\
+         </h3>",
+        id, title
+    );
+}
+
+fn print_sidebar_title(buf: &mut Buffer, id: &str, title: &str) {
+    buf.push_str("<div class=\"block\">");
+    print_sidebar_title_inner(buf, id, title);
+    buf.push_str("</div>");
+}
+
+fn print_sidebar_block(
+    buf: &mut Buffer,
+    id: &str,
+    title: &str,
+    items: impl Iterator<Item = impl fmt::Display>,
+) {
+    buf.push_str("<div class=\"block\">");
+    print_sidebar_title_inner(buf, id, title);
+    buf.push_str("<ul>");
+    for item in items {
+        write!(buf, "<li>{}</li>", item);
+    }
+    buf.push_str("</ul></div>");
+}
+
 fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) {
-    buf.write_str("<div class=\"block items\">");
+    buf.write_str("<section>");
 
     fn print_sidebar_section(
         out: &mut Buffer,
         items: &[clean::Item],
-        before: &str,
+        id: &str,
+        title: &str,
         filter: impl Fn(&clean::Item) -> bool,
-        write: impl Fn(&mut Buffer, &str),
-        after: &str,
+        mapper: impl Fn(&str) -> String,
     ) {
-        let mut items = items
+        let mut items: Vec<&str> = items
             .iter()
             .filter_map(|m| match m.name {
                 Some(ref name) if filter(m) => Some(name.as_str()),
@@ -2235,52 +2237,44 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean
 
         if !items.is_empty() {
             items.sort_unstable();
-            out.push_str(before);
-            for item in items.into_iter() {
-                write(out, &item);
-            }
-            out.push_str(after);
+            print_sidebar_block(out, id, title, items.into_iter().map(mapper));
         }
     }
 
     print_sidebar_section(
         buf,
         &t.items,
-        "<h3 class=\"sidebar-title\"><a href=\"#associated-types\">\
-            Associated Types</a></h3><div class=\"sidebar-links\">",
+        "associated-types",
+        "Associated Types",
         |m| m.is_associated_type(),
-        |out, sym| write!(out, "<a href=\"#associatedtype.{0}\">{0}</a>", sym),
-        "</div>",
+        |sym| format!("<a href=\"#associatedtype.{0}\">{0}</a>", sym),
     );
 
     print_sidebar_section(
         buf,
         &t.items,
-        "<h3 class=\"sidebar-title\"><a href=\"#associated-const\">\
-            Associated Constants</a></h3><div class=\"sidebar-links\">",
+        "associated-const",
+        "Associated Constants",
         |m| m.is_associated_const(),
-        |out, sym| write!(out, "<a href=\"#associatedconstant.{0}\">{0}</a>", sym),
-        "</div>",
+        |sym| format!("<a href=\"#associatedconstant.{0}\">{0}</a>", sym),
     );
 
     print_sidebar_section(
         buf,
         &t.items,
-        "<h3 class=\"sidebar-title\"><a href=\"#required-methods\">\
-            Required Methods</a></h3><div class=\"sidebar-links\">",
+        "required-methods",
+        "Required Methods",
         |m| m.is_ty_method(),
-        |out, sym| write!(out, "<a href=\"#tymethod.{0}\">{0}</a>", sym),
-        "</div>",
+        |sym| format!("<a href=\"#tymethod.{0}\">{0}</a>", sym),
     );
 
     print_sidebar_section(
         buf,
         &t.items,
-        "<h3 class=\"sidebar-title\"><a href=\"#provided-methods\">\
-            Provided Methods</a></h3><div class=\"sidebar-links\">",
+        "provided-methods",
+        "Provided Methods",
         |m| m.is_method(),
-        |out, sym| write!(out, "<a href=\"#method.{0}\">{0}</a>", sym),
-        "</div>",
+        |sym| format!("<a href=\"#method.{0}\">{0}</a>", sym),
     );
 
     let cache = cx.cache();
@@ -2295,29 +2289,23 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean
 
         if !res.is_empty() {
             res.sort();
-            buf.push_str(
-                "<h3 class=\"sidebar-title\"><a href=\"#foreign-impls\">\
-                    Implementations on Foreign Types</a></h3>\
-                 <div class=\"sidebar-links\">",
+            print_sidebar_block(
+                buf,
+                "foreign-impls",
+                "Implementations on Foreign Types",
+                res.iter().map(|(name, id)| format!("<a href=\"#{}\">{}</a>", id, Escape(&name))),
             );
-            for (name, id) in res.into_iter() {
-                write!(buf, "<a href=\"#{}\">{}</a>", id, Escape(&name));
-            }
-            buf.push_str("</div>");
         }
     }
 
     sidebar_assoc_items(cx, buf, it);
 
-    buf.push_str("<h3 class=\"sidebar-title\"><a href=\"#implementors\">Implementors</a></h3>");
+    print_sidebar_title(buf, "implementors", "Implementors");
     if t.is_auto {
-        buf.push_str(
-            "<h3 class=\"sidebar-title\"><a \
-                href=\"#synthetic-implementors\">Auto Implementors</a></h3>",
-        );
+        print_sidebar_title(buf, "synthetic-implementors", "Auto Implementors");
     }
 
-    buf.push_str("</div>")
+    buf.push_str("</section>")
 }
 
 fn sidebar_primitive(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
@@ -2325,7 +2313,7 @@ fn sidebar_primitive(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
     sidebar_assoc_items(cx, &mut sidebar, it);
 
     if !sidebar.is_empty() {
-        write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
+        write!(buf, "<section>{}</section>", sidebar.into_inner());
     }
 }
 
@@ -2334,7 +2322,7 @@ fn sidebar_typedef(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
     sidebar_assoc_items(cx, &mut sidebar, it);
 
     if !sidebar.is_empty() {
-        write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
+        write!(buf, "<section>{}</section>", sidebar.into_inner());
     }
 }
 
@@ -2355,22 +2343,13 @@ fn sidebar_union(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, u: &clean
     let fields = get_struct_fields_name(&u.fields);
 
     if !fields.is_empty() {
-        sidebar.push_str(
-            "<h3 class=\"sidebar-title\"><a href=\"#fields\">Fields</a></h3>\
-            <div class=\"sidebar-links\">",
-        );
-
-        for field in fields {
-            sidebar.push_str(&field);
-        }
-
-        sidebar.push_str("</div>");
+        print_sidebar_block(&mut sidebar, "fields", "Fields", fields.iter());
     }
 
     sidebar_assoc_items(cx, &mut sidebar, it);
 
     if !sidebar.is_empty() {
-        write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
+        write!(buf, "<section>{}</section>", sidebar.into_inner());
     }
 }
 
@@ -2388,17 +2367,13 @@ fn sidebar_enum(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, e: &clean:
         .collect::<Vec<_>>();
     if !variants.is_empty() {
         variants.sort_unstable();
-        sidebar.push_str(&format!(
-            "<h3 class=\"sidebar-title\"><a href=\"#variants\">Variants</a></h3>\
-             <div class=\"sidebar-links\">{}</div>",
-            variants.join(""),
-        ));
+        print_sidebar_block(&mut sidebar, "variants", "Variants", variants.iter());
     }
 
     sidebar_assoc_items(cx, &mut sidebar, it);
 
     if !sidebar.is_empty() {
-        write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
+        write!(buf, "<section>{}</section>", sidebar.into_inner());
     }
 }
 
@@ -2569,7 +2544,15 @@ fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) {
     }
 
     if !sidebar.is_empty() {
-        write!(buf, "<div class=\"block items\"><ul>{}</ul></div>", sidebar);
+        write!(
+            buf,
+            "<section>\
+                 <div class=\"block\">\
+                     <ul>{}</ul>\
+                 </div>\
+             </section>",
+            sidebar
+        );
     }
 }
 
@@ -2578,7 +2561,7 @@ fn sidebar_foreign_type(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
     sidebar_assoc_items(cx, &mut sidebar, it);
 
     if !sidebar.is_empty() {
-        write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
+        write!(buf, "<section>{}</section>", sidebar.into_inner());
     }
 }
 
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 662221ae773..f1e0a89883a 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -484,10 +484,6 @@ h2.location a {
 	overflow: hidden;
 }
 
-.sidebar-links a {
-	white-space: nowrap;
-}
-
 .sidebar h2 {
 	border-bottom: none;
 	font-weight: 500;
@@ -504,11 +500,14 @@ h2.location a {
 	margin: 0;
 }
 
-.sidebar-links,
-.block {
+.sidebar-elems .block {
 	margin-bottom: 2em;
 }
 
+.sidebar-elems .block li a {
+	white-space: nowrap;
+}
+
 .mobile-topbar {
 	display: none;
 }
diff --git a/src/test/rustdoc-gui/hash-item-expansion.goml b/src/test/rustdoc-gui/hash-item-expansion.goml
index 2885978ce1f..a680635ef8a 100644
--- a/src/test/rustdoc-gui/hash-item-expansion.goml
+++ b/src/test/rustdoc-gui/hash-item-expansion.goml
@@ -5,7 +5,7 @@ assert-attribute: ("#blanket-implementations-list > details:nth-child(2)", {"ope
 // We first check that the impl block is open by default.
 assert-attribute: ("#implementations + details", {"open": ""})
 // To ensure that we will click on the currently hidden method.
-assert-text: (".sidebar-links > a", "must_use")
-click: ".sidebar-links > a"
+assert-text: (".sidebar-elems section .block li > a", "must_use")
+click: ".sidebar-elems section .block li > a"
 // We check that the impl block was opened as expected so that we can see the method.
 assert-attribute: ("#implementations + details", {"open": ""})
diff --git a/src/test/rustdoc-gui/sidebar-mobile.goml b/src/test/rustdoc-gui/sidebar-mobile.goml
index 9581aa74b0f..79f18db8fc7 100644
--- a/src/test/rustdoc-gui/sidebar-mobile.goml
+++ b/src/test/rustdoc-gui/sidebar-mobile.goml
@@ -33,7 +33,7 @@ assert-property: (".mobile-topbar", {"clientHeight": "45"})
 // Check that clicking an element from the sidebar scrolls to the right place
 // so the target is not obscured by the topbar.
 click: ".sidebar-menu-toggle"
-click: ".sidebar-links a"
+click: ".sidebar-elems section .block li > a"
 assert-position: ("#method\.must_use", {"y": 45})
 
 // Check that the bottom-most item on the sidebar menu can be scrolled fully into view.
diff --git a/src/test/rustdoc-gui/sidebar.goml b/src/test/rustdoc-gui/sidebar.goml
index 9505e00512f..6b79b00d3f7 100644
--- a/src/test/rustdoc-gui/sidebar.goml
+++ b/src/test/rustdoc-gui/sidebar.goml
@@ -13,15 +13,15 @@ assert-css: ("#all-types", {"color": "rgb(53, 109, 164)"})
 // We check that we have the crates list and that the "current" on is "test_docs".
 assert-text: (".sidebar-elems .crate > ul > li > a.current", "test_docs")
 // And we're also supposed to have the list of items in the current module.
-assert-text: (".sidebar-elems .items > ul > li:nth-child(1)", "Modules")
-assert-text: (".sidebar-elems .items > ul > li:nth-child(2)", "Macros")
-assert-text: (".sidebar-elems .items > ul > li:nth-child(3)", "Structs")
-assert-text: (".sidebar-elems .items > ul > li:nth-child(4)", "Enums")
-assert-text: (".sidebar-elems .items > ul > li:nth-child(5)", "Traits")
-assert-text: (".sidebar-elems .items > ul > li:nth-child(6)", "Functions")
-assert-text: (".sidebar-elems .items > ul > li:nth-child(7)", "Type Definitions")
-assert-text: (".sidebar-elems .items > ul > li:nth-child(8)", "Unions")
-assert-text: (".sidebar-elems .items > ul > li:nth-child(9)", "Keywords")
+assert-text: (".sidebar-elems section ul > li:nth-child(1)", "Modules")
+assert-text: (".sidebar-elems section ul > li:nth-child(2)", "Macros")
+assert-text: (".sidebar-elems section ul > li:nth-child(3)", "Structs")
+assert-text: (".sidebar-elems section ul > li:nth-child(4)", "Enums")
+assert-text: (".sidebar-elems section ul > li:nth-child(5)", "Traits")
+assert-text: (".sidebar-elems section ul > li:nth-child(6)", "Functions")
+assert-text: (".sidebar-elems section ul > li:nth-child(7)", "Type Definitions")
+assert-text: (".sidebar-elems section ul > li:nth-child(8)", "Unions")
+assert-text: (".sidebar-elems section ul > li:nth-child(9)", "Keywords")
 assert-text: ("#structs + .item-table .item-left > a", "Foo")
 click: "#structs + .item-table .item-left > a"
 
@@ -30,7 +30,7 @@ assert-count: (".sidebar .location", 2)
 // We check that there is no crate listed outside of the top level.
 assert-false: ".sidebar-elems > .crate"
 
-click: ".sidebar-links a"
+click: ".sidebar-elems section .block li > a"
 assert-property-false: ("html", {"scrollTop": "0"})
 
 click: ".sidebar h2.location a"
@@ -47,11 +47,11 @@ assert-text: (".sidebar > .location", "Crate lib2")
 // We check that we have the crates list and that the "current" on is now "lib2".
 assert-text: (".sidebar-elems .crate > ul > li > a.current", "lib2")
 // We now go to the "foobar" function page.
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(2)", "Structs")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(3)", "Traits")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(4)", "Functions")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(5)", "Type Definitions")
+assert-text: (".sidebar-elems > section .block ul > li:nth-child(1)", "Modules")
+assert-text: (".sidebar-elems > section .block ul > li:nth-child(2)", "Structs")
+assert-text: (".sidebar-elems > section .block ul > li:nth-child(3)", "Traits")
+assert-text: (".sidebar-elems > section .block ul > li:nth-child(4)", "Functions")
+assert-text: (".sidebar-elems > section .block ul > li:nth-child(5)", "Type Definitions")
 assert-text: ("#functions + .item-table .item-left > a", "foobar")
 click: "#functions + .item-table .item-left > a"
 
@@ -72,12 +72,12 @@ goto: ./sub_module/sub_sub_module/index.html
 assert-text: (".sidebar > .location", "Module sub_sub_module")
 // We check that we don't have the crate list.
 assert-false: ".sidebar-elems .crate"
-assert-text: (".sidebar-elems .items > ul > li:nth-child(1)", "Functions")
+assert-text: (".sidebar-elems > section ul > li:nth-child(1)", "Functions")
 assert-text: ("#functions + .item-table .item-left > a", "foo")
 
 // Links to trait implementations in the sidebar should not wrap even if they are long.
 goto: file://|DOC_PATH|/lib2/struct.HasALongTraitWithParams.html
-assert-property: (".sidebar-links a", {"offsetHeight": 29})
+assert-property: (".sidebar-elems section .block li > a", {"offsetHeight": 29})
 
 // Test that clicking on of the "In <module>" headings in the sidebar links to the
 // appropriate anchor in index.html.
diff --git a/src/test/rustdoc-gui/trait-sidebar-item-order.goml b/src/test/rustdoc-gui/trait-sidebar-item-order.goml
index 38942baa0b5..d77d1dca483 100644
--- a/src/test/rustdoc-gui/trait-sidebar-item-order.goml
+++ b/src/test/rustdoc-gui/trait-sidebar-item-order.goml
@@ -1,8 +1,8 @@
 // Checks that the elements in the sidebar are alphabetically sorted.
 goto: file://|DOC_PATH|/test_docs/trait.AnotherOne.html
-assert-text: (".sidebar-links a:nth-of-type(1)", "another")
-assert-text: (".sidebar-links a:nth-of-type(2)", "func1")
-assert-text: (".sidebar-links a:nth-of-type(3)", "func2")
-assert-text: (".sidebar-links a:nth-of-type(4)", "func3")
-assert-text: (".sidebar-links a:nth-of-type(5)", "hello")
-assert-text: (".sidebar-links a:nth-of-type(6)", "why_not")
+assert-text: (".sidebar-elems section .block li:nth-of-type(1) > a", "another")
+assert-text: (".sidebar-elems section .block li:nth-of-type(2) > a", "func1")
+assert-text: (".sidebar-elems section .block li:nth-of-type(3) > a", "func2")
+assert-text: (".sidebar-elems section .block li:nth-of-type(4) > a", "func3")
+assert-text: (".sidebar-elems section .block li:nth-of-type(5) > a", "hello")
+assert-text: (".sidebar-elems section .block li:nth-of-type(6) > a", "why_not")
diff --git a/src/test/rustdoc/associated-consts.rs b/src/test/rustdoc/associated-consts.rs
index 6ae5e20632e..da50fb86cd5 100644
--- a/src/test/rustdoc/associated-consts.rs
+++ b/src/test/rustdoc/associated-consts.rs
@@ -10,7 +10,7 @@ pub struct Bar;
 
 // @has 'foo/struct.Bar.html'
 // @has - '//h3[@class="sidebar-title"]' 'Associated Constants'
-// @has - '//div[@class="sidebar-elems"]//div[@class="sidebar-links"]/a' 'FOO'
+// @has - '//div[@class="sidebar-elems"]//a' 'FOO'
 impl Trait for Bar {
     const FOO: u32 = 1;
 
@@ -23,7 +23,7 @@ pub enum Foo {
 
 // @has 'foo/enum.Foo.html'
 // @has - '//h3[@class="sidebar-title"]' 'Associated Constants'
-// @has - '//div[@class="sidebar-elems"]//div[@class="sidebar-links"]/a' 'FOO'
+// @has - '//div[@class="sidebar-elems"]//a' 'FOO'
 impl Trait for Foo {
     const FOO: u32 = 1;
 
diff --git a/src/test/rustdoc/deref-mut-methods.rs b/src/test/rustdoc/deref-mut-methods.rs
index 0e27fc90b69..fdf8434224f 100644
--- a/src/test/rustdoc/deref-mut-methods.rs
+++ b/src/test/rustdoc/deref-mut-methods.rs
@@ -9,7 +9,7 @@ impl Foo {
 }
 
 // @has foo/struct.Bar.html
-// @has - '//div[@class="sidebar-links"]/a[@href="#method.foo"]' 'foo'
+// @has - '//*[@class="sidebar-elems"]//*[@class="block"]//a[@href="#method.foo"]' 'foo'
 pub struct Bar {
     foo: Foo,
 }
diff --git a/src/test/rustdoc/deref-recursive-pathbuf.rs b/src/test/rustdoc/deref-recursive-pathbuf.rs
index 9ab338ca9b1..746df9c804e 100644
--- a/src/test/rustdoc/deref-recursive-pathbuf.rs
+++ b/src/test/rustdoc/deref-recursive-pathbuf.rs
@@ -8,9 +8,9 @@
 // @has '-' '//*[@id="deref-methods-Path"]' 'Methods from Deref<Target = Path>'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.exists"]' 'pub fn exists(&self)'
 // @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-PathBuf"]' 'Methods from Deref<Target=PathBuf>'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.as_path"]' 'as_path'
+// @has '-' '//*[@class="sidebar-elems"]//*[@class="block"]//a[@href="#method.as_path"]' 'as_path'
 // @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Path"]' 'Methods from Deref<Target=Path>'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.exists"]' 'exists'
+// @has '-' '//*[@class="sidebar-elems"]//*[@class="block"]//a[@href="#method.exists"]' 'exists'
 
 #![crate_name = "foo"]
 
diff --git a/src/test/rustdoc/deref-recursive.rs b/src/test/rustdoc/deref-recursive.rs
index c07e048b065..d5f8473f284 100644
--- a/src/test/rustdoc/deref-recursive.rs
+++ b/src/test/rustdoc/deref-recursive.rs
@@ -8,9 +8,9 @@
 // @has '-' '//*[@id="deref-methods-Baz"]' 'Methods from Deref<Target = Baz>'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.baz"]' 'pub fn baz(&self)'
 // @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Bar"]' 'Methods from Deref<Target=Bar>'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.bar"]' 'bar'
+// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.bar"]' 'bar'
 // @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Baz"]' 'Methods from Deref<Target=Baz>'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.baz"]' 'baz'
+// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.baz"]' 'baz'
 
 #![crate_name = "foo"]
 
diff --git a/src/test/rustdoc/deref-typedef.rs b/src/test/rustdoc/deref-typedef.rs
index ad7a96c5dad..28f977e315a 100644
--- a/src/test/rustdoc/deref-typedef.rs
+++ b/src/test/rustdoc/deref-typedef.rs
@@ -7,10 +7,10 @@
 // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_c"]' 'pub fn foo_c(&self)'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_j"]' 'pub fn foo_j(&self)'
 // @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-FooJ"]' 'Methods from Deref<Target=FooJ>'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_a"]' 'foo_a'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_b"]' 'foo_b'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_c"]' 'foo_c'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_j"]' 'foo_j'
+// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_a"]' 'foo_a'
+// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_b"]' 'foo_b'
+// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_c"]' 'foo_c'
+// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_j"]' 'foo_j'
 
 pub struct FooA;
 pub type FooB = FooA;
diff --git a/src/test/rustdoc/double-quote-escape.rs b/src/test/rustdoc/double-quote-escape.rs
index 546af2c121a..b7bbf140cfd 100644
--- a/src/test/rustdoc/double-quote-escape.rs
+++ b/src/test/rustdoc/double-quote-escape.rs
@@ -8,5 +8,5 @@ pub trait Foo<T> {
 pub struct Bar;
 
 // @has foo/struct.Bar.html
-// @has - '//*[@class="sidebar-links"]/a[@href="#impl-Foo%3Cunsafe%20extern%20%22C%22%20fn()%3E"]' 'Foo<unsafe extern "C" fn()>'
+// @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo%3Cunsafe%20extern%20%22C%22%20fn()%3E"]' 'Foo<unsafe extern "C" fn()>'
 impl Foo<unsafe extern "C" fn()> for Bar {}
diff --git a/src/test/rustdoc/generic-impl.rs b/src/test/rustdoc/generic-impl.rs
index 0f6cba93f95..1268c9587f8 100644
--- a/src/test/rustdoc/generic-impl.rs
+++ b/src/test/rustdoc/generic-impl.rs
@@ -7,7 +7,7 @@ pub struct Bar;
 
 // @has foo/struct.Foo.html '//*[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
 pub struct Foo;
-// @has foo/struct.Foo.html '//div[@class="sidebar-links"]/a[@href="#impl-ToString"]' 'ToString'
+// @has foo/struct.Foo.html '//*[@class="sidebar-elems"]//section//a[@href="#impl-ToString"]' 'ToString'
 
 impl fmt::Display for Foo {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
diff --git a/src/test/rustdoc/method-list.rs b/src/test/rustdoc/method-list.rs
index 9f24e817fd3..50f4af3aaaf 100644
--- a/src/test/rustdoc/method-list.rs
+++ b/src/test/rustdoc/method-list.rs
@@ -1,8 +1,8 @@
 #![crate_name = "foo"]
 
 // @has foo/struct.Foo.html
-// @has - '//*[@class="sidebar-links"]/a' 'super_long_name'
-// @has - '//*[@class="sidebar-links"]/a' 'Disp'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'super_long_name'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'Disp'
 pub struct Foo(usize);
 
 impl Foo {
diff --git a/src/test/rustdoc/negative-impl-sidebar.rs b/src/test/rustdoc/negative-impl-sidebar.rs
index d63ab346045..b995fff1f9a 100644
--- a/src/test/rustdoc/negative-impl-sidebar.rs
+++ b/src/test/rustdoc/negative-impl-sidebar.rs
@@ -5,5 +5,5 @@ pub struct Foo;
 
 // @has foo/struct.Foo.html
 // @has - '//*[@class="sidebar-title"]/a[@href="#trait-implementations"]' 'Trait Implementations'
-// @has - '//*[@class="sidebar-links"]/a' '!Sync'
+// @has - '//*[@class="sidebar-elems"]//section//a' '!Sync'
 impl !Sync for Foo {}
diff --git a/src/test/rustdoc/recursive-deref-sidebar.rs b/src/test/rustdoc/recursive-deref-sidebar.rs
index 65a7debc253..619f40eff89 100644
--- a/src/test/rustdoc/recursive-deref-sidebar.rs
+++ b/src/test/rustdoc/recursive-deref-sidebar.rs
@@ -9,13 +9,13 @@ impl B { pub fn foo_b(&self) {} }
 pub struct C {}
 impl C { pub fn foo_c(&self) {} }
 
-// @has recursive_deref_sidebar/struct.A.html '//div[@class="sidebar-links"]' 'foo_b'
+// @has recursive_deref_sidebar/struct.A.html '//*[@class="sidebar-elems"]//section' 'foo_b'
 impl Deref for A {
     type Target = B;
     fn deref(&self) -> &B { todo!() }
 }
 
-// @has recursive_deref_sidebar/struct.A.html '//div[@class="sidebar-links"]' 'foo_c'
+// @has recursive_deref_sidebar/struct.A.html '//*[@class="sidebar-elems"]//section' 'foo_c'
 impl Deref for B {
     type Target = C;
     fn deref(&self) -> &C { todo!() }
diff --git a/src/test/rustdoc/sidebar-items.rs b/src/test/rustdoc/sidebar-items.rs
index ee670e88b5c..375cad9da7f 100644
--- a/src/test/rustdoc/sidebar-items.rs
+++ b/src/test/rustdoc/sidebar-items.rs
@@ -2,13 +2,13 @@
 
 // @has foo/trait.Foo.html
 // @has - '//*[@class="sidebar-title"]/a[@href="#required-methods"]' 'Required Methods'
-// @has - '//*[@class="sidebar-links"]/a' 'bar'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'bar'
 // @has - '//*[@class="sidebar-title"]/a[@href="#provided-methods"]' 'Provided Methods'
-// @has - '//*[@class="sidebar-links"]/a' 'foo'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'foo'
 // @has - '//*[@class="sidebar-title"]/a[@href="#associated-const"]' 'Associated Constants'
-// @has - '//*[@class="sidebar-links"]/a' 'BAR'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'BAR'
 // @has - '//*[@class="sidebar-title"]/a[@href="#associated-types"]' 'Associated Types'
-// @has - '//*[@class="sidebar-links"]/a' 'Output'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'Output'
 pub trait Foo {
     const BAR: u32 = 0;
     type Output: ?Sized;
@@ -19,9 +19,9 @@ pub trait Foo {
 
 // @has foo/struct.Bar.html
 // @has - '//*[@class="sidebar-title"]/a[@href="#fields"]' 'Fields'
-// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.f"]' 'f'
-// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.u"]' 'u'
-// @!has - '//*[@class="sidebar-links"]/a' 'waza'
+// @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f"]' 'f'
+// @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.u"]' 'u'
+// @!has - '//*[@class="sidebar-elems"]//section//a' 'waza'
 pub struct Bar {
     pub f: u32,
     pub u: u32,
@@ -30,8 +30,8 @@ pub struct Bar {
 
 // @has foo/enum.En.html
 // @has - '//*[@class="sidebar-title"]/a[@href="#variants"]' 'Variants'
-// @has - '//*[@class="sidebar-links"]/a' 'Foo'
-// @has - '//*[@class="sidebar-links"]/a' 'Bar'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'Foo'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'Bar'
 pub enum En {
     Foo,
     Bar,
@@ -39,9 +39,9 @@ pub enum En {
 
 // @has foo/union.MyUnion.html
 // @has - '//*[@class="sidebar-title"]/a[@href="#fields"]' 'Fields'
-// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.f1"]' 'f1'
-// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.f2"]' 'f2'
-// @!has - '//*[@class="sidebar-links"]/a' 'waza'
+// @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f1"]' 'f1'
+// @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f2"]' 'f2'
+// @!has - '//*[@class="sidebar-elems"]//section//a' 'waza'
 pub union MyUnion {
     pub f1: u32,
     pub f2: f32,
diff --git a/src/test/rustdoc/sidebar-link-generation.rs b/src/test/rustdoc/sidebar-link-generation.rs
index 76b77b9bcbb..7858f35a261 100644
--- a/src/test/rustdoc/sidebar-link-generation.rs
+++ b/src/test/rustdoc/sidebar-link-generation.rs
@@ -1,6 +1,6 @@
 #![crate_name = "foo"]
 
-// @has foo/struct.SomeStruct.html '//*[@class="sidebar-links"]/a[@href="#method.some_fn-1"]' \
+// @has foo/struct.SomeStruct.html '//*[@class="sidebar-elems"]//section//li/a[@href="#method.some_fn-1"]' \
 //          "some_fn"
 pub struct SomeStruct<T> { _inner: T }
 
diff --git a/src/test/rustdoc/sidebar-links-to-foreign-impl.rs b/src/test/rustdoc/sidebar-links-to-foreign-impl.rs
index 63e486b8834..15515039659 100644
--- a/src/test/rustdoc/sidebar-links-to-foreign-impl.rs
+++ b/src/test/rustdoc/sidebar-links-to-foreign-impl.rs
@@ -5,9 +5,9 @@
 // @has foo/trait.Foo.html
 // @has - '//*[@class="sidebar-title"]/a[@href="#foreign-impls"]' 'Implementations on Foreign Types'
 // @has - '//h2[@id="foreign-impls"]' 'Implementations on Foreign Types'
-// @has - '//*[@class="sidebar-links"]/a[@href="#impl-Foo-for-u32"]' 'u32'
+// @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo-for-u32"]' 'u32'
 // @has - '//*[@id="impl-Foo-for-u32"]//h3[@class="code-header in-band"]' 'impl Foo for u32'
-// @has - '//*[@class="sidebar-links"]/a[@href="#impl-Foo-for-%26%27a%20str"]' "&'a str"
+// @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo-for-%26%27a%20str"]' "&'a str"
 // @has - '//*[@id="impl-Foo-for-%26%27a%20str"]//h3[@class="code-header in-band"]' "impl<'a> Foo for &'a str"
 pub trait Foo {}