Merge from vscode 79a1f5a5ca0c6c53db617aa1fa5a2396d2caebe2

This commit is contained in:
ADS Merger
2020-05-31 19:47:51 +00:00
parent 84492049e8
commit 28be33cfea
913 changed files with 28242 additions and 15549 deletions

View File

@@ -10,14 +10,16 @@ import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecyc
import { ISplice } from 'vs/base/common/sequence';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { CellKind, CellOutputKind, ExtHostNotebookShape, IMainContext, MainContext, MainThreadNotebookShape, NotebookCellOutputsSplice, MainThreadDocumentsShape, INotebookEditorPropertiesChangeData, INotebookDocumentsAndEditorsDelta } from 'vs/workbench/api/common/extHost.protocol';
import { CellKind, ExtHostNotebookShape, IMainContext, MainContext, MainThreadNotebookShape, NotebookCellOutputsSplice, MainThreadDocumentsShape, INotebookEditorPropertiesChangeData, INotebookDocumentsAndEditorsDelta } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { CellEditType, CellUri, diff, ICellEditOperation, ICellInsertEdit, IErrorOutput, INotebookDisplayOrder, INotebookEditData, IOrderedMimeType, IStreamOutput, ITransformedDisplayOutputDto, mimeTypeSupportedByCore, NotebookCellsChangedEvent, NotebookCellsSplice2, sortMimeTypes, ICellDeleteEdit, notebookDocumentMetadataDefaults, NotebookCellsChangeType, NotebookDataDto } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { Disposable as VSCodeDisposable } from './extHostTypes';
import { CellEditType, CellUri, diff, ICellEditOperation, ICellInsertEdit, INotebookDisplayOrder, INotebookEditData, NotebookCellsChangedEvent, NotebookCellsSplice2, ICellDeleteEdit, notebookDocumentMetadataDefaults, NotebookCellsChangeType, NotebookDataDto, IOutputRenderRequest, IOutputRenderResponse, IOutputRenderResponseOutputInfo, IOutputRenderResponseCellInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
import { CancellationToken } from 'vs/base/common/cancellation';
import { ExtHostDocumentData } from 'vs/workbench/api/common/extHostDocumentData';
import { NotImplementedProxy } from 'vs/base/common/types';
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/webview';
interface IObservable<T> {
proxy: T;
@@ -40,6 +42,12 @@ function getObservable<T extends Object>(obj: T): IObservable<T> {
};
}
interface INotebookEventEmitter {
emitModelChange(events: vscode.NotebookCellsChangeEvent): void;
emitCellOutputsChange(event: vscode.NotebookCellOutputsChangeEvent): void;
emitCellLanguageChange(event: vscode.NotebookCellLanguageChangeEvent): void;
}
export class ExtHostCell extends Disposable implements vscode.NotebookCell {
// private originalSource: string[];
@@ -59,14 +67,17 @@ export class ExtHostCell extends Disposable implements vscode.NotebookCell {
return this._documentData.document;
}
get notebook(): vscode.NotebookDocument {
return this._notebook;
}
get source() {
// todo@jrieken remove this
return this._documentData.getText();
}
constructor(
private readonly viewType: string,
private readonly documentUri: URI,
private readonly _notebook: ExtHostNotebookDocument,
readonly handle: number,
readonly uri: URI,
content: string,
@@ -133,7 +144,7 @@ export class ExtHostCell extends Disposable implements vscode.NotebookCell {
}
private updateMetadata(): Promise<void> {
return this._proxy.$updateNotebookCellMetadata(this.viewType, this.documentUri, this.handle, this._metadata);
return this._proxy.$updateNotebookCellMetadata(this._notebook.viewType, this._notebook.uri, this.handle, this._metadata);
}
attachTextDocument(document: ExtHostDocumentData) {
@@ -217,9 +228,12 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
return this._versionId;
}
private _disposed = false;
constructor(
private readonly _proxy: MainThreadNotebookShape,
private _documentsAndEditors: ExtHostDocumentsAndEditors,
private _emitter: INotebookEventEmitter,
public viewType: string,
public uri: URI,
public renderingHandler: ExtHostNotebookOutputRenderingHandler
@@ -238,6 +252,7 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
}
dispose() {
this._disposed = true;
super.dispose();
this._cellDisposableMapping.forEach(cell => cell.dispose());
}
@@ -246,7 +261,8 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
get isDirty() { return false; }
accpetModelChanged(event: NotebookCellsChangedEvent) {
accpetModelChanged(event: NotebookCellsChangedEvent): void {
this._versionId = event.versionId;
if (event.kind === NotebookCellsChangeType.ModelChange) {
this.$spliceNotebookCells(event.changes);
} else if (event.kind === NotebookCellsChangeType.Move) {
@@ -258,19 +274,19 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
} else if (event.kind === NotebookCellsChangeType.ChangeLanguage) {
this.$changeCellLanguage(event.index, event.language);
}
this._versionId = event.versionId;
}
private $spliceNotebookCells(splices: NotebookCellsSplice2[]): void {
if (!splices.length) {
if (this._disposed) {
return;
}
let contentChangeEvents: vscode.NotebookCellsChangeData[] = [];
splices.reverse().forEach(splice => {
let cellDtos = splice[2];
let newCells = cellDtos.map(cell => {
const extCell = new ExtHostCell(this.viewType, this.uri, cell.handle, URI.revive(cell.uri), cell.source.join('\n'), cell.cellKind, cell.language, cell.outputs, cell.metadata, this._proxy);
const extCell = new ExtHostCell(this, cell.handle, URI.revive(cell.uri), cell.source.join('\n'), cell.cellKind, cell.language, cell.outputs, cell.metadata, this._proxy);
const documentData = this._documentsAndEditors.getDocument(URI.revive(cell.uri));
if (documentData) {
@@ -297,107 +313,88 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
}
this.cells.splice(splice[0], splice[1], ...newCells);
const event: vscode.NotebookCellsChangeData = {
start: splice[0],
deletedCount: splice[1],
items: newCells
};
contentChangeEvents.push(event);
});
this._emitter.emitModelChange({
document: this,
changes: contentChangeEvents
});
}
private $moveCell(index: number, newIdx: number) {
private $moveCell(index: number, newIdx: number): void {
const cells = this.cells.splice(index, 1);
this.cells.splice(newIdx, 0, ...cells);
const changes: vscode.NotebookCellsChangeData[] = [{
start: index,
deletedCount: 1,
items: []
}, {
start: newIdx,
deletedCount: 0,
items: cells
}];
this._emitter.emitModelChange({
document: this,
changes
});
}
private $clearCellOutputs(index: number) {
private $clearCellOutputs(index: number): void {
const cell = this.cells[index];
cell.outputs = [];
const event: vscode.NotebookCellOutputsChangeEvent = { document: this, cells: [cell] };
this._emitter.emitCellOutputsChange(event);
}
private $clearAllCellOutputs() {
this.cells.forEach(cell => cell.outputs = []);
private $clearAllCellOutputs(): void {
const modifedCells: vscode.NotebookCell[] = [];
this.cells.forEach(cell => {
if (cell.outputs.length !== 0) {
cell.outputs = [];
modifedCells.push(cell);
}
});
const event: vscode.NotebookCellOutputsChangeEvent = { document: this, cells: modifedCells };
this._emitter.emitCellOutputsChange(event);
}
private $changeCellLanguage(index: number, language: string) {
private $changeCellLanguage(index: number, language: string): void {
const cell = this.cells[index];
cell.language = language;
const event: vscode.NotebookCellLanguageChangeEvent = { document: this, cell, language };
this._emitter.emitCellLanguageChange(event);
}
eventuallyUpdateCellOutputs(cell: ExtHostCell, diffs: ISplice<vscode.CellOutput>[]) {
async eventuallyUpdateCellOutputs(cell: ExtHostCell, diffs: ISplice<vscode.CellOutput>[]) {
let renderers = new Set<number>();
let outputDtos: NotebookCellOutputsSplice[] = diffs.map(diff => {
let outputs = diff.toInsert;
let transformedOutputs = outputs.map(output => {
if (output.outputKind === CellOutputKind.Rich) {
const ret = this.transformMimeTypes(output);
if (ret.orderedMimeTypes[ret.pickedMimeTypeIndex].isResolved) {
renderers.add(ret.orderedMimeTypes[ret.pickedMimeTypeIndex].rendererId!);
}
return ret;
} else {
return output as IStreamOutput | IErrorOutput;
}
});
return [diff.start, diff.deleteCount, transformedOutputs];
return [diff.start, diff.deleteCount, outputs];
});
this._proxy.$spliceNotebookCellOutputs(this.viewType, this.uri, cell.handle, outputDtos, Array.from(renderers));
}
transformMimeTypes(output: vscode.CellDisplayOutput): ITransformedDisplayOutputDto {
let mimeTypes = Object.keys(output.data);
let coreDisplayOrder = this.renderingHandler.outputDisplayOrder;
const sorted = sortMimeTypes(mimeTypes, coreDisplayOrder?.userOrder || [], this._displayOrder, coreDisplayOrder?.defaultOrder || []);
let orderMimeTypes: IOrderedMimeType[] = [];
sorted.forEach(mimeType => {
let handlers = this.renderingHandler.findBestMatchedRenderer(mimeType);
if (handlers.length) {
let renderedOutput = handlers[0].render(this, output, mimeType);
orderMimeTypes.push({
mimeType: mimeType,
isResolved: true,
rendererId: handlers[0].handle,
output: renderedOutput
});
for (let i = 1; i < handlers.length; i++) {
orderMimeTypes.push({
mimeType: mimeType,
isResolved: false,
rendererId: handlers[i].handle
});
}
if (mimeTypeSupportedByCore(mimeType)) {
orderMimeTypes.push({
mimeType: mimeType,
isResolved: false,
rendererId: -1
});
}
} else {
orderMimeTypes.push({
mimeType: mimeType,
isResolved: false
});
}
await this._proxy.$spliceNotebookCellOutputs(this.viewType, this.uri, cell.handle, outputDtos, Array.from(renderers));
this._emitter.emitCellOutputsChange({
document: this,
cells: [cell]
});
return {
outputKind: output.outputKind,
data: output.data,
orderedMimeTypes: orderMimeTypes,
pickedMimeTypeIndex: 0
};
}
getCell(cellHandle: number) {
return this.cells.find(cell => cell.handle === cellHandle);
}
getCell2(cellUri: UriComponents) {
return this.cells.find(cell => cell.uri.fragment === cellUri.fragment);
}
attachCellTextDocument(textDocument: ExtHostDocumentData) {
let cell = this.cells.find(cell => cell.uri.toString() === textDocument.document.uri.toString());
if (cell) {
@@ -448,25 +445,10 @@ export class NotebookEditorCellEditBuilder implements vscode.NotebookEditorCellE
source: sourceArr,
language,
cellKind: type,
outputs: (outputs as any[]), // TODO@rebornix
outputs: outputs,
metadata
};
const transformedOutputs = outputs.map(output => {
if (output.outputKind === CellOutputKind.Rich) {
const ret = this.editor.document.transformMimeTypes(output);
if (ret.orderedMimeTypes[ret.pickedMimeTypeIndex].isResolved) {
this._renderers.add(ret.orderedMimeTypes[ret.pickedMimeTypeIndex].rendererId!);
}
return ret;
} else {
return output as IStreamOutput | IErrorOutput;
}
});
cell.outputs = transformedOutputs;
this._collectedEdits.push({
editType: CellEditType.Insert,
index,
@@ -489,6 +471,35 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
private _viewColumn: vscode.ViewColumn | undefined;
selection?: ExtHostCell = undefined;
private _active: boolean = false;
get active(): boolean {
return this._active;
}
set active(_state: boolean) {
throw readonly('active');
}
private _visible: boolean = false;
get visible(): boolean {
return this._visible;
}
set visible(_state: boolean) {
throw readonly('visible');
}
_acceptVisibility(value: boolean) {
this._visible = value;
}
_acceptActive(value: boolean) {
this._active = value;
}
private _onDidDispose = new Emitter<void>();
readonly onDidDispose: Event<void> = this._onDidDispose.event;
onDidReceiveMessage: vscode.Event<any> = this._onDidReceiveMessage.event;
constructor(
@@ -497,6 +508,7 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
public uri: URI,
private _proxy: MainThreadNotebookShape,
private _onDidReceiveMessage: Emitter<any>,
private _webviewInitData: WebviewInitData,
public document: ExtHostNotebookDocument,
private _documentsAndEditors: ExtHostDocumentsAndEditors
) {
@@ -584,6 +596,13 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
return this._proxy.$postMessage(this.document.handle, message);
}
asWebviewUri(localResource: vscode.Uri): vscode.Uri {
return asWebviewUri(this._webviewInitData, this.id, localResource);
}
dispose() {
this._onDidDispose.fire();
super.dispose();
}
}
export class ExtHostNotebookOutputRenderer {
@@ -620,16 +639,21 @@ export interface ExtHostNotebookOutputRenderingHandler {
}
export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostNotebookOutputRenderingHandler {
private static _handlePool: number = 0;
private readonly _proxy: MainThreadNotebookShape;
private readonly _notebookContentProviders = new Map<string, { readonly provider: vscode.NotebookContentProvider, readonly extension: IExtensionDescription; }>();
private readonly _notebookKernels = new Map<string, { readonly kernel: vscode.NotebookKernel, readonly extension: IExtensionDescription; }>();
private readonly _documents = new Map<string, ExtHostNotebookDocument>();
private readonly _unInitializedDocuments = new Map<string, ExtHostNotebookDocument>();
private readonly _editors = new Map<string, { editor: ExtHostNotebookEditor, onDidReceiveMessage: Emitter<any>; }>();
private readonly _notebookOutputRenderers = new Map<number, ExtHostNotebookOutputRenderer>();
private readonly _onDidChangeNotebookDocument = new Emitter<{ document: ExtHostNotebookDocument, changes: NotebookCellsChangedEvent[]; }>();
readonly onDidChangeNotebookDocument: Event<{ document: ExtHostNotebookDocument, changes: NotebookCellsChangedEvent[]; }> = this._onDidChangeNotebookDocument.event;
private readonly _notebookOutputRenderers = new Map<string, ExtHostNotebookOutputRenderer>();
private readonly _onDidChangeNotebookCells = new Emitter<vscode.NotebookCellsChangeEvent>();
readonly onDidChangeNotebookCells = this._onDidChangeNotebookCells.event;
private readonly _onDidChangeCellOutputs = new Emitter<vscode.NotebookCellOutputsChangeEvent>();
readonly onDidChangeCellOutputs = this._onDidChangeCellOutputs.event;
private readonly _onDidChangeCellLanguage = new Emitter<vscode.NotebookCellLanguageChangeEvent>();
readonly onDidChangeCellLanguage = this._onDidChangeCellLanguage.event;
private readonly _onDidChangeActiveNotebookEditor = new Emitter<vscode.NotebookEditor | undefined>();
readonly onDidChangeActiveNotebookEditor = this._onDidChangeActiveNotebookEditor.event;
private _outputDisplayOrder: INotebookDisplayOrder | undefined;
@@ -653,8 +677,11 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
onDidOpenNotebookDocument: Event<vscode.NotebookDocument> = this._onDidOpenNotebookDocument.event;
private _onDidCloseNotebookDocument = new Emitter<vscode.NotebookDocument>();
onDidCloseNotebookDocument: Event<vscode.NotebookDocument> = this._onDidCloseNotebookDocument.event;
visibleNotebookEditors: ExtHostNotebookEditor[] = [];
private _onDidChangeVisibleNotebookEditors = new Emitter<vscode.NotebookEditor[]>();
onDidChangeVisibleNotebookEditors = this._onDidChangeVisibleNotebookEditors.event;
constructor(mainContext: IMainContext, commands: ExtHostCommands, private _documentsAndEditors: ExtHostDocumentsAndEditors) {
constructor(mainContext: IMainContext, commands: ExtHostCommands, private _documentsAndEditors: ExtHostDocumentsAndEditors, private readonly _webviewInitData: WebviewInitData) {
this._proxy = mainContext.getProxy(MainContext.MainThreadNotebook);
commands.registerArgumentProcessor({
@@ -683,15 +710,85 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
filter: vscode.NotebookOutputSelector,
renderer: vscode.NotebookOutputRenderer
): vscode.Disposable {
if (this._notebookKernels.has(type)) {
throw new Error(`Notebook renderer for '${type}' already registered`);
}
let extHostRenderer = new ExtHostNotebookOutputRenderer(type, filter, renderer);
this._notebookOutputRenderers.set(extHostRenderer.handle, extHostRenderer);
this._proxy.$registerNotebookRenderer({ id: extension.identifier, location: extension.extensionLocation }, type, filter, extHostRenderer.handle, renderer.preloads || []);
return new VSCodeDisposable(() => {
this._notebookOutputRenderers.delete(extHostRenderer.handle);
this._proxy.$unregisterNotebookRenderer(extHostRenderer.handle);
this._notebookOutputRenderers.set(extHostRenderer.type, extHostRenderer);
this._proxy.$registerNotebookRenderer({ id: extension.identifier, location: extension.extensionLocation }, type, filter, renderer.preloads || []);
return new extHostTypes.Disposable(() => {
this._notebookOutputRenderers.delete(extHostRenderer.type);
this._proxy.$unregisterNotebookRenderer(extHostRenderer.type);
});
}
async $renderOutputs(uriComponents: UriComponents, id: string, request: IOutputRenderRequest<UriComponents>): Promise<IOutputRenderResponse<UriComponents> | undefined> {
if (!this._notebookOutputRenderers.has(id)) {
throw new Error(`Notebook renderer for '${id}' is not registered`);
}
const document = this._documents.get(URI.revive(uriComponents).toString());
if (!document) {
return undefined; // {{SQL CARBON EDIT}} strict-null-checks
}
const renderer = this._notebookOutputRenderers.get(id)!;
const cellsResponse: IOutputRenderResponseCellInfo<UriComponents>[] = request.items.map(cellInfo => {
const cell = document.getCell2(cellInfo.key);
const outputResponse: IOutputRenderResponseOutputInfo[] = cellInfo.outputs.map(output => {
return {
index: output.index,
mimeType: output.mimeType,
handlerId: id,
transformedOutput: renderer.render(document, cell!.outputs[output.index] as vscode.CellDisplayOutput, output.mimeType)
};
});
return {
key: cellInfo.key,
outputs: outputResponse
};
});
return { items: cellsResponse };
}
/**
* The request carry the raw data for outputs so we don't look up in the existing document
*/
async $renderOutputs2<T>(uriComponents: UriComponents, id: string, request: IOutputRenderRequest<T>): Promise<IOutputRenderResponse<T> | undefined> {
if (!this._notebookOutputRenderers.has(id)) {
throw new Error(`Notebook renderer for '${id}' is not registered`);
}
const document = this._documents.get(URI.revive(uriComponents).toString());
if (!document) {
return undefined; // {{SQL CARBON EDIT}} strict-null-checks
}
const renderer = this._notebookOutputRenderers.get(id)!;
const cellsResponse: IOutputRenderResponseCellInfo<T>[] = request.items.map(cellInfo => {
const outputResponse: IOutputRenderResponseOutputInfo[] = cellInfo.outputs.map(output => {
return {
index: output.index,
mimeType: output.mimeType,
handlerId: id,
transformedOutput: renderer.render(document, output.output! as vscode.CellDisplayOutput, output.mimeType)
};
});
return {
key: cellInfo.key,
outputs: outputResponse
};
});
return { items: cellsResponse };
}
findBestMatchedRenderer(mimeType: string): ExtHostNotebookOutputRenderer[] {
let matches: ExtHostNotebookOutputRenderer[] = [];
for (let renderer of this._notebookOutputRenderers) {
@@ -713,50 +810,70 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
throw new Error(`Notebook provider for '${viewType}' already registered`);
}
// if ((<any>provider).executeCell) {
// throw new Error('NotebookContentKernel.executeCell is removed, please use vscode.notebook.registerNotebookKernel instead.');
// }
this._notebookContentProviders.set(viewType, { extension, provider });
this._proxy.$registerNotebookProvider({ id: extension.identifier, location: extension.extensionLocation }, viewType);
return new VSCodeDisposable(() => {
const listener = provider.onDidChangeNotebook
? provider.onDidChangeNotebook(e => this._proxy.$onNotebookChange(viewType, e.document.uri))
: Disposable.None;
this._proxy.$registerNotebookProvider({ id: extension.identifier, location: extension.extensionLocation }, viewType, provider.kernel ? { id: viewType, label: provider.kernel.label, extensionLocation: extension.extensionLocation, preloads: provider.kernel.preloads } : undefined);
return new extHostTypes.Disposable(() => {
listener.dispose();
this._notebookContentProviders.delete(viewType);
this._proxy.$unregisterNotebookProvider(viewType);
});
}
async $resolveNotebookData(viewType: string, uri: UriComponents): Promise<NotebookDataDto | undefined> {
let provider = this._notebookContentProviders.get(viewType);
let document = this._documents.get(URI.revive(uri).toString());
registerNotebookKernel(extension: IExtensionDescription, id: string, selectors: vscode.GlobPattern[], kernel: vscode.NotebookKernel): vscode.Disposable {
if (this._notebookKernels.has(id)) {
throw new Error(`Notebook kernel for '${id}' already registered`);
}
this._notebookKernels.set(id, { kernel, extension });
const transformedSelectors = selectors.map(selector => typeConverters.GlobPattern.from(selector));
this._proxy.$registerNotebookKernel({ id: extension.identifier, location: extension.extensionLocation }, id, kernel.label, transformedSelectors, kernel.preloads || []);
return new extHostTypes.Disposable(() => {
this._notebookKernels.delete(id);
this._proxy.$unregisterNotebookKernel(id);
});
}
async $resolveNotebookData(viewType: string, uri: UriComponents): Promise<NotebookDataDto | undefined> {
const provider = this._notebookContentProviders.get(viewType);
const revivedUri = URI.revive(uri);
if (provider) {
let document = this._documents.get(URI.revive(uri).toString());
if (!document) {
const that = this;
document = this._unInitializedDocuments.get(revivedUri.toString()) ?? new ExtHostNotebookDocument(this._proxy, this._documentsAndEditors, {
emitModelChange(event: vscode.NotebookCellsChangeEvent): void {
that._onDidChangeNotebookCells.fire(event);
},
emitCellOutputsChange(event: vscode.NotebookCellOutputsChangeEvent): void {
that._onDidChangeCellOutputs.fire(event);
},
emitCellLanguageChange(event: vscode.NotebookCellLanguageChangeEvent): void {
that._onDidChangeCellLanguage.fire(event);
}
}, viewType, revivedUri, this);
this._unInitializedDocuments.set(revivedUri.toString(), document);
}
if (provider && document) {
const rawCells = await provider.provider.openNotebook(URI.revive(uri));
const renderers = new Set<number>();
const dto = {
metadata: {
...notebookDocumentMetadataDefaults,
...rawCells.metadata
},
languages: rawCells.languages,
cells: rawCells.cells.map(cell => {
let transformedOutputs = cell.outputs.map(output => {
if (output.outputKind === CellOutputKind.Rich) {
// TODO display string[]
const ret = this._transformMimeTypes(document!, (rawCells.metadata.displayOrder as string[]) || [], output);
if (ret.orderedMimeTypes[ret.pickedMimeTypeIndex].isResolved) {
renderers.add(ret.orderedMimeTypes[ret.pickedMimeTypeIndex].rendererId!);
}
return ret;
} else {
return output as IStreamOutput | IErrorOutput;
}
});
return {
language: cell.language,
cellKind: cell.cellKind,
metadata: cell.metadata,
source: cell.source,
outputs: transformedOutputs
};
})
cells: rawCells.cells,
};
return dto;
@@ -765,58 +882,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
return undefined; // {{SQL CARBON EDIT}}
}
private _transformMimeTypes(document: ExtHostNotebookDocument, displayOrder: string[], output: vscode.CellDisplayOutput): ITransformedDisplayOutputDto {
let mimeTypes = Object.keys(output.data);
let coreDisplayOrder = this.outputDisplayOrder;
const sorted = sortMimeTypes(mimeTypes, coreDisplayOrder?.userOrder || [], displayOrder, coreDisplayOrder?.defaultOrder || []);
let orderMimeTypes: IOrderedMimeType[] = [];
sorted.forEach(mimeType => {
let handlers = this.findBestMatchedRenderer(mimeType);
if (handlers.length) {
let renderedOutput = handlers[0].render(document, output, mimeType);
orderMimeTypes.push({
mimeType: mimeType,
isResolved: true,
rendererId: handlers[0].handle,
output: renderedOutput
});
for (let i = 1; i < handlers.length; i++) {
orderMimeTypes.push({
mimeType: mimeType,
isResolved: false,
rendererId: handlers[i].handle
});
}
if (mimeTypeSupportedByCore(mimeType)) {
orderMimeTypes.push({
mimeType: mimeType,
isResolved: false,
rendererId: -1
});
}
} else {
orderMimeTypes.push({
mimeType: mimeType,
isResolved: false
});
}
});
return {
outputKind: output.outputKind,
data: output.data,
orderedMimeTypes: orderMimeTypes,
pickedMimeTypeIndex: 0
};
}
async $executeNotebook(viewType: string, uri: UriComponents, cellHandle: number | undefined, token: CancellationToken): Promise<void> {
async $executeNotebook(viewType: string, uri: UriComponents, cellHandle: number | undefined, useAttachedKernel: boolean, token: CancellationToken): Promise<void> {
let document = this._documents.get(URI.revive(uri).toString());
if (!document) {
@@ -824,9 +890,38 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}
if (this._notebookContentProviders.has(viewType)) {
let cell = cellHandle !== undefined ? document.getCell(cellHandle) : undefined;
const cell = cellHandle !== undefined ? document.getCell(cellHandle) : undefined;
const provider = this._notebookContentProviders.get(viewType)!.provider;
return this._notebookContentProviders.get(viewType)!.provider.executeCell(document, cell, token);
if (provider.kernel && useAttachedKernel) {
if (cell) {
return provider.kernel.executeCell(document, cell, token);
} else {
return provider.kernel.executeAllCells(document, token);
}
}
}
}
async $executeNotebook2(kernelId: string, viewType: string, uri: UriComponents, cellHandle: number | undefined, token: CancellationToken): Promise<void> {
let document = this._documents.get(URI.revive(uri).toString());
if (!document || document.viewType !== viewType) {
return;
}
let kernelInfo = this._notebookKernels.get(kernelId);
if (!kernelInfo) {
return;
}
let cell = cellHandle !== undefined ? document.getCell(cellHandle) : undefined;
if (cell) {
return kernelInfo.kernel.executeCell(document, cell, token);
} else {
return kernelInfo.kernel.executeAllCells(document, token);
}
}
@@ -872,8 +967,21 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
this._outputDisplayOrder = displayOrder;
}
$onDidReceiveMessage(uri: UriComponents, message: any): void {
let editor = this._editors.get(URI.revive(uri).toString());
// TODO: remove document - editor one on one mapping
private _getEditorFromURI(uriComponents: UriComponents) {
const uriStr = URI.revive(uriComponents).toString();
let editor: { editor: ExtHostNotebookEditor, onDidReceiveMessage: Emitter<any>; } | undefined;
this._editors.forEach(e => {
if (e.editor.uri.toString() === uriStr) {
editor = e;
}
});
return editor;
}
$onDidReceiveMessage(editorId: string, message: any): void {
let editor = this._editors.get(editorId);
if (editor) {
editor.onDidReceiveMessage.fire(message);
@@ -881,20 +989,15 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEvent): void {
let editor = this._editors.get(URI.revive(uriComponents).toString());
const document = this._documents.get(URI.revive(uriComponents).toString());
if (editor) {
editor.editor.document.accpetModelChanged(event);
this._onDidChangeNotebookDocument.fire({
document: editor.editor.document,
changes: [event]
});
if (document) {
document.accpetModelChanged(event);
}
}
$acceptEditorPropertiesChanged(uriComponents: UriComponents, data: INotebookEditorPropertiesChangeData): void {
let editor = this._editors.get(URI.revive(uriComponents).toString());
let editor = this._getEditorFromURI(uriComponents);
if (!editor) {
return;
@@ -910,61 +1013,196 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
editor.editor.selection = undefined;
}
}
if (data.metadata) {
editor.editor.document.metadata = {
...notebookDocumentMetadataDefaults,
...data.metadata
};
}
}
private _createExtHostEditor(document: ExtHostNotebookDocument, editorId: string, selections: number[]) {
const onDidReceiveMessage = new Emitter<any>();
const revivedUri = document.uri;
let editor = new ExtHostNotebookEditor(
document.viewType,
editorId,
revivedUri,
this._proxy,
onDidReceiveMessage,
this._webviewInitData,
document,
this._documentsAndEditors
);
const cells = editor.document.cells;
if (selections.length) {
const firstCell = selections[0];
editor.selection = cells.find(cell => cell.handle === firstCell);
} else {
editor.selection = undefined;
}
this._editors.get(editorId)?.editor.dispose();
this._editors.set(editorId, { editor, onDidReceiveMessage });
}
async $acceptDocumentAndEditorsDelta(delta: INotebookDocumentsAndEditorsDelta) {
let editorChanged = false;
if (delta.removedDocuments) {
delta.removedDocuments.forEach((uri) => {
let document = this._documents.get(URI.revive(uri).toString());
const revivedUri = URI.revive(uri);
const revivedUriStr = revivedUri.toString();
let document = this._documents.get(revivedUriStr);
if (document) {
document.dispose();
this._documents.delete(URI.revive(uri).toString());
this._documents.delete(revivedUriStr);
this._onDidCloseNotebookDocument.fire(document);
}
let editor = this._editors.get(URI.revive(uri).toString());
if (editor) {
editor.editor.dispose();
editor.onDidReceiveMessage.dispose();
this._editors.delete(URI.revive(uri).toString());
}
[...this._editors.values()].forEach((e) => {
if (e.editor.uri.toString() === revivedUriStr) {
e.editor.dispose();
e.onDidReceiveMessage.dispose();
this._editors.delete(e.editor.id);
editorChanged = true;
}
});
});
}
if (delta.addedDocuments) {
delta.addedDocuments.forEach(modelData => {
const revivedUri = URI.revive(modelData.uri);
const revivedUriStr = revivedUri.toString();
const viewType = modelData.viewType;
if (!this._documents.has(revivedUri.toString())) {
let document = new ExtHostNotebookDocument(this._proxy, this._documentsAndEditors, viewType, revivedUri, this);
this._documents.set(revivedUri.toString(), document);
if (!this._documents.has(revivedUriStr)) {
const that = this;
let document = this._unInitializedDocuments.get(revivedUriStr) ?? new ExtHostNotebookDocument(this._proxy, this._documentsAndEditors, {
emitModelChange(event: vscode.NotebookCellsChangeEvent): void {
that._onDidChangeNotebookCells.fire(event);
},
emitCellOutputsChange(event: vscode.NotebookCellOutputsChangeEvent): void {
that._onDidChangeCellOutputs.fire(event);
},
emitCellLanguageChange(event: vscode.NotebookCellLanguageChangeEvent): void {
that._onDidChangeCellLanguage.fire(event);
}
}, viewType, revivedUri, this);
this._unInitializedDocuments.delete(revivedUriStr);
if (modelData.metadata) {
document.metadata = {
...notebookDocumentMetadataDefaults,
...modelData.metadata
};
}
document.accpetModelChanged({
kind: NotebookCellsChangeType.ModelChange,
versionId: modelData.versionId,
changes: [[
0,
0,
modelData.cells
]]
});
this._documents.get(revivedUriStr)?.dispose();
this._documents.set(revivedUriStr, document);
// create editor if populated
if (modelData.attachedEditor) {
this._createExtHostEditor(document, modelData.attachedEditor.id, modelData.attachedEditor.selections);
editorChanged = true;
}
}
const onDidReceiveMessage = new Emitter<any>();
const document = this._documents.get(revivedUri.toString())!;
let editor = new ExtHostNotebookEditor(
viewType,
`${ExtHostNotebookController._handlePool++}`,
revivedUri,
this._proxy,
onDidReceiveMessage,
document,
this._documentsAndEditors
);
const document = this._documents.get(revivedUriStr)!;
this._onDidOpenNotebookDocument.fire(document);
// TODO, does it already exist?
this._editors.set(revivedUri.toString(), { editor, onDidReceiveMessage });
});
}
if (delta.newActiveEditor) {
this._activeNotebookDocument = this._documents.get(URI.revive(delta.newActiveEditor).toString());
this._activeNotebookEditor = this._editors.get(URI.revive(delta.newActiveEditor).toString())?.editor;
if (delta.addedEditors) {
delta.addedEditors.forEach(editorModelData => {
if (this._editors.has(editorModelData.id)) {
return;
}
const revivedUri = URI.revive(editorModelData.documentUri);
const document = this._documents.get(revivedUri.toString());
if (document) {
this._createExtHostEditor(document, editorModelData.id, editorModelData.selections);
editorChanged = true;
}
});
}
const removedEditors: { editor: ExtHostNotebookEditor, onDidReceiveMessage: Emitter<any>; }[] = [];
if (delta.removedEditors) {
delta.removedEditors.forEach(editorid => {
const editor = this._editors.get(editorid);
if (editor) {
editorChanged = true;
this._editors.delete(editorid);
if (this.activeNotebookEditor?.id === editor.editor.id) {
this._activeNotebookEditor = undefined;
this._activeNotebookDocument = undefined;
}
removedEditors.push(editor);
}
});
}
if (editorChanged) {
removedEditors.forEach(e => {
e.editor.dispose();
e.onDidReceiveMessage.dispose();
});
}
if (delta.visibleEditors) {
this.visibleNotebookEditors = delta.visibleEditors.map(id => this._editors.get(id)?.editor).filter(editor => !!editor) as ExtHostNotebookEditor[];
const visibleEditorsSet = new Set<string>();
this.visibleNotebookEditors.forEach(editor => visibleEditorsSet.add(editor.id));
[...this._editors.values()].forEach((e) => {
const newValue = visibleEditorsSet.has(e.editor.id);
e.editor._acceptVisibility(newValue);
});
this.visibleNotebookEditors = [...this._editors.values()].map(e => e.editor).filter(e => e.visible);
this._onDidChangeVisibleNotebookEditors.fire(this.visibleNotebookEditors);
}
if (delta.newActiveEditor !== undefined) {
if (delta.newActiveEditor) {
this._activeNotebookEditor = this._editors.get(delta.newActiveEditor)?.editor;
this._activeNotebookEditor?._acceptActive(true);
this._activeNotebookDocument = this._activeNotebookEditor ? this._documents.get(this._activeNotebookEditor!.uri.toString()) : undefined;
} else {
this._activeNotebookEditor = undefined;
this._activeNotebookDocument = undefined;
}
this._onDidChangeActiveNotebookEditor.fire(this._activeNotebookEditor);
}
[...this._editors.values()].forEach((e) => {
if (e.editor !== this.activeNotebookEditor) {
e.editor._acceptActive(false);
}
});
}
}