diff --git a/.changeset/tender-peaches-yell.md b/.changeset/tender-peaches-yell.md new file mode 100644 index 00000000..7f0bb2f8 --- /dev/null +++ b/.changeset/tender-peaches-yell.md @@ -0,0 +1,6 @@ +--- +"marko-vscode": patch +"@marko/language-server": patch +--- + +Implement hover provider for tag names. diff --git a/server/src/service/marko/hover/OpenTagName.ts b/server/src/service/marko/hover/OpenTagName.ts new file mode 100644 index 00000000..8637e08b --- /dev/null +++ b/server/src/service/marko/hover/OpenTagName.ts @@ -0,0 +1,30 @@ +import type { Node } from "../../../utils/parser"; +import { getDocFile } from "../../../utils/doc-file"; +import type { HoverMeta, HoverResult } from "."; +import getTagNameCompletion from "../util/get-tag-name-completion"; +import { START_OF_FILE } from "../../../utils/utils"; +import type { MarkupContent } from "vscode-languageserver"; + +export function OpenTagName({ + document, + lookup, + parsed, + node, +}: HoverMeta): HoverResult { + const importer = getDocFile(document); + const tag = node.parent; + const range = parsed.locationAt(node); + const tagDef = tag.nameText && lookup.getTag(tag.nameText); + + if (tagDef) { + const completion = getTagNameCompletion({ + tag: tagDef, + range: START_OF_FILE, + importer, + }); + return { + range, + contents: completion.documentation as MarkupContent, + }; + } +} diff --git a/server/src/service/marko/hover/index.ts b/server/src/service/marko/hover/index.ts new file mode 100644 index 00000000..c68fd3ca --- /dev/null +++ b/server/src/service/marko/hover/index.ts @@ -0,0 +1,36 @@ +import type { TextDocument } from "vscode-languageserver-textdocument"; +import type { HoverParams, Hover } from "vscode-languageserver"; +import { getCompilerInfo, parse } from "../../../utils/compiler"; +import type { Plugin, Result } from "../../types"; +import { NodeType } from "../../../utils/parser"; +import { OpenTagName } from "./OpenTagName"; + +export type HoverResult = Result; +export interface HoverMeta + extends ReturnType { + document: TextDocument; + params: HoverParams; + parsed: ReturnType; + offset: number; + code: string; + node: N; +} + +const handlers: Record) => HoverResult> = { + OpenTagName, +}; + +export const doHover: Plugin["doHover"] = async (doc, params) => { + const parsed = parse(doc); + const offset = doc.offsetAt(params.position); + const node = parsed.nodeAt(offset); + return await handlers[NodeType[node.type]]?.({ + document: doc, + params, + parsed, + offset, + node, + code: doc.getText(), + ...getCompilerInfo(doc), + }); +}; diff --git a/server/src/service/marko/index.ts b/server/src/service/marko/index.ts index 825c535c..b7f38195 100644 --- a/server/src/service/marko/index.ts +++ b/server/src/service/marko/index.ts @@ -1,6 +1,7 @@ import type { Plugin } from "../types"; import { doComplete } from "./complete"; import { doValidate } from "./validate"; +import { doHover } from "./hover"; import { findDefinition } from "./definition"; import { findDocumentLinks } from "./document-links"; import { findDocumentSymbols } from "./document-symbols"; @@ -9,6 +10,7 @@ import { format } from "./format"; export default { doComplete, doValidate, + doHover, findDefinition, findDocumentLinks, findDocumentSymbols, diff --git a/server/src/service/marko/util/get-tag-name-completion.ts b/server/src/service/marko/util/get-tag-name-completion.ts index 6fcc2931..57b00d84 100644 --- a/server/src/service/marko/util/get-tag-name-completion.ts +++ b/server/src/service/marko/util/get-tag-name-completion.ts @@ -32,16 +32,16 @@ export default function getTagNameCompletion({ ); const nodeModuleName = nodeModuleMatch && nodeModuleMatch[1]; - const isCoreTag = nodeModuleName === "marko"; - + const isCoreTag = + /^@?marko[/-]/.test(tag.taglibId) || nodeModuleName === "marko"; const documentation = { kind: MarkupKind.Markdown, value: tag.html - ? `Built in [<${tag.name}>](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/${tag.name}) HTML tag.` + ? `Built in [<${tag.name}>](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/${tag.name}) HTML tag.` + : isCoreTag + ? `Core Marko <${tag.name}> tag.` : nodeModuleName - ? isCoreTag - ? `Core Marko [<${tag.name}>](${fileURIForTag}) tag.` - : `Custom Marko tag discovered from the ["${nodeModuleName}"](${fileURIForTag}) npm package.` + ? `Custom Marko tag discovered from the ["${nodeModuleName}"](${fileURIForTag}) npm package.` : `Custom Marko tag discovered from:\n\n[${ importer ? path.relative(importer, fileForTag) : fileForTag }](${fileURIForTag})`,