mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 21:09:43 +00:00
support revert notebook cell metadata in diff view.
This commit is contained in:
parent
342899271d
commit
883749806b
|
@ -78,6 +78,12 @@
|
|||
"group": "inline@1"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"jsonValidation": [
|
||||
{
|
||||
"fileMatch": "vscode://vscode-notebook-cell-metadata/*",
|
||||
"url": "vscode://schemas/notebook/cellmetadata"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,6 +123,8 @@ export class MenuId {
|
|||
static readonly NotebookCellInsert = new MenuId('NotebookCellInsert');
|
||||
static readonly NotebookCellBetween = new MenuId('NotebookCellBetween');
|
||||
static readonly NotebookCellListTop = new MenuId('NotebookCellTop');
|
||||
static readonly NotebookDiffCellMetadataTitle = new MenuId('NotebookDiffCellMetadataTitle');
|
||||
static readonly NotebookDiffCellOutputsTitle = new MenuId('NotebookDiffCellOutputsTitle');
|
||||
static readonly BulkEditTitle = new MenuId('BulkEditTitle');
|
||||
static readonly BulkEditContext = new MenuId('BulkEditContext');
|
||||
static readonly TimelineItemContext = new MenuId('TimelineItemContext');
|
||||
|
|
2
src/vs/vscode.proposed.d.ts
vendored
2
src/vs/vscode.proposed.d.ts
vendored
|
@ -1179,7 +1179,7 @@ declare module 'vscode' {
|
|||
|
||||
export interface NotebookCellMetadata {
|
||||
/**
|
||||
* Controls if the content of a cell is editable or not.
|
||||
* Controls whether a cell's editor is editable/readonly.
|
||||
*/
|
||||
editable?: boolean;
|
||||
|
||||
|
|
|
@ -17,8 +17,17 @@ import { IModelService } from 'vs/editor/common/services/modelService';
|
|||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { format } from 'vs/base/common/jsonFormatter';
|
||||
import { applyEdits } from 'vs/base/common/jsonEdit';
|
||||
import { NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellUri, NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { hash } from 'vs/base/common/hash';
|
||||
import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IMenu, IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions';
|
||||
import { CodiconActionViewItem } from 'vs/workbench/contrib/notebook/browser/view/renderers/commonViewComponents';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
|
||||
const fixedEditorOptions: IEditorOptions = {
|
||||
padding: {
|
||||
|
@ -61,6 +70,8 @@ const fixedDiffEditorOptions: IDiffEditorOptions = {
|
|||
class PropertyHeader extends Disposable {
|
||||
protected _foldingIndicator!: HTMLElement;
|
||||
protected _statusSpan!: HTMLElement;
|
||||
protected _toolbar!: ToolBar;
|
||||
protected _menu!: IMenu;
|
||||
|
||||
constructor(
|
||||
readonly cell: CellDiffViewModel,
|
||||
|
@ -74,7 +85,13 @@ class PropertyHeader extends Disposable {
|
|||
unChangedLabel: string;
|
||||
changedLabel: string;
|
||||
prefix: string;
|
||||
}
|
||||
menuId: MenuId;
|
||||
},
|
||||
@IContextMenuService readonly contextMenuService: IContextMenuService,
|
||||
@IKeybindingService readonly keybindingService: IKeybindingService,
|
||||
@INotificationService readonly notificationService: INotificationService,
|
||||
@IMenuService readonly menuService: IMenuService,
|
||||
@IContextKeyService readonly contextKeyService: IContextKeyService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
@ -83,8 +100,6 @@ class PropertyHeader extends Disposable {
|
|||
let metadataChanged = this.accessor.checkIfModified(this.cell);
|
||||
this._foldingIndicator = DOM.append(this.metadataHeaderContainer, DOM.$('.property-folding-indicator'));
|
||||
DOM.addClass(this._foldingIndicator, this.accessor.prefix);
|
||||
|
||||
|
||||
this._updateFoldingIcon();
|
||||
const metadataStatus = DOM.append(this.metadataHeaderContainer, DOM.$('div.property-status'));
|
||||
this._statusSpan = DOM.append(metadataStatus, DOM.$('span'));
|
||||
|
@ -97,6 +112,29 @@ class PropertyHeader extends Disposable {
|
|||
this._statusSpan.textContent = this.accessor.unChangedLabel;
|
||||
}
|
||||
|
||||
const cellToolbarContainer = DOM.append(this.metadataHeaderContainer, DOM.$('div.property-toolbar'));
|
||||
this._toolbar = new ToolBar(cellToolbarContainer, this.contextMenuService, {
|
||||
actionViewItemProvider: action => {
|
||||
if (action instanceof MenuItemAction) {
|
||||
const item = new CodiconActionViewItem(action, this.keybindingService, this.notificationService, this.contextMenuService);
|
||||
return item;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
this._toolbar.context = {
|
||||
cell: this.cell
|
||||
};
|
||||
|
||||
this._menu = this.menuService.createMenu(this.accessor.menuId, this.contextKeyService);
|
||||
|
||||
if (metadataChanged) {
|
||||
const actions: IAction[] = [];
|
||||
createAndFillInActionBarActions(this._menu, { shouldForwardArgs: true }, actions);
|
||||
this._toolbar.setActions(actions);
|
||||
}
|
||||
|
||||
this._register(this.notebookEditor.onMouseUp(e => {
|
||||
if (!e.event.target) {
|
||||
return;
|
||||
|
@ -138,6 +176,22 @@ class PropertyHeader extends Disposable {
|
|||
this.accessor.updateInfoRendering();
|
||||
}
|
||||
|
||||
refresh() {
|
||||
let metadataChanged = this.accessor.checkIfModified(this.cell);
|
||||
if (metadataChanged) {
|
||||
this._statusSpan.textContent = this.accessor.changedLabel;
|
||||
this._statusSpan.style.fontWeight = 'bold';
|
||||
DOM.addClass(this.metadataHeaderContainer, 'modified');
|
||||
const actions: IAction[] = [];
|
||||
createAndFillInActionBarActions(this._menu, undefined, actions);
|
||||
this._toolbar.setActions(actions);
|
||||
} else {
|
||||
this._statusSpan.textContent = this.accessor.unChangedLabel;
|
||||
this._statusSpan.style.fontWeight = 'normal';
|
||||
this._toolbar.setActions([]);
|
||||
}
|
||||
}
|
||||
|
||||
private _updateFoldingIcon() {
|
||||
if (this.accessor.getFoldingState(this.cell) === PropertyFoldingState.Collapsed) {
|
||||
this._foldingIndicator.innerHTML = renderCodicons('$(chevron-right)');
|
||||
|
@ -229,14 +283,15 @@ abstract class AbstractCellRenderer extends Disposable {
|
|||
this._metadataHeaderContainer = DOM.append(this._diffEditorContainer, DOM.$('.metadata-header-container'));
|
||||
this._metadataInfoContainer = DOM.append(this._diffEditorContainer, DOM.$('.metadata-info-container'));
|
||||
|
||||
this._metadataHeader = new PropertyHeader(
|
||||
this._metadataHeader = this.instantiationService.createInstance(
|
||||
PropertyHeader,
|
||||
this.cell,
|
||||
this._metadataHeaderContainer,
|
||||
this.notebookEditor,
|
||||
{
|
||||
updateInfoRendering: this.updateMetadataRendering.bind(this),
|
||||
checkIfModified: (cell) => {
|
||||
return cell.type === 'modified' && hash(this._getFormatedMetadataJSON(cell.original?.metadata || {})) !== hash(this._getFormatedMetadataJSON(cell.modified?.metadata ?? {}));
|
||||
return hash(this._getFormatedMetadataJSON(cell.original?.metadata || {}, cell.original?.language)) !== hash(this._getFormatedMetadataJSON(cell.modified?.metadata ?? {}, cell.modified?.language));
|
||||
},
|
||||
getFoldingState: (cell) => {
|
||||
return cell.metadataFoldingState;
|
||||
|
@ -246,7 +301,8 @@ abstract class AbstractCellRenderer extends Disposable {
|
|||
},
|
||||
unChangedLabel: 'Metadata',
|
||||
changedLabel: 'Metadata changed',
|
||||
prefix: 'metadata'
|
||||
prefix: 'metadata',
|
||||
menuId: MenuId.NotebookDiffCellMetadataTitle
|
||||
}
|
||||
);
|
||||
this._register(this._metadataHeader);
|
||||
|
@ -255,7 +311,8 @@ abstract class AbstractCellRenderer extends Disposable {
|
|||
this._outputHeaderContainer = DOM.append(this._diffEditorContainer, DOM.$('.output-header-container'));
|
||||
this._outputInfoContainer = DOM.append(this._diffEditorContainer, DOM.$('.output-info-container'));
|
||||
|
||||
this._outputHeader = new PropertyHeader(
|
||||
this._outputHeader = this.instantiationService.createInstance(
|
||||
PropertyHeader,
|
||||
this.cell,
|
||||
this._outputHeaderContainer,
|
||||
this.notebookEditor,
|
||||
|
@ -272,7 +329,8 @@ abstract class AbstractCellRenderer extends Disposable {
|
|||
},
|
||||
unChangedLabel: 'Outputs',
|
||||
changedLabel: 'Outputs changed',
|
||||
prefix: 'output'
|
||||
prefix: 'output',
|
||||
menuId: MenuId.NotebookDiffCellOutputsTitle
|
||||
}
|
||||
);
|
||||
this._register(this._outputHeader);
|
||||
|
@ -310,7 +368,6 @@ abstract class AbstractCellRenderer extends Disposable {
|
|||
this._outputEditorContainer = DOM.append(this._outputInfoContainer, DOM.$('.output-editor-container'));
|
||||
this._buildOutputEditor();
|
||||
} else {
|
||||
console.log(this.cell);
|
||||
this._layoutInfo.outputHeight = this._outputEditor.getContentHeight();
|
||||
this.layout({ outputEditor: true });
|
||||
}
|
||||
|
@ -323,21 +380,7 @@ abstract class AbstractCellRenderer extends Disposable {
|
|||
}
|
||||
|
||||
protected _getFormatedMetadataJSON(metadata: NotebookCellMetadata, language?: string) {
|
||||
let filteredMetadata: { [key: string]: any } = {};
|
||||
if (this.notebookEditor.textModel) {
|
||||
const transientMetadata = this.notebookEditor.textModel!.transientOptions.transientMetadata;
|
||||
|
||||
const keys = new Set([...Object.keys(metadata)]);
|
||||
for (let key of keys) {
|
||||
if (!(transientMetadata[key as keyof NotebookCellMetadata])
|
||||
) {
|
||||
filteredMetadata[key] = metadata[key as keyof NotebookCellMetadata];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
filteredMetadata = metadata;
|
||||
}
|
||||
|
||||
const filteredMetadata: { [key: string]: any } = metadata;
|
||||
const content = JSON.stringify({
|
||||
language,
|
||||
...filteredMetadata
|
||||
|
@ -349,39 +392,124 @@ abstract class AbstractCellRenderer extends Disposable {
|
|||
return metadataSource;
|
||||
}
|
||||
|
||||
private _applySanitizedMetadataChanges(currentMetadata: NotebookCellMetadata, newMetadata: any) {
|
||||
let result: { [key: string]: any } = {};
|
||||
let newLangauge: string | undefined = undefined;
|
||||
try {
|
||||
const newMetadataObj = JSON.parse(newMetadata);
|
||||
const keys = new Set([...Object.keys(newMetadataObj)]);
|
||||
for (let key of keys) {
|
||||
switch (key as keyof NotebookCellMetadata) {
|
||||
case 'breakpointMargin':
|
||||
case 'editable':
|
||||
case 'hasExecutionOrder':
|
||||
case 'inputCollapsed':
|
||||
case 'outputCollapsed':
|
||||
case 'runnable':
|
||||
// boolean
|
||||
if (typeof newMetadataObj[key] === 'boolean') {
|
||||
result[key] = newMetadataObj[key];
|
||||
} else {
|
||||
result[key] = currentMetadata[key as keyof NotebookCellMetadata];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'executionOrder':
|
||||
case 'lastRunDuration':
|
||||
// number
|
||||
if (typeof newMetadataObj[key] === 'number') {
|
||||
result[key] = newMetadataObj[key];
|
||||
} else {
|
||||
result[key] = currentMetadata[key as keyof NotebookCellMetadata];
|
||||
}
|
||||
break;
|
||||
case 'runState':
|
||||
// enum
|
||||
if (typeof newMetadataObj[key] === 'number' && [1, 2, 3, 4].indexOf(newMetadataObj[key]) >= 0) {
|
||||
result[key] = newMetadataObj[key];
|
||||
} else {
|
||||
result[key] = currentMetadata[key as keyof NotebookCellMetadata];
|
||||
}
|
||||
break;
|
||||
case 'statusMessage':
|
||||
// string
|
||||
if (typeof newMetadataObj[key] === 'string') {
|
||||
result[key] = newMetadataObj[key];
|
||||
} else {
|
||||
result[key] = currentMetadata[key as keyof NotebookCellMetadata];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (key === 'language') {
|
||||
newLangauge = newMetadataObj[key];
|
||||
}
|
||||
result[key] = newMetadataObj[key];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newLangauge !== undefined && newLangauge !== this.cell.modified!.language) {
|
||||
this.notebookEditor.textModel!.changeCellLanguage(this.cell.modified!.handle, newLangauge);
|
||||
}
|
||||
this.notebookEditor.textModel!.changeCellMetadata(this.cell.modified!.handle, result, false);
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
|
||||
private _buildMetadataEditor() {
|
||||
if (this.cell.type === 'modified') {
|
||||
if (this.cell.type === 'modified' || this.cell.type === 'unchanged') {
|
||||
const originalMetadataSource = this._getFormatedMetadataJSON(this.cell.original?.metadata || {}, this.cell.original?.language);
|
||||
const modifiedMetadataSource = this._getFormatedMetadataJSON(this.cell.modified?.metadata || {}, this.cell.modified?.language);
|
||||
if (originalMetadataSource !== modifiedMetadataSource) {
|
||||
this._metadataEditor = this.instantiationService.createInstance(DiffEditorWidget, this._metadataEditorContainer!, {
|
||||
...fixedDiffEditorOptions,
|
||||
overflowWidgetsDomNode: this.notebookEditor.getOverflowContainerDomNode(),
|
||||
readOnly: true
|
||||
});
|
||||
this._metadataEditor = this.instantiationService.createInstance(DiffEditorWidget, this._metadataEditorContainer!, {
|
||||
...fixedDiffEditorOptions,
|
||||
overflowWidgetsDomNode: this.notebookEditor.getOverflowContainerDomNode(),
|
||||
readOnly: false,
|
||||
originalEditable: false
|
||||
});
|
||||
|
||||
DOM.addClass(this._metadataEditorContainer!, 'diff');
|
||||
DOM.addClass(this._metadataEditorContainer!, 'diff');
|
||||
|
||||
const mode = this.modeService.create('json');
|
||||
const originalMetadataModel = this.modelService.createModel(originalMetadataSource, mode, undefined, true);
|
||||
const modifiedMetadataModel = this.modelService.createModel(modifiedMetadataSource, mode, undefined, true);
|
||||
this._metadataEditor.setModel({
|
||||
original: originalMetadataModel,
|
||||
modified: modifiedMetadataModel
|
||||
});
|
||||
const mode = this.modeService.create('json');
|
||||
const originalMetadataModel = this.modelService.createModel(originalMetadataSource, mode, CellUri.generateCellMetadataUri(this.cell.original!.uri, this.cell.original!.handle), false);
|
||||
const modifiedMetadataModel = this.modelService.createModel(modifiedMetadataSource, mode, CellUri.generateCellMetadataUri(this.cell.modified!.uri, this.cell.modified!.handle), false);
|
||||
this._metadataEditor.setModel({
|
||||
original: originalMetadataModel,
|
||||
modified: modifiedMetadataModel
|
||||
});
|
||||
|
||||
this._layoutInfo.metadataHeight = this._metadataEditor.getContentHeight();
|
||||
this.layout({ metadataEditor: true });
|
||||
this._register(originalMetadataModel);
|
||||
this._register(modifiedMetadataModel);
|
||||
|
||||
this._register(this._metadataEditor.onDidContentSizeChange((e) => {
|
||||
if (e.contentHeightChanged && this.cell.metadataFoldingState === PropertyFoldingState.Expanded) {
|
||||
this._layoutInfo.metadataHeight = e.contentHeight;
|
||||
this.layout({ metadataEditor: true });
|
||||
}
|
||||
}));
|
||||
this._layoutInfo.metadataHeight = this._metadataEditor.getContentHeight();
|
||||
this.layout({ metadataEditor: true });
|
||||
|
||||
return;
|
||||
}
|
||||
this._register(this._metadataEditor.onDidContentSizeChange((e) => {
|
||||
if (e.contentHeightChanged && this.cell.metadataFoldingState === PropertyFoldingState.Expanded) {
|
||||
this._layoutInfo.metadataHeight = e.contentHeight;
|
||||
this.layout({ metadataEditor: true });
|
||||
}
|
||||
}));
|
||||
|
||||
let respondingToContentChange = false;
|
||||
|
||||
this._register(modifiedMetadataModel.onDidChangeContent(() => {
|
||||
respondingToContentChange = true;
|
||||
const value = modifiedMetadataModel.getValue();
|
||||
this._applySanitizedMetadataChanges(this.cell.modified!.metadata, value);
|
||||
this._metadataHeader.refresh();
|
||||
respondingToContentChange = false;
|
||||
}));
|
||||
|
||||
this._register(this.cell.modified!.onDidChangeMetadata(() => {
|
||||
if (respondingToContentChange) {
|
||||
return;
|
||||
}
|
||||
|
||||
const modifiedMetadataSource = this._getFormatedMetadataJSON(this.cell.modified?.metadata || {}, this.cell.modified?.language);
|
||||
modifiedMetadataModel.setValue(modifiedMetadataSource);
|
||||
}));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this._metadataEditor = this.instantiationService.createInstance(CodeEditorWidget, this._metadataEditorContainer!, {
|
||||
|
@ -390,16 +518,26 @@ abstract class AbstractCellRenderer extends Disposable {
|
|||
width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, true),
|
||||
height: 0
|
||||
},
|
||||
overflowWidgetsDomNode: this.notebookEditor.getOverflowContainerDomNode()
|
||||
overflowWidgetsDomNode: this.notebookEditor.getOverflowContainerDomNode(),
|
||||
readOnly: false
|
||||
}, {});
|
||||
|
||||
const mode = this.modeService.create('json');
|
||||
const mode = this.modeService.create('jsonc');
|
||||
const originalMetadataSource = this._getFormatedMetadataJSON(
|
||||
this.cell.type === 'insert'
|
||||
? this.cell.modified!.metadata || {}
|
||||
: this.cell.original!.metadata || {});
|
||||
const metadataModel = this.modelService.createModel(originalMetadataSource, mode, undefined, true);
|
||||
const uri = this.cell.type === 'insert'
|
||||
? this.cell.modified!.uri
|
||||
: this.cell.original!.uri;
|
||||
const handle = this.cell.type === 'insert'
|
||||
? this.cell.modified!.handle
|
||||
: this.cell.original!.handle;
|
||||
|
||||
const modelUri = CellUri.generateCellMetadataUri(uri, handle);
|
||||
const metadataModel = this.modelService.createModel(originalMetadataSource, mode, modelUri, false);
|
||||
this._metadataEditor.setModel(metadataModel);
|
||||
this._register(metadataModel);
|
||||
|
||||
this._layoutInfo.metadataHeight = this._metadataEditor.getContentHeight();
|
||||
this.layout({ metadataEditor: true });
|
||||
|
@ -422,7 +560,7 @@ abstract class AbstractCellRenderer extends Disposable {
|
|||
}
|
||||
|
||||
private _buildOutputEditor() {
|
||||
if (this.cell.type === 'modified' && !this.notebookEditor.textModel!.transientOptions.transientOutputs) {
|
||||
if ((this.cell.type === 'modified' || this.cell.type === 'unchanged') && !this.notebookEditor.textModel!.transientOptions.transientOutputs) {
|
||||
const originalOutputsSource = this._getFormatedOutputJSON(this.cell.original?.outputs || []);
|
||||
const modifiedOutputsSource = this._getFormatedOutputJSON(this.cell.modified?.outputs || []);
|
||||
if (originalOutputsSource !== modifiedOutputsSource) {
|
||||
|
|
|
@ -79,6 +79,18 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.notebook-text-diff-editor .cell-diff-editor-container .output-header-container,
|
||||
.notebook-text-diff-editor .cell-diff-editor-container .metadata-header-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.notebook-text-diff-editor .cell-diff-editor-container .output-header-container .property-toolbar,
|
||||
.notebook-text-diff-editor .cell-diff-editor-container .metadata-header-container .property-toolbar {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.notebook-text-diff-editor .cell-diff-editor-container .output-header-container .property-status,
|
||||
.notebook-text-diff-editor .cell-diff-editor-container .metadata-header-container .property-status {
|
||||
font-size: 12px;
|
||||
|
|
|
@ -8,6 +8,7 @@ import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/act
|
|||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { viewColumnToEditorGroup } from 'vs/workbench/api/common/shared/editor';
|
||||
import { ActiveEditorContext } from 'vs/workbench/common/editor';
|
||||
import { CellDiffViewModel } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel';
|
||||
import { NotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor';
|
||||
import { NotebookDiffEditorInput } from 'vs/workbench/contrib/notebook/browser/notebookDiffEditorInput';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
|
@ -48,3 +49,33 @@ registerAction2(class extends Action2 {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super(
|
||||
{
|
||||
id: 'notebook.diff.cell.revertMetadata',
|
||||
title: localize('notebook.diff.cell.revertMetadata', "Revert Metadata"),
|
||||
icon: { id: 'codicon/discard' },
|
||||
f1: false,
|
||||
menu: {
|
||||
id: MenuId.NotebookDiffCellMetadataTitle
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
run(accessor: ServicesAccessor, context?: { cell: CellDiffViewModel }) {
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
|
||||
const original = context.cell.original;
|
||||
const modified = context.cell.modified;
|
||||
|
||||
if (!original || !modified) {
|
||||
return;
|
||||
}
|
||||
|
||||
modified.metadata = original.metadata;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -48,6 +48,8 @@ import { INotebookEditorWorkerService } from 'vs/workbench/contrib/notebook/comm
|
|||
import { NotebookEditorWorkerServiceImpl } from 'vs/workbench/contrib/notebook/common/services/notebookWorkerServiceImpl';
|
||||
import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService';
|
||||
import { NotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/browser/notebookCellStatusBarServiceImpl';
|
||||
import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
|
||||
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||
|
||||
// Editor Contribution
|
||||
|
||||
|
@ -440,9 +442,79 @@ class CellContentProvider implements ITextModelContentProvider {
|
|||
}
|
||||
}
|
||||
|
||||
class RegisterSchemasContribution extends Disposable implements IWorkbenchContribution {
|
||||
constructor() {
|
||||
super();
|
||||
this.registerMetadataSchemas();
|
||||
}
|
||||
|
||||
private registerMetadataSchemas(): void {
|
||||
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
|
||||
const metadataSchema: IJSONSchema = {
|
||||
properties: {
|
||||
['language']: {
|
||||
type: 'string',
|
||||
description: 'The language for the cell'
|
||||
},
|
||||
['editable']: {
|
||||
type: 'boolean',
|
||||
description: `Controls whether a cell's editor is editable/readonly`
|
||||
},
|
||||
['runnable']: {
|
||||
type: 'boolean',
|
||||
description: 'Controls if the cell is executable'
|
||||
},
|
||||
['breakpointMargin']: {
|
||||
type: 'boolean',
|
||||
description: 'Controls if the cell has a margin to support the breakpoint UI'
|
||||
},
|
||||
['hasExecutionOrder']: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the execution order indicator will be displayed'
|
||||
},
|
||||
['executionOrder']: {
|
||||
type: 'number',
|
||||
description: 'The order in which this cell was executed'
|
||||
},
|
||||
['statusMessage']: {
|
||||
type: 'string',
|
||||
description: `A status message to be shown in the cell's status bar`
|
||||
},
|
||||
['runState']: {
|
||||
type: 'integer',
|
||||
description: `The cell's current run state`
|
||||
},
|
||||
['runStartTime']: {
|
||||
type: 'number',
|
||||
description: 'If the cell is running, the time at which the cell started running'
|
||||
},
|
||||
['lastRunDuration']: {
|
||||
type: 'number',
|
||||
description: `The total duration of the cell's last run`
|
||||
},
|
||||
['inputCollapsed']: {
|
||||
type: 'boolean',
|
||||
description: `Whether a code cell's editor is collapsed`
|
||||
},
|
||||
['outputCollapsed']: {
|
||||
type: 'boolean',
|
||||
description: `Whether a code cell's outputs are collapsed`
|
||||
}
|
||||
},
|
||||
// patternProperties: allSettings.patternProperties,
|
||||
additionalProperties: true,
|
||||
allowTrailingCommas: true,
|
||||
allowComments: true
|
||||
};
|
||||
|
||||
jsonRegistry.registerSchema('vscode://schemas/notebook/cellmetadata', metadataSchema);
|
||||
}
|
||||
}
|
||||
|
||||
const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(NotebookContribution, LifecyclePhase.Starting);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(CellContentProvider, LifecyclePhase.Starting);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(RegisterSchemasContribution, LifecyclePhase.Starting);
|
||||
|
||||
registerSingleton(INotebookService, NotebookService);
|
||||
registerSingleton(INotebookEditorWorkerService, NotebookEditorWorkerServiceImpl);
|
||||
|
|
|
@ -474,6 +474,7 @@ export function getCellUndoRedoComparisonKey(uri: URI) {
|
|||
export namespace CellUri {
|
||||
|
||||
export const scheme = Schemas.vscodeNotebookCell;
|
||||
|
||||
const _regex = /^\d{7,}/;
|
||||
|
||||
export function generate(notebook: URI, handle: number): URI {
|
||||
|
@ -483,6 +484,14 @@ export namespace CellUri {
|
|||
});
|
||||
}
|
||||
|
||||
export function generateCellMetadataUri(notebook: URI, handle: number): URI {
|
||||
return notebook.with({
|
||||
scheme: Schemas.vscode,
|
||||
authority: 'vscode-notebook-cell-metadata',
|
||||
fragment: `${handle.toString().padStart(7, '0')}${notebook.scheme !== Schemas.file ? notebook.scheme : ''}`
|
||||
});
|
||||
}
|
||||
|
||||
export function parse(cell: URI): { notebook: URI, handle: number } | undefined {
|
||||
if (cell.scheme !== scheme) {
|
||||
return undefined;
|
||||
|
|
Loading…
Reference in a new issue