diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 21de2db1dfe74..7bddeb2f33f75 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -413,9 +413,9 @@ impl ToJson for Type { match self.name { Some(ref name) => { let mut data = BTreeMap::new(); - data.insert("name".to_owned(), name.to_json()); + data.insert("n".to_owned(), name.to_json()); if let Some(ref generics) = self.generics { - data.insert("generics".to_owned(), generics.to_json()); + data.insert("g".to_owned(), generics.to_json()); } Json::Object(data) }, @@ -438,8 +438,12 @@ impl ToJson for IndexItemFunctionType { Json::Null } else { let mut data = BTreeMap::new(); - data.insert("inputs".to_owned(), self.inputs.to_json()); - data.insert("output".to_owned(), self.output.to_json()); + if !self.inputs.is_empty() { + data.insert("i".to_owned(), self.inputs.to_json()); + } + if let Some(ref output) = self.output { + data.insert("o".to_owned(), output.to_json()); + } Json::Object(data) } } @@ -789,7 +793,8 @@ fn write_shared(cx: &Context, format!( r#"var themes = document.getElementById("theme-choices"); var themePicker = document.getElementById("theme-picker"); -themePicker.onclick = function() {{ + +function switchThemeButtonState() {{ if (themes.style.display === "block") {{ themes.style.display = "none"; themePicker.style.borderBottomRightRadius = "3px"; @@ -800,12 +805,29 @@ themePicker.onclick = function() {{ themePicker.style.borderBottomLeftRadius = "0"; }} }}; + +function handleThemeButtonsBlur(e) {{ + var active = document.activeElement; + var related = e.relatedTarget; + + if (active.id !== "themePicker" && + (!active.parentNode || active.parentNode.id !== "theme-choices") && + (!related || + (related.id !== "themePicker" && + (!related.parentNode || related.parentNode.id !== "theme-choices")))) {{ + switchThemeButtonState(); + }} +}} + +themePicker.onclick = switchThemeButtonState; +themePicker.onblur = handleThemeButtonsBlur; [{}].forEach(function(item) {{ var but = document.createElement('button'); but.innerHTML = item; but.onclick = function(el) {{ switchTheme(currentTheme, mainTheme, item); }}; + but.onblur = handleThemeButtonsBlur; themes.appendChild(but); }});"#, themes.iter() @@ -879,8 +901,8 @@ themePicker.onclick = function() {{ } fn show_item(item: &IndexItem, krate: &str) -> String { - format!("{{'crate':'{}','ty':{},'name':'{}','path':'{}'{}}}", - krate, item.ty as usize, item.name, item.path, + format!("{{'crate':'{}','ty':{},'name':'{}','desc':'{}','p':'{}'{}}}", + krate, item.ty as usize, item.name, item.desc.replace("'", "\\'"), item.path, if let Some(p) = item.parent_idx { format!(",'parent':{}", p) } else { @@ -1442,7 +1464,7 @@ impl<'a> Cache { ty: item.type_(), name: item_name.to_string(), path: path.clone(), - desc: String::new(), + desc: plain_summary_line(item.doc_value()), parent: None, parent_idx: None, search_type: get_index_search_type(&item), diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 8569abeb09cc1..9224bd1c50890 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -57,6 +57,12 @@ return this.indexOf(searchString, position) === position; }; } + if (!String.prototype.endsWith) { + String.prototype.endsWith = function(suffix, length) { + var l = length || this.length; + return this.indexOf(suffix, l - suffix.length) !== -1; + }; + } function getPageId() { var id = document.location.href.split('#')[1]; @@ -454,12 +460,16 @@ var obj = searchIndex[results[i].id]; obj.lev = results[i].lev; if (isType !== true || obj.type) { + var res = buildHrefAndPath(obj); + obj.displayPath = pathSplitter(res[0]); + obj.fullPath = obj.displayPath + obj.name; + obj.href = res[1]; out.push(obj); + if (out.length >= MAX_RESULTS) { + break; + } } } - if (out.length >= MAX_RESULTS) { - break; - } } return out; } @@ -587,8 +597,8 @@ // match as well. var lev_distance = MAX_LEV_DISTANCE + 1; if (val.generics.length > 0) { - if (obj.generics && obj.generics.length >= val.generics.length) { - var elems = obj.generics.slice(0); + if (obj.g && obj.g.length >= val.generics.length) { + var elems = obj.g.slice(0); var total = 0; var done = 0; // We need to find the type that matches the most to remove it in order @@ -620,11 +630,11 @@ // Check for type name and type generics (if any). function checkType(obj, val, literalSearch) { var lev_distance = MAX_LEV_DISTANCE + 1; - if (obj.name === val.name) { + if (obj.n === val.name) { if (literalSearch === true) { if (val.generics && val.generics.length !== 0) { - if (obj.generics && obj.length >= val.generics.length) { - var elems = obj.generics.slice(0); + if (obj.g && obj.length >= val.generics.length) { + var elems = obj.g.slice(0); var allFound = true; var x; @@ -648,7 +658,7 @@ } // If the type has generics but don't match, then it won't return at this point. // Otherwise, `checkGenerics` will return 0 and it'll return. - if (obj.generics && obj.generics.length !== 0) { + if (obj.g && obj.g.length !== 0) { var tmp_lev = checkGenerics(obj, val); if (tmp_lev <= MAX_LEV_DISTANCE) { return tmp_lev; @@ -659,22 +669,22 @@ } // Names didn't match so let's check if one of the generic types could. if (literalSearch === true) { - if (obj.generics && obj.generics.length > 0) { - for (var x = 0; x < obj.generics.length; ++x) { - if (obj.generics[x] === val.name) { + if (obj.g && obj.g.length > 0) { + for (var x = 0; x < obj.g.length; ++x) { + if (obj.g[x] === val.name) { return true; } } } return false; } - var lev_distance = Math.min(levenshtein(obj.name, val.name), lev_distance); + var lev_distance = Math.min(levenshtein(obj.n, val.name), lev_distance); if (lev_distance <= MAX_LEV_DISTANCE) { lev_distance = Math.min(checkGenerics(obj, val), lev_distance); - } else if (obj.generics && obj.generics.length > 0) { + } else if (obj.g && obj.g.length > 0) { // We can check if the type we're looking for is inside the generics! - for (var x = 0; x < obj.generics.length; ++x) { - lev_distance = Math.min(levenshtein(obj.generics[x], val.name), + for (var x = 0; x < obj.g.length; ++x) { + lev_distance = Math.min(levenshtein(obj.g[x], val.name), lev_distance); } } @@ -686,9 +696,9 @@ function findArg(obj, val, literalSearch) { var lev_distance = MAX_LEV_DISTANCE + 1; - if (obj && obj.type && obj.type.inputs.length > 0) { - for (var i = 0; i < obj.type.inputs.length; i++) { - var tmp = checkType(obj.type.inputs[i], val, literalSearch); + if (obj && obj.type && obj.type.i && obj.type.i.length > 0) { + for (var i = 0; i < obj.type.i.length; i++) { + var tmp = checkType(obj.type.i[i], val, literalSearch); if (literalSearch === true && tmp === true) { return true; } @@ -704,8 +714,8 @@ function checkReturned(obj, val, literalSearch) { var lev_distance = MAX_LEV_DISTANCE + 1; - if (obj && obj.type && obj.type.output) { - var tmp = checkType(obj.type.output, val, literalSearch); + if (obj && obj.type && obj.type.o) { + var tmp = checkType(obj.type.o, val, literalSearch); if (literalSearch === true && tmp === true) { return true; } @@ -850,7 +860,7 @@ var fullId = generateId(ty); // allow searching for void (no output) functions as well - var typeOutput = type.output ? type.output.name : ""; + var typeOutput = type.o ? type.o.name : ""; var returned = checkReturned(ty, output, true); if (output.name === "*" || returned === true) { var in_args = false; @@ -1017,6 +1027,13 @@ ALIASES[window.currentCrate][query.raw]) { var aliases = ALIASES[window.currentCrate][query.raw]; for (var i = 0; i < aliases.length; ++i) { + aliases[i].is_alias = true; + aliases[i].alias = query.raw; + aliases[i].path = aliases[i].p; + var res = buildHrefAndPath(aliases[i]); + aliases[i].displayPath = pathSplitter(res[0]); + aliases[i].fullPath = aliases[i].displayPath + aliases[i].name; + aliases[i].href = res[1]; ret['others'].unshift(aliases[i]); if (ret['others'].length > MAX_RESULTS) { ret['others'].pop(); @@ -1179,16 +1196,6 @@ }; } - function escape(content) { - var h1 = document.createElement('h1'); - h1.textContent = content; - return h1.innerHTML; - } - - function pathSplitter(path) { - return '' + path.replace(/::/g, '::'); - } - function buildHrefAndPath(item) { var displayPath; var href; @@ -1227,6 +1234,20 @@ return [displayPath, href]; } + function escape(content) { + var h1 = document.createElement('h1'); + h1.textContent = content; + return h1.innerHTML; + } + + function pathSplitter(path) { + var tmp = '' + path.replace(/::/g, '::'); + if (tmp.endsWith("")) { + return tmp.slice(0, tmp.length - 6); + } + return tmp; + } + function addTab(array, query, display) { var extraStyle = ''; if (display === false) { @@ -1234,31 +1255,33 @@ } var output = ''; + var duplicates = {}; + var length = 0; if (array.length > 0) { output = ''; - var shown = []; array.forEach(function(item) { - var name, type, href, displayPath; - - var id_ty = item.ty + item.path + item.name; - if (shown.indexOf(id_ty) !== -1) { - return; - } + var name, type; - shown.push(id_ty); name = item.name; type = itemTypes[item.ty]; - var res = buildHrefAndPath(item); - var href = res[1]; - var displayPath = res[0]; + if (item.is_alias !== true) { + if (duplicates[item.fullPath]) { + return; + } + duplicates[item.fullPath] = true; + } + length += 1; output += ''; }); @@ -1269,7 +1292,7 @@ encodeURIComponent('rust ' + query.query) + '">DuckDuckGo?'; } - return output; + return [output, length]; } function makeTabHeader(tabNb, text, nbElems) { @@ -1284,28 +1307,28 @@ if (results['others'].length === 1 && getCurrentValue('rustdoc-go-to-only-result') === "true") { var elem = document.createElement('a'); - var res = buildHrefAndPath(results['others'][0]); - elem.href = res[1]; + elem.href = results['others'][0].href; elem.style.display = 'none'; // For firefox, we need the element to be in the DOM so it can be clicked. document.body.appendChild(elem); elem.click(); } - var output, query = getQuery(search_input.value); + var query = getQuery(search_input.value); currentResults = query.id; - output = '

Results for ' + escape(query.query) + + + var ret_others = addTab(results['others'], query); + var ret_in_args = addTab(results['in_args'], query, false); + var ret_returned = addTab(results['returned'], query, false); + + var output = '

Results for ' + escape(query.query) + (query.type ? ' (type: ' + escape(query.type) + ')' : '') + '

' + '
' + - makeTabHeader(0, "In Names", results['others'].length) + - makeTabHeader(1, "In Parameters", results['in_args'].length) + - makeTabHeader(2, "In Return Types", results['returned'].length) + - '
'; - - output += addTab(results['others'], query); - output += addTab(results['in_args'], query, false); - output += addTab(results['returned'], query, false); - output += '
'; + makeTabHeader(0, "In Names", ret_others[1]) + + makeTabHeader(1, "In Parameters", ret_in_args[1]) + + makeTabHeader(2, "In Return Types", ret_returned[1]) + + '
' + + ret_others[0] + ret_in_args[0] + ret_returned[0] + '
'; addClass(document.getElementById('main'), 'hidden'); var search = document.getElementById('search'); @@ -1347,12 +1370,13 @@ } } if (queries.length > 1) { - function getSmallest(arrays, positions) { + function getSmallest(arrays, positions, notDuplicates) { var start = null; for (var it = 0; it < positions.length; ++it) { if (arrays[it].length > positions[it] && - (start === null || start > arrays[it][positions[it]].lev)) { + (start === null || start > arrays[it][positions[it]].lev) && + !notDuplicates[arrays[it][positions[it]].fullPath]) { start = arrays[it][positions[it]].lev; } } @@ -1362,19 +1386,23 @@ function mergeArrays(arrays) { var ret = []; var positions = []; + var notDuplicates = {}; for (var x = 0; x < arrays.length; ++x) { positions.push(0); } while (ret.length < MAX_RESULTS) { - var smallest = getSmallest(arrays, positions); + var smallest = getSmallest(arrays, positions, notDuplicates); + if (smallest === null) { break; } for (x = 0; x < arrays.length && ret.length < MAX_RESULTS; ++x) { if (arrays[x].length > positions[x] && - arrays[x][positions[x]].lev === smallest) { + arrays[x][positions[x]].lev === smallest && + !notDuplicates[arrays[x][positions[x]].fullPath]) { ret.push(arrays[x][positions[x]]); + notDuplicates[arrays[x][positions[x]].fullPath] = true; positions[x] += 1; } } diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index da4be7db5aa92..493a75e25211d 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -382,7 +382,7 @@ kbd { } #theme-choices > button:hover, #theme-choices > button:focus { - background-color: #444; + background-color: #4e4e4e; } @media (max-width: 700px) { @@ -397,3 +397,10 @@ kbd { #all-types:hover { background-color: #606060; } + +.search-results td span.alias { + color: #fff; +} +.search-results td span.grey { + color: #ccc; +} \ No newline at end of file diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 12af01d2e2498..22f4635fb02e1 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -390,4 +390,11 @@ kbd { } #all-types:hover { background-color: #f9f9f9; +} + +.search-results td span.alias { + color: #000; +} +.search-results td span.grey { + color: #999; } \ No newline at end of file diff --git a/src/test/rustdoc-js/deduplication.js b/src/test/rustdoc-js/deduplication.js new file mode 100644 index 0000000000000..0f29607d5c993 --- /dev/null +++ b/src/test/rustdoc-js/deduplication.js @@ -0,0 +1,21 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-order + +const QUERY = 'is_nan'; + +const EXPECTED = { + 'others': [ + { 'path': 'std::f32', 'name': 'is_nan' }, + { 'path': 'std::f64', 'name': 'is_nan' }, + { 'path': 'std::option::Option', 'name': 'is_none' }, + ], +}; diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index 25f7a2d1294c5..47667d93cb7f1 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -160,10 +160,11 @@ function main(argv) { // execQuery first parameter is built in getQuery (which takes in the search input). // execQuery last parameter is built in buildIndex. // buildIndex requires the hashmap from search-index. - var functionsToLoad = ["levenshtein", "validateResult", "getQuery", "buildIndex", "execQuery", - "execSearch"]; + var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult", + "getQuery", "buildIndex", "execQuery", "execSearch"]; finalJS += 'window = { "currentCrate": "std" };\n'; + finalJS += 'var rootPath = "../";\n'; finalJS += ALIASES; finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs); finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs);
' + - '' + - pathSplitter(displayPath) + '' + + '' + + (item.is_alias === true ? + ('' + item.alias + '  - see ') : '') + + item.displayPath + '' + name + '' + - '' + + '' + '' + escape(item.desc) + '