mirror of
https://github.com/microsoft/vscode.git
synced 2026-07-08 15:55:15 +01:00
Merge branch 'roblou/executionService'
This commit is contained in:
@@ -872,6 +872,64 @@ suite('Notebook API tests', function () {
|
||||
assert.strictEqual(cell.executionSummary?.timing?.endTime, 20);
|
||||
|
||||
});
|
||||
|
||||
test.skip('execution cancelled when delete while executing', async () => {
|
||||
const document = await openRandomNotebookDocument();
|
||||
const cell = document.cellAt(0);
|
||||
|
||||
let executionWasCancelled = false;
|
||||
const cancelledKernel = new class extends Kernel {
|
||||
constructor() {
|
||||
super('cancelledKernel', '');
|
||||
}
|
||||
|
||||
override async _execute(cells: vscode.NotebookCell[]) {
|
||||
const [cell] = cells;
|
||||
const exe = this.controller.createNotebookCellExecution(cell);
|
||||
exe.token.onCancellationRequested(() => executionWasCancelled = true);
|
||||
}
|
||||
};
|
||||
testDisposables.push(cancelledKernel.controller);
|
||||
|
||||
const notebook = await openRandomNotebookDocument();
|
||||
await vscode.window.showNotebookDocument(notebook);
|
||||
await assertKernel(cancelledKernel, notebook);
|
||||
await vscode.commands.executeCommand('notebook.cell.execute');
|
||||
|
||||
// Delete executing cell
|
||||
const edit = new vscode.WorkspaceEdit();
|
||||
edit.replaceNotebookCells(cell!.notebook.uri, new vscode.NotebookRange(cell!.index, cell!.index + 1), []);
|
||||
await vscode.workspace.applyEdit(edit);
|
||||
|
||||
assert.strictEqual(executionWasCancelled, true);
|
||||
});
|
||||
|
||||
test('execution cancelled when kernel changed', async () => {
|
||||
await openRandomNotebookDocument();
|
||||
let executionWasCancelled = false;
|
||||
const cancelledKernel = new class extends Kernel {
|
||||
constructor() {
|
||||
super('cancelledKernel', '');
|
||||
}
|
||||
|
||||
override async _execute(cells: vscode.NotebookCell[]) {
|
||||
const [cell] = cells;
|
||||
const exe = this.controller.createNotebookCellExecution(cell);
|
||||
exe.token.onCancellationRequested(() => executionWasCancelled = true);
|
||||
}
|
||||
};
|
||||
|
||||
const notebook = await openRandomNotebookDocument();
|
||||
await vscode.window.showNotebookDocument(notebook);
|
||||
testDisposables.push(cancelledKernel.controller);
|
||||
await assertKernel(cancelledKernel, notebook);
|
||||
await vscode.commands.executeCommand('notebook.cell.execute');
|
||||
|
||||
const newKernel = new Kernel('newKernel', 'kernel');
|
||||
testDisposables.push(newKernel.controller);
|
||||
await assertKernel(newKernel, notebook);
|
||||
assert.strictEqual(executionWasCancelled, true);
|
||||
});
|
||||
});
|
||||
|
||||
suite('statusbar', () => {
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
|
||||
import * as notebookCommon from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellExecutionUpdateType, ICellExecuteUpdate } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
|
||||
import { CellExecutionUpdateType } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
|
||||
import { ICellExecuteUpdate, ICellExecutionComplete } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
||||
|
||||
export namespace NotebookDto {
|
||||
|
||||
@@ -112,6 +113,10 @@ export namespace NotebookDto {
|
||||
}
|
||||
}
|
||||
|
||||
export function fromCellExecuteCompleteDto(data: extHostProtocol.ICellExecutionCompleteDto): ICellExecutionComplete {
|
||||
return data;
|
||||
}
|
||||
|
||||
export function fromCellEditOperationDto(edit: extHostProtocol.ICellEditOperationDto): notebookCommon.ICellEditOperation {
|
||||
if (edit.editType === notebookCommon.CellEditType.Replace) {
|
||||
return {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { flatten, groupBy, isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { combinedDisposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { combinedDisposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { ILanguageService } from 'vs/editor/common/services/language';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
@@ -14,10 +14,11 @@ import { NotebookDto } from 'vs/workbench/api/browser/mainThreadNotebookDto';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService';
|
||||
import { INotebookCellExecution, INotebookExecutionService } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
|
||||
import { CellUri } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
||||
import { INotebookKernel, INotebookKernelChangeEvent, INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
|
||||
import { SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
import { ExtHostContext, ExtHostNotebookKernelsShape, ICellExecuteUpdateDto, IExtHostContext, INotebookKernelDto2, MainContext, MainThreadNotebookKernelsShape } from '../common/extHost.protocol';
|
||||
import { ExtHostContext, ExtHostNotebookKernelsShape, ICellExecuteUpdateDto, ICellExecutionCompleteDto, IExtHostContext, INotebookKernelDto2, MainContext, MainThreadNotebookKernelsShape } from '../common/extHost.protocol';
|
||||
|
||||
abstract class MainThreadKernel implements INotebookKernel {
|
||||
|
||||
@@ -106,14 +107,13 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape
|
||||
private readonly _kernels = new Map<number, [kernel: MainThreadKernel, registraion: IDisposable]>();
|
||||
private readonly _proxy: ExtHostNotebookKernelsShape;
|
||||
|
||||
private readonly _executions = new Map<number, INotebookCellExecution>();
|
||||
private readonly _executions = new Set<string>();
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@ILanguageService private readonly _languageService: ILanguageService,
|
||||
@INotebookKernelService private readonly _notebookKernelService: INotebookKernelService,
|
||||
@INotebookExecutionService private readonly _notebookExecutionService: INotebookExecutionService,
|
||||
// @INotebookService private readonly _notebookService: INotebookService,
|
||||
@INotebookExecutionStateService private readonly _notebookExecutionStateService: INotebookExecutionStateService,
|
||||
@INotebookEditorService notebookEditorService: INotebookEditorService
|
||||
) {
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebookKernels);
|
||||
@@ -121,6 +121,20 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape
|
||||
notebookEditorService.listNotebookEditors().forEach(this._onEditorAdd, this);
|
||||
notebookEditorService.onDidAddNotebookEditor(this._onEditorAdd, this, this._disposables);
|
||||
notebookEditorService.onDidRemoveNotebookEditor(this._onEditorRemove, this, this._disposables);
|
||||
|
||||
this._disposables.add(toDisposable(() => {
|
||||
// EH shut down, complete all executions started by this EH
|
||||
this._executions.forEach(e => {
|
||||
const uri = CellUri.parse(URI.parse(e));
|
||||
if (uri) {
|
||||
this._notebookExecutionStateService.completeNotebookCellExecution(uri.notebook, uri.handle, { });
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
this._disposables.add(this._notebookExecutionStateService.onDidChangeCellExecution(e => {
|
||||
this._proxy.$cellExecutionChanged(e.notebook, e.cellHandle, e.changed?.state);
|
||||
}));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
@@ -235,30 +249,34 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape
|
||||
|
||||
// --- execution
|
||||
|
||||
$addExecution(handle: number, uri: UriComponents, cellHandle: number): void {
|
||||
const execution = this._notebookExecutionService.createNotebookCellExecution(URI.revive(uri), cellHandle);
|
||||
this._executions.set(handle, execution);
|
||||
$addExecution(rawUri: UriComponents, cellHandle: number): void {
|
||||
const uri = URI.revive(rawUri);
|
||||
this._notebookExecutionStateService.createNotebookCellExecution(uri, cellHandle);
|
||||
|
||||
const cellUri = CellUri.generateCellUri(uri, cellHandle, uri.scheme);
|
||||
this._executions.add(cellUri.toString());
|
||||
}
|
||||
|
||||
$updateExecutions(data: SerializableObjectWithBuffers<ICellExecuteUpdateDto[]>): void {
|
||||
const updates = data.value;
|
||||
const groupedUpdates = groupBy(updates, (a, b) => a.executionHandle - b.executionHandle);
|
||||
const groupedUpdates = groupBy(updates, (a, b) => a.cellHandle - b.cellHandle);
|
||||
groupedUpdates.forEach(datas => {
|
||||
const first = datas[0];
|
||||
const execution = this._executions.get(first.executionHandle);
|
||||
if (!execution) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
execution.update(datas.map(NotebookDto.fromCellExecuteUpdateDto));
|
||||
const uri = URI.revive(first.uri);
|
||||
this._notebookExecutionStateService.updateNotebookCellExecution(uri, first.cellHandle, datas.map(NotebookDto.fromCellExecuteUpdateDto));
|
||||
} catch (e) {
|
||||
onUnexpectedError(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$removeExecution(handle: number): void {
|
||||
this._executions.delete(handle);
|
||||
$completeExecution(rawUri: UriComponents, cellHandle: number, data: SerializableObjectWithBuffers<ICellExecutionCompleteDto>): void {
|
||||
const uri = URI.revive(rawUri);
|
||||
this._notebookExecutionStateService.completeNotebookCellExecution(uri, cellHandle, NotebookDto.fromCellExecuteCompleteDto(data.value));
|
||||
|
||||
const cellUri = CellUri.generateCellUri(uri, cellHandle, uri.scheme);
|
||||
this._executions.delete(cellUri.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1124,7 +1124,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
},
|
||||
onDidChangeNotebookCellExecutionState(listener, thisArgs?, disposables?) {
|
||||
checkProposedApiEnabled(extension, 'notebookCellExecutionState');
|
||||
return extHostNotebook.onDidChangeNotebookCellExecutionState(listener, thisArgs, disposables);
|
||||
return extHostNotebookKernels.onDidChangeNotebookCellExecutionState(listener, thisArgs, disposables);
|
||||
},
|
||||
onDidChangeCellOutputs(listener, thisArgs?, disposables?) {
|
||||
checkProposedApiEnabled(extension, 'notebookEditor');
|
||||
|
||||
@@ -54,7 +54,8 @@ import { IRevealOptions, ITreeItem } from 'vs/workbench/common/views';
|
||||
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||
import { IAdapterDescriptor, IConfig, IDebugSessionReplMode } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import * as notebookCommon from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellExecutionUpdateType, ICellExecutionComplete, ICellExecutionStateUpdate } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
|
||||
import { CellExecutionUpdateType } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
|
||||
import { ICellExecutionComplete, ICellExecutionStateUpdate } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
||||
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange';
|
||||
import { OutputChannelUpdateMode } from 'vs/workbench/contrib/output/common/output';
|
||||
import { InputValidationType } from 'vs/workbench/contrib/scm/common/scm';
|
||||
@@ -922,7 +923,7 @@ export interface INotebookKernelDto2 {
|
||||
|
||||
export interface ICellExecuteOutputEditDto {
|
||||
editType: CellExecutionUpdateType.Output;
|
||||
executionHandle: number;
|
||||
uri: UriComponents;
|
||||
cellHandle: number;
|
||||
append?: boolean;
|
||||
outputs: NotebookOutputDto[]
|
||||
@@ -930,21 +931,24 @@ export interface ICellExecuteOutputEditDto {
|
||||
|
||||
export interface ICellExecuteOutputItemEditDto {
|
||||
editType: CellExecutionUpdateType.OutputItems;
|
||||
executionHandle: number;
|
||||
uri: UriComponents;
|
||||
cellHandle: number;
|
||||
append?: boolean;
|
||||
outputId: string;
|
||||
items: NotebookOutputItemDto[]
|
||||
}
|
||||
|
||||
export interface ICellExecutionStateUpdateDto extends ICellExecutionStateUpdate {
|
||||
executionHandle: number;
|
||||
uri: UriComponents;
|
||||
cellHandle: number;
|
||||
}
|
||||
|
||||
export interface ICellExecutionCompleteDto extends ICellExecutionComplete {
|
||||
executionHandle: number;
|
||||
uri: UriComponents;
|
||||
cellHandle: number;
|
||||
}
|
||||
|
||||
export type ICellExecuteUpdateDto = ICellExecuteOutputEditDto | ICellExecuteOutputItemEditDto | ICellExecutionStateUpdateDto | ICellExecutionCompleteDto;
|
||||
export type ICellExecuteUpdateDto = ICellExecuteOutputEditDto | ICellExecuteOutputItemEditDto | ICellExecutionStateUpdateDto;
|
||||
|
||||
export interface MainThreadNotebookKernelsShape extends IDisposable {
|
||||
$postMessage(handle: number, editorId: string | undefined, message: any): Promise<boolean>;
|
||||
@@ -953,9 +957,9 @@ export interface MainThreadNotebookKernelsShape extends IDisposable {
|
||||
$removeKernel(handle: number): void;
|
||||
$updateNotebookPriority(handle: number, uri: UriComponents, value: number | undefined): void;
|
||||
|
||||
$addExecution(handle: number, uri: UriComponents, cellHandle: number): void;
|
||||
$addExecution(uri: UriComponents, cellHandle: number): void;
|
||||
$updateExecutions(data: SerializableObjectWithBuffers<ICellExecuteUpdateDto[]>): void;
|
||||
$removeExecution(handle: number): void;
|
||||
$completeExecution(uri: UriComponents, cellHandle: number, data: SerializableObjectWithBuffers<ICellExecutionCompleteDto>): void;
|
||||
}
|
||||
|
||||
export interface MainThreadNotebookRenderersShape extends IDisposable {
|
||||
@@ -2088,6 +2092,7 @@ export interface ExtHostNotebookKernelsShape {
|
||||
$executeCells(handle: number, uri: UriComponents, handles: number[]): Promise<void>;
|
||||
$cancelCells(handle: number, uri: UriComponents, handles: number[]): Promise<void>;
|
||||
$acceptKernelMessageFromRenderer(handle: number, editorId: string, message: any): void;
|
||||
$cellExecutionChanged(uri: UriComponents, cellHandle: number, state: notebookCommon.NotebookCellExecutionState | undefined): void;
|
||||
}
|
||||
|
||||
export interface ExtHostInteractiveShape {
|
||||
|
||||
@@ -56,8 +56,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
|
||||
readonly onDidChangeCellMetadata = this._onDidChangeCellMetadata.event;
|
||||
private readonly _onDidChangeActiveNotebookEditor = new Emitter<vscode.NotebookEditor | undefined>();
|
||||
readonly onDidChangeActiveNotebookEditor = this._onDidChangeActiveNotebookEditor.event;
|
||||
private readonly _onDidChangeCellExecutionState = new Emitter<vscode.NotebookCellExecutionStateChangeEvent>();
|
||||
readonly onDidChangeNotebookCellExecutionState = this._onDidChangeCellExecutionState.event;
|
||||
|
||||
private _activeNotebookEditor: ExtHostNotebookEditor | undefined;
|
||||
get activeNotebookEditor(): vscode.NotebookEditor | undefined {
|
||||
@@ -459,9 +457,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
|
||||
},
|
||||
emitCellMetadataChange(event: vscode.NotebookCellMetadataChangeEvent): void {
|
||||
that._onDidChangeCellMetadata.fire(event);
|
||||
},
|
||||
emitCellExecutionStateChange(event: vscode.NotebookCellExecutionStateChangeEvent): void {
|
||||
that._onDidChangeCellExecutionState.fire(event);
|
||||
}
|
||||
},
|
||||
uri,
|
||||
|
||||
@@ -10,7 +10,6 @@ import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||
import { ExtHostDocumentsAndEditors, IExtHostModelAddedData } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
||||
import * as notebookCommon from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
@@ -129,7 +128,6 @@ export interface INotebookEventEmitter {
|
||||
emitModelChange(events: vscode.NotebookCellsChangeEvent): void;
|
||||
emitCellOutputsChange(event: vscode.NotebookCellOutputsChangeEvent): void;
|
||||
emitCellMetadataChange(event: vscode.NotebookCellMetadataChangeEvent): void;
|
||||
emitCellExecutionStateChange(event: vscode.NotebookCellExecutionStateChangeEvent): void;
|
||||
}
|
||||
|
||||
|
||||
@@ -373,14 +371,7 @@ export class ExtHostNotebookDocument {
|
||||
|
||||
private _changeCellInternalMetadata(index: number, newInternalMetadata: notebookCommon.NotebookCellInternalMetadata): void {
|
||||
const cell = this._cells[index];
|
||||
|
||||
const originalInternalMetadata = cell.internalMetadata;
|
||||
cell.setInternalMetadata(newInternalMetadata);
|
||||
|
||||
if (originalInternalMetadata.runState !== newInternalMetadata.runState) {
|
||||
const executionState = newInternalMetadata.runState ?? extHostTypes.NotebookCellExecutionState.Idle;
|
||||
this._emitter.emitCellExecutionStateChange(deepFreeze({ document: this.apiNotebook, cell: cell.apiCell, state: executionState }));
|
||||
}
|
||||
}
|
||||
|
||||
getCellFromApiCell(apiCell: vscode.NotebookCell): ExtHostCell | undefined {
|
||||
|
||||
@@ -18,8 +18,9 @@ import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitData
|
||||
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
|
||||
import { ExtHostCell, ExtHostNotebookDocument } from 'vs/workbench/api/common/extHostNotebookDocument';
|
||||
import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { NotebookCellOutput } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { NotebookCellOutput, NotebookCellExecutionState as ExtHostNotebookCellExecutionState } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { asWebviewUri } from 'vs/workbench/api/common/shared/webview';
|
||||
import { NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellExecutionUpdateType } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
|
||||
import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
@@ -46,6 +47,9 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
|
||||
private readonly _kernelData = new Map<number, IKernelData>();
|
||||
private _handlePool: number = 0;
|
||||
|
||||
private readonly _onDidChangeCellExecutionState = new Emitter<vscode.NotebookCellExecutionStateChangeEvent>();
|
||||
readonly onDidChangeNotebookCellExecutionState = this._onDidChangeCellExecutionState.event;
|
||||
|
||||
constructor(
|
||||
mainContext: IMainContext,
|
||||
private readonly _initData: IExtHostInitDataService,
|
||||
@@ -331,6 +335,17 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
|
||||
obj.onDidReceiveMessage.fire(Object.freeze({ editor: editor.apiEditor, message }));
|
||||
}
|
||||
|
||||
$cellExecutionChanged(uri: UriComponents, cellHandle: number, state: NotebookCellExecutionState | undefined): void {
|
||||
const document = this._extHostNotebook.getNotebookDocument(URI.revive(uri));
|
||||
const cell = document.getCell(cellHandle);
|
||||
if (cell) {
|
||||
this._onDidChangeCellExecutionState.fire({
|
||||
cell: cell.apiCell,
|
||||
state: state ?? ExtHostNotebookCellExecutionState.Idle
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
_createNotebookCellExecution(cell: vscode.NotebookCell): vscode.NotebookCellExecution {
|
||||
@@ -366,9 +381,6 @@ enum NotebookCellExecutionTaskState {
|
||||
}
|
||||
|
||||
class NotebookCellExecutionTask extends Disposable {
|
||||
private static HANDLE = 0;
|
||||
private _handle = NotebookCellExecutionTask.HANDLE++;
|
||||
|
||||
private _onDidChangeState = new Emitter<void>();
|
||||
readonly onDidChangeState = this._onDidChangeState.event;
|
||||
|
||||
@@ -391,7 +403,7 @@ class NotebookCellExecutionTask extends Disposable {
|
||||
this._collector = new TimeoutBasedCollector(10, updates => this.update(updates));
|
||||
|
||||
this._executionOrder = _cell.internalMetadata.executionOrder;
|
||||
this._proxy.$addExecution(this._handle, this._cell.notebook.uri, this._cell.handle);
|
||||
this._proxy.$addExecution(this._cell.notebook.uri, this._cell.handle);
|
||||
}
|
||||
|
||||
cancel(): void {
|
||||
@@ -448,7 +460,7 @@ class NotebookCellExecutionTask extends Disposable {
|
||||
return this.updateSoon(
|
||||
{
|
||||
editType: CellExecutionUpdateType.Output,
|
||||
executionHandle: this._handle,
|
||||
uri: this._document.uri,
|
||||
cellHandle: handle,
|
||||
append,
|
||||
outputs: outputDtos
|
||||
@@ -459,7 +471,8 @@ class NotebookCellExecutionTask extends Disposable {
|
||||
items = NotebookCellOutput.ensureUniqueMimeTypes(asArray(items), true);
|
||||
return this.updateSoon({
|
||||
editType: CellExecutionUpdateType.OutputItems,
|
||||
executionHandle: this._handle,
|
||||
uri: this._document.uri,
|
||||
cellHandle: this._cell.handle,
|
||||
items: items.map(extHostTypeConverters.NotebookCellOutputItem.from),
|
||||
outputId: output.id,
|
||||
append
|
||||
@@ -476,7 +489,8 @@ class NotebookCellExecutionTask extends Disposable {
|
||||
that._executionOrder = v;
|
||||
that.update([{
|
||||
editType: CellExecutionUpdateType.ExecutionState,
|
||||
executionHandle: that._handle,
|
||||
uri: that._document.uri,
|
||||
cellHandle: that._cell.handle,
|
||||
executionOrder: that._executionOrder
|
||||
}]);
|
||||
},
|
||||
@@ -491,7 +505,8 @@ class NotebookCellExecutionTask extends Disposable {
|
||||
|
||||
that.update({
|
||||
editType: CellExecutionUpdateType.ExecutionState,
|
||||
executionHandle: that._handle,
|
||||
uri: that._document.uri,
|
||||
cellHandle: that._cell.handle,
|
||||
runStartTime: startTime
|
||||
});
|
||||
},
|
||||
@@ -504,18 +519,16 @@ class NotebookCellExecutionTask extends Disposable {
|
||||
that._state = NotebookCellExecutionTaskState.Resolved;
|
||||
that._onDidChangeState.fire();
|
||||
|
||||
that.updateSoon({
|
||||
editType: CellExecutionUpdateType.Complete,
|
||||
executionHandle: that._handle,
|
||||
runEndTime: endTime,
|
||||
lastRunSuccess: success
|
||||
});
|
||||
|
||||
// The last update needs to be ordered correctly and applied immediately,
|
||||
// so we use updateSoon and immediately flush.
|
||||
that._collector.flush();
|
||||
|
||||
that._proxy.$removeExecution(that._handle);
|
||||
that._proxy.$completeExecution(that._document.uri, that._cell.handle, new SerializableObjectWithBuffers({
|
||||
uri: that._document.uri,
|
||||
cellHandle: that._cell.handle,
|
||||
runEndTime: endTime,
|
||||
lastRunSuccess: success
|
||||
}));
|
||||
},
|
||||
|
||||
clearOutput(cell?: vscode.NotebookCell): Thenable<void> {
|
||||
|
||||
@@ -57,6 +57,7 @@ import { INotebookEditorViewState } from 'vs/workbench/contrib/notebook/browser/
|
||||
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
|
||||
import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfiguration';
|
||||
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
||||
|
||||
const DECORATION_KEY = 'interactiveInputDecoration';
|
||||
const INTERACTIVE_EDITOR_VIEW_STATE_PREFERENCE_KEY = 'InteractiveEditorViewState';
|
||||
@@ -102,6 +103,7 @@ export class InteractiveEditor extends EditorPane {
|
||||
#menuService: IMenuService;
|
||||
#contextMenuService: IContextMenuService;
|
||||
#editorGroupService: IEditorGroupsService;
|
||||
#notebookExecutionStateService: INotebookExecutionStateService;
|
||||
#widgetDisposableStore: DisposableStore = this._register(new DisposableStore());
|
||||
#dimension?: DOM.Dimension;
|
||||
#notebookOptions: NotebookOptions;
|
||||
@@ -127,7 +129,8 @@ export class InteractiveEditor extends EditorPane {
|
||||
@IMenuService menuService: IMenuService,
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IEditorGroupsService editorGroupService: IEditorGroupsService,
|
||||
@ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService
|
||||
@ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService,
|
||||
@INotebookExecutionStateService notebookExecutionStateService: INotebookExecutionStateService
|
||||
) {
|
||||
super(
|
||||
InteractiveEditor.ID,
|
||||
@@ -145,8 +148,9 @@ export class InteractiveEditor extends EditorPane {
|
||||
this.#menuService = menuService;
|
||||
this.#contextMenuService = contextMenuService;
|
||||
this.#editorGroupService = editorGroupService;
|
||||
this.#notebookExecutionStateService = notebookExecutionStateService;
|
||||
|
||||
this.#notebookOptions = new NotebookOptions(configurationService, { cellToolbarInteraction: 'hover', globalToolbar: true, defaultCellCollapseConfig: { codeCell: { inputCollapsed: true } } });
|
||||
this.#notebookOptions = new NotebookOptions(configurationService, notebookExecutionStateService, { cellToolbarInteraction: 'hover', globalToolbar: true, defaultCellCollapseConfig: { codeCell: { inputCollapsed: true } } });
|
||||
this.#editorMemento = this.getEditorMemento<InteractiveEditorViewState>(editorGroupService, textResourceConfigurationService, INTERACTIVE_EDITOR_VIEW_STATE_PREFERENCE_KEY);
|
||||
|
||||
codeEditorService.registerDecorationType('interactive-decoration', DECORATION_KEY, {});
|
||||
@@ -566,8 +570,12 @@ export class InteractiveEditor extends EditorPane {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.#lastCell?.internalMetadata.runState === NotebookCellExecutionState.Executing) {
|
||||
return;
|
||||
if (this.#lastCell) {
|
||||
const runState = this.#notebookExecutionStateService.getCellExecutionState(this.#lastCell.uri)?.state;
|
||||
if (runState === NotebookCellExecutionState.Executing) {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// scroll to bottom
|
||||
|
||||
+36
-19
@@ -6,6 +6,7 @@
|
||||
import { disposableTimeout, RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { themeColorFromId } from 'vs/platform/theme/common/themeService';
|
||||
import { ICellVisibilityChangeEvent, NotebookVisibleCellObserver } from 'vs/workbench/contrib/notebook/browser/contrib/cellStatusBar/notebookVisibleCellObserver';
|
||||
import { formatCellDuration, ICellViewModel, INotebookEditor, INotebookEditorContribution } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
@@ -13,6 +14,7 @@ import { registerNotebookContribution } from 'vs/workbench/contrib/notebook/brow
|
||||
import { cellStatusIconError, cellStatusIconSuccess } from 'vs/workbench/contrib/notebook/browser/notebookEditorWidget';
|
||||
import { CellViewModel, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
|
||||
import { CellStatusbarAlignment, INotebookCellStatusBarItem, NotebookCellExecutionState, NotebookCellInternalMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { ICellExecutionEntry, INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
||||
|
||||
export class NotebookStatusBarController extends Disposable {
|
||||
private readonly _visibleCells = new Map<number, IDisposable>();
|
||||
@@ -20,7 +22,7 @@ export class NotebookStatusBarController extends Disposable {
|
||||
|
||||
constructor(
|
||||
private readonly _notebookEditor: INotebookEditor,
|
||||
private readonly _itemFactory: (vm: NotebookViewModel, cell: CellViewModel) => IDisposable
|
||||
private readonly _itemFactory: (vm: NotebookViewModel, cell: CellViewModel) => IDisposable,
|
||||
) {
|
||||
super();
|
||||
this._observer = this._register(new NotebookVisibleCellObserver(this._notebookEditor));
|
||||
@@ -62,9 +64,11 @@ export class NotebookStatusBarController extends Disposable {
|
||||
export class ExecutionStateCellStatusBarContrib extends Disposable implements INotebookEditorContribution {
|
||||
static id: string = 'workbench.notebook.statusBar.execState';
|
||||
|
||||
constructor(notebookEditor: INotebookEditor) {
|
||||
constructor(notebookEditor: INotebookEditor,
|
||||
@IInstantiationService instantiationService: IInstantiationService
|
||||
) {
|
||||
super();
|
||||
this._register(new NotebookStatusBarController(notebookEditor, (vm, cell) => new ExecutionStateCellStatusBarItem(vm, cell)));
|
||||
this._register(new NotebookStatusBarController(notebookEditor, (vm, cell) => instantiationService.createInstance(ExecutionStateCellStatusBarItem, vm, cell)));
|
||||
}
|
||||
}
|
||||
registerNotebookContribution(ExecutionStateCellStatusBarContrib.id, ExecutionStateCellStatusBarContrib);
|
||||
@@ -81,16 +85,22 @@ class ExecutionStateCellStatusBarItem extends Disposable {
|
||||
|
||||
constructor(
|
||||
private readonly _notebookViewModel: NotebookViewModel,
|
||||
private readonly _cell: ICellViewModel
|
||||
private readonly _cell: ICellViewModel,
|
||||
@INotebookExecutionStateService private readonly _executionStateService: INotebookExecutionStateService
|
||||
) {
|
||||
super();
|
||||
|
||||
this._update();
|
||||
this._register(this._executionStateService.onDidChangeCellExecution(e => {
|
||||
if (e.affectsCell(this._cell.model)) {
|
||||
this._update();
|
||||
}
|
||||
}));
|
||||
this._register(this._cell.model.onDidChangeInternalMetadata(() => this._update()));
|
||||
}
|
||||
|
||||
private async _update() {
|
||||
const items = this._getItemsForCell(this._cell);
|
||||
const items = this._getItemsForCell();
|
||||
if (Array.isArray(items)) {
|
||||
this._currentItemIds = this._notebookViewModel.deltaCellStatusBarItems(this._currentItemIds, [{ handle: this._cell.handle, items }]);
|
||||
}
|
||||
@@ -99,18 +109,20 @@ class ExecutionStateCellStatusBarItem extends Disposable {
|
||||
/**
|
||||
* Returns undefined if there should be no change, and an empty array if all items should be removed.
|
||||
*/
|
||||
private _getItemsForCell(cell: ICellViewModel): INotebookCellStatusBarItem[] | undefined {
|
||||
if (this._currentExecutingStateTimer && !cell.internalMetadata.isPaused) {
|
||||
private _getItemsForCell(): INotebookCellStatusBarItem[] | undefined {
|
||||
if (this._currentExecutingStateTimer && !this._cell.internalMetadata.isPaused) {
|
||||
return;
|
||||
}
|
||||
|
||||
const item = this._getItemForState(cell.internalMetadata);
|
||||
const runState = this._executionStateService.getCellExecutionState(this._cell.uri);
|
||||
const item = this._getItemForState(runState, this._cell.internalMetadata);
|
||||
|
||||
// Show the execution spinner for a minimum time
|
||||
if (cell.internalMetadata.runState === NotebookCellExecutionState.Executing) {
|
||||
if (runState?.state === NotebookCellExecutionState.Executing) {
|
||||
this._currentExecutingStateTimer = this._register(disposableTimeout(() => {
|
||||
const runState = this._executionStateService.getCellExecutionState(this._cell.uri);
|
||||
this._currentExecutingStateTimer = undefined;
|
||||
if (cell.internalMetadata.runState !== NotebookCellExecutionState.Executing) {
|
||||
if (runState?.state !== NotebookCellExecutionState.Executing) {
|
||||
this._update();
|
||||
}
|
||||
}, ExecutionStateCellStatusBarItem.MIN_SPINNER_TIME));
|
||||
@@ -119,9 +131,10 @@ class ExecutionStateCellStatusBarItem extends Disposable {
|
||||
return item ? [item] : [];
|
||||
}
|
||||
|
||||
private _getItemForState(internalMetadata: NotebookCellInternalMetadata): INotebookCellStatusBarItem | undefined {
|
||||
const { runState, lastRunSuccess, isPaused } = internalMetadata;
|
||||
if (!runState && lastRunSuccess) {
|
||||
private _getItemForState(runState: ICellExecutionEntry | undefined, internalMetadata: NotebookCellInternalMetadata): INotebookCellStatusBarItem | undefined {
|
||||
const state = runState?.state;
|
||||
const { lastRunSuccess, isPaused } = internalMetadata;
|
||||
if (!state && lastRunSuccess) {
|
||||
return <INotebookCellStatusBarItem>{
|
||||
text: '$(notebook-state-success)',
|
||||
color: themeColorFromId(cellStatusIconSuccess),
|
||||
@@ -129,7 +142,7 @@ class ExecutionStateCellStatusBarItem extends Disposable {
|
||||
alignment: CellStatusbarAlignment.Left,
|
||||
priority: Number.MAX_SAFE_INTEGER
|
||||
};
|
||||
} else if (!runState && lastRunSuccess === false) {
|
||||
} else if (!state && lastRunSuccess === false) {
|
||||
return <INotebookCellStatusBarItem>{
|
||||
text: '$(notebook-state-error)',
|
||||
color: themeColorFromId(cellStatusIconError),
|
||||
@@ -137,14 +150,14 @@ class ExecutionStateCellStatusBarItem extends Disposable {
|
||||
alignment: CellStatusbarAlignment.Left,
|
||||
priority: Number.MAX_SAFE_INTEGER
|
||||
};
|
||||
} else if (runState === NotebookCellExecutionState.Pending) {
|
||||
} else if (state === NotebookCellExecutionState.Pending) {
|
||||
return <INotebookCellStatusBarItem>{
|
||||
text: '$(notebook-state-pending)',
|
||||
tooltip: localize('notebook.cell.status.pending', "Pending"),
|
||||
alignment: CellStatusbarAlignment.Left,
|
||||
priority: Number.MAX_SAFE_INTEGER
|
||||
};
|
||||
} else if (runState === NotebookCellExecutionState.Executing) {
|
||||
} else if (state === NotebookCellExecutionState.Executing) {
|
||||
return <INotebookCellStatusBarItem>{
|
||||
text: `$(notebook-state-executing${isPaused ? '' : '~spin'})`,
|
||||
tooltip: localize('notebook.cell.status.executing', "Executing"),
|
||||
@@ -166,9 +179,11 @@ class ExecutionStateCellStatusBarItem extends Disposable {
|
||||
export class TimerCellStatusBarContrib extends Disposable implements INotebookEditorContribution {
|
||||
static id: string = 'workbench.notebook.statusBar.execTimer';
|
||||
|
||||
constructor(notebookEditor: INotebookEditor) {
|
||||
constructor(
|
||||
notebookEditor: INotebookEditor,
|
||||
@IInstantiationService instantiationService: IInstantiationService) {
|
||||
super();
|
||||
this._register(new NotebookStatusBarController(notebookEditor, (vm, cell) => new TimerCellStatusBarItem(vm, cell)));
|
||||
this._register(new NotebookStatusBarController(notebookEditor, (vm, cell) => instantiationService.createInstance(TimerCellStatusBarItem, vm, cell)));
|
||||
}
|
||||
}
|
||||
registerNotebookContribution(TimerCellStatusBarContrib.id, TimerCellStatusBarContrib);
|
||||
@@ -182,6 +197,7 @@ class TimerCellStatusBarItem extends Disposable {
|
||||
constructor(
|
||||
private readonly _notebookViewModel: NotebookViewModel,
|
||||
private readonly _cell: ICellViewModel,
|
||||
@INotebookExecutionStateService private readonly _executionStateService: INotebookExecutionStateService
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -192,7 +208,8 @@ class TimerCellStatusBarItem extends Disposable {
|
||||
|
||||
private async _update() {
|
||||
let item: INotebookCellStatusBarItem | undefined;
|
||||
const state = this._cell.internalMetadata.runState;
|
||||
const runState = this._executionStateService.getCellExecutionState(this._cell.uri);
|
||||
const state = runState?.state;
|
||||
if (this._cell.internalMetadata.isPaused) {
|
||||
item = undefined;
|
||||
} else if (state === NotebookCellExecutionState.Executing) {
|
||||
|
||||
@@ -25,6 +25,7 @@ import * as icons from 'vs/workbench/contrib/notebook/browser/notebookIcons';
|
||||
import { CellEditType, CellKind, ICellEditOperation, NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange';
|
||||
import { ILanguageDetectionService } from 'vs/workbench/services/languageDetection/common/languageDetectionWorkerService';
|
||||
import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
||||
|
||||
const CLEAR_ALL_CELLS_OUTPUTS_COMMAND_ID = 'notebook.clearAllCellsOutputs';
|
||||
const EDIT_CELL_COMMAND_ID = 'notebook.cell.edit';
|
||||
@@ -197,6 +198,7 @@ registerAction2(class ClearCellOutputsAction extends NotebookCellAction {
|
||||
}
|
||||
|
||||
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
|
||||
const notebookExecutionStateService = accessor.get(INotebookExecutionStateService);
|
||||
const editor = context.notebookEditor;
|
||||
if (!editor.hasModel() || !editor.textModel.length) {
|
||||
return;
|
||||
@@ -211,10 +213,10 @@ registerAction2(class ClearCellOutputsAction extends NotebookCellAction {
|
||||
|
||||
editor.textModel.applyEdits([{ editType: CellEditType.Output, index, outputs: [] }], true, undefined, () => undefined, undefined);
|
||||
|
||||
if (context.cell.internalMetadata.runState !== NotebookCellExecutionState.Executing) {
|
||||
const runState = notebookExecutionStateService.getCellExecutionState(context.cell.uri)?.state;
|
||||
if (runState !== NotebookCellExecutionState.Executing) {
|
||||
context.notebookEditor.textModel.applyEdits([{
|
||||
editType: CellEditType.PartialInternalMetadata, index, internalMetadata: {
|
||||
runState: null,
|
||||
runStartTime: null,
|
||||
runStartTimeAdjustment: null,
|
||||
runEndTime: null,
|
||||
@@ -258,6 +260,7 @@ registerAction2(class ClearAllCellOutputsAction extends NotebookAction {
|
||||
}
|
||||
|
||||
async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise<void> {
|
||||
const notebookExecutionStateService = accessor.get(INotebookExecutionStateService);
|
||||
const editor = context.notebookEditor;
|
||||
if (!editor.hasModel() || !editor.textModel.length) {
|
||||
return;
|
||||
@@ -269,10 +272,10 @@ registerAction2(class ClearAllCellOutputsAction extends NotebookAction {
|
||||
})), true, undefined, () => undefined, undefined);
|
||||
|
||||
const clearExecutionMetadataEdits = editor.textModel.cells.map((cell, index) => {
|
||||
if (cell.internalMetadata.runState !== NotebookCellExecutionState.Executing) {
|
||||
const runState = notebookExecutionStateService.getCellExecutionState(cell.uri)?.state;
|
||||
if (runState !== NotebookCellExecutionState.Executing) {
|
||||
return {
|
||||
editType: CellEditType.PartialInternalMetadata, index, internalMetadata: {
|
||||
runState: null,
|
||||
runStartTime: null,
|
||||
runStartTimeAdjustment: null,
|
||||
runEndTime: null,
|
||||
|
||||
@@ -16,7 +16,7 @@ import { insertCell } from 'vs/workbench/contrib/notebook/browser/controller/cel
|
||||
import { cellExecutionArgs, CellToolbarOrder, CELL_TITLE_CELL_GROUP_ID, executeNotebookCondition, getContextFromActiveEditor, getContextFromUri, INotebookActionContext, INotebookCellActionContext, INotebookCellToolbarActionContext, INotebookCommandContext, NotebookAction, NotebookCellAction, NotebookMultiCellAction, NOTEBOOK_EDITOR_WIDGET_ACTION_WEIGHT, parseMultiCellExecutionArgs } from 'vs/workbench/contrib/notebook/browser/controller/coreActions';
|
||||
import { CellEditState, CellFocusMode, EXECUTE_CELL_COMMAND_ID, NOTEBOOK_CELL_EXECUTING, NOTEBOOK_CELL_EXECUTION_STATE, NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_TYPE, NOTEBOOK_HAS_RUNNING_CELL, NOTEBOOK_INTERRUPTIBLE_KERNEL, NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_KERNEL_COUNT, NOTEBOOK_MISSING_KERNEL_EXTENSION } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import * as icons from 'vs/workbench/contrib/notebook/browser/notebookIcons';
|
||||
import { CellKind, NotebookCellExecutionState, NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellKind, NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebookEditorInput';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
@@ -65,9 +65,6 @@ async function runCell(accessor: ServicesAccessor, context: INotebookActionConte
|
||||
}
|
||||
|
||||
if (context.ui && context.cell) {
|
||||
if (context.cell.internalMetadata.runState === NotebookCellExecutionState.Executing) {
|
||||
return;
|
||||
}
|
||||
await context.notebookEditor.executeNotebookCells(Iterable.single(context.cell));
|
||||
if (context.autoReveal) {
|
||||
const cellIndex = context.notebookEditor.getCellIndex(context.cell);
|
||||
|
||||
@@ -41,6 +41,7 @@ import { BackLayerWebView, INotebookDelegateForWebview } from 'vs/workbench/cont
|
||||
import { NotebookDiffEditorEventDispatcher, NotebookDiffLayoutChangedEvent } from 'vs/workbench/contrib/notebook/browser/diff/eventDispatcher';
|
||||
import { FontMeasurements } from 'vs/editor/browser/config/fontMeasurements';
|
||||
import { NotebookOptions } from 'vs/workbench/contrib/notebook/common/notebookOptions';
|
||||
import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
||||
|
||||
const $ = DOM.$;
|
||||
|
||||
@@ -98,9 +99,10 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@INotebookExecutionStateService notebookExecutionStateService: INotebookExecutionStateService,
|
||||
) {
|
||||
super(NotebookTextDiffEditor.ID, telemetryService, themeService, storageService);
|
||||
this._notebookOptions = new NotebookOptions(this.configurationService);
|
||||
this._notebookOptions = new NotebookOptions(this.configurationService, notebookExecutionStateService);
|
||||
this._register(this._notebookOptions);
|
||||
const editorOptions = this.configurationService.getValue<ICodeEditorOptions>('editor');
|
||||
this._fontInfo = FontMeasurements.readFontInfo(BareFontInfo.createFromRawSettings(editorOptions, getZoomLevel(), getPixelRatio()));
|
||||
|
||||
@@ -95,12 +95,14 @@ import 'vs/workbench/contrib/notebook/browser/diff/notebookDiffActions';
|
||||
// Output renderers registration
|
||||
import 'vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform';
|
||||
import { editorOptionsRegistry } from 'vs/editor/common/config/editorOptions';
|
||||
import { NotebookExecutionStateService } from 'vs/workbench/contrib/notebook/browser/notebookExecutionStateServiceImpl';
|
||||
import { NotebookExecutionService } from 'vs/workbench/contrib/notebook/browser/notebookExecutionServiceImpl';
|
||||
import { INotebookExecutionService } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
|
||||
import { INotebookKeymapService } from 'vs/workbench/contrib/notebook/common/notebookKeymapService';
|
||||
import { NotebookKeymapService } from 'vs/workbench/contrib/notebook/browser/notebookKeymapServiceImpl';
|
||||
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
|
||||
import { PLAINTEXT_LANGUAGE_ID } from 'vs/editor/common/modes/modesRegistry';
|
||||
import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
||||
|
||||
/*--------------------------------------------------------------------------------------------- */
|
||||
|
||||
@@ -627,6 +629,7 @@ registerSingleton(INotebookCellStatusBarService, NotebookCellStatusBarService, t
|
||||
registerSingleton(INotebookEditorService, NotebookEditorWidgetService, true);
|
||||
registerSingleton(INotebookKernelService, NotebookKernelService, true);
|
||||
registerSingleton(INotebookExecutionService, NotebookExecutionService, true);
|
||||
registerSingleton(INotebookExecutionStateService, NotebookExecutionStateService, true);
|
||||
registerSingleton(INotebookRendererMessagingService, NotebookRendererMessagingService, true);
|
||||
registerSingleton(INotebookKeymapService, NotebookKeymapService, true);
|
||||
|
||||
|
||||
@@ -723,7 +723,6 @@ export enum CursorAtBoundary {
|
||||
export interface CellViewModelStateChangeEvent {
|
||||
readonly metadataChanged?: boolean;
|
||||
readonly internalMetadataChanged?: boolean;
|
||||
readonly runStateChanged?: boolean;
|
||||
readonly selectionChanged?: boolean;
|
||||
readonly focusModeChanged?: boolean;
|
||||
readonly editStateChanged?: boolean;
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ICellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { CellKind, INotebookTextModel, NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { INotebookKernel, INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
|
||||
import { IWorkspaceTrustRequestService } from 'vs/platform/workspace/common/workspaceTrust';
|
||||
import { SELECT_KERNEL_ID } from 'vs/workbench/contrib/notebook/browser/controller/coreActions';
|
||||
|
||||
export class NotebookEditorKernelManager extends Disposable {
|
||||
|
||||
constructor(
|
||||
@ICommandService private readonly _commandService: ICommandService,
|
||||
@INotebookKernelService private readonly _notebookKernelService: INotebookKernelService,
|
||||
@IWorkspaceTrustRequestService private readonly _workspaceTrustRequestService: IWorkspaceTrustRequestService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
getSelectedOrSuggestedKernel(notebook: INotebookTextModel): INotebookKernel | undefined {
|
||||
// returns SELECTED or the ONLY available kernel
|
||||
const info = this._notebookKernelService.getMatchingKernel(notebook);
|
||||
return info.selected ?? (info.all.length === 1 ? info.all[0] : undefined);
|
||||
}
|
||||
|
||||
async executeNotebookCells(notebook: INotebookTextModel, cells: Iterable<ICellViewModel>): Promise<void> {
|
||||
const message = nls.localize('notebookRunTrust', "Executing a notebook cell will run code from this workspace.");
|
||||
const trust = await this._workspaceTrustRequestService.requestWorkspaceTrust({ message });
|
||||
if (!trust) {
|
||||
return;
|
||||
}
|
||||
|
||||
let kernel = this.getSelectedOrSuggestedKernel(notebook);
|
||||
if (!kernel) {
|
||||
await this._commandService.executeCommand(SELECT_KERNEL_ID);
|
||||
kernel = this.getSelectedOrSuggestedKernel(notebook);
|
||||
}
|
||||
|
||||
if (!kernel) {
|
||||
return;
|
||||
}
|
||||
|
||||
const cellHandles: number[] = [];
|
||||
for (const cell of cells) {
|
||||
if (cell.cellKind !== CellKind.Code || cell.internalMetadata.runState === NotebookCellExecutionState.Pending || cell.internalMetadata.runState === NotebookCellExecutionState.Executing) {
|
||||
continue;
|
||||
}
|
||||
if (!kernel.supportedLanguages.includes(cell.language)) {
|
||||
continue;
|
||||
}
|
||||
cellHandles.push(cell.handle);
|
||||
}
|
||||
|
||||
if (cellHandles.length > 0) {
|
||||
this._notebookKernelService.selectKernelForNotebook(kernel, notebook);
|
||||
await kernel.executeNotebookCellsRequest(notebook.uri, cellHandles);
|
||||
}
|
||||
}
|
||||
|
||||
async cancelNotebookCells(notebook: INotebookTextModel, cells: Iterable<ICellViewModel>): Promise<void> {
|
||||
let kernel = this.getSelectedOrSuggestedKernel(notebook);
|
||||
if (kernel) {
|
||||
await kernel.cancelNotebookCellExecution(notebook.uri, Array.from(cells, cell => cell.handle));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
import { getPixelRatio, getZoomLevel } from 'vs/base/browser/browser';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import * as aria from 'vs/base/browser/ui/aria/aria';
|
||||
import { IMouseWheelEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import * as aria from 'vs/base/browser/ui/aria/aria';
|
||||
import { IListContextMenuEvent } from 'vs/base/browser/ui/list/list';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { SequencerByKey } from 'vs/base/common/async';
|
||||
@@ -18,11 +18,13 @@ import { extname, isEqual } from 'vs/base/common/resources';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import 'vs/css!./media/notebook';
|
||||
import { FontMeasurements } from 'vs/editor/browser/config/fontMeasurements';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { IEditor } from 'vs/editor/common/editorCommon';
|
||||
import { SuggestController } from 'vs/editor/contrib/suggest/suggestController';
|
||||
import * as nls from 'vs/nls';
|
||||
import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { IMenuService, MenuId } from 'vs/platform/actions/common/actions';
|
||||
@@ -32,45 +34,44 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
|
||||
import { registerZIndex, ZIndex } from 'vs/platform/layout/browser/zIndexRegistry';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { contrastBorder, diffInserted, diffRemoved, editorBackground, errorForeground, focusBorder, foreground, iconForeground, listInactiveSelectionBackground, registerColor, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, textBlockQuoteBackground, textBlockQuoteBorder, textLinkActiveForeground, textLinkForeground, textPreformatForeground, toolbarHoverBackground, transparent } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { PANEL_BORDER, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { debugIconStartForeground } from 'vs/workbench/contrib/debug/browser/debugColors';
|
||||
import { CellEditState, CellFocusMode, IActiveNotebookEditorDelegate, ICellOutputViewModel, ICellViewModel, ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IFocusNotebookCellOptions, IGenericCellViewModel, IInsetRenderOutput, INotebookCellOutputLayoutInfo, INotebookDeltaDecoration, INotebookEditorContribution, INotebookEditorContributionDescription, INotebookEditorCreationOptions, INotebookEditorDelegate, INotebookEditorMouseEvent, INotebookEditorOptions, NotebookCellStateChangedEvent, NotebookLayoutChangedEvent, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_OUTPUT_FOCUSED, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { NotebookDecorationCSSRules, NotebookRefCountedStyleSheet } from 'vs/workbench/contrib/notebook/browser/viewParts/notebookEditorDecorations';
|
||||
import { NotebookEditorContextKeys } from 'vs/workbench/contrib/notebook/browser/viewParts/notebookEditorWidgetContextKeys';
|
||||
import { NotebookEditorToolbar } from 'vs/workbench/contrib/notebook/browser/viewParts/notebookEditorToolbar';
|
||||
import { NotebookEditorExtensionsRegistry } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions';
|
||||
import { NotebookEditorKernelManager } from 'vs/workbench/contrib/notebook/browser/notebookEditorKernelManager';
|
||||
import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService';
|
||||
import { NotebookCellList, NOTEBOOK_WEBVIEW_BOUNDARY } from 'vs/workbench/contrib/notebook/browser/view/notebookCellList';
|
||||
import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer';
|
||||
import { BackLayerWebView, INotebookWebviewMessage } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView';
|
||||
import { notebookDebug } from 'vs/workbench/contrib/notebook/browser/notebookLogger';
|
||||
import { CellContextKeyManager } from 'vs/workbench/contrib/notebook/browser/view/cellParts/cellContextKeys';
|
||||
import { CellDragAndDropController } from 'vs/workbench/contrib/notebook/browser/view/cellParts/cellDnd';
|
||||
import { NotebookCellList, NOTEBOOK_WEBVIEW_BOUNDARY } from 'vs/workbench/contrib/notebook/browser/view/notebookCellList';
|
||||
import { INotebookCellList } from 'vs/workbench/contrib/notebook/browser/view/notebookRenderingCommon';
|
||||
import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer';
|
||||
import { BackLayerWebView, INotebookWebviewMessage } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView';
|
||||
import { CodeCellRenderer, MarkupCellRenderer, NotebookCellListDelegate } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer';
|
||||
import { IAckOutputHeight, IMarkupCellInitialization } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages';
|
||||
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
|
||||
import { NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher';
|
||||
import { MarkupCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markupCellViewModel';
|
||||
import { CellViewModel, IModelDecorationsChangeAccessor, INotebookEditorViewState, INotebookViewCellsUpdateEvent, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
|
||||
import { ViewContext } from 'vs/workbench/contrib/notebook/browser/viewModel/viewContext';
|
||||
import { NotebookDecorationCSSRules, NotebookRefCountedStyleSheet } from 'vs/workbench/contrib/notebook/browser/viewParts/notebookEditorDecorations';
|
||||
import { NotebookEditorToolbar } from 'vs/workbench/contrib/notebook/browser/viewParts/notebookEditorToolbar';
|
||||
import { NotebookEditorContextKeys } from 'vs/workbench/contrib/notebook/browser/viewParts/notebookEditorWidgetContextKeys';
|
||||
import { ListTopCellToolbar } from 'vs/workbench/contrib/notebook/browser/viewParts/notebookTopCellToolbar';
|
||||
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
|
||||
import { CellKind, SelectionStateType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange';
|
||||
import { editorGutterModifiedBackground } from 'vs/workbench/contrib/scm/browser/dirtydiffDecorator';
|
||||
import { IWebview } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
import { mark } from 'vs/workbench/contrib/notebook/common/notebookPerformance';
|
||||
import { FontMeasurements } from 'vs/editor/browser/config/fontMeasurements';
|
||||
import { INotebookExecutionService } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
|
||||
import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
||||
import { INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
|
||||
import { NotebookOptions, OutputInnerContainerTopPadding } from 'vs/workbench/contrib/notebook/common/notebookOptions';
|
||||
import { ViewContext } from 'vs/workbench/contrib/notebook/browser/viewModel/viewContext';
|
||||
import { mark } from 'vs/workbench/contrib/notebook/common/notebookPerformance';
|
||||
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange';
|
||||
import { INotebookRendererMessagingService } from 'vs/workbench/contrib/notebook/common/notebookRendererMessagingService';
|
||||
import { IAckOutputHeight, IMarkupCellInitialization } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewMessages';
|
||||
import { SuggestController } from 'vs/editor/contrib/suggest/suggestController';
|
||||
import { registerZIndex, ZIndex } from 'vs/platform/layout/browser/zIndexRegistry';
|
||||
import { INotebookCellList } from 'vs/workbench/contrib/notebook/browser/view/notebookRenderingCommon';
|
||||
import { notebookDebug } from 'vs/workbench/contrib/notebook/browser/notebookLogger';
|
||||
import { ListTopCellToolbar } from 'vs/workbench/contrib/notebook/browser/viewParts/notebookTopCellToolbar';
|
||||
import { editorGutterModifiedBackground } from 'vs/workbench/contrib/scm/browser/dirtydiffDecorator';
|
||||
import { IWebview } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
|
||||
const $ = DOM.$;
|
||||
|
||||
@@ -323,7 +324,6 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
|
||||
protected readonly _contributions = new Map<string, INotebookEditorContribution>();
|
||||
private _scrollBeyondLastLine: boolean;
|
||||
private readonly _insetModifyQueueByOutputId = new SequencerByKey<string>();
|
||||
private _kernelManger: NotebookEditorKernelManager;
|
||||
private _cellContextKeyManager: CellContextKeyManager | null = null;
|
||||
private _isVisible = false;
|
||||
private readonly _uuid = generateUuid();
|
||||
@@ -399,13 +399,15 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
|
||||
@IContextMenuService private readonly contextMenuService: IContextMenuService,
|
||||
@IMenuService private readonly menuService: IMenuService,
|
||||
@IThemeService private readonly themeService: IThemeService,
|
||||
@ITelemetryService private readonly telemetryService: ITelemetryService
|
||||
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
||||
@INotebookExecutionService private readonly notebookExecutionService: INotebookExecutionService,
|
||||
@INotebookExecutionStateService notebookExecutionStateService: INotebookExecutionStateService,
|
||||
) {
|
||||
super();
|
||||
this.isEmbedded = creationOptions.isEmbedded ?? false;
|
||||
this._readOnly = creationOptions.isReadOnly ?? false;
|
||||
|
||||
this._notebookOptions = creationOptions.options ?? new NotebookOptions(this.configurationService);
|
||||
this._notebookOptions = creationOptions.options ?? new NotebookOptions(this.configurationService, notebookExecutionStateService);
|
||||
this._register(this._notebookOptions);
|
||||
this._viewContext = new ViewContext(this._notebookOptions, new NotebookEventDispatcher());
|
||||
this._register(this._viewContext.eventDispatcher.onDidChangeCellState(e => {
|
||||
@@ -418,7 +420,6 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
|
||||
|
||||
this._register(this.instantiationService.createInstance(NotebookEditorContextKeys, this));
|
||||
|
||||
this._kernelManger = this.instantiationService.createInstance(NotebookEditorKernelManager);
|
||||
this._register(notebookKernelService.onDidChangeSelectedNotebooks(e => {
|
||||
if (isEqual(e.notebook, this.viewModel?.uri)) {
|
||||
this._loadKernelPreloads();
|
||||
@@ -2052,7 +2053,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
|
||||
}
|
||||
|
||||
get activeKernel() {
|
||||
return this.textModel && this._kernelManger.getSelectedOrSuggestedKernel(this.textModel);
|
||||
return this.textModel && this.notebookExecutionService.getSelectedOrSuggestedKernel(this.textModel);
|
||||
}
|
||||
|
||||
async cancelNotebookCells(cells?: Iterable<ICellViewModel>): Promise<void> {
|
||||
@@ -2062,7 +2063,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
|
||||
if (!cells) {
|
||||
cells = this.viewModel.viewCells;
|
||||
}
|
||||
return this._kernelManger.cancelNotebookCells(this.textModel, cells);
|
||||
return this.notebookExecutionService.cancelNotebookCellHandles(this.textModel, Array.from(cells).map(cell => cell.handle));
|
||||
}
|
||||
|
||||
async executeNotebookCells(cells?: Iterable<ICellViewModel>): Promise<void> {
|
||||
@@ -2072,7 +2073,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
|
||||
if (!cells) {
|
||||
cells = this.viewModel.viewCells;
|
||||
}
|
||||
return this._kernelManger.executeNotebookCells(this.textModel, cells);
|
||||
return this.notebookExecutionService.executeNotebookCells(this.textModel, Array.from(cells).map(c => c.model));
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
@@ -3,127 +3,83 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import * as nls from 'vs/nls';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IWorkspaceTrustRequestService } from 'vs/platform/workspace/common/workspaceTrust';
|
||||
import { SELECT_KERNEL_ID } from 'vs/workbench/contrib/notebook/browser/controller/coreActions';
|
||||
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
|
||||
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
|
||||
import { CellEditType, ICellEditOperation, NotebookCellExecutionState, NotebookCellInternalMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellExecutionUpdateType, ICellExecuteUpdate, INotebookCellExecution, INotebookExecutionService } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
|
||||
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
|
||||
import { CellKind, INotebookTextModel } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { INotebookExecutionService } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
|
||||
import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
||||
import { INotebookKernel, INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
|
||||
|
||||
export class NotebookExecutionService implements INotebookExecutionService {
|
||||
declare _serviceBrand: undefined;
|
||||
|
||||
constructor(
|
||||
@INotebookService private readonly _notebookService: INotebookService,
|
||||
@ICommandService private readonly _commandService: ICommandService,
|
||||
@INotebookKernelService private readonly _notebookKernelService: INotebookKernelService,
|
||||
@IWorkspaceTrustRequestService private readonly _workspaceTrustRequestService: IWorkspaceTrustRequestService,
|
||||
@ILogService private readonly _logService: ILogService,
|
||||
@INotebookExecutionStateService private readonly _notebookExecutionStateService: INotebookExecutionStateService
|
||||
) {
|
||||
}
|
||||
|
||||
createNotebookCellExecution(notebook: URI, cellHandle: number): INotebookCellExecution {
|
||||
return new CellExecution(notebook, cellHandle, this._notebookService);
|
||||
getSelectedOrSuggestedKernel(notebook: INotebookTextModel): INotebookKernel | undefined {
|
||||
// TODO later can be inlined in notebookEditorWidget
|
||||
// returns SELECTED or the ONLY available kernel
|
||||
const info = this._notebookKernelService.getMatchingKernel(notebook);
|
||||
return info.selected ?? (info.all.length === 1 ? info.all[0] : undefined);
|
||||
}
|
||||
}
|
||||
|
||||
function updateToEdit(update: ICellExecuteUpdate, cellHandle: number, model: NotebookCellTextModel): ICellEditOperation {
|
||||
if (update.editType === CellExecutionUpdateType.Output) {
|
||||
return {
|
||||
editType: CellEditType.Output,
|
||||
handle: update.cellHandle,
|
||||
append: update.append,
|
||||
outputs: update.outputs,
|
||||
};
|
||||
} else if (update.editType === CellExecutionUpdateType.OutputItems) {
|
||||
return {
|
||||
editType: CellEditType.OutputItems,
|
||||
items: update.items,
|
||||
append: update.append,
|
||||
outputId: update.outputId
|
||||
};
|
||||
} else if (update.editType === CellExecutionUpdateType.Complete) {
|
||||
return {
|
||||
editType: CellEditType.PartialInternalMetadata,
|
||||
handle: cellHandle,
|
||||
internalMetadata: {
|
||||
runState: null,
|
||||
lastRunSuccess: update.lastRunSuccess,
|
||||
runStartTime: model.internalMetadata.didPause ? null : model.internalMetadata.runStartTime,
|
||||
runEndTime: model.internalMetadata.didPause ? null : update.runEndTime,
|
||||
isPaused: false,
|
||||
didPause: false
|
||||
async executeNotebookCells(notebook: INotebookTextModel, cells: Iterable<NotebookCellTextModel>): Promise<void> {
|
||||
const cellsArr = Array.from(cells);
|
||||
this._logService.debug(`NotebookExecutionService#executeNotebookCells ${JSON.stringify(cellsArr.map(c => c.handle))}`);
|
||||
const message = nls.localize('notebookRunTrust', "Executing a notebook cell will run code from this workspace.");
|
||||
const trust = await this._workspaceTrustRequestService.requestWorkspaceTrust({ message });
|
||||
if (!trust) {
|
||||
return;
|
||||
}
|
||||
|
||||
let kernel = this.getSelectedOrSuggestedKernel(notebook);
|
||||
if (!kernel) {
|
||||
await this._commandService.executeCommand(SELECT_KERNEL_ID);
|
||||
kernel = this.getSelectedOrSuggestedKernel(notebook);
|
||||
}
|
||||
|
||||
if (!kernel) {
|
||||
return;
|
||||
}
|
||||
|
||||
const cellHandles: number[] = [];
|
||||
for (const cell of cellsArr) {
|
||||
const cellExe = this._notebookExecutionStateService.getCellExecutionState(cell.uri);
|
||||
if (cell.cellKind !== CellKind.Code || !!cellExe) {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
} else if (update.editType === CellExecutionUpdateType.ExecutionState) {
|
||||
const newInternalMetadata: Partial<NotebookCellInternalMetadata> = {
|
||||
runState: NotebookCellExecutionState.Executing,
|
||||
};
|
||||
if (typeof update.executionOrder !== 'undefined') {
|
||||
newInternalMetadata.executionOrder = update.executionOrder;
|
||||
}
|
||||
if (typeof update.runStartTime !== 'undefined') {
|
||||
newInternalMetadata.runStartTime = update.runStartTime;
|
||||
}
|
||||
return {
|
||||
editType: CellEditType.PartialInternalMetadata,
|
||||
handle: cellHandle,
|
||||
internalMetadata: newInternalMetadata
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error('Unknown cell update type');
|
||||
}
|
||||
|
||||
class CellExecution implements INotebookCellExecution, IDisposable {
|
||||
private readonly _notebookModel: NotebookTextModel;
|
||||
|
||||
private _isDisposed = false;
|
||||
|
||||
constructor(
|
||||
readonly notebook: URI,
|
||||
readonly cellHandle: number,
|
||||
private readonly _notebookService: INotebookService,
|
||||
) {
|
||||
const notebookModel = this._notebookService.getNotebookTextModel(notebook);
|
||||
if (!notebookModel) {
|
||||
throw new Error('Notebook not found: ' + notebook);
|
||||
}
|
||||
|
||||
this._notebookModel = notebookModel;
|
||||
|
||||
const startExecuteEdit: ICellEditOperation = {
|
||||
editType: CellEditType.PartialInternalMetadata,
|
||||
handle: cellHandle,
|
||||
internalMetadata: {
|
||||
runState: NotebookCellExecutionState.Pending,
|
||||
executionOrder: null,
|
||||
didPause: false
|
||||
if (!kernel.supportedLanguages.includes(cell.language)) {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
this._applyExecutionEdits([startExecuteEdit]);
|
||||
}
|
||||
|
||||
update(updates: ICellExecuteUpdate[]): void {
|
||||
if (this._isDisposed) {
|
||||
throw new Error('Cannot update disposed execution');
|
||||
cellHandles.push(cell.handle);
|
||||
}
|
||||
|
||||
const cellModel = this._notebookModel.cells.find(c => c.handle === this.cellHandle);
|
||||
if (!cellModel) {
|
||||
throw new Error('Cell not found: ' + this.cellHandle);
|
||||
}
|
||||
|
||||
const edits = updates.map(update => updateToEdit(update, this.cellHandle, cellModel));
|
||||
this._applyExecutionEdits(edits);
|
||||
|
||||
if (updates.some(u => u.editType === CellExecutionUpdateType.Complete)) {
|
||||
this.dispose();
|
||||
if (cellHandles.length > 0) {
|
||||
this._notebookKernelService.selectKernelForNotebook(kernel, notebook);
|
||||
await kernel.executeNotebookCellsRequest(notebook.uri, cellHandles);
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._isDisposed = true;
|
||||
async cancelNotebookCellHandles(notebook: INotebookTextModel, cells: Iterable<number>): Promise<void> {
|
||||
const cellsArr = Array.from(cells);
|
||||
this._logService.debug(`NotebookExecutionService#cancelNotebookCellHandles ${JSON.stringify(cellsArr)}`);
|
||||
const kernel = this.getSelectedOrSuggestedKernel(notebook);
|
||||
if (kernel) {
|
||||
await kernel.cancelNotebookCellExecution(notebook.uri, cellsArr);
|
||||
}
|
||||
}
|
||||
|
||||
private _applyExecutionEdits(edits: ICellEditOperation[]): void {
|
||||
this._notebookModel.applyEdits(edits, true, undefined, () => undefined, undefined, false);
|
||||
async cancelNotebookCells(notebook: INotebookTextModel, cells: Iterable<NotebookCellTextModel>): Promise<void> {
|
||||
this.cancelNotebookCellHandles(notebook, Array.from(cells, cell => cell.handle));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,347 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ResourceMap } from 'vs/base/common/map';
|
||||
import { isEqual } from 'vs/base/common/resources';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
|
||||
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
|
||||
import { CellEditType, CellUri, ICellEditOperation, NotebookCellExecutionState, NotebookCellInternalMetadata, NotebookTextModelWillAddRemoveEvent } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellExecutionUpdateType, INotebookExecutionService } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
|
||||
import { ICellExecuteUpdate, ICellExecutionComplete, ICellExecutionEntry, ICellExecutionStateChangedEvent, INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
||||
import { INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
|
||||
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
|
||||
|
||||
export class NotebookExecutionStateService extends Disposable implements INotebookExecutionStateService {
|
||||
declare _serviceBrand: undefined;
|
||||
|
||||
private readonly _executions = new ResourceMap<NotebookExecution>();
|
||||
|
||||
private readonly _onDidChangeCellExecution = new Emitter<ICellExecutionStateChangedEvent>();
|
||||
onDidChangeCellExecution = this._onDidChangeCellExecution.event;
|
||||
|
||||
constructor(
|
||||
@INotebookKernelService private readonly _notebookKernelService: INotebookKernelService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@ILogService private readonly _logService: ILogService,
|
||||
) {
|
||||
super();
|
||||
|
||||
this._register(this._notebookKernelService.onDidChangeSelectedNotebooks(e => {
|
||||
if (e.newKernel) {
|
||||
const notebookExecution = this._executions.get(e.notebook);
|
||||
if (notebookExecution) {
|
||||
notebookExecution.cancelAll();
|
||||
this.checkNotebookExecutionEmpty(e.notebook);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
getCellExecutionState(cellUri: URI): ICellExecutionEntry | undefined {
|
||||
const parsed = CellUri.parse(cellUri);
|
||||
if (!parsed) {
|
||||
throw new Error(`Not a cell URI: ${cellUri}`);
|
||||
}
|
||||
|
||||
const exe = this._executions.get(parsed.notebook);
|
||||
if (exe) {
|
||||
return exe.getCellExecution(parsed.handle);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getCellExecutionStatesForNotebook(notebook: URI): ICellExecutionEntry[] {
|
||||
const exe = this._executions.get(notebook);
|
||||
return (exe?.getCellExecutions() ?? []);
|
||||
}
|
||||
|
||||
createNotebookCellExecution(notebook: URI, cellHandle: number): void {
|
||||
let notebookExecution = this._executions.get(notebook);
|
||||
if (!notebookExecution) {
|
||||
notebookExecution = this._instantiationService.createInstance(NotebookExecution, notebook);
|
||||
this._executions.set(notebook, notebookExecution);
|
||||
}
|
||||
|
||||
const exe = notebookExecution.addExecution(cellHandle);
|
||||
this._onDidChangeCellExecution.fire(new NotebookExecutionEvent(notebook, cellHandle, exe));
|
||||
}
|
||||
|
||||
updateNotebookCellExecution(notebook: URI, cellHandle: number, updates: ICellExecuteUpdate[]): void {
|
||||
const notebookExecution = this._executions.get(notebook);
|
||||
if (!notebookExecution) {
|
||||
this._logService.error(`notebook execution not found for ${notebook}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const exe = notebookExecution.updateExecution(cellHandle, updates);
|
||||
if (exe) {
|
||||
this._onDidChangeCellExecution.fire(new NotebookExecutionEvent(notebook, cellHandle, exe));
|
||||
}
|
||||
}
|
||||
|
||||
completeNotebookCellExecution(notebook: URI, cellHandle: number, complete: ICellExecutionComplete): void {
|
||||
const notebookExecution = this._executions.get(notebook);
|
||||
if (!notebookExecution) {
|
||||
this._logService.error(`notebook execution not found for ${notebook}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const exe = notebookExecution.completeExecution(cellHandle, complete);
|
||||
if (exe) {
|
||||
this.checkNotebookExecutionEmpty(notebook);
|
||||
this._onDidChangeCellExecution.fire(new NotebookExecutionEvent(notebook, cellHandle));
|
||||
}
|
||||
}
|
||||
|
||||
private checkNotebookExecutionEmpty(notebook: URI): void {
|
||||
const notebookExecution = this._executions.get(notebook);
|
||||
if (!notebookExecution) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (notebookExecution.isEmpty()) {
|
||||
this._logService.debug(`NotebookExecution#dispose ${notebook.toString()}`);
|
||||
notebookExecution.dispose();
|
||||
this._executions.delete(notebook);
|
||||
}
|
||||
}
|
||||
|
||||
override dispose(): void {
|
||||
super.dispose();
|
||||
this._executions.forEach(e => e.dispose());
|
||||
this._executions.clear();
|
||||
}
|
||||
}
|
||||
|
||||
class NotebookExecutionEvent implements ICellExecutionStateChangedEvent {
|
||||
constructor(
|
||||
readonly notebook: URI,
|
||||
readonly cellHandle: number,
|
||||
readonly changed?: CellExecution
|
||||
) { }
|
||||
|
||||
affectsCell(cell: NotebookCellTextModel): boolean {
|
||||
const parsedUri = CellUri.parse(cell.uri);
|
||||
return !!parsedUri && isEqual(this.notebook, parsedUri.notebook) && this.cellHandle === parsedUri.handle;
|
||||
}
|
||||
}
|
||||
|
||||
class NotebookExecution extends Disposable {
|
||||
private readonly _notebookModel: NotebookTextModel;
|
||||
|
||||
private readonly _cellExecutions = new Map<number, CellExecution>();
|
||||
|
||||
constructor(
|
||||
notebook: URI,
|
||||
@INotebookService private readonly _notebookService: INotebookService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@INotebookExecutionService private readonly _notebookExecutionService: INotebookExecutionService,
|
||||
@ILogService private readonly _logService: ILogService,
|
||||
) {
|
||||
super();
|
||||
this._logService.debug(`NotebookExecution#ctor ${notebook.toString()}`);
|
||||
|
||||
const notebookModel = this._notebookService.getNotebookTextModel(notebook);
|
||||
if (!notebookModel) {
|
||||
throw new Error('Notebook not found: ' + notebook);
|
||||
}
|
||||
|
||||
this._notebookModel = notebookModel;
|
||||
this._register(this._notebookModel.onWillAddRemoveCells(e => this.onWillAddRemoveCells(e)));
|
||||
this._register(this._notebookModel.onWillDispose(() => this.onWillDisposeDocument()));
|
||||
}
|
||||
|
||||
getCellExecution(cellHandle: number): CellExecution | undefined {
|
||||
return this._cellExecutions.get(cellHandle);
|
||||
}
|
||||
|
||||
getCellExecutions(): CellExecution[] {
|
||||
return Array.from(this._cellExecutions.values());
|
||||
}
|
||||
|
||||
private getCellLog(cellHandle: number): string {
|
||||
return `${this._notebookModel.uri.toString()}, ${cellHandle}`;
|
||||
}
|
||||
|
||||
isEmpty(): boolean {
|
||||
return this._cellExecutions.size === 0;
|
||||
}
|
||||
|
||||
cancelAll(): void {
|
||||
this._logService.debug(`NotebookExecution#cancelAll`);
|
||||
this._notebookExecutionService.cancelNotebookCellHandles(this._notebookModel, this._cellExecutions.keys());
|
||||
}
|
||||
|
||||
addExecution(cellHandle: number): CellExecution {
|
||||
this._logService.debug(`NotebookExecution#addExecution ${this.getCellLog(cellHandle)}`);
|
||||
const execution = this._instantiationService.createInstance(CellExecution, cellHandle, this._notebookModel);
|
||||
this._cellExecutions.set(cellHandle, execution);
|
||||
return execution;
|
||||
}
|
||||
|
||||
updateExecution(cellHandle: number, updates: ICellExecuteUpdate[]): CellExecution | undefined {
|
||||
this.logUpdates(cellHandle, updates);
|
||||
const execution = this._cellExecutions.get(cellHandle);
|
||||
if (!execution) {
|
||||
this._logService.error(`no execution for cell ${cellHandle}`);
|
||||
return;
|
||||
}
|
||||
|
||||
execution.update(updates);
|
||||
return execution;
|
||||
}
|
||||
|
||||
private logUpdates(cellHandle: number, updates: ICellExecuteUpdate[]): void {
|
||||
const updateTypes = updates.map(u => CellExecutionUpdateType[u.editType]).join(', ');
|
||||
this._logService.debug(`NotebookExecution#updateExecution ${this.getCellLog(cellHandle)}, [${updateTypes}]`);
|
||||
}
|
||||
|
||||
completeExecution(cellHandle: number, complete: ICellExecutionComplete): CellExecution | undefined {
|
||||
this._logService.debug(`NotebookExecution#completeExecution ${this.getCellLog(cellHandle)}`);
|
||||
|
||||
const execution = this._cellExecutions.get(cellHandle);
|
||||
if (!execution) {
|
||||
this._logService.error(`no execution for cell ${cellHandle}`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
execution.complete(complete);
|
||||
return execution;
|
||||
} finally {
|
||||
this._cellExecutions.delete(cellHandle);
|
||||
}
|
||||
}
|
||||
|
||||
private onWillDisposeDocument(): void {
|
||||
this._logService.debug(`NotebookExecution#onWillDisposeDocument`);
|
||||
this.cancelAll();
|
||||
}
|
||||
|
||||
private onWillAddRemoveCells(e: NotebookTextModelWillAddRemoveEvent): void {
|
||||
const handles = new Set(this._cellExecutions.keys());
|
||||
const myDeletedHandles = new Set<number>();
|
||||
e.rawEvent.changes.forEach(([start, deleteCount]) => {
|
||||
if (deleteCount) {
|
||||
const deletedHandles = this._notebookModel.cells.slice(start, start + deleteCount).map(c => c.handle);
|
||||
deletedHandles.forEach(h => {
|
||||
if (handles.has(h)) {
|
||||
myDeletedHandles.add(h);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if (myDeletedHandles.size) {
|
||||
this._logService.debug(`NotebookExecution#onWillAddRemoveCells, ${JSON.stringify([...myDeletedHandles])}`);
|
||||
this._notebookExecutionService.cancelNotebookCellHandles(this._notebookModel, myDeletedHandles);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateToEdit(update: ICellExecuteUpdate, cellHandle: number): ICellEditOperation {
|
||||
if (update.editType === CellExecutionUpdateType.Output) {
|
||||
return {
|
||||
editType: CellEditType.Output,
|
||||
handle: update.cellHandle,
|
||||
append: update.append,
|
||||
outputs: update.outputs,
|
||||
};
|
||||
} else if (update.editType === CellExecutionUpdateType.OutputItems) {
|
||||
return {
|
||||
editType: CellEditType.OutputItems,
|
||||
items: update.items,
|
||||
append: update.append,
|
||||
outputId: update.outputId
|
||||
};
|
||||
} else if (update.editType === CellExecutionUpdateType.ExecutionState) {
|
||||
const newInternalMetadata: Partial<NotebookCellInternalMetadata> = { };
|
||||
if (typeof update.executionOrder !== 'undefined') {
|
||||
newInternalMetadata.executionOrder = update.executionOrder;
|
||||
}
|
||||
if (typeof update.runStartTime !== 'undefined') {
|
||||
newInternalMetadata.runStartTime = update.runStartTime;
|
||||
}
|
||||
return {
|
||||
editType: CellEditType.PartialInternalMetadata,
|
||||
handle: cellHandle,
|
||||
internalMetadata: newInternalMetadata
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error('Unknown cell update type');
|
||||
}
|
||||
|
||||
class CellExecution implements ICellExecutionEntry {
|
||||
private _state: NotebookCellExecutionState = NotebookCellExecutionState.Pending;
|
||||
get state() {
|
||||
return this._state;
|
||||
}
|
||||
|
||||
get notebook(): URI {
|
||||
return this._notebookModel.uri;
|
||||
}
|
||||
|
||||
constructor(
|
||||
readonly cellHandle: number,
|
||||
private readonly _notebookModel: NotebookTextModel,
|
||||
@ILogService private readonly _logService: ILogService,
|
||||
) {
|
||||
const startExecuteEdit: ICellEditOperation = {
|
||||
editType: CellEditType.PartialInternalMetadata,
|
||||
handle: this.cellHandle,
|
||||
internalMetadata: {
|
||||
runStartTime: null,
|
||||
runEndTime: null,
|
||||
lastRunSuccess: null,
|
||||
executionOrder: null,
|
||||
didPause: false
|
||||
}
|
||||
};
|
||||
this._applyExecutionEdits([startExecuteEdit]);
|
||||
}
|
||||
|
||||
update(updates: ICellExecuteUpdate[]): void {
|
||||
if (updates.some(u => u.editType === CellExecutionUpdateType.ExecutionState)) {
|
||||
this._state = NotebookCellExecutionState.Executing;
|
||||
}
|
||||
|
||||
const edits = updates.map(update => updateToEdit(update, this.cellHandle));
|
||||
this._applyExecutionEdits(edits);
|
||||
}
|
||||
|
||||
complete(completionData: ICellExecutionComplete): void {
|
||||
const cellModel = this._notebookModel.cells.find(c => c.handle === this.cellHandle);
|
||||
if (!cellModel) {
|
||||
this._logService.debug(`CellExecution#complete, updating cell not in notebook: ${this._notebookModel.uri.toString()}, ${this.cellHandle}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const edit: ICellEditOperation = {
|
||||
editType: CellEditType.PartialInternalMetadata,
|
||||
handle: this.cellHandle,
|
||||
internalMetadata: {
|
||||
lastRunSuccess: completionData.lastRunSuccess,
|
||||
runStartTime: cellModel.internalMetadata.didPause ? null : cellModel.internalMetadata.runStartTime,
|
||||
runEndTime: cellModel.internalMetadata.didPause ? null : completionData.runEndTime,
|
||||
isPaused: false,
|
||||
didPause: false
|
||||
}
|
||||
};
|
||||
this._applyExecutionEdits([edit]);
|
||||
}
|
||||
|
||||
private _applyExecutionEdits(edits: ICellEditOperation[]): void {
|
||||
this._notebookModel.applyEdits(edits, true, undefined, () => undefined, undefined, false);
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import { CellEditState, CellFocusMode, CellViewModelStateChangeEvent, ICellViewM
|
||||
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
|
||||
import { MarkupCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markupCellViewModel';
|
||||
import { NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
||||
|
||||
export class CellContextKeyManager extends Disposable {
|
||||
|
||||
@@ -30,25 +31,32 @@ export class CellContextKeyManager extends Disposable {
|
||||
constructor(
|
||||
private readonly notebookEditor: INotebookEditorDelegate,
|
||||
private element: ICellViewModel,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
|
||||
@INotebookExecutionStateService private readonly _notebookExecutionStateService: INotebookExecutionStateService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.contextKeyService.bufferChangeEvents(() => {
|
||||
this.cellType = NOTEBOOK_CELL_TYPE.bindTo(this.contextKeyService);
|
||||
this.cellEditable = NOTEBOOK_CELL_EDITABLE.bindTo(this.contextKeyService);
|
||||
this.cellFocused = NOTEBOOK_CELL_FOCUSED.bindTo(this.contextKeyService);
|
||||
this.cellEditorFocused = NOTEBOOK_CELL_EDITOR_FOCUSED.bindTo(this.contextKeyService);
|
||||
this.markdownEditMode = NOTEBOOK_CELL_MARKDOWN_EDIT_MODE.bindTo(this.contextKeyService);
|
||||
this.cellRunState = NOTEBOOK_CELL_EXECUTION_STATE.bindTo(this.contextKeyService);
|
||||
this.cellExecuting = NOTEBOOK_CELL_EXECUTING.bindTo(this.contextKeyService);
|
||||
this.cellHasOutputs = NOTEBOOK_CELL_HAS_OUTPUTS.bindTo(this.contextKeyService);
|
||||
this.cellContentCollapsed = NOTEBOOK_CELL_INPUT_COLLAPSED.bindTo(this.contextKeyService);
|
||||
this.cellOutputCollapsed = NOTEBOOK_CELL_OUTPUT_COLLAPSED.bindTo(this.contextKeyService);
|
||||
this.cellLineNumbers = NOTEBOOK_CELL_LINE_NUMBERS.bindTo(this.contextKeyService);
|
||||
this._contextKeyService.bufferChangeEvents(() => {
|
||||
this.cellType = NOTEBOOK_CELL_TYPE.bindTo(this._contextKeyService);
|
||||
this.cellEditable = NOTEBOOK_CELL_EDITABLE.bindTo(this._contextKeyService);
|
||||
this.cellFocused = NOTEBOOK_CELL_FOCUSED.bindTo(this._contextKeyService);
|
||||
this.cellEditorFocused = NOTEBOOK_CELL_EDITOR_FOCUSED.bindTo(this._contextKeyService);
|
||||
this.markdownEditMode = NOTEBOOK_CELL_MARKDOWN_EDIT_MODE.bindTo(this._contextKeyService);
|
||||
this.cellRunState = NOTEBOOK_CELL_EXECUTION_STATE.bindTo(this._contextKeyService);
|
||||
this.cellExecuting = NOTEBOOK_CELL_EXECUTING.bindTo(this._contextKeyService);
|
||||
this.cellHasOutputs = NOTEBOOK_CELL_HAS_OUTPUTS.bindTo(this._contextKeyService);
|
||||
this.cellContentCollapsed = NOTEBOOK_CELL_INPUT_COLLAPSED.bindTo(this._contextKeyService);
|
||||
this.cellOutputCollapsed = NOTEBOOK_CELL_OUTPUT_COLLAPSED.bindTo(this._contextKeyService);
|
||||
this.cellLineNumbers = NOTEBOOK_CELL_LINE_NUMBERS.bindTo(this._contextKeyService);
|
||||
|
||||
this.updateForElement(element);
|
||||
});
|
||||
|
||||
this._register(this._notebookExecutionStateService.onDidChangeCellExecution(e => {
|
||||
if (e.affectsCell(this.element.model)) {
|
||||
this.updateForExecutionState();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public updateForElement(element: ICellViewModel) {
|
||||
@@ -68,9 +76,9 @@ export class CellContextKeyManager extends Disposable {
|
||||
this.cellType.set('code');
|
||||
}
|
||||
|
||||
this.contextKeyService.bufferChangeEvents(() => {
|
||||
this._contextKeyService.bufferChangeEvents(() => {
|
||||
this.updateForFocusState();
|
||||
this.updateForInternalMetadata();
|
||||
this.updateForExecutionState();
|
||||
this.updateForEditState();
|
||||
this.updateForCollapseState();
|
||||
this.updateForOutputs();
|
||||
@@ -80,9 +88,9 @@ export class CellContextKeyManager extends Disposable {
|
||||
}
|
||||
|
||||
private onDidChangeState(e: CellViewModelStateChangeEvent) {
|
||||
this.contextKeyService.bufferChangeEvents(() => {
|
||||
this._contextKeyService.bufferChangeEvents(() => {
|
||||
if (e.internalMetadataChanged) {
|
||||
this.updateForInternalMetadata();
|
||||
this.updateForExecutionState();
|
||||
}
|
||||
|
||||
if (e.editStateChanged) {
|
||||
@@ -115,18 +123,18 @@ export class CellContextKeyManager extends Disposable {
|
||||
|
||||
}
|
||||
|
||||
private updateForInternalMetadata() {
|
||||
private updateForExecutionState() {
|
||||
const internalMetadata = this.element.internalMetadata;
|
||||
this.cellEditable.set(!this.notebookEditor.isReadOnly);
|
||||
|
||||
const runState = internalMetadata.runState;
|
||||
const exeState = this._notebookExecutionStateService.getCellExecutionState(this.element.uri);
|
||||
if (this.element instanceof MarkupCellViewModel) {
|
||||
this.cellRunState.reset();
|
||||
this.cellExecuting.reset();
|
||||
} else if (runState === NotebookCellExecutionState.Executing) {
|
||||
} else if (exeState?.state === NotebookCellExecutionState.Executing) {
|
||||
this.cellRunState.set('executing');
|
||||
this.cellExecuting.set(true);
|
||||
} else if (runState === NotebookCellExecutionState.Pending) {
|
||||
} else if (exeState?.state === NotebookCellExecutionState.Pending) {
|
||||
this.cellRunState.set('pending');
|
||||
this.cellExecuting.set(true);
|
||||
} else if (internalMetadata.lastRunSuccess === true) {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { deepClone } from 'vs/base/common/objects';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IEditorOptions, LineNumbersType } from 'vs/editor/common/config/editorOptions';
|
||||
import { localize } from 'vs/nls';
|
||||
import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
@@ -133,20 +134,27 @@ export class CellEditorOptions extends CellPart {
|
||||
return computed;
|
||||
}
|
||||
|
||||
getUpdatedValue(internalMetadata?: NotebookCellInternalMetadata): IEditorOptions {
|
||||
const options = this.getValue(internalMetadata);
|
||||
getUpdatedValue(internalMetadata: NotebookCellInternalMetadata, cellUri: URI): IEditorOptions {
|
||||
const options = this.getValue(internalMetadata, cellUri);
|
||||
delete options.hover; // This is toggled by a debug editor contribution
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
getValue(internalMetadata?: NotebookCellInternalMetadata): IEditorOptions {
|
||||
getValue(internalMetadata: NotebookCellInternalMetadata, cellUri: URI): IEditorOptions {
|
||||
return {
|
||||
...this._value,
|
||||
...{
|
||||
padding: internalMetadata ?
|
||||
this.notebookOptions.computeEditorPadding(internalMetadata) :
|
||||
{ top: 12, bottom: 12 }
|
||||
padding: this.notebookOptions.computeEditorPadding(internalMetadata, cellUri)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
getDefaultValue(): IEditorOptions {
|
||||
return {
|
||||
...this._value,
|
||||
...{
|
||||
padding: { top: 12, bottom: 12 }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { CellViewModelStateChangeEvent, ICellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { BaseCellRenderTemplate } from 'vs/workbench/contrib/notebook/browser/view/notebookRenderingCommon';
|
||||
import { ICellExecutionStateChangedEvent } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
||||
|
||||
export abstract class CellPart extends Disposable {
|
||||
constructor() {
|
||||
@@ -33,4 +34,9 @@ export abstract class CellPart extends Disposable {
|
||||
* Update per cell state change
|
||||
*/
|
||||
abstract updateState(element: ICellViewModel, e: CellViewModelStateChangeEvent): void;
|
||||
|
||||
/**
|
||||
* Update per execution state change.
|
||||
*/
|
||||
updateForExecutionState(element: ICellViewModel, e: ICellExecutionStateChangedEvent): void { }
|
||||
}
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';
|
||||
import { ICellViewModel, CellViewModelStateChangeEvent } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { CellViewModelStateChangeEvent, ICellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { CellPart } from 'vs/workbench/contrib/notebook/browser/view/cellParts/cellPart';
|
||||
import { NotebookCellExecutionState, NotebookCellInternalMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { ICellExecutionStateChangedEvent, INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
||||
|
||||
export class CellProgressBar extends CellPart {
|
||||
private readonly _progressBar: ProgressBar;
|
||||
@@ -14,7 +15,8 @@ export class CellProgressBar extends CellPart {
|
||||
|
||||
constructor(
|
||||
editorContainer: HTMLElement,
|
||||
collapsedInputContainer: HTMLElement) {
|
||||
collapsedInputContainer: HTMLElement,
|
||||
@INotebookExecutionStateService private readonly _notebookExecutionStateService: INotebookExecutionStateService) {
|
||||
super();
|
||||
|
||||
this._progressBar = this._register(new ProgressBar(editorContainer));
|
||||
@@ -25,7 +27,7 @@ export class CellProgressBar extends CellPart {
|
||||
}
|
||||
|
||||
renderCell(element: ICellViewModel): void {
|
||||
this.updateForInternalMetadata(element, element.internalMetadata);
|
||||
this._updateForExecutionState(element);
|
||||
}
|
||||
|
||||
prepareLayout(): void {
|
||||
@@ -36,29 +38,35 @@ export class CellProgressBar extends CellPart {
|
||||
// nothing to update
|
||||
}
|
||||
|
||||
override updateForExecutionState(element: ICellViewModel, e: ICellExecutionStateChangedEvent): void {
|
||||
this._updateForExecutionState(element, e);
|
||||
}
|
||||
|
||||
updateState(element: ICellViewModel, e: CellViewModelStateChangeEvent): void {
|
||||
if (e.metadataChanged || e.internalMetadataChanged) {
|
||||
this.updateForInternalMetadata(element, element.internalMetadata);
|
||||
this._updateForExecutionState(element);
|
||||
}
|
||||
|
||||
if (e.inputCollapsedChanged) {
|
||||
const exeState = this._notebookExecutionStateService.getCellExecutionState(element.uri);
|
||||
if (element.isInputCollapsed) {
|
||||
this._progressBar.hide();
|
||||
if (element.internalMetadata.runState === NotebookCellExecutionState.Executing) {
|
||||
if (exeState?.state === NotebookCellExecutionState.Executing) {
|
||||
showProgressBar(this._collapsedProgressBar);
|
||||
}
|
||||
} else {
|
||||
this._collapsedProgressBar.hide();
|
||||
if (element.internalMetadata.runState === NotebookCellExecutionState.Executing) {
|
||||
if (exeState?.state === NotebookCellExecutionState.Executing) {
|
||||
showProgressBar(this._progressBar);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateForInternalMetadata(element: ICellViewModel, internalMetadata: NotebookCellInternalMetadata): void {
|
||||
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 (internalMetadata.runState === NotebookCellExecutionState.Executing && !internalMetadata.isPaused) {
|
||||
if (exeState?.state === NotebookCellExecutionState.Executing && !element.internalMetadata.isPaused) {
|
||||
showProgressBar(progressBar);
|
||||
} else {
|
||||
progressBar.hide();
|
||||
|
||||
@@ -104,7 +104,7 @@ export class CellEditorStatusBar extends CellPart {
|
||||
|
||||
updateInternalLayoutNow(element: ICellViewModel): void {
|
||||
// todo@rebornix layer breaker
|
||||
this._cellContainer.classList.toggle('cell-statusbar-hidden', this._notebookEditor.notebookOptions.computeEditorStatusbarHeight(element.internalMetadata) === 0);
|
||||
this._cellContainer.classList.toggle('cell-statusbar-hidden', this._notebookEditor.notebookOptions.computeEditorStatusbarHeight(element.internalMetadata, element.uri) === 0);
|
||||
|
||||
const layoutInfo = element.layoutInfo;
|
||||
const width = layoutInfo.editorWidth;
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { raceCancellation } from 'vs/base/common/async';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { Codicon, CSSIcon } from 'vs/base/common/codicons';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { IDimension } from 'vs/editor/common/editorCommon';
|
||||
@@ -15,18 +15,19 @@ import { IReadonlyTextBuffer } from 'vs/editor/common/model';
|
||||
import { tokenizeToStringSync } from 'vs/editor/common/modes/textToHtmlTokenizer';
|
||||
import { ILanguageService } from 'vs/editor/common/services/language';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { CellFocusMode, EXPAND_CELL_INPUT_COMMAND_ID, IActiveNotebookEditorDelegate } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { CodeCellRenderTemplate } from 'vs/workbench/contrib/notebook/browser/view/notebookRenderingCommon';
|
||||
import { CellEditorOptions } from 'vs/workbench/contrib/notebook/browser/view/cellParts/cellEditorOptions';
|
||||
import { CellOutputContainer } from 'vs/workbench/contrib/notebook/browser/view/cellParts/cellOutput';
|
||||
import { CellPart } from 'vs/workbench/contrib/notebook/browser/view/cellParts/cellPart';
|
||||
import { ClickTargetType } from 'vs/workbench/contrib/notebook/browser/view/cellParts/cellWidgets';
|
||||
import { CodeCellRenderTemplate } from 'vs/workbench/contrib/notebook/browser/view/notebookRenderingCommon';
|
||||
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
|
||||
import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService';
|
||||
import { CellPart } from 'vs/workbench/contrib/notebook/browser/view/cellParts/cellPart';
|
||||
import { CellEditorOptions } from 'vs/workbench/contrib/notebook/browser/view/cellParts/cellEditorOptions';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
||||
|
||||
|
||||
export class CodeCell extends Disposable {
|
||||
@@ -49,6 +50,7 @@ export class CodeCell extends Disposable {
|
||||
@IOpenerService readonly openerService: IOpenerService,
|
||||
@ILanguageService readonly languageService: ILanguageService,
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@INotebookExecutionStateService notebookExecutionStateService: INotebookExecutionStateService
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -64,6 +66,14 @@ export class CodeCell extends Disposable {
|
||||
this.registerDecorations();
|
||||
this.registerMouseListener();
|
||||
|
||||
this._register(notebookExecutionStateService.onDidChangeCellExecution(e => {
|
||||
if (e.affectsCell(this.viewCell.model)) {
|
||||
this.cellParts.forEach(cellPart => {
|
||||
cellPart.updateForExecutionState(this.viewCell, e);
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this.viewCell.onDidChangeState(e => {
|
||||
this.cellParts.forEach(cellPart => {
|
||||
cellPart.updateState(this.viewCell, e);
|
||||
@@ -121,8 +131,8 @@ export class CodeCell extends Disposable {
|
||||
this._register(Event.runAndSubscribe(viewCell.onDidChangeOutputs, this.updateForOutputs.bind(this)));
|
||||
this._register(Event.runAndSubscribe(viewCell.onDidChangeLayout, this.updateForLayout.bind(this)));
|
||||
|
||||
this._register(cellEditorOptions.onDidChange(() => templateData.editor.updateOptions(cellEditorOptions.getUpdatedValue(this.viewCell.internalMetadata))));
|
||||
templateData.editor.updateOptions(cellEditorOptions.getUpdatedValue(this.viewCell.internalMetadata));
|
||||
this._register(cellEditorOptions.onDidChange(() => templateData.editor.updateOptions(cellEditorOptions.getUpdatedValue(this.viewCell.internalMetadata, this.viewCell.uri))));
|
||||
templateData.editor.updateOptions(cellEditorOptions.getUpdatedValue(this.viewCell.internalMetadata, this.viewCell.uri));
|
||||
cellEditorOptions.setLineNumbers(this.viewCell.lineNumbers);
|
||||
}
|
||||
|
||||
@@ -148,7 +158,7 @@ export class CodeCell extends Disposable {
|
||||
private calculateInitEditorHeight() {
|
||||
const lineNum = this.viewCell.lineCount;
|
||||
const lineHeight = this.viewCell.layoutInfo.fontInfo?.lineHeight || 17;
|
||||
const editorPadding = this.notebookEditor.notebookOptions.computeEditorPadding(this.viewCell.internalMetadata);
|
||||
const editorPadding = this.notebookEditor.notebookOptions.computeEditorPadding(this.viewCell.internalMetadata, this.viewCell.uri);
|
||||
const editorHeight = this.viewCell.layoutInfo.editorHeight === 0
|
||||
? lineNum * lineHeight + editorPadding.top + editorPadding.bottom
|
||||
: this.viewCell.layoutInfo.editorHeight;
|
||||
@@ -210,10 +220,10 @@ export class CodeCell extends Disposable {
|
||||
}
|
||||
|
||||
const isReadonly = this.notebookEditor.isReadOnly;
|
||||
const padding = this.notebookEditor.notebookOptions.computeEditorPadding(this.viewCell.internalMetadata);
|
||||
const padding = this.notebookEditor.notebookOptions.computeEditorPadding(this.viewCell.internalMetadata, this.viewCell.uri);
|
||||
const options = editor.getOptions();
|
||||
if (options.get(EditorOption.readOnly) !== isReadonly || options.get(EditorOption.padding) !== padding) {
|
||||
editor.updateOptions({ readOnly: this.notebookEditor.isReadOnly, padding: this.notebookEditor.notebookOptions.computeEditorPadding(this.viewCell.internalMetadata) });
|
||||
editor.updateOptions({ readOnly: this.notebookEditor.isReadOnly, padding: this.notebookEditor.notebookOptions.computeEditorPadding(this.viewCell.internalMetadata, this.viewCell.uri) });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,7 +326,7 @@ export class CodeCell extends Disposable {
|
||||
// Mouse click handlers
|
||||
this._register(this.templateData.statusBar.onDidClick(e => {
|
||||
if (e.type !== ClickTargetType.ContributedCommandItem) {
|
||||
const target = this.templateData.editor.getTargetAtClientPoint(e.event.clientX, e.event.clientY - this.notebookEditor.notebookOptions.computeEditorStatusbarHeight(this.viewCell.internalMetadata));
|
||||
const target = this.templateData.editor.getTargetAtClientPoint(e.event.clientX, e.event.clientY - this.notebookEditor.notebookOptions.computeEditorStatusbarHeight(this.viewCell.internalMetadata, this.viewCell.uri));
|
||||
if (target?.position) {
|
||||
this.templateData.editor.setPosition(target.position);
|
||||
this.templateData.editor.focus();
|
||||
|
||||
@@ -62,7 +62,7 @@ export class StatefulMarkdownCell extends Disposable {
|
||||
|
||||
this.cellEditorOptions = this._register(new CellEditorOptions(this.notebookEditor, this.notebookEditor.notebookOptions, this.configurationService, this.viewCell.language));
|
||||
this.cellEditorOptions.setLineNumbers(this.viewCell.lineNumbers);
|
||||
this.editorOptions = this.cellEditorOptions.getValue(this.viewCell.internalMetadata);
|
||||
this.editorOptions = this.cellEditorOptions.getValue(this.viewCell.internalMetadata, this.viewCell.uri);
|
||||
|
||||
this._register(toDisposable(() => renderedEditors.delete(this.viewCell)));
|
||||
this.registerListeners();
|
||||
@@ -172,7 +172,7 @@ export class StatefulMarkdownCell extends Disposable {
|
||||
}));
|
||||
|
||||
this._register(this.cellEditorOptions.onDidChange(() => {
|
||||
this.updateEditorOptions(this.cellEditorOptions.getUpdatedValue(this.viewCell.internalMetadata));
|
||||
this.updateEditorOptions(this.cellEditorOptions.getUpdatedValue(this.viewCell.internalMetadata, this.viewCell.uri));
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -298,7 +298,7 @@ export class StatefulMarkdownCell extends Disposable {
|
||||
const width = this.notebookEditor.notebookOptions.computeMarkdownCellEditorWidth(this.notebookEditor.getLayoutInfo().width);
|
||||
const lineNum = this.viewCell.lineCount;
|
||||
const lineHeight = this.viewCell.layoutInfo.fontInfo?.lineHeight || 17;
|
||||
const editorPadding = this.notebookEditor.notebookOptions.computeEditorPadding(this.viewCell.internalMetadata);
|
||||
const editorPadding = this.notebookEditor.notebookOptions.computeEditorPadding(this.viewCell.internalMetadata, this.viewCell.uri);
|
||||
editorHeight = Math.max(lineNum, 1) * lineHeight + editorPadding.top + editorPadding.bottom;
|
||||
|
||||
this.templateData.editorContainer.innerText = '';
|
||||
|
||||
@@ -396,7 +396,7 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
|
||||
EditorContextKeys.inCompositeEditor.bindTo(editorContextKeyService).set(true);
|
||||
|
||||
const editor = editorInstaService.createInstance(CodeEditorWidget, editorContainer, {
|
||||
...this.editorOptions.getValue(),
|
||||
...this.editorOptions.getDefaultValue(),
|
||||
dimension: {
|
||||
width: 0,
|
||||
height: 0
|
||||
@@ -408,7 +408,7 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
|
||||
|
||||
templateDisposables.add(editor);
|
||||
|
||||
const progressBar = templateDisposables.add(new CellProgressBar(editorPart, cellInputCollapsedContainer));
|
||||
const progressBar = templateDisposables.add(this.instantiationService.createInstance(CellProgressBar, editorPart, cellInputCollapsedContainer));
|
||||
|
||||
const statusBar = templateDisposables.add(this.instantiationService.createInstance(CellEditorStatusBar, this.notebookEditor, container, editorPart));
|
||||
|
||||
|
||||
@@ -188,8 +188,8 @@ export abstract class BaseCellViewModel extends Disposable {
|
||||
}));
|
||||
|
||||
this._register(model.onDidChangeInternalMetadata(e => {
|
||||
this._onDidChangeState.fire({ internalMetadataChanged: true, runStateChanged: e.runStateChanged });
|
||||
if (e.runStateChanged || e.lastRunSuccessChanged) {
|
||||
this._onDidChangeState.fire({ internalMetadataChanged: true });
|
||||
if (e.lastRunSuccessChanged) {
|
||||
// Statusbar visibility may change
|
||||
this.layoutChange({});
|
||||
}
|
||||
@@ -473,7 +473,7 @@ export abstract class BaseCellViewModel extends Disposable {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const editorPadding = this._viewContext.notebookOptions.computeEditorPadding(this.internalMetadata);
|
||||
const editorPadding = this._viewContext.notebookOptions.computeEditorPadding(this.internalMetadata, this.uri);
|
||||
return this._textEditor.getTopForLineNumber(line) + editorPadding.top;
|
||||
}
|
||||
|
||||
@@ -482,7 +482,7 @@ export abstract class BaseCellViewModel extends Disposable {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const editorPadding = this._viewContext.notebookOptions.computeEditorPadding(this.internalMetadata);
|
||||
const editorPadding = this._viewContext.notebookOptions.computeEditorPadding(this.internalMetadata, this.uri);
|
||||
return this._textEditor.getTopForPosition(line, column) + editorPadding.top;
|
||||
}
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
|
||||
newState = CellLayoutState.Estimated;
|
||||
}
|
||||
|
||||
const statusbarHeight = this.viewContext.notebookOptions.computeEditorStatusbarHeight(this.internalMetadata);
|
||||
const statusbarHeight = this.viewContext.notebookOptions.computeEditorStatusbarHeight(this.internalMetadata, this.uri);
|
||||
const indicatorHeight = editorHeight + statusbarHeight + outputTotalHeight + outputShowMoreContainerHeight;
|
||||
const outputContainerOffset = notebookLayoutConfiguration.editorToolbarHeight
|
||||
+ notebookLayoutConfiguration.cellTopMargin // CELL_TOP_MARGIN
|
||||
@@ -314,7 +314,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
|
||||
}
|
||||
|
||||
const verticalScrollbarHeight = hasScrolling ? 12 : 0; // take zoom level into account
|
||||
const editorPadding = this.viewContext.notebookOptions.computeEditorPadding(this.internalMetadata);
|
||||
const editorPadding = this.viewContext.notebookOptions.computeEditorPadding(this.internalMetadata, this.uri);
|
||||
return this.lineCount * lineHeight
|
||||
+ editorPadding.top
|
||||
+ editorPadding.bottom // EDITOR_BOTTOM_PADDING
|
||||
@@ -327,7 +327,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
|
||||
return layoutConfiguration.editorToolbarHeight
|
||||
+ layoutConfiguration.cellTopMargin
|
||||
+ editorHeight
|
||||
+ this.viewContext.notebookOptions.computeEditorStatusbarHeight(this.internalMetadata)
|
||||
+ this.viewContext.notebookOptions.computeEditorStatusbarHeight(this.internalMetadata, this.uri)
|
||||
+ outputsTotalHeight
|
||||
+ outputShowMoreContainerHeight
|
||||
+ bottomToolbarGap
|
||||
|
||||
+14
-28
@@ -5,9 +5,8 @@
|
||||
|
||||
import { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ICellViewModel, KERNEL_EXTENSIONS, NOTEBOOK_MISSING_KERNEL_EXTENSION, NOTEBOOK_HAS_OUTPUTS, NOTEBOOK_HAS_RUNNING_CELL, NOTEBOOK_INTERRUPTIBLE_KERNEL, NOTEBOOK_KERNEL_COUNT, NOTEBOOK_KERNEL_SELECTED, NOTEBOOK_USE_CONSOLIDATED_OUTPUT_BUTTON, NOTEBOOK_VIEW_TYPE, INotebookEditorDelegate, NOTEBOOK_CELL_TOOLBAR_LOCATION } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
|
||||
import { NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { ICellViewModel, INotebookEditorDelegate, KERNEL_EXTENSIONS, NOTEBOOK_CELL_TOOLBAR_LOCATION, NOTEBOOK_HAS_OUTPUTS, NOTEBOOK_HAS_RUNNING_CELL, NOTEBOOK_INTERRUPTIBLE_KERNEL, NOTEBOOK_KERNEL_COUNT, NOTEBOOK_KERNEL_SELECTED, NOTEBOOK_MISSING_KERNEL_EXTENSION, NOTEBOOK_USE_CONSOLIDATED_OUTPUT_BUTTON, NOTEBOOK_VIEW_TYPE } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
||||
import { INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
|
||||
@@ -25,14 +24,14 @@ export class NotebookEditorContextKeys {
|
||||
|
||||
private readonly _disposables = new DisposableStore();
|
||||
private readonly _viewModelDisposables = new DisposableStore();
|
||||
private readonly _cellStateListeners: IDisposable[] = [];
|
||||
private readonly _cellOutputsListeners: IDisposable[] = [];
|
||||
|
||||
constructor(
|
||||
private readonly _editor: INotebookEditorDelegate,
|
||||
@INotebookKernelService private readonly _notebookKernelService: INotebookKernelService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IExtensionService private readonly _extensionService: IExtensionService
|
||||
@IExtensionService private readonly _extensionService: IExtensionService,
|
||||
@INotebookExecutionStateService private readonly _notebookExecutionStateService: INotebookExecutionStateService
|
||||
) {
|
||||
this._notebookKernelCount = NOTEBOOK_KERNEL_COUNT.bindTo(contextKeyService);
|
||||
this._notebookKernelSelected = NOTEBOOK_KERNEL_SELECTED.bindTo(contextKeyService);
|
||||
@@ -52,6 +51,7 @@ export class NotebookEditorContextKeys {
|
||||
this._disposables.add(_notebookKernelService.onDidChangeSelectedNotebooks(this._updateKernelContext, this));
|
||||
this._disposables.add(_editor.notebookOptions.onDidChangeOptions(this._updateForNotebookOptions, this));
|
||||
this._disposables.add(_extensionService.onDidChangeExtensions(this._updateForInstalledExtension, this));
|
||||
this._disposables.add(_notebookExecutionStateService.onDidChangeCellExecution(this._updateForCellExecution, this));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
@@ -61,8 +61,6 @@ export class NotebookEditorContextKeys {
|
||||
this._interruptibleKernel.reset();
|
||||
this._someCellRunning.reset();
|
||||
this._viewType.reset();
|
||||
dispose(this._cellStateListeners);
|
||||
this._cellStateListeners.length = 0;
|
||||
dispose(this._cellOutputsListeners);
|
||||
this._cellOutputsListeners.length = 0;
|
||||
}
|
||||
@@ -73,8 +71,6 @@ export class NotebookEditorContextKeys {
|
||||
this._updateForNotebookOptions();
|
||||
|
||||
this._viewModelDisposables.clear();
|
||||
dispose(this._cellStateListeners);
|
||||
this._cellStateListeners.length = 0;
|
||||
dispose(this._cellOutputsListeners);
|
||||
this._cellOutputsListeners.length = 0;
|
||||
|
||||
@@ -82,22 +78,6 @@ export class NotebookEditorContextKeys {
|
||||
return;
|
||||
}
|
||||
|
||||
let executionCount = 0;
|
||||
|
||||
const addCellStateListener = (c: ICellViewModel) => {
|
||||
return (c as CellViewModel).onDidChangeState(e => {
|
||||
if (!e.runStateChanged) {
|
||||
return;
|
||||
}
|
||||
if (c.internalMetadata.runState === NotebookCellExecutionState.Pending) {
|
||||
executionCount++;
|
||||
} else if (!c.internalMetadata.runState) {
|
||||
executionCount--;
|
||||
}
|
||||
this._someCellRunning.set(executionCount > 0);
|
||||
});
|
||||
};
|
||||
|
||||
const recomputeOutputsExistence = () => {
|
||||
let hasOutputs = false;
|
||||
if (this._editor.hasModel()) {
|
||||
@@ -120,7 +100,6 @@ export class NotebookEditorContextKeys {
|
||||
|
||||
for (let i = 0; i < this._editor.getLength(); i++) {
|
||||
const cell = this._editor.cellAt(i);
|
||||
this._cellStateListeners.push(addCellStateListener(cell));
|
||||
this._cellOutputsListeners.push(addCellOutputsListener(cell));
|
||||
}
|
||||
|
||||
@@ -130,15 +109,22 @@ export class NotebookEditorContextKeys {
|
||||
this._viewModelDisposables.add(this._editor.onDidChangeViewCells(e => {
|
||||
e.splices.reverse().forEach(splice => {
|
||||
const [start, deleted, newCells] = splice;
|
||||
const deletedCellStates = this._cellStateListeners.splice(start, deleted, ...newCells.map(addCellStateListener));
|
||||
const deletedCellOutputStates = this._cellOutputsListeners.splice(start, deleted, ...newCells.map(addCellOutputsListener));
|
||||
dispose(deletedCellStates);
|
||||
dispose(deletedCellOutputStates);
|
||||
});
|
||||
}));
|
||||
this._viewType.set(this._editor.textModel.viewType);
|
||||
}
|
||||
|
||||
private _updateForCellExecution(): void {
|
||||
if (this._editor.textModel) {
|
||||
const notebookExe = this._notebookExecutionStateService.getCellExecutionStatesForNotebook(this._editor.textModel.uri);
|
||||
this._someCellRunning.set(notebookExe.length > 0);
|
||||
} else {
|
||||
this._someCellRunning.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
private async _updateForInstalledExtension(): Promise<void> {
|
||||
if (!this._editor.hasModel()) {
|
||||
return;
|
||||
|
||||
@@ -62,7 +62,6 @@ export class NotebookCellTextModel extends Disposable implements ICell {
|
||||
}
|
||||
|
||||
set internalMetadata(newInternalMetadata: NotebookCellInternalMetadata) {
|
||||
const runStateChanged = this._internalMetadata.runState !== newInternalMetadata.runState;
|
||||
const lastRunSuccessChanged = this._internalMetadata.lastRunSuccess !== newInternalMetadata.lastRunSuccess;
|
||||
newInternalMetadata = {
|
||||
...newInternalMetadata,
|
||||
@@ -70,7 +69,7 @@ export class NotebookCellTextModel extends Disposable implements ICell {
|
||||
};
|
||||
this._internalMetadata = newInternalMetadata;
|
||||
this._hash = null;
|
||||
this._onDidChangeInternalMetadata.fire({ runStateChanged, lastRunSuccessChanged });
|
||||
this._onDidChangeInternalMetadata.fire({ lastRunSuccessChanged });
|
||||
}
|
||||
|
||||
get language() {
|
||||
|
||||
@@ -159,6 +159,7 @@ export class NotebookEventEmitter extends PauseableEmitter<NotebookTextModelChan
|
||||
|
||||
export class NotebookTextModel extends Disposable implements INotebookTextModel {
|
||||
|
||||
private _isDisposed = false;
|
||||
private readonly _onWillDispose: Emitter<void> = this._register(new Emitter<void>());
|
||||
private readonly _onWillAddRemoveCells = this._register(new Emitter<NotebookTextModelWillAddRemoveEvent>());
|
||||
private readonly _onDidChangeContent = this._register(new Emitter<NotebookTextModelChangedEvent>());
|
||||
@@ -344,6 +345,12 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
||||
}
|
||||
|
||||
override dispose() {
|
||||
if (this._isDisposed) {
|
||||
// NotebookEditorModel can be disposed twice, don't fire onWillDispose again
|
||||
return;
|
||||
}
|
||||
|
||||
this._isDisposed = true;
|
||||
this._onWillDispose.fire();
|
||||
this._undoService.removeElements(this.uri);
|
||||
|
||||
|
||||
@@ -101,7 +101,6 @@ export interface NotebookCellMetadata {
|
||||
export interface NotebookCellInternalMetadata {
|
||||
executionOrder?: number;
|
||||
lastRunSuccess?: boolean;
|
||||
runState?: NotebookCellExecutionState;
|
||||
runStartTime?: number;
|
||||
runStartTimeAdjustment?: number;
|
||||
runEndTime?: number;
|
||||
@@ -200,7 +199,6 @@ export interface ICellOutput {
|
||||
}
|
||||
|
||||
export interface CellInternalMetadataChangedEvent {
|
||||
readonly runStateChanged?: boolean;
|
||||
readonly lastRunSuccessChanged?: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IOutputDto, IOutputItemDto } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
|
||||
import { INotebookTextModel, IOutputDto, IOutputItemDto } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { INotebookKernel } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
|
||||
|
||||
export enum CellExecutionUpdateType {
|
||||
Output = 1,
|
||||
OutputItems = 2,
|
||||
ExecutionState = 3,
|
||||
Complete = 4,
|
||||
}
|
||||
|
||||
export interface ICellExecuteOutputEdit {
|
||||
@@ -28,30 +28,13 @@ export interface ICellExecuteOutputItemEdit {
|
||||
items: IOutputItemDto[]
|
||||
}
|
||||
|
||||
export type ICellExecuteUpdate = ICellExecuteOutputEdit | ICellExecuteOutputItemEdit | ICellExecutionStateUpdate | ICellExecutionComplete;
|
||||
|
||||
export interface ICellExecutionStateUpdate {
|
||||
editType: CellExecutionUpdateType.ExecutionState;
|
||||
executionOrder?: number;
|
||||
runStartTime?: number;
|
||||
}
|
||||
|
||||
export interface ICellExecutionComplete {
|
||||
editType: CellExecutionUpdateType.Complete;
|
||||
runEndTime?: number;
|
||||
lastRunSuccess?: boolean;
|
||||
}
|
||||
|
||||
export interface INotebookCellExecution {
|
||||
readonly notebook: URI;
|
||||
readonly cellHandle: number;
|
||||
update(updates: ICellExecuteUpdate[]): void;
|
||||
}
|
||||
|
||||
export const INotebookExecutionService = createDecorator<INotebookExecutionService>('INotebookExecutionService');
|
||||
|
||||
export interface INotebookExecutionService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
createNotebookCellExecution(notebook: URI, cellHandle: number): INotebookCellExecution;
|
||||
getSelectedOrSuggestedKernel(notebook: INotebookTextModel): INotebookKernel | undefined;
|
||||
executeNotebookCells(notebook: INotebookTextModel, cells: Iterable<NotebookCellTextModel>): Promise<void>;
|
||||
cancelNotebookCells(notebook: INotebookTextModel, cells: Iterable<NotebookCellTextModel>): Promise<void>;
|
||||
cancelNotebookCellHandles(notebook: INotebookTextModel, cells: Iterable<number>): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
|
||||
import { NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellExecutionUpdateType, ICellExecuteOutputEdit, ICellExecuteOutputItemEdit } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
|
||||
|
||||
export type ICellExecuteUpdate = ICellExecuteOutputEdit | ICellExecuteOutputItemEdit | ICellExecutionStateUpdate;
|
||||
|
||||
export interface ICellExecutionStateUpdate {
|
||||
editType: CellExecutionUpdateType.ExecutionState;
|
||||
executionOrder?: number;
|
||||
runStartTime?: number;
|
||||
}
|
||||
|
||||
export interface ICellExecutionComplete {
|
||||
runEndTime?: number;
|
||||
lastRunSuccess?: boolean;
|
||||
}
|
||||
|
||||
export interface ICellExecutionEntry {
|
||||
notebook: URI;
|
||||
cellHandle: number;
|
||||
state: NotebookCellExecutionState;
|
||||
}
|
||||
|
||||
export interface ICellExecutionStateChangedEvent {
|
||||
notebook: URI;
|
||||
cellHandle: number;
|
||||
changed?: ICellExecutionEntry; // undefined -> execution was completed
|
||||
affectsCell(cell: NotebookCellTextModel): boolean;
|
||||
}
|
||||
|
||||
export const INotebookExecutionStateService = createDecorator<INotebookExecutionStateService>('INotebookExecutionStateService');
|
||||
|
||||
export interface INotebookExecutionStateService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
onDidChangeCellExecution: Event<ICellExecutionStateChangedEvent>;
|
||||
|
||||
getCellExecutionStatesForNotebook(notebook: URI): ICellExecutionEntry[];
|
||||
|
||||
getCellExecutionState(cellUri: URI): ICellExecutionEntry | undefined;
|
||||
|
||||
createNotebookCellExecution(notebook: URI, cellHandle: number): void;
|
||||
updateNotebookCellExecution(notebook: URI, cellHandle: number, updates: ICellExecuteUpdate[]): void;
|
||||
completeNotebookCellExecution(notebook: URI, cellHandle: number, complete: ICellExecutionComplete): void;
|
||||
}
|
||||
@@ -5,8 +5,10 @@
|
||||
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IConfigurationChangeEvent, IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { NotebookCellDefaultCollapseConfig, NotebookCellInternalMetadata, NotebookSetting, ShowCellStatusBarType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
||||
|
||||
const SCROLLABLE_ELEMENT_PADDING_TOP = 18;
|
||||
|
||||
@@ -109,7 +111,11 @@ export class NotebookOptions extends Disposable {
|
||||
protected readonly _onDidChangeOptions = this._register(new Emitter<NotebookOptionsChangeEvent>());
|
||||
readonly onDidChangeOptions = this._onDidChangeOptions.event;
|
||||
|
||||
constructor(private readonly configurationService: IConfigurationService, private readonly overrides?: { cellToolbarInteraction: string, globalToolbar: boolean, defaultCellCollapseConfig?: NotebookCellDefaultCollapseConfig }) {
|
||||
constructor(
|
||||
private readonly configurationService: IConfigurationService,
|
||||
private readonly notebookExecutionStateService: INotebookExecutionStateService,
|
||||
private readonly overrides?: { cellToolbarInteraction: string, globalToolbar: boolean, defaultCellCollapseConfig?: NotebookCellDefaultCollapseConfig }
|
||||
) {
|
||||
super();
|
||||
const showCellStatusBar = this.configurationService.getValue<ShowCellStatusBarType>(NotebookSetting.showCellStatusBar);
|
||||
const globalToolbar = overrides?.globalToolbar ?? this.configurationService.getValue<boolean | undefined>(NotebookSetting.globalToolbar) ?? true;
|
||||
@@ -439,25 +445,26 @@ export class NotebookOptions extends Disposable {
|
||||
return 0;
|
||||
}
|
||||
|
||||
computeEditorPadding(internalMetadata: NotebookCellInternalMetadata) {
|
||||
computeEditorPadding(internalMetadata: NotebookCellInternalMetadata, cellUri: URI) {
|
||||
return {
|
||||
top: getEditorTopPadding(),
|
||||
bottom: this.statusBarIsVisible(internalMetadata)
|
||||
bottom: this.statusBarIsVisible(internalMetadata, cellUri)
|
||||
? this._layoutConfiguration.editorBottomPadding
|
||||
: this._layoutConfiguration.editorBottomPaddingWithoutStatusBar
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
computeEditorStatusbarHeight(internalMetadata: NotebookCellInternalMetadata) {
|
||||
return this.statusBarIsVisible(internalMetadata) ? this.computeStatusBarHeight() : 0;
|
||||
computeEditorStatusbarHeight(internalMetadata: NotebookCellInternalMetadata, cellUri: URI) {
|
||||
return this.statusBarIsVisible(internalMetadata, cellUri) ? this.computeStatusBarHeight() : 0;
|
||||
}
|
||||
|
||||
private statusBarIsVisible(internalMetadata: NotebookCellInternalMetadata): boolean {
|
||||
private statusBarIsVisible(internalMetadata: NotebookCellInternalMetadata, cellUri: URI): boolean {
|
||||
const exe = this.notebookExecutionStateService.getCellExecutionState(cellUri);
|
||||
if (this._layoutConfiguration.showCellStatusBar === 'visible') {
|
||||
return true;
|
||||
} else if (this._layoutConfiguration.showCellStatusBar === 'visibleAfterExecute') {
|
||||
return typeof internalMetadata.lastRunSuccess === 'boolean' || internalMetadata.runState !== undefined;
|
||||
return typeof internalMetadata.lastRunSuccess === 'boolean' || exe !== undefined;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
||||
import { NotebookOptions } from 'vs/workbench/contrib/notebook/common/notebookOptions';
|
||||
import { createNotebookCellList, setupInstantiationService, withTestNotebook } from 'vs/workbench/contrib/notebook/test/browser/testNotebookEditor';
|
||||
|
||||
@@ -20,7 +21,7 @@ suite('NotebookCellList', () => {
|
||||
suiteSetup(() => {
|
||||
disposables = new DisposableStore();
|
||||
instantiationService = setupInstantiationService(disposables);
|
||||
notebookDefaultOptions = new NotebookOptions(instantiationService.get(IConfigurationService));
|
||||
notebookDefaultOptions = new NotebookOptions(instantiationService.get(IConfigurationService), instantiationService.get(INotebookExecutionStateService));
|
||||
topInsertToolbarHeight = notebookDefaultOptions.computeTopInsertToolbarHeight();
|
||||
|
||||
});
|
||||
|
||||
+19
-19
@@ -5,25 +5,25 @@
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as sinon from 'sinon';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { mock } from 'vs/base/test/common/mock';
|
||||
import { assertThrowsAsync } from 'vs/base/test/common/utils';
|
||||
import { PLAINTEXT_LANGUAGE_ID } from 'vs/editor/common/modes/modesRegistry';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { NotebookEditorKernelManager } from 'vs/workbench/contrib/notebook/browser/notebookEditorKernelManager';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { insertCellAtIndex } from 'vs/workbench/contrib/notebook/browser/controller/cellOperations';
|
||||
import { NotebookExecutionService } from 'vs/workbench/contrib/notebook/browser/notebookExecutionServiceImpl';
|
||||
import { NotebookKernelService } from 'vs/workbench/contrib/notebook/browser/notebookKernelServiceImpl';
|
||||
import { NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
|
||||
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
|
||||
import { CellKind, IOutputDto, NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { setupInstantiationService, withTestNotebook as _withTestNotebook } from 'vs/workbench/contrib/notebook/test/browser/testNotebookEditor';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { ISelectedNotebooksChangeEvent, INotebookKernelService, INotebookKernel } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
|
||||
import { NotebookKernelService } from 'vs/workbench/contrib/notebook/browser/notebookKernelServiceImpl';
|
||||
import { INotebookKernel, INotebookKernelService, ISelectedNotebooksChangeEvent } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
|
||||
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
|
||||
import { mock } from 'vs/base/test/common/mock';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { PLAINTEXT_LANGUAGE_ID } from 'vs/editor/common/modes/modesRegistry';
|
||||
import { insertCellAtIndex } from 'vs/workbench/contrib/notebook/browser/controller/cellOperations';
|
||||
import { setupInstantiationService, withTestNotebook as _withTestNotebook } from 'vs/workbench/contrib/notebook/test/browser/testNotebookEditor';
|
||||
|
||||
suite('NotebookEditorKernelManager', () => {
|
||||
suite('NotebookExecutionService', () => {
|
||||
|
||||
let instantiationService: TestInstantiationService;
|
||||
let kernelService: INotebookKernelService;
|
||||
@@ -65,10 +65,10 @@ suite('NotebookEditorKernelManager', () => {
|
||||
await withTestNotebook(
|
||||
[],
|
||||
async (viewModel) => {
|
||||
const kernelManager = instantiationService.createInstance(NotebookEditorKernelManager);
|
||||
const executionService = instantiationService.createInstance(NotebookExecutionService);
|
||||
|
||||
const cell = insertCellAtIndex(viewModel, 1, 'var c = 3', 'javascript', CellKind.Code, {}, [], true);
|
||||
await assertThrowsAsync(async () => await kernelManager.executeNotebookCell(cell));
|
||||
await assertThrowsAsync(async () => await executionService.executeNotebookCell(cell));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -78,9 +78,9 @@ suite('NotebookEditorKernelManager', () => {
|
||||
async (viewModel) => {
|
||||
|
||||
kernelService.registerKernel(new TestNotebookKernel({ languages: ['testlang'] }));
|
||||
const kernelManager = instantiationService.createInstance(NotebookEditorKernelManager);
|
||||
const executionService = instantiationService.createInstance(NotebookExecutionService);
|
||||
const cell = insertCellAtIndex(viewModel, 1, 'var c = 3', 'javascript', CellKind.Code, {}, [], true);
|
||||
await assertThrowsAsync(async () => await kernelManager.executeNotebookCell(cell));
|
||||
await assertThrowsAsync(async () => await executionService.executeNotebookCell(cell));
|
||||
|
||||
});
|
||||
});
|
||||
@@ -91,12 +91,12 @@ suite('NotebookEditorKernelManager', () => {
|
||||
async (viewModel) => {
|
||||
const kernel = new TestNotebookKernel({ languages: ['javascript'] });
|
||||
kernelService.registerKernel(kernel);
|
||||
const kernelManager = instantiationService.createInstance(NotebookEditorKernelManager);
|
||||
const executionService = instantiationService.createInstance(NotebookExecutionService);
|
||||
const executeSpy = sinon.spy();
|
||||
kernel.executeNotebookCellsRequest = executeSpy;
|
||||
|
||||
const cell = insertCellAtIndex(viewModel, 0, 'var c = 3', 'javascript', CellKind.Code, {}, [], true);
|
||||
await kernelManager.executeNotebookCells(viewModel.notebookDocument, [cell]);
|
||||
await executionService.executeNotebookCells(viewModel.notebookDocument, [cell]);
|
||||
assert.strictEqual(executeSpy.calledOnce, true);
|
||||
});
|
||||
});
|
||||
@@ -121,13 +121,13 @@ suite('NotebookEditorKernelManager', () => {
|
||||
};
|
||||
|
||||
kernelService.registerKernel(kernel);
|
||||
const kernelManager = instantiationService.createInstance(NotebookEditorKernelManager);
|
||||
const executionService = instantiationService.createInstance(NotebookExecutionService);
|
||||
|
||||
let event: ISelectedNotebooksChangeEvent | undefined;
|
||||
kernelService.onDidChangeSelectedNotebooks(e => event = e);
|
||||
|
||||
const cell = insertCellAtIndex(viewModel, 0, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true);
|
||||
await kernelManager.executeNotebookCells(viewModel.notebookDocument, [cell]);
|
||||
await executionService.executeNotebookCells(viewModel.notebookDocument, [cell]);
|
||||
|
||||
assert.strictEqual(didExecute, true);
|
||||
assert.ok(event !== undefined);
|
||||
@@ -0,0 +1,116 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { mock } from 'vs/base/test/common/mock';
|
||||
import { PLAINTEXT_LANGUAGE_ID } from 'vs/editor/common/modes/modesRegistry';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { insertCellAtIndex } from 'vs/workbench/contrib/notebook/browser/controller/cellOperations';
|
||||
import { NotebookExecutionService } from 'vs/workbench/contrib/notebook/browser/notebookExecutionServiceImpl';
|
||||
import { NotebookExecutionStateService } from 'vs/workbench/contrib/notebook/browser/notebookExecutionStateServiceImpl';
|
||||
import { NotebookKernelService } from 'vs/workbench/contrib/notebook/browser/notebookKernelServiceImpl';
|
||||
import { NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
|
||||
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
|
||||
import { CellEditType, CellKind, IOutputDto, NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { INotebookExecutionService } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
|
||||
import { INotebookKernel, INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
|
||||
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
|
||||
import { setupInstantiationService, withTestNotebook as _withTestNotebook } from 'vs/workbench/contrib/notebook/test/browser/testNotebookEditor';
|
||||
|
||||
suite('NotebookExecutionStateService', () => {
|
||||
|
||||
let instantiationService: TestInstantiationService;
|
||||
let kernelService: INotebookKernelService;
|
||||
let disposables: DisposableStore;
|
||||
|
||||
setup(function () {
|
||||
|
||||
disposables = new DisposableStore();
|
||||
|
||||
instantiationService = setupInstantiationService(disposables);
|
||||
|
||||
instantiationService.stub(INotebookService, new class extends mock<INotebookService>() {
|
||||
override onDidAddNotebookDocument = Event.None;
|
||||
override onWillRemoveNotebookDocument = Event.None;
|
||||
override getNotebookTextModels() { return []; }
|
||||
});
|
||||
|
||||
kernelService = instantiationService.createInstance(NotebookKernelService);
|
||||
instantiationService.set(INotebookKernelService, kernelService);
|
||||
instantiationService.set(INotebookExecutionService, instantiationService.createInstance(NotebookExecutionService));
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
disposables.dispose();
|
||||
});
|
||||
|
||||
async function withTestNotebook(cells: [string, string, CellKind, IOutputDto[], NotebookCellMetadata][], callback: (viewModel: NotebookViewModel, textModel: NotebookTextModel) => void | Promise<void>) {
|
||||
return _withTestNotebook(cells, (editor, viewModel) => callback(viewModel, viewModel.notebookDocument));
|
||||
}
|
||||
|
||||
test('cancel execution when cell is deleted', async function () {
|
||||
return withTestNotebook([], async viewModel => {
|
||||
instantiationService.stub(INotebookService, new class extends mock<INotebookService>() {
|
||||
override getNotebookTextModel(uri: URI): NotebookTextModel | undefined {
|
||||
return viewModel.notebookDocument;
|
||||
}
|
||||
});
|
||||
|
||||
let didCancel = false;
|
||||
const kernel = new class extends TestNotebookKernel {
|
||||
constructor() {
|
||||
super({ languages: ['javascript'] });
|
||||
}
|
||||
|
||||
override async executeNotebookCellsRequest(): Promise<void> { }
|
||||
|
||||
override async cancelNotebookCellExecution(): Promise<void> {
|
||||
didCancel = true;
|
||||
}
|
||||
};
|
||||
kernelService.registerKernel(kernel);
|
||||
|
||||
const executionStateService: NotebookExecutionStateService = instantiationService.createInstance(NotebookExecutionStateService);
|
||||
|
||||
const cell = insertCellAtIndex(viewModel, 0, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true);
|
||||
executionStateService.createNotebookCellExecution(viewModel.uri, cell.handle);
|
||||
assert.strictEqual(didCancel, false);
|
||||
viewModel.notebookDocument.applyEdits([{
|
||||
editType: CellEditType.Replace, index: 0, count: 1, cells: []
|
||||
}], true, undefined, () => undefined, undefined, false);
|
||||
await timeout(0);
|
||||
assert.strictEqual(didCancel, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
class TestNotebookKernel implements INotebookKernel {
|
||||
id: string = 'test';
|
||||
label: string = '';
|
||||
viewType = '*';
|
||||
onDidChange = Event.None;
|
||||
extension: ExtensionIdentifier = new ExtensionIdentifier('test');
|
||||
localResourceRoot: URI = URI.file('/test');
|
||||
description?: string | undefined;
|
||||
detail?: string | undefined;
|
||||
preloadUris: URI[] = [];
|
||||
preloadProvides: string[] = [];
|
||||
supportedLanguages: string[] = [];
|
||||
executeNotebookCellsRequest(): Promise<void> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
cancelNotebookCellExecution(): Promise<void> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
constructor(opts?: { languages: string[] }) {
|
||||
this.supportedLanguages = opts?.languages ?? [PLAINTEXT_LANGUAGE_ID];
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import { CellKind, diff } from 'vs/workbench/contrib/notebook/common/notebookCom
|
||||
import { NotebookOptions } from 'vs/workbench/contrib/notebook/common/notebookOptions';
|
||||
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange';
|
||||
import { NotebookEditorTestModel, setupInstantiationService, withTestNotebook } from 'vs/workbench/contrib/notebook/test/browser/testNotebookEditor';
|
||||
import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
||||
|
||||
suite('NotebookViewModel', () => {
|
||||
let disposables: DisposableStore;
|
||||
@@ -54,7 +55,7 @@ suite('NotebookViewModel', () => {
|
||||
test('ctor', function () {
|
||||
const notebook = new NotebookTextModel('notebook', URI.parse('test'), [], {}, { transientCellMetadata: {}, transientDocumentMetadata: {}, transientOutputs: false }, undoRedoService, modelService, languageService);
|
||||
const model = new NotebookEditorTestModel(notebook);
|
||||
const viewContext = new ViewContext(new NotebookOptions(instantiationService.get(IConfigurationService)), new NotebookEventDispatcher());
|
||||
const viewContext = new ViewContext(new NotebookOptions(instantiationService.get(IConfigurationService), instantiationService.get(INotebookExecutionStateService)), new NotebookEventDispatcher());
|
||||
const viewModel = new NotebookViewModel('notebook', model.notebook, viewContext, null, { isReadOnly: false }, instantiationService, bulkEditService, undoRedoService, textModelService);
|
||||
assert.strictEqual(viewModel.viewType, 'notebook');
|
||||
});
|
||||
|
||||
@@ -15,10 +15,10 @@ import { mock } from 'vs/base/test/common/mock';
|
||||
import { EditorFontLigatures } from 'vs/editor/common/config/editorOptions';
|
||||
import { FontInfo } from 'vs/editor/common/config/fontInfo';
|
||||
import { ILanguageConfigurationService } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||
import { IModelService } from 'vs/editor/common/services/model';
|
||||
import { ModelService } from 'vs/editor/common/services/modelService';
|
||||
import { ILanguageService } from 'vs/editor/common/services/language';
|
||||
import { LanguageService } from 'vs/editor/common/services/languageService';
|
||||
import { IModelService } from 'vs/editor/common/services/model';
|
||||
import { ModelService } from 'vs/editor/common/services/modelService';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { TestLanguageConfigurationService } from 'vs/editor/test/common/modes/testLanguageConfigurationService';
|
||||
import { BrowserClipboardService } from 'vs/platform/clipboard/browser/clipboardService';
|
||||
@@ -29,6 +29,7 @@ import { TestConfigurationService } from 'vs/platform/configuration/test/common/
|
||||
import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
|
||||
import { IListService, ListService } from 'vs/platform/list/browser/listService';
|
||||
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
@@ -49,13 +50,13 @@ import { ViewContext } from 'vs/workbench/contrib/notebook/browser/viewModel/vie
|
||||
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
|
||||
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
|
||||
import { CellKind, CellUri, INotebookDiffEditorModel, INotebookEditorModel, IOutputDto, IResolvedNotebookEditorModel, NotebookCellMetadata, SelectionStateType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { ICellExecuteUpdate, ICellExecutionComplete, ICellExecutionEntry, ICellExecutionStateChangedEvent, INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
||||
import { NotebookOptions } from 'vs/workbench/contrib/notebook/common/notebookOptions';
|
||||
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange';
|
||||
import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService';
|
||||
import { TestWorkspaceTrustRequestService } from 'vs/workbench/services/workspaces/test/common/testWorkspaceTrustService';
|
||||
import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
|
||||
import { TestLayoutService } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||
import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||
|
||||
export class TestCell extends NotebookCellTextModel {
|
||||
constructor(
|
||||
@@ -174,6 +175,7 @@ export function setupInstantiationService(disposables = new DisposableStore()) {
|
||||
instantiationService.stub(IClipboardService, instantiationService.createInstance(BrowserClipboardService));
|
||||
instantiationService.stub(IStorageService, new TestStorageService());
|
||||
instantiationService.stub(IWorkspaceTrustRequestService, new TestWorkspaceTrustRequestService(true));
|
||||
instantiationService.stub(INotebookExecutionStateService, new TestNotebookExecutionStateService());
|
||||
|
||||
return instantiationService;
|
||||
}
|
||||
@@ -192,7 +194,7 @@ function _createTestNotebookEditor(instantiationService: TestInstantiationServic
|
||||
}), {}, { transientCellMetadata: {}, transientDocumentMetadata: {}, transientOutputs: false });
|
||||
|
||||
const model = new NotebookEditorTestModel(notebook);
|
||||
const notebookOptions = new NotebookOptions(instantiationService.get(IConfigurationService));
|
||||
const notebookOptions = new NotebookOptions(instantiationService.get(IConfigurationService), instantiationService.get(INotebookExecutionStateService));
|
||||
const viewContext = new ViewContext(notebookOptions, new NotebookEventDispatcher());
|
||||
const viewModel: NotebookViewModel = instantiationService.createInstance(NotebookViewModel, viewType, model.notebook, viewContext, null, { isReadOnly: false });
|
||||
|
||||
@@ -385,7 +387,7 @@ export function createNotebookCellList(instantiationService: TestInstantiationSe
|
||||
'NotebookCellList',
|
||||
DOM.$('container'),
|
||||
DOM.$('body'),
|
||||
viewContext ?? new ViewContext(new NotebookOptions(instantiationService.get(IConfigurationService)), new NotebookEventDispatcher()),
|
||||
viewContext ?? new ViewContext(new NotebookOptions(instantiationService.get(IConfigurationService), instantiationService.get(INotebookExecutionStateService)), new NotebookEventDispatcher()),
|
||||
delegate,
|
||||
[renderer],
|
||||
instantiationService.get<IContextKeyService>(IContextKeyService),
|
||||
@@ -406,3 +408,26 @@ export function createNotebookCellList(instantiationService: TestInstantiationSe
|
||||
export function valueBytesFromString(value: string): VSBuffer {
|
||||
return VSBuffer.fromString(value);
|
||||
}
|
||||
|
||||
class TestNotebookExecutionStateService implements INotebookExecutionStateService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
onDidChangeCellExecution = new Emitter<ICellExecutionStateChangedEvent>().event;
|
||||
|
||||
getCellExecutionStatesForNotebook(notebook: URI): ICellExecutionEntry[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
getCellExecutionState(cellUri: URI): ICellExecutionEntry | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
createNotebookCellExecution(notebook: URI, cellHandle: number): void {
|
||||
}
|
||||
|
||||
updateNotebookCellExecution(notebook: URI, cellHandle: number, updates: ICellExecuteUpdate[]): void {
|
||||
}
|
||||
|
||||
completeNotebookCellExecution(notebook: URI, cellHandle: number, complete: ICellExecutionComplete): void {
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user