未验证 提交 93a0c99f 编写于 作者: P Peng Lyu 提交者: GitHub

Merge pull request #106313 from microsoft/rebornix/nbdebt

notebook text model debt
......@@ -14,9 +14,10 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { ILogService } from 'vs/platform/log/common/log';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService';
import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellEditType, CellKind, DisplayOrderKey, ICellEditOperation, ICellRange, IEditor, INotebookDocumentFilter, NotebookCellMetadata, NotebookCellOutputsSplice, NotebookDocumentMetadata, NOTEBOOK_DISPLAY_ORDER, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellEditType, CellKind, DisplayOrderKey, ICellEditOperation, ICellRange, IEditor, IMainCellDto, INotebookDocumentFilter, NotebookCellMetadata, NotebookCellOutputsSplice, NotebookCellsChangeType, NotebookDocumentMetadata, NOTEBOOK_DISPLAY_ORDER, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IMainNotebookController, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, INotebookCellStatusBarEntryDto, INotebookDocumentsAndEditorsDelta, INotebookModelAddedData, MainContext, MainThreadNotebookShape, NotebookEditorRevealType, NotebookExtensionDescription } from '../common/extHost.protocol';
......@@ -59,7 +60,7 @@ class DocumentAndEditorState {
const apiEditors = [];
for (let id in after.textEditors) {
const editor = after.textEditors.get(id)!;
apiEditors.push({ id, documentUri: editor.uri!, selections: editor!.textModel!.selections, visibleRanges: editor.visibleRanges });
apiEditors.push({ id, documentUri: editor.uri!, selections: editor!.getSelectionHandles(), visibleRanges: editor.visibleRanges });
}
return {
......@@ -73,7 +74,7 @@ class DocumentAndEditorState {
const addedAPIEditors = editorDelta.added.map(add => ({
id: add.getId(),
documentUri: add.uri!,
selections: add.textModel!.selections || [],
selections: add.getSelectionHandles(),
visibleRanges: add.visibleRanges
}));
......@@ -231,7 +232,12 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
if (!this._editorEventListenersMapping.has(editor.getId())) {
const disposableStore = new DisposableStore();
disposableStore.add(editor.onDidChangeVisibleRanges(() => {
this._proxy.$acceptEditorPropertiesChanged(editor.getId(), { visibleRanges: { ranges: editor.visibleRanges } });
this._proxy.$acceptEditorPropertiesChanged(editor.getId(), { visibleRanges: { ranges: editor.visibleRanges }, selections: null });
}));
disposableStore.add(editor.onDidChangeSelection(() => {
const selectionHandles = editor.getSelectionHandles();
this._proxy.$acceptEditorPropertiesChanged(editor.getId(), { visibleRanges: null, selections: { selections: selectionHandles } });
}));
this._editorEventListenersMapping.set(editor.getId(), disposableStore);
......@@ -256,21 +262,49 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
notebookEditorAddedHandler(editor);
});
const cellToDto = (cell: NotebookCellTextModel): IMainCellDto => {
return {
handle: cell.handle,
uri: cell.uri,
source: cell.textBuffer.getLinesContent(),
eol: cell.textBuffer.getEOL(),
language: cell.language,
cellKind: cell.cellKind,
outputs: cell.outputs,
metadata: cell.metadata
};
};
const notebookDocumentAddedHandler = (textModel: NotebookTextModel) => {
if (this._documentEventListenersMapping.has(textModel.uri)) {
return;
if (!this._editorEventListenersMapping.has(textModel.uri.toString())) {
const disposableStore = new DisposableStore();
disposableStore.add(textModel!.onDidChangeContent(e => {
const data =
e.kind === NotebookCellsChangeType.ModelChange || e.kind === NotebookCellsChangeType.Initialize
? {
kind: e.kind,
versionId: e.versionId,
changes: e.changes.map(diff => [diff[0], diff[1], diff[2].map(cell => cellToDto(cell as NotebookCellTextModel))] as [number, number, IMainCellDto[]])
}
: (
e.kind === NotebookCellsChangeType.Move
? {
kind: e.kind,
index: e.index,
length: e.length,
newIdx: e.newIdx,
versionId: e.versionId,
cells: e.cells.map(cell => cellToDto(cell as NotebookCellTextModel))
}
: e
);
this._proxy.$acceptModelChanged(textModel.uri, data, textModel.isDirty);
this._proxy.$acceptDocumentPropertiesChanged(textModel.uri, { metadata: null });
}));
this._editorEventListenersMapping.set(textModel!.uri.toString(), disposableStore);
}
const disposableStore = new DisposableStore();
disposableStore.add(textModel.onDidModelChangeProxy(e => {
this._proxy.$acceptModelChanged(textModel!.uri, e, textModel!.isDirty);
this._proxy.$acceptDocumentPropertiesChanged(textModel.uri, { selections: { selections: textModel!.selections }, metadata: null });
}));
disposableStore.add(textModel.onDidSelectionChange(e => {
const selectionsChange = e ? { selections: e } : null;
this._proxy.$acceptDocumentPropertiesChanged(textModel.uri, { selections: selectionsChange, metadata: null });
}));
this._documentEventListenersMapping.set(textModel.uri, disposableStore);
};
this._notebookService.listNotebookDocuments().forEach(notebookDocumentAddedHandler);
......@@ -432,7 +466,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
textModel.insertTemplateCell(mainCell);
}
this._proxy.$acceptDocumentPropertiesChanged(textModel.uri, { selections: null, metadata: textModel.metadata });
this._proxy.$acceptDocumentPropertiesChanged(textModel.uri, { metadata: textModel.metadata });
return;
},
resolveNotebookEditor: async (viewType: string, uri: URI, editorId: string) => {
......@@ -542,7 +576,16 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
async $updateNotebookCellMetadata(viewType: string, resource: UriComponents, handle: number, metadata: NotebookCellMetadata): Promise<void> {
this.logService.debug('MainThreadNotebooks#updateNotebookCellMetadata', resource.path, handle, metadata);
const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
textModel?.changeCellMetadata(handle, metadata, true);
if (!textModel) {
return;
}
const index = textModel.cells.findIndex(cell => cell.handle === handle);
if (index < 0) {
return;
}
textModel.applyEdit(textModel.versionId, [{ editType: CellEditType.Metadata, index, metadata }], true);
}
async $spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[]): Promise<void> {
......@@ -551,7 +594,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
if (textModel) {
this._notebookService.transformSpliceOutputs(textModel, splices);
textModel.spliceNotebookCellOutputs(cellHandle, splices);
textModel._spliceNotebookCellOutputs(cellHandle, splices);
}
}
......
......@@ -51,7 +51,7 @@ import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
import { TunnelOptions } from 'vs/platform/remote/common/tunnel';
import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline';
import { revive } from 'vs/base/common/marshalling';
import { IProcessedOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEvent, NotebookDataDto, IMainCellDto, INotebookDocumentFilter, INotebookKernelInfoDto2, TransientMetadata, INotebookCellStatusBarEntry, ICellRange } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IProcessedOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEventDto, NotebookDataDto, IMainCellDto, INotebookDocumentFilter, INotebookKernelInfoDto2, TransientMetadata, INotebookCellStatusBarEntry, ICellRange } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import { Dto } from 'vs/base/common/types';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
......@@ -1640,11 +1640,11 @@ export interface INotebookVisibleRangesEvent {
export interface INotebookEditorPropertiesChangeData {
visibleRanges: INotebookVisibleRangesEvent | null;
selections: INotebookSelectionChangeEvent | null;
}
export interface INotebookDocumentPropertiesChangeData {
metadata: NotebookDocumentMetadata | null;
selections: INotebookSelectionChangeEvent | null;
}
export interface INotebookModelAddedData {
......@@ -1686,7 +1686,7 @@ export interface ExtHostNotebookShape {
$acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void;
$acceptNotebookActiveKernelChange(event: { uri: UriComponents, providerHandle: number | undefined, kernelId: string | undefined }): void;
$onDidReceiveMessage(editorId: string, rendererId: string | undefined, message: unknown): void;
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEvent, isDirty: boolean): void;
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEventDto, isDirty: boolean): void;
$acceptModelSaved(uriComponents: UriComponents): void;
$acceptEditorPropertiesChanged(id: string, data: INotebookEditorPropertiesChangeData): void;
$acceptDocumentPropertiesChanged(uriComponents: UriComponents, data: INotebookDocumentPropertiesChangeData): void;
......
......@@ -22,7 +22,7 @@ import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePa
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/webview';
import { addIdToOutput, CellEditType, CellOutputKind, CellStatusbarAlignment, CellUri, diff, ICellEditOperation, ICellReplaceEdit, IMainCellDto, INotebookCellStatusBarEntry, INotebookDisplayOrder, INotebookEditData, INotebookKernelInfoDto2, IProcessedOutput, NotebookCellMetadata, NotebookCellsChangedEvent, NotebookCellsChangeType, NotebookCellsSplice2, NotebookDataDto, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { addIdToOutput, CellEditType, CellOutputKind, CellStatusbarAlignment, CellUri, diff, ICellEditOperation, ICellReplaceEdit, IMainCellDto, INotebookCellStatusBarEntry, INotebookDisplayOrder, INotebookEditData, INotebookKernelInfoDto2, IProcessedOutput, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2, NotebookDataDto, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import * as vscode from 'vscode';
import { Cache } from './cache';
import { ResourceMap } from 'vs/base/common/map';
......@@ -212,8 +212,7 @@ export class ExtHostNotebookDocument extends Disposable {
private _cellDisposableMapping = new Map<number, DisposableStore>();
private _notebook: vscode.NotebookDocument | undefined;
private _metadata: Required<vscode.NotebookDocumentMetadata> = notebookDocumentMetadataDefaults;
private _metadata: Required<vscode.NotebookDocumentMetadata>;
private _metadataChangeListener: IDisposable;
private _versionId = 0;
private _isDirty: boolean = false;
......@@ -229,13 +228,14 @@ export class ExtHostNotebookDocument extends Disposable {
private readonly _documentsAndEditors: ExtHostDocumentsAndEditors,
private readonly _emitter: INotebookEventEmitter,
private readonly _viewType: string,
metadata: Required<vscode.NotebookDocumentMetadata>,
public readonly uri: URI,
public readonly renderingHandler: ExtHostNotebookOutputRenderingHandler,
private readonly _storagePath: URI | undefined
) {
super();
const observableMetadata = getObservable(notebookDocumentMetadataDefaults);
const observableMetadata = getObservable(metadata);
this._metadata = observableMetadata.proxy;
this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => {
this._tryUpdateMetadata();
......@@ -313,7 +313,7 @@ export class ExtHostNotebookDocument extends Disposable {
this._backup = undefined;
}
acceptModelChanged(event: NotebookCellsChangedEvent, isDirty: boolean): void {
acceptModelChanged(event: NotebookCellsChangedEventDto, isDirty: boolean): void {
this._versionId = event.versionId;
this._isDirty = isDirty;
if (event.kind === NotebookCellsChangeType.Initialize) {
......@@ -324,13 +324,9 @@ export class ExtHostNotebookDocument extends Disposable {
this._moveCell(event.index, event.newIdx);
} else if (event.kind === NotebookCellsChangeType.Output) {
this._setCellOutputs(event.index, event.outputs);
} else if (event.kind === NotebookCellsChangeType.CellClearOutput) {
this._clearCellOutputs(event.index);
} else if (event.kind === NotebookCellsChangeType.CellsClearOutput) {
this._clearAllCellOutputs();
} else if (event.kind === NotebookCellsChangeType.ChangeLanguage) {
this._changeCellLanguage(event.index, event.language);
} else if (event.kind === NotebookCellsChangeType.ChangeMetadata) {
} else if (event.kind === NotebookCellsChangeType.ChangeCellMetadata) {
this._changeCellMetadata(event.index, event.metadata);
}
}
......@@ -421,25 +417,6 @@ export class ExtHostNotebookDocument extends Disposable {
this._emitter.emitCellOutputsChange({ document: this.notebookDocument, cells: [cell.cell] });
}
private _clearCellOutputs(index: number): void {
const cell = this._cells[index].cell;
cell.outputs = [];
const event: vscode.NotebookCellOutputsChangeEvent = { document: this.notebookDocument, cells: [cell] };
this._emitter.emitCellOutputsChange(event);
}
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.notebookDocument, cells: modifedCells };
this._emitter.emitCellOutputsChange(event);
}
private _changeCellLanguage(index: number, language: string): void {
const cell = this._cells[index];
const event: vscode.NotebookCellLanguageChangeEvent = { document: this.notebookDocument, cell: cell.cell, language };
......@@ -1247,7 +1224,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
this._webviewComm.get(editorId)?.onDidReceiveMessage(forRendererType, message);
}
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEvent, isDirty: boolean): void {
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEventDto, isDirty: boolean): void {
const document = this._documents.get(URI.revive(uriComponents));
if (document) {
document.acceptModelChanged(event, isDirty);
......@@ -1283,15 +1260,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
visibleRanges: editor.editor.visibleRanges
});
}
}
$acceptDocumentPropertiesChanged(uriComponents: UriComponents, data: INotebookDocumentPropertiesChangeData): void {
this.logService.debug('ExtHostNotebook#$acceptDocumentPropertiesChanged', uriComponents.path, data);
const editor = this._getEditorFromURI(uriComponents);
if (!editor) {
return;
}
if (data.selections) {
if (data.selections.selections.length) {
......@@ -1306,7 +1274,15 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
selection: editor.editor.selection
});
}
}
$acceptDocumentPropertiesChanged(uriComponents: UriComponents, data: INotebookDocumentPropertiesChangeData): void {
this.logService.debug('ExtHostNotebook#$acceptDocumentPropertiesChanged', uriComponents.path, data);
const editor = this._getEditorFromURI(uriComponents);
if (!editor) {
return;
}
if (data.metadata) {
editor.editor.notebookData.notebookDocument.metadata = {
......@@ -1400,15 +1376,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
emitCellMetadataChange(event: vscode.NotebookCellMetadataChangeEvent): void {
that._onDidChangeCellMetadata.fire(event);
}
}, viewType, uri, this, storageRoot);
if (modelData.metadata) {
document.notebookDocument.metadata = {
...notebookDocumentMetadataDefaults,
...modelData.metadata
};
}
}, viewType, { ...notebookDocumentMetadataDefaults, ...modelData.metadata }, uri, this, storageRoot);
document.acceptModelChanged({
kind: NotebookCellsChangeType.Initialize,
......
......@@ -20,7 +20,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis
import { IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/quickinput/common/quickInput';
import { BaseCellRenderTemplate, CellEditState, CellFocusMode, ICellViewModel, INotebookEditor, NOTEBOOK_CELL_INPUT_COLLAPSED, NOTEBOOK_CELL_EDITABLE, NOTEBOOK_CELL_HAS_OUTPUTS, NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_OUTPUT_COLLAPSED, NOTEBOOK_CELL_TYPE, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_RUNNABLE, NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_OUTPUT_FOCUSED, EXPAND_CELL_CONTENT_COMMAND_ID, NOTEBOOK_CELL_EDITOR_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
import { CellKind, CellUri, NotebookCellRunState, NOTEBOOK_EDITOR_CURSOR_BOUNDARY } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellEditType, CellKind, CellUri, NotebookCellMetadata, NotebookCellRunState, NOTEBOOK_EDITOR_CURSOR_BOUNDARY } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
......@@ -1290,14 +1290,25 @@ registerAction2(class extends NotebookCellAction {
return;
}
editor.viewModel.notebookDocument.clearCellOutput(context.cell.handle);
const cell = context.cell;
const index = editor.viewModel.notebookDocument.cells.indexOf(cell.model);
if (index < 0) {
return;
}
editor.viewModel.notebookDocument.applyEdit(editor.viewModel.notebookDocument.versionId, [{ editType: CellEditType.Output, index, outputs: [] }], true);
if (context.cell.metadata && context.cell.metadata?.runState !== NotebookCellRunState.Running) {
context.notebookEditor.viewModel!.notebookDocument.deltaCellMetadata(context.cell.handle, {
runState: NotebookCellRunState.Idle,
runStartTime: undefined,
lastRunDuration: undefined,
statusMessage: undefined
});
context.notebookEditor.viewModel!.notebookDocument.applyEdit(context.notebookEditor.viewModel!.notebookDocument.versionId, [{
editType: CellEditType.Metadata, index, metadata: {
...context.cell.metadata,
runState: NotebookCellRunState.Idle,
runStartTime: undefined,
lastRunDuration: undefined,
statusMessage: undefined
}
}], true);
}
}
});
......@@ -1423,7 +1434,10 @@ registerAction2(class extends NotebookAction {
return;
}
editor.viewModel.notebookDocument.clearAllCellOutputs();
editor.viewModel.notebookDocument.applyEdit(editor.viewModel.notebookDocument.versionId,
editor.viewModel.notebookDocument.cells.map((cell, index) => ({
editType: CellEditType.Output, index, outputs: []
})), true);
}
});
......@@ -1543,7 +1557,27 @@ registerAction2(class extends NotebookCellAction {
}
});
registerAction2(class extends NotebookCellAction {
abstract class ChangeNotebookCellMetadataAction extends NotebookCellAction {
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
const cell = context.cell;
const textModel = context.notebookEditor.viewModel?.notebookDocument;
if (!textModel) {
return;
}
const index = textModel.cells.indexOf(cell.model);
if (index < 0) {
return;
}
textModel.applyEdit(textModel.versionId, [{ editType: CellEditType.Metadata, index, metadata: { ...context.cell.metadata, ...this.getMetadataDelta() } }], true);
}
abstract getMetadataDelta(): NotebookCellMetadata;
}
registerAction2(class extends ChangeNotebookCellMetadataAction {
constructor() {
super({
id: COLLAPSE_CELL_INPUT_COMMAND_ID,
......@@ -1561,12 +1595,12 @@ registerAction2(class extends NotebookCellAction {
});
}
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
context.notebookEditor.viewModel!.notebookDocument.deltaCellMetadata(context.cell.handle, { inputCollapsed: true });
getMetadataDelta(): NotebookCellMetadata {
return { inputCollapsed: true };
}
});
registerAction2(class extends NotebookCellAction {
registerAction2(class extends ChangeNotebookCellMetadataAction {
constructor() {
super({
id: EXPAND_CELL_CONTENT_COMMAND_ID,
......@@ -1584,12 +1618,12 @@ registerAction2(class extends NotebookCellAction {
});
}
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
context.notebookEditor.viewModel!.notebookDocument.deltaCellMetadata(context.cell.handle, { inputCollapsed: false });
getMetadataDelta(): NotebookCellMetadata {
return { inputCollapsed: false };
}
});
registerAction2(class extends NotebookCellAction {
registerAction2(class extends ChangeNotebookCellMetadataAction {
constructor() {
super({
id: COLLAPSE_CELL_OUTPUT_COMMAND_ID,
......@@ -1607,12 +1641,12 @@ registerAction2(class extends NotebookCellAction {
});
}
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
context.notebookEditor.viewModel!.notebookDocument.deltaCellMetadata(context.cell.handle, { outputCollapsed: true });
getMetadataDelta(): NotebookCellMetadata {
return { outputCollapsed: true };
}
});
registerAction2(class extends NotebookCellAction {
registerAction2(class extends ChangeNotebookCellMetadataAction {
constructor() {
super({
id: EXPAND_CELL_OUTPUT_COMMAND_ID,
......@@ -1630,8 +1664,8 @@ registerAction2(class extends NotebookCellAction {
});
}
async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
context.notebookEditor.viewModel!.notebookDocument.deltaCellMetadata(context.cell.handle, { outputCollapsed: false });
getMetadataDelta(): NotebookCellMetadata {
return { outputCollapsed: false };
}
});
......
......@@ -43,11 +43,7 @@ export class SCMController extends Disposable implements INotebookEditorContribu
this.update();
if (this._notebookEditor.textModel) {
this._localDisposable.add(this._notebookEditor.textModel.onDidChangeContent(() => {
this.update();
}));
this._localDisposable.add(this._notebookEditor.textModel.onDidChangeCells(() => {
this._localDisposable.add(this._notebookEditor.textModel.onDidChangeContent((e) => {
this.update();
}));
}
......
......@@ -17,7 +17,7 @@ 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 { CellUri, NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellEditType, 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';
......@@ -451,7 +451,15 @@ abstract class AbstractCellRenderer extends Disposable {
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);
const index = this.notebookEditor.textModel!.cells.indexOf(this.cell.modified!);
if (index < 0) {
return;
}
this.notebookEditor.textModel!.applyEdit(this.notebookEditor.textModel!.versionId, [
{ editType: CellEditType.Metadata, index, metadata: result }
], true);
} catch {
}
}
......
......@@ -233,6 +233,7 @@ export interface INotebookEditor extends IEditor {
getDomNode(): HTMLElement;
getOverflowContainerDomNode(): HTMLElement;
getInnerWebview(): Webview | undefined;
getSelectionHandles(): number[];
/**
* Focus the notebook editor cell list
......
......@@ -215,6 +215,9 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
this._cursorNavigationMode = v;
}
private readonly _onDidChangeSelection = this._register(new Emitter<void>());
get onDidChangeSelection(): Event<void> { return this._onDidChangeSelection.event; }
private readonly _onDidChangeVisibleRanges = this._register(new Emitter<void>());
onDidChangeVisibleRanges: Event<void> = this._onDidChangeVisibleRanges.event;
......@@ -268,6 +271,10 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
return this._uuid;
}
getSelectionHandles(): number[] {
return this.viewModel?.selectionHandles || [];
}
hasModel() {
return !!this._notebookViewModel;
}
......@@ -933,6 +940,10 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
}
}
this._localStore.add(this.viewModel.onDidChangeSelection(() => {
this._onDidChangeSelection.fire();
}));
this._localStore.add(this._list!.onWillScroll(e => {
this._onWillScroll.fire(e);
if (!this._webviewResolved) {
......
......@@ -48,7 +48,7 @@ import { StatefulMarkdownCell } from 'vs/workbench/contrib/notebook/browser/view
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel';
import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
import { CellKind, NotebookCellMetadata, NotebookCellRunState, ShowCellStatusBarKey } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellEditType, CellKind, NotebookCellMetadata, NotebookCellRunState, ShowCellStatusBarKey } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { createAndFillInActionBarActionsWithVerticalSeparators, VerticalSeparator, VerticalSeparatorViewItem } from './cellActionView';
const $ = DOM.$;
......@@ -332,10 +332,21 @@ abstract class AbstractCellRenderer {
return;
}
const textModel = this.notebookEditor.viewModel!.notebookDocument;
const index = textModel.cells.indexOf(templateData.currentRenderedCell.model);
if (index < 0) {
return;
}
if (templateData.currentRenderedCell.metadata?.inputCollapsed) {
this.notebookEditor.viewModel!.notebookDocument.deltaCellMetadata(templateData.currentRenderedCell.handle, { inputCollapsed: false });
textModel.applyEdit(textModel.versionId, [
{ editType: CellEditType.Metadata, index, metadata: { ...templateData.currentRenderedCell.metadata, inputCollapsed: false } }
], true);
} else if (templateData.currentRenderedCell.metadata?.outputCollapsed) {
this.notebookEditor.viewModel!.notebookDocument.deltaCellMetadata(templateData.currentRenderedCell.handle, { outputCollapsed: false });
textModel.applyEdit(textModel.versionId, [
{ editType: CellEditType.Metadata, index, metadata: { ...templateData.currentRenderedCell.metadata, outputCollapsed: false } }
], true);
}
}));
}
......
......@@ -52,12 +52,10 @@ export class JoinCellEdit implements IResourceUndoRedoElement {
const cell = this.editingDelegate.createCellViewModel(this._deletedRawCell);
if (this.direction === 'above') {
this.editingDelegate.insertCell(this.index, this._deletedRawCell);
this.editingDelegate.emitSelections([cell.handle]);
this.editingDelegate.insertCell(this.index, this._deletedRawCell, [cell.handle]);
cell.focusMode = CellFocusMode.Editor;
} else {
this.editingDelegate.insertCell(this.index, cell.model);
this.editingDelegate.emitSelections([this.cell.handle]);
this.editingDelegate.insertCell(this.index, cell.model, [this.cell.handle]);
this.cell.focusMode = CellFocusMode.Editor;
}
}
......@@ -72,8 +70,7 @@ export class JoinCellEdit implements IResourceUndoRedoElement {
{ range: this.inverseRange, text: this.insertContent }
]);
this.editingDelegate.deleteCell(this.index);
this.editingDelegate.emitSelections([this.cell.handle]);
this.editingDelegate.deleteCell(this.index, [this.cell.handle]);
this.cell.focusMode = CellFocusMode.Editor;
}
}
......@@ -110,10 +107,9 @@ export class SplitCellEdit implements IResourceUndoRedoElement {
this.cell.setSelections(this.selections);
for (let j = 1; j < this.cellContents.length; j++) {
this.editingDelegate.deleteCell(this.index + 1);
this.editingDelegate.deleteCell(this.index + 1, j === this.cellContents.length - 1 ? [this.cell.handle] : undefined);
}
this.editingDelegate.emitSelections([this.cell.handle]);
this.cell.focusMode = CellFocusMode.Editor;
}
......@@ -134,7 +130,6 @@ export class SplitCellEdit implements IResourceUndoRedoElement {
}
if (lastCell) {
this.editingDelegate.emitSelections([lastCell.handle]);
lastCell.focusMode = CellFocusMode.Editor;
}
}
......
......@@ -23,7 +23,7 @@ import { NotebookEventDispatcher, NotebookMetadataChangedEvent } from 'vs/workbe
import { CellFoldingState, EditorFoldingStateDelegate } from 'vs/workbench/contrib/notebook/browser/contrib/fold/foldingModel';
import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel';
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
import { CellKind, NotebookCellMetadata, INotebookSearchOptions, ICellRange } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellKind, NotebookCellMetadata, INotebookSearchOptions, ICellRange, NotebookCellsChangeType, ICell, NotebookCellTextModelSplice } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { FoldingRegions } from 'vs/editor/contrib/folding/foldingRanges';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { MarkdownRenderer } from 'vs/workbench/contrib/notebook/browser/view/renderers/mdRenderer';
......@@ -214,7 +214,6 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
}
this._selections = selections;
this._notebook.selections = selections;
this._onDidChangeSelection.fire();
}
......@@ -248,8 +247,8 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
this.id = '$notebookViewModel' + MODEL_ID;
this._instanceId = strings.singleLetterHash(MODEL_ID);
this._register(this._notebook.onDidChangeCells(e => {
const diffs = e.splices.map(splice => {
const compute = (changes: NotebookCellTextModelSplice<ICell>[], synchronous: boolean) => {
const diffs = changes.map(splice => {
return [splice[0], splice[1], splice[2].map(cell => {
return createCellViewModel(this._instantiationService, this, cell as NotebookCellTextModel);
})] as [number, number, CellViewModel[]];
......@@ -272,7 +271,7 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
});
this._onDidChangeViewCells.fire({
synchronous: e.synchronous,
synchronous: synchronous,
splices: diffs
});
......@@ -303,17 +302,31 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
}
this.selectionHandles = endSelectionHandles;
}));
};
this._register(this._notebook.onDidChangeContent(e => {
let changes: NotebookCellTextModelSplice<ICell>[] = [];
this._register(this._notebook.onDidChangeMetadata(e => {
this.eventDispatcher.emit([new NotebookMetadataChangedEvent(e)]);
if (e.kind === NotebookCellsChangeType.ModelChange || e.kind === NotebookCellsChangeType.Initialize) {
changes = e.changes;
compute(changes, e.synchronous);
return;
} else if (e.kind === NotebookCellsChangeType.Move) {
compute([[e.index, e.length, []]], e.synchronous);
compute([[e.newIdx, 0, e.cells]], e.synchronous);
} else {
return;
}
}));
this._register(this._notebook.emitSelections(selections => {
// text model emit selection change (for example, undo/redo)
// we should update the selection handle wisely
// TODO@rebornix, if the editor is note selected, undo/redo should not change the focused element selection
this.updateSelectionsFromEdits(selections);
this._register(this._notebook.onDidChangeContent(e => {
if (e.kind === NotebookCellsChangeType.ChangeDocumentMetadata) {
this.eventDispatcher.emit([new NotebookMetadataChangedEvent(this._notebook.metadata)]);
}
if (e.endSelections) {
this.updateSelectionsFromEdits(e.endSelections);
}
}));
this._register(this.eventDispatcher.onDidChangeLayout((e) => {
......@@ -607,14 +620,15 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
createCell(index: number, source: string, language: string, type: CellKind, metadata: NotebookCellMetadata | undefined, synchronous: boolean, pushUndoStop: boolean = true, previouslyFocused: ICellViewModel[] = []) {
const beforeSelections = previouslyFocused.map(e => e.handle);
this._notebook.createCell2(index, source, language, type, metadata, synchronous, pushUndoStop, beforeSelections, undefined);
// TODO@rebornix, rely on createCell to be sync
const cell = this._notebook.createCellTextModel(source, language, type, [], metadata);
this._notebook.insertCell(index, cell, synchronous, pushUndoStop, beforeSelections, undefined);
// TODO, rely on createCell to be sync
return this.viewCells[index];
}
insertCell(index: number, cell: NotebookCellTextModel, synchronous: boolean, pushUndoStop: boolean = true): CellViewModel {
this._notebook.insertCell2(index, cell, synchronous, pushUndoStop);
// TODO@rebornix, rely on createCell to be sync // this will trigger it to synchronous update
this._notebook.insertCell(index, cell, synchronous, pushUndoStop, undefined, undefined);
// TODO, rely on createCell to be sync // this will trigger it to synchronous update
return this._viewCells[index];
}
......@@ -637,7 +651,7 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
}
}
this._notebook.deleteCell2(index, synchronous, pushUndoStop, this.selectionHandles, endSelections);
this._notebook.deleteCell(index, synchronous, pushUndoStop, this.selectionHandles, endSelections);
}
/**
......@@ -654,7 +668,7 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
return false;
}
this._notebook.moveCellToIdx2(index, length, newIdx, synchronous, pushedToUndoStack, undefined, [viewCell.handle]);
this._notebook.moveCellToIdx(index, length, newIdx, synchronous, pushedToUndoStack, undefined, [viewCell.handle]);
return true;
}
......@@ -757,9 +771,6 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
},
deleteCell: (index: number) => {
this.deleteCell(index, true, false);
},
emitSelections: (selections: number[]) => {
this.updateSelectionsFromEdits(selections);
}
}
));
......@@ -828,7 +839,7 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
insertContent,
cell,
{
insertCell: (index: number, cell: NotebookCellTextModel) => {
insertCell: (index: number, cell: NotebookCellTextModel, endSelections?: number[]) => {
this.insertCell(index, cell, true, false);
},
deleteCell: (index: number) => {
......@@ -836,9 +847,6 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
},
createCellViewModel: (cell: NotebookCellTextModel) => {
return createCellViewModel(this._instantiationService, this, cell);
},
emitSelections: (selections: number[]) => {
this.updateSelectionsFromEdits(selections);
}
})
);
......@@ -882,7 +890,7 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
insertContent,
below,
{
insertCell: (index: number, cell: NotebookCellTextModel) => {
insertCell: (index: number, cell: NotebookCellTextModel, endSelections?: number[]) => {
this.insertCell(index, cell, true, false);
},
deleteCell: (index: number) => {
......@@ -890,9 +898,6 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
},
createCellViewModel: (cell: NotebookCellTextModel) => {
return createCellViewModel(this._instantiationService, this, cell);
},
emitSelections: (selections: number[]) => {
this.updateSelectionsFromEdits(selections);
}
})
);
......
......@@ -12,11 +12,10 @@ import { NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/noteb
* It should not modify Undo/Redo stack
*/
export interface ITextCellEditingDelegate {
insertCell?(index: number, cell: NotebookCellTextModel): void;
deleteCell?(index: number): void;
insertCell?(index: number, cell: NotebookCellTextModel, endSelections?: number[]): void;
deleteCell?(index: number, endSelections?: number[]): void;
moveCell?(fromIndex: number, length: number, toIndex: number, beforeSelections: number[] | undefined, endSelections: number[] | undefined): void;
updateCellMetadata?(index: number, newMetadata: NotebookCellMetadata): void;
emitSelections(selections: number[]): void;
}
......@@ -38,20 +37,14 @@ export class InsertCellEdit implements IResourceUndoRedoElement {
throw new Error('Notebook Delete Cell not implemented for Undo/Redo');
}
this.editingDelegate.deleteCell(this.insertIndex);
if (this.beforedSelections) {
this.editingDelegate.emitSelections(this.beforedSelections);
}
this.editingDelegate.deleteCell(this.insertIndex, this.beforedSelections);
}
redo(): void {
if (!this.editingDelegate.insertCell) {
throw new Error('Notebook Insert Cell not implemented for Undo/Redo');
}
this.editingDelegate.insertCell(this.insertIndex, this.cell);
if (this.endSelections) {
this.editingDelegate.emitSelections(this.endSelections);
}
this.editingDelegate.insertCell(this.insertIndex, this.cell, this.endSelections);
}
}
......@@ -77,10 +70,7 @@ export class DeleteCellEdit implements IResourceUndoRedoElement {
throw new Error('Notebook Insert Cell not implemented for Undo/Redo');
}
this.editingDelegate.insertCell(this.insertIndex, this._cell);
if (this.beforedSelections) {
this.editingDelegate.emitSelections(this.beforedSelections);
}
this.editingDelegate.insertCell(this.insertIndex, this._cell, this.beforedSelections);
}
redo(): void {
......@@ -88,10 +78,7 @@ export class DeleteCellEdit implements IResourceUndoRedoElement {
throw new Error('Notebook Delete Cell not implemented for Undo/Redo');
}
this.editingDelegate.deleteCell(this.insertIndex);
if (this.endSelections) {
this.editingDelegate.emitSelections(this.endSelections);
}
this.editingDelegate.deleteCell(this.insertIndex, this.endSelections);
}
}
......@@ -116,9 +103,6 @@ export class MoveCellEdit implements IResourceUndoRedoElement {
}
this.editingDelegate.moveCell(this.toIndex, this.length, this.fromIndex, this.endSelections, this.beforedSelections);
if (this.beforedSelections) {
this.editingDelegate.emitSelections(this.beforedSelections);
}
}
redo(): void {
......@@ -127,9 +111,6 @@ export class MoveCellEdit implements IResourceUndoRedoElement {
}
this.editingDelegate.moveCell(this.fromIndex, this.length, this.toIndex, this.beforedSelections, this.endSelections);
if (this.endSelections) {
this.editingDelegate.emitSelections(this.endSelections);
}
}
}
......@@ -152,17 +133,13 @@ export class SpliceCellsEdit implements IResourceUndoRedoElement {
this.diffs.forEach(diff => {
for (let i = 0; i < diff[2].length; i++) {
this.editingDelegate.deleteCell!(diff[0]);
this.editingDelegate.deleteCell!(diff[0], this.beforeHandles);
}
diff[1].reverse().forEach(cell => {
this.editingDelegate.insertCell!(diff[0], cell);
this.editingDelegate.insertCell!(diff[0], cell, this.beforeHandles);
});
});
if (this.beforeHandles) {
this.editingDelegate.emitSelections(this.beforeHandles);
}
}
redo(): void {
......@@ -172,17 +149,13 @@ export class SpliceCellsEdit implements IResourceUndoRedoElement {
this.diffs.reverse().forEach(diff => {
for (let i = 0; i < diff[1].length; i++) {
this.editingDelegate.deleteCell!(diff[0]);
this.editingDelegate.deleteCell!(diff[0], this.endHandles);
}
diff[2].reverse().forEach(cell => {
this.editingDelegate.insertCell!(diff[0], cell);
this.editingDelegate.insertCell!(diff[0], cell, this.endHandles);
});
});
if (this.endHandles) {
this.editingDelegate.emitSelections(this.endHandles);
}
}
}
......
......@@ -276,8 +276,6 @@ export interface INotebookTextModel {
readonly versionId: number;
languages: string[];
readonly cells: readonly ICell[];
onDidChangeCells: Event<{ synchronous: boolean, splices: NotebookCellTextModelSplice[] }>;
onDidChangeContent: Event<void>;
onWillDispose(listener: () => void): IDisposable;
}
......@@ -311,10 +309,10 @@ export type IRenderOutput = IRenderNoOutput | IInsetRenderOutput;
export const outputHasDynamicHeight = (o: IRenderOutput) => o.type !== RenderOutputType.Extension && o.hasDynamicHeight;
export type NotebookCellTextModelSplice = [
export type NotebookCellTextModelSplice<T> = [
number /* start */,
number,
ICell[]
T[]
];
export type NotebookCellOutputsSplice = [
......@@ -347,26 +345,35 @@ export enum NotebookCellsChangeType {
CellsClearOutput = 4,
ChangeLanguage = 5,
Initialize = 6,
ChangeMetadata = 7,
ChangeCellMetadata = 7,
Output = 8,
ChangeCellContent = 9,
ChangeDocumentMetadata = 10
}
export interface NotebookCellsInitializeEvent {
export interface NotebookCellsInitializeEvent<T> {
readonly kind: NotebookCellsChangeType.Initialize;
readonly changes: NotebookCellsSplice2[];
readonly changes: NotebookCellTextModelSplice<T>[];
readonly versionId: number;
}
export interface NotebookCellsModelChangedEvent {
export interface NotebookCellContentChangeEvent {
readonly kind: NotebookCellsChangeType.ChangeCellContent;
readonly versionId: number;
}
export interface NotebookCellsModelChangedEvent<T> {
readonly kind: NotebookCellsChangeType.ModelChange;
readonly changes: NotebookCellsSplice2[];
readonly changes: NotebookCellTextModelSplice<T>[];
readonly versionId: number;
}
export interface NotebookCellsModelMoveEvent {
export interface NotebookCellsModelMoveEvent<T> {
readonly kind: NotebookCellsChangeType.Move;
readonly index: number;
readonly length: number;
readonly newIdx: number;
readonly cells: T[];
readonly versionId: number;
}
......@@ -375,17 +382,7 @@ export interface NotebookOutputChangedEvent {
readonly index: number;
readonly versionId: number;
readonly outputs: IProcessedOutput[];
}
export interface NotebookCellClearOutputEvent {
readonly kind: NotebookCellsChangeType.CellClearOutput;
readonly index: number;
readonly versionId: number;
}
export interface NotebookCellsClearOutputEvent {
readonly kind: NotebookCellsChangeType.CellsClearOutput;
readonly versionId: number;
readonly transient: boolean;
}
export interface NotebookCellsChangeLanguageEvent {
......@@ -396,13 +393,20 @@ export interface NotebookCellsChangeLanguageEvent {
}
export interface NotebookCellsChangeMetadataEvent {
readonly kind: NotebookCellsChangeType.ChangeMetadata;
readonly kind: NotebookCellsChangeType.ChangeCellMetadata;
readonly versionId: number;
readonly index: number;
readonly metadata: NotebookCellMetadata | undefined;
}
export type NotebookCellsChangedEvent = NotebookCellsInitializeEvent | NotebookCellsModelChangedEvent | NotebookCellsModelMoveEvent | NotebookOutputChangedEvent | NotebookCellClearOutputEvent | NotebookCellsClearOutputEvent | NotebookCellsChangeLanguageEvent | NotebookCellsChangeMetadataEvent;
export interface NotebookDocumentChangeMetadataEvent {
readonly kind: NotebookCellsChangeType.ChangeDocumentMetadata;
readonly versionId: number;
readonly metadata: NotebookDocumentMetadata | undefined;
}
export type NotebookCellsChangedEventDto = NotebookCellsInitializeEvent<IMainCellDto> | NotebookDocumentChangeMetadataEvent | NotebookCellContentChangeEvent | NotebookCellsModelChangedEvent<IMainCellDto> | NotebookCellsModelMoveEvent<IMainCellDto> | NotebookOutputChangedEvent | NotebookCellsChangeLanguageEvent | NotebookCellsChangeMetadataEvent;
export type NotebookTextModelChangedEvent = (NotebookCellsInitializeEvent<ICell> | NotebookDocumentChangeMetadataEvent | NotebookCellContentChangeEvent | NotebookCellsModelChangedEvent<ICell> | NotebookCellsModelMoveEvent<ICell> | NotebookOutputChangedEvent | NotebookCellsChangeLanguageEvent | NotebookCellsChangeMetadataEvent) & { synchronous: boolean; endSelections?: number[] };
export const enum CellEditType {
Replace = 1,
......@@ -687,6 +691,8 @@ export interface IEditor extends editorCommon.ICompositeCodeEditor {
readonly onDidChangeModel: Event<NotebookTextModel | undefined>;
readonly onDidFocusEditorWidget: Event<void>;
readonly onDidChangeVisibleRanges: Event<void>;
readonly onDidChangeSelection: Event<void>;
getSelectionHandles(): number[];
isNotebookEditor: boolean;
visibleRanges: ICellRange[];
uri?: URI;
......
......@@ -6,7 +6,7 @@
import * as nls from 'vs/nls';
import { EditorModel, IRevertOptions } from 'vs/workbench/common/editor';
import { Emitter, Event } from 'vs/base/common/event';
import { INotebookEditorModel, NotebookDocumentBackupData } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookEditorModel, NotebookCellsChangeType, NotebookDocumentBackupData } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { URI } from 'vs/base/common/uri';
......@@ -145,9 +145,12 @@ export class NotebookEditorModel extends EditorModel implements INotebookEditorM
this._register(this._notebook);
this._register(this._notebook.onDidChangeContent(() => {
this._onDidChangeContent.fire();
this._register(this._notebook.onDidChangeContent(e => {
if (e.kind !== NotebookCellsChangeType.Initialize) {
this._onDidChangeContent.fire();
}
}));
this._register(this._notebook.onDidChangeDirty(() => {
this._onDidChangeDirty.fire();
}));
......
......@@ -69,18 +69,18 @@ suite('NotebookViewModel', () => {
['//c', 'javascript', CellKind.Code, [], { editable: true }],
],
(editor, viewModel) => {
viewModel.moveCellToIdx(0, 1, 0, false);
viewModel.moveCellToIdx(0, 1, 0, true);
// no-op
assert.equal(viewModel.viewCells[0].getText(), '//a');
assert.equal(viewModel.viewCells[1].getText(), '//b');
viewModel.moveCellToIdx(0, 1, 1, false);
viewModel.moveCellToIdx(0, 1, 1, true);
// b, a, c
assert.equal(viewModel.viewCells[0].getText(), '//b');
assert.equal(viewModel.viewCells[1].getText(), '//a');
assert.equal(viewModel.viewCells[2].getText(), '//c');
viewModel.moveCellToIdx(0, 1, 2, false);
viewModel.moveCellToIdx(0, 1, 2, true);
// a, c, b
assert.equal(viewModel.viewCells[0].getText(), '//a');
assert.equal(viewModel.viewCells[1].getText(), '//c');
......@@ -100,12 +100,12 @@ suite('NotebookViewModel', () => {
['//c', 'javascript', CellKind.Code, [], { editable: true }],
],
(editor, viewModel) => {
viewModel.moveCellToIdx(1, 1, 0, false);
viewModel.moveCellToIdx(1, 1, 0, true);
// b, a, c
assert.equal(viewModel.viewCells[0].getText(), '//b');
assert.equal(viewModel.viewCells[1].getText(), '//a');
viewModel.moveCellToIdx(2, 1, 0, false);
viewModel.moveCellToIdx(2, 1, 0, true);
// c, b, a
assert.equal(viewModel.viewCells[0].getText(), '//c');
assert.equal(viewModel.viewCells[1].getText(), '//b');
......
......@@ -66,6 +66,9 @@ export class TestNotebookEditor implements INotebookEditor {
constructor(
) { }
getSelectionHandles(): number[] {
return [];
}
setOptions(options: NotebookEditorOptions | undefined): Promise<void> {
......@@ -82,6 +85,7 @@ export class TestNotebookEditor implements INotebookEditor {
onDidScroll = new Emitter<ScrollEvent>().event;
onWillDispose = new Emitter<void>().event;
onDidChangeVisibleRanges: Event<void> = new Emitter<void>().event;
onDidChangeSelection: Event<void> = new Emitter<void>().event;
visibleRanges: ICellRange[] = [];
uri?: URI | undefined;
textModel?: NotebookTextModel | undefined;
......@@ -333,7 +337,7 @@ export class NotebookEditorTestModel extends EditorModel implements INotebookEdi
) {
super();
if (_notebook && _notebook.onDidChangeCells) {
if (_notebook && _notebook.onDidChangeContent) {
this._register(_notebook.onDidChangeContent(() => {
this._dirty = true;
this._onDidChangeDirty.fire();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册