diff --git a/README.md b/README.md index 085d977..0c9c7a5 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ To start the emulator and begin debugging automatically: "args": ["--dap"], "stopOnEntry": true, "cwd": "${workspaceFolder}", + "srcDirs": ["${workspaceFolder}/lib/src", ...], "trace": true } ``` @@ -75,6 +76,7 @@ To start the emulator and begin debugging automatically: * `args`: Enter whatever arguments your emulator needs to enable DAP server. * `stopOnEntry`: Set to `true` to halt at program start. * `cwd`: Working directory. +* `srcDirs`: Optional additional list of paths to lookup for source files * `trace`: Enables DAP message logging for troubleshooting. ### Attach to a Running Emulator @@ -142,6 +144,7 @@ for the pack is being received. List of emulators supporting this variation of DAP: * Emu Emu — The [X65 Computer](https://x65.zone/) Emulator. +* Steckschwein Steckschwein Emulator — The [Steckschwein](https://www.steckschwein.de/) Emulator. If you know any other, please [create a PR][4] with an update to the list. diff --git a/package.json b/package.json index 05db837..2c9ac85 100644 --- a/package.json +++ b/package.json @@ -178,6 +178,14 @@ "type": "string", "description": "Absolute path to the working directory.", "default": "${cwd}" + }, + "srcDirs": { + "type": "array", + "items": { + "type": "string" + }, + "description": "An additional list of lookup paths for source files - e.g. required if we step from main debug code into a subroutine of a library", + "default": false } } }, @@ -203,6 +211,14 @@ "type": "boolean", "description": "Run without debugging.", "default": false + }, + "srcDirs": { + "type": "array", + "items": { + "type": "string" + }, + "description": "An additional list of lookup paths for source files - e.g. required if we step from main debug code into a subroutine of a library", + "default": false } } } diff --git a/src/cc65Debug.ts b/src/cc65Debug.ts index 4590ded..7c8ad8a 100644 --- a/src/cc65Debug.ts +++ b/src/cc65Debug.ts @@ -12,6 +12,7 @@ */ import { type ChildProcessWithoutNullStreams, spawn } from "node:child_process"; +import * as fs from "node:fs"; import * as path from "node:path"; import { Logger, LoggingDebugSession, TerminatedEvent, logger } from "@vscode/debugadapter"; import type { DebugProtocol } from "@vscode/debugprotocol"; @@ -52,6 +53,8 @@ interface IRequestArguments extends DebugProtocol.LaunchRequestArguments { trace?: boolean; /** run without debugging */ noDebug?: boolean; + /** An additional list of lookup paths for source files - e.g. required if we step from main debug code into a subroutine of a library */ + srcDirs?: string[]; } interface ILaunchRequestArguments extends IRequestArguments { @@ -105,6 +108,11 @@ export class Cc65DebugSession extends LoggingDebugSession { this.setDebuggerLinesStartAt1(true); this.setDebuggerColumnsStartAt1(true); + const srcDirs: string[] = this._session.configuration.srcDirs || []; + + this._debugPathBases = [ + ...new Set([...this._debugPathBases, ...((srcDirs as string[]) ?? [])]), + ]; // make sure to 'Stop' the buffered logging if 'trace' is not set logger.setup( this._session.configuration.trace ? Logger.LogLevel.Verbose : Logger.LogLevel.Stop, @@ -696,10 +704,14 @@ export class Cc65DebugSession extends LoggingDebugSession { showUser: true, }); } - + const dbgFileBaseName = path.basename(sourceBase); + const dbgFileSize = fs.statSync(source.path).size; const dbgFile = this._debugData?.file.find((file) => { const filePath = `${path.posix.sep}${normalizePath(file.name)}`; - return filePath.endsWith(`${path.posix.sep}${sourceBase}`); + return ( + dbgFileSize === file.size && + filePath.endsWith(`${path.posix.sep}${dbgFileBaseName}`) + ); }); if (!response.body) response.body = { breakpoints: [] }; @@ -717,7 +729,7 @@ export class Cc65DebugSession extends LoggingDebugSession { } // Store path base for later name reconstruction - const fileBase = normalizePath(dbgFile.name).slice(0, -sourceBase.length); + const fileBase = sourceBase.slice(0, -normalizePath(dbgFile.name).length); if (!this._debugPathBases.includes(fileBase)) this._debugPathBases.push(fileBase); // map source lines to memory addresses @@ -926,9 +938,15 @@ export class Cc65DebugSession extends LoggingDebugSession { // -------------------------------------------------------------------- private dbgFile2workspace(dbgFile: DbgFile) { const fileName = normalizePath(dbgFile.name); - for (const base of this._debugPathBases) { - if (fileName.startsWith(base)) { - return fileName.slice(base.length); + // lookup relative to workspaceFolder + const workspaceFolder = normalizePath( + path.resolve(this._session.workspaceFolder?.uri.fsPath || "."), + ); + // build path and do fs lookup + for (const pathBase of this._debugPathBases) { + const candidate = path.resolve(workspaceFolder, pathBase, fileName); + if (fs.existsSync(candidate) && fs.statSync(candidate).size === dbgFile.size) { + return normalizePath(path.relative(workspaceFolder, candidate)); } } }