Change:
Currently the API provides a way to send custom events to debug adapters. But it is missing one fairly important thing - there is no way to know what the current thread id / frame id is. So a debug adapter could maybe guess. But it feels like there should really be a way to query this.
Hi I noticed you self-assigned this recently. I was wondering, is there any kind of plan as to what an eventual API on this might look like? I also wanted to check that this feature request is the same one discussed on a different repo . Is the idea here to allow access to the ID of the "current" stack frame in the sense of the one that the user has selected in the VS Code debugger view in the sidebar?
It is unclear if this ever gets implemented, but I have a personal interest in it, thus I assigned it to myself to keep track of it.
Will you accept a PR for this? I have the code . I tried to keep it smallest and coherent with existing code as possible.
In principle we are willing to accept a PR. But since this is extension API it has to go through our extension API review process. The first thing we need is an API proposal.
is it something I can start? or it is something that is done only internally
you can start just here. Please study some existing API items with the "api-proposal" label to learn how API proposals look like.
Hello, I also need the feature (get the current user selected frame id) in order to update the windows of the debugger extension (especially for multi-core devices). Does this feature make progress? Is there any workaround to get the frame id?
if you'd like to help, you can write the API proposal. That would be the first step.
What do I need to do to write the API proposal? I would propose extending the debug namespace by an event which fires when the user selected a different stack frame in the call stack window. For example: export namespace debug { / An event which fires when the user selected a different stack frame in the call stack window. / export const onDidChangeSelectedStackFrame: Event<StackFrame; } The interface StackFrame consists of two properties: frameId and associated threadId. This would provide enough information to update the thread and stack frame in the Debug Adapter via custom request. export interface StackFrame { / Id of the associated thread (DAP id). / readonly threadId: number; / Id of the stack frame (DAP id). / readonly frameId: number; } What do you think about this?
If this is implemented, it needs to be specific to a session. As in threadId/frameId are not enough. We have to deal with multiple concurrent debug sessions. Needs DebugSession object or at least the sessionId. Doesn't frameId encapsulate/include threadId from a DA's perspective?
Yes, but I think you want to expose both so that a VS Code extension could call any DAP API which either took a thread id or a frame id.
could you tell me what the use case is? And does "current" mean "selected in the UI"?
Yes, "current" means the one selected in the UI. I originally ran into this when I wanted to implement Set Next Statement in the C# extension before the VS Code UI support for it. It has also come up when potentially wanting to support a disassembly window (though again, this was solved by building the feature in VS Code instead). My team doesn't have a current need for this, though I still think this is a good idea as this makes the extension API very limited in terms of building any kind of debugger feature. Without this feature, it isn't possible for an extension to make valid DAP requests for lots of feature areas, especially anything involving looking at variables/expression evaluation.
For another use case, I ran into this when trying to develop a debugging extension for Python. One of the features was that you could type in a variable name, or more generally an expression, and you would get back a certain visualization of the value of that expression. In order to do this, the extension sends the expression over the DAP to have Python evaluate it and send the value back. However, the variable, or any variables in the expression have to actually be in scope for this to work. If the user clicks back to a different stack frame in the UI, they can now view the values of variables in the built-in VSCode debugging panel. Since my extension also allows you to, in a sense, view the values of variables, the user expects to be be able to use it for any variables that they can see in the debugging panel. So I need to know when they switch stack frames to give them that experience. Right now my extension basically maintains a parallel list of stack frames in the UI, so if the user wants to climb back up the call stack and use my extension, they have to click the stack frame in both VSCode's built-in UI and in my extension's UI.
My use case is my . When the user selects a different stack frame than the top one, the watch windows and the visualizer window disagree.
I also have a use-case for having additional views participate in the debugging; being able to show a custom "registers" view that tracks with selection, for example. We also have some breakpoint functionality that changes if we're in an active session, and would leverage the active thread to 'scope' which threads for which it is active. So, I'd want to both interrogate the current/selected thread/stack frame (in session context) and to listen for changes
What would be the next step for moving this forward? It is required for our use-case, where we are moving an existing debugger to vscode, and need to provide functionality that depends on the frame selection context. But I believe this would be required more generally for any debugger that wants to provide any custom views that should show information for the selected context. Ive started a branch based on 's original branch (proof of concept), and would propose the API below. How are API change discussions driven, by the issue topic "api-proposal"? (I haven't attempted to contribute before; can i add "api-proposal". Should i assign this to me?) (edited: fixed copy/paste error, moved types outside of 'debug' namespace)
Hopefully, we get some traction on this. I have been waiting nearly three years for this. So many exciting things can happen with this.
can you have a look at the POC of ()?
Looking at , I think this is a reasonable proposal. I think that we could move forward with getting this into vscode as proposed API. I can't give any guarantee on how quickly we can stabilize that API but I think we could give you all something to experiment with and see if it properly fits your scenarios. Info about frame/thread/session is exposed to API as context for contributed context menu actions in the callstack view. I think we should have extension API that matches that, which is set up here: And I think I'd like to see three types here instead of one type with some optional properties that are only valid in certain combinations. Also we should be more specific, maybe say and . I wish there was one word that could mean "thread or frame or session", then I would say . If you can prepare a PR against the vscode repo, we can get it merged into vscode as proposed API.
Thank you very much I want to make sure I understand; I think you are saying you would like the highlighted code, which sets up the menu item context, to be exposed through this new listener API. The existing context is 'any' with three properties. You would also like to see distinct types, and I'm not sure where you mean; something like this, where each of these types would be what each of those functions set up today? OR or are you thinking something like:
i separated the listener registrations and event types into two more specific ones; hoping this is more like what you're suggesting. (I wasn't sure about: the menu item context example seems to be type-less, with optional properties, and wasn't sure how to reconcile that with the rest of you comment) Thank you for your comments! Maybe you could take a quick look before I do a PR
Sorry, I meant more like the way you had it initially with a single event and focus property, like your first example "Context" doesn't have to be part of the name. Also, instead of , you can use a property of the type that already exists
Thanks again! I still have some questions, but thought it might be easier to just create the PR and work through it there: I did switch back to the one listener registration, and a 'union' event type. But kept "Focus" in the name for the type to have it be distinct from other types elsewhere, and did not include DebugSession in the union, as that can be listened to elsewhere. (But maybe the PR it the place...). Happy to hear all feedback. re: paperwork, wasn't sure how to associate the pr with the issue, not sure if someone needs to assign to me? Let me know if i'm missing some steps, etc, Also let m e know if there's anything I can do to facilitate (meeting, etc). (Looking forward! This is critical for us to move forward, and I expect it really does open up some interesting and obvious debug enhancements.)
Does anybody also need to react to the selected debug configuration in the dropdown? There is also a feature request for this- I'm less enthusiastic about that, it seems unexpected to have the dropdown do anything other than decide which launch config to start. But another extension has a usecase where it signals which platform and arch you are targeting and so they can change up the UI based on that information. If you would also use that here it might make sense to tackle it at the same time.
Seems like an unrelated feature to me; I would suggest it should be a separate API - I think the distinction between selection related to artifacts related directly to debug UI context is different than "debug-related" UI selection (I think its debatable that it belongs in the 'debug' namespace) I'd prefer to keep the scope of this change minimal - this is must-have for providing UI that can show information for a thread/stackframe context in sync with the existing views. (Do you happen to have the issue? I'd like to understand the scenario - i'm not imagining why it changing the UI after launching isn't acceptable. Thanks!)
Verified the proposal exists, re-opening this issue for having a single record of all discussions until finalised. There are issues with the form of the proposals, namely us not using discriminated unions but old fashioned classes and instanceof-checks
Hi , i'm still trying to learn and understand the contribution process, and wanted to understand your comment above; is there some action I should take for the changes that were part of this PR? I see you a lint rule, and also disabled it for the discriminators in some of the debug types; do these need to change? Thanks!
Instead of using the discriminated type union interfaces for , we will use classes, and consumers can check the type with . If you would like to work on that, go for it, but we can also leave it alone while it's in the proposed state. If you work on it, the class implementations go in and you can see how this is handled for other APIs.
thanks for the guidance! i took a stab at it here: i was uncertain on: is it typical to expose the statis "isXXXXXX" functions as part of the API? how should I handle checking the "DebugSession" property? i a comment to the pull request Also, how does a "proposed api" get promoted to first-class API? And is there any process in which i can participate, or anything i can do?
Unfortunately not - we have regular meetings in which API proposals are discussed and fine-tuned but those aren't public. The overall process is outlined here:
Wanted to ask if there is anything I can do to make the discussions about promoting this proposed API easier? Would a runnable demo help, like a pull request? Animated GIF or other form of doc/example? Thanks again!
This API has been finalized and will in tomorrow's Insiders and the next stable release. Please refer to for the final API.

