提交 b9c163fa 编写于 作者: R rebornix

asWebUri.

上级 48539eea
......@@ -345,3 +345,15 @@ suite('regression', () => {
assert.equal(vscode.notebook.activeNotebookEditor!.selection?.language, 'typescript');
});
});
suite('webview resource uri', () => {
test('asWebviewUri', async function () {
const resource = vscode.Uri.parse(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
await waitFor(500);
assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true, 'notebook first');
const uri = vscode.notebook.activeNotebookEditor!.asWebviewUri(vscode.Uri.parse('./hello.png'));
assert.equal(uri.scheme, 'vscode-resource');
});
});
......@@ -1732,6 +1732,11 @@ declare module 'vscode' {
*/
postMessage(message: any): Thenable<boolean>;
/**
* Convert a uri for the local file system to one that can be used inside outputs webview.
*/
asWebviewUri(localResource: Uri): Uri;
edit(callback: (editBuilder: NotebookEditorCellEdit) => void): Thenable<boolean>;
}
......@@ -1794,6 +1799,8 @@ declare module 'vscode' {
// revert?(document: NotebookDocument, cancellation: CancellationToken): Thenable<void>;
// backup?(document: NotebookDocument, cancellation: CancellationToken): Thenable<CustomDocumentBackup>;
kernel?: NotebookKernel;
/**
* Responsible for filling in outputs for the cell
*/
......
......@@ -17,6 +17,7 @@ import { CancellationToken } from 'vs/base/common/cancellation';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { IRelativePattern } from 'vs/base/common/glob';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { generateUuid } from 'vs/base/common/uuid';
export class MainThreadNotebookDocument extends Disposable {
private _textModel: NotebookTextModel;
......@@ -29,10 +30,11 @@ export class MainThreadNotebookDocument extends Disposable {
private readonly _proxy: ExtHostNotebookShape,
public handle: number,
public viewType: string,
public uri: URI
public uri: URI,
public webviewId: string,
) {
super();
this._textModel = new NotebookTextModel(handle, viewType, uri);
this._textModel = new NotebookTextModel(handle, viewType, uri, webviewId);
this._register(this._textModel.onDidModelChange(e => {
this._proxy.$acceptModelChanged(this.uri, e);
}));
......@@ -121,8 +123,8 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
this._notebookService.unregisterNotebookRenderer(handle);
}
async $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string): Promise<void> {
let controller = new MainThreadNotebookController(this._proxy, this, viewType);
async $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, hasKernelSupport: boolean): Promise<void> {
let controller = new MainThreadNotebookController(this._proxy, this, viewType, hasKernelSupport);
this._notebookProviders.set(viewType, controller);
this._notebookService.registerNotebookController(viewType, extension, controller);
return;
......@@ -176,8 +178,8 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
controller?.spliceNotebookCellOutputs(resource, cellHandle, splices, renderers);
}
async executeNotebook(viewType: string, uri: URI, token: CancellationToken): Promise<void> {
return this._proxy.$executeNotebook(viewType, uri, undefined, token);
async executeNotebook(viewType: string, uri: URI, useAttachedKernel: boolean, token: CancellationToken): Promise<void> {
return this._proxy.$executeNotebook(viewType, uri, undefined, useAttachedKernel, token);
}
async $postMessage(handle: number, value: any): Promise<boolean> {
......@@ -203,7 +205,8 @@ export class MainThreadNotebookController implements IMainNotebookController {
constructor(
private readonly _proxy: ExtHostNotebookShape,
private _mainThreadNotebook: MainThreadNotebooks,
private _viewType: string
private _viewType: string,
readonly hasKernelSupport: boolean
) {
}
......@@ -227,7 +230,7 @@ export class MainThreadNotebookController implements IMainNotebookController {
return mainthreadNotebook.textModel;
}
let document = new MainThreadNotebookDocument(this._proxy, MainThreadNotebookController.documentHandle++, viewType, uri);
let document = new MainThreadNotebookDocument(this._proxy, MainThreadNotebookController.documentHandle++, viewType, uri, generateUuid());
await this.createNotebookDocument(document);
if (forBackup) {
......@@ -272,8 +275,8 @@ export class MainThreadNotebookController implements IMainNotebookController {
mainthreadNotebook?.textModel.$spliceNotebookCellOutputs(cellHandle, splices);
}
async executeNotebook(viewType: string, uri: URI, token: CancellationToken): Promise<void> {
return this._mainThreadNotebook.executeNotebook(viewType, uri, token);
async executeNotebook(viewType: string, uri: URI, useAttachedKernel: boolean, token: CancellationToken): Promise<void> {
return this._mainThreadNotebook.executeNotebook(viewType, uri, useAttachedKernel, token);
}
onDidReceiveMessage(uri: UriComponents, message: any): void {
......@@ -287,6 +290,7 @@ export class MainThreadNotebookController implements IMainNotebookController {
addedDocuments: [{
viewType: document.viewType,
handle: document.handle,
webviewId: document.webviewId,
uri: document.uri,
metadata: document.textModel.metadata
}]
......@@ -327,8 +331,8 @@ export class MainThreadNotebookController implements IMainNotebookController {
document?.textModel.updateRenderers(renderers);
}
async executeNotebookCell(uri: URI, handle: number, token: CancellationToken): Promise<void> {
return this._proxy.$executeNotebook(this._viewType, uri, handle, token);
async executeNotebookCell(uri: URI, handle: number, useAttachedKernel: boolean, token: CancellationToken): Promise<void> {
return this._proxy.$executeNotebook(this._viewType, uri, handle, useAttachedKernel, token);
}
async save(uri: URI, token: CancellationToken): Promise<boolean> {
......
......@@ -134,7 +134,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostWindow = rpcProtocol.set(ExtHostContext.ExtHostWindow, new ExtHostWindow(rpcProtocol));
const extHostProgress = rpcProtocol.set(ExtHostContext.ExtHostProgress, new ExtHostProgress(rpcProtocol.getProxy(MainContext.MainThreadProgress)));
const extHostLabelService = rpcProtocol.set(ExtHostContext.ExtHosLabelService, new ExtHostLabelService(rpcProtocol));
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors));
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, initData.environment));
const extHostTheming = rpcProtocol.set(ExtHostContext.ExtHostTheming, new ExtHostTheming(rpcProtocol));
const extHostAuthentication = rpcProtocol.set(ExtHostContext.ExtHostAuthentication, new ExtHostAuthentication(rpcProtocol));
const extHostTimeline = rpcProtocol.set(ExtHostContext.ExtHostTimeline, new ExtHostTimeline(rpcProtocol, extHostCommands));
......
......@@ -689,7 +689,7 @@ export type NotebookCellOutputsSplice = [
];
export interface MainThreadNotebookShape extends IDisposable {
$registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string): Promise<void>;
$registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, hasKernelSupport: boolean): Promise<void>;
$unregisterNotebookProvider(viewType: string): Promise<void>;
$registerNotebookRenderer(extension: NotebookExtensionDescription, type: string, selectors: INotebookMimeTypeSelector, handle: number, preloads: UriComponents[]): Promise<void>;
$unregisterNotebookRenderer(handle: number): Promise<void>;
......@@ -1545,6 +1545,7 @@ export interface INotebookEditorPropertiesChangeData {
export interface INotebookModelAddedData {
uri: UriComponents;
handle: number;
webviewId: string;
// versionId: number;
viewType: string;
metadata?: NotebookDocumentMetadata;
......@@ -1560,7 +1561,7 @@ export interface INotebookDocumentsAndEditorsDelta {
export interface ExtHostNotebookShape {
$resolveNotebookData(viewType: string, uri: UriComponents): Promise<NotebookDataDto | undefined>;
$executeNotebook(viewType: string, uri: UriComponents, cellHandle: number | undefined, token: CancellationToken): Promise<void>;
$executeNotebook(viewType: string, uri: UriComponents, cellHandle: number | undefined, useAttachedKernel: boolean, token: CancellationToken): Promise<void>;
$executeNotebook2(kernelId: string, viewType: string, uri: UriComponents, cellHandle: number | undefined, token: CancellationToken): Promise<void>;
$saveNotebook(viewType: string, uri: UriComponents, token: CancellationToken): Promise<boolean>;
$saveNotebookAs(viewType: string, uri: UriComponents, target: UriComponents, token: CancellationToken): Promise<boolean>;
......
......@@ -19,6 +19,7 @@ import { CancellationToken } from 'vs/base/common/cancellation';
import { ExtHostDocumentData } from 'vs/workbench/api/common/extHostDocumentData';
import { NotImplementedProxy } from 'vs/base/common/types';
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/webview';
interface IObservable<T> {
proxy: T;
......@@ -498,6 +499,8 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
public uri: URI,
private _proxy: MainThreadNotebookShape,
private _onDidReceiveMessage: Emitter<any>,
private _webviewId: string,
private _webviewInitData: WebviewInitData,
public document: ExtHostNotebookDocument,
private _documentsAndEditors: ExtHostDocumentsAndEditors
) {
......@@ -585,6 +588,9 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
return this._proxy.$postMessage(this.document.handle, message);
}
asWebviewUri(localResource: vscode.Uri): vscode.Uri {
return asWebviewUri(this._webviewInitData, this._webviewId, localResource);
}
}
export class ExtHostNotebookOutputRenderer {
......@@ -656,7 +662,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
private _onDidCloseNotebookDocument = new Emitter<vscode.NotebookDocument>();
onDidCloseNotebookDocument: Event<vscode.NotebookDocument> = this._onDidCloseNotebookDocument.event;
constructor(mainContext: IMainContext, commands: ExtHostCommands, private _documentsAndEditors: ExtHostDocumentsAndEditors) {
constructor(mainContext: IMainContext, commands: ExtHostCommands, private _documentsAndEditors: ExtHostDocumentsAndEditors, private readonly _webviewInitData: WebviewInitData) {
this._proxy = mainContext.getProxy(MainContext.MainThreadNotebook);
commands.registerArgumentProcessor({
......@@ -716,7 +722,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}
this._notebookContentProviders.set(viewType, { extension, provider });
this._proxy.$registerNotebookProvider({ id: extension.identifier, location: extension.extensionLocation }, viewType);
this._proxy.$registerNotebookProvider({ id: extension.identifier, location: extension.extensionLocation }, viewType, !!provider.kernel);
return new VSCodeDisposable(() => {
this._notebookContentProviders.delete(viewType);
this._proxy.$unregisterNotebookProvider(viewType);
......@@ -833,7 +839,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
};
}
async $executeNotebook(viewType: string, uri: UriComponents, cellHandle: number | undefined, token: CancellationToken): Promise<void> {
async $executeNotebook(viewType: string, uri: UriComponents, cellHandle: number | undefined, useAttachedKernel: boolean, token: CancellationToken): Promise<void> {
let document = this._documents.get(URI.revive(uri).toString());
if (!document) {
......@@ -841,9 +847,18 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}
if (this._notebookContentProviders.has(viewType)) {
let cell = cellHandle !== undefined ? document.getCell(cellHandle) : undefined;
const cell = cellHandle !== undefined ? document.getCell(cellHandle) : undefined;
const provider = this._notebookContentProviders.get(viewType)!.provider;
return this._notebookContentProviders.get(viewType)!.provider.executeCell(document, cell, token);
if (provider.kernel && useAttachedKernel) {
if (cell) {
return provider.kernel.executeCell(document, cell, token);
} else {
return provider.kernel.executeAllCells(document, token);
}
} else {
return provider.executeCell(document, cell, token);
}
}
}
......@@ -1004,6 +1019,8 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
revivedUri,
this._proxy,
onDidReceiveMessage,
modelData.webviewId,
this._webviewInitData,
document,
this._documentsAndEditors
);
......
......@@ -3,76 +3,16 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { INotebookEditor, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_IS_ACTIVE_EDITOR } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { INotebookEditor, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_HAS_MULTIPLE_KERNELS } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IQuickInputService, QuickPickInput, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import * as nls from 'vs/nls';
import { registerAction2, Action2 } from 'vs/platform/actions/common/actions';
import { registerAction2, Action2, MenuId } from 'vs/platform/actions/common/actions';
import { NOTEBOOK_ACTIONS_CATEGORY, INotebookCellActionContext } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
// export class NotebookEditorStatus extends Disposable implements IWorkbenchContribution {
// private _localStore: DisposableStore = new DisposableStore();
// private kernelInfoElement = this._register(new MutableDisposable<IStatusbarEntryAccessor>());
// constructor(
// @IEditorService private readonly editorService: IEditorService,
// @IStatusbarService private readonly statusbarService: IStatusbarService,
// ) {
// super();
// this.registerListeners();
// }
// private registerListeners(): void {
// this._register(this.editorService.onDidActiveEditorChange(() => this.updateStatusBar()));
// this.updateStatusBar();
// }
// private async updateStatusBar(): Promise<void> {
// this._localStore.clear();
// const activeEditorPane = this.editorService.activeEditorPane as any | undefined;
// if (!activeEditorPane?.isNotebookEditor) {
// this.kernelInfoElement.clear();
// return;
// }
// const editor = activeEditorPane.getControl() as INotebookEditor;
// this._localStore.add(editor.onDidChangeKernel(() => {
// this.updateKernelInfo(editor.activeKernel);
// }));
// this.updateKernelInfo(editor.activeKernel);
// }
// private updateKernelInfo(kernelInfo: INotebookKernelInfo | undefined) {
// if (!kernelInfo) {
// this.kernelInfoElement.clear();
// return;
// }
// const props: IStatusbarEntry = {
// text: kernelInfo.label,
// ariaLabel: kernelInfo.label,
// tooltip: nls.localize('selectKernel', "Select Notebook Kernel"),
// command: 'notebook.selectKernel'
// };
// this.updateElement(this.kernelInfoElement, props, 'status.notebook.kernel', nls.localize('selectKernel', "Select Notebook Kernel"), StatusbarAlignment.RIGHT, 50);
// }
// private updateElement(element: MutableDisposable<IStatusbarEntryAccessor>, props: IStatusbarEntry, id: string, name: string, alignment: StatusbarAlignment, priority: number) {
// if (!element.value) {
// element.value = this.statusbarService.addEntry(props, id, name, alignment, priority);
// } else {
// element.value.update(props);
// }
// }
// }
// Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NotebookEditorStatus, LifecyclePhase.Eventually);
registerAction2(class extends Action2 {
constructor() {
......@@ -82,12 +22,12 @@ registerAction2(class extends Action2 {
title: nls.localize('notebookActions.selectKernel', "Select Notebook Kernel"),
precondition: ContextKeyExpr.and(NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_EDITOR_FOCUSED),
icon: { id: 'codicon/server-environment' },
// menu: {
// id: MenuId.EditorTitle,
// // when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', that.id), that.refreshContextKey),
// group: 'navigation',
// order: -2,
// },
menu: {
id: MenuId.EditorTitle,
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_HAS_MULTIPLE_KERNELS),
group: 'navigation',
order: -2,
},
f1: true
});
}
......@@ -119,6 +59,22 @@ registerAction2(class extends Action2 {
};
});
const provider = notebookService.getContributedNotebookProviders(editor.viewModel!.uri)[0];
if (provider.hasKernelSupport) {
picks.unshift({
id: provider.id,
label: provider.displayName,
picked: !activeKernel, // no active kernel, the builtin kernel of the provider is used
description: activeKernel === undefined
? nls.localize('currentActiveBuiltinKernel', " (Currently Active)")
: '',
run: () => {
editor.activeKernel = undefined;
}
});
}
const action = await quickInputService.pick(picks, { placeHolder: nls.localize('pickAction', "Select Action"), matchOnDetail: true });
return action?.run();
......
......@@ -47,6 +47,10 @@ export const NOTEBOOK_CELL_MARKDOWN_EDIT_MODE = new RawContextKey<boolean>('note
export const NOTEBOOK_CELL_RUN_STATE = new RawContextKey<string>('notebookCellRunState', undefined); // idle, running
export const NOTEBOOK_CELL_HAS_OUTPUTS = new RawContextKey<boolean>('notebookCellHasOutputs', false); // bool
// Kernels
export const NOTEBOOK_HAS_MULTIPLE_KERNELS = new RawContextKey<boolean>('notebookHasMultipleKernels', false);
export interface NotebookLayoutInfo {
width: number;
height: number;
......
......@@ -30,7 +30,7 @@ import { registerThemingParticipant } from 'vs/platform/theme/common/themeServic
import { EditorMemento } from 'vs/workbench/browser/parts/editor/baseEditor';
import { EditorOptions, IEditorMemento } from 'vs/workbench/common/editor';
import { CELL_MARGIN, CELL_RUN_GUTTER, EDITOR_BOTTOM_PADDING, EDITOR_TOP_MARGIN, EDITOR_TOP_PADDING, SCROLLABLE_ELEMENT_PADDING_TOP } from 'vs/workbench/contrib/notebook/browser/constants';
import { CellEditState, CellFocusMode, ICellRange, ICellViewModel, IEditableCellViewModel, INotebookCellList, INotebookEditor, INotebookEditorContribution, INotebookEditorMouseEvent, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_RUNNABLE } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellEditState, CellFocusMode, ICellRange, ICellViewModel, IEditableCellViewModel, INotebookCellList, INotebookEditor, INotebookEditorContribution, INotebookEditorMouseEvent, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_RUNNABLE, NOTEBOOK_HAS_MULTIPLE_KERNELS } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { NotebookEditorExtensionsRegistry } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions';
import { NotebookCellList } from 'vs/workbench/contrib/notebook/browser/view/notebookCellList';
import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer';
......@@ -87,6 +87,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
private editorEditable: IContextKey<boolean> | null = null;
private editorRunnable: IContextKey<boolean> | null = null;
private editorExecutingNotebook: IContextKey<boolean> | null = null;
private notebookHasMultipleKernels: IContextKey<boolean> | null = null;
private outputRenderer: OutputRenderer;
protected readonly _contributions: { [key: string]: INotebookEditorContribution; };
private scrollBeyondLastLine: boolean;
......@@ -98,7 +99,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
@IStorageService storageService: IStorageService,
@INotebookService private notebookService: INotebookService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IContextKeyService readonly contextKeyService: IContextKeyService,
@ILayoutService private readonly _layoutService: ILayoutService
) {
super();
......@@ -204,6 +205,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
this.editorRunnable = NOTEBOOK_EDITOR_RUNNABLE.bindTo(this.contextKeyService);
this.editorRunnable.set(true);
this.editorExecutingNotebook = NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK.bindTo(this.contextKeyService);
this.notebookHasMultipleKernels = NOTEBOOK_HAS_MULTIPLE_KERNELS.bindTo(this.contextKeyService);
this.notebookHasMultipleKernels.set(false);
const contributions = NotebookEditorExtensionsRegistry.getEditorContributions();
......@@ -284,15 +287,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
);
dndController.setList(this.list);
this.webview = this.instantiationService.createInstance(BackLayerWebView, this);
this.webview.webview.onDidBlur(() => this.updateEditorFocus());
this.webview.webview.onDidFocus(() => this.updateEditorFocus());
this._register(this.webview.onMessage(message => {
if (this.viewModel) {
this.notebookService.onDidReceiveMessage(this.viewModel.viewType, this.viewModel.uri, message);
}
}));
this.list.rowsContainer.appendChild(this.webview.element);
// create Webview
this._register(this.list);
this._register(combinedDisposable(...renders));
......@@ -355,13 +350,11 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
await this.attachModel(textModel, viewState);
}
const availableKernels = this.notebookService.getContributedNotebookKernels(textModel.viewType, textModel.uri);
this.activeKernel = availableKernels[0];
this._setKernels(textModel);
this.localStore.add(this.notebookService.onDidChangeKernels(() => {
if (this.activeKernel === undefined) {
const availableKernels = this.notebookService.getContributedNotebookKernels(textModel.viewType, textModel.uri);
this.activeKernel = availableKernels[0];
this._setKernels(textModel);
}
}));
......@@ -396,11 +389,35 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
this.viewModel?.dispose();
// avoid event
this.notebookViewModel = undefined;
this.webview?.clearInsets();
this.webview?.clearPreloadsCache();
// this.webview?.clearInsets();
// this.webview?.clearPreloadsCache();
this.webview?.dispose();
this.webview?.element.remove();
this.webview = null;
this.list?.clear();
}
private _setKernels(textModel: NotebookTextModel) {
const provider = this.notebookService.getContributedNotebookProviders(this.viewModel!.uri)[0];
const availableKernels = this.notebookService.getContributedNotebookKernels(textModel.viewType, textModel.uri);
if (provider.hasKernelSupport && availableKernels.length > 0) {
this.notebookHasMultipleKernels!.set(true);
} else if (availableKernels.length > 1) {
this.notebookHasMultipleKernels!.set(true);
} else {
this.notebookHasMultipleKernels!.set(false);
}
if (provider && provider.hasKernelSupport) {
// it has a builtin kernel, don't automatically choose a kernel
return;
}
// the provider doesn't have a builtin kernel, choose a kernel
this.activeKernel = availableKernels[0];
}
private updateForMetadata(): void {
this.editorEditable?.set(!!this.viewModel!.metadata?.editable);
this.editorRunnable?.set(!!this.viewModel!.metadata?.runnable);
......@@ -408,13 +425,21 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
DOM.toggleClass(this.getDomNode(), 'notebook-editor-editable', !!this.viewModel!.metadata?.editable);
}
private async attachModel(textModel: NotebookTextModel, viewState: INotebookEditorViewState | undefined) {
if (!this.webview) {
this.webview = this.instantiationService.createInstance(BackLayerWebView, this);
this.list?.rowsContainer.insertAdjacentElement('afterbegin', this.webview!.element);
}
private createWebview(id: string) {
this.webview = this.instantiationService.createInstance(BackLayerWebView, this, id);
this.webview.webview.onDidBlur(() => this.updateEditorFocus());
this.webview.webview.onDidFocus(() => this.updateEditorFocus());
this.localStore.add(this.webview.onMessage(message => {
if (this.viewModel) {
this.notebookService.onDidReceiveMessage(this.viewModel.viewType, this.viewModel.uri, message);
}
}));
this.list?.rowsContainer.insertAdjacentElement('afterbegin', this.webview.element);
}
await this.webview.waitForInitialization();
private async attachModel(textModel: NotebookTextModel, viewState: INotebookEditorViewState | undefined) {
this.createWebview(textModel.webviewId);
await this.webview!.waitForInitialization();
this.eventDispatcher = new NotebookEventDispatcher();
this.viewModel = this.instantiationService.createInstance(NotebookViewModel, textModel.viewType, textModel, this.eventDispatcher, this.getLayoutInfo());
......@@ -532,8 +557,15 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
}
}
getEditorViewState() {
const state = this.notebookViewModel!.getEditorViewState();
getEditorViewState(): INotebookEditorViewState {
const state = this.notebookViewModel?.getEditorViewState();
if (!state) {
return {
editingCells: {},
editorViewStates: {}
};
}
if (this.list) {
state.scrollPosition = { left: this.list.scrollLeft, top: this.list.scrollTop };
let cellHeights: { [key: number]: number } = {};
......@@ -1021,15 +1053,17 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
try {
this.editorExecutingNotebook!.set(true);
this.notebookViewModel!.currentTokenSource = tokenSource;
const provider = this.notebookService.getContributedNotebookProviders(this.viewModel!.uri)[0];
if (provider) {
const viewType = provider.id;
const notebookUri = this.notebookViewModel!.uri;
if (this._activeKernel) {
await this.notebookService.executeNotebook2(this.notebookViewModel!.viewType, this.notebookViewModel!.uri, this._activeKernel.id, tokenSource.token);
} else {
const provider = this.notebookService.getContributedNotebookProviders(this.viewModel!.uri)[0];
if (provider) {
const viewType = provider.id;
const notebookUri = this.notebookViewModel!.uri;
return await this.notebookService.executeNotebook(viewType, notebookUri, tokenSource.token);
if (this._activeKernel) {
await this.notebookService.executeNotebook2(this.notebookViewModel!.viewType, this.notebookViewModel!.uri, this._activeKernel.id, tokenSource.token);
} else if (provider.hasKernelSupport) {
return await this.notebookService.executeNotebook(viewType, notebookUri, true, tokenSource.token);
} else {
return await this.notebookService.executeNotebook(viewType, notebookUri, false, tokenSource.token);
}
}
......@@ -1070,10 +1104,13 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
if (provider) {
const viewType = provider.id;
const notebookUri = this.notebookViewModel!.uri;
if (this._activeKernel) {
return await this.notebookService.executeNotebookCell2(viewType, notebookUri, cell.handle, this._activeKernel.id, tokenSource.token);
} else if (provider.hasKernelSupport) {
return await this.notebookService.executeNotebookCell(viewType, notebookUri, cell.handle, true, tokenSource.token);
} else {
return await this.notebookService.executeNotebookCell(viewType, notebookUri, cell.handle, tokenSource.token);
return await this.notebookService.executeNotebookCell(viewType, notebookUri, cell.handle, false, tokenSource.token);
}
}
} finally {
......
......@@ -178,6 +178,7 @@ export class NotebookService extends Disposable implements INotebookService, ICu
registerNotebookController(viewType: string, extensionData: NotebookExtensionDescription, controller: IMainNotebookController) {
this._notebookProviders.set(viewType, { extensionData, controller });
this.notebookProviderInfoStore.get(viewType)!.hasKernelSupport = controller.hasKernelSupport;
this._onDidChangeViewTypes.fire();
}
......@@ -312,20 +313,20 @@ export class NotebookService extends Disposable implements INotebookService, ICu
return modelData.model;
}
async executeNotebook(viewType: string, uri: URI, token: CancellationToken): Promise<void> {
async executeNotebook(viewType: string, uri: URI, useAttachedKernel: boolean, token: CancellationToken): Promise<void> {
let provider = this._notebookProviders.get(viewType);
if (provider) {
return provider.controller.executeNotebook(viewType, uri, token);
return provider.controller.executeNotebook(viewType, uri, useAttachedKernel, token);
}
return;
}
async executeNotebookCell(viewType: string, uri: URI, handle: number, token: CancellationToken): Promise<void> {
async executeNotebookCell(viewType: string, uri: URI, handle: number, useAttachedKernel: boolean, token: CancellationToken): Promise<void> {
const provider = this._notebookProviders.get(viewType);
if (provider) {
await provider.controller.executeNotebookCell(uri, handle, token);
await provider.controller.executeNotebookCell(uri, handle, useAttachedKernel, token);
}
}
......
......@@ -136,9 +136,11 @@ export class BackLayerWebView extends Disposable {
private readonly _onMessage = this._register(new Emitter<any>());
public readonly onMessage: Event<any> = this._onMessage.event;
private _initalized: Promise<void>;
private _disposed = false;
constructor(
public notebookEditor: INotebookEditor,
public id: string,
@IWebviewService readonly webviewService: IWebviewService,
@IOpenerService readonly openerService: IOpenerService,
@INotebookService private readonly notebookService: INotebookService,
......@@ -473,7 +475,7 @@ ${loaderJs}
return { cell: this.insetMapping.get(output)!.cell, output };
}
initialize(content: string) {
async initialize(content: string) {
this.webview = this._createInset(this.webviewService, content);
this.webview.mountTo(this.element);
......@@ -558,7 +560,7 @@ ${loaderJs}
private _createInset(webviewService: IWebviewService, content: string) {
const rootPath = URI.file(path.dirname(getPathFromAmdModule(require, '')));
this.localResourceRootsCache = [...this.notebookService.getNotebookProviderResourceRoots(), rootPath];
const webview = webviewService.createWebviewElement('' + UUID.generateUuid(), {
const webview = webviewService.createWebviewElement(this.id, {
enableFindWidget: false,
}, {
allowMultipleAPIAcquire: true,
......@@ -570,6 +572,10 @@ ${loaderJs}
}
shouldUpdateInset(cell: CodeCellViewModel, output: IOutput, cellTop: number) {
if (this._disposed) {
return;
}
let outputCache = this.insetMapping.get(output)!;
let outputIndex = cell.outputs.indexOf(output);
let outputOffset = cellTop + cell.getOutputOffset(outputIndex);
......@@ -586,6 +592,10 @@ ${loaderJs}
}
updateViewScrollTop(top: number, items: { cell: CodeCellViewModel, output: IOutput, cellTop: number }[]) {
if (this._disposed) {
return;
}
let widgets: IContentWidgetTopRequest[] = items.map(item => {
let outputCache = this.insetMapping.get(item.output)!;
let id = outputCache.outputId;
......@@ -613,6 +623,10 @@ ${loaderJs}
}
createInset(cell: CodeCellViewModel, output: IOutput, cellTop: number, offset: number, shadowContent: string, preloads: Set<number>) {
if (this._disposed) {
return;
}
this.updateRendererPreloads(preloads);
let initialTop = cellTop + offset;
......@@ -648,6 +662,10 @@ ${loaderJs}
}
removeInset(output: IOutput) {
if (this._disposed) {
return;
}
let outputCache = this.insetMapping.get(output);
if (!outputCache) {
return;
......@@ -664,6 +682,10 @@ ${loaderJs}
}
hideInset(output: IOutput) {
if (this._disposed) {
return;
}
let outputCache = this.insetMapping.get(output);
if (!outputCache) {
return;
......@@ -679,6 +701,10 @@ ${loaderJs}
}
clearInsets() {
if (this._disposed) {
return;
}
this.webview.sendMessage({
type: 'clear'
});
......@@ -688,6 +714,10 @@ ${loaderJs}
}
focusOutput(cellId: string) {
if (this._disposed) {
return;
}
this.webview.focus();
setTimeout(() => { // Need this, or focus decoration is not shown. No clue.
this.webview.sendMessage({
......@@ -698,6 +728,10 @@ ${loaderJs}
}
updateRendererPreloads(preloads: ReadonlySet<number>) {
if (this._disposed) {
return;
}
let resources: string[] = [];
let extensionLocations: URI[] = [];
preloads.forEach(preload => {
......@@ -741,4 +775,9 @@ ${loaderJs}
clearPreloadsCache() {
this.preloadsCache.clear();
}
dispose() {
this._disposed = true;
super.dispose();
}
}
......@@ -104,7 +104,8 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
constructor(
public handle: number,
public viewType: string,
public uri: URI
public uri: URI,
public webviewId: string
) {
super();
this.cells = [];
......
......@@ -18,6 +18,7 @@ export class NotebookProviderInfo {
readonly displayName: string;
readonly selector: readonly NotebookSelector[];
readonly providerDisplayName: string;
hasKernelSupport: boolean = false;
constructor(descriptor: {
readonly id: string;
......
......@@ -17,10 +17,11 @@ import { INotebookEditorModelManager } from 'vs/workbench/contrib/notebook/commo
export const INotebookService = createDecorator<INotebookService>('notebookService');
export interface IMainNotebookController {
hasKernelSupport: boolean;
createNotebook(viewType: string, uri: URI, forBackup: boolean, forceReload: boolean): Promise<NotebookTextModel | undefined>;
executeNotebook(viewType: string, uri: URI, token: CancellationToken): Promise<void>;
executeNotebook(viewType: string, uri: URI, useAttachedKernel: boolean, token: CancellationToken): Promise<void>;
onDidReceiveMessage(uri: URI, message: any): void;
executeNotebookCell(uri: URI, handle: number, token: CancellationToken): Promise<void>;
executeNotebookCell(uri: URI, handle: number, useAttachedKernel: boolean, token: CancellationToken): Promise<void>;
removeNotebookDocument(notebook: INotebookTextModel): Promise<void>;
save(uri: URI, token: CancellationToken): Promise<boolean>;
saveAs(uri: URI, target: URI, token: CancellationToken): Promise<boolean>;
......@@ -42,8 +43,8 @@ export interface INotebookService {
getRendererInfo(handle: number): INotebookRendererInfo | undefined;
resolveNotebook(viewType: string, uri: URI, forceReload: boolean): Promise<NotebookTextModel | undefined>;
createNotebookFromBackup(viewType: string, uri: URI, metadata: NotebookDocumentMetadata, languages: string[], cells: ICellDto2[]): Promise<NotebookTextModel | undefined>;
executeNotebook(viewType: string, uri: URI, token: CancellationToken): Promise<void>;
executeNotebookCell(viewType: string, uri: URI, handle: number, token: CancellationToken): Promise<void>;
executeNotebook(viewType: string, uri: URI, useAttachedKernel: boolean, token: CancellationToken): Promise<void>;
executeNotebookCell(viewType: string, uri: URI, handle: number, useAttachedKernel: boolean, token: CancellationToken): Promise<void>;
executeNotebook2(viewType: string, uri: URI, kernelId: string, token: CancellationToken): Promise<void>;
executeNotebookCell2(viewType: string, uri: URI, handle: number, kernelId: string, token: CancellationToken): Promise<void>;
getContributedNotebookProviders(resource: URI): readonly NotebookProviderInfo[];
......
......@@ -15,6 +15,7 @@ import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/no
import { NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher';
import { TrackedRangeStickiness } from 'vs/editor/common/model';
import { reduceCellRanges, ICellRange } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { generateUuid } from 'vs/base/common/uuid';
suite('NotebookViewModel', () => {
const instantiationService = new TestInstantiationService();
......@@ -23,7 +24,7 @@ suite('NotebookViewModel', () => {
instantiationService.spy(IUndoRedoService, 'pushElement');
test('ctor', function () {
const notebook = new NotebookTextModel(0, 'notebook', URI.parse('test'));
const notebook = new NotebookTextModel(0, 'notebook', URI.parse('test'), generateUuid());
const model = new NotebookEditorTestModel(notebook);
const eventDispatcher = new NotebookEventDispatcher();
const viewModel = new NotebookViewModel('notebook', model.notebook, eventDispatcher, null, instantiationService, blukEditService, undoRedoService);
......
......@@ -22,6 +22,8 @@ import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/no
import { CellKind, CellUri, INotebookEditorModel, IOutput, NotebookCellMetadata, INotebookKernelInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { Webview } from 'vs/workbench/contrib/webview/browser/webview';
import { ICompositeCodeEditor, IEditor } from 'vs/editor/common/editorCommon';
import { generateUuid } from 'vs/base/common/uuid';
export class TestCell extends NotebookCellTextModel {
constructor(
public viewType: string,
......@@ -266,7 +268,7 @@ export class NotebookEditorTestModel extends EditorModel implements INotebookEdi
export function withTestNotebook(instantiationService: IInstantiationService, blukEditService: IBulkEditService, undoRedoService: IUndoRedoService, cells: [string[], string, CellKind, IOutput[], NotebookCellMetadata][], callback: (editor: TestNotebookEditor, viewModel: NotebookViewModel, textModel: NotebookTextModel) => void) {
const viewType = 'notebook';
const editor = new TestNotebookEditor();
const notebook = new NotebookTextModel(0, viewType, URI.parse('test'));
const notebook = new NotebookTextModel(0, viewType, URI.parse('test'), generateUuid());
notebook.cells = cells.map((cell, index) => {
return new NotebookCellTextModel(notebook.uri, index, cell[0], cell[1], cell[2], cell[3], cell[4]);
});
......
......@@ -44,7 +44,7 @@ suite('NotebookConcatDocument', function () {
});
extHostDocumentsAndEditors = new ExtHostDocumentsAndEditors(rpcProtocol, new NullLogService());
extHostDocuments = new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors);
extHostNotebooks = new ExtHostNotebookController(rpcProtocol, new ExtHostCommands(rpcProtocol, new NullLogService()), extHostDocumentsAndEditors);
extHostNotebooks = new ExtHostNotebookController(rpcProtocol, new ExtHostCommands(rpcProtocol, new NullLogService()), extHostDocumentsAndEditors, { isExtensionDevelopmentDebug: false, webviewCspSource: '', webviewResourceRoot: '' });
let reg = extHostNotebooks.registerNotebookContentProvider(nullExtensionDescription, 'test', new class extends mock<vscode.NotebookContentProvider>() {
// async openNotebook() { }
});
......@@ -52,7 +52,8 @@ suite('NotebookConcatDocument', function () {
addedDocuments: [{
handle: 0,
uri: notebookUri,
viewType: 'test'
viewType: 'test',
webviewId: 'testid'
}]
});
extHostNotebooks.$acceptModelChanged(notebookUri, {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册