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; +}