]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/static/main.js
Rollup merge of #80901 - jyn514:better-colors, r=Mark-Simulacrum
[rust.git] / src / librustdoc / html / static / main.js
1 // From rust:
2 /* global ALIASES, currentCrate, rootPath */
3
4 // Local js definitions:
5 /* global addClass, getCurrentValue, hasClass */
6 /* global onEachLazy, hasOwnProperty, removeClass, updateLocalStorage */
7 /* global hideThemeButtonState, showThemeButtonState */
8
9 if (!String.prototype.startsWith) {
10     String.prototype.startsWith = function(searchString, position) {
11         position = position || 0;
12         return this.indexOf(searchString, position) === position;
13     };
14 }
15 if (!String.prototype.endsWith) {
16     String.prototype.endsWith = function(suffix, length) {
17         var l = length || this.length;
18         return this.indexOf(suffix, l - suffix.length) !== -1;
19     };
20 }
21
22 if (!DOMTokenList.prototype.add) {
23     DOMTokenList.prototype.add = function(className) {
24         if (className && !hasClass(this, className)) {
25             if (this.className && this.className.length > 0) {
26                 this.className += " " + className;
27             } else {
28                 this.className = className;
29             }
30         }
31     };
32 }
33
34 if (!DOMTokenList.prototype.remove) {
35     DOMTokenList.prototype.remove = function(className) {
36         if (className && this.className) {
37             this.className = (" " + this.className + " ").replace(" " + className + " ", " ")
38                                                          .trim();
39         }
40     };
41 }
42
43
44 // Gets the human-readable string for the virtual-key code of the
45 // given KeyboardEvent, ev.
46 //
47 // This function is meant as a polyfill for KeyboardEvent#key,
48 // since it is not supported in IE 11 or Chrome for Android. We also test for
49 // KeyboardEvent#keyCode because the handleShortcut handler is
50 // also registered for the keydown event, because Blink doesn't fire
51 // keypress on hitting the Escape key.
52 //
53 // So I guess you could say things are getting pretty interoperable.
54 function getVirtualKey(ev) {
55     if ("key" in ev && typeof ev.key != "undefined") {
56         return ev.key;
57     }
58
59     var c = ev.charCode || ev.keyCode;
60     if (c == 27) {
61         return "Escape";
62     }
63     return String.fromCharCode(c);
64 }
65
66 function getSearchInput() {
67     return document.getElementsByClassName("search-input")[0];
68 }
69
70 function getSearchElement() {
71     return document.getElementById("search");
72 }
73
74 function getThemesElement() {
75     return document.getElementById("theme-choices");
76 }
77
78 function getThemePickerElement() {
79     return document.getElementById("theme-picker");
80 }
81
82 // Sets the focus on the search bar at the top of the page
83 function focusSearchBar() {
84     getSearchInput().focus();
85 }
86
87 // Removes the focus from the search bar
88 function defocusSearchBar() {
89     getSearchInput().blur();
90 }
91
92 (function() {
93     "use strict";
94
95     // This mapping table should match the discriminants of
96     // `rustdoc::html::item_type::ItemType` type in Rust.
97     var itemTypes = ["mod",
98                      "externcrate",
99                      "import",
100                      "struct",
101                      "enum",
102                      "fn",
103                      "type",
104                      "static",
105                      "trait",
106                      "impl",
107                      "tymethod",
108                      "method",
109                      "structfield",
110                      "variant",
111                      "macro",
112                      "primitive",
113                      "associatedtype",
114                      "constant",
115                      "associatedconstant",
116                      "union",
117                      "foreigntype",
118                      "keyword",
119                      "existential",
120                      "attr",
121                      "derive",
122                      "traitalias"];
123
124     var disableShortcuts = getSettingValue("disable-shortcuts") === "true";
125     var search_input = getSearchInput();
126     var searchTimeout = null;
127     var toggleAllDocsId = "toggle-all-docs";
128
129     // On the search screen, so you remain on the last tab you opened.
130     //
131     // 0 for "In Names"
132     // 1 for "In Parameters"
133     // 2 for "In Return Types"
134     var currentTab = 0;
135
136     var mouseMovedAfterSearch = true;
137
138     var titleBeforeSearch = document.title;
139     var searchTitle = null;
140
141     function clearInputTimeout() {
142         if (searchTimeout !== null) {
143             clearTimeout(searchTimeout);
144             searchTimeout = null;
145         }
146     }
147
148     function getPageId() {
149         if (window.location.hash) {
150             var tmp = window.location.hash.replace(/^#/, "");
151             if (tmp.length > 0) {
152                 return tmp;
153             }
154         }
155         return null;
156     }
157
158     function showSidebar() {
159         var elems = document.getElementsByClassName("sidebar-elems")[0];
160         if (elems) {
161             addClass(elems, "show-it");
162         }
163         var sidebar = document.getElementsByClassName("sidebar")[0];
164         if (sidebar) {
165             addClass(sidebar, "mobile");
166             var filler = document.getElementById("sidebar-filler");
167             if (!filler) {
168                 var div = document.createElement("div");
169                 div.id = "sidebar-filler";
170                 sidebar.appendChild(div);
171             }
172         }
173     }
174
175     function hideSidebar() {
176         var elems = document.getElementsByClassName("sidebar-elems")[0];
177         if (elems) {
178             removeClass(elems, "show-it");
179         }
180         var sidebar = document.getElementsByClassName("sidebar")[0];
181         removeClass(sidebar, "mobile");
182         var filler = document.getElementById("sidebar-filler");
183         if (filler) {
184             filler.remove();
185         }
186         document.getElementsByTagName("body")[0].style.marginTop = "";
187     }
188
189     function showSearchResults(search) {
190         if (search === null || typeof search === 'undefined') {
191             search = getSearchElement();
192         }
193         addClass(main, "hidden");
194         removeClass(search, "hidden");
195         mouseMovedAfterSearch = false;
196         document.title = searchTitle;
197     }
198
199     function hideSearchResults(search) {
200         if (search === null || typeof search === 'undefined') {
201             search = getSearchElement();
202         }
203         addClass(search, "hidden");
204         removeClass(main, "hidden");
205         document.title = titleBeforeSearch;
206     }
207
208     // used for special search precedence
209     var TY_PRIMITIVE = itemTypes.indexOf("primitive");
210     var TY_KEYWORD = itemTypes.indexOf("keyword");
211
212     function getQueryStringParams() {
213         var params = {};
214         window.location.search.substring(1).split("&").
215             map(function(s) {
216                 var pair = s.split("=");
217                 params[decodeURIComponent(pair[0])] =
218                     typeof pair[1] === "undefined" ? null : decodeURIComponent(pair[1]);
219             });
220         return params;
221     }
222
223     function browserSupportsHistoryApi() {
224         return window.history && typeof window.history.pushState === "function";
225     }
226
227     function isHidden(elem) {
228         return elem.offsetHeight === 0;
229     }
230
231     var main = document.getElementById("main");
232     var savedHash = "";
233
234     function handleHashes(ev) {
235         var elem;
236         var search = getSearchElement();
237         if (ev !== null && search && !hasClass(search, "hidden") && ev.newURL) {
238             // This block occurs when clicking on an element in the navbar while
239             // in a search.
240             hideSearchResults(search);
241             var hash = ev.newURL.slice(ev.newURL.indexOf("#") + 1);
242             if (browserSupportsHistoryApi()) {
243                 history.replaceState(hash, "", "?search=#" + hash);
244             }
245             elem = document.getElementById(hash);
246             if (elem) {
247                 elem.scrollIntoView();
248             }
249         }
250         // This part is used in case an element is not visible.
251         if (savedHash !== window.location.hash) {
252             savedHash = window.location.hash;
253             if (savedHash.length === 0) {
254                 return;
255             }
256             elem = document.getElementById(savedHash.slice(1)); // we remove the '#'
257             if (!elem || !isHidden(elem)) {
258                 return;
259             }
260             var parent = elem.parentNode;
261             if (parent && hasClass(parent, "impl-items")) {
262                 // In case this is a trait implementation item, we first need to toggle
263                 // the "Show hidden undocumented items".
264                 onEachLazy(parent.getElementsByClassName("collapsed"), function(e) {
265                     if (e.parentNode === parent) {
266                         // Only click on the toggle we're looking for.
267                         e.click();
268                         return true;
269                     }
270                 });
271                 if (isHidden(elem)) {
272                     // The whole parent is collapsed. We need to click on its toggle as well!
273                     if (hasClass(parent.lastElementChild, "collapse-toggle")) {
274                         parent.lastElementChild.click();
275                     }
276                 }
277             }
278         }
279     }
280
281     function highlightSourceLines(match, ev) {
282         if (typeof match === "undefined") {
283             // If we're in mobile mode, we should hide the sidebar in any case.
284             hideSidebar();
285             match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/);
286         }
287         if (!match) {
288             return;
289         }
290         var from = parseInt(match[1], 10);
291         var to = from;
292         if (typeof match[2] !== "undefined") {
293             to = parseInt(match[2], 10);
294         }
295         if (to < from) {
296             var tmp = to;
297             to = from;
298             from = tmp;
299         }
300         var elem = document.getElementById(from);
301         if (!elem) {
302             return;
303         }
304         if (!ev) {
305             var x = document.getElementById(from);
306             if (x) {
307                 x.scrollIntoView();
308             }
309         }
310         onEachLazy(document.getElementsByClassName("line-numbers"), function(e) {
311             onEachLazy(e.getElementsByTagName("span"), function(i_e) {
312                 removeClass(i_e, "line-highlighted");
313             });
314         });
315         for (var i = from; i <= to; ++i) {
316             elem = document.getElementById(i);
317             if (!elem) {
318                 break;
319             }
320             addClass(elem, "line-highlighted");
321         }
322     }
323
324     function onHashChange(ev) {
325         // If we're in mobile mode, we should hide the sidebar in any case.
326         hideSidebar();
327         var match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/);
328         if (match) {
329             return highlightSourceLines(match, ev);
330         }
331         handleHashes(ev);
332     }
333
334     function expandSection(id) {
335         var elem = document.getElementById(id);
336         if (elem && isHidden(elem)) {
337             var h3 = elem.parentNode.previousElementSibling;
338             if (h3 && h3.tagName !== "H3") {
339                 h3 = h3.previousElementSibling; // skip div.docblock
340             }
341
342             if (h3) {
343                 var collapses = h3.getElementsByClassName("collapse-toggle");
344                 if (collapses.length > 0) {
345                     // The element is not visible, we need to make it appear!
346                     collapseDocs(collapses[0], "show");
347                 }
348             }
349         }
350     }
351
352     function getHelpElement() {
353         buildHelperPopup();
354         return document.getElementById("help");
355     }
356
357     function displayHelp(display, ev, help) {
358         help = help ? help : getHelpElement();
359         if (display === true) {
360             if (hasClass(help, "hidden")) {
361                 ev.preventDefault();
362                 removeClass(help, "hidden");
363                 addClass(document.body, "blur");
364             }
365         } else if (hasClass(help, "hidden") === false) {
366             ev.preventDefault();
367             addClass(help, "hidden");
368             removeClass(document.body, "blur");
369         }
370     }
371
372     function handleEscape(ev) {
373         var help = getHelpElement();
374         var search = getSearchElement();
375         if (hasClass(help, "hidden") === false) {
376             displayHelp(false, ev, help);
377         } else if (hasClass(search, "hidden") === false) {
378             clearInputTimeout();
379             ev.preventDefault();
380             hideSearchResults(search);
381         }
382         defocusSearchBar();
383         hideThemeButtonState();
384     }
385
386     function handleShortcut(ev) {
387         // Don't interfere with browser shortcuts
388         if (ev.ctrlKey || ev.altKey || ev.metaKey || disableShortcuts === true) {
389             return;
390         }
391
392         if (document.activeElement.tagName === "INPUT") {
393             switch (getVirtualKey(ev)) {
394             case "Escape":
395                 handleEscape(ev);
396                 break;
397             }
398         } else {
399             switch (getVirtualKey(ev)) {
400             case "Escape":
401                 handleEscape(ev);
402                 break;
403
404             case "s":
405             case "S":
406                 displayHelp(false, ev);
407                 ev.preventDefault();
408                 focusSearchBar();
409                 break;
410
411             case "+":
412             case "-":
413                 ev.preventDefault();
414                 toggleAllDocs();
415                 break;
416
417             case "?":
418                 displayHelp(true, ev);
419                 break;
420
421             case "t":
422             case "T":
423                 displayHelp(false, ev);
424                 ev.preventDefault();
425                 var themePicker = getThemePickerElement();
426                 themePicker.click();
427                 themePicker.focus();
428                 break;
429
430             default:
431                 var themePicker = getThemePickerElement();
432                 if (themePicker.parentNode.contains(ev.target)) {
433                     handleThemeKeyDown(ev);
434                 }
435             }
436         }
437     }
438
439     function handleThemeKeyDown(ev) {
440         var active = document.activeElement;
441         var themes = getThemesElement();
442         switch (getVirtualKey(ev)) {
443         case "ArrowUp":
444             ev.preventDefault();
445             if (active.previousElementSibling && ev.target.id !== "theme-picker") {
446                 active.previousElementSibling.focus();
447             } else {
448                 showThemeButtonState();
449                 themes.lastElementChild.focus();
450             }
451             break;
452         case "ArrowDown":
453             ev.preventDefault();
454             if (active.nextElementSibling && ev.target.id !== "theme-picker") {
455                 active.nextElementSibling.focus();
456             } else {
457                 showThemeButtonState();
458                 themes.firstElementChild.focus();
459             }
460             break;
461         case "Enter":
462         case "Return":
463         case "Space":
464             if (ev.target.id === "theme-picker" && themes.style.display === "none") {
465                 ev.preventDefault();
466                 showThemeButtonState();
467                 themes.firstElementChild.focus();
468             }
469             break;
470         case "Home":
471             ev.preventDefault();
472             themes.firstElementChild.focus();
473             break;
474         case "End":
475             ev.preventDefault();
476             themes.lastElementChild.focus();
477             break;
478         // The escape key is handled in handleEscape, not here,
479         // so that pressing escape will close the menu even if it isn't focused
480         }
481     }
482
483     function findParentElement(elem, tagName) {
484         do {
485             if (elem && elem.tagName === tagName) {
486                 return elem;
487             }
488             elem = elem.parentNode;
489         } while (elem);
490         return null;
491     }
492
493     document.addEventListener("keypress", handleShortcut);
494     document.addEventListener("keydown", handleShortcut);
495
496     document.addEventListener("mousemove", function() { mouseMovedAfterSearch = true; });
497
498     var handleSourceHighlight = (function() {
499         var prev_line_id = 0;
500
501         var set_fragment = function(name) {
502             var x = window.scrollX,
503                 y = window.scrollY;
504             if (browserSupportsHistoryApi()) {
505                 history.replaceState(null, null, "#" + name);
506                 highlightSourceLines();
507             } else {
508                 location.replace("#" + name);
509             }
510             // Prevent jumps when selecting one or many lines
511             window.scrollTo(x, y);
512         };
513
514         return function(ev) {
515             var cur_line_id = parseInt(ev.target.id, 10);
516             ev.preventDefault();
517
518             if (ev.shiftKey && prev_line_id) {
519                 // Swap selection if needed
520                 if (prev_line_id > cur_line_id) {
521                     var tmp = prev_line_id;
522                     prev_line_id = cur_line_id;
523                     cur_line_id = tmp;
524                 }
525
526                 set_fragment(prev_line_id + "-" + cur_line_id);
527             } else {
528                 prev_line_id = cur_line_id;
529
530                 set_fragment(cur_line_id);
531             }
532         };
533     }());
534
535     document.addEventListener("click", function(ev) {
536         if (hasClass(ev.target, "help-button")) {
537             displayHelp(true, ev);
538         } else if (hasClass(ev.target, "collapse-toggle")) {
539             collapseDocs(ev.target, "toggle");
540         } else if (hasClass(ev.target.parentNode, "collapse-toggle")) {
541             collapseDocs(ev.target.parentNode, "toggle");
542         } else if (ev.target.tagName === "SPAN" && hasClass(ev.target.parentNode, "line-numbers")) {
543             handleSourceHighlight(ev);
544         } else if (hasClass(getHelpElement(), "hidden") === false) {
545             var help = getHelpElement();
546             var is_inside_help_popup = ev.target !== help && help.contains(ev.target);
547             if (is_inside_help_popup === false) {
548                 addClass(help, "hidden");
549                 removeClass(document.body, "blur");
550             }
551         } else {
552             // Making a collapsed element visible on onhashchange seems
553             // too late
554             var a = findParentElement(ev.target, "A");
555             if (a && a.hash) {
556                 expandSection(a.hash.replace(/^#/, ""));
557             }
558         }
559     });
560
561     (function() {
562         var x = document.getElementsByClassName("version-selector");
563         if (x.length > 0) {
564             x[0].onchange = function() {
565                 var i, match,
566                     url = document.location.href,
567                     stripped = "",
568                     len = rootPath.match(/\.\.\//g).length + 1;
569
570                 for (i = 0; i < len; ++i) {
571                     match = url.match(/\/[^\/]*$/);
572                     if (i < len - 1) {
573                         stripped = match[0] + stripped;
574                     }
575                     url = url.substring(0, url.length - match[0].length);
576                 }
577
578                 var selectedVersion = document.getElementsByClassName("version-selector")[0].value;
579                 url += "/" + selectedVersion + stripped;
580
581                 document.location.href = url;
582             };
583         }
584     }());
585
586     /**
587      * A function to compute the Levenshtein distance between two strings
588      * Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported
589      * Full License can be found at http://creativecommons.org/licenses/by-sa/3.0/legalcode
590      * This code is an unmodified version of the code written by Marco de Wit
591      * and was found at http://stackoverflow.com/a/18514751/745719
592      */
593     var levenshtein_row2 = [];
594     function levenshtein(s1, s2) {
595         if (s1 === s2) {
596             return 0;
597         }
598         var s1_len = s1.length, s2_len = s2.length;
599         if (s1_len && s2_len) {
600             var i1 = 0, i2 = 0, a, b, c, c2, row = levenshtein_row2;
601             while (i1 < s1_len) {
602                 row[i1] = ++i1;
603             }
604             while (i2 < s2_len) {
605                 c2 = s2.charCodeAt(i2);
606                 a = i2;
607                 ++i2;
608                 b = i2;
609                 for (i1 = 0; i1 < s1_len; ++i1) {
610                     c = a + (s1.charCodeAt(i1) !== c2 ? 1 : 0);
611                     a = row[i1];
612                     b = b < a ? (b < c ? b + 1 : c) : (a < c ? a + 1 : c);
613                     row[i1] = b;
614                 }
615             }
616             return b;
617         }
618         return s1_len + s2_len;
619     }
620
621     window.initSearch = function(rawSearchIndex) {
622         var MAX_LEV_DISTANCE = 3;
623         var MAX_RESULTS = 200;
624         var GENERICS_DATA = 1;
625         var NAME = 0;
626         var INPUTS_DATA = 0;
627         var OUTPUT_DATA = 1;
628         var NO_TYPE_FILTER = -1;
629         var currentResults, index, searchIndex;
630         var ALIASES = {};
631         var params = getQueryStringParams();
632
633         // Populate search bar with query string search term when provided,
634         // but only if the input bar is empty. This avoid the obnoxious issue
635         // where you start trying to do a search, and the index loads, and
636         // suddenly your search is gone!
637         if (search_input.value === "") {
638             search_input.value = params.search || "";
639         }
640
641         /**
642          * Executes the query and builds an index of results
643          * @param  {[Object]} query      [The user query]
644          * @param  {[type]} searchWords  [The list of search words to query
645          *                                against]
646          * @param  {[type]} filterCrates [Crate to search in if defined]
647          * @return {[type]}              [A search index of results]
648          */
649         function execQuery(query, searchWords, filterCrates) {
650             function itemTypeFromName(typename) {
651                 for (var i = 0, len = itemTypes.length; i < len; ++i) {
652                     if (itemTypes[i] === typename) {
653                         return i;
654                     }
655                 }
656                 return NO_TYPE_FILTER;
657             }
658
659             var valLower = query.query.toLowerCase(),
660                 val = valLower,
661                 typeFilter = itemTypeFromName(query.type),
662                 results = {}, results_in_args = {}, results_returned = {},
663                 split = valLower.split("::");
664
665             split = split.filter(function(segment) { return segment !== ""; });
666
667             function transformResults(results, isType) {
668                 var out = [];
669                 for (var i = 0, len = results.length; i < len; ++i) {
670                     if (results[i].id > -1) {
671                         var obj = searchIndex[results[i].id];
672                         obj.lev = results[i].lev;
673                         if (isType !== true || obj.type) {
674                             var res = buildHrefAndPath(obj);
675                             obj.displayPath = pathSplitter(res[0]);
676                             obj.fullPath = obj.displayPath + obj.name;
677                             // To be sure than it some items aren't considered as duplicate.
678                             obj.fullPath += "|" + obj.ty;
679                             obj.href = res[1];
680                             out.push(obj);
681                             if (out.length >= MAX_RESULTS) {
682                                 break;
683                             }
684                         }
685                     }
686                 }
687                 return out;
688             }
689
690             function sortResults(results, isType) {
691                 var ar = [];
692                 for (var entry in results) {
693                     if (hasOwnProperty(results, entry)) {
694                         ar.push(results[entry]);
695                     }
696                 }
697                 results = ar;
698                 var i, len, result;
699                 for (i = 0, len = results.length; i < len; ++i) {
700                     result = results[i];
701                     result.word = searchWords[result.id];
702                     result.item = searchIndex[result.id] || {};
703                 }
704                 // if there are no results then return to default and fail
705                 if (results.length === 0) {
706                     return [];
707                 }
708
709                 results.sort(function(aaa, bbb) {
710                     var a, b;
711
712                     // sort by exact match with regard to the last word (mismatch goes later)
713                     a = (aaa.word !== val);
714                     b = (bbb.word !== val);
715                     if (a !== b) { return a - b; }
716
717                     // Sort by non levenshtein results and then levenshtein results by the distance
718                     // (less changes required to match means higher rankings)
719                     a = (aaa.lev);
720                     b = (bbb.lev);
721                     if (a !== b) { return a - b; }
722
723                     // sort by crate (non-current crate goes later)
724                     a = (aaa.item.crate !== window.currentCrate);
725                     b = (bbb.item.crate !== window.currentCrate);
726                     if (a !== b) { return a - b; }
727
728                     // sort by item name length (longer goes later)
729                     a = aaa.word.length;
730                     b = bbb.word.length;
731                     if (a !== b) { return a - b; }
732
733                     // sort by item name (lexicographically larger goes later)
734                     a = aaa.word;
735                     b = bbb.word;
736                     if (a !== b) { return (a > b ? +1 : -1); }
737
738                     // sort by index of keyword in item name (no literal occurrence goes later)
739                     a = (aaa.index < 0);
740                     b = (bbb.index < 0);
741                     if (a !== b) { return a - b; }
742                     // (later literal occurrence, if any, goes later)
743                     a = aaa.index;
744                     b = bbb.index;
745                     if (a !== b) { return a - b; }
746
747                     // special precedence for primitive and keyword pages
748                     if ((aaa.item.ty === TY_PRIMITIVE && bbb.item.ty !== TY_KEYWORD) ||
749                         (aaa.item.ty === TY_KEYWORD && bbb.item.ty !== TY_PRIMITIVE)) {
750                         return -1;
751                     }
752                     if ((bbb.item.ty === TY_PRIMITIVE && aaa.item.ty !== TY_PRIMITIVE) ||
753                         (bbb.item.ty === TY_KEYWORD && aaa.item.ty !== TY_KEYWORD)) {
754                         return 1;
755                     }
756
757                     // sort by description (no description goes later)
758                     a = (aaa.item.desc === "");
759                     b = (bbb.item.desc === "");
760                     if (a !== b) { return a - b; }
761
762                     // sort by type (later occurrence in `itemTypes` goes later)
763                     a = aaa.item.ty;
764                     b = bbb.item.ty;
765                     if (a !== b) { return a - b; }
766
767                     // sort by path (lexicographically larger goes later)
768                     a = aaa.item.path;
769                     b = bbb.item.path;
770                     if (a !== b) { return (a > b ? +1 : -1); }
771
772                     // que sera, sera
773                     return 0;
774                 });
775
776                 for (i = 0, len = results.length; i < len; ++i) {
777                     var result = results[i];
778
779                     // this validation does not make sense when searching by types
780                     if (result.dontValidate) {
781                         continue;
782                     }
783                     var name = result.item.name.toLowerCase(),
784                         path = result.item.path.toLowerCase(),
785                         parent = result.item.parent;
786
787                     if (isType !== true &&
788                         validateResult(name, path, split, parent) === false)
789                     {
790                         result.id = -1;
791                     }
792                 }
793                 return transformResults(results);
794             }
795
796             function extractGenerics(val) {
797                 val = val.toLowerCase();
798                 if (val.indexOf("<") !== -1) {
799                     var values = val.substring(val.indexOf("<") + 1, val.lastIndexOf(">"));
800                     return {
801                         name: val.substring(0, val.indexOf("<")),
802                         generics: values.split(/\s*,\s*/),
803                     };
804                 }
805                 return {
806                     name: val,
807                     generics: [],
808                 };
809             }
810
811             function getObjectFromId(id) {
812                 if (typeof id === "number") {
813                     return searchIndex[id];
814                 }
815                 return {'name': id};
816             }
817
818             function checkGenerics(obj, val) {
819                 // The names match, but we need to be sure that all generics kinda
820                 // match as well.
821                 var lev_distance = MAX_LEV_DISTANCE + 1;
822                 if (val.generics.length > 0) {
823                     if (obj.length > GENERICS_DATA &&
824                           obj[GENERICS_DATA].length >= val.generics.length) {
825                         var elems = obj[GENERICS_DATA].slice(0);
826                         var total = 0;
827                         var done = 0;
828                         // We need to find the type that matches the most to remove it in order
829                         // to move forward.
830                         var vlength = val.generics.length;
831                         for (var y = 0; y < vlength; ++y) {
832                             var lev = { pos: -1, lev: MAX_LEV_DISTANCE + 1};
833                             var firstGeneric = getObjectFromId(val.generics[y]).name;
834                             for (var x = 0, elength = elems.length; x < elength; ++x) {
835                                 var tmp_lev = levenshtein(getObjectFromId(elems[x]).name,
836                                                                           firstGeneric);
837                                 if (tmp_lev < lev.lev) {
838                                     lev.lev = tmp_lev;
839                                     lev.pos = x;
840                                 }
841                             }
842                             if (lev.pos !== -1) {
843                                 elems.splice(lev.pos, 1);
844                                 lev_distance = Math.min(lev.lev, lev_distance);
845                                 total += lev.lev;
846                                 done += 1;
847                             } else {
848                                 return MAX_LEV_DISTANCE + 1;
849                             }
850                         }
851                         return Math.ceil(total / done);
852                     }
853                 }
854                 return MAX_LEV_DISTANCE + 1;
855             }
856
857             // Check for type name and type generics (if any).
858             function checkType(obj, val, literalSearch) {
859                 var lev_distance = MAX_LEV_DISTANCE + 1;
860                 var len, x, y, e_len, firstGeneric;
861                 if (obj[NAME] === val.name) {
862                     if (literalSearch === true) {
863                         if (val.generics && val.generics.length !== 0) {
864                             if (obj.length > GENERICS_DATA &&
865                                   obj[GENERICS_DATA].length >= val.generics.length) {
866                                 var elems = obj[GENERICS_DATA].slice(0);
867                                 var allFound = true;
868
869                                 len = val.generics.length;
870                                 for (y = 0; allFound === true && y < len; ++y) {
871                                     allFound = false;
872                                     firstGeneric = getObjectFromId(val.generics[y]).name;
873                                     e_len = elems.length;
874                                     for (x = 0; allFound === false && x < e_len; ++x) {
875                                         allFound = getObjectFromId(elems[x]).name === firstGeneric;
876                                     }
877                                     if (allFound === true) {
878                                         elems.splice(x - 1, 1);
879                                     }
880                                 }
881                                 if (allFound === true) {
882                                     return true;
883                                 }
884                             } else {
885                                 return false;
886                             }
887                         }
888                         return true;
889                     }
890                     // If the type has generics but don't match, then it won't return at this point.
891                     // Otherwise, `checkGenerics` will return 0 and it'll return.
892                     if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length !== 0) {
893                         var tmp_lev = checkGenerics(obj, val);
894                         if (tmp_lev <= MAX_LEV_DISTANCE) {
895                             return tmp_lev;
896                         }
897                     } else {
898                         return 0;
899                     }
900                 }
901                 // Names didn't match so let's check if one of the generic types could.
902                 if (literalSearch === true) {
903                      if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
904                         return obj[GENERICS_DATA].some(
905                             function(name) {
906                                 return name === val.name;
907                             });
908                     }
909                     return false;
910                 }
911                 lev_distance = Math.min(levenshtein(obj[NAME], val.name), lev_distance);
912                 if (lev_distance <= MAX_LEV_DISTANCE) {
913                     // The generics didn't match but the name kinda did so we give it
914                     // a levenshtein distance value that isn't *this* good so it goes
915                     // into the search results but not too high.
916                     lev_distance = Math.ceil((checkGenerics(obj, val) + lev_distance) / 2);
917                 } else if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
918                     // We can check if the type we're looking for is inside the generics!
919                     var olength = obj[GENERICS_DATA].length;
920                     for (x = 0; x < olength; ++x) {
921                         lev_distance = Math.min(levenshtein(obj[GENERICS_DATA][x], val.name),
922                                                 lev_distance);
923                     }
924                 }
925                 // Now whatever happens, the returned distance is "less good" so we should mark it
926                 // as such, and so we add 1 to the distance to make it "less good".
927                 return lev_distance + 1;
928             }
929
930             function findArg(obj, val, literalSearch, typeFilter) {
931                 var lev_distance = MAX_LEV_DISTANCE + 1;
932
933                 if (obj && obj.type && obj.type[INPUTS_DATA] && obj.type[INPUTS_DATA].length > 0) {
934                     var length = obj.type[INPUTS_DATA].length;
935                     for (var i = 0; i < length; i++) {
936                         var tmp = obj.type[INPUTS_DATA][i];
937                         if (typePassesFilter(typeFilter, tmp[1]) === false) {
938                             continue;
939                         }
940                         tmp = checkType(tmp, val, literalSearch);
941                         if (literalSearch === true) {
942                             if (tmp === true) {
943                                 return true;
944                             }
945                             continue;
946                         }
947                         lev_distance = Math.min(tmp, lev_distance);
948                         if (lev_distance === 0) {
949                             return 0;
950                         }
951                     }
952                 }
953                 return literalSearch === true ? false : lev_distance;
954             }
955
956             function checkReturned(obj, val, literalSearch, typeFilter) {
957                 var lev_distance = MAX_LEV_DISTANCE + 1;
958
959                 if (obj && obj.type && obj.type.length > OUTPUT_DATA) {
960                     var ret = obj.type[OUTPUT_DATA];
961                     if (typeof ret[0] === "string") {
962                         ret = [ret];
963                     }
964                     for (var x = 0, len = ret.length; x < len; ++x) {
965                         var tmp = ret[x];
966                         if (typePassesFilter(typeFilter, tmp[1]) === false) {
967                             continue;
968                         }
969                         tmp = checkType(tmp, val, literalSearch);
970                         if (literalSearch === true) {
971                             if (tmp === true) {
972                                 return true;
973                             }
974                             continue;
975                         }
976                         lev_distance = Math.min(tmp, lev_distance);
977                         if (lev_distance === 0) {
978                             return 0;
979                         }
980                     }
981                 }
982                 return literalSearch === true ? false : lev_distance;
983             }
984
985             function checkPath(contains, lastElem, ty) {
986                 if (contains.length === 0) {
987                     return 0;
988                 }
989                 var ret_lev = MAX_LEV_DISTANCE + 1;
990                 var path = ty.path.split("::");
991
992                 if (ty.parent && ty.parent.name) {
993                     path.push(ty.parent.name.toLowerCase());
994                 }
995
996                 var length = path.length;
997                 var clength = contains.length;
998                 if (clength > length) {
999                     return MAX_LEV_DISTANCE + 1;
1000                 }
1001                 for (var i = 0; i < length; ++i) {
1002                     if (i + clength > length) {
1003                         break;
1004                     }
1005                     var lev_total = 0;
1006                     var aborted = false;
1007                     for (var x = 0; x < clength; ++x) {
1008                         var lev = levenshtein(path[i + x], contains[x]);
1009                         if (lev > MAX_LEV_DISTANCE) {
1010                             aborted = true;
1011                             break;
1012                         }
1013                         lev_total += lev;
1014                     }
1015                     if (aborted === false) {
1016                         ret_lev = Math.min(ret_lev, Math.round(lev_total / clength));
1017                     }
1018                 }
1019                 return ret_lev;
1020             }
1021
1022             function typePassesFilter(filter, type) {
1023                 // No filter
1024                 if (filter <= NO_TYPE_FILTER) return true;
1025
1026                 // Exact match
1027                 if (filter === type) return true;
1028
1029                 // Match related items
1030                 var name = itemTypes[type];
1031                 switch (itemTypes[filter]) {
1032                     case "constant":
1033                         return name === "associatedconstant";
1034                     case "fn":
1035                         return name === "method" || name === "tymethod";
1036                     case "type":
1037                         return name === "primitive" || name === "associatedtype";
1038                     case "trait":
1039                         return name === "traitalias";
1040                 }
1041
1042                 // No match
1043                 return false;
1044             }
1045
1046             function generateId(ty) {
1047                 if (ty.parent && ty.parent.name) {
1048                     return itemTypes[ty.ty] + ty.path + ty.parent.name + ty.name;
1049                 }
1050                 return itemTypes[ty.ty] + ty.path + ty.name;
1051             }
1052
1053             function createAliasFromItem(item) {
1054                 return {
1055                     crate: item.crate,
1056                     name: item.name,
1057                     path: item.path,
1058                     desc: item.desc,
1059                     ty: item.ty,
1060                     parent: item.parent,
1061                     type: item.type,
1062                     is_alias: true,
1063                 };
1064             }
1065
1066             function handleAliases(ret, query, filterCrates) {
1067                 // We separate aliases and crate aliases because we want to have current crate
1068                 // aliases to be before the others in the displayed results.
1069                 var aliases = [];
1070                 var crateAliases = [];
1071                 if (filterCrates !== undefined) {
1072                     if (ALIASES[filterCrates] && ALIASES[filterCrates][query.search]) {
1073                         var query_aliases = ALIASES[filterCrates][query.search];
1074                         var len = query_aliases.length;
1075                         for (var i = 0; i < len; ++i) {
1076                             aliases.push(createAliasFromItem(searchIndex[query_aliases[i]]));
1077                         }
1078                     }
1079                 } else {
1080                     Object.keys(ALIASES).forEach(function(crate) {
1081                         if (ALIASES[crate][query.search]) {
1082                             var pushTo = crate === window.currentCrate ? crateAliases : aliases;
1083                             var query_aliases = ALIASES[crate][query.search];
1084                             var len = query_aliases.length;
1085                             for (var i = 0; i < len; ++i) {
1086                                 pushTo.push(createAliasFromItem(searchIndex[query_aliases[i]]));
1087                             }
1088                         }
1089                     });
1090                 }
1091
1092                 var sortFunc = function(aaa, bbb) {
1093                     if (aaa.path < bbb.path) {
1094                         return 1;
1095                     } else if (aaa.path === bbb.path) {
1096                         return 0;
1097                     }
1098                     return -1;
1099                 };
1100                 crateAliases.sort(sortFunc);
1101                 aliases.sort(sortFunc);
1102
1103                 var pushFunc = function(alias) {
1104                     alias.alias = query.raw;
1105                     var res = buildHrefAndPath(alias);
1106                     alias.displayPath = pathSplitter(res[0]);
1107                     alias.fullPath = alias.displayPath + alias.name;
1108                     alias.href = res[1];
1109
1110                     ret.others.unshift(alias);
1111                     if (ret.others.length > MAX_RESULTS) {
1112                         ret.others.pop();
1113                     }
1114                 };
1115                 onEach(aliases, pushFunc);
1116                 onEach(crateAliases, pushFunc);
1117             }
1118
1119             // quoted values mean literal search
1120             var nSearchWords = searchWords.length;
1121             var i, it;
1122             var ty;
1123             var fullId;
1124             var returned;
1125             var in_args;
1126             var len;
1127             if ((val.charAt(0) === "\"" || val.charAt(0) === "'") &&
1128                 val.charAt(val.length - 1) === val.charAt(0))
1129             {
1130                 val = extractGenerics(val.substr(1, val.length - 2));
1131                 for (i = 0; i < nSearchWords; ++i) {
1132                     if (filterCrates !== undefined && searchIndex[i].crate !== filterCrates) {
1133                         continue;
1134                     }
1135                     in_args = findArg(searchIndex[i], val, true, typeFilter);
1136                     returned = checkReturned(searchIndex[i], val, true, typeFilter);
1137                     ty = searchIndex[i];
1138                     fullId = generateId(ty);
1139
1140                     if (searchWords[i] === val.name
1141                         && typePassesFilter(typeFilter, searchIndex[i].ty)
1142                         && results[fullId] === undefined) {
1143                         results[fullId] = {
1144                             id: i,
1145                             index: -1,
1146                             dontValidate: true,
1147                         };
1148                     }
1149                     if (in_args === true && results_in_args[fullId] === undefined) {
1150                         results_in_args[fullId] = {
1151                             id: i,
1152                             index: -1,
1153                             dontValidate: true,
1154                         };
1155                     }
1156                     if (returned === true && results_returned[fullId] === undefined) {
1157                         results_returned[fullId] = {
1158                             id: i,
1159                             index: -1,
1160                             dontValidate: true,
1161                         };
1162                     }
1163                 }
1164                 query.inputs = [val];
1165                 query.output = val;
1166                 query.search = val;
1167             // searching by type
1168             } else if (val.search("->") > -1) {
1169                 var trimmer = function(s) { return s.trim(); };
1170                 var parts = val.split("->").map(trimmer);
1171                 var input = parts[0];
1172                 // sort inputs so that order does not matter
1173                 var inputs = input.split(",").map(trimmer).sort();
1174                 for (i = 0, len = inputs.length; i < len; ++i) {
1175                     inputs[i] = extractGenerics(inputs[i]);
1176                 }
1177                 var output = extractGenerics(parts[1]);
1178
1179                 for (i = 0; i < nSearchWords; ++i) {
1180                     if (filterCrates !== undefined && searchIndex[i].crate !== filterCrates) {
1181                         continue;
1182                     }
1183                     var type = searchIndex[i].type;
1184                     ty = searchIndex[i];
1185                     if (!type) {
1186                         continue;
1187                     }
1188                     fullId = generateId(ty);
1189
1190                     returned = checkReturned(ty, output, true, NO_TYPE_FILTER);
1191                     if (output.name === "*" || returned === true) {
1192                         in_args = false;
1193                         var is_module = false;
1194
1195                         if (input === "*") {
1196                             is_module = true;
1197                         } else {
1198                             var allFound = true;
1199                             for (it = 0, len = inputs.length; allFound === true && it < len; it++) {
1200                                 allFound = checkType(type, inputs[it], true);
1201                             }
1202                             in_args = allFound;
1203                         }
1204                         if (in_args === true) {
1205                             results_in_args[fullId] = {
1206                                 id: i,
1207                                 index: -1,
1208                                 dontValidate: true,
1209                             };
1210                         }
1211                         if (returned === true) {
1212                             results_returned[fullId] = {
1213                                 id: i,
1214                                 index: -1,
1215                                 dontValidate: true,
1216                             };
1217                         }
1218                         if (is_module === true) {
1219                             results[fullId] = {
1220                                 id: i,
1221                                 index: -1,
1222                                 dontValidate: true,
1223                             };
1224                         }
1225                     }
1226                 }
1227                 query.inputs = inputs.map(function(input) {
1228                     return input.name;
1229                 });
1230                 query.output = output.name;
1231             } else {
1232                 query.inputs = [val];
1233                 query.output = val;
1234                 query.search = val;
1235                 // gather matching search results up to a certain maximum
1236                 val = val.replace(/\_/g, "");
1237
1238                 var valGenerics = extractGenerics(val);
1239
1240                 var paths = valLower.split("::");
1241                 var j;
1242                 for (j = 0, len = paths.length; j < len; ++j) {
1243                     if (paths[j] === "") {
1244                         paths.splice(j, 1);
1245                         j -= 1;
1246                     }
1247                 }
1248                 val = paths[paths.length - 1];
1249                 var contains = paths.slice(0, paths.length > 1 ? paths.length - 1 : 1);
1250
1251                 var lev;
1252                 for (j = 0; j < nSearchWords; ++j) {
1253                     ty = searchIndex[j];
1254                     if (!ty || (filterCrates !== undefined && ty.crate !== filterCrates)) {
1255                         continue;
1256                     }
1257                     var lev_add = 0;
1258                     if (paths.length > 1) {
1259                         lev = checkPath(contains, paths[paths.length - 1], ty);
1260                         if (lev > MAX_LEV_DISTANCE) {
1261                             continue;
1262                         } else if (lev > 0) {
1263                             lev_add = lev / 10;
1264                         }
1265                     }
1266
1267                     returned = MAX_LEV_DISTANCE + 1;
1268                     in_args = MAX_LEV_DISTANCE + 1;
1269                     var index = -1;
1270                     // we want lev results to go lower than others
1271                     lev = MAX_LEV_DISTANCE + 1;
1272                     fullId = generateId(ty);
1273
1274                     if (searchWords[j].indexOf(split[i]) > -1 ||
1275                         searchWords[j].indexOf(val) > -1 ||
1276                         searchWords[j].replace(/_/g, "").indexOf(val) > -1)
1277                     {
1278                         // filter type: ... queries
1279                         if (typePassesFilter(typeFilter, ty.ty) && results[fullId] === undefined) {
1280                             index = searchWords[j].replace(/_/g, "").indexOf(val);
1281                         }
1282                     }
1283                     if ((lev = levenshtein(searchWords[j], val)) <= MAX_LEV_DISTANCE) {
1284                         if (typePassesFilter(typeFilter, ty.ty) === false) {
1285                             lev = MAX_LEV_DISTANCE + 1;
1286                         } else {
1287                             lev += 1;
1288                         }
1289                     }
1290                     in_args = findArg(ty, valGenerics, false, typeFilter);
1291                     returned = checkReturned(ty, valGenerics, false, typeFilter);
1292
1293                     lev += lev_add;
1294                     if (lev > 0 && val.length > 3 && searchWords[j].indexOf(val) > -1) {
1295                         if (val.length < 6) {
1296                             lev -= 1;
1297                         } else {
1298                             lev = 0;
1299                         }
1300                     }
1301                     if (in_args <= MAX_LEV_DISTANCE) {
1302                         if (results_in_args[fullId] === undefined) {
1303                             results_in_args[fullId] = {
1304                                 id: j,
1305                                 index: index,
1306                                 lev: in_args,
1307                             };
1308                         }
1309                         results_in_args[fullId].lev =
1310                             Math.min(results_in_args[fullId].lev, in_args);
1311                     }
1312                     if (returned <= MAX_LEV_DISTANCE) {
1313                         if (results_returned[fullId] === undefined) {
1314                             results_returned[fullId] = {
1315                                 id: j,
1316                                 index: index,
1317                                 lev: returned,
1318                             };
1319                         }
1320                         results_returned[fullId].lev =
1321                             Math.min(results_returned[fullId].lev, returned);
1322                     }
1323                     if (index !== -1 || lev <= MAX_LEV_DISTANCE) {
1324                         if (index !== -1 && paths.length < 2) {
1325                             lev = 0;
1326                         }
1327                         if (results[fullId] === undefined) {
1328                             results[fullId] = {
1329                                 id: j,
1330                                 index: index,
1331                                 lev: lev,
1332                             };
1333                         }
1334                         results[fullId].lev = Math.min(results[fullId].lev, lev);
1335                     }
1336                 }
1337             }
1338
1339             var ret = {
1340                 "in_args": sortResults(results_in_args, true),
1341                 "returned": sortResults(results_returned, true),
1342                 "others": sortResults(results),
1343             };
1344             handleAliases(ret, query, filterCrates);
1345             return ret;
1346         }
1347
1348         /**
1349          * Validate performs the following boolean logic. For example:
1350          * "File::open" will give IF A PARENT EXISTS => ("file" && "open")
1351          * exists in (name || path || parent) OR => ("file" && "open") exists in
1352          * (name || path )
1353          *
1354          * This could be written functionally, but I wanted to minimise
1355          * functions on stack.
1356          *
1357          * @param  {[string]} name   [The name of the result]
1358          * @param  {[string]} path   [The path of the result]
1359          * @param  {[string]} keys   [The keys to be used (["file", "open"])]
1360          * @param  {[object]} parent [The parent of the result]
1361          * @return {[boolean]}       [Whether the result is valid or not]
1362          */
1363         function validateResult(name, path, keys, parent) {
1364             for (var i = 0, len = keys.length; i < len; ++i) {
1365                 // each check is for validation so we negate the conditions and invalidate
1366                 if (!(
1367                     // check for an exact name match
1368                     name.indexOf(keys[i]) > -1 ||
1369                     // then an exact path match
1370                     path.indexOf(keys[i]) > -1 ||
1371                     // next if there is a parent, check for exact parent match
1372                     (parent !== undefined && parent.name !== undefined &&
1373                         parent.name.toLowerCase().indexOf(keys[i]) > -1) ||
1374                     // lastly check to see if the name was a levenshtein match
1375                     levenshtein(name, keys[i]) <= MAX_LEV_DISTANCE)) {
1376                     return false;
1377                 }
1378             }
1379             return true;
1380         }
1381
1382         function getQuery(raw) {
1383             var matches, type, query;
1384             query = raw;
1385
1386             matches = query.match(/^(fn|mod|struct|enum|trait|type|const|macro)\s*:\s*/i);
1387             if (matches) {
1388                 type = matches[1].replace(/^const$/, "constant");
1389                 query = query.substring(matches[0].length);
1390             }
1391
1392             return {
1393                 raw: raw,
1394                 query: query,
1395                 type: type,
1396                 id: query + type
1397             };
1398         }
1399
1400         function initSearchNav() {
1401             var hoverTimeout;
1402
1403             var click_func = function(e) {
1404                 var el = e.target;
1405                 // to retrieve the real "owner" of the event.
1406                 while (el.tagName !== "TR") {
1407                     el = el.parentNode;
1408                 }
1409                 var dst = e.target.getElementsByTagName("a");
1410                 if (dst.length < 1) {
1411                     return;
1412                 }
1413                 dst = dst[0];
1414                 if (window.location.pathname === dst.pathname) {
1415                     hideSearchResults();
1416                     document.location.href = dst.href;
1417                 }
1418             };
1419             var mouseover_func = function(e) {
1420                 if (mouseMovedAfterSearch) {
1421                     var el = e.target;
1422                     // to retrieve the real "owner" of the event.
1423                     while (el.tagName !== "TR") {
1424                         el = el.parentNode;
1425                     }
1426                     clearTimeout(hoverTimeout);
1427                     hoverTimeout = setTimeout(function() {
1428                         onEachLazy(document.getElementsByClassName("search-results"), function(e) {
1429                             onEachLazy(e.getElementsByClassName("result"), function(i_e) {
1430                                 removeClass(i_e, "highlighted");
1431                             });
1432                         });
1433                         addClass(el, "highlighted");
1434                     }, 20);
1435                 }
1436             };
1437             onEachLazy(document.getElementsByClassName("search-results"), function(e) {
1438                 onEachLazy(e.getElementsByClassName("result"), function(i_e) {
1439                     i_e.onclick = click_func;
1440                     i_e.onmouseover = mouseover_func;
1441                 });
1442             });
1443
1444             search_input.onkeydown = function(e) {
1445                 // "actives" references the currently highlighted item in each search tab.
1446                 // Each array in "actives" represents a tab.
1447                 var actives = [[], [], []];
1448                 // "current" is used to know which tab we're looking into.
1449                 var current = 0;
1450                 onEachLazy(document.getElementById("results").childNodes, function(e) {
1451                     onEachLazy(e.getElementsByClassName("highlighted"), function(h_e) {
1452                         actives[current].push(h_e);
1453                     });
1454                     current += 1;
1455                 });
1456
1457                 if (e.which === 38) { // up
1458                     if (e.ctrlKey) { // Going through result tabs.
1459                         printTab(currentTab > 0 ? currentTab - 1 : 2);
1460                     } else {
1461                         if (!actives[currentTab].length ||
1462                             !actives[currentTab][0].previousElementSibling) {
1463                             return;
1464                         }
1465                         addClass(actives[currentTab][0].previousElementSibling, "highlighted");
1466                         removeClass(actives[currentTab][0], "highlighted");
1467                     }
1468                     e.preventDefault();
1469                 } else if (e.which === 40) { // down
1470                     if (e.ctrlKey) { // Going through result tabs.
1471                         printTab(currentTab > 1 ? 0 : currentTab + 1);
1472                     } else if (!actives[currentTab].length) {
1473                         var results = document.getElementById("results").childNodes;
1474                         if (results.length > 0) {
1475                             var res = results[currentTab].getElementsByClassName("result");
1476                             if (res.length > 0) {
1477                                 addClass(res[0], "highlighted");
1478                             }
1479                         }
1480                     } else if (actives[currentTab][0].nextElementSibling) {
1481                         addClass(actives[currentTab][0].nextElementSibling, "highlighted");
1482                         removeClass(actives[currentTab][0], "highlighted");
1483                     }
1484                     e.preventDefault();
1485                 } else if (e.which === 13) { // return
1486                     if (actives[currentTab].length) {
1487                         document.location.href =
1488                             actives[currentTab][0].getElementsByTagName("a")[0].href;
1489                     }
1490                 } else if (e.which === 16) { // shift
1491                     // Does nothing, it's just to avoid losing "focus" on the highlighted element.
1492                 } else if (actives[currentTab].length > 0) {
1493                     removeClass(actives[currentTab][0], "highlighted");
1494                 }
1495             };
1496         }
1497
1498         function buildHrefAndPath(item) {
1499             var displayPath;
1500             var href;
1501             var type = itemTypes[item.ty];
1502             var name = item.name;
1503             var path = item.path;
1504
1505             if (type === "mod") {
1506                 displayPath = path + "::";
1507                 href = rootPath + path.replace(/::/g, "/") + "/" +
1508                        name + "/index.html";
1509             } else if (type === "primitive" || type === "keyword") {
1510                 displayPath = "";
1511                 href = rootPath + path.replace(/::/g, "/") +
1512                        "/" + type + "." + name + ".html";
1513             } else if (type === "externcrate") {
1514                 displayPath = "";
1515                 href = rootPath + name + "/index.html";
1516             } else if (item.parent !== undefined) {
1517                 var myparent = item.parent;
1518                 var anchor = "#" + type + "." + name;
1519                 var parentType = itemTypes[myparent.ty];
1520                 var pageType = parentType;
1521                 var pageName = myparent.name;
1522
1523                 if (parentType === "primitive") {
1524                     displayPath = myparent.name + "::";
1525                 } else if (type === "structfield" && parentType === "variant") {
1526                     // Structfields belonging to variants are special: the
1527                     // final path element is the enum name.
1528                     var splitPath = item.path.split("::");
1529                     var enumName = splitPath.pop();
1530                     path = splitPath.join("::");
1531                     displayPath = path + "::" + enumName + "::" + myparent.name + "::";
1532                     anchor = "#variant." + myparent.name + ".field." + name;
1533                     pageType = "enum";
1534                     pageName = enumName;
1535                 } else {
1536                     displayPath = path + "::" + myparent.name + "::";
1537                 }
1538                 href = rootPath + path.replace(/::/g, "/") +
1539                        "/" + pageType +
1540                        "." + pageName +
1541                        ".html" + anchor;
1542             } else {
1543                 displayPath = item.path + "::";
1544                 href = rootPath + item.path.replace(/::/g, "/") +
1545                        "/" + type + "." + name + ".html";
1546             }
1547             return [displayPath, href];
1548         }
1549
1550         function escape(content) {
1551             var h1 = document.createElement("h1");
1552             h1.textContent = content;
1553             return h1.innerHTML;
1554         }
1555
1556         function pathSplitter(path) {
1557             var tmp = "<span>" + path.replace(/::/g, "::</span><span>");
1558             if (tmp.endsWith("<span>")) {
1559                 return tmp.slice(0, tmp.length - 6);
1560             }
1561             return tmp;
1562         }
1563
1564         function addTab(array, query, display) {
1565             var extraStyle = "";
1566             if (display === false) {
1567                 extraStyle = " style=\"display: none;\"";
1568             }
1569
1570             var output = "";
1571             var duplicates = {};
1572             var length = 0;
1573             if (array.length > 0) {
1574                 output = "<table class=\"search-results\"" + extraStyle + ">";
1575
1576                 array.forEach(function(item) {
1577                     var name, type;
1578
1579                     name = item.name;
1580                     type = itemTypes[item.ty];
1581
1582                     if (item.is_alias !== true) {
1583                         if (duplicates[item.fullPath]) {
1584                             return;
1585                         }
1586                         duplicates[item.fullPath] = true;
1587                     }
1588                     length += 1;
1589
1590                     output += "<tr class=\"" + type + " result\"><td>" +
1591                               "<a href=\"" + item.href + "\">" +
1592                               (item.is_alias === true ?
1593                                ("<span class=\"alias\"><b>" + item.alias + " </b></span><span " +
1594                                   "class=\"grey\"><i>&nbsp;- see&nbsp;</i></span>") : "") +
1595                               item.displayPath + "<span class=\"" + type + "\">" +
1596                               name + "</span></a></td><td>" +
1597                               "<a href=\"" + item.href + "\">" +
1598                               "<span class=\"desc\">" + item.desc +
1599                               "&nbsp;</span></a></td></tr>";
1600                 });
1601                 output += "</table>";
1602             } else {
1603                 output = "<div class=\"search-failed\"" + extraStyle + ">No results :(<br/>" +
1604                     "Try on <a href=\"https://duckduckgo.com/?q=" +
1605                     encodeURIComponent("rust " + query.query) +
1606                     "\">DuckDuckGo</a>?<br/><br/>" +
1607                     "Or try looking in one of these:<ul><li>The <a " +
1608                     "href=\"https://doc.rust-lang.org/reference/index.html\">Rust Reference</a> " +
1609                     " for technical details about the language.</li><li><a " +
1610                     "href=\"https://doc.rust-lang.org/rust-by-example/index.html\">Rust By " +
1611                     "Example</a> for expository code examples.</a></li><li>The <a " +
1612                     "href=\"https://doc.rust-lang.org/book/index.html\">Rust Book</a> for " +
1613                     "introductions to language features and the language itself.</li><li><a " +
1614                     "href=\"https://docs.rs\">Docs.rs</a> for documentation of crates released on" +
1615                     " <a href=\"https://crates.io/\">crates.io</a>.</li></ul></div>";
1616             }
1617             return [output, length];
1618         }
1619
1620         function makeTabHeader(tabNb, text, nbElems) {
1621             if (currentTab === tabNb) {
1622                 return "<button class=\"selected\">" + text +
1623                        " <div class=\"count\">(" + nbElems + ")</div></button>";
1624             }
1625             return "<button>" + text + " <div class=\"count\">(" + nbElems + ")</div></button>";
1626         }
1627
1628         function showResults(results) {
1629             var search = getSearchElement();
1630             if (results.others.length === 1
1631                 && getSettingValue("go-to-only-result") === "true"
1632                 // By default, the search DOM element is "empty" (meaning it has no children not
1633                 // text content). Once a search has been run, it won't be empty, even if you press
1634                 // ESC or empty the search input (which also "cancels" the search).
1635                 && (!search.firstChild || search.firstChild.innerText !== getSearchLoadingText()))
1636             {
1637                 var elem = document.createElement("a");
1638                 elem.href = results.others[0].href;
1639                 elem.style.display = "none";
1640                 // For firefox, we need the element to be in the DOM so it can be clicked.
1641                 document.body.appendChild(elem);
1642                 elem.click();
1643                 return;
1644             }
1645             var query = getQuery(search_input.value);
1646
1647             currentResults = query.id;
1648
1649             var ret_others = addTab(results.others, query);
1650             var ret_in_args = addTab(results.in_args, query, false);
1651             var ret_returned = addTab(results.returned, query, false);
1652
1653             var output = "<h1>Results for " + escape(query.query) +
1654                 (query.type ? " (type: " + escape(query.type) + ")" : "") + "</h1>" +
1655                 "<div id=\"titles\">" +
1656                 makeTabHeader(0, "In Names", ret_others[1]) +
1657                 makeTabHeader(1, "In Parameters", ret_in_args[1]) +
1658                 makeTabHeader(2, "In Return Types", ret_returned[1]) +
1659                 "</div><div id=\"results\">" +
1660                 ret_others[0] + ret_in_args[0] + ret_returned[0] + "</div>";
1661
1662             search.innerHTML = output;
1663             showSearchResults(search);
1664             var tds = search.getElementsByTagName("td");
1665             var td_width = 0;
1666             if (tds.length > 0) {
1667                 td_width = tds[0].offsetWidth;
1668             }
1669             var width = search.offsetWidth - 40 - td_width;
1670             onEachLazy(search.getElementsByClassName("desc"), function(e) {
1671                 e.style.width = width + "px";
1672             });
1673             initSearchNav();
1674             var elems = document.getElementById("titles").childNodes;
1675             elems[0].onclick = function() { printTab(0); };
1676             elems[1].onclick = function() { printTab(1); };
1677             elems[2].onclick = function() { printTab(2); };
1678             printTab(currentTab);
1679         }
1680
1681         function execSearch(query, searchWords, filterCrates) {
1682             function getSmallest(arrays, positions, notDuplicates) {
1683                 var start = null;
1684
1685                 for (var it = 0, len = positions.length; it < len; ++it) {
1686                     if (arrays[it].length > positions[it] &&
1687                         (start === null || start > arrays[it][positions[it]].lev) &&
1688                         !notDuplicates[arrays[it][positions[it]].fullPath]) {
1689                         start = arrays[it][positions[it]].lev;
1690                     }
1691                 }
1692                 return start;
1693             }
1694
1695             function mergeArrays(arrays) {
1696                 var ret = [];
1697                 var positions = [];
1698                 var notDuplicates = {};
1699
1700                 for (var x = 0, arrays_len = arrays.length; x < arrays_len; ++x) {
1701                     positions.push(0);
1702                 }
1703                 while (ret.length < MAX_RESULTS) {
1704                     var smallest = getSmallest(arrays, positions, notDuplicates);
1705
1706                     if (smallest === null) {
1707                         break;
1708                     }
1709                     for (x = 0; x < arrays_len && ret.length < MAX_RESULTS; ++x) {
1710                         if (arrays[x].length > positions[x] &&
1711                                 arrays[x][positions[x]].lev === smallest &&
1712                                 !notDuplicates[arrays[x][positions[x]].fullPath]) {
1713                             ret.push(arrays[x][positions[x]]);
1714                             notDuplicates[arrays[x][positions[x]].fullPath] = true;
1715                             positions[x] += 1;
1716                         }
1717                     }
1718                 }
1719                 return ret;
1720             }
1721
1722             var queries = query.raw.split(",");
1723             var results = {
1724                 "in_args": [],
1725                 "returned": [],
1726                 "others": [],
1727             };
1728
1729             for (var i = 0, len = queries.length; i < len; ++i) {
1730                 query = queries[i].trim();
1731                 if (query.length !== 0) {
1732                     var tmp = execQuery(getQuery(query), searchWords, filterCrates);
1733
1734                     results.in_args.push(tmp.in_args);
1735                     results.returned.push(tmp.returned);
1736                     results.others.push(tmp.others);
1737                 }
1738             }
1739             if (queries.length > 1) {
1740                 return {
1741                     "in_args": mergeArrays(results.in_args),
1742                     "returned": mergeArrays(results.returned),
1743                     "others": mergeArrays(results.others),
1744                 };
1745             }
1746             return {
1747                 "in_args": results.in_args[0],
1748                 "returned": results.returned[0],
1749                 "others": results.others[0],
1750             };
1751         }
1752
1753         function getFilterCrates() {
1754             var elem = document.getElementById("crate-search");
1755
1756             if (elem && elem.value !== "All crates" && hasOwnProperty(rawSearchIndex, elem.value)) {
1757                 return elem.value;
1758             }
1759             return undefined;
1760         }
1761
1762         function search(e, forced) {
1763             var params = getQueryStringParams();
1764             var query = getQuery(search_input.value.trim());
1765
1766             if (e) {
1767                 e.preventDefault();
1768             }
1769
1770             if (query.query.length === 0) {
1771                 return;
1772             }
1773             if (forced !== true && query.id === currentResults) {
1774                 if (query.query.length > 0) {
1775                     putBackSearch(search_input);
1776                 }
1777                 return;
1778             }
1779
1780             // Update document title to maintain a meaningful browser history
1781             searchTitle = "Results for " + query.query + " - Rust";
1782
1783             // Because searching is incremental by character, only the most
1784             // recent search query is added to the browser history.
1785             if (browserSupportsHistoryApi()) {
1786                 if (!history.state && !params.search) {
1787                     history.pushState(query, "", "?search=" + encodeURIComponent(query.raw));
1788                 } else {
1789                     history.replaceState(query, "", "?search=" + encodeURIComponent(query.raw));
1790                 }
1791             }
1792
1793             var filterCrates = getFilterCrates();
1794             showResults(execSearch(query, index, filterCrates));
1795         }
1796
1797         function buildIndex(rawSearchIndex) {
1798             searchIndex = [];
1799             var searchWords = [];
1800             var i;
1801             var currentIndex = 0;
1802
1803             for (var crate in rawSearchIndex) {
1804                 if (!hasOwnProperty(rawSearchIndex, crate)) { continue; }
1805
1806                 var crateSize = 0;
1807
1808                 searchWords.push(crate);
1809                 searchIndex.push({
1810                     crate: crate,
1811                     ty: 1, // == ExternCrate
1812                     name: crate,
1813                     path: "",
1814                     desc: rawSearchIndex[crate].doc,
1815                     type: null,
1816                 });
1817                 currentIndex += 1;
1818
1819                 // an array of [(Number) item type,
1820                 //              (String) name,
1821                 //              (String) full path or empty string for previous path,
1822                 //              (String) description,
1823                 //              (Number | null) the parent path index to `paths`]
1824                 //              (Object | null) the type of the function (if any)
1825                 var items = rawSearchIndex[crate].i;
1826                 // an array of [(Number) item type,
1827                 //              (String) name]
1828                 var paths = rawSearchIndex[crate].p;
1829                 // a array of [(String) alias name
1830                 //             [Number] index to items]
1831                 var aliases = rawSearchIndex[crate].a;
1832
1833                 // convert `rawPaths` entries into object form
1834                 var len = paths.length;
1835                 for (i = 0; i < len; ++i) {
1836                     paths[i] = {ty: paths[i][0], name: paths[i][1]};
1837                 }
1838
1839                 // convert `items` into an object form, and construct word indices.
1840                 //
1841                 // before any analysis is performed lets gather the search terms to
1842                 // search against apart from the rest of the data.  This is a quick
1843                 // operation that is cached for the life of the page state so that
1844                 // all other search operations have access to this cached data for
1845                 // faster analysis operations
1846                 len = items.length;
1847                 var lastPath = "";
1848                 for (i = 0; i < len; ++i) {
1849                     var rawRow = items[i];
1850                     if (!rawRow[2]) {
1851                         rawRow[2] = lastPath;
1852                     }
1853                     var row = {
1854                         crate: crate,
1855                         ty: rawRow[0],
1856                         name: rawRow[1],
1857                         path: rawRow[2],
1858                         desc: rawRow[3],
1859                         parent: paths[rawRow[4]],
1860                         type: rawRow[5],
1861                     };
1862                     searchIndex.push(row);
1863                     if (typeof row.name === "string") {
1864                         var word = row.name.toLowerCase();
1865                         searchWords.push(word);
1866                     } else {
1867                         searchWords.push("");
1868                     }
1869                     lastPath = row.path;
1870                     crateSize += 1;
1871                 }
1872
1873                 if (aliases) {
1874                     ALIASES[crate] = {};
1875                     var j, local_aliases;
1876                     for (var alias_name in aliases) {
1877                         if (!aliases.hasOwnProperty(alias_name)) { continue; }
1878
1879                         if (!ALIASES[crate].hasOwnProperty(alias_name)) {
1880                             ALIASES[crate][alias_name] = [];
1881                         }
1882                         local_aliases = aliases[alias_name];
1883                         for (j = 0, len = local_aliases.length; j < len; ++j) {
1884                             ALIASES[crate][alias_name].push(local_aliases[j] + currentIndex);
1885                         }
1886                     }
1887                 }
1888                 currentIndex += crateSize;
1889             }
1890             return searchWords;
1891         }
1892
1893         function startSearch() {
1894             var callback = function() {
1895                 clearInputTimeout();
1896                 if (search_input.value.length === 0) {
1897                     if (browserSupportsHistoryApi()) {
1898                         history.replaceState("", window.currentCrate + " - Rust", "?search=");
1899                     }
1900                     hideSearchResults();
1901                 } else {
1902                     searchTimeout = setTimeout(search, 500);
1903                 }
1904             };
1905             search_input.onkeyup = callback;
1906             search_input.oninput = callback;
1907             document.getElementsByClassName("search-form")[0].onsubmit = function(e) {
1908                 e.preventDefault();
1909                 clearInputTimeout();
1910                 search();
1911             };
1912             search_input.onchange = function(e) {
1913                 if (e.target !== document.activeElement) {
1914                     // To prevent doing anything when it's from a blur event.
1915                     return;
1916                 }
1917                 // Do NOT e.preventDefault() here. It will prevent pasting.
1918                 clearInputTimeout();
1919                 // zero-timeout necessary here because at the time of event handler execution the
1920                 // pasted content is not in the input field yet. Shouldn’t make any difference for
1921                 // change, though.
1922                 setTimeout(search, 0);
1923             };
1924             search_input.onpaste = search_input.onchange;
1925
1926             var selectCrate = document.getElementById("crate-search");
1927             if (selectCrate) {
1928                 selectCrate.onchange = function() {
1929                     updateLocalStorage("rustdoc-saved-filter-crate", selectCrate.value);
1930                     search(undefined, true);
1931                 };
1932             }
1933
1934             // Push and pop states are used to add search results to the browser
1935             // history.
1936             if (browserSupportsHistoryApi()) {
1937                 // Store the previous <title> so we can revert back to it later.
1938                 var previousTitle = document.title;
1939
1940                 window.addEventListener("popstate", function(e) {
1941                     var params = getQueryStringParams();
1942                     // Revert to the previous title manually since the History
1943                     // API ignores the title parameter.
1944                     document.title = previousTitle;
1945                     // When browsing forward to search results the previous
1946                     // search will be repeated, so the currentResults are
1947                     // cleared to ensure the search is successful.
1948                     currentResults = null;
1949                     // Synchronize search bar with query string state and
1950                     // perform the search. This will empty the bar if there's
1951                     // nothing there, which lets you really go back to a
1952                     // previous state with nothing in the bar.
1953                     if (params.search && params.search.length > 0) {
1954                         search_input.value = params.search;
1955                         // Some browsers fire "onpopstate" for every page load
1956                         // (Chrome), while others fire the event only when actually
1957                         // popping a state (Firefox), which is why search() is
1958                         // called both here and at the end of the startSearch()
1959                         // function.
1960                         search(e);
1961                     } else {
1962                         search_input.value = "";
1963                         // When browsing back from search results the main page
1964                         // visibility must be reset.
1965                         hideSearchResults();
1966                     }
1967                 });
1968             }
1969             search();
1970         }
1971
1972         index = buildIndex(rawSearchIndex);
1973         startSearch();
1974
1975         // Draw a convenient sidebar of known crates if we have a listing
1976         if (rootPath === "../" || rootPath === "./") {
1977             var sidebar = document.getElementsByClassName("sidebar-elems")[0];
1978             if (sidebar) {
1979                 var div = document.createElement("div");
1980                 div.className = "block crate";
1981                 div.innerHTML = "<h3>Crates</h3>";
1982                 var ul = document.createElement("ul");
1983                 div.appendChild(ul);
1984
1985                 var crates = [];
1986                 for (var crate in rawSearchIndex) {
1987                     if (!hasOwnProperty(rawSearchIndex, crate)) {
1988                         continue;
1989                     }
1990                     crates.push(crate);
1991                 }
1992                 crates.sort();
1993                 for (var i = 0; i < crates.length; ++i) {
1994                     var klass = "crate";
1995                     if (rootPath !== "./" && crates[i] === window.currentCrate) {
1996                         klass += " current";
1997                     }
1998                     var link = document.createElement("a");
1999                     link.href = rootPath + crates[i] + "/index.html";
2000                     // The summary in the search index has HTML, so we need to
2001                     // dynamically render it as plaintext.
2002                     link.title = convertHTMLToPlaintext(rawSearchIndex[crates[i]].doc);
2003                     link.className = klass;
2004                     link.textContent = crates[i];
2005
2006                     var li = document.createElement("li");
2007                     li.appendChild(link);
2008                     ul.appendChild(li);
2009                 }
2010                 sidebar.appendChild(div);
2011             }
2012         }
2013     };
2014
2015     /**
2016      * Convert HTML to plaintext:
2017      *
2018      *   * Replace "<code>foo</code>" with "`foo`"
2019      *   * Strip all other HTML tags
2020      *
2021      * Used by the dynamic sidebar crate list renderer.
2022      *
2023      * @param  {[string]} html [The HTML to convert]
2024      * @return {[string]}      [The resulting plaintext]
2025      */
2026     function convertHTMLToPlaintext(html) {
2027         var x = document.createElement("div");
2028         x.innerHTML = html.replace('<code>', '`').replace('</code>', '`');
2029         return x.innerText;
2030     }
2031
2032
2033     // delayed sidebar rendering.
2034     window.initSidebarItems = function(items) {
2035         var sidebar = document.getElementsByClassName("sidebar-elems")[0];
2036         var current = window.sidebarCurrent;
2037
2038         function block(shortty, longty) {
2039             var filtered = items[shortty];
2040             if (!filtered) {
2041                 return;
2042             }
2043
2044             var div = document.createElement("div");
2045             div.className = "block " + shortty;
2046             var h3 = document.createElement("h3");
2047             h3.textContent = longty;
2048             div.appendChild(h3);
2049             var ul = document.createElement("ul");
2050
2051             for (var i = 0, len = filtered.length; i < len; ++i) {
2052                 var item = filtered[i];
2053                 var name = item[0];
2054                 var desc = item[1]; // can be null
2055
2056                 var klass = shortty;
2057                 if (name === current.name && shortty === current.ty) {
2058                     klass += " current";
2059                 }
2060                 var path;
2061                 if (shortty === "mod") {
2062                     path = name + "/index.html";
2063                 } else {
2064                     path = shortty + "." + name + ".html";
2065                 }
2066                 var link = document.createElement("a");
2067                 link.href = current.relpath + path;
2068                 link.title = desc;
2069                 link.className = klass;
2070                 link.textContent = name;
2071                 var li = document.createElement("li");
2072                 li.appendChild(link);
2073                 ul.appendChild(li);
2074             }
2075             div.appendChild(ul);
2076             if (sidebar) {
2077                 sidebar.appendChild(div);
2078             }
2079         }
2080
2081         block("primitive", "Primitive Types");
2082         block("mod", "Modules");
2083         block("macro", "Macros");
2084         block("struct", "Structs");
2085         block("enum", "Enums");
2086         block("union", "Unions");
2087         block("constant", "Constants");
2088         block("static", "Statics");
2089         block("trait", "Traits");
2090         block("fn", "Functions");
2091         block("type", "Type Definitions");
2092         block("foreigntype", "Foreign Types");
2093         block("keyword", "Keywords");
2094         block("traitalias", "Trait Aliases");
2095     };
2096
2097     window.register_implementors = function(imp) {
2098         var implementors = document.getElementById("implementors-list");
2099         var synthetic_implementors = document.getElementById("synthetic-implementors-list");
2100
2101         if (synthetic_implementors) {
2102             // This `inlined_types` variable is used to avoid having the same implementation
2103             // showing up twice. For example "String" in the "Sync" doc page.
2104             //
2105             // By the way, this is only used by and useful for traits implemented automatically
2106             // (like "Send" and "Sync").
2107             var inlined_types = new Set();
2108             onEachLazy(synthetic_implementors.getElementsByClassName("impl"), function(el) {
2109                 var aliases = el.getAttribute("aliases");
2110                 if (!aliases) {
2111                     return;
2112                 }
2113                 aliases.split(",").forEach(function(alias) {
2114                     inlined_types.add(alias);
2115                 });
2116             });
2117         }
2118
2119         var libs = Object.getOwnPropertyNames(imp);
2120         for (var i = 0, llength = libs.length; i < llength; ++i) {
2121             if (libs[i] === currentCrate) { continue; }
2122             var structs = imp[libs[i]];
2123
2124             struct_loop:
2125             for (var j = 0, slength = structs.length; j < slength; ++j) {
2126                 var struct = structs[j];
2127
2128                 var list = struct.synthetic ? synthetic_implementors : implementors;
2129
2130                 if (struct.synthetic) {
2131                     for (var k = 0, stlength = struct.types.length; k < stlength; k++) {
2132                         if (inlined_types.has(struct.types[k])) {
2133                             continue struct_loop;
2134                         }
2135                         inlined_types.add(struct.types[k]);
2136                     }
2137                 }
2138
2139                 var code = document.createElement("code");
2140                 code.innerHTML = struct.text;
2141
2142                 onEachLazy(code.getElementsByTagName("a"), function(elem) {
2143                     var href = elem.getAttribute("href");
2144
2145                     if (href && href.indexOf("http") !== 0) {
2146                         elem.setAttribute("href", rootPath + href);
2147                     }
2148                 });
2149
2150                 var display = document.createElement("h3");
2151                 addClass(display, "impl");
2152                 display.innerHTML = "<span class=\"in-band\"><table class=\"table-display\">" +
2153                     "<tbody><tr><td><code>" + code.outerHTML + "</code></td><td></td></tr>" +
2154                     "</tbody></table></span>";
2155                 list.appendChild(display);
2156             }
2157         }
2158     };
2159     if (window.pending_implementors) {
2160         window.register_implementors(window.pending_implementors);
2161     }
2162
2163     function labelForToggleButton(sectionIsCollapsed) {
2164         if (sectionIsCollapsed) {
2165             // button will expand the section
2166             return "+";
2167         }
2168         // button will collapse the section
2169         // note that this text is also set in the HTML template in render.rs
2170         return "\u2212"; // "\u2212" is "−" minus sign
2171     }
2172
2173     function onEveryMatchingChild(elem, className, func) {
2174         if (elem && className && func) {
2175             var length = elem.childNodes.length;
2176             var nodes = elem.childNodes;
2177             for (var i = 0; i < length; ++i) {
2178                 if (hasClass(nodes[i], className)) {
2179                     func(nodes[i]);
2180                 } else {
2181                     onEveryMatchingChild(nodes[i], className, func);
2182                 }
2183             }
2184         }
2185     }
2186
2187     function toggleAllDocs(pageId, fromAutoCollapse) {
2188         var innerToggle = document.getElementById(toggleAllDocsId);
2189         if (!innerToggle) {
2190             return;
2191         }
2192         if (hasClass(innerToggle, "will-expand")) {
2193             updateLocalStorage("rustdoc-collapse", "false");
2194             removeClass(innerToggle, "will-expand");
2195             onEveryMatchingChild(innerToggle, "inner", function(e) {
2196                 e.innerHTML = labelForToggleButton(false);
2197             });
2198             innerToggle.title = "collapse all docs";
2199             if (fromAutoCollapse !== true) {
2200                 onEachLazy(document.getElementsByClassName("collapse-toggle"), function(e) {
2201                     collapseDocs(e, "show");
2202                 });
2203             }
2204         } else {
2205             updateLocalStorage("rustdoc-collapse", "true");
2206             addClass(innerToggle, "will-expand");
2207             onEveryMatchingChild(innerToggle, "inner", function(e) {
2208                 var parent = e.parentNode;
2209                 var superParent = null;
2210
2211                 if (parent) {
2212                     superParent = parent.parentNode;
2213                 }
2214                 if (!parent || !superParent || superParent.id !== "main" ||
2215                     hasClass(parent, "impl") === false) {
2216                     e.innerHTML = labelForToggleButton(true);
2217                 }
2218             });
2219             innerToggle.title = "expand all docs";
2220             if (fromAutoCollapse !== true) {
2221                 onEachLazy(document.getElementsByClassName("collapse-toggle"), function(e) {
2222                     var parent = e.parentNode;
2223                     var superParent = null;
2224
2225                     if (parent) {
2226                         superParent = parent.parentNode;
2227                     }
2228                     if (!parent || !superParent || superParent.id !== "main" ||
2229                         hasClass(parent, "impl") === false) {
2230                         collapseDocs(e, "hide", pageId);
2231                     }
2232                 });
2233             }
2234         }
2235     }
2236
2237     function collapseDocs(toggle, mode, pageId) {
2238         if (!toggle || !toggle.parentNode) {
2239             return;
2240         }
2241
2242         function adjustToggle(arg) {
2243             return function(e) {
2244                 if (hasClass(e, "toggle-label")) {
2245                     if (arg) {
2246                         e.style.display = "inline-block";
2247                     } else {
2248                         e.style.display = "none";
2249                     }
2250                 }
2251                 if (hasClass(e, "inner")) {
2252                     e.innerHTML = labelForToggleButton(arg);
2253                 }
2254             };
2255         }
2256
2257         function implHider(addOrRemove, fullHide) {
2258             return function(n) {
2259                 var shouldHide =
2260                     fullHide === true ||
2261                     hasClass(n, "method") === true ||
2262                     hasClass(n, "associatedconstant") === true;
2263                 if (shouldHide === true || hasClass(n, "type") === true) {
2264                     if (shouldHide === true) {
2265                         if (addOrRemove) {
2266                             addClass(n, "hidden-by-impl-hider");
2267                         } else {
2268                             removeClass(n, "hidden-by-impl-hider");
2269                         }
2270                     }
2271                     var ns = n.nextElementSibling;
2272                     while (ns && (hasClass(ns, "docblock") || hasClass(ns, "item-info"))) {
2273                         if (addOrRemove) {
2274                             addClass(ns, "hidden-by-impl-hider");
2275                         } else {
2276                             removeClass(ns, "hidden-by-impl-hider");
2277                         }
2278                         ns = ns.nextElementSibling;
2279                     }
2280                 }
2281             };
2282         }
2283
2284         var relatedDoc;
2285         var action = mode;
2286         if (hasClass(toggle.parentNode, "impl") === false) {
2287             relatedDoc = toggle.parentNode.nextElementSibling;
2288             if (hasClass(relatedDoc, "item-info")) {
2289                 relatedDoc = relatedDoc.nextElementSibling;
2290             }
2291             if (hasClass(relatedDoc, "docblock") || hasClass(relatedDoc, "sub-variant")) {
2292                 if (mode === "toggle") {
2293                     if (hasClass(relatedDoc, "hidden-by-usual-hider")) {
2294                         action = "show";
2295                     } else {
2296                         action = "hide";
2297                     }
2298                 }
2299                 if (action === "hide") {
2300                     addClass(relatedDoc, "hidden-by-usual-hider");
2301                     onEachLazy(toggle.childNodes, adjustToggle(true));
2302                     addClass(toggle.parentNode, "collapsed");
2303                 } else if (action === "show") {
2304                     removeClass(relatedDoc, "hidden-by-usual-hider");
2305                     removeClass(toggle.parentNode, "collapsed");
2306                     onEachLazy(toggle.childNodes, adjustToggle(false));
2307                 }
2308             }
2309         } else {
2310             // we are collapsing the impl block(s).
2311
2312             var parentElem = toggle.parentNode;
2313             relatedDoc = parentElem;
2314             var docblock = relatedDoc.nextElementSibling;
2315
2316             while (hasClass(relatedDoc, "impl-items") === false) {
2317                 relatedDoc = relatedDoc.nextElementSibling;
2318             }
2319
2320             if (!relatedDoc && hasClass(docblock, "docblock") === false) {
2321                 return;
2322             }
2323
2324             // Hide all functions, but not associated types/consts.
2325
2326             if (mode === "toggle") {
2327                 if (hasClass(relatedDoc, "fns-now-collapsed") ||
2328                     hasClass(docblock, "hidden-by-impl-hider")) {
2329                     action = "show";
2330                 } else {
2331                     action = "hide";
2332                 }
2333             }
2334
2335             var dontApplyBlockRule = toggle.parentNode.parentNode.id !== "main";
2336             if (action === "show") {
2337                 removeClass(relatedDoc, "fns-now-collapsed");
2338                 // Stability/deprecation/portability information is never hidden.
2339                 if (hasClass(docblock, "item-info") === false) {
2340                     removeClass(docblock, "hidden-by-usual-hider");
2341                 }
2342                 onEachLazy(toggle.childNodes, adjustToggle(false, dontApplyBlockRule));
2343                 onEachLazy(relatedDoc.childNodes, implHider(false, dontApplyBlockRule));
2344             } else if (action === "hide") {
2345                 addClass(relatedDoc, "fns-now-collapsed");
2346                 // Stability/deprecation/portability information should be shown even when detailed
2347                 // info is hidden.
2348                 if (hasClass(docblock, "item-info") === false) {
2349                     addClass(docblock, "hidden-by-usual-hider");
2350                 }
2351                 onEachLazy(toggle.childNodes, adjustToggle(true, dontApplyBlockRule));
2352                 onEachLazy(relatedDoc.childNodes, implHider(true, dontApplyBlockRule));
2353             }
2354         }
2355     }
2356
2357     function collapser(pageId, e, collapse) {
2358         // inherent impl ids are like "impl" or impl-<number>'.
2359         // they will never be hidden by default.
2360         var n = e.parentElement;
2361         if (n.id.match(/^impl(?:-\d+)?$/) === null) {
2362             // Automatically minimize all non-inherent impls
2363             if (collapse || hasClass(n, "impl")) {
2364                 collapseDocs(e, "hide", pageId);
2365             }
2366         }
2367     }
2368
2369     function autoCollapse(pageId, collapse) {
2370         if (collapse) {
2371             toggleAllDocs(pageId, true);
2372         } else if (getSettingValue("auto-hide-trait-implementations") !== "false") {
2373             var impl_list = document.getElementById("trait-implementations-list");
2374
2375             if (impl_list !== null) {
2376                 onEachLazy(impl_list.getElementsByClassName("collapse-toggle"), function(e) {
2377                     collapser(pageId, e, collapse);
2378                 });
2379             }
2380
2381             var blanket_list = document.getElementById("blanket-implementations-list");
2382
2383             if (blanket_list !== null) {
2384                 onEachLazy(blanket_list.getElementsByClassName("collapse-toggle"), function(e) {
2385                     collapser(pageId, e, collapse);
2386                 });
2387             }
2388         }
2389     }
2390
2391     function insertAfter(newNode, referenceNode) {
2392         referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
2393     }
2394
2395     function createSimpleToggle(sectionIsCollapsed) {
2396         var toggle = document.createElement("a");
2397         toggle.href = "javascript:void(0)";
2398         toggle.className = "collapse-toggle";
2399         toggle.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(sectionIsCollapsed) +
2400                            "</span>]";
2401         return toggle;
2402     }
2403
2404     function createToggle(toggle, otherMessage, fontSize, extraClass, show) {
2405         var span = document.createElement("span");
2406         span.className = "toggle-label";
2407         if (show) {
2408             span.style.display = "none";
2409         }
2410         if (!otherMessage) {
2411             span.innerHTML = "&nbsp;Expand&nbsp;description";
2412         } else {
2413             span.innerHTML = otherMessage;
2414         }
2415
2416         if (fontSize) {
2417             span.style.fontSize = fontSize;
2418         }
2419
2420         var mainToggle = toggle.cloneNode(true);
2421         mainToggle.appendChild(span);
2422
2423         var wrapper = document.createElement("div");
2424         wrapper.className = "toggle-wrapper";
2425         if (!show) {
2426             addClass(wrapper, "collapsed");
2427             var inner = mainToggle.getElementsByClassName("inner");
2428             if (inner && inner.length > 0) {
2429                 inner[0].innerHTML = "+";
2430             }
2431         }
2432         if (extraClass) {
2433             addClass(wrapper, extraClass);
2434         }
2435         wrapper.appendChild(mainToggle);
2436         return wrapper;
2437     }
2438
2439     (function() {
2440         var toggles = document.getElementById(toggleAllDocsId);
2441         if (toggles) {
2442             toggles.onclick = toggleAllDocs;
2443         }
2444
2445         var toggle = createSimpleToggle(false);
2446         var hideMethodDocs = getSettingValue("auto-hide-method-docs") === "true";
2447         var hideImplementors = getSettingValue("auto-collapse-implementors") !== "false";
2448         var pageId = getPageId();
2449
2450         var func = function(e) {
2451             var next = e.nextElementSibling;
2452             if (next && hasClass(next, "item-info")) {
2453               next = next.nextElementSibling;
2454             }
2455             if (!next) {
2456                 return;
2457             }
2458             if (hasClass(next, "docblock")) {
2459                 var newToggle = toggle.cloneNode(true);
2460                 insertAfter(newToggle, e.childNodes[e.childNodes.length - 1]);
2461                 if (hideMethodDocs === true && hasClass(e, "method") === true) {
2462                     collapseDocs(newToggle, "hide", pageId);
2463                 }
2464             }
2465         };
2466
2467         var funcImpl = function(e) {
2468             var next = e.nextElementSibling;
2469             if (next && hasClass(next, "item-info")) {
2470                 next = next.nextElementSibling;
2471             }
2472             if (next && hasClass(next, "docblock")) {
2473                 next = next.nextElementSibling;
2474             }
2475             if (!next) {
2476                 return;
2477             }
2478             if (hasClass(e, "impl") &&
2479                 (next.getElementsByClassName("method").length > 0 ||
2480                  next.getElementsByClassName("associatedconstant").length > 0)) {
2481                 var newToggle = toggle.cloneNode(true);
2482                 insertAfter(newToggle, e.childNodes[e.childNodes.length - 1]);
2483                 // In case the option "auto-collapse implementors" is not set to false, we collapse
2484                 // all implementors.
2485                 if (hideImplementors === true && e.parentNode.id === "implementors-list") {
2486                     collapseDocs(newToggle, "hide", pageId);
2487                 }
2488             }
2489         };
2490
2491         onEachLazy(document.getElementsByClassName("method"), func);
2492         onEachLazy(document.getElementsByClassName("associatedconstant"), func);
2493         onEachLazy(document.getElementsByClassName("impl"), funcImpl);
2494         var impl_call = function() {};
2495         if (hideMethodDocs === true) {
2496             impl_call = function(e, newToggle) {
2497                 if (e.id.match(/^impl(?:-\d+)?$/) === null) {
2498                     // Automatically minimize all non-inherent impls
2499                     if (hasClass(e, "impl") === true) {
2500                         collapseDocs(newToggle, "hide", pageId);
2501                     }
2502                 }
2503             };
2504         }
2505         var newToggle = document.createElement("a");
2506         newToggle.href = "javascript:void(0)";
2507         newToggle.className = "collapse-toggle hidden-default collapsed";
2508         newToggle.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(true) +
2509                               "</span>] Show hidden undocumented items";
2510         function toggleClicked() {
2511             if (hasClass(this, "collapsed")) {
2512                 removeClass(this, "collapsed");
2513                 onEachLazy(this.parentNode.getElementsByClassName("hidden"), function(x) {
2514                     if (hasClass(x, "content") === false) {
2515                         removeClass(x, "hidden");
2516                         addClass(x, "x");
2517                     }
2518                 }, true);
2519                 this.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(false) +
2520                                  "</span>] Hide undocumented items";
2521             } else {
2522                 addClass(this, "collapsed");
2523                 onEachLazy(this.parentNode.getElementsByClassName("x"), function(x) {
2524                     if (hasClass(x, "content") === false) {
2525                         addClass(x, "hidden");
2526                         removeClass(x, "x");
2527                     }
2528                 }, true);
2529                 this.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(true) +
2530                                  "</span>] Show hidden undocumented items";
2531             }
2532         }
2533         onEachLazy(document.getElementsByClassName("impl-items"), function(e) {
2534             onEachLazy(e.getElementsByClassName("associatedconstant"), func);
2535             var hiddenElems = e.getElementsByClassName("hidden");
2536             var needToggle = false;
2537
2538             var needToggle = onEachLazy(e.getElementsByClassName("hidden"), function(hiddenElem) {
2539                 if (hasClass(hiddenElem, "content") === false &&
2540                     hasClass(hiddenElem, "docblock") === false) {
2541                     return true;
2542                 }
2543             });
2544             if (needToggle === true) {
2545                 var inner_toggle = newToggle.cloneNode(true);
2546                 inner_toggle.onclick = toggleClicked;
2547                 e.insertBefore(inner_toggle, e.firstChild);
2548                 impl_call(e.previousSibling, inner_toggle);
2549             }
2550         });
2551
2552         var currentType = document.getElementsByClassName("type-decl")[0];
2553         var className = null;
2554         if (currentType) {
2555             currentType = currentType.getElementsByClassName("rust")[0];
2556             if (currentType) {
2557                 currentType.classList.forEach(function(item) {
2558                     if (item !== "main") {
2559                         className = item;
2560                         return true;
2561                     }
2562                 });
2563             }
2564         }
2565         var showItemDeclarations = getSettingValue("auto-hide-" + className);
2566         if (showItemDeclarations === null) {
2567             if (className === "enum" || className === "macro") {
2568                 showItemDeclarations = "false";
2569             } else if (className === "struct" || className === "union" || className === "trait") {
2570                 showItemDeclarations = "true";
2571             } else {
2572                 // In case we found an unknown type, we just use the "parent" value.
2573                 showItemDeclarations = getSettingValue("auto-hide-declarations");
2574             }
2575         }
2576         showItemDeclarations = showItemDeclarations === "false";
2577         function buildToggleWrapper(e) {
2578             if (hasClass(e, "autohide")) {
2579                 var wrap = e.previousElementSibling;
2580                 if (wrap && hasClass(wrap, "toggle-wrapper")) {
2581                     var inner_toggle = wrap.childNodes[0];
2582                     var extra = e.childNodes[0].tagName === "H3";
2583
2584                     e.style.display = "none";
2585                     addClass(wrap, "collapsed");
2586                     onEachLazy(inner_toggle.getElementsByClassName("inner"), function(e) {
2587                         e.innerHTML = labelForToggleButton(true);
2588                     });
2589                     onEachLazy(inner_toggle.getElementsByClassName("toggle-label"), function(e) {
2590                         e.style.display = "inline-block";
2591                         if (extra === true) {
2592                             e.innerHTML = " Show " + e.childNodes[0].innerHTML;
2593                         }
2594                     });
2595                 }
2596             }
2597             if (e.parentNode.id === "main") {
2598                 var otherMessage = "";
2599                 var fontSize;
2600                 var extraClass;
2601
2602                 if (hasClass(e, "type-decl")) {
2603                     fontSize = "20px";
2604                     otherMessage = "&nbsp;Show&nbsp;declaration";
2605                     if (showItemDeclarations === false) {
2606                         extraClass = "collapsed";
2607                     }
2608                 } else if (hasClass(e, "sub-variant")) {
2609                     otherMessage = "&nbsp;Show&nbsp;fields";
2610                 } else if (hasClass(e, "non-exhaustive")) {
2611                     otherMessage = "&nbsp;This&nbsp;";
2612                     if (hasClass(e, "non-exhaustive-struct")) {
2613                         otherMessage += "struct";
2614                     } else if (hasClass(e, "non-exhaustive-enum")) {
2615                         otherMessage += "enum";
2616                     } else if (hasClass(e, "non-exhaustive-variant")) {
2617                         otherMessage += "enum variant";
2618                     } else if (hasClass(e, "non-exhaustive-type")) {
2619                         otherMessage += "type";
2620                     }
2621                     otherMessage += "&nbsp;is&nbsp;marked&nbsp;as&nbsp;non-exhaustive";
2622                 } else if (hasClass(e.childNodes[0], "impl-items")) {
2623                     extraClass = "marg-left";
2624                 }
2625
2626                 e.parentNode.insertBefore(
2627                     createToggle(
2628                         toggle,
2629                         otherMessage,
2630                         fontSize,
2631                         extraClass,
2632                         hasClass(e, "type-decl") === false || showItemDeclarations === true),
2633                     e);
2634                 if (hasClass(e, "type-decl") === true && showItemDeclarations === true) {
2635                     collapseDocs(e.previousSibling.childNodes[0], "toggle");
2636                 }
2637                 if (hasClass(e, "non-exhaustive") === true) {
2638                     collapseDocs(e.previousSibling.childNodes[0], "toggle");
2639                 }
2640             }
2641         }
2642
2643         onEachLazy(document.getElementsByClassName("docblock"), buildToggleWrapper);
2644         onEachLazy(document.getElementsByClassName("sub-variant"), buildToggleWrapper);
2645         var pageId = getPageId();
2646
2647         autoCollapse(pageId, getSettingValue("collapse") === "true");
2648
2649         if (pageId !== null) {
2650             expandSection(pageId);
2651         }
2652     }());
2653
2654     function createToggleWrapper(tog) {
2655         var span = document.createElement("span");
2656         span.className = "toggle-label";
2657         span.style.display = "none";
2658         span.innerHTML = "&nbsp;Expand&nbsp;attributes";
2659         tog.appendChild(span);
2660
2661         var wrapper = document.createElement("div");
2662         wrapper.className = "toggle-wrapper toggle-attributes";
2663         wrapper.appendChild(tog);
2664         return wrapper;
2665     }
2666
2667     (function() {
2668         // To avoid checking on "rustdoc-item-attributes" value on every loop...
2669         var itemAttributesFunc = function() {};
2670         if (getSettingValue("auto-hide-attributes") !== "false") {
2671             itemAttributesFunc = function(x) {
2672                 collapseDocs(x.previousSibling.childNodes[0], "toggle");
2673             };
2674         }
2675         var attributesToggle = createToggleWrapper(createSimpleToggle(false));
2676         onEachLazy(main.getElementsByClassName("attributes"), function(i_e) {
2677             var attr_tog = attributesToggle.cloneNode(true);
2678             if (hasClass(i_e, "top-attr") === true) {
2679                 addClass(attr_tog, "top-attr");
2680             }
2681             i_e.parentNode.insertBefore(attr_tog, i_e);
2682             itemAttributesFunc(i_e);
2683         });
2684     }());
2685
2686     (function() {
2687         // To avoid checking on "rustdoc-line-numbers" value on every loop...
2688         var lineNumbersFunc = function() {};
2689         if (getSettingValue("line-numbers") === "true") {
2690             lineNumbersFunc = function(x) {
2691                 var count = x.textContent.split("\n").length;
2692                 var elems = [];
2693                 for (var i = 0; i < count; ++i) {
2694                     elems.push(i + 1);
2695                 }
2696                 var node = document.createElement("pre");
2697                 addClass(node, "line-number");
2698                 node.innerHTML = elems.join("\n");
2699                 x.parentNode.insertBefore(node, x);
2700             };
2701         }
2702         onEachLazy(document.getElementsByClassName("rust-example-rendered"), function(e) {
2703             if (hasClass(e, "compile_fail")) {
2704                 e.addEventListener("mouseover", function() {
2705                     this.parentElement.previousElementSibling.childNodes[0].style.color = "#f00";
2706                 });
2707                 e.addEventListener("mouseout", function() {
2708                     this.parentElement.previousElementSibling.childNodes[0].style.color = "";
2709                 });
2710             } else if (hasClass(e, "ignore")) {
2711                 e.addEventListener("mouseover", function() {
2712                     this.parentElement.previousElementSibling.childNodes[0].style.color = "#ff9200";
2713                 });
2714                 e.addEventListener("mouseout", function() {
2715                     this.parentElement.previousElementSibling.childNodes[0].style.color = "";
2716                 });
2717             }
2718             lineNumbersFunc(e);
2719         });
2720     }());
2721
2722     onEachLazy(document.getElementsByClassName("notable-traits"), function(e) {
2723         e.onclick = function() {
2724             this.getElementsByClassName('notable-traits-tooltiptext')[0]
2725                 .classList.toggle("force-tooltip");
2726         };
2727     });
2728
2729     // In the search display, allows to switch between tabs.
2730     function printTab(nb) {
2731         if (nb === 0 || nb === 1 || nb === 2) {
2732             currentTab = nb;
2733         }
2734         var nb_copy = nb;
2735         onEachLazy(document.getElementById("titles").childNodes, function(elem) {
2736             if (nb_copy === 0) {
2737                 addClass(elem, "selected");
2738             } else {
2739                 removeClass(elem, "selected");
2740             }
2741             nb_copy -= 1;
2742         });
2743         onEachLazy(document.getElementById("results").childNodes, function(elem) {
2744             if (nb === 0) {
2745                 elem.style.display = "";
2746             } else {
2747                 elem.style.display = "none";
2748             }
2749             nb -= 1;
2750         });
2751     }
2752
2753     function putBackSearch(search_input) {
2754         var search = getSearchElement();
2755         if (search_input.value !== "" && hasClass(search, "hidden")) {
2756             showSearchResults(search);
2757             if (browserSupportsHistoryApi()) {
2758                 history.replaceState(search_input.value,
2759                                      "",
2760                                      "?search=" + encodeURIComponent(search_input.value));
2761             }
2762             document.title = searchTitle;
2763         }
2764     }
2765
2766     function getSearchLoadingText() {
2767         return "Loading search results...";
2768     }
2769
2770     if (search_input) {
2771         search_input.onfocus = function() {
2772             putBackSearch(this);
2773         };
2774     }
2775
2776     var params = getQueryStringParams();
2777     if (params && params.search) {
2778         var search = getSearchElement();
2779         search.innerHTML = "<h3 style=\"text-align: center;\">" + getSearchLoadingText() + "</h3>";
2780         showSearchResults(search);
2781     }
2782
2783     var sidebar_menu = document.getElementsByClassName("sidebar-menu")[0];
2784     if (sidebar_menu) {
2785         sidebar_menu.onclick = function() {
2786             var sidebar = document.getElementsByClassName("sidebar")[0];
2787             if (hasClass(sidebar, "mobile") === true) {
2788                 hideSidebar();
2789             } else {
2790                 showSidebar();
2791             }
2792         };
2793     }
2794
2795     if (main) {
2796         onEachLazy(main.getElementsByClassName("loading-content"), function(e) {
2797             e.remove();
2798         });
2799         onEachLazy(main.childNodes, function(e) {
2800             // Unhide the actual content once loading is complete. Headers get
2801             // flex treatment for their horizontal layout, divs get block treatment
2802             // for vertical layout (column-oriented flex layout for divs caused
2803             // errors in mobile browsers).
2804             if (e.tagName === "H2" || e.tagName === "H3") {
2805                 var nextTagName = e.nextElementSibling.tagName;
2806                 if (nextTagName == "H2" || nextTagName == "H3") {
2807                     e.nextElementSibling.style.display = "flex";
2808                 } else {
2809                     e.nextElementSibling.style.display = "block";
2810                 }
2811             }
2812         });
2813     }
2814
2815     function enableSearchInput() {
2816         if (search_input) {
2817             search_input.removeAttribute('disabled');
2818         }
2819     }
2820
2821     window.addSearchOptions = function(crates) {
2822         var elem = document.getElementById("crate-search");
2823
2824         if (!elem) {
2825             enableSearchInput();
2826             return;
2827         }
2828         var crates_text = [];
2829         if (Object.keys(crates).length > 1) {
2830             for (var crate in crates) {
2831                 if (hasOwnProperty(crates, crate)) {
2832                     crates_text.push(crate);
2833                 }
2834             }
2835         }
2836         crates_text.sort(function(a, b) {
2837             var lower_a = a.toLowerCase();
2838             var lower_b = b.toLowerCase();
2839
2840             if (lower_a < lower_b) {
2841                 return -1;
2842             } else if (lower_a > lower_b) {
2843                 return 1;
2844             }
2845             return 0;
2846         });
2847         var savedCrate = getSettingValue("saved-filter-crate");
2848         for (var i = 0, len = crates_text.length; i < len; ++i) {
2849             var option = document.createElement("option");
2850             option.value = crates_text[i];
2851             option.innerText = crates_text[i];
2852             elem.appendChild(option);
2853             // Set the crate filter from saved storage, if the current page has the saved crate
2854             // filter.
2855             //
2856             // If not, ignore the crate filter -- we want to support filtering for crates on sites
2857             // like doc.rust-lang.org where the crates may differ from page to page while on the
2858             // same domain.
2859             if (crates_text[i] === savedCrate) {
2860                 elem.value = savedCrate;
2861             }
2862         }
2863         enableSearchInput();
2864     };
2865
2866     function buildHelperPopup() {
2867         var popup = document.createElement("aside");
2868         addClass(popup, "hidden");
2869         popup.id = "help";
2870
2871         var book_info = document.createElement("span");
2872         book_info.innerHTML = "You can find more information in \
2873             <a href=\"https://doc.rust-lang.org/rustdoc/\">the rustdoc book</a>.";
2874
2875         var container = document.createElement("div");
2876         var shortcuts = [
2877             ["?", "Show this help dialog"],
2878             ["S", "Focus the search field"],
2879             ["T", "Focus the theme picker menu"],
2880             ["↑", "Move up in search results"],
2881             ["↓", "Move down in search results"],
2882             ["ctrl + ↑ / ↓", "Switch result tab"],
2883             ["&#9166;", "Go to active search result"],
2884             ["+", "Expand all sections"],
2885             ["-", "Collapse all sections"],
2886         ].map(x => "<dt>" +
2887             x[0].split(" ")
2888                 .map((y, index) => (index & 1) === 0 ? "<kbd>" + y + "</kbd>" : y)
2889                 .join("") + "</dt><dd>" + x[1] + "</dd>").join("");
2890         var div_shortcuts = document.createElement("div");
2891         addClass(div_shortcuts, "shortcuts");
2892         div_shortcuts.innerHTML = "<h2>Keyboard Shortcuts</h2><dl>" + shortcuts + "</dl></div>";
2893
2894         var infos = [
2895             "Prefix searches with a type followed by a colon (e.g., <code>fn:</code>) to \
2896              restrict the search to a given item kind.",
2897             "Accepted kinds are: <code>fn</code>, <code>mod</code>, <code>struct</code>, \
2898              <code>enum</code>, <code>trait</code>, <code>type</code>, <code>macro</code>, \
2899              and <code>const</code>.",
2900             "Search functions by type signature (e.g., <code>vec -&gt; usize</code> or \
2901              <code>* -&gt; vec</code>)",
2902             "Search multiple things at once by splitting your query with comma (e.g., \
2903              <code>str,u8</code> or <code>String,struct:Vec,test</code>)",
2904             "You can look for items with an exact name by putting double quotes around \
2905              your request: <code>\"string\"</code>",
2906             "Look for items inside another one by searching for a path: <code>vec::Vec</code>",
2907         ].map(x => "<p>" + x + "</p>").join("");
2908         var div_infos = document.createElement("div");
2909         addClass(div_infos, "infos");
2910         div_infos.innerHTML = "<h2>Search Tricks</h2>" + infos;
2911
2912         container.appendChild(book_info);
2913         container.appendChild(div_shortcuts);
2914         container.appendChild(div_infos);
2915
2916         popup.appendChild(container);
2917         insertAfter(popup, getSearchElement());
2918         // So that it's only built once and then it'll do nothing when called!
2919         buildHelperPopup = function() {};
2920     }
2921
2922     onHashChange(null);
2923     window.onhashchange = onHashChange;
2924 }());
2925
2926 // This is required in firefox. Explanations: when going back in the history, firefox doesn't re-run
2927 // the JS, therefore preventing rustdoc from setting a few things required to be able to reload the
2928 // previous search results (if you navigated to a search result with the keyboard, pressed enter on
2929 // it to navigate to that result, and then came back to this page).
2930 window.onunload = function(){};