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