mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-23 18:19:12 +01:00
For #149271 - `NotebookEditor.document` -> `NotebookEditor.notebook` - Add `selection` to for setting primary selections. Matches `TextDocument.selection` - Deprecate `showNotebookDocument`
233 lines
6.6 KiB
TypeScript
233 lines
6.6 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
import { ICellEditOperationDto, MainThreadNotebookEditorsShape } from 'vs/workbench/api/common/extHost.protocol';
|
|
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
|
import * as extHostConverter from 'vs/workbench/api/common/extHostTypeConverters';
|
|
import { CellEditType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
|
import * as vscode from 'vscode';
|
|
import { ExtHostNotebookDocument } from './extHostNotebookDocument';
|
|
import { illegalArgument } from 'vs/base/common/errors';
|
|
|
|
interface INotebookEditData {
|
|
documentVersionId: number;
|
|
cellEdits: ICellEditOperationDto[];
|
|
}
|
|
|
|
class NotebookEditorCellEditBuilder implements vscode.NotebookEditorEdit {
|
|
|
|
private readonly _documentVersionId: number;
|
|
|
|
private _finalized: boolean = false;
|
|
private _collectedEdits: ICellEditOperationDto[] = [];
|
|
|
|
constructor(documentVersionId: number) {
|
|
this._documentVersionId = documentVersionId;
|
|
}
|
|
|
|
finalize(): INotebookEditData {
|
|
this._finalized = true;
|
|
return {
|
|
documentVersionId: this._documentVersionId,
|
|
cellEdits: this._collectedEdits
|
|
};
|
|
}
|
|
|
|
private _throwIfFinalized() {
|
|
if (this._finalized) {
|
|
throw new Error('Edit is only valid while callback runs');
|
|
}
|
|
}
|
|
|
|
replaceMetadata(value: { [key: string]: any }): void {
|
|
this._throwIfFinalized();
|
|
this._collectedEdits.push({
|
|
editType: CellEditType.DocumentMetadata,
|
|
metadata: value
|
|
});
|
|
}
|
|
|
|
replaceCellMetadata(index: number, metadata: Record<string, any>): void {
|
|
this._throwIfFinalized();
|
|
this._collectedEdits.push({
|
|
editType: CellEditType.PartialMetadata,
|
|
index,
|
|
metadata
|
|
});
|
|
}
|
|
|
|
replaceCells(from: number, to: number, cells: vscode.NotebookCellData[]): void {
|
|
this._throwIfFinalized();
|
|
if (from === to && cells.length === 0) {
|
|
return;
|
|
}
|
|
this._collectedEdits.push({
|
|
editType: CellEditType.Replace,
|
|
index: from,
|
|
count: to - from,
|
|
cells: cells.map(extHostConverter.NotebookCellData.from)
|
|
});
|
|
}
|
|
}
|
|
|
|
export class ExtHostNotebookEditor {
|
|
|
|
public static readonly apiEditorsToExtHost = new WeakMap<vscode.NotebookEditor, ExtHostNotebookEditor>();
|
|
|
|
private _selections: vscode.NotebookRange[] = [];
|
|
private _visibleRanges: vscode.NotebookRange[] = [];
|
|
private _viewColumn?: vscode.ViewColumn;
|
|
|
|
private _visible: boolean = false;
|
|
private readonly _hasDecorationsForKey = new Set<string>();
|
|
|
|
private _editor?: vscode.NotebookEditor;
|
|
|
|
constructor(
|
|
readonly id: string,
|
|
private readonly _proxy: MainThreadNotebookEditorsShape,
|
|
readonly notebookData: ExtHostNotebookDocument,
|
|
visibleRanges: vscode.NotebookRange[],
|
|
selections: vscode.NotebookRange[],
|
|
viewColumn: vscode.ViewColumn | undefined
|
|
) {
|
|
this._selections = selections;
|
|
this._visibleRanges = visibleRanges;
|
|
this._viewColumn = viewColumn;
|
|
}
|
|
|
|
get apiEditor(): vscode.NotebookEditor {
|
|
if (!this._editor) {
|
|
const that = this;
|
|
this._editor = {
|
|
get document() {
|
|
return that.notebookData.apiNotebook;
|
|
},
|
|
get notebook() {
|
|
return that.notebookData.apiNotebook;
|
|
},
|
|
get selection() {
|
|
return that._selections[0];
|
|
},
|
|
set selection(selection: vscode.NotebookRange) {
|
|
this.selections = [selection];
|
|
},
|
|
get selections() {
|
|
return that._selections;
|
|
},
|
|
set selections(value: vscode.NotebookRange[]) {
|
|
if (!Array.isArray(value) || !value.every(extHostTypes.NotebookRange.isNotebookRange)) {
|
|
throw illegalArgument('selections');
|
|
}
|
|
that._selections = value;
|
|
that._trySetSelections(value);
|
|
},
|
|
get visibleRanges() {
|
|
return that._visibleRanges;
|
|
},
|
|
revealRange(range, revealType) {
|
|
that._proxy.$tryRevealRange(
|
|
that.id,
|
|
extHostConverter.NotebookRange.from(range),
|
|
revealType ?? extHostTypes.NotebookEditorRevealType.Default
|
|
);
|
|
},
|
|
get viewColumn() {
|
|
return that._viewColumn;
|
|
},
|
|
edit(callback) {
|
|
const edit = new NotebookEditorCellEditBuilder(this.document.version);
|
|
callback(edit);
|
|
return that._applyEdit(edit.finalize());
|
|
},
|
|
setDecorations(decorationType, range) {
|
|
return that.setDecorations(decorationType, range);
|
|
}
|
|
};
|
|
|
|
ExtHostNotebookEditor.apiEditorsToExtHost.set(this._editor, this);
|
|
}
|
|
return this._editor;
|
|
}
|
|
|
|
get visible(): boolean {
|
|
return this._visible;
|
|
}
|
|
|
|
_acceptVisibility(value: boolean) {
|
|
this._visible = value;
|
|
}
|
|
|
|
_acceptVisibleRanges(value: vscode.NotebookRange[]): void {
|
|
this._visibleRanges = value;
|
|
}
|
|
|
|
_acceptSelections(selections: vscode.NotebookRange[]): void {
|
|
this._selections = selections;
|
|
}
|
|
|
|
private _trySetSelections(value: vscode.NotebookRange[]): void {
|
|
this._proxy.$trySetSelections(this.id, value.map(extHostConverter.NotebookRange.from));
|
|
}
|
|
|
|
_acceptViewColumn(value: vscode.ViewColumn | undefined) {
|
|
this._viewColumn = value;
|
|
}
|
|
|
|
private _applyEdit(editData: INotebookEditData): Promise<boolean> {
|
|
|
|
// return when there is nothing to do
|
|
if (editData.cellEdits.length === 0) {
|
|
return Promise.resolve(true);
|
|
}
|
|
|
|
const compressedEdits: ICellEditOperationDto[] = [];
|
|
let compressedEditsIndex = -1;
|
|
|
|
for (let i = 0; i < editData.cellEdits.length; i++) {
|
|
if (compressedEditsIndex < 0) {
|
|
compressedEdits.push(editData.cellEdits[i]);
|
|
compressedEditsIndex++;
|
|
continue;
|
|
}
|
|
|
|
const prevIndex = compressedEditsIndex;
|
|
const prev = compressedEdits[prevIndex];
|
|
|
|
const edit = editData.cellEdits[i];
|
|
if (prev.editType === CellEditType.Replace && edit.editType === CellEditType.Replace) {
|
|
if (prev.index === edit.index) {
|
|
prev.cells.push(...(editData.cellEdits[i] as any).cells);
|
|
prev.count += (editData.cellEdits[i] as any).count;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
compressedEdits.push(editData.cellEdits[i]);
|
|
compressedEditsIndex++;
|
|
}
|
|
|
|
return this._proxy.$tryApplyEdits(this.id, editData.documentVersionId, compressedEdits);
|
|
}
|
|
|
|
setDecorations(decorationType: vscode.NotebookEditorDecorationType, range: vscode.NotebookRange): void {
|
|
if (range.isEmpty && !this._hasDecorationsForKey.has(decorationType.key)) {
|
|
// avoid no-op call to the renderer
|
|
return;
|
|
}
|
|
if (range.isEmpty) {
|
|
this._hasDecorationsForKey.delete(decorationType.key);
|
|
} else {
|
|
this._hasDecorationsForKey.add(decorationType.key);
|
|
}
|
|
|
|
return this._proxy.$trySetDecorations(
|
|
this.id,
|
|
extHostConverter.NotebookRange.from(range),
|
|
decorationType.key
|
|
);
|
|
}
|
|
}
|