Debug Adapters

Debug Adapters are intermediary tools which conform to the Debug Adapter Protocol, an open-source specification for debuggers that work with multiple IDEs.

To coordinate interactive debugging for a specific language or framework, the IDE starts an instance of a debug adapter to handle the specifics of starting and communicating with the debugging target (or debuggee). The debug adapter then handles all communication between the IDE and itself to “adapt” the debugger in question to a common interface the IDE understands.

Added in Nova 9.

Contributing a Debug Adapter

Providing support for a debug adapter in your extension is achieved by contributing a Task Assistant via the AssistantRegistry API. Your task assistant should provide support for the Run action. When the IDE resolves this action to run, your extension should return a TaskDebugAdapterAction object describing how to start and communicate with your debug adapter.

For example, in an extension contributing a debug adapter for Python, your task assistant might look something like:

class PythonTaskAssistant {
    resolveTaskAction(context) {
        let actionType = context.action;
        if (actionType == Task.Run) {
            let config = context.config;
            
            let action = new TaskDebugAdapterAction('debugpy');
            
            action.command = "/usr/bin/python3";
            action.args = ["-m", "debugpy"];
            
            action.debugArgs = {
                program: config.get("python.debug.script", "string")
            };
            
            return action;
        }
        else {
            return null;
        }
    }
}

Your assistant can control the arguments and launch behaviors of the adapter in any way it wishes via the TaskDebugAdapterAction API, such as by providing context and user-configurable options for the task which are then read by your assistant and provided to the adapter via the debugArgs property.

Manifest Description

Your extension should provide a description of your adapter defining the user-readable name of the debug adapter. This description is used when showing UI elements related to the adapter when running a debug session or managing breakpoints.

Within your extension manifest, define a debugAdapters object keyed by the identifier of your adapter. The identifier key should be the same as is provided when creating a TaskDebugAdapterAction.

"debugAdapters": {
    "debugpy": {
        "name": "Python (debugpy)",
        "image": "debugpy"
    }
},

Supported properties for an adapter description are:

Breakpoints

To support breakpoints with a debug adapter, your extension should provide a description of the contexts in which breakpoints are supported.

Within your extension manifest, define a breakpoints array containing one or more Breakpoint Templates:

"breakpoints": [
    {
        "syntax": "python"
    }
]

Supported properties for a breakpoint template are:

Custom Requests and Events

Extensions can send custom requests and receive custom events from the adapter they contribute by using the DebugSession API. Session objects allow an extension to register to receive custom events that might be sent from the adapter to handle specific features or functionality that is not otherwise part of the Debug Adapter Protocol.

Child Sessions

A debug session coordinates debugging for a single target (or debuggee), which can be many things, such as an external process, a web page running within a browser, or a script running on a remote host. If the debuggee, in turn, starts additional “child” targets then your extension can indicate this to the IDE and start a child session for each child debuggee.

Child sessions can be started using the startChildSession() method of the DebugSession API. Most frequently, this method would be invoked in response to a custom event received from the adapter, as the Debug Adapter Protocol itself does not itself (as of early 2022) define a mechanism for listening for and starting child sessions.