Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DAP documentation #902

Closed
pretentious7 opened this issue Dec 31, 2020 · 34 comments
Closed

DAP documentation #902

pretentious7 opened this issue Dec 31, 2020 · 34 comments
Labels
*question Issue represents a question, should be posted to StackOverflow (VS Code)

Comments

@pretentious7
Copy link

pretentious7 commented Dec 31, 2020

Hello!

I've been trying to get this running in neovim, but I've been having a lot of trouble, are there any docs for how just the DAP is supposed to work, separate from vscode?

Thanks.

@connor4312
Copy link
Member

Insofar as DAP is concerned, we follow the specification.

Though I don't think we have consumers using debugServer.js -- VS (proper, not Code) uses the flatSessionLauncher. The primary difference in this versus the older debugger is that it leverages multiple debug sessions. The messaging for dealing with multiple sessions is not defined in DAP, so the flatSessionLauncher tacks on a session ID property that can be used to disambiguate messages -- and likewise it expects messages coming in to have a session ID so it knows where to send them. Along with that there's this custom message which is used to indicate when a new target is available and should be initialized.

From the other thread:

But it then rejected all the breakpoints that I tried to set.

This is actually expected if they were sent to the root session -- the root is a logical wrapper session and doesn't implement any debugging methods.

@mfussenegger
Copy link

The messaging for dealing with multiple sessions is not defined in DAP, so the flatSessionLauncher tacks on a session ID property that can be used to disambiguate messages -- and likewise it expects messages coming in to have a session ID so it knows where to send them.

Which launcher should be used if the client doesn't support the customized sessionID and custom message?

The comments in the flatSessionLauncher mention stdin/out communication. How do you launch it to use stdio communication instead of TCP?

Is there an issue in the debug-adapter-protocol repository that suggests a sessionID protocol extension or something like that - or is the intention that this multi-session handling will only ever work with Visual Studio and Visual studio Code?

@connor4312
Copy link
Member

connor4312 commented Jan 1, 2021

Which launcher should be used if the client doesn't support the customized sessionID and custom message?

You can try out the vsDebugServer, which spins up a server on a separate port instead of using session IDs for messages. Here's the config/message that comes down when a child session is ready for attachment:

childAttachConfig[
'__jsDebugChildServer'
] = (result.server.address() as net.AddressInfo).port.toString();
// Custom message currently not part of DAP
parentSession.connection._send({
seq: 0,
command: 'attachedChildSession',
type: 'request',
arguments: {
config: childAttachConfig,
},
});

The comments in the flatSessionLauncher mention stdin/out communication. How do you launch it to use stdio communication instead of TCP?

by not passing a port when calling node flatSessionLauncher [port]

Is there an issue in the debug-adapter-protocol repository that suggests a sessionID protocol extension or something like that - or is the intention that this multi-session handling will only ever work with Visual Studio and Visual studio Code?

Not right now. I'll talk to Andre and open an issue there after the holiday (monday)

@connor4312 connor4312 added the *question Issue represents a question, should be posted to StackOverflow (VS Code) label Jan 9, 2021
@entropitor
Copy link