Discussion:
return extHostDebugService.breakpoints; }, get activeStackItem() { <del> if (!isProposedApiEnabled(extension, 'debugFocus')) { return undefined; } </del> return extHostDebugService.activeStackItem; }, registerDebugVisualizationProvider(id, provider) {

return _asExtensionEvent(extHostDebugService.onDidChangeBreakpoints)(listener, thisArgs, disposables); }, onDidChangeActiveStackItem(listener, thisArg?, disposables?) { <del> checkProposedApiEnabled(extension, 'debugFocus'); </del> return _asExtensionEvent(extHostDebugService.onDidChangeActiveStackItem)(listener, thisArg, disposables); }, registerDebugConfigurationProvider(debugType: string, provider: vscode.DebugConfigurationProvider, triggerKind?: vscode.DebugConfigurationProviderTriggerKind) {

contribViewsWelcome: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribViewsWelcome.d.ts', createFileSystemWatcher: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.createFileSystemWatcher.d.ts', customEditorMove: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.customEditorMove.d.ts', <del> debugFocus: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.debugFocus.d.ts', </del> debugVisualization: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.debugVisualization.d.ts', defaultChatParticipant: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.defaultChatParticipant.d.ts', diffCommand: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.diffCommand.d.ts',

} /** <ins> * Represents a thread in a debug session. */ export class DebugThread { /** * Debug session for thread. */ readonly session: DebugSession; /** * ID of the associated thread in the debug protocol. */ readonly threadId: number; /** * @hidden */ private constructor(session: DebugSession, threadId: number); } /** * Represents a stack frame in a debug session. */ export class DebugStackFrame { /** * Debug session for thread. */ readonly session: DebugSession; /** * ID of the associated thread in the debug protocol. */ readonly threadId: number; /** * ID of the stack frame in the debug protocol. */ readonly frameId: number; /** * @hidden */ private constructor(session: DebugSession, threadId: number, frameId: number); } /** </ins> * Namespace for debug functionality. */ export namespace debug {

export const onDidChangeBreakpoints: Event<BreakpointsChangeEvent>; /** <ins> * The currently focused thread or stack frame, or `undefined` if no * thread or stack is focused. A thread can be focused any time there is * an active debug session, while a stack frame can only be focused when * a session is paused and the call stack has been retrieved. */ export const activeStackItem: DebugThread | DebugStackFrame | undefined; /** * An event which fires when the {@link debug.activeStackItem} has changed. */ export const onDidChangeActiveStackItem: Event<DebugThread | DebugStackFrame | undefined>; /** </ins> * Register a {@link DebugConfigurationProvider debug configuration provider} for a specific debug type. * The optional {@link DebugConfigurationProviderTriggerKind triggerKind} can be used to specify when the `provideDebugConfigurations` method of the provider is triggered. * Currently two trigger kinds are possible: with the value `Initial` (or if no trigger kind argument is given) the `provideDebugConfigurations` method is used to provide the initial debug configurations to be copied into a newly created launch.json.

<del> /*--------------------------------------------------------------------------------------------- *  Copyright (c) Microsoft Corporation. All rights reserved. *  Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ declare module 'vscode' { // See https://github.com/microsoft/vscode/issues/63943 export class DebugThread { /** * Create a ThreadFocus * @param session * @param threadId */ constructor(session: DebugSession, threadId: number); /** * Debug session for thread. */ readonly session: DebugSession; /** * ID of the associated thread in the debug protocol. */ readonly threadId: number; } export class DebugStackFrame { /** * Create a StackFrameFocus * @param session * @param threadId * @param frameId */ constructor(session: DebugSession, threadId?: number, frameId?: number); /** * Debug session for thread. */ readonly session: DebugSession; /** * Id of the associated thread in the debug protocol. */ readonly threadId: number; /** * Id of the stack frame in the debug protocol. */ readonly frameId: number; } export namespace debug { /** * The currently focused thread or stack frame, or `undefined` if no * thread or stack is focused. */ export const activeStackItem: DebugThread | DebugStackFrame | undefined; /** * An event which fires when the {@link debug.activeStackItem} has changed. */ export const onDidChangeActiveStackItem: Event<DebugThread | DebugStackFrame | undefined>; } } </del>