提交 a14736ca 编写于 作者: R rebornix

introduce visible notebook editors

上级 9a384768
......@@ -1879,7 +1879,8 @@ declare module 'vscode' {
export const onDidOpenNotebookDocument: Event<NotebookDocument>;
export const onDidCloseNotebookDocument: Event<NotebookDocument>;
// export const onDidChangeVisibleNotebookEditors: Event<NotebookEditor[]>;
export let visibleNotebookEditors: NotebookEditor[];
export const onDidChangeVisibleNotebookEditors: Event<NotebookEditor[]>;
// remove activeNotebookDocument, now that there is activeNotebookEditor.document
export let activeNotebookDocument: NotebookDocument | undefined;
......
......@@ -4,11 +4,11 @@
*--------------------------------------------------------------------------------------------*/
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { MainContext, MainThreadNotebookShape, NotebookExtensionDescription, IExtHostContext, ExtHostNotebookShape, ExtHostContext } from '../common/extHost.protocol';
import { Disposable } from 'vs/base/common/lifecycle';
import { MainContext, MainThreadNotebookShape, NotebookExtensionDescription, IExtHostContext, ExtHostNotebookShape, ExtHostContext, INotebookDocumentsAndEditorsDelta } from '../common/extHost.protocol';
import { Disposable, IDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
import { URI, UriComponents } from 'vs/base/common/uri';
import { INotebookService, IMainNotebookController } from 'vs/workbench/contrib/notebook/common/notebookService';
import { INotebookTextModel, INotebookMimeTypeSelector, NOTEBOOK_DISPLAY_ORDER, NotebookCellOutputsSplice, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation, ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellEditType, CellKind, INotebookKernelInfo, INotebookKernelInfoDto, INotebookTextModelBackup } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookTextModel, INotebookMimeTypeSelector, NOTEBOOK_DISPLAY_ORDER, NotebookCellOutputsSplice, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation, ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellEditType, CellKind, INotebookKernelInfo, INotebookKernelInfoDto, INotebookTextModelBackup, IEditor } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
......@@ -58,11 +58,77 @@ export class MainThreadNotebookDocument extends Disposable {
}
}
class DocumentAndEditorState {
static ofMaps<K, V>(before: Map<K, V>, after: Map<K, V>): { removed: V[], added: V[] } {
const removed: V[] = [];
const added: V[] = [];
before.forEach((value, index) => {
if (!after.has(index)) {
removed.push(value);
}
});
after.forEach((value, index) => {
if (!before.has(index)) {
added.push(value);
}
});
return { removed, added };
}
static compute(before: DocumentAndEditorState | undefined, after: DocumentAndEditorState): INotebookDocumentsAndEditorsDelta {
if (!before) {
const apiEditors = [];
for (let id in after.textEditors) {
const editor = after.textEditors.get(id)!;
apiEditors.push({ id, documentUri: editor.uri!, selections: editor!.textModel!.selections });
}
return {
addedDocuments: [],
addedEditors: apiEditors
};
}
// const documentDelta = delta.ofSets(before.documents, after.documents);
const editorDelta = DocumentAndEditorState.ofMaps(before.textEditors, after.textEditors);
const addedAPIEditors = editorDelta.added.map(add => ({
id: add.getId(),
documentUri: add.uri!,
selections: add.textModel!.selections
}));
const removedAPIEditors = editorDelta.removed.map(removed => removed.getId());
// const oldActiveEditor = before.activeEditor !== after.activeEditor ? before.activeEditor : undefined;
const newActiveEditor = before.activeEditor !== after.activeEditor ? after.activeEditor : undefined;
// return new DocumentAndEditorStateDelta(
// documentDelta.removed, documentDelta.added,
// editorDelta.removed, editorDelta.added,
// oldActiveEditor, newActiveEditor
// );
return {
addedEditors: addedAPIEditors,
removedEditors: removedAPIEditors,
newActiveEditor: newActiveEditor
};
}
constructor(
readonly documents: Set<URI>,
readonly textEditors: Map<string, IEditor>,
readonly activeEditor: string | null | undefined,
) {
//
}
}
@extHostNamedCustomer(MainContext.MainThreadNotebook)
export class MainThreadNotebooks extends Disposable implements MainThreadNotebookShape {
private readonly _notebookProviders = new Map<string, MainThreadNotebookController>();
private readonly _notebookKernels = new Map<string, MainThreadNotebookKernel>();
private readonly _proxy: ExtHostNotebookShape;
private _toDisposeOnEditorRemove = new Map<string, IDisposable>();
private _currentState?: DocumentAndEditorState;
constructor(
extHostContext: IExtHostContext,
......@@ -90,10 +156,18 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
registerListeners() {
this._register(this._notebookService.onDidChangeActiveEditor(e => {
this._proxy.$acceptDocumentAndEditorsDelta({
newActiveEditor: e.uri
newActiveEditor: e
});
}));
this._register(this._notebookService.onNotebookEditorAdd(editor => {
this._addNotebookEditor(editor);
}));
this._register(this._notebookService.onNotebookEditorRemove(editor => {
this._removeNotebookEditor(editor);
}));
const updateOrder = () => {
let userOrder = this.configurationService.getValue<string[]>('notebook.displayOrder');
this._proxy.$acceptDisplayOrder({
......@@ -115,6 +189,57 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
}));
}
private _addNotebookEditor(e: IEditor) {
this._toDisposeOnEditorRemove.set(e.getId(), combinedDisposable(
e.onDidChangeModel(() => this._updateState()),
e.onDidFocusEditorWidget(() => this._updateState(e)),
));
this._updateState();
}
private _removeNotebookEditor(e: IEditor) {
const sub = this._toDisposeOnEditorRemove.get(e.getId());
if (sub) {
this._toDisposeOnEditorRemove.delete(e.getId());
sub.dispose();
this._updateState();
}
}
private async _updateState(focusedNotebookEditor?: IEditor) {
const documents = new Set<URI>();
this._notebookService.listNotebookDocuments().forEach(document => {
documents.add(document.uri);
});
const editors = new Map<string, IEditor>();
let activeEditor: string | null = null;
for (const editor of this._notebookService.listNotebookEditors()) {
if (editor.hasModel()) {
editors.set(editor.getId(), editor);
if (editor.hasFocus()) {
activeEditor = editor.getId();
}
}
}
// editors always have view model attached, which means there is already a document in exthost.
const newState = new DocumentAndEditorState(documents, editors, activeEditor);
const delta = DocumentAndEditorState.compute(this._currentState, newState);
// const isEmptyChange = (!delta.addedDocuments || delta.addedDocuments.length === 0)
// && (!delta.removedDocuments || delta.removedDocuments.length === 0)
// && (!delta.addedEditors || delta.addedEditors.length === 0)
// && (!delta.removedEditors || delta.removedEditors.length === 0)
// && (delta.newActiveEditor === undefined)
// if (!isEmptyChange) {
this._currentState = newState;
await this._proxy.$acceptDocumentAndEditorsDelta(delta);
// }
}
async $registerNotebookRenderer(extension: NotebookExtensionDescription, type: string, selectors: INotebookMimeTypeSelector, handle: number, preloads: UriComponents[]): Promise<void> {
this._notebookService.registerNotebookRenderer(handle, extension, type, selectors, preloads.map(uri => URI.revive(uri)));
}
......
......@@ -918,6 +918,12 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
checkProposedApiEnabled(extension);
return extHostNotebook.onDidCloseNotebookDocument;
},
get visibleNotebookEditors() {
return extHostNotebook.visibleNotebookEditors;
},
get onDidChangeVisibleNotebookEditors() {
return extHostNotebook.onDidChangeVisibleNotebookEditors;
},
registerNotebookContentProvider: (viewType: string, provider: vscode.NotebookContentProvider) => {
checkProposedApiEnabled(extension);
return extHostNotebook.registerNotebookContentProvider(extension, viewType, provider);
......
......@@ -1553,12 +1553,18 @@ export interface INotebookModelAddedData {
metadata?: NotebookDocumentMetadata;
}
export interface INotebookEditorAddData {
id: string;
documentUri: UriComponents;
selections: number[];
}
export interface INotebookDocumentsAndEditorsDelta {
removedDocuments?: UriComponents[];
addedDocuments?: INotebookModelAddedData[];
// removedEditors?: string[];
// addedEditors?: ITextEditorAddData[];
newActiveEditor?: UriComponents | null;
removedEditors?: string[];
addedEditors?: INotebookEditorAddData[];
newActiveEditor?: string | null;
}
export interface ExtHostNotebookShape {
......
......@@ -219,6 +219,8 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
return this._versionId;
}
webviewId: string = '';
constructor(
private readonly _proxy: MainThreadNotebookShape,
private _documentsAndEditors: ExtHostDocumentsAndEditors,
......@@ -499,7 +501,7 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
public uri: URI,
private _proxy: MainThreadNotebookShape,
private _onDidReceiveMessage: Emitter<any>,
private _webviewId: string,
public _webviewId: string,
private _webviewInitData: WebviewInitData,
public document: ExtHostNotebookDocument,
private _documentsAndEditors: ExtHostDocumentsAndEditors
......@@ -627,8 +629,6 @@ export interface ExtHostNotebookOutputRenderingHandler {
}
export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostNotebookOutputRenderingHandler {
private static _handlePool: number = 0;
private readonly _proxy: MainThreadNotebookShape;
private readonly _notebookContentProviders = new Map<string, { readonly provider: vscode.NotebookContentProvider, readonly extension: IExtensionDescription; }>();
private readonly _notebookKernels = new Map<string, { readonly kernel: vscode.NotebookKernel, readonly extension: IExtensionDescription; }>();
......@@ -662,6 +662,9 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
onDidOpenNotebookDocument: Event<vscode.NotebookDocument> = this._onDidOpenNotebookDocument.event;
private _onDidCloseNotebookDocument = new Emitter<vscode.NotebookDocument>();
onDidCloseNotebookDocument: Event<vscode.NotebookDocument> = this._onDidCloseNotebookDocument.event;
visibleNotebookEditors: ExtHostNotebookEditor[] = [];
private _onDidChangeVisibleNotebookEditors = new Emitter<vscode.NotebookEditor[]>();
onDidChangeVisibleNotebookEditors = this._onDidChangeVisibleNotebookEditors.event;
constructor(mainContext: IMainContext, commands: ExtHostCommands, private _documentsAndEditors: ExtHostDocumentsAndEditors, private readonly _webviewInitData: WebviewInitData) {
this._proxy = mainContext.getProxy(MainContext.MainThreadNotebook);
......@@ -934,8 +937,21 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
this._outputDisplayOrder = displayOrder;
}
// TODO: remove document - editor one on one mapping
private _getEditorFromURI(uriComponents: UriComponents) {
const uriStr = URI.revive(uriComponents).toString();
let editor: { editor: ExtHostNotebookEditor, onDidReceiveMessage: Emitter<any>; } | undefined;
this._editors.forEach(e => {
if (e.editor.uri.toString() === uriStr) {
editor = e;
}
});
return editor;
}
$onDidReceiveMessage(uri: UriComponents, message: any): void {
let editor = this._editors.get(URI.revive(uri).toString());
let editor = this._getEditorFromURI(uri);
if (editor) {
editor.onDidReceiveMessage.fire(message);
......@@ -943,7 +959,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEvent): void {
let editor = this._editors.get(URI.revive(uriComponents).toString());
let editor = this._getEditorFromURI(uriComponents);
if (editor) {
editor.editor.document.accpetModelChanged(event);
......@@ -956,7 +972,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}
$acceptEditorPropertiesChanged(uriComponents: UriComponents, data: INotebookEditorPropertiesChangeData): void {
let editor = this._editors.get(URI.revive(uriComponents).toString());
let editor = this._getEditorFromURI(uriComponents);
if (!editor) {
return;
......@@ -1029,34 +1045,79 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
]
});
document.webviewId = modelData.webviewId;
this._documents.set(revivedUriStr, document);
}
const onDidReceiveMessage = new Emitter<any>();
const document = this._documents.get(revivedUriStr)!;
this._onDidOpenNotebookDocument.fire(document);
});
}
let editor = new ExtHostNotebookEditor(
viewType,
`${ExtHostNotebookController._handlePool++}`,
revivedUri,
this._proxy,
onDidReceiveMessage,
modelData.webviewId,
this._webviewInitData,
document,
this._documentsAndEditors
);
let editorChanged = false;
this._onDidOpenNotebookDocument.fire(document);
if (delta.addedEditors) {
delta.addedEditors.forEach(editorModelData => {
const revivedUri = URI.revive(editorModelData.documentUri);
const document = this._documents.get(revivedUri.toString());
if (document) {
const onDidReceiveMessage = new Emitter<any>();
let editor = new ExtHostNotebookEditor(
document.viewType,
editorModelData.id,
revivedUri,
this._proxy,
onDidReceiveMessage,
document.webviewId,
this._webviewInitData,
document,
this._documentsAndEditors
);
const cells = editor.document.cells;
if (editorModelData.selections.length) {
const firstCell = editorModelData.selections[0];
editor.selection = cells.find(cell => cell.handle === firstCell);
} else {
editor.selection = undefined;
}
editorChanged = true;
this._editors.set(editorModelData.id, { editor, onDidReceiveMessage });
}
});
}
if (delta.removedEditors) {
delta.removedEditors.forEach(editorid => {
const editor = this._editors.get(editorid);
// TODO, does it already exist?
this._editors.set(revivedUriStr, { editor, onDidReceiveMessage });
if (editor) {
editorChanged = true;
this._editors.delete(editorid);
// TODO, dispose the editor
}
});
}
if (delta.newActiveEditor) {
this._activeNotebookDocument = this._documents.get(URI.revive(delta.newActiveEditor).toString());
this._activeNotebookEditor = this._editors.get(URI.revive(delta.newActiveEditor).toString())?.editor;
if (editorChanged) {
this.visibleNotebookEditors = [...this._editors.values()].map(e => e.editor);
this._onDidChangeVisibleNotebookEditors.fire(this.visibleNotebookEditors);
}
if (delta.newActiveEditor !== undefined) {
if (delta.newActiveEditor) {
this._activeNotebookEditor = this._editors.get(delta.newActiveEditor)?.editor;
this._activeNotebookDocument = this._documents.get(this._activeNotebookEditor!.uri.toString());
} else {
this._activeNotebookEditor = undefined;
this._activeNotebookDocument = undefined;
}
}
}
}
......@@ -144,9 +144,10 @@ export class NotebookContribution extends Disposable implements IWorkbenchContri
}));
this._register(this.editorService.onDidActiveEditorChange(() => {
if (this.editorService.activeEditor && this.editorService.activeEditor! instanceof NotebookEditorInput) {
let editorInput = this.editorService.activeEditor! as NotebookEditorInput;
this.notebookService.updateActiveNotebookDocument(editorInput.viewType!, editorInput.resource!);
const activeEditorPane = editorService.activeEditorPane as any | undefined;
const notebookEditor = activeEditorPane?.isNotebookEditor ? activeEditorPane.getControl() : undefined;
if (notebookEditor) {
this.notebookService.updateActiveNotebookEditor(notebookEditor);
}
}));
......
......@@ -23,9 +23,9 @@ import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/outpu
import { CellLanguageStatusBarItem, TimerRenderer } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer';
import { CellViewModel, IModelDecorationsChangeAccessor, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
import { CellKind, IOutput, IRenderOutput, NotebookCellMetadata, NotebookDocumentMetadata, INotebookKernelInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellKind, IOutput, IRenderOutput, NotebookCellMetadata, NotebookDocumentMetadata, INotebookKernelInfo, IEditor } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { Webview } from 'vs/workbench/contrib/webview/browser/webview';
import { ICompositeCodeEditor } from 'vs/editor/common/editorCommon';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
export const KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED = new RawContextKey<boolean>('notebookFindWidgetFocused', false);
......@@ -143,7 +143,7 @@ export interface INotebookEditorContribution {
restoreViewState?(state: any): void;
}
export interface INotebookEditor extends ICompositeCodeEditor {
export interface INotebookEditor extends IEditor {
/**
* Notebook view model attached to the current editor
......@@ -154,11 +154,13 @@ export interface INotebookEditor extends ICompositeCodeEditor {
* An event emitted when the model of this editor has changed.
* @event
*/
readonly onDidChangeModel: Event<void>;
readonly onDidChangeModel: Event<NotebookTextModel | undefined>;
readonly onDidFocusEditorWidget: Event<void>;
isNotebookEditor: boolean;
activeKernel: INotebookKernelInfo | undefined;
readonly onDidChangeKernel: Event<void>;
getId(): string;
getDomNode(): HTMLElement;
getInnerWebview(): Webview | undefined;
......@@ -167,6 +169,8 @@ export interface INotebookEditor extends ICompositeCodeEditor {
*/
focus(): void;
hasFocus(): boolean;
/**
* Select & focus cell
*/
......
......@@ -68,6 +68,7 @@ export class NotebookEditorOptions extends EditorOptions {
}
let EDITOR_ID = 0;
export class NotebookEditorWidget extends Disposable implements INotebookEditor {
static readonly ID: string = 'workbench.editor.notebook';
......@@ -94,8 +95,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
private scrollBeyondLastLine: boolean;
private readonly memento: Memento;
private _isDisposed: boolean = false;
private readonly _id: number;
constructor(
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IStorageService storageService: IStorageService,
......@@ -105,6 +105,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
@ILayoutService private readonly _layoutService: ILayoutService
) {
super();
this._id = (++EDITOR_ID);
this.memento = new Memento(NotebookEditorWidget.ID, storageService);
this.outputRenderer = new OutputRenderer(this, this.instantiationService);
......@@ -119,21 +120,41 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
}
}
});
this.notebookService.addNotebookEditor(this);
}
public getId(): string {
return 'vs.editor.INotebookEditor:' + this._id;
}
private readonly _onDidChangeModel = new Emitter<void>();
readonly onDidChangeModel: Event<void> = this._onDidChangeModel.event;
private readonly _onDidChangeModel = new Emitter<NotebookTextModel | undefined>();
readonly onDidChangeModel: Event<NotebookTextModel | undefined> = this._onDidChangeModel.event;
private readonly _onDidFocusEditorWidget = new Emitter<void>();
readonly onDidFocusEditorWidget = this._onDidFocusEditorWidget.event;
set viewModel(newModel: NotebookViewModel | undefined) {
this.notebookViewModel = newModel;
this._onDidChangeModel.fire();
this._onDidChangeModel.fire(newModel?.notebookDocument);
}
get viewModel() {
return this.notebookViewModel;
}
get uri() {
return this.notebookViewModel?.uri;
}
get textModel() {
return this.notebookViewModel?.notebookDocument;
}
hasModel() {
return !!this.notebookViewModel;
}
private _activeKernel: INotebookKernelInfo | undefined = undefined;
private readonly _onDidChangeKernel = new Emitter<void>();
readonly onDidChangeKernel: Event<void> = this._onDidChangeKernel.event;
......@@ -158,11 +179,11 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
//#region Editor Core
protected getEditorMemento<T>(editorGroupService: IEditorGroupsService, key: string, limit: number = 10): IEditorMemento<T> {
const mementoKey = `${this.getId()}${key}`;
const mementoKey = `${NotebookEditorWidget.ID}${key}`;
let editorMemento = NotebookEditorWidget.EDITOR_MEMENTOS.get(mementoKey);
if (!editorMemento) {
editorMemento = new EditorMemento(this.getId(), key, this.getMemento(StorageScope.WORKSPACE), limit, editorGroupService);
editorMemento = new EditorMemento(NotebookEditorWidget.ID, key, this.getMemento(StorageScope.WORKSPACE), limit, editorGroupService);
NotebookEditorWidget.EDITOR_MEMENTOS.set(mementoKey, editorMemento);
}
......@@ -173,12 +194,6 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
return this.memento.getMemento(scope);
}
getId(): string {
return NotebookEditorWidget.ID;
}
public get isNotebookEditor() {
return true;
}
......@@ -187,6 +202,11 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
// Note - focus going to the webview will fire 'blur', but the webview element will be
// a descendent of the notebook editor root.
this.editorFocus?.set(DOM.isAncestor(document.activeElement, this.overlayContainer));
this._onDidFocusEditorWidget.fire();
}
hasFocus() {
return this.editorFocus?.get() || false;
}
createEditor(): void {
......@@ -1256,6 +1276,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
dispose() {
this._isDisposed = true;
this.notebookService.removeNotebookEditor(this);
const keys = Object.keys(this._contributions);
for (let i = 0, len = keys.length; i < len; i++) {
const contributionId = keys[i];
......
......@@ -23,6 +23,7 @@ import { NotebookEditorModelManager } from 'vs/workbench/contrib/notebook/common
import { INotebookService, IMainNotebookController } from 'vs/workbench/contrib/notebook/common/notebookService';
import * as glob from 'vs/base/common/glob';
import { basename } from 'vs/base/common/resources';
import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
function MODEL_ID(resource: URI): string {
return resource.toString();
......@@ -101,8 +102,13 @@ export class NotebookService extends Disposable implements INotebookService, ICu
notebookProviderInfoStore: NotebookProviderInfoStore = new NotebookProviderInfoStore();
notebookRenderersInfoStore: NotebookOutputRendererInfoStore = new NotebookOutputRendererInfoStore();
private readonly _models: { [modelId: string]: ModelData; };
private _onDidChangeActiveEditor = new Emitter<{ viewType: string, uri: URI }>();
onDidChangeActiveEditor: Event<{ viewType: string, uri: URI }> = this._onDidChangeActiveEditor.event;
private _onDidChangeActiveEditor = new Emitter<string>();
onDidChangeActiveEditor: Event<string> = this._onDidChangeActiveEditor.event;
private readonly _onNotebookEditorAdd: Emitter<INotebookEditor> = this._register(new Emitter<INotebookEditor>());
public readonly onNotebookEditorAdd: Event<INotebookEditor> = this._onNotebookEditorAdd.event;
private readonly _onNotebookEditorRemove: Emitter<INotebookEditor> = this._register(new Emitter<INotebookEditor>());
public readonly onNotebookEditorRemove: Event<INotebookEditor> = this._onNotebookEditorRemove.event;
private readonly _notebookEditors: { [editorId: string]: INotebookEditor; };
private readonly _onDidChangeViewTypes = new Emitter<void>();
onDidChangeViewTypes: Event<void> = this._onDidChangeViewTypes.event;
......@@ -121,6 +127,7 @@ export class NotebookService extends Disposable implements INotebookService, ICu
super();
this._models = {};
this._notebookEditors = Object.create(null);
this.modelManager = this.instantiationService.createInstance(NotebookEditorModelManager);
notebookProviderExtensionPoint.setHandler((extensions) => {
......@@ -352,6 +359,25 @@ export class NotebookService extends Disposable implements INotebookService, ICu
return ret;
}
removeNotebookEditor(editor: INotebookEditor) {
if (delete this._notebookEditors[editor.getId()]) {
this._onNotebookEditorRemove.fire(editor);
}
}
addNotebookEditor(editor: INotebookEditor) {
this._notebookEditors[editor.getId()] = editor;
this._onNotebookEditorAdd.fire(editor);
}
listNotebookEditors(): INotebookEditor[] {
return Object.keys(this._notebookEditors).map(id => this._notebookEditors[id]);
}
listNotebookDocuments(): NotebookTextModel[] {
return Object.keys(this._models).map(id => this._models[id].model);
}
destoryNotebookDocument(viewType: string, notebook: INotebookTextModel): void {
let provider = this._notebookProviders.get(viewType);
......@@ -360,8 +386,8 @@ export class NotebookService extends Disposable implements INotebookService, ICu
}
}
updateActiveNotebookDocument(viewType: string, resource: URI): void {
this._onDidChangeActiveEditor.fire({ viewType, uri: resource });
updateActiveNotebookEditor(editor: INotebookEditor) {
this._onDidChangeActiveEditor.fire(editor.getId());
}
setToCopy(items: NotebookCellTextModel[]) {
......
......@@ -507,3 +507,14 @@ export interface INotebookTextModelBackup {
languages: string[];
cells: ICellDto2[]
}
export interface IEditor extends editorCommon.ICompositeCodeEditor {
readonly onDidChangeModel: Event<NotebookTextModel | undefined>;
readonly onDidFocusEditorWidget: Event<void>;
isNotebookEditor: boolean;
uri?: URI;
textModel?: NotebookTextModel;
getId(): string;
hasFocus(): boolean;
hasModel(): boolean;
}
......@@ -8,7 +8,7 @@ import { URI } from 'vs/base/common/uri';
import { NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider';
import { NotebookExtensionDescription } from 'vs/workbench/api/common/extHost.protocol';
import { Event } from 'vs/base/common/event';
import { INotebookTextModel, INotebookMimeTypeSelector, INotebookRendererInfo, NotebookDocumentMetadata, ICellDto2, INotebookKernelInfo, INotebookKernelInfoDto, INotebookTextModelBackup } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookTextModel, INotebookMimeTypeSelector, INotebookRendererInfo, NotebookDocumentMetadata, ICellDto2, INotebookKernelInfo, INotebookKernelInfoDto, INotebookTextModelBackup, IEditor } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { CancellationToken } from 'vs/base/common/cancellation';
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
......@@ -31,7 +31,9 @@ export interface INotebookService {
_serviceBrand: undefined;
modelManager: INotebookEditorModelManager;
canResolve(viewType: string): Promise<boolean>;
onDidChangeActiveEditor: Event<{ viewType: string, uri: URI }>;
onDidChangeActiveEditor: Event<string>;
onNotebookEditorAdd: Event<IEditor>;
onNotebookEditorRemove: Event<IEditor>;
onDidChangeKernels: Event<void>;
registerNotebookController(viewType: string, extensionData: NotebookExtensionDescription, controller: IMainNotebookController): void;
unregisterNotebookProvider(viewType: string): void;
......@@ -51,10 +53,17 @@ export interface INotebookService {
getContributedNotebookProvider(viewType: string): NotebookProviderInfo | undefined;
getNotebookProviderResourceRoots(): URI[];
destoryNotebookDocument(viewType: string, notebook: INotebookTextModel): void;
updateActiveNotebookDocument(viewType: string, resource: URI): void;
updateActiveNotebookEditor(editor: IEditor): void;
save(viewType: string, resource: URI, token: CancellationToken): Promise<boolean>;
saveAs(viewType: string, resource: URI, target: URI, token: CancellationToken): Promise<boolean>;
onDidReceiveMessage(viewType: string, uri: URI, message: any): void;
setToCopy(items: NotebookCellTextModel[]): void;
getToCopy(): NotebookCellTextModel[] | undefined;
// editor events
addNotebookEditor(editor: IEditor): void;
removeNotebookEditor(editor: IEditor): void;
listNotebookEditors(): readonly IEditor[];
listNotebookDocuments(): readonly NotebookTextModel[];
}
......@@ -45,6 +45,19 @@ export class TestNotebookEditor implements INotebookEditor {
constructor(
) { }
hasModel(): boolean {
return true;
}
onDidFocusEditorWidget: Event<void> = new Emitter<void>().event;
hasFocus(): boolean {
return true;
}
getId(): string {
return 'notebook.testEditor';
}
activeKernel: INotebookKernelInfo | undefined;
onDidChangeKernel: Event<void> = new Emitter<void>().event;
onDidChangeActiveEditor: Event<ICompositeCodeEditor> = new Emitter<ICompositeCodeEditor>().event;
......@@ -53,8 +66,8 @@ export class TestNotebookEditor implements INotebookEditor {
throw new Error('Method not implemented.');
}
private _onDidChangeModel = new Emitter<void>();
onDidChangeModel: Event<void> = this._onDidChangeModel.event;
private _onDidChangeModel = new Emitter<NotebookTextModel | undefined>();
onDidChangeModel: Event<NotebookTextModel | undefined> = this._onDidChangeModel.event;
getContribution<T extends INotebookEditorContribution>(id: string): T {
throw new Error('Method not implemented.');
}
......
......@@ -63,9 +63,16 @@ suite('NotebookConcatDocument', function () {
outputs: [],
}],
versionId: 0
}]
}],
addedEditors: [
{
documentUri: notebookUri,
id: '_notebook_editor_0',
selections: [0]
}
]
});
await extHostNotebooks.$acceptDocumentAndEditorsDelta({ newActiveEditor: notebookUri });
await extHostNotebooks.$acceptDocumentAndEditorsDelta({ newActiveEditor: '_notebook_editor_0' });
notebook = extHostNotebooks.activeNotebookDocument!;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册