Skip to content

Commit 054c342

Browse files
committed
step into targets support
fixes microsoft#90793
1 parent ae4a8e3 commit 054c342

6 files changed

Lines changed: 77 additions & 6 deletions

File tree

src/vs/workbench/contrib/debug/browser/debugEditorActions.ts

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,17 @@ import { Range } from 'vs/editor/common/core/range';
99
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
1010
import { ServicesAccessor, registerEditorAction, EditorAction, IActionOptions } from 'vs/editor/browser/editorExtensions';
1111
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
12-
import { IDebugService, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE, State, VIEWLET_ID, IDebugEditorContribution, EDITOR_CONTRIBUTION_ID, BreakpointWidgetContext, IBreakpoint, BREAKPOINT_EDITOR_CONTRIBUTION_ID, IBreakpointEditorContribution, REPL_VIEW_ID } from 'vs/workbench/contrib/debug/common/debug';
12+
import { IDebugService, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE, State, VIEWLET_ID, IDebugEditorContribution, EDITOR_CONTRIBUTION_ID, BreakpointWidgetContext, IBreakpoint, BREAKPOINT_EDITOR_CONTRIBUTION_ID, IBreakpointEditorContribution, REPL_VIEW_ID, CONTEXT_STEP_INTO_TARGETS_SUPPORTED } from 'vs/workbench/contrib/debug/common/debug';
1313
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
1414
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
1515
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
1616
import { openBreakpointSource } from 'vs/workbench/contrib/debug/browser/breakpointsView';
1717
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
1818
import { PanelFocusContext } from 'vs/workbench/common/panel';
1919
import { IViewsService } from 'vs/workbench/common/views';
20+
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
21+
import { Action } from 'vs/base/common/actions';
22+
import { getDomNodePagePosition } from 'vs/base/browser/dom';
2023

2124
export const TOGGLE_BREAKPOINT_ID = 'editor.debug.action.toggleBreakpoint';
2225
class ToggleBreakpointAction extends EditorAction {
@@ -241,6 +244,48 @@ class ShowDebugHoverAction extends EditorAction {
241244
}
242245
}
243246

247+
class StepIntoTargetsAction extends EditorAction {
248+
249+
public static readonly ID = 'editor.debug.action.stepIntoTargets';
250+
public static readonly LABEL = nls.localize('stepIntoTargets', "Step Into Targets...");
251+
252+
constructor() {
253+
super({
254+
id: StepIntoTargetsAction.ID,
255+
label: StepIntoTargetsAction.LABEL,
256+
alias: 'Debug: Step Into Targets...',
257+
precondition: ContextKeyExpr.and(CONTEXT_STEP_INTO_TARGETS_SUPPORTED, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), EditorContextKeys.editorTextFocus),
258+
contextMenuOpts: {
259+
group: 'debug',
260+
order: 1.5
261+
}
262+
});
263+
}
264+
265+
async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
266+
const debugService = accessor.get(IDebugService);
267+
const contextMenuService = accessor.get(IContextMenuService);
268+
const session = debugService.getViewModel().focusedSession;
269+
const frame = debugService.getViewModel().focusedStackFrame;
270+
271+
if (session && frame && editor.hasModel()) {
272+
const targets = await session.stepInTargets(frame.frameId);
273+
const position = editor.getPosition();
274+
const cursorCoords = editor.getScrolledVisiblePosition(position);
275+
const editorCoords = getDomNodePagePosition(editor.getDomNode());
276+
const x = editorCoords.left + cursorCoords.left;
277+
const y = editorCoords.top + cursorCoords.top + cursorCoords.height;
278+
279+
contextMenuService.showContextMenu({
280+
getAnchor: () => ({ x, y }),
281+
getActions: () => {
282+
return targets.map(t => new Action(`stepIntoTarget:${t.id}`, t.label, undefined, true, () => session.stepIn(frame.thread.threadId, t.id)));
283+
}
284+
});
285+
}
286+
}
287+
}
288+
244289
class GoToBreakpointAction extends EditorAction {
245290
constructor(private isNext: boolean, opts: IActionOptions) {
246291
super(opts);
@@ -307,6 +352,7 @@ registerEditorAction(ToggleBreakpointAction);
307352
registerEditorAction(ConditionalBreakpointAction);
308353
registerEditorAction(LogPointAction);
309354
registerEditorAction(RunToCursorAction);
355+
registerEditorAction(StepIntoTargetsAction);
310356
registerEditorAction(SelectionToReplAction);
311357
registerEditorAction(SelectionToWatchExpressionsAction);
312358
registerEditorAction(ShowDebugHoverAction);

src/vs/workbench/contrib/debug/browser/debugSession.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -489,12 +489,12 @@ export class DebugSession implements IDebugSession {
489489
await this.raw.next({ threadId });
490490
}
491491

492-
async stepIn(threadId: number): Promise<void> {
492+
async stepIn(threadId: number, targetId?: number): Promise<void> {
493493
if (!this.raw) {
494494
throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'stepIn'));
495495
}
496496

497-
await this.raw.stepIn({ threadId });
497+
await this.raw.stepIn({ threadId, targetId });
498498
}
499499

500500
async stepOut(threadId: number): Promise<void> {
@@ -613,6 +613,15 @@ export class DebugSession implements IDebugSession {
613613
}, token);
614614
}
615615

