diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 85a76054a12d..e8343b2e21c8 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -2799,6 +2799,8 @@ class DocSearch {
result_list.sort((aaa, bbb) => {
const aai = aaa.item;
const bbi = bbb.item;
+ const ap = aai.modulePath !== undefined ? aai.modulePath : "";
+ const bp = bbi.modulePath !== undefined ? bbi.modulePath : "";
/** @type {number} */
let a;
/** @type {number} */
@@ -2829,14 +2831,25 @@ class DocSearch {
if (a !== b) {
return a - b;
}
- }
- // Sort by distance in the path part, if specified
- // (less changes required to match means higher rankings)
- a = Number(aaa.path_dist);
- b = Number(bbb.path_dist);
- if (a !== b) {
- return a - b;
+ if (parsedQuery.elems[0] &&
+ parsedQuery.elems[0].pathWithoutLast.length !== 0
+ ) {
+ // Sort by distance in the path part, if specified
+ // (less changes required to match means higher rankings)
+ a = Number(aaa.path_dist);
+ b = Number(bbb.path_dist);
+ if (a !== b) {
+ return a - b;
+ }
+
+ // sort by path (longer goes later)
+ a = ap.length + (aai.parent ? aai.parent.name.length + 2 : 0);
+ b = bp.length + (bbi.parent ? bbi.parent.name.length + 2 : 0);
+ if (a !== b) {
+ return a - b;
+ }
+ }
}
// (later literal occurrence, if any, goes later)
@@ -2890,8 +2903,8 @@ class DocSearch {
}
// sort by item name (lexicographically larger goes later)
- let aw = aai.normalizedName;
- let bw = bbi.normalizedName;
+ const aw = aai.normalizedName;
+ const bw = bbi.normalizedName;
if (aw !== bw) {
return (aw > bw ? +1 : -1);
}
@@ -2914,12 +2927,8 @@ class DocSearch {
}
// sort by path (lexicographically larger goes later)
- const ap = aai.modulePath;
- const bp = bbi.modulePath;
- aw = ap === undefined ? "" : ap;
- bw = bp === undefined ? "" : bp;
- if (aw !== bw) {
- return (aw > bw ? +1 : -1);
+ if (ap !== bp) {
+ return (ap > bp ? +1 : -1);
}
// que sera, sera
@@ -3848,13 +3857,19 @@ class DocSearch {
let dist_total = 0;
for (let x = 0; x < clength; ++x) {
const [p, c] = [path[i + x], contains[x]];
+ const indexOf = p.indexOf(c);
if (parsedQuery.literalSearch && p !== c) {
continue pathiter;
- } else if (Math.floor((p.length - c.length) / 3) <= maxPathEditDistance &&
- p.indexOf(c) !== -1
- ) {
+ } else if (indexOf !== -1) {
// discount distance on substring match
- dist_total += Math.floor((p.length - c.length) / 3);
+ // if component is surrounded by underscores or edges,
+ // count the distance as zero
+ if (
+ (indexOf !== 0 && p[indexOf - 1] !== "_") ||
+ (indexOf + c.length !== p.length && p[indexOf + c.length] !== "_")
+ ) {
+ dist_total += Math.floor((p.length - c.length) / 3);
+ }
} else {
const dist = editDistance(p, c, maxPathEditDistance);
if (dist > maxPathEditDistance) {
diff --git a/tests/rustdoc-js-std/path-maxeditdistance.js b/tests/rustdoc-js-std/path-maxeditdistance.js
index b22a506eee5f..96d58d239865 100644
--- a/tests/rustdoc-js-std/path-maxeditdistance.js
+++ b/tests/rustdoc-js-std/path-maxeditdistance.js
@@ -10,15 +10,24 @@ const EXPECTED = [
query: 'vec::iter',
others: [
// std::net::ToSocketAttrs::iter should not show up here
+ { 'path': 'std::collections::vec_deque', 'name': 'Iter' },
{ 'path': 'std::collections::VecDeque', 'name': 'iter' },
+ { 'path': 'std::collections::vec_deque', 'name': 'IterMut' },
{ 'path': 'std::collections::VecDeque', 'name': 'iter_mut' },
- { 'path': 'std::vec::Vec', 'name': 'from_iter' },
{ 'path': 'std::vec', 'name': 'IntoIter' },
+ { 'path': 'std::vec::Vec', 'name': 'from_iter' },
{ 'path': 'std::vec::Vec', 'name': 'into_iter' },
- { 'path': 'std::vec::ExtractIf', 'name': 'into_iter' },
{ 'path': 'std::vec::Drain', 'name': 'into_iter' },
- { 'path': 'std::vec::IntoIter', 'name': 'into_iter' },
{ 'path': 'std::vec::Splice', 'name': 'into_iter' },
+ { 'path': 'std::vec::IntoIter', 'name': 'into_iter' },
+ { 'path': 'std::vec::ExtractIf', 'name': 'into_iter' },
+ { 'path': 'std::collections::vec_deque', 'name': 'IntoIter' },
+ { 'path': 'std::collections::vec_deque::Iter', 'name': 'into_iter' },
+ { 'path': 'std::collections::vec_deque::Drain', 'name': 'into_iter' },
+ { 'path': 'std::collections::vec_deque::Splice', 'name': 'into_iter' },
+ { 'path': 'std::collections::vec_deque::IterMut', 'name': 'into_iter' },
+ { 'path': 'std::collections::vec_deque::IntoIter', 'name': 'into_iter' },
+ { 'path': 'std::collections::vec_deque::ExtractIf', 'name': 'into_iter' },
{ 'path': 'std::collections::VecDeque', 'name': 'from_iter' },
{ 'path': 'std::collections::VecDeque', 'name': 'into_iter' },
],
diff --git a/tests/rustdoc-js/path-substring.js b/tests/rustdoc-js/path-substring.js
new file mode 100644
index 000000000000..86529e4f100c
--- /dev/null
+++ b/tests/rustdoc-js/path-substring.js
@@ -0,0 +1,75 @@
+// exact-check
+// ignore-tidy-linelength
+const EXPECTED = [
+ // should match (substring)
+ {
+ 'query': 'struct:now::Country',
+ 'others': [
+ { 'path': 'x::now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their', 'name': 'Country' },
+ ],
+ },
+ {
+ 'query': 'struct:is::Country',
+ 'others': [
+ { 'path': 'x::now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their', 'name': 'Country' },
+ ],
+ },
+ {
+ 'query': 'struct:is_the::Country',
+ 'others': [
+ { 'path': 'x::now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their', 'name': 'Country' },
+ ],
+ },
+ {
+ 'query': 'struct:the::Country',
+ 'others': [
+ { 'path': 'x::now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their', 'name': 'Country' },
+ ],
+ },
+ {
+ 'query': 'struct:their::Country',
+ 'others': [
+ { 'path': 'x::now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their', 'name': 'Country' },
+ ],
+ },
+ // should not match
+ {
+ 'query': 'struct:ood::Country',
+ 'others': [],
+ },
+ {
+ 'query': 'struct:goo::Country',
+ 'others': [],
+ },
+ {
+ 'query': 'struct:he::Country',
+ 'others': [],
+ },
+ {
+ 'query': 'struct:heir::Country',
+ 'others': [],
+ },
+ {
+ 'query': 'struct:hei::Country',
+ 'others': [],
+ },
+ {
+ 'query': 'struct:no::Country',
+ 'others': [],
+ },
+ // should match (edit distance)
+ {
+ 'query': 'struct:nowisthetimeforallgoodmentocometotheaidoftheir::Country',
+ 'others': [
+ { 'path': 'x::nowisthetimeforallgoodmentocometotheaidoftheir', 'name': 'Country' },
+ { 'path': 'x::now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their', 'name': 'Country' },
+ ],
+ },
+ {
+ 'query': 'struct:now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their::Country',
+ 'others': [
+ { 'path': 'x::now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their', 'name': 'Country' },
+ { 'path': 'x::nowisthetimeforallgoodmentocometotheaidoftheir', 'name': 'Country' },
+ ],
+ },
+];
diff --git a/tests/rustdoc-js/path-substring.rs b/tests/rustdoc-js/path-substring.rs
new file mode 100644
index 000000000000..0d093d84c1c9
--- /dev/null
+++ b/tests/rustdoc-js/path-substring.rs
@@ -0,0 +1,7 @@
+#![crate_name = "x"]
+pub mod now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their {
+ pub struct Country;
+}
+pub mod nowisthetimeforallgoodmentocometotheaidoftheir {
+ pub struct Country;
+}