]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/static/main.js
Auto merge of #80200 - mahkoh:dst-offset, r=nagisa
[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                 var length = itemTypes.length;
652                 for (var i = 0; i < length; ++i) {
653                     if (itemTypes[i] === typename) {
654                         return i;
655                     }
656                 }
657                 return NO_TYPE_FILTER;
658             }
659
660             var valLower = query.query.toLowerCase(),
661                 val = valLower,
662                 typeFilter = itemTypeFromName(query.type),
663                 results = {}, results_in_args = {}, results_returned = {},
664                 split = valLower.split("::");
665
666             split = split.filter(function(segment) { return segment !== ""; });
667
668             function transformResults(results, isType) {
669                 var out = [];
670                 var length = results.length;
671                 for (var i = 0; i < length; ++i) {
672                     if (results[i].id > -1) {
673                         var obj = searchIndex[results[i].id];
674                         obj.lev = results[i].lev;
675                         if (isType !== true || obj.type) {
676                             var res = buildHrefAndPath(obj);
677                             obj.displayPath = pathSplitter(res[0]);
678                             obj.fullPath = obj.displayPath + obj.name;
679                             // To be sure than it some items aren't considered as duplicate.
680                             obj.fullPath += "|" + obj.ty;
681                             obj.href = res[1];
682                             out.push(obj);
683                             if (out.length >= MAX_RESULTS) {
684                                 break;
685                             }
686                         }
687                     }
688                 }
689                 return out;
690             }
691
692             function sortResults(results, isType) {
693                 var ar = [];
694                 for (var entry in results) {
695                     if (hasOwnProperty(results, entry)) {
696                         ar.push(results[entry]);
697                     }
698                 }
699                 results = ar;
700                 var i;
701                 var nresults = results.length;
702                 for (i = 0; i < nresults; ++i) {
703                     results[i].word = searchWords[results[i].id];
704                     results[i].item = searchIndex[results[i].id] || {};
705                 }
706                 // if there are no results then return to default and fail
707                 if (results.length === 0) {
708                     return [];
709                 }
710
711                 results.sort(function(aaa, bbb) {
712                     var a, b;
713
714                     // sort by exact match with regard to the last word (mismatch goes later)
715                     a = (aaa.word !== val);
716                     b = (bbb.word !== val);
717                     if (a !== b) { return a - b; }
718
719                     // Sort by non levenshtein results and then levenshtein results by the distance
720                     // (less changes required to match means higher rankings)
721                     a = (aaa.lev);
722                     b = (bbb.lev);
723                     if (a !== b) { return a - b; }
724
725                     // sort by crate (non-current crate goes later)
726                     a = (aaa.item.crate !== window.currentCrate);
727                     b = (bbb.item.crate !== window.currentCrate);
728                     if (a !== b) { return a - b; }
729
730                     // sort by item name length (longer goes later)
731                     a = aaa.word.length;
732                     b = bbb.word.length;
733                     if (a !== b) { return a - b; }
734
735                     // sort by item name (lexicographically larger goes later)
736                     a = aaa.word;
737                     b = bbb.word;
738                     if (a !== b) { return (a > b ? +1 : -1); }
739
740                     // sort by index of keyword in item name (no literal occurrence goes later)
741                     a = (aaa.index < 0);
742                     b = (bbb.index < 0);
743                     if (a !== b) { return a - b; }
744                     // (later literal occurrence, if any, goes later)
745                     a = aaa.index;
746                     b = bbb.index;
747                     if (a !== b) { return a - b; }
748
749                     // special precedence for primitive and keyword pages
750                     if ((aaa.item.ty === TY_PRIMITIVE && bbb.item.ty !== TY_KEYWORD) ||
751                         (aaa.item.ty === TY_KEYWORD && bbb.item.ty !== TY_PRIMITIVE)) {
752                         return -1;
753                     }
754                     if ((bbb.item.ty === TY_PRIMITIVE && aaa.item.ty !== TY_PRIMITIVE) ||
755                         (bbb.item.ty === TY_KEYWORD && aaa.item.ty !== TY_KEYWORD)) {
756                         return 1;
757                     }
758
759                     // sort by description (no description goes later)
760                     a = (aaa.item.desc === "");
761                     b = (bbb.item.desc === "");
762                     if (a !== b) { return a - b; }
763
764                     // sort by type (later occurrence in `itemTypes` goes later)
765                     a = aaa.item.ty;
766                     b = bbb.item.ty;
767                     if (a !== b) { return a - b; }
768
769                     // sort by path (lexicographically larger goes later)
770                     a = aaa.item.path;
771                     b = bbb.item.path;
772                     if (a !== b) { return (a > b ? +1 : -1); }
773
774                     // que sera, sera
775                     return 0;
776                 });
777
778                 var length = results.length;
779                 for (i = 0; i < length; ++i) {
780                     var result = results[i];
781
782                     // this validation does not make sense when searching by types
783                     if (result.dontValidate) {
784                         continue;
785                     }
786                     var name = result.item.name.toLowerCase(),
787                         path = result.item.path.toLowerCase(),
788                         parent = result.item.parent;
789
790                     if (isType !== true &&
791                         validateResult(name, path, split, parent) === false)
792                     {
793                         result.id = -1;
794                     }
795                 }
796                 return transformResults(results);
797             }
798
799             function extractGenerics(val) {
800                 val = val.toLowerCase();
801                 if (val.indexOf("<") !== -1) {
802                     var values = val.substring(val.indexOf("<") + 1, val.lastIndexOf(">"));
803                     return {
804                         name: val.substring(0, val.indexOf("<")),
805                         generics: values.split(/\s*,\s*/),
806                     };
807                 }
808                 return {
809                     name: val,
810                     generics: [],
811                 };
812             }
813
814             function getObjectFromId(id) {
815                 if (typeof id === "number") {
816                     return searchIndex[id];
817                 }
818                 return {'name': id};
819             }
820
821             function checkGenerics(obj, val) {
822                 // The names match, but we need to be sure that all generics kinda
823                 // match as well.
824                 var lev_distance = MAX_LEV_DISTANCE + 1;
825                 if (val.generics.length > 0) {
826                     if (obj.length > GENERICS_DATA &&
827                           obj[GENERICS_DATA].length >= val.generics.length) {
828                         var elems = obj[GENERICS_DATA].slice(0);
829                         var total = 0;
830                         var done = 0;
831                         // We need to find the type that matches the most to remove it in order
832                         // to move forward.
833                         var vlength = val.generics.length;
834                         for (var y = 0; y < vlength; ++y) {
835                             var lev = { pos: -1, lev: MAX_LEV_DISTANCE + 1};
836                             var elength = elems.length;
837                             var firstGeneric = getObjectFromId(val.generics[y]).name;
838                             for (var x = 0; x < elength; ++x) {
839                                 var tmp_lev = levenshtein(getObjectFromId(elems[x]).name,
840                                                           firstGeneric);
841                                 if (tmp_lev < lev.lev) {
842                                     lev.lev = tmp_lev;
843                                     lev.pos = x;
844                                 }
845                             }
846                             if (lev.pos !== -1) {
847                                 elems.splice(lev.pos, 1);
848                                 lev_distance = Math.min(lev.lev, lev_distance);
849                                 total += lev.lev;
850                                 done += 1;
851                             } else {
852                                 return MAX_LEV_DISTANCE + 1;
853                             }
854                         }
855                         return Math.ceil(total / done);
856                     }
857                 }
858                 return MAX_LEV_DISTANCE + 1;
859             }
860
861             // Check for type name and type generics (if any).
862             function checkType(obj, val, literalSearch) {
863                 var lev_distance = MAX_LEV_DISTANCE + 1;
864                 var x;
865                 if (obj[NAME] === val.name) {
866                     if (literalSearch === true) {
867                         if (val.generics && val.generics.length !== 0) {
868                             if (obj.length > GENERICS_DATA &&
869                                   obj[GENERICS_DATA].length >= val.generics.length) {
870                                 var elems = obj[GENERICS_DATA].slice(0);
871                                 var allFound = true;
872
873                                 for (var y = 0; allFound === true && y < val.generics.length; ++y) {
874                                     allFound = false;
875                                     var firstGeneric = getObjectFromId(val.generics[y]).name;
876                                     for (x = 0; allFound === false && x < elems.length; ++x) {
877                                         allFound = getObjectFromId(elems[x]).name === firstGeneric;
878                                     }
879                                     if (allFound === true) {
880                                         elems.splice(x - 1, 1);
881                                     }
882                                 }
883                                 if (allFound === true) {
884                                     return true;
885                                 }
886                             } else {
887                                 return false;
888                             }
889                         }
890                         return true;
891                     }
892                     // If the type has generics but don't match, then it won't return at this point.
893                     // Otherwise, `checkGenerics` will return 0 and it'll return.
894                     if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length !== 0) {
895                         var tmp_lev = checkGenerics(obj, val);
896                         if (tmp_lev <= MAX_LEV_DISTANCE) {
897                             return tmp_lev;
898                         }
899                     } else {
900                         return 0;
901                     }
902                 }
903                 // Names didn't match so let's check if one of the generic types could.
904                 if (literalSearch === true) {
905                      if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
906                         var length = obj[GENERICS_DATA].length;
907                         for (x = 0; x < length; ++x) {
908                             if (obj[GENERICS_DATA][x] === val.name) {
909                                 return true;
910                             }
911                         }
912                     }
913                     return false;
914                 }
915                 lev_distance = Math.min(levenshtein(obj[NAME], val.name), lev_distance);
916                 if (lev_distance <= MAX_LEV_DISTANCE) {
917                     // The generics didn't match but the name kinda did so we give it
918                     // a levenshtein distance value that isn't *this* good so it goes
919                     // into the search results but not too high.
920                     lev_distance = Math.ceil((checkGenerics(obj, val) + lev_distance) / 2);
921                 } else if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
922                     // We can check if the type we're looking for is inside the generics!
923                     var olength = obj[GENERICS_DATA].length;
924                     for (x = 0; x < olength; ++x) {
925                         lev_distance = Math.min(levenshtein(obj[GENERICS_DATA][x], val.name),
926                                                 lev_distance);
927                     }
928                 }
929                 // Now whatever happens, the returned distance is "less good" so we should mark it
930                 // as such, and so we add 1 to the distance to make it "less good".
931                 return lev_distance + 1;
932             }
933
934             function findArg(obj, val, literalSearch, typeFilter) {
935                 var lev_distance = MAX_LEV_DISTANCE + 1;
936
937                 if (obj && obj.type && obj.type[INPUTS_DATA] && obj.type[INPUTS_DATA].length > 0) {
938                     var length = obj.type[INPUTS_DATA].length;
939                     for (var i = 0; i < length; i++) {
940                         var tmp = obj.type[INPUTS_DATA][i];
941                         if (typePassesFilter(typeFilter, tmp[1]) === false) {
942                             continue;
943                         }
944                         tmp = checkType(tmp, val, literalSearch);
945                         if (literalSearch === true) {
946                             if (tmp === true) {
947                                 return true;
948                             }
949                             continue;
950                         }
951                         lev_distance = Math.min(tmp, lev_distance);
952                         if (lev_distance === 0) {
953                             return 0;
954                         }
955                     }
956                 }
957                 return literalSearch === true ? false : lev_distance;
958             }
959
960             function checkReturned(obj, val, literalSearch, typeFilter) {
961                 var lev_distance = MAX_LEV_DISTANCE + 1;
962
963                 if (obj && obj.type && obj.type.length > OUTPUT_DATA) {
964                     var ret = obj.type[OUTPUT_DATA];
965                     if (typeof ret[0] === "string") {
966                         ret = [ret];
967                     }
968                     for (var x = 0; x < ret.length; ++x) {
969                         var tmp = ret[x];
970                         if (typePassesFilter(typeFilter, tmp[1]) === false) {
971                             continue;
972                         }
973                         tmp = checkType(tmp, val, literalSearch);
974                         if (literalSearch === true) {
975                             if (tmp === true) {
976                                 return true;
977                             }
978                             continue;
979                         }
980                         lev_distance = Math.min(tmp, lev_distance);
981                         if (lev_distance === 0) {
982                             return 0;
983                         }
984                     }
985                 }
986                 return literalSearch === true ? false : lev_distance;
987             }
988
989             function checkPath(contains, lastElem, ty) {
990                 if (contains.length === 0) {
991                     return 0;
992                 }
993                 var ret_lev = MAX_LEV_DISTANCE + 1;
994                 var path = ty.path.split("::");
995
996                 if (ty.parent && ty.parent.name) {
997                     path.push(ty.parent.name.toLowerCase());
998                 }
999
1000                 var length = path.length;
1001                 var clength = contains.length;
1002                 if (clength > length) {
1003                     return MAX_LEV_DISTANCE + 1;
1004                 }
1005                 for (var i = 0; i < length; ++i) {
1006                     if (i + clength > length) {
1007                         break;
1008                     }
1009                     var lev_total = 0;
1010                     var aborted = false;
1011                     for (var x = 0; x < clength; ++x) {
1012                         var lev = levenshtein(path[i + x], contains[x]);
1013                         if (lev > MAX_LEV_DISTANCE) {
1014                             aborted = true;
1015                             break;
1016                         }
1017                         lev_total += lev;
1018                     }
1019                     if (aborted === false) {
1020                         ret_lev = Math.min(ret_lev, Math.round(lev_total / clength));
1021                     }
1022                 }
1023                 return ret_lev;
1024             }
1025
1026             function typePassesFilter(filter, type) {
1027                 // No filter
1028                 if (filter <= NO_TYPE_FILTER) return true;
1029
1030                 // Exact match
1031                 if (filter === type) return true;
1032
1033                 // Match related items
1034                 var name = itemTypes[type];
1035                 switch (itemTypes[filter]) {
1036                     case "constant":
1037                         return name === "associatedconstant";
1038                     case "fn":
1039                         return name === "method" || name === "tymethod";
1040                     case "type":
1041                         return name === "primitive" || name === "associatedtype";
1042                     case "trait":
1043                         return name === "traitalias";
1044                 }
1045
1046                 // No match
1047                 return false;
1048             }
1049
1050             function generateId(ty) {
1051                 if (ty.parent && ty.parent.name) {
1052                     return itemTypes[ty.ty] + ty.path + ty.parent.name + ty.name;
1053                 }
1054                 return itemTypes[ty.ty] + ty.path + ty.name;
1055             }
1056
1057             function createAliasFromItem(item) {
1058                 return {
1059                     crate: item.crate,
1060                     name: item.name,
1061                     path: item.path,
1062                     desc: item.desc,
1063                     ty: item.ty,
1064                     parent: item.parent,
1065                     type: item.type,
1066                     is_alias: true,
1067                 };
1068             }
1069
1070             function handleAliases(ret, query, filterCrates) {
1071                 // We separate aliases and crate aliases because we want to have current crate
1072                 // aliases to be before the others in the displayed results.
1073                 var aliases = [];
1074                 var crateAliases = [];
1075                 var i;
1076                 if (filterCrates !== undefined) {
1077                     if (ALIASES[filterCrates] && ALIASES[filterCrates][query.search]) {
1078                         for (i = 0; i < ALIASES[filterCrates][query.search].length; ++i) {
1079                             aliases.push(
1080                                 createAliasFromItem(
1081                                     searchIndex[ALIASES[filterCrates][query.search][i]]));
1082                         }
1083                     }
1084                 } else {
1085                     Object.keys(ALIASES).forEach(function(crate) {
1086                         if (ALIASES[crate][query.search]) {
1087                             var pushTo = crate === window.currentCrate ? crateAliases : aliases;
1088                             for (i = 0; i < ALIASES[crate][query.search].length; ++i) {
1089                                 pushTo.push(
1090                                     createAliasFromItem(
1091                                         searchIndex[ALIASES[crate][query.search][i]]));
1092                             }
1093                         }
1094                     });
1095                 }
1096
1097                 var sortFunc = function(aaa, bbb) {
1098                     if (aaa.path < bbb.path) {
1099                         return 1;
1100                     } else if (aaa.path === bbb.path) {
1101                         return 0;
1102                     }
1103                     return -1;
1104                 };
1105                 crateAliases.sort(sortFunc);
1106                 aliases.sort(sortFunc);
1107
1108                 var pushFunc = function(alias) {
1109                     alias.alias = query.raw;
1110                     var res = buildHrefAndPath(alias);
1111                     alias.displayPath = pathSplitter(res[0]);
1112                     alias.fullPath = alias.displayPath + alias.name;
1113                     alias.href = res[1];
1114
1115                     ret.others.unshift(alias);
1116                     if (ret.others.length > MAX_RESULTS) {
1117                         ret.others.pop();
1118                     }
1119                 };
1120                 onEach(aliases, pushFunc);
1121                 onEach(crateAliases, pushFunc);
1122             }
1123
1124             // quoted values mean literal search
1125             var nSearchWords = searchWords.length;
1126             var i;
1127             var ty;
1128             var fullId;
1129             var returned;
1130             var in_args;
1131             if ((val.charAt(0) === "\"" || val.charAt(0) === "'") &&
1132                 val.charAt(val.length - 1) === val.charAt(0))
1133             {
1134                 val = extractGenerics(val.substr(1, val.length - 2));
1135                 for (i = 0; i < nSearchWords; ++i) {
1136                     if (filterCrates !== undefined && searchIndex[i].crate !== filterCrates) {
1137                         continue;
1138                     }
1139                     in_args = findArg(searchIndex[i], val, true, typeFilter);
1140                     returned = checkReturned(searchIndex[i], val, true, typeFilter);
1141                     ty = searchIndex[i];
1142                     fullId = generateId(ty);
1143
1144                     if (searchWords[i] === val.name
1145                         && typePassesFilter(typeFilter, searchIndex[i].ty)
1146                         && results[fullId] === undefined) {
1147                         results[fullId] = {
1148                             id: i,
1149                             index: -1,
1150                             dontValidate: true,
1151                         };
1152                     }
1153                     if (in_args === true && results_in_args[fullId] === undefined) {
1154                         results_in_args[fullId] = {
1155                             id: i,
1156                             index: -1,
1157                             dontValidate: true,
1158                         };
1159                     }
1160                     if (returned === true && results_returned[fullId] === undefined) {
1161                         results_returned[fullId] = {
1162                             id: i,
1163                             index: -1,
1164                             dontValidate: true,
1165                         };
1166                     }
1167                 }
1168                 query.inputs = [val];
1169                 query.output = val;
1170                 query.search = val;
1171             // searching by type
1172             } else if (val.search("->") > -1) {
1173                 var trimmer = function(s) { return s.trim(); };
1174                 var parts = val.split("->").map(trimmer);
1175                 var input = parts[0];
1176                 // sort inputs so that order does not matter
1177                 var inputs = input.split(",").map(trimmer).sort();
1178                 for (i = 0; i < inputs.length; ++i) {
1179                     inputs[i] = extractGenerics(inputs[i]);
1180                 }
1181                 var output = extractGenerics(parts[1]);
1182
1183                 for (i = 0; i < nSearchWords; ++i) {
1184                     if (filterCrates !== undefined && searchIndex[i].crate !== filterCrates) {
1185                         continue;
1186                     }
1187                     var type = searchIndex[i].type;
1188                     ty = searchIndex[i];
1189                     if (!type) {
1190                         continue;
1191                     }
1192                     fullId = generateId(ty);
1193
1194                     returned = checkReturned(ty, output, true, NO_TYPE_FILTER);
1195                     if (output.name === "*" || returned === true) {
1196                         in_args = false;
1197                         var is_module = false;
1198
1199                         if (input === "*") {
1200                             is_module = true;
1201                         } else {
1202                             var allFound = true;
1203                             for (var it = 0; allFound === true && it < inputs.length; it++) {
1204                                 allFound = checkType(type, inputs[it], true);
1205                             }
1206                             in_args = allFound;
1207                         }
1208                         if (in_args === true) {
1209                             results_in_args[fullId] = {
1210                                 id: i,
1211                                 index: -1,
1212                                 dontValidate: true,
1213                             };
1214                         }
1215                         if (returned === true) {
1216                             results_returned[fullId] = {
1217                                 id: i,
1218                                 index: -1,
1219                                 dontValidate: true,
1220                             };
1221                         }
1222                         if (is_module === true) {
1223                             results[fullId] = {
1224                                 id: i,
1225                                 index: -1,
1226                                 dontValidate: true,
1227                             };
1228                         }
1229                     }
1230                 }
1231                 query.inputs = inputs.map(function(input) {
1232                     return input.name;
1233                 });
1234                 query.output = output.name;
1235             } else {
1236                 query.inputs = [val];
1237                 query.output = val;
1238                 query.search = val;
1239                 // gather matching search results up to a certain maximum
1240                 val = val.replace(/\_/g, "");
1241
1242                 var valGenerics = extractGenerics(val);
1243
1244                 var paths = valLower.split("::");
1245                 var j;
1246                 for (j = 0; j < paths.length; ++j) {
1247                     if (paths[j] === "") {
1248                         paths.splice(j, 1);
1249                         j -= 1;
1250                     }
1251                 }
1252                 val = paths[paths.length - 1];
1253                 var contains = paths.slice(0, paths.length > 1 ? paths.length - 1 : 1);
1254
1255                 var lev;
1256                 for (j = 0; j < nSearchWords; ++j) {
1257                     ty = searchIndex[j];
1258                     if (!ty || (filterCrates !== undefined && ty.crate !== filterCrates)) {
1259                         continue;
1260                     }
1261                     var lev_add = 0;
1262                     if (paths.length > 1) {
1263                         lev = checkPath(contains, paths[paths.length - 1], ty);
1264                         if (lev > MAX_LEV_DISTANCE) {
1265                             continue;
1266                         } else if (lev > 0) {
1267                             lev_add = lev / 10;
1268                         }
1269                     }
1270
1271                     returned = MAX_LEV_DISTANCE + 1;
1272                     in_args = MAX_LEV_DISTANCE + 1;
1273                     var index = -1;
1274                     // we want lev results to go lower than others
1275                     lev = MAX_LEV_DISTANCE + 1;
1276                     fullId = generateId(ty);
1277
1278                     if (searchWords[j].indexOf(split[i]) > -1 ||
1279                         searchWords[j].indexOf(val) > -1 ||
1280                         searchWords[j].replace(/_/g, "").indexOf(val) > -1)
1281                     {
1282                         // filter type: ... queries
1283                         if (typePassesFilter(typeFilter, ty.ty) && results[fullId] === undefined) {
1284                             index = searchWords[j].replace(/_/g, "").indexOf(val);
1285                         }
1286                     }
1287                     if ((lev = levenshtein(searchWords[j], val)) <= MAX_LEV_DISTANCE) {
1288                         if (typePassesFilter(typeFilter, ty.ty) === false) {
1289                             lev = MAX_LEV_DISTANCE + 1;
1290                         } else {
1291                             lev += 1;
1292                         }
1293                     }
1294                     in_args = findArg(ty, valGenerics, false, typeFilter);
1295                     returned = checkReturned(ty, valGenerics, false, typeFilter);
1296
1297                     lev += lev_add;
1298                     if (lev > 0 && val.length > 3 && searchWords[j].indexOf(val) > -1) {
1299                         if (val.length < 6) {
1300                             lev -= 1;
1301                         } else {
1302                             lev = 0;
1303                         }
1304                     }
1305                     if (in_args <= MAX_LEV_DISTANCE) {
1306                         if (results_in_args[fullId] === undefined) {
1307                             results_in_args[fullId] = {
1308                                 id: j,
1309                                 index: index,
1310                                 lev: in_args,
1311                             };
1312                         }
1313                         results_in_args[fullId].lev =
1314                             Math.min(results_in_args[fullId].lev, in_args);
1315                     }
1316                     if (returned <= MAX_LEV_DISTANCE) {
1317                         if (results_returned[fullId] === undefined) {
1318                             results_returned[fullId] = {
1319                                 id: j,
1320                                 index: index,
1321                                 lev: returned,
1322                             };
1323                         }
1324                         results_returned[fullId].lev =
1325                             Math.min(results_returned[fullId].lev, returned);
1326                     }
1327                     if (index !== -1 || lev <= MAX_LEV_DISTANCE) {
1328                         if (index !== -1 && paths.length < 2) {
1329                             lev = 0;
1330                         }
1331                         if (results[fullId] === undefined) {
1332                             results[fullId] = {
1333                                 id: j,
1334                                 index: index,
1335                                 lev: lev,
1336                             };
1337                         }
1338                         results[fullId].lev = Math.min(results[fullId].lev, lev);
1339                     }
1340                 }
1341             }
1342
1343             var ret = {
1344                 "in_args": sortResults(results_in_args, true),
1345                 "returned": sortResults(results_returned, true),
1346                 "others": sortResults(results),
1347             };
1348             handleAliases(ret, query, filterCrates);
1349             return ret;
1350         }
1351
1352         /**
1353          * Validate performs the following boolean logic. For example:
1354          * "File::open" will give IF A PARENT EXISTS => ("file" && "open")
1355          * exists in (name || path || parent) OR => ("file" && "open") exists in
1356          * (name || path )
1357          *
1358          * This could be written functionally, but I wanted to minimise
1359          * functions on stack.
1360          *
1361          * @param  {[string]} name   [The name of the result]
1362          * @param  {[string]} path   [The path of the result]
1363          * @param  {[string]} keys   [The keys to be used (["file", "open"])]
1364          * @param  {[object]} parent [The parent of the result]
1365          * @return {[boolean]}       [Whether the result is valid or not]
1366          */
1367         function validateResult(name, path, keys, parent) {
1368             for (var i = 0; i < keys.length; ++i) {
1369                 // each check is for validation so we negate the conditions and invalidate
1370                 if (!(
1371                     // check for an exact name match
1372                     name.indexOf(keys[i]) > -1 ||
1373                     // then an exact path match
1374                     path.indexOf(keys[i]) > -1 ||
1375                     // next if there is a parent, check for exact parent match
1376                     (parent !== undefined && parent.name !== undefined &&
1377                         parent.name.toLowerCase().indexOf(keys[i]) > -1) ||
1378                     // lastly check to see if the name was a levenshtein match
1379                     levenshtein(name, keys[i]) <= MAX_LEV_DISTANCE)) {
1380                     return false;
1381                 }
1382             }
1383             return true;
1384         }
1385
1386         function getQuery(raw) {
1387             var matches, type, query;
1388             query = raw;
1389
1390             matches = query.match(/^(fn|mod|struct|enum|trait|type|const|macro)\s*:\s*/i);
1391             if (matches) {
1392                 type = matches[1].replace(/^const$/, "constant");
1393                 query = query.substring(matches[0].length);
1394             }
1395
1396             return {
1397                 raw: raw,
1398                 query: query,
1399                 type: type,
1400                 id: query + type
1401             };
1402         }
1403
1404         function initSearchNav() {
1405             var hoverTimeout;
1406
1407             var click_func = function(e) {
1408                 var el = e.target;
1409                 // to retrieve the real "owner" of the event.
1410                 while (el.tagName !== "TR") {
1411                     el = el.parentNode;
1412                 }
1413                 var dst = e.target.getElementsByTagName("a");
1414                 if (dst.length < 1) {
1415                     return;
1416                 }
1417                 dst = dst[0];
1418                 if (window.location.pathname === dst.pathname) {
1419                     hideSearchResults();
1420                     document.location.href = dst.href;
1421                 }
1422             };
1423             var mouseover_func = function(e) {
1424                 if (mouseMovedAfterSearch) {
1425                     var el = e.target;
1426                     // to retrieve the real "owner" of the event.
1427                     while (el.tagName !== "TR") {
1428                         el = el.parentNode;
1429                     }
1430                     clearTimeout(hoverTimeout);
1431                     hoverTimeout = setTimeout(function() {
1432                         onEachLazy(document.getElementsByClassName("search-results"), function(e) {
1433                             onEachLazy(e.getElementsByClassName("result"), function(i_e) {
1434                                 removeClass(i_e, "highlighted");
1435                             });
1436                         });
1437                         addClass(el, "highlighted");
1438                     }, 20);
1439                 }
1440             };
1441             onEachLazy(document.getElementsByClassName("search-results"), function(e) {
1442                 onEachLazy(e.getElementsByClassName("result"), function(i_e) {
1443                     i_e.onclick = click_func;
1444                     i_e.onmouseover = mouseover_func;
1445                 });
1446             });
1447
1448             search_input.onkeydown = function(e) {
1449                 // "actives" references the currently highlighted item in each search tab.
1450                 // Each array in "actives" represents a tab.
1451                 var actives = [[], [], []];
1452                 // "current" is used to know which tab we're looking into.
1453                 var current = 0;
1454                 onEachLazy(document.getElementById("results").childNodes, function(e) {
1455                     onEachLazy(e.getElementsByClassName("highlighted"), function(h_e) {
1456                         actives[current].push(h_e);
1457                     });
1458                     current += 1;
1459                 });
1460
1461                 if (e.which === 38) { // up
1462                     if (e.ctrlKey) { // Going through result tabs.
1463                         printTab(currentTab > 0 ? currentTab - 1 : 2);
1464                     } else {
1465                         if (!actives[currentTab].length ||
1466                             !actives[currentTab][0].previousElementSibling) {
1467                             return;
1468                         }
1469                         addClass(actives[currentTab][0].previousElementSibling, "highlighted");
1470                         removeClass(actives[currentTab][0], "highlighted");
1471                     }
1472                     e.preventDefault();
1473                 } else if (e.which === 40) { // down
1474                     if (e.ctrlKey) { // Going through result tabs.
1475                         printTab(currentTab > 1 ? 0 : currentTab + 1);
1476                     } else if (!actives[currentTab].length) {
1477                         var results = document.getElementById("results").childNodes;
1478                         if (results.length > 0) {
1479                             var res = results[currentTab].getElementsByClassName("result");
1480                             if (res.length > 0) {
1481                                 addClass(res[0], "highlighted");
1482                             }
1483                         }
1484                     } else if (actives[currentTab][0].nextElementSibling) {
1485                         addClass(actives[currentTab][0].nextElementSibling, "highlighted");
1486                         removeClass(actives[currentTab][0], "highlighted");
1487                     }
1488                     e.preventDefault();
1489                 } else if (e.which === 13) { // return
1490                     if (actives[currentTab].length) {
1491                         document.location.href =
1492                             actives[currentTab][0].getElementsByTagName("a")[0].href;
1493                     }
1494                 } else if (e.which === 16) { // shift
1495                     // Does nothing, it's just to avoid losing "focus" on the highlighted element.
1496                 } else if (actives[currentTab].length > 0) {
1497                     removeClass(actives[currentTab][0], "highlighted");
1498                 }
1499             };
1500         }
1501
1502         function buildHrefAndPath(item) {
1503             var displayPath;
1504             var href;
1505             var type = itemTypes[item.ty];
1506             var name = item.name;
1507             var path = item.path;
1508
1509             if (type === "mod") {
1510                 displayPath = path + "::";
1511                 href = rootPath + path.replace(/::/g, "/") + "/" +
1512                        name + "/index.html";
1513             } else if (type === "primitive" || type === "keyword") {
1514                 displayPath = "";
1515                 href = rootPath + path.replace(/::/g, "/") +
1516                        "/" + type + "." + name + ".html";
1517             } else if (type === "externcrate") {
1518                 displayPath = "";
1519                 href = rootPath + name + "/index.html";
1520             } else if (item.parent !== undefined) {
1521                 var myparent = item.parent;
1522                 var anchor = "#" + type + "." + name;
1523                 var parentType = itemTypes[myparent.ty];
1524                 var pageType = parentType;
1525                 var pageName = myparent.name;
1526
1527                 if (parentType === "primitive") {
1528                     displayPath = myparent.name + "::";
1529                 } else if (type === "structfield" && parentType === "variant") {
1530                     // Structfields belonging to variants are special: the
1531                     // final path element is the enum name.
1532                     var splitPath = item.path.split("::");
1533                     var enumName = splitPath.pop();
1534                     path = splitPath.join("::");
1535                     displayPath = path + "::" + enumName + "::" + myparent.name + "::";
1536                     anchor = "#variant." + myparent.name + ".field." + name;
1537                     pageType = "enum";
1538                     pageName = enumName;
1539                 } else {
1540                     displayPath = path + "::" + myparent.name + "::";
1541                 }
1542                 href = rootPath + path.replace(/::/g, "/") +
1543                        "/" + pageType +
1544                        "." + pageName +
1545                        ".html" + anchor;
1546             } else {
1547                 displayPath = item.path + "::";
1548                 href = rootPath + item.path.replace(/::/g, "/") +
1549                        "/" + type + "." + name + ".html";
1550             }
1551             return [displayPath, href];
1552         }
1553
1554         function escape(content) {
1555             var h1 = document.createElement("h1");
1556             h1.textContent = content;
1557             return h1.innerHTML;
1558         }
1559
1560         function pathSplitter(path) {
1561             var tmp = "<span>" + path.replace(/::/g, "::</span><span>");
1562             if (tmp.endsWith("<span>")) {
1563                 return tmp.slice(0, tmp.length - 6);
1564             }
1565             return tmp;
1566         }
1567
1568         function addTab(array, query, display) {
1569             var extraStyle = "";
1570             if (display === false) {
1571                 extraStyle = " style=\"display: none;\"";
1572             }
1573
1574             var output = "";
1575             var duplicates = {};
1576             var length = 0;
1577             if (array.length > 0) {
1578                 output = "<table class=\"search-results\"" + extraStyle + ">";
1579
1580                 array.forEach(function(item) {
1581                     var name, type;
1582
1583                     name = item.name;
1584                     type = itemTypes[item.ty];
1585
1586                     if (item.is_alias !== true) {
1587                         if (duplicates[item.fullPath]) {
1588                             return;
1589                         }
1590                         duplicates[item.fullPath] = true;
1591                     }
1592                     length += 1;
1593
1594                     output += "<tr class=\"" + type + " result\"><td>" +
1595                               "<a href=\"" + item.href + "\">" +
1596                               (item.is_alias === true ?
1597                                ("<span class=\"alias\"><b>" + item.alias + " </b></span><span " +
1598                                   "class=\"grey\"><i>&nbsp;- see&nbsp;</i></span>") : "") +
1599                               item.displayPath + "<span class=\"" + type + "\">" +
1600                               name + "</span></a></td><td>" +
1601                               "<a href=\"" + item.href + "\">" +
1602                               "<span class=\"desc\">" + item.desc +
1603                               "&nbsp;</span></a></td></tr>";
1604                 });
1605                 output += "</table>";
1606             } else {
1607                 output = "<div class=\"search-failed\"" + extraStyle + ">No results :(<br/>" +
1608                     "Try on <a href=\"https://duckduckgo.com/?q=" +
1609                     encodeURIComponent("rust " + query.query) +
1610                     "\">DuckDuckGo</a>?<br/><br/>" +
1611                     "Or try looking in one of these:<ul><li>The <a " +
1612                     "href=\"https://doc.rust-lang.org/reference/index.html\">Rust Reference</a> " +
1613                     " for technical details about the language.</li><li><a " +
1614                     "href=\"https://doc.rust-lang.org/rust-by-example/index.html\">Rust By " +
1615                     "Example</a> for expository code examples.</a></li><li>The <a " +
1616                     "href=\"https://doc.rust-lang.org/book/index.html\">Rust Book</a> for " +
1617                     "introductions to language features and the language itself.</li><li><a " +
1618                     "href=\"https://docs.rs\">Docs.rs</a> for documentation of crates released on" +
1619                     " <a href=\"https://crates.io/\">crates.io</a>.</li></ul></div>";
1620             }
1621             return [output, length];
1622         }
1623
1624         function makeTabHeader(tabNb, text, nbElems) {
1625             if (currentTab === tabNb) {
1626                 return "<button class=\"selected\">" + text +
1627                        " <div class=\"count\">(" + nbElems + ")</div></button>";
1628             }
1629             return "<button>" + text + " <div class=\"count\">(" + nbElems + ")</div></button>";
1630         }
1631
1632         function showResults(results) {
1633             var search = getSearchElement();
1634             if (results.others.length === 1
1635                 && getSettingValue("go-to-only-result") === "true"
1636                 // By default, the search DOM element is "empty" (meaning it has no children not
1637                 // text content). Once a search has been run, it won't be empty, even if you press
1638                 // ESC or empty the search input (which also "cancels" the search).
1639                 && (!search.firstChild || search.firstChild.innerText !== getSearchLoadingText()))
1640             {
1641                 var elem = document.createElement("a");
1642                 elem.href = results.others[0].href;
1643                 elem.style.display = "none";
1644                 // For firefox, we need the element to be in the DOM so it can be clicked.
1645                 document.body.appendChild(elem);
1646                 elem.click();
1647                 return;
1648             }
1649             var query = getQuery(search_input.value);
1650
1651             currentResults = query.id;
1652
1653             var ret_others = addTab(results.others, query);
1654             var ret_in_args = addTab(results.in_args, query, false);
1655             var ret_returned = addTab(results.returned, query, false);
1656
1657             var output = "<h1>Results for " + escape(query.query) +
1658                 (query.type ? " (type: " + escape(query.type) + ")" : "") + "</h1>" +
1659                 "<div id=\"titles\">" +
1660                 makeTabHeader(0, "In Names", ret_others[1]) +
1661                 makeTabHeader(1, "In Parameters", ret_in_args[1]) +
1662                 makeTabHeader(2, "In Return Types", ret_returned[1]) +
1663                 "</div><div id=\"results\">" +
1664                 ret_others[0] + ret_in_args[0] + ret_returned[0] + "</div>";
1665
1666             search.innerHTML = output;
1667             showSearchResults(search);
1668             var tds = search.getElementsByTagName("td");
1669             var td_width = 0;
1670             if (tds.length > 0) {
1671                 td_width = tds[0].offsetWidth;
1672             }
1673             var width = search.offsetWidth - 40 - td_width;
1674             onEachLazy(search.getElementsByClassName("desc"), function(e) {
1675                 e.style.width = width + "px";
1676             });
1677             initSearchNav();
1678             var elems = document.getElementById("titles").childNodes;
1679             elems[0].onclick = function() { printTab(0); };
1680             elems[1].onclick = function() { printTab(1); };
1681             elems[2].onclick = function() { printTab(2); };
1682             printTab(currentTab);
1683         }
1684
1685         function execSearch(query, searchWords, filterCrates) {
1686             function getSmallest(arrays, positions, notDuplicates) {
1687                 var start = null;
1688
1689                 for (var it = 0; it < positions.length; ++it) {
1690                     if (arrays[it].length > positions[it] &&
1691                         (start === null || start > arrays[it][positions[it]].lev) &&
1692                         !notDuplicates[arrays[it][positions[it]].fullPath]) {
1693                         start = arrays[it][positions[it]].lev;
1694                     }
1695                 }
1696                 return start;
1697             }
1698
1699             function mergeArrays(arrays) {
1700                 var ret = [];
1701                 var positions = [];
1702                 var notDuplicates = {};
1703
1704                 for (var x = 0; x < arrays.length; ++x) {
1705                     positions.push(0);
1706                 }
1707                 while (ret.length < MAX_RESULTS) {
1708                     var smallest = getSmallest(arrays, positions, notDuplicates);
1709
1710                     if (smallest === null) {
1711                         break;
1712                     }
1713                     for (x = 0; x < arrays.length && ret.length < MAX_RESULTS; ++x) {
1714                         if (arrays[x].length > positions[x] &&
1715                                 arrays[x][positions[x]].lev === smallest &&
1716                                 !notDuplicates[arrays[x][positions[x]].fullPath]) {
1717                             ret.push(arrays[x][positions[x]]);
1718                             notDuplicates[arrays[x][positions[x]].fullPath] = true;
1719                             positions[x] += 1;
1720                         }
1721                     }
1722                 }
1723                 return ret;
1724             }
1725
1726             var queries = query.raw.split(",");
1727             var results = {
1728                 "in_args": [],
1729                 "returned": [],
1730                 "others": [],
1731             };
1732
1733             for (var i = 0; i < queries.length; ++i) {
1734                 query = queries[i].trim();
1735                 if (query.length !== 0) {
1736                     var tmp = execQuery(getQuery(query), searchWords, filterCrates);
1737
1738                     results.in_args.push(tmp.in_args);
1739                     results.returned.push(tmp.returned);
1740                     results.others.push(tmp.others);
1741                 }
1742             }
1743             if (queries.length > 1) {
1744                 return {
1745                     "in_args": mergeArrays(results.in_args),
1746                     "returned": mergeArrays(results.returned),
1747                     "others": mergeArrays(results.others),
1748                 };
1749             }
1750             return {
1751                 "in_args": results.in_args[0],
1752                 "returned": results.returned[0],
1753                 "others": results.others[0],
1754             };
1755         }
1756
1757         function getFilterCrates() {
1758             var elem = document.getElementById("crate-search");
1759
1760             if (elem && elem.value !== "All crates" && hasOwnProperty(rawSearchIndex, elem.value)) {
1761                 return elem.value;
1762             }
1763             return undefined;
1764         }
1765
1766         function search(e, forced) {
1767             var params = getQueryStringParams();
1768             var query = getQuery(search_input.value.trim());
1769
1770             if (e) {
1771                 e.preventDefault();
1772             }
1773
1774             if (query.query.length === 0) {
1775                 return;
1776             }
1777             if (forced !== true && query.id === currentResults) {
1778                 if (query.query.length > 0) {
1779                     putBackSearch(search_input);
1780                 }
1781                 return;
1782             }
1783
1784             // Update document title to maintain a meaningful browser history
1785             searchTitle = "Results for " + query.query + " - Rust";
1786
1787             // Because searching is incremental by character, only the most
1788             // recent search query is added to the browser history.
1789             if (browserSupportsHistoryApi()) {
1790                 if (!history.state && !params.search) {
1791                     history.pushState(query, "", "?search=" + encodeURIComponent(query.raw));
1792                 } else {
1793                     history.replaceState(query, "", "?search=" + encodeURIComponent(query.raw));
1794                 }
1795             }
1796
1797             var filterCrates = getFilterCrates();
1798             showResults(execSearch(query, index, filterCrates));
1799         }
1800
1801         function buildIndex(rawSearchIndex) {
1802             searchIndex = [];
1803             var searchWords = [];
1804             var i;
1805             var currentIndex = 0;
1806
1807             for (var crate in rawSearchIndex) {
1808                 if (!hasOwnProperty(rawSearchIndex, crate)) { continue; }
1809
1810                 var crateSize = 0;
1811
1812                 searchWords.push(crate);
1813                 searchIndex.push({
1814                     crate: crate,
1815                     ty: 1, // == ExternCrate
1816                     name: crate,
1817                     path: "",
1818                     desc: rawSearchIndex[crate].doc,
1819                     type: null,
1820                 });
1821                 currentIndex += 1;
1822
1823                 // an array of [(Number) item type,
1824                 //              (String) name,
1825                 //              (String) full path or empty string for previous path,
1826                 //              (String) description,
1827                 //              (Number | null) the parent path index to `paths`]
1828                 //              (Object | null) the type of the function (if any)
1829                 var items = rawSearchIndex[crate].i;
1830                 // an array of [(Number) item type,
1831                 //              (String) name]
1832                 var paths = rawSearchIndex[crate].p;
1833                 // a array of [(String) alias name
1834                 //             [Number] index to items]
1835                 var aliases = rawSearchIndex[crate].a;
1836
1837                 // convert `rawPaths` entries into object form
1838                 var len = paths.length;
1839                 for (i = 0; i < len; ++i) {
1840                     paths[i] = {ty: paths[i][0], name: paths[i][1]};
1841                 }
1842
1843                 // convert `items` into an object form, and construct word indices.
1844                 //
1845                 // before any analysis is performed lets gather the search terms to
1846                 // search against apart from the rest of the data.  This is a quick
1847                 // operation that is cached for the life of the page state so that
1848                 // all other search operations have access to this cached data for
1849                 // faster analysis operations
1850                 len = items.length;
1851                 var lastPath = "";
1852                 for (i = 0; i < len; ++i) {
1853                     var rawRow = items[i];
1854                     if (!rawRow[2]) {
1855                         rawRow[2] = lastPath;
1856                     }
1857                     var row = {
1858                         crate: crate,
1859                         ty: rawRow[0],
1860                         name: rawRow[1],
1861                         path: rawRow[2],
1862                         desc: rawRow[3],
1863                         parent: paths[rawRow[4]],
1864                         type: rawRow[5],
1865                     };
1866                     searchIndex.push(row);
1867                     if (typeof row.name === "string") {
1868                         var word = row.name.toLowerCase();
1869                         searchWords.push(word);
1870                     } else {
1871                         searchWords.push("");
1872                     }
1873                     lastPath = row.path;
1874                     crateSize += 1;
1875                 }
1876
1877                 if (aliases) {
1878                     ALIASES[crate] = {};
1879                     var j, local_aliases;
1880                     for (var alias_name in aliases) {
1881                         if (!aliases.hasOwnProperty(alias_name)) { continue; }
1882
1883                         if (!ALIASES[crate].hasOwnProperty(alias_name)) {
1884                             ALIASES[crate][alias_name] = [];
1885                         }
1886                         local_aliases = aliases[alias_name];
1887                         for (j = 0; j < local_aliases.length; ++j) {
1888                             ALIASES[crate][alias_name].push(local_aliases[j] + currentIndex);
1889                         }
1890                     }
1891                 }
1892                 currentIndex += crateSize;
1893             }
1894             return searchWords;
1895         }
1896
1897         function startSearch() {
1898             var callback = function() {
1899                 clearInputTimeout();
1900                 if (search_input.value.length === 0) {
1901                     if (browserSupportsHistoryApi()) {
1902                         history.replaceState("", window.currentCrate + " - Rust", "?search=");
1903                     }
1904                     hideSearchResults();
1905                 } else {
1906                     searchTimeout = setTimeout(search, 500);
1907                 }
1908             };
1909             search_input.onkeyup = callback;
1910             search_input.oninput = callback;
1911             document.getElementsByClassName("search-form")[0].onsubmit = function(e) {
1912                 e.preventDefault();
1913                 clearInputTimeout();
1914                 search();
1915             };
1916             search_input.onchange = function(e) {
1917                 if (e.target !== document.activeElement) {
1918                     // To prevent doing anything when it's from a blur event.
1919                     return;
1920                 }
1921                 // Do NOT e.preventDefault() here. It will prevent pasting.
1922                 clearInputTimeout();
1923                 // zero-timeout necessary here because at the time of event handler execution the
1924                 // pasted content is not in the input field yet. Shouldn’t make any difference for
1925                 // change, though.
1926                 setTimeout(search, 0);
1927             };
1928             search_input.onpaste = search_input.onchange;
1929
1930             var selectCrate = document.getElementById("crate-search");
1931             if (selectCrate) {
1932                 selectCrate.onchange = function() {
1933                     updateLocalStorage("rustdoc-saved-filter-crate", selectCrate.value);
1934                     search(undefined, true);
1935                 };
1936             }
1937
1938             // Push and pop states are used to add search results to the browser
1939             // history.
1940             if (browserSupportsHistoryApi()) {
1941                 // Store the previous <title> so we can revert back to it later.
1942                 var previousTitle = document.title;
1943
1944                 window.addEventListener("popstate", function(e) {
1945                     var params = getQueryStringParams();
1946                     // Revert to the previous title manually since the History
1947                     // API ignores the title parameter.
1948                     document.title = previousTitle;
1949                     // When browsing forward to search results the previous
1950                     // search will be repeated, so the currentResults are
1951                     // cleared to ensure the search is successful.
1952                     currentResults = null;
1953                     // Synchronize search bar with query string state and
1954                     // perform the search. This will empty the bar if there's
1955                     // nothing there, which lets you really go back to a
1956                     // previous state with nothing in the bar.
1957                     if (params.search && params.search.length > 0) {
1958                         search_input.value = params.search;
1959                         // Some browsers fire "onpopstate" for every page load
1960                         // (Chrome), while others fire the event only when actually
1961                         // popping a state (Firefox), which is why search() is
1962                         // called both here and at the end of the startSearch()
1963                         // function.
1964                         search(e);
1965                     } else {
1966                         search_input.value = "";
1967                         // When browsing back from search results the main page
1968                         // visibility must be reset.
1969                         hideSearchResults();
1970                     }
1971                 });
1972             }
1973             search();
1974         }
1975
1976         index = buildIndex(rawSearchIndex);
1977         startSearch();
1978
1979         // Draw a convenient sidebar of known crates if we have a listing
1980         if (rootPath === "../" || rootPath === "./") {
1981             var sidebar = document.getElementsByClassName("sidebar-elems")[0];
1982             if (sidebar) {
1983                 var div = document.createElement("div");
1984                 div.className = "block crate";
1985                 div.innerHTML = "<h3>Crates</h3>";
1986                 var ul = document.createElement("ul");
1987                 div.appendChild(ul);
1988
1989                 var crates = [];
1990                 for (var crate in rawSearchIndex) {
1991                     if (!hasOwnProperty(rawSearchIndex, crate)) {
1992                         continue;
1993                     }
1994                     crates.push(crate);
1995                 }
1996                 crates.sort();
1997                 for (var i = 0; i < crates.length; ++i) {
1998                     var klass = "crate";
1999                     if (rootPath !== "./" && crates[i] === window.currentCrate) {
2000                         klass += " current";
2001                     }
2002                     var link = document.createElement("a");
2003                     link.href = rootPath + crates[i] + "/index.html";
2004                     // The summary in the search index has HTML, so we need to
2005                     // dynamically render it as plaintext.
2006                     link.title = convertHTMLToPlaintext(rawSearchIndex[crates[i]].doc);
2007                     link.className = klass;
2008                     link.textContent = crates[i];
2009
2010                     var li = document.createElement("li");
2011                     li.appendChild(link);
2012                     ul.appendChild(li);
2013                 }
2014                 sidebar.appendChild(div);
2015             }
2016         }
2017     };
2018
2019     /**
2020      * Convert HTML to plaintext:
2021      *
2022      *   * Replace "<code>foo</code>" with "`foo`"
2023      *   * Strip all other HTML tags
2024      *
2025      * Used by the dynamic sidebar crate list renderer.
2026      *
2027      * @param  {[string]} html [The HTML to convert]
2028      * @return {[string]}      [The resulting plaintext]
2029      */
2030     function convertHTMLToPlaintext(html) {
2031         var x = document.createElement("div");
2032         x.innerHTML = html.replace('<code>', '`').replace('</code>', '`');
2033         return x.innerText;
2034     }
2035
2036
2037     // delayed sidebar rendering.
2038     window.initSidebarItems = function(items) {
2039         var sidebar = document.getElementsByClassName("sidebar-elems")[0];
2040         var current = window.sidebarCurrent;
2041
2042         function block(shortty, longty) {
2043             var filtered = items[shortty];
2044             if (!filtered) {
2045                 return;
2046             }
2047
2048             var div = document.createElement("div");
2049             div.className = "block " + shortty;
2050             var h3 = document.createElement("h3");
2051             h3.textContent = longty;
2052             div.appendChild(h3);
2053             var ul = document.createElement("ul");
2054
2055             var length = filtered.length;
2056             for (var i = 0; i < length; ++i) {
2057                 var item = filtered[i];
2058                 var name = item[0];
2059                 var desc = item[1]; // can be null
2060
2061                 var klass = shortty;
2062                 if (name === current.name && shortty === current.ty) {
2063                     klass += " current";
2064                 }
2065                 var path;
2066                 if (shortty === "mod") {
2067                     path = name + "/index.html";
2068                 } else {
2069                     path = shortty + "." + name + ".html";
2070                 }
2071                 var link = document.createElement("a");
2072                 link.href = current.relpath + path;
2073                 link.title = desc;
2074                 link.className = klass;
2075                 link.textContent = name;
2076                 var li = document.createElement("li");
2077                 li.appendChild(link);
2078                 ul.appendChild(li);
2079             }
2080             div.appendChild(ul);
2081             if (sidebar) {
2082                 sidebar.appendChild(div);
2083             }
2084         }
2085
2086         block("primitive", "Primitive Types");
2087         block("mod", "Modules");
2088         block("macro", "Macros");
2089         block("struct", "Structs");
2090         block("enum", "Enums");
2091         block("union", "Unions");
2092         block("constant", "Constants");
2093         block("static", "Statics");
2094         block("trait", "Traits");
2095         block("fn", "Functions");
2096         block("type", "Type Definitions");
2097         block("foreigntype", "Foreign Types");
2098         block("keyword", "Keywords");
2099         block("traitalias", "Trait Aliases");
2100     };
2101
2102     window.register_implementors = function(imp) {
2103         var implementors = document.getElementById("implementors-list");
2104         var synthetic_implementors = document.getElementById("synthetic-implementors-list");
2105
2106         if (synthetic_implementors) {
2107             // This `inlined_types` variable is used to avoid having the same implementation
2108             // showing up twice. For example "String" in the "Sync" doc page.
2109             //
2110             // By the way, this is only used by and useful for traits implemented automatically
2111             // (like "Send" and "Sync").
2112             var inlined_types = new Set();
2113             onEachLazy(synthetic_implementors.getElementsByClassName("impl"), function(el) {
2114                 var aliases = el.getAttribute("aliases");
2115                 if (!aliases) {
2116                     return;
2117                 }
2118                 aliases.split(",").forEach(function(alias) {
2119                     inlined_types.add(alias);
2120                 });
2121             });
2122         }
2123
2124         var libs = Object.getOwnPropertyNames(imp);
2125         var llength = libs.length;
2126         for (var i = 0; i < llength; ++i) {
2127             if (libs[i] === currentCrate) { continue; }
2128             var structs = imp[libs[i]];
2129
2130             var slength = structs.length;
2131             struct_loop:
2132             for (var j = 0; j < slength; ++j) {
2133                 var struct = structs[j];
2134
2135                 var list = struct.synthetic ? synthetic_implementors : implementors;
2136
2137                 if (struct.synthetic) {
2138                     var stlength = struct.types.length;
2139                     for (var k = 0; k < stlength; k++) {
2140                         if (inlined_types.has(struct.types[k])) {
2141                             continue struct_loop;
2142                         }
2143                         inlined_types.add(struct.types[k]);
2144                     }
2145                 }
2146
2147                 var code = document.createElement("code");
2148                 code.innerHTML = struct.text;
2149
2150                 onEachLazy(code.getElementsByTagName("a"), function(elem) {
2151                     var href = elem.getAttribute("href");
2152
2153                     if (href && href.indexOf("http") !== 0) {
2154                         elem.setAttribute("href", rootPath + href);
2155                     }
2156                 });
2157
2158                 var display = document.createElement("h3");
2159                 addClass(display, "impl");
2160                 display.innerHTML = "<span class=\"in-band\"><table class=\"table-display\">" +
2161                     "<tbody><tr><td><code>" + code.outerHTML + "</code></td><td></td></tr>" +
2162                     "</tbody></table></span>";
2163                 list.appendChild(display);
2164             }
2165         }
2166     };
2167     if (window.pending_implementors) {
2168         window.register_implementors(window.pending_implementors);
2169     }
2170
2171     function labelForToggleButton(sectionIsCollapsed) {
2172         if (sectionIsCollapsed) {
2173             // button will expand the section
2174             return "+";
2175         }
2176         // button will collapse the section
2177         // note that this text is also set in the HTML template in render.rs
2178         return "\u2212"; // "\u2212" is "−" minus sign
2179     }
2180
2181     function onEveryMatchingChild(elem, className, func) {
2182         if (elem && className && func) {
2183             var length = elem.childNodes.length;
2184             var nodes = elem.childNodes;
2185             for (var i = 0; i < length; ++i) {
2186                 if (hasClass(nodes[i], className)) {
2187                     func(nodes[i]);
2188                 } else {
2189                     onEveryMatchingChild(nodes[i], className, func);
2190                 }
2191             }
2192         }
2193     }
2194
2195     function toggleAllDocs(pageId, fromAutoCollapse) {
2196         var innerToggle = document.getElementById(toggleAllDocsId);
2197         if (!innerToggle) {
2198             return;
2199         }
2200         if (hasClass(innerToggle, "will-expand")) {
2201             updateLocalStorage("rustdoc-collapse", "false");
2202             removeClass(innerToggle, "will-expand");
2203             onEveryMatchingChild(innerToggle, "inner", function(e) {
2204                 e.innerHTML = labelForToggleButton(false);
2205             });
2206             innerToggle.title = "collapse all docs";
2207             if (fromAutoCollapse !== true) {
2208                 onEachLazy(document.getElementsByClassName("collapse-toggle"), function(e) {
2209                     collapseDocs(e, "show");
2210                 });
2211             }
2212         } else {
2213             updateLocalStorage("rustdoc-collapse", "true");
2214             addClass(innerToggle, "will-expand");
2215             onEveryMatchingChild(innerToggle, "inner", function(e) {
2216                 var parent = e.parentNode;
2217                 var superParent = null;
2218
2219                 if (parent) {
2220                     superParent = parent.parentNode;
2221                 }
2222                 if (!parent || !superParent || superParent.id !== "main" ||
2223                     hasClass(parent, "impl") === false) {
2224                     e.innerHTML = labelForToggleButton(true);
2225                 }
2226             });
2227             innerToggle.title = "expand all docs";
2228             if (fromAutoCollapse !== true) {
2229                 onEachLazy(document.getElementsByClassName("collapse-toggle"), function(e) {
2230                     var parent = e.parentNode;
2231                     var superParent = null;
2232
2233                     if (parent) {
2234                         superParent = parent.parentNode;
2235                     }
2236                     if (!parent || !superParent || superParent.id !== "main" ||
2237                         hasClass(parent, "impl") === false) {
2238                         collapseDocs(e, "hide", pageId);
2239                     }
2240                 });
2241             }
2242         }
2243     }
2244
2245     function collapseDocs(toggle, mode, pageId) {
2246         if (!toggle || !toggle.parentNode) {
2247             return;
2248         }
2249
2250         function adjustToggle(arg) {
2251             return function(e) {
2252                 if (hasClass(e, "toggle-label")) {
2253                     if (arg) {
2254                         e.style.display = "inline-block";
2255                     } else {
2256                         e.style.display = "none";
2257                     }
2258                 }
2259                 if (hasClass(e, "inner")) {
2260                     e.innerHTML = labelForToggleButton(arg);
2261                 }
2262             };
2263         }
2264
2265         function implHider(addOrRemove, fullHide) {
2266             return function(n) {
2267                 var shouldHide =
2268                     fullHide === true ||
2269                     hasClass(n, "method") === true ||
2270                     hasClass(n, "associatedconstant") === true;
2271                 if (shouldHide === true || hasClass(n, "type") === true) {
2272                     if (shouldHide === true) {
2273                         if (addOrRemove) {
2274                             addClass(n, "hidden-by-impl-hider");
2275                         } else {
2276                             removeClass(n, "hidden-by-impl-hider");
2277                         }
2278                     }
2279                     var ns = n.nextElementSibling;
2280                     while (ns && (hasClass(ns, "docblock") || hasClass(ns, "item-info"))) {
2281                         if (addOrRemove) {
2282                             addClass(ns, "hidden-by-impl-hider");
2283                         } else {
2284                             removeClass(ns, "hidden-by-impl-hider");
2285                         }
2286                         ns = ns.nextElementSibling;
2287                     }
2288                 }
2289             };
2290         }
2291
2292         var relatedDoc;
2293         var action = mode;
2294         if (hasClass(toggle.parentNode, "impl") === false) {
2295             relatedDoc = toggle.parentNode.nextElementSibling;
2296             if (hasClass(relatedDoc, "item-info")) {
2297                 relatedDoc = relatedDoc.nextElementSibling;
2298             }
2299             if (hasClass(relatedDoc, "docblock") || hasClass(relatedDoc, "sub-variant")) {
2300                 if (mode === "toggle") {
2301                     if (hasClass(relatedDoc, "hidden-by-usual-hider")) {
2302                         action = "show";
2303                     } else {
2304                         action = "hide";
2305                     }
2306                 }
2307                 if (action === "hide") {
2308                     addClass(relatedDoc, "hidden-by-usual-hider");
2309                     onEachLazy(toggle.childNodes, adjustToggle(true));
2310                     addClass(toggle.parentNode, "collapsed");
2311                 } else if (action === "show") {
2312                     removeClass(relatedDoc, "hidden-by-usual-hider");
2313                     removeClass(toggle.parentNode, "collapsed");
2314                     onEachLazy(toggle.childNodes, adjustToggle(false));
2315                 }
2316             }
2317         } else {
2318             // we are collapsing the impl block(s).
2319
2320             var parentElem = toggle.parentNode;
2321             relatedDoc = parentElem;
2322             var docblock = relatedDoc.nextElementSibling;
2323
2324             while (hasClass(relatedDoc, "impl-items") === false) {
2325                 relatedDoc = relatedDoc.nextElementSibling;
2326             }
2327
2328             if (!relatedDoc && hasClass(docblock, "docblock") === false) {
2329                 return;
2330             }
2331
2332             // Hide all functions, but not associated types/consts.
2333
2334             if (mode === "toggle") {
2335                 if (hasClass(relatedDoc, "fns-now-collapsed") ||
2336                     hasClass(docblock, "hidden-by-impl-hider")) {
2337                     action = "show";
2338                 } else {
2339                     action = "hide";
2340                 }
2341             }
2342
2343             var dontApplyBlockRule = toggle.parentNode.parentNode.id !== "main";
2344             if (action === "show") {
2345                 removeClass(relatedDoc, "fns-now-collapsed");
2346                 // Stability/deprecation/portability information is never hidden.
2347                 if (hasClass(docblock, "item-info") === false) {
2348                     removeClass(docblock, "hidden-by-usual-hider");
2349                 }
2350                 onEachLazy(toggle.childNodes, adjustToggle(false, dontApplyBlockRule));
2351                 onEachLazy(relatedDoc.childNodes, implHider(false, dontApplyBlockRule));
2352             } else if (action === "hide") {
2353                 addClass(relatedDoc, "fns-now-collapsed");
2354                 // Stability/deprecation/portability information should be shown even when detailed
2355                 // info is hidden.
2356                 if (hasClass(docblock, "item-info") === false) {
2357                     addClass(docblock, "hidden-by-usual-hider");
2358                 }
2359                 onEachLazy(toggle.childNodes, adjustToggle(true, dontApplyBlockRule));
2360                 onEachLazy(relatedDoc.childNodes, implHider(true, dontApplyBlockRule));
2361             }
2362         }
2363     }
2364
2365     function collapser(pageId, e, collapse) {
2366         // inherent impl ids are like "impl" or impl-<number>'.
2367         // they will never be hidden by default.
2368         var n = e.parentElement;
2369         if (n.id.match(/^impl(?:-\d+)?$/) === null) {
2370             // Automatically minimize all non-inherent impls
2371             if (collapse || hasClass(n, "impl")) {
2372                 collapseDocs(e, "hide", pageId);
2373             }
2374         }
2375     }
2376
2377     function autoCollapse(pageId, collapse) {
2378         if (collapse) {
2379             toggleAllDocs(pageId, true);
2380         } else if (getSettingValue("auto-hide-trait-implementations") !== "false") {
2381             var impl_list = document.getElementById("trait-implementations-list");
2382
2383             if (impl_list !== null) {
2384                 onEachLazy(impl_list.getElementsByClassName("collapse-toggle"), function(e) {
2385                     collapser(pageId, e, collapse);
2386                 });
2387             }
2388
2389             var blanket_list = document.getElementById("blanket-implementations-list");
2390
2391             if (blanket_list !== null) {
2392                 onEachLazy(blanket_list.getElementsByClassName("collapse-toggle"), function(e) {
2393                     collapser(pageId, e, collapse);
2394                 });
2395             }
2396         }
2397     }
2398
2399     function insertAfter(newNode, referenceNode) {
2400         referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
2401     }
2402
2403     function createSimpleToggle(sectionIsCollapsed) {
2404         var toggle = document.createElement("a");
2405         toggle.href = "javascript:void(0)";
2406         toggle.className = "collapse-toggle";
2407         toggle.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(sectionIsCollapsed) +
2408                            "</span>]";
2409         return toggle;
2410     }
2411
2412     function createToggle(toggle, otherMessage, fontSize, extraClass, show) {
2413         var span = document.createElement("span");
2414         span.className = "toggle-label";
2415         if (show) {
2416             span.style.display = "none";
2417         }
2418         if (!otherMessage) {
2419             span.innerHTML = "&nbsp;Expand&nbsp;description";
2420         } else {
2421             span.innerHTML = otherMessage;
2422         }
2423
2424         if (fontSize) {
2425             span.style.fontSize = fontSize;
2426         }
2427
2428         var mainToggle = toggle.cloneNode(true);
2429         mainToggle.appendChild(span);
2430
2431         var wrapper = document.createElement("div");
2432         wrapper.className = "toggle-wrapper";
2433         if (!show) {
2434             addClass(wrapper, "collapsed");
2435             var inner = mainToggle.getElementsByClassName("inner");
2436             if (inner && inner.length > 0) {
2437                 inner[0].innerHTML = "+";
2438             }
2439         }
2440         if (extraClass) {
2441             addClass(wrapper, extraClass);
2442         }
2443         wrapper.appendChild(mainToggle);
2444         return wrapper;
2445     }
2446
2447     (function() {
2448         var toggles = document.getElementById(toggleAllDocsId);
2449         if (toggles) {
2450             toggles.onclick = toggleAllDocs;
2451         }
2452
2453         var toggle = createSimpleToggle(false);
2454         var hideMethodDocs = getSettingValue("auto-hide-method-docs") === "true";
2455         var hideImplementors = getSettingValue("auto-collapse-implementors") !== "false";
2456         var pageId = getPageId();
2457
2458         var func = function(e) {
2459             var next = e.nextElementSibling;
2460             if (next && hasClass(next, "item-info")) {
2461               next = next.nextElementSibling;
2462             }
2463             if (!next) {
2464                 return;
2465             }
2466             if (hasClass(next, "docblock")) {
2467                 var newToggle = toggle.cloneNode(true);
2468                 insertAfter(newToggle, e.childNodes[e.childNodes.length - 1]);
2469                 if (hideMethodDocs === true && hasClass(e, "method") === true) {
2470                     collapseDocs(newToggle, "hide", pageId);
2471                 }
2472             }
2473         };
2474
2475         var funcImpl = function(e) {
2476             var next = e.nextElementSibling;
2477             if (next && hasClass(next, "item-info")) {
2478                 next = next.nextElementSibling;
2479             }
2480             if (next && hasClass(next, "docblock")) {
2481                 next = next.nextElementSibling;
2482             }
2483             if (!next) {
2484                 return;
2485             }
2486             if (hasClass(e, "impl") &&
2487                 (next.getElementsByClassName("method").length > 0 ||
2488                  next.getElementsByClassName("associatedconstant").length > 0)) {
2489                 var newToggle = toggle.cloneNode(true);
2490                 insertAfter(newToggle, e.childNodes[e.childNodes.length - 1]);
2491                 // In case the option "auto-collapse implementors" is not set to false, we collapse
2492                 // all implementors.
2493                 if (hideImplementors === true && e.parentNode.id === "implementors-list") {
2494                     collapseDocs(newToggle, "hide", pageId);
2495                 }
2496             }
2497         };
2498
2499         onEachLazy(document.getElementsByClassName("method"), func);
2500         onEachLazy(document.getElementsByClassName("associatedconstant"), func);
2501         onEachLazy(document.getElementsByClassName("impl"), funcImpl);
2502         var impl_call = function() {};
2503         if (hideMethodDocs === true) {
2504             impl_call = function(e, newToggle) {
2505                 if (e.id.match(/^impl(?:-\d+)?$/) === null) {
2506                     // Automatically minimize all non-inherent impls
2507                     if (hasClass(e, "impl") === true) {
2508                         collapseDocs(newToggle, "hide", pageId);
2509                     }
2510                 }
2511             };
2512         }
2513         var newToggle = document.createElement("a");
2514         newToggle.href = "javascript:void(0)";
2515         newToggle.className = "collapse-toggle hidden-default collapsed";
2516         newToggle.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(true) +
2517                               "</span>] Show hidden undocumented items";
2518         function toggleClicked() {
2519             if (hasClass(this, "collapsed")) {
2520                 removeClass(this, "collapsed");
2521                 onEachLazy(this.parentNode.getElementsByClassName("hidden"), function(x) {
2522                     if (hasClass(x, "content") === false) {
2523                         removeClass(x, "hidden");
2524                         addClass(x, "x");
2525                     }
2526                 }, true);
2527                 this.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(false) +
2528                                  "</span>] Hide undocumented items";
2529             } else {
2530                 addClass(this, "collapsed");
2531                 onEachLazy(this.parentNode.getElementsByClassName("x"), function(x) {
2532                     if (hasClass(x, "content") === false) {
2533                         addClass(x, "hidden");
2534                         removeClass(x, "x");
2535                     }
2536                 }, true);
2537                 this.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(true) +
2538                                  "</span>] Show hidden undocumented items";
2539             }
2540         }
2541         onEachLazy(document.getElementsByClassName("impl-items"), function(e) {
2542             onEachLazy(e.getElementsByClassName("associatedconstant"), func);
2543             var hiddenElems = e.getElementsByClassName("hidden");
2544             var needToggle = false;
2545
2546             var needToggle = onEachLazy(e.getElementsByClassName("hidden"), function(hiddenElem) {
2547                 if (hasClass(hiddenElem, "content") === false &&
2548                     hasClass(hiddenElem, "docblock") === false) {
2549                     return true;
2550                 }
2551             });
2552             if (needToggle === true) {
2553                 var inner_toggle = newToggle.cloneNode(true);
2554                 inner_toggle.onclick = toggleClicked;
2555                 e.insertBefore(inner_toggle, e.firstChild);
2556                 impl_call(e.previousSibling, inner_toggle);
2557             }
2558         });
2559
2560         var currentType = document.getElementsByClassName("type-decl")[0];
2561         var className = null;
2562         if (currentType) {
2563             currentType = currentType.getElementsByClassName("rust")[0];
2564             if (currentType) {
2565                 currentType.classList.forEach(function(item) {
2566                     if (item !== "main") {
2567                         className = item;
2568                         return true;
2569                     }
2570                 });
2571             }
2572         }
2573         var showItemDeclarations = getSettingValue("auto-hide-" + className);
2574         if (showItemDeclarations === null) {
2575             if (className === "enum" || className === "macro") {
2576                 showItemDeclarations = "false";
2577             } else if (className === "struct" || className === "union" || className === "trait") {
2578                 showItemDeclarations = "true";
2579             } else {
2580                 // In case we found an unknown type, we just use the "parent" value.
2581                 showItemDeclarations = getSettingValue("auto-hide-declarations");
2582             }
2583         }
2584         showItemDeclarations = showItemDeclarations === "false";
2585         function buildToggleWrapper(e) {
2586             if (hasClass(e, "autohide")) {
2587                 var wrap = e.previousElementSibling;
2588                 if (wrap && hasClass(wrap, "toggle-wrapper")) {
2589                     var inner_toggle = wrap.childNodes[0];
2590                     var extra = e.childNodes[0].tagName === "H3";
2591
2592                     e.style.display = "none";
2593                     addClass(wrap, "collapsed");
2594                     onEachLazy(inner_toggle.getElementsByClassName("inner"), function(e) {
2595                         e.innerHTML = labelForToggleButton(true);
2596                     });
2597                     onEachLazy(inner_toggle.getElementsByClassName("toggle-label"), function(e) {
2598                         e.style.display = "inline-block";
2599                         if (extra === true) {
2600                             e.innerHTML = " Show " + e.childNodes[0].innerHTML;
2601                         }
2602                     });
2603                 }
2604             }
2605             if (e.parentNode.id === "main") {
2606                 var otherMessage = "";
2607                 var fontSize;
2608                 var extraClass;
2609
2610                 if (hasClass(e, "type-decl")) {
2611                     fontSize = "20px";
2612                     otherMessage = "&nbsp;Show&nbsp;declaration";
2613                     if (showItemDeclarations === false) {
2614                         extraClass = "collapsed";
2615                     }
2616                 } else if (hasClass(e, "sub-variant")) {
2617                     otherMessage = "&nbsp;Show&nbsp;fields";
2618                 } else if (hasClass(e, "non-exhaustive")) {
2619                     otherMessage = "&nbsp;This&nbsp;";
2620                     if (hasClass(e, "non-exhaustive-struct")) {
2621                         otherMessage += "struct";
2622                     } else if (hasClass(e, "non-exhaustive-enum")) {
2623                         otherMessage += "enum";
2624                     } else if (hasClass(e, "non-exhaustive-variant")) {
2625                         otherMessage += "enum variant";
2626                     } else if (hasClass(e, "non-exhaustive-type")) {
2627                         otherMessage += "type";
2628                     }
2629                     otherMessage += "&nbsp;is&nbsp;marked&nbsp;as&nbsp;non-exhaustive";
2630                 } else if (hasClass(e.childNodes[0], "impl-items")) {
2631                     extraClass = "marg-left";
2632                 }
2633
2634                 e.parentNode.insertBefore(
2635                     createToggle(
2636                         toggle,
2637                         otherMessage,
2638                         fontSize,
2639                         extraClass,
2640                         hasClass(e, "type-decl") === false || showItemDeclarations === true),
2641                     e);
2642                 if (hasClass(e, "type-decl") === true && showItemDeclarations === true) {
2643                     collapseDocs(e.previousSibling.childNodes[0], "toggle");
2644                 }
2645                 if (hasClass(e, "non-exhaustive") === true) {
2646                     collapseDocs(e.previousSibling.childNodes[0], "toggle");
2647                 }
2648             }
2649         }
2650
2651         onEachLazy(document.getElementsByClassName("docblock"), buildToggleWrapper);
2652         onEachLazy(document.getElementsByClassName("sub-variant"), buildToggleWrapper);
2653         var pageId = getPageId();
2654
2655         autoCollapse(pageId, getSettingValue("collapse") === "true");
2656
2657         if (pageId !== null) {
2658             expandSection(pageId);
2659         }
2660     }());
2661
2662     function createToggleWrapper(tog) {
2663         var span = document.createElement("span");
2664         span.className = "toggle-label";
2665         span.style.display = "none";
2666         span.innerHTML = "&nbsp;Expand&nbsp;attributes";
2667         tog.appendChild(span);
2668
2669         var wrapper = document.createElement("div");
2670         wrapper.className = "toggle-wrapper toggle-attributes";
2671         wrapper.appendChild(tog);
2672         return wrapper;
2673     }
2674
2675     (function() {
2676         // To avoid checking on "rustdoc-item-attributes" value on every loop...
2677         var itemAttributesFunc = function() {};
2678         if (getSettingValue("auto-hide-attributes") !== "false") {
2679             itemAttributesFunc = function(x) {
2680                 collapseDocs(x.previousSibling.childNodes[0], "toggle");
2681             };
2682         }
2683         var attributesToggle = createToggleWrapper(createSimpleToggle(false));
2684         onEachLazy(main.getElementsByClassName("attributes"), function(i_e) {
2685             var attr_tog = attributesToggle.cloneNode(true);
2686             if (hasClass(i_e, "top-attr") === true) {
2687                 addClass(attr_tog, "top-attr");
2688             }
2689             i_e.parentNode.insertBefore(attr_tog, i_e);
2690             itemAttributesFunc(i_e);
2691         });
2692     }());
2693
2694     (function() {
2695         // To avoid checking on "rustdoc-line-numbers" value on every loop...
2696         var lineNumbersFunc = function() {};
2697         if (getSettingValue("line-numbers") === "true") {
2698             lineNumbersFunc = function(x) {
2699                 var count = x.textContent.split("\n").length;
2700                 var elems = [];
2701                 for (var i = 0; i < count; ++i) {
2702                     elems.push(i + 1);
2703                 }
2704                 var node = document.createElement("pre");
2705                 addClass(node, "line-number");
2706                 node.innerHTML = elems.join("\n");
2707                 x.parentNode.insertBefore(node, x);
2708             };
2709         }
2710         onEachLazy(document.getElementsByClassName("rust-example-rendered"), function(e) {
2711             if (hasClass(e, "compile_fail")) {
2712                 e.addEventListener("mouseover", function() {
2713                     this.parentElement.previousElementSibling.childNodes[0].style.color = "#f00";
2714                 });
2715                 e.addEventListener("mouseout", function() {
2716                     this.parentElement.previousElementSibling.childNodes[0].style.color = "";
2717                 });
2718             } else if (hasClass(e, "ignore")) {
2719                 e.addEventListener("mouseover", function() {
2720                     this.parentElement.previousElementSibling.childNodes[0].style.color = "#ff9200";
2721                 });
2722                 e.addEventListener("mouseout", function() {
2723                     this.parentElement.previousElementSibling.childNodes[0].style.color = "";
2724                 });
2725             }
2726             lineNumbersFunc(e);
2727         });
2728     }());
2729
2730     onEachLazy(document.getElementsByClassName("notable-traits"), function(e) {
2731         e.onclick = function() {
2732             this.getElementsByClassName('notable-traits-tooltiptext')[0]
2733                 .classList.toggle("force-tooltip");
2734         };
2735     });
2736
2737     // In the search display, allows to switch between tabs.
2738     function printTab(nb) {
2739         if (nb === 0 || nb === 1 || nb === 2) {
2740             currentTab = nb;
2741         }
2742         var nb_copy = nb;
2743         onEachLazy(document.getElementById("titles").childNodes, function(elem) {
2744             if (nb_copy === 0) {
2745                 addClass(elem, "selected");
2746             } else {
2747                 removeClass(elem, "selected");
2748             }
2749             nb_copy -= 1;
2750         });
2751         onEachLazy(document.getElementById("results").childNodes, function(elem) {
2752             if (nb === 0) {
2753                 elem.style.display = "";
2754             } else {
2755                 elem.style.display = "none";
2756             }
2757             nb -= 1;
2758         });
2759     }
2760
2761     function putBackSearch(search_input) {
2762         var search = getSearchElement();
2763         if (search_input.value !== "" && hasClass(search, "hidden")) {
2764             showSearchResults(search);
2765             if (browserSupportsHistoryApi()) {
2766                 history.replaceState(search_input.value,
2767                                      "",
2768                                      "?search=" + encodeURIComponent(search_input.value));
2769             }
2770             document.title = searchTitle;
2771         }
2772     }
2773
2774     function getSearchLoadingText() {
2775         return "Loading search results...";
2776     }
2777
2778     if (search_input) {
2779         search_input.onfocus = function() {
2780             putBackSearch(this);
2781         };
2782     }
2783
2784     var params = getQueryStringParams();
2785     if (params && params.search) {
2786         var search = getSearchElement();
2787         search.innerHTML = "<h3 style=\"text-align: center;\">" + getSearchLoadingText() + "</h3>";
2788         showSearchResults(search);
2789     }
2790
2791     var sidebar_menu = document.getElementsByClassName("sidebar-menu")[0];
2792     if (sidebar_menu) {
2793         sidebar_menu.onclick = function() {
2794             var sidebar = document.getElementsByClassName("sidebar")[0];
2795             if (hasClass(sidebar, "mobile") === true) {
2796                 hideSidebar();
2797             } else {
2798                 showSidebar();
2799             }
2800         };
2801     }
2802
2803     if (main) {
2804         onEachLazy(main.getElementsByClassName("loading-content"), function(e) {
2805             e.remove();
2806         });
2807         onEachLazy(main.childNodes, function(e) {
2808             // Unhide the actual content once loading is complete. Headers get
2809             // flex treatment for their horizontal layout, divs get block treatment
2810             // for vertical layout (column-oriented flex layout for divs caused
2811             // errors in mobile browsers).
2812             if (e.tagName === "H2" || e.tagName === "H3") {
2813                 var nextTagName = e.nextElementSibling.tagName;
2814                 if (nextTagName == "H2" || nextTagName == "H3") {
2815                     e.nextElementSibling.style.display = "flex";
2816                 } else {
2817                     e.nextElementSibling.style.display = "block";
2818                 }
2819             }
2820         });
2821     }
2822
2823     function enableSearchInput() {
2824         if (search_input) {
2825             search_input.removeAttribute('disabled');
2826         }
2827     }
2828
2829     window.addSearchOptions = function(crates) {
2830         var elem = document.getElementById("crate-search");
2831
2832         if (!elem) {
2833             enableSearchInput();
2834             return;
2835         }
2836         var crates_text = [];
2837         if (Object.keys(crates).length > 1) {
2838             for (var crate in crates) {
2839                 if (hasOwnProperty(crates, crate)) {
2840                     crates_text.push(crate);
2841                 }
2842             }
2843         }
2844         crates_text.sort(function(a, b) {
2845             var lower_a = a.toLowerCase();
2846             var lower_b = b.toLowerCase();
2847
2848             if (lower_a < lower_b) {
2849                 return -1;
2850             } else if (lower_a > lower_b) {
2851                 return 1;
2852             }
2853             return 0;
2854         });
2855         var savedCrate = getSettingValue("saved-filter-crate");
2856         for (var i = 0; i < crates_text.length; ++i) {
2857             var option = document.createElement("option");
2858             option.value = crates_text[i];
2859             option.innerText = crates_text[i];
2860             elem.appendChild(option);
2861             // Set the crate filter from saved storage, if the current page has the saved crate
2862             // filter.
2863             //
2864             // If not, ignore the crate filter -- we want to support filtering for crates on sites
2865             // like doc.rust-lang.org where the crates may differ from page to page while on the
2866             // same domain.
2867             if (crates_text[i] === savedCrate) {
2868                 elem.value = savedCrate;
2869             }
2870         }
2871         enableSearchInput();
2872     };
2873
2874     function buildHelperPopup() {
2875         var popup = document.createElement("aside");
2876         addClass(popup, "hidden");
2877         popup.id = "help";
2878
2879         var book_info = document.createElement("span");
2880         book_info.innerHTML = "You can find more information in \
2881             <a href=\"https://doc.rust-lang.org/rustdoc/\">the rustdoc book</a>.";
2882
2883         var container = document.createElement("div");
2884         var shortcuts = [
2885             ["?", "Show this help dialog"],
2886             ["S", "Focus the search field"],
2887             ["T", "Focus the theme picker menu"],
2888             ["↑", "Move up in search results"],
2889             ["↓", "Move down in search results"],
2890             ["ctrl + ↑ / ↓", "Switch result tab"],
2891             ["&#9166;", "Go to active search result"],
2892             ["+", "Expand all sections"],
2893             ["-", "Collapse all sections"],
2894         ].map(x => "<dt>" +
2895             x[0].split(" ")
2896                 .map((y, index) => (index & 1) === 0 ? "<kbd>" + y + "</kbd>" : y)
2897                 .join("") + "</dt><dd>" + x[1] + "</dd>").join("");
2898         var div_shortcuts = document.createElement("div");
2899         addClass(div_shortcuts, "shortcuts");
2900         div_shortcuts.innerHTML = "<h2>Keyboard Shortcuts</h2><dl>" + shortcuts + "</dl></div>";
2901
2902         var infos = [
2903             "Prefix searches with a type followed by a colon (e.g., <code>fn:</code>) to \
2904              restrict the search to a given item kind.",
2905             "Accepted kinds are: <code>fn</code>, <code>mod</code>, <code>struct</code>, \
2906              <code>enum</code>, <code>trait</code>, <code>type</code>, <code>macro</code>, \
2907              and <code>const</code>.",
2908             "Search functions by type signature (e.g., <code>vec -&gt; usize</code> or \
2909              <code>* -&gt; vec</code>)",
2910             "Search multiple things at once by splitting your query with comma (e.g., \
2911              <code>str,u8</code> or <code>String,struct:Vec,test</code>)",
2912             "You can look for items with an exact name by putting double quotes around \
2913              your request: <code>\"string\"</code>",
2914             "Look for items inside another one by searching for a path: <code>vec::Vec</code>",
2915         ].map(x => "<p>" + x + "</p>").join("");
2916         var div_infos = document.createElement("div");
2917         addClass(div_infos, "infos");
2918         div_infos.innerHTML = "<h2>Search Tricks</h2>" + infos;
2919
2920         container.appendChild(book_info);
2921         container.appendChild(div_shortcuts);
2922         container.appendChild(div_infos);
2923
2924         popup.appendChild(container);
2925         insertAfter(popup, getSearchElement());
2926         // So that it's only built once and then it'll do nothing when called!
2927         buildHelperPopup = function() {};
2928     }
2929
2930     onHashChange(null);
2931     window.onhashchange = onHashChange;
2932 }());
2933
2934 // This is required in firefox. Explanations: when going back in the history, firefox doesn't re-run
2935 // the JS, therefore preventing rustdoc from setting a few things required to be able to reload the
2936 // previous search results (if you navigated to a search result with the keyboard, pressed enter on
2937 // it to navigate to that result, and then came back to this page).
2938 window.onunload = function(){};