616+
async stepInTargets(frameId: number): Promise<{ id: number, label: string }[]> {
617+
if (!this.raw) {
618+
return Promise.reject(new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'stepInTargets')));
619+
}
620+
621+
const response = await this.raw.stepInTargets({ frameId });
622+
return response.body.targets;
623+
}
624+
616625
async cancel(progressId: string): Promise<DebugProtocol.CancelResponse> {
617626
if (!this.raw) {
618627
return Promise.reject(new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'cancel')));

src/vs/workbench/contrib/debug/browser/rawDebugSession.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,13 @@ export class RawDebugSession implements IDisposable {
349349
return Promise.reject(new Error('restartFrame not supported'));
350350
}
351351

352+
stepInTargets(args: DebugProtocol.StepInTargetsArguments): Promise<DebugProtocol.StepInTargetsResponse> {
353+
if (this.capabilities.supportsStepInTargetsRequest) {
354+
return this.send('stepInTargets', args);
355+
}
356+
return Promise.reject(new Error('stepInTargets not supported'));
357+
}
358+
352359
completions(args: DebugProtocol.CompletionsArguments, token: CancellationToken): Promise<DebugProtocol.CompletionsResponse> {
353360
if (this.capabilities.supportsCompletionsRequest) {
354361
return this.send<DebugProtocol.CompletionsResponse>('completions', args, token);

src/vs/workbench/contrib/debug/common/debug.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export const CONTEXT_FOCUSED_SESSION_IS_ATTACH = new RawContextKey<boolean>('foc
5656
export const CONTEXT_STEP_BACK_SUPPORTED = new RawContextKey<boolean>('stepBackSupported', false);
5757
export const CONTEXT_RESTART_FRAME_SUPPORTED = new RawContextKey<boolean>('restartFrameSupported', false);
5858
export const CONTEXT_JUMP_TO_CURSOR_SUPPORTED = new RawContextKey<boolean>('jumpToCursorSupported', false);
59+
export const CONTEXT_STEP_INTO_TARGETS_SUPPORTED = new RawContextKey<boolean>('stepIntoTargetsSupported', false);
5960
export const CONTEXT_BREAKPOINTS_EXIST = new RawContextKey<boolean>('breakpointsExist', false);
6061

6162
export const EDITOR_CONTRIBUTION_ID = 'editor.contrib.debug';
@@ -229,14 +230,15 @@ export interface IDebugSession extends ITreeElement {
229230

230231
restartFrame(frameId: number, threadId: number): Promise<void>;
231232
next(threadId: number): Promise<void>;
232-
stepIn(threadId: number): Promise<void>;
233+
stepIn(threadId: number, targetId?: number): Promise<void>;
233234
stepOut(threadId: number): Promise<void>;
234235
stepBack(threadId: number): Promise<void>;
235236
continue(threadId: number): Promise<void>;
236237
reverseContinue(threadId: number): Promise<void>;
237238
pause(threadId: number): Promise<void>;
238239
terminateThreads(threadIds: number[]): Promise<void>;
239240

241+
stepInTargets(frameId: number): Promise<{ id: number, label: string }[]>;
240242
completions(frameId: number | undefined, text: string, position: Position, overwriteBefore: number, token: CancellationToken): Promise<DebugProtocol.CompletionsResponse>;
241243
setVariable(variablesReference: number | undefined, name: string, value: string): Promise<DebugProtocol.SetVariableResponse>;
242244
loadSource(resource: uri): Promise<DebugProtocol.SourceResponse>;

src/vs/workbench/contrib/debug/common/debugViewModel.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { Event, Emitter } from 'vs/base/common/event';
7-
import { CONTEXT_EXPRESSION_SELECTED, IViewModel, IStackFrame, IDebugSession, IThread, IExpression, IFunctionBreakpoint, CONTEXT_BREAKPOINT_SELECTED, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_JUMP_TO_CURSOR_SUPPORTED } from 'vs/workbench/contrib/debug/common/debug';
7+
import { CONTEXT_EXPRESSION_SELECTED, IViewModel, IStackFrame, IDebugSession, IThread, IExpression, IFunctionBreakpoint, CONTEXT_BREAKPOINT_SELECTED, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_JUMP_TO_CURSOR_SUPPORTED, CONTEXT_STEP_INTO_TARGETS_SUPPORTED } from 'vs/workbench/contrib/debug/common/debug';
88
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
99
import { isSessionAttach } from 'vs/workbench/contrib/debug/common/debugUtils';
1010

@@ -27,6 +27,7 @@ export class ViewModel implements IViewModel {
2727
private stepBackSupportedContextKey: IContextKey<boolean>;
2828
private focusedSessionIsAttach: IContextKey<boolean>;
2929
private restartFrameSupportedContextKey: IContextKey<boolean>;
30+
private stepIntoTargetsSupported: IContextKey<boolean>;
3031
private jumpToCursorSupported: IContextKey<boolean>;
3132

3233
constructor(contextKeyService: IContextKeyService) {
@@ -37,6 +38,7 @@ export class ViewModel implements IViewModel {
3738
this.stepBackSupportedContextKey = CONTEXT_STEP_BACK_SUPPORTED.bindTo(contextKeyService);
3839
this.focusedSessionIsAttach = CONTEXT_FOCUSED_SESSION_IS_ATTACH.bindTo(contextKeyService);
3940
this.restartFrameSupportedContextKey = CONTEXT_RESTART_FRAME_SUPPORTED.bindTo(contextKeyService);
41+
this.stepIntoTargetsSupported = CONTEXT_STEP_INTO_TARGETS_SUPPORTED.bindTo(contextKeyService);
4042
this.jumpToCursorSupported = CONTEXT_JUMP_TO_CURSOR_SUPPORTED.bindTo(contextKeyService);
4143
}
4244

@@ -67,6 +69,7 @@ export class ViewModel implements IViewModel {
6769
this.loadedScriptsSupportedContextKey.set(session ? !!session.capabilities.supportsLoadedSourcesRequest : false);
6870
this.stepBackSupportedContextKey.set(session ? !!session.capabilities.supportsStepBack : false);
6971
this.restartFrameSupportedContextKey.set(session ? !!session.capabilities.supportsRestartFrame : false);
72+
this.stepIntoTargetsSupported.set(session ? !!session.capabilities.supportsStepInTargetsRequest : false);
7073
this.jumpToCursorSupported.set(session ? !!session.capabilities.supportsGotoTargetsRequest : false);
7174
const attach = !!session && isSessionAttach(session);
7275
this.focusedSessionIsAttach.set(attach);

src/vs/workbench/contrib/debug/test/common/mockDebug.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ export class MockDebugService implements IDebugService {
136136

137137
export class MockSession implements IDebugSession {
138138

139+
stepInTargets(frameId: number): Promise<{ id: number; label: string; }[]> {
140+
throw new Error('Method not implemented.');
141+
}
142+
139143
cancel(_progressId: string): Promise<DebugProtocol.CancelResponse> {
140144
throw new Error('Method not implemented.');
141145
}
@@ -304,7 +308,7 @@ export class MockSession implements IDebugSession {
304308
next(threadId: number): Promise<void> {
305309
throw new Error('Method not implemented.');
306310
}
307-
stepIn(threadId: number): Promise<void> {
311+
stepIn(threadId: number, targetId?: number): Promise<void> {
308312
throw new Error('Method not implemented.');
309313
}
310314
stepOut(threadId: number): Promise<void> {

0 commit comments

Comments
 (0)