Skip to content

Commit

Permalink
Support debugging via launch.json for AHK v1 and AHK v2 (#606)
Browse files Browse the repository at this point in the history
  • Loading branch information
mark-wiemer authored Feb 19, 2025
1 parent 6c80f9c commit 838d258
Show file tree
Hide file tree
Showing 12 changed files with 123 additions and 48 deletions.
37 changes: 37 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,43 @@
"--extensionDevelopmentPath=${workspaceFolder}"
],
"testConfiguration": "${workspaceFolder}/.vscode-test.mjs"
},
// below configs are just for manual tests, not for debugging this project
{
"name": "AHK v1 \\",
"type": "ahk",
"request": "launch",
"program": "${workspaceFolder}\\demos\\manualTests\\debugger.ahk1"
},
{
"name": "AHK v2 \\",
"type": "ahk2",
"request": "launch",
"program": "${workspaceFolder}\\demos\\manualTests\\debugger.ahk2"
},
{
"name": "AHK v1 /",
"type": "ahk",
"request": "launch",
"program": "${workspaceFolder}/demos/manualTests/debugger.ahk1"
},
{
"name": "AHK v2 /",
"type": "ahk2",
"request": "launch",
"program": "${workspaceFolder}/demos/manualTests/debugger.ahk2"
},
{
"name": "AHK v1 mixed",
"type": "ahk",
"request": "launch",
"program": "${workspaceFolder}/demos\\manualTests/debugger.ahk1"
},
{
"name": "AHK v2 mixed",
"type": "ahk2",
"request": "launch",
"program": "${workspaceFolder}/demos\\manualTests/debugger.ahk2"
}
]
}
9 changes: 9 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

## 6.5.0 - unreleased 💞

