Change:
Testing A lot of flickering goes on when executing a cell, can the number in [] not get its text cleared and instead go from [5] to [6] for example to minimize flickering? !
We clear the execution order when execution starts, and jupyter itself does not provide the new execution order until slightly after execution starts. All I can think of is doing something on the rendering side, like wait a bit to render a cleared execution order?
``
Found it annoying while testing Not that in the video, I was dragging an ipywidgets slider, which somehow is updating execution status. Though it didn't really increment the execution count, it kept flickering. https://user- It's also annoying to see the spinner. Bump it to July as I found this UX a bit unpleasant.
I wonder if that is related to creating a fake execution to update an output. Should be possible to do that atomically but I can check
To summarize since this goes on the plan, two related issues: Blinking when doing normal execution due to updating the execution count async Blinking and showing running state when updating outputs with the "fake" execution object. I'm not sure what we will be able to do about the running state - we even have code that specifically ensures that if the cell enters the running state, it should show the running indicator for some minimum amount of time
So far I have Fixed an issue with the extension using temp executions unnecessarily, so for the original report it doesn't blink anymore Fixed some unnecessary blinking for normal executions However, it's hard to avoid this for actual fake executions, because since this is a workaround for our API, it's not really clear how to detect this and treat them differently. We've said that we want an execution to show the progress spinner for a minimum time, 500ms, so that you can definitely tell in the UI that an execution happened, even if it is very fast. So then even if an execution is created and completed within the same js task, we will still show the progress spinner. This is good for fast normal executions and not good for "fake" executions. We could say that an execution that is completed immediately does not get the spinner at all, but I don't like that because it could hurt some simple kernel that doesn't need to do any async work as part of an execution. So I'm very open to ideas on how to improve this.
For future reference, here is a snippet that does a "fake" execution to update outputs outside of an execution.
Interesting, I hadn't realize this - in the snippet above in vscode adds outputs to the cell. In Jupyter lab, it actually writes to a different log instead of adding outputs to the cell. To understand this usecase I'm looking for an example that updates the output in jupyter lab outside of an execution - I remember there was one which I think involved subprocess, but I can't find an example anywhere. Wondering whether you have one handy
Verification steps: No flickering of the execution order or timer in a normal execution of a cell in a Jupyter notebook No flickering when changing the slider with this code:Some other ipywidget scenarios will still produce flickering from "fake executions", this is probably not solvable without API changes. Discovered that it's actually not working as expected in some other cases and so it could get more investigation later.
Verified

