aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar JeremyFunk <jeremy@kombo.dev> 2023-09-17 17:59:01 +0200
committerGravatar GitHub <noreply@github.com> 2023-09-17 08:59:01 -0700
commitc6b25adeea36b76045553eaa2af75d3a14f71a2d (patch)
tree2e8652454e97890e324ffcd74c7a0d1bedf9143d
parent0404d09cc74d865c09a9c4fa965d078035d07027 (diff)
downloadbun-c6b25adeea36b76045553eaa2af75d3a14f71a2d.tar.gz
bun-c6b25adeea36b76045553eaa2af75d3a14f71a2d.tar.zst
bun-c6b25adeea36b76045553eaa2af75d3a14f71a2d.zip
Implement VSCode tasks for bun (#5529)
* Fix VSCode extension configuration documentation * Fix config descriptions * Fix typo * Implement bun.lockb highlighter * Update style * Improve styling * Revert bunlock change * Implement bun tasks * Revert change * Package json codelens * Fixes * Refactor
-rw-r--r--packages/bun-vscode/example/package.json4
-rw-r--r--packages/bun-vscode/package.json22
-rw-r--r--packages/bun-vscode/scripts/build.mjs4
-rw-r--r--packages/bun-vscode/src/extension.ts12
-rw-r--r--packages/bun-vscode/src/features/debug.ts90
-rw-r--r--packages/bun-vscode/src/features/lockfile/index.ts (renamed from packages/bun-vscode/src/features/lockfile.ts)30
-rw-r--r--packages/bun-vscode/src/features/lockfile/lockfile.style.ts35
-rw-r--r--packages/bun-vscode/src/features/tasks/package.json.ts197
-rw-r--r--packages/bun-vscode/src/features/tasks/tasks.ts59
9 files changed, 372 insertions, 81 deletions
diff --git a/packages/bun-vscode/example/package.json b/packages/bun-vscode/example/package.json
index 602fba159..91055b5f5 100644
--- a/packages/bun-vscode/example/package.json
+++ b/packages/bun-vscode/example/package.json
@@ -7,6 +7,10 @@
"mime": "^3.0.0",
"mime-db": "^1.52.0"
},
+ "scripts": {
+ "run": "hello.js",
+ "start": "bun hello.js"
+ },
"trustedDependencies": [
"mime"
],
diff --git a/packages/bun-vscode/package.json b/packages/bun-vscode/package.json
index f0a9e065e..501257eb0 100644
--- a/packages/bun-vscode/package.json
+++ b/packages/bun-vscode/package.json
@@ -54,13 +54,7 @@
"../bun-inspector-protocol"
],
"activationEvents": [
- "onLanguage:javascript",
- "onLanguage:javascriptreact",
- "onLanguage:typescript",
- "onLanguage:typescriptreact",
- "workspaceContains:**/.lockb",
- "onDebugResolve:bun",
- "onDebugDynamicConfigurations:bun"
+ "onStartupFinished"
],
"browser": "dist/web-extension.js",
"bugs": {
@@ -294,6 +288,20 @@
],
"priority": "default"
}
+ ],
+ "taskDefinitions": [
+ {
+ "type": "bun",
+ "required": [
+ "script"
+ ],
+ "properties": {
+ "script": {
+ "type": "string",
+ "description": "The script to execute"
+ }
+ }
+ }
]
}
}
diff --git a/packages/bun-vscode/scripts/build.mjs b/packages/bun-vscode/scripts/build.mjs
index 261965840..5db577281 100644
--- a/packages/bun-vscode/scripts/build.mjs
+++ b/packages/bun-vscode/scripts/build.mjs
@@ -12,6 +12,10 @@ buildSync({
external: ["vscode"],
platform: "node",
format: "cjs",
+
+ // The following settings are required to allow for extension debugging
+ minify: false,
+ sourcemap: true,
});
rmSync("extension", { recursive: true, force: true });
diff --git a/packages/bun-vscode/src/extension.ts b/packages/bun-vscode/src/extension.ts
index e333aedd7..175165fa7 100644
--- a/packages/bun-vscode/src/extension.ts
+++ b/packages/bun-vscode/src/extension.ts
@@ -1,10 +1,14 @@
import * as vscode from "vscode";
-import activateLockfile from "./features/lockfile";
-import activateDebug from "./features/debug";
+import { registerTaskProvider } from "./features/tasks/tasks";
+import { registerDebugger } from "./features/debug";
+import { registerPackageJsonProviders } from "./features/tasks/package.json";
+import { registerBunlockEditor } from "./features/lockfile";
export function activate(context: vscode.ExtensionContext) {
- activateLockfile(context);
- activateDebug(context);
+ registerBunlockEditor(context);
+ registerDebugger(context);
+ registerTaskProvider(context);
+ registerPackageJsonProviders(context);
}
export function deactivate() {}
diff --git a/packages/bun-vscode/src/features/debug.ts b/packages/bun-vscode/src/features/debug.ts
index 2ea21dbe8..d5522c493 100644
--- a/packages/bun-vscode/src/features/debug.ts
+++ b/packages/bun-vscode/src/features/debug.ts
@@ -4,43 +4,44 @@ import { DebugAdapter, UnixSignal } from "../../../bun-debug-adapter-protocol";
import { DebugSession } from "@vscode/debugadapter";
import { tmpdir } from "node:os";
-const debugConfiguration: vscode.DebugConfiguration = {
+export const DEBUG_CONFIGURATION: vscode.DebugConfiguration = {
type: "bun",
+ internalConsoleOptions: "neverOpen",
request: "launch",
name: "Debug File",
program: "${file}",
cwd: "${workspaceFolder}",
stopOnEntry: false,
watchMode: false,
- internalConsoleOptions: "neverOpen",
+
};
-const runConfiguration: vscode.DebugConfiguration = {
+export const RUN_CONFIGURATION: vscode.DebugConfiguration = {
type: "bun",
+ internalConsoleOptions: "neverOpen",
request: "launch",
name: "Run File",
program: "${file}",
cwd: "${workspaceFolder}",
noDebug: true,
watchMode: false,
- internalConsoleOptions: "neverOpen",
};
-const attachConfiguration: vscode.DebugConfiguration = {
+const ATTACH_CONFIGURATION: vscode.DebugConfiguration = {
type: "bun",
+ internalConsoleOptions: "neverOpen",
request: "attach",
name: "Attach Bun",
url: "ws://localhost:6499/",
stopOnEntry: false,
- internalConsoleOptions: "neverOpen",
};
const adapters = new Map<string, FileDebugSession>();
-export default function (context: vscode.ExtensionContext, factory?: vscode.DebugAdapterDescriptorFactory) {
+export function registerDebugger(context: vscode.ExtensionContext, factory?: vscode.DebugAdapterDescriptorFactory) {
context.subscriptions.push(
- vscode.commands.registerCommand("extension.bun.runFile", RunFileCommand),
- vscode.commands.registerCommand("extension.bun.debugFile", DebugFileCommand),
+ vscode.commands.registerCommand("extension.bun.runFile", runFileCommand),
+ vscode.commands.registerCommand("extension.bun.debugFile", debugFileCommand),
vscode.debug.registerDebugConfigurationProvider(
"bun",
new DebugConfigurationProvider(),
@@ -52,15 +53,15 @@ export default function (context: vscode.ExtensionContext, factory?: vscode.Debu
vscode.DebugConfigurationProviderTriggerKind.Dynamic,
),
vscode.debug.registerDebugAdapterDescriptorFactory("bun", factory ?? new InlineDebugAdapterFactory()),
- vscode.window.onDidOpenTerminal(InjectDebugTerminal),
+ vscode.window.onDidOpenTerminal(injectDebugTerminal),
);
}
-function RunFileCommand(resource?: vscode.Uri): void {
+function runFileCommand(resource?: vscode.Uri): void {
const path = getActivePath(resource);
if (path) {
vscode.debug.startDebugging(undefined, {
- ...runConfiguration,
+ ...RUN_CONFIGURATION,
noDebug: true,
program: path,
runtime: getRuntime(resource),
@@ -68,22 +69,21 @@ function RunFileCommand(resource?: vscode.Uri): void {
}
}
-function DebugFileCommand(resource?: vscode.Uri): void {
+export function debugCommand(command: string) {
+ vscode.debug.startDebugging(undefined, {
+ ...DEBUG_CONFIGURATION,
+ program: command,
+ runtime: getRuntime(),
+ });
+}
+
+function debugFileCommand(resource?: vscode.Uri) {
const path = getActivePath(resource);
- if (path) {
- vscode.debug.startDebugging(undefined, {
- ...debugConfiguration,
- program: path,
- runtime: getRuntime(resource),
- });
- }
+ if (path) debugCommand(path);
}
-function InjectDebugTerminal(terminal: vscode.Terminal): void {
- const enabled = getConfig("debugTerminal.enabled");
- if (enabled === false) {
- return;
- }
+function injectDebugTerminal(terminal: vscode.Terminal): void {
+ if (!getConfig("debugTerminal.enabled")) return
const { name, creationOptions } = terminal;
if (name !== "JavaScript Debug Terminal") {
@@ -118,16 +118,9 @@ function InjectDebugTerminal(terminal: vscode.Terminal): void {
setTimeout(() => terminal.dispose(), 100);
}
-class TerminalProfileProvider implements vscode.TerminalProfileProvider {
- provideTerminalProfile(token: vscode.CancellationToken): vscode.ProviderResult<vscode.TerminalProfile> {
- const { terminalProfile } = new TerminalDebugSession();
- return terminalProfile;
- }
-}
-
class DebugConfigurationProvider implements vscode.DebugConfigurationProvider {
provideDebugConfigurations(folder?: vscode.WorkspaceFolder): vscode.ProviderResult<vscode.DebugConfiguration[]> {
- return [debugConfiguration, runConfiguration, attachConfiguration];
+ return [DEBUG_CONFIGURATION, RUN_CONFIGURATION, ATTACH_CONFIGURATION];
}
resolveDebugConfiguration(
@@ -139,9 +132,9 @@ class DebugConfigurationProvider implements vscode.DebugConfigurationProvider {
const { request } = config;
if (request === "attach") {
- target = attachConfiguration;
+ target = ATTACH_CONFIGURATION;
} else {
- target = debugConfiguration;
+ target = DEBUG_CONFIGURATION;
}
// If the configuration is missing a default property, copy it from the template.
@@ -219,7 +212,7 @@ class TerminalDebugSession extends FileDebugSession {
this.signal = new UnixSignal();
this.signal.on("Signal.received", () => {
vscode.debug.startDebugging(undefined, {
- ...attachConfiguration,
+ ...ATTACH_CONFIGURATION,
url: this.adapter.url,
});
});
@@ -238,34 +231,19 @@ class TerminalDebugSession extends FileDebugSession {
}
}
-function getActiveDocument(): vscode.TextDocument | undefined {
- return vscode.window.activeTextEditor?.document;
-}
-
function getActivePath(target?: vscode.Uri): string | undefined {
- if (!target) {
- target = getActiveDocument()?.uri;
- }
- return target?.fsPath;
-}
-
-function isJavaScript(languageId?: string): boolean {
- return (
- languageId === "javascript" ||
- languageId === "javascriptreact" ||
- languageId === "typescript" ||
- languageId === "typescriptreact"
- );
+ return target?.fsPath ?? vscode.window.activeTextEditor?.document?.uri.fsPath;
}
function getRuntime(scope?: vscode.ConfigurationScope): string {
- const value = getConfig("runtime", scope);
+ const value = getConfig<string>("runtime", scope);
if (typeof value === "string" && value.trim().length > 0) {
return value;
}
return "bun";
}
-function getConfig<T>(path: string, scope?: vscode.ConfigurationScope): unknown {
- return vscode.workspace.getConfiguration("bun", scope).get(path);
+function getConfig<T>(path: string, scope?: vscode.ConfigurationScope) {
+ return vscode.workspace.getConfiguration("bun", scope).get<T>(path);
}
+ \ No newline at end of file
diff --git a/packages/bun-vscode/src/features/lockfile.ts b/packages/bun-vscode/src/features/lockfile/index.ts
index 777649270..df901b288 100644
--- a/packages/bun-vscode/src/features/lockfile.ts
+++ b/packages/bun-vscode/src/features/lockfile/index.ts
@@ -38,10 +38,10 @@ export class BunLockfileEditorProvider implements vscode.CustomReadonlyEditorPro
function renderLockfile({ webview }: vscode.WebviewPanel, preview: string, extensionUri: vscode.Uri): void {
const styleVSCodeUri = webview.asWebviewUri(vscode.Uri.joinPath(extensionUri, "media", "vscode.css"));
const lockfileContent = styleLockfile(preview);
-
- const lineNumbers: string[] = []
- for(let i = 0; i < lockfileContent.split('\n').length; i++){
- lineNumbers.push(`<span class="line-number">${i + 1}</span>`)
+
+ const lineNumbers: string[] = [];
+ for (let i = 0; i < lockfileContent.split("\n").length; i++) {
+ lineNumbers.push(`<span class="line-number">${i + 1}</span>`);
}
webview.html = `
@@ -50,7 +50,7 @@ function renderLockfile({ webview }: vscode.WebviewPanel, preview: string, exten
<head>
<meta charset="UTF-8">
- <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src ${webview.cspSource};">
+ <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src ${webview.cspSource};">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -59,7 +59,7 @@ function renderLockfile({ webview }: vscode.WebviewPanel, preview: string, exten
<body>
<div class="bunlock">
<div class="lines">
- ${lineNumbers.join('\n')}
+ ${lineNumbers.join("\n")}
</div>
<code>${lockfileContent}</code>
</div>
@@ -96,15 +96,17 @@ function previewLockfile(uri: vscode.Uri, token?: vscode.CancellationToken): Pro
});
}
-export default function (context: vscode.ExtensionContext): void {
+export function registerBunlockEditor(context: vscode.ExtensionContext): void {
const viewType = "bun.lockb";
const provider = new BunLockfileEditorProvider(context);
- vscode.window.registerCustomEditorProvider(viewType, provider, {
- supportsMultipleEditorsPerDocument: true,
- webviewOptions: {
- enableFindWidget: true,
- retainContextWhenHidden: true,
- },
- });
+ context.subscriptions.push(
+ vscode.window.registerCustomEditorProvider(viewType, provider, {
+ supportsMultipleEditorsPerDocument: true,
+ webviewOptions: {
+ enableFindWidget: true,
+ retainContextWhenHidden: true,
+ },
+ }),
+ );
}
diff --git a/packages/bun-vscode/src/features/lockfile/lockfile.style.ts b/packages/bun-vscode/src/features/lockfile/lockfile.style.ts
new file mode 100644
index 000000000..7c4650497
--- /dev/null
+++ b/packages/bun-vscode/src/features/lockfile/lockfile.style.ts
@@ -0,0 +1,35 @@
+export function styleLockfile(preview: string) {
+ // Match all lines that don't start with a whitespace character
+ const lines = preview.split(/\n(?!\s)/);
+
+ return lines.map(styleSection).join("\n");
+}
+
+function styleSection(section: string) {
+ const lines = section.split(/\n/);
+
+ return lines.map(styleLine).join("\n");
+}
+
+function styleLine(line: string) {
+ if (line.startsWith("#")) {
+ return `<span class="mtk5">${line}</span>`;
+ }
+
+ const parts = line.trim().split(" ");
+ if (line.startsWith(" ")) {
+ return `<span><span class="mtk1">&nbsp;&nbsp;&nbsp;&nbsp;${parts[0]}&nbsp;</span><span class="mtk16">${parts[1]}</span></span>`;
+ }
+ if (line.startsWith(" ")) {
+ const leftPart = `<span class="mtk6">&nbsp;&nbsp;${parts[0]}&nbsp;</span>`;
+
+ if (parts.length === 1) return `<span>${leftPart}</span>`;
+
+ if (parts[1].startsWith('"http://') || parts[1].startsWith('"https://'))
+ return `<span>${leftPart}<span class="mtk12 detected-link">${parts[1]}</span></span>`;
+ if (parts[1].startsWith('"')) return `<span>${leftPart}<span class="mtk16">${parts[1]}</span></span>`;
+
+ return `<span>${leftPart}<span class="mtk6">${parts[1]}</span></span>`;
+ }
+ return `<span class="mtk1">${line}&nbsp;</span>`;
+}
diff --git a/packages/bun-vscode/src/features/tasks/package.json.ts b/packages/bun-vscode/src/features/tasks/package.json.ts
new file mode 100644
index 000000000..f9a24937d
--- /dev/null
+++ b/packages/bun-vscode/src/features/tasks/package.json.ts
@@ -0,0 +1,197 @@
+/**
+ * Automatically generates tasks from package.json scripts.
+ */
+import * as vscode from "vscode";
+import { BunTask } from "./tasks";
+import { debugCommand } from "../debug";
+
+/**
+ * Parses tasks defined in the package.json.
+ */
+export async function providePackageJsonTasks(): Promise<BunTask[]> {
+ //
+ const scripts: Record<string, string> = await (async () => {
+ try {
+ const file = vscode.Uri.file(vscode.workspace.workspaceFolders[0]?.uri.fsPath + "/package.json");
+
+ // Load contents of package.json, no need to check if file exists, we return null if it doesn't
+ const contents = await vscode.workspace.fs.readFile(file);
+ return JSON.parse(contents.toString()).scripts;
+ } catch {
+ return null;
+ }
+ })();
+ if (!scripts) return [];
+
+ return Object.entries(scripts).map(([name, script]) => {
+ // Prefix script with bun if it doesn't already start with bun
+ const shellCommand = script.startsWith("bun") ? script : `bun ${script}`;
+
+ const task = new BunTask({
+ script,
+ name,
+ detail: `${shellCommand} - package.json`,
+ execution: new vscode.ShellExecution(shellCommand),
+ });
+ return task;
+ });
+}
+
+export function registerPackageJsonProviders(context: vscode.ExtensionContext) {
+ registerCodeLensProvider(context);
+ registerHoverProvider(context);
+}
+
+/**
+ * Utility function to extract the scripts from a package.json file, including their name and position in the document.
+ */
+function extractScriptsFromPackageJson(document: vscode.TextDocument) {
+ const content = document.getText();
+ const matches = content.match(/"scripts"\s*:\s*{([\s\S]*?)}/);
+ if (!matches || matches.length < 2) return null;
+
+ const startIndex = content.indexOf(matches[0]);
+ const endIndex = startIndex + matches[0].length;
+ const range = new vscode.Range(document.positionAt(startIndex), document.positionAt(endIndex));
+
+ const scripts = matches[1].split(/,\s*/).map(script => {
+ const [name, command] = script.split(/s*:\s*/);
+ return {
+ name: name.replace(/"/g, "").trim(),
+ command: command.replace(/"/g, "").trim(),
+ range: new vscode.Range(
+ document.positionAt(startIndex + matches[0].indexOf(name)),
+ document.positionAt(startIndex + matches[0].indexOf(name) + name.length + command.length),
+ ),
+ };
+ });
+
+ return {
+ range,
+ scripts,
+ };
+}
+
+/**
+ * This function registers a CodeLens provider for package.json files. It is used to display the "Run" and "Debug" buttons
+ * above the scripts properties in package.json (inline).
+ */
+function registerCodeLensProvider(context: vscode.ExtensionContext) {
+ context.subscriptions.push(
+ // Register CodeLens provider for package.json files
+ vscode.languages.registerCodeLensProvider(
+ {
+ language: "json",
+ scheme: "file",
+ pattern: "**/package.json",
+ },
+ {
+ provideCodeLenses(document: vscode.TextDocument) {
+ const { range } = extractScriptsFromPackageJson(document);
+
+ const codeLenses: vscode.CodeLens[] = [];
+ codeLenses.push(
+ new vscode.CodeLens(range, {
+ title: "$(breakpoints-view-icon) Bun: Debug",
+ tooltip: "Debug a script using bun",
+ command: "extension.bun.codelens.run",
+ arguments: [{ type: "debug" }],
+ }),
+ new vscode.CodeLens(range, {
+ title: "$(debug-start) Bun: Run",
+ tooltip: "Run a script using bun",
+ command: "extension.bun.codelens.run",
+ arguments: [{ type: "run" }],
+ }),
+ );
+ return codeLenses;
+ },
+ resolveCodeLens(codeLens) {
+ return codeLens;
+ },
+ },
+ ),
+ // Register the commands that are executed when clicking the CodeLens buttons
+ vscode.commands.registerCommand("extension.bun.codelens.run", async ({ type }: { type: "debug" | "run" }) => {
+ const tasks = (await vscode.tasks.fetchTasks({ type: "bun" })) as BunTask[];
+ if (tasks.length === 0) return;
+
+ const pick = await vscode.window.showQuickPick(
+ tasks
+ .filter(task => task.detail.endsWith("package.json"))
+ .map(task => ({
+ label: task.name,
+ detail: task.detail,
+ })),
+ );
+ if (!pick) return;
+
+ const task = tasks.find(task => task.name === pick.label);
+ if (!task) return;
+
+ const command = type === "debug" ? "extension.bun.codelens.debug.task" : "extension.bun.codelens.run.task";
+
+ vscode.commands.executeCommand(command, {
+ script: task.definition.script,
+ name: task.name,
+ });
+ }),
+ );
+}
+
+function getActiveTerminal(name: string) {
+ return vscode.window.terminals.filter(terminal => terminal.name === name);
+}
+
+interface CommandArgs {
+ script: string;
+ name: string;
+}
+
+/**
+ * This function registers a Hover language feature provider for package.json files. It is used to display the
+ * "Run" and "Debug" buttons when hovering over a script property in package.json.
+ */
+function registerHoverProvider(context: vscode.ExtensionContext) {
+ context.subscriptions.push(
+ vscode.languages.registerHoverProvider("json", {
+ provideHover(document, position) {
+ const { scripts } = extractScriptsFromPackageJson(document);
+
+ return {
+ contents: scripts.map(script => {
+ if (!script.range.contains(position)) return null;
+
+ const command = encodeURI(JSON.stringify({ script: script.command, name: script.name }));
+
+ const markdownString = new vscode.MarkdownString(
+ `[Debug](command:extension.bun.codelens.debug.task?${command}) | [Run](command:extension.bun.codelens.run.task?${command})`,
+ );
+ markdownString.isTrusted = true;
+
+ return markdownString;
+ }),
+ };
+ },
+ }),
+ vscode.commands.registerCommand("extension.bun.codelens.debug.task", async ({ script, name }: CommandArgs) => {
+ if (script.startsWith("bun ")) script = script.slice(4);
+ debugCommand(script);
+ }),
+ vscode.commands.registerCommand("extension.bun.codelens.run.task", async ({ script, name }: CommandArgs) => {
+ if (script.startsWith("bun ")) script = script.slice(4);
+
+ name = `Bun Task: ${name}`;
+ const terminals = getActiveTerminal(name);
+ if (terminals.length > 0) {
+ terminals[0].show();
+ terminals[0].sendText(`bun ${script}`);
+ return;
+ }
+
+ const terminal = vscode.window.createTerminal({name});
+ terminal.show();
+ terminal.sendText(`bun ${script}`);
+ }),
+ );
+}
diff --git a/packages/bun-vscode/src/features/tasks/tasks.ts b/packages/bun-vscode/src/features/tasks/tasks.ts
new file mode 100644
index 000000000..aabeb3920
--- /dev/null
+++ b/packages/bun-vscode/src/features/tasks/tasks.ts
@@ -0,0 +1,59 @@
+import * as vscode from "vscode";
+import { providePackageJsonTasks } from "./package.json";
+
+interface BunTaskDefinition extends vscode.TaskDefinition {
+ script: string;
+}
+
+export class BunTask extends vscode.Task {
+ declare definition: BunTaskDefinition;
+
+ constructor({
+ script,
+ name,
+ detail,
+ execution,
+ scope = vscode.TaskScope.Workspace,
+ }: {
+ script: string;
+ name: string;
+ detail?: string;
+ scope?: vscode.WorkspaceFolder | vscode.TaskScope.Global | vscode.TaskScope.Workspace;
+ execution?: vscode.ProcessExecution | vscode.ShellExecution | vscode.CustomExecution;
+ }) {
+ super({ type: "bun", script }, scope, name, "bun", execution);
+ this.detail = detail;
+ }
+}
+
+/**
+ * Registers the task provider for the bun extension.
+ */
+export function registerTaskProvider(context: vscode.ExtensionContext) {
+ const taskProvider: vscode.TaskProvider<BunTask> = {
+ provideTasks: async () => await providePackageJsonTasks(),
+ resolveTask: task => resolveTask(task),
+ };
+ context.subscriptions.push(vscode.tasks.registerTaskProvider("bun", taskProvider));
+}
+
+/**
+ * Parses tasks defined in the vscode tasks.json file.
+ * For more information, see https://code.visualstudio.com/api/extension-guides/task-provider
+ */
+export function resolveTask(task: BunTask): BunTask | undefined {
+ // Make sure the task has a script defined
+ const definition: BunTask["definition"] = task.definition;
+ if (!definition.script) return task;
+ const shellCommand = definition.script.startsWith("bun ") ? definition.script : `bun ${definition.script}`;
+
+ const newTask = new vscode.Task(
+ definition,
+ task.scope ?? vscode.TaskScope.Workspace,
+ task.name,
+ "bun",
+ new vscode.ShellExecution(shellCommand),
+ ) as BunTask;
+ newTask.detail = `${shellCommand} - tasks.json`;
+ return newTask;
+}