import * as vscode from "vscode"; import { spawn } from "node:child_process"; import { styleLockfile } from "./lockfile.style"; export type BunLockfile = vscode.CustomDocument & { readonly preview: string; }; export class BunLockfileEditorProvider implements vscode.CustomReadonlyEditorProvider { constructor(private context: vscode.ExtensionContext) {} async openCustomDocument( uri: vscode.Uri, openContext: vscode.CustomDocumentOpenContext, token: vscode.CancellationToken, ): Promise { const preview = await previewLockfile(uri, token); return { uri, preview, dispose() {}, }; } async resolveCustomEditor( document: BunLockfile, webviewPanel: vscode.WebviewPanel, token: vscode.CancellationToken, ): Promise { const { preview } = document; webviewPanel.webview.options = { localResourceRoots: [this.context.extensionUri], }; renderLockfile(webviewPanel, preview, this.context.extensionUri); } } function renderLockfile({ webview }: vscode.WebviewPanel, preview: string, extensionUri: vscode.Uri): void { const styleVSCodeUri = webview.asWebviewUri(vscode.Uri.joinPath(extensionUri, "assets", "vscode.css")); const lockfileContent = styleLockfile(preview); const lineNumbers: string[] = []; for (let i = 0; i < lockfileContent.split("\n").length; i++) { lineNumbers.push(`${i + 1}`); } webview.html = `
${lineNumbers.join("\n")}
${lockfileContent}
`; } function previewLockfile(uri: vscode.Uri, token?: vscode.CancellationToken): Promise { return new Promise((resolve, reject) => { const process = spawn("bun", [uri.fsPath], { stdio: ["ignore", "pipe", "pipe"], }); token?.onCancellationRequested(() => { process.kill(); }); let stdout = ""; process.stdout.on("data", (data: Buffer) => { stdout += data.toString(); }); let stderr = ""; process.stderr.on("data", (data: Buffer) => { stderr += data.toString(); }); process.on("error", error => { reject(error); }); process.on("exit", code => { if (code === 0) { resolve(stdout); } else { reject(new Error(`Bun exited with code: ${code}\n${stderr}`)); } }); }); } export function registerBunlockEditor(context: vscode.ExtensionContext): void { const viewType = "bun.lockb"; const provider = new BunLockfileEditorProvider(context); context.subscriptions.push( vscode.window.registerCustomEditorProvider(viewType, provider, { supportsMultipleEditorsPerDocument: true, webviewOptions: { enableFindWidget: true, retainContextWhenHidden: true, }, }), ); }