sindarin-dap is an implementation of a Debug Adapter Protocol (DAP) client. It relies on the structures and types provided by Pharo-LanguageServer.
The main goal of this project is to map Sindarin commands to their DAP equivalents, allowing the debugger to be controlled through Sindarin scripts.
The client currently works exclusively over socket connections.
Metacello new
baseline: 'PharoDAPClient';
repository: 'github://FlavienVolant/sindarin-dap:main';
loadDAPClient is the base class responsible for:
- Managing the connection to the DAP server
- Sending messages on the main thread
- Receiving responses on a separate thread
It also implements a callback mechanism to handle:
- Responses to specific requests
- Incoming requests and events from the DAP server
SindarinDAPClient is the main entry point of the project.
It extends DAPClient and provides an implementation of Sindarin commands as DAP messages.
Unlike DAPClient, this client is designed to behave synchronously by waiting for responses. See:
handleAsyncResponse: anAction returning: key
Since the client may need to store data inside the debuggee, and this behavior depends on the target language, the following methods are left as subclass responsibilities:
dapRegistryAt: keyAsString put: valueAsStringinitializeDapRegistry
These require DAP capabilities such as supportSetExpressions or supportSetVariables.
DAPClientBuilder is the recommended way to configure and initialize a DAP client.
It handles:
- The handshake with the DAP server
- Sending initialization data at the correct time
See the Examples initialize methods for usage.
ClientDAPPresenter is a UI tool that displays all:
- Requests
- Responses
- Events
that go through the client.
The client currently supports:
- Python ->
DAPClientForPY - Java ->
DAPClientForJAVA - JavaScript ->
DAPClientForJS
Refer to the corresponding help/documentation for each language to learn how to set up your environment and start debugging.
This client uses debugpy as the DAP adapter.
Install debugpy using pip:
pip install debugpyRun your Python script with debugpy and wait for the client to attach:
python -m debugpy --listen 5678 --wait-for-client py/script.pyThe DAP client is configured via DAPClientForPY.
You can adapt the following example to your setup:
DAPClientBuilder new
client: self;
port: 5678;
adapterID: 'python';
attachArguments: self attachArguments;
breakpoint: '/path/to/your/script.py' line: 8;
functionBreakpoint: 'toto' condition: 'True';
startClientSession
attachArguments
^ {
('name' -> 'Attach to Python').
('type' -> 'python').
('connect' -> {
('host' -> 'localhost').
('port' -> 5678) } asDictionary).
('redirectOutput' -> true).
('showReturnValue' -> true) } asDictionary- Start the
debugpyadapter (see above) - In a Pharo Playground, run:
client := ClientDAPPresenter newWithClient: DAPClientForPY new.
client open.This client uses the Microsoft vscode-js-debug adapter.
- Node.js
vscode-js-debug(tested withv1.112.0)
Download a release from:
https://github.com/microsoft/vscode-js-debug/releases
Extract it, then locate the DAP server entry point:
js-debug/src/dapDebugServer.js
Run your Node.js script in debug mode:
node --inspect-brk=0.0.0.0:9229 js/script.jsThis starts Node with the inspector protocol enabled and waits for a debugger to attach.
Launch the debug adapter server:
node js-debug/src/dapDebugServer.js 5678
The adapter will listen for DAP connections on port 5678.
This adapter require the client to support startDebuggingRequest. Therefore, a second DAP client (DAPClientForJSStartDebug) is created with extended attachArguments.
initialize
super initialize.
requestHandlers
at: 'startDebugging'
put: [ :req | self handleStartDebuggingRequest: req ]
handleStartDebuggingRequest: aStartDebuggingRequest
| childClient |
childClient := DAPClientForJSStartDebug new
attachOtherArguments:
(aStartDebuggingRequest
at: 'arguments'
at: 'configuration').
childClient startSession.
(ClientDAPPresenter newWithClient: childClient) openstartSession
DAPClientBuilder new
client: self;
adapterID: 'node';
port: 5678;
attachArguments: self attachArguments;
startClientSession
attachArguments
^ {
('name' -> 'Attach Node.js script.js').
('type' -> 'pwa-node').
('request' -> 'attach').
('address' -> 'localhost').
('port' -> 9229).
('continueOnAttach' -> true)
} asDictionary- Start your Node.js script with --inspect-brk
- Start the vscode-js-debug adapter
- In a Pharo Playground, run:
client := DAPClientForJS new startSession.The Java client relies on the java-debug adapter from Microsoft.
This adapter is designed to work as a plugin for the Java Language Server (eclipse.jdt.ls).
eclipse.jdt.ls(Java Language Server)java-debugplugin
One simple way to obtain the adapter is to install the VS Code extension:
- Debugger for Java (Microsoft)
After installation, you can find the required JAR in:
.vscode/extensions/vscjava.vscode-java-debug-<version>/server/
Look for a file like:
com.microsoft.java.debug.plugin-<version>.jar
The Java program must be started in debug mode using JDWP, so the debugger can attach to it:
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005 \
-cp target/classes \
example.MainThis starts the JVM in debug mode and listens on port 5005.
To use java-debug, you must start eclipse.jdt.ls with the debug plugin included in the bundles initialization option:
{
"initializationOptions": {
"bundles": [
"path/to/com.microsoft.java.debug.plugin-<version>.jar"
]
}
}Once eclipse.jdt.ls is running, send the following command via your LSP client:
{
"command": "vscode.java.startDebugSession"
}The server will respond with a port number where the DAP adapter is listening.
Use DAPClientForJAVA and configure it with the port returned by the LSP server:
DAPClientBuilder new
client: self;
port: 63461; "Replace with the returned port"
adapterID: 'java';
attachArguments: self attachArguments;
breakpoint:
'/path/to/your/project/src/main/java/example/Main.java'
line: 5;
breakpoint:
'/path/to/your/project/src/main/java/example/Main.java'
line: 9;
functionBreakpoint: 'example.Bar#toto'
condition:
'true';
startClientSession
attachArguments
^ {
('name' -> 'Attach to Java').
('type' -> 'server').
('hostName' -> 'localhost').
('port' -> 5005).
('projectName' -> 'java') } asDictionary- Start your Java program with JDWP enabled
- Start
eclipse.jdt.lswith thejava-debugplugin - Send the
vscode.java.startDebugSessioncommand via your LSP client - Retrieve the port from the response
- In a Pharo Playground, run:
client := ClientDAPPresenter newWithClient: DAPClientForJAVA new.
client open.