feat(language-server): merge HTML completions and hover into one response
This commit is contained in:
@@ -1,4 +1,12 @@
|
||||
import { getLanguageService, TextDocument as HtmlTextDocument } from "vscode-html-languageservice";
|
||||
// The default `main` entrypoint is a UMD bundle whose internal AMD-style
|
||||
// `require("./parser/htmlScanner")` calls survive bundling literally instead
|
||||
// of being inlined, so a bundled language server fails at runtime with
|
||||
// "Cannot find module './parser/htmlScanner'". The ESM entrypoint bundles
|
||||
// cleanly, so import it explicitly.
|
||||
import {
|
||||
getLanguageService,
|
||||
TextDocument as HtmlTextDocument,
|
||||
} from "vscode-html-languageservice/lib/esm/htmlLanguageService.js";
|
||||
import { isInsideHtml, virtualHtmlDocument } from "./html-regions.ts";
|
||||
import { offsetAt, type Position, type TextDocument } from "./index.ts";
|
||||
|
||||
@@ -126,3 +134,27 @@ export function htmlTagComplete(document: TextDocument, position: Position): str
|
||||
|
||||
return selfClosingTagCompletion(document.text, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* One completion list from both sources.
|
||||
*
|
||||
* WRNexus entries take the `0` sortText prefix so they rank above HTML without
|
||||
* either list being filtered. An exact label collision resolves to the
|
||||
* WRNexus entry: a component named `Table` is what the author meant.
|
||||
*/
|
||||
interface CompletionLike {
|
||||
label: string;
|
||||
kind?: number;
|
||||
sortText?: string;
|
||||
}
|
||||
|
||||
export function mergeCompletions(
|
||||
wrnexus: CompletionLike[],
|
||||
html: CompletionLike[],
|
||||
): CompletionLike[] {
|
||||
const taken = new Set(wrnexus.map((item) => item.label));
|
||||
return [
|
||||
...wrnexus.map((item) => ({ ...item, sortText: `0${item.sortText ?? item.label}` })),
|
||||
...html.filter((item) => !taken.has(item.label)),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ import {
|
||||
htmlToWrn,
|
||||
type TextDocument,
|
||||
} from "./index.ts";
|
||||
import { htmlCompletions, htmlHover, mergeCompletions } from "./html-service.ts";
|
||||
import { clearHtmlRegionCache } from "./html-regions.ts";
|
||||
|
||||
type JsonRpc = { jsonrpc?: string; id?: number | string; method?: string; params?: any };
|
||||
const documents = new Map<string, TextDocument>();
|
||||
@@ -111,7 +113,9 @@ async function handle(message: JsonRpc): Promise<void> {
|
||||
capabilities: {
|
||||
textDocumentSync: { openClose: true, change: 1, save: true },
|
||||
documentFormattingProvider: true,
|
||||
completionProvider: { triggerCharacters: ["<", "@", ":", "."] },
|
||||
completionProvider: {
|
||||
triggerCharacters: ["<", "@", ":", ".", " ", "=", '"', "/"],
|
||||
},
|
||||
hoverProvider: true,
|
||||
definitionProvider: true,
|
||||
referencesProvider: true,
|
||||
@@ -172,6 +176,7 @@ async function handle(message: JsonRpc): Promise<void> {
|
||||
case "textDocument/didClose":
|
||||
clearDiagnosticTimer(params.textDocument.uri);
|
||||
documents.delete(params.textDocument.uri);
|
||||
clearHtmlRegionCache(params.textDocument.uri);
|
||||
send({
|
||||
jsonrpc: "2.0",
|
||||
method: "textDocument/publishDiagnostics",
|
||||
@@ -195,9 +200,13 @@ async function handle(message: JsonRpc): Promise<void> {
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "textDocument/completion":
|
||||
result(message.id, [...completionItems(), ...workspaceCompletionItems(workspaceRoot)]);
|
||||
case "textDocument/completion": {
|
||||
const document = documents.get(params.textDocument.uri);
|
||||
const wrnexus = [...completionItems(), ...workspaceCompletionItems(workspaceRoot)];
|
||||
const html = document ? htmlCompletions(document, params.position) : [];
|
||||
result(message.id, html.length ? mergeCompletions(wrnexus, html) : wrnexus);
|
||||
break;
|
||||
}
|
||||
case "textDocument/documentSymbol": {
|
||||
const document = documents.get(params.textDocument.uri);
|
||||
result(message.id, document ? documentSymbols(document) : []);
|
||||
@@ -210,7 +219,8 @@ async function handle(message: JsonRpc): Promise<void> {
|
||||
}
|
||||
case "textDocument/hover": {
|
||||
const document = documents.get(params.textDocument.uri);
|
||||
result(message.id, document ? hover(document, params.position) : null);
|
||||
const html = document ? htmlHover(document, params.position) : null;
|
||||
result(message.id, html ?? (document ? hover(document, params.position) : null));
|
||||
break;
|
||||
}
|
||||
case "textDocument/definition": {
|
||||
|
||||
Reference in New Issue
Block a user