diff --git a/extension/README.md b/extension/README.md
index 7494c765..5e775cc9 100644
--- a/extension/README.md
+++ b/extension/README.md
@@ -90,6 +90,7 @@ also appear in the editor title bar, the Explorer, or **Project Options**.
| **Project Options** | Open the project menu |
| **Build** | Build without running |
| **Run** | Build and run in the emulator |
+| **Debug** | Build and debug in the emulator, with breakpoints and step back |
| **Run This File** | Run the active file, without changing the project |
| **Run Main File** | Run the project's main file |
| **Follow Active Editor** | Run whichever program is in the editor |
diff --git a/extension/docs/emulator.md b/extension/docs/emulator.md
index ca3e8b14..a7cad317 100644
--- a/extension/docs/emulator.md
+++ b/extension/docs/emulator.md
@@ -55,8 +55,10 @@ states, so it keeps about 10 seconds.
## Debug
-Press F5 to build the program and debug it. Press
-Ctrl+F5 (**Run Without Debugging**) to just run it.
+Click **Debug** (the bug button beside **Run**, at the top right of the
+editor) or run **8bitworkshop: Debug** to build the program and debug it.
+In a folder with a launch configuration, F5 does the same, and
+Ctrl+F5 (**Run Without Debugging**) just runs it.
- **Breakpoints:** click left of a line number in C or assembly. You can
also add a breakpoint on a function by name (**+** in the Breakpoints
diff --git a/extension/package.json b/extension/package.json
index 7c1ab897..eb2f6866 100644
--- a/extension/package.json
+++ b/extension/package.json
@@ -111,6 +111,12 @@
"category": "8bitworkshop",
"icon": "$(play)"
},
+ {
+ "command": "8bitworkshop.debug",
+ "title": "Debug",
+ "category": "8bitworkshop",
+ "icon": "$(debug-alt)"
+ },
{
"command": "8bitworkshop.runThisFile",
"title": "Run This File",
@@ -358,6 +364,11 @@
"when": "8bitworkshop.canRun && activeWebviewPanelId != '8bitworkshop.emulator'",
"group": "navigation"
},
+ {
+ "command": "8bitworkshop.debug",
+ "when": "8bitworkshop.canRun && activeWebviewPanelId != '8bitworkshop.emulator' && !inDebugMode",
+ "group": "navigation"
+ },
{
"command": "8bitworkshop.copyToWorkspace",
"when": "resourceScheme == 8bws-preset",
diff --git a/extension/src/extension.ts b/extension/src/extension.ts
index 6a676eb0..d83658c2 100644
--- a/extension/src/extension.ts
+++ b/extension/src/extension.ts
@@ -84,6 +84,7 @@ export function activate(ctx: vscode.ExtensionContext) {
}));
command('build', () => buildCommand(false));
command('run', () => buildCommand(true));
+ command('debug', () => debugCommand());
command('runThisFile', (uri?: vscode.Uri) => runThisFile(uri));
command('runMainFile', () => runMainFile());
command('followActiveEditor', () => followActiveEditor());
@@ -371,19 +372,30 @@ async function projectMenu() {
////// build and run
async function buildCommand(run: boolean) {
+ var target = await ensureTarget();
+ if (target) await buildAndMaybeRun(target, run, 'command');
+}
+
+/** Debug the current target, as F5 would with no launch configuration. */
+async function debugCommand() {
+ var target = await ensureTarget();
+ if (!target) return;
+ // no mainFile: the launch debugs the current target (see launchTarget)
+ await vscode.debug.startDebugging(vscode.workspace.getWorkspaceFolder(target.main),
+ { type: '8bitworkshop', request: 'launch', name: `Debug ${describeTarget(target)}` });
+}
+
+/** The current target; for a file no project owns yet, start one from it (case 2). */
+async function ensureTarget(): Promise {
var target = currentTarget();
- if (!target) {
- // no project owns this file yet: start one from it (case 2)
- var uri = activeUri();
- if (!uri || !isSourceFile(uri.fsPath)) {
- vscode.window.showWarningMessage('8bitworkshop: open a source file, or run "8bitworkshop: New Project...".');
- return;
- }
- if (!await setMainFile(uri)) return;
- target = currentTarget();
- if (!target) return;
+ if (target) return target;
+ var uri = activeUri();
+ if (!uri || !isSourceFile(uri.fsPath)) {
+ vscode.window.showWarningMessage('8bitworkshop: open a source file, or run "8bitworkshop: New Project...".');
+ return undefined;
}
- await buildAndMaybeRun(target, run, 'command');
+ if (!await setMainFile(uri)) return undefined;
+ return currentTarget();
}
async function buildAndMaybeRun(target: Target, run: boolean, reason: BuildReason) {