vscode icon indicating copy to clipboard operation
vscode copied to clipboard

Give extension the ability to know where the current debug session is stopped

Open zobo opened this issue 3 weeks ago • 6 comments

Hello all! I'm currently revisiting the EvaluatableExpression topic with @bmewburn, the author of the vscode-intelephens language server for PHP.

The situation that we are exploring is, when the IDE asks for an evaluable expression at some document position, there is no info about the debugger context provided with this request - in contrast to LSP InlineValue request where this can be infered from the stoppedLocation. So relying alone on the provideEvaluatableExpression call, the extension cannot give an informed decision whether the verb at the position is a variable in scope.

Looking at the public VS Code API, we could use the activeStackItem to get the current frameId, but there is no API to get to the actual Document and Position data. Is there a way for an extension to get the current Document/Position of an active debugger session execution?

Was the EvaluatableExpression designed so that it gives information just if the verb is a variable or not, or should it take into account if it is also in debugger scope...

Why isn't EvaluatableExpression an LSP request in the first place?

Thank you for the feedback.

Ref: https://github.com/xdebug/vscode-php-debug/issues/1080#issuecomment-3592000865

zobo avatar Nov 30 '25 10:11 zobo

I think the way to do this is to send a stackTrace request on the debug session using the information from the activeStackItem, using the DebugSession.customRequest method.

In the debug APIs we reflect only the UI state of the editor which is not represented to the debug adapter itself. For interactions with the state of the debug adapter, you'll want to speak DAP to the DebugSession directly.

connor4312 avatar Dec 09 '25 18:12 connor4312

Thanks @connor4312 . If I understand correctly, a language server extension would use DebugSession.customRequest to send a stackTrace request with the startFrame value being the activeStackItem.frameId and then use the returned StackFrame.line and StackFrame.column as context?

Could the same approach have been done with InlineValuesProvider? Why does it get an InlineValuesContext?

bmewburn avatar Dec 10 '25 05:12 bmewburn

If I understand correctly, a language server extension would use DebugSession.customRequest to send a stackTrace request with the startFrame value being the activeStackItem.frameId and then use the returned StackFrame.line and StackFrame.column as context?

Correct

Could the same approach have been done with InlineValuesProvider? Why does it get an InlineValuesContext?

Inline values are pretty much always going to depend on where the execution state is, so it made sense to make that accessible. We've not before seen any case where a language server needed such context to determine evaluatable expressions, generally these have been a result of the language constructs and not the debugger state.

connor4312 avatar Dec 10 '25 06:12 connor4312

This would work, since we are talking about a standard DAP message, and the Language Server extension doesn't need to be aware of what the specific implementation is providing debug services - there could be, and are, more than one debug adapter implementations for the same language. It does however feel a bit redundant, that the IDE first asks DA for the stack frames, and then the language extensions asks for stack frames again.

However, what I'm taking away from this is, that apparently the design of EvaluatableExpression was not meant to have any context of the debugger state. We'll see how it works out.

zobo avatar Dec 10 '25 07:12 zobo

We've not before seen any case where a language server needed such context to determine evaluatable expressions

Getting the expression at the position is simple enough without context. It's more answering the question of "should the expression at position x be evaluated given the debugger is stopped at y?". Here's an example with typescript where hovering over n in an out of scope function that accepts a number shows a value of 'a'.

Image

It's all a bit edge case though as it only happens when variables have the same name.

Maybe vscode could use the LSP textDocument.documentSymbol result to decide if the hover is applicable to the current debugger state?

bmewburn avatar Dec 10 '25 07:12 bmewburn

It's more answering the question of "should the expression at position x be evaluated given the debugger is stopped at y?". Here's an example with typescript where hovering over n in an out of scope function that accepts a number shows a value of 'a'.

For this reason we actually did add a line and column to the evaluate request, and I actually did use that in the JS debug adapter to show the correct value for shadowed variables (whenever possible) on the debugger side. Maybe that is the more appropriate approach for you as well? Return the evaluatable based on language construct and leave it to the debug adapter to set the variables/context correctly.

connor4312 avatar Dec 10 '25 16:12 connor4312

Maybe that is the more appropriate approach for you as well? Return the evaluatable based on language construct and leave it to the debug adapter to set the variables/context correctly.

Makes sense. I'm not sure how much the PHP DA knows about the ranges to decide this.

bmewburn avatar Dec 10 '25 19:12 bmewburn

I would argue against that. In the concrete case, php-debug, the adapter barely understands any PHP, let alone the AST and DOM required to understand what variable positions would be in scope or not. If I read your PR correctly, you can get some context about scopes with lines from data that is provided by the JS debugger engine - this is not possible with PHP/Xdebug.

zobo avatar Dec 10 '25 21:12 zobo