mirror of
https://github.com/tridactyl/tridactyl.git
synced 2026-09-10 07:16:33 -04:00
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.
This commit is contained in:
parent
62d4cb89e3
commit
a7d6115688
|
|
@ -32,6 +32,17 @@ function convertMetadata(project) {
|
||||||
.map(part => part.text || "")
|
.map(part => part.text || "")
|
||||||
.join("")
|
.join("")
|
||||||
.replace(/\n+$/, "")
|
.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) => ({
|
const normalizeParameter = (parameter, resolving) => ({
|
||||||
name: parameter.name,
|
name: parameter.name,
|
||||||
|
|
@ -152,15 +163,16 @@ function convertMetadata(project) {
|
||||||
.filter(node => node.kind === KIND.Function)
|
.filter(node => node.kind === KIND.Function)
|
||||||
.map(node => {
|
.map(node => {
|
||||||
const signature = node.signatures?.[0]
|
const signature = node.signatures?.[0]
|
||||||
|
const comment = signature?.comment || node.comment
|
||||||
|
const flags = argFlags(comment)
|
||||||
return [
|
return [
|
||||||
node.name,
|
node.name,
|
||||||
{
|
{
|
||||||
doc:
|
doc: commentText(comment),
|
||||||
commentText(signature?.comment) ||
|
|
||||||
commentText(node.comment),
|
|
||||||
params: (signature?.parameters || []).map(parameter =>
|
params: (signature?.parameters || []).map(parameter =>
|
||||||
normalizeParameter(parameter),
|
normalizeParameter(parameter),
|
||||||
),
|
),
|
||||||
|
...(Object.keys(flags).length ? { flags } : {}),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
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) {
|
getReflectionClasses(reflection) {
|
||||||
const kind = ReflectionKind.classString(reflection.kind)
|
const kind = ReflectionKind.classString(reflection.kind)
|
||||||
const parent =
|
const parent =
|
||||||
|
|
|
||||||
|
|
@ -5532,26 +5532,8 @@ const KILL_STACK: Element[] = []
|
||||||
*
|
*
|
||||||
* Hinting action flags (only one can be specified):
|
* Hinting action flags (only one can be specified):
|
||||||
*
|
*
|
||||||
* - -t open in a new foreground tab
|
* {{tridactyl-arg-list}}
|
||||||
* - -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
|
|
||||||
* - `-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 `<Esc>`), 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.
|
* - `-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 `<Esc>`), 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.
|
* - `-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()}`.
|
* - -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)
|
* - `;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`.
|
* 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
|
//#content
|
||||||
export async function hint(...args: string[]): Promise<any> {
|
export async function hint(...args: string[]): Promise<any> {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue