Rollup merge of #56332 - GuillaumeGomez:specifi-crate-search, r=QuietMisdreavus
[rustdoc] Specific crate search Reopening of #54706. Fixes #54616. <img width="1440" alt="screenshot 2018-11-29 at 01 29 11" src="https://user-images.githubusercontent.com/3050060/49191372-979adf80-f376-11e8-963e-e4feb927c1da.png"> r? @QuietMisdreavus
This commit is contained in:
commit
a88feabac4
10 changed files with 164 additions and 26 deletions
|
@ -57,6 +57,9 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
|
|||
{css_extension}\
|
||||
{favicon}\
|
||||
{in_header}\
|
||||
<style type=\"text/css\">\
|
||||
#crate-search{{background-image:url(\"{root_path}down-arrow{suffix}.svg\");}}\
|
||||
</style>\
|
||||
</head>\
|
||||
<body class=\"rustdoc {css_class}\">\
|
||||
<!--[if lte IE 8]>\
|
||||
|
@ -81,11 +84,16 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
|
|||
<nav class=\"sub\">\
|
||||
<form class=\"search-form js-only\">\
|
||||
<div class=\"search-container\">\
|
||||
<input class=\"search-input\" name=\"search\" \
|
||||
autocomplete=\"off\" \
|
||||
spellcheck=\"false\" \
|
||||
placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
|
||||
type=\"search\">\
|
||||
<div>\
|
||||
<select id=\"crate-search\">\
|
||||
<option value=\"All crates\">All crates</option>\
|
||||
</select>\
|
||||
<input class=\"search-input\" name=\"search\" \
|
||||
autocomplete=\"off\" \
|
||||
spellcheck=\"false\" \
|
||||
placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
|
||||
type=\"search\">\
|
||||
</div>\
|
||||
<a id=\"settings-menu\" href=\"{root_path}settings.html\">\
|
||||
<img src=\"{root_path}wheel{suffix}.svg\" width=\"18\" alt=\"Change settings\">\
|
||||
</a>\
|
||||
|
|
|
@ -793,6 +793,8 @@ fn write_shared(
|
|||
static_files::BRUSH_SVG)?;
|
||||
write(cx.dst.join(&format!("wheel{}.svg", cx.shared.resource_suffix)),
|
||||
static_files::WHEEL_SVG)?;
|
||||
write(cx.dst.join(&format!("down-arrow{}.svg", cx.shared.resource_suffix)),
|
||||
static_files::DOWN_ARROW_SVG)?;
|
||||
write_minify(cx.dst.join(&format!("light{}.css", cx.shared.resource_suffix)),
|
||||
static_files::themes::LIGHT,
|
||||
options.enable_minification)?;
|
||||
|
@ -1066,7 +1068,7 @@ themePicker.onblur = handleThemeButtonsBlur;
|
|||
&[(minifier::js::Keyword::Null, "N")]),
|
||||
&dst);
|
||||
}
|
||||
try_err!(writeln!(&mut w, "initSearch(searchIndex);"), &dst);
|
||||
try_err!(writeln!(&mut w, "initSearch(searchIndex);addSearchOptions(searchIndex);"), &dst);
|
||||
|
||||
if options.enable_index_page {
|
||||
if let Some(index_page) = options.index_page.clone() {
|
||||
|
|
1
src/librustdoc/html/static/down-arrow.svg
Normal file
1
src/librustdoc/html/static/down-arrow.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg height="128px" id="Layer_1" style="enable-background:new 0 0 128 128;" version="1.1" viewBox="0 0 128 128" width="128px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g><line style="fill:none;stroke:#2F3435;stroke-width:12;stroke-linecap:square;stroke-miterlimit:10;" x1="111" x2="64" y1="40.5" y2="87.499"/><line style="fill:none;stroke:#2F3435;stroke-width:12;stroke-linecap:square;stroke-miterlimit:10;" x1="64" x2="17" y1="87.499" y2="40.5"/></g></svg>
|
After Width: | Height: | Size: 637 B |
|
@ -218,12 +218,14 @@ if (!String.prototype.endsWith) {
|
|||
//
|
||||
// So I guess you could say things are getting pretty interoperable.
|
||||
function getVirtualKey(ev) {
|
||||
if ("key" in ev && typeof ev.key != "undefined")
|
||||
if ("key" in ev && typeof ev.key != "undefined") {
|
||||
return ev.key;
|
||||
}
|
||||
|
||||
var c = ev.charCode || ev.keyCode;
|
||||
if (c == 27)
|
||||
if (c == 27) {
|
||||
return "Escape";
|
||||
}
|
||||
return String.fromCharCode(c);
|
||||
}
|
||||
|
||||
|
@ -431,12 +433,13 @@ if (!String.prototype.endsWith) {
|
|||
|
||||
/**
|
||||
* Executes the query and builds an index of results
|
||||
* @param {[Object]} query [The user query]
|
||||
* @param {[type]} searchWords [The list of search words to query
|
||||
* against]
|
||||
* @return {[type]} [A search index of results]
|
||||
* @param {[Object]} query [The user query]
|
||||
* @param {[type]} searchWords [The list of search words to query
|
||||
* against]
|
||||
* @param {[type]} filterCrates [Crate to search in if defined]
|
||||
* @return {[type]} [A search index of results]
|
||||
*/
|
||||
function execQuery(query, searchWords) {
|
||||
function execQuery(query, searchWords, filterCrates) {
|
||||
function itemTypeFromName(typename) {
|
||||
for (var i = 0; i < itemTypes.length; ++i) {
|
||||
if (itemTypes[i] === typename) {
|
||||
|
@ -812,6 +815,9 @@ if (!String.prototype.endsWith) {
|
|||
{
|
||||
val = extractGenerics(val.substr(1, val.length - 2));
|
||||
for (var i = 0; i < nSearchWords; ++i) {
|
||||
if (filterCrates !== undefined && searchIndex[i].crate !== filterCrates) {
|
||||
continue;
|
||||
}
|
||||
var in_args = findArg(searchIndex[i], val, true);
|
||||
var returned = checkReturned(searchIndex[i], val, true);
|
||||
var ty = searchIndex[i];
|
||||
|
@ -866,6 +872,9 @@ if (!String.prototype.endsWith) {
|
|||
var output = extractGenerics(parts[1]);
|
||||
|
||||
for (var i = 0; i < nSearchWords; ++i) {
|
||||
if (filterCrates !== undefined && searchIndex[i].crate !== filterCrates) {
|
||||
continue;
|
||||
}
|
||||
var type = searchIndex[i].type;
|
||||
var ty = searchIndex[i];
|
||||
if (!type) {
|
||||
|
@ -937,11 +946,11 @@ if (!String.prototype.endsWith) {
|
|||
var contains = paths.slice(0, paths.length > 1 ? paths.length - 1 : 1);
|
||||
|
||||
for (j = 0; j < nSearchWords; ++j) {
|
||||
var lev_distance;
|
||||
var ty = searchIndex[j];
|
||||
if (!ty) {
|
||||
if (!ty || (filterCrates !== undefined && ty.crate !== filterCrates)) {
|
||||
continue;
|
||||
}
|
||||
var lev_distance;
|
||||
var lev_add = 0;
|
||||
if (paths.length > 1) {
|
||||
var lev = checkPath(contains, paths[paths.length - 1], ty);
|
||||
|
@ -1326,7 +1335,7 @@ if (!String.prototype.endsWith) {
|
|||
return '<div>' + text + ' <div class="count">(' + nbElems + ')</div></div>';
|
||||
}
|
||||
|
||||
function showResults(results) {
|
||||
function showResults(results, filterCrates) {
|
||||
if (results['others'].length === 1 &&
|
||||
getCurrentValue('rustdoc-go-to-only-result') === "true") {
|
||||
var elem = document.createElement('a');
|
||||
|
@ -1344,8 +1353,13 @@ if (!String.prototype.endsWith) {
|
|||
var ret_in_args = addTab(results['in_args'], query, false);
|
||||
var ret_returned = addTab(results['returned'], query, false);
|
||||
|
||||
var filter = "";
|
||||
if (filterCrates !== undefined) {
|
||||
filter = " (in <b>" + filterCrates + "</b> crate)";
|
||||
}
|
||||
|
||||
var output = '<h1>Results for ' + escape(query.query) +
|
||||
(query.type ? ' (type: ' + escape(query.type) + ')' : '') + '</h1>' +
|
||||
(query.type ? ' (type: ' + escape(query.type) + ')' : '') + filter + '</h1>' +
|
||||
'<div id="titles">' +
|
||||
makeTabHeader(0, "In Names", ret_others[1]) +
|
||||
makeTabHeader(1, "In Parameters", ret_in_args[1]) +
|
||||
|
@ -1374,7 +1388,7 @@ if (!String.prototype.endsWith) {
|
|||
printTab(currentTab);
|
||||
}
|
||||
|
||||
function execSearch(query, searchWords) {
|
||||
function execSearch(query, searchWords, filterCrates) {
|
||||
var queries = query.raw.split(",");
|
||||
var results = {
|
||||
'in_args': [],
|
||||
|
@ -1385,7 +1399,7 @@ if (!String.prototype.endsWith) {
|
|||
for (var i = 0; i < queries.length; ++i) {
|
||||
var query = queries[i].trim();
|
||||
if (query.length !== 0) {
|
||||
var tmp = execQuery(getQuery(query), searchWords);
|
||||
var tmp = execQuery(getQuery(query), searchWords, filterCrates);
|
||||
|
||||
results['in_args'].push(tmp['in_args']);
|
||||
results['returned'].push(tmp['returned']);
|
||||
|
@ -1447,7 +1461,16 @@ if (!String.prototype.endsWith) {
|
|||
}
|
||||
}
|
||||
|
||||
function search(e) {
|
||||
function getFilterCrates() {
|
||||
var elem = document.getElementById("crate-search");
|
||||
|
||||
if (elem && elem.value !== "All crates" && rawSearchIndex.hasOwnProperty(elem.value)) {
|
||||
return elem.value;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function search(e, forced) {
|
||||
var params = getQueryStringParams();
|
||||
var query = getQuery(search_input.value.trim());
|
||||
|
||||
|
@ -1455,7 +1478,10 @@ if (!String.prototype.endsWith) {
|
|||
e.preventDefault();
|
||||
}
|
||||
|
||||
if (query.query.length === 0 || query.id === currentResults) {
|
||||
if (query.query.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (forced !== true && query.id === currentResults) {
|
||||
if (query.query.length > 0) {
|
||||
putBackSearch(search_input);
|
||||
}
|
||||
|
@ -1475,7 +1501,8 @@ if (!String.prototype.endsWith) {
|
|||
}
|
||||
}
|
||||
|
||||
showResults(execSearch(query, index));
|
||||
var filterCrates = getFilterCrates();
|
||||
showResults(execSearch(query, index, filterCrates), filterCrates);
|
||||
}
|
||||
|
||||
function buildIndex(rawSearchIndex) {
|
||||
|
@ -1575,6 +1602,13 @@ if (!String.prototype.endsWith) {
|
|||
};
|
||||
search_input.onpaste = search_input.onchange;
|
||||
|
||||
var selectCrate = document.getElementById('crate-search');
|
||||
if (selectCrate) {
|
||||
selectCrate.onchange = function() {
|
||||
search(undefined, true);
|
||||
};
|
||||
}
|
||||
|
||||
// Push and pop states are used to add search results to the browser
|
||||
// history.
|
||||
if (browserSupportsHistoryApi()) {
|
||||
|
@ -2323,6 +2357,39 @@ if (!String.prototype.endsWith) {
|
|||
if (window.location.hash && window.location.hash.length > 0) {
|
||||
expandSection(window.location.hash.replace(/^#/, ''));
|
||||
}
|
||||
|
||||
function addSearchOptions(crates) {
|
||||
var elem = document.getElementById('crate-search');
|
||||
|
||||
if (!elem) {
|
||||
return;
|
||||
}
|
||||
var crates_text = [];
|
||||
for (var crate in crates) {
|
||||
if (crates.hasOwnProperty(crate)) {
|
||||
crates_text.push(crate);
|
||||
}
|
||||
}
|
||||
crates_text.sort(function(a, b) {
|
||||
var lower_a = a.toLowerCase();
|
||||
var lower_b = b.toLowerCase();
|
||||
|
||||
if (lower_a < lower_b) {
|
||||
return -1;
|
||||
} else if (lower_a > lower_b) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
for (var i = 0; i < crates_text.length; ++i) {
|
||||
var option = document.createElement("option");
|
||||
option.value = crates_text[i];
|
||||
option.innerText = crates_text[i];
|
||||
elem.appendChild(option);
|
||||
}
|
||||
}
|
||||
|
||||
window.addSearchOptions = addSearchOptions;
|
||||
}());
|
||||
|
||||
// Sets the focus on the search bar at the top of the page
|
||||
|
|
|
@ -620,13 +620,36 @@ a {
|
|||
.search-container {
|
||||
position: relative;
|
||||
}
|
||||
.search-container > div {
|
||||
display: inline-flex;
|
||||
width: calc(100% - 34px);
|
||||
}
|
||||
#crate-search {
|
||||
margin-top: 5px;
|
||||
padding: 6px;
|
||||
padding-right: 19px;
|
||||
border: 0;
|
||||
border-right: 0;
|
||||
border-radius: 4px 0 0 4px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
border-right: 1px solid;
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
/* Removes default arrow from firefox */
|
||||
text-indent: 0.01px;
|
||||
text-overflow: "";
|
||||
background-repeat: no-repeat;
|
||||
background-color: transparent;
|
||||
background-size: 16%;
|
||||
background-position: calc(100% - 1px) 56%;
|
||||
}
|
||||
.search-container > .top-button {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 10px;
|
||||
}
|
||||
.search-input {
|
||||
width: calc(100% - 34px);
|
||||
/* Override Normalize.css: we have margins and do
|
||||
not want to overflow - the `moz` attribute is necessary
|
||||
until Firefox 29, too early to drop at this point */
|
||||
|
@ -634,13 +657,14 @@ a {
|
|||
box-sizing: border-box !important;
|
||||
outline: none;
|
||||
border: none;
|
||||
border-radius: 1px;
|
||||
border-radius: 0 1px 1px 0;
|
||||
margin-top: 5px;
|
||||
padding: 10px 16px;
|
||||
font-size: 17px;
|
||||
transition: border-color 300ms ease;
|
||||
transition: border-radius 300ms ease-in-out;
|
||||
transition: box-shadow 300ms ease-in-out;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-input:focus {
|
||||
|
|
|
@ -182,9 +182,15 @@ a.test-arrow {
|
|||
color: #999;
|
||||
}
|
||||
|
||||
#crate-search {
|
||||
color: #111;
|
||||
background-color: #f0f0f0;
|
||||
border-color: #000;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
color: #111;
|
||||
box-shadow: 0 0 0 1px #000, 0 0 0 2px transparent;
|
||||
box-shadow: 1px 0 0 1px #000, 0 0 0 2px transparent;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
|
|
|
@ -182,9 +182,16 @@ a.test-arrow {
|
|||
color: #999;
|
||||
}
|
||||
|
||||
#crate-search {
|
||||
color: #555;
|
||||
background-color: white;
|
||||
border-color: #e0e0e0;
|
||||
box-shadow: 0px 0 0 1px #e0e0e0, 0 0 0 2px transparent;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
color: #555;
|
||||
box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent;
|
||||
box-shadow: 1px 0 0 1px #e0e0e0, 0 0 0 2px transparent;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,9 @@ pub static BRUSH_SVG: &'static [u8] = include_bytes!("static/brush.svg");
|
|||
/// The file contents of `wheel.svg`, the icon used for the settings button.
|
||||
pub static WHEEL_SVG: &'static [u8] = include_bytes!("static/wheel.svg");
|
||||
|
||||
/// The file contents of `down-arrow.svg`, the icon used for the crate choice combobox.
|
||||
pub static DOWN_ARROW_SVG: &'static [u8] = include_bytes!("static/down-arrow.svg");
|
||||
|
||||
/// The contents of `COPYRIGHT.txt`, the license listing for files distributed with documentation
|
||||
/// output.
|
||||
pub static COPYRIGHT: &'static [u8] = include_bytes!("static/COPYRIGHT.txt");
|
||||
|
|
19
src/test/rustdoc-js/filter-crate.js
Normal file
19
src/test/rustdoc-js/filter-crate.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// exact-check
|
||||
|
||||
const QUERY = 'hashmap';
|
||||
const FILTER_CRATE = 'core';
|
||||
|
||||
const EXPECTED = {
|
||||
'others': [
|
||||
],
|
||||
};
|
|
@ -259,6 +259,7 @@ function main(argv) {
|
|||
'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;');
|
||||
const expected = loadedFile.EXPECTED;
|
||||
const query = loadedFile.QUERY;
|
||||
const filter_crate = loadedFile.FILTER_CRATE;
|
||||
const ignore_order = loadedFile.ignore_order;
|
||||
const exact_check = loadedFile.exact_check;
|
||||
const should_fail = loadedFile.should_fail;
|
||||
|
|
Loading…
Reference in a new issue