This commit is contained in:
Don Jayamanne 2024-08-22 11:26:50 +10:00
parent d45795cfc4
commit 5809a68666
No known key found for this signature in database
GPG key ID: 6E3F5E00E1354B5F
9 changed files with 318 additions and 29 deletions

View file

@ -123,7 +123,10 @@ function createCodeCellFromNotebookCell(cell: NotebookCellData, preferredLanguag
const codeCell: any = {
cell_type: 'code',
execution_count: cell.executionSummary?.executionOrder ?? null,
// Possible the metadata was edited as part of diff view
// In diff view we display execution_count as part of metadata, hence when execution count changes in metadata,
// We need to change that here as well, i.e. give preference to any execution_count value in metadata.
execution_count: cellMetadata.execution_count ?? cell.executionSummary?.executionOrder ?? null,
source: splitMultilineString(cell.value.replace(/\r\n/g, '\n')),
outputs: (cell.outputs || []).map(translateCellDisplayOutput),
metadata: cellMetadata.metadata

View file

@ -66,6 +66,7 @@ export namespace Schemas {
export const vscodeNotebookCellMetadataDiff = 'vscode-notebook-cell-metadata-diff';
export const vscodeNotebookCellOutput = 'vscode-notebook-cell-output';
export const vscodeNotebookCellOutputDiff = 'vscode-notebook-cell-output-diff';
export const vscodeNotebookMetadata = 'vscode-notebook-metadata';
export const vscodeInteractiveInput = 'vscode-interactive-input';
export const vscodeSettings = 'vscode-settings';

View file

@ -11,7 +11,7 @@ import { ContextKeyExpr, ContextKeyExpression } from 'vs/platform/contextkey/com
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { ActiveEditorContext } from 'vs/workbench/common/contextkeys';
import { DiffElementCellViewModelBase, SideBySideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel';
import { INotebookTextDiffEditor, NOTEBOOK_DIFF_CELL_IGNORE_WHITESPACE_KEY, NOTEBOOK_DIFF_CELL_INPUT, NOTEBOOK_DIFF_CELL_PROPERTY, NOTEBOOK_DIFF_CELL_PROPERTY_EXPANDED, NOTEBOOK_DIFF_CELLS_COLLAPSED, NOTEBOOK_DIFF_HAS_UNCHANGED_CELLS, NOTEBOOK_DIFF_UNCHANGED_CELLS_HIDDEN } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser';
import { INotebookTextDiffEditor, NOTEBOOK_DIFF_CELL_IGNORE_WHITESPACE_KEY, NOTEBOOK_DIFF_CELL_INPUT, NOTEBOOK_DIFF_CELL_PROPERTY, NOTEBOOK_DIFF_CELL_PROPERTY_EXPANDED, NOTEBOOK_DIFF_CELLS_COLLAPSED, NOTEBOOK_DIFF_HAS_UNCHANGED_CELLS, NOTEBOOK_DIFF_ITEM_DIFF_STATE, NOTEBOOK_DIFF_ITEM_KIND, NOTEBOOK_DIFF_UNCHANGED_CELLS_HIDDEN } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser';
import { NotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditor';
import { NotebookDiffEditorInput } from 'vs/workbench/contrib/notebook/common/notebookDiffEditorInput';
import { nextChangeIcon, openAsTextIcon, previousChangeIcon, renderOutputIcon, revertIcon, toggleWhitespace } from 'vs/workbench/contrib/notebook/browser/notebookIcons';
@ -26,6 +26,8 @@ import { CellEditType, NOTEBOOK_DIFF_EDITOR_ID } from 'vs/workbench/contrib/note
import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfiguration';
import { NotebookMultiTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookMultiDiffEditor';
import { Codicon } from 'vs/base/common/codicons';
import type { URI } from 'vs/base/common/uri';
import { TextEditorSelectionRevealType, type ITextEditorOptions } from 'vs/platform/editor/common/editor';
// ActiveEditorContext.isEqualTo(SearchEditorConstants.SearchEditorID)
@ -153,12 +155,173 @@ registerAction2(class extends Action2 {
}
});
registerAction2(class GoToFileAction extends Action2 {
constructor() {
super({
id: 'notebook.multiDiffEditor.goToCell',
title: localize2('goToCell', 'Go To Cell'),
icon: Codicon.goToFile,
menu: {
when: ContextKeyExpr.and(ActiveEditorContext.isEqualTo(NotebookMultiTextDiffEditor.ID), ContextKeyExpr.equals(NOTEBOOK_DIFF_ITEM_KIND.key, 'Cell'), ContextKeyExpr.notEquals(NOTEBOOK_DIFF_ITEM_DIFF_STATE.key, 'delete')),
id: MenuId.MultiDiffEditorFileToolbar,
order: 0,
group: 'navigation',
},
});
}
async run(accessor: ServicesAccessor, ...args: any[]): Promise<void> {
const uri = args[0] as URI;
const editorService = accessor.get(IEditorService);
const activeEditorPane = editorService.activeEditorPane;
if (!(activeEditorPane instanceof NotebookMultiTextDiffEditor)) {
return;
}
await editorService.openEditor({
resource: uri,
options: {
selectionRevealType: TextEditorSelectionRevealType.CenterIfOutsideViewport,
} satisfies ITextEditorOptions,
});
}
});
const revertInput = localize('notebook.diff.cell.revertInput', "Revert Input");
registerAction2(class extends Action2 {
constructor() {
super({
id: 'notebook.multiDiffEditor.cell.revertInput',
title: revertInput,
icon: revertIcon,
menu: {
when: ContextKeyExpr.and(ActiveEditorContext.isEqualTo(NotebookMultiTextDiffEditor.ID), ContextKeyExpr.equals(NOTEBOOK_DIFF_ITEM_KIND.key, 'Cell'), ContextKeyExpr.equals(NOTEBOOK_DIFF_ITEM_DIFF_STATE.key, 'modified')),
id: MenuId.MultiDiffEditorFileToolbar,
order: 2,
group: 'navigation',
},
});
}
async run(accessor: ServicesAccessor, ...args: any[]): Promise<void> {
const uri = args[0] as URI;
const editorService = accessor.get(IEditorService);
const activeEditorPane = editorService.activeEditorPane;
if (!(activeEditorPane instanceof NotebookMultiTextDiffEditor)) {
return;
}
const item = activeEditorPane.getDiffElementViewModel(uri);
if (item && item instanceof SideBySideDiffElementViewModel) {
const modified = item.modified;
const original = item.original;
if (!original || !modified) {
return;
}
const bulkEditService = accessor.get(IBulkEditService);
await bulkEditService.apply([
new ResourceTextEdit(modified.uri, { range: modified.textModel.getFullModelRange(), text: original.textModel.getValue() }),
], { quotableLabel: 'Revert Notebook Cell Content Change' });
}
}
});
const revertOutputs = localize('notebook.diff.cell.revertOutputs', "Revert Outputs");
registerAction2(class extends Action2 {
constructor() {
super(
{
id: 'notebook.multiDiffEditor.cell.revertOutputs',
title: revertOutputs,
icon: revertIcon,
f1: false,
menu: {
when: ContextKeyExpr.and(ActiveEditorContext.isEqualTo(NotebookMultiTextDiffEditor.ID), ContextKeyExpr.equals(NOTEBOOK_DIFF_ITEM_KIND.key, 'Output'), ContextKeyExpr.equals(NOTEBOOK_DIFF_ITEM_DIFF_STATE.key, 'modified')),
id: MenuId.MultiDiffEditorFileToolbar,
order: 2,
group: 'navigation',
},
}
);
}
async run(accessor: ServicesAccessor, ...args: any[]): Promise<void> {
const uri = args[0] as URI;
const editorService = accessor.get(IEditorService);
const activeEditorPane = editorService.activeEditorPane;
if (!(activeEditorPane instanceof NotebookMultiTextDiffEditor)) {
return;
}
const item = activeEditorPane.getDiffElementViewModel(uri);
if (item && item instanceof SideBySideDiffElementViewModel) {
const original = item.original;
const modifiedCellIndex = item.modifiedDocument.cells.findIndex(cell => cell.handle === item.modified.handle);
if (modifiedCellIndex === -1) {
return;
}
item.mainDocumentTextModel.applyEdits([{
editType: CellEditType.Output, index: modifiedCellIndex, outputs: original.outputs
}], true, undefined, () => undefined, undefined, true);
}
}
});
const revertMetadata = localize('notebook.diff.cell.revertMetadata', "Revert Metadata");
registerAction2(class extends Action2 {
constructor() {
super(
{
id: 'notebook.multiDiffEditor.cell.revertMetadata',
title: revertMetadata,
icon: revertIcon,
f1: false,
menu: {
when: ContextKeyExpr.and(ActiveEditorContext.isEqualTo(NotebookMultiTextDiffEditor.ID), ContextKeyExpr.equals(NOTEBOOK_DIFF_ITEM_KIND.key, 'Metadata'), ContextKeyExpr.equals(NOTEBOOK_DIFF_ITEM_DIFF_STATE.key, 'modified')),
id: MenuId.MultiDiffEditorFileToolbar,
order: 2,
group: 'navigation',
},
}
);
}
async run(accessor: ServicesAccessor, ...args: any[]): Promise<void> {
const uri = args[0] as URI;
const editorService = accessor.get(IEditorService);
const activeEditorPane = editorService.activeEditorPane;
if (!(activeEditorPane instanceof NotebookMultiTextDiffEditor)) {
return;
}
const item = activeEditorPane.getDiffElementViewModel(uri);
if (item && item instanceof SideBySideDiffElementViewModel) {
const original = item.original;
const modifiedCellIndex = item.modifiedDocument.cells.findIndex(cell => cell.handle === item.modified.handle);
if (modifiedCellIndex === -1) {
return;
}
item.mainDocumentTextModel.applyEdits([{
editType: CellEditType.Metadata, index: modifiedCellIndex, metadata: original.metadata
}], true, undefined, () => undefined, undefined, true);
}
}
});
registerAction2(class extends Action2 {
constructor() {
super(
{
id: 'notebook.diff.cell.revertMetadata',
title: localize('notebook.diff.cell.revertMetadata', "Revert Metadata"),
title: revertMetadata,
icon: revertIcon,
f1: false,
menu: {
@ -304,13 +467,12 @@ registerAction2(class extends Action2 {
}
});
registerAction2(class extends Action2 {
constructor() {
super(
{
id: 'notebook.diff.cell.revertInput',
title: localize('notebook.diff.cell.revertInput', "Revert Input"),
title: revertInput,
icon: revertIcon,
f1: false,
menu: {

View file

@ -149,6 +149,8 @@ export const NOTEBOOK_DIFF_CELL_PROPERTY_EXPANDED = new RawContextKey<boolean>('
export const NOTEBOOK_DIFF_CELLS_COLLAPSED = new RawContextKey<boolean>('notebookDiffEditorAllCollapsed', undefined, localize('notebookDiffEditorAllCollapsed', "Whether all cells in notebook diff editor are collapsed"));
export const NOTEBOOK_DIFF_HAS_UNCHANGED_CELLS = new RawContextKey<boolean>('notebookDiffEditorHasUnchangedCells', undefined, localize('notebookDiffEditorHasUnchangedCells', "Whether there are unchanged cells in the notebook diff editor"));
export const NOTEBOOK_DIFF_UNCHANGED_CELLS_HIDDEN = new RawContextKey<boolean>('notebookDiffEditorHiddenUnchangedCells', undefined, localize('notebookDiffEditorHiddenUnchangedCells', "Whether the unchanged cells in the notebook diff editor are hidden"));
export const NOTEBOOK_DIFF_ITEM_KIND = new RawContextKey<boolean>('notebookDiffEditorItemKind', undefined, localize('notebookDiffEditorItemKind', "The kind of item in the notebook diff editor, Cell, Metadata or Output"));
export const NOTEBOOK_DIFF_ITEM_DIFF_STATE = new RawContextKey<boolean>('notebookDiffEditorItemDiffState', undefined, localize('notebookDiffEditorItemDiffState', "The diff state of item in the notebook diff editor, delete, insert, modified or unchanged"));
export interface INotebookDiffViewModelUpdateEvent {
readonly start: number;

View file

@ -11,11 +11,12 @@ import { Schemas } from 'vs/base/common/network';
import type { URI } from 'vs/base/common/uri';
import { FontInfo } from 'vs/editor/common/config/fontInfo';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import type { ContextKeyValue } from 'vs/platform/contextkey/common/contextkey';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { MultiDiffEditorItem } from 'vs/workbench/contrib/multiDiffEditor/browser/multiDiffSourceResolverService';
import { DiffElementCellViewModelBase, DiffElementPlaceholderViewModel, IDiffElementViewModelBase, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel';
import { NotebookDiffEditorEventDispatcher } from 'vs/workbench/contrib/notebook/browser/diff/eventDispatcher';
import { INotebookDiffViewModel, INotebookDiffViewModelUpdateEvent } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser';
import { INotebookDiffViewModel, INotebookDiffViewModelUpdateEvent, NOTEBOOK_DIFF_ITEM_DIFF_STATE, NOTEBOOK_DIFF_ITEM_KIND } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { CellUri, INotebookDiffEditorModel, INotebookDiffResult } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
@ -99,44 +100,62 @@ export class NotebookDiffViewModel extends Disposable implements INotebookDiffVi
this.diffEditorItems = [];
const originalSourceUri = this.model.original.resource!;
const modifiedSourceUri = this.model.modified.resource!;
const hideOutput = this.model.modified.notebook.transientOptions.transientOutputs;
const hideMetadata = this.model.modified.notebook.transientOptions.transientCellMetadata;
this._hasUnchangedCells = false;
this.items.forEach(item => {
switch (item.type) {
case 'delete': {
this.diffEditorItems.push(new NotebookMultiDiffEditorItem(item.original!.uri, undefined, undefined, item.type));
const originalMetadata = CellUri.generateCellPropertyUri(originalSourceUri, item.original!.handle, Schemas.vscodeNotebookCellMetadata);
this.diffEditorItems.push(new NotebookMultiDiffEditorItem(originalMetadata, undefined, undefined, item.type));
this.diffEditorItems.push(new NotebookMultiDiffEditorCellItem(item.original!.uri, undefined, item.type));
if (!hideMetadata) {
const originalMetadata = CellUri.generateCellPropertyUri(originalSourceUri, item.original!.handle, Schemas.vscodeNotebookCellMetadata);
this.diffEditorItems.push(new NotebookMultiDiffEditorMetadataItem(originalMetadata, undefined, item.type));
}
if (!hideOutput) {
const originalOutput = CellUri.generateCellPropertyUri(originalSourceUri, item.original!.handle, Schemas.vscodeNotebookCellOutput);
this.diffEditorItems.push(new NotebookMultiDiffEditorOutputItem(originalOutput, undefined, item.type));
}
break;
}
case 'insert': {
this.diffEditorItems.push(new NotebookMultiDiffEditorItem(undefined, item.modified!.uri, item.modified!.uri, item.type));
const modifiedMetadata = CellUri.generateCellPropertyUri(modifiedSourceUri, item.modified!.handle, Schemas.vscodeNotebookCellMetadata);
this.diffEditorItems.push(new NotebookMultiDiffEditorItem(modifiedMetadata, undefined, item.modified!.uri, item.type));
this.diffEditorItems.push(new NotebookMultiDiffEditorCellItem(undefined, item.modified!.uri, item.type));
if (!hideMetadata) {
const modifiedMetadata = CellUri.generateCellPropertyUri(modifiedSourceUri, item.modified!.handle, Schemas.vscodeNotebookCellMetadata);
this.diffEditorItems.push(new NotebookMultiDiffEditorMetadataItem(modifiedMetadata, undefined, item.type));
}
if (!hideOutput) {
const modifiedOutput = CellUri.generateCellPropertyUri(modifiedSourceUri, item.modified!.handle, Schemas.vscodeNotebookCellOutput);
this.diffEditorItems.push(new NotebookMultiDiffEditorOutputItem(undefined, modifiedOutput, item.type));
}
break;
}
case 'modified': {
this.diffEditorItems.push(new NotebookMultiDiffEditorItem(item.original!.uri, item.modified!.uri, item.modified!.uri, item.type));
if (item.checkMetadataIfModified()) {
this.diffEditorItems.push(new NotebookMultiDiffEditorCellItem(item.original!.uri, item.modified!.uri, item.type));
if (item.checkMetadataIfModified() && !hideMetadata) {
const originalMetadata = CellUri.generateCellPropertyUri(originalSourceUri, item.original!.handle, Schemas.vscodeNotebookCellMetadata);
const modifiedMetadata = CellUri.generateCellPropertyUri(modifiedSourceUri, item.modified!.handle, Schemas.vscodeNotebookCellMetadata);
this.diffEditorItems.push(new NotebookMultiDiffEditorItem(originalMetadata, modifiedMetadata, item.modified!.uri, item.type));
this.diffEditorItems.push(new NotebookMultiDiffEditorMetadataItem(originalMetadata, modifiedMetadata, item.type));
}
if (item.checkIfOutputsModified()) {
if (item.checkIfOutputsModified() && !hideOutput) {
const originalOutput = CellUri.generateCellPropertyUri(originalSourceUri, item.original!.handle, Schemas.vscodeNotebookCellOutput);
const modifiedOutput = CellUri.generateCellPropertyUri(modifiedSourceUri, item.modified!.handle, Schemas.vscodeNotebookCellOutput);
this.diffEditorItems.push(new NotebookMultiDiffEditorItem(originalOutput, modifiedOutput, item.modified!.uri, item.type));
this.diffEditorItems.push(new NotebookMultiDiffEditorOutputItem(originalOutput, modifiedOutput, item.type));
}
break;
}
case 'unchanged': {
this._hasUnchangedCells = true;
this.diffEditorItems.push(new NotebookMultiDiffEditorItem(item.original!.uri, item.modified!.uri, item.modified!.uri, item.type));
const originalMetadata = CellUri.generateCellPropertyUri(originalSourceUri, item.original!.handle, Schemas.vscodeNotebookCellMetadata);
const modifiedMetadata = CellUri.generateCellPropertyUri(modifiedSourceUri, item.modified!.handle, Schemas.vscodeNotebookCellMetadata);
this.diffEditorItems.push(new NotebookMultiDiffEditorItem(originalMetadata, modifiedMetadata, item.modified!.uri, item.type));
const originalOutput = CellUri.generateCellPropertyUri(originalSourceUri, item.original!.handle, Schemas.vscodeNotebookCellOutput);
const modifiedOutput = CellUri.generateCellPropertyUri(modifiedSourceUri, item.modified!.handle, Schemas.vscodeNotebookCellOutput);
this.diffEditorItems.push(new NotebookMultiDiffEditorItem(originalOutput, modifiedOutput, item.modified!.uri, item.type));
this.diffEditorItems.push(new NotebookMultiDiffEditorCellItem(item.original!.uri, item.modified!.uri, item.type));
if (!hideMetadata) {
const originalMetadata = CellUri.generateCellPropertyUri(originalSourceUri, item.original!.handle, Schemas.vscodeNotebookCellMetadata);
const modifiedMetadata = CellUri.generateCellPropertyUri(modifiedSourceUri, item.modified!.handle, Schemas.vscodeNotebookCellMetadata);
this.diffEditorItems.push(new NotebookMultiDiffEditorMetadataItem(originalMetadata, modifiedMetadata, item.type));
}
if (!hideOutput) {
const originalOutput = CellUri.generateCellPropertyUri(originalSourceUri, item.original!.handle, Schemas.vscodeNotebookCellOutput);
const modifiedOutput = CellUri.generateCellPropertyUri(modifiedSourceUri, item.modified!.handle, Schemas.vscodeNotebookCellOutput);
this.diffEditorItems.push(new NotebookMultiDiffEditorOutputItem(originalOutput, modifiedOutput, item.type));
}
break;
}
}
@ -440,13 +459,54 @@ function computeModifiedLCS(change: IDiffChange, originalModel: NotebookTextMode
}
class NotebookMultiDiffEditorItem extends MultiDiffEditorItem {
abstract class NotebookMultiDiffEditorItem extends MultiDiffEditorItem {
constructor(
originalUri: URI | undefined,
modifiedUri: URI | undefined,
goToFileUri: URI | undefined,
public readonly type: IDiffElementViewModelBase['type'],
contextKeys?: Record<string, ContextKeyValue>,
) {
super(originalUri, modifiedUri, goToFileUri);
// super(originalUri, modifiedUri, goToFileUri, contextKeys);
}
}
class NotebookMultiDiffEditorCellItem extends NotebookMultiDiffEditorItem {
constructor(
originalUri: URI | undefined,
modifiedUri: URI | undefined,
type: IDiffElementViewModelBase['type'],
) {
super(originalUri, modifiedUri, modifiedUri || originalUri, type, {
[NOTEBOOK_DIFF_ITEM_KIND.key]: 'Cell',
[NOTEBOOK_DIFF_ITEM_DIFF_STATE.key]: type
});
}
}
class NotebookMultiDiffEditorMetadataItem extends NotebookMultiDiffEditorItem {
constructor(
originalUri: URI | undefined,
modifiedUri: URI | undefined,
type: IDiffElementViewModelBase['type'],
) {
super(originalUri, modifiedUri, modifiedUri || originalUri, type, {
[NOTEBOOK_DIFF_ITEM_KIND.key]: 'Metadata',
[NOTEBOOK_DIFF_ITEM_DIFF_STATE.key]: type
});
}
}
class NotebookMultiDiffEditorOutputItem extends NotebookMultiDiffEditorItem {
constructor(
originalUri: URI | undefined,
modifiedUri: URI | undefined,
type: IDiffElementViewModelBase['type'],
) {
super(originalUri, modifiedUri, modifiedUri || originalUri, type, {
[NOTEBOOK_DIFF_ITEM_KIND.key]: 'Output',
[NOTEBOOK_DIFF_ITEM_DIFF_STATE.key]: type
});
}
}

View file

@ -20,7 +20,7 @@ import { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo';
import { PixelRatio } from 'vs/base/browser/pixelRatio';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
import { INotebookDiffEditorModel, NOTEBOOK_MULTI_DIFF_EDITOR_ID } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellUri, INotebookDiffEditorModel, NOTEBOOK_MULTI_DIFF_EDITOR_ID } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { FontMeasurements } from 'vs/editor/browser/config/fontMeasurements';
import { NotebookOptions } from 'vs/workbench/contrib/notebook/browser/notebookOptions';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
@ -36,6 +36,8 @@ import { NotebookDiffViewModel } from 'vs/workbench/contrib/notebook/browser/dif
import { NotebookDiffEditorEventDispatcher } from 'vs/workbench/contrib/notebook/browser/diff/eventDispatcher';
import { NOTEBOOK_DIFF_CELLS_COLLAPSED, NOTEBOOK_DIFF_HAS_UNCHANGED_CELLS, NOTEBOOK_DIFF_UNCHANGED_CELLS_HIDDEN } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser';
import type { MultiDiffEditorViewModel } from 'vs/editor/browser/widget/multiDiffEditor/multiDiffEditorViewModel';
import type { URI } from 'vs/base/common/uri';
import { type IDiffElementViewModelBase } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel';
export class NotebookMultiTextDiffEditor extends EditorPane {
private _multiDiffEditorWidget?: MultiDiffEditorWidget;
@ -111,6 +113,7 @@ export class NotebookMultiTextDiffEditor extends EditorPane {
this.viewModel = this.modelSpecificResources.add(new NotebookDiffViewModel(model, this.notebookEditorWorkerService, this.instantiationService, this.configurationService, eventDispatcher, this.notebookService, undefined, true));
await this.viewModel.computeDiff(this.modelSpecificResources.add(new CancellationTokenSource()).token);
this.ctxHasUnchangedCells.set(this.viewModel.hasUnchangedCells);
this.ctxHasUnchangedCells.set(this.viewModel.hasUnchangedCells);
const widgetInput = this.modelSpecificResources.add(NotebookMultiDiffEditorWidgetInput.createInput(this.viewModel, this.instantiationService));
this.widgetViewModel = this.modelSpecificResources.add(await widgetInput.getViewModel());
@ -169,6 +172,30 @@ export class NotebookMultiTextDiffEditor extends EditorPane {
this.ctxHiddenUnchangedCells.set(this.viewModel.includeUnchanged);
}
}
public getDiffElementViewModel(uri: URI): IDiffElementViewModelBase | undefined {
if (uri.scheme === Schemas.vscodeNotebookCellOutput || uri.scheme === Schemas.vscodeNotebookCellOutputDiff ||
uri.scheme === Schemas.vscodeNotebookCellMetadata || uri.scheme === Schemas.vscodeNotebookCellMetadataDiff
) {
const data = CellUri.parseCellPropertyUri(uri, uri.scheme);
if (data) {
uri = CellUri.generate(data.notebook, data.handle);
}
}
return this.viewModel?.items.find(c => {
switch (c.type) {
case 'delete':
return c.original?.uri.toString() === uri.toString();
case 'insert':
return c.modified?.uri.toString() === uri.toString();
case 'modified':
case 'unchanged':
return c.modified?.uri.toString() === uri.toString() || c.original?.uri.toString() === uri.toString();
default:
return;
}
});
}
}

View file

@ -29,7 +29,7 @@ import { NotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookEd
import { NotebookEditorInput, NotebookEditorInputOptions } from 'vs/workbench/contrib/notebook/common/notebookEditorInput';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { NotebookService } from 'vs/workbench/contrib/notebook/browser/services/notebookServiceImpl';
import { CellKind, CellUri, IResolvedNotebookEditorModel, NotebookWorkingCopyTypeIdentifier, NotebookSetting, ICellOutput, ICell } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellKind, CellUri, IResolvedNotebookEditorModel, NotebookWorkingCopyTypeIdentifier, NotebookSetting, ICellOutput, ICell, NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { INotebookEditorModelResolverService } from 'vs/workbench/contrib/notebook/common/notebookEditorModelResolverService';
@ -437,15 +437,24 @@ class CellInfoContentProvider {
let result: ITextModel | null = null;
const mode = this._languageService.createById('json');
const disposables = new DisposableStore();
for (const cell of ref.object.notebook.cells) {
if (cell.handle === data.handle) {
const cellIndex = ref.object.notebook.cells.indexOf(cell);
const metadataSource = getFormattedMetadataJSON(ref.object.notebook, cell.metadata, cell.language);
result = this._modelService.createModel(
metadataSource,
mode,
resource
);
this._disposables.push(disposables.add(ref.object.notebook.onDidChangeContent(e => {
if (result && e.rawEvents.some(event => event.kind === NotebookCellsChangeType.ChangeCellMetadata && event.index === cellIndex)) {
const value = getFormattedMetadataJSON(ref.object.notebook, cell.metadata, cell.language);
if (result.getValue() !== value) {
result.setValue(getFormattedMetadataJSON(ref.object.notebook, cell.metadata, cell.language));
}
}
})));
break;
}
}
@ -456,6 +465,7 @@ class CellInfoContentProvider {
}
const once = result.onWillDispose(() => {
disposables.dispose();
once.dispose();
ref.dispose();
});

View file

@ -34,7 +34,7 @@ import { ICellExecutionError } from 'vs/workbench/contrib/notebook/common/notebo
import { INotebookTextModelLike } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange';
import { RegisteredEditorPriority } from 'vs/workbench/services/editor/common/editorResolverService';
import { generate as generateUri, parse as parseUri } from 'vs/workbench/services/notebook/common/notebookDocumentService';
import { generateMetadataUri, generate as generateUri, parseMetadataUri, parse as parseUri } from 'vs/workbench/services/notebook/common/notebookDocumentService';
import { IWorkingCopyBackupMeta, IWorkingCopySaveEvent } from 'vs/workbench/services/workingCopy/common/workingCopy';
export const NOTEBOOK_EDITOR_ID = 'workbench.editor.notebook';
@ -561,6 +561,15 @@ export interface INotebookContributionData {
priority?: RegisteredEditorPriority;
}
export namespace NotebookUri {
export const scheme = Schemas.vscodeNotebookMetadata;
export function generate(notebook: URI): URI {
return generateMetadataUri(notebook);
}
export function parse(metadata: URI): URI | undefined {
return parseMetadataUri(metadata);
}
}
export namespace CellUri {
export const scheme = Schemas.vscodeNotebookCell;

View file

@ -51,6 +51,21 @@ export function generate(notebook: URI, handle: number): URI {
return notebook.with({ scheme: Schemas.vscodeNotebookCell, fragment });
}
export function parseMetadataUri(metadata: URI): URI | undefined {
if (metadata.scheme !== Schemas.vscodeNotebookMetadata) {
return undefined;
}
const _scheme = decodeBase64(metadata.fragment).toString();
return metadata.with({ scheme: _scheme, fragment: null });
}
export function generateMetadataUri(notebook: URI): URI {
const fragment = `${encodeBase64(VSBuffer.fromString(notebook.scheme), true, true)}`;
return notebook.with({ scheme: Schemas.vscodeNotebookMetadata, fragment });
}
export interface INotebookDocumentService {
readonly _serviceBrand: undefined;