- Add [docs/debugging.md](./docs/debugging.md) and [docs/\_welcome.md](./docs/_welcome.md)
- Fix `.vscode/launch.json` support for AHK v1 ([Issue #603](https://github.com/mark-wiemer/ahkpp/issues/603))
- Add `.vscode/launch.json` support for AHK v2 ([PR #606](https://github.com/mark-wiemer/ahkpp/issues/603))
- Change "AutoHotkey execute bin not found: ..." to "AutoHotkey interpreter not found" with a preceding message showing the interpreter path. ([PR #606](https://github.com/mark-wiemer/ahkpp/issues/603))
- Remove the `runtime` argument from `launch.json` support due to issues with cross-version debugging ([PR #606](https://github.com/mark-wiemer/ahkpp/issues/603))
- We are not considering this a breaking change as this behavior didn't work before. If you'd like to use different AHK interpreters across different workspaces, use IDE workspace settings. If you'd like to use different AHK interpreters within a single workspace, please [open a discussion](https://github.com/mark-wiemer/ahkpp/discussions/new/choose)

## 6.4.3 - 2025-01-18 🎆

- Fix IniWrite IntelliSense ([#590](https://github.com/mark-wiemer/ahkpp/issues/590))
Expand Down
4 changes: 4 additions & 0 deletions demos/manualTests/debugger.ahk1
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@
x := 1
y := 2 ; Breakpoint here
z := 3
MsgBox, 0, % "AHK v1", % "Hello from AHK v1", 1

; With this file open, try to debug the AHK v2 file using each launch config
; With this file open, try to debug this file using any launch config
4 changes: 4 additions & 0 deletions demos/manualTests/debugger.ahk2
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@
x := 1
y := 2 ; Breakpoint here
z := 3
MsgBox("Hello from AHK v2", "AHK v2", "T1")

; With this file open, try to debug the AHK v1 file using each launch config
; With this file open, try to debug this file using any launch config
18 changes: 15 additions & 3 deletions docs/debugging.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ AHK++ adds run and debug buttons to the editor's title bar whenever an AHK file

VS Code supports debug configurations definitions in `.vscode/launch.json`. This can be a useful way to run your `main.ahk` script from wherever you are in your workspace with a single keystroke.

⚠️ There are some known issues with AHK++ support for debug configurations, refer to [#603](https://github.com/mark-wiemer/ahkpp/issues/603) for details.

1. Create `.vscode/launch.json` in your workspace
1. Populate it with whatever launch config you prefer, for example:

Expand All @@ -34,11 +32,25 @@ VS Code supports debug configurations definitions in `.vscode/launch.json`. This
"type": "ahk", // or ahk2
"request": "launch",
"name": "AutoHotkey debugger",
"program": "${workspaceFolder}\\main.ahk1", // requires backslashes for now
"program": "${workspaceFolder}/main.ahk1", // backslashes and mixed slashes also supported
"stopOnEntry": true,
},
],
}
```

1. Press `F5` to debug your project

### Notes

AHK++ ignores the `runtime` argument common in other debuggers. Instead, all debug sessions use either the `V1: File > interpreterPath` or `V2: File > interpreterPath` setting. See [settings.md](./settings.md) for details.

## Troubleshooting

If debugging starts but suddenly stops silently, you may have a syntax error. Try just running your script, not debugging it, to see if it works. For advanced troubleshooting, see [troubleshooting.md](./troubleshooting.md)

---

## For contributors

Debuggers are hard to work with. We recommend adding `Out.debug` statements, re-packaging the extension, re-installing it, and restarting extensions. Then you can work with the `demos/manualTests/debugger.ahk*` files. Trying to start a debugger while in a debug session is difficult. Trying to debug a debugger at all is also difficult. Good luck, be patient, and be ready to read a lot of docs.
4 changes: 2 additions & 2 deletions docs/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Interpreter not found:

Some settings changes only take effect after restart. Other issues may arise that are mitigated with a restart.

To restart all extensions, press F1 to open the command palette and enter "Developer: Restart Extension Host". Extensions should restart within a few seconds.
To restart all extensions, press `F1` to open the command palette and enter "Developer: Restart Extension Host". Extensions should restart within a few seconds.

If you're able to consistently reproduce the issue, please [open a bug](https://github.com/mark-wiemer/ahkpp/issues/new/choose).

Expand All @@ -49,4 +49,4 @@ These steps shouldn't be necessary for most issues, and may be difficult to exec

### Debug logs

Using Ctrl+Shift+U to open the output view, you can select either of the AHK++ channels to see all debug logs. You're welcome to map these logs to `Output.debug` and `console.log` calls in the source code. Please include your findings if you [open a bug](https://github.com/mark-wiemer/ahkpp/issues/new/choose).
Using `Ctrl+Shift+U` to open the output view, you can select either of the AHK++ channels to see all debug logs. You're welcome to map these logs to `Output.debug` and `console.log` calls in the source code. Please include your findings if you [open a bug](https://github.com/mark-wiemer/ahkpp/issues/new/choose).
16 changes: 8 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 0 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -782,7 +782,6 @@
"ahk"
],
"program": "./out/debugger/DebugAdapter.js",
"runtime": "\"C:\\Program Files\\AutoHotkey\\AutoHotkeyU64.exe\"",
"configurationAttributes": {
"launch": {
"required": [
Expand All @@ -794,11 +793,6 @@
"description": "Absolute path to the AHK v1 script to debug.",
"default": "${file}"
},
"runtime": {
"type": "string",
"description": "Absolute path to an AutoHotkey v1 interpreter.",
"default": "C:\\Program Files\\AutoHotkey\\AutoHotkeyU64.exe"
},
"stopOnEntry": {
"type": "boolean",
"description": "Automatically stop after launch.",
Expand Down Expand Up @@ -858,7 +852,6 @@
"ahk2"
],
"program": "./out/debugger/DebugAdapter.js",
"runtime": "\"C:\\Program Files\\AutoHotkey\\v2\\AutoHotkey64.exe\"",
"configurationAttributes": {
"launch": {
"required": [
Expand All @@ -870,11 +863,6 @@
"description": "Absolute path to the AHK v2 script to debug.",
"default": "${file}"
},
"runtime": {
"type": "string",
"description": "Absolute path to an AutoHotkey v2 interpreter.",
"default": "C:\\Program Files\\AutoHotkey\\v2\\AutoHotkey64.exe"
},
"stopOnEntry": {
"type": "boolean",
"description": "Automatically stop after launch.",
Expand Down
3 changes: 3 additions & 0 deletions src/debugger/DebugAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { Out } from 'src/common/out';
import { DebugSession } from './debugSession';

Out.debug('Starting DebugAdapter');

DebugSession.run(DebugSession);
54 changes: 33 additions & 21 deletions src/debugger/debugDispatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,12 @@ import { StackHandler } from './handler/StackHandler';
import { VariableHandler } from './handler/variableHandler';
import { DbgpResponse } from './struct/dbgpResponse';
import { VarScope } from './struct/scope';

import getPort from 'get-port';
import { spawn } from 'child_process';
import { resolve } from 'path';
import { existsSync } from 'fs';
import { Out } from '../common/out';
import { Global, ConfigKey } from '../common/global';
import { isV1 } from '../common/codeUtil';

/** An AHK runtime debugger, ref https://xdebug.org/docs/dbgp */
export class DebugDispatcher extends EventEmitter {
Expand All @@ -34,19 +32,34 @@ export class DebugDispatcher extends EventEmitter {

/** Start executing the given program. */
public async start(args: LaunchRequestArguments) {
const interpreterPathKey = isV1()
? ConfigKey.interpreterPathV1
: ConfigKey.interpreterPathV2;
const runtime: string =
args.runtime ?? Global.getConfig(interpreterPathKey);
Out.debug(`DebugDispatcher.start#args`);
Out.debug(`\t${JSON.stringify(args)}`);
/** Default to AHK v1 if type not provided */
const isAhk2 = args.type === 'ahk2';
const interpreterPathKey = isAhk2
? ConfigKey.interpreterPathV2
: ConfigKey.interpreterPathV1;
const runtime = Global.getConfig<string>(interpreterPathKey);
Out.debug(`DebugDispatcher.start#args.runtime`);
Out.debug(`\t${runtime}`);
if (!existsSync(runtime)) {
// Exact text is referenced in changelog, update changelog when updating this value
Out.log(`AutoHotkey interpreter not found`);
Out.debug(
`Please update v${isAhk2 ? 2 : 1}: File > interpreterPath`,
);
this.end();
return;
}

// #region misc settings
const dbgpSettings = args.dbgpSettings ?? {};
const { maxChildren, maxData }: LaunchRequestArguments['dbgpSettings'] =
{
maxChildren: 300,
maxData: 131072,
...dbgpSettings,
};

this.breakPointHandler = new BreakPointHandler();
this.stackHandler = new StackHandler();
this.variableHandler = new VariableHandler();
Expand All @@ -58,7 +71,7 @@ export class DebugDispatcher extends EventEmitter {
.start()
.on('init', () => {
this.breakPointHandler.loopPoints((bp) => {
this.setBreakPonit(bp);
this.setBreakpoint(bp);
});
this.sendCommand(
`feature_set -n max_children -v ${maxChildren}`,
Expand Down Expand Up @@ -94,19 +107,18 @@ export class DebugDispatcher extends EventEmitter {
}
}
});
// #endregion

//* Setup program path
if (!args.program) {
args.program = await RunnerService.getPathByActive();
}

const programName = getFileNameOnly(args.program);
Out.debug(`DebugDispatcher.start#programName`);
Out.debug(`\t${programName}`);

if (!existsSync(runtime)) {
// Exact text is referenced in docs, update docs when updating this value
Out.log(`AutoHotkey execute bin not found: ${runtime}`);
this.end();
return;
}

//* Spawn AHK process
Out.debug(`DebugDispatcher.start: Spawning process`);
const ahkProcess = spawn(
runtime,
['/ErrorStdOut', `/debug=localhost:${port}`, programName],
Expand Down Expand Up @@ -295,7 +307,7 @@ export class DebugDispatcher extends EventEmitter {
return this.stackHandler.handle(args, response);
}

private async setBreakPonit(bp: DebugProtocol.Breakpoint) {
private async setBreakpoint(bp: DebugProtocol.Breakpoint) {
if (this.debugServer && bp.verified) {
const res = await this.sendCommand(
`breakpoint_set -t line -f ${bp.source.path} -n ${bp.line}`,
Expand All @@ -313,7 +325,7 @@ export class DebugDispatcher extends EventEmitter {
path,
sourceBreakpoints,
(bp) => {
this.setBreakPonit(bp);
this.setBreakpoint(bp);
},
);
}
Expand Down Expand Up @@ -346,11 +358,11 @@ export class DebugDispatcher extends EventEmitter {

/**
* Returns the user-friendly "name" of the file instead of its path
* @param path backslash-delimited path
* @param path slash-delimited path (backslash, forward slash, or mixed)
* @returns last segment of the path
* @example ('c:\\Users\\mark\\myScript.ahk') => 'myScript.ahk'
*/
const getFileNameOnly = (path: string): string => {
const splitPath = path.split('\\');
const splitPath = path.split(/\\\\|\//);
return splitPath[splitPath.length - 1];
};
6 changes: 4 additions & 2 deletions src/debugger/debugSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { DebugProtocol } from '@vscode/debugprotocol';
import { DebugDispatcher } from './debugDispatcher';
import { Continue } from './struct/command';
import { VscodeScope } from './struct/scope';
import { Out } from 'src/common/out';

/**
* This interface describes the mock-debug specific launch attributes
Expand All @@ -20,10 +21,10 @@ import { VscodeScope } from './struct/scope';
*/
export interface LaunchRequestArguments
extends DebugProtocol.LaunchRequestArguments {
/** AHK v1 or AHK v2 */
type?: 'ahk' | 'ahk2';
/** An absolute path to the "program" to debug. */
program: string;
/** An absolute path to the AutoHotkey.exe. */
runtime: string;
dbgpSettings: {
maxChildren: number;
maxData: number;
Expand All @@ -38,6 +39,7 @@ export class DebugSession extends LoggingDebugSession {
private dispatcher: DebugDispatcher;

public constructor() {
Out.debug('DebugSession.constructor');
super();

// this debugger uses zero-based lines and columns
Expand Down
4 changes: 4 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ export function activate(context: vscode.ExtensionContext) {
'ahk',
new InlineDebugAdapterFactory(),
),
vscode.debug.registerDebugAdapterDescriptorFactory(
'ahk2',
new InlineDebugAdapterFactory(),
),
createEditorListener(),
vscode.commands.registerCommand('ahk++.compile', () =>
RunnerService.compile(false),
Expand Down

0 comments on commit 838d258

Please sign in to comment.