diff options
Diffstat (limited to 'src/librustdoc/html/static')
| -rw-r--r-- | src/librustdoc/html/static/css/rustdoc.css | 51 | ||||
| -rw-r--r-- | src/librustdoc/html/static/js/main.js | 52 | ||||
| -rw-r--r-- | src/librustdoc/html/static/js/rustdoc.d.ts | 16 | ||||
| -rw-r--r-- | src/librustdoc/html/static/js/scrape-examples.js | 45 | ||||
| -rw-r--r-- | src/librustdoc/html/static/js/search.js | 101 | ||||
| -rw-r--r-- | src/librustdoc/html/static/js/storage.js | 2 |
6 files changed, 177 insertions, 90 deletions
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index dc27d7943d9..86f1a42bc01 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -956,6 +956,40 @@ rustdoc-topbar { .example-wrap.digits-8 { --example-wrap-digits-count: 8ch; } .example-wrap.digits-9 { --example-wrap-digits-count: 9ch; } +.example-wrap .expansion { + position: relative; + display: inline; +} +.example-wrap .expansion > input { + display: block; + position: absolute; + appearance: none; + content: '↕'; + left: -20px; + top: 0; + border: 1px solid var(--border-color); + border-radius: 4px; + cursor: pointer; + color: var(--main-color); + padding: 0 2px; + line-height: 20px; +} +.example-wrap .expansion > input::after { + content: "↕"; +} +.example-wrap .expansion .expanded { + display: none; + color: var(--main-color); +} +.example-wrap .expansion > input:checked ~ .expanded, +.example-wrap .expansion > input:checked ~ * .expanded { + display: inherit; +} +.example-wrap .expansion > input:checked ~ .original, +.example-wrap .expansion > input:checked ~ * .original { + display: none; +} + .example-wrap [data-nosnippet] { width: calc(var(--example-wrap-digits-count) + var(--line-number-padding) * 2); } @@ -964,6 +998,17 @@ rustdoc-topbar { var(--example-wrap-digits-count) + var(--line-number-padding) * 2 + var(--line-number-right-margin)); } +.src .example-wrap .expansion [data-nosnippet] { + /* FIXME: Once <https://bugzilla.mozilla.org/show_bug.cgi?id=1949948> is solved, uncomment + next line and remove the two other rules. */ + /*left: calc(( + var(--example-wrap-digits-count) + var(--line-number-padding) * 2 + + var(--line-number-right-margin)) * -1);*/ + position: initial; + margin-left: calc(( + var(--example-wrap-digits-count) + var(--line-number-padding) * 2 + + var(--line-number-right-margin)) * -1); +} .example-wrap [data-nosnippet] { color: var(--src-line-numbers-span-color); @@ -978,9 +1023,6 @@ rustdoc-topbar { position: absolute; left: 0; } -.example-wrap .line-highlighted[data-nosnippet] { - background-color: var(--src-line-number-highlighted-background-color); -} .example-wrap pre > code { position: relative; display: block; @@ -995,6 +1037,9 @@ rustdoc-topbar { .example-wrap [data-nosnippet]:target { border-right: none; } +.example-wrap .line-highlighted[data-nosnippet] { + background-color: var(--src-line-number-highlighted-background-color); +} .example-wrap.hide-lines [data-nosnippet] { display: none; } diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index af43fd48dd1..4fcba5f120b 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -407,9 +407,7 @@ function preLoadCss(cssUrl) { function loadSearch() { if (!searchLoaded) { searchLoaded = true; - // @ts-expect-error window.rr_ = data => { - // @ts-expect-error window.searchIndex = data; }; if (!window.StringdexOnload) { @@ -1277,13 +1275,11 @@ function preLoadCss(cssUrl) { } window.addEventListener("resize", () => { - // @ts-expect-error if (window.CURRENT_TOOLTIP_ELEMENT) { // As a workaround to the behavior of `contains: layout` used in doc togglers, // tooltip popovers are positioned using javascript. // // This means when the window is resized, we need to redo the layout. - // @ts-expect-error const base = window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE; const force_visible = base.TOOLTIP_FORCE_VISIBLE; hideTooltip(false); @@ -1329,11 +1325,9 @@ function preLoadCss(cssUrl) { */ function showTooltip(e) { const notable_ty = e.getAttribute("data-notable-ty"); - // @ts-expect-error if (!window.NOTABLE_TRAITS && notable_ty) { const data = document.getElementById("notable-traits-data"); if (data) { - // @ts-expect-error window.NOTABLE_TRAITS = JSON.parse(data.innerText); } else { throw new Error("showTooltip() called with notable without any notable traits!"); @@ -1341,14 +1335,15 @@ function preLoadCss(cssUrl) { } // Make this function idempotent. If the tooltip is already shown, avoid doing extra work // and leave it alone. - // @ts-expect-error if (window.CURRENT_TOOLTIP_ELEMENT && window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE === e) { - // @ts-expect-error clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT); return; } window.hideAllModals(false); - const wrapper = document.createElement("div"); + // use Object.assign to make sure the object has the correct type + // with all of the correct fields before it is assigned to a variable, + // as typescript has no way to change the type of a variable once it is initialized. + const wrapper = Object.assign(document.createElement("div"), {TOOLTIP_BASE: e}); if (notable_ty) { wrapper.innerHTML = "<div class=\"content\">" + // @ts-expect-error @@ -1394,11 +1389,7 @@ function preLoadCss(cssUrl) { ); } wrapper.style.visibility = ""; - // @ts-expect-error window.CURRENT_TOOLTIP_ELEMENT = wrapper; - // @ts-expect-error - window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE = e; - // @ts-expect-error clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT); wrapper.onpointerenter = ev => { // If this is a synthetic touch event, ignore it. A click event will be along shortly. @@ -1433,19 +1424,15 @@ function preLoadCss(cssUrl) { */ function setTooltipHoverTimeout(element, show) { clearTooltipHoverTimeout(element); - // @ts-expect-error if (!show && !window.CURRENT_TOOLTIP_ELEMENT) { // To "hide" an already hidden element, just cancel its timeout. return; } - // @ts-expect-error if (show && window.CURRENT_TOOLTIP_ELEMENT) { // To "show" an already visible element, just cancel its timeout. return; } - // @ts-expect-error if (window.CURRENT_TOOLTIP_ELEMENT && - // @ts-expect-error window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE !== element) { // Don't do anything if another tooltip is already visible. return; @@ -1468,24 +1455,20 @@ function preLoadCss(cssUrl) { */ function clearTooltipHoverTimeout(element) { if (element.TOOLTIP_HOVER_TIMEOUT !== undefined) { - // @ts-expect-error removeClass(window.CURRENT_TOOLTIP_ELEMENT, "fade-out"); clearTimeout(element.TOOLTIP_HOVER_TIMEOUT); delete element.TOOLTIP_HOVER_TIMEOUT; } } - // @ts-expect-error + /** + * @param {Event & { relatedTarget: Node }} event + */ function tooltipBlurHandler(event) { - // @ts-expect-error if (window.CURRENT_TOOLTIP_ELEMENT && - // @ts-expect-error !window.CURRENT_TOOLTIP_ELEMENT.contains(document.activeElement) && - // @ts-expect-error !window.CURRENT_TOOLTIP_ELEMENT.contains(event.relatedTarget) && - // @ts-expect-error !window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.contains(document.activeElement) && - // @ts-expect-error !window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.contains(event.relatedTarget) ) { // Work around a difference in the focus behaviour between Firefox, Chrome, and Safari. @@ -1507,30 +1490,22 @@ function preLoadCss(cssUrl) { * If set to `false`, leave keyboard focus alone. */ function hideTooltip(focus) { - // @ts-expect-error if (window.CURRENT_TOOLTIP_ELEMENT) { - // @ts-expect-error if (window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE) { if (focus) { - // @ts-expect-error window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.focus(); } - // @ts-expect-error window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE = false; } - // @ts-expect-error document.body.removeChild(window.CURRENT_TOOLTIP_ELEMENT); - // @ts-expect-error clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT); - // @ts-expect-error - window.CURRENT_TOOLTIP_ELEMENT = null; + window.CURRENT_TOOLTIP_ELEMENT = undefined; } } onEachLazy(document.getElementsByClassName("tooltip"), e => { e.onclick = () => { e.TOOLTIP_FORCE_VISIBLE = e.TOOLTIP_FORCE_VISIBLE ? false : true; - // @ts-expect-error if (window.CURRENT_TOOLTIP_ELEMENT && !e.TOOLTIP_FORCE_VISIBLE) { hideTooltip(true); } else { @@ -1566,9 +1541,7 @@ function preLoadCss(cssUrl) { if (ev.pointerType !== "mouse") { return; } - // @ts-expect-error if (!e.TOOLTIP_FORCE_VISIBLE && window.CURRENT_TOOLTIP_ELEMENT && - // @ts-expect-error !window.CURRENT_TOOLTIP_ELEMENT.contains(ev.relatedTarget)) { // Tooltip pointer leave gesture: // @@ -1601,7 +1574,6 @@ function preLoadCss(cssUrl) { // * https://www.nngroup.com/articles/tooltip-guidelines/ // * https://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown setTooltipHoverTimeout(e, false); - // @ts-expect-error addClass(window.CURRENT_TOOLTIP_ELEMENT, "fade-out"); } }; @@ -1649,7 +1621,7 @@ function preLoadCss(cssUrl) { ["⏎", "Go to active search result"], ["+", "Expand all sections"], ["-", "Collapse all sections"], - // for the sake of brevity, we don't say "inherint impl blocks", + // for the sake of brevity, we don't say "inherit impl blocks", // although that would be more correct, // since trait impl blocks are collapsed by - ["_", "Collapse all sections, including impl blocks"], @@ -1707,8 +1679,7 @@ function preLoadCss(cssUrl) { if (isHelpPage) { const help_section = document.createElement("section"); help_section.appendChild(container); - // @ts-expect-error - document.getElementById("main-content").appendChild(help_section); + nonnull(document.getElementById("main-content")).appendChild(help_section); } else { onEachLazy(document.getElementsByClassName("help-menu"), menu => { if (menu.offsetWidth !== 0) { @@ -1854,8 +1825,7 @@ function preLoadCss(cssUrl) { sidebarButton.addEventListener("click", e => { removeClass(document.documentElement, "hide-sidebar"); updateLocalStorage("hide-sidebar", "false"); - if (document.querySelector(".rustdoc.src")) { - // @ts-expect-error + if (window.rustdocToggleSrcSidebar) { window.rustdocToggleSrcSidebar(); } e.preventDefault(); diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts index 56581aebf06..3ac10742e41 100644 --- a/src/librustdoc/html/static/js/rustdoc.d.ts +++ b/src/librustdoc/html/static/js/rustdoc.d.ts @@ -28,6 +28,9 @@ declare global { currentTheme: HTMLLinkElement|null; /** Generated in `render/context.rs` */ SIDEBAR_ITEMS?: { [key: string]: string[] }; + /** Notable trait data */ + NOTABLE_TRAITS?: { [key: string]: string }; + CURRENT_TOOLTIP_ELEMENT?: HTMLElement & { TOOLTIP_BASE: HTMLElement }; /** Used by the popover tooltip code. */ RUSTDOC_TOOLTIP_HOVER_MS: number; /** Used by the popover tooltip code. */ @@ -93,6 +96,10 @@ declare global { pending_type_impls?: rustdoc.TypeImpls, rustdoc_add_line_numbers_to_examples?: function(), rustdoc_remove_line_numbers_from_examples?: function(), + /** JSON-encoded raw search index */ + searchIndex: string, + /** Used in search index shards in order to load data into the in-memory database */ + rr_: function(string), } interface HTMLElement { /** Used by the popover tooltip code. */ @@ -514,4 +521,13 @@ declare namespace rustdoc { options?: string[], default: string | boolean, } + + /** + * Single element in the data-locs field of a scraped example. + * First field is the start and end char index, + * other fields seem to be unused. + * + * Generated by `render_call_locations` in `render/mod.rs`. + */ + type ScrapedLoc = [[number, number], string, string] } diff --git a/src/librustdoc/html/static/js/scrape-examples.js b/src/librustdoc/html/static/js/scrape-examples.js index d641405c875..eeab591bcd8 100644 --- a/src/librustdoc/html/static/js/scrape-examples.js +++ b/src/librustdoc/html/static/js/scrape-examples.js @@ -1,7 +1,4 @@ -/* global addClass, hasClass, removeClass, onEachLazy */ - -// Eventually fix this. -// @ts-nocheck + /* global addClass, hasClass, removeClass, onEachLazy, nonnull */ "use strict"; @@ -14,8 +11,16 @@ const DEFAULT_MAX_LINES = 5; const HIDDEN_MAX_LINES = 10; - // Scroll code block to the given code location + /** + * Scroll code block to the given code location + * @param {HTMLElement} elt + * @param {[number, number]} loc + * @param {boolean} isHidden + */ function scrollToLoc(elt, loc, isHidden) { + /** @type {HTMLElement[]} */ + // blocked on https://github.com/microsoft/TypeScript/issues/29037 + // @ts-expect-error const lines = elt.querySelectorAll("[data-nosnippet]"); let scrollOffset; @@ -35,10 +40,15 @@ scrollOffset = offsetMid - halfHeight; } - lines[0].parentElement.scrollTo(0, scrollOffset); - elt.querySelector(".rust").scrollTo(0, scrollOffset); + nonnull(lines[0].parentElement).scrollTo(0, scrollOffset); + nonnull(elt.querySelector(".rust")).scrollTo(0, scrollOffset); } + /** + * @param {HTMLElement} parent + * @param {string} className + * @param {string} content + */ function createScrapeButton(parent, className, content) { const button = document.createElement("button"); button.className = className; @@ -50,20 +60,24 @@ window.updateScrapedExample = (example, buttonHolder) => { let locIndex = 0; const highlights = Array.prototype.slice.call(example.querySelectorAll(".highlight")); - const link = example.querySelector(".scraped-example-title a"); + + /** @type {HTMLAnchorElement} */ + const link = nonnull(example.querySelector(".scraped-example-title a")); let expandButton = null; if (!example.classList.contains("expanded")) { expandButton = createScrapeButton(buttonHolder, "expand", "Show all"); } - const isHidden = example.parentElement.classList.contains("more-scraped-examples"); + const isHidden = nonnull(example.parentElement).classList.contains("more-scraped-examples"); + // @ts-expect-error const locs = example.locs; if (locs.length > 1) { const next = createScrapeButton(buttonHolder, "next", "Next usage"); const prev = createScrapeButton(buttonHolder, "prev", "Previous usage"); // Toggle through list of examples in a given file + /** @type {function(function(): void): void} */ const onChangeLoc = changeIndex => { removeClass(highlights[locIndex], "focus"); changeIndex(); @@ -106,10 +120,19 @@ } }; + /** + * Initialize the `locs` field + * + * @param {HTMLElement & {locs?: rustdoc.ScrapedLoc[]}} example + * @param {boolean} isHidden + */ function setupLoc(example, isHidden) { - example.locs = JSON.parse(example.attributes.getNamedItem("data-locs").textContent); + const locs_str = nonnull(example.attributes.getNamedItem("data-locs")).textContent; + const locs = + JSON.parse(nonnull(nonnull(locs_str))); + example.locs = locs; // Start with the first example in view - scrollToLoc(example, example.locs[0][0], isHidden); + scrollToLoc(example, locs[0][0], isHidden); } const firstExamples = document.querySelectorAll(".scraped-example-list > .scraped-example"); diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index d55208150b8..3fb4db3a89c 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -587,6 +587,45 @@ function getNextElem(query, parserState, elems, isInGenerics) { /** @type {rustdoc.ParserQueryElement[]} */ const generics = []; + /** @type {function(string, string): void} */ + const handleRefOrPtr = (chr, name) => { + if (parserState.typeFilter !== null && parserState.typeFilter !== "primitive") { + throw [ + "Invalid search type: primitive ", + chr, + " and ", + parserState.typeFilter, + " both specified", + ]; + } + parserState.typeFilter = null; + parserState.pos += 1; + let c = parserState.userQuery[parserState.pos]; + while (c === " " && parserState.pos < parserState.length) { + parserState.pos += 1; + c = parserState.userQuery[parserState.pos]; + } + const generics = []; + const pos = parserState.pos; + if (parserState.userQuery.slice(pos, pos + 3) === "mut") { + generics.push(makePrimitiveElement("mut", { typeFilter: "keyword" })); + parserState.pos += 3; + c = parserState.userQuery[parserState.pos]; + } else if (chr === "*" && parserState.userQuery.slice(pos, pos + 5) === "const") { + // make *const T parse the same as *T + parserState.pos += 5; + c = parserState.userQuery[parserState.pos]; + } + while (c === " " && parserState.pos < parserState.length) { + parserState.pos += 1; + c = parserState.userQuery[parserState.pos]; + } + if (!isEndCharacter(c) && parserState.pos < parserState.length) { + getFilteredNextElem(query, parserState, generics, isInGenerics); + } + elems.push(makePrimitiveElement(name, { generics })); + }; + skipWhitespace(parserState); let start = parserState.pos; let end; @@ -636,36 +675,9 @@ function getNextElem(query, parserState, elems, isInGenerics) { elems.push(makePrimitiveElement(name, { bindingName, generics })); } } else if (parserState.userQuery[parserState.pos] === "&") { - if (parserState.typeFilter !== null && parserState.typeFilter !== "primitive") { - throw [ - "Invalid search type: primitive ", - "&", - " and ", - parserState.typeFilter, - " both specified", - ]; - } - parserState.typeFilter = null; - parserState.pos += 1; - let c = parserState.userQuery[parserState.pos]; - while (c === " " && parserState.pos < parserState.length) { - parserState.pos += 1; - c = parserState.userQuery[parserState.pos]; - } - const generics = []; - if (parserState.userQuery.slice(parserState.pos, parserState.pos + 3) === "mut") { - generics.push(makePrimitiveElement("mut", { typeFilter: "keyword" })); - parserState.pos += 3; - c = parserState.userQuery[parserState.pos]; - } - while (c === " " && parserState.pos < parserState.length) { - parserState.pos += 1; - c = parserState.userQuery[parserState.pos]; - } - if (!isEndCharacter(c) && parserState.pos < parserState.length) { - getFilteredNextElem(query, parserState, generics, isInGenerics); - } - elems.push(makePrimitiveElement("reference", { generics })); + handleRefOrPtr("&", "reference"); + } else if (parserState.userQuery[parserState.pos] === "*") { + handleRefOrPtr("*", "pointer"); } else { const isStringElem = parserState.userQuery[start] === "\""; // We handle the strings on their own mostly to make code easier to follow. @@ -1185,6 +1197,7 @@ class DocSearch { this.typeNameIdOfUnit = -1; this.typeNameIdOfTupleOrUnit = -1; this.typeNameIdOfReference = -1; + this.typeNameIdOfPointer = -1; this.typeNameIdOfHof = -1; this.utf8decoder = new TextDecoder(); @@ -1224,6 +1237,7 @@ class DocSearch { tupleOrUnit, // reference matches `&` reference, + pointer, // never matches `!` never, ] = await Promise.all([ @@ -1239,6 +1253,7 @@ class DocSearch { nn.search("unit"), nn.search("()"), nn.search("reference"), + nn.search("pointer"), nn.search("never"), ]); /** @@ -1270,6 +1285,7 @@ class DocSearch { this.typeNameIdOfUnit = await first(unit, TY_PRIMITIVE, ""); this.typeNameIdOfTupleOrUnit = await first(tupleOrUnit, TY_PRIMITIVE, ""); this.typeNameIdOfReference = await first(reference, TY_PRIMITIVE, ""); + this.typeNameIdOfPointer = await first(pointer, TY_PRIMITIVE, ""); this.typeNameIdOfHof = await first(hof, TY_PRIMITIVE, ""); this.typeNameIdOfNever = await first(never, TY_PRIMITIVE, ""); } @@ -2309,6 +2325,25 @@ class DocSearch { }, result), ); return true; + } else if (fnType.id === this.typeNameIdOfPointer) { + pushText({ name: "*", highlighted: fnType.highlighted }, result); + if (fnType.generics.length < 2) { + pushText({ name: "const ", highlighted: fnType.highlighted }, result); + } + let prevHighlighted = false; + await onEachBtwnAsync( + fnType.generics, + async value => { + prevHighlighted = !!value.highlighted; + await writeFn(value, result); + }, + // @ts-expect-error + value => pushText({ + name: " ", + highlighted: prevHighlighted && value.highlighted, + }, result), + ); + return true; } else if ( fnType.id === this.typeNameIdOfFn || fnType.id === this.typeNameIdOfFnMut || @@ -5244,15 +5279,13 @@ if (typeof window !== "undefined") { // search.index/root is loaded by main.js, so // this script doesn't need to launch it, but // must pick it up - // @ts-ignore if (window.searchIndex) { - // @ts-ignore window.rr_(window.searchIndex); } }, loadTreeByHash: hashHex => { const script = document.createElement("script"); - script.src = `${ROOT_PATH}/search.index/${hashHex}.js`; + script.src = `${ROOT_PATH}search.index/${hashHex}.js`; script.onerror = e => { if (databaseCallbacks) { databaseCallbacks.err_rn_(hashHex, e); @@ -5262,7 +5295,7 @@ if (typeof window !== "undefined") { }, loadDataByNameAndHash: (name, hashHex) => { const script = document.createElement("script"); - script.src = `${ROOT_PATH}/search.index/${name}/${hashHex}.js`; + script.src = `${ROOT_PATH}search.index/${name}/${hashHex}.js`; script.onerror = e => { if (databaseCallbacks) { databaseCallbacks.err_rd_(hashHex, e); diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index c055eb0f808..40ab8be03c9 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -117,7 +117,7 @@ function addClass(elem, className) { * Remove a class from a DOM Element. If `elem` is null, * does nothing. This function is idempotent. * - * @param {Element|null} elem + * @param {Element|null|undefined} elem * @param {string} className */ // eslint-disable-next-line no-unused-vars |
