mirror of
https://github.com/microsoft/vscode.git
synced 2026-09-14 15:22:15 +01:00
@@ -28,7 +28,6 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { ReplModel } from 'vs/workbench/contrib/debug/common/replModel';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { variableSetEmitter } from 'vs/workbench/contrib/debug/browser/variablesView';
|
||||
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { distinct } from 'vs/base/common/arrays';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
@@ -52,6 +51,7 @@ export class DebugSession implements IDebugSession {
|
||||
private rawListeners: IDisposable[] = [];
|
||||
private fetchThreadsScheduler: RunOnceScheduler | undefined;
|
||||
private repl: ReplModel;
|
||||
private stoppedDetails: IRawStoppedDetails | undefined;
|
||||
|
||||
private readonly _onDidChangeState = new Emitter<void>();
|
||||
private readonly _onDidEndAdapter = new Emitter<AdapterEndEvent | undefined>();
|
||||
@@ -247,7 +247,8 @@ export class DebugSession implements IDebugSession {
|
||||
supportsVariablePaging: true, // #9537
|
||||
supportsRunInTerminalRequest: true, // #10574
|
||||
locale: platform.locale,
|
||||
supportsProgressReporting: true // #92253
|
||||
supportsProgressReporting: true, // #92253
|
||||
supportsInvalidatedEvent: true // #106745
|
||||
});
|
||||
|
||||
this.initialized = true;
|
||||
@@ -800,6 +801,7 @@ export class DebugSession implements IDebugSession {
|
||||
}));
|
||||
|
||||
this.rawListeners.push(this.raw.onDidStop(async event => {
|
||||
this.stoppedDetails = event.body;
|
||||
await this.fetchThreads(event.body);
|
||||
const thread = typeof event.body.threadId === 'number' ? this.getThread(event.body.threadId) : undefined;
|
||||
if (thread) {
|
||||
@@ -1001,6 +1003,19 @@ export class DebugSession implements IDebugSession {
|
||||
this.rawListeners.push(this.raw.onDidProgressEnd(event => {
|
||||
this._onDidProgressEnd.fire(event);
|
||||
}));
|
||||
this.rawListeners.push(this.raw.onDidInvalidated(async event => {
|
||||
if (!(event.body.areas && event.body.areas.length === 1 && event.body.areas[0] === 'variables')) {
|
||||
// If invalidated event only requires to update variables, do that, otherwise refatch threads https://github.com/microsoft/vscode/issues/106745
|
||||
this.cancelAllRequests();
|
||||
this.model.clearThreads(this.getId(), true);
|
||||
await this.fetchThreads(this.stoppedDetails);
|
||||
}
|
||||
|
||||
const viewModel = this.debugService.getViewModel();
|
||||
if (viewModel.focusedSession === this) {
|
||||
viewModel.updateViews();
|
||||
}
|
||||
}));
|
||||
|
||||
this.rawListeners.push(this.raw.onDidExitAdapter(event => this.onDidExitAdapter(event)));
|
||||
}
|
||||
@@ -1091,7 +1106,7 @@ export class DebugSession implements IDebugSession {
|
||||
async addReplExpression(stackFrame: IStackFrame | undefined, name: string): Promise<void> {
|
||||
await this.repl.addReplExpression(this, stackFrame, name);
|
||||
// Evaluate all watch expressions and fetch variables again since repl evaluation might have changed some.
|
||||
variableSetEmitter.fire();
|
||||
this.debugService.getViewModel().updateViews();
|
||||
}
|
||||
|
||||
appendToRepl(data: string | IExpression, severity: severity, source?: IReplElementSource): void {
|
||||
|
||||
@@ -69,6 +69,7 @@ export class RawDebugSession implements IDisposable {
|
||||
private readonly _onDidProgressStart = new Emitter<DebugProtocol.ProgressStartEvent>();
|
||||
private readonly _onDidProgressUpdate = new Emitter<DebugProtocol.ProgressUpdateEvent>();
|
||||
private readonly _onDidProgressEnd = new Emitter<DebugProtocol.ProgressEndEvent>();
|
||||
private readonly _onDidInvalidated = new Emitter<DebugProtocol.InvalidatedEvent>();
|
||||
private readonly _onDidCustomEvent = new Emitter<DebugProtocol.Event>();
|
||||
private readonly _onDidEvent = new Emitter<DebugProtocol.Event>();
|
||||
|
||||
@@ -150,6 +151,9 @@ export class RawDebugSession implements IDisposable {
|
||||
case 'progressEnd':
|
||||
this._onDidProgressEnd.fire(event as DebugProtocol.ProgressEndEvent);
|
||||
break;
|
||||
case 'invalidated':
|
||||
this._onDidInvalidated.fire(event as DebugProtocol.InvalidatedEvent);
|
||||
break;
|
||||
default:
|
||||
this._onDidCustomEvent.fire(event);
|
||||
break;
|
||||
@@ -230,6 +234,10 @@ export class RawDebugSession implements IDisposable {
|
||||
return this._onDidProgressEnd.event;
|
||||
}
|
||||
|
||||
get onDidInvalidated(): Event<DebugProtocol.InvalidatedEvent> {
|
||||
return this._onDidInvalidated.event;
|
||||
}
|
||||
|
||||
get onDidEvent(): Event<DebugProtocol.Event> {
|
||||
return this._onDidEvent.event;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
|
||||
import { ITreeRenderer, ITreeNode, ITreeMouseEvent, ITreeContextMenuEvent, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService';
|
||||
import { IAsyncDataTreeViewState } from 'vs/base/browser/ui/tree/asyncDataTree';
|
||||
import { FuzzyScore, createMatches } from 'vs/base/common/filters';
|
||||
@@ -41,7 +40,6 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
const $ = dom.$;
|
||||
let forgetScopes = true;
|
||||
|
||||
export const variableSetEmitter = new Emitter<void>();
|
||||
let variableInternalContext: Variable | undefined;
|
||||
let dataBreakpointInfoResponse: IDataBreakpointInfoResponse | undefined;
|
||||
|
||||
@@ -52,7 +50,7 @@ interface IVariablesContext {
|
||||
|
||||
export class VariablesView extends ViewPane {
|
||||
|
||||
private onFocusStackFrameScheduler: RunOnceScheduler;
|
||||
private updateTreeScheduler: RunOnceScheduler;
|
||||
private needsRefresh = false;
|
||||
private tree!: WorkbenchAsyncDataTree<IStackFrame | null, IExpression | IScope, FuzzyScore>;
|
||||
private savedViewState = new Map<string, IAsyncDataTreeViewState>();
|
||||
@@ -85,7 +83,7 @@ export class VariablesView extends ViewPane {
|
||||
this.variableEvaluateName = CONTEXT_VARIABLE_EVALUATE_NAME_PRESENT.bindTo(contextKeyService);
|
||||
|
||||
// Use scheduler to prevent unnecessary flashing
|
||||
this.onFocusStackFrameScheduler = new RunOnceScheduler(async () => {
|
||||
this.updateTreeScheduler = new RunOnceScheduler(async () => {
|
||||
const stackFrame = this.debugService.getViewModel().focusedStackFrame;
|
||||
|
||||
this.needsRefresh = false;
|
||||
@@ -142,9 +140,9 @@ export class VariablesView extends ViewPane {
|
||||
// Refresh the tree immediately if the user explictly changed stack frames.
|
||||
// Otherwise postpone the refresh until user stops stepping.
|
||||
const timeout = sf.explicit ? 0 : undefined;
|
||||
this.onFocusStackFrameScheduler.schedule(timeout);
|
||||
this.updateTreeScheduler.schedule(timeout);
|
||||
}));
|
||||
this._register(variableSetEmitter.event(() => {
|
||||
this._register(this.debugService.getViewModel().onWillUpdateViews(() => {
|
||||
const stackFrame = this.debugService.getViewModel().focusedStackFrame;
|
||||
if (stackFrame && forgetScopes) {
|
||||
stackFrame.forgetScopes();
|
||||
@@ -157,7 +155,7 @@ export class VariablesView extends ViewPane {
|
||||
|
||||
this._register(this.onDidChangeBodyVisibility(visible => {
|
||||
if (visible && this.needsRefresh) {
|
||||
this.onFocusStackFrameScheduler.schedule();
|
||||
this.updateTreeScheduler.schedule();
|
||||
}
|
||||
}));
|
||||
let horizontalScrolling: boolean | undefined;
|
||||
@@ -358,7 +356,7 @@ export class VariablesRenderer extends AbstractExpressionsRenderer {
|
||||
.then(() => {
|
||||
// Do not refresh scopes due to a node limitation #15520
|
||||
forgetScopes = false;
|
||||
variableSetEmitter.fire();
|
||||
this.debugService.getViewModel().updateViews();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import { IDragAndDropData } from 'vs/base/browser/dnd';
|
||||
import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView';
|
||||
import { FuzzyScore } from 'vs/base/common/filters';
|
||||
import { IHighlight } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
|
||||
import { variableSetEmitter, VariablesRenderer } from 'vs/workbench/contrib/debug/browser/variablesView';
|
||||
import { VariablesRenderer } from 'vs/workbench/contrib/debug/browser/variablesView';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { dispose } from 'vs/base/common/lifecycle';
|
||||
import { IViewDescriptorService } from 'vs/workbench/common/views';
|
||||
@@ -34,12 +34,12 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
|
||||
const MAX_VALUE_RENDER_LENGTH_IN_VIEWLET = 1024;
|
||||
let ignoreVariableSetEmitter = false;
|
||||
let ignoreViewUpdates = false;
|
||||
let useCachedEvaluation = false;
|
||||
|
||||
export class WatchExpressionsView extends ViewPane {
|
||||
|
||||
private onWatchExpressionsUpdatedScheduler: RunOnceScheduler;
|
||||
private watchExpressionsUpdatedScheduler: RunOnceScheduler;
|
||||
private needsRefresh = false;
|
||||
private tree!: WorkbenchAsyncDataTree<IDebugService | IExpression, IExpression, FuzzyScore>;
|
||||
|
||||
@@ -58,7 +58,7 @@ export class WatchExpressionsView extends ViewPane {
|
||||
) {
|
||||
super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService);
|
||||
|
||||
this.onWatchExpressionsUpdatedScheduler = new RunOnceScheduler(() => {
|
||||
this.watchExpressionsUpdatedScheduler = new RunOnceScheduler(() => {
|
||||
this.needsRefresh = false;
|
||||
this.tree.updateChildren();
|
||||
}, 50);
|
||||
@@ -117,19 +117,19 @@ export class WatchExpressionsView extends ViewPane {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.onWatchExpressionsUpdatedScheduler.isScheduled()) {
|
||||
this.onWatchExpressionsUpdatedScheduler.schedule();
|
||||
if (!this.watchExpressionsUpdatedScheduler.isScheduled()) {
|
||||
this.watchExpressionsUpdatedScheduler.schedule();
|
||||
}
|
||||
}));
|
||||
this._register(variableSetEmitter.event(() => {
|
||||
if (!ignoreVariableSetEmitter) {
|
||||
this._register(this.debugService.getViewModel().onWillUpdateViews(() => {
|
||||
if (!ignoreViewUpdates) {
|
||||
this.tree.updateChildren();
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this.onDidChangeBodyVisibility(visible => {
|
||||
if (visible && this.needsRefresh) {
|
||||
this.onWatchExpressionsUpdatedScheduler.schedule();
|
||||
this.watchExpressionsUpdatedScheduler.schedule();
|
||||
}
|
||||
}));
|
||||
let horizontalScrolling: boolean | undefined;
|
||||
@@ -291,9 +291,9 @@ export class WatchExpressionsRenderer extends AbstractExpressionsRenderer {
|
||||
onFinish: (value: string, success: boolean) => {
|
||||
if (success && value) {
|
||||
this.debugService.renameWatchExpression(expression.getId(), value);
|
||||
ignoreVariableSetEmitter = true;
|
||||
variableSetEmitter.fire();
|
||||
ignoreVariableSetEmitter = false;
|
||||
ignoreViewUpdates = true;
|
||||
this.debugService.getViewModel().updateViews();
|
||||
ignoreViewUpdates = false;
|
||||
} else if (!expression.name) {
|
||||
this.debugService.removeWatchExpressions(expression.getId());
|
||||
}
|
||||
|
||||
@@ -437,12 +437,14 @@ export interface IViewModel extends ITreeElement {
|
||||
getSelectedFunctionBreakpoint(): IFunctionBreakpoint | undefined;
|
||||
setSelectedExpression(expression: IExpression | undefined): void;
|
||||
setSelectedFunctionBreakpoint(functionBreakpoint: IFunctionBreakpoint | undefined): void;
|
||||
updateViews(): void;
|
||||
|
||||
isMultiSessionView(): boolean;
|
||||
|
||||
onDidFocusSession: Event<IDebugSession | undefined>;
|
||||
onDidFocusStackFrame: Event<{ stackFrame: IStackFrame | undefined, explicit: boolean }>;
|
||||
onDidSelectExpression: Event<IExpression | undefined>;
|
||||
onWillUpdateViews: Event<void>;
|
||||
}
|
||||
|
||||
export interface IEvaluate {
|
||||
|
||||
@@ -20,6 +20,7 @@ export class ViewModel implements IViewModel {
|
||||
private readonly _onDidFocusSession = new Emitter<IDebugSession | undefined>();
|
||||
private readonly _onDidFocusStackFrame = new Emitter<{ stackFrame: IStackFrame | undefined, explicit: boolean }>();
|
||||
private readonly _onDidSelectExpression = new Emitter<IExpression | undefined>();
|
||||
private readonly _onWillUpdateViews = new Emitter<void>();
|
||||
private multiSessionView: boolean;
|
||||
private expressionSelectedContextKey!: IContextKey<boolean>;
|
||||
private breakpointSelectedContextKey!: IContextKey<boolean>;
|
||||
@@ -115,6 +116,14 @@ export class ViewModel implements IViewModel {
|
||||
return this.selectedFunctionBreakpoint;
|
||||
}
|
||||
|
||||
updateViews(): void {
|
||||
this._onWillUpdateViews.fire();
|
||||
}
|
||||
|
||||
get onWillUpdateViews(): Event<void> {
|
||||
return this._onWillUpdateViews.event;
|
||||
}
|
||||
|
||||
setSelectedFunctionBreakpoint(functionBreakpoint: IFunctionBreakpoint | undefined): void {
|
||||
this.selectedFunctionBreakpoint = functionBreakpoint;
|
||||
this.breakpointSelectedContextKey.set(!!functionBreakpoint);
|
||||
|
||||
@@ -10,7 +10,7 @@ import { MockRawSession, createMockDebugModel, mockUriIdentityService } from 'vs
|
||||
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
|
||||
import { DebugSession } from 'vs/workbench/contrib/debug/browser/debugSession';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { IDebugSessionOptions, State } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IDebugSessionOptions, State, IDebugService } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { NullOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { createDecorationsForStackFrame } from 'vs/workbench/contrib/debug/browser/callStackEditorContribution';
|
||||
import { Constants } from 'vs/base/common/uint';
|
||||
@@ -19,7 +19,15 @@ import { getStackFrameThreadAndSessionToFocus } from 'vs/workbench/contrib/debug
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
|
||||
export function createMockSession(model: DebugModel, name = 'mockSession', options?: IDebugSessionOptions): DebugSession {
|
||||
return new DebugSession(generateUuid(), { resolved: { name, type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, options, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, NullOpenerService, undefined!, undefined!, mockUriIdentityService);
|
||||
return new DebugSession(generateUuid(), { resolved: { name, type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, options, {
|
||||
getViewModel(): any {
|
||||
return {
|
||||
updateViews(): void {
|
||||
// noop
|
||||
}
|
||||
};
|
||||
}
|
||||
} as IDebugService, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, NullOpenerService, undefined!, undefined!, mockUriIdentityService);
|
||||
}
|
||||
|
||||
function createTwoStackFrames(session: DebugSession): { firstStackFrame: StackFrame, secondStackFrame: StackFrame } {
|
||||
|
||||
Reference in New Issue
Block a user