From a7d6115688385f31c701f2a18e17d3f742474b0a Mon Sep 17 00:00:00 2001 From: Robert Hill Date: Wed, 26 Aug 2026 23:43:18 -0400 Subject: [PATCH 1/8] Add @arg tag support for documenting excmd flags Extracts @arg -flag description tags from excmd JSDoc into a flags map in the generated metadata, and renders them as one bullet list in `:help`. A docstring can drop a `{{tridactyl-arg-list}}` marker anywhere in its prose to control where that list renders, since the @arg tags themselves must stay at the end of the comment (TSDoc runs a block tag's content until the next tag). Annotates `hint` as the first user of this new format. Related to #5397 (which-key), split out per review discussion since which-key depends on this. --- scripts/convert_typedoc_metadata.js | 18 +++++-- scripts/typedoc-theme.mjs | 75 +++++++++++++++++++++++++++++ src/excmds.ts | 55 +++++++++++++-------- 3 files changed, 125 insertions(+), 23 deletions(-) diff --git a/scripts/convert_typedoc_metadata.js b/scripts/convert_typedoc_metadata.js index 4aa9289a..f9f7fc52 100644 --- a/scripts/convert_typedoc_metadata.js +++ b/scripts/convert_typedoc_metadata.js @@ -32,6 +32,17 @@ function convertMetadata(project) { .map(part => part.text || "") .join("") .replace(/\n+$/, "") + // Extract @arg tags: `@arg -flag description` -> flags["-flag"] = "description" + const argFlags = comment => { + const flags = {} + for (const tag of comment?.blockTags || []) { + if (tag.tag !== "@arg") continue + const text = (tag.content || []).map(part => part.text || "").join("") + const m = /^(-\S+)\s+(.+)$/.exec(text.trim()) + if (m) flags[m[1]] = m[2] + } + return flags + } const normalizeParameter = (parameter, resolving) => ({ name: parameter.name, @@ -152,15 +163,16 @@ function convertMetadata(project) { .filter(node => node.kind === KIND.Function) .map(node => { const signature = node.signatures?.[0] + const comment = signature?.comment || node.comment + const flags = argFlags(comment) return [ node.name, { - doc: - commentText(signature?.comment) || - commentText(node.comment), + doc: commentText(comment), params: (signature?.parameters || []).map(parameter => normalizeParameter(parameter), ), + ...(Object.keys(flags).length ? { flags } : {}), }, ] }), diff --git a/scripts/typedoc-theme.mjs b/scripts/typedoc-theme.mjs index efcc2c3a..94b3c59e 100644 --- a/scripts/typedoc-theme.mjs +++ b/scripts/typedoc-theme.mjs @@ -252,7 +252,82 @@ class TridactylRouter extends KindRouter { } } +function parseArgTag(tag) { + const text = (tag.content || []).map(part => part.text || "").join("") + const m = /^(-\S+)\s+(.+)$/.exec(text.trim()) + return m ? [m[1], m[2]] : undefined +} + +function renderArgList(anchor, parsed) { + if (parsed.length === 0) return null + return h( + "div", + { class: "tsd-tag-arg tsd-comment tsd-typography" }, + h( + "h4", + { class: "tsd-anchor-link", id: anchor }, + "Arguments", + h( + "a", + { href: `#${anchor}`, "aria-label": "Permalink", class: "tsd-anchor-icon" }, + h( + "svg", + { viewBox: "0 0 24 24", "aria-hidden": "true" }, + h("use", { href: "../assets/icons.svg#icon-anchor" }), + ), + ), + ), + h( + "ul", + null, + parsed.map(([flag, desc]) => h("li", null, h("code", null, flag), " ", desc)), + ), + ) +} + +const ARG_MARKER = "{{tridactyl-arg-list}}" + class TridactylTheme extends DefaultTheme { + getRenderContext(page) { + const context = super.getRenderContext(page) + const defaultCommentSummary = context.commentSummary + context.commentSummary = props => { + const owner = props.isParameter?.() ? props.parent : props + const argTags = (owner?.comment?.blockTags || []).filter( + tag => tag.tag === "@arg", + ) + const summaryParts = props.comment?.summary || [] + const markerIndex = summaryParts.findIndex( + part => part.kind === "text" && part.text.includes(ARG_MARKER), + ) + if (argTags.length === 0 || markerIndex === -1) + return defaultCommentSummary(props) + + argTags.forEach(tag => (tag.skipRendering = true)) + const parsed = argTags.map(parseArgTag).filter(Boolean) + const anchor = `${String(owner.name || "arguments").toLowerCase()}-arguments` + + const markerPart = summaryParts[markerIndex] + const [beforeText, afterText] = markerPart.text.split(ARG_MARKER) + const before = [ + ...summaryParts.slice(0, markerIndex), + ...(beforeText ? [{ kind: "text", text: beforeText }] : []), + ] + const after = [ + ...(afterText ? [{ kind: "text", text: afterText }] : []), + ...summaryParts.slice(markerIndex + 1), + ] + return h( + JSX.Fragment, + null, + before.length > 0 && context.displayParts(before), + renderArgList(anchor, parsed), + after.length > 0 && context.displayParts(after), + ) + } + return context + } + getReflectionClasses(reflection) { const kind = ReflectionKind.classString(reflection.kind) const parent = diff --git a/src/excmds.ts b/src/excmds.ts index 0c497392..dfa14f26 100644 --- a/src/excmds.ts +++ b/src/excmds.ts @@ -5532,26 +5532,8 @@ const KILL_STACK: Element[] = [] * * Hinting action flags (only one can be specified): * - * - -t open in a new foreground tab - * - -b open in background - * - -y copy (yank) link's target to clipboard - * - -p copy an element's text to the clipboard - * - -h select an element (as if you click-n-dragged over it) - * - -P copy an element's title/alt text to the clipboard - * - -r read an element's text with text-to-speech - * - -i view an image - * - -I view an image in a new tab - * - -k irreversibly deletes an element from the page (until reload) - * - -K hides an element on the page; hidden elements can be restored using [[elementunhide]]. - * - -s save (download) the linked resource - * - -S save the linked image - * - -a save-as the linked resource - * - -A save-as the linked image - * - -; focus an element and set it as the element or the child of the element to scroll - * - -# yank an element's anchor URL to clipboard - * - -w open in new window - * - -wp open in new private window - * - -z scroll an element to the top of the viewport + * {{tridactyl-arg-list}} + * * - `-pipe selector key` e.g, `-pipe a href` returns the URL of the chosen link on a page. Only makes sense with `composite`, e.g, `composite hint -pipe .some-class>a textContent | yank`. If you don't select a hint (i.e. press ``), will return an empty string. Most useful when used like `-c` to do things other than opening links. NB: the query selector cannot contain any spaces. * - `-W excmd...` pass hint href as the final argument to excmd and execute, e.g, `hint -W mpvsafe` to open YouTube videos. NB: passing it to bare [[exclaim]] is dangerous - see `get exaliases.mpvsafe` for an example of how to do it safely. The usual [[composite]] caveats for `;` and `|` in URLs apply. If you need to use a query selector, use `-pipe` instead. * - -F [callback] - run a custom callback on the selected hint, e.g. `hint -JF e => {tri.excmds.tabopen("-b",e.href); e.remove()}`. @@ -5620,6 +5602,39 @@ const KILL_STACK: Element[] = [] * - `;d` and `;gd` - open links in discarded background tabs (defer loading until tab is switched to) * * NB: by default, hinting respects whether links say they should be opened in new tabs (i.e. `target=_blank`). If you wish to override this you can use `:hint -JW open` to force the hints to open in the current tab. JavaScript hints (grey ones) will always open wherever they want, but if you want to include these anyway you can use `:hint -W open`. + * + * @arg -t open in a new foreground tab + * @arg -b open in background + * @arg -y copy (yank) link's target to clipboard + * @arg -p copy an element's text to the clipboard + * @arg -h select an element (as if you click-n-dragged over it) + * @arg -P copy an element's title/alt text to the clipboard + * @arg -r read an element's text with text-to-speech + * @arg -i view an image + * @arg -I view an image in a new tab + * @arg -k irreversibly deletes an element from the page (until reload) + * @arg -K hides an element on the page; hidden elements can be restored using elementunhide + * @arg -s save (download) the linked resource + * @arg -S save the linked image + * @arg -a save-as the linked resource + * @arg -A save-as the linked image + * @arg -; focus an element and set it as the element or the child of the element to scroll + * @arg -# yank an element's anchor URL to clipboard + * @arg -w open in new window + * @arg -wp open in new private window + * @arg -z scroll an element to the top of the viewport + * @arg -pipe pipe attribute to clipboard + * @arg -W run excmd with hint href + * @arg -F run JS callback + * @arg -c hint CSS selector only + * @arg -C hint CSS selector and defaults + * @arg -x exclude CSS selector + * @arg -f filter hints by text + * @arg -fr filter hints by regex + * @arg -J disable JS hints + * @arg -V include invisible elements + * @arg -q rapid (stay in hint mode) + * @arg -! execute all hints immediately */ //#content export async function hint(...args: string[]): Promise { From e744f5651de8ccfd04ac2bb75ece52074af53d84 Mon Sep 17 00:00:00 2001 From: Robert Hill Date: Thu, 27 Aug 2026 14:44:07 -0400 Subject: [PATCH 2/8] Rename @arg tag to @flag @arg is a bit ambiguous since an "argument" can hold anything. @flag better matches what this tag actually documents (excmd command-line flags). --- scripts/convert_typedoc_metadata.js | 4 +- scripts/typedoc-theme.mjs | 28 ++++++------ src/excmds.ts | 66 ++++++++++++++--------------- 3 files changed, 49 insertions(+), 49 deletions(-) diff --git a/scripts/convert_typedoc_metadata.js b/scripts/convert_typedoc_metadata.js index f9f7fc52..32accfbd 100644 --- a/scripts/convert_typedoc_metadata.js +++ b/scripts/convert_typedoc_metadata.js @@ -32,11 +32,11 @@ function convertMetadata(project) { .map(part => part.text || "") .join("") .replace(/\n+$/, "") - // Extract @arg tags: `@arg -flag description` -> flags["-flag"] = "description" + // Extract @flag tags: `@flag -flag description` -> flags["-flag"] = "description" const argFlags = comment => { const flags = {} for (const tag of comment?.blockTags || []) { - if (tag.tag !== "@arg") continue + if (tag.tag !== "@flag") continue const text = (tag.content || []).map(part => part.text || "").join("") const m = /^(-\S+)\s+(.+)$/.exec(text.trim()) if (m) flags[m[1]] = m[2] diff --git a/scripts/typedoc-theme.mjs b/scripts/typedoc-theme.mjs index 94b3c59e..8d31c6fa 100644 --- a/scripts/typedoc-theme.mjs +++ b/scripts/typedoc-theme.mjs @@ -252,21 +252,21 @@ class TridactylRouter extends KindRouter { } } -function parseArgTag(tag) { +function parseFlagTag(tag) { const text = (tag.content || []).map(part => part.text || "").join("") const m = /^(-\S+)\s+(.+)$/.exec(text.trim()) return m ? [m[1], m[2]] : undefined } -function renderArgList(anchor, parsed) { +function renderFlagList(anchor, parsed) { if (parsed.length === 0) return null return h( "div", - { class: "tsd-tag-arg tsd-comment tsd-typography" }, + { class: "tsd-tag-flag tsd-comment tsd-typography" }, h( "h4", { class: "tsd-anchor-link", id: anchor }, - "Arguments", + "Flags", h( "a", { href: `#${anchor}`, "aria-label": "Permalink", class: "tsd-anchor-icon" }, @@ -285,7 +285,7 @@ function renderArgList(anchor, parsed) { ) } -const ARG_MARKER = "{{tridactyl-arg-list}}" +const FLAG_MARKER = "{{tridactyl-flag-list}}" class TridactylTheme extends DefaultTheme { getRenderContext(page) { @@ -293,22 +293,22 @@ class TridactylTheme extends DefaultTheme { const defaultCommentSummary = context.commentSummary context.commentSummary = props => { const owner = props.isParameter?.() ? props.parent : props - const argTags = (owner?.comment?.blockTags || []).filter( - tag => tag.tag === "@arg", + const flagTags = (owner?.comment?.blockTags || []).filter( + tag => tag.tag === "@flag", ) const summaryParts = props.comment?.summary || [] const markerIndex = summaryParts.findIndex( - part => part.kind === "text" && part.text.includes(ARG_MARKER), + part => part.kind === "text" && part.text.includes(FLAG_MARKER), ) - if (argTags.length === 0 || markerIndex === -1) + if (flagTags.length === 0 || markerIndex === -1) return defaultCommentSummary(props) - argTags.forEach(tag => (tag.skipRendering = true)) - const parsed = argTags.map(parseArgTag).filter(Boolean) - const anchor = `${String(owner.name || "arguments").toLowerCase()}-arguments` + flagTags.forEach(tag => (tag.skipRendering = true)) + const parsed = flagTags.map(parseFlagTag).filter(Boolean) + const anchor = `${String(owner.name || "flags").toLowerCase()}-flags` const markerPart = summaryParts[markerIndex] - const [beforeText, afterText] = markerPart.text.split(ARG_MARKER) + const [beforeText, afterText] = markerPart.text.split(FLAG_MARKER) const before = [ ...summaryParts.slice(0, markerIndex), ...(beforeText ? [{ kind: "text", text: beforeText }] : []), @@ -321,7 +321,7 @@ class TridactylTheme extends DefaultTheme { JSX.Fragment, null, before.length > 0 && context.displayParts(before), - renderArgList(anchor, parsed), + renderFlagList(anchor, parsed), after.length > 0 && context.displayParts(after), ) } diff --git a/src/excmds.ts b/src/excmds.ts index dfa14f26..68474c1c 100644 --- a/src/excmds.ts +++ b/src/excmds.ts @@ -5532,7 +5532,7 @@ const KILL_STACK: Element[] = [] * * Hinting action flags (only one can be specified): * - * {{tridactyl-arg-list}} + * {{tridactyl-flag-list}} * * - `-pipe selector key` e.g, `-pipe a href` returns the URL of the chosen link on a page. Only makes sense with `composite`, e.g, `composite hint -pipe .some-class>a textContent | yank`. If you don't select a hint (i.e. press ``), will return an empty string. Most useful when used like `-c` to do things other than opening links. NB: the query selector cannot contain any spaces. * - `-W excmd...` pass hint href as the final argument to excmd and execute, e.g, `hint -W mpvsafe` to open YouTube videos. NB: passing it to bare [[exclaim]] is dangerous - see `get exaliases.mpvsafe` for an example of how to do it safely. The usual [[composite]] caveats for `;` and `|` in URLs apply. If you need to use a query selector, use `-pipe` instead. @@ -5603,38 +5603,38 @@ const KILL_STACK: Element[] = [] * * NB: by default, hinting respects whether links say they should be opened in new tabs (i.e. `target=_blank`). If you wish to override this you can use `:hint -JW open` to force the hints to open in the current tab. JavaScript hints (grey ones) will always open wherever they want, but if you want to include these anyway you can use `:hint -W open`. * - * @arg -t open in a new foreground tab - * @arg -b open in background - * @arg -y copy (yank) link's target to clipboard - * @arg -p copy an element's text to the clipboard - * @arg -h select an element (as if you click-n-dragged over it) - * @arg -P copy an element's title/alt text to the clipboard - * @arg -r read an element's text with text-to-speech - * @arg -i view an image - * @arg -I view an image in a new tab - * @arg -k irreversibly deletes an element from the page (until reload) - * @arg -K hides an element on the page; hidden elements can be restored using elementunhide - * @arg -s save (download) the linked resource - * @arg -S save the linked image - * @arg -a save-as the linked resource - * @arg -A save-as the linked image - * @arg -; focus an element and set it as the element or the child of the element to scroll - * @arg -# yank an element's anchor URL to clipboard - * @arg -w open in new window - * @arg -wp open in new private window - * @arg -z scroll an element to the top of the viewport - * @arg -pipe pipe attribute to clipboard - * @arg -W run excmd with hint href - * @arg -F run JS callback - * @arg -c hint CSS selector only - * @arg -C hint CSS selector and defaults - * @arg -x exclude CSS selector - * @arg -f filter hints by text - * @arg -fr filter hints by regex - * @arg -J disable JS hints - * @arg -V include invisible elements - * @arg -q rapid (stay in hint mode) - * @arg -! execute all hints immediately + * @flag -t open in a new foreground tab + * @flag -b open in background + * @flag -y copy (yank) link's target to clipboard + * @flag -p copy an element's text to the clipboard + * @flag -h select an element (as if you click-n-dragged over it) + * @flag -P copy an element's title/alt text to the clipboard + * @flag -r read an element's text with text-to-speech + * @flag -i view an image + * @flag -I view an image in a new tab + * @flag -k irreversibly deletes an element from the page (until reload) + * @flag -K hides an element on the page; hidden elements can be restored using elementunhide + * @flag -s save (download) the linked resource + * @flag -S save the linked image + * @flag -a save-as the linked resource + * @flag -A save-as the linked image + * @flag -; focus an element and set it as the element or the child of the element to scroll + * @flag -# yank an element's anchor URL to clipboard + * @flag -w open in new window + * @flag -wp open in new private window + * @flag -z scroll an element to the top of the viewport + * @flag -pipe pipe attribute to clipboard + * @flag -W run excmd with hint href + * @flag -F run JS callback + * @flag -c hint CSS selector only + * @flag -C hint CSS selector and defaults + * @flag -x exclude CSS selector + * @flag -f filter hints by text + * @flag -fr filter hints by regex + * @flag -J disable JS hints + * @flag -V include invisible elements + * @flag -q rapid (stay in hint mode) + * @flag -! execute all hints immediately */ //#content export async function hint(...args: string[]): Promise { From 14ade554b5f6a1f6d674dcb6c1fc1b843704eb8c Mon Sep 17 00:00:00 2001 From: Robert Hill Date: Thu, 27 Aug 2026 23:05:20 -0400 Subject: [PATCH 3/8] Split @flag descriptions and add @endflags for multi-section docs - @flag text now splits on the first blank line into a short label (shown in the flag list) and longer elaboration prose rendered beneath it. - @endflags closes a run of @flag tags and flushes them. This prevents TSDoc from swallowing any trailing text into the last @flag. - Markdown headings inside trailing content are also kept out of the page's sidebar nav to avoid cluttering it with each excmd's subsections. --- scripts/convert_typedoc_metadata.js | 15 +++-- scripts/typedoc-theme.mjs | 95 +++++++++++++---------------- 2 files changed, 53 insertions(+), 57 deletions(-) diff --git a/scripts/convert_typedoc_metadata.js b/scripts/convert_typedoc_metadata.js index 32accfbd..c74f3037 100644 --- a/scripts/convert_typedoc_metadata.js +++ b/scripts/convert_typedoc_metadata.js @@ -32,14 +32,21 @@ function convertMetadata(project) { .map(part => part.text || "") .join("") .replace(/\n+$/, "") - // Extract @flag tags: `@flag -flag description` -> flags["-flag"] = "description" const argFlags = comment => { const flags = {} for (const tag of comment?.blockTags || []) { if (tag.tag !== "@flag") continue - const text = (tag.content || []).map(part => part.text || "").join("") - const m = /^(-\S+)\s+(.+)$/.exec(text.trim()) - if (m) flags[m[1]] = m[2] + const text = (tag.content || []) + .map(part => part.text || "") + .join("") + const m = /^(-\S+)[ \t]+([^\n]+)\n*([\s\S]*)$/.exec(text.trim()) + if (!m) continue + const [, flag, short, rest] = m + const elaboration = rest.trim() + flags[flag] = { + short, + description: elaboration ? `${short}\n\n${elaboration}` : short, + } } return flags } diff --git a/scripts/typedoc-theme.mjs b/scripts/typedoc-theme.mjs index 8d31c6fa..ee1d45e0 100644 --- a/scripts/typedoc-theme.mjs +++ b/scripts/typedoc-theme.mjs @@ -254,76 +254,65 @@ class TridactylRouter extends KindRouter { function parseFlagTag(tag) { const text = (tag.content || []).map(part => part.text || "").join("") - const m = /^(-\S+)\s+(.+)$/.exec(text.trim()) - return m ? [m[1], m[2]] : undefined + const m = /^(-\S+)[ \t]+([^\n]+)\n*([\s\S]*)$/.exec(text.trim()) + if (!m) return undefined + const [, flag, short, rest] = m + const elaboration = rest.trim() + return [flag, short, elaboration] } -function renderFlagList(anchor, parsed) { +function renderFlagList(context, parsed) { if (parsed.length === 0) return null return h( - "div", - { class: "tsd-tag-flag tsd-comment tsd-typography" }, - h( - "h4", - { class: "tsd-anchor-link", id: anchor }, - "Flags", + "ul", + { class: "tsd-tag-flag tsd-parameter-list" }, + parsed.map(([flag, short, elaboration]) => h( - "a", - { href: `#${anchor}`, "aria-label": "Permalink", class: "tsd-anchor-icon" }, - h( - "svg", - { viewBox: "0 0 24 24", "aria-hidden": "true" }, - h("use", { href: "../assets/icons.svg#icon-anchor" }), - ), + "li", + null, + h("code", null, flag), + " ", + short, + elaboration && + context.displayParts([{ kind: "text", text: elaboration }]), ), ), - h( - "ul", - null, - parsed.map(([flag, desc]) => h("li", null, h("code", null, flag), " ", desc)), - ), ) } -const FLAG_MARKER = "{{tridactyl-flag-list}}" - class TridactylTheme extends DefaultTheme { getRenderContext(page) { const context = super.getRenderContext(page) const defaultCommentSummary = context.commentSummary context.commentSummary = props => { - const owner = props.isParameter?.() ? props.parent : props - const flagTags = (owner?.comment?.blockTags || []).filter( - tag => tag.tag === "@flag", - ) - const summaryParts = props.comment?.summary || [] - const markerIndex = summaryParts.findIndex( - part => part.kind === "text" && part.text.includes(FLAG_MARKER), - ) - if (flagTags.length === 0 || markerIndex === -1) + const blockTags = props.comment?.blockTags || [] + if (!blockTags.some(tag => tag.tag === "@flag" || tag.tag === "@endflags")) return defaultCommentSummary(props) - flagTags.forEach(tag => (tag.skipRendering = true)) - const parsed = flagTags.map(parseFlagTag).filter(Boolean) - const anchor = `${String(owner.name || "flags").toLowerCase()}-flags` - - const markerPart = summaryParts[markerIndex] - const [beforeText, afterText] = markerPart.text.split(FLAG_MARKER) - const before = [ - ...summaryParts.slice(0, markerIndex), - ...(beforeText ? [{ kind: "text", text: beforeText }] : []), - ] - const after = [ - ...(afterText ? [{ kind: "text", text: afterText }] : []), - ...summaryParts.slice(markerIndex + 1), - ] - return h( - JSX.Fragment, - null, - before.length > 0 && context.displayParts(before), - renderFlagList(anchor, parsed), - after.length > 0 && context.displayParts(after), - ) + const summaryHeadingCount = page.pageHeadings.length + const nodes = [context.displayParts(props.comment?.summary || [])] + page.pageHeadings.length = summaryHeadingCount + let flagRun = [] + const flushFlags = () => { + if (flagRun.length === 0) return + const parsed = flagRun.map(parseFlagTag).filter(Boolean) + nodes.push(renderFlagList(context, parsed)) + flagRun = [] + } + for (const tag of blockTags) { + if (tag.tag === "@flag") { + tag.skipRendering = true + flagRun.push(tag) + } else if (tag.tag === "@endflags") { + tag.skipRendering = true + flushFlags() + const headingCount = page.pageHeadings.length + nodes.push(context.displayParts(tag.content || [])) + page.pageHeadings.length = headingCount + } + } + flushFlags() + return h(JSX.Fragment, null, ...nodes) } return context } From fea486503336108424fe23f5764ac3a0baf1ac60 Mon Sep 17 00:00:00 2001 From: Robert Hill Date: Thu, 27 Aug 2026 23:16:20 -0400 Subject: [PATCH 4/8] Rewrite hint's doc comment using @flag/@endflags - Replaces the {{tridactyl-flag-list}} marker and prose flag bullets with @flag tags and two @endflags boundaries. This keeps the flags rendered where they're placed in the code without the rest of the docs getting swallowed into the last flag's content. - Moves @param below the content summary to match where the content is rendered on the Help doc. - Also fixes -pipe and -W, which had their flag name wrapped in backticks and were silently dropped by the parser. --- src/excmds.ts | 114 ++++++++++++++++++++++++++------------------------ 1 file changed, 59 insertions(+), 55 deletions(-) diff --git a/src/excmds.ts b/src/excmds.ts index 68474c1c..45c52e18 100644 --- a/src/excmds.ts +++ b/src/excmds.ts @@ -5526,50 +5526,85 @@ const KILL_STACK: Element[] = [] /** * Hint a page. * - * @param args Arguments to the `:hint` command. Multiple flags can be combined as long as they don't conflict. + * Multiple flags can be used in the `:hint` command and combined as long as they don't conflict. * Selectors can be specified either standalone (without a flag preceding them) or with the `-c` option. Arguments that * take callbacks (`-F` or `-W`) should be specified last, as they consume the rest of the command line. * - * Hinting action flags (only one can be specified): + * #### Hinting action flags (only one can be specified): * - * {{tridactyl-flag-list}} + * @flag -t open in a new foreground tab + * @flag -b open in background + * @flag -y copy (yank) link's target to clipboard + * @flag -p copy an element's text to the clipboard + * @flag -h select an element (as if you click-n-dragged over it) + * @flag -P copy an element's title/alt text to the clipboard + * @flag -r read an element's text with text-to-speech + * @flag -i view an image + * @flag -I view an image in a new tab + * @flag -k irreversibly deletes an element from the page (until reload) + * @flag -K hides an element on the page + * - Hidden elements can be restored using [[elementunhide]]. + * @flag -s save (download) the linked resource + * @flag -S save the linked image + * @flag -a save-as the linked resource + * @flag -A save-as the linked image + * @flag -; focus an element and set it as the element or the child of the element to scroll + * @flag -# yank an element's anchor URL to clipboard + * @flag -w open in new window + * @flag -wp open in new private window + * @flag -z scroll an element to the top of the viewport + * @flag -pipe `selector key`, e.g, `-pipe a href` returns the URL of the chosen link on a page. + * - Only makes sense with `composite`, e.g, `composite hint -pipe .some-class>a textContent | yank`. + * - If you don't select a hint (i.e. press ``), will return an empty string. + * - Most useful when used like `-c` to do things other than opening links. + * - NB: the query selector cannot contain any spaces. + * @flag -W `excmd...` pass hint href as the final argument to excmd and execute. + * - e.g, `hint -W mpvsafe` to open YouTube videos. + * - NB: passing it to bare [[exclaim]] is dangerous - see `get exaliases.mpvsafe` for an example of how to do it safely. + * - The usual [[composite]] caveats for `;` and `|` in URLs apply. + * - If you need to use a query selector, use `-pipe` instead. + * @flag -F [callback] - run a custom callback on the selected hint + * - e.g. `hint -JF e => {tri.excmds.tabopen("-b",e.href); e.remove()}`. + * @endflags * - * - `-pipe selector key` e.g, `-pipe a href` returns the URL of the chosen link on a page. Only makes sense with `composite`, e.g, `composite hint -pipe .some-class>a textContent | yank`. If you don't select a hint (i.e. press ``), will return an empty string. Most useful when used like `-c` to do things other than opening links. NB: the query selector cannot contain any spaces. - * - `-W excmd...` pass hint href as the final argument to excmd and execute, e.g, `hint -W mpvsafe` to open YouTube videos. NB: passing it to bare [[exclaim]] is dangerous - see `get exaliases.mpvsafe` for an example of how to do it safely. The usual [[composite]] caveats for `;` and `|` in URLs apply. If you need to use a query selector, use `-pipe` instead. - * - -F [callback] - run a custom callback on the selected hint, e.g. `hint -JF e => {tri.excmds.tabopen("-b",e.href); e.remove()}`. + * #### Element selection flags * - * Element selection flags: + * @flag -c hint links that match the css selector + * - `bind ;c hint -c [class*="expand"],[class*="togg"]` works particularly well on reddit and HN. + * - This works with most other hint modes, with the caveat that if other hint mode takes arguments your selector must contain no spaces, i.e. `hint -c[yourOtherFlag] [selector] [your other flag's arguments, which may contain spaces]` + * @flag -C like -c but also hints all elements that would normally be hinted given the other options selected + * @flag -x exclude the matched elements from hinting + * @flag -f hint links and inputs that display the given text + * - `bind hint -f Edit`. + * - Backslashes can escape spaces: `bind hint -f Save\ as` + * @flag -fr use RegExp to hint the links and inputs + * @flag -J disable javascript hints + * - Don't generate hints related to javascript events. This is particularly useful when used with the `-c` option when you want to generate only hints for the specified css selectors. + * - Also useful on sites with plenty of useless javascript elements such as google.com + * @flag -V create hints for invisible elements + * - By default, elements outside the viewport when calling :hint are not hinted; this includes them anyways. + * @endflags * - * - -c [selector] hint links that match the css selector - * - `bind ;c hint -c [class*="expand"],[class*="togg"]` works particularly well on reddit and HN - * - this works with most other hint modes, with the caveat that if other hint mode takes arguments your selector must contain no spaces, i.e. `hint -c[yourOtherFlag] [selector] [your other flag's arguments, which may contain spaces]` - * - -C [selector] like `-c [selector]` but also hints all elements that would normally be hinted given the other options selected - * - -x [selector] exclude the matched elements from hinting - * - -f [text] hint links and inputs that display the given text - * - `bind hint -f Edit` - * - Backslashes can escape spaces: `bind hint -f Save\ as` - * - -fr [text] use RegExp to hint the links and inputs - * - -J* disable javascript hints. Don't generate hints related to javascript events. This is particularly useful when used with the `-c` option when you want to generate only hints for the specified css selectors. Also useful on sites with plenty of useless javascript elements such as google.com - * - -V create hints for invisible elements. By default, elements outside the viewport when calling :hint are not hinted, this includes them anyways. - * - * Hinting mode selection: + * #### Hinting mode selection: * * - -q* quick (or rapid) hints mode. Stay in hint mode until you press ``, e.g. `:hint -qb` to open multiple hints in the background or `:hint -qW excmd` to execute excmd once for each hint. This will return an array containing all elements or the result of executed functions (e.g. `hint -qpipe a href` will return an array of links). * - For example, use `bind ;jg hint -Jc .rc > .r > a` on google.com to generate hints only for clickable search results of a given query * - -! execute all hints without waiting for a selection * - For example, `hint -!bf Comments` opens in background tabs all visible links whose text matches `Comments` * - * Deprecated options: + * #### Deprecated options: * * - -br deprecated, use `-qb` instead * + * #### Usage: + * * Excepting the custom selector mode, background hint mode and the "immediate" modifier, each of these hint modes is available by default as `;