///
import type { DeviceInfo, RokuDeploy } from 'roku-deploy';
import { LoggingDebugSession } from '@vscode/debugadapter';
import type { DebugProtocol } from '@vscode/debugprotocol';
import { ProjectManager } from '../managers/ProjectManager';
import type { LaunchConfiguration, ComponentLibraryConfiguration } from '../LaunchConfiguration';
import { FileManager } from '../managers/FileManager';
import { SourceMapManager } from '../managers/SourceMapManager';
import { LocationManager } from '../managers/LocationManager';
import { BreakpointManager } from '../managers/BreakpointManager';
import { FileLoggingManager } from '../logging';
export declare class BrightScriptDebugSession extends LoggingDebugSession {
constructor();
start(inStream: NodeJS.ReadableStream, outStream: NodeJS.WritableStream): void;
/**
* Once the client has disconnected, drop outgoing events instead of writing to the dead stream.
* Writing to a broken pipe re-triggers the base 'error' -> shutdown() handler in a tight loop.
*/
sendEvent(event: DebugProtocol.Event): void;
setupProcessErrorHandlers(): void;
private handlingProcessError;
/**
* True when an error indicates the client (e.g. VS Code) has gone away, such as a broken stdout pipe
* (EPIPE). Writing to a dead pipe just produces more EPIPEs, so we must not try to report over it.
*/
private isClientGoneError;
/**
* Tear down the process error handlers and forcibly exit, so we never leave an orphaned adapter
* spinning in the background after the client is gone or a graceful shutdown has hung.
*/
private forceExit;
private handleProcessError;
teardownProcessErrorHandlers(): void;
private onDeviceBreakpointsChanged;
logger: import("@rokucommunity/logger").Logger;
private readonly isWindowsPlatform;
/**
* A sequence used to help identify log statements for requests
*/
private idCounter;
fileManager: FileManager;
projectManager: ProjectManager;
fileLoggingManager: FileLoggingManager;
private processErrorHandlersRegistered;
private isCrashed;
/** Set once the client (e.g. VS Code) disconnects, so we stop writing to a now-dead stream */
private clientDisconnected;
/** How long to wait for a graceful shutdown before forcibly exiting the process */
private shutdownForceExitTimeout;
private _uncaughtExceptionHandler;
private _unhandledRejectionHandler;
breakpointManager: BreakpointManager;
locationManager: LocationManager;
sourceMapManager: SourceMapManager;
rokuDeploy: RokuDeploy;
private componentLibraryServer;
private rokuAdapterDeferred;
/**
* A promise that is resolved whenever the app has started running for the first time
*/
private firstRunDeferred;
/**
* Resolved whenever we're finished copying all the files to staging for all projects
*/
private stagingDefered;
private evaluateRefIdLookup;
private evaluateRefIdCounter;
private variables;
/**
* Caches the device lookups performed while resolving completion requests. Variables don't change
* while the debugger is paused, so this avoids repeated round-trips for the same path. Cleared by
* `clearState` whenever the debugger resumes or steps.
*/
private completionParentVariableCache;
private rokuAdapter;
private perfettoManager;
private rendezvousTracker;
tempVarPrefix: string;
/**
* The progressId of the active launch progress bar, if any.
* Cleared once the ProgressEndEvent is sent.
*/
private launchProgressId;
/**
* The first encountered compile error, will be used to send to the client as a runtime error (nicer UI presentation)
*/
private compileError;
/**
* A magic number to represent a fake thread that will be used for showing compile errors in the UI as if they were runtime crashes
*/
private COMPILE_ERROR_THREAD_ID;
private get enableDebugProtocol();
/**
* Check if the Roku firmware supports Perfetto tracing (requires OS 15.2 or higher)
*/
private get supportsPerfettoTracing();
/**
* Get a promise that resolves when the roku adapter is ready to be used
*/
private getRokuAdapter;
private launchConfiguration;
private initRequestArgs;
private exceptionBreakpoints;
/**
* The 'initialize' request is the first request called by the frontend
* to interrogate the features the debug adapter provides.
*/
initializeRequest(response: DebugProtocol.InitializeResponse, args: DebugProtocol.InitializeRequestArguments): void;
protected setExceptionBreakPointsRequest(response: DebugProtocol.SetExceptionBreakpointsResponse, args: DebugProtocol.SetExceptionBreakpointsArguments): Promise;
protected setTransientsToInvalid(): Promise;
private showPopupMessage;
private static requestIdSequence;
private sendCustomRequest;
/**
* Get the cwd from the launchConfiguration, or default to process.cwd()
*/
private get cwd();
deviceInfo: DeviceInfo;
/**
* Set defaults and standardize values for all of the LaunchConfiguration values
* @param config
* @returns
*/
private normalizeLaunchConfig;
launchRequest(response: DebugProtocol.LaunchResponse, config: LaunchConfiguration): Promise;
protected configurationDoneRequest(response: DebugProtocol.ConfigurationDoneResponse, args: DebugProtocol.ConfigurationDoneArguments): Promise;
/**
* Activate all required functionality for profiling
*/
private initializeProfiling;
/**
* If profiling was marked "connectOnStart", try connecting right away
*/
private tryProfilingConnectOnStart;
/**
* Clear certain properties that need reset whenever a debug session is restarted (via vscode or launched from the Roku home screen)
*/
private resetSessionState;
/**
* Activate rendezvous tracking (IF enabled in the LaunchConfig)
*/
initRendezvousTracking(): Promise;
private _initRendezvousTracking;
/**
* Anytime a roku adapter emits diagnostics, this method is called to handle it.
*/
private handleDiagnostics;
private publishTimeout;
private publish;
private pendingSendLogPromise;
/**
* Send log output to the "client" (i.e. vscode)
* @param logOutput
*/
private sendLogOutput;
/**
* Extracts potential package paths from a given line of text.
*
* This method uses a regular expression to find matches in the provided line
* and returns an array of objects containing details about each match.
*
* @param input - The line of text to search for potential package paths.
* @returns An array of objects, each containing:
* - `fullMatch`: The full matched string.
* - `path`: The extracted path from the match.
* - `lineNumber`: The line number extracted from the match.
* - `columnNumber`: The column number extracted from the match, or `undefined` if not found.
*/
private getPotentialPkgPaths;
/**
* Converts the filename property in backtrace objects in the given input string to source paths if found
*/
private convertBacktracePaths;
private runAutomaticSceneGraphCommands;
/**
* Stage, insert breakpoints, and package the main project
*/
prepareMainProject(): Promise;
/**
* Inject breakpoint STOP statements into the staged main project and create the zip package.
* Runs after the DAP `InitializedEvent` so client-side `setBreakpoints` requests have landed
* before any STOPs are written to the staged .brs files (telnet path) and before the zip is sealed.
*/
private packageMainProject;
/**
* Accepts custom events and requests from the extension
* @param command name of the command to execute
*/
protected customRequest(command: string, response: DebugProtocol.Response, args: any): Promise;
/**
* Stores the path to the staging folder for each component library
*/
protected prepareComponentLibraries(componentLibraries: ComponentLibraryConfiguration[]): Promise;
/**
* Inject breakpoint STOPs into the staged complibs, seal their zips, install installable ones,
* and start static file hosting. Runs in `configurationDoneRequest` (after `InitializedEvent`)
* so client-side `setBreakpoints` requests have landed before the staged .brs files are written
* and the zips are sealed.
*/
protected packageAndHostComponentLibraries(componentLibraries: ComponentLibraryConfiguration[], port: number): Promise;
protected sourceRequest(response: DebugProtocol.SourceResponse, args: DebugProtocol.SourceArguments): void;
/**
* Called every time a breakpoint is created, modified, or deleted, for each file. This receives the entire list of breakpoints every time.
*/
setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments): Promise;
protected exceptionInfoRequest(response: DebugProtocol.ExceptionInfoResponse, args: DebugProtocol.ExceptionInfoArguments): void;
protected threadsRequest(response: DebugProtocol.ThreadsResponse): Promise;
/**
* Get the thread name to display in the UI based on the thread info we have.
* This is what displays in the `call stack` region in vscode
* @param thread
* @returns
*/
private getThreadName;
protected stackTraceRequest(response: DebugProtocol.StackTraceResponse, args: DebugProtocol.StackTraceArguments): Promise;
protected scopesRequest(response: DebugProtocol.ScopesResponse, args: DebugProtocol.ScopesArguments): Promise;
/**
* Get the locals scope container for a frame, creating an (unpopulated) one if it doesn't exist yet.
* The child variables are filled in lazily by `populateScopeVariables`.
*/
private getOrCreateLocalsScope;
protected continueRequest(response: DebugProtocol.ContinueResponse, args: DebugProtocol.ContinueArguments): Promise;
protected pauseRequest(response: DebugProtocol.PauseResponse, args: DebugProtocol.PauseArguments): Promise;
protected reverseContinueRequest(response: DebugProtocol.ReverseContinueResponse, args: DebugProtocol.ReverseContinueArguments): void;
/**
* Clicked the "Step Over" button
* @param response
* @param args
*/
protected nextRequest(response: DebugProtocol.NextResponse, args: DebugProtocol.NextArguments): Promise;
protected stepInRequest(response: DebugProtocol.StepInResponse, args: DebugProtocol.StepInArguments): Promise;
protected stepOutRequest(response: DebugProtocol.StepOutResponse, args: DebugProtocol.StepOutArguments): Promise;
protected stepBackRequest(response: DebugProtocol.StepBackResponse, args: DebugProtocol.StepBackArguments): void;
variablesRequest(response: DebugProtocol.VariablesResponse, args: DebugProtocol.VariablesArguments): Promise;
private debounceSendInvalidatedEvent;
private filterVariablesUpdates;
/**
* Takes a scope variable and populates its child variables based on the scope type and the current adapter type.
* @param v scope variable to populate
* @param args
*/
private populateScopeVariables;
private evaluateRequestPromise;
private evaluateVarIndexByFrameId;
private getNextVarIndex;
evaluateRequest(response: DebugProtocol.EvaluateResponse, args: DebugProtocol.EvaluateArguments): Promise;
private evaluateExpressionToTempVar;
private bulkEvaluateExpressionToTempVar;
protected completionsRequest(response: DebugProtocol.CompletionsResponse, args: DebugProtocol.CompletionsArguments, request?: DebugProtocol.Request): Promise;
/**
* Gets the closest completion details the incoming completion request.
*/
private getClosestCompletionDetails;
/**
* Compute the span of input text that a completion replaces: the run of identifier characters
* immediately before the cursor. This lets the client filter the list correctly as the user keeps
* typing past the first character.
*
* `start` is a 0-based offset into the line, NOT a client column. Per the Debug Adapter Protocol,
* `CompletionItem.start` is measured in UTF-16 code units and the client maps it to a position
* itself, so it must not be run through `toClientColumn` (unlike stack-frame, breakpoint, and scope
* positions). Our debugger column base is already 0-based, so the internal offset is sent as-is.
*/
private getCompletionReplaceRange;
/**
* Scan backwards from `column` to find the nearest opening bracket (`(`, `[`, or `{`) that has not
* been closed before the cursor. Returns the opener's index and character, or undefined if none.
*/
private findUnclosedOpener;
/**
* Resolve the parent variable for a completion request. Prefers the in-memory locals for the frame,
* then falls back to a device lookup. Device lookups are cached for the duration of the paused state
* (cleared by `clearState`) so repeated completion requests on the same path don't hammer the device.
*/
private resolveCompletionParentVariable;
/**
* Rebuild a valid BrightScript accessor expression from a resolved variable path. String-literal keys
* arrive already quoted from `getVariablePath` and are emitted as `["key"]` so they stay case-sensitive
* on the device (Roku AAs can be set case-sensitive); numeric segments use `[index]`, and identifiers
* use dot access. This keeps array indices and string keys correct through the device lookup.
*/
private buildVariableExpression;
/**
* Normalize a variable path segment or variable name for matching: drop surrounding string-key quotes
* and lower-case it. BrightScript variables and dotted access are case-insensitive, and the device
* reports names lower-cased, so this lets the in-memory lookup find the parent regardless of the casing
* the user typed (ex: `topRef` matching the cached `topref`).
*/
private normalizeVariableName;
/**
* Resolve a variable path against the current frame's local scope. The first path segment is matched
* against the frame's locals (not the global pool of every materialized variable), then we walk down
* the child variables. The empty path (`['']`) resolves to the locals scope container itself.
*/
private findFrameVariableByPath;
private findVariableByPath;
private debuggerVarTypeToRoType;
/**
* Called when the host stops debugging
* @param response
* @param args
*/
protected disconnectRequest(response: DebugProtocol.DisconnectResponse, args: DebugProtocol.DisconnectArguments, request?: DebugProtocol.Request): Promise;
private createRokuAdapter;
protected restartRequest(response: DebugProtocol.RestartResponse, args: DebugProtocol.RestartArguments, request?: DebugProtocol.Request): Promise;
private exitAppTimeout;
private ensureAppIsInactive;
/**
* Used to track whether the entry breakpoint has already been handled
*/
private entryBreakpointWasHandled;
/**
* Registers the main events for the RokuAdapter
*/
private connectRokuAdapter;
private onSuspend;
private setupSuspendedState;
private getVariableFromResult;
/**
* Helper function to merge the results of an evaluate call into an existing EvaluateContainer
* Used primarily for custom variables
*/
private mergeEvaluateContainers;
private getEvaluateRefId;
private clearState;
/**
* Sends a launch progress event to the client if the client supports progress reporting.
* - `'start'`: begins a new progress bar with the given message. Assigns a new progressId.
* - `'update'`: updates the message on the active progress bar.
* - `'end'`: dismisses the active progress bar with an optional final message.
*/
private sendLaunchProgress;
/**
* Tells the client to re-request all variables because we've invalidated them
* @param threadId
* @param stackFrameId
*/
private sendInvalidatedEvent;
/**
* If `stopOnEntry` is enabled, register the entry breakpoint.
*/
handleEntryBreakpoint(): Promise;
/**
* Converts a debugger line number to a client line number.
*
* @param debuggerLine - The line number from the debugger as zero based.
* @param defaultDebuggerLine - An optional default line number, as zero based, to use if `debuggerLine` is not provided.
* @returns The corresponding client line number.
*/
private toClientLine;
/**
* Converts a debugger column number to a client column number.
*
* @param debuggerLine - The column number from the debugger as zero based.
* @param defaultDebuggerLine - An optional default column number, as zero based, to use if `debuggerLine` is not provided.
* @returns The corresponding client column number.
*/
private toClientColumn;
/**
* Converts a client line number to a debugger line number.
*
* @param clientLine - The line number from the client.
* @param defaultDebuggerLine - An optional default line number, as zero based, to use if `clientLine` is not provided.
* @returns The corresponding debugger line number as zero based.
*/
private toDebuggerLine;
/**
* Converts a client column number to a debugger column number.
*
* @param clientLine - The column number from the client.
* @param defaultDebuggerLine - An optional default column number, as zero based, to use if `clientLine` is not provided.
* @returns The corresponding debugger column number as zero based.
*/
private toDebuggerColumn;
private shutdownPromise;
/**
* Called when the debugger is terminated. Feel free to call this as frequently as you want; we'll only run the shutdown process the first time, and return
* the same promise on subsequent calls
*/
shutdown(errorMessage?: string, modal?: boolean): Promise;
private _shutdown;
}
export interface AugmentedVariable extends DebugProtocol.Variable {
childVariables?: AugmentedVariable[];
request_seq?: number;
frameId?: number;
/**
* only used for lazy variables
*/
isResolved?: boolean;
/**
* used to indicate that this variable is a scope variable
* and may require special handling
*/
isScope?: boolean;
}