Port most notebook model code over to be behind a service (#3068)

- Defines a new NotebookService in Azure Data Studio which will be used to interact with notebooks. Since notebooks can require per-file instantiation the provider is just used to create & track managers for a given URI.
- Inject this into notebook.component.ts and pass required parameters that'll be used to properly initialize a manger into the method. Actual initialization not done yet.
- Port over & recompile notebook model code
- Define most required APIs in sqlops.proposed.d.ts. In the future, these will be used by extensions to contribute their own providers.
This commit is contained in:
Kevin Cunnane
2018-10-31 22:01:40 -07:00
committed by GitHub
parent ac0ffab99c
commit fc3bf45a7f
29 changed files with 2973 additions and 53 deletions

View File

@@ -0,0 +1,76 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as sqlops from 'sqlops';
import * as vscode from 'vscode';
import { TPromise } from 'vs/base/common/winjs.base';
import { IMainContext } from 'vs/workbench/api/node/extHost.protocol';
import { Disposable } from 'vs/workbench/api/node/extHostTypes';
import { localize } from 'vs/nls';
import { ExtHostNotebookShape, MainThreadNotebookShape, SqlMainContext } from 'sql/workbench/api/node/sqlExtHost.protocol';
export class ExtHostNotebook implements ExtHostNotebookShape {
private static _handlePool: number = 0;
private readonly _proxy: MainThreadNotebookShape;
private _providers = new Map<number, sqlops.nb.NotebookProvider>();
constructor(private _mainContext: IMainContext) {
this._proxy = _mainContext.getProxy(SqlMainContext.MainThreadNotebook);
}
//#region APIs called by main thread
getNotebookManager(notebookUri: vscode.Uri): Thenable<number> {
throw new Error('Not implemented');
}
handleNotebookClosed(notebookUri: vscode.Uri): void {
throw new Error('Not implemented');
}
//#endregion
//#region APIs called by extensions
registerNotebookProvider(provider: sqlops.nb.NotebookProvider): vscode.Disposable {
if (!provider || !provider.providerId) {
throw new Error(localize('providerRequired', 'A NotebookProvider with valid providerId must be passed to this method'));
}
const handle = this._addNewProvider(provider);
this._proxy.$registerNotebookProvider(provider.providerId, handle);
return this._createDisposable(handle);
}
//#endregion
//#region private methods
private _createDisposable(handle: number): Disposable {
return new Disposable(() => {
this._providers.delete(handle);
this._proxy.$unregisterNotebookProvider(handle);
});
}
private _nextHandle(): number {
return ExtHostNotebook._handlePool++;
}
private _withProvider<A, R>(handle: number, ctor: { new(...args: any[]): A }, callback: (adapter: A) => TPromise<R>): TPromise<R> {
let provider = this._providers.get(handle);
if (!(provider instanceof ctor)) {
return TPromise.wrapError<R>(new Error('no adapter found'));
}
return callback(<any>provider);
}
private _addNewProvider(adapter: sqlops.nb.NotebookProvider): number {
const handle = this._nextHandle();
this._providers.set(handle, adapter);
return handle;
}
//#endregion
}

View File

@@ -0,0 +1,77 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as sqlops from 'sqlops';
import { SqlExtHostContext, SqlMainContext, ExtHostNotebookShape, MainThreadNotebookShape } from 'sql/workbench/api/node/sqlExtHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { Disposable } from 'vs/base/common/lifecycle';
import { IExtHostContext } from 'vs/workbench/api/node/extHost.protocol';
import { INotebookService, INotebookProvider, INotebookManager } from 'sql/services/notebook/notebookService';
import URI from 'vs/base/common/uri';
@extHostNamedCustomer(SqlMainContext.MainThreadNotebook)
export class MainThreadNotebook extends Disposable implements MainThreadNotebookShape {
private _proxy: ExtHostNotebookShape;
private _registrations: { [handle: number]: NotebookProviderWrapper } = Object.create(null);
constructor(
extHostContext: IExtHostContext,
@INotebookService private notebookService: INotebookService
) {
super();
if (extHostContext) {
this._proxy = extHostContext.getProxy(SqlExtHostContext.ExtHostNotebook);
}
}
//#region Extension host callable methods
public $registerNotebookProvider(providerId: string, handle: number): void {
let notebookProvider = new NotebookProviderWrapper(providerId, handle);
this._registrations[providerId] = notebookProvider;
this.notebookService.registerProvider(providerId, notebookProvider);
}
public $unregisterNotebookProvider(handle: number): void {
let registration = this._registrations[handle];
if (registration) {
this.notebookService.unregisterProvider(registration.providerId);
registration.dispose();
delete this._registrations[handle];
}
}
//#endregion
}
class NotebookProviderWrapper extends Disposable implements INotebookProvider {
constructor(public readonly providerId, public readonly handle: number) {
super();
}
getNotebookManager(notebookUri: URI): Thenable<INotebookManager> {
// TODO must call through to setup in the extension host
return Promise.resolve(new NotebookManagerWrapper(this.providerId));
}
handleNotebookClosed(notebookUri: URI): void {
// TODO implement call through to extension host
}
}
class NotebookManagerWrapper implements INotebookManager {
constructor(public readonly providerId) {
}
sessionManager: sqlops.nb.SessionManager;
contentManager: sqlops.nb.ContentManager;
serverManager: sqlops.nb.ServerManager;
}

View File

@@ -37,6 +37,7 @@ import { ExtHostModelViewDialog } from 'sql/workbench/api/node/extHostModelViewD
import { ExtHostModelViewTreeViews } from 'sql/workbench/api/node/extHostModelViewTree';
import { ExtHostQueryEditor } from 'sql/workbench/api/node/extHostQueryEditor';
import { ExtHostBackgroundTaskManagement } from './extHostBackgroundTaskManagement';
import { ExtHostNotebook } from 'sql/workbench/api/node/extHostNotebook';
export interface ISqlExtensionApiFactory {
vsCodeFactory(extension: IExtensionDescription): typeof vscode;
@@ -73,6 +74,7 @@ export function createApiFactory(
const extHostDashboard = rpcProtocol.set(SqlExtHostContext.ExtHostDashboard, new ExtHostDashboard(rpcProtocol));
const extHostModelViewDialog = rpcProtocol.set(SqlExtHostContext.ExtHostModelViewDialog, new ExtHostModelViewDialog(rpcProtocol, extHostModelView, extHostBackgroundTaskManagement));
const extHostQueryEditor = rpcProtocol.set(SqlExtHostContext.ExtHostQueryEditor, new ExtHostQueryEditor(rpcProtocol));
const extHostNotebook = rpcProtocol.set(SqlExtHostContext.ExtHostNotebook, new ExtHostNotebook(rpcProtocol));
return {
@@ -402,6 +404,12 @@ export function createApiFactory(
}
};
const nb = {
registerNotebookProvider(provider: sqlops.nb.NotebookProvider): vscode.Disposable {
return extHostNotebook.registerNotebookProvider(provider);
}
};
return {
accounts,
connection,
@@ -437,7 +445,8 @@ export function createApiFactory(
CardType: sqlExtHostTypes.CardType,
Orientation: sqlExtHostTypes.Orientation,
SqlThemeIcon: sqlExtHostTypes.SqlThemeIcon,
TreeComponentItem: sqlExtHostTypes.TreeComponentItem
TreeComponentItem: sqlExtHostTypes.TreeComponentItem,
nb: nb
};
}
};

View File

@@ -23,7 +23,8 @@ import 'sql/workbench/api/node/mainThreadDashboardWebview';
import 'sql/workbench/api/node/mainThreadQueryEditor';
import 'sql/workbench/api/node/mainThreadModelView';
import 'sql/workbench/api/node/mainThreadModelViewDialog';
import './mainThreadAccountManagement';
import 'sql/workbench/api/node/mainThreadNotebook';
import 'sql/workbench/api/node/mainThreadAccountManagement';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
export class SqlExtHostContribution implements IWorkbenchContribution {

View File

@@ -545,6 +545,7 @@ export const SqlMainContext = {
MainThreadDashboard: createMainId<MainThreadDashboardShape>('MainThreadDashboard'),
MainThreadModelViewDialog: createMainId<MainThreadModelViewDialogShape>('MainThreadModelViewDialog'),
MainThreadQueryEditor: createMainId<MainThreadQueryEditorShape>('MainThreadQueryEditor'),
MainThreadNotebook: createMainId<MainThreadNotebookShape>('MainThreadNotebook')
};
export const SqlExtHostContext = {
@@ -563,7 +564,8 @@ export const SqlExtHostContext = {
ExtHostModelViewTreeViews: createExtId<ExtHostModelViewTreeViewsShape>('ExtHostModelViewTreeViews'),
ExtHostDashboard: createExtId<ExtHostDashboardShape>('ExtHostDashboard'),
ExtHostModelViewDialog: createExtId<ExtHostModelViewDialogShape>('ExtHostModelViewDialog'),
ExtHostQueryEditor: createExtId<ExtHostQueryEditorShape>('ExtHostQueryEditor')
ExtHostQueryEditor: createExtId<ExtHostQueryEditorShape>('ExtHostQueryEditor'),
ExtHostNotebook: createExtId<ExtHostNotebookShape>('ExtHostNotebook')
};
export interface MainThreadDashboardShape extends IDisposable {
@@ -703,4 +705,21 @@ export interface ExtHostQueryEditorShape {
export interface MainThreadQueryEditorShape extends IDisposable {
$connect(fileUri: string, connectionId: string): Thenable<void>;
$runQuery(fileUri: string): void;
}
export interface ExtHostNotebookShape {
/**
* Looks up a notebook manager for a given notebook URI
* @param {vscode.Uri} notebookUri
* @returns {Thenable<string>} handle of the manager to be used when sending
*/
getNotebookManager(notebookUri: vscode.Uri): Thenable<number>;
handleNotebookClosed(notebookUri: vscode.Uri): void;
}
export interface MainThreadNotebookShape extends IDisposable {
$registerNotebookProvider(providerId: string, handle: number): void;
$unregisterNotebookProvider(handle: number): void;
}