From c8f8ed2a9cea9dc3076df8ffbb317f0fa73f0ae9 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Wed, 11 Mar 2026 19:57:06 +0100 Subject: [PATCH] add doc strings --- .github/workflows/publish.yml | 3 ++- src/backend/adapter.ts | 32 ++++++++++++++++++++++++++++++++ src/backend/expand_value.ts | 2 ++ src/backend/mi2/mi2.ts | 14 ++++++++++++++ src/backend/mi2/types.ts | 4 ++++ src/extension.ts | 3 +++ src/frontend/registers.ts | 5 +++++ src/utils.ts | 18 ++++++++++++++++++ 8 files changed, 80 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 84eb70b..e72668c 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -20,6 +20,7 @@ jobs: registry-url: https://registry.npmjs.org - run: npm install -g npm@latest - - run: npm ci + - run: npm install + - run: rm -rf dist - run: npm run build - run: npm publish --provenance --access public diff --git a/src/backend/adapter.ts b/src/backend/adapter.ts index 4364e07..799e17d 100644 --- a/src/backend/adapter.ts +++ b/src/backend/adapter.ts @@ -23,6 +23,7 @@ import { MI2 } from './mi2/mi2'; import { MINode } from './mi_parse'; import { SymbolTable } from './symbols'; +/** Wraps a variable reference with options. */ class ExtendedVariable { constructor( public name: string, @@ -45,6 +46,7 @@ class CustomContinuedEvent extends Event { } } +/** DAP implementation on top of GDB/MI2. */ export class GDBDebugSession extends DebugSession { private variableHandles = new Handles(131072); private variableHandlesReverse: { [name: string]: number } = {}; @@ -68,6 +70,7 @@ export class GDBDebugSession extends DebugSession { super(debuggerLinesStartAt1, isServer); } + /** Attaches MI2 listeners and sends InitializedEvent. */ initDebugger(): void { this.miDebugger.on('launcherror', this.launchError.bind(this)); this.miDebugger.on('quit', this.quitEvent.bind(this)); @@ -85,6 +88,7 @@ export class GDBDebugSession extends DebugSession { this.sendEvent(new InitializedEvent()); } + /** Responds to DAP initialize with capabilities. */ protected initializeRequest(response: any, args: any): void { response.body.supportsConditionalBreakpoints = true; response.body.supportsConfigurationDoneRequest = true; @@ -98,16 +102,19 @@ export class GDBDebugSession extends DebugSession { this.sendResponse(response); } + /** Handles DAP launch request. */ protected launchRequest(response: any, args: any): void { this.args = args; this.processLaunchAttachRequest(response, false); } + /** Handles DAP attach request. */ protected attachRequest(response: any, args: any): void { this.args = args; this.processLaunchAttachRequest(response, true); } + /** Core launch/attach handler. */ private processLaunchAttachRequest(response: any, isAttach: boolean): void { this.quit = false; this.attached = false; @@ -168,6 +175,7 @@ export class GDBDebugSession extends DebugSession { ); } + /** Handles custom DAP requests. */ protected customRequest(command: string, response: any, args: any): void { switch (command) { case 'set-force-disassembly': @@ -238,6 +246,7 @@ export class GDBDebugSession extends DebugSession { } } + /** Handles disassemble custom request. */ protected async disassembleRequest(response: any, args: any): Promise { if (args.function) { try { @@ -282,6 +291,7 @@ export class GDBDebugSession extends DebugSession { } } + /** Gets/caches function disassembly. */ private async getDisassemblyForFunction(functionName: string, file: string): Promise { const func = this.symbolTable.getFunctionByName(functionName, file); if (!func) { @@ -309,6 +319,7 @@ export class GDBDebugSession extends DebugSession { return func; } + /** Gets disassembly for address range. */ private async getDisassemblyForAddresses(startAddress: number, length: number): Promise { const endAddress = startAddress + length; const result = await this.miDebugger.sendCommand( @@ -324,6 +335,7 @@ export class GDBDebugSession extends DebugSession { })); } + /** Reads memory via MI. */ private customReadMemoryRequest(response: any, address: number, length: number): void { this.miDebugger.examineMemory(address, length).then( (data) => { @@ -342,6 +354,7 @@ export class GDBDebugSession extends DebugSession { ); } + /** Writes memory via MI. */ private customWriteMemoryRequest(response: any, address: number, data: string): void { const hexAddr = hexFormat(address, 8); this.miDebugger.sendCommand(`data-write-memory-bytes ${hexAddr} ${data}`).then( @@ -355,6 +368,7 @@ export class GDBDebugSession extends DebugSession { ); } + /** Reads CPU registers via MI. */ private customReadRegistersRequest(response: any): void { this.miDebugger.sendCommand('data-list-register-values x').then( (result) => { @@ -379,6 +393,7 @@ export class GDBDebugSession extends DebugSession { ); } + /** Reads register names via MI. */ private customReadRegisterListRequest(response: any): void { this.miDebugger.sendCommand('data-list-register-names').then( (result) => { @@ -402,6 +417,7 @@ export class GDBDebugSession extends DebugSession { ); } + /** Handles DAP disconnect. */ protected disconnectRequest(response: any, args: any): void { if (this.miDebugger) { if (this.attached) { @@ -413,6 +429,7 @@ export class GDBDebugSession extends DebugSession { this.sendResponse(response); } + /** Handles DAP terminate. */ protected terminateRequest(response: any, args: any): void { if (this.miDebugger) { this.miDebugger.stop(); @@ -420,6 +437,7 @@ export class GDBDebugSession extends DebugSession { this.sendResponse(response); } + /** Handles DAP restart. */ protected restartRequest(response: any, args: any): void { const doRestart = () => { this.miDebugger @@ -448,10 +466,12 @@ export class GDBDebugSession extends DebugSession { } } + /** Emits adapter output event. */ private handleAdapterOutput(text: string): void { this.sendEvent(new AdapterOutputEvent(text, 'out')); } + /** Forwards GDB console/log messages. */ private handleMsg(type: string, message: string): void { if (type === 'target') { type = 'stdout'; @@ -462,12 +482,14 @@ export class GDBDebugSession extends DebugSession { this.sendEvent(new OutputEvent(message, type)); } + /** Emits continued events. */ private handleRunning(info: any): void { this.stopped = false; this.sendEvent(new ContinuedEvent(this.currentThreadId, true)); this.sendEvent(new CustomContinuedEvent(this.currentThreadId, true)); } + /** Emits stopped events for breakpoints. */ private handleBreakpoint(info: any): void { const threadId = parseInt(info.record('thread-id') || this.currentThreadId); this.stopped = true; @@ -476,6 +498,7 @@ export class GDBDebugSession extends DebugSession { this.sendEvent(new CustomStopEvent('breakpoint', threadId)); } + /** Emits stopped events for step end. */ private handleBreak(info: any): void { this.stopped = true; this.stoppedReason = 'step'; @@ -483,6 +506,7 @@ export class GDBDebugSession extends DebugSession { this.sendEvent(new CustomStopEvent('step', this.currentThreadId)); } + /** Emits stopped events for user pause. */ private handlePause(info: any): void { this.stopped = true; this.stoppedReason = 'user request'; @@ -490,19 +514,23 @@ export class GDBDebugSession extends DebugSession { this.sendEvent(new CustomStopEvent('user request', this.currentThreadId)); } + /** Emits thread started. */ private handleThreadCreated(info: any): void { this.sendEvent(new ThreadEvent('started', info.threadId)); } + /** Emits thread exited. */ private handleThreadExited(info: any): void { this.sendEvent(new ThreadEvent('exited', info.threadId)); } + /** Emits thread selected. */ private handleThreadSelected(info: any): void { this.currentThreadId = info.threadId; this.sendEvent(new ThreadEvent('selected', info.threadId)); } + /** Handles unexpected stop. */ private stopEvent(info: any): void { if (!this.started) { this.crashed = true; @@ -515,16 +543,19 @@ export class GDBDebugSession extends DebugSession { } } + /** Handles GDB quit. */ private quitEvent(): void { this.quit = true; this.sendEvent(new TerminatedEvent()); } + /** Handles launch error. */ private launchError(err: any): void { this.handleMsg('stderr', `Could not start debugger process > ${err.toString()}\n`); this.quitEvent(); } + /** Handles function breakpoints. */ protected setFunctionBreakPointsRequest(response: any, args: any): void { if (!args.breakpoints || !args.breakpoints.length) { return; @@ -579,6 +610,7 @@ export class GDBDebugSession extends DebugSession { } } + /** Handles source/disassembly breakpoints. */ protected setBreakPointsRequest(response: any, args: any): void { const setBreakpoints = async (shouldContinue: boolean) => { this.debugReady = true; diff --git a/src/backend/expand_value.ts b/src/backend/expand_value.ts index 2cba1f0..c772f5c 100644 --- a/src/backend/expand_value.ts +++ b/src/backend/expand_value.ts @@ -16,6 +16,7 @@ export function isExpandable(value: string): number { return 0; } if (value.startsWith('{...}')) { + /** Determines if a value string is expandable. */ return 2; } if (value[0] === '{') { @@ -39,6 +40,7 @@ export function expandValue( root: string = '', extra?: any ): any { + /** Parses a GDB value string into a DAP variable tree. */ const parseQuotedString = (): string => { value = value.trim(); if (value[0] !== '"' && value[0] !== "'") { diff --git a/src/backend/mi2/mi2.ts b/src/backend/mi2/mi2.ts index 62091d9..72f8a6e 100644 --- a/src/backend/mi2/mi2.ts +++ b/src/backend/mi2/mi2.ts @@ -33,6 +33,7 @@ export class MI2 extends EventEmitter { super(); } + /** Spawns GDB and sends startup MI commands. */ connect(cwd: string, commands: string[]): Promise { return new Promise((resolve, reject) => { const args = [...this.args]; @@ -67,6 +68,7 @@ export class MI2 extends EventEmitter { }); } + /** Buffers and dispatches stdout lines. */ stdout(data: any): void { this.buffer += typeof data === 'string' ? data : data.toString('utf8'); const newlineIndex = this.buffer.lastIndexOf('\n'); @@ -81,6 +83,7 @@ export class MI2 extends EventEmitter { } } + /** Buffers and logs stderr lines. */ stderr(data: any): void { this.errbuf += typeof data === 'string' ? data : data.toString('utf8'); const newlineIndex = this.errbuf.lastIndexOf('\n'); @@ -94,6 +97,7 @@ export class MI2 extends EventEmitter { } } + /** Splits and logs multi-line stderr. */ onOutputStderr(output: string): void { const lines = output.split('\n'); lines.forEach((line) => { @@ -101,6 +105,7 @@ export class MI2 extends EventEmitter { }); } + /** Handles partial line; logs non-MI output. */ onOutputPartial(line: string): boolean { if (isPlainOutput(line)) { this.logNoNewLine('stdout', line); @@ -109,6 +114,7 @@ export class MI2 extends EventEmitter { return false; } + /** Parses and routes MI output lines. */ onOutput(output: string): void { const lines = output.split('\n'); lines.forEach((line) => { @@ -208,6 +214,7 @@ export class MI2 extends EventEmitter { }); } + /** Sends -gdb-exit; optional force-kill after 1s. */ stop(forceKill: boolean = false): void { if (forceKill) { const proc = this.process; @@ -221,6 +228,7 @@ export class MI2 extends EventEmitter { this.sendRaw('-gdb-exit'); } + /** Sends -target-detach with fallback kill. */ detach(): void { const proc = this.process; const killTimeout = setTimeout(() => { @@ -232,6 +240,7 @@ export class MI2 extends EventEmitter { this.sendRaw('-target-detach'); } + /** Interrupts a thread. */ interrupt(threadId: number): Promise { return new Promise((resolve, reject) => { this.sendCommand(`exec-interrupt --thread ${threadId}`).then( @@ -243,6 +252,7 @@ export class MI2 extends EventEmitter { }); } + /** Continues a thread. */ continue(threadId: number): Promise { return new Promise((resolve, reject) => { this.sendCommand(`exec-continue --thread ${threadId}`).then( @@ -254,6 +264,7 @@ export class MI2 extends EventEmitter { }); } + /** Steps to next line/instruction. */ next(threadId: number, instruction: boolean): Promise { return new Promise((resolve, reject) => { const command = instruction ? 'exec-next-instruction' : 'exec-next'; @@ -266,6 +277,7 @@ export class MI2 extends EventEmitter { }); } + /** Steps into next line/instruction. */ step(threadId: number, instruction: boolean): Promise { return new Promise((resolve, reject) => { const command = instruction ? 'exec-step-instruction' : 'exec-step'; @@ -278,6 +290,7 @@ export class MI2 extends EventEmitter { }); } + /** Steps out of current function. */ stepOut(threadId: number): Promise { return new Promise((resolve, reject) => { this.sendCommand(`exec-finish --thread ${threadId}`).then( @@ -289,6 +302,7 @@ export class MI2 extends EventEmitter { }); } + /** Restarts by sending MI commands. */ restart(commands: string[]): Promise { return this._sendCommandSequence(commands); } diff --git a/src/backend/mi2/types.ts b/src/backend/mi2/types.ts index b846da8..66e6009 100644 --- a/src/backend/mi2/types.ts +++ b/src/backend/mi2/types.ts @@ -31,6 +31,7 @@ export class VariableObject { applyChanges(node: any): void { this.value = MINode.valueOf(node, 'value'); if (MINode.valueOf(node, 'type_changed')) { + /** Applies a -var-update changelist entry. */ this.type = MINode.valueOf(node, 'new_type'); } this.dynamic = !!MINode.valueOf(node, 'dynamic'); @@ -42,6 +43,7 @@ export class VariableObject { isCompound(): boolean { return ( this.numchild > 0 || + /** True if this variable has children. */ this.value === '{...}' || (this.dynamic && (this.displayhint === 'array' || this.displayhint === 'map')) ); @@ -51,6 +53,7 @@ export class VariableObject { toProtocolVariable(): any { return { name: this.exp, + /** Converts to DAP Variable. */ evaluateName: this.fullExp || this.exp, value: this.value === undefined ? '' : this.value, type: this.type, @@ -80,6 +83,7 @@ export class MIError { /** Returns " (from )". */ toString(): string { return `${(this as any).message} (from ${(this as any).source})`; + /** Returns " (from )". */ } } diff --git a/src/extension.ts b/src/extension.ts index 2e0bc0b..deb169a 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -9,6 +9,9 @@ import { MemoryTreeProvider } from './frontend/memory_tree_provider'; import { PeripheralTreeProvider, RecordType as PeripheralRecordType } from './frontend/peripheral'; import { RegisterTreeProvider, RecordType as RegisterRecordType } from './frontend/registers'; +/** + * Main entry point and controller for the PlatformIO Debug VS Code extension. + */ class PlatformIODebugExtension { private adapterOutputChannel: vscode.OutputChannel = null; private functionSymbols: any[] = null; diff --git a/src/frontend/registers.ts b/src/frontend/registers.ts index 3edf3f3..d60240d 100644 --- a/src/frontend/registers.ts +++ b/src/frontend/registers.ts @@ -23,6 +23,7 @@ export class TreeNode extends vscode.TreeItem { title: 'Selected Node', }; } +/** TreeItem for registers panel. */ } /** Base for register tree nodes. */ @@ -47,6 +48,7 @@ export class BaseNode { setFormat(format: NumberFormat): void { this.format = format; } +/** Base for register tree nodes. */ } /** CPU register node; may have FieldNode children. */ @@ -85,6 +87,7 @@ export class RegisterNode extends BaseNode { this.currentValue = 0; } + /** CPU register node; may have FieldNode children. */ extractBits(offset: number, width: number): number { return extractBits(this.currentValue, offset, width); } @@ -153,6 +156,7 @@ export class RegisterNode extends BaseNode { } return settings; } +/** Named bit-field within special registers. */ } /** Named bit-field within special registers. */ @@ -217,6 +221,7 @@ export class FieldNode extends BaseNode { } return null; } +/** TreeDataProvider for platformio-debug.registers. */ } /** TreeDataProvider for platformio-debug.registers. */ diff --git a/src/utils.ts b/src/utils.ts index 5925818..a6fad80 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -2,6 +2,9 @@ * Formats a number as a zero-padded hexadecimal string. */ export function hexFormat(value: number, padding: number = 8, includePrefix: boolean = true): string { +/** + * Formats a number as a zero-padded hexadecimal string. + */ let result = value.toString(16); while (result.length < padding) { result = '0' + result; @@ -18,6 +21,9 @@ export function binaryFormat( includePrefix: boolean = true, groupByNibble: boolean = false ): string { +/** + * Formats a number as a binary string, with optional nibble grouping. + */ let result = (value >>> 0).toString(2); while (result.length < padding) { result = '0' + result; @@ -40,6 +46,9 @@ export function binaryFormat( * Creates a bitmask covering the specified bit range. */ export function createMask(offset: number, width: number): number { +/** + * Creates a bitmask covering the specified bit range. + */ let mask = 0; const end = offset + width - 1; for (let i = offset; i <= end; i++) { @@ -52,6 +61,9 @@ export function createMask(offset: number, width: number): number { * Extracts a bit field from a value. */ export function extractBits(value: number, offset: number, width: number): number { +/** + * Extracts a bit field from a value. + */ return ((value & createMask(offset, width)) >>> offset) >>> 0; } @@ -59,6 +71,9 @@ export function extractBits(value: number, offset: number, width: number): numbe * Parses a URL query string into a key-value map. */ export function parseQuery(queryString: string): { [key: string]: string } { +/** + * Parses a URL query string into a key-value map. + */ const params: { [key: string]: string } = {}; const pairs = (queryString[0] === '?' ? queryString.substr(1) : queryString).split('&'); for (const pair of pairs) { @@ -72,6 +87,9 @@ export function parseQuery(queryString: string): { [key: string]: string } { * Encodes a function name and source file into a disassembly:// URI. */ export function encodeDisassembly(name: string, file: string): string { +/** + * Encodes a function name and source file into a disassembly:// URI. + */ let uri = 'disassembly:///'; if (file) { uri += `${file}:`;