about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-05-15 05:39:35 +0000
committerbors <bors@rust-lang.org>2018-05-15 05:39:35 +0000
commitd5ecf70fd6b66be5205ebbef1c00c7366a78b751 (patch)
tree5647d13d6e860f75054778fbd2aa6f5b3881d96f
parentd711dc9d57b7992d1d946ba1a7e10ee6693293c2 (diff)
parentf0db2cf14e8b58eb04d40e8aebea0a7a987097eb (diff)
downloadrust-d5ecf70fd6b66be5205ebbef1c00c7366a78b751.tar.gz
rust-d5ecf70fd6b66be5205ebbef1c00c7366a78b751.zip
Auto merge of #50259 - GuillaumeGomez:improve-results, r=ollie27
Rustdoc improvements

Fixes #50658. (last commit)

A lot of small improvements.

r? @QuietMisdreavus
-rw-r--r--src/librustdoc/html/render.rs38
-rw-r--r--src/librustdoc/html/static/main.js156
-rw-r--r--src/librustdoc/html/static/themes/dark.css9
-rw-r--r--src/librustdoc/html/static/themes/light.css7
-rw-r--r--src/test/rustdoc-js/deduplication.js21
-rw-r--r--src/tools/rustdoc-js/tester.js5
6 files changed, 161 insertions, 75 deletions
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index fe9fc3ddd68..32cfb05bbe4 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 8569abeb09c..9224bd1c508 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 '<span>' + path.replace(/::/g, '::</span><span>');
-        }
-
         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 = '<span>' + path.replace(/::/g, '::</span><span>');
+            if (tmp.endsWith("<span>")) {
+                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 = '<table class="search-results"' + extraStyle + '>';
-                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 += '<tr class="' + type + ' result"><td>' +
-                              '<a href="' + href + '">' +
-                              pathSplitter(displayPath) + '<span class="' + type + '">' +
+                              '<a href="' + item.href + '">' +
+                              (item.is_alias === true ?
+                               ('<span class="alias"><b>' + item.alias + ' </b></span><span ' +
+                                  'class="grey"><i>&nbsp;- see&nbsp;</i></span>') : '') +
+                              item.displayPath + '<span class="' + type + '">' +
                               name + '</span></a></td><td>' +
-                              '<a href="' + href + '">' +
+                              '<a href="' + item.href + '">' +
                               '<span class="desc">' + escape(item.desc) +
                               '&nbsp;</span></a></td></tr>';
                 });
@@ -1269,7 +1292,7 @@
                     encodeURIComponent('rust ' + query.query) +
                     '">DuckDuckGo</a>?</div>';
             }
-            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 = '<h1>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 = '<h1>Results for ' + escape(query.query) +
                 (query.type ? ' (type: ' + escape(query.type) + ')' : '') + '</h1>' +
                 '<div id="titles">' +
-                makeTabHeader(0, "In Names", results['others'].length) +
-                makeTabHeader(1, "In Parameters", results['in_args'].length) +
-                makeTabHeader(2, "In Return Types", results['returned'].length) +
-                '</div><div id="results">';
-
-            output += addTab(results['others'], query);
-            output += addTab(results['in_args'], query, false);
-            output += addTab(results['returned'], query, false);
-            output += '</div>';
+                makeTabHeader(0, "In Names", ret_others[1]) +
+                makeTabHeader(1, "In Parameters", ret_in_args[1]) +
+                makeTabHeader(2, "In Return Types", ret_returned[1]) +
+                '</div><div id="results">' +
+                ret_others[0] + ret_in_args[0] + ret_returned[0] + '</div>';
 
             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 da4be7db5aa..493a75e2521 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 12af01d2e24..22f4635fb02 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 00000000000..0f29607d5c9
--- /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 <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.
+
+// 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 25f7a2d1294..47667d93cb7 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);