Let a `vscode.NotebookCell` only be what's spec'd in the API not more. Make things froozen and readonly when possible
This commit is contained in:
Johannes Rieken 2020-08-21 12:08:41 +02:00
parent 3723dfa35c
commit 3462e29ea0
3 changed files with 78 additions and 76 deletions

View file

@ -1325,7 +1325,7 @@ declare module 'vscode' {
readonly viewType: string;
readonly isDirty: boolean;
readonly isUntitled: boolean;
readonly cells: NotebookCell[];
readonly cells: ReadonlyArray<NotebookCell>;
languages: string[];
displayOrder?: GlobPattern[];
metadata: NotebookDocumentMetadata;

View file

@ -58,7 +58,7 @@ interface INotebookEventEmitter {
const addIdToOutput = (output: IRawOutput, id = UUID.generateUuid()): IProcessedOutput => output.outputKind === CellOutputKind.Rich
? ({ ...output, outputId: id }) : output;
export class ExtHostCell extends Disposable implements vscode.NotebookCell {
export class ExtHostCell extends Disposable {
public static asModelAddData(notebook: ExtHostNotebookDocument, cell: IMainCellDto): IExtHostModelAddedData {
return {
@ -85,49 +85,56 @@ export class ExtHostCell extends Disposable implements vscode.NotebookCell {
readonly uri: URI;
readonly cellKind: CellKind;
private _document: vscode.TextDocument | undefined;
private _cell: vscode.NotebookCell | undefined;
constructor(
private _proxy: MainThreadNotebookShape,
readonly notebook: ExtHostNotebookDocument,
private _extHostDocument: ExtHostDocumentsAndEditors,
cell: IMainCellDto,
private readonly _proxy: MainThreadNotebookShape,
private readonly _notebook: ExtHostNotebookDocument,
private readonly _extHostDocument: ExtHostDocumentsAndEditors,
private readonly _cellData: IMainCellDto,
) {
super();
this.handle = cell.handle;
this.uri = URI.revive(cell.uri);
this.cellKind = cell.cellKind;
this.handle = _cellData.handle;
this.uri = URI.revive(_cellData.uri);
this.cellKind = _cellData.cellKind;
this._outputs = cell.outputs;
this._outputs = _cellData.outputs;
for (const output of this._outputs) {
this._outputMapping.set(output, output.outputId);
delete output.outputId;
}
const observableMetadata = getObservable(cell.metadata ?? {});
const observableMetadata = getObservable(_cellData.metadata ?? {});
this._metadata = observableMetadata.proxy;
this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => {
this._updateMetadata();
}));
}
get document(): vscode.TextDocument {
if (!this._document) {
this._document = this._extHostDocument.getDocument(this.uri)?.document;
get cell(): vscode.NotebookCell {
if (!this._cell) {
const that = this;
const document = this._extHostDocument.getDocument(this.uri)!.document;
this._cell = Object.freeze({
notebook: that._notebook,
uri: that.uri,
cellKind: this._cellData.cellKind,
document,
language: document.languageId,
get outputs() { return that._outputs; },
set outputs(value) { that._updateOutputs(value); },
get metadata() { return that._metadata; },
set metadata(value) {
that.setMetadata(value);
that._updateMetadata();
},
});
}
return this._document!;
return this._cell;
}
get language(): string {
return this.document.languageId;
}
get outputs() {
return this._outputs;
}
set outputs(newOutputs: vscode.CellOutput[]) {
private _updateOutputs(newOutputs: vscode.CellOutput[]) {
const rawDiffs = diff<vscode.CellOutput>(this._outputs || [], newOutputs || [], (a) => {
return this._outputMapping.has(a);
});
@ -157,15 +164,6 @@ export class ExtHostCell extends Disposable implements vscode.NotebookCell {
this._onDidChangeOutputs.fire(transformedDiffs);
}
get metadata() {
return this._metadata;
}
set metadata(newMetadata: vscode.NotebookCellMetadata) {
this.setMetadata(newMetadata);
this._updateMetadata();
}
setMetadata(newMetadata: vscode.NotebookCellMetadata): void {
// Don't apply metadata defaults here, 'undefined' means 'inherit from document metadata'
this._metadataChangeListener.dispose();
@ -177,7 +175,21 @@ export class ExtHostCell extends Disposable implements vscode.NotebookCell {
}
private _updateMetadata(): Promise<void> {
return this._proxy.$updateNotebookCellMetadata(this.notebook.viewType, this.notebook.uri, this.handle, this._metadata);
return this._proxy.$updateNotebookCellMetadata(this._notebook.viewType, this._notebook.uri, this.handle, this._metadata);
}
}
class RawContentChangeEvent {
constructor(readonly start: number, readonly deletedCount: number, readonly deletedItems: ExtHostCell[], readonly items: ExtHostCell[]) { }
static asApiEvent(event: RawContentChangeEvent): vscode.NotebookCellsChangeData {
return Object.freeze({
start: event.start,
deletedCount: event.deletedCount,
deletedItems: event.deletedItems.map(data => data.cell),
items: event.items.map(data => data.cell)
});
}
}
@ -189,8 +201,8 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
private _cellDisposableMapping = new Map<number, DisposableStore>();
get cells() {
return this._cells;
get cells(): ReadonlyArray<vscode.NotebookCell> {
return this._cells.map(cellData => cellData.cell);
}
private _languages: string[] = [];
@ -367,7 +379,7 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
return;
}
const contentChangeEvents: vscode.NotebookCellsChangeData[] = [];
const contentChangeEvents: RawContentChangeEvent[] = [];
const addedCellDocuments: IExtHostModelAddedData[] = [];
const removedCellDocuments: URI[] = [];
@ -395,22 +407,16 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
});
for (let j = splice[0]; j < splice[0] + splice[1]; j++) {
this._cellDisposableMapping.get(this.cells[j].handle)?.dispose();
this._cellDisposableMapping.delete(this.cells[j].handle);
this._cellDisposableMapping.get(this._cells[j].handle)?.dispose();
this._cellDisposableMapping.delete(this._cells[j].handle);
}
const deletedItems = this.cells.splice(splice[0], splice[1], ...newCells);
contentChangeEvents.push({
start: splice[0],
deletedCount: splice[1],
deletedItems,
items: newCells
});
const deletedItems = this._cells.splice(splice[0], splice[1], ...newCells);
for (let cell of deletedItems) {
removedCellDocuments.push(cell.uri);
}
contentChangeEvents.push(new RawContentChangeEvent(splice[0], splice[1], deletedItems, newCells));
});
this._documentsAndEditors.acceptDocumentsAndEditorsDelta({
@ -421,24 +427,24 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
if (!initialization) {
this._emitter.emitModelChange({
document: this,
changes: contentChangeEvents
changes: contentChangeEvents.map(RawContentChangeEvent.asApiEvent)
});
}
}
private _moveCell(index: number, newIdx: number): void {
const cells = this.cells.splice(index, 1);
this.cells.splice(newIdx, 0, ...cells);
const cells = this._cells.splice(index, 1);
this._cells.splice(newIdx, 0, ...cells);
const changes: vscode.NotebookCellsChangeData[] = [{
start: index,
deletedCount: 1,
deletedItems: cells,
deletedItems: cells.map(data => data.cell),
items: []
}, {
start: newIdx,
deletedCount: 0,
deletedItems: [],
items: cells
items: cells.map(data => data.cell)
}];
this._emitter.emitModelChange({
document: this,
@ -466,15 +472,15 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
}
private _changeCellLanguage(index: number, language: string): void {
const cell = this.cells[index];
const event: vscode.NotebookCellLanguageChangeEvent = { document: this, cell, language };
const cell = this._cells[index];
const event: vscode.NotebookCellLanguageChangeEvent = { document: this, cell: cell.cell, language };
this._emitter.emitCellLanguageChange(event);
}
private _changeCellMetadata(index: number, newMetadata: NotebookCellMetadata): void {
const cell = this.cells[index];
const cell = this._cells[index];
cell.setMetadata(newMetadata);
const event: vscode.NotebookCellMetadataChangeEvent = { document: this, cell };
const event: vscode.NotebookCellMetadataChangeEvent = { document: this, cell: cell.cell };
this._emitter.emitCellMetadataChange(event);
}
@ -488,16 +494,16 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
await this._proxy.$spliceNotebookCellOutputs(this.viewType, this.uri, cell.handle, outputDtos, Array.from(renderers));
this._emitter.emitCellOutputsChange({
document: this,
cells: [cell]
cells: [cell.cell]
});
}
getCell(cellHandle: number): ExtHostCell | undefined {
return this.cells.find(cell => cell.handle === cellHandle);
return this._cells.find(cell => cell.handle === cellHandle);
}
getCell2(cellUri: UriComponents): ExtHostCell | undefined {
return this.cells.find(cell => cell.uri.fragment === cellUri.fragment);
return this._cells.find(cell => cell.uri.fragment === cellUri.fragment);
}
}
@ -606,7 +612,7 @@ class ExtHostWebviewCommWrapper extends Disposable {
export class ExtHostNotebookEditor extends Disposable implements vscode.NotebookEditor {
private _viewColumn: vscode.ViewColumn | undefined;
selection?: ExtHostCell = undefined;
selection?: vscode.NotebookCell;
private _active: boolean = false;
get active(): boolean {
@ -855,7 +861,7 @@ export class ExtHostNotebookKernelProviderAdapter extends Disposable {
}
if (cell) {
return withToken(token => (kernel.executeCell as any)(document, cell, token));
return withToken(token => (kernel.executeCell as any)(document, cell.cell, token));
} else {
return withToken(token => (kernel.executeAllCells as any)(document, token));
}
@ -869,7 +875,7 @@ export class ExtHostNotebookKernelProviderAdapter extends Disposable {
}
if (cell) {
return kernel.cancelCellExecution(document, cell);
return kernel.cancelCellExecution(document, cell.cell);
} else {
return kernel.cancelAllCellsExecution(document);
}
@ -1009,7 +1015,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
outputId: output.outputId,
mimeType: output.mimeType,
handlerId: id,
transformedOutput: renderer.render(document, cell.outputs[output.index] as vscode.CellDisplayOutput, output.outputId, output.mimeType)
transformedOutput: renderer.render(document, cell.cell.outputs[output.index] as vscode.CellDisplayOutput, output.outputId, output.mimeType)
};
});
@ -1298,7 +1304,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
if (provider.kernel) {
if (cell) {
return provider.kernel.cancelCellExecution(document, cell);
return provider.kernel.cancelCellExecution(document, cell.cell);
} else {
return provider.kernel.cancelAllCellsExecution(document);
}
@ -1338,7 +1344,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
const cell = cellHandle !== undefined ? document.getCell(cellHandle) : undefined;
if (cell) {
return withToken(token => (kernelInfo!.kernel.executeCell as any)(document, cell, token));
return withToken(token => (kernelInfo!.kernel.executeCell as any)(document, cell.cell, token));
} else {
return withToken(token => (kernelInfo!.kernel.executeAllCells as any)(document, token));
}
@ -1466,11 +1472,9 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}
if (data.selections) {
const cells = editor.editor.document.cells;
if (data.selections.selections.length) {
const firstCell = data.selections.selections[0];
editor.editor.selection = cells.find(cell => cell.handle === firstCell);
editor.editor.selection = editor.editor.document.getCell(firstCell)?.cell;
} else {
editor.editor.selection = undefined;
}
@ -1502,11 +1506,9 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
document
);
const cells = editor.document.cells;
if (selections.length) {
const firstCell = selections[0];
editor.selection = cells.find(cell => cell.handle === firstCell);
editor.selection = editor.document.getCell(firstCell)?.cell;
} else {
editor.selection = undefined;
}

View file

@ -6,7 +6,7 @@
import * as types from 'vs/workbench/api/common/extHostTypes';
import * as vscode from 'vscode';
import { Event, Emitter } from 'vs/base/common/event';
import { ExtHostNotebookController, ExtHostCell } from 'vs/workbench/api/common/extHostNotebook';
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer';
import { DisposableStore } from 'vs/base/common/lifecycle';
@ -21,7 +21,7 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
private _disposables = new DisposableStore();
private _isClosed = false;
private _cells!: ExtHostCell[];
private _cells!: vscode.NotebookCell[];
private _cellUris!: ResourceMap<number>;
private _cellLengths!: PrefixSumComputer;
private _cellLines!: PrefixSumComputer;
@ -78,7 +78,7 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
for (const cell of this._notebook.cells) {
if (cell.cellKind === CellKind.Code && (!this._selector || score(this._selector, cell.uri, cell.language, true))) {
this._cellUris.set(cell.uri, this._cells.length);
this._cells.push(<ExtHostCell>cell);
this._cells.push(cell);
cellLengths.push(cell.document.getText().length + 1);
cellLineCounts.push(cell.document.lineCount);
}