feat(vscode): close HTML tags as they are typed in .wrn files

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-18 21:16:47 +05:30
co-authored by Claude Opus 5
parent d9e8f5be82
commit e83f0366ef
6 changed files with 179 additions and 33 deletions
+6
View File
@@ -24,6 +24,7 @@ import {
htmlFoldingRanges,
htmlHover,
htmlLinkedEditingRanges,
htmlTagComplete,
mergeCompletions,
} from "./html-service.ts";
import { clearHtmlRegionCache } from "./html-regions.ts";
@@ -242,6 +243,11 @@ async function handle(message: JsonRpc): Promise<void> {
result(message.id, ranges ? { ranges } : null);
break;
}
case "wrn/tagComplete": {
const document = documents.get(params.textDocument.uri);
result(message.id, document ? htmlTagComplete(document, params.position) : null);
break;
}
case "textDocument/definition": {
const document = documents.get(params.textDocument.uri);
result(message.id, document ? definitionLocation(document, params.position) : null);
@@ -371,3 +371,53 @@ test("advertises and serves folding ranges and linked editing ranges over the wi
process.kill();
await process.exited;
});
test("serves wrn/tagComplete over the wire", async () => {
const process = Bun.spawn(
["bun", "run", fileURLToPath(new URL("../src/server.ts", import.meta.url))],
{ stdin: "pipe", stdout: "pipe", stderr: "pipe" },
);
const uri = "file:///tag-complete.wrn";
const text = `page A {
view {
<div>
}
}
`;
const reader = process.stdout.getReader();
let output = "";
async function readUntil(marker: string): Promise<void> {
while (!output.includes(marker)) {
const chunk = await reader.read();
if (chunk.done) break;
output += new TextDecoder().decode(chunk.value);
}
}
process.stdin.write(packet({ jsonrpc: "2.0", id: 1, method: "initialize", params: {} }));
await process.stdin.flush();
await readUntil('"id":1');
process.stdin.write(
packet({
jsonrpc: "2.0",
method: "textDocument/didOpen",
params: { textDocument: { uri, version: 1, text } },
}),
);
process.stdin.write(
packet({
jsonrpc: "2.0",
id: 2,
method: "wrn/tagComplete",
params: { textDocument: { uri }, position: { line: 2, character: 9 } },
}),
);
await process.stdin.flush();
await readUntil('"id":2');
const reply = output.slice(output.indexOf('"id":2'));
expect(reply).toContain('"result":"$0</div>"');
process.kill();
await process.exited;
});