Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,12 @@ The extension provides a **custom `winapp` debug type** that launches your app w

| `debuggerType` | Language | Required Extension |
|----------------|----------|--------------------|
| `coreclr` (default) | C# / .NET | [C# Dev Kit](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp) |
| `coreclr` | C# / .NET | [C#](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp) |
| `cppvsdbg` | C / C++ | [C/C++](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) |
| `node` | Node.js / Electron | Built-in |

> On your first debug session, if the extension for the selected `debuggerType` isn't installed, WinApp offers to install it and continues the session automatically — no manual reload needed in most cases. If no `debuggerType` is set and none is installed yet, WinApp lets you pick the debugger that matches your project (C#, C/C++, or built-in Node.js/Electron).

**Example `launch.json`:**

```jsonc
Expand All @@ -158,7 +160,7 @@ The extension provides a **custom `winapp` debug type** that launches your app w
|----------|------|---------|-------------|
| `inputFolder` | string | | Path to the build output folder containing your app binaries (e.g., `${workspaceFolder}/bin/Debug/net8.0-windows10.0.22621`). If not set, you will be prompted to select a folder. |
| `manifest` | string | | Path to the `AppxManifest.xml` file. If not set, the CLI auto-detects from the input folder or current directory. |
| `debuggerType` | string | `coreclr` | Underlying debugger to use (`coreclr`, `cppvsdbg`, or `node`). |
| `debuggerType` | string | | Optional underlying debugger override (`coreclr`, `cppvsdbg`, or `node`). If omitted, WinApp reuses an installed debugger or prompts you to pick one. |
| `workingDirectory` | string | workspace folder | Working directory for the application. |
| `args` | string | | Command-line arguments to pass to the application. |
| `outputAppxDirectory` | string | | Output directory for the loose-layout package. Defaults to an `AppX` folder inside the input folder. |
Expand Down
13 changes: 8 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,12 @@
},
"debuggerType": {
"type": "string",
"description": "The underlying debugger to use (e.g., 'coreclr', 'cppvsdbg')",
"default": "coreclr"
"enum": [
"coreclr",
"cppvsdbg",
"node"
],
"description": "Optional override for the underlying debugger to use. Omit to let WinApp reuse an installed debugger or prompt you to pick one ('coreclr', 'cppvsdbg', or 'node')."
},
"workingDirectory": {
"type": "string",
Expand Down Expand Up @@ -195,8 +199,7 @@
"body": {
"type": "winapp",
"request": "launch",
"name": "WinApp: Launch and Attach",
"debuggerType": "coreclr"
"name": "WinApp: Launch and Attach"
}
}
]
Expand All @@ -216,7 +219,7 @@
"clean": "node -e \"require('fs').rmSync('bin', {recursive: true, force: true}); require('fs').rmSync('out', {recursive: true, force: true}); require('fs').rmSync('dist', {recursive: true, force: true});\"",
"download-cli": "pwsh -NoProfile -Command \"& ./scripts/download-cli.ps1\"",
"download-cli:latest": "pwsh -NoProfile -Command \"& ./scripts/download-cli.ps1 -Tag latest\"",
"test:unit": "tsc -p ./ && node -e \"require('fs').cpSync('src/test/fixtures','out/test/fixtures',{recursive:true})\" && mocha out/test/project-detection.test.js && npx tsx --test src/test/extension-field-validator.test.ts src/test/extension-templates.test.ts src/test/manifest-edge-cases.test.ts src/test/manifest-parser.test.ts src/test/manifest-validator.test.ts src/test/project-resolver.test.ts src/test/redos-prevention.test.ts src/test/xml-utils.test.ts src/test/shell-escape.test.ts"
"test:unit": "tsc -p ./ && node -e \"require('fs').cpSync('src/test/fixtures','out/test/fixtures',{recursive:true})\" && mocha out/test/project-detection.test.js && npx tsx --test src/test/debugger-resolver.test.ts src/test/extension-field-validator.test.ts src/test/extension-templates.test.ts src/test/manifest-edge-cases.test.ts src/test/manifest-parser.test.ts src/test/manifest-validator.test.ts src/test/project-resolver.test.ts src/test/redos-prevention.test.ts src/test/xml-utils.test.ts src/test/shell-escape.test.ts"
},
"dependencies": {
"@xmldom/xmldom": "^0.9.9",
Expand Down
55 changes: 55 additions & 0 deletions src/debugger-resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
export interface DebuggerExtensionRequirement {
id: string;
name: string;
}

/**
* Maps debugger types to the VS Code extensions that provide them.
*/
export const DEBUGGER_EXTENSION_REQUIREMENTS: Record<string, DebuggerExtensionRequirement> = {
'coreclr': { id: 'ms-dotnettools.csharp', name: 'C# (ms-dotnettools.csharp)' },
'cppvsdbg': { id: 'ms-vscode.cpptools', name: 'C/C++ (ms-vscode.cpptools)' },
};

/**
* Debugger types to consider (in preference order) when a launch configuration
* doesn't specify one, and we need to reuse an already-installed extension.
*/
export const DEFAULT_DEBUGGER_CANDIDATES: string[] = ['coreclr', 'cppvsdbg'];

export const DEBUGGER_CHOICE_LABELS = {
installCsharp: 'Install C# (.NET)',
installCpp: 'Install C/C++',
useNode: 'Use Node.js / Electron (built-in)'
} as const;

export function getDebuggerExtensionRequirement(debuggerType: string): DebuggerExtensionRequirement | undefined {
return DEBUGGER_EXTENSION_REQUIREMENTS[debuggerType];
}

export function chooseInstalledDebuggerType(
installedExtensionIds: Iterable<string>,
candidates: readonly string[] = DEFAULT_DEBUGGER_CANDIDATES
): string | undefined {
const installed = new Set([...installedExtensionIds].map(id => id.toLowerCase()));
for (const candidate of candidates) {
const requirement = getDebuggerExtensionRequirement(candidate);
if (requirement && installed.has(requirement.id.toLowerCase())) {
return candidate;
}
}
return undefined;
}

export function getDebuggerTypeFromChoice(choice: string | undefined): string | undefined {
if (choice === DEBUGGER_CHOICE_LABELS.installCsharp) {
return 'coreclr';
}
if (choice === DEBUGGER_CHOICE_LABELS.installCpp) {
return 'cppvsdbg';
}
if (choice === DEBUGGER_CHOICE_LABELS.useNode) {
return 'node';
}
return undefined;
}
Loading
Loading