Update output editor when output model is being updated.

This commit is contained in:
rebornix 2021-11-23 17:40:11 -08:00
parent 8e18e33892
commit c1f2f40bcd
No known key found for this signature in database
GPG key ID: 181FC90D15393C20
3 changed files with 112 additions and 83 deletions

View file

@ -13,7 +13,7 @@ import { format } from 'vs/base/common/jsonFormatter';
import { applyEdits } from 'vs/base/common/jsonEdit';
import { ITextModel, ITextBufferFactory, DefaultEndOfLine, ITextBuffer } from 'vs/editor/common/model';
import { IModelService } from 'vs/editor/common/services/modelService';
import { IModeService } from 'vs/editor/common/services/modeService';
import { ILanguageSelection, IModeService } from 'vs/editor/common/services/modeService';
import { ITextModelContentProvider, ITextModelService } from 'vs/editor/common/services/resolverService';
import * as nls from 'vs/nls';
import { Extensions, IConfigurationPropertySchema, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
@ -100,6 +100,7 @@ import { NotebookExecutionService } from 'vs/workbench/contrib/notebook/browser/
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';
/*--------------------------------------------------------------------------------------------- */
@ -372,25 +373,55 @@ class CellInfoContentProvider {
return result;
}
private parseStreamOutput(resource: URI, op?: ICellOutput) {
private parseStreamOutput(op?: ICellOutput): { content: string, mode: ILanguageSelection } | undefined {
if (!op) {
return;
}
const streamOutputData = getStreamOutputData(op.outputs);
if (streamOutputData) {
const result = this._modelService.createModel(
streamOutputData,
this._modeService.create('plaintext'),
resource
);
return result;
return {
content: streamOutputData,
mode: this._modeService.create('plaintext')
};
}
return;
}
private _getResult(data: {
notebook: URI;
handle: number;
outputId?: string | undefined;
}, cell: NotebookCellTextModel) {
let result: { content: string, mode: ILanguageSelection } | undefined = undefined;
const mode = this._modeService.create('json');
const op = cell.outputs.find(op => op.outputId === data.outputId);
const streamOutputData = this.parseStreamOutput(op);
if (streamOutputData) {
result = streamOutputData;
return result;
}
const content = JSON.stringify(cell.outputs.map(output => ({
metadata: output.metadata,
outputItems: output.outputs.map(opit => ({
mimeType: opit.mime,
data: opit.data.toString()
}))
})));
const edits = format(content, undefined, {});
const outputSource = applyEdits(content, edits);
result = {
content: outputSource,
mode
};
return result;
}
async provideOutputTextContent(resource: URI): Promise<ITextModel | null> {
const existing = this._modelService.getModel(resource);
if (existing) {
@ -403,48 +434,37 @@ class CellInfoContentProvider {
}
const ref = await this._notebookModelResolverService.resolve(data.notebook);
let result: ITextModel | null = null;
const cell = ref.object.notebook.cells.find(cell => cell.handle === data.handle);
const mode = this._modeService.create('json');
for (const cell of ref.object.notebook.cells) {
if (cell.handle !== data.handle) {
continue;
}
const op = cell.outputs.find(op => op.outputId === data.outputId);
const streamOutputData = this.parseStreamOutput(resource, op);
if (streamOutputData) {
result = streamOutputData;
break;
}
const content = JSON.stringify(cell.outputs.map(output => ({
metadata: output.metadata,
outputItems: output.outputs.map(opit => ({
mimeType: opit.mime,
data: opit.data.toString()
}))
})));
const edits = format(content, undefined, {});
const outputSource = applyEdits(content, edits);
result = this._modelService.createModel(
outputSource,
mode,
resource
);
break;
if (!cell) {
return null;
}
const result = this._getResult(data, cell);
if (result) {
const once = result.onWillDispose(() => {
const model = this._modelService.createModel(result.content, result.mode, resource);
const cellModelListener = Event.any(cell.onDidChangeOutputs, cell.onDidChangeOutputItems)(() => {
const newResult = this._getResult(data, cell);
if (!newResult) {
return;
}
model.setValue(newResult.content);
model.setMode(newResult.mode.languageId);
});
const once = model.onWillDispose(() => {
once.dispose();
cellModelListener.dispose();
ref.dispose();
});
return model;
}
return result;
return null;
}
}

View file

@ -15,12 +15,15 @@ import { PieceTreeTextBufferBuilder } from 'vs/editor/common/model/pieceTreeText
import { TextModel } from 'vs/editor/common/model/textModel';
import { IModeService } from 'vs/editor/common/services/modeService';
import { NotebookCellOutputTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellOutputTextModel';
import { CellInternalMetadataChangedEvent, CellKind, ICell, ICellOutput, IOutputDto, NotebookCellInternalMetadata, NotebookCellMetadata, NotebookCellOutputsSplice, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellInternalMetadataChangedEvent, CellKind, ICell, ICellOutput, IOutputDto, IOutputItemDto, NotebookCellInternalMetadata, NotebookCellMetadata, NotebookCellOutputsSplice, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
export class NotebookCellTextModel extends Disposable implements ICell {
private readonly _onDidChangeOutputs = this._register(new Emitter<NotebookCellOutputsSplice>());
onDidChangeOutputs: Event<NotebookCellOutputsSplice> = this._onDidChangeOutputs.event;
private readonly _onDidChangeOutputItems = this._register(new Emitter<void>());
onDidChangeOutputItems: Event<void> = this._onDidChangeOutputItems.event;
private readonly _onDidChangeContent = this._register(new Emitter<'content' | 'language' | 'mime'>());
onDidChangeContent: Event<'content' | 'language' | 'mime'> = this._onDidChangeContent.event;
@ -264,6 +267,24 @@ export class NotebookCellTextModel extends Disposable implements ICell {
this._onDidChangeOutputs.fire(splice);
}
changeOutputItems(outputId: string, append: boolean, items: IOutputItemDto[]): boolean {
const outputIndex = this.outputs.findIndex(output => output.outputId === outputId);
if (outputIndex < 0) {
return false;
}
const output = this.outputs[outputIndex];
if (append) {
output.appendData(items);
} else {
output.replaceData(items);
}
this._onDidChangeOutputItems.fire();
return true;
}
private _outputNotEqualFastCheck(left: ICellOutput[], right: ICellOutput[]) {
if (left.length !== right.length) {
return false;

View file

@ -955,53 +955,41 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
}
private _appendNotebookCellOutputItems(cell: NotebookCellTextModel, outputId: string, items: IOutputItemDto[]) {
const outputIndex = cell.outputs.findIndex(output => output.outputId === outputId);
if (cell.changeOutputItems(outputId, true, items)) {
this._pauseableEmitter.fire({
rawEvents: [{
kind: NotebookCellsChangeType.OutputItem,
index: this._cells.indexOf(cell),
outputId: outputId,
outputItems: items,
append: true,
transient: this.transientOptions.transientOutputs
if (outputIndex < 0) {
return;
}],
versionId: this.versionId,
synchronous: true,
endSelectionState: undefined
});
}
const output = cell.outputs[outputIndex];
output.appendData(items);
this._pauseableEmitter.fire({
rawEvents: [{
kind: NotebookCellsChangeType.OutputItem,
index: this._cells.indexOf(cell),
outputId: output.outputId,
outputItems: items,
append: true,
transient: this.transientOptions.transientOutputs
}],
versionId: this.versionId,
synchronous: true,
endSelectionState: undefined
});
}
private _replaceNotebookCellOutputItems(cell: NotebookCellTextModel, outputId: string, items: IOutputItemDto[]) {
const outputIndex = cell.outputs.findIndex(output => output.outputId === outputId);
if (cell.changeOutputItems(outputId, false, items)) {
this._pauseableEmitter.fire({
rawEvents: [{
kind: NotebookCellsChangeType.OutputItem,
index: this._cells.indexOf(cell),
outputId: outputId,
outputItems: items,
append: false,
transient: this.transientOptions.transientOutputs
if (outputIndex < 0) {
return;
}],
versionId: this.versionId,
synchronous: true,
endSelectionState: undefined
});
}
const output = cell.outputs[outputIndex];
output.replaceData(items);
this._pauseableEmitter.fire({
rawEvents: [{
kind: NotebookCellsChangeType.OutputItem,
index: this._cells.indexOf(cell),
outputId: output.outputId,
outputItems: items,
append: false,
transient: this.transientOptions.transientOutputs
}],
versionId: this.versionId,
synchronous: true,
endSelectionState: undefined
});
}
private _moveCellToIdx(index: number, length: number, newIdx: number, synchronous: boolean, pushedToUndoStack: boolean, beforeSelections: ISelectionState | undefined, endSelections: ISelectionState | undefined): boolean {