diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/breakpoints/notebookBreakpoints.ts b/src/vs/workbench/contrib/notebook/browser/contrib/breakpoints/notebookBreakpoints.ts index f1836653a29c9..fad21ea33924b 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/breakpoints/notebookBreakpoints.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/breakpoints/notebookBreakpoints.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ +import { RunOnceScheduler } from 'vs/base/common/async'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { ResourceMap } from 'vs/base/common/map'; import { Schemas } from 'vs/base/common/network'; @@ -133,22 +134,30 @@ Registry.as(WorkbenchExtensions.Workbench).regi class NotebookCellPausing extends Disposable implements IWorkbenchContribution { private readonly _pausedCells = new Set(); + private _scheduler: RunOnceScheduler; + constructor( @IDebugService private readonly _debugService: IDebugService, @INotebookExecutionStateService private readonly _notebookExecutionStateService: INotebookExecutionStateService, ) { super(); - this._register(_debugService.getModel().onDidChangeCallStack(() => this.onDidChangeCallStack())); + this._register(_debugService.getModel().onDidChangeCallStack(() => { + // First update using the stale callstack if the real callstack is empty, to reduce blinking while stepping. + // After not pausing for 2s, update again with the latest callstack. + this.onDidChangeCallStack(true); + this._scheduler.schedule(); + })); + this._scheduler = this._register(new RunOnceScheduler(() => this.onDidChangeCallStack(false), 2000)); } - private async onDidChangeCallStack(): Promise { + private async onDidChangeCallStack(fallBackOnStaleCallstack: boolean): Promise { const newPausedCells = new Set(); for (const session of this._debugService.getModel().getSessions()) { for (const thread of session.getAllThreads()) { let callStack = thread.getCallStack(); - if (!callStack.length) { + if (fallBackOnStaleCallstack && !callStack.length) { callStack = (thread as Thread).getStaleCallStack(); } @@ -174,12 +183,13 @@ class NotebookCellPausing extends Disposable implements IWorkbenchContribution { private editIsPaused(cellUri: URI, isPaused: boolean) { const parsed = CellUri.parse(cellUri); - if (parsed && isPaused) { + if (parsed) { const exeState = this._notebookExecutionStateService.getCellExecutionState(cellUri); - if (exeState) { + if (exeState && (exeState.isPaused !== isPaused || !exeState.didPause)) { this._notebookExecutionStateService.updateNotebookCellExecution(parsed.notebook, parsed.handle, [{ editType: CellExecutionUpdateType.ExecutionState, - didPause: true + didPause: true, + isPaused }]); } } diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/cellStatusBar/executionStatusBarItemController.ts b/src/vs/workbench/contrib/notebook/browser/contrib/cellStatusBar/executionStatusBarItemController.ts index 5728406b05fac..20d2dace2b6ee 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/cellStatusBar/executionStatusBarItemController.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/cellStatusBar/executionStatusBarItemController.ts @@ -112,7 +112,7 @@ class ExecutionStateCellStatusBarItem extends Disposable { */ private _getItemsForCell(): INotebookCellStatusBarItem[] | undefined { const runState = this._executionStateService.getCellExecutionState(this._cell.uri); - if (this._currentExecutingStateTimer && !runState?.didPause) { + if (this._currentExecutingStateTimer && !runState?.isPaused) { return; } @@ -159,7 +159,7 @@ class ExecutionStateCellStatusBarItem extends Disposable { priority: Number.MAX_SAFE_INTEGER }; } else if (state === NotebookCellExecutionState.Executing) { - const icon = runState?.didPause ? + const icon = runState?.isPaused ? executingStateIcon : ThemeIcon.modify(executingStateIcon, 'spin'); return { diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/execute/executionEditorProgress.ts b/src/vs/workbench/contrib/notebook/browser/contrib/execute/executionEditorProgress.ts index 696b46f725d1a..9b2e3da9d46d2 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/execute/executionEditorProgress.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/execute/executionEditorProgress.ts @@ -51,7 +51,7 @@ export class ExecutionEditorProgressController extends Disposable implements INo return false; }; - if (!executing.length || executing.some(executionIsVisible) || executing.some(e => e.didPause)) { + if (!executing.length || executing.some(executionIsVisible) || executing.some(e => e.isPaused)) { this._notebookEditor.hideProgress(); } else { this._notebookEditor.showProgress(); diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts b/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts index d97a5fa61b37d..c1b45cbff6cb5 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts @@ -448,7 +448,7 @@ export class NotebookCellOutline extends Disposable implements IOutline u.editType === CellExecutionUpdateType.ExecutionState && typeof u.isPaused === 'boolean'); + if (lastIsPausedUpdate) { + this._isPaused = (lastIsPausedUpdate as ICellExecutionStateUpdate).isPaused!; + } + const edits = updates.map(update => updateToEdit(update, this.cellHandle)); this._applyExecutionEdits(edits); } diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellProgressBar.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellProgressBar.ts index c43e9993fa632..f11d53b183836 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellProgressBar.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellProgressBar.ts @@ -66,7 +66,7 @@ export class CellProgressBar extends CellPart { private _updateForExecutionState(element: ICellViewModel, e?: ICellExecutionStateChangedEvent): void { const exeState = e?.changed ?? this._notebookExecutionStateService.getCellExecutionState(element.uri); const progressBar = element.isInputCollapsed ? this._collapsedProgressBar : this._progressBar; - if (exeState?.state === NotebookCellExecutionState.Executing && !exeState.didPause) { + if (exeState?.state === NotebookCellExecutionState.Executing && !exeState.isPaused) { showProgressBar(progressBar); } else { progressBar.hide(); diff --git a/src/vs/workbench/contrib/notebook/common/notebookExecutionStateService.ts b/src/vs/workbench/contrib/notebook/common/notebookExecutionStateService.ts index 0acf45d3bc0e3..4a969429c8455 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookExecutionStateService.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookExecutionStateService.ts @@ -16,6 +16,7 @@ export interface ICellExecutionStateUpdate { executionOrder?: number; runStartTime?: number; didPause?: boolean; + isPaused?: boolean; } export interface ICellExecutionComplete { @@ -28,6 +29,7 @@ export interface ICellExecutionEntry { cellHandle: number; state: NotebookCellExecutionState; didPause: boolean; + isPaused: boolean; } export interface ICellExecutionStateChangedEvent {