mirror of
https://github.com/Microsoft/vscode
synced 2024-09-18 01:58:27 +00:00
Merge pull request #117204 from microsoft/rebornix/nb-selections
Notebook selections/CellRange
This commit is contained in:
commit
08eac1a22d
12
src/vs/vscode.proposed.d.ts
vendored
12
src/vs/vscode.proposed.d.ts
vendored
|
@ -1264,11 +1264,13 @@ declare module 'vscode' {
|
|||
// todo@API should not be undefined, rather a default
|
||||
readonly selection?: NotebookCell;
|
||||
|
||||
// @rebornix
|
||||
// todo@API should replace selection
|
||||
// never empty!
|
||||
// primary/secondary selections
|
||||
// readonly selections: NotebookCellRange[];
|
||||
/**
|
||||
* todo@API should replace selection
|
||||
* The selections on this notebook editor.
|
||||
*
|
||||
* The primary selection (or focused range) is `selections[0]`. When the document has no cells, the primary selection is empty `{ start: 0, end: 0 }`;
|
||||
*/
|
||||
readonly selections: NotebookCellRange[];
|
||||
|
||||
/**
|
||||
* The current visible ranges in the editor (vertically).
|
||||
|
|
|
@ -96,7 +96,7 @@ class DocumentAndEditorState {
|
|||
return {
|
||||
id: add.getId(),
|
||||
documentUri: add.uri!,
|
||||
selections: add.getSelectionHandles(),
|
||||
selections: add.getSelections(),
|
||||
visibleRanges: add.visibleRanges
|
||||
};
|
||||
}
|
||||
|
@ -244,8 +244,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
|||
}));
|
||||
|
||||
disposableStore.add(editor.onDidChangeSelection(() => {
|
||||
const selectionHandles = editor.getSelectionHandles();
|
||||
this._proxy.$acceptEditorPropertiesChanged(editor.getId(), { visibleRanges: null, selections: { selections: selectionHandles } });
|
||||
this._proxy.$acceptEditorPropertiesChanged(editor.getId(), { visibleRanges: null, selections: { selections: editor.getSelections() } });
|
||||
}));
|
||||
|
||||
this._editorEventListenersMapping.set(editor.getId(), disposableStore);
|
||||
|
@ -689,7 +688,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
|||
if (notebookEditor.viewModel && options.selection && notebookEditor.viewModel.viewCells[options.selection.start]) {
|
||||
const focusedCell = notebookEditor.viewModel.viewCells[options.selection.start];
|
||||
notebookEditor.revealInCenterIfOutsideViewport(focusedCell);
|
||||
notebookEditor.selectElement(focusedCell);
|
||||
notebookEditor.focusElement(focusedCell);
|
||||
}
|
||||
return notebookEditor.getId();
|
||||
} else {
|
||||
|
|
|
@ -1742,8 +1742,7 @@ export interface ExtHostCommentsShape {
|
|||
}
|
||||
|
||||
export interface INotebookSelectionChangeEvent {
|
||||
// handles
|
||||
selections: number[];
|
||||
selections: ICellRange[];
|
||||
}
|
||||
|
||||
export interface INotebookVisibleRangesEvent {
|
||||
|
@ -1771,7 +1770,7 @@ export interface INotebookModelAddedData {
|
|||
export interface INotebookEditorAddData {
|
||||
id: string;
|
||||
documentUri: UriComponents;
|
||||
selections: number[];
|
||||
selections: ICellRange[];
|
||||
visibleRanges: ICellRange[];
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,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 { CellStatusbarAlignment, CellUri, INotebookCellStatusBarEntry, INotebookExclusiveDocumentFilter, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookDataDto, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellStatusbarAlignment, CellUri, ICellRange, INotebookCellStatusBarEntry, INotebookExclusiveDocumentFilter, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookDataDto, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import * as vscode from 'vscode';
|
||||
import { ResourceMap } from 'vs/base/common/map';
|
||||
import { ExtHostCell, ExtHostNotebookDocument } from './extHostNotebookDocument';
|
||||
|
@ -589,16 +589,11 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
|
|||
}
|
||||
|
||||
if (data.selections) {
|
||||
if (data.selections.selections.length) {
|
||||
const firstCell = data.selections.selections[0];
|
||||
editor.editor.selection = editor.editor.notebookData.getCell(firstCell)?.cell;
|
||||
} else {
|
||||
editor.editor.selection = undefined;
|
||||
}
|
||||
editor.editor._acceptSelections(data.selections.selections);
|
||||
|
||||
this._onDidChangeNotebookEditorSelection.fire({
|
||||
notebookEditor: editor.editor.editor,
|
||||
selection: editor.editor.selection
|
||||
selection: editor.editor.editor.selection
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -609,7 +604,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
|
|||
document.acceptDocumentPropertiesChanged(data);
|
||||
}
|
||||
|
||||
private _createExtHostEditor(document: ExtHostNotebookDocument, editorId: string, selections: number[], visibleRanges: extHostTypes.NotebookCellRange[]) {
|
||||
private _createExtHostEditor(document: ExtHostNotebookDocument, editorId: string, selections: ICellRange[], visibleRanges: extHostTypes.NotebookCellRange[]) {
|
||||
const revivedUri = document.uri;
|
||||
let webComm = this._webviewComm.get(editorId);
|
||||
|
||||
|
@ -625,13 +620,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
|
|||
document
|
||||
);
|
||||
|
||||
if (selections.length) {
|
||||
const firstCell = selections[0];
|
||||
editor.selection = editor.notebookData.getCell(firstCell)?.cell;
|
||||
} else {
|
||||
editor.selection = undefined;
|
||||
}
|
||||
|
||||
editor._acceptSelections(selections);
|
||||
editor._acceptVisibleRanges(visibleRanges);
|
||||
|
||||
this._editors.get(editorId)?.editor.dispose();
|
||||
|
|
|
@ -326,6 +326,10 @@ export class ExtHostNotebookDocument extends Disposable {
|
|||
this._emitter.emitCellMetadataChange(event);
|
||||
}
|
||||
|
||||
getCellFromIndex(index: number): ExtHostCell | undefined {
|
||||
return this._cells[index];
|
||||
}
|
||||
|
||||
getCell(cellHandle: number): ExtHostCell | undefined {
|
||||
return this._cells.find(cell => cell.handle === cellHandle);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import { Emitter, Event } from 'vs/base/common/event';
|
|||
import { MainThreadNotebookShape } 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, ICellEditOperation, ICellReplaceEdit, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellEditType, ICellEditOperation, ICellRange, ICellReplaceEdit, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtHostNotebookDocument } from './extHostNotebookDocument';
|
||||
|
||||
|
@ -85,9 +85,8 @@ class NotebookEditorCellEditBuilder implements vscode.NotebookEditorEdit {
|
|||
}
|
||||
|
||||
export class ExtHostNotebookEditor {
|
||||
|
||||
//TODO@rebornix noop setter?
|
||||
selection?: vscode.NotebookCell;
|
||||
private _selection?: vscode.NotebookCell;
|
||||
private _selections: vscode.NotebookCellRange[] = [];
|
||||
|
||||
private _visibleRanges: extHostTypes.NotebookCellRange[] = [];
|
||||
private _viewColumn?: vscode.ViewColumn;
|
||||
|
@ -123,7 +122,10 @@ export class ExtHostNotebookEditor {
|
|||
return that.notebookData.notebookDocument;
|
||||
},
|
||||
get selection() {
|
||||
return that.selection;
|
||||
return that._selection;
|
||||
},
|
||||
get selections() {
|
||||
return that._selections;
|
||||
},
|
||||
get visibleRanges() {
|
||||
return that._visibleRanges;
|
||||
|
@ -173,6 +175,12 @@ export class ExtHostNotebookEditor {
|
|||
this._visibleRanges = value;
|
||||
}
|
||||
|
||||
_acceptSelections(selections: ICellRange[]): void {
|
||||
const primarySelection = selections[0];
|
||||
this._selection = primarySelection ? this.notebookData.getCellFromIndex(primarySelection.start)?.cell : undefined;
|
||||
this._selections = selections.map(val => new extHostTypes.NotebookCellRange(val.start, val.end));
|
||||
}
|
||||
|
||||
get active(): boolean {
|
||||
return this._active;
|
||||
}
|
||||
|
|
|
@ -160,7 +160,7 @@ export class NotebookFindWidget extends SimpleFindReplaceWidget implements INote
|
|||
|
||||
private revealCellRange(cellIndex: number, matchIndex: number) {
|
||||
this._findMatches[cellIndex].cell.editState = CellEditState.Editing;
|
||||
this._notebookEditor.selectElement(this._findMatches[cellIndex].cell);
|
||||
this._notebookEditor.focusElement(this._findMatches[cellIndex].cell);
|
||||
this._notebookEditor.setCellSelection(this._findMatches[cellIndex].cell, this._findMatches[cellIndex].matches[matchIndex].range);
|
||||
this._notebookEditor.revealRangeInCenterIfOutsideViewportAsync(this._findMatches[cellIndex].cell, this._findMatches[cellIndex].matches[matchIndex].range);
|
||||
}
|
||||
|
|
|
@ -134,6 +134,7 @@ export class FoldingController extends Disposable implements INotebookEditorCont
|
|||
}
|
||||
|
||||
this.setFoldingStateUp(modelIndex, state === CellFoldingState.Collapsed ? CellFoldingState.Expanded : CellFoldingState.Collapsed, 1);
|
||||
this._notebookEditor.focusElement(cellViewModel);
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -225,7 +226,7 @@ registerAction2(class extends Action2 {
|
|||
}
|
||||
|
||||
const viewIndex = editor.viewModel!.getNearestVisibleCellIndexUpwards(index);
|
||||
editor.selectElement(editor.viewModel!.viewCells[viewIndex]);
|
||||
editor.focusElement(editor.viewModel!.viewCells[viewIndex]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -9,7 +9,7 @@ import { TrackedRangeStickiness } from 'vs/editor/common/model';
|
|||
import { FoldingRegion, FoldingRegions } from 'vs/editor/contrib/folding/foldingRanges';
|
||||
import { IFoldingRangeData, sanitizeRanges } from 'vs/editor/contrib/folding/syntaxRangeProvider';
|
||||
import { CellViewModel, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
|
||||
import { CellKind, ICellRange } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellKind, cellRangesToIndexes, ICellRange } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
|
||||
type RegionFilter = (r: FoldingRegion) => boolean;
|
||||
type RegionFilterWithLevel = (r: FoldingRegion, level: number) => boolean;
|
||||
|
@ -52,10 +52,7 @@ export class FoldingModel extends Disposable {
|
|||
return;
|
||||
}
|
||||
|
||||
const selectionHandles = this._viewModel.selectionHandles;
|
||||
const indexes = selectionHandles.map(handle =>
|
||||
this._viewModel!.getCellIndex(this._viewModel!.getCellByHandle(handle)!)
|
||||
);
|
||||
const indexes = cellRangesToIndexes(this._viewModel.getSelections());
|
||||
|
||||
let changed = false;
|
||||
|
||||
|
|
|
@ -389,7 +389,8 @@ class NotebookCellOutline implements IOutline<OutlineEntry> {
|
|||
includeCodeCells = this._configurationService.getValue<boolean>('notebook.breadcrumbs.showCodeCells');
|
||||
}
|
||||
|
||||
const [selected] = viewModel.selectionHandles;
|
||||
const selectedCellIndex = viewModel.getSelection().start;
|
||||
const selected = viewModel.getCellByIndex(selectedCellIndex)?.handle;
|
||||
const entries: OutlineEntry[] = [];
|
||||
|
||||
for (let i = 0; i < viewModel.viewCells.length; i++) {
|
||||
|
@ -511,8 +512,7 @@ class NotebookCellOutline implements IOutline<OutlineEntry> {
|
|||
const { viewModel } = this._editor;
|
||||
|
||||
if (viewModel) {
|
||||
const [selected] = viewModel.selectionHandles;
|
||||
const cell = viewModel.getCellByHandle(selected);
|
||||
const cell = viewModel.getCellByIndex(viewModel.getSelection()?.start);
|
||||
if (cell) {
|
||||
for (let entry of this._entries) {
|
||||
newActive = entry.find(cell, []);
|
||||
|
|
|
@ -324,6 +324,8 @@ export interface INotebookEditorCreationOptions {
|
|||
export interface IActiveNotebookEditor extends INotebookEditor {
|
||||
viewModel: NotebookViewModel;
|
||||
uri: URI;
|
||||
// selection is never undefined when the editor is attached to a document.
|
||||
getSelection(): ICellRange;
|
||||
}
|
||||
|
||||
export interface INotebookEditor extends IEditor, ICommonNotebookEditor {
|
||||
|
@ -358,7 +360,6 @@ export interface INotebookEditor extends IEditor, ICommonNotebookEditor {
|
|||
getDomNode(): HTMLElement;
|
||||
getOverflowContainerDomNode(): HTMLElement;
|
||||
getInnerWebview(): Webview | undefined;
|
||||
getSelectionHandles(): number[];
|
||||
getSelectionViewModels(): ICellViewModel[];
|
||||
|
||||
/**
|
||||
|
@ -375,7 +376,7 @@ export interface INotebookEditor extends IEditor, ICommonNotebookEditor {
|
|||
/**
|
||||
* Select & focus cell
|
||||
*/
|
||||
selectElement(cell: ICellViewModel): void;
|
||||
focusElement(cell: ICellViewModel): void;
|
||||
|
||||
/**
|
||||
* Layout info for the notebook editor
|
||||
|
@ -642,6 +643,7 @@ export interface INotebookCellList {
|
|||
focusElement(element: ICellViewModel): void;
|
||||
selectElement(element: ICellViewModel): void;
|
||||
getFocusedElements(): ICellViewModel[];
|
||||
getSelectedElements(): ICellViewModel[];
|
||||
revealElementsInView(range: ICellRange): void;
|
||||
revealElementInView(element: ICellViewModel): void;
|
||||
revealElementInViewAtTop(element: ICellViewModel): void;
|
||||
|
|
|
@ -334,8 +334,12 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
|||
return this._uuid;
|
||||
}
|
||||
|
||||
getSelectionHandles(): number[] {
|
||||
return this.viewModel?.selectionHandles || [];
|
||||
getSelections() {
|
||||
return this.viewModel?.getSelections() ?? [];
|
||||
}
|
||||
|
||||
getSelection() {
|
||||
return this.viewModel?.getSelection();
|
||||
}
|
||||
|
||||
getSelectionViewModels(): ICellViewModel[] {
|
||||
|
@ -343,7 +347,18 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
|||
return [];
|
||||
}
|
||||
|
||||
return this.viewModel.selectionHandles.map(handle => this.viewModel!.getCellByHandle(handle)) as ICellViewModel[];
|
||||
const cellsSet = new Set<number>();
|
||||
|
||||
return this.viewModel.getSelections().map(range => this.viewModel!.viewCells.slice(range.start, range.end)).reduce((a, b) => {
|
||||
b.forEach(cell => {
|
||||
if (!cellsSet.has(cell.handle)) {
|
||||
cellsSet.add(cell.handle);
|
||||
a.push(cell);
|
||||
}
|
||||
});
|
||||
|
||||
return a;
|
||||
}, [] as ICellViewModel[]);
|
||||
}
|
||||
|
||||
hasModel(): this is IActiveNotebookEditor {
|
||||
|
@ -725,7 +740,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
|||
const cellOptions = options.cellOptions;
|
||||
const cell = this.viewModel.viewCells.find(cell => cell.uri.toString() === cellOptions.resource.toString());
|
||||
if (cell) {
|
||||
this.selectElement(cell);
|
||||
this.focusElement(cell);
|
||||
await this.revealInCenterIfOutsideViewportAsync(cell);
|
||||
const editor = this._renderedEditors.get(cell)!;
|
||||
if (editor) {
|
||||
|
@ -1279,9 +1294,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
|||
|
||||
//#region Editor Features
|
||||
|
||||
selectElement(cell: ICellViewModel) {
|
||||
this._list.selectElement(cell);
|
||||
// this.viewModel!.selectionHandles = [cell.handle];
|
||||
focusElement(cell: ICellViewModel) {
|
||||
this._list.focusElement(cell);
|
||||
}
|
||||
|
||||
revealCellRangeInView(range: ICellRange) {
|
||||
|
@ -1516,7 +1530,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
|||
(direction === 'above' ? index : nextIndex) :
|
||||
index;
|
||||
const focused = this._list.getFocusedElements();
|
||||
return this.viewModel.createCell(insertIndex, initialText, language, type, undefined, [], true, undefined, focused);
|
||||
const selections = this._list.getSelectedElements();
|
||||
return this.viewModel.createCell(insertIndex, initialText, language, type, undefined, [], true, undefined, focused[0]?.handle ?? null, selections);
|
||||
}
|
||||
|
||||
async splitNotebookCell(cell: ICellViewModel): Promise<CellViewModel[] | null> {
|
||||
|
@ -1884,7 +1899,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
|||
}
|
||||
|
||||
if (focusItem === 'editor') {
|
||||
this.selectElement(cell);
|
||||
this.focusElement(cell);
|
||||
this._list.focusView();
|
||||
|
||||
cell.editState = CellEditState.Editing;
|
||||
|
@ -1893,7 +1908,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
|||
this.revealInCenterIfOutsideViewport(cell);
|
||||
}
|
||||
} else if (focusItem === 'output') {
|
||||
this.selectElement(cell);
|
||||
this.focusElement(cell);
|
||||
this._list.focusView();
|
||||
|
||||
if (!this._webview) {
|
||||
|
@ -1915,7 +1930,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
|||
cell.editState = CellEditState.Preview;
|
||||
cell.focusMode = CellFocusMode.Container;
|
||||
|
||||
this.selectElement(cell);
|
||||
this.focusElement(cell);
|
||||
if (!options?.skipReveal) {
|
||||
this.revealInCenterIfOutsideViewport(cell);
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ import { NotebookKernelProviderAssociationRegistry, NotebookViewTypesExtensionRe
|
|||
import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
|
||||
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
|
||||
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
|
||||
import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, BUILTIN_RENDERER_ID, CellEditType, CellKind, DisplayOrderKey, ICellEditOperation, INotebookDecorationRenderOptions, INotebookKernel, INotebookKernelProvider, INotebookMarkdownRendererInfo, INotebookRendererInfo, INotebookTextModel, IOrderedMimeType, IOutputDto, mimeTypeIsAlwaysSecure, mimeTypeSupportedByCore, NotebookDataDto, notebookDocumentFilterMatch, NotebookEditorPriority, NOTEBOOK_DISPLAY_ORDER, RENDERER_NOT_AVAILABLE, sortMimeTypes, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, BUILTIN_RENDERER_ID, CellEditType, CellKind, DisplayOrderKey, ICellEditOperation, INotebookDecorationRenderOptions, INotebookKernel, INotebookKernelProvider, INotebookMarkdownRendererInfo, INotebookRendererInfo, INotebookTextModel, IOrderedMimeType, IOutputDto, mimeTypeIsAlwaysSecure, mimeTypeSupportedByCore, NotebookDataDto, notebookDocumentFilterMatch, NotebookEditorPriority, NOTEBOOK_DISPLAY_ORDER, RENDERER_NOT_AVAILABLE, SelectionStateType, sortMimeTypes, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { NotebookMarkdownRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookMarkdownRenderer';
|
||||
import { NotebookOutputRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookOutputRenderer';
|
||||
import { NotebookEditorDescriptor, NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider';
|
||||
|
@ -534,7 +534,10 @@ export class NotebookService extends Disposable implements INotebookService, IEd
|
|||
source: cell.getValue(),
|
||||
language: cell.language,
|
||||
cellKind: cell.cellKind,
|
||||
outputs: cell.outputs.map(output => ({ ...output, /* paste should generate new outputId */ outputId: UUID.generateUuid() })),
|
||||
outputs: cell.outputs.map(output => ({
|
||||
outputs: output.outputs,
|
||||
/* paste should generate new outputId */ outputId: UUID.generateUuid()
|
||||
})),
|
||||
metadata: cloneMetadata(cell)
|
||||
};
|
||||
};
|
||||
|
@ -600,14 +603,17 @@ export class NotebookService extends Disposable implements INotebookService, IEd
|
|||
clipboardService.writeText(selectedCells.map(cell => cell.getText()).join('\n'));
|
||||
const selectionIndexes = selectedCells.map(cell => [cell, viewModel.getCellIndex(cell)] as [ICellViewModel, number]).sort((a, b) => b[1] - a[1]);
|
||||
const edits: ICellEditOperation[] = selectionIndexes.map(value => ({ editType: CellEditType.Replace, index: value[1], count: 1, cells: [] }));
|
||||
const firstSelectIndex = selectionIndexes[0][1];
|
||||
const newFocusedCellHandle = firstSelectIndex < viewModel.notebookDocument.cells.length
|
||||
? viewModel.notebookDocument.cells[firstSelectIndex].handle
|
||||
: viewModel.notebookDocument.cells[viewModel.notebookDocument.cells.length - 1].handle;
|
||||
|
||||
viewModel.notebookDocument.applyEdits(viewModel.notebookDocument.versionId, edits, true, editor.getSelectionHandles(), () => {
|
||||
const firstSelectIndex = selectionIndexes[0][1];
|
||||
if (firstSelectIndex < viewModel.notebookDocument.cells.length) {
|
||||
return [viewModel.notebookDocument.cells[firstSelectIndex].handle];
|
||||
} else {
|
||||
return [viewModel.notebookDocument.cells[viewModel.notebookDocument.cells.length - 1].handle];
|
||||
}
|
||||
viewModel.notebookDocument.applyEdits(viewModel.notebookDocument.versionId, edits, true, { kind: SelectionStateType.Index, selections: viewModel.getSelections() }, () => {
|
||||
return {
|
||||
kind: SelectionStateType.Handle,
|
||||
primary: newFocusedCellHandle,
|
||||
selections: [newFocusedCellHandle]
|
||||
};
|
||||
}, undefined, true);
|
||||
notebookService.setToCopy(selectedCells.map(cell => cell.model), false);
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ import { IListService, IWorkbenchListOptions, WorkbenchList } from 'vs/platform/
|
|||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { CellRevealPosition, CellRevealType, CursorAtBoundary, getVisibleCells, ICellViewModel, INotebookCellList, reduceCellRanges, CellEditState, CellFocusMode, BaseCellRenderTemplate, NOTEBOOK_CELL_LIST_FOCUSED, cellRangesEqual, ICellOutputViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { CellViewModel, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
|
||||
import { diff, NOTEBOOK_EDITOR_CURSOR_BOUNDARY, CellKind, ICellRange, NOTEBOOK_EDITOR_CURSOR_BEGIN_END } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { diff, NOTEBOOK_EDITOR_CURSOR_BOUNDARY, CellKind, ICellRange, NOTEBOOK_EDITOR_CURSOR_BEGIN_END, cellRangesToIndexes, SelectionStateType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { clamp } from 'vs/base/common/numbers';
|
||||
import { SCROLLABLE_ELEMENT_PADDING_TOP } from 'vs/workbench/contrib/notebook/browser/constants';
|
||||
|
||||
|
@ -365,12 +365,12 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
|
|||
|
||||
this._viewModelStore.add(model.onDidChangeSelection(() => {
|
||||
// convert model selections to view selections
|
||||
const viewSelections = model.selectionHandles.map(handle => {
|
||||
return model.getCellByHandle(handle);
|
||||
}).filter(cell => !!cell).map(cell => this._getViewIndexUpperBound(cell!));
|
||||
const viewSelections = cellRangesToIndexes(model.getSelections()).map(index => model.getCellByIndex(index)).filter(cell => !!cell).map(cell => this._getViewIndexUpperBound(cell!));
|
||||
this.setSelection(viewSelections, undefined, true);
|
||||
if (viewSelections.length) {
|
||||
this.setFocus([viewSelections[0]]);
|
||||
const primary = cellRangesToIndexes([model.getSelection()]).map(index => model.getCellByIndex(index)).filter(cell => !!cell).map(cell => this._getViewIndexUpperBound(cell!));
|
||||
|
||||
if (primary.length) {
|
||||
this.setFocus(primary, undefined, true);
|
||||
}
|
||||
}));
|
||||
|
||||
|
@ -501,7 +501,7 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
|
|||
}
|
||||
|
||||
const selectionsLeft = [];
|
||||
this._viewModel!.selectionHandles.forEach(handle => {
|
||||
this.getSelectedElements().map(el => el.handle).forEach(handle => {
|
||||
if (this._viewModel!.hasCell(handle)) {
|
||||
selectionsLeft.push(handle);
|
||||
}
|
||||
|
@ -509,7 +509,7 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
|
|||
|
||||
if (!selectionsLeft.length && this._viewModel!.viewCells.length) {
|
||||
// after splice, the selected cells are deleted
|
||||
this._viewModel!.selectionHandles = [this._viewModel!.viewCells[0].handle];
|
||||
this._viewModel!.updateSelectionsFromEdits({ kind: SelectionStateType.Index, selections: [{ start: 0, end: 1 }] });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -574,19 +574,14 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
|
|||
const index = this._getViewIndexUpperBound(cell);
|
||||
|
||||
if (index >= 0) {
|
||||
this.setFocus([index]);
|
||||
this.setFocus([index], undefined, false);
|
||||
}
|
||||
}
|
||||
|
||||
selectElement(cell: ICellViewModel) {
|
||||
if (this._viewModel) {
|
||||
this._viewModel.selectionHandles = [cell.handle];
|
||||
}
|
||||
|
||||
const index = this._getViewIndexUpperBound(cell);
|
||||
if (index >= 0) {
|
||||
this.setSelection([index]);
|
||||
this.setFocus([index]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -599,24 +594,39 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
|
|||
}
|
||||
|
||||
setFocus(indexes: number[], browserEvent?: UIEvent, ignoreTextModelUpdate?: boolean): void {
|
||||
// if (!indexes.length) {
|
||||
// return;
|
||||
// }
|
||||
if (ignoreTextModelUpdate) {
|
||||
super.setFocus(indexes, browserEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
// if (this._viewModel && !ignoreTextModelUpdate) {
|
||||
// this._viewModel.selectionHandles = indexes.map(index => this.element(index)).map(cell => cell.handle);
|
||||
// }
|
||||
if (!indexes.length) {
|
||||
if (this._viewModel) {
|
||||
this._viewModel.updateSelectionsFromView(null, []);
|
||||
}
|
||||
} else {
|
||||
if (this._viewModel) {
|
||||
const focusedElementHandle = this.element(indexes[0]).handle;
|
||||
this._viewModel.updateSelectionsFromView(focusedElementHandle, [focusedElementHandle]);
|
||||
}
|
||||
}
|
||||
|
||||
super.setFocus(indexes, browserEvent);
|
||||
}
|
||||
|
||||
setSelection(indexes: number[], browserEvent?: UIEvent | undefined, ignoreTextModelUpdate?: boolean) {
|
||||
if (!indexes.length) {
|
||||
if (ignoreTextModelUpdate) {
|
||||
super.setSelection(indexes, browserEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._viewModel && !ignoreTextModelUpdate) {
|
||||
this._viewModel.selectionHandles = indexes.map(index => this.element(index)).map(cell => cell.handle);
|
||||
if (!indexes.length) {
|
||||
if (this._viewModel) {
|
||||
this._viewModel.updateSelectionsFromView(this.getFocusedElements()[0]?.handle ?? null, []);
|
||||
}
|
||||
} else {
|
||||
if (this._viewModel) {
|
||||
this._viewModel.updateSelectionsFromView(this.getFocusedElements()[0]?.handle ?? null, indexes.map(index => this.element(index)).map(cell => cell.handle));
|
||||
}
|
||||
}
|
||||
|
||||
super.setSelection(indexes, browserEvent);
|
||||
|
|
|
@ -313,7 +313,7 @@ abstract class AbstractCellRenderer {
|
|||
protected commonRenderTemplate(templateData: BaseCellRenderTemplate): void {
|
||||
templateData.disposables.add(DOM.addDisposableListener(templateData.container, DOM.EventType.FOCUS, () => {
|
||||
if (templateData.currentRenderedCell) {
|
||||
this.notebookEditor.selectElement(templateData.currentRenderedCell);
|
||||
this.notebookEditor.focusElement(templateData.currentRenderedCell);
|
||||
}
|
||||
}, true));
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { CellKind, IOutputDto, NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellKind, IOutputDto, NotebookCellMetadata, SelectionStateType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { IResourceUndoRedoElement, UndoRedoElementType } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { BaseCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel';
|
||||
|
@ -52,10 +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, [cell.handle]);
|
||||
this.editingDelegate.insertCell(this.index, this._deletedRawCell, { kind: SelectionStateType.Handle, primary: cell.handle, selections: [cell.handle] });
|
||||
cell.focusMode = CellFocusMode.Editor;
|
||||
} else {
|
||||
this.editingDelegate.insertCell(this.index, cell.model, [this.cell.handle]);
|
||||
this.editingDelegate.insertCell(this.index, cell.model, { kind: SelectionStateType.Handle, primary: this.cell.handle, selections: [this.cell.handle] });
|
||||
this.cell.focusMode = CellFocusMode.Editor;
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ export class JoinCellEdit implements IResourceUndoRedoElement {
|
|||
{ range: this.inverseRange, text: this.insertContent }
|
||||
]);
|
||||
|
||||
this.editingDelegate.deleteCell(this.index, [this.cell.handle]);
|
||||
this.editingDelegate.deleteCell(this.index, { kind: SelectionStateType.Handle, primary: this.cell.handle, selections: [this.cell.handle] });
|
||||
this.cell.focusMode = CellFocusMode.Editor;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
|
||||
function rangesEqual(a: ICellRange[], b: ICellRange[]) {
|
||||
if (a.length !== b.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
if (a[i].start !== b[i].start || a[i].end !== b[i].end) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle first, then we migrate to ICellRange competely
|
||||
// Challenge is List View talks about `element`, which needs extra work to convert to ICellRange as we support Folding and Cell Move
|
||||
export class NotebookCellSelectionCollection extends Disposable {
|
||||
private readonly _onDidChangeSelection = this._register(new Emitter<void>());
|
||||
get onDidChangeSelection(): Event<void> { return this._onDidChangeSelection.event; }
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
private _primary: ICellRange | null = null;
|
||||
|
||||
private _selections: ICellRange[] = [];
|
||||
|
||||
get selections(): ICellRange[] {
|
||||
return this._selections;
|
||||
}
|
||||
|
||||
get selection(): ICellRange {
|
||||
return this._selections[0];
|
||||
}
|
||||
|
||||
setState(primary: ICellRange | null, selections: ICellRange[], forceEventEmit: boolean) {
|
||||
if (primary !== null) {
|
||||
const primaryRange = primary;
|
||||
// TODO@rebornix deal with overlap
|
||||
const newSelections = [primaryRange, ...selections.filter(selection => !(selection.start === primaryRange.start && selection.end === primaryRange.end)).sort((a, b) => a.start - b.start)];
|
||||
|
||||
const changed = primary !== this._primary || !rangesEqual(this._selections, newSelections);
|
||||
this._primary = primary;
|
||||
this._selections = newSelections;
|
||||
|
||||
if (!this._selections.length) {
|
||||
this._selections.push({ start: 0, end: 0 });
|
||||
}
|
||||
|
||||
if (changed || forceEventEmit) {
|
||||
this._onDidChangeSelection.fire();
|
||||
}
|
||||
} else {
|
||||
const changed = primary !== this._primary || !rangesEqual(this._selections, selections);
|
||||
|
||||
this._primary = primary;
|
||||
this._selections = selections;
|
||||
|
||||
if (!this._selections.length) {
|
||||
this._selections.push({ start: 0, end: 0 });
|
||||
}
|
||||
|
||||
if (changed || forceEventEmit) {
|
||||
this._onDidChangeSelection.fire();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setFocus(selection: ICellRange | null, forceEventEmit: boolean) {
|
||||
this.setState(selection, this._selections, forceEventEmit);
|
||||
}
|
||||
|
||||
setSelections(selections: ICellRange[], forceEventEmit: boolean) {
|
||||
this.setState(this._primary, selections, forceEventEmit);
|
||||
}
|
||||
}
|
|
@ -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, NotebookCellsChangeType, ICell, NotebookCellTextModelSplice, CellEditType, IOutputDto } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellKind, NotebookCellMetadata, INotebookSearchOptions, ICellRange, NotebookCellsChangeType, ICell, NotebookCellTextModelSplice, CellEditType, IOutputDto, SelectionStateType, ISelectionState, cellIndexesToRanges, cellRangesToIndexes } 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/editor/browser/core/markdownRenderer';
|
||||
|
@ -31,6 +31,7 @@ import { dirname } from 'vs/base/common/resources';
|
|||
import { IPosition, Position } from 'vs/editor/common/core/position';
|
||||
import { MultiModelEditStackElement, SingleModelEditStackElement } from 'vs/editor/common/model/editStack';
|
||||
import { ResourceNotebookCellEdit } from 'vs/workbench/contrib/bulkEdit/browser/bulkCellEdits';
|
||||
import { NotebookCellSelectionCollection } from 'vs/workbench/contrib/notebook/browser/viewModel/cellSelectionCollection';
|
||||
|
||||
export interface INotebookEditorViewState {
|
||||
editingCells: { [key: number]: boolean };
|
||||
|
@ -130,20 +131,6 @@ function _normalizeOptions(options: IModelDecorationOptions): ModelDecorationOpt
|
|||
return ModelDecorationOptions.createDynamic(options);
|
||||
}
|
||||
|
||||
function selectionsEqual(a: number[], b: number[]) {
|
||||
if (a.length !== b.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
if (a[i] !== b[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
let MODEL_ID = 0;
|
||||
|
||||
|
||||
|
@ -199,20 +186,23 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
|
|||
private readonly _onDidChangeSelection = this._register(new Emitter<void>());
|
||||
get onDidChangeSelection(): Event<void> { return this._onDidChangeSelection.event; }
|
||||
|
||||
private _selections: number[] = [];
|
||||
private _selectionCollection = new NotebookCellSelectionCollection();
|
||||
|
||||
get selectionHandles() {
|
||||
return this._selections;
|
||||
private get selectionHandles() {
|
||||
const handlesSet = new Set<number>();
|
||||
const handles: number[] = [];
|
||||
cellRangesToIndexes(this._selectionCollection.selections).map(index => this.getCellByIndex(index)).forEach(cell => {
|
||||
if (cell && !handlesSet.has(cell.handle)) {
|
||||
handles.push(cell.handle);
|
||||
}
|
||||
});
|
||||
|
||||
return handles;
|
||||
}
|
||||
|
||||
set selectionHandles(selections: number[]) {
|
||||
selections = selections.sort();
|
||||
if (selectionsEqual(selections, this.selectionHandles)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._selections = selections;
|
||||
this._onDidChangeSelection.fire();
|
||||
private set selectionHandles(selectionHandles: number[]) {
|
||||
const indexes = selectionHandles.map(handle => this._viewCells.findIndex(cell => cell.handle === handle));
|
||||
this._selectionCollection.setSelections(cellIndexesToRanges(indexes), true);
|
||||
}
|
||||
|
||||
private _decorationsTree = new DecorationsTree();
|
||||
|
@ -299,6 +289,7 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
|
|||
}
|
||||
}
|
||||
|
||||
// TODO@rebornix
|
||||
this.selectionHandles = endSelectionHandles;
|
||||
};
|
||||
|
||||
|
@ -327,8 +318,8 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
|
|||
}
|
||||
});
|
||||
|
||||
if (contentChanges.endSelections) {
|
||||
this.updateSelectionsFromEdits(contentChanges.endSelections);
|
||||
if (contentChanges.endSelectionState) {
|
||||
this.updateSelectionsFromEdits(contentChanges.endSelectionState);
|
||||
}
|
||||
}));
|
||||
|
||||
|
@ -348,6 +339,10 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
|
|||
});
|
||||
}));
|
||||
|
||||
this._register(this._selectionCollection.onDidChangeSelection(e => {
|
||||
this._onDidChangeSelection.fire(e);
|
||||
}));
|
||||
|
||||
this._viewCells = this._notebook.cells.map(cell => {
|
||||
return createCellViewModel(this._instantiationService, this, cell);
|
||||
});
|
||||
|
@ -357,13 +352,33 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
|
|||
});
|
||||
}
|
||||
|
||||
getSelection() {
|
||||
return this._selectionCollection.selection;
|
||||
}
|
||||
|
||||
getSelections() {
|
||||
return this._selectionCollection.selections;
|
||||
}
|
||||
|
||||
setFocus(focused: boolean) {
|
||||
this._focused = focused;
|
||||
}
|
||||
|
||||
updateSelectionsFromEdits(selections: number[]) {
|
||||
updateSelectionsFromView(primary: number | null, selections: number[]) {
|
||||
const primaryIndex = primary !== null ? this.getCellIndexByHandle(primary) : null;
|
||||
const selectionIndexes = selections.map(sel => this.getCellIndexByHandle(sel));
|
||||
this._selectionCollection.setState(primaryIndex !== null ? { start: primaryIndex, end: primaryIndex + 1 } : null, cellIndexesToRanges(selectionIndexes), false);
|
||||
}
|
||||
|
||||
updateSelectionsFromEdits(state: ISelectionState) {
|
||||
if (this._focused) {
|
||||
this.selectionHandles = selections;
|
||||
if (state.kind === SelectionStateType.Handle) {
|
||||
const primaryIndex = state.primary !== null ? this.getCellIndexByHandle(state.primary) : null;
|
||||
const selectionIndexes = state.selections.map(sel => this.getCellIndexByHandle(sel));
|
||||
this._selectionCollection.setState(primaryIndex !== null ? { start: primaryIndex, end: primaryIndex + 1 } : null, cellIndexesToRanges(selectionIndexes), true);
|
||||
} else {
|
||||
this._selectionCollection.setState(state.selections[0] ?? null, state.selections, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -454,10 +469,18 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
|
|||
return this._handleToViewCellMapping.get(handle);
|
||||
}
|
||||
|
||||
getCellIndexByHandle(handle: number): number {
|
||||
return this._viewCells.findIndex(cell => cell.handle === handle);
|
||||
}
|
||||
|
||||
getCellIndex(cell: ICellViewModel) {
|
||||
return this._viewCells.indexOf(cell as CellViewModel);
|
||||
}
|
||||
|
||||
getCellByIndex(index: number) {
|
||||
return this._viewCells[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* If this._viewCells[index] is visible then return index
|
||||
*/
|
||||
|
@ -645,7 +668,7 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
|
|||
return result;
|
||||
}
|
||||
|
||||
createCell(index: number, source: string, language: string, type: CellKind, metadata: NotebookCellMetadata | undefined, outputs: IOutputDto[], synchronous: boolean, pushUndoStop: boolean = true, previouslyFocused: ICellViewModel[] = []): CellViewModel {
|
||||
createCell(index: number, source: string, language: string, type: CellKind, metadata: NotebookCellMetadata | undefined, outputs: IOutputDto[], synchronous: boolean, pushUndoStop: boolean = true, previouslyPrimary: number | null = null, previouslyFocused: ICellViewModel[] = []): CellViewModel {
|
||||
const beforeSelections = previouslyFocused.map(e => e.handle);
|
||||
this._notebook.applyEdits(this._notebook.versionId, [
|
||||
{
|
||||
|
@ -662,29 +685,24 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
|
|||
}
|
||||
]
|
||||
}
|
||||
], synchronous, beforeSelections, () => undefined, undefined);
|
||||
], synchronous, { kind: SelectionStateType.Handle, primary: previouslyPrimary, selections: beforeSelections }, () => undefined, undefined);
|
||||
return this._viewCells[index];
|
||||
}
|
||||
|
||||
deleteCell(index: number, synchronous: boolean, pushUndoStop: boolean = true) {
|
||||
const primarySelectionIndex = this.selectionHandles.length ? this._viewCells.indexOf(this.getCellByHandle(this.selectionHandles[0])!) : null;
|
||||
let endSelections: number[] = [];
|
||||
if (this.selectionHandles.length) {
|
||||
const primarySelectionHandle = this.selectionHandles[0];
|
||||
const primarySelectionIndex = this.getSelection()?.start ?? null;
|
||||
let endPrimarySelection: number | null = null;
|
||||
|
||||
if (index === primarySelectionIndex) {
|
||||
if (primarySelectionIndex < this.length - 1) {
|
||||
endSelections = [this._viewCells[primarySelectionIndex + 1].handle];
|
||||
} else if (primarySelectionIndex === this.length - 1 && this.length > 1) {
|
||||
endSelections = [this._viewCells[primarySelectionIndex - 1].handle];
|
||||
} else {
|
||||
endSelections = [];
|
||||
}
|
||||
} else {
|
||||
endSelections = [primarySelectionHandle];
|
||||
if (index === primarySelectionIndex) {
|
||||
if (primarySelectionIndex < this.length - 1) {
|
||||
endPrimarySelection = this._viewCells[primarySelectionIndex + 1].handle;
|
||||
} else if (primarySelectionIndex === this.length - 1 && this.length > 1) {
|
||||
endPrimarySelection = this._viewCells[primarySelectionIndex - 1].handle;
|
||||
}
|
||||
}
|
||||
|
||||
let endSelections: number[] = this.selectionHandles.filter(handle => handle !== endPrimarySelection);
|
||||
|
||||
this._notebook.applyEdits(this._notebook.versionId, [
|
||||
{
|
||||
editType: CellEditType.Replace,
|
||||
|
@ -693,8 +711,8 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
|
|||
cells: []
|
||||
}],
|
||||
synchronous,
|
||||
this.selectionHandles,
|
||||
() => endSelections,
|
||||
{ kind: SelectionStateType.Index, selections: this.getSelections() },
|
||||
() => ({ kind: SelectionStateType.Handle, primary: endPrimarySelection, selections: endSelections }),
|
||||
undefined,
|
||||
pushUndoStop
|
||||
);
|
||||
|
@ -721,7 +739,7 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD
|
|||
length,
|
||||
newIdx
|
||||
}
|
||||
], synchronous, undefined, () => [viewCell.handle], undefined);
|
||||
], synchronous, { kind: SelectionStateType.Index, selections: this.getSelections() }, () => ({ kind: SelectionStateType.Index, selections: [{ start: newIdx, end: newIdx + 1 }] }), undefined);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,15 +6,15 @@
|
|||
import { IResourceUndoRedoElement, UndoRedoElementType } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
|
||||
import { NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { ISelectionState, NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
|
||||
/**
|
||||
* It should not modify Undo/Redo stack
|
||||
*/
|
||||
export interface ITextCellEditingDelegate {
|
||||
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;
|
||||
insertCell?(index: number, cell: NotebookCellTextModel, endSelections?: ISelectionState): void;
|
||||
deleteCell?(index: number, endSelections?: ISelectionState): void;
|
||||
moveCell?(fromIndex: number, length: number, toIndex: number, beforeSelections: ISelectionState | undefined, endSelections?: ISelectionState): void;
|
||||
updateCellMetadata?(index: number, newMetadata: NotebookCellMetadata): void;
|
||||
}
|
||||
|
||||
|
@ -28,8 +28,8 @@ export class MoveCellEdit implements IResourceUndoRedoElement {
|
|||
private length: number,
|
||||
private toIndex: number,
|
||||
private editingDelegate: ITextCellEditingDelegate,
|
||||
private beforedSelections: number[] | undefined,
|
||||
private endSelections: number[] | undefined
|
||||
private beforedSelections: ISelectionState | undefined,
|
||||
private endSelections: ISelectionState | undefined
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -57,8 +57,8 @@ export class SpliceCellsEdit implements IResourceUndoRedoElement {
|
|||
public resource: URI,
|
||||
private diffs: [number, NotebookCellTextModel[], NotebookCellTextModel[]][],
|
||||
private editingDelegate: ITextCellEditingDelegate,
|
||||
private beforeHandles: number[] | undefined,
|
||||
private endHandles: number[] | undefined
|
||||
private beforeHandles: ISelectionState | undefined,
|
||||
private endHandles: ISelectionState | undefined
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import { Emitter, Event } from 'vs/base/common/event';
|
|||
import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
|
||||
import { INotebookTextModel, NotebookCellOutputsSplice, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation, CellEditType, CellUri, notebookDocumentMetadataDefaults, diff, NotebookCellsChangeType, ICellDto2, TransientOptions, NotebookTextModelChangedEvent, NotebookRawContentEvent, IOutputDto, ICellOutput, IOutputItemDto } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { INotebookTextModel, NotebookCellOutputsSplice, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation, CellEditType, CellUri, notebookDocumentMetadataDefaults, diff, NotebookCellsChangeType, ICellDto2, TransientOptions, NotebookTextModelChangedEvent, NotebookRawContentEvent, IOutputDto, ICellOutput, IOutputItemDto, ISelectionState } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { ITextSnapshot } from 'vs/editor/common/model';
|
||||
import { IUndoRedoService, UndoRedoElementType, IUndoRedoElement, IResourceUndoRedoElement, UndoRedoGroup, IWorkspaceUndoRedoElement } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { MoveCellEdit, SpliceCellsEdit, CellMetadataEdit } from 'vs/workbench/contrib/notebook/common/model/cellEdit';
|
||||
|
@ -59,10 +59,10 @@ class StackOperation implements IWorkspaceUndoRedoElement {
|
|||
type: UndoRedoElementType.Workspace;
|
||||
|
||||
private _operations: IUndoRedoElement[] = [];
|
||||
private _beginSelectionState: number[] | undefined = undefined;
|
||||
private _resultSelectionState: number[] | undefined = undefined;
|
||||
private _beginSelectionState: ISelectionState | undefined = undefined;
|
||||
private _resultSelectionState: ISelectionState | undefined = undefined;
|
||||
|
||||
constructor(readonly resource: URI, readonly label: string, readonly undoRedoGroup: UndoRedoGroup | undefined, private _delayedEmitter: DelayedEmitter, selectionState: number[] | undefined) {
|
||||
constructor(readonly resource: URI, readonly label: string, readonly undoRedoGroup: UndoRedoGroup | undefined, private _delayedEmitter: DelayedEmitter, selectionState: ISelectionState | undefined) {
|
||||
this.type = UndoRedoElementType.Workspace;
|
||||
this._beginSelectionState = selectionState;
|
||||
}
|
||||
|
@ -74,13 +74,13 @@ class StackOperation implements IWorkspaceUndoRedoElement {
|
|||
return this._operations.length === 0;
|
||||
}
|
||||
|
||||
pushEndSelectionState(selectionState: number[] | undefined) {
|
||||
pushEndSelectionState(selectionState: ISelectionState | undefined) {
|
||||
this._resultSelectionState = selectionState;
|
||||
}
|
||||
|
||||
pushEditOperation(element: IUndoRedoElement, beginSelectionState: number[] | undefined, resultSelectionState: number[] | undefined) {
|
||||
pushEditOperation(element: IUndoRedoElement, beginSelectionState: ISelectionState | undefined, resultSelectionState: ISelectionState | undefined) {
|
||||
if (this._operations.length === 0) {
|
||||
this._beginSelectionState = this._beginSelectionState || beginSelectionState;
|
||||
this._beginSelectionState = this._beginSelectionState ?? beginSelectionState;
|
||||
}
|
||||
this._operations.push(element);
|
||||
this._resultSelectionState = resultSelectionState;
|
||||
|
@ -109,7 +109,7 @@ export class NotebookOperationManager {
|
|||
|
||||
}
|
||||
|
||||
pushStackElement(label: string, selectionState: number[] | undefined, undoRedoGroup: UndoRedoGroup | undefined) {
|
||||
pushStackElement(label: string, selectionState: ISelectionState | undefined, undoRedoGroup: UndoRedoGroup | undefined) {
|
||||
if (this._pendingStackOperation) {
|
||||
this._pendingStackOperation.pushEndSelectionState(selectionState);
|
||||
if (!this._pendingStackOperation.isEmpty) {
|
||||
|
@ -122,7 +122,7 @@ export class NotebookOperationManager {
|
|||
this._pendingStackOperation = new StackOperation(this._resource, label, undoRedoGroup, this._delayedEmitter, selectionState);
|
||||
}
|
||||
|
||||
pushEditOperation(element: IUndoRedoElement, beginSelectionState: number[] | undefined, resultSelectionState: number[] | undefined) {
|
||||
pushEditOperation(element: IUndoRedoElement, beginSelectionState: ISelectionState | undefined, resultSelectionState: ISelectionState | undefined) {
|
||||
if (this._pendingStackOperation) {
|
||||
this._pendingStackOperation.pushEditOperation(element, beginSelectionState, resultSelectionState);
|
||||
return;
|
||||
|
@ -148,7 +148,7 @@ class DelayedEmitter {
|
|||
this._deferredCnt++;
|
||||
}
|
||||
|
||||
endDeferredEmit(endSelections: number[] | undefined): void {
|
||||
endDeferredEmit(endSelections: ISelectionState | undefined): void {
|
||||
this._deferredCnt--;
|
||||
if (this._deferredCnt === 0) {
|
||||
this._computeEndState();
|
||||
|
@ -158,7 +158,7 @@ class DelayedEmitter {
|
|||
{
|
||||
rawEvents: this._notebookTextModelChangedEvent.rawEvents,
|
||||
versionId: this._textModel.versionId,
|
||||
endSelections: endSelections || this._notebookTextModelChangedEvent.endSelections,
|
||||
endSelectionState: endSelections,
|
||||
synchronous: this._notebookTextModelChangedEvent.synchronous
|
||||
}
|
||||
);
|
||||
|
@ -169,7 +169,7 @@ class DelayedEmitter {
|
|||
}
|
||||
|
||||
|
||||
emit(data: NotebookRawContentEvent, synchronous: boolean, endSelections?: number[]) {
|
||||
emit(data: NotebookRawContentEvent, synchronous: boolean, endSelections?: ISelectionState) {
|
||||
|
||||
if (this._deferredCnt === 0) {
|
||||
this._computeEndState();
|
||||
|
@ -178,7 +178,7 @@ class DelayedEmitter {
|
|||
rawEvents: [data],
|
||||
versionId: this._textModel.versionId,
|
||||
synchronous,
|
||||
endSelections
|
||||
endSelectionState: endSelections
|
||||
}
|
||||
);
|
||||
} else {
|
||||
|
@ -186,7 +186,7 @@ class DelayedEmitter {
|
|||
this._notebookTextModelChangedEvent = {
|
||||
rawEvents: [data],
|
||||
versionId: this._textModel.versionId,
|
||||
endSelections: endSelections,
|
||||
endSelectionState: endSelections,
|
||||
synchronous: synchronous
|
||||
};
|
||||
} else {
|
||||
|
@ -194,7 +194,7 @@ class DelayedEmitter {
|
|||
this._notebookTextModelChangedEvent = {
|
||||
rawEvents: [...this._notebookTextModelChangedEvent.rawEvents, data],
|
||||
versionId: this._textModel.versionId,
|
||||
endSelections: endSelections ? endSelections : this._notebookTextModelChangedEvent.endSelections,
|
||||
endSelectionState: endSelections !== undefined ? endSelections : this._notebookTextModelChangedEvent.endSelectionState,
|
||||
synchronous: synchronous
|
||||
};
|
||||
}
|
||||
|
@ -279,11 +279,11 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
|||
super.dispose();
|
||||
}
|
||||
|
||||
pushStackElement(label: string, selectionState: number[] | undefined, undoRedoGroup: UndoRedoGroup | undefined) {
|
||||
pushStackElement(label: string, selectionState: ISelectionState | undefined, undoRedoGroup: UndoRedoGroup | undefined) {
|
||||
this._operationManager.pushStackElement(label, selectionState, undoRedoGroup);
|
||||
}
|
||||
|
||||
applyEdits(modelVersionId: number, rawEdits: ICellEditOperation[], synchronous: boolean, beginSelectionState: number[] | undefined, endSelectionsComputer: () => number[] | undefined, undoRedoGroup: UndoRedoGroup | undefined, computeUndoRedo: boolean = true): boolean {
|
||||
applyEdits(modelVersionId: number, rawEdits: ICellEditOperation[], synchronous: boolean, beginSelectionState: ISelectionState | undefined, endSelectionsComputer: () => ISelectionState | undefined, undoRedoGroup: UndoRedoGroup | undefined, computeUndoRedo: boolean = true): boolean {
|
||||
if (modelVersionId !== this._versionId) {
|
||||
return false;
|
||||
}
|
||||
|
@ -415,8 +415,8 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
|||
|
||||
if (computeUndoRedo) {
|
||||
this._operationManager.pushEditOperation(new SpliceCellsEdit(this.uri, undoDiff, {
|
||||
insertCell: (index, cell, endSelections?: number[]) => { this._insertNewCell(index, [cell], true, endSelections); },
|
||||
deleteCell: (index, endSelections?: number[]) => { this._removeCell(index, 1, true, endSelections); },
|
||||
insertCell: (index, cell, endSelections) => { this._insertNewCell(index, [cell], true, endSelections); },
|
||||
deleteCell: (index, endSelections) => { this._removeCell(index, 1, true, endSelections); },
|
||||
}, undefined, undefined), undefined, undefined);
|
||||
}
|
||||
|
||||
|
@ -473,7 +473,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
|||
this._eventEmitter.emit({ kind: NotebookCellsChangeType.ChangeDocumentMetadata, metadata: this.metadata, transient: this._isDocumentMetadataChangeTransient(oldMetadata, metadata) }, true);
|
||||
}
|
||||
|
||||
private _insertNewCell(index: number, cells: NotebookCellTextModel[], synchronous: boolean, endSelections?: number[]): void {
|
||||
private _insertNewCell(index: number, cells: NotebookCellTextModel[], synchronous: boolean, endSelections: ISelectionState | undefined): void {
|
||||
for (let i = 0; i < cells.length; i++) {
|
||||
this._mapping.set(cells[i].handle, cells[i]);
|
||||
const dirtyStateListener = cells[i].onDidChangeContent(() => {
|
||||
|
@ -498,7 +498,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
|||
return;
|
||||
}
|
||||
|
||||
private _removeCell(index: number, count: number, synchronous: boolean, endSelections?: number[]) {
|
||||
private _removeCell(index: number, count: number, synchronous: boolean, endSelections: ISelectionState | undefined) {
|
||||
for (let i = index; i < index + count; i++) {
|
||||
const cell = this._cells[i];
|
||||
this._cellListeners.get(cell.handle)?.dispose();
|
||||
|
@ -617,7 +617,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
|||
}(), undefined, undefined);
|
||||
}
|
||||
|
||||
this._eventEmitter.emit({ kind: NotebookCellsChangeType.ChangeLanguage, index: this._cells.indexOf(cell), language: languageId, transient: false }, true);
|
||||
this._eventEmitter.emit({ kind: NotebookCellsChangeType.ChangeLanguage, index: this._cells.indexOf(cell), language: languageId, transient: false }, true, undefined);
|
||||
}
|
||||
|
||||
private _spliceNotebookCellOutputs2(cellHandle: number, outputs: ICellOutput[], computeUndoRedo: boolean): void {
|
||||
|
@ -691,13 +691,13 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
|||
outputItems: items,
|
||||
append: false,
|
||||
transient: this.transientOptions.transientOutputs
|
||||
}, true);
|
||||
}, true, undefined);
|
||||
}
|
||||
|
||||
private _moveCellToIdx(index: number, length: number, newIdx: number, synchronous: boolean, pushedToUndoStack: boolean, beforeSelections: number[] | undefined, endSelections: number[] | undefined): boolean {
|
||||
private _moveCellToIdx(index: number, length: number, newIdx: number, synchronous: boolean, pushedToUndoStack: boolean, beforeSelections: ISelectionState | undefined, endSelections: ISelectionState | undefined): boolean {
|
||||
if (pushedToUndoStack) {
|
||||
this._operationManager.pushEditOperation(new MoveCellEdit(this.uri, index, length, newIdx, {
|
||||
moveCell: (fromIndex: number, length: number, toIndex: number, beforeSelections: number[] | undefined, endSelections: number[] | undefined) => {
|
||||
moveCell: (fromIndex: number, length: number, toIndex: number, beforeSelections: ISelectionState | undefined, endSelections: ISelectionState | undefined) => {
|
||||
this._moveCellToIdx(fromIndex, length, toIndex, true, false, beforeSelections, endSelections);
|
||||
},
|
||||
}, beforeSelections, endSelections), beforeSelections, endSelections);
|
||||
|
|
|
@ -298,11 +298,34 @@ export type NotebookCellsChangedEventDto = {
|
|||
};
|
||||
|
||||
export type NotebookRawContentEvent = (NotebookCellsInitializeEvent<ICell> | NotebookDocumentChangeMetadataEvent | NotebookCellContentChangeEvent | NotebookCellsModelChangedEvent<ICell> | NotebookCellsModelMoveEvent<ICell> | NotebookOutputChangedEvent | NotebookOutputItemChangedEvent | NotebookCellsChangeLanguageEvent | NotebookCellsChangeMetadataEvent | NotebookDocumentUnknownChangeEvent) & { transient: boolean; };
|
||||
|
||||
export enum SelectionStateType {
|
||||
Handle = 0,
|
||||
Index = 1
|
||||
}
|
||||
|
||||
export interface ISelectionHandleState {
|
||||
kind: SelectionStateType.Handle;
|
||||
primary: number | null;
|
||||
selections: number[];
|
||||
}
|
||||
|
||||
export interface ISelectionIndexState {
|
||||
kind: SelectionStateType.Index;
|
||||
|
||||
/**
|
||||
* [primarySelection, ...secondarySelections]
|
||||
*/
|
||||
selections: ICellRange[];
|
||||
}
|
||||
|
||||
export type ISelectionState = ISelectionHandleState | ISelectionIndexState;
|
||||
|
||||
export type NotebookTextModelChangedEvent = {
|
||||
readonly rawEvents: NotebookRawContentEvent[];
|
||||
readonly versionId: number;
|
||||
readonly synchronous: boolean;
|
||||
readonly endSelections?: number[];
|
||||
readonly endSelectionState: ISelectionState | undefined;
|
||||
};
|
||||
|
||||
export const enum CellEditType {
|
||||
|
@ -657,7 +680,8 @@ export interface IEditor extends editorCommon.ICompositeCodeEditor {
|
|||
readonly onDidFocusEditorWidget: Event<void>;
|
||||
readonly onDidChangeVisibleRanges: Event<void>;
|
||||
readonly onDidChangeSelection: Event<void>;
|
||||
getSelectionHandles(): number[];
|
||||
getSelection(): ICellRange | undefined;
|
||||
getSelections(): ICellRange[];
|
||||
isNotebookEditor: boolean;
|
||||
visibleRanges: ICellRange[];
|
||||
uri?: URI;
|
||||
|
@ -800,3 +824,33 @@ export interface INotebookDecorationRenderOptions {
|
|||
borderColor?: string | ThemeColor;
|
||||
top?: editorCommon.IContentDecorationRenderOptions;
|
||||
}
|
||||
|
||||
|
||||
export function cellIndexesToRanges(indexes: number[]) {
|
||||
const first = indexes.shift();
|
||||
|
||||
if (first === undefined) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return indexes.reduce(function (ranges, num) {
|
||||
if (num <= ranges[0][1]) {
|
||||
ranges[0][1] = num + 1;
|
||||
} else {
|
||||
ranges.unshift([num, num + 1]);
|
||||
}
|
||||
return ranges;
|
||||
}, [[first, first + 1]]).reverse().map(val => ({ start: val[0], end: val[1] }));
|
||||
}
|
||||
|
||||
export function cellRangesToIndexes(ranges: ICellRange[]) {
|
||||
const indexes = ranges.reduce((a, b) => {
|
||||
for (let i = b.start; i < b.end; i++) {
|
||||
a.push(i);
|
||||
}
|
||||
|
||||
return a;
|
||||
}, [] as number[]);
|
||||
|
||||
return indexes;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { NOTEBOOK_DISPLAY_ORDER, sortMimeTypes, CellKind, diff, CellUri } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { NOTEBOOK_DISPLAY_ORDER, sortMimeTypes, CellKind, diff, CellUri, cellRangesToIndexes, cellIndexesToRanges } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { TestCell, setupInstantiationService } from 'vs/workbench/contrib/notebook/test/testNotebookEditor';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
|
@ -355,3 +355,24 @@ suite('CellUri', function () {
|
|||
assert.equal(actual?.notebook.toString(), nb.toString());
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
suite('CellRange', function () {
|
||||
|
||||
test('Cell range to index', function () {
|
||||
assert.deepStrictEqual(cellRangesToIndexes([]), []);
|
||||
assert.deepStrictEqual(cellRangesToIndexes([{ start: 0, end: 0 }]), []);
|
||||
assert.deepStrictEqual(cellRangesToIndexes([{ start: 0, end: 1 }]), [0]);
|
||||
assert.deepStrictEqual(cellRangesToIndexes([{ start: 0, end: 2 }]), [0, 1]);
|
||||
assert.deepStrictEqual(cellRangesToIndexes([{ start: 0, end: 2 }, { start: 2, end: 3 }]), [0, 1, 2]);
|
||||
assert.deepStrictEqual(cellRangesToIndexes([{ start: 0, end: 2 }, { start: 3, end: 4 }]), [0, 1, 3]);
|
||||
});
|
||||
|
||||
test('Cell index to range', function () {
|
||||
assert.deepStrictEqual(cellIndexesToRanges([]), []);
|
||||
assert.deepStrictEqual(cellIndexesToRanges([0]), [{ start: 0, end: 1 }]);
|
||||
assert.deepStrictEqual(cellIndexesToRanges([0, 1]), [{ start: 0, end: 2 }]);
|
||||
assert.deepStrictEqual(cellIndexesToRanges([0, 1, 2]), [{ start: 0, end: 3 }]);
|
||||
assert.deepStrictEqual(cellIndexesToRanges([0, 1, 3]), [{ start: 0, end: 2 }, { start: 3, end: 4 }]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { CellKind, CellEditType, NotebookTextModelChangedEvent } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellKind, CellEditType, NotebookTextModelChangedEvent, SelectionStateType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { withTestNotebook, TestCell, setupInstantiationService } from 'vs/workbench/contrib/notebook/test/testNotebookEditor';
|
||||
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
|
||||
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
|
@ -300,7 +300,7 @@ suite('NotebookTextModel', () => {
|
|||
textModel.applyEdits(textModel.versionId, [
|
||||
{ editType: CellEditType.Replace, index: 1, count: 1, cells: [] },
|
||||
{ editType: CellEditType.Replace, index: 1, count: 0, cells: [new TestCell(viewModel.viewType, 5, 'var e = 5;', 'javascript', CellKind.Code, [], textModelService)] },
|
||||
], true, undefined, () => [0], undefined);
|
||||
], true, undefined, () => ({ kind: SelectionStateType.Index, selections: [{ start: 0, end: 1 }] }), undefined);
|
||||
|
||||
assert.equal(textModel.cells.length, 4);
|
||||
assert.equal(textModel.cells[0].getValue(), 'var a = 1;');
|
||||
|
@ -309,7 +309,7 @@ suite('NotebookTextModel', () => {
|
|||
|
||||
assert.notEqual(changeEvent, undefined);
|
||||
assert.equal(changeEvent!.rawEvents.length, 2);
|
||||
assert.deepEqual(changeEvent!.endSelections, [0]);
|
||||
assert.deepEqual(changeEvent!.endSelectionState?.selections, [{ start: 0, end: 1 }]);
|
||||
assert.equal(textModel.versionId, version + 1);
|
||||
eventListener.dispose();
|
||||
}
|
||||
|
@ -341,11 +341,11 @@ suite('NotebookTextModel', () => {
|
|||
editType: CellEditType.Metadata,
|
||||
metadata: { editable: false },
|
||||
}
|
||||
], true, undefined, () => [0], undefined);
|
||||
], true, undefined, () => ({ kind: SelectionStateType.Index, selections: [{ start: 0, end: 1 }] }), undefined);
|
||||
|
||||
assert.notEqual(changeEvent, undefined);
|
||||
assert.equal(changeEvent!.rawEvents.length, 2);
|
||||
assert.deepEqual(changeEvent!.endSelections, [0]);
|
||||
assert.deepEqual(changeEvent!.endSelectionState?.selections, [{ start: 0, end: 1 }]);
|
||||
assert.equal(textModel.versionId, version + 1);
|
||||
eventListener.dispose();
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ suite('NotebookViewModel', () => {
|
|||
assert.equal(viewModel.viewCells[0].metadata?.editable, true);
|
||||
assert.equal(viewModel.viewCells[1].metadata?.editable, false);
|
||||
|
||||
const cell = viewModel.createCell(1, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true, []);
|
||||
const cell = viewModel.createCell(1, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true, null, []);
|
||||
assert.equal(viewModel.viewCells.length, 3);
|
||||
assert.equal(viewModel.notebookDocument.cells.length, 3);
|
||||
assert.equal(viewModel.getCellIndex(cell), 1);
|
||||
|
|
|
@ -65,6 +65,12 @@ export class TestNotebookEditor implements INotebookEditor {
|
|||
|
||||
constructor(
|
||||
) { }
|
||||
getSelection(): ICellRange | undefined {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
getSelections(): ICellRange[] {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
getSelectionViewModels(): ICellViewModel[] {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
@ -111,11 +117,6 @@ export class TestNotebookEditor implements INotebookEditor {
|
|||
removeEditorDecorations(key: string): void {
|
||||
// throw new Error('Method not implemented.');
|
||||
}
|
||||
getSelectionHandles(): number[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
setOptions(options: NotebookEditorOptions | undefined): Promise<void> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
@ -227,7 +228,7 @@ export class TestNotebookEditor implements INotebookEditor {
|
|||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
selectElement(cell: CellViewModel): void {
|
||||
focusElement(cell: CellViewModel): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ suite('NotebookCell#Document', function () {
|
|||
addedEditors: [{
|
||||
documentUri: notebookUri,
|
||||
id: '_notebook_editor_0',
|
||||
selections: [0],
|
||||
selections: [{ start: 0, end: 1 }],
|
||||
visibleRanges: []
|
||||
}]
|
||||
});
|
||||
|
|
|
@ -75,7 +75,7 @@ suite('NotebookConcatDocument', function () {
|
|||
{
|
||||
documentUri: notebookUri,
|
||||
id: '_notebook_editor_0',
|
||||
selections: [0],
|
||||
selections: [{ start: 0, end: 1 }],
|
||||
visibleRanges: []
|
||||
}
|
||||
]
|
||||
|
|
Loading…
Reference in a new issue