Skip to content

Commit 4210825

Browse files
Rollup merge of #154798 - notriddle:sub-word-path-match, r=GuillaumeGomez
rustdoc-search: match path components on words Since the length of a path is treated as sorting criteria, and every path that contains the query without exactly matching it must be longer, exact matches will always sort first if they exist. Fixes #154733
2 parents 67898f8 + f1d240c commit 4210825

4 files changed

Lines changed: 128 additions & 22 deletions

File tree

src/librustdoc/html/static/js/search.js

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2799,6 +2799,8 @@ class DocSearch {
27992799
result_list.sort((aaa, bbb) => {
28002800
const aai = aaa.item;
28012801
const bbi = bbb.item;
2802+
const ap = aai.modulePath !== undefined ? aai.modulePath : "";
2803+
const bp = bbi.modulePath !== undefined ? bbi.modulePath : "";
28022804
/** @type {number} */
28032805
let a;
28042806
/** @type {number} */
@@ -2829,14 +2831,25 @@ class DocSearch {
28292831
if (a !== b) {
28302832
return a - b;
28312833
}
2832-
}
28332834

2834-
// Sort by distance in the path part, if specified
2835-
// (less changes required to match means higher rankings)
2836-
a = Number(aaa.path_dist);
2837-
b = Number(bbb.path_dist);
2838-
if (a !== b) {
2839-
return a - b;
2835+
if (parsedQuery.elems[0] &&
2836+
parsedQuery.elems[0].pathWithoutLast.length !== 0
2837+
) {
2838+
// Sort by distance in the path part, if specified
2839+
// (less changes required to match means higher rankings)
2840+
a = Number(aaa.path_dist);
2841+
b = Number(bbb.path_dist);
2842+
if (a !== b) {
2843+
return a - b;
2844+
}
2845+
2846+
// sort by path (longer goes later)
2847+
a = ap.length + (aai.parent ? aai.parent.name.length + 2 : 0);
2848+
b = bp.length + (bbi.parent ? bbi.parent.name.length + 2 : 0);
2849+
if (a !== b) {
2850+
return a - b;
2851+
}
2852+
}
28402853
}
28412854

28422855
// (later literal occurrence, if any, goes later)
@@ -2890,8 +2903,8 @@ class DocSearch {
28902903
}
28912904

28922905
// sort by item name (lexicographically larger goes later)
2893-
let aw = aai.normalizedName;
2894-
let bw = bbi.normalizedName;
2906+
const aw = aai.normalizedName;
2907+
const bw = bbi.normalizedName;
28952908
if (aw !== bw) {
28962909
return (aw > bw ? +1 : -1);
28972910
}
@@ -2914,12 +2927,8 @@ class DocSearch {
29142927
}
29152928

29162929
// sort by path (lexicographically larger goes later)
2917-
const ap = aai.modulePath;
2918-
const bp = bbi.modulePath;
2919-
aw = ap === undefined ? "" : ap;
2920-
bw = bp === undefined ? "" : bp;
2921-
if (aw !== bw) {
2922-
return (aw > bw ? +1 : -1);
2930+
if (ap !== bp) {
2931+
return (ap > bp ? +1 : -1);
29232932
}
29242933

29252934
// que sera, sera
@@ -3848,13 +3857,19 @@ class DocSearch {
38483857
let dist_total = 0;
38493858
for (let x = 0; x < clength; ++x) {
38503859
const [p, c] = [path[i + x], contains[x]];
3860+
const indexOf = p.indexOf(c);
38513861
if (parsedQuery.literalSearch && p !== c) {
38523862
continue pathiter;
3853-
} else if (Math.floor((p.length - c.length) / 3) <= maxPathEditDistance &&
3854-
p.indexOf(c) !== -1
3855-
) {
3863+
} else if (indexOf !== -1) {
38563864
// discount distance on substring match
3857-
dist_total += Math.floor((p.length - c.length) / 3);
3865+
// if component is surrounded by underscores or edges,
3866+
// count the distance as zero
3867+
if (
3868+
(indexOf !== 0 && p[indexOf - 1] !== "_") ||
3869+
(indexOf + c.length !== p.length && p[indexOf + c.length] !== "_")
3870+
) {
3871+
dist_total += Math.floor((p.length - c.length) / 3);
3872+
}
38583873
} else {
38593874
const dist = editDistance(p, c, maxPathEditDistance);
38603875
if (dist > maxPathEditDistance) {

tests/rustdoc-js-std/path-maxeditdistance.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,24 @@ const EXPECTED = [
1010
query: 'vec::iter',
1111
others: [
1212
// std::net::ToSocketAttrs::iter should not show up here
13+
{ 'path': 'std::collections::vec_deque', 'name': 'Iter' },
1314
{ 'path': 'std::collections::VecDeque', 'name': 'iter' },
15+
{ 'path': 'std::collections::vec_deque', 'name': 'IterMut' },
1416
{ 'path': 'std::collections::VecDeque', 'name': 'iter_mut' },
15-
{ 'path': 'std::vec::Vec', 'name': 'from_iter' },
1617
{ 'path': 'std::vec', 'name': 'IntoIter' },
18+
{ 'path': 'std::vec::Vec', 'name': 'from_iter' },
1719
{ 'path': 'std::vec::Vec', 'name': 'into_iter' },
18-
{ 'path': 'std::vec::ExtractIf', 'name': 'into_iter' },
1920
{ 'path': 'std::vec::Drain', 'name': 'into_iter' },
20-
{ 'path': 'std::vec::IntoIter', 'name': 'into_iter' },
2121
{ 'path': 'std::vec::Splice', 'name': 'into_iter' },
22+
{ 'path': 'std::vec::IntoIter', 'name': 'into_iter' },
23+
{ 'path': 'std::vec::ExtractIf', 'name': 'into_iter' },
24+
{ 'path': 'std::collections::vec_deque', 'name': 'IntoIter' },
25+
{ 'path': 'std::collections::vec_deque::Iter', 'name': 'into_iter' },
26+
{ 'path': 'std::collections::vec_deque::Drain', 'name': 'into_iter' },
27+
{ 'path': 'std::collections::vec_deque::Splice', 'name': 'into_iter' },
28+
{ 'path': 'std::collections::vec_deque::IterMut', 'name': 'into_iter' },
29+
{ 'path': 'std::collections::vec_deque::IntoIter', 'name': 'into_iter' },
30+
{ 'path': 'std::collections::vec_deque::ExtractIf', 'name': 'into_iter' },
2231
{ 'path': 'std::collections::VecDeque', 'name': 'from_iter' },
2332
{ 'path': 'std::collections::VecDeque', 'name': 'into_iter' },
2433
],

tests/rustdoc-js/path-substring.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// exact-check
2+
// ignore-tidy-linelength
3+
const EXPECTED = [
4+
// should match (substring)
5+
{
6+
'query': 'struct:now::Country',
7+
'others': [
8+
{ 'path': 'x::now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their', 'name': 'Country' },
9+
],
10+
},
11+
{
12+
'query': 'struct:is::Country',
13+
'others': [
14+
{ 'path': 'x::now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their', 'name': 'Country' },
15+
],
16+
},
17+
{
18+
'query': 'struct:is_the::Country',
19+
'others': [
20+
{ 'path': 'x::now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their', 'name': 'Country' },
21+
],
22+
},
23+
{
24+
'query': 'struct:the::Country',
25+
'others': [
26+
{ 'path': 'x::now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their', 'name': 'Country' },
27+
],
28+
},
29+
{
30+
'query': 'struct:their::Country',
31+
'others': [
32+
{ 'path': 'x::now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their', 'name': 'Country' },
33+
],
34+
},
35+
// should not match
36+
{
37+
'query': 'struct:ood::Country',
38+
'others': [],
39+
},
40+
{
41+
'query': 'struct:goo::Country',
42+
'others': [],
43+
},
44+
{
45+
'query': 'struct:he::Country',
46+
'others': [],
47+
},
48+
{
49+
'query': 'struct:heir::Country',
50+
'others': [],
51+
},
52+
{
53+
'query': 'struct:hei::Country',
54+
'others': [],
55+
},
56+
{
57+
'query': 'struct:no::Country',
58+
'others': [],
59+
},
60+
// should match (edit distance)
61+
{
62+
'query': 'struct:nowisthetimeforallgoodmentocometotheaidoftheir::Country',
63+
'others': [
64+
{ 'path': 'x::nowisthetimeforallgoodmentocometotheaidoftheir', 'name': 'Country' },
65+
{ 'path': 'x::now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their', 'name': 'Country' },
66+
],
67+
},
68+
{
69+
'query': 'struct:now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their::Country',
70+
'others': [
71+
{ 'path': 'x::now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their', 'name': 'Country' },
72+
{ 'path': 'x::nowisthetimeforallgoodmentocometotheaidoftheir', 'name': 'Country' },
73+
],
74+
},
75+
];

tests/rustdoc-js/path-substring.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#![crate_name = "x"]
2+
pub mod now_is_the_time_for_all_good_men_to_come_to_the_aid_of_their {
3+
pub struct Country;
4+
}
5+
pub mod nowisthetimeforallgoodmentocometotheaidoftheir {
6+
pub struct Country;
7+
}

0 commit comments

Comments
 (0)