Discussion:
private _currentItemIds: string[] = []; <del> private _currentExecutingStateTimer: IDisposable | undefined; </del> <ins> private _showedExecutingStateTime: number | undefined; private _clearExecutingStateTimer: IDisposable | undefined; </ins> constructor( private readonly _notebookViewModel: INotebookViewModel,

*/ private _getItemsForCell(): INotebookCellStatusBarItem[] | undefined { const runState = this._executionStateService.getCellExecution(this._cell.uri); <del> if (this._currentExecutingStateTimer && !runState?.isPaused) { return; } const item = this._getItemForState(runState, this._cell.internalMetadata); </del> // Show the execution spinner for a minimum time <del> if (runState?.state === NotebookCellExecutionState.Executing) { this._currentExecutingStateTimer = this._register(disposableTimeout(() => { const runState = this._executionStateService.getCellExecution(this._cell.uri); this._currentExecutingStateTimer = undefined; if (runState?.state !== NotebookCellExecutionState.Executing) { this._update(); </del> <ins> if (runState?.state === NotebookCellExecutionState.Executing && typeof this._showedExecutingStateTime !== 'number') { this._showedExecutingStateTime = Date.now(); } else if (runState?.state !== NotebookCellExecutionState.Executing && typeof this._showedExecutingStateTime === 'number') { const timeUntilMin = ExecutionStateCellStatusBarItem.MIN_SPINNER_TIME - (Date.now() - this._showedExecutingStateTime); if (timeUntilMin > 0) { if (!this._clearExecutingStateTimer) { this._clearExecutingStateTimer = disposableTimeout(() => { this._showedExecutingStateTime = undefined; this._clearExecutingStateTimer = undefined; this._update(); }, timeUntilMin); </ins> } <del> }, ExecutionStateCellStatusBarItem.MIN_SPINNER_TIME)); </del> <ins> return undefined; } else { this._showedExecutingStateTime = undefined; } </ins> } <ins> const item = this._getItemForState(runState, this._cell.internalMetadata); </ins> return item ? [item] : []; }

} registerNotebookContribution(TimerCellStatusBarContrib.id, TimerCellStatusBarContrib); <ins> const UPDATE_TIMER_GRACE_PERIOD = 200; </ins> class TimerCellStatusBarItem extends Disposable { private static UPDATE_INTERVAL = 100; private _currentItemIds: string[] = []; private _scheduler: RunOnceScheduler; <ins> private _deferredUpdate: IDisposable | undefined; </ins> constructor( private readonly _notebookViewModel: INotebookViewModel, private readonly _cell: ICellViewModel,

} const items = item ? [item] : []; <del> this._currentItemIds = this._notebookViewModel.deltaCellStatusBarItems(this._currentItemIds, [{ handle: this._cell.handle, items }]); </del> <ins> if (!items.length && !!runState) { if (!this._deferredUpdate) { this._deferredUpdate = disposableTimeout(() => { this._deferredUpdate = undefined; this._currentItemIds = this._notebookViewModel.deltaCellStatusBarItems(this._currentItemIds, [{ handle: this._cell.handle, items }]); }, UPDATE_TIMER_GRACE_PERIOD); } } else { this._deferredUpdate?.dispose(); this._deferredUpdate = undefined; this._currentItemIds = this._notebookViewModel.deltaCellStatusBarItems(this._currentItemIds, [{ handle: this._cell.handle, items }]); } </ins> } private _getTimeItem(startTime: number, endTime: number, adjustment: number = 0): INotebookCellStatusBarItem {

override dispose() { super.dispose(); <ins> this._deferredUpdate?.dispose(); </ins> this._notebookViewModel.deltaCellStatusBarItems(this._currentItemIds, [{ handle: this._cell.handle, items: [] }]); } }

if (!exe) { exe = this._createNotebookCellExecution(notebook, cellHandle); notebookExecutionMap.set(cellHandle, exe); <ins> exe.initialize(); </ins> this._onDidChangeCellExecution.fire(new NotebookExecutionEvent(notebookUri, cellHandle, exe)); }

) { super(); this._logService.debug(`CellExecution#ctor ${this.getCellLog()}`); <ins> } initialize() { </ins> const startExecuteEdit: ICellEditOperation = { editType: CellEditType.PartialInternalMetadata, handle: this.cellHandle,

*--------------------------------------------------------------------------------------------*/ import * as DOM from 'vs/base/browser/dom'; <ins> import { disposableTimeout } from 'vs/base/common/async'; </ins> import { DisposableStore } from 'vs/base/common/lifecycle'; import { ICellViewModel, INotebookEditorDelegate } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellViewModelStateChangeEvent } from 'vs/workbench/contrib/notebook/browser/notebookViewEvents'; import { CellPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; import { NotebookCellInternalMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; <ins> import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService'; const UPDATE_EXECUTION_ORDER_GRACE_PERIOD = 200; </ins> export class CellExecutionPart extends CellPart { private kernelDisposables = this._register(new DisposableStore()); constructor( private readonly _notebookEditor: INotebookEditorDelegate, <del> private readonly _executionOrderLabel: HTMLElement </del> <ins> private readonly _executionOrderLabel: HTMLElement, @INotebookExecutionStateService private readonly _notebookExecutionStateService: INotebookExecutionStateService </ins> ) { super();

} protected override didRenderCell(element: ICellViewModel): void { <del> this.updateExecutionOrder(element.internalMetadata); </del> <ins> this.updateExecutionOrder(element.internalMetadata, true); </ins> } <del> private updateExecutionOrder(internalMetadata: NotebookCellInternalMetadata): void { </del> <ins> private updateExecutionOrder(internalMetadata: NotebookCellInternalMetadata, forceClear = false): void { </ins> if (this._notebookEditor.activeKernel?.implementsExecutionOrder) { <ins> // If the executionOrder was just cleared, and the cell is executing, wait just a bit before clearing the view to avoid flashing if (typeof internalMetadata.executionOrder !== 'number' && !forceClear && !!this._notebookExecutionStateService.getCellExecution(this.currentCell!.uri)) { const renderingCell = this.currentCell; this.cellDisposables.add(disposableTimeout(() => { if (this.currentCell === renderingCell) { this.updateExecutionOrder(this.currentCell!.internalMetadata, true); } }, UPDATE_EXECUTION_ORDER_GRACE_PERIOD)); return; } </ins> const executionOrderLabel = typeof internalMetadata.executionOrder === 'number' ? `[${internalMetadata.executionOrder}]` : '[ ]';

templateDisposables.add(scopedInstaService.createInstance(RunToolbar, this.notebookEditor, contextKeyService, container, runButtonContainer)), templateDisposables.add(new CellDecorations(rootContainer, decorationContainer)), templateDisposables.add(scopedInstaService.createInstance(CellComments, this.notebookEditor, cellCommentPartContainer)), <del> templateDisposables.add(new CellExecutionPart(this.notebookEditor, executionOrderLabel)), </del> <ins> templateDisposables.add(scopedInstaService.createInstance(CellExecutionPart, this.notebookEditor, executionOrderLabel)), </ins> templateDisposables.add(scopedInstaService.createInstance(CollapsedCellOutput, this.notebookEditor, cellOutputCollapsedContainer)), templateDisposables.add(new CollapsedCellInput(this.notebookEditor, cellInputCollapsedContainer)), templateDisposables.add(new CellFocusPart(container, focusSinkElement, this.notebookEditor)),