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