@connor4312 Would we also be able to use debugServer.js to avoid the whole sessionId thingy? (#902 (comment))

How does this package relate to https://github.com/microsoft/vscode-node-debug2?

@connor4312
Copy link
Member

node-debug2 is deprecated and has been replaced by this package.

Ultimately you'll need to deal with multiple sessions and sessionIds in some way.

@entropitor
Copy link

entropitor commented Apr 6, 2021

Okay, that's helpful to know, I really love that microsoft is investing in LSP and DAP to make it more extensible and make it work across editors but it would really help if the custom extensions were as documented, at least for the required ones. As it's not super clear from this thread.

Is the following flow correct:
Editor starts debug adapter
adapter returns that message with the sessionId/port in
Editor initializes with seq to 0 and with the sessionId / to that port

if the editor wants a new session, it can just re-init with a new sessionId and again with sequence number 0?

@mickaelistria
Copy link

Ultimately you'll need to deal with multiple sessions and sessionIds in some way.

I don't see such sessions part of the DAP specification. Am I missing something?

@entropitor
Copy link

entropitor commented Apr 7, 2021

I tried implementing this for nvim-dap but it feels very complex. So first you start up a vsDebugServer.js, that one only outputs the port of the root session. With that port, you talk DAP to initialize and configure, breakpoints get rejected and when you send a launch/attach command, you get the specific message (attachedChildSession).

Then you need to connect to that port and send the init DAP messages again (including breakpoints?), I guess? Do you still need to send the launch command as well?

( I guess instead of connecting to that port, you could use the other server and then you would have to use the same connection, just with a connectionId?)

@mickaelistria
Copy link

I tried implementing this for nvim-dap but it feels very complex. So first you start up a vsDebugServer.js, that one only outputs the port of the root session.

This can be simplified by passing directly a port to the command, so you don't have to read the output to know the port.

you get the specific message (attachedChildSession).

That's the main issue I see. This command seems necessary yet it's not part of the spec. So it seems to me that vscode-js-debug is not actually DAP compliant as it requires non-standard messages to be usable?

@entropitor
Copy link

What I also find strange is that if there is a launch/attach request for pwa-node, the attachedChildSession has type pwa-chrome. Do we just need to send this whole config again? What's the difference between pwa-node and pwa-chrome? Is this a bug or expected? A bit more documentation would really help to understand what's supposed to happen (e.g. a sequence diagram or something)

@connor4312
Copy link
Member

I don't see such sessions part of the DAP specification. Am I missing something?

Currently DAP itself has no knowledge of the relation between different sessions, therefore we use out-of-bounds signalling today. However, that might change with microsoft/vscode#116730.

Is the following flow correct

That looks correct, yea. Though we don't really care about seq.

if the editor wants a new session, it can just re-init with a new sessionId

If by re-init you mean launch a new vsDebugServer, yes. I believe the vsDebugServer is currently designed such that it is unique for each session 'tree'. Though in practice I'm less familiar with it as it's only consumed by our friends at VS proper.

Then you need to connect to that port and send the init DAP messages again (including breakpoints?), I guess? Do you still need to send the launch command as well?
.... Do we just need to send this whole config again?

That's all correct. VS Code sends all its breakpoints to each session, so that's what js-debug expects. When launching the child you should use the configuration given in the config argument of attachedChildSession.

What I also find strange is that if there is a launch/attach request for pwa-node, the attachedChildSession has type pwa-chrome

That's surprising, the type should be the same except when developing a VS Code extension, which you are not doing.

type:
parentConfig.type === DebugType.ExtensionHost
? DebugType.Chrome
: (parentConfig.type as DebugType),

@mickaelistria
Copy link

OK, so it's impossible to use this debug adapter with plain DAP at the moment. Would it be possible to have some flag or initialization option such as --no-session that would just start one session and stick to DAP standard messages (ie no need to care about attachedChildSession) ?

@entropitor
Copy link

If by re-init you mean launch a new vsDebugServer, yes. I believe the vsDebugServer is currently designed such that it is unique for each session 'tree'. Though in practice I'm less familiar with it as it's only consumed by our friends at VS proper.

So every time the editor wants to start a session, it needs to start a new root session? What is the tree you are talking about? In what scenario can you get more than a root and child session?

How would the flow look with flatSessionManager, would you also need to restart a new flatSessionManager? Or how do you start a new session / tree there?

That's surprising, the type should be the same except when developing a VS Code extension, which you are not doing.

I'll report back if I work on this further, but that's what I got in my initial tests of the protocol etc. I was very confused by that

@connor4312
Copy link
Member

In what scenario can you get more than a root and child session?

There are several of them: multiple tabs debugging a browser, webworkers, service workers, iframes, child processes, and worker_threads. These form the "tree" I was referring to.

How would the flow look with flatSessionManager, would you also need to restart a new flatSessionManager?

Yea, the difference is that the sessions are inline in the same server/connection instead of having a separate websocket server for each child.

@entropitor
Copy link

But so every time the editor starts up a session, a new root session is needed? The root session cannot be re-used by the client?

@connor4312
Copy link
Member

Right

@mickaelistria
Copy link

@EricCornelson What do you think about proposal in #902 (comment) to have a flag instructing debug adapter to assume there is just 1 session and not send unexpected messages?

@connor4312
Copy link
Member

Would it be possible to have some flag or initialization option such as --no-session that would just start one session and stick to DAP standard messages

I am not eager to support such a feature. It adds complexity to this already pretty complex package and loses features.

A far simpler way would perhaps be some bit of translator code that flattens the top session and ignores all child sessions if the editor can't support them.

@entropitor
Copy link

I am not eager to support such a feature. It adds complexity to this already pretty complex package and loses features.

It loses features only for those clients that don't support it, but on the other hand, it will actually provide features as right now it just doesn't work in other editors. And I get that there is complexity but right now the complexity will actually have to live in every editor, which is fine if it were the official protocol but it's just an extension for 1 language.

A far simpler way would perhaps be some bit of translator code that flattens the top session and ignores all child sessions if the editor can't support them.

That sounds okay to me. Would that top session then just be the first child session (so no root session, you immediately get the "child" session and there cannot be any other children?

@mickaelistria
Copy link

A far simpler way would perhaps be some bit of translator code that flattens the top session and ignores all child sessions if the editor can't support them.

Sure, that sounds like a good way to do it as well; and I trust you if you think it's simpler.
The idea is to allow editors that support plain and regular DAP, and are working well with node-debug2 or other debug adapters that stick to DAP, to be able to work with this debug adapter without dealing with the vscode-js-debug specific "session" model that is not part of the protocol (yet). Would the suggested approach allow that?

Or maybe is it possible to implement the Debug Adapter in a way that if only 1 session is existing and attached, all requests to the root debug adapter get forwarded to the single session? Most clients that are doing just-DAP could work with that as they'll likely never start multiple sessions (DAP doesn't allow that).

@EricCornelson
Copy link
Contributor

I'd agree with Connor here. It's already sort of cumbersome in VS to deal with the "root session", as that whole concept (if I recall correctly) was created particularly because VS Code can use it to show a nice hierarchical tree of debug targets (VS doesn't have the concept of "child" and "parent" sessions at all, so we end up with a dummy process in the UI that represents the "root" session).

I'd be in favor of flattening the root session to be whatever the first debug session happens to be (e.g. the web page or the first node process).

For what it's worth, we did propose adding this to the debug adapter protocol, but it hasn't reached a critical mass yet to be adopted.

@entropitor
Copy link

entropitor commented Apr 9, 2021

I was able to get a child session working with vsDebugServer.js but my breakpoints are still being rejected. Is there a certain moment you need to send them? Or maybe it needs more info? (I'm using the vsDebugServer.js)

(Is there maybe a way to get a log of all messages sent from VSCode to this DAP so I can checkout what they are doing? Because the exact same flow is working in VSCode but not in neovim)

(In case it's important, it's in typescript and I'm trying to debug a jest test)

@connor4312
Copy link
Member

connor4312 commented Apr 12, 2021

Unless you pass --runInBand, Jest will run tests in parallel in child processes. Without supporting nested debug sessions you will be unable to debug these.

You can have js-debug log traffic to a text file by setting trace: { logFile: "log.txt" } in the launch config.

@mickaelistria
Copy link

Unless you pass --runInBand, Jest will run tests in parallel in child processes. Without supporting nested debug sessions you will be unable to debug these.

OK, but what about the case of a plain node.js hello world ? Couldn't the Debug Adapter support a similar --runInBand flag that would remove the session grain to make it work with regular/standard DAP clients.

@connor4312
Copy link
Member

Sure, that is technically possible. Perhaps with some custom debug launcher script that has some bit of translation code (#902 (comment)). I would accept a PR for this provided it can be done is a reasonably durable self-contained way.

@mickaelistria
Copy link

OK, thanks. I've opened #969 to track this task. Please comment on #969 whether there is something I missed about what would be the best implementation.

@entropitor
Copy link

I got it working for neovim now (mfussenegger/nvim-dap#136 (comment)) but we were wondering (mfussenegger/nvim-dap#281), do we actually need to send a response to the attachedChildSession request? Or should this have been an event instead of a request? Because it seems to work without a response...

@entropitor
Copy link

entropitor commented Aug 26, 2021

Also, when I use jest and launch, my breakpoints keep getting rejected (even on the actual session) while they are working (the debugger stops). When I try to use an attach configuration, they keep getting rejected and they are not working. I'm in the right session though because when I set a breakpoint in vs code, it does show in my ui, I get all the details from the debugger

From what I can see in the trace logs, I don't see a difference in the command, is there anything special you need to do for breakpoints in typescript to work?

@mickaelistria
Copy link

I'm back on this topic. Do I get it right that at the moment:
vscode-js-debug adapter is not compliant with DAP specification, because it cannot work without client adding support for custom attachedChildSession?
If I'm wrong, perfect; can someone enlighten me on how to work without my client understanding those sessions?
If I'm right, is there any chance this "session" pattern can be properly described in the specification? I saw they are mentioned, but concrete integration data like message type and expected reaction from client still seems missing.

@gfszr
Copy link
Contributor

gfszr commented Jul 8, 2022

@connor4312 While trying to use vscode-js-debug for Node debugging as a DAP server for a DAP Client, I did manage to get it working with debugServerMain.js <port> using DAP over TCP and it looks like everything works under that single connection, but I'm experiencing a weird issue in which everything looks to work OK (The debug console, output, etc), breakpoints are bounded correctly, but once a breakpoint is hit the session is stuck and the process being debugged is stuck.

Did something like that happened somehow in the past? I'm using node v18.0.0, and vscode-js-debug v1.69.0.

@mxsdev
Copy link

mxsdev commented Jul 8, 2022

@gfszr I managed to get it working with vsDebugServer, and I did in fact run into this issue. What was happening was that a child session was launched, and I needed to initialize it in order for the program to continue. After the command was sent, however, that child session was terminated, and I needed to then send my continue requests to its parent session.

I'm not sure exactly how it works with debugServerMain, but if it does run multiple sessions, then maybe see if you are sending your continue command to the right session. Hope that helps!

For anyone else stumbling upon this thread, check out this post where I discuss potential solutions to the aforementioned breakpoints issue.

@gfszr
Copy link
Contributor

gfszr commented Jul 8, 2022

@mxsdev Thanks for your quick reply! I'm not sure exactly how debugServerMain splits child sessions, for now it looks like all sessions operate on the single connection (Which is good - I don't want to perform changes to the DAP Client but rather write a simple "translation" layer that proxies DAP) - whilst vsDebugServer spawns different DAP connections for each. What changes have you done in the DAP client side to handle multiple connections?

@jcuffe
Copy link

jcuffe commented Oct 27, 2022

Hey all! Came here after a short jaunt through google searches for a DAP-compliant javascript debugger. Sad to see that the choice between conforming to a specification and having features is as difficult as it seems here 😞

Is it the general consensus that if I want to debug javascript using a tool that implements DAP as specified, I should use the deprecated node-debug2 package?

@connor4312
Copy link
Member

connor4312 commented Nov 5, 2022

Fyi this will soon be compliant with the adoption of microsoft/debug-adapter-protocol#79 this month, though DAP clients may take longer to update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
*question Issue represents a question, should be posted to StackOverflow (VS Code)
Projects
None yet
Development

No branches or pull requests

9 participants