]>
git.proxmox.com Git - rustc.git/blob - src/librustdoc/html/static/main.js
2 /* global ALIASES, currentCrate, rootPath */
4 // Local js definitions:
5 /* global addClass, getCurrentValue, hasClass */
6 /* global onEach, removeClass, updateLocalStorage */
8 if (!String
.prototype.startsWith
) {
9 String
.prototype.startsWith = function(searchString
, position
) {
10 position
= position
|| 0;
11 return this.indexOf(searchString
, position
) === position
;
14 if (!String
.prototype.endsWith
) {
15 String
.prototype.endsWith = function(suffix
, length
) {
16 var l
= length
|| this.length
;
17 return this.indexOf(suffix
, l
- suffix
.length
) !== -1;
21 if (!DOMTokenList
.prototype.add
) {
22 DOMTokenList
.prototype.add = function(className
) {
23 if (className
&& !hasClass(this, className
)) {
24 if (this.className
&& this.className
.length
> 0) {
25 this.className
+= " " + className
;
27 this.className
= className
;
33 if (!DOMTokenList
.prototype.remove
) {
34 DOMTokenList
.prototype.remove = function(className
) {
35 if (className
&& this.className
) {
36 this.className
= (" " + this.className
+ " ").replace(" " + className
+ " ", " ")
42 function getSearchInput() {
43 return document
.getElementsByClassName("search-input")[0];
46 function getSearchElement() {
47 return document
.getElementById("search");
53 // This mapping table should match the discriminants of
54 // `rustdoc::html::item_type::ItemType` type in Rust.
55 var itemTypes
= ["mod",
82 var disableShortcuts
= getCurrentValue("rustdoc-disable-shortcuts") === "true";
83 var search_input
= getSearchInput();
85 // On the search screen, so you remain on the last tab you opened.
88 // 1 for "In Parameters"
89 // 2 for "In Return Types"
92 var titleBeforeSearch
= document
.title
;
94 function getPageId() {
95 var id
= document
.location
.href
.split("#")[1];
97 return id
.split("?")[0].split("&")[0];
102 function showSidebar() {
103 var elems
= document
.getElementsByClassName("sidebar-elems")[0];
105 addClass(elems
, "show-it");
107 var sidebar
= document
.getElementsByClassName("sidebar")[0];
109 addClass(sidebar
, "mobile");
110 var filler
= document
.getElementById("sidebar-filler");
112 var div
= document
.createElement("div");
113 div
.id
= "sidebar-filler";
114 sidebar
.appendChild(div
);
117 var themePickers
= document
.getElementsByClassName("theme-picker");
118 if (themePickers
&& themePickers
.length
> 0) {
119 themePickers
[0].style
.display
= "none";
123 function hideSidebar() {
124 var elems
= document
.getElementsByClassName("sidebar-elems")[0];
126 removeClass(elems
, "show-it");
128 var sidebar
= document
.getElementsByClassName("sidebar")[0];
129 removeClass(sidebar
, "mobile");
130 var filler
= document
.getElementById("sidebar-filler");
134 document
.getElementsByTagName("body")[0].style
.marginTop
= "";
135 var themePickers
= document
.getElementsByClassName("theme-picker");
136 if (themePickers
&& themePickers
.length
> 0) {
137 themePickers
[0].style
.display
= null;
141 // used for special search precedence
142 var TY_PRIMITIVE
= itemTypes
.indexOf("primitive");
143 var TY_KEYWORD
= itemTypes
.indexOf("keyword");
145 function getQueryStringParams() {
147 window
.location
.search
.substring(1).split("&").
149 var pair
= s
.split("=");
150 params
[decodeURIComponent(pair
[0])] =
151 typeof pair
[1] === "undefined" ? null : decodeURIComponent(pair
[1]);
156 function browserSupportsHistoryApi() {
157 return window
.history
&& typeof window
.history
.pushState
=== "function";
160 function isHidden(elem
) {
161 return elem
.offsetHeight
=== 0;
164 var main
= document
.getElementById("main");
167 function handleHashes(ev
) {
168 var search
= getSearchElement();
169 if (ev
!== null && search
&& !hasClass(search
, "hidden") && ev
.newURL
) {
170 // This block occurs when clicking on an element in the navbar while
172 addClass(search
, "hidden");
173 removeClass(main
, "hidden");
174 var hash
= ev
.newURL
.slice(ev
.newURL
.indexOf("#") + 1);
175 if (browserSupportsHistoryApi()) {
176 history
.replaceState(hash
, "", "?search=#" + hash
);
178 var elem
= document
.getElementById(hash
);
180 elem
.scrollIntoView();
183 // This part is used in case an element is not visible.
184 if (savedHash
!== window
.location
.hash
) {
185 savedHash
= window
.location
.hash
;
186 if (savedHash
.length
=== 0) {
189 var elem
= document
.getElementById(savedHash
.slice(1)); // we remove the '#'
190 if (!elem
|| !isHidden(elem
)) {
193 var parent
= elem
.parentNode
;
194 if (parent
&& hasClass(parent
, "impl-items")) {
195 // In case this is a trait implementation item, we first need to toggle
196 // the "Show hidden undocumented items".
197 onEachLazy(parent
.getElementsByClassName("collapsed"), function(e
) {
198 if (e
.parentNode
=== parent
) {
199 // Only click on the toggle we're looking for.
204 if (isHidden(elem
)) {
205 // The whole parent is collapsed. We need to click on its toggle as well!
206 if (hasClass(parent
.lastElementChild
, "collapse-toggle")) {
207 parent
.lastElementChild
.click();
214 function highlightSourceLines(match
, ev
) {
215 if (typeof match
=== "undefined") {
216 // If we're in mobile mode, we should hide the sidebar in any case.
218 match
= window
.location
.hash
.match(/^#?(\d+)(?:-(\d+))?$/);
223 var from = parseInt(match
[1], 10);
225 if (typeof match
[2] !== "undefined") {
226 to
= parseInt(match
[2], 10);
233 var elem
= document
.getElementById(from);
238 var x
= document
.getElementById(from);
243 onEachLazy(document
.getElementsByClassName("line-numbers"), function(e
) {
244 onEachLazy(e
.getElementsByTagName("span"), function(i_e
) {
245 removeClass(i_e
, "line-highlighted");
248 for (var i
= from; i
<= to
; ++i
) {
249 elem
= document
.getElementById(i
);
253 addClass(elem
, "line-highlighted");
257 function onHashChange(ev
) {
258 // If we're in mobile mode, we should hide the sidebar in any case.
260 var match
= window
.location
.hash
.match(/^#?(\d+)(?:-(\d+))?$/);
262 return highlightSourceLines(match
, ev
);
267 function expandSection(id
) {
268 var elem
= document
.getElementById(id
);
269 if (elem
&& isHidden(elem
)) {
270 var h3
= elem
.parentNode
.previousElementSibling
;
271 if (h3
&& h3
.tagName
!== "H3") {
272 h3
= h3
.previousElementSibling
; // skip div.docblock
276 var collapses
= h3
.getElementsByClassName("collapse-toggle");
277 if (collapses
.length
> 0) {
278 // The element is not visible, we need to make it appear!
279 collapseDocs(collapses
[0], "show");
285 // Gets the human-readable string for the virtual-key code of the
286 // given KeyboardEvent, ev.
288 // This function is meant as a polyfill for KeyboardEvent#key,
289 // since it is not supported in Trident. We also test for
290 // KeyboardEvent#keyCode because the handleShortcut handler is
291 // also registered for the keydown event, because Blink doesn't fire
292 // keypress on hitting the Escape key.
294 // So I guess you could say things are getting pretty interoperable.
295 function getVirtualKey(ev
) {
296 if ("key" in ev
&& typeof ev
.key
!= "undefined") {
300 var c
= ev
.charCode
|| ev
.keyCode
;
304 return String
.fromCharCode(c
);
307 function getHelpElement() {
308 return document
.getElementById("help");
311 function displayHelp(display
, ev
, help
) {
312 var help
= help
? help
: getHelpElement();
313 if (display
=== true) {
314 if (hasClass(help
, "hidden")) {
316 removeClass(help
, "hidden");
317 addClass(document
.body
, "blur");
319 } else if (hasClass(help
, "hidden") === false) {
321 addClass(help
, "hidden");
322 removeClass(document
.body
, "blur");
326 function handleEscape(ev
) {
327 var help
= getHelpElement();
328 var search
= getSearchElement();
330 if (hasClass(help
, "hidden") === false) {
331 displayHelp(false, ev
, help
);
332 } else if (hasClass(search
, "hidden") === false) {
334 addClass(search
, "hidden");
335 removeClass(main
, "hidden");
336 document
.title
= titleBeforeSearch
;
341 function handleShortcut(ev
) {
342 // Don't interfere with browser shortcuts
343 if (ev
.ctrlKey
|| ev
.altKey
|| ev
.metaKey
|| disableShortcuts
=== true) {
347 if (document
.activeElement
.tagName
=== "INPUT") {
348 switch (getVirtualKey(ev
)) {
354 switch (getVirtualKey(ev
)) {
361 displayHelp(false, ev
);
376 displayHelp(true, ev
);
383 function findParentElement(elem
, tagName
) {
385 if (elem
&& elem
.tagName
=== tagName
) {
388 elem
= elem
.parentNode
;
393 document
.onkeypress
= handleShortcut
;
394 document
.onkeydown
= handleShortcut
;
396 var handleSourceHighlight
= (function() {
397 var prev_line_id
= 0;
399 var set_fragment = function(name
) {
400 var x
= window
.scrollX
,
402 if (browserSupportsHistoryApi()) {
403 history
.replaceState(null, null, "#" + name
);
404 highlightSourceLines();
406 location
.replace("#" + name
);
408 // Prevent jumps when selecting one or many lines
409 window
.scrollTo(x
, y
);
412 return function(ev
) {
413 var cur_line_id
= parseInt(ev
.target
.id
, 10);
416 if (ev
.shiftKey
&& prev_line_id
) {
417 // Swap selection if needed
418 if (prev_line_id
> cur_line_id
) {
419 var tmp
= prev_line_id
;
420 prev_line_id
= cur_line_id
;
424 set_fragment(prev_line_id
+ "-" + cur_line_id
);
426 prev_line_id
= cur_line_id
;
428 set_fragment(cur_line_id
);
433 document
.onclick = function(ev
) {
434 if (hasClass(ev
.target
, "collapse-toggle")) {
435 collapseDocs(ev
.target
, "toggle");
436 } else if (hasClass(ev
.target
.parentNode
, "collapse-toggle")) {
437 collapseDocs(ev
.target
.parentNode
, "toggle");
438 } else if (ev
.target
.tagName
=== "SPAN" && hasClass(ev
.target
.parentNode
, "line-numbers")) {
439 handleSourceHighlight(ev
);
440 } else if (hasClass(getHelpElement(), "hidden") === false) {
441 var help
= getHelpElement();
442 var is_inside_help_popup
= ev
.target
!== help
&& help
.contains(ev
.target
);
443 if (is_inside_help_popup
=== false) {
444 addClass(help
, "hidden");
445 removeClass(document
.body
, "blur");
448 // Making a collapsed element visible on onhashchange seems
450 var a
= findParentElement(ev
.target
, "A");
452 expandSection(a
.hash
.replace(/^#/, ""));
457 var x
= document
.getElementsByClassName("version-selector");
459 x
[0].onchange = function() {
461 url
= document
.location
.href
,
463 len
= rootPath
.match(/\.\.\//g).length
+ 1;
465 for (i
= 0; i
< len
; ++i
) {
466 match
= url
.match(/\/[^\/]*$/);
468 stripped
= match
[0] + stripped
;
470 url
= url
.substring(0, url
.length
- match
[0].length
);
473 url
+= "/" + document
.getElementsByClassName("version-selector")[0].value
+ stripped
;
475 document
.location
.href
= url
;
480 * A function to compute the Levenshtein distance between two strings
481 * Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported
482 * Full License can be found at http://creativecommons.org/licenses/by-sa/3.0/legalcode
483 * This code is an unmodified version of the code written by Marco de Wit
484 * and was found at http://stackoverflow.com/a/18514751/745719
486 var levenshtein_row2
= [];
487 function levenshtein(s1
, s2
) {
491 var s1_len
= s1
.length
, s2_len
= s2
.length
;
492 if (s1_len
&& s2_len
) {
493 var i1
= 0, i2
= 0, a
, b
, c
, c2
, row
= levenshtein_row2
;
494 while (i1
< s1_len
) {
497 while (i2
< s2_len
) {
498 c2
= s2
.charCodeAt(i2
);
502 for (i1
= 0; i1
< s1_len
; ++i1
) {
503 c
= a
+ (s1
.charCodeAt(i1
) !== c2
? 1 : 0);
505 b
= b
< a
? (b
< c
? b
+ 1 : c
) : (a
< c
? a
+ 1 : c
);
511 return s1_len
+ s2_len
;
514 function initSearch(rawSearchIndex
) {
515 var currentResults
, index
, searchIndex
;
516 var MAX_LEV_DISTANCE
= 3;
517 var MAX_RESULTS
= 200;
518 var GENERICS_DATA
= 1;
522 var params
= getQueryStringParams();
524 // Populate search bar with query string search term when provided,
525 // but only if the input bar is empty. This avoid the obnoxious issue
526 // where you start trying to do a search, and the index loads, and
527 // suddenly your search is gone!
528 if (search_input
.value
=== "") {
529 search_input
.value
= params
.search
|| "";
533 * Executes the query and builds an index of results
534 * @param {[Object]} query [The user query]
535 * @param {[type]} searchWords [The list of search words to query
537 * @param {[type]} filterCrates [Crate to search in if defined]
538 * @return {[type]} [A search index of results]
540 function execQuery(query
, searchWords
, filterCrates
) {
541 function itemTypeFromName(typename
) {
542 var length
= itemTypes
.length
;
543 for (var i
= 0; i
< length
; ++i
) {
544 if (itemTypes
[i
] === typename
) {
551 var valLower
= query
.query
.toLowerCase(),
553 typeFilter
= itemTypeFromName(query
.type
),
554 results
= {}, results_in_args
= {}, results_returned
= {},
555 split
= valLower
.split("::");
557 var length
= split
.length
;
558 for (var z
= 0; z
< length
; ++z
) {
559 if (split
[z
] === "") {
565 function transformResults(results
, isType
) {
567 var length
= results
.length
;
568 for (var i
= 0; i
< length
; ++i
) {
569 if (results
[i
].id
> -1) {
570 var obj
= searchIndex
[results
[i
].id
];
571 obj
.lev
= results
[i
].lev
;
572 if (isType
!== true || obj
.type
) {
573 var res
= buildHrefAndPath(obj
);
574 obj
.displayPath
= pathSplitter(res
[0]);
575 obj
.fullPath
= obj
.displayPath
+ obj
.name
;
576 // To be sure than it some items aren't considered as duplicate.
577 obj
.fullPath
+= "|" + obj
.ty
;
580 if (out
.length
>= MAX_RESULTS
) {
589 function sortResults(results
, isType
) {
591 for (var entry
in results
) {
592 if (results
.hasOwnProperty(entry
)) {
593 ar
.push(results
[entry
]);
598 var nresults
= results
.length
;
599 for (i
= 0; i
< nresults
; ++i
) {
600 results
[i
].word
= searchWords
[results
[i
].id
];
601 results
[i
].item
= searchIndex
[results
[i
].id
] || {};
603 // if there are no results then return to default and fail
604 if (results
.length
=== 0) {
608 results
.sort(function(aaa
, bbb
) {
611 // sort by exact match with regard to the last word (mismatch goes later)
612 a
= (aaa
.word
!== val
);
613 b
= (bbb
.word
!== val
);
614 if (a
!== b
) { return a
- b
; }
616 // Sort by non levenshtein results and then levenshtein results by the distance
617 // (less changes required to match means higher rankings)
620 if (a
!== b
) { return a
- b
; }
622 // sort by crate (non-current crate goes later)
623 a
= (aaa
.item
.crate
!== window
.currentCrate
);
624 b
= (bbb
.item
.crate
!== window
.currentCrate
);
625 if (a
!== b
) { return a
- b
; }
627 // sort by item name length (longer goes later)
630 if (a
!== b
) { return a
- b
; }
632 // sort by item name (lexicographically larger goes later)
635 if (a
!== b
) { return (a
> b
? +1 : -1); }
637 // sort by index of keyword in item name (no literal occurrence goes later)
640 if (a
!== b
) { return a
- b
; }
641 // (later literal occurrence, if any, goes later)
644 if (a
!== b
) { return a
- b
; }
646 // special precedence for primitive and keyword pages
647 if ((aaa
.item
.ty
=== TY_PRIMITIVE
&& bbb
.item
.ty
!== TY_KEYWORD
) ||
648 (aaa
.item
.ty
=== TY_KEYWORD
&& bbb
.item
.ty
!== TY_PRIMITIVE
)) {
651 if ((bbb
.item
.ty
=== TY_PRIMITIVE
&& aaa
.item
.ty
!== TY_PRIMITIVE
) ||
652 (bbb
.item
.ty
=== TY_KEYWORD
&& aaa
.item
.ty
!== TY_KEYWORD
)) {
656 // sort by description (no description goes later)
657 a
= (aaa
.item
.desc
=== "");
658 b
= (bbb
.item
.desc
=== "");
659 if (a
!== b
) { return a
- b
; }
661 // sort by type (later occurrence in `itemTypes` goes later)
664 if (a
!== b
) { return a
- b
; }
666 // sort by path (lexicographically larger goes later)
669 if (a
!== b
) { return (a
> b
? +1 : -1); }
675 var length
= results
.length
;
676 for (i
= 0; i
< length
; ++i
) {
677 var result
= results
[i
];
679 // this validation does not make sense when searching by types
680 if (result
.dontValidate
) {
683 var name
= result
.item
.name
.toLowerCase(),
684 path
= result
.item
.path
.toLowerCase(),
685 parent
= result
.item
.parent
;
687 if (isType
!== true &&
688 validateResult(name
, path
, split
, parent
) === false)
693 return transformResults(results
);
696 function extractGenerics(val
) {
697 val
= val
.toLowerCase();
698 if (val
.indexOf("<") !== -1) {
699 var values
= val
.substring(val
.indexOf("<") + 1, val
.lastIndexOf(">"));
701 name
: val
.substring(0, val
.indexOf("<")),
702 generics
: values
.split(/\s*,\s*/),
711 function checkGenerics(obj
, val
) {
712 // The names match, but we need to be sure that all generics kinda
714 var lev_distance
= MAX_LEV_DISTANCE
+ 1;
715 if (val
.generics
.length
> 0) {
716 if (obj
.length
> GENERICS_DATA
&&
717 obj
[GENERICS_DATA
].length
>= val
.generics
.length
) {
718 var elems
= obj
[GENERICS_DATA
].slice(0);
721 // We need to find the type that matches the most to remove it in order
723 var vlength
= val
.generics
.length
;
724 for (var y
= 0; y
< vlength
; ++y
) {
725 var lev
= { pos
: -1, lev
: MAX_LEV_DISTANCE
+ 1};
726 var elength
= elems
.length
;
727 for (var x
= 0; x
< elength
; ++x
) {
728 var tmp_lev
= levenshtein(elems
[x
], val
.generics
[y
]);
729 if (tmp_lev
< lev
.lev
) {
734 if (lev
.pos
!== -1) {
735 elems
.splice(lev
.pos
, 1);
736 lev_distance
= Math
.min(lev
.lev
, lev_distance
);
740 return MAX_LEV_DISTANCE
+ 1;
743 return Math
.ceil(total
/ done
);
746 return MAX_LEV_DISTANCE
+ 1;
749 // Check for type name and type generics (if any).
750 function checkType(obj
, val
, literalSearch
) {
751 var lev_distance
= MAX_LEV_DISTANCE
+ 1;
753 if (obj
[NAME
] === val
.name
) {
754 if (literalSearch
=== true) {
755 if (val
.generics
&& val
.generics
.length
!== 0) {
756 if (obj
.length
> GENERICS_DATA
&&
757 obj
[GENERICS_DATA
].length
>= val
.generics
.length
) {
758 var elems
= obj
[GENERICS_DATA
].slice(0);
761 for (var y
= 0; allFound
=== true && y
< val
.generics
.length
; ++y
) {
763 for (x
= 0; allFound
=== false && x
< elems
.length
; ++x
) {
764 allFound
= elems
[x
] === val
.generics
[y
];
766 if (allFound
=== true) {
767 elems
.splice(x
- 1, 1);
770 if (allFound
=== true) {
779 // If the type has generics but don't match, then it won't return at this point.
780 // Otherwise, `checkGenerics` will return 0 and it'll return.
781 if (obj
.length
> GENERICS_DATA
&& obj
[GENERICS_DATA
].length
!== 0) {
782 var tmp_lev
= checkGenerics(obj
, val
);
783 if (tmp_lev
<= MAX_LEV_DISTANCE
) {
790 // Names didn't match so let's check if one of the generic types could.
791 if (literalSearch
=== true) {
792 if (obj
.length
> GENERICS_DATA
&& obj
[GENERICS_DATA
].length
> 0) {
793 var length
= obj
[GENERICS_DATA
].length
;
794 for (x
= 0; x
< length
; ++x
) {
795 if (obj
[GENERICS_DATA
][x
] === val
.name
) {
802 lev_distance
= Math
.min(levenshtein(obj
[NAME
], val
.name
), lev_distance
);
803 if (lev_distance
<= MAX_LEV_DISTANCE
) {
804 // The generics didn't match but the name kinda did so we give it
805 // a levenshtein distance value that isn't *this* good so it goes
806 // into the search results but not too high.
807 lev_distance
= Math
.ceil((checkGenerics(obj
, val
) + lev_distance
) / 2);
808 } else if (obj
.length
> GENERICS_DATA
&& obj
[GENERICS_DATA
].length
> 0) {
809 // We can check if the type we're looking for is inside the generics!
810 var olength
= obj
[GENERICS_DATA
].length
;
811 for (x
= 0; x
< olength
; ++x
) {
812 lev_distance
= Math
.min(levenshtein(obj
[GENERICS_DATA
][x
], val
.name
),
816 // Now whatever happens, the returned distance is "less good" so we should mark it
817 // as such, and so we add 1 to the distance to make it "less good".
818 return lev_distance
+ 1;
821 function findArg(obj
, val
, literalSearch
) {
822 var lev_distance
= MAX_LEV_DISTANCE
+ 1;
824 if (obj
&& obj
.type
&& obj
.type
[INPUTS_DATA
] &&
825 obj
.type
[INPUTS_DATA
].length
> 0) {
826 var length
= obj
.type
[INPUTS_DATA
].length
;
827 for (var i
= 0; i
< length
; i
++) {
828 var tmp
= checkType(obj
.type
[INPUTS_DATA
][i
], val
, literalSearch
);
829 if (literalSearch
=== true && tmp
=== true) {
832 lev_distance
= Math
.min(tmp
, lev_distance
);
833 if (lev_distance
=== 0) {
838 return literalSearch
=== true ? false : lev_distance
;
841 function checkReturned(obj
, val
, literalSearch
) {
842 var lev_distance
= MAX_LEV_DISTANCE
+ 1;
844 if (obj
&& obj
.type
&& obj
.type
.length
> OUTPUT_DATA
) {
845 var ret
= obj
.type
[OUTPUT_DATA
];
846 if (!obj
.type
[OUTPUT_DATA
].length
) {
849 for (var x
= 0; x
< ret
.length
; ++x
) {
851 if (typeof r
=== "string") {
854 var tmp
= checkType(r
, val
, literalSearch
);
855 if (literalSearch
=== true) {
861 lev_distance
= Math
.min(tmp
, lev_distance
);
862 if (lev_distance
=== 0) {
867 return literalSearch
=== true ? false : lev_distance
;
870 function checkPath(contains
, lastElem
, ty
) {
871 if (contains
.length
=== 0) {
874 var ret_lev
= MAX_LEV_DISTANCE
+ 1;
875 var path
= ty
.path
.split("::");
877 if (ty
.parent
&& ty
.parent
.name
) {
878 path
.push(ty
.parent
.name
.toLowerCase());
881 var length
= path
.length
;
882 var clength
= contains
.length
;
883 if (clength
> length
) {
884 return MAX_LEV_DISTANCE
+ 1;
886 for (var i
= 0; i
< length
; ++i
) {
887 if (i
+ clength
> length
) {
892 for (var x
= 0; x
< clength
; ++x
) {
893 var lev
= levenshtein(path
[i
+ x
], contains
[x
]);
894 if (lev
> MAX_LEV_DISTANCE
) {
900 if (aborted
=== false) {
901 ret_lev
= Math
.min(ret_lev
, Math
.round(lev_total
/ clength
));
907 function typePassesFilter(filter
, type
) {
909 if (filter
< 0) return true;
912 if (filter
=== type
) return true;
914 // Match related items
915 var name
= itemTypes
[type
];
916 switch (itemTypes
[filter
]) {
918 return (name
== "associatedconstant");
920 return (name
== "method" || name
== "tymethod");
922 return (name
== "primitive" || name
== "keyword");
929 function generateId(ty
) {
930 if (ty
.parent
&& ty
.parent
.name
) {
931 return itemTypes
[ty
.ty
] + ty
.path
+ ty
.parent
.name
+ ty
.name
;
933 return itemTypes
[ty
.ty
] + ty
.path
+ ty
.name
;
936 // quoted values mean literal search
937 var nSearchWords
= searchWords
.length
;
943 if ((val
.charAt(0) === "\"" || val
.charAt(0) === "'") &&
944 val
.charAt(val
.length
- 1) === val
.charAt(0))
946 val
= extractGenerics(val
.substr(1, val
.length
- 2));
947 for (i
= 0; i
< nSearchWords
; ++i
) {
948 if (filterCrates
!== undefined && searchIndex
[i
].crate
!== filterCrates
) {
951 in_args
= findArg(searchIndex
[i
], val
, true);
952 returned
= checkReturned(searchIndex
[i
], val
, true);
954 fullId
= generateId(ty
);
956 if (searchWords
[i
] === val
.name
) {
957 // filter type: ... queries
958 if (typePassesFilter(typeFilter
, searchIndex
[i
].ty
) &&
959 results
[fullId
] === undefined)
961 results
[fullId
] = {id
: i
, index
: -1};
963 } else if ((in_args
=== true || returned
=== true) &&
964 typePassesFilter(typeFilter
, searchIndex
[i
].ty
)) {
965 if (in_args
=== true || returned
=== true) {
966 if (in_args
=== true) {
967 results_in_args
[fullId
] = {
973 if (returned
=== true) {
974 results_returned
[fullId
] = {
989 query
.inputs
= [val
];
993 } else if (val
.search("->") > -1) {
994 var trimmer = function(s
) { return s
.trim(); };
995 var parts
= val
.split("->").map(trimmer
);
996 var input
= parts
[0];
997 // sort inputs so that order does not matter
998 var inputs
= input
.split(",").map(trimmer
).sort();
999 for (i
= 0; i
< inputs
.length
; ++i
) {
1000 inputs
[i
] = extractGenerics(inputs
[i
]);
1002 var output
= extractGenerics(parts
[1]);
1004 for (i
= 0; i
< nSearchWords
; ++i
) {
1005 if (filterCrates
!== undefined && searchIndex
[i
].crate
!== filterCrates
) {
1008 var type
= searchIndex
[i
].type
;
1009 ty
= searchIndex
[i
];
1013 fullId
= generateId(ty
);
1015 // allow searching for void (no output) functions as well
1016 var typeOutput
= type
.length
> OUTPUT_DATA
? type
[OUTPUT_DATA
].name
: "";
1017 returned
= checkReturned(ty
, output
, true);
1018 if (output
.name
=== "*" || returned
=== true) {
1020 var is_module
= false;
1022 if (input
=== "*") {
1025 var allFound
= true;
1026 for (var it
= 0; allFound
=== true && it
< inputs
.length
; it
++) {
1027 allFound
= checkType(type
, inputs
[it
], true);
1031 if (in_args
=== true) {
1032 results_in_args
[fullId
] = {
1038 if (returned
=== true) {
1039 results_returned
[fullId
] = {
1045 if (is_module
=== true) {
1054 query
.inputs
= inputs
.map(function(input
) {
1057 query
.output
= output
.name
;
1059 query
.inputs
= [val
];
1062 // gather matching search results up to a certain maximum
1063 val
= val
.replace(/\_/g, "");
1065 var valGenerics
= extractGenerics(val
);
1067 var paths
= valLower
.split("::");
1069 for (j
= 0; j
< paths
.length
; ++j
) {
1070 if (paths
[j
] === "") {
1075 val
= paths
[paths
.length
- 1];
1076 var contains
= paths
.slice(0, paths
.length
> 1 ? paths
.length
- 1 : 1);
1080 for (j
= 0; j
< nSearchWords
; ++j
) {
1081 ty
= searchIndex
[j
];
1082 if (!ty
|| (filterCrates
!== undefined && ty
.crate
!== filterCrates
)) {
1086 if (paths
.length
> 1) {
1087 lev
= checkPath(contains
, paths
[paths
.length
- 1], ty
);
1088 if (lev
> MAX_LEV_DISTANCE
) {
1090 } else if (lev
> 0) {
1095 returned
= MAX_LEV_DISTANCE
+ 1;
1096 in_args
= MAX_LEV_DISTANCE
+ 1;
1098 // we want lev results to go lower than others
1099 lev
= MAX_LEV_DISTANCE
+ 1;
1100 fullId
= generateId(ty
);
1102 if (searchWords
[j
].indexOf(split
[i
]) > -1 ||
1103 searchWords
[j
].indexOf(val
) > -1 ||
1104 searchWords
[j
].replace(/_
/g
, "").indexOf(val
) > -1)
1106 // filter type: ... queries
1107 if (typePassesFilter(typeFilter
, ty
.ty
) && results
[fullId
] === undefined) {
1108 index
= searchWords
[j
].replace(/_
/g
, "").indexOf(val
);
1111 if ((lev
= levenshtein(searchWords
[j
], val
)) <= MAX_LEV_DISTANCE
) {
1112 if (typePassesFilter(typeFilter
, ty
.ty
) === false) {
1113 lev
= MAX_LEV_DISTANCE
+ 1;
1118 if ((in_args
= findArg(ty
, valGenerics
)) <= MAX_LEV_DISTANCE
) {
1119 if (typePassesFilter(typeFilter
, ty
.ty
) === false) {
1120 in_args
= MAX_LEV_DISTANCE
+ 1;
1123 if ((returned
= checkReturned(ty
, valGenerics
)) <= MAX_LEV_DISTANCE
) {
1124 if (typePassesFilter(typeFilter
, ty
.ty
) === false) {
1125 returned
= MAX_LEV_DISTANCE
+ 1;
1130 if (lev
> 0 && val
.length
> 3 && searchWords
[j
].indexOf(val
) > -1) {
1131 if (val
.length
< 6) {
1137 if (in_args
<= MAX_LEV_DISTANCE
) {
1138 if (results_in_args
[fullId
] === undefined) {
1139 results_in_args
[fullId
] = {
1145 results_in_args
[fullId
].lev
=
1146 Math
.min(results_in_args
[fullId
].lev
, in_args
);
1148 if (returned
<= MAX_LEV_DISTANCE
) {
1149 if (results_returned
[fullId
] === undefined) {
1150 results_returned
[fullId
] = {
1156 results_returned
[fullId
].lev
=
1157 Math
.min(results_returned
[fullId
].lev
, returned
);
1159 if (index
!== -1 || lev
<= MAX_LEV_DISTANCE
) {
1160 if (index
!== -1 && paths
.length
< 2) {
1163 if (results
[fullId
] === undefined) {
1170 results
[fullId
].lev
= Math
.min(results
[fullId
].lev
, lev
);
1176 "in_args": sortResults(results_in_args
, true),
1177 "returned": sortResults(results_returned
, true),
1178 "others": sortResults(results
),
1180 if (ALIASES
&& ALIASES
[window
.currentCrate
] &&
1181 ALIASES
[window
.currentCrate
][query
.raw
]) {
1182 var aliases
= ALIASES
[window
.currentCrate
][query
.raw
];
1183 for (i
= 0; i
< aliases
.length
; ++i
) {
1184 aliases
[i
].is_alias
= true;
1185 aliases
[i
].alias
= query
.raw
;
1186 aliases
[i
].path
= aliases
[i
].p
;
1187 var res
= buildHrefAndPath(aliases
[i
]);
1188 aliases
[i
].displayPath
= pathSplitter(res
[0]);
1189 aliases
[i
].fullPath
= aliases
[i
].displayPath
+ aliases
[i
].name
;
1190 aliases
[i
].href
= res
[1];
1191 ret
.others
.unshift(aliases
[i
]);
1192 if (ret
.others
.length
> MAX_RESULTS
) {
1201 * Validate performs the following boolean logic. For example:
1202 * "File::open" will give IF A PARENT EXISTS => ("file" && "open")
1203 * exists in (name || path || parent) OR => ("file" && "open") exists in
1206 * This could be written functionally, but I wanted to minimise
1207 * functions on stack.
1209 * @param {[string]} name [The name of the result]
1210 * @param {[string]} path [The path of the result]
1211 * @param {[string]} keys [The keys to be used (["file", "open"])]
1212 * @param {[object]} parent [The parent of the result]
1213 * @return {[boolean]} [Whether the result is valid or not]
1215 function validateResult(name
, path
, keys
, parent
) {
1216 for (var i
= 0; i
< keys
.length
; ++i
) {
1217 // each check is for validation so we negate the conditions and invalidate
1219 // check for an exact name match
1220 name
.indexOf(keys
[i
]) > -1 ||
1221 // then an exact path match
1222 path
.indexOf(keys
[i
]) > -1 ||
1223 // next if there is a parent, check for exact parent match
1224 (parent
!== undefined && parent
.name
!== undefined &&
1225 parent
.name
.toLowerCase().indexOf(keys
[i
]) > -1) ||
1226 // lastly check to see if the name was a levenshtein match
1227 levenshtein(name
, keys
[i
]) <= MAX_LEV_DISTANCE
)) {
1234 function getQuery(raw
) {
1235 var matches
, type
, query
;
1238 matches
= query
.match(/^(fn|mod|struct|enum|trait|type|const|macro)\s*:\s*/i);
1240 type
= matches
[1].replace(/^const$/, "constant");
1241 query
= query
.substring(matches
[0].length
);
1252 function initSearchNav() {
1255 var click_func = function(e
) {
1257 // to retrieve the real "owner" of the event.
1258 while (el
.tagName
!== "TR") {
1261 var dst
= e
.target
.getElementsByTagName("a");
1262 if (dst
.length
< 1) {
1266 if (window
.location
.pathname
=== dst
.pathname
) {
1267 addClass(getSearchElement(), "hidden");
1268 removeClass(main
, "hidden");
1269 document
.location
.href
= dst
.href
;
1272 var mouseover_func = function(e
) {
1274 // to retrieve the real "owner" of the event.
1275 while (el
.tagName
!== "TR") {
1278 clearTimeout(hoverTimeout
);
1279 hoverTimeout
= setTimeout(function() {
1280 onEachLazy(document
.getElementsByClassName("search-results"), function(e
) {
1281 onEachLazy(e
.getElementsByClassName("result"), function(i_e
) {
1282 removeClass(i_e
, "highlighted");
1285 addClass(el
, "highlighted");
1288 onEachLazy(document
.getElementsByClassName("search-results"), function(e
) {
1289 onEachLazy(e
.getElementsByClassName("result"), function(i_e
) {
1290 i_e
.onclick
= click_func
;
1291 i_e
.onmouseover
= mouseover_func
;
1295 search_input
.onkeydown = function(e
) {
1296 // "actives" references the currently highlighted item in each search tab.
1297 // Each array in "actives" represents a tab.
1298 var actives
= [[], [], []];
1299 // "current" is used to know which tab we're looking into.
1301 onEachLazy(document
.getElementById("results").childNodes
, function(e
) {
1302 onEachLazy(e
.getElementsByClassName("highlighted"), function(e
) {
1303 actives
[current
].push(e
);
1308 if (e
.which
=== 38) { // up
1309 if (!actives
[currentTab
].length
||
1310 !actives
[currentTab
][0].previousElementSibling
) {
1314 addClass(actives
[currentTab
][0].previousElementSibling
, "highlighted");
1315 removeClass(actives
[currentTab
][0], "highlighted");
1316 } else if (e
.which
=== 40) { // down
1317 if (!actives
[currentTab
].length
) {
1318 var results
= document
.getElementById("results").childNodes
;
1319 if (results
.length
> 0) {
1320 var res
= results
[currentTab
].getElementsByClassName("result");
1321 if (res
.length
> 0) {
1322 addClass(res
[0], "highlighted");
1325 } else if (actives
[currentTab
][0].nextElementSibling
) {
1326 addClass(actives
[currentTab
][0].nextElementSibling
, "highlighted");
1327 removeClass(actives
[currentTab
][0], "highlighted");
1329 } else if (e
.which
=== 13) { // return
1330 if (actives
[currentTab
].length
) {
1331 document
.location
.href
=
1332 actives
[currentTab
][0].getElementsByTagName("a")[0].href
;
1334 } else if (e
.which
=== 9) { // tab
1336 printTab(currentTab
> 0 ? currentTab
- 1 : 2);
1338 printTab(currentTab
> 1 ? 0 : currentTab
+ 1);
1341 } else if (e
.which
=== 16) { // shift
1342 // Does nothing, it's just to avoid losing "focus" on the highlighted element.
1343 } else if (e
.which
=== 27) { // escape
1345 } else if (actives
[currentTab
].length
> 0) {
1346 removeClass(actives
[currentTab
][0], "highlighted");
1351 function buildHrefAndPath(item
) {
1354 var type
= itemTypes
[item
.ty
];
1355 var name
= item
.name
;
1357 if (type
=== "mod") {
1358 displayPath
= item
.path
+ "::";
1359 href
= rootPath
+ item
.path
.replace(/::/g, "/") + "/" +
1360 name
+ "/index.html";
1361 } else if (type
=== "primitive" || type
=== "keyword") {
1363 href
= rootPath
+ item
.path
.replace(/::/g, "/") +
1364 "/" + type
+ "." + name
+ ".html";
1365 } else if (type
=== "externcrate") {
1367 href
= rootPath
+ name
+ "/index.html";
1368 } else if (item
.parent
!== undefined) {
1369 var myparent
= item
.parent
;
1370 var anchor
= "#" + type
+ "." + name
;
1371 var parentType
= itemTypes
[myparent
.ty
];
1372 if (parentType
=== "primitive") {
1373 displayPath
= myparent
.name
+ "::";
1375 displayPath
= item
.path
+ "::" + myparent
.name
+ "::";
1377 href
= rootPath
+ item
.path
.replace(/::/g, "/") +
1379 "." + myparent
.name
+
1382 displayPath
= item
.path
+ "::";
1383 href
= rootPath
+ item
.path
.replace(/::/g, "/") +
1384 "/" + type
+ "." + name
+ ".html";
1386 return [displayPath
, href
];
1389 function escape(content
) {
1390 var h1
= document
.createElement("h1");
1391 h1
.textContent
= content
;
1392 return h1
.innerHTML
;
1395 function pathSplitter(path
) {
1396 var tmp
= "<span>" + path
.replace(/::/g, "::</span><span>");
1397 if (tmp
.endsWith("<span>")) {
1398 return tmp
.slice(0, tmp
.length
- 6);
1403 function addTab(array
, query
, display
) {
1404 var extraStyle
= "";
1405 if (display
=== false) {
1406 extraStyle
= " style=\"display: none;\"";
1410 var duplicates
= {};
1412 if (array
.length
> 0) {
1413 output
= "<table class=\"search-results\"" + extraStyle
+ ">";
1415 array
.forEach(function(item
) {
1419 type
= itemTypes
[item
.ty
];
1421 if (item
.is_alias
!== true) {
1422 if (duplicates
[item
.fullPath
]) {
1425 duplicates
[item
.fullPath
] = true;
1429 output
+= "<tr class=\"" + type
+ " result\"><td>" +
1430 "<a href=\"" + item
.href
+ "\">" +
1431 (item
.is_alias
=== true ?
1432 ("<span class=\"alias\"><b>" + item
.alias
+ " </b></span><span " +
1433 "class=\"grey\"><i> - see </i></span>") : "") +
1434 item
.displayPath
+ "<span class=\"" + type
+ "\">" +
1435 name
+ "</span></a></td><td>" +
1436 "<a href=\"" + item
.href
+ "\">" +
1437 "<span class=\"desc\">" + escape(item
.desc
) +
1438 " </span></a></td></tr>";
1440 output
+= "</table>";
1442 output
= "<div class=\"search-failed\"" + extraStyle
+ ">No results :(<br/>" +
1443 "Try on <a href=\"https://duckduckgo.com/?q=" +
1444 encodeURIComponent("rust " + query
.query
) +
1445 "\">DuckDuckGo</a>?<br/><br/>" +
1446 "Or try looking in one of these:<ul><li>The <a " +
1447 "href=\"https://doc.rust-lang.org/reference/index.html\">Rust Reference</a> " +
1448 " for technical details about the language.</li><li><a " +
1449 "href=\"https://doc.rust-lang.org/rust-by-example/index.html\">Rust By " +
1450 "Example</a> for expository code examples.</a></li><li>The <a " +
1451 "href=\"https://doc.rust-lang.org/book/index.html\">Rust Book</a> for " +
1452 "introductions to language features and the language itself.</li><li><a " +
1453 "href=\"https://docs.rs\">Docs.rs</a> for documentation of crates released on" +
1454 " <a href=\"https://crates.io/\">crates.io</a>.</li></ul></div>";
1456 return [output
, length
];
1459 function makeTabHeader(tabNb
, text
, nbElems
) {
1460 if (currentTab
=== tabNb
) {
1461 return "<div class=\"selected\">" + text
+
1462 " <div class=\"count\">(" + nbElems
+ ")</div></div>";
1464 return "<div>" + text
+ " <div class=\"count\">(" + nbElems
+ ")</div></div>";
1467 function showResults(results
) {
1468 if (results
.others
.length
=== 1 &&
1469 getCurrentValue("rustdoc-go-to-only-result") === "true") {
1470 var elem
= document
.createElement("a");
1471 elem
.href
= results
.others
[0].href
;
1472 elem
.style
.display
= "none";
1473 // For firefox, we need the element to be in the DOM so it can be clicked.
1474 document
.body
.appendChild(elem
);
1477 var query
= getQuery(search_input
.value
);
1479 currentResults
= query
.id
;
1481 var ret_others
= addTab(results
.others
, query
);
1482 var ret_in_args
= addTab(results
.in_args
, query
, false);
1483 var ret_returned
= addTab(results
.returned
, query
, false);
1485 var output
= "<h1>Results for " + escape(query
.query
) +
1486 (query
.type
? " (type: " + escape(query
.type
) + ")" : "") + "</h1>" +
1487 "<div id=\"titles\">" +
1488 makeTabHeader(0, "In Names", ret_others
[1]) +
1489 makeTabHeader(1, "In Parameters", ret_in_args
[1]) +
1490 makeTabHeader(2, "In Return Types", ret_returned
[1]) +
1491 "</div><div id=\"results\">" +
1492 ret_others
[0] + ret_in_args
[0] + ret_returned
[0] + "</div>";
1494 addClass(main
, "hidden");
1495 var search
= getSearchElement();
1496 removeClass(search
, "hidden");
1497 search
.innerHTML
= output
;
1498 var tds
= search
.getElementsByTagName("td");
1500 if (tds
.length
> 0) {
1501 td_width
= tds
[0].offsetWidth
;
1503 var width
= search
.offsetWidth
- 40 - td_width
;
1504 onEachLazy(search
.getElementsByClassName("desc"), function(e
) {
1505 e
.style
.width
= width
+ "px";
1508 var elems
= document
.getElementById("titles").childNodes
;
1509 elems
[0].onclick = function() { printTab(0); };
1510 elems
[1].onclick = function() { printTab(1); };
1511 elems
[2].onclick = function() { printTab(2); };
1512 printTab(currentTab
);
1515 function execSearch(query
, searchWords
, filterCrates
) {
1516 function getSmallest(arrays
, positions
, notDuplicates
) {
1519 for (var it
= 0; it
< positions
.length
; ++it
) {
1520 if (arrays
[it
].length
> positions
[it
] &&
1521 (start
=== null || start
> arrays
[it
][positions
[it
]].lev
) &&
1522 !notDuplicates
[arrays
[it
][positions
[it
]].fullPath
]) {
1523 start
= arrays
[it
][positions
[it
]].lev
;
1529 function mergeArrays(arrays
) {
1532 var notDuplicates
= {};
1534 for (var x
= 0; x
< arrays
.length
; ++x
) {
1537 while (ret
.length
< MAX_RESULTS
) {
1538 var smallest
= getSmallest(arrays
, positions
, notDuplicates
);
1540 if (smallest
=== null) {
1543 for (x
= 0; x
< arrays
.length
&& ret
.length
< MAX_RESULTS
; ++x
) {
1544 if (arrays
[x
].length
> positions
[x
] &&
1545 arrays
[x
][positions
[x
]].lev
=== smallest
&&
1546 !notDuplicates
[arrays
[x
][positions
[x
]].fullPath
]) {
1547 ret
.push(arrays
[x
][positions
[x
]]);
1548 notDuplicates
[arrays
[x
][positions
[x
]].fullPath
] = true;
1556 var queries
= query
.raw
.split(",");
1563 for (var i
= 0; i
< queries
.length
; ++i
) {
1564 query
= queries
[i
].trim();
1565 if (query
.length
!== 0) {
1566 var tmp
= execQuery(getQuery(query
), searchWords
, filterCrates
);
1568 results
.in_args
.push(tmp
.in_args
);
1569 results
.returned
.push(tmp
.returned
);
1570 results
.others
.push(tmp
.others
);
1573 if (queries
.length
> 1) {
1575 "in_args": mergeArrays(results
.in_args
),
1576 "returned": mergeArrays(results
.returned
),
1577 "others": mergeArrays(results
.others
),
1581 "in_args": results
.in_args
[0],
1582 "returned": results
.returned
[0],
1583 "others": results
.others
[0],
1588 function getFilterCrates() {
1589 var elem
= document
.getElementById("crate-search");
1591 if (elem
&& elem
.value
!== "All crates" && rawSearchIndex
.hasOwnProperty(elem
.value
)) {
1597 function search(e
, forced
) {
1598 var params
= getQueryStringParams();
1599 var query
= getQuery(search_input
.value
.trim());
1605 if (query
.query
.length
=== 0) {
1608 if (forced
!== true && query
.id
=== currentResults
) {
1609 if (query
.query
.length
> 0) {
1610 putBackSearch(search_input
);
1615 // Update document title to maintain a meaningful browser history
1616 document
.title
= "Results for " + query
.query
+ " - Rust";
1618 // Because searching is incremental by character, only the most
1619 // recent search query is added to the browser history.
1620 if (browserSupportsHistoryApi()) {
1621 if (!history
.state
&& !params
.search
) {
1622 history
.pushState(query
, "", "?search=" + encodeURIComponent(query
.raw
));
1624 history
.replaceState(query
, "", "?search=" + encodeURIComponent(query
.raw
));
1628 var filterCrates
= getFilterCrates();
1629 showResults(execSearch(query
, index
, filterCrates
));
1632 function buildIndex(rawSearchIndex
) {
1634 var searchWords
= [];
1637 for (var crate
in rawSearchIndex
) {
1638 if (!rawSearchIndex
.hasOwnProperty(crate
)) { continue; }
1640 searchWords
.push(crate
);
1643 ty
: 1, // == ExternCrate
1646 desc
: rawSearchIndex
[crate
].doc
,
1650 // an array of [(Number) item type,
1652 // (String) full path or empty string for previous path,
1653 // (String) description,
1654 // (Number | null) the parent path index to `paths`]
1655 // (Object | null) the type of the function (if any)
1656 var items
= rawSearchIndex
[crate
].i
;
1657 // an array of [(Number) item type,
1659 var paths
= rawSearchIndex
[crate
].p
;
1661 // convert `paths` into an object form
1662 var len
= paths
.length
;
1663 for (i
= 0; i
< len
; ++i
) {
1664 paths
[i
] = {ty
: paths
[i
][0], name
: paths
[i
][1]};
1667 // convert `items` into an object form, and construct word indices.
1669 // before any analysis is performed lets gather the search terms to
1670 // search against apart from the rest of the data. This is a quick
1671 // operation that is cached for the life of the page state so that
1672 // all other search operations have access to this cached data for
1673 // faster analysis operations
1676 for (i
= 0; i
< len
; ++i
) {
1677 var rawRow
= items
[i
];
1678 var row
= {crate
: crate
, ty
: rawRow
[0], name
: rawRow
[1],
1679 path
: rawRow
[2] || lastPath
, desc
: rawRow
[3],
1680 parent
: paths
[rawRow
[4]], type
: rawRow
[5]};
1681 searchIndex
.push(row
);
1682 if (typeof row
.name
=== "string") {
1683 var word
= row
.name
.toLowerCase();
1684 searchWords
.push(word
);
1686 searchWords
.push("");
1688 lastPath
= row
.path
;
1694 function startSearch() {
1696 var callback = function() {
1697 clearTimeout(searchTimeout
);
1698 if (search_input
.value
.length
=== 0) {
1699 if (browserSupportsHistoryApi()) {
1700 history
.replaceState("", window
.currentCrate
+ " - Rust", "?search=");
1702 if (hasClass(main
, "content")) {
1703 removeClass(main
, "hidden");
1705 var search_c
= getSearchElement();
1706 if (hasClass(search_c
, "content")) {
1707 addClass(search_c
, "hidden");
1710 searchTimeout
= setTimeout(search
, 500);
1713 search_input
.onkeyup
= callback
;
1714 search_input
.oninput
= callback
;
1715 document
.getElementsByClassName("search-form")[0].onsubmit = function(e
) {
1717 clearTimeout(searchTimeout
);
1720 search_input
.onchange = function(e
) {
1721 // Do NOT e.preventDefault() here. It will prevent pasting.
1722 clearTimeout(searchTimeout
);
1723 // zero-timeout necessary here because at the time of event handler execution the
1724 // pasted content is not in the input field yet. Shouldn’t make any difference for
1726 setTimeout(search
, 0);
1728 search_input
.onpaste
= search_input
.onchange
;
1730 var selectCrate
= document
.getElementById("crate-search");
1732 selectCrate
.onchange = function() {
1733 updateLocalStorage("rustdoc-saved-filter-crate", selectCrate
.value
);
1734 search(undefined, true);
1738 // Push and pop states are used to add search results to the browser
1740 if (browserSupportsHistoryApi()) {
1741 // Store the previous <title> so we can revert back to it later.
1742 var previousTitle
= document
.title
;
1744 window
.onpopstate = function(e
) {
1745 var params
= getQueryStringParams();
1746 // When browsing back from search results the main page
1747 // visibility must be reset.
1748 if (!params
.search
) {
1749 if (hasClass(main
, "content")) {
1750 removeClass(main
, "hidden");
1752 var search_c
= getSearchElement();
1753 if (hasClass(search_c
, "content")) {
1754 addClass(search_c
, "hidden");
1757 // Revert to the previous title manually since the History
1758 // API ignores the title parameter.
1759 document
.title
= previousTitle
;
1760 // When browsing forward to search results the previous
1761 // search will be repeated, so the currentResults are
1762 // cleared to ensure the search is successful.
1763 currentResults
= null;
1764 // Synchronize search bar with query string state and
1765 // perform the search. This will empty the bar if there's
1766 // nothing there, which lets you really go back to a
1767 // previous state with nothing in the bar.
1768 if (params
.search
) {
1769 search_input
.value
= params
.search
;
1771 search_input
.value
= "";
1773 // Some browsers fire "onpopstate" for every page load
1774 // (Chrome), while others fire the event only when actually
1775 // popping a state (Firefox), which is why search() is
1776 // called both here and at the end of the startSearch()
1784 index
= buildIndex(rawSearchIndex
);
1787 // Draw a convenient sidebar of known crates if we have a listing
1788 if (rootPath
=== "../" || rootPath
=== "./") {
1789 var sidebar
= document
.getElementsByClassName("sidebar-elems")[0];
1791 var div
= document
.createElement("div");
1792 div
.className
= "block crate";
1793 div
.innerHTML
= "<h3>Crates</h3>";
1794 var ul
= document
.createElement("ul");
1795 div
.appendChild(ul
);
1798 for (var crate
in rawSearchIndex
) {
1799 if (!rawSearchIndex
.hasOwnProperty(crate
)) {
1805 for (var i
= 0; i
< crates
.length
; ++i
) {
1806 var klass
= "crate";
1807 if (rootPath
!== "./" && crates
[i
] === window
.currentCrate
) {
1808 klass
+= " current";
1810 var link
= document
.createElement("a");
1811 link
.href
= rootPath
+ crates
[i
] + "/index.html";
1812 link
.title
= rawSearchIndex
[crates
[i
]].doc
;
1813 link
.className
= klass
;
1814 link
.textContent
= crates
[i
];
1816 var li
= document
.createElement("li");
1817 li
.appendChild(link
);
1820 sidebar
.appendChild(div
);
1825 window
.initSearch
= initSearch
;
1827 // delayed sidebar rendering.
1828 function initSidebarItems(items
) {
1829 var sidebar
= document
.getElementsByClassName("sidebar-elems")[0];
1830 var current
= window
.sidebarCurrent
;
1832 function block(shortty
, longty
) {
1833 var filtered
= items
[shortty
];
1838 var div
= document
.createElement("div");
1839 div
.className
= "block " + shortty
;
1840 var h3
= document
.createElement("h3");
1841 h3
.textContent
= longty
;
1842 div
.appendChild(h3
);
1843 var ul
= document
.createElement("ul");
1845 var length
= filtered
.length
;
1846 for (var i
= 0; i
< length
; ++i
) {
1847 var item
= filtered
[i
];
1849 var desc
= item
[1]; // can be null
1851 var klass
= shortty
;
1852 if (name
=== current
.name
&& shortty
=== current
.ty
) {
1853 klass
+= " current";
1856 if (shortty
=== "mod") {
1857 path
= name
+ "/index.html";
1859 path
= shortty
+ "." + name
+ ".html";
1861 var link
= document
.createElement("a");
1862 link
.href
= current
.relpath
+ path
;
1864 link
.className
= klass
;
1865 link
.textContent
= name
;
1866 var li
= document
.createElement("li");
1867 li
.appendChild(link
);
1870 div
.appendChild(ul
);
1872 sidebar
.appendChild(div
);
1876 block("primitive", "Primitive Types");
1877 block("mod", "Modules");
1878 block("macro", "Macros");
1879 block("struct", "Structs");
1880 block("enum", "Enums");
1881 block("union", "Unions");
1882 block("constant", "Constants");
1883 block("static", "Statics");
1884 block("trait", "Traits");
1885 block("fn", "Functions");
1886 block("type", "Type Definitions");
1887 block("foreigntype", "Foreign Types");
1888 block("keyword", "Keywords");
1889 block("traitalias", "Trait Aliases");
1892 window
.initSidebarItems
= initSidebarItems
;
1894 window
.register_implementors = function(imp
) {
1895 var implementors
= document
.getElementById("implementors-list");
1896 var synthetic_implementors
= document
.getElementById("synthetic-implementors-list");
1898 var libs
= Object
.getOwnPropertyNames(imp
);
1899 var llength
= libs
.length
;
1900 for (var i
= 0; i
< llength
; ++i
) {
1901 if (libs
[i
] === currentCrate
) { continue; }
1902 var structs
= imp
[libs
[i
]];
1904 var slength
= structs
.length
;
1906 for (var j
= 0; j
< slength
; ++j
) {
1907 var struct
= structs
[j
];
1909 var list
= struct
.synthetic
? synthetic_implementors
: implementors
;
1911 if (struct
.synthetic
) {
1912 var stlength
= struct
.types
.length
;
1913 for (var k
= 0; k
< stlength
; k
++) {
1914 if (window
.inlined_types
.has(struct
.types
[k
])) {
1915 continue struct_loop
;
1917 window
.inlined_types
.add(struct
.types
[k
]);
1921 var code
= document
.createElement("code");
1922 code
.innerHTML
= struct
.text
;
1924 var x
= code
.getElementsByTagName("a");
1925 var xlength
= x
.length
;
1926 for (var it
= 0; it
< xlength
; it
++) {
1927 var href
= x
[it
].getAttribute("href");
1928 if (href
&& href
.indexOf("http") !== 0) {
1929 x
[it
].setAttribute("href", rootPath
+ href
);
1932 var display
= document
.createElement("h3");
1933 addClass(display
, "impl");
1934 display
.innerHTML
= "<span class=\"in-band\"><table class=\"table-display\">" +
1935 "<tbody><tr><td><code>" + code
.outerHTML
+ "</code></td><td></td></tr>" +
1936 "</tbody></table></span>";
1937 list
.appendChild(display
);
1941 if (window
.pending_implementors
) {
1942 window
.register_implementors(window
.pending_implementors
);
1945 function labelForToggleButton(sectionIsCollapsed
) {
1946 if (sectionIsCollapsed
) {
1947 // button will expand the section
1950 // button will collapse the section
1951 // note that this text is also set in the HTML template in render.rs
1952 return "\u2212"; // "\u2212" is "−" minus sign
1955 function onEveryMatchingChild(elem
, className
, func
) {
1956 if (elem
&& className
&& func
) {
1957 var length
= elem
.childNodes
.length
;
1958 var nodes
= elem
.childNodes
;
1959 for (var i
= 0; i
< length
; ++i
) {
1960 if (hasClass(nodes
[i
], className
)) {
1963 onEveryMatchingChild(nodes
[i
], className
, func
);
1969 function toggleAllDocs(pageId
, fromAutoCollapse
) {
1970 var innerToggle
= document
.getElementById("toggle-all-docs");
1974 if (hasClass(innerToggle
, "will-expand")) {
1975 updateLocalStorage("rustdoc-collapse", "false");
1976 removeClass(innerToggle
, "will-expand");
1977 onEveryMatchingChild(innerToggle
, "inner", function(e
) {
1978 e
.innerHTML
= labelForToggleButton(false);
1980 innerToggle
.title
= "collapse all docs";
1981 if (fromAutoCollapse
!== true) {
1982 onEachLazy(document
.getElementsByClassName("collapse-toggle"), function(e
) {
1983 collapseDocs(e
, "show");
1987 updateLocalStorage("rustdoc-collapse", "true");
1988 addClass(innerToggle
, "will-expand");
1989 onEveryMatchingChild(innerToggle
, "inner", function(e
) {
1990 var parent
= e
.parentNode
;
1991 var superParent
= null;
1994 superParent
= parent
.parentNode
;
1996 if (!parent
|| !superParent
|| superParent
.id
!== "main" ||
1997 hasClass(parent
, "impl") === false) {
1998 e
.innerHTML
= labelForToggleButton(true);
2001 innerToggle
.title
= "expand all docs";
2002 if (fromAutoCollapse
!== true) {
2003 onEachLazy(document
.getElementsByClassName("collapse-toggle"), function(e
) {
2004 var parent
= e
.parentNode
;
2005 var superParent
= null;
2008 superParent
= parent
.parentNode
;
2010 if (!parent
|| !superParent
|| superParent
.id
!== "main" ||
2011 hasClass(parent
, "impl") === false) {
2012 collapseDocs(e
, "hide", pageId
);
2019 function collapseDocs(toggle
, mode
, pageId
) {
2020 if (!toggle
|| !toggle
.parentNode
) {
2024 function adjustToggle(arg
) {
2025 return function(e
) {
2026 if (hasClass(e
, "toggle-label")) {
2028 e
.style
.display
= "inline-block";
2030 e
.style
.display
= "none";
2033 if (hasClass(e
, "inner")) {
2034 e
.innerHTML
= labelForToggleButton(arg
);
2039 function implHider(addOrRemove
, fullHide
) {
2040 return function(n
) {
2041 var is_method
= hasClass(n
, "method") || fullHide
;
2042 if (is_method
|| hasClass(n
, "type")) {
2043 if (is_method
=== true) {
2045 addClass(n
, "hidden-by-impl-hider");
2047 removeClass(n
, "hidden-by-impl-hider");
2050 var ns
= n
.nextElementSibling
;
2053 hasClass(ns
, "docblock") ||
2054 hasClass(ns
, "stability"))) {
2056 addClass(ns
, "hidden-by-impl-hider");
2058 removeClass(ns
, "hidden-by-impl-hider");
2060 ns
= ns
.nextElementSibling
;
2071 if (hasClass(toggle
.parentNode
, "impl") === false) {
2072 relatedDoc
= toggle
.parentNode
.nextElementSibling
;
2073 if (hasClass(relatedDoc
, "stability")) {
2074 relatedDoc
= relatedDoc
.nextElementSibling
;
2076 if (hasClass(relatedDoc
, "docblock") || hasClass(relatedDoc
, "sub-variant")) {
2077 if (mode
=== "toggle") {
2078 if (hasClass(relatedDoc
, "hidden-by-usual-hider")) {
2084 if (action
=== "hide") {
2085 addClass(relatedDoc
, "hidden-by-usual-hider");
2086 onEachLazy(toggle
.childNodes
, adjustToggle(true));
2087 addClass(toggle
.parentNode
, "collapsed");
2088 } else if (action
=== "show") {
2089 removeClass(relatedDoc
, "hidden-by-usual-hider");
2090 removeClass(toggle
.parentNode
, "collapsed");
2091 onEachLazy(toggle
.childNodes
, adjustToggle(false));
2095 // we are collapsing the impl block(s).
2097 var parentElem
= toggle
.parentNode
;
2098 relatedDoc
= parentElem
;
2099 var docblock
= relatedDoc
.nextElementSibling
;
2101 while (hasClass(relatedDoc
, "impl-items") === false) {
2102 relatedDoc
= relatedDoc
.nextElementSibling
;
2105 if ((!relatedDoc
&& hasClass(docblock
, "docblock") === false) ||
2106 (pageId
&& document
.getElementById(pageId
))) {
2110 // Hide all functions, but not associated types/consts.
2112 if (mode
=== "toggle") {
2113 if (hasClass(relatedDoc
, "fns-now-collapsed") ||
2114 hasClass(docblock
, "hidden-by-impl-hider")) {
2121 var dontApplyBlockRule
= toggle
.parentNode
.parentNode
.id
!== "main";
2122 if (action
=== "show") {
2123 removeClass(relatedDoc
, "fns-now-collapsed");
2124 removeClass(docblock
, "hidden-by-usual-hider");
2125 onEachLazy(toggle
.childNodes
, adjustToggle(false, dontApplyBlockRule
));
2126 onEachLazy(relatedDoc
.childNodes
, implHider(false, dontApplyBlockRule
));
2127 } else if (action
=== "hide") {
2128 addClass(relatedDoc
, "fns-now-collapsed");
2129 addClass(docblock
, "hidden-by-usual-hider");
2130 onEachLazy(toggle
.childNodes
, adjustToggle(true, dontApplyBlockRule
));
2131 onEachLazy(relatedDoc
.childNodes
, implHider(true, dontApplyBlockRule
));
2136 function collapser(e
, collapse
) {
2137 // inherent impl ids are like "impl" or impl-<number>'.
2138 // they will never be hidden by default.
2139 var n
= e
.parentElement
;
2140 if (n
.id
.match(/^impl(?:-\d+)?$/) === null) {
2141 // Automatically minimize all non-inherent impls
2142 if (collapse
|| hasClass(n
, "impl")) {
2143 collapseDocs(e
, "hide", pageId
);
2148 function autoCollapse(pageId
, collapse
) {
2150 toggleAllDocs(pageId
, true);
2151 } else if (getCurrentValue("rustdoc-auto-hide-trait-implementations") !== "false") {
2152 var impl_list
= document
.getElementById("implementations-list");
2154 if (impl_list
!== null) {
2155 onEachLazy(impl_list
.getElementsByClassName("collapse-toggle"), function(e
) {
2156 collapser(e
, collapse
);
2160 var blanket_list
= document
.getElementById("blanket-implementations-list");
2162 if (blanket_list
!== null) {
2163 onEachLazy(blanket_list
.getElementsByClassName("collapse-toggle"), function(e
) {
2164 collapser(e
, collapse
);
2170 var toggles
= document
.getElementById("toggle-all-docs");
2172 toggles
.onclick
= toggleAllDocs
;
2175 function insertAfter(newNode
, referenceNode
) {
2176 referenceNode
.parentNode
.insertBefore(newNode
, referenceNode
.nextSibling
);
2179 function createSimpleToggle(sectionIsCollapsed
) {
2180 var toggle
= document
.createElement("a");
2181 toggle
.href
= "javascript:void(0)";
2182 toggle
.className
= "collapse-toggle";
2183 toggle
.innerHTML
= "[<span class=\"inner\">" + labelForToggleButton(sectionIsCollapsed
) +
2188 var toggle
= createSimpleToggle(false);
2189 var hideMethodDocs
= getCurrentValue("rustdoc-auto-hide-method-docs") === "true";
2190 var pageId
= getPageId();
2192 var func = function(e
) {
2193 var next
= e
.nextElementSibling
;
2197 if (hasClass(next
, "docblock") === true ||
2198 (hasClass(next
, "stability") === true &&
2199 hasClass(next
.nextElementSibling
, "docblock") === true)) {
2200 var newToggle
= toggle
.cloneNode(true);
2201 insertAfter(newToggle
, e
.childNodes
[e
.childNodes
.length
- 1]);
2202 if (hideMethodDocs
=== true && hasClass(e
, "method") === true) {
2203 collapseDocs(newToggle
, "hide", pageId
);
2208 var funcImpl = function(e
) {
2209 var next
= e
.nextElementSibling
;
2210 if (next
&& hasClass(next
, "docblock")) {
2211 next
= next
.nextElementSibling
;
2216 if (next
.getElementsByClassName("method").length
> 0 && hasClass(e
, "impl")) {
2217 insertAfter(toggle
.cloneNode(true), e
.childNodes
[e
.childNodes
.length
- 1]);
2221 onEachLazy(document
.getElementsByClassName("method"), func
);
2222 onEachLazy(document
.getElementsByClassName("associatedconstant"), func
);
2223 onEachLazy(document
.getElementsByClassName("impl"), funcImpl
);
2224 var impl_call = function() {};
2225 if (hideMethodDocs
=== true) {
2226 impl_call = function(e
, newToggle
, pageId
) {
2227 if (e
.id
.match(/^impl(?:-\d+)?$/) === null) {
2228 // Automatically minimize all non-inherent impls
2229 if (hasClass(e
, "impl") === true) {
2230 collapseDocs(newToggle
, "hide", pageId
);
2235 var newToggle
= document
.createElement("a");
2236 newToggle
.href
= "javascript:void(0)";
2237 newToggle
.className
= "collapse-toggle hidden-default collapsed";
2238 newToggle
.innerHTML
= "[<span class=\"inner\">" + labelForToggleButton(true) +
2239 "</span>] Show hidden undocumented items";
2240 function toggleClicked() {
2241 if (hasClass(this, "collapsed")) {
2242 removeClass(this, "collapsed");
2243 onEachLazy(this.parentNode
.getElementsByClassName("hidden"), function(x
) {
2244 if (hasClass(x
, "content") === false) {
2245 removeClass(x
, "hidden");
2249 this.innerHTML
= "[<span class=\"inner\">" + labelForToggleButton(false) +
2250 "</span>] Hide undocumented items";
2252 addClass(this, "collapsed");
2253 onEachLazy(this.parentNode
.getElementsByClassName("x"), function(x
) {
2254 if (hasClass(x
, "content") === false) {
2255 addClass(x
, "hidden");
2256 removeClass(x
, "x");
2259 this.innerHTML
= "[<span class=\"inner\">" + labelForToggleButton(true) +
2260 "</span>] Show hidden undocumented items";
2263 onEachLazy(document
.getElementsByClassName("impl-items"), function(e
) {
2264 onEachLazy(e
.getElementsByClassName("associatedconstant"), func
);
2265 var hiddenElems
= e
.getElementsByClassName("hidden");
2266 var needToggle
= false;
2268 var hlength
= hiddenElems
.length
;
2269 for (var i
= 0; i
< hlength
; ++i
) {
2270 if (hasClass(hiddenElems
[i
], "content") === false &&
2271 hasClass(hiddenElems
[i
], "docblock") === false) {
2276 if (needToggle
=== true) {
2277 var inner_toggle
= newToggle
.cloneNode(true);
2278 inner_toggle
.onclick
= toggleClicked
;
2279 e
.insertBefore(inner_toggle
, e
.firstChild
);
2280 impl_call(e
.previousSibling
, inner_toggle
, pageId
);
2284 function createToggle(otherMessage
, fontSize
, extraClass
, show
) {
2285 var span
= document
.createElement("span");
2286 span
.className
= "toggle-label";
2288 span
.style
.display
= "none";
2290 if (!otherMessage
) {
2291 span
.innerHTML
= " Expand description";
2293 span
.innerHTML
= otherMessage
;
2297 span
.style
.fontSize
= fontSize
;
2300 var mainToggle
= toggle
.cloneNode(true);
2301 mainToggle
.appendChild(span
);
2303 var wrapper
= document
.createElement("div");
2304 wrapper
.className
= "toggle-wrapper";
2306 addClass(wrapper
, "collapsed");
2307 var inner
= mainToggle
.getElementsByClassName("inner");
2308 if (inner
&& inner
.length
> 0) {
2309 inner
[0].innerHTML
= "+";
2313 addClass(wrapper
, extraClass
);
2315 wrapper
.appendChild(mainToggle
);
2319 var currentType
= document
.getElementsByClassName("type-decl")[0];
2320 var className
= null;
2322 currentType
= currentType
.getElementsByClassName("rust")[0];
2324 currentType
.classList
.forEach(function(item
) {
2325 if (item
!== "main") {
2332 var showItemDeclarations
= getCurrentValue("rustdoc-auto-hide-" + className
);
2333 if (showItemDeclarations
=== null) {
2334 if (className
=== "enum" || className
=== "macro") {
2335 showItemDeclarations
= "false";
2336 } else if (className
=== "struct" || className
=== "union" || className
=== "trait") {
2337 showItemDeclarations
= "true";
2339 // In case we found an unknown type, we just use the "parent" value.
2340 showItemDeclarations
= getCurrentValue("rustdoc-auto-hide-declarations");
2343 showItemDeclarations
= showItemDeclarations
=== "false";
2344 function buildToggleWrapper(e
) {
2345 if (hasClass(e
, "autohide")) {
2346 var wrap
= e
.previousElementSibling
;
2347 if (wrap
&& hasClass(wrap
, "toggle-wrapper")) {
2348 var inner_toggle
= wrap
.childNodes
[0];
2349 var extra
= e
.childNodes
[0].tagName
=== "H3";
2351 e
.style
.display
= "none";
2352 addClass(wrap
, "collapsed");
2353 onEachLazy(inner_toggle
.getElementsByClassName("inner"), function(e
) {
2354 e
.innerHTML
= labelForToggleButton(true);
2356 onEachLazy(inner_toggle
.getElementsByClassName("toggle-label"), function(e
) {
2357 e
.style
.display
= "inline-block";
2358 if (extra
=== true) {
2359 i_e
.innerHTML
= " Show " + e
.childNodes
[0].innerHTML
;
2364 if (e
.parentNode
.id
=== "main") {
2365 var otherMessage
= "";
2369 if (hasClass(e
, "type-decl")) {
2371 otherMessage
= " Show declaration";
2372 if (showItemDeclarations
=== false) {
2373 extraClass
= "collapsed";
2375 } else if (hasClass(e
, "sub-variant")) {
2376 otherMessage
= " Show fields";
2377 } else if (hasClass(e
, "non-exhaustive")) {
2378 otherMessage
= " This ";
2379 if (hasClass(e
, "non-exhaustive-struct")) {
2380 otherMessage
+= "struct";
2381 } else if (hasClass(e
, "non-exhaustive-enum")) {
2382 otherMessage
+= "enum";
2383 } else if (hasClass(e
, "non-exhaustive-variant")) {
2384 otherMessage
+= "enum variant";
2385 } else if (hasClass(e
, "non-exhaustive-type")) {
2386 otherMessage
+= "type";
2388 otherMessage
+= " is marked as non-exhaustive";
2389 } else if (hasClass(e
.childNodes
[0], "impl-items")) {
2390 extraClass
= "marg-left";
2393 e
.parentNode
.insertBefore(
2394 createToggle(otherMessage
,
2397 hasClass(e
, "type-decl") === false || showItemDeclarations
=== true),
2399 if (hasClass(e
, "type-decl") === true && showItemDeclarations
=== true) {
2400 collapseDocs(e
.previousSibling
.childNodes
[0], "toggle");
2402 if (hasClass(e
, "non-exhaustive") === true) {
2403 collapseDocs(e
.previousSibling
.childNodes
[0], "toggle");
2408 onEachLazy(document
.getElementsByClassName("docblock"), buildToggleWrapper
);
2409 onEachLazy(document
.getElementsByClassName("sub-variant"), buildToggleWrapper
);
2411 function createToggleWrapper(tog
) {
2412 var span
= document
.createElement("span");
2413 span
.className
= "toggle-label";
2414 span
.style
.display
= "none";
2415 span
.innerHTML
= " Expand attributes";
2416 tog
.appendChild(span
);
2418 var wrapper
= document
.createElement("div");
2419 wrapper
.className
= "toggle-wrapper toggle-attributes";
2420 wrapper
.appendChild(tog
);
2424 // To avoid checking on "rustdoc-item-attributes" value on every loop...
2425 var itemAttributesFunc = function() {};
2426 if (getCurrentValue("rustdoc-auto-hide-attributes") !== "false") {
2427 itemAttributesFunc = function(x
) {
2428 collapseDocs(x
.previousSibling
.childNodes
[0], "toggle");
2431 var attributesToggle
= createToggleWrapper(createSimpleToggle(false));
2432 onEachLazy(main
.getElementsByClassName("attributes"), function(i_e
) {
2433 var attr_tog
= attributesToggle
.cloneNode(true);
2434 if (hasClass(i_e
, "top-attr") === true) {
2435 addClass(attr_tog
, "top-attr");
2437 i_e
.parentNode
.insertBefore(attr_tog
, i_e
);
2438 itemAttributesFunc(i_e
);
2441 // To avoid checking on "rustdoc-line-numbers" value on every loop...
2442 var lineNumbersFunc = function() {};
2443 if (getCurrentValue("rustdoc-line-numbers") === "true") {
2444 lineNumbersFunc = function(x
) {
2445 var count
= x
.textContent
.split("\n").length
;
2447 for (var i
= 0; i
< count
; ++i
) {
2450 var node
= document
.createElement("pre");
2451 addClass(node
, "line-number");
2452 node
.innerHTML
= elems
.join("\n");
2453 x
.parentNode
.insertBefore(node
, x
);
2456 onEachLazy(document
.getElementsByClassName("rust-example-rendered"), function(e
) {
2457 if (hasClass(e
, "compile_fail")) {
2458 e
.addEventListener("mouseover", function(event
) {
2459 this.parentElement
.previousElementSibling
.childNodes
[0].style
.color
= "#f00";
2461 e
.addEventListener("mouseout", function(event
) {
2462 this.parentElement
.previousElementSibling
.childNodes
[0].style
.color
= "";
2464 } else if (hasClass(e
, "ignore")) {
2465 e
.addEventListener("mouseover", function(event
) {
2466 this.parentElement
.previousElementSibling
.childNodes
[0].style
.color
= "#ff9200";
2468 e
.addEventListener("mouseout", function(event
) {
2469 this.parentElement
.previousElementSibling
.childNodes
[0].style
.color
= "";
2475 function showModal(content
) {
2476 var modal
= document
.createElement("div");
2477 modal
.id
= "important";
2478 addClass(modal
, "modal");
2479 modal
.innerHTML
= "<div class=\"modal-content\"><div class=\"close\" id=\"modal-close\">✕" +
2480 "</div><div class=\"whiter\"></div><span class=\"docblock\">" + content
+
2482 document
.getElementsByTagName("body")[0].appendChild(modal
);
2483 document
.getElementById("modal-close").onclick
= hideModal
;
2484 modal
.onclick
= hideModal
;
2487 function hideModal() {
2488 var modal
= document
.getElementById("important");
2490 modal
.parentNode
.removeChild(modal
);
2494 onEachLazy(document
.getElementsByClassName("important-traits"), function(e
) {
2495 e
.onclick = function() {
2496 showModal(e
.lastElementChild
.innerHTML
);
2500 // In the search display, allows to switch between tabs.
2501 function printTab(nb
) {
2502 if (nb
=== 0 || nb
=== 1 || nb
=== 2) {
2506 onEachLazy(document
.getElementById("titles").childNodes
, function(elem
) {
2507 if (nb_copy
=== 0) {
2508 addClass(elem
, "selected");
2510 removeClass(elem
, "selected");
2514 onEachLazy(document
.getElementById("results").childNodes
, function(elem
) {
2516 elem
.style
.display
= "";
2518 elem
.style
.display
= "none";
2524 function putBackSearch(search_input
) {
2525 if (search_input
.value
!== "") {
2526 addClass(main
, "hidden");
2527 removeClass(getSearchElement(), "hidden");
2528 if (browserSupportsHistoryApi()) {
2529 history
.replaceState(search_input
.value
,
2531 "?search=" + encodeURIComponent(search_input
.value
));
2537 search_input
.onfocus = function() {
2538 putBackSearch(this);
2542 var params
= getQueryStringParams();
2543 if (params
&& params
.search
) {
2544 addClass(main
, "hidden");
2545 var search
= getSearchElement();
2546 removeClass(search
, "hidden");
2547 search
.innerHTML
= "<h3 style=\"text-align: center;\">Loading search results...</h3>";
2550 var sidebar_menu
= document
.getElementsByClassName("sidebar-menu")[0];
2552 sidebar_menu
.onclick = function() {
2553 var sidebar
= document
.getElementsByClassName("sidebar")[0];
2554 if (hasClass(sidebar
, "mobile") === true) {
2562 window
.onresize = function() {
2566 autoCollapse(getPageId(), getCurrentValue("rustdoc-collapse") === "true");
2568 if (window
.location
.hash
&& window
.location
.hash
.length
> 0) {
2569 expandSection(window
.location
.hash
.replace(/^#/, ""));
2573 onEachLazy(main
.getElementsByClassName("loading-content"), function(e
) {
2576 onEachLazy(main
.childNodes
, function(e
) {
2577 // Unhide the actual content once loading is complete. Headers get
2578 // flex treatment for their horizontal layout, divs get block treatment
2579 // for vertical layout (column-oriented flex layout for divs caused
2580 // errors in mobile browsers).
2581 if (e
.tagName
=== "H2" || e
.tagName
=== "H3") {
2582 var nextTagName
= e
.nextElementSibling
.tagName
;
2583 if (nextTagName
== "H2" || nextTagName
== "H3") {
2584 e
.nextElementSibling
.style
.display
= "flex";
2586 e
.nextElementSibling
.style
.display
= "block";
2592 function addSearchOptions(crates
) {
2593 var elem
= document
.getElementById("crate-search");
2598 var crates_text
= [];
2599 if (Object
.keys(crates
).length
> 1) {
2600 for (var crate
in crates
) {
2601 if (crates
.hasOwnProperty(crate
)) {
2602 crates_text
.push(crate
);
2606 crates_text
.sort(function(a
, b
) {
2607 var lower_a
= a
.toLowerCase();
2608 var lower_b
= b
.toLowerCase();
2610 if (lower_a
< lower_b
) {
2612 } else if (lower_a
> lower_b
) {
2617 var savedCrate
= getCurrentValue("rustdoc-saved-filter-crate");
2618 for (var i
= 0; i
< crates_text
.length
; ++i
) {
2619 var option
= document
.createElement("option");
2620 option
.value
= crates_text
[i
];
2621 option
.innerText
= crates_text
[i
];
2622 elem
.appendChild(option
);
2623 // Set the crate filter from saved storage, if the current page has the saved crate
2626 // If not, ignore the crate filter -- we want to support filtering for crates on sites
2627 // like doc.rust-lang.org where the crates may differ from page to page while on the
2629 if (crates_text
[i
] === savedCrate
) {
2630 elem
.value
= savedCrate
;
2635 search_input
.removeAttribute('disabled');
2639 window
.addSearchOptions
= addSearchOptions
;
2641 function buildHelperPopup() {
2642 var popup
= document
.createElement("aside");
2643 addClass(popup
, "hidden");
2646 var container
= document
.createElement("div");
2648 ["?", "Show this help dialog"],
2649 ["S", "Focus the search field"],
2650 ["↑", "Move up in search results"],
2651 ["↓", "Move down in search results"],
2652 ["↹", "Switch tab"],
2653 ["⏎", "Go to active search result"],
2654 ["+", "Expand all sections"],
2655 ["-", "Collapse all sections"],
2656 ].map(x
=> "<dt><kbd>" + x
[0] + "</kbd></dt><dd>" + x
[1] + "</dd>").join("");
2657 var div_shortcuts
= document
.createElement("div");
2658 addClass(div_shortcuts
, "shortcuts");
2659 div_shortcuts
.innerHTML
= "<h2>Keyboard Shortcuts</h2><dl>" + shortcuts
+ "</dl></div>";
2662 "Prefix searches with a type followed by a colon (e.g., <code>fn:</code>) to \
2663 restrict the search to a given type.",
2664 "Accepted types are: <code>fn</code>, <code>mod</code>, <code>struct</code>, \
2665 <code>enum</code>, <code>trait</code>, <code>type</code>, <code>macro</code>, \
2666 and <code>const</code>.",
2667 "Search functions by type signature (e.g., <code>vec -> usize</code> or \
2668 <code>* -> vec</code>)",
2669 "Search multiple things at once by splitting your query with comma (e.g., \
2670 <code>str,u8</code> or <code>String,struct:Vec,test</code>)",
2671 "You can look for items with an exact name by putting double quotes around \
2672 your request: <code>\"string\"</code>",
2673 "Look for items inside another one by searching for a path: <code>vec::Vec</code>",
2674 ].map(x
=> "<p>" + x
+ "</p>").join("");
2675 var div_infos
= document
.createElement("div");
2676 addClass(div_infos
, "infos");
2677 div_infos
.innerHTML
= "<h2>Search Tricks</h2>" + infos
;
2679 container
.appendChild(div_shortcuts
);
2680 container
.appendChild(div_infos
);
2682 popup
.appendChild(container
);
2683 insertAfter(popup
, getSearchElement());
2687 window
.onhashchange
= onHashChange
;
2692 // Sets the focus on the search bar at the top of the page
2693 function focusSearchBar() {
2694 getSearchInput().focus();
2697 // Removes the focus from the search bar
2698 function defocusSearchBar() {
2699 getSearchInput().blur();