Archived
Split up NotebookProvider into separate providers for handling file serialization and cell execution. (#17176)
This commit is contained in:
@@ -7,14 +7,14 @@ import { nb } from 'azdata';
|
|||||||
|
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { charCountToJsCountDiff, jsIndexToCharIndex } from './text';
|
import { charCountToJsCountDiff, jsIndexToCharIndex } from './text';
|
||||||
import { JupyterNotebookProvider } from '../jupyter/jupyterNotebookProvider';
|
import { JupyterExecuteProvider } from '../jupyter/jupyterExecuteProvider';
|
||||||
import { JupyterSessionManager } from '../jupyter/jupyterSessionManager';
|
import { JupyterSessionManager } from '../jupyter/jupyterSessionManager';
|
||||||
|
|
||||||
const timeoutMilliseconds = 3000;
|
const timeoutMilliseconds = 3000;
|
||||||
|
|
||||||
export class NotebookCompletionItemProvider implements vscode.CompletionItemProvider {
|
export class NotebookCompletionItemProvider implements vscode.CompletionItemProvider {
|
||||||
|
|
||||||
constructor(private _notebookProvider: JupyterNotebookProvider) {
|
constructor(private _notebookProvider: JupyterExecuteProvider) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext)
|
public provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext)
|
||||||
@@ -45,9 +45,9 @@ export class NotebookCompletionItemProvider implements vscode.CompletionItemProv
|
|||||||
|
|
||||||
private async tryFindKernelForDocument(document: vscode.TextDocument, info: INewIntellisenseInfo): Promise<nb.IKernel> {
|
private async tryFindKernelForDocument(document: vscode.TextDocument, info: INewIntellisenseInfo): Promise<nb.IKernel> {
|
||||||
try {
|
try {
|
||||||
let notebookManager = await this._notebookProvider.getNotebookManager(document.uri);
|
let executeManager = await this._notebookProvider.getExecuteManager(document.uri);
|
||||||
if (notebookManager) {
|
if (executeManager) {
|
||||||
let sessionManager: JupyterSessionManager = <JupyterSessionManager>(notebookManager.sessionManager);
|
let sessionManager: JupyterSessionManager = <JupyterSessionManager>(executeManager.sessionManager);
|
||||||
let sessions = sessionManager.listRunning();
|
let sessions = sessionManager.listRunning();
|
||||||
if (sessions && sessions.length > 0) {
|
if (sessions && sessions.length > 0) {
|
||||||
let session = sessions.find(session => session.path === info.notebook.uri.path);
|
let session = sessions.find(session => session.path === info.notebook.uri.path);
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import { IPrompter, IQuestion, QuestionTypes } from '../prompts/question';
|
|||||||
import { AppContext } from '../common/appContext';
|
import { AppContext } from '../common/appContext';
|
||||||
import { LocalJupyterServerManager, ServerInstanceFactory } from './jupyterServerManager';
|
import { LocalJupyterServerManager, ServerInstanceFactory } from './jupyterServerManager';
|
||||||
import { NotebookCompletionItemProvider } from '../intellisense/completionItemProvider';
|
import { NotebookCompletionItemProvider } from '../intellisense/completionItemProvider';
|
||||||
import { JupyterNotebookProvider } from './jupyterNotebookProvider';
|
|
||||||
import { ConfigurePythonWizard } from '../dialog/configurePython/configurePythonWizard';
|
import { ConfigurePythonWizard } from '../dialog/configurePython/configurePythonWizard';
|
||||||
import CodeAdapter from '../prompts/adapter';
|
import CodeAdapter from '../prompts/adapter';
|
||||||
import { ManagePackagesDialog } from '../dialog/managePackages/managePackagesDialog';
|
import { ManagePackagesDialog } from '../dialog/managePackages/managePackagesDialog';
|
||||||
@@ -28,6 +27,7 @@ import { LocalPipPackageManageProvider } from './localPipPackageManageProvider';
|
|||||||
import { LocalCondaPackageManageProvider } from './localCondaPackageManageProvider';
|
import { LocalCondaPackageManageProvider } from './localCondaPackageManageProvider';
|
||||||
import { ManagePackagesDialogModel, ManagePackageDialogOptions } from '../dialog/managePackages/managePackagesDialogModel';
|
import { ManagePackagesDialogModel, ManagePackageDialogOptions } from '../dialog/managePackages/managePackagesDialogModel';
|
||||||
import { PyPiClient } from './pypiClient';
|
import { PyPiClient } from './pypiClient';
|
||||||
|
import { JupyterExecuteProvider } from './jupyterExecuteProvider';
|
||||||
|
|
||||||
let untitledCounter = 0;
|
let untitledCounter = 0;
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ export class JupyterController {
|
|||||||
private _packageManageProviders = new Map<string, IPackageManageProvider>();
|
private _packageManageProviders = new Map<string, IPackageManageProvider>();
|
||||||
|
|
||||||
private prompter: IPrompter;
|
private prompter: IPrompter;
|
||||||
private _notebookProvider: JupyterNotebookProvider;
|
private _executeProvider: JupyterExecuteProvider;
|
||||||
|
|
||||||
constructor(private appContext: AppContext) {
|
constructor(private appContext: AppContext) {
|
||||||
this.prompter = new CodeAdapter();
|
this.prompter = new CodeAdapter();
|
||||||
@@ -47,8 +47,8 @@ export class JupyterController {
|
|||||||
return this.appContext && this.appContext.extensionContext;
|
return this.appContext && this.appContext.extensionContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get notebookProvider(): JupyterNotebookProvider {
|
public get executeProvider(): JupyterExecuteProvider {
|
||||||
return this._notebookProvider;
|
return this._executeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PUBLIC METHODS //////////////////////////////////////////////////////
|
// PUBLIC METHODS //////////////////////////////////////////////////////
|
||||||
@@ -79,21 +79,19 @@ export class JupyterController {
|
|||||||
let supportedFileFilter: vscode.DocumentFilter[] = [
|
let supportedFileFilter: vscode.DocumentFilter[] = [
|
||||||
{ scheme: 'untitled', language: '*' }
|
{ scheme: 'untitled', language: '*' }
|
||||||
];
|
];
|
||||||
this.registerNotebookProvider();
|
|
||||||
this.extensionContext.subscriptions.push(vscode.languages.registerCompletionItemProvider(supportedFileFilter, new NotebookCompletionItemProvider(this._notebookProvider), '.'));
|
|
||||||
|
|
||||||
this.registerDefaultPackageManageProviders();
|
this._executeProvider = new JupyterExecuteProvider((documentUri: vscode.Uri) => new LocalJupyterServerManager({
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private registerNotebookProvider(): void {
|
|
||||||
this._notebookProvider = new JupyterNotebookProvider((documentUri: vscode.Uri) => new LocalJupyterServerManager({
|
|
||||||
documentPath: documentUri.fsPath,
|
documentPath: documentUri.fsPath,
|
||||||
jupyterInstallation: this._jupyterInstallation,
|
jupyterInstallation: this._jupyterInstallation,
|
||||||
extensionContext: this.extensionContext,
|
extensionContext: this.extensionContext,
|
||||||
factory: this._serverInstanceFactory
|
factory: this._serverInstanceFactory
|
||||||
}));
|
}));
|
||||||
azdata.nb.registerNotebookProvider(this._notebookProvider);
|
azdata.nb.registerExecuteProvider(this._executeProvider);
|
||||||
|
|
||||||
|
this.extensionContext.subscriptions.push(vscode.languages.registerCompletionItemProvider(supportedFileFilter, new NotebookCompletionItemProvider(this._executeProvider), '.'));
|
||||||
|
|
||||||
|
this.registerDefaultPackageManageProviders();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private saveProfileAndCreateNotebook(profile: azdata.IConnectionProfile): Promise<void> {
|
private saveProfileAndCreateNotebook(profile: azdata.IConnectionProfile): Promise<void> {
|
||||||
|
|||||||
+1
-4
@@ -10,7 +10,7 @@ import { ServerConnection, SessionManager } from '@jupyterlab/services';
|
|||||||
import { JupyterSessionManager } from './jupyterSessionManager';
|
import { JupyterSessionManager } from './jupyterSessionManager';
|
||||||
import { LocalJupyterServerManager } from './jupyterServerManager';
|
import { LocalJupyterServerManager } from './jupyterServerManager';
|
||||||
|
|
||||||
export class JupyterNotebookManager implements nb.NotebookManager, vscode.Disposable {
|
export class JupyterExecuteManager implements nb.ExecuteManager, vscode.Disposable {
|
||||||
protected _serverSettings: ServerConnection.ISettings;
|
protected _serverSettings: ServerConnection.ISettings;
|
||||||
private _sessionManager: JupyterSessionManager;
|
private _sessionManager: JupyterSessionManager;
|
||||||
|
|
||||||
@@ -21,9 +21,6 @@ export class JupyterNotebookManager implements nb.NotebookManager, vscode.Dispos
|
|||||||
this._sessionManager.installation = this._serverManager.instanceOptions.install;
|
this._sessionManager.installation = this._serverManager.instanceOptions.install;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public get contentManager(): nb.ContentManager {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get sessionManager(): nb.SessionManager {
|
public get sessionManager(): nb.SessionManager {
|
||||||
return this._sessionManager;
|
return this._sessionManager;
|
||||||
+13
-17
@@ -11,41 +11,41 @@ const localize = nls.loadMessageBundle();
|
|||||||
|
|
||||||
import * as constants from '../common/constants';
|
import * as constants from '../common/constants';
|
||||||
import * as utils from '../common/utils';
|
import * as utils from '../common/utils';
|
||||||
import { JupyterNotebookManager } from './jupyterNotebookManager';
|
import { JupyterExecuteManager } from './jupyterExecuteManager';
|
||||||
import { LocalJupyterServerManager } from './jupyterServerManager';
|
import { LocalJupyterServerManager } from './jupyterServerManager';
|
||||||
import { JupyterSessionManager } from './jupyterSessionManager';
|
import { JupyterSessionManager } from './jupyterSessionManager';
|
||||||
|
|
||||||
export type ServerManagerFactory = (documentUri: vscode.Uri) => LocalJupyterServerManager;
|
export type ServerManagerFactory = (documentUri: vscode.Uri) => LocalJupyterServerManager;
|
||||||
|
|
||||||
export class JupyterNotebookProvider implements nb.NotebookProvider {
|
export class JupyterExecuteProvider implements nb.NotebookExecuteProvider {
|
||||||
readonly providerId: string = constants.jupyterNotebookProviderId;
|
readonly providerId: string = constants.jupyterNotebookProviderId;
|
||||||
private managerTracker = new Map<string, JupyterNotebookManager>();
|
private executeManagerTracker = new Map<string, JupyterExecuteManager>();
|
||||||
|
|
||||||
constructor(private createServerManager: ServerManagerFactory) {
|
constructor(private createServerManager: ServerManagerFactory) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public getNotebookManager(notebookUri: vscode.Uri): Thenable<nb.NotebookManager> {
|
public getExecuteManager(notebookUri: vscode.Uri): Thenable<nb.ExecuteManager> {
|
||||||
if (!notebookUri) {
|
if (!notebookUri) {
|
||||||
return Promise.reject(localize('errNotebookUriMissing', "A notebook path is required"));
|
return Promise.reject(localize('errNotebookUriMissing', "A notebook path is required"));
|
||||||
}
|
}
|
||||||
return Promise.resolve(this.doGetNotebookManager(notebookUri));
|
return Promise.resolve(this.doGetExecuteManager(notebookUri));
|
||||||
}
|
}
|
||||||
|
|
||||||
public get notebookManagerCount(): number {
|
public get executeManagerCount(): number {
|
||||||
return this.managerTracker.size;
|
return this.executeManagerTracker.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
private doGetNotebookManager(notebookUri: vscode.Uri): nb.NotebookManager {
|
private doGetExecuteManager(notebookUri: vscode.Uri): nb.ExecuteManager {
|
||||||
let baseFolder = this.transformToBaseFolder(notebookUri?.fsPath?.toString());
|
let baseFolder = this.transformToBaseFolder(notebookUri?.fsPath?.toString());
|
||||||
let manager = this.managerTracker.get(baseFolder);
|
let manager = this.executeManagerTracker.get(baseFolder);
|
||||||
if (!manager) {
|
if (!manager) {
|
||||||
let baseFolderUri = vscode.Uri.file(baseFolder);
|
let baseFolderUri = vscode.Uri.file(baseFolder);
|
||||||
if (!baseFolderUri) {
|
if (!baseFolderUri) {
|
||||||
baseFolderUri = notebookUri;
|
baseFolderUri = notebookUri;
|
||||||
}
|
}
|
||||||
let serverManager = this.createServerManager(baseFolderUri);
|
let serverManager = this.createServerManager(baseFolderUri);
|
||||||
manager = new JupyterNotebookManager(serverManager);
|
manager = new JupyterExecuteManager(serverManager);
|
||||||
this.managerTracker.set(baseFolder, manager);
|
this.executeManagerTracker.set(baseFolder, manager);
|
||||||
}
|
}
|
||||||
return manager;
|
return manager;
|
||||||
}
|
}
|
||||||
@@ -56,7 +56,7 @@ export class JupyterNotebookProvider implements nb.NotebookProvider {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let baseFolder = this.transformToBaseFolder(notebookUri.fsPath.toString());
|
let baseFolder = this.transformToBaseFolder(notebookUri.fsPath.toString());
|
||||||
let manager = this.managerTracker.get(baseFolder);
|
let manager = this.executeManagerTracker.get(baseFolder);
|
||||||
if (manager) {
|
if (manager) {
|
||||||
let sessionManager = (manager.sessionManager as JupyterSessionManager);
|
let sessionManager = (manager.sessionManager as JupyterSessionManager);
|
||||||
let session = sessionManager.listRunning().find(e => e.path === notebookUri.fsPath);
|
let session = sessionManager.listRunning().find(e => e.path === notebookUri.fsPath);
|
||||||
@@ -70,7 +70,7 @@ export class JupyterNotebookProvider implements nb.NotebookProvider {
|
|||||||
const timeoutInMs = timeoutInMinutes * 60 * 1000;
|
const timeoutInMs = timeoutInMinutes * 60 * 1000;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (sessionManager.listRunning().length === 0) {
|
if (sessionManager.listRunning().length === 0) {
|
||||||
this.managerTracker.delete(baseFolder);
|
this.executeManagerTracker.delete(baseFolder);
|
||||||
manager.dispose();
|
manager.dispose();
|
||||||
}
|
}
|
||||||
}, timeoutInMs);
|
}, timeoutInMs);
|
||||||
@@ -79,10 +79,6 @@ export class JupyterNotebookProvider implements nb.NotebookProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public get standardKernels(): nb.IStandardKernel[] {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
private transformToBaseFolder(notebookPath: string): string {
|
private transformToBaseFolder(notebookPath: string): string {
|
||||||
let parsedPath = path.parse(notebookPath);
|
let parsedPath = path.parse(notebookPath);
|
||||||
let userHome = utils.getUserHome();
|
let userHome = utils.getUserHome();
|
||||||
@@ -58,7 +58,7 @@ const configBase = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export class JupyterSessionManager implements nb.SessionManager {
|
export class JupyterSessionManager implements nb.SessionManager, vscode.Disposable {
|
||||||
private _ready: Deferred<void>;
|
private _ready: Deferred<void>;
|
||||||
private _isReady: boolean;
|
private _isReady: boolean;
|
||||||
private _sessionManager: Session.IManager;
|
private _sessionManager: Session.IManager;
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
import { nb } from 'azdata';
|
|
||||||
import * as vscode from 'vscode';
|
|
||||||
import { Contents } from '@jupyterlab/services';
|
|
||||||
|
|
||||||
export class RemoteContentManager implements nb.ContentManager {
|
|
||||||
|
|
||||||
constructor(private contents: Contents.IManager) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public getNotebookContents(notebookUri: vscode.Uri): Thenable<nb.INotebookContents> {
|
|
||||||
return this.getNotebookContentsAsync(notebookUri.fsPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getNotebookContentsAsync(path: string): Promise<nb.INotebookContents> {
|
|
||||||
if (!path) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
// Note: intentionally letting caller handle exceptions
|
|
||||||
let contentsModel = await this.contents.get(path);
|
|
||||||
if (!contentsModel) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return <nb.INotebookContents>contentsModel.content;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async save(notebookUri: vscode.Uri, notebook: nb.INotebookContents): Promise<nb.INotebookContents> {
|
|
||||||
let path = notebookUri.fsPath;
|
|
||||||
await this.contents.save(path, {
|
|
||||||
path: path,
|
|
||||||
content: notebook,
|
|
||||||
type: 'notebook',
|
|
||||||
format: 'json'
|
|
||||||
});
|
|
||||||
return notebook;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -9,19 +9,19 @@ import * as vscode from 'vscode';
|
|||||||
import * as TypeMoq from 'typemoq';
|
import * as TypeMoq from 'typemoq';
|
||||||
|
|
||||||
import { NotebookCompletionItemProvider } from '../../intellisense/completionItemProvider';
|
import { NotebookCompletionItemProvider } from '../../intellisense/completionItemProvider';
|
||||||
import { JupyterNotebookProvider } from '../../jupyter/jupyterNotebookProvider';
|
|
||||||
import { NotebookUtils } from '../../common/notebookUtils';
|
import { NotebookUtils } from '../../common/notebookUtils';
|
||||||
import { JupyterNotebookManager } from '../../jupyter/jupyterNotebookManager';
|
import { JupyterExecuteManager } from '../../jupyter/jupyterExecuteManager';
|
||||||
import { JupyterSessionManager, JupyterSession } from '../../jupyter/jupyterSessionManager';
|
import { JupyterSessionManager, JupyterSession } from '../../jupyter/jupyterSessionManager';
|
||||||
import { LocalJupyterServerManager } from '../../jupyter/jupyterServerManager';
|
import { LocalJupyterServerManager } from '../../jupyter/jupyterServerManager';
|
||||||
import { TestKernel } from '../common';
|
import { TestKernel } from '../common';
|
||||||
import { sleep } from '../common/testUtils';
|
import { sleep } from '../common/testUtils';
|
||||||
|
import { JupyterExecuteProvider } from '../../jupyter/jupyterExecuteProvider';
|
||||||
|
|
||||||
describe('Completion Item Provider', function () {
|
describe('Completion Item Provider', function () {
|
||||||
let completionItemProvider: NotebookCompletionItemProvider;
|
let completionItemProvider: NotebookCompletionItemProvider;
|
||||||
let notebookProviderMock: TypeMoq.IMock<JupyterNotebookProvider>;
|
let executeProviderMock: TypeMoq.IMock<JupyterExecuteProvider>;
|
||||||
let notebookUtils: NotebookUtils;
|
let notebookUtils: NotebookUtils;
|
||||||
let notebookManager: JupyterNotebookManager;
|
let notebookManager: JupyterExecuteManager;
|
||||||
let mockSessionManager: TypeMoq.IMock<JupyterSessionManager>;
|
let mockSessionManager: TypeMoq.IMock<JupyterSessionManager>;
|
||||||
let mockServerManager: TypeMoq.IMock<LocalJupyterServerManager>;
|
let mockServerManager: TypeMoq.IMock<LocalJupyterServerManager>;
|
||||||
let mockJupyterSession: TypeMoq.IMock<JupyterSession>;
|
let mockJupyterSession: TypeMoq.IMock<JupyterSession>;
|
||||||
@@ -45,10 +45,10 @@ describe('Completion Item Provider', function () {
|
|||||||
mockSessionManager = TypeMoq.Mock.ofType<JupyterSessionManager>();
|
mockSessionManager = TypeMoq.Mock.ofType<JupyterSessionManager>();
|
||||||
mockJupyterSession = TypeMoq.Mock.ofType<JupyterSession>();
|
mockJupyterSession = TypeMoq.Mock.ofType<JupyterSession>();
|
||||||
kernel = new TestKernel(true, true);
|
kernel = new TestKernel(true, true);
|
||||||
notebookManager = new JupyterNotebookManager(mockServerManager.object, mockSessionManager.object);
|
notebookManager = new JupyterExecuteManager(mockServerManager.object, mockSessionManager.object);
|
||||||
notebookProviderMock = TypeMoq.Mock.ofType<JupyterNotebookProvider>();
|
executeProviderMock = TypeMoq.Mock.ofType<JupyterExecuteProvider>();
|
||||||
notebookProviderMock.setup(n => n.getNotebookManager(TypeMoq.It.isAny())).returns(() => Promise.resolve(notebookManager));
|
executeProviderMock.setup(n => n.getExecuteManager(TypeMoq.It.isAny())).returns(() => Promise.resolve(notebookManager));
|
||||||
completionItemProvider = new NotebookCompletionItemProvider(notebookProviderMock.object);
|
completionItemProvider = new NotebookCompletionItemProvider(executeProviderMock.object);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not return items when undefined passed in for every parameter', async () => {
|
it('should not return items when undefined passed in for every parameter', async () => {
|
||||||
|
|||||||
@@ -1,94 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
import * as vscode from 'vscode';
|
|
||||||
import * as should from 'should';
|
|
||||||
import * as TypeMoq from 'typemoq';
|
|
||||||
import * as path from 'path';
|
|
||||||
import { ContentsManager, Contents } from '@jupyterlab/services';
|
|
||||||
import { nb } from 'azdata';
|
|
||||||
import 'mocha';
|
|
||||||
|
|
||||||
import { INotebook, CellTypes } from '../../contracts/content';
|
|
||||||
import { RemoteContentManager } from '../../jupyter/remoteContentManager';
|
|
||||||
import * as testUtils from '../common/testUtils';
|
|
||||||
|
|
||||||
let expectedNotebookContent: INotebook = {
|
|
||||||
cells: [{
|
|
||||||
cell_type: CellTypes.Code,
|
|
||||||
source: 'insert into t1 values (c1, c2)',
|
|
||||||
metadata: { language: 'python' },
|
|
||||||
execution_count: 1
|
|
||||||
}],
|
|
||||||
metadata: {
|
|
||||||
kernelspec: {
|
|
||||||
name: 'mssql',
|
|
||||||
language: 'sql'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
nbformat: 5,
|
|
||||||
nbformat_minor: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
function verifyMatchesExpectedNotebook(notebook: nb.INotebookContents): void {
|
|
||||||
should(notebook.cells).have.length(1, 'Expected 1 cell');
|
|
||||||
should(notebook.cells[0].cell_type).equal(CellTypes.Code);
|
|
||||||
should(notebook.cells[0].source).equal(expectedNotebookContent.cells[0].source);
|
|
||||||
should(notebook.metadata.kernelspec.name).equal(expectedNotebookContent.metadata.kernelspec.name);
|
|
||||||
should(notebook.nbformat).equal(expectedNotebookContent.nbformat);
|
|
||||||
should(notebook.nbformat_minor).equal(expectedNotebookContent.nbformat_minor);
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('Remote Content Manager', function (): void {
|
|
||||||
let mockJupyterManager = TypeMoq.Mock.ofType(ContentsManager);
|
|
||||||
let contentManager = new RemoteContentManager(mockJupyterManager.object);
|
|
||||||
|
|
||||||
// TODO re-enable when we bring in usage of remote content managers / binders
|
|
||||||
// it('Should return undefined if path is undefined', async function(): Promise<void> {
|
|
||||||
// let content = await contentManager.getNotebookContents(undefined);
|
|
||||||
// should(content).be.undefined();
|
|
||||||
// // tslint:disable-next-line:no-null-keyword
|
|
||||||
// content = await contentManager.getNotebookContents(null);
|
|
||||||
// should(content).be.undefined();
|
|
||||||
// content = await contentManager.getNotebookContents(vscode.Uri.file(''));
|
|
||||||
// should(content).be.undefined();
|
|
||||||
// });
|
|
||||||
|
|
||||||
it('Should throw if API call throws', async function (): Promise<void> {
|
|
||||||
let exception = new Error('Path was wrong');
|
|
||||||
mockJupyterManager.setup(c => c.get(TypeMoq.It.isAny(), TypeMoq.It.isAny())).throws(exception);
|
|
||||||
await testUtils.assertThrowsAsync(async () => await contentManager.getNotebookContents(vscode.Uri.file('/path/doesnot/exist.ipynb')), undefined);
|
|
||||||
});
|
|
||||||
it('Should return notebook contents parsed as INotebook when valid notebook file parsed', async function (): Promise<void> {
|
|
||||||
// Given a valid request to the notebook server
|
|
||||||
let remotePath = '/remote/path/that/exists.ipynb';
|
|
||||||
let contentsModel: Contents.IModel = {
|
|
||||||
name: path.basename(remotePath),
|
|
||||||
content: expectedNotebookContent,
|
|
||||||
path: remotePath,
|
|
||||||
type: 'notebook',
|
|
||||||
writable: false,
|
|
||||||
created: undefined,
|
|
||||||
last_modified: undefined,
|
|
||||||
mimetype: 'json',
|
|
||||||
format: 'json'
|
|
||||||
};
|
|
||||||
mockJupyterManager.setup(c => c.get(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(contentsModel));
|
|
||||||
// when I read the content
|
|
||||||
let notebook = await contentManager.getNotebookContents(vscode.Uri.file(remotePath));
|
|
||||||
// then I expect notebook format to match
|
|
||||||
verifyMatchesExpectedNotebook(notebook);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should return undefined if service does not return anything', async function (): Promise<void> {
|
|
||||||
// Given a valid request to the notebook server
|
|
||||||
let remotePath = '/remote/path/that/does/not/exist.ipynb';
|
|
||||||
mockJupyterManager.setup(c => c.get(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(undefined));
|
|
||||||
// when I read the content
|
|
||||||
let notebook = await contentManager.getNotebookContents(vscode.Uri.file(remotePath));
|
|
||||||
// then I expect notebook format to match
|
|
||||||
should(notebook).be.undefined();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
+11
-22
@@ -14,10 +14,10 @@ import { JupyterServerInstallation } from '../../jupyter/jupyterServerInstallati
|
|||||||
import { Deferred } from '../../common/promise';
|
import { Deferred } from '../../common/promise';
|
||||||
import { MockExtensionContext } from '../common/stubs';
|
import { MockExtensionContext } from '../common/stubs';
|
||||||
import { JupyterSessionManager } from '../../jupyter/jupyterSessionManager';
|
import { JupyterSessionManager } from '../../jupyter/jupyterSessionManager';
|
||||||
import { JupyterNotebookManager } from '../../jupyter/jupyterNotebookManager';
|
import { JupyterExecuteManager } from '../../jupyter/jupyterExecuteManager';
|
||||||
import { initInstallAndInstance } from './serverManager.test';
|
import { initInstallAndInstance } from './serverManager.test';
|
||||||
|
|
||||||
describe('Jupyter Notebook Manager', function (): void {
|
describe('Jupyter Execute Manager', function (): void {
|
||||||
const pythonKernelSpec: azdata.nb.IKernelSpec = {
|
const pythonKernelSpec: azdata.nb.IKernelSpec = {
|
||||||
name: 'python3',
|
name: 'python3',
|
||||||
display_name: 'Python 3'
|
display_name: 'Python 3'
|
||||||
@@ -25,7 +25,7 @@ describe('Jupyter Notebook Manager', function (): void {
|
|||||||
let expectedPath = 'my/notebook.ipynb';
|
let expectedPath = 'my/notebook.ipynb';
|
||||||
let serverManager: LocalJupyterServerManager;
|
let serverManager: LocalJupyterServerManager;
|
||||||
let sessionManager: JupyterSessionManager;
|
let sessionManager: JupyterSessionManager;
|
||||||
let notebookManager: JupyterNotebookManager;
|
let executeManager: JupyterExecuteManager;
|
||||||
let deferredInstall: Deferred<void>;
|
let deferredInstall: Deferred<void>;
|
||||||
let mockExtensionContext: MockExtensionContext;
|
let mockExtensionContext: MockExtensionContext;
|
||||||
let mockFactory: TypeMoq.IMock<ServerInstanceFactory>;
|
let mockFactory: TypeMoq.IMock<ServerInstanceFactory>;
|
||||||
@@ -48,48 +48,37 @@ describe('Jupyter Notebook Manager', function (): void {
|
|||||||
serverManager = new LocalJupyterServerManager(serverManagerOptions);
|
serverManager = new LocalJupyterServerManager(serverManagerOptions);
|
||||||
|
|
||||||
sessionManager = new JupyterSessionManager();
|
sessionManager = new JupyterSessionManager();
|
||||||
notebookManager = new JupyterNotebookManager(serverManager, sessionManager);
|
executeManager = new JupyterExecuteManager(serverManager, sessionManager);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Server settings should be set', async function (): Promise<void> {
|
it('Server settings should be set', async function (): Promise<void> {
|
||||||
should(notebookManager.serverSettings).be.undefined();
|
should(executeManager.serverSettings).be.undefined();
|
||||||
let expectedUri = vscode.Uri.parse('http://localhost:1234?token=abcdefghijk');
|
let expectedUri = vscode.Uri.parse('http://localhost:1234?token=abcdefghijk');
|
||||||
initInstallAndInstance(expectedUri, mockFactory);
|
initInstallAndInstance(expectedUri, mockFactory);
|
||||||
deferredInstall.resolve();
|
deferredInstall.resolve();
|
||||||
|
|
||||||
// When I start the server
|
// When I start the server
|
||||||
await serverManager.startServer(pythonKernelSpec);
|
await serverManager.startServer(pythonKernelSpec);
|
||||||
should(notebookManager.serverSettings.baseUrl).equal('http://localhost:1234', 'Server settings did not match expected value');
|
should(executeManager.serverSettings.baseUrl).equal('http://localhost:1234', 'Server settings did not match expected value');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Session Manager should exist', async function (): Promise<void> {
|
it('Session Manager should exist', async function (): Promise<void> {
|
||||||
should(notebookManager.sessionManager).deepEqual(sessionManager);
|
should(executeManager.sessionManager).deepEqual(sessionManager);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Server Manager should exist', async function (): Promise<void> {
|
it('Server Manager should exist', async function (): Promise<void> {
|
||||||
should(notebookManager.serverManager).deepEqual(serverManager);
|
should(executeManager.serverManager).deepEqual(serverManager);
|
||||||
});
|
|
||||||
|
|
||||||
it('Content manager should always be undefined', async function (): Promise<void> {
|
|
||||||
should(notebookManager.contentManager).be.undefined();
|
|
||||||
let expectedUri = vscode.Uri.parse('http://localhost:1234?token=abcdefghijk');
|
|
||||||
initInstallAndInstance(expectedUri, mockFactory);
|
|
||||||
deferredInstall.resolve();
|
|
||||||
|
|
||||||
// When I start the server
|
|
||||||
await serverManager.startServer(pythonKernelSpec);
|
|
||||||
should(notebookManager.contentManager).be.undefined();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Session and server managers should be shutdown/stopped on dispose', async function(): Promise<void> {
|
it('Session and server managers should be shutdown/stopped on dispose', async function(): Promise<void> {
|
||||||
let sessionManager = TypeMoq.Mock.ofType<JupyterSessionManager>();
|
let sessionManager = TypeMoq.Mock.ofType<JupyterSessionManager>();
|
||||||
let serverManager = TypeMoq.Mock.ofType<LocalJupyterServerManager>();
|
let serverManager = TypeMoq.Mock.ofType<LocalJupyterServerManager>();
|
||||||
notebookManager = new JupyterNotebookManager(serverManager.object, sessionManager.object);
|
executeManager = new JupyterExecuteManager(serverManager.object, sessionManager.object);
|
||||||
sessionManager.setup(s => s.shutdownAll()).returns(() => new Promise((resolve) => resolve()));
|
sessionManager.setup(s => s.shutdownAll()).returns(() => new Promise((resolve) => resolve()));
|
||||||
serverManager.setup(s => s.stopServer()).returns(() => new Promise((resolve) => resolve()));
|
serverManager.setup(s => s.stopServer()).returns(() => new Promise((resolve) => resolve()));
|
||||||
|
|
||||||
// After I dispose the notebook manager
|
// After I dispose the execute manager
|
||||||
notebookManager.dispose();
|
executeManager.dispose();
|
||||||
|
|
||||||
// Session and server managers should be shutdown/stopped
|
// Session and server managers should be shutdown/stopped
|
||||||
sessionManager.verify((s) => s.shutdownAll(), TypeMoq.Times.once());
|
sessionManager.verify((s) => s.shutdownAll(), TypeMoq.Times.once());
|
||||||
@@ -76,24 +76,23 @@ describe('Jupyter Controller', function () {
|
|||||||
|
|
||||||
it('Returns expected values from notebook provider', async () => {
|
it('Returns expected values from notebook provider', async () => {
|
||||||
await controller.activate();
|
await controller.activate();
|
||||||
should(controller.notebookProvider.standardKernels).deepEqual([], 'Notebook provider standard kernels should return empty array');
|
should(controller.executeProvider.providerId).equal('jupyter', 'Notebook provider should be jupyter');
|
||||||
should(controller.notebookProvider.providerId).equal('jupyter', 'Notebook provider should be jupyter');
|
await should(controller.executeProvider.getExecuteManager(undefined)).be.rejected();
|
||||||
await should(controller.notebookProvider.getNotebookManager(undefined)).be.rejected();
|
should(controller.executeProvider.executeManagerCount).equal(0);
|
||||||
should(controller.notebookProvider.notebookManagerCount).equal(0);
|
controller.executeProvider.handleNotebookClosed(undefined);
|
||||||
controller.notebookProvider.handleNotebookClosed(undefined);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Returns notebook manager for real notebook editor', async () => {
|
it('Returns execute manager for real notebook editor', async () => {
|
||||||
await controller.activate();
|
await controller.activate();
|
||||||
let notebookUtils = new NotebookUtils();
|
let notebookUtils = new NotebookUtils();
|
||||||
const notebookEditor = await notebookUtils.newNotebook(undefined);
|
const notebookEditor = await notebookUtils.newNotebook(undefined);
|
||||||
let notebookManager = await controller.notebookProvider.getNotebookManager(notebookEditor.document.uri);
|
let notebookManager = await controller.executeProvider.getExecuteManager(notebookEditor.document.uri);
|
||||||
should(controller.notebookProvider.notebookManagerCount).equal(1);
|
should(controller.executeProvider.executeManagerCount).equal(1);
|
||||||
|
|
||||||
// Session manager should not be immediately ready
|
// Session manager should not be immediately ready
|
||||||
should(notebookManager.sessionManager.isReady).equal(false);
|
should(notebookManager.sessionManager.isReady).equal(false);
|
||||||
// Session manager should not immediately have specs
|
// Session manager should not immediately have specs
|
||||||
should(notebookManager.sessionManager.specs).equal(undefined);
|
should(notebookManager.sessionManager.specs).equal(undefined);
|
||||||
controller.notebookProvider.handleNotebookClosed(notebookEditor.document.uri);
|
controller.executeProvider.handleNotebookClosed(notebookEditor.document.uri);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Vendored
+15
-27
@@ -4919,23 +4919,8 @@ declare module 'azdata' {
|
|||||||
deleteCell(index: number): void;
|
deleteCell(index: number): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export function registerSerializationProvider(provider: NotebookSerializationProvider): vscode.Disposable;
|
||||||
* Register a notebook provider. The supported file types handled by this
|
export function registerExecuteProvider(provider: NotebookExecuteProvider): vscode.Disposable;
|
||||||
* provider are defined in the `package.json:
|
|
||||||
* ```json
|
|
||||||
* {
|
|
||||||
* "contributes": {
|
|
||||||
* "notebook.providers": [{
|
|
||||||
* "provider": "providername",
|
|
||||||
* "fileExtensions": ["FILEEXT"]
|
|
||||||
* }]
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
* @param notebook provider
|
|
||||||
* @returns disposable
|
|
||||||
*/
|
|
||||||
export function registerNotebookProvider(provider: NotebookProvider): vscode.Disposable;
|
|
||||||
|
|
||||||
export interface IStandardKernel {
|
export interface IStandardKernel {
|
||||||
readonly name: string;
|
readonly name: string;
|
||||||
@@ -4943,24 +4928,27 @@ declare module 'azdata' {
|
|||||||
readonly connectionProviderIds: string[];
|
readonly connectionProviderIds: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NotebookProvider {
|
export interface NotebookSerializationProvider {
|
||||||
readonly providerId: string;
|
readonly providerId: string;
|
||||||
/**
|
getSerializationManager(notebookUri: vscode.Uri): Thenable<SerializationManager>;
|
||||||
* @deprecated standardKernels will be removed in an upcoming release. Standard kernel contribution
|
}
|
||||||
* should happen via JSON for extensions. Until this is removed, notebook providers can safely return an empty array.
|
|
||||||
*/
|
export interface NotebookExecuteProvider {
|
||||||
readonly standardKernels: IStandardKernel[];
|
readonly providerId: string;
|
||||||
getNotebookManager(notebookUri: vscode.Uri): Thenable<NotebookManager>;
|
getExecuteManager(notebookUri: vscode.Uri): Thenable<ExecuteManager>;
|
||||||
handleNotebookClosed(notebookUri: vscode.Uri): void;
|
handleNotebookClosed(notebookUri: vscode.Uri): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NotebookManager {
|
export interface SerializationManager {
|
||||||
/**
|
/**
|
||||||
* Manages reading and writing contents to/from files.
|
* Manages reading and writing contents to/from files.
|
||||||
* Files may be local or remote, with this manager giving them a chance to convert and migrate
|
* Files may be local or remote, with this manager giving them a chance to convert and migrate
|
||||||
* from specific notebook file types to and from a standard type for this UI
|
* from specific notebook file types to and from a standard type for this UI
|
||||||
*/
|
*/
|
||||||
readonly contentManager: ContentManager;
|
readonly contentManager: ContentManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExecuteManager {
|
||||||
/**
|
/**
|
||||||
* A SessionManager that handles starting, stopping and handling notifications around sessions.
|
* A SessionManager that handles starting, stopping and handling notifications around sessions.
|
||||||
* Each notebook has 1 session associated with it, and the session is responsible
|
* Each notebook has 1 session associated with it, and the session is responsible
|
||||||
@@ -5009,7 +4997,7 @@ declare module 'azdata' {
|
|||||||
/* Reads contents from a Uri representing a local or remote notebook and returns a
|
/* Reads contents from a Uri representing a local or remote notebook and returns a
|
||||||
* JSON object containing the cells and metadata about the notebook
|
* JSON object containing the cells and metadata about the notebook
|
||||||
*/
|
*/
|
||||||
getNotebookContents(notebookUri: vscode.Uri): Thenable<INotebookContents>;
|
deserializeNotebook(contents: string): Thenable<INotebookContents>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save a file.
|
* Save a file.
|
||||||
@@ -5021,7 +5009,7 @@ declare module 'azdata' {
|
|||||||
* @returns A thenable which resolves with the file content model when the
|
* @returns A thenable which resolves with the file content model when the
|
||||||
* file is saved.
|
* file is saved.
|
||||||
*/
|
*/
|
||||||
save(notebookUri: vscode.Uri, notebook: INotebookContents): Thenable<INotebookContents>;
|
serializeNotebook(notebook: INotebookContents): Thenable<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ import { IExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
|
|||||||
import { Event, Emitter } from 'vs/base/common/event';
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
|
||||||
import { INotebookService, INotebookProvider, INotebookManager } from 'sql/workbench/services/notebook/browser/notebookService';
|
import { INotebookService, IExecuteProvider, IExecuteManager, ISerializationProvider, ISerializationManager } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||||
import { INotebookManagerDetails, INotebookSessionDetails, INotebookKernelDetails, FutureMessageType, INotebookFutureDetails, INotebookFutureDone } from 'sql/workbench/api/common/sqlExtHostTypes';
|
import { IExecuteManagerDetails, INotebookSessionDetails, INotebookKernelDetails, FutureMessageType, INotebookFutureDetails, INotebookFutureDone, ISerializationManagerDetails } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
import { LocalContentManager } from 'sql/workbench/services/notebook/common/localContentManager';
|
import { LocalContentManager } from 'sql/workbench/services/notebook/common/localContentManager';
|
||||||
import { Deferred } from 'sql/base/common/promise';
|
import { Deferred } from 'sql/base/common/promise';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
@@ -22,7 +22,8 @@ import type { FutureInternal } from 'sql/workbench/services/notebook/browser/int
|
|||||||
export class MainThreadNotebook extends Disposable implements MainThreadNotebookShape {
|
export class MainThreadNotebook extends Disposable implements MainThreadNotebookShape {
|
||||||
|
|
||||||
private _proxy: ExtHostNotebookShape;
|
private _proxy: ExtHostNotebookShape;
|
||||||
private _providers = new Map<number, NotebookProviderWrapper>();
|
private _serializationProviders = new Map<number, SerializationProviderWrapper>();
|
||||||
|
private _executeProviders = new Map<number, ExecuteProviderWrapper>();
|
||||||
private _futures = new Map<number, FutureWrapper>();
|
private _futures = new Map<number, FutureWrapper>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -45,22 +46,41 @@ export class MainThreadNotebook extends Disposable implements MainThreadNotebook
|
|||||||
}
|
}
|
||||||
|
|
||||||
//#region Extension host callable methods
|
//#region Extension host callable methods
|
||||||
public $registerNotebookProvider(providerId: string, handle: number): void {
|
public $registerSerializationProvider(providerId: string, handle: number): void {
|
||||||
let proxy: Proxies = {
|
let proxy: Proxies = {
|
||||||
main: this,
|
main: this,
|
||||||
ext: this._proxy
|
ext: this._proxy
|
||||||
};
|
};
|
||||||
let notebookProvider = this.instantiationService.createInstance(NotebookProviderWrapper, proxy, providerId, handle);
|
let notebookProvider = this.instantiationService.createInstance(SerializationProviderWrapper, proxy, providerId, handle);
|
||||||
this._providers.set(handle, notebookProvider);
|
this._serializationProviders.set(handle, notebookProvider);
|
||||||
this.notebookService.registerProvider(providerId, notebookProvider);
|
this.notebookService.registerSerializationProvider(providerId, notebookProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
public $unregisterNotebookProvider(handle: number): void {
|
public $registerExecuteProvider(providerId: string, handle: number): void {
|
||||||
let registration = this._providers.get(handle);
|
let proxy: Proxies = {
|
||||||
|
main: this,
|
||||||
|
ext: this._proxy
|
||||||
|
};
|
||||||
|
let notebookProvider = this.instantiationService.createInstance(ExecuteProviderWrapper, proxy, providerId, handle);
|
||||||
|
this._executeProviders.set(handle, notebookProvider);
|
||||||
|
this.notebookService.registerExecuteProvider(providerId, notebookProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
public $unregisterSerializationProvider(handle: number): void {
|
||||||
|
let registration = this._serializationProviders.get(handle);
|
||||||
if (registration) {
|
if (registration) {
|
||||||
this.notebookService.unregisterProvider(registration.providerId);
|
this.notebookService.unregisterSerializationProvider(registration.providerId);
|
||||||
registration.dispose();
|
registration.dispose();
|
||||||
this._providers.delete(handle);
|
this._serializationProviders.delete(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public $unregisterExecuteProvider(handle: number): void {
|
||||||
|
let registration = this._executeProviders.get(handle);
|
||||||
|
if (registration) {
|
||||||
|
this.notebookService.unregisterExecuteProvider(registration.providerId);
|
||||||
|
registration.dispose();
|
||||||
|
this._executeProviders.delete(handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,8 +106,8 @@ interface Proxies {
|
|||||||
ext: ExtHostNotebookShape;
|
ext: ExtHostNotebookShape;
|
||||||
}
|
}
|
||||||
|
|
||||||
class NotebookProviderWrapper extends Disposable implements INotebookProvider {
|
class SerializationProviderWrapper extends Disposable implements ISerializationProvider {
|
||||||
private _notebookUriToManagerMap = new Map<string, NotebookManagerWrapper>();
|
private _notebookUriToManagerMap = new Map<string, SerializationManagerWrapper>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _proxy: Proxies,
|
private _proxy: Proxies,
|
||||||
@@ -98,16 +118,45 @@ class NotebookProviderWrapper extends Disposable implements INotebookProvider {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
getNotebookManager(notebookUri: URI): Thenable<INotebookManager> {
|
getSerializationManager(notebookUri: URI): Thenable<ISerializationManager> {
|
||||||
// TODO must call through to setup in the extension host
|
// TODO must call through to setup in the extension host
|
||||||
return this.doGetNotebookManager(notebookUri);
|
return this.doGetSerializationManager(notebookUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async doGetNotebookManager(notebookUri: URI): Promise<INotebookManager> {
|
private async doGetSerializationManager(notebookUri: URI): Promise<ISerializationManager> {
|
||||||
let uriString = notebookUri.toString();
|
let uriString = notebookUri.toString();
|
||||||
let manager = this._notebookUriToManagerMap.get(uriString);
|
let manager = this._notebookUriToManagerMap.get(uriString);
|
||||||
if (!manager) {
|
if (!manager) {
|
||||||
manager = this.instantiationService.createInstance(NotebookManagerWrapper, this._proxy, this.providerId, notebookUri);
|
manager = this.instantiationService.createInstance(SerializationManagerWrapper, this._proxy, this.providerId, notebookUri);
|
||||||
|
await manager.initialize(this.providerHandle);
|
||||||
|
this._notebookUriToManagerMap.set(uriString, manager);
|
||||||
|
}
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExecuteProviderWrapper extends Disposable implements IExecuteProvider {
|
||||||
|
private _notebookUriToManagerMap = new Map<string, ExecuteManagerWrapper>();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private _proxy: Proxies,
|
||||||
|
public readonly providerId: string,
|
||||||
|
public readonly providerHandle: number,
|
||||||
|
@IInstantiationService private readonly instantiationService: IInstantiationService
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
getExecuteManager(notebookUri: URI): Thenable<IExecuteManager> {
|
||||||
|
// TODO must call through to setup in the extension host
|
||||||
|
return this.doGetExecuteManager(notebookUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async doGetExecuteManager(notebookUri: URI): Promise<IExecuteManager> {
|
||||||
|
let uriString = notebookUri.toString();
|
||||||
|
let manager = this._notebookUriToManagerMap.get(uriString);
|
||||||
|
if (!manager) {
|
||||||
|
manager = this.instantiationService.createInstance(ExecuteManagerWrapper, this._proxy, this.providerId, notebookUri);
|
||||||
await manager.initialize(this.providerHandle);
|
await manager.initialize(this.providerHandle);
|
||||||
this._notebookUriToManagerMap.set(uriString, manager);
|
this._notebookUriToManagerMap.set(uriString, manager);
|
||||||
}
|
}
|
||||||
@@ -120,11 +169,9 @@ class NotebookProviderWrapper extends Disposable implements INotebookProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class NotebookManagerWrapper implements INotebookManager {
|
class SerializationManagerWrapper implements ISerializationManager {
|
||||||
private _sessionManager: azdata.nb.SessionManager;
|
|
||||||
private _contentManager: azdata.nb.ContentManager;
|
private _contentManager: azdata.nb.ContentManager;
|
||||||
private _serverManager: azdata.nb.ServerManager;
|
private managerDetails: ISerializationManagerDetails;
|
||||||
private managerDetails: INotebookManagerDetails;
|
|
||||||
|
|
||||||
constructor(private _proxy: Proxies,
|
constructor(private _proxy: Proxies,
|
||||||
public readonly providerId: string,
|
public readonly providerId: string,
|
||||||
@@ -132,10 +179,35 @@ class NotebookManagerWrapper implements INotebookManager {
|
|||||||
@IInstantiationService private readonly instantiationService: IInstantiationService
|
@IInstantiationService private readonly instantiationService: IInstantiationService
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
public async initialize(providerHandle: number): Promise<NotebookManagerWrapper> {
|
public async initialize(providerHandle: number): Promise<SerializationManagerWrapper> {
|
||||||
this.managerDetails = await this._proxy.ext.$getNotebookManager(providerHandle, this.notebookUri);
|
this.managerDetails = await this._proxy.ext.$getSerializationManagerDetails(providerHandle, this.notebookUri);
|
||||||
let managerHandle = this.managerDetails.handle;
|
let managerHandle = this.managerDetails.handle;
|
||||||
this._contentManager = this.managerDetails.hasContentManager ? new ContentManagerWrapper(managerHandle, this._proxy) : this.instantiationService.createInstance(LocalContentManager);
|
this._contentManager = this.managerDetails.hasContentManager ? new ContentManagerWrapper(managerHandle, this._proxy) : this.instantiationService.createInstance(LocalContentManager);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get contentManager(): azdata.nb.ContentManager {
|
||||||
|
return this._contentManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get managerHandle(): number {
|
||||||
|
return this.managerDetails.handle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExecuteManagerWrapper implements IExecuteManager {
|
||||||
|
private _sessionManager: azdata.nb.SessionManager;
|
||||||
|
private _serverManager: azdata.nb.ServerManager;
|
||||||
|
private managerDetails: IExecuteManagerDetails;
|
||||||
|
|
||||||
|
constructor(private _proxy: Proxies,
|
||||||
|
public readonly providerId: string,
|
||||||
|
private notebookUri: URI
|
||||||
|
) { }
|
||||||
|
|
||||||
|
public async initialize(providerHandle: number): Promise<ExecuteManagerWrapper> {
|
||||||
|
this.managerDetails = await this._proxy.ext.$getExecuteManagerDetails(providerHandle, this.notebookUri);
|
||||||
|
let managerHandle = this.managerDetails.handle;
|
||||||
this._serverManager = this.managerDetails.hasServerManager ? new ServerManagerWrapper(managerHandle, this._proxy) : undefined;
|
this._serverManager = this.managerDetails.hasServerManager ? new ServerManagerWrapper(managerHandle, this._proxy) : undefined;
|
||||||
this._sessionManager = new SessionManagerWrapper(managerHandle, this._proxy);
|
this._sessionManager = new SessionManagerWrapper(managerHandle, this._proxy);
|
||||||
return this;
|
return this;
|
||||||
@@ -144,9 +216,6 @@ class NotebookManagerWrapper implements INotebookManager {
|
|||||||
public get sessionManager(): azdata.nb.SessionManager {
|
public get sessionManager(): azdata.nb.SessionManager {
|
||||||
return this._sessionManager;
|
return this._sessionManager;
|
||||||
}
|
}
|
||||||
public get contentManager(): azdata.nb.ContentManager {
|
|
||||||
return this._contentManager;
|
|
||||||
}
|
|
||||||
public get serverManager(): azdata.nb.ServerManager {
|
public get serverManager(): azdata.nb.ServerManager {
|
||||||
return this._serverManager;
|
return this._serverManager;
|
||||||
}
|
}
|
||||||
@@ -160,12 +229,12 @@ class ContentManagerWrapper implements azdata.nb.ContentManager {
|
|||||||
|
|
||||||
constructor(private handle: number, private _proxy: Proxies) {
|
constructor(private handle: number, private _proxy: Proxies) {
|
||||||
}
|
}
|
||||||
getNotebookContents(notebookUri: URI): Thenable<azdata.nb.INotebookContents> {
|
deserializeNotebook(contents: string): Thenable<azdata.nb.INotebookContents> {
|
||||||
return this._proxy.ext.$getNotebookContents(this.handle, notebookUri);
|
return this._proxy.ext.$deserializeNotebook(this.handle, contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
save(path: URI, notebook: azdata.nb.INotebookContents): Thenable<azdata.nb.INotebookContents> {
|
serializeNotebook(notebook: azdata.nb.INotebookContents): Thenable<string> {
|
||||||
return this._proxy.ext.$save(this.handle, path, notebook);
|
return this._proxy.ext.$serializeNotebook(this.handle, notebook);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ import { localize } from 'vs/nls';
|
|||||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||||
|
|
||||||
import { ExtHostNotebookShape, MainThreadNotebookShape, SqlMainContext } from 'sql/workbench/api/common/sqlExtHost.protocol';
|
import { ExtHostNotebookShape, MainThreadNotebookShape, SqlMainContext } from 'sql/workbench/api/common/sqlExtHost.protocol';
|
||||||
import { INotebookManagerDetails, INotebookSessionDetails, INotebookKernelDetails, INotebookFutureDetails, FutureMessageType } from 'sql/workbench/api/common/sqlExtHostTypes';
|
import { IExecuteManagerDetails, INotebookSessionDetails, INotebookKernelDetails, INotebookFutureDetails, FutureMessageType, ISerializationManagerDetails } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
|
|
||||||
type Adapter = azdata.nb.NotebookProvider | azdata.nb.NotebookManager | azdata.nb.ISession | azdata.nb.IKernel | azdata.nb.IFuture;
|
type Adapter = azdata.nb.NotebookSerializationProvider | azdata.nb.SerializationManager | azdata.nb.NotebookExecuteProvider | azdata.nb.ExecuteManager | azdata.nb.ISession | azdata.nb.IKernel | azdata.nb.IFuture;
|
||||||
|
|
||||||
export class ExtHostNotebook implements ExtHostNotebookShape {
|
export class ExtHostNotebook implements ExtHostNotebookShape {
|
||||||
private static _handlePool: number = 0;
|
private static _handlePool: number = 0;
|
||||||
@@ -28,26 +28,40 @@ export class ExtHostNotebook implements ExtHostNotebookShape {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//#region APIs called by main thread
|
//#region APIs called by main thread
|
||||||
async $getNotebookManager(providerHandle: number, notebookUri: UriComponents): Promise<INotebookManagerDetails> {
|
async $getSerializationManagerDetails(providerHandle: number, notebookUri: UriComponents): Promise<ISerializationManagerDetails> {
|
||||||
let uri = URI.revive(notebookUri);
|
let uri = URI.revive(notebookUri);
|
||||||
let uriString = uri.toString();
|
let uriString = uri.toString();
|
||||||
let adapter = this.findManagerForUri(uriString);
|
let adapter = this.findSerializationManagerForUri(uriString);
|
||||||
if (!adapter) {
|
if (!adapter) {
|
||||||
adapter = await this._withProvider(providerHandle, (provider) => {
|
adapter = await this._withSerializationProvider(providerHandle, (provider) => {
|
||||||
return this.getOrCreateManager(provider, uri);
|
return this.getOrCreateSerializationManager(provider, uri);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
handle: adapter.handle,
|
||||||
|
hasContentManager: !!adapter.contentManager
|
||||||
|
};
|
||||||
|
}
|
||||||
|
async $getExecuteManagerDetails(providerHandle: number, notebookUri: UriComponents): Promise<IExecuteManagerDetails> {
|
||||||
|
let uri = URI.revive(notebookUri);
|
||||||
|
let uriString = uri.toString();
|
||||||
|
let adapter = this.findExecuteManagerForUri(uriString);
|
||||||
|
if (!adapter) {
|
||||||
|
adapter = await this._withExecuteProvider(providerHandle, (provider) => {
|
||||||
|
return this.getOrCreateExecuteManager(provider, uri);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
handle: adapter.handle,
|
handle: adapter.handle,
|
||||||
hasContentManager: !!adapter.contentManager,
|
|
||||||
hasServerManager: !!adapter.serverManager
|
hasServerManager: !!adapter.serverManager
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
$handleNotebookClosed(notebookUri: UriComponents): void {
|
$handleNotebookClosed(notebookUri: UriComponents): void {
|
||||||
let uri = URI.revive(notebookUri);
|
let uri = URI.revive(notebookUri);
|
||||||
let uriString = uri.toString();
|
let uriString = uri.toString();
|
||||||
let manager = this.findManagerForUri(uriString);
|
let manager = this.findExecuteManagerForUri(uriString);
|
||||||
if (manager) {
|
if (manager) {
|
||||||
manager.provider.handleNotebookClosed(uri);
|
manager.provider.handleNotebookClosed(uri);
|
||||||
this._adapters.delete(manager.handle);
|
this._adapters.delete(manager.handle);
|
||||||
@@ -62,12 +76,12 @@ export class ExtHostNotebook implements ExtHostNotebookShape {
|
|||||||
return this._withServerManager(managerHandle, (serverManager) => serverManager.stopServer());
|
return this._withServerManager(managerHandle, (serverManager) => serverManager.stopServer());
|
||||||
}
|
}
|
||||||
|
|
||||||
$getNotebookContents(managerHandle: number, notebookUri: UriComponents): Thenable<azdata.nb.INotebookContents> {
|
$deserializeNotebook(managerHandle: number, contents: string): Thenable<azdata.nb.INotebookContents> {
|
||||||
return this._withContentManager(managerHandle, (contentManager) => contentManager.getNotebookContents(URI.revive(notebookUri)));
|
return this._withContentManager(managerHandle, (contentManager) => contentManager.deserializeNotebook(contents));
|
||||||
}
|
}
|
||||||
|
|
||||||
$save(managerHandle: number, notebookUri: UriComponents, notebook: azdata.nb.INotebookContents): Thenable<azdata.nb.INotebookContents> {
|
$serializeNotebook(managerHandle: number, notebook: azdata.nb.INotebookContents): Thenable<string> {
|
||||||
return this._withContentManager(managerHandle, (contentManager) => contentManager.save(URI.revive(notebookUri), notebook));
|
return this._withContentManager(managerHandle, (contentManager) => contentManager.serializeNotebook(notebook));
|
||||||
}
|
}
|
||||||
|
|
||||||
$refreshSpecs(managerHandle: number): Thenable<azdata.nb.IAllKernels> {
|
$refreshSpecs(managerHandle: number): Thenable<azdata.nb.IAllKernels> {
|
||||||
@@ -222,12 +236,21 @@ export class ExtHostNotebook implements ExtHostNotebookShape {
|
|||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region APIs called by extensions
|
//#region APIs called by extensions
|
||||||
registerNotebookProvider(provider: azdata.nb.NotebookProvider): vscode.Disposable {
|
registerExecuteProvider(provider: azdata.nb.NotebookExecuteProvider): vscode.Disposable {
|
||||||
if (!provider || !provider.providerId) {
|
if (!provider || !provider.providerId) {
|
||||||
throw new Error(localize('providerRequired', "A NotebookProvider with valid providerId must be passed to this method"));
|
throw new Error(localize('executeProviderRequired', "A NotebookExecuteProvider with valid providerId must be passed to this method"));
|
||||||
}
|
}
|
||||||
const handle = this._addNewAdapter(provider);
|
const handle = this._addNewAdapter(provider);
|
||||||
this._proxy.$registerNotebookProvider(provider.providerId, handle);
|
this._proxy.$registerExecuteProvider(provider.providerId, handle);
|
||||||
|
return this._createDisposable(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
registerSerializationProvider(provider: azdata.nb.NotebookSerializationProvider): vscode.Disposable {
|
||||||
|
if (!provider || !provider.providerId) {
|
||||||
|
throw new Error(localize('serializationProviderRequired', "A NotebookSerializationProvider with valid providerId must be passed to this method"));
|
||||||
|
}
|
||||||
|
const handle = this._addNewAdapter(provider);
|
||||||
|
this._proxy.$registerSerializationProvider(provider.providerId, handle);
|
||||||
return this._createDisposable(handle);
|
return this._createDisposable(handle);
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
@@ -245,8 +268,8 @@ export class ExtHostNotebook implements ExtHostNotebookShape {
|
|||||||
return matchingAdapters;
|
return matchingAdapters;
|
||||||
}
|
}
|
||||||
|
|
||||||
private findManagerForUri(uriString: string): NotebookManagerAdapter {
|
private findSerializationManagerForUri(uriString: string): SerializationManagerAdapter {
|
||||||
for (let manager of this.getAdapters(NotebookManagerAdapter)) {
|
for (let manager of this.getAdapters(SerializationManagerAdapter)) {
|
||||||
if (manager.uriString === uriString) {
|
if (manager.uriString === uriString) {
|
||||||
return manager;
|
return manager;
|
||||||
}
|
}
|
||||||
@@ -254,10 +277,27 @@ export class ExtHostNotebook implements ExtHostNotebookShape {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getOrCreateManager(provider: azdata.nb.NotebookProvider, notebookUri: URI): Promise<NotebookManagerAdapter> {
|
private findExecuteManagerForUri(uriString: string): ExecuteManagerAdapter {
|
||||||
let manager = await provider.getNotebookManager(notebookUri);
|
for (let manager of this.getAdapters(ExecuteManagerAdapter)) {
|
||||||
|
if (manager.uriString === uriString) {
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getOrCreateSerializationManager(provider: azdata.nb.NotebookSerializationProvider, notebookUri: URI): Promise<SerializationManagerAdapter> {
|
||||||
|
let manager = await provider.getSerializationManager(notebookUri);
|
||||||
let uriString = notebookUri.toString();
|
let uriString = notebookUri.toString();
|
||||||
let adapter = new NotebookManagerAdapter(provider, manager, uriString);
|
let adapter = new SerializationManagerAdapter(provider, manager, uriString);
|
||||||
|
adapter.handle = this._addNewAdapter(adapter);
|
||||||
|
return adapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getOrCreateExecuteManager(provider: azdata.nb.NotebookExecuteProvider, notebookUri: URI): Promise<ExecuteManagerAdapter> {
|
||||||
|
let manager = await provider.getExecuteManager(notebookUri);
|
||||||
|
let uriString = notebookUri.toString();
|
||||||
|
let adapter = new ExecuteManagerAdapter(provider, manager, uriString);
|
||||||
adapter.handle = this._addNewAdapter(adapter);
|
adapter.handle = this._addNewAdapter(adapter);
|
||||||
return adapter;
|
return adapter;
|
||||||
}
|
}
|
||||||
@@ -272,23 +312,39 @@ export class ExtHostNotebook implements ExtHostNotebookShape {
|
|||||||
return ExtHostNotebook._handlePool++;
|
return ExtHostNotebook._handlePool++;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _withProvider<R>(handle: number, callback: (provider: azdata.nb.NotebookProvider) => R | PromiseLike<R>): Promise<R> {
|
private _withSerializationProvider(handle: number, callback: (provider: azdata.nb.NotebookSerializationProvider) => SerializationManagerAdapter | PromiseLike<SerializationManagerAdapter>): Promise<SerializationManagerAdapter> {
|
||||||
let provider = this._adapters.get(handle) as azdata.nb.NotebookProvider;
|
let provider = this._adapters.get(handle) as azdata.nb.NotebookSerializationProvider;
|
||||||
if (provider === undefined) {
|
if (provider === undefined) {
|
||||||
return Promise.reject(new Error(localize('errNoProvider', "no notebook provider found")));
|
return Promise.reject(new Error(localize('errNoSerializationProvider', "No notebook serialization provider found")));
|
||||||
}
|
}
|
||||||
return Promise.resolve(callback(provider));
|
return Promise.resolve(callback(provider));
|
||||||
}
|
}
|
||||||
|
|
||||||
private _withNotebookManager<R>(handle: number, callback: (manager: NotebookManagerAdapter) => R | PromiseLike<R>): Promise<R> {
|
private _withExecuteProvider(handle: number, callback: (provider: azdata.nb.NotebookExecuteProvider) => ExecuteManagerAdapter | PromiseLike<ExecuteManagerAdapter>): Promise<ExecuteManagerAdapter> {
|
||||||
let manager = this._adapters.get(handle) as NotebookManagerAdapter;
|
let provider = this._adapters.get(handle) as azdata.nb.NotebookExecuteProvider;
|
||||||
if (manager === undefined) {
|
if (provider === undefined) {
|
||||||
return Promise.reject(new Error(localize('errNoManager', "No Manager found")));
|
return Promise.reject(new Error(localize('errNoExecuteProvider', "No notebook execute provider found")));
|
||||||
}
|
}
|
||||||
return this.callbackWithErrorWrap<R>(callback, manager);
|
return Promise.resolve(callback(provider));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async callbackWithErrorWrap<R>(callback: (manager: NotebookManagerAdapter) => R | PromiseLike<R>, manager: NotebookManagerAdapter): Promise<R> {
|
private _withSerializationManager<R>(handle: number, callback: (manager: SerializationManagerAdapter) => R | PromiseLike<R>): Promise<R> {
|
||||||
|
let manager = this._adapters.get(handle) as SerializationManagerAdapter;
|
||||||
|
if (manager === undefined) {
|
||||||
|
return Promise.reject(new Error(localize('errNoSerializationManager', "No serialization manager found")));
|
||||||
|
}
|
||||||
|
return this.callbackWithErrorWrap<SerializationManagerAdapter, R>(callback, manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _withExecuteManager<R>(handle: number, callback: (manager: ExecuteManagerAdapter) => R | PromiseLike<R>): Promise<R> {
|
||||||
|
let manager = this._adapters.get(handle) as ExecuteManagerAdapter;
|
||||||
|
if (manager === undefined) {
|
||||||
|
return Promise.reject(new Error(localize('errNoExecuteManager', "No execute manager found")));
|
||||||
|
}
|
||||||
|
return this.callbackWithErrorWrap<ExecuteManagerAdapter, R>(callback, manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async callbackWithErrorWrap<A, R>(callback: (manager: A) => R | PromiseLike<R>, manager: A): Promise<R> {
|
||||||
try {
|
try {
|
||||||
let value = await callback(manager);
|
let value = await callback(manager);
|
||||||
return value;
|
return value;
|
||||||
@@ -298,7 +354,7 @@ export class ExtHostNotebook implements ExtHostNotebookShape {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _withServerManager<R>(handle: number, callback: (manager: azdata.nb.ServerManager) => PromiseLike<R>): Promise<R> {
|
private _withServerManager<R>(handle: number, callback: (manager: azdata.nb.ServerManager) => PromiseLike<R>): Promise<R> {
|
||||||
return this._withNotebookManager(handle, (notebookManager) => {
|
return this._withExecuteManager(handle, (notebookManager) => {
|
||||||
let serverManager = notebookManager.serverManager;
|
let serverManager = notebookManager.serverManager;
|
||||||
if (!serverManager) {
|
if (!serverManager) {
|
||||||
return Promise.reject(new Error(localize('noServerManager', "Notebook Manager for notebook {0} does not have a server manager. Cannot perform operations on it", notebookManager.uriString)));
|
return Promise.reject(new Error(localize('noServerManager', "Notebook Manager for notebook {0} does not have a server manager. Cannot perform operations on it", notebookManager.uriString)));
|
||||||
@@ -308,7 +364,7 @@ export class ExtHostNotebook implements ExtHostNotebookShape {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _withContentManager<R>(handle: number, callback: (manager: azdata.nb.ContentManager) => PromiseLike<R>): Promise<R> {
|
private _withContentManager<R>(handle: number, callback: (manager: azdata.nb.ContentManager) => PromiseLike<R>): Promise<R> {
|
||||||
return this._withNotebookManager(handle, (notebookManager) => {
|
return this._withSerializationManager(handle, (notebookManager) => {
|
||||||
let contentManager = notebookManager.contentManager;
|
let contentManager = notebookManager.contentManager;
|
||||||
if (!contentManager) {
|
if (!contentManager) {
|
||||||
return Promise.reject(new Error(localize('noContentManager', "Notebook Manager for notebook {0} does not have a content manager. Cannot perform operations on it", notebookManager.uriString)));
|
return Promise.reject(new Error(localize('noContentManager', "Notebook Manager for notebook {0} does not have a content manager. Cannot perform operations on it", notebookManager.uriString)));
|
||||||
@@ -318,7 +374,7 @@ export class ExtHostNotebook implements ExtHostNotebookShape {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _withSessionManager<R>(handle: number, callback: (manager: azdata.nb.SessionManager) => PromiseLike<R>): Promise<R> {
|
private _withSessionManager<R>(handle: number, callback: (manager: azdata.nb.SessionManager) => PromiseLike<R>): Promise<R> {
|
||||||
return this._withNotebookManager(handle, (notebookManager) => {
|
return this._withExecuteManager(handle, (notebookManager) => {
|
||||||
let sessionManager = notebookManager.sessionManager;
|
let sessionManager = notebookManager.sessionManager;
|
||||||
if (!sessionManager) {
|
if (!sessionManager) {
|
||||||
return Promise.reject(new Error(localize('noSessionManager', "Notebook Manager for notebook {0} does not have a session manager. Cannot perform operations on it", notebookManager.uriString)));
|
return Promise.reject(new Error(localize('noSessionManager', "Notebook Manager for notebook {0} does not have a session manager. Cannot perform operations on it", notebookManager.uriString)));
|
||||||
@@ -344,12 +400,11 @@ export class ExtHostNotebook implements ExtHostNotebookShape {
|
|||||||
//#endregion
|
//#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SerializationManagerAdapter implements azdata.nb.SerializationManager {
|
||||||
class NotebookManagerAdapter implements azdata.nb.NotebookManager {
|
|
||||||
public handle: number;
|
public handle: number;
|
||||||
constructor(
|
constructor(
|
||||||
public readonly provider: azdata.nb.NotebookProvider,
|
public readonly provider: azdata.nb.NotebookSerializationProvider,
|
||||||
private manager: azdata.nb.NotebookManager,
|
private manager: azdata.nb.SerializationManager,
|
||||||
public readonly uriString: string
|
public readonly uriString: string
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
@@ -357,6 +412,16 @@ class NotebookManagerAdapter implements azdata.nb.NotebookManager {
|
|||||||
public get contentManager(): azdata.nb.ContentManager {
|
public get contentManager(): azdata.nb.ContentManager {
|
||||||
return this.manager.contentManager;
|
return this.manager.contentManager;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExecuteManagerAdapter implements azdata.nb.ExecuteManager {
|
||||||
|
public handle: number;
|
||||||
|
constructor(
|
||||||
|
public readonly provider: azdata.nb.NotebookExecuteProvider,
|
||||||
|
private manager: azdata.nb.ExecuteManager,
|
||||||
|
public readonly uriString: string
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
public get sessionManager(): azdata.nb.SessionManager {
|
public get sessionManager(): azdata.nb.SessionManager {
|
||||||
return this.manager.sessionManager;
|
return this.manager.sessionManager;
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ export class ExtHostNotebookDocumentsAndEditors implements ExtHostNotebookDocume
|
|||||||
|
|
||||||
registerNavigationProvider(provider: azdata.nb.NavigationProvider): vscode.Disposable {
|
registerNavigationProvider(provider: azdata.nb.NavigationProvider): vscode.Disposable {
|
||||||
if (!provider || !provider.providerId) {
|
if (!provider || !provider.providerId) {
|
||||||
throw new Error(localize('providerRequired', "A NotebookProvider with valid providerId must be passed to this method"));
|
throw new Error(localize('navigationProviderRequired', "A NavigationProvider with valid providerId must be passed to this method"));
|
||||||
}
|
}
|
||||||
const handle = this._addNewAdapter(provider);
|
const handle = this._addNewAdapter(provider);
|
||||||
this._proxy.$registerNavigationProvider(provider.providerId, handle);
|
this._proxy.$registerNavigationProvider(provider.providerId, handle);
|
||||||
|
|||||||
@@ -546,8 +546,11 @@ export function createAdsApiFactory(accessor: ServicesAccessor): IAdsExtensionAp
|
|||||||
showNotebookDocument(uri: vscode.Uri, showOptions: azdata.nb.NotebookShowOptions) {
|
showNotebookDocument(uri: vscode.Uri, showOptions: azdata.nb.NotebookShowOptions) {
|
||||||
return extHostNotebookDocumentsAndEditors.showNotebookDocument(uri, showOptions);
|
return extHostNotebookDocumentsAndEditors.showNotebookDocument(uri, showOptions);
|
||||||
},
|
},
|
||||||
registerNotebookProvider(provider: azdata.nb.NotebookProvider): vscode.Disposable {
|
registerSerializationProvider(provider: azdata.nb.NotebookSerializationProvider): vscode.Disposable {
|
||||||
return extHostNotebook.registerNotebookProvider(provider);
|
return extHostNotebook.registerSerializationProvider(provider);
|
||||||
|
},
|
||||||
|
registerExecuteProvider(provider: azdata.nb.NotebookExecuteProvider): vscode.Disposable {
|
||||||
|
return extHostNotebook.registerExecuteProvider(provider);
|
||||||
},
|
},
|
||||||
registerNavigationProvider(provider: azdata.nb.NavigationProvider): vscode.Disposable {
|
registerNavigationProvider(provider: azdata.nb.NavigationProvider): vscode.Disposable {
|
||||||
return extHostNotebookDocumentsAndEditors.registerNavigationProvider(provider);
|
return extHostNotebookDocumentsAndEditors.registerNavigationProvider(provider);
|
||||||
|
|||||||
@@ -18,9 +18,10 @@ import { ITreeComponentItem } from 'sql/workbench/common/views';
|
|||||||
import { ITaskHandlerDescription } from 'sql/workbench/services/tasks/common/tasks';
|
import { ITaskHandlerDescription } from 'sql/workbench/services/tasks/common/tasks';
|
||||||
import {
|
import {
|
||||||
IItemConfig, IComponentShape, IModelViewDialogDetails, IModelViewTabDetails, IModelViewButtonDetails,
|
IItemConfig, IComponentShape, IModelViewDialogDetails, IModelViewTabDetails, IModelViewButtonDetails,
|
||||||
IModelViewWizardDetails, IModelViewWizardPageDetails, INotebookManagerDetails, INotebookSessionDetails,
|
IModelViewWizardDetails, IModelViewWizardPageDetails, IExecuteManagerDetails, INotebookSessionDetails,
|
||||||
INotebookKernelDetails, INotebookFutureDetails, FutureMessageType, INotebookFutureDone, ISingleNotebookEditOperation,
|
INotebookKernelDetails, INotebookFutureDetails, FutureMessageType, INotebookFutureDone, ISingleNotebookEditOperation,
|
||||||
NotebookChangeKind
|
NotebookChangeKind,
|
||||||
|
ISerializationManagerDetails
|
||||||
} from 'sql/workbench/api/common/sqlExtHostTypes';
|
} from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
import { IUndoStopOptions } from 'vs/workbench/api/common/extHost.protocol';
|
import { IUndoStopOptions } from 'vs/workbench/api/common/extHost.protocol';
|
||||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||||
@@ -863,7 +864,8 @@ export interface ExtHostNotebookShape {
|
|||||||
* Looks up a notebook manager for a given notebook URI
|
* Looks up a notebook manager for a given notebook URI
|
||||||
* @returns handle of the manager to be used when sending
|
* @returns handle of the manager to be used when sending
|
||||||
*/
|
*/
|
||||||
$getNotebookManager(providerHandle: number, notebookUri: UriComponents): Thenable<INotebookManagerDetails>;
|
$getSerializationManagerDetails(providerHandle: number, notebookUri: UriComponents): Thenable<ISerializationManagerDetails>;
|
||||||
|
$getExecuteManagerDetails(providerHandle: number, notebookUri: UriComponents): Thenable<IExecuteManagerDetails>;
|
||||||
$handleNotebookClosed(notebookUri: UriComponents): void;
|
$handleNotebookClosed(notebookUri: UriComponents): void;
|
||||||
|
|
||||||
// Server Manager APIs
|
// Server Manager APIs
|
||||||
@@ -871,8 +873,8 @@ export interface ExtHostNotebookShape {
|
|||||||
$doStopServer(managerHandle: number): Thenable<void>;
|
$doStopServer(managerHandle: number): Thenable<void>;
|
||||||
|
|
||||||
// Content Manager APIs
|
// Content Manager APIs
|
||||||
$getNotebookContents(managerHandle: number, notebookUri: UriComponents): Thenable<azdata.nb.INotebookContents>;
|
$deserializeNotebook(managerHandle: number, contents: string): Thenable<azdata.nb.INotebookContents>;
|
||||||
$save(managerHandle: number, notebookUri: UriComponents, notebook: azdata.nb.INotebookContents): Thenable<azdata.nb.INotebookContents>;
|
$serializeNotebook(managerHandle: number, notebook: azdata.nb.INotebookContents): Thenable<string>;
|
||||||
|
|
||||||
// Session Manager APIs
|
// Session Manager APIs
|
||||||
$refreshSpecs(managerHandle: number): Thenable<azdata.nb.IAllKernels>;
|
$refreshSpecs(managerHandle: number): Thenable<azdata.nb.IAllKernels>;
|
||||||
@@ -899,8 +901,10 @@ export interface ExtHostNotebookShape {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface MainThreadNotebookShape extends IDisposable {
|
export interface MainThreadNotebookShape extends IDisposable {
|
||||||
$registerNotebookProvider(providerId: string, handle: number): void;
|
$registerSerializationProvider(providerId: string, handle: number): void;
|
||||||
$unregisterNotebookProvider(handle: number): void;
|
$registerExecuteProvider(providerId: string, handle: number): void;
|
||||||
|
$unregisterSerializationProvider(handle: number): void;
|
||||||
|
$unregisterExecuteProvider(handle: number): void;
|
||||||
$onFutureMessage(futureId: number, type: FutureMessageType, payload: azdata.nb.IMessage): void;
|
$onFutureMessage(futureId: number, type: FutureMessageType, payload: azdata.nb.IMessage): void;
|
||||||
$onFutureDone(futureId: number, done: INotebookFutureDone): void;
|
$onFutureDone(futureId: number, done: INotebookFutureDone): void;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -551,9 +551,13 @@ export class SqlThemeIcon {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface INotebookManagerDetails {
|
export interface ISerializationManagerDetails {
|
||||||
handle: number;
|
handle: number;
|
||||||
hasContentManager: boolean;
|
hasContentManager: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IExecuteManagerDetails {
|
||||||
|
handle: number;
|
||||||
hasServerManager: boolean;
|
hasServerManager: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ export const UNTITLED_QUERY_EDITOR_TYPEID = 'workbench.editorinputs.untitledQuer
|
|||||||
export const FILE_QUERY_EDITOR_TYPEID = 'workbench.editorinputs.fileQueryInput';
|
export const FILE_QUERY_EDITOR_TYPEID = 'workbench.editorinputs.fileQueryInput';
|
||||||
export const RESOURCE_VIEWER_TYPEID = 'workbench.editorinputs.resourceViewerInput';
|
export const RESOURCE_VIEWER_TYPEID = 'workbench.editorinputs.resourceViewerInput';
|
||||||
|
|
||||||
|
export const JUPYTER_PROVIDER_ID = 'jupyter';
|
||||||
|
|
||||||
export const enum NotebookLanguage {
|
export const enum NotebookLanguage {
|
||||||
Notebook = 'Notebook',
|
Notebook = 'Notebook',
|
||||||
Ipynb = 'ipynb'
|
Ipynb = 'ipynb'
|
||||||
|
|||||||
@@ -13,11 +13,10 @@ import { IStandardKernelWithProvider, getProvidersForFileName, getStandardKernel
|
|||||||
import { INotebookService, DEFAULT_NOTEBOOK_PROVIDER, IProviderInfo } from 'sql/workbench/services/notebook/browser/notebookService';
|
import { INotebookService, DEFAULT_NOTEBOOK_PROVIDER, IProviderInfo } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { ITextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService';
|
import { ITextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||||
import { INotebookModel, IContentManager, NotebookContentChange } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
import { INotebookModel, IContentLoader, NotebookContentChange } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||||
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
|
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
|
||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
import { ITextFileSaveOptions, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
|
import { ITextFileSaveOptions, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
import { LocalContentManager } from 'sql/workbench/services/notebook/common/localContentManager';
|
|
||||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
@@ -37,6 +36,7 @@ import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/no
|
|||||||
import { INotebookInput } from 'sql/workbench/services/notebook/browser/interface';
|
import { INotebookInput } from 'sql/workbench/services/notebook/browser/interface';
|
||||||
import { EditorModel } from 'vs/workbench/common/editor/editorModel';
|
import { EditorModel } from 'vs/workbench/common/editor/editorModel';
|
||||||
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
|
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
|
||||||
|
import { LocalContentManager } from 'sql/workbench/services/notebook/common/localContentManager';
|
||||||
|
|
||||||
export type ModeViewSaveHandler = (handle: number) => Thenable<boolean>;
|
export type ModeViewSaveHandler = (handle: number) => Thenable<boolean>;
|
||||||
|
|
||||||
@@ -61,8 +61,8 @@ export class NotebookEditorModel extends EditorModel {
|
|||||||
notebook.modelReady.then((model) => {
|
notebook.modelReady.then((model) => {
|
||||||
if (!this._changeEventsHookedUp) {
|
if (!this._changeEventsHookedUp) {
|
||||||
this._changeEventsHookedUp = true;
|
this._changeEventsHookedUp = true;
|
||||||
this._register(model.kernelChanged(e => this.updateModel(undefined, NotebookChangeType.KernelChanged)));
|
this._register(model.kernelChanged(e => this.updateModel(undefined, NotebookChangeType.KernelChanged).catch(e => onUnexpectedError(e))));
|
||||||
this._register(model.contentChanged(e => this.updateModel(e, e.changeType)));
|
this._register(model.contentChanged(e => this.updateModel(e, e.changeType).catch(e => onUnexpectedError(e))));
|
||||||
this._register(notebook.model.onActiveCellChanged((cell) => {
|
this._register(notebook.model.onActiveCellChanged((cell) => {
|
||||||
if (cell) {
|
if (cell) {
|
||||||
this._notebookTextFileModel.activeCellGuid = cell.cellGuid;
|
this._notebookTextFileModel.activeCellGuid = cell.cellGuid;
|
||||||
@@ -120,7 +120,7 @@ export class NotebookEditorModel extends EditorModel {
|
|||||||
this._onDidChangeDirty.fire();
|
this._onDidChangeDirty.fire();
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateModel(contentChange?: NotebookContentChange, type?: NotebookChangeType): void {
|
public async updateModel(contentChange?: NotebookContentChange, type?: NotebookChangeType): Promise<void> {
|
||||||
// If text editor model is readonly, exit early as no changes need to occur on the model
|
// If text editor model is readonly, exit early as no changes need to occur on the model
|
||||||
// Note: this follows what happens in fileCommands where update/save logic is skipped for readonly text editor models
|
// Note: this follows what happens in fileCommands where update/save logic is skipped for readonly text editor models
|
||||||
if (this.textEditorModel?.isReadonly()) {
|
if (this.textEditorModel?.isReadonly()) {
|
||||||
@@ -171,14 +171,14 @@ export class NotebookEditorModel extends EditorModel {
|
|||||||
if (editAppliedSuccessfully) {
|
if (editAppliedSuccessfully) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.replaceEntireTextEditorModel(notebookModel, type);
|
await this.replaceEntireTextEditorModel(notebookModel, type);
|
||||||
this._lastEditFullReplacement = true;
|
this._lastEditFullReplacement = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public replaceEntireTextEditorModel(notebookModel: INotebookModel, type: NotebookChangeType) {
|
public replaceEntireTextEditorModel(notebookModel: INotebookModel, type: NotebookChangeType): Promise<void> {
|
||||||
this._notebookTextFileModel.replaceEntireTextEditorModel(notebookModel, type, this.textEditorModel);
|
return this._notebookTextFileModel.replaceEntireTextEditorModel(notebookModel, type, this.textEditorModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private sendNotebookSerializationStateChange(): void {
|
private sendNotebookSerializationStateChange(): void {
|
||||||
@@ -224,7 +224,7 @@ export abstract class NotebookInput extends EditorInput implements INotebookInpu
|
|||||||
private readonly _layoutChanged: Emitter<void> = this._register(new Emitter<void>());
|
private readonly _layoutChanged: Emitter<void> = this._register(new Emitter<void>());
|
||||||
private _model: NotebookEditorModel;
|
private _model: NotebookEditorModel;
|
||||||
private _untitledEditorModel: IUntitledTextEditorModel;
|
private _untitledEditorModel: IUntitledTextEditorModel;
|
||||||
private _contentManager: IContentManager;
|
private _contentLoader: IContentLoader;
|
||||||
private _providersLoaded: Promise<void>;
|
private _providersLoaded: Promise<void>;
|
||||||
private _dirtyListener: IDisposable;
|
private _dirtyListener: IDisposable;
|
||||||
private _notebookEditorOpenedTimestamp: number;
|
private _notebookEditorOpenedTimestamp: number;
|
||||||
@@ -274,11 +274,12 @@ export abstract class NotebookInput extends EditorInput implements INotebookInpu
|
|||||||
return this._notebookFindModel;
|
return this._notebookFindModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get contentManager(): IContentManager {
|
public get contentLoader(): IContentLoader {
|
||||||
if (!this._contentManager) {
|
if (!this._contentLoader) {
|
||||||
this._contentManager = this.instantiationService.createInstance(NotebookEditorContentManager, this);
|
let contentManager = this.instantiationService.createInstance(LocalContentManager);
|
||||||
|
this._contentLoader = this.instantiationService.createInstance(NotebookEditorContentLoader, this, contentManager);
|
||||||
}
|
}
|
||||||
return this._contentManager;
|
return this._contentLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override getName(): string {
|
public override getName(): string {
|
||||||
@@ -292,6 +293,10 @@ export abstract class NotebookInput extends EditorInput implements INotebookInpu
|
|||||||
return EditorInputCapabilities.None;
|
return EditorInputCapabilities.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get providersLoaded(): Promise<void> {
|
||||||
|
return this._providersLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
public async getProviderInfo(): Promise<IProviderInfo> {
|
public async getProviderInfo(): Promise<IProviderInfo> {
|
||||||
await this._providersLoaded;
|
await this._providersLoaded;
|
||||||
return {
|
return {
|
||||||
@@ -313,14 +318,14 @@ export abstract class NotebookInput extends EditorInput implements INotebookInpu
|
|||||||
}
|
}
|
||||||
|
|
||||||
override async save(groupId: number, options?: ITextFileSaveOptions): Promise<IEditorInput | undefined> {
|
override async save(groupId: number, options?: ITextFileSaveOptions): Promise<IEditorInput | undefined> {
|
||||||
this.updateModel();
|
await this.updateModel();
|
||||||
let input = await this.textInput.save(groupId, options);
|
let input = await this.textInput.save(groupId, options);
|
||||||
await this.setTrustForNewEditor(input);
|
await this.setTrustForNewEditor(input);
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
override async saveAs(group: number, options?: ITextFileSaveOptions): Promise<IEditorInput | undefined> {
|
override async saveAs(group: number, options?: ITextFileSaveOptions): Promise<IEditorInput | undefined> {
|
||||||
this.updateModel();
|
await this.updateModel();
|
||||||
let input = await this.textInput.saveAs(group, options);
|
let input = await this.textInput.saveAs(group, options);
|
||||||
await this.setTrustForNewEditor(input);
|
await this.setTrustForNewEditor(input);
|
||||||
return input;
|
return input;
|
||||||
@@ -438,6 +443,8 @@ export abstract class NotebookInput extends EditorInput implements INotebookInpu
|
|||||||
let standardKernels = getStandardKernelsForProvider(provider, this.notebookService);
|
let standardKernels = getStandardKernelsForProvider(provider, this.notebookService);
|
||||||
this._standardKernels.push(...standardKernels);
|
this._standardKernels.push(...standardKernels);
|
||||||
});
|
});
|
||||||
|
let serializationProvider = await this.notebookService.getOrCreateSerializationManager(this._providerId, this._resource);
|
||||||
|
this._contentLoader = this.instantiationService.createInstance(NotebookEditorContentLoader, this, serializationProvider.contentManager);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -497,8 +504,8 @@ export abstract class NotebookInput extends EditorInput implements INotebookInpu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateModel(): void {
|
public updateModel(): Promise<void> {
|
||||||
this._model.updateModel();
|
return this._model.updateModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override matches(otherInput: any): boolean {
|
public override matches(otherInput: any): boolean {
|
||||||
@@ -510,17 +517,14 @@ export abstract class NotebookInput extends EditorInput implements INotebookInpu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NotebookEditorContentManager implements IContentManager {
|
export class NotebookEditorContentLoader implements IContentLoader {
|
||||||
constructor(
|
constructor(
|
||||||
private notebookInput: NotebookInput,
|
private notebookInput: NotebookInput,
|
||||||
@IInstantiationService private readonly instantiationService: IInstantiationService) {
|
private contentManager: azdata.nb.ContentManager) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadContent(): Promise<azdata.nb.INotebookContents> {
|
async loadContent(): Promise<azdata.nb.INotebookContents> {
|
||||||
let notebookEditorModel = await this.notebookInput.resolve();
|
let notebookEditorModel = await this.notebookInput.resolve();
|
||||||
let contentManager = this.instantiationService.createInstance(LocalContentManager);
|
return this.contentManager.deserializeNotebook(notebookEditorModel.contentString);
|
||||||
let contents = await contentManager.loadFromContentString(notebookEditorModel.contentString);
|
|
||||||
return contents;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -200,8 +200,15 @@ export class NotebookTextFileModel {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public replaceEntireTextEditorModel(notebookModel: INotebookModel, type: NotebookChangeType, textEditorModel: ITextEditorModel) {
|
public async replaceEntireTextEditorModel(notebookModel: INotebookModel, type: NotebookChangeType, textEditorModel: ITextEditorModel): Promise<void> {
|
||||||
let content = JSON.stringify(notebookModel.toJSON(type), undefined, ' ');
|
let content: string;
|
||||||
|
let notebookContents = notebookModel.toJSON(type);
|
||||||
|
let serializer = notebookModel.serializationManager;
|
||||||
|
if (serializer) {
|
||||||
|
content = await serializer.contentManager.serializeNotebook(notebookContents);
|
||||||
|
} else {
|
||||||
|
content = JSON.stringify(notebookContents, undefined, ' ');
|
||||||
|
}
|
||||||
let model = textEditorModel.textEditorModel;
|
let model = textEditorModel.textEditorModel;
|
||||||
let endLine = model.getLineCount();
|
let endLine = model.getLineCount();
|
||||||
let endCol = model.getLineMaxColumn(endLine);
|
let endCol = model.getLineMaxColumn(endLine);
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ import { ImageMimeTypes, TextCellEditModes } from 'sql/workbench/services/notebo
|
|||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
import { NotebookInput } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
|
import { NotebookInput } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
|
||||||
import { INotebookModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
import { INotebookModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||||
import { INotebookManager } from 'sql/workbench/services/notebook/browser/notebookService';
|
import { IExecuteManager } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||||
import { NotebookExplorerViewletViewsContribution } from 'sql/workbench/contrib/notebook/browser/notebookExplorer/notebookExplorerViewlet';
|
import { NotebookExplorerViewletViewsContribution } from 'sql/workbench/contrib/notebook/browser/notebookExplorer/notebookExplorerViewlet';
|
||||||
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||||
import { ContributedEditorPriority, IEditorOverrideService } from 'vs/workbench/services/editor/common/editorOverrideService';
|
import { ContributedEditorPriority, IEditorOverrideService } from 'vs/workbench/services/editor/common/editorOverrideService';
|
||||||
@@ -62,6 +62,7 @@ import { IModeService } from 'vs/editor/common/services/modeService';
|
|||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
||||||
import { useNewMarkdownRendererKey } from 'sql/workbench/contrib/notebook/common/notebookCommon';
|
import { useNewMarkdownRendererKey } from 'sql/workbench/contrib/notebook/common/notebookCommon';
|
||||||
|
import { JUPYTER_PROVIDER_ID } from 'sql/workbench/common/constants';
|
||||||
|
|
||||||
Registry.as<IEditorInputFactoryRegistry>(EditorExtensions.EditorInputFactories)
|
Registry.as<IEditorInputFactoryRegistry>(EditorExtensions.EditorInputFactories)
|
||||||
.registerEditorInputSerializer(FileNotebookInput.ID, FileNoteBookEditorInputSerializer);
|
.registerEditorInputSerializer(FileNotebookInput.ID, FileNoteBookEditorInputSerializer);
|
||||||
@@ -189,10 +190,10 @@ CommandsRegistry.registerCommand({
|
|||||||
for (let editor of editors) {
|
for (let editor of editors) {
|
||||||
if (editor instanceof NotebookInput) {
|
if (editor instanceof NotebookInput) {
|
||||||
let model: INotebookModel = editor.notebookModel;
|
let model: INotebookModel = editor.notebookModel;
|
||||||
if (model.providerId === 'jupyter' && model.clientSession.isReady) {
|
if (model.providerId === JUPYTER_PROVIDER_ID && model.clientSession.isReady) {
|
||||||
// Jupyter server needs to be restarted so that the correct Python installation is used
|
// Jupyter server needs to be restarted so that the correct Python installation is used
|
||||||
if (!jupyterServerRestarted && restartJupyterServer) {
|
if (!jupyterServerRestarted && restartJupyterServer) {
|
||||||
let jupyterNotebookManager: INotebookManager = model.notebookManagers.find(x => x.providerId === 'jupyter');
|
let jupyterNotebookManager: IExecuteManager = model.executeManagers.find(x => x.providerId === JUPYTER_PROVIDER_ID);
|
||||||
// Shutdown all current Jupyter sessions before stopping the server
|
// Shutdown all current Jupyter sessions before stopping the server
|
||||||
await jupyterNotebookManager.sessionManager.shutdownAll();
|
await jupyterNotebookManager.sessionManager.shutdownAll();
|
||||||
// Jupyter session manager needs to be disposed so that a new one is created with the new server info
|
// Jupyter session manager needs to be disposed so that a new one is created with the new server info
|
||||||
@@ -222,8 +223,8 @@ CommandsRegistry.registerCommand({
|
|||||||
for (let editor of editors) {
|
for (let editor of editors) {
|
||||||
if (editor instanceof NotebookInput) {
|
if (editor instanceof NotebookInput) {
|
||||||
let model: INotebookModel = editor.notebookModel;
|
let model: INotebookModel = editor.notebookModel;
|
||||||
if (model?.providerId === 'jupyter') {
|
if (model?.providerId === JUPYTER_PROVIDER_ID) {
|
||||||
let jupyterNotebookManager: INotebookManager = model.notebookManagers.find(x => x.providerId === 'jupyter');
|
let jupyterNotebookManager: IExecuteManager = model.executeManagers.find(x => x.providerId === JUPYTER_PROVIDER_ID);
|
||||||
await jupyterNotebookManager.sessionManager.shutdownAll();
|
await jupyterNotebookManager.sessionManager.shutdownAll();
|
||||||
jupyterNotebookManager.sessionManager.dispose();
|
jupyterNotebookManager.sessionManager.dispose();
|
||||||
await jupyterNotebookManager.serverManager.stopServer();
|
await jupyterNotebookManager.serverManager.stopServer();
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/no
|
|||||||
import * as notebookUtils from 'sql/workbench/services/notebook/browser/models/notebookUtils';
|
import * as notebookUtils from 'sql/workbench/services/notebook/browser/models/notebookUtils';
|
||||||
import { AngularDisposable } from 'sql/base/browser/lifecycle';
|
import { AngularDisposable } from 'sql/base/browser/lifecycle';
|
||||||
import { IBootstrapParams } from 'sql/workbench/services/bootstrap/common/bootstrapParams';
|
import { IBootstrapParams } from 'sql/workbench/services/bootstrap/common/bootstrapParams';
|
||||||
import { INotebookParams, INotebookService, INotebookManager, DEFAULT_NOTEBOOK_PROVIDER, SQL_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/browser/notebookService';
|
import { INotebookParams, INotebookService, IExecuteManager, DEFAULT_NOTEBOOK_PROVIDER, SQL_NOTEBOOK_PROVIDER, ISerializationManager } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||||
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
||||||
import { CellMagicMapper } from 'sql/workbench/contrib/notebook/browser/models/cellMagicMapper';
|
import { CellMagicMapper } from 'sql/workbench/contrib/notebook/browser/models/cellMagicMapper';
|
||||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||||
@@ -38,7 +38,8 @@ export const NOTEBOOKEDITOR_SELECTOR: string = 'notebookeditor-component';
|
|||||||
export class NotebookEditorComponent extends AngularDisposable {
|
export class NotebookEditorComponent extends AngularDisposable {
|
||||||
private readonly defaultViewMode = ViewMode.Notebook;
|
private readonly defaultViewMode = ViewMode.Notebook;
|
||||||
private profile: IConnectionProfile;
|
private profile: IConnectionProfile;
|
||||||
private notebookManagers: INotebookManager[] = [];
|
private serializationManagers: ISerializationManager[] = [];
|
||||||
|
private executeManagers: IExecuteManager[] = [];
|
||||||
private _modelReadyDeferred = new Deferred<NotebookModel>();
|
private _modelReadyDeferred = new Deferred<NotebookModel>();
|
||||||
|
|
||||||
public model: NotebookModel;
|
public model: NotebookModel;
|
||||||
@@ -80,7 +81,8 @@ export class NotebookEditorComponent extends AngularDisposable {
|
|||||||
|
|
||||||
private async doLoad(): Promise<void> {
|
private async doLoad(): Promise<void> {
|
||||||
await this.createModelAndLoadContents();
|
await this.createModelAndLoadContents();
|
||||||
await this.setNotebookManager();
|
await this.setSerializationManager();
|
||||||
|
await this.setExecuteManager();
|
||||||
await this.loadModel();
|
await this.loadModel();
|
||||||
|
|
||||||
this.setActiveView();
|
this.setActiveView();
|
||||||
@@ -93,21 +95,23 @@ export class NotebookEditorComponent extends AngularDisposable {
|
|||||||
await this.model.requestModelLoad();
|
await this.model.requestModelLoad();
|
||||||
this.detectChanges();
|
this.detectChanges();
|
||||||
this.setContextKeyServiceWithProviderId(this.model.providerId);
|
this.setContextKeyServiceWithProviderId(this.model.providerId);
|
||||||
await this.model.startSession(this.model.notebookManager, undefined, true);
|
await this.model.startSession(this.model.executeManager, undefined, true);
|
||||||
this.fillInActionsForCurrentContext();
|
this.fillInActionsForCurrentContext();
|
||||||
this.detectChanges();
|
this.detectChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createModelAndLoadContents(): Promise<void> {
|
private async createModelAndLoadContents(): Promise<void> {
|
||||||
|
let providerInfo = await this._notebookParams.providerInfo;
|
||||||
let model = new NotebookModel({
|
let model = new NotebookModel({
|
||||||
factory: this.modelFactory,
|
factory: this.modelFactory,
|
||||||
notebookUri: this._notebookParams.notebookUri,
|
notebookUri: this._notebookParams.notebookUri,
|
||||||
connectionService: this.connectionManagementService,
|
connectionService: this.connectionManagementService,
|
||||||
notificationService: this.notificationService,
|
notificationService: this.notificationService,
|
||||||
notebookManagers: this.notebookManagers,
|
serializationManagers: this.serializationManagers,
|
||||||
contentManager: this._notebookParams.input.contentManager,
|
executeManagers: this.executeManagers,
|
||||||
|
contentLoader: this._notebookParams.input.contentLoader,
|
||||||
cellMagicMapper: new CellMagicMapper(this.notebookService.languageMagics),
|
cellMagicMapper: new CellMagicMapper(this.notebookService.languageMagics),
|
||||||
providerId: 'sql',
|
providerId: providerInfo.providerId,
|
||||||
defaultKernel: this._notebookParams.input.defaultKernel,
|
defaultKernel: this._notebookParams.input.defaultKernel,
|
||||||
layoutChanged: this._notebookParams.input.layoutChanged,
|
layoutChanged: this._notebookParams.input.layoutChanged,
|
||||||
capabilitiesService: this.capabilitiesService,
|
capabilitiesService: this.capabilitiesService,
|
||||||
@@ -132,11 +136,19 @@ export class NotebookEditorComponent extends AngularDisposable {
|
|||||||
this.detectChanges();
|
this.detectChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async setNotebookManager(): Promise<void> {
|
private async setSerializationManager(): Promise<void> {
|
||||||
let providerInfo = await this._notebookParams.providerInfo;
|
let providerInfo = await this._notebookParams.providerInfo;
|
||||||
for (let providerId of providerInfo.providers) {
|
for (let providerId of providerInfo.providers) {
|
||||||
let notebookManager = await this.notebookService.getOrCreateNotebookManager(providerId, this._notebookParams.notebookUri);
|
let manager = await this.notebookService.getOrCreateSerializationManager(providerId, this._notebookParams.notebookUri);
|
||||||
this.notebookManagers.push(notebookManager);
|
this.serializationManagers.push(manager);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async setExecuteManager(): Promise<void> {
|
||||||
|
let providerInfo = await this._notebookParams.providerInfo;
|
||||||
|
for (let providerId of providerInfo.providers) {
|
||||||
|
let manager = await this.notebookService.getOrCreateExecuteManager(providerId, this._notebookParams.notebookUri);
|
||||||
|
this.executeManagers.push(manager);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,14 +22,14 @@ import { IProductService } from 'vs/platform/product/common/productService';
|
|||||||
import { Separator } from 'vs/base/common/actions';
|
import { Separator } from 'vs/base/common/actions';
|
||||||
import { INotebookModelOptions } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
import { INotebookModelOptions } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||||
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
|
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
|
||||||
import { NotebookEditorContentManager } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
|
import { NotebookEditorContentLoader } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory';
|
import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory';
|
||||||
import { CellTypes } from 'sql/workbench/services/notebook/common/contracts';
|
import { CellTypes } from 'sql/workbench/services/notebook/common/contracts';
|
||||||
import { nb } from 'azdata';
|
import { nb } from 'azdata';
|
||||||
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
||||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||||
import { NotebookManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
|
import { ExecuteManagerStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
|
||||||
|
|
||||||
suite('CellToolbarActions', function (): void {
|
suite('CellToolbarActions', function (): void {
|
||||||
suite('removeDuplicatedAndStartingSeparators', function (): void {
|
suite('removeDuplicatedAndStartingSeparators', function (): void {
|
||||||
@@ -202,13 +202,14 @@ export async function createandLoadNotebookModel(codeContent?: nb.INotebookConte
|
|||||||
|
|
||||||
let serviceCollection = new ServiceCollection();
|
let serviceCollection = new ServiceCollection();
|
||||||
let instantiationService = new InstantiationService(serviceCollection, true);
|
let instantiationService = new InstantiationService(serviceCollection, true);
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(codeContent ? codeContent : defaultCodeContent));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(codeContent ? codeContent : defaultCodeContent));
|
||||||
let defaultModelOptions: INotebookModelOptions = {
|
let defaultModelOptions: INotebookModelOptions = {
|
||||||
notebookUri: URI.file('/some/path.ipynb'),
|
notebookUri: URI.file('/some/path.ipynb'),
|
||||||
factory: new ModelFactory(instantiationService),
|
factory: new ModelFactory(instantiationService),
|
||||||
notebookManagers: [new NotebookManagerStub()],
|
serializationManagers: [new SerializationManagerStub()],
|
||||||
contentManager: mockContentManager.object,
|
executeManagers: [new ExecuteManagerStub()],
|
||||||
|
contentLoader: mockContentManager.object,
|
||||||
notificationService: undefined,
|
notificationService: undefined,
|
||||||
connectionService: undefined,
|
connectionService: undefined,
|
||||||
providerId: 'SQL',
|
providerId: 'SQL',
|
||||||
|
|||||||
@@ -17,10 +17,11 @@ import { NodeStub, NotebookServiceStub } from 'sql/workbench/contrib/notebook/te
|
|||||||
import { basenameOrAuthority } from 'vs/base/common/resources';
|
import { basenameOrAuthority } from 'vs/base/common/resources';
|
||||||
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
|
||||||
import { IExtensionService, NullExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
import { IExtensionService, NullExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
import { INotebookService, IProviderInfo } from 'sql/workbench/services/notebook/browser/notebookService';
|
import { INotebookService, IProviderInfo, ISerializationManager } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||||
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
|
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
|
||||||
import { EditorInputCapabilities } from 'vs/workbench/common/editor';
|
import { EditorInputCapabilities } from 'vs/workbench/common/editor';
|
||||||
|
import { LocalContentManager } from 'sql/workbench/services/notebook/common/localContentManager';
|
||||||
|
|
||||||
suite('Notebook Input', function (): void {
|
suite('Notebook Input', function (): void {
|
||||||
const instantiationService = workbenchInstantiationService();
|
const instantiationService = workbenchInstantiationService();
|
||||||
@@ -39,9 +40,14 @@ suite('Notebook Input', function (): void {
|
|||||||
name: 'TestName',
|
name: 'TestName',
|
||||||
displayName: 'TestDisplayName',
|
displayName: 'TestDisplayName',
|
||||||
connectionProviderIds: ['TestId'],
|
connectionProviderIds: ['TestId'],
|
||||||
notebookProvider: 'TestProvider'
|
notebookProvider: testProvider
|
||||||
}];
|
}];
|
||||||
});
|
});
|
||||||
|
let testManager: ISerializationManager = {
|
||||||
|
providerId: testProvider,
|
||||||
|
contentManager: instantiationService.createInstance(LocalContentManager)
|
||||||
|
};
|
||||||
|
mockNotebookService.setup(s => s.getOrCreateSerializationManager(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(testManager));
|
||||||
|
|
||||||
(instantiationService as TestInstantiationService).stub(INotebookService, mockNotebookService.object);
|
(instantiationService as TestInstantiationService).stub(INotebookService, mockNotebookService.object);
|
||||||
|
|
||||||
@@ -87,11 +93,11 @@ suite('Notebook Input', function (): void {
|
|||||||
// Notebook URI
|
// Notebook URI
|
||||||
assert.deepStrictEqual(untitledNotebookInput.notebookUri, untitledUri);
|
assert.deepStrictEqual(untitledNotebookInput.notebookUri, untitledUri);
|
||||||
|
|
||||||
// Content Manager
|
// Notebook editor timestamp
|
||||||
assert.notStrictEqual(untitledNotebookInput.editorOpenedTimestamp, undefined);
|
assert.notStrictEqual(untitledNotebookInput.editorOpenedTimestamp, undefined);
|
||||||
|
|
||||||
// Notebook editor timestamp
|
// Content Loader
|
||||||
assert.notStrictEqual(untitledNotebookInput.contentManager, undefined);
|
assert.notStrictEqual(untitledNotebookInput.contentLoader, undefined);
|
||||||
|
|
||||||
// Layout changed event
|
// Layout changed event
|
||||||
assert.notStrictEqual(untitledNotebookInput.layoutChanged, undefined);
|
assert.notStrictEqual(untitledNotebookInput.layoutChanged, undefined);
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ import { NotebookModelStub } from 'sql/workbench/contrib/notebook/test/stubs';
|
|||||||
import { NotebookEditorStub } from 'sql/workbench/contrib/notebook/test/testCommon';
|
import { NotebookEditorStub } from 'sql/workbench/contrib/notebook/test/testCommon';
|
||||||
import { notebookConstants } from 'sql/workbench/services/notebook/browser/interfaces';
|
import { notebookConstants } from 'sql/workbench/services/notebook/browser/interfaces';
|
||||||
import { ICellModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
import { ICellModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||||
import { INavigationProvider, INotebookEditor, INotebookManager, INotebookParams, INotebookProvider, NavigationProviders, SQL_NOTEBOOK_PROVIDER, unsavedBooksContextKey } from 'sql/workbench/services/notebook/browser/notebookService';
|
import { INavigationProvider, INotebookEditor, IExecuteManager, INotebookParams, IExecuteProvider, NavigationProviders, SQL_NOTEBOOK_PROVIDER, unsavedBooksContextKey, ISerializationProvider, ISerializationManager } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||||
import { FailToSaveTrustState, NotebookService, NotebookServiceNoProviderRegistered, NotebookUriNotDefined, ProviderDescriptor } from 'sql/workbench/services/notebook/browser/notebookServiceImpl';
|
import { FailToSaveTrustState, NotebookService, NotebookServiceNoProviderRegistered, NotebookUriNotDefined, ExecuteProviderDescriptor, SerializationProviderDescriptor } from 'sql/workbench/services/notebook/browser/notebookServiceImpl';
|
||||||
import { NotebookChangeType } from 'sql/workbench/services/notebook/common/contracts';
|
import { NotebookChangeType } from 'sql/workbench/services/notebook/common/contracts';
|
||||||
import { Extensions, INotebookProviderRegistry, NotebookProviderRegistration } from 'sql/workbench/services/notebook/common/notebookRegistry';
|
import { INotebookProviderRegistry, NotebookProviderRegistryId, ProviderDescriptionRegistration } from 'sql/workbench/services/notebook/common/notebookRegistry';
|
||||||
import * as TypeMoq from 'typemoq';
|
import * as TypeMoq from 'typemoq';
|
||||||
import { errorHandler, onUnexpectedError } from 'vs/base/common/errors';
|
import { errorHandler, onUnexpectedError } from 'vs/base/common/errors';
|
||||||
import { Emitter, Event } from 'vs/base/common/event';
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
@@ -36,9 +36,15 @@ import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/commo
|
|||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { TestConfigurationService } from 'sql/platform/connection/test/common/testConfigurationService';
|
import { TestConfigurationService } from 'sql/platform/connection/test/common/testConfigurationService';
|
||||||
|
|
||||||
/**
|
class TestContentManager implements azdata.nb.ContentManager {
|
||||||
* class to mock azdata.nb.ServerManager object
|
deserializeNotebook(contents: string): Thenable<azdata.nb.INotebookContents> {
|
||||||
*/
|
throw new Error('Method not implemented.');
|
||||||
|
}
|
||||||
|
serializeNotebook(notebook: azdata.nb.INotebookContents): Thenable<string> {
|
||||||
|
throw new Error('Method not implemented.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class TestServerManager implements azdata.nb.ServerManager {
|
class TestServerManager implements azdata.nb.ServerManager {
|
||||||
isStarted: boolean = true; //by default our mock creates ServerManager in started mode.
|
isStarted: boolean = true; //by default our mock creates ServerManager in started mode.
|
||||||
onServerStarted: Event<void>;
|
onServerStarted: Event<void>;
|
||||||
@@ -48,14 +54,16 @@ class TestServerManager implements azdata.nb.ServerManager {
|
|||||||
async stopServer(): Promise<void> {
|
async stopServer(): Promise<void> {
|
||||||
this.isStarted = false;
|
this.isStarted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
class TestSerializationManager implements ISerializationManager {
|
||||||
* TestNotebookManager - creates a NotebookManager object that helps keep track of state needed by testing
|
constructor(
|
||||||
*/
|
public providerId: string = 'providerId1',
|
||||||
class TestNotebookManager implements INotebookManager {
|
public contentManager: TestContentManager = new TestContentManager()
|
||||||
contentManager: undefined;
|
) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestExecuteManager implements IExecuteManager {
|
||||||
sessionManager: undefined;
|
sessionManager: undefined;
|
||||||
constructor(
|
constructor(
|
||||||
public providerId: string = 'providerId1',
|
public providerId: string = 'providerId1',
|
||||||
@@ -63,16 +71,24 @@ class TestNotebookManager implements INotebookManager {
|
|||||||
) { }
|
) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
class TestSerializationProvider implements ISerializationProvider {
|
||||||
* * TestNotebookProvider - creates a NotebookManager object that helps keep track of state needed by testing
|
|
||||||
*/
|
|
||||||
class TestNotebookProvider implements INotebookProvider {
|
|
||||||
constructor(
|
constructor(
|
||||||
public providerId: string = 'providerId1',
|
public providerId: string = 'providerId1',
|
||||||
public manager: TestNotebookManager = new TestNotebookManager(providerId)
|
public manager: TestSerializationManager = new TestSerializationManager(providerId)
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
getNotebookManager(uri: URI): Thenable<INotebookManager> {
|
getSerializationManager(notebookUri: URI): Thenable<ISerializationManager> {
|
||||||
|
return Promise.resolve(this.manager);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestExecuteProvider implements IExecuteProvider {
|
||||||
|
constructor(
|
||||||
|
public providerId: string = 'providerId1',
|
||||||
|
public manager: TestExecuteManager = new TestExecuteManager(providerId)
|
||||||
|
) { }
|
||||||
|
|
||||||
|
getExecuteManager(uri: URI): Thenable<IExecuteManager> {
|
||||||
return Promise.resolve(this.manager);
|
return Promise.resolve(this.manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,9 +98,11 @@ class TestNotebookProvider implements INotebookProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
suite('ProviderDescriptor:', () => {
|
suite('ProviderDescriptor:', () => {
|
||||||
test('Verifies varies getter setters of Provider Descriptor', async () => {
|
test('Verifies various getters & setters for Serialization Provider Descriptor', async () => {
|
||||||
const notebookProvider = <INotebookProvider>{};
|
const providerId = 'TestId';
|
||||||
const providerDescriptor = new ProviderDescriptor(notebookProvider);
|
const notebookProvider = <ISerializationProvider>{};
|
||||||
|
const providerDescriptor = new SerializationProviderDescriptor(providerId, notebookProvider);
|
||||||
|
assert.strictEqual(providerDescriptor.providerId, providerId, 'providerDescriptor providerId should return correct provider ID');
|
||||||
assert.strictEqual(providerDescriptor.instance, notebookProvider, `providerDescriptor instance should be the value passed into the constructor`);
|
assert.strictEqual(providerDescriptor.instance, notebookProvider, `providerDescriptor instance should be the value passed into the constructor`);
|
||||||
const providerInstancePromise = providerDescriptor.instanceReady;
|
const providerInstancePromise = providerDescriptor.instanceReady;
|
||||||
assert.notStrictEqual(providerInstancePromise, undefined, `providerDescriptor instanceReady should not return an undefined promise object`);
|
assert.notStrictEqual(providerInstancePromise, undefined, `providerDescriptor instanceReady should not return an undefined promise object`);
|
||||||
@@ -92,9 +110,26 @@ suite('ProviderDescriptor:', () => {
|
|||||||
assert.strictEqual(result, notebookProvider, `instanceReady property of the providerDescriptor should resolve with notebookProvider object that it was constructed with`);
|
assert.strictEqual(result, notebookProvider, `instanceReady property of the providerDescriptor should resolve with notebookProvider object that it was constructed with`);
|
||||||
|
|
||||||
providerDescriptor.instance = undefined;
|
providerDescriptor.instance = undefined;
|
||||||
assert.strictEqual(providerDescriptor.instance, undefined, `provider.Descriptor instance should be undefined when we set it explicitly to undefined`);
|
assert.strictEqual(providerDescriptor.instance, undefined, `providerDescriptor instance should be undefined when we set it explicitly to undefined`);
|
||||||
providerDescriptor.instance = notebookProvider;
|
providerDescriptor.instance = notebookProvider;
|
||||||
assert.strictEqual(providerDescriptor.instance, notebookProvider, `provider.Descriptor instance should be instance: ${notebookProvider} that we explicitly set it to`);
|
assert.strictEqual(providerDescriptor.instance, notebookProvider, `providerDescriptor instance should be instance: ${notebookProvider} that we explicitly set it to`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Verifies various getters & setters for Execute Provider Descriptor', async () => {
|
||||||
|
const providerId = 'TestId';
|
||||||
|
const notebookProvider = <IExecuteProvider>{};
|
||||||
|
const providerDescriptor = new ExecuteProviderDescriptor(providerId, notebookProvider);
|
||||||
|
assert.strictEqual(providerDescriptor.providerId, providerId, 'providerDescriptor providerId should return correct provider ID');
|
||||||
|
assert.strictEqual(providerDescriptor.instance, notebookProvider, `providerDescriptor instance should be the value passed into the constructor`);
|
||||||
|
const providerInstancePromise = providerDescriptor.instanceReady;
|
||||||
|
assert.notStrictEqual(providerInstancePromise, undefined, `providerDescriptor instanceReady should not return an undefined promise object`);
|
||||||
|
const result = await providerInstancePromise;
|
||||||
|
assert.strictEqual(result, notebookProvider, `instanceReady property of the providerDescriptor should resolve with notebookProvider object that it was constructed with`);
|
||||||
|
|
||||||
|
providerDescriptor.instance = undefined;
|
||||||
|
assert.strictEqual(providerDescriptor.instance, undefined, `providerDescriptor instance should be undefined when we set it explicitly to undefined`);
|
||||||
|
providerDescriptor.instance = notebookProvider;
|
||||||
|
assert.strictEqual(providerDescriptor.instance, notebookProvider, `providerDescriptor instance should be instance: ${notebookProvider} that we explicitly set it to`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -198,7 +233,7 @@ suite.skip('NotebookService:', function (): void {
|
|||||||
await notebookService.registrationComplete;
|
await notebookService.registrationComplete;
|
||||||
assert.deepStrictEqual(notebookService.getProvidersForFileType('ipynb'), ['sql'], 'sql provider should be registered for ipynb extension');
|
assert.deepStrictEqual(notebookService.getProvidersForFileType('ipynb'), ['sql'], 'sql provider should be registered for ipynb extension');
|
||||||
|
|
||||||
const otherProviderRegistration: NotebookProviderRegistration = {
|
const otherProviderRegistration: ProviderDescriptionRegistration = {
|
||||||
fileExtensions: 'ipynb',
|
fileExtensions: 'ipynb',
|
||||||
standardKernels: {
|
standardKernels: {
|
||||||
name: 'kernel1',
|
name: 'kernel1',
|
||||||
@@ -208,8 +243,8 @@ suite.skip('NotebookService:', function (): void {
|
|||||||
provider: 'otherProvider'
|
provider: 'otherProvider'
|
||||||
};
|
};
|
||||||
|
|
||||||
const notebookRegistry = Registry.as<INotebookProviderRegistry>(Extensions.NotebookProviderContribution);
|
const notebookRegistry = Registry.as<INotebookProviderRegistry>(NotebookProviderRegistryId);
|
||||||
notebookRegistry.registerNotebookProvider(otherProviderRegistration);
|
notebookRegistry.registerProviderDescription(otherProviderRegistration);
|
||||||
|
|
||||||
assert.deepStrictEqual(notebookService.getProvidersForFileType('ipynb'), ['sql', 'otherProvider'], 'otherProvider should also be registered for ipynb extension');
|
assert.deepStrictEqual(notebookService.getProvidersForFileType('ipynb'), ['sql', 'otherProvider'], 'otherProvider should also be registered for ipynb extension');
|
||||||
assert.deepStrictEqual(notebookService.getSupportedFileExtensions(), ['IPYNB'], 'Only IPYNB should be registered as supported file extension');
|
assert.deepStrictEqual(notebookService.getSupportedFileExtensions(), ['IPYNB'], 'Only IPYNB should be registered as supported file extension');
|
||||||
@@ -223,10 +258,10 @@ suite.skip('NotebookService:', function (): void {
|
|||||||
assert.strictEqual(notebookService['_store']['_isDisposed'], true, `underlying disposable store object should be disposed state`);
|
assert.strictEqual(notebookService['_store']['_isDisposed'], true, `underlying disposable store object should be disposed state`);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('verify that getOrCreateNotebookManager does not throw when extensionService.whenInstalledExtensionRegistered() throws', async () => {
|
test('verify that getOrCreateSerializationManager does not throw when extensionService.whenInstalledExtensionRegistered() throws', async () => {
|
||||||
const providerId = 'providerId1';
|
const providerId = 'providerId1';
|
||||||
createRegisteredProviderWithManager({ notebookService, providerId });
|
createExecuteProviderWithManager({ notebookService, providerId });
|
||||||
notebookService.registerProvider(providerId, undefined);
|
notebookService.registerSerializationProvider(providerId, undefined);
|
||||||
//verify method under test logs error and does not throw when extensionService.whenInstalledExtensionRegistered() throws
|
//verify method under test logs error and does not throw when extensionService.whenInstalledExtensionRegistered() throws
|
||||||
const error: Error = new Error('Extension Registration Failed');
|
const error: Error = new Error('Extension Registration Failed');
|
||||||
extensionServiceMock.setup(x => x.whenInstalledExtensionsRegistered()).throws(error);
|
extensionServiceMock.setup(x => x.whenInstalledExtensionsRegistered()).throws(error);
|
||||||
@@ -236,18 +271,34 @@ suite.skip('NotebookService:', function (): void {
|
|||||||
assert.strictEqual(_error, error, `error object passed to logService.error call must be the one thrown from whenInstalledExtensionsRegistered call`);
|
assert.strictEqual(_error, error, `error object passed to logService.error call must be the one thrown from whenInstalledExtensionsRegistered call`);
|
||||||
})
|
})
|
||||||
.verifiable(TypeMoq.Times.once());
|
.verifiable(TypeMoq.Times.once());
|
||||||
await notebookService.getOrCreateNotebookManager(providerId, URI.parse('untitled:uri1'));
|
await notebookService.getOrCreateSerializationManager(providerId, URI.parse('untitled:uri1'));
|
||||||
logServiceMock.verifyAll();
|
logServiceMock.verifyAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('verify that getOrCreateExecuteManager does not throw when extensionService.whenInstalledExtensionRegistered() throws', async () => {
|
||||||
|
const providerId = 'providerId1';
|
||||||
|
createExecuteProviderWithManager({ notebookService, providerId });
|
||||||
|
notebookService.registerExecuteProvider(providerId, undefined);
|
||||||
|
//verify method under test logs error and does not throw when extensionService.whenInstalledExtensionRegistered() throws
|
||||||
|
const error: Error = new Error('Extension Registration Failed');
|
||||||
|
extensionServiceMock.setup(x => x.whenInstalledExtensionsRegistered()).throws(error);
|
||||||
|
|
||||||
test('verify that getOrCreateNotebookManager throws when no providers are registered', async () => {
|
logServiceMock.setup(x => x.error(TypeMoq.It.isAny()))
|
||||||
const methodName = 'getOrCreateNotebookManager';
|
.returns((_error: string | Error, ...args: any[]) => {
|
||||||
|
assert.strictEqual(_error, error, `error object passed to logService.error call must be the one thrown from whenInstalledExtensionsRegistered call`);
|
||||||
|
})
|
||||||
|
.verifiable(TypeMoq.Times.once());
|
||||||
|
await notebookService.getOrCreateExecuteManager(providerId, URI.parse('untitled:uri1'));
|
||||||
|
logServiceMock.verifyAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('verify that getOrCreateSerializationManager throws when no providers are registered', async () => {
|
||||||
|
const methodName = 'getOrCreateSerializationManager';
|
||||||
|
|
||||||
// register the builtin sql provider to be undefined
|
// register the builtin sql provider to be undefined
|
||||||
notebookService.registerProvider(SQL_NOTEBOOK_PROVIDER, undefined);
|
notebookService.registerSerializationProvider(SQL_NOTEBOOK_PROVIDER, undefined);
|
||||||
try {
|
try {
|
||||||
await notebookService.getOrCreateNotebookManager('test', URI.parse('untitled:uri1'));
|
await notebookService.getOrCreateSerializationManager('test', URI.parse('untitled:uri1'));
|
||||||
throw Error(`${methodName} did not throw as was expected`);
|
throw Error(`${methodName} did not throw as was expected`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
assert.strictEqual((error as Error).message, NotebookServiceNoProviderRegistered, `${methodName} should throw error with message:${NotebookServiceNoProviderRegistered}' when no providers are registered`);
|
assert.strictEqual((error as Error).message, NotebookServiceNoProviderRegistered, `${methodName} should throw error with message:${NotebookServiceNoProviderRegistered}' when no providers are registered`);
|
||||||
@@ -256,7 +307,29 @@ suite.skip('NotebookService:', function (): void {
|
|||||||
// when even the default provider is not registered, method under test throws exception
|
// when even the default provider is not registered, method under test throws exception
|
||||||
unRegisterProviders(notebookService);
|
unRegisterProviders(notebookService);
|
||||||
try {
|
try {
|
||||||
await notebookService.getOrCreateNotebookManager(SQL_NOTEBOOK_PROVIDER, URI.parse('untitled:uri1'));
|
await notebookService.getOrCreateSerializationManager(SQL_NOTEBOOK_PROVIDER, URI.parse('untitled:uri1'));
|
||||||
|
throw Error(`${methodName} did not throw as was expected`);
|
||||||
|
} catch (error) {
|
||||||
|
assert.strictEqual((error as Error).message, NotebookServiceNoProviderRegistered, `${methodName} should throw error with message:${NotebookServiceNoProviderRegistered}' when no providers are registered`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('verify that getOrCreateExecuteManager throws when no providers are registered', async () => {
|
||||||
|
const methodName = 'getOrCreateExecuteManager';
|
||||||
|
|
||||||
|
// register the builtin sql provider to be undefined
|
||||||
|
notebookService.registerExecuteProvider(SQL_NOTEBOOK_PROVIDER, undefined);
|
||||||
|
try {
|
||||||
|
await notebookService.getOrCreateExecuteManager('test', URI.parse('untitled:uri1'));
|
||||||
|
throw Error(`${methodName} did not throw as was expected`);
|
||||||
|
} catch (error) {
|
||||||
|
assert.strictEqual((error as Error).message, NotebookServiceNoProviderRegistered, `${methodName} should throw error with message:${NotebookServiceNoProviderRegistered}' when no providers are registered`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// when even the default provider is not registered, method under test throws exception
|
||||||
|
unRegisterProviders(notebookService);
|
||||||
|
try {
|
||||||
|
await notebookService.getOrCreateExecuteManager(SQL_NOTEBOOK_PROVIDER, URI.parse('untitled:uri1'));
|
||||||
throw Error(`${methodName} did not throw as was expected`);
|
throw Error(`${methodName} did not throw as was expected`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
assert.strictEqual((error as Error).message, NotebookServiceNoProviderRegistered, `${methodName} should throw error with message:${NotebookServiceNoProviderRegistered}' when no providers are registered`);
|
assert.strictEqual((error as Error).message, NotebookServiceNoProviderRegistered, `${methodName} should throw error with message:${NotebookServiceNoProviderRegistered}' when no providers are registered`);
|
||||||
@@ -282,27 +355,50 @@ suite.skip('NotebookService:', function (): void {
|
|||||||
assert.strictEqual(result, provider1, `${methodName} must return the provider that we registered with netbookService for the provider id: ${provider1.providerId}`);
|
assert.strictEqual(result, provider1, `${methodName} must return the provider that we registered with netbookService for the provider id: ${provider1.providerId}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('verifies return value of getOrCreateNotebookManager', async () => {
|
test('verifies return value of getOrCreateSerializationManager', async () => {
|
||||||
await notebookService.registrationComplete;
|
await notebookService.registrationComplete;
|
||||||
try {
|
try {
|
||||||
await notebookService.getOrCreateNotebookManager(SQL_NOTEBOOK_PROVIDER, undefined);
|
await notebookService.getOrCreateSerializationManager(SQL_NOTEBOOK_PROVIDER, undefined);
|
||||||
throw new Error('expected exception was not thrown');
|
throw new Error('expected exception was not thrown');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
assert.strictEqual((error as Error).message, NotebookUriNotDefined, `getOrCreateNotebookManager must throw with UriNotDefined error, when a valid uri is not provided`);
|
assert.strictEqual((error as Error).message, NotebookUriNotDefined, `getOrCreateSerializationManager must throw with UriNotDefined error, when a valid uri is not provided`);
|
||||||
}
|
}
|
||||||
const provider1Id = SQL_NOTEBOOK_PROVIDER;
|
const provider1Id = SQL_NOTEBOOK_PROVIDER;
|
||||||
const { providerId: provider2Id, manager: provider2Manager } = createRegisteredProviderWithManager({ providerId: 'provider2Id', notebookService });
|
const { providerId: provider2Id, manager: provider2Manager } = createExecuteProviderWithManager({ providerId: 'provider2Id', notebookService });
|
||||||
|
|
||||||
const uri1: URI = URI.parse(`untitled:test1`);
|
const uri1: URI = URI.parse(`untitled:test1`);
|
||||||
const uri2: URI = URI.parse(`untitled:test2`);
|
const uri2: URI = URI.parse(`untitled:test2`);
|
||||||
const result1 = await notebookService.getOrCreateNotebookManager(provider1Id, uri1);
|
const result1 = await notebookService.getOrCreateSerializationManager(provider1Id, uri1);
|
||||||
const result2 = await notebookService.getOrCreateNotebookManager(provider2Id, uri2);
|
const result2 = await notebookService.getOrCreateSerializationManager(provider2Id, uri2);
|
||||||
const result1Again = await notebookService.getOrCreateNotebookManager(provider1Id, uri1);
|
const result1Again = await notebookService.getOrCreateSerializationManager(provider1Id, uri1);
|
||||||
assert.strictEqual(result2, provider2Manager, `the notebook manager for the provider must be the one returned by getNotebookManager of the provider`);
|
assert.strictEqual(result2, provider2Manager, `the serialization manager for the provider must be the one returned by getSerializationManager of the provider`);
|
||||||
assert.notStrictEqual(result1, result2, `different notebookManagers should be returned for different uris`);
|
assert.notStrictEqual(result1, result2, `different serialization managers should be returned for different uris`);
|
||||||
assert.strictEqual(result1, result1Again, `same notebookManagers should be returned for same uri for builtin providers`);
|
assert.strictEqual(result1, result1Again, `same serialization managers should be returned for same uri for builtin providers`);
|
||||||
const result2Again = await notebookService.getOrCreateNotebookManager(provider2Id, uri2);
|
const result2Again = await notebookService.getOrCreateSerializationManager(provider2Id, uri2);
|
||||||
assert.strictEqual(result2, result2Again, `same notebookManagers should be returned for same uri for custom providers`);
|
assert.strictEqual(result2, result2Again, `same serialization managers should be returned for same uri for custom providers`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('verifies return value of getOrCreateExecuteManager', async () => {
|
||||||
|
await notebookService.registrationComplete;
|
||||||
|
try {
|
||||||
|
await notebookService.getOrCreateExecuteManager(SQL_NOTEBOOK_PROVIDER, undefined);
|
||||||
|
throw new Error('expected exception was not thrown');
|
||||||
|
} catch (error) {
|
||||||
|
assert.strictEqual((error as Error).message, NotebookUriNotDefined, `getOrCreateExecuteManager must throw with UriNotDefined error, when a valid uri is not provided`);
|
||||||
|
}
|
||||||
|
const provider1Id = SQL_NOTEBOOK_PROVIDER;
|
||||||
|
const { providerId: provider2Id, manager: provider2Manager } = createExecuteProviderWithManager({ providerId: 'provider2Id', notebookService });
|
||||||
|
|
||||||
|
const uri1: URI = URI.parse(`untitled:test1`);
|
||||||
|
const uri2: URI = URI.parse(`untitled:test2`);
|
||||||
|
const result1 = await notebookService.getOrCreateExecuteManager(provider1Id, uri1);
|
||||||
|
const result2 = await notebookService.getOrCreateExecuteManager(provider2Id, uri2);
|
||||||
|
const result1Again = await notebookService.getOrCreateExecuteManager(provider1Id, uri1);
|
||||||
|
assert.strictEqual(result2, provider2Manager, `the execute manager for the provider must be the one returned by getExecuteManager of the provider`);
|
||||||
|
assert.notStrictEqual(result1, result2, `different execute managers should be returned for different uris`);
|
||||||
|
assert.strictEqual(result1, result1Again, `same execute managers should be returned for same uri for builtin providers`);
|
||||||
|
const result2Again = await notebookService.getOrCreateExecuteManager(provider2Id, uri2);
|
||||||
|
assert.strictEqual(result2, result2Again, `same execute managers should be returned for same uri for custom providers`);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('verifies add/remove/find/list/renameNotebookEditor methods and corresponding events', async () => {
|
test('verifies add/remove/find/list/renameNotebookEditor methods and corresponding events', async () => {
|
||||||
@@ -360,24 +456,43 @@ suite.skip('NotebookService:', function (): void {
|
|||||||
assert.strictEqual(editorsRemoved, 1, `onNotebookEditorRemove should have been called that increments editorsRemoved value`);
|
assert.strictEqual(editorsRemoved, 1, `onNotebookEditorRemove should have been called that increments editorsRemoved value`);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('test registration of a new provider with multiple filetypes & kernels and verify that corresponding manager is returned by getOrCreateNotebookManager', async () => {
|
test('test registration of a new serialization provider with multiple filetypes & kernels and verify that corresponding manager is returned by getOrCreateSerializationManager methods', async () => {
|
||||||
const providerId = 'Jpeg';
|
const providerId = 'Jpeg';
|
||||||
const notebookProviderRegistration = <NotebookProviderRegistration>{
|
const notebookProviderRegistration = <ProviderDescriptionRegistration>{
|
||||||
provider: providerId,
|
provider: providerId,
|
||||||
fileExtensions: ['jpeg', 'jpg'],
|
fileExtensions: ['jpeg', 'jpg'],
|
||||||
standardKernels: [<azdata.nb.IStandardKernel>{ name: 'kernel1' }, <azdata.nb.IStandardKernel>{ name: 'kernel2' }]
|
standardKernels: [<azdata.nb.IStandardKernel>{ name: 'kernel1' }, <azdata.nb.IStandardKernel>{ name: 'kernel2' }]
|
||||||
};
|
};
|
||||||
const notebookRegistry = Registry.as<INotebookProviderRegistry>(Extensions.NotebookProviderContribution);
|
const notebookRegistry = Registry.as<INotebookProviderRegistry>(NotebookProviderRegistryId);
|
||||||
notebookRegistry.registerNotebookProvider(notebookProviderRegistration);
|
notebookRegistry.registerProviderDescription(notebookProviderRegistration);
|
||||||
const managerPromise = notebookService.getOrCreateNotebookManager(providerId, URI.parse('untitled:jpg'));
|
|
||||||
const providerInstance = createRegisteredProviderWithManager({ notebookService, providerId });
|
const serializationManagerPromise = notebookService.getOrCreateSerializationManager(providerId, URI.parse('untitled:jpg'));
|
||||||
notebookService.registerProvider(providerId, providerInstance);
|
const serializationProviderInstance = createSerializationProviderWithManager({ notebookService, providerId });
|
||||||
const result = await managerPromise;
|
notebookService.registerSerializationProvider(providerId, serializationProviderInstance);
|
||||||
|
const serializationResult = await serializationManagerPromise;
|
||||||
|
|
||||||
// verify result
|
// verify result
|
||||||
assert.strictEqual(result, providerInstance.manager, `createRegisteredProviderWithManager must return the manager corresponding to INotebookProvider that we registered`);
|
assert.strictEqual(serializationResult, serializationProviderInstance.manager, `createSerializationProviderWithManager must return the serialization manager corresponding to ISerializationProvider that we registered`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('test registration of a new execute provider with multiple filetypes & kernels and verify that corresponding manager is returned by getOrCreateExecuteManager methods', async () => {
|
||||||
|
const providerId = 'Jpeg';
|
||||||
|
const notebookProviderRegistration = <ProviderDescriptionRegistration>{
|
||||||
|
provider: providerId,
|
||||||
|
fileExtensions: ['jpeg', 'jpg'],
|
||||||
|
standardKernels: [<azdata.nb.IStandardKernel>{ name: 'kernel1' }, <azdata.nb.IStandardKernel>{ name: 'kernel2' }]
|
||||||
|
};
|
||||||
|
const notebookRegistry = Registry.as<INotebookProviderRegistry>(NotebookProviderRegistryId);
|
||||||
|
notebookRegistry.registerProviderDescription(notebookProviderRegistration);
|
||||||
|
|
||||||
|
const executeManagerPromise = notebookService.getOrCreateExecuteManager(providerId, URI.parse('untitled:jpg'));
|
||||||
|
const executeProviderInstance = createExecuteProviderWithManager({ notebookService, providerId });
|
||||||
|
notebookService.registerExecuteProvider(providerId, executeProviderInstance);
|
||||||
|
const executeResult = await executeManagerPromise;
|
||||||
|
|
||||||
|
// verify result
|
||||||
|
assert.strictEqual(executeResult, executeProviderInstance.manager, `createExecuteProviderWithManager must return the execute manager corresponding to IExecuteProvider that we registered`);
|
||||||
|
});
|
||||||
|
|
||||||
test('verify that firing of extensionService.onDidUninstallExtension event calls removeContributedProvidersFromCache', async () => {
|
test('verify that firing of extensionService.onDidUninstallExtension event calls removeContributedProvidersFromCache', async () => {
|
||||||
const methodName = 'removeContributedProvidersFromCache';
|
const methodName = 'removeContributedProvidersFromCache';
|
||||||
@@ -480,7 +595,7 @@ suite.skip('NotebookService:', function (): void {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
suite(`serialization tests`, () => {
|
suite(`serialization state tests`, () => {
|
||||||
for (const isTrusted of [true, false, undefined]) {
|
for (const isTrusted of [true, false, undefined]) {
|
||||||
for (const isModelTrusted of [true, false]) {
|
for (const isModelTrusted of [true, false]) {
|
||||||
if (isTrusted !== undefined && !isModelTrusted) {
|
if (isTrusted !== undefined && !isModelTrusted) {
|
||||||
@@ -576,10 +691,11 @@ suite.skip('NotebookService:', function (): void {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function unRegisterProviders(notebookService: NotebookService) {
|
function unRegisterProviders(notebookService: NotebookService) {
|
||||||
const notebookRegistry = Registry.as<INotebookProviderRegistry>(Extensions.NotebookProviderContribution);
|
const notebookRegistry = Registry.as<INotebookProviderRegistry>(NotebookProviderRegistryId);
|
||||||
// unregister all builtin providers
|
// unregister all builtin providers
|
||||||
for (const providerContribution of notebookRegistry.providers) {
|
for (const providerContribution of notebookRegistry.providerDescriptions) {
|
||||||
notebookService.unregisterProvider(providerContribution.provider);
|
notebookService.unregisterSerializationProvider(providerContribution.provider);
|
||||||
|
notebookService.unregisterExecuteProvider(providerContribution.provider);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -595,21 +711,32 @@ function setTrustedSetup(notebookService: NotebookService) {
|
|||||||
return notebookUri;
|
return notebookUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createRegisteredProviderWithManager({ notebookService, providerId = 'providerId', testProviderManagers = undefined }: { providerId?: string; notebookService: NotebookService; testProviderManagers?: TestNotebookProvider[] }): TestNotebookProvider {
|
function createSerializationProviderWithManager({ notebookService, providerId = 'providerId', testProviderManagers = undefined }: { providerId?: string; notebookService: NotebookService; testProviderManagers?: TestSerializationProvider[] }): TestSerializationProvider {
|
||||||
const provider = new TestNotebookProvider(providerId);
|
const provider = new TestSerializationProvider(providerId);
|
||||||
notebookService.registerProvider(providerId, provider);
|
notebookService.registerSerializationProvider(providerId, provider);
|
||||||
if (testProviderManagers !== undefined) {
|
if (testProviderManagers !== undefined) {
|
||||||
testProviderManagers.push(provider);
|
testProviderManagers.push(provider);
|
||||||
}
|
}
|
||||||
return provider;
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addManagers({ notebookService, prefix = 'providerId', uriPrefix = 'id', count = 1 }: { notebookService: NotebookService; prefix?: string; uriPrefix?: string; count?: number; }): Promise<TestNotebookProvider[]> {
|
function createExecuteProviderWithManager({ notebookService, providerId = 'providerId', testProviderManagers = undefined }: { providerId?: string; notebookService: NotebookService; testProviderManagers?: TestExecuteProvider[] }): TestExecuteProvider {
|
||||||
|
const provider = new TestExecuteProvider(providerId);
|
||||||
|
notebookService.registerExecuteProvider(providerId, provider);
|
||||||
|
if (testProviderManagers !== undefined) {
|
||||||
|
testProviderManagers.push(provider);
|
||||||
|
}
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addManagers({ notebookService, prefix = 'providerId', uriPrefix = 'id', count = 1 }: { notebookService: NotebookService; prefix?: string; uriPrefix?: string; count?: number; }): Promise<TestExecuteProvider[]> {
|
||||||
const testProviderManagers = [];
|
const testProviderManagers = [];
|
||||||
for (let i: number = 1; i <= count; i++) {
|
for (let i: number = 1; i <= count; i++) {
|
||||||
const providerId = `${prefix}${i}`;
|
const providerId = `${prefix}${i}`;
|
||||||
createRegisteredProviderWithManager({ providerId, notebookService, testProviderManagers });
|
createSerializationProviderWithManager({ providerId, notebookService, testProviderManagers });
|
||||||
await notebookService.getOrCreateNotebookManager(providerId, URI.parse(`${uriPrefix}${i}`));
|
createExecuteProviderWithManager({ providerId, notebookService, testProviderManagers });
|
||||||
|
await notebookService.getOrCreateSerializationManager(providerId, URI.parse(`${uriPrefix}${i}`));
|
||||||
|
await notebookService.getOrCreateExecuteManager(providerId, URI.parse(`${uriPrefix}${i}`));
|
||||||
}
|
}
|
||||||
return testProviderManagers;
|
return testProviderManagers;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
|
|||||||
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
|
||||||
import { NotebookManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
|
import { ExecuteManagerStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
|
||||||
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
|
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
|
||||||
import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory';
|
import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory';
|
||||||
import { INotebookModelOptions } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
import { INotebookModelOptions } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||||
@@ -24,7 +24,7 @@ import { InstantiationService } from 'vs/platform/instantiation/common/instantia
|
|||||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||||
import { NullLogService } from 'vs/platform/log/common/log';
|
import { NullLogService } from 'vs/platform/log/common/log';
|
||||||
import { TestConnectionManagementService } from 'sql/platform/connection/test/common/testConnectionManagementService';
|
import { TestConnectionManagementService } from 'sql/platform/connection/test/common/testConnectionManagementService';
|
||||||
import { NotebookEditorContentManager } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
|
import { NotebookEditorContentLoader } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
|
||||||
import { SessionManager } from 'sql/workbench/contrib/notebook/test/emptySessionClasses';
|
import { SessionManager } from 'sql/workbench/contrib/notebook/test/emptySessionClasses';
|
||||||
import { NullAdsTelemetryService } from 'sql/platform/telemetry/common/adsTelemetryService';
|
import { NullAdsTelemetryService } from 'sql/platform/telemetry/common/adsTelemetryService';
|
||||||
import { CellTypes } from 'sql/workbench/services/notebook/common/contracts';
|
import { CellTypes } from 'sql/workbench/services/notebook/common/contracts';
|
||||||
@@ -79,7 +79,8 @@ let configurationService: IConfigurationService;
|
|||||||
|
|
||||||
suite('NotebookViewModel', function (): void {
|
suite('NotebookViewModel', function (): void {
|
||||||
let defaultViewName = 'Default New View';
|
let defaultViewName = 'Default New View';
|
||||||
let notebookManagers = [new NotebookManagerStub()];
|
let serializationManagers = [new SerializationManagerStub()];
|
||||||
|
let executeManagers = [new ExecuteManagerStub()];
|
||||||
let mockSessionManager: TypeMoq.Mock<nb.SessionManager>;
|
let mockSessionManager: TypeMoq.Mock<nb.SessionManager>;
|
||||||
let memento: TypeMoq.Mock<Memento>;
|
let memento: TypeMoq.Mock<Memento>;
|
||||||
let queryConnectionService: TypeMoq.Mock<TestConnectionManagementService>;
|
let queryConnectionService: TypeMoq.Mock<TestConnectionManagementService>;
|
||||||
@@ -239,7 +240,7 @@ suite('NotebookViewModel', function (): void {
|
|||||||
|
|
||||||
function setupServices() {
|
function setupServices() {
|
||||||
mockSessionManager = TypeMoq.Mock.ofType(SessionManager);
|
mockSessionManager = TypeMoq.Mock.ofType(SessionManager);
|
||||||
notebookManagers[0].sessionManager = mockSessionManager.object;
|
executeManagers[0].sessionManager = mockSessionManager.object;
|
||||||
notificationService = TypeMoq.Mock.ofType<INotificationService>(TestNotificationService, TypeMoq.MockBehavior.Loose);
|
notificationService = TypeMoq.Mock.ofType<INotificationService>(TestNotificationService, TypeMoq.MockBehavior.Loose);
|
||||||
capabilitiesService = TypeMoq.Mock.ofType<ICapabilitiesService>(TestCapabilitiesService);
|
capabilitiesService = TypeMoq.Mock.ofType<ICapabilitiesService>(TestCapabilitiesService);
|
||||||
memento = TypeMoq.Mock.ofType(Memento, TypeMoq.MockBehavior.Loose, '');
|
memento = TypeMoq.Mock.ofType(Memento, TypeMoq.MockBehavior.Loose, '');
|
||||||
@@ -252,8 +253,9 @@ suite('NotebookViewModel', function (): void {
|
|||||||
defaultModelOptions = {
|
defaultModelOptions = {
|
||||||
notebookUri: defaultUri,
|
notebookUri: defaultUri,
|
||||||
factory: new ModelFactory(instantiationService),
|
factory: new ModelFactory(instantiationService),
|
||||||
notebookManagers,
|
serializationManagers: serializationManagers,
|
||||||
contentManager: undefined,
|
executeManagers: executeManagers,
|
||||||
|
contentLoader: undefined,
|
||||||
notificationService: notificationService.object,
|
notificationService: notificationService.object,
|
||||||
connectionService: queryConnectionService.object,
|
connectionService: queryConnectionService.object,
|
||||||
providerId: 'SQL',
|
providerId: 'SQL',
|
||||||
@@ -265,9 +267,9 @@ suite('NotebookViewModel', function (): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function initializeNotebookViewsExtension(contents: nb.INotebookContents): Promise<NotebookViewsExtension> {
|
async function initializeNotebookViewsExtension(contents: nb.INotebookContents): Promise<NotebookViewsExtension> {
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(contents));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(contents));
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
|
|
||||||
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
||||||
await model.loadContents();
|
await model.loadContents();
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilit
|
|||||||
import { TestCapabilitiesService } from 'sql/platform/capabilities/test/common/testCapabilitiesService';
|
import { TestCapabilitiesService } from 'sql/platform/capabilities/test/common/testCapabilitiesService';
|
||||||
import { TestConnectionManagementService } from 'sql/platform/connection/test/common/testConnectionManagementService';
|
import { TestConnectionManagementService } from 'sql/platform/connection/test/common/testConnectionManagementService';
|
||||||
import { NullAdsTelemetryService } from 'sql/platform/telemetry/common/adsTelemetryService';
|
import { NullAdsTelemetryService } from 'sql/platform/telemetry/common/adsTelemetryService';
|
||||||
import { NotebookEditorContentManager } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
|
import { NotebookEditorContentLoader } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
|
||||||
import { DeleteViewAction, InsertCellAction } from 'sql/workbench/contrib/notebook/browser/notebookViews/notebookViewsActions';
|
import { DeleteViewAction, InsertCellAction } from 'sql/workbench/contrib/notebook/browser/notebookViews/notebookViewsActions';
|
||||||
import { SessionManager } from 'sql/workbench/contrib/notebook/test/emptySessionClasses';
|
import { SessionManager } from 'sql/workbench/contrib/notebook/test/emptySessionClasses';
|
||||||
import { NotebookManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
|
import { ExecuteManagerStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
|
||||||
import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory';
|
import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory';
|
||||||
import { ICellModel, INotebookModelOptions, ViewMode } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
import { ICellModel, INotebookModelOptions, ViewMode } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||||
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
|
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
|
||||||
@@ -58,7 +58,8 @@ let initialNotebookContent: nb.INotebookContents = {
|
|||||||
|
|
||||||
suite('Notebook Views Actions', function (): void {
|
suite('Notebook Views Actions', function (): void {
|
||||||
let defaultViewName = 'Default New View';
|
let defaultViewName = 'Default New View';
|
||||||
let notebookManagers = [new NotebookManagerStub()];
|
let serializationManagers = [new SerializationManagerStub()];
|
||||||
|
let executeManagers = [new ExecuteManagerStub()];
|
||||||
let mockSessionManager: TypeMoq.Mock<nb.SessionManager>;
|
let mockSessionManager: TypeMoq.Mock<nb.SessionManager>;
|
||||||
let memento: TypeMoq.Mock<Memento>;
|
let memento: TypeMoq.Mock<Memento>;
|
||||||
let queryConnectionService: TypeMoq.Mock<TestConnectionManagementService>;
|
let queryConnectionService: TypeMoq.Mock<TestConnectionManagementService>;
|
||||||
@@ -164,7 +165,7 @@ suite('Notebook Views Actions', function (): void {
|
|||||||
|
|
||||||
function setupServices() {
|
function setupServices() {
|
||||||
mockSessionManager = TypeMoq.Mock.ofType(SessionManager);
|
mockSessionManager = TypeMoq.Mock.ofType(SessionManager);
|
||||||
notebookManagers[0].sessionManager = mockSessionManager.object;
|
executeManagers[0].sessionManager = mockSessionManager.object;
|
||||||
notificationService = TypeMoq.Mock.ofType<INotificationService>(TestNotificationService, TypeMoq.MockBehavior.Loose);
|
notificationService = TypeMoq.Mock.ofType<INotificationService>(TestNotificationService, TypeMoq.MockBehavior.Loose);
|
||||||
capabilitiesService = TypeMoq.Mock.ofType<ICapabilitiesService>(TestCapabilitiesService);
|
capabilitiesService = TypeMoq.Mock.ofType<ICapabilitiesService>(TestCapabilitiesService);
|
||||||
memento = TypeMoq.Mock.ofType(Memento, TypeMoq.MockBehavior.Loose, '');
|
memento = TypeMoq.Mock.ofType(Memento, TypeMoq.MockBehavior.Loose, '');
|
||||||
@@ -177,8 +178,9 @@ suite('Notebook Views Actions', function (): void {
|
|||||||
defaultModelOptions = {
|
defaultModelOptions = {
|
||||||
notebookUri: defaultUri,
|
notebookUri: defaultUri,
|
||||||
factory: new ModelFactory(instantiationService),
|
factory: new ModelFactory(instantiationService),
|
||||||
notebookManagers,
|
serializationManagers: serializationManagers,
|
||||||
contentManager: undefined,
|
executeManagers: executeManagers,
|
||||||
|
contentLoader: undefined,
|
||||||
notificationService: notificationService.object,
|
notificationService: notificationService.object,
|
||||||
connectionService: queryConnectionService.object,
|
connectionService: queryConnectionService.object,
|
||||||
providerId: 'SQL',
|
providerId: 'SQL',
|
||||||
@@ -190,9 +192,9 @@ suite('Notebook Views Actions', function (): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function initializeNotebookViewsExtension(contents: nb.INotebookContents): Promise<NotebookViewsExtension> {
|
async function initializeNotebookViewsExtension(contents: nb.INotebookContents): Promise<NotebookViewsExtension> {
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(contents));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(contents));
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
|
|
||||||
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
||||||
await model.loadContents();
|
await model.loadContents();
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
|
|||||||
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
|
||||||
import { NotebookManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
|
import { ExecuteManagerStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
|
||||||
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
|
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
|
||||||
import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory';
|
import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory';
|
||||||
import { INotebookModelOptions } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
import { INotebookModelOptions } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||||
@@ -24,7 +24,7 @@ import { InstantiationService } from 'vs/platform/instantiation/common/instantia
|
|||||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||||
import { NullLogService } from 'vs/platform/log/common/log';
|
import { NullLogService } from 'vs/platform/log/common/log';
|
||||||
import { TestConnectionManagementService } from 'sql/platform/connection/test/common/testConnectionManagementService';
|
import { TestConnectionManagementService } from 'sql/platform/connection/test/common/testConnectionManagementService';
|
||||||
import { NotebookEditorContentManager } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
|
import { NotebookEditorContentLoader } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
|
||||||
import { SessionManager } from 'sql/workbench/contrib/notebook/test/emptySessionClasses';
|
import { SessionManager } from 'sql/workbench/contrib/notebook/test/emptySessionClasses';
|
||||||
import { NullAdsTelemetryService } from 'sql/platform/telemetry/common/adsTelemetryService';
|
import { NullAdsTelemetryService } from 'sql/platform/telemetry/common/adsTelemetryService';
|
||||||
import { CellTypes } from 'sql/workbench/services/notebook/common/contracts';
|
import { CellTypes } from 'sql/workbench/services/notebook/common/contracts';
|
||||||
@@ -62,7 +62,8 @@ let configurationService: IConfigurationService;
|
|||||||
|
|
||||||
suite('NotebookViews', function (): void {
|
suite('NotebookViews', function (): void {
|
||||||
let defaultViewName = 'Default New View';
|
let defaultViewName = 'Default New View';
|
||||||
let notebookManagers = [new NotebookManagerStub()];
|
let serializationManagers = [new SerializationManagerStub()];
|
||||||
|
let executeManagers = [new ExecuteManagerStub()];
|
||||||
let mockSessionManager: TypeMoq.Mock<nb.SessionManager>;
|
let mockSessionManager: TypeMoq.Mock<nb.SessionManager>;
|
||||||
let memento: TypeMoq.Mock<Memento>;
|
let memento: TypeMoq.Mock<Memento>;
|
||||||
let queryConnectionService: TypeMoq.Mock<TestConnectionManagementService>;
|
let queryConnectionService: TypeMoq.Mock<TestConnectionManagementService>;
|
||||||
@@ -131,7 +132,7 @@ suite('NotebookViews', function (): void {
|
|||||||
|
|
||||||
function setupServices() {
|
function setupServices() {
|
||||||
mockSessionManager = TypeMoq.Mock.ofType(SessionManager);
|
mockSessionManager = TypeMoq.Mock.ofType(SessionManager);
|
||||||
notebookManagers[0].sessionManager = mockSessionManager.object;
|
executeManagers[0].sessionManager = mockSessionManager.object;
|
||||||
notificationService = TypeMoq.Mock.ofType<INotificationService>(TestNotificationService, TypeMoq.MockBehavior.Loose);
|
notificationService = TypeMoq.Mock.ofType<INotificationService>(TestNotificationService, TypeMoq.MockBehavior.Loose);
|
||||||
capabilitiesService = TypeMoq.Mock.ofType<ICapabilitiesService>(TestCapabilitiesService);
|
capabilitiesService = TypeMoq.Mock.ofType<ICapabilitiesService>(TestCapabilitiesService);
|
||||||
memento = TypeMoq.Mock.ofType(Memento, TypeMoq.MockBehavior.Loose, '');
|
memento = TypeMoq.Mock.ofType(Memento, TypeMoq.MockBehavior.Loose, '');
|
||||||
@@ -144,8 +145,9 @@ suite('NotebookViews', function (): void {
|
|||||||
defaultModelOptions = {
|
defaultModelOptions = {
|
||||||
notebookUri: defaultUri,
|
notebookUri: defaultUri,
|
||||||
factory: new ModelFactory(instantiationService),
|
factory: new ModelFactory(instantiationService),
|
||||||
notebookManagers,
|
serializationManagers: serializationManagers,
|
||||||
contentManager: undefined,
|
executeManagers: executeManagers,
|
||||||
|
contentLoader: undefined,
|
||||||
notificationService: notificationService.object,
|
notificationService: notificationService.object,
|
||||||
connectionService: queryConnectionService.object,
|
connectionService: queryConnectionService.object,
|
||||||
providerId: 'SQL',
|
providerId: 'SQL',
|
||||||
@@ -157,9 +159,9 @@ suite('NotebookViews', function (): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function initializeExtension(): Promise<NotebookViewsExtension> {
|
async function initializeExtension(): Promise<NotebookViewsExtension> {
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(initialNotebookContent));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(initialNotebookContent));
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
|
|
||||||
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
||||||
await model.loadContents();
|
await model.loadContents();
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ import { URI } from 'vs/base/common/uri';
|
|||||||
|
|
||||||
import { ClientSession } from 'sql/workbench/services/notebook/browser/models/clientSession';
|
import { ClientSession } from 'sql/workbench/services/notebook/browser/models/clientSession';
|
||||||
import { SessionManager, EmptySession } from 'sql/workbench/contrib/notebook/test/emptySessionClasses';
|
import { SessionManager, EmptySession } from 'sql/workbench/contrib/notebook/test/emptySessionClasses';
|
||||||
import { NotebookManagerStub, ServerManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
|
import { ExecuteManagerStub, ServerManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
|
||||||
import { isUndefinedOrNull } from 'vs/base/common/types';
|
import { isUndefinedOrNull } from 'vs/base/common/types';
|
||||||
|
|
||||||
suite('Client Session', function (): void {
|
suite('Client Session', function (): void {
|
||||||
let path = URI.file('my/notebook.ipynb');
|
let path = URI.file('my/notebook.ipynb');
|
||||||
let notebookManager: NotebookManagerStub;
|
let notebookManager: ExecuteManagerStub;
|
||||||
let serverManager: ServerManagerStub;
|
let serverManager: ServerManagerStub;
|
||||||
let mockSessionManager: TypeMoq.Mock<nb.SessionManager>;
|
let mockSessionManager: TypeMoq.Mock<nb.SessionManager>;
|
||||||
let notificationService: TypeMoq.Mock<INotificationService>;
|
let notificationService: TypeMoq.Mock<INotificationService>;
|
||||||
@@ -27,19 +27,19 @@ suite('Client Session', function (): void {
|
|||||||
setup(() => {
|
setup(() => {
|
||||||
serverManager = new ServerManagerStub();
|
serverManager = new ServerManagerStub();
|
||||||
mockSessionManager = TypeMoq.Mock.ofType(SessionManager);
|
mockSessionManager = TypeMoq.Mock.ofType(SessionManager);
|
||||||
notebookManager = new NotebookManagerStub();
|
notebookManager = new ExecuteManagerStub();
|
||||||
notebookManager.serverManager = serverManager;
|
notebookManager.serverManager = serverManager;
|
||||||
notebookManager.sessionManager = mockSessionManager.object;
|
notebookManager.sessionManager = mockSessionManager.object;
|
||||||
notificationService = TypeMoq.Mock.ofType<INotificationService>(TestNotificationService, TypeMoq.MockBehavior.Loose);
|
notificationService = TypeMoq.Mock.ofType<INotificationService>(TestNotificationService, TypeMoq.MockBehavior.Loose);
|
||||||
|
|
||||||
session = new ClientSession({
|
session = new ClientSession({
|
||||||
notebookManager: notebookManager,
|
executeManager: notebookManager,
|
||||||
notebookUri: path,
|
notebookUri: path,
|
||||||
notificationService: notificationService.object,
|
notificationService: notificationService.object,
|
||||||
kernelSpec: { name: 'python', display_name: 'Python 3', language: 'python' }
|
kernelSpec: { name: 'python', display_name: 'Python 3', language: 'python' }
|
||||||
});
|
});
|
||||||
|
|
||||||
let serverlessNotebookManager = new NotebookManagerStub();
|
let serverlessNotebookManager = new ExecuteManagerStub();
|
||||||
serverlessNotebookManager.sessionManager = mockSessionManager.object;
|
serverlessNotebookManager.sessionManager = mockSessionManager.object;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@ suite('Client Session', function (): void {
|
|||||||
|
|
||||||
let remoteSession = new ClientSession({
|
let remoteSession = new ClientSession({
|
||||||
kernelSpec: { name: 'python', display_name: 'Python 3', language: 'python' },
|
kernelSpec: { name: 'python', display_name: 'Python 3', language: 'python' },
|
||||||
notebookManager: newNotebookManager,
|
executeManager: newNotebookManager,
|
||||||
notebookUri: path,
|
notebookUri: path,
|
||||||
notificationService: notificationService.object
|
notificationService: notificationService.object
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,14 +10,12 @@ import * as fs from 'fs';
|
|||||||
import * as pfs from 'vs/base/node/pfs';
|
import * as pfs from 'vs/base/node/pfs';
|
||||||
|
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import * as tempWrite from 'temp-write';
|
|
||||||
import { LocalContentManager } from 'sql/workbench/services/notebook/common/localContentManager';
|
import { LocalContentManager } from 'sql/workbench/services/notebook/common/localContentManager';
|
||||||
import { CellTypes } from 'sql/workbench/services/notebook/common/contracts';
|
import { CellTypes } from 'sql/workbench/services/notebook/common/contracts';
|
||||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||||
import { TestFileService } from 'vs/workbench/test/browser/workbenchTestServices';
|
import { TestFileService } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||||
import { IFileService, IReadFileOptions, IFileContent, IWriteFileOptions, IFileStatWithMetadata } from 'vs/platform/files/common/files';
|
import { IFileService, IReadFileOptions, IFileContent, IWriteFileOptions, IFileStatWithMetadata } from 'vs/platform/files/common/files';
|
||||||
import { VSBuffer, VSBufferReadable } from 'vs/base/common/buffer';
|
import { VSBuffer, VSBufferReadable } from 'vs/base/common/buffer';
|
||||||
import { isUndefinedOrNull } from 'vs/base/common/types';
|
|
||||||
import { promisify } from 'util';
|
import { promisify } from 'util';
|
||||||
|
|
||||||
let expectedNotebookContent: nb.INotebookContents = {
|
let expectedNotebookContent: nb.INotebookContents = {
|
||||||
@@ -69,34 +67,15 @@ suite('Local Content Manager', function (): void {
|
|||||||
contentManager = instantiationService.createInstance(LocalContentManager);
|
contentManager = instantiationService.createInstance(LocalContentManager);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Should return undefined if path is undefined', async function (): Promise<void> {
|
|
||||||
let content = await contentManager.getNotebookContents(undefined);
|
|
||||||
assert(isUndefinedOrNull(content));
|
|
||||||
// tslint:disable-next-line:no-null-keyword
|
|
||||||
content = await contentManager.getNotebookContents(null);
|
|
||||||
assert(isUndefinedOrNull(content));
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Should throw if file does not exist', async function (): Promise<void> {
|
|
||||||
try {
|
|
||||||
await contentManager.getNotebookContents(URI.file('/path/doesnot/exist.ipynb'));
|
|
||||||
assert.fail('expected to throw');
|
|
||||||
} catch (e) { }
|
|
||||||
});
|
|
||||||
test('Should return notebook contents parsed as INotebook when valid notebook file parsed', async function (): Promise<void> {
|
test('Should return notebook contents parsed as INotebook when valid notebook file parsed', async function (): Promise<void> {
|
||||||
// Given a file containing a valid notebook
|
let notebook = await contentManager.deserializeNotebook(notebookContentString);
|
||||||
let localFile = tempWrite.sync(notebookContentString, 'notebook.ipynb');
|
|
||||||
// when I read the content
|
|
||||||
let notebook = await contentManager.getNotebookContents(URI.file(localFile));
|
|
||||||
// then I expect notebook format to match
|
// then I expect notebook format to match
|
||||||
verifyMatchesExpectedNotebook(notebook);
|
verifyMatchesExpectedNotebook(notebook);
|
||||||
});
|
});
|
||||||
test('Should ignore invalid content in the notebook file', async function (): Promise<void> {
|
test('Should ignore invalid content in the notebook file', async function (): Promise<void> {
|
||||||
// Given a file containing a notebook with some garbage properties
|
// Given a file containing a notebook with some garbage properties
|
||||||
let invalidContent = notebookContentString + '\\nasddfdsafasdf';
|
let invalidContent = notebookContentString + '\\nasddfdsafasdf';
|
||||||
let localFile = tempWrite.sync(invalidContent, 'notebook.ipynb');
|
let notebook = await contentManager.deserializeNotebook(invalidContent);
|
||||||
// when I read the content
|
|
||||||
let notebook = await contentManager.getNotebookContents(URI.file(localFile));
|
|
||||||
// then I expect notebook format to still be valid
|
// then I expect notebook format to still be valid
|
||||||
verifyMatchesExpectedNotebook(notebook);
|
verifyMatchesExpectedNotebook(notebook);
|
||||||
});
|
});
|
||||||
@@ -130,10 +109,8 @@ suite('Local Content Manager', function (): void {
|
|||||||
nbformat_minor: 2
|
nbformat_minor: 2
|
||||||
};
|
};
|
||||||
let mimeContentString = JSON.stringify(mimeNotebook);
|
let mimeContentString = JSON.stringify(mimeNotebook);
|
||||||
// Given a file containing a valid notebook with multiline mime type
|
|
||||||
let localFile = tempWrite.sync(mimeContentString, 'notebook.ipynb');
|
|
||||||
// when I read the content
|
// when I read the content
|
||||||
let notebook = await contentManager.getNotebookContents(URI.file(localFile));
|
let notebook = await contentManager.deserializeNotebook(mimeContentString);
|
||||||
// then I expect output to have been normalized into a single string
|
// then I expect output to have been normalized into a single string
|
||||||
let displayOutput = <nb.IDisplayData>notebook.cells[0].outputs[0];
|
let displayOutput = <nb.IDisplayData>notebook.cells[0].outputs[0];
|
||||||
assert.strictEqual(displayOutput.data['text/html'], '<div></div>');
|
assert.strictEqual(displayOutput.data['text/html'], '<div></div>');
|
||||||
@@ -141,7 +118,7 @@ suite('Local Content Manager', function (): void {
|
|||||||
|
|
||||||
test('Should create a new empty notebook if content is undefined', async function (): Promise<void> {
|
test('Should create a new empty notebook if content is undefined', async function (): Promise<void> {
|
||||||
// verify that when loading content from an empty string, a new notebook is created.
|
// verify that when loading content from an empty string, a new notebook is created.
|
||||||
let content = await contentManager.loadFromContentString(undefined);
|
let content = await contentManager.deserializeNotebook(undefined);
|
||||||
assert.strictEqual(content.metadata, undefined, 'Verify that metadata is undefined');
|
assert.strictEqual(content.metadata, undefined, 'Verify that metadata is undefined');
|
||||||
// verify that the notebook is empty
|
// verify that the notebook is empty
|
||||||
assert.strictEqual(content.cells.length, 0, 'Notebook should be empty, so the number of cells should be 0');
|
assert.strictEqual(content.cells.length, 0, 'Notebook should be empty, so the number of cells should be 0');
|
||||||
@@ -149,12 +126,22 @@ suite('Local Content Manager', function (): void {
|
|||||||
|
|
||||||
test('Should create a new empty notebook if content is an empty string', async function (): Promise<void> {
|
test('Should create a new empty notebook if content is an empty string', async function (): Promise<void> {
|
||||||
// verify that when loading content from an empty string, a new notebook is created.
|
// verify that when loading content from an empty string, a new notebook is created.
|
||||||
let content = await contentManager.loadFromContentString('');
|
let content = await contentManager.deserializeNotebook('');
|
||||||
assert.strictEqual(content.metadata, undefined, 'Verify that metadata is undefined');
|
assert.strictEqual(content.metadata, undefined, 'Verify that metadata is undefined');
|
||||||
// verify that the notebook is empty
|
// verify that the notebook is empty
|
||||||
assert.strictEqual(content.cells.length, 0, 'Notebook should be empty, so the number of cells should be 0');
|
assert.strictEqual(content.cells.length, 0, 'Notebook should be empty, so the number of cells should be 0');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Should return undefined if notebook contents are undefined', async function (): Promise<void> {
|
||||||
|
let strContent = await contentManager.serializeNotebook(undefined);
|
||||||
|
assert.strictEqual(strContent, undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should return stringified version of notebook contents', async function (): Promise<void> {
|
||||||
|
let strContent = await contentManager.serializeNotebook(expectedNotebookContent);
|
||||||
|
assert.strictEqual(strContent, JSON.stringify(expectedNotebookContent, undefined, ' '));
|
||||||
|
});
|
||||||
|
|
||||||
test('Should create a markdown cell', async function (): Promise<void> {
|
test('Should create a markdown cell', async function (): Promise<void> {
|
||||||
let expectedNotebookMarkdownContent: nb.INotebookContents = {
|
let expectedNotebookMarkdownContent: nb.INotebookContents = {
|
||||||
cells: [{
|
cells: [{
|
||||||
@@ -173,7 +160,7 @@ suite('Local Content Manager', function (): void {
|
|||||||
};
|
};
|
||||||
let markdownNotebookContent = JSON.stringify(expectedNotebookMarkdownContent);
|
let markdownNotebookContent = JSON.stringify(expectedNotebookMarkdownContent);
|
||||||
// verify that notebooks support markdown cells
|
// verify that notebooks support markdown cells
|
||||||
let notebook = await contentManager.loadFromContentString(markdownNotebookContent);
|
let notebook = await contentManager.deserializeNotebook(markdownNotebookContent);
|
||||||
// assert that markdown cell is supported by
|
// assert that markdown cell is supported by
|
||||||
// verifying the notebook matches the expectedNotebookMarkdownContent format
|
// verifying the notebook matches the expectedNotebookMarkdownContent format
|
||||||
assert.strictEqual(notebook.cells.length, 1, 'The number of cells should be equal to 1');
|
assert.strictEqual(notebook.cells.length, 1, 'The number of cells should be equal to 1');
|
||||||
@@ -207,7 +194,7 @@ suite('Local Content Manager', function (): void {
|
|||||||
};
|
};
|
||||||
let streamOutputContent = JSON.stringify(expectedNotebookStreamOutputContent);
|
let streamOutputContent = JSON.stringify(expectedNotebookStreamOutputContent);
|
||||||
// Verify that the stream output type is supported
|
// Verify that the stream output type is supported
|
||||||
let notebook = await contentManager.loadFromContentString(streamOutputContent);
|
let notebook = await contentManager.deserializeNotebook(streamOutputContent);
|
||||||
assert.strictEqual(notebook.cells[0].outputs[0].output_type, 'stream', 'Cell output from notebook should be stream');
|
assert.strictEqual(notebook.cells[0].outputs[0].output_type, 'stream', 'Cell output from notebook should be stream');
|
||||||
assert.strictEqual(notebook.cells[0].cell_type, expectedNotebookStreamOutputContent.cells[0].cell_type, 'Cell type of notebook should match the expectedNotebookStreamOutputContent');
|
assert.strictEqual(notebook.cells[0].cell_type, expectedNotebookStreamOutputContent.cells[0].cell_type, 'Cell type of notebook should match the expectedNotebookStreamOutputContent');
|
||||||
});
|
});
|
||||||
|
|||||||
+66
-60
@@ -32,7 +32,7 @@ import { TestLifecycleService, TestTextFileService, workbenchInstantiationServic
|
|||||||
import { Range } from 'vs/editor/common/core/range';
|
import { Range } from 'vs/editor/common/core/range';
|
||||||
import { nb } from 'azdata';
|
import { nb } from 'azdata';
|
||||||
import { Emitter } from 'vs/base/common/event';
|
import { Emitter } from 'vs/base/common/event';
|
||||||
import { INotebookEditor, INotebookManager } from 'sql/workbench/services/notebook/browser/notebookService';
|
import { INotebookEditor, IExecuteManager, ISerializationManager } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||||
@@ -50,9 +50,13 @@ class ServiceAccessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class NotebookManagerStub implements INotebookManager {
|
class SerializationManagerStub implements ISerializationManager {
|
||||||
providerId: string;
|
providerId: string;
|
||||||
contentManager: nb.ContentManager;
|
contentManager: nb.ContentManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExecuteManagerStub implements IExecuteManager {
|
||||||
|
providerId: string;
|
||||||
sessionManager: nb.SessionManager;
|
sessionManager: nb.SessionManager;
|
||||||
serverManager: nb.ServerManager;
|
serverManager: nb.ServerManager;
|
||||||
}
|
}
|
||||||
@@ -62,7 +66,8 @@ let defaultUri = URI.file('/some/path.ipynb');
|
|||||||
// Note: these tests are intentionally written to be extremely brittle and break on any changes to notebook/cell serialization changes.
|
// Note: these tests are intentionally written to be extremely brittle and break on any changes to notebook/cell serialization changes.
|
||||||
// If any of these tests fail, it is likely that notebook editor rehydration will fail with cryptic JSON messages.
|
// If any of these tests fail, it is likely that notebook editor rehydration will fail with cryptic JSON messages.
|
||||||
suite('Notebook Editor Model', function (): void {
|
suite('Notebook Editor Model', function (): void {
|
||||||
let notebookManagers = [new NotebookManagerStub()];
|
let serializationManagers = [new SerializationManagerStub()];
|
||||||
|
let executeManagers = [new ExecuteManagerStub()];
|
||||||
let notebookModel: NotebookModel;
|
let notebookModel: NotebookModel;
|
||||||
const instantiationService: IInstantiationService = workbenchInstantiationService();
|
const instantiationService: IInstantiationService = workbenchInstantiationService();
|
||||||
let accessor: ServiceAccessor;
|
let accessor: ServiceAccessor;
|
||||||
@@ -156,8 +161,9 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
defaultModelOptions = {
|
defaultModelOptions = {
|
||||||
notebookUri: defaultUri,
|
notebookUri: defaultUri,
|
||||||
factory: new ModelFactory(instantiationService),
|
factory: new ModelFactory(instantiationService),
|
||||||
notebookManagers,
|
serializationManagers: serializationManagers,
|
||||||
contentManager: undefined,
|
executeManagers: executeManagers,
|
||||||
|
contentLoader: undefined,
|
||||||
notificationService: notificationService.object,
|
notificationService: notificationService.object,
|
||||||
connectionService: queryConnectionService.object,
|
connectionService: queryConnectionService.object,
|
||||||
providerId: 'SQL',
|
providerId: 'SQL',
|
||||||
@@ -197,7 +203,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
cells: [newCell],
|
cells: [newCell],
|
||||||
cellIndex: 0
|
cellIndex: 0
|
||||||
};
|
};
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
||||||
assert(notebookEditorModel.lastEditFullReplacement);
|
assert(notebookEditorModel.lastEditFullReplacement);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
||||||
@@ -221,7 +227,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
cells: [newCell],
|
cells: [newCell],
|
||||||
cellIndex: 0
|
cellIndex: 0
|
||||||
};
|
};
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
||||||
assert(notebookEditorModel.lastEditFullReplacement);
|
assert(notebookEditorModel.lastEditFullReplacement);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(25), ' "execution_count": null');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(25), ' "execution_count": null');
|
||||||
@@ -233,7 +239,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
cellIndex: 0
|
cellIndex: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellExecuted);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellExecuted);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(12), ' "azdata_cell_guid": "' + newCell.cellGuid + '"');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(12), ' "azdata_cell_guid": "' + newCell.cellGuid + '"');
|
||||||
@@ -250,7 +256,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
cellIndex: 0
|
cellIndex: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellExecuted);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellExecuted);
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(25), ' "execution_count": 10');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(25), ' "execution_count": 10');
|
||||||
assert(!notebookEditorModel.lastEditFullReplacement);
|
assert(!notebookEditorModel.lastEditFullReplacement);
|
||||||
|
|
||||||
@@ -261,7 +267,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
cellIndex: 0
|
cellIndex: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellExecuted);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellExecuted);
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(25), ' "execution_count": 15');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(25), ' "execution_count": 15');
|
||||||
assert(!notebookEditorModel.lastEditFullReplacement);
|
assert(!notebookEditorModel.lastEditFullReplacement);
|
||||||
|
|
||||||
@@ -272,7 +278,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
cellIndex: 0
|
cellIndex: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellExecuted);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellExecuted);
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(25), ' "execution_count": 105');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(25), ' "execution_count": 105');
|
||||||
assert(!notebookEditorModel.lastEditFullReplacement);
|
assert(!notebookEditorModel.lastEditFullReplacement);
|
||||||
});
|
});
|
||||||
@@ -289,7 +295,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
cells: [newCell],
|
cells: [newCell],
|
||||||
cellIndex: 0
|
cellIndex: 0
|
||||||
};
|
};
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
||||||
assert(notebookEditorModel.lastEditFullReplacement);
|
assert(notebookEditorModel.lastEditFullReplacement);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(14), ' "outputs": [');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(14), ' "outputs": [');
|
||||||
@@ -300,7 +306,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
cellIndex: 0
|
cellIndex: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellOutputCleared);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellOutputCleared);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(12), ' "azdata_cell_guid": "' + newCell.cellGuid + '"');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(12), ' "azdata_cell_guid": "' + newCell.cellGuid + '"');
|
||||||
@@ -323,7 +329,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
cells: [newCell],
|
cells: [newCell],
|
||||||
cellIndex: 0
|
cellIndex: 0
|
||||||
};
|
};
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
||||||
assert(notebookEditorModel.lastEditFullReplacement);
|
assert(notebookEditorModel.lastEditFullReplacement);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(14), ' "outputs": [');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(14), ' "outputs": [');
|
||||||
@@ -342,7 +348,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellSourceUpdated);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellSourceUpdated);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' "This is a test\\n",');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' "This is a test\\n",');
|
||||||
@@ -369,7 +375,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
cells: [newCell],
|
cells: [newCell],
|
||||||
cellIndex: 0
|
cellIndex: 0
|
||||||
};
|
};
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
||||||
assert(notebookEditorModel.lastEditFullReplacement);
|
assert(notebookEditorModel.lastEditFullReplacement);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(14), ' "outputs": [');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(14), ' "outputs": [');
|
||||||
@@ -388,7 +394,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellSourceUpdated);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellSourceUpdated);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' "This is a test"');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' "This is a test"');
|
||||||
@@ -413,7 +419,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
cells: [newCell],
|
cells: [newCell],
|
||||||
cellIndex: 0
|
cellIndex: 0
|
||||||
};
|
};
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
||||||
assert(notebookEditorModel.lastEditFullReplacement);
|
assert(notebookEditorModel.lastEditFullReplacement);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(14), ' "outputs": [');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(14), ' "outputs": [');
|
||||||
@@ -427,7 +433,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
modelContentChangedEvent: undefined
|
modelContentChangedEvent: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellSourceUpdated);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellSourceUpdated);
|
||||||
|
|
||||||
assert(!notebookEditorModel.lastEditFullReplacement, 'should not do a full replacement for a source update');
|
assert(!notebookEditorModel.lastEditFullReplacement, 'should not do a full replacement for a source update');
|
||||||
|
|
||||||
@@ -453,7 +459,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
cells: [newCell],
|
cells: [newCell],
|
||||||
cellIndex: 0
|
cellIndex: 0
|
||||||
};
|
};
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
||||||
assert(notebookEditorModel.lastEditFullReplacement);
|
assert(notebookEditorModel.lastEditFullReplacement);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(14), ' "outputs": [');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(14), ' "outputs": [');
|
||||||
@@ -467,7 +473,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
modelContentChangedEvent: undefined
|
modelContentChangedEvent: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellSourceUpdated);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellSourceUpdated);
|
||||||
|
|
||||||
assert(!notebookEditorModel.lastEditFullReplacement, 'should not do a full replacement for a source update');
|
assert(!notebookEditorModel.lastEditFullReplacement, 'should not do a full replacement for a source update');
|
||||||
|
|
||||||
@@ -494,7 +500,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
cells: [newCell],
|
cells: [newCell],
|
||||||
cellIndex: 0
|
cellIndex: 0
|
||||||
};
|
};
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
||||||
assert(notebookEditorModel.lastEditFullReplacement);
|
assert(notebookEditorModel.lastEditFullReplacement);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
||||||
@@ -516,7 +522,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellSourceUpdated);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellSourceUpdated);
|
||||||
assert(!notebookEditorModel.lastEditFullReplacement);
|
assert(!notebookEditorModel.lastEditFullReplacement);
|
||||||
|
|
||||||
contentChange = {
|
contentChange = {
|
||||||
@@ -533,7 +539,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellSourceUpdated);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellSourceUpdated);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' ""');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' ""');
|
||||||
@@ -558,7 +564,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
cells: [newCell],
|
cells: [newCell],
|
||||||
cellIndex: 0
|
cellIndex: 0
|
||||||
};
|
};
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(14), ' "outputs": [');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(14), ' "outputs": [');
|
||||||
|
|
||||||
@@ -576,7 +582,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellSourceUpdated);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellSourceUpdated);
|
||||||
assert(!notebookEditorModel.lastEditFullReplacement);
|
assert(!notebookEditorModel.lastEditFullReplacement);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
||||||
@@ -600,7 +606,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellSourceUpdated);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellSourceUpdated);
|
||||||
assert(!notebookEditorModel.lastEditFullReplacement);
|
assert(!notebookEditorModel.lastEditFullReplacement);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
||||||
@@ -630,7 +636,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
cells: [cell],
|
cells: [cell],
|
||||||
cellIndex: 0
|
cellIndex: 0
|
||||||
};
|
};
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
||||||
assert(notebookEditorModel.lastEditFullReplacement);
|
assert(notebookEditorModel.lastEditFullReplacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -647,7 +653,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellSourceUpdated);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellSourceUpdated);
|
||||||
assert(!notebookEditorModel.lastEditFullReplacement);
|
assert(!notebookEditorModel.lastEditFullReplacement);
|
||||||
|
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
@@ -677,7 +683,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
cells: [newCell],
|
cells: [newCell],
|
||||||
cellIndex: 0
|
cellIndex: 0
|
||||||
};
|
};
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
||||||
assert(notebookEditorModel.lastEditFullReplacement);
|
assert(notebookEditorModel.lastEditFullReplacement);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(14), ' "outputs": [');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(14), ' "outputs": [');
|
||||||
@@ -689,7 +695,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
cells: [newCell]
|
cells: [newCell]
|
||||||
};
|
};
|
||||||
|
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellOutputUpdated);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellOutputUpdated);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(12), ' "azdata_cell_guid": "' + newCell.cellGuid + '"');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(12), ' "azdata_cell_guid": "' + newCell.cellGuid + '"');
|
||||||
@@ -714,7 +720,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
cells: [newCell],
|
cells: [newCell],
|
||||||
cellIndex: 0
|
cellIndex: 0
|
||||||
};
|
};
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
||||||
assert(notebookEditorModel.lastEditFullReplacement);
|
assert(notebookEditorModel.lastEditFullReplacement);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(14), ' "outputs": [');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(14), ' "outputs": [');
|
||||||
@@ -728,7 +734,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
cells: [newCell]
|
cells: [newCell]
|
||||||
};
|
};
|
||||||
|
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellOutputUpdated);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellOutputUpdated);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(12), ' "azdata_cell_guid": "' + newCell.cellGuid + '"');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(12), ' "azdata_cell_guid": "' + newCell.cellGuid + '"');
|
||||||
@@ -750,7 +756,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
cells: [newCell]
|
cells: [newCell]
|
||||||
};
|
};
|
||||||
|
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellOutputUpdated);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellOutputUpdated);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(32), ' "text": "test test test"');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(32), ' "text": "test test test"');
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(33), ' }');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(33), ' }');
|
||||||
@@ -779,7 +785,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
cellIndex: 0
|
cellIndex: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
||||||
assert(notebookEditorModel.lastEditFullReplacement);
|
assert(notebookEditorModel.lastEditFullReplacement);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(14), ' "outputs": [],');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(14), ' "outputs": [],');
|
||||||
@@ -792,7 +798,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
cells: [newCell]
|
cells: [newCell]
|
||||||
};
|
};
|
||||||
|
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellOutputUpdated);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellOutputUpdated);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(12), ' "azdata_cell_guid": "' + newCell.cellGuid + '"');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(12), ' "azdata_cell_guid": "' + newCell.cellGuid + '"');
|
||||||
@@ -810,9 +816,9 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
||||||
|
|
||||||
let newCell = notebookModel.addCell(CellTypes.Code);
|
let newCell = notebookModel.addCell(CellTypes.Code);
|
||||||
setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
await setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
||||||
|
|
||||||
addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '"This text is in quotes"');
|
await addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '"This text is in quotes"');
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' "\\"This text is in quotes\\""');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' "\\"This text is in quotes\\""');
|
||||||
|
|
||||||
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
||||||
@@ -825,9 +831,9 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
||||||
|
|
||||||
let newCell = notebookModel.addCell(CellTypes.Code);
|
let newCell = notebookModel.addCell(CellTypes.Code);
|
||||||
setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
await setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
||||||
|
|
||||||
addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '""""""""""');
|
await addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '""""""""""');
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' "\\"\\"\\"\\"\\"\\"\\"\\"\\"\\""');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' "\\"\\"\\"\\"\\"\\"\\"\\"\\"\\""');
|
||||||
|
|
||||||
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
||||||
@@ -840,9 +846,9 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
||||||
|
|
||||||
let newCell = notebookModel.addCell(CellTypes.Code);
|
let newCell = notebookModel.addCell(CellTypes.Code);
|
||||||
setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
await setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
||||||
|
|
||||||
addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '\\\\\\\\\\');
|
await addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '\\\\\\\\\\');
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' "\\\\\\\\\\\\\\\\\\\\\"');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' "\\\\\\\\\\\\\\\\\\\\\"');
|
||||||
|
|
||||||
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
||||||
@@ -855,9 +861,9 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
||||||
|
|
||||||
let newCell = notebookModel.addCell(CellTypes.Code);
|
let newCell = notebookModel.addCell(CellTypes.Code);
|
||||||
setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
await setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
||||||
|
|
||||||
addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '\"\"\"\"\"\"\"\"\"\"');
|
await addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '\"\"\"\"\"\"\"\"\"\"');
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' "\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\""');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' "\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\""');
|
||||||
|
|
||||||
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
||||||
@@ -870,9 +876,9 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
||||||
|
|
||||||
let newCell = notebookModel.addCell(CellTypes.Code);
|
let newCell = notebookModel.addCell(CellTypes.Code);
|
||||||
setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
await setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
||||||
|
|
||||||
addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, 'this is a long line in a cell test. Everything should serialize correctly! # Comments here: adding more tests is fun?');
|
await addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, 'this is a long line in a cell test. Everything should serialize correctly! # Comments here: adding more tests is fun?');
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' "this is a long line in a cell test. Everything should serialize correctly! # Comments here: adding more tests is fun?"');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' "this is a long line in a cell test. Everything should serialize correctly! # Comments here: adding more tests is fun?"');
|
||||||
|
|
||||||
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
||||||
@@ -885,9 +891,9 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
||||||
|
|
||||||
let newCell = notebookModel.addCell(CellTypes.Code);
|
let newCell = notebookModel.addCell(CellTypes.Code);
|
||||||
setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
await setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
||||||
|
|
||||||
addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '`~1!2@3#4$5%6^7&8*9(0)-_=+[{]}\\|;:",<.>/?\'');
|
await addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '`~1!2@3#4$5%6^7&8*9(0)-_=+[{]}\\|;:",<.>/?\'');
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' "`~1!2@3#4$5%6^7&8*9(0)-_=+[{]}\\\\|;:\\",<.>/?\'"');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' "`~1!2@3#4$5%6^7&8*9(0)-_=+[{]}\\\\|;:\\",<.>/?\'"');
|
||||||
|
|
||||||
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
||||||
@@ -900,9 +906,9 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
||||||
|
|
||||||
let newCell = notebookModel.addCell(CellTypes.Code);
|
let newCell = notebookModel.addCell(CellTypes.Code);
|
||||||
setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
await setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
||||||
|
|
||||||
addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '\'\'\'\'');
|
await addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '\'\'\'\'');
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' "\'\'\'\'"');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' "\'\'\'\'"');
|
||||||
|
|
||||||
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
||||||
@@ -915,9 +921,9 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
||||||
|
|
||||||
let newCell = notebookModel.addCell(CellTypes.Code);
|
let newCell = notebookModel.addCell(CellTypes.Code);
|
||||||
setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
await setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
||||||
|
|
||||||
addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '');
|
await addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '');
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' ""');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' ""');
|
||||||
|
|
||||||
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
||||||
@@ -930,9 +936,9 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
||||||
|
|
||||||
let newCell = notebookModel.addCell(CellTypes.Code);
|
let newCell = notebookModel.addCell(CellTypes.Code);
|
||||||
setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
await setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
||||||
|
|
||||||
addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '"test"' + os.EOL + 'test""');
|
await addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '"test"' + os.EOL + 'test""');
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' "\\"test\\"\\n",');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' "\\"test\\"\\n",');
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
||||||
@@ -952,9 +958,9 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
||||||
|
|
||||||
let newCell = notebookModel.addCell(CellTypes.Code);
|
let newCell = notebookModel.addCell(CellTypes.Code);
|
||||||
setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
await setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
||||||
|
|
||||||
addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '"""""test"' + os.EOL + '"""""""test\\""');
|
await addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '"""""test"' + os.EOL + '"""""""test\\""');
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' "\\"\\"\\"\\"\\"test\\"\\n",');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(9), ' "\\"\\"\\"\\"\\"test\\"\\n",');
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(8), ' "source": [');
|
||||||
@@ -983,7 +989,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
return new NotebookEditorModel(defaultUri, textFileEditorModel, mockNotebookService.object, testResourcePropertiesService);
|
return new NotebookEditorModel(defaultUri, textFileEditorModel, mockNotebookService.object, testResourcePropertiesService);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupTextEditorModelWithEmptyOutputs(notebookEditorModel: NotebookEditorModel, newCell: ICellModel) {
|
async function setupTextEditorModelWithEmptyOutputs(notebookEditorModel: NotebookEditorModel, newCell: ICellModel) {
|
||||||
// clear outputs
|
// clear outputs
|
||||||
newCell[<any>'_outputs'] = [];
|
newCell[<any>'_outputs'] = [];
|
||||||
|
|
||||||
@@ -993,13 +999,13 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
cellIndex: 0
|
cellIndex: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
||||||
assert(notebookEditorModel.lastEditFullReplacement);
|
assert(notebookEditorModel.lastEditFullReplacement);
|
||||||
|
|
||||||
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(14), ' "outputs": [],');
|
assert.strictEqual(notebookEditorModel.editorModel.textEditorModel.getLineContent(14), ' "outputs": [],');
|
||||||
}
|
}
|
||||||
|
|
||||||
function addTextToBeginningOfTextEditorModel(notebookEditorModel: NotebookEditorModel, newCell: ICellModel, textToAdd: string) {
|
async function addTextToBeginningOfTextEditorModel(notebookEditorModel: NotebookEditorModel, newCell: ICellModel, textToAdd: string) {
|
||||||
let contentChange: NotebookContentChange = {
|
let contentChange: NotebookContentChange = {
|
||||||
changeType: NotebookChangeType.CellSourceUpdated,
|
changeType: NotebookChangeType.CellSourceUpdated,
|
||||||
cells: [newCell],
|
cells: [newCell],
|
||||||
@@ -1014,7 +1020,7 @@ suite('Notebook Editor Model', function (): void {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellSourceUpdated);
|
await notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellSourceUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel: NotebookEditorModel, newCell: ICellModel) {
|
function ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel: NotebookEditorModel, newCell: ICellModel) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { nb } from 'azdata';
|
|||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
|
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { NotebookManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
|
import { ExecuteManagerStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
|
||||||
import { CellTypes } from 'sql/workbench/services/notebook/common/contracts';
|
import { CellTypes } from 'sql/workbench/services/notebook/common/contracts';
|
||||||
import { IClientSession, INotebookModelOptions } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
import { IClientSession, INotebookModelOptions } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||||
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
|
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
|
||||||
@@ -26,7 +26,7 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
|
|||||||
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
||||||
import { ClientSession } from 'sql/workbench/services/notebook/browser/models/clientSession';
|
import { ClientSession } from 'sql/workbench/services/notebook/browser/models/clientSession';
|
||||||
import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
|
import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||||
import { NotebookEditorContentManager } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
|
import { NotebookEditorContentLoader } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
|
||||||
import { NotebookRange } from 'sql/workbench/services/notebook/browser/notebookService';
|
import { NotebookRange } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||||
import { NotebookMarkdownRenderer } from 'sql/workbench/contrib/notebook/browser/outputs/notebookMarkdown';
|
import { NotebookMarkdownRenderer } from 'sql/workbench/contrib/notebook/browser/outputs/notebookMarkdown';
|
||||||
import { NullAdsTelemetryService } from 'sql/platform/telemetry/common/adsTelemetryService';
|
import { NullAdsTelemetryService } from 'sql/platform/telemetry/common/adsTelemetryService';
|
||||||
@@ -67,8 +67,8 @@ let instantiationService: IInstantiationService;
|
|||||||
let serviceCollection = new ServiceCollection();
|
let serviceCollection = new ServiceCollection();
|
||||||
|
|
||||||
suite('Notebook Find Model', function (): void {
|
suite('Notebook Find Model', function (): void {
|
||||||
|
let serializationManagers = [new SerializationManagerStub()];
|
||||||
let notebookManagers = [new NotebookManagerStub()];
|
let executeManagers = [new ExecuteManagerStub()];
|
||||||
let memento: TypeMoq.Mock<Memento>;
|
let memento: TypeMoq.Mock<Memento>;
|
||||||
let queryConnectionService: TypeMoq.Mock<TestConnectionManagementService>;
|
let queryConnectionService: TypeMoq.Mock<TestConnectionManagementService>;
|
||||||
let defaultModelOptions: INotebookModelOptions;
|
let defaultModelOptions: INotebookModelOptions;
|
||||||
@@ -92,8 +92,9 @@ suite('Notebook Find Model', function (): void {
|
|||||||
defaultModelOptions = {
|
defaultModelOptions = {
|
||||||
notebookUri: defaultUri,
|
notebookUri: defaultUri,
|
||||||
factory: new ModelFactory(instantiationService),
|
factory: new ModelFactory(instantiationService),
|
||||||
notebookManagers,
|
serializationManagers: serializationManagers,
|
||||||
contentManager: undefined,
|
executeManagers: executeManagers,
|
||||||
|
contentLoader: undefined,
|
||||||
notificationService: notificationService.object,
|
notificationService: notificationService.object,
|
||||||
connectionService: queryConnectionService.object,
|
connectionService: queryConnectionService.object,
|
||||||
providerId: 'SQL',
|
providerId: 'SQL',
|
||||||
@@ -434,9 +435,9 @@ suite('Notebook Find Model', function (): void {
|
|||||||
|
|
||||||
|
|
||||||
async function initNotebookModel(contents: nb.INotebookContents): Promise<void> {
|
async function initNotebookModel(contents: nb.INotebookContents): Promise<void> {
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(contents));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(contents));
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
// Initialize the model
|
// Initialize the model
|
||||||
model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
||||||
await model.loadContents();
|
await model.loadContents();
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
|
|||||||
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
|
||||||
import { NotebookManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
|
import { ExecuteManagerStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
|
||||||
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
|
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
|
||||||
import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory';
|
import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory';
|
||||||
import { IClientSession, INotebookModelOptions, NotebookContentChange, IClientSessionOptions, ICellModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
import { IClientSession, INotebookModelOptions, NotebookContentChange, IClientSessionOptions, ICellModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||||
@@ -29,7 +29,7 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
|
|||||||
import { NullLogService } from 'vs/platform/log/common/log';
|
import { NullLogService } from 'vs/platform/log/common/log';
|
||||||
import { TestConnectionManagementService } from 'sql/platform/connection/test/common/testConnectionManagementService';
|
import { TestConnectionManagementService } from 'sql/platform/connection/test/common/testConnectionManagementService';
|
||||||
import { isUndefinedOrNull } from 'vs/base/common/types';
|
import { isUndefinedOrNull } from 'vs/base/common/types';
|
||||||
import { NotebookEditorContentManager } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
|
import { NotebookEditorContentLoader } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
|
||||||
import { SessionManager } from 'sql/workbench/contrib/notebook/test/emptySessionClasses';
|
import { SessionManager } from 'sql/workbench/contrib/notebook/test/emptySessionClasses';
|
||||||
import { mssqlProviderName } from 'sql/platform/connection/common/constants';
|
import { mssqlProviderName } from 'sql/platform/connection/common/constants';
|
||||||
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
||||||
@@ -138,7 +138,8 @@ let instantiationService: IInstantiationService;
|
|||||||
let configurationService: IConfigurationService;
|
let configurationService: IConfigurationService;
|
||||||
|
|
||||||
suite('notebook model', function (): void {
|
suite('notebook model', function (): void {
|
||||||
let notebookManagers = [new NotebookManagerStub()];
|
let serializationManagers = [new SerializationManagerStub()];
|
||||||
|
let executeManagers = [new ExecuteManagerStub()];
|
||||||
let mockSessionManager: TypeMoq.Mock<nb.SessionManager>;
|
let mockSessionManager: TypeMoq.Mock<nb.SessionManager>;
|
||||||
let memento: TypeMoq.Mock<Memento>;
|
let memento: TypeMoq.Mock<Memento>;
|
||||||
let queryConnectionService: TypeMoq.Mock<TestConnectionManagementService>;
|
let queryConnectionService: TypeMoq.Mock<TestConnectionManagementService>;
|
||||||
@@ -146,7 +147,7 @@ suite('notebook model', function (): void {
|
|||||||
const logService = new NullLogService();
|
const logService = new NullLogService();
|
||||||
setup(() => {
|
setup(() => {
|
||||||
mockSessionManager = TypeMoq.Mock.ofType(SessionManager);
|
mockSessionManager = TypeMoq.Mock.ofType(SessionManager);
|
||||||
notebookManagers[0].sessionManager = mockSessionManager.object;
|
executeManagers[0].sessionManager = mockSessionManager.object;
|
||||||
sessionReady = new Deferred<void>();
|
sessionReady = new Deferred<void>();
|
||||||
notificationService = TypeMoq.Mock.ofType<INotificationService>(TestNotificationService, TypeMoq.MockBehavior.Loose);
|
notificationService = TypeMoq.Mock.ofType<INotificationService>(TestNotificationService, TypeMoq.MockBehavior.Loose);
|
||||||
capabilitiesService = new TestCapabilitiesService();
|
capabilitiesService = new TestCapabilitiesService();
|
||||||
@@ -160,8 +161,9 @@ suite('notebook model', function (): void {
|
|||||||
defaultModelOptions = {
|
defaultModelOptions = {
|
||||||
notebookUri: defaultUri,
|
notebookUri: defaultUri,
|
||||||
factory: new ModelFactory(instantiationService),
|
factory: new ModelFactory(instantiationService),
|
||||||
notebookManagers,
|
serializationManagers: serializationManagers,
|
||||||
contentManager: undefined,
|
executeManagers: executeManagers,
|
||||||
|
contentLoader: undefined,
|
||||||
notificationService: notificationService.object,
|
notificationService: notificationService.object,
|
||||||
connectionService: queryConnectionService.object,
|
connectionService: queryConnectionService.object,
|
||||||
providerId: 'SQL',
|
providerId: 'SQL',
|
||||||
@@ -171,7 +173,7 @@ suite('notebook model', function (): void {
|
|||||||
capabilitiesService: capabilitiesService
|
capabilitiesService: capabilitiesService
|
||||||
};
|
};
|
||||||
clientSessionOptions = {
|
clientSessionOptions = {
|
||||||
notebookManager: defaultModelOptions.notebookManagers[0],
|
executeManager: defaultModelOptions.executeManagers[0],
|
||||||
notebookUri: defaultModelOptions.notebookUri,
|
notebookUri: defaultModelOptions.notebookUri,
|
||||||
notificationService: notificationService.object,
|
notificationService: notificationService.object,
|
||||||
kernelSpec: defaultModelOptions.defaultKernel
|
kernelSpec: defaultModelOptions.defaultKernel
|
||||||
@@ -200,9 +202,9 @@ suite('notebook model', function (): void {
|
|||||||
nbformat_minor: 5
|
nbformat_minor: 5
|
||||||
};
|
};
|
||||||
|
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(emptyNotebook));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(emptyNotebook));
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
// When I initialize the model
|
// When I initialize the model
|
||||||
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
||||||
await model.loadContents();
|
await model.loadContents();
|
||||||
@@ -216,9 +218,9 @@ suite('notebook model', function (): void {
|
|||||||
|
|
||||||
test('Should use trusted state set in model load', async function (): Promise<void> {
|
test('Should use trusted state set in model load', async function (): Promise<void> {
|
||||||
// Given a notebook
|
// Given a notebook
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
// When I initialize the model
|
// When I initialize the model
|
||||||
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
||||||
await model.loadContents(true);
|
await model.loadContents(true);
|
||||||
@@ -231,9 +233,9 @@ suite('notebook model', function (): void {
|
|||||||
test('Should throw if model load fails', async function (): Promise<void> {
|
test('Should throw if model load fails', async function (): Promise<void> {
|
||||||
// Given a call to get Contents fails
|
// Given a call to get Contents fails
|
||||||
let error = new Error('File not found');
|
let error = new Error('File not found');
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.reject(error));//.throws(error);
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.reject(error));//.throws(error);
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
|
|
||||||
// When I initalize the model
|
// When I initalize the model
|
||||||
// Then it should throw
|
// Then it should throw
|
||||||
@@ -245,9 +247,9 @@ suite('notebook model', function (): void {
|
|||||||
|
|
||||||
test('Should convert cell info to CellModels', async function (): Promise<void> {
|
test('Should convert cell info to CellModels', async function (): Promise<void> {
|
||||||
// Given a notebook with 2 cells
|
// Given a notebook with 2 cells
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
|
|
||||||
// When I initalize the model
|
// When I initalize the model
|
||||||
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
||||||
@@ -261,18 +263,18 @@ suite('notebook model', function (): void {
|
|||||||
|
|
||||||
test('Should handle multiple notebook managers', async function (): Promise<void> {
|
test('Should handle multiple notebook managers', async function (): Promise<void> {
|
||||||
// Given a notebook with 2 cells
|
// Given a notebook with 2 cells
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
|
|
||||||
let defaultNotebookManager = new NotebookManagerStub();
|
let defaultNotebookManager = new ExecuteManagerStub();
|
||||||
defaultNotebookManager.providerId = 'SQL';
|
defaultNotebookManager.providerId = 'SQL';
|
||||||
|
|
||||||
let jupyterNotebookManager = new NotebookManagerStub();
|
let jupyterNotebookManager = new ExecuteManagerStub();
|
||||||
jupyterNotebookManager.providerId = 'jupyter';
|
jupyterNotebookManager.providerId = 'jupyter';
|
||||||
|
|
||||||
// Setup 2 notebook managers
|
// Setup 2 notebook managers
|
||||||
defaultModelOptions.notebookManagers = [defaultNotebookManager, jupyterNotebookManager];
|
defaultModelOptions.executeManagers = [defaultNotebookManager, jupyterNotebookManager];
|
||||||
|
|
||||||
// Change default notebook provider id to jupyter
|
// Change default notebook provider id to jupyter
|
||||||
defaultModelOptions.providerId = 'jupyter';
|
defaultModelOptions.providerId = 'jupyter';
|
||||||
@@ -282,7 +284,7 @@ suite('notebook model', function (): void {
|
|||||||
await model.loadContents();
|
await model.loadContents();
|
||||||
|
|
||||||
// I expect the default provider to be jupyter
|
// I expect the default provider to be jupyter
|
||||||
assert.strictEqual(model.notebookManager.providerId, 'jupyter', 'Notebook manager provider id incorrect');
|
assert.strictEqual(model.executeManager.providerId, 'jupyter', 'Notebook manager provider id incorrect');
|
||||||
|
|
||||||
// Similarly, change default notebook provider id to SQL
|
// Similarly, change default notebook provider id to SQL
|
||||||
defaultModelOptions.providerId = 'SQL';
|
defaultModelOptions.providerId = 'SQL';
|
||||||
@@ -292,13 +294,13 @@ suite('notebook model', function (): void {
|
|||||||
await model.loadContents();
|
await model.loadContents();
|
||||||
|
|
||||||
// I expect the default provider to be SQL
|
// I expect the default provider to be SQL
|
||||||
assert.strictEqual(model.notebookManager.providerId, 'SQL', 'Notebook manager provider id incorrect after 2nd model load');
|
assert.strictEqual(model.executeManager.providerId, 'SQL', 'Notebook manager provider id incorrect after 2nd model load');
|
||||||
|
|
||||||
// Check that the getters return the correct values
|
// Check that the getters return the correct values
|
||||||
assert.strictEqual(model.notebookManagers.length, 2, 'There should be 2 notebook managers');
|
assert.strictEqual(model.executeManagers.length, 2, 'There should be 2 notebook managers');
|
||||||
assert(!isUndefinedOrNull(model.getNotebookManager('SQL')), 'SQL notebook manager is not defined');
|
assert(!isUndefinedOrNull(model.getExecuteManager('SQL')), 'SQL notebook manager is not defined');
|
||||||
assert(!isUndefinedOrNull(model.getNotebookManager('jupyter')), 'Jupyter notebook manager is not defined');
|
assert(!isUndefinedOrNull(model.getExecuteManager('jupyter')), 'Jupyter notebook manager is not defined');
|
||||||
assert(isUndefinedOrNull(model.getNotebookManager('foo')), 'foo notebook manager is incorrectly defined');
|
assert(isUndefinedOrNull(model.getExecuteManager('foo')), 'foo notebook manager is incorrectly defined');
|
||||||
|
|
||||||
// Check other properties to ensure that they're returning as expected
|
// Check other properties to ensure that they're returning as expected
|
||||||
// No server manager was passed into the notebook manager stub, so expect hasServerManager to return false
|
// No server manager was passed into the notebook manager stub, so expect hasServerManager to return false
|
||||||
@@ -308,9 +310,9 @@ suite('notebook model', function (): void {
|
|||||||
|
|
||||||
test('Should set active cell correctly', async function (): Promise<void> {
|
test('Should set active cell correctly', async function (): Promise<void> {
|
||||||
// Given a notebook with 2 cells
|
// Given a notebook with 2 cells
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
|
|
||||||
// When I initalize the model
|
// When I initalize the model
|
||||||
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
||||||
@@ -364,10 +366,10 @@ suite('notebook model', function (): void {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Should set notebook parameter and injected parameter cell correctly', async function (): Promise<void> {
|
test('Should set notebook parameter and injected parameter cell correctly', async function (): Promise<void> {
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedParameterizedNotebookContent));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedParameterizedNotebookContent));
|
||||||
defaultModelOptions.notebookUri = defaultUri;
|
defaultModelOptions.notebookUri = defaultUri;
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
|
|
||||||
// When I initialize the model
|
// When I initialize the model
|
||||||
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
||||||
@@ -392,10 +394,10 @@ suite('notebook model', function (): void {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Should set notebookUri parameters to new cell correctly', async function (): Promise<void> {
|
test('Should set notebookUri parameters to new cell correctly', async function (): Promise<void> {
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContentOneCell));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContentOneCell));
|
||||||
defaultModelOptions.notebookUri = notebookUriParams;
|
defaultModelOptions.notebookUri = notebookUriParams;
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
|
|
||||||
// When I initialize the model
|
// When I initialize the model
|
||||||
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
||||||
@@ -412,14 +414,14 @@ suite('notebook model', function (): void {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Should set notebookUri parameters to new cell after parameters cell correctly', async function (): Promise<void> {
|
test('Should set notebookUri parameters to new cell after parameters cell correctly', async function (): Promise<void> {
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
let expectedNotebookContentParameterCell = expectedNotebookContentOneCell;
|
let expectedNotebookContentParameterCell = expectedNotebookContentOneCell;
|
||||||
//Set the cell to be tagged as parameter cell
|
//Set the cell to be tagged as parameter cell
|
||||||
expectedNotebookContentParameterCell.cells[0].metadata.tags = ['parameters'];
|
expectedNotebookContentParameterCell.cells[0].metadata.tags = ['parameters'];
|
||||||
|
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContentParameterCell));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContentParameterCell));
|
||||||
defaultModelOptions.notebookUri = notebookUriParams;
|
defaultModelOptions.notebookUri = notebookUriParams;
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
|
|
||||||
// When I initialize the model
|
// When I initialize the model
|
||||||
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
||||||
@@ -436,11 +438,11 @@ suite('notebook model', function (): void {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Should set notebookUri parameters to new cell after injected parameters cell correctly', async function (): Promise<void> {
|
test('Should set notebookUri parameters to new cell after injected parameters cell correctly', async function (): Promise<void> {
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
|
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedParameterizedNotebookContent));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedParameterizedNotebookContent));
|
||||||
defaultModelOptions.notebookUri = notebookUriParams;
|
defaultModelOptions.notebookUri = notebookUriParams;
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
|
|
||||||
// When I initialize the model
|
// When I initialize the model
|
||||||
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
||||||
@@ -457,9 +459,9 @@ suite('notebook model', function (): void {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Should move first cell below second cell correctly', async function (): Promise<void> {
|
test('Should move first cell below second cell correctly', async function (): Promise<void> {
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
|
|
||||||
// When I initialize the model
|
// When I initialize the model
|
||||||
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
||||||
@@ -477,9 +479,9 @@ suite('notebook model', function (): void {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Should move second cell up above the first cell correctly', async function (): Promise<void> {
|
test('Should move second cell up above the first cell correctly', async function (): Promise<void> {
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
|
|
||||||
// When I initialize the model
|
// When I initialize the model
|
||||||
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
||||||
@@ -498,9 +500,9 @@ suite('notebook model', function (): void {
|
|||||||
|
|
||||||
test('Should delete cells correctly', async function (): Promise<void> {
|
test('Should delete cells correctly', async function (): Promise<void> {
|
||||||
// Given a notebook with 2 cells
|
// Given a notebook with 2 cells
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
|
|
||||||
// When I initalize the model
|
// When I initalize the model
|
||||||
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
||||||
@@ -549,9 +551,9 @@ suite('notebook model', function (): void {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Should notify cell on metadata change', async function (): Promise<void> {
|
test('Should notify cell on metadata change', async function (): Promise<void> {
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
|
|
||||||
// When I initalize the model
|
// When I initalize the model
|
||||||
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
||||||
@@ -566,9 +568,9 @@ suite('notebook model', function (): void {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Should set cell language correctly after cell type conversion', async function (): Promise<void> {
|
test('Should set cell language correctly after cell type conversion', async function (): Promise<void> {
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
|
|
||||||
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
||||||
await model.loadContents();
|
await model.loadContents();
|
||||||
@@ -594,9 +596,9 @@ suite('notebook model', function (): void {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Should load contents but then go to error state if client session startup fails', async function (): Promise<void> {
|
test('Should load contents but then go to error state if client session startup fails', async function (): Promise<void> {
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContentOneCell));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContentOneCell));
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
|
|
||||||
// Given I have a session that fails to start
|
// Given I have a session that fails to start
|
||||||
sessionReady.resolve();
|
sessionReady.resolve();
|
||||||
@@ -608,7 +610,7 @@ suite('notebook model', function (): void {
|
|||||||
await model.requestModelLoad();
|
await model.requestModelLoad();
|
||||||
// starting client session fails at startSessionInstance due to:
|
// starting client session fails at startSessionInstance due to:
|
||||||
// Cannot set property 'defaultKernelLoaded' of undefined
|
// Cannot set property 'defaultKernelLoaded' of undefined
|
||||||
await assert.rejects(async () => { await model.startSession(notebookManagers[0]); });
|
await assert.rejects(async () => { await model.startSession(executeManagers[0]); });
|
||||||
// Then I expect load to succeed
|
// Then I expect load to succeed
|
||||||
assert.strictEqual(model.cells.length, 1);
|
assert.strictEqual(model.cells.length, 1);
|
||||||
assert(model.clientSession);
|
assert(model.clientSession);
|
||||||
@@ -623,15 +625,15 @@ suite('notebook model', function (): void {
|
|||||||
let model = await loadModelAndStartClientSession(expectedNotebookContent);
|
let model = await loadModelAndStartClientSession(expectedNotebookContent);
|
||||||
|
|
||||||
assert.strictEqual(model.inErrorState, false);
|
assert.strictEqual(model.inErrorState, false);
|
||||||
assert.strictEqual(model.notebookManagers.length, 1);
|
assert.strictEqual(model.executeManagers.length, 1);
|
||||||
assert.deepStrictEqual(model.clientSession, mockClientSession);
|
assert.deepStrictEqual(model.clientSession, mockClientSession);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Should notify on trust set', async function () {
|
test('Should notify on trust set', async function () {
|
||||||
// Given a notebook that's been loaded
|
// Given a notebook that's been loaded
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
||||||
await model.requestModelLoad();
|
await model.requestModelLoad();
|
||||||
|
|
||||||
@@ -697,9 +699,9 @@ suite('notebook model', function (): void {
|
|||||||
expectedNotebookContent.metadata['custom-object'] = { prop1: 'value1', prop2: 'value2' };
|
expectedNotebookContent.metadata['custom-object'] = { prop1: 'value1', prop2: 'value2' };
|
||||||
|
|
||||||
// Given a notebook
|
// Given a notebook
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
// When I initialize the model
|
// When I initialize the model
|
||||||
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, undefined, queryConnectionService.object, configurationService);
|
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, undefined, queryConnectionService.object, configurationService);
|
||||||
await model.loadContents();
|
await model.loadContents();
|
||||||
@@ -808,9 +810,9 @@ suite('notebook model', function (): void {
|
|||||||
nbformat: 4,
|
nbformat: 4,
|
||||||
nbformat_minor: 5
|
nbformat_minor: 5
|
||||||
};
|
};
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(notebook));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(notebook));
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
|
|
||||||
// And a matching connection profile
|
// And a matching connection profile
|
||||||
let expectedConnectionProfile = <ConnectionProfile>{
|
let expectedConnectionProfile = <ConnectionProfile>{
|
||||||
@@ -858,9 +860,9 @@ suite('notebook model', function (): void {
|
|||||||
nbformat: 4,
|
nbformat: 4,
|
||||||
nbformat_minor: 5
|
nbformat_minor: 5
|
||||||
};
|
};
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(notebook));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(notebook));
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
|
|
||||||
// When I initialize the model
|
// When I initialize the model
|
||||||
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService);
|
||||||
@@ -885,9 +887,9 @@ suite('notebook model', function (): void {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Should keep kernel alias as language info kernel alias name even if kernel spec is seralized as SQL', async function () {
|
test('Should keep kernel alias as language info kernel alias name even if kernel spec is seralized as SQL', async function () {
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedKernelAliasNotebookContentOneCell));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedKernelAliasNotebookContentOneCell));
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
|
|
||||||
queryConnectionService.setup(c => c.getActiveConnections(TypeMoq.It.isAny())).returns(() => null);
|
queryConnectionService.setup(c => c.getActiveConnections(TypeMoq.It.isAny())).returns(() => null);
|
||||||
|
|
||||||
@@ -904,9 +906,9 @@ suite('notebook model', function (): void {
|
|||||||
});
|
});
|
||||||
|
|
||||||
async function loadModelAndStartClientSession(notebookContent: nb.INotebookContents): Promise<NotebookModel> {
|
async function loadModelAndStartClientSession(notebookContent: nb.INotebookContents): Promise<NotebookModel> {
|
||||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
|
||||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(notebookContent));
|
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(notebookContent));
|
||||||
defaultModelOptions.contentManager = mockContentManager.object;
|
defaultModelOptions.contentLoader = mockContentManager.object;
|
||||||
|
|
||||||
queryConnectionService.setup(c => c.getActiveConnections(TypeMoq.It.isAny())).returns(() => null);
|
queryConnectionService.setup(c => c.getActiveConnections(TypeMoq.It.isAny())).returns(() => null);
|
||||||
|
|
||||||
@@ -921,7 +923,7 @@ suite('notebook model', function (): void {
|
|||||||
|
|
||||||
await model.requestModelLoad();
|
await model.requestModelLoad();
|
||||||
|
|
||||||
await model.startSession(notebookManagers[0]);
|
await model.startSession(executeManagers[0]);
|
||||||
|
|
||||||
// Then I expect load to succeed
|
// Then I expect load to succeed
|
||||||
assert(!isUndefinedOrNull(model.clientSession), 'clientSession should exist after session is started');
|
assert(!isUndefinedOrNull(model.clientSession), 'clientSession should exist after session is started');
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import * as vsEvent from 'vs/base/common/event';
|
|||||||
import { INotebookModel, ICellModel, IClientSession, NotebookContentChange, ISingleNotebookEditOperation, MoveDirection, ViewMode } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
import { INotebookModel, ICellModel, IClientSession, NotebookContentChange, ISingleNotebookEditOperation, MoveDirection, ViewMode } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||||
import { INotebookFindModel } from 'sql/workbench/contrib/notebook/browser/models/notebookFindModel';
|
import { INotebookFindModel } from 'sql/workbench/contrib/notebook/browser/models/notebookFindModel';
|
||||||
import { NotebookChangeType, CellType } from 'sql/workbench/services/notebook/common/contracts';
|
import { NotebookChangeType, CellType } from 'sql/workbench/services/notebook/common/contracts';
|
||||||
import { INotebookManager, INotebookService, INotebookEditor, ILanguageMagic, INotebookProvider, INavigationProvider, INotebookParams, INotebookSection, ICellEditorProvider, NotebookRange } from 'sql/workbench/services/notebook/browser/notebookService';
|
import { IExecuteManager, INotebookService, INotebookEditor, ILanguageMagic, IExecuteProvider, INavigationProvider, INotebookParams, INotebookSection, ICellEditorProvider, NotebookRange, ISerializationProvider, ISerializationManager } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||||
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
|
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
|
||||||
import { IModelDecorationsChangeAccessor } from 'vs/editor/common/model';
|
import { IModelDecorationsChangeAccessor } from 'vs/editor/common/model';
|
||||||
import { NotebookFindMatch } from 'sql/workbench/contrib/notebook/browser/find/notebookFindDecorations';
|
import { NotebookFindMatch } from 'sql/workbench/contrib/notebook/browser/find/notebookFindDecorations';
|
||||||
@@ -47,7 +47,10 @@ export class NotebookModelStub implements INotebookModel {
|
|||||||
get sessionLoadFinished(): Promise<void> {
|
get sessionLoadFinished(): Promise<void> {
|
||||||
throw new Error('method not implemented.');
|
throw new Error('method not implemented.');
|
||||||
}
|
}
|
||||||
get notebookManagers(): INotebookManager[] {
|
get serializationManager(): ISerializationManager {
|
||||||
|
throw new Error('method not implemented.');
|
||||||
|
}
|
||||||
|
get executeManagers(): IExecuteManager[] {
|
||||||
throw new Error('method not implemented.');
|
throw new Error('method not implemented.');
|
||||||
}
|
}
|
||||||
get kernelChanged(): vsEvent.Event<nb.IKernelChangedArgs> {
|
get kernelChanged(): vsEvent.Event<nb.IKernelChangedArgs> {
|
||||||
@@ -197,9 +200,13 @@ export class NotebookFindModelStub implements INotebookFindModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NotebookManagerStub implements INotebookManager {
|
export class SerializationManagerStub implements ISerializationManager {
|
||||||
providerId: string;
|
providerId: string;
|
||||||
contentManager: nb.ContentManager;
|
contentManager: nb.ContentManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ExecuteManagerStub implements IExecuteManager {
|
||||||
|
providerId: string;
|
||||||
sessionManager: nb.SessionManager;
|
sessionManager: nb.SessionManager;
|
||||||
serverManager: nb.ServerManager;
|
serverManager: nb.ServerManager;
|
||||||
}
|
}
|
||||||
@@ -245,10 +252,16 @@ export class NotebookServiceStub implements INotebookService {
|
|||||||
setTrusted(notebookUri: URI, isTrusted: boolean): Promise<boolean> {
|
setTrusted(notebookUri: URI, isTrusted: boolean): Promise<boolean> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
registerProvider(providerId: string, provider: INotebookProvider): void {
|
registerSerializationProvider(providerId: string, provider: ISerializationProvider): void {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
unregisterProvider(providerId: string): void {
|
registerExecuteProvider(providerId: string, provider: IExecuteProvider): void {
|
||||||
|
throw new Error('Method not implemented.');
|
||||||
|
}
|
||||||
|
unregisterSerializationProvider(providerId: string): void {
|
||||||
|
throw new Error('Method not implemented.');
|
||||||
|
}
|
||||||
|
unregisterExecuteProvider(providerId: string): void {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
registerNavigationProvider(provider: INavigationProvider): void {
|
registerNavigationProvider(provider: INavigationProvider): void {
|
||||||
@@ -266,7 +279,10 @@ export class NotebookServiceStub implements INotebookService {
|
|||||||
getStandardKernelsForProvider(provider: string): nb.IStandardKernel[] {
|
getStandardKernelsForProvider(provider: string): nb.IStandardKernel[] {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
getOrCreateNotebookManager(providerId: string, uri: URI): Thenable<INotebookManager> {
|
getOrCreateSerializationManager(providerId: string, uri: URI): Promise<ISerializationManager> {
|
||||||
|
throw new Error('Method not implemented.');
|
||||||
|
}
|
||||||
|
getOrCreateExecuteManager(providerId: string, uri: URI): Thenable<IExecuteManager> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
addNotebookEditor(editor: INotebookEditor): void {
|
addNotebookEditor(editor: INotebookEditor): void {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import { IContentManager } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
import { IContentLoader } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||||
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
|
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
|
||||||
|
|
||||||
export interface INotebookInput {
|
export interface INotebookInput {
|
||||||
@@ -14,11 +14,12 @@ export interface INotebookInput {
|
|||||||
isDirty(): boolean;
|
isDirty(): boolean;
|
||||||
setDirty(boolean);
|
setDirty(boolean);
|
||||||
readonly notebookUri: URI;
|
readonly notebookUri: URI;
|
||||||
updateModel(): void;
|
updateModel(): Promise<void>;
|
||||||
readonly editorOpenedTimestamp: number;
|
readonly editorOpenedTimestamp: number;
|
||||||
readonly layoutChanged: Event<void>;
|
readonly layoutChanged: Event<void>;
|
||||||
readonly contentManager: IContentManager;
|
readonly contentLoader: IContentLoader;
|
||||||
readonly standardKernels: IStandardKernelWithProvider[];
|
readonly standardKernels: IStandardKernelWithProvider[];
|
||||||
|
readonly providersLoaded: Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isINotebookInput(value: any): value is INotebookInput {
|
export function isINotebookInput(value: any): value is INotebookInput {
|
||||||
@@ -29,7 +30,7 @@ export function isINotebookInput(value: any): value is INotebookInput {
|
|||||||
typeof value.isDirty === 'function' &&
|
typeof value.isDirty === 'function' &&
|
||||||
typeof value.layoutChanged === 'function' &&
|
typeof value.layoutChanged === 'function' &&
|
||||||
typeof value.editorOpenedTimestamp === 'number' &&
|
typeof value.editorOpenedTimestamp === 'number' &&
|
||||||
typeof value.contentManager === 'object' &&
|
typeof value.contentLoader === 'object' &&
|
||||||
typeof value.standardKernels === 'object') {
|
typeof value.standardKernels === 'object') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { getErrorMessage } from 'vs/base/common/errors';
|
|||||||
|
|
||||||
import { IClientSession, IClientSessionOptions } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
import { IClientSession, IClientSessionOptions } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||||
import { Deferred } from 'sql/base/common/promise';
|
import { Deferred } from 'sql/base/common/promise';
|
||||||
import { INotebookManager } from 'sql/workbench/services/notebook/browser/notebookService';
|
import { IExecuteManager } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||||
|
|
||||||
type KernelChangeHandler = (kernel: nb.IKernelChangedArgs) => Promise<void>;
|
type KernelChangeHandler = (kernel: nb.IKernelChangedArgs) => Promise<void>;
|
||||||
@@ -45,14 +45,14 @@ export class ClientSession implements IClientSession {
|
|||||||
|
|
||||||
private _serverLoadFinished: Promise<void> = Promise.resolve();
|
private _serverLoadFinished: Promise<void> = Promise.resolve();
|
||||||
private _session: nb.ISession | undefined;
|
private _session: nb.ISession | undefined;
|
||||||
private isServerStarted: boolean = false;
|
private _isServerStarted: boolean = false;
|
||||||
private notebookManager: INotebookManager;
|
private _executeManager: IExecuteManager;
|
||||||
private _kernelConfigActions: ((kernelName: string) => Promise<any>)[] = [];
|
private _kernelConfigActions: ((kernelName: string) => Promise<any>)[] = [];
|
||||||
private _connectionId: string = '';
|
private _connectionId: string = '';
|
||||||
|
|
||||||
constructor(private options: IClientSessionOptions) {
|
constructor(private options: IClientSessionOptions) {
|
||||||
this._notebookUri = options.notebookUri;
|
this._notebookUri = options.notebookUri;
|
||||||
this.notebookManager = options.notebookManager;
|
this._executeManager = options.executeManager;
|
||||||
this._isReady = false;
|
this._isReady = false;
|
||||||
this._ready = new Deferred<void>();
|
this._ready = new Deferred<void>();
|
||||||
this._kernelChangeCompleted = new Deferred<void>();
|
this._kernelChangeCompleted = new Deferred<void>();
|
||||||
@@ -77,23 +77,23 @@ export class ClientSession implements IClientSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async startServer(kernelSpec: nb.IKernelSpec): Promise<void> {
|
private async startServer(kernelSpec: nb.IKernelSpec): Promise<void> {
|
||||||
let serverManager = this.notebookManager.serverManager;
|
let serverManager = this._executeManager.serverManager;
|
||||||
if (serverManager) {
|
if (serverManager) {
|
||||||
await serverManager.startServer(kernelSpec);
|
await serverManager.startServer(kernelSpec);
|
||||||
if (!serverManager.isStarted) {
|
if (!serverManager.isStarted) {
|
||||||
throw new Error(localize('ServerNotStarted', "Server did not start for unknown reason"));
|
throw new Error(localize('ServerNotStarted', "Server did not start for unknown reason"));
|
||||||
}
|
}
|
||||||
this.isServerStarted = serverManager.isStarted;
|
this._isServerStarted = serverManager.isStarted;
|
||||||
} else {
|
} else {
|
||||||
this.isServerStarted = true;
|
this._isServerStarted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async initializeSession(): Promise<void> {
|
private async initializeSession(): Promise<void> {
|
||||||
await this._serverLoadFinished;
|
await this._serverLoadFinished;
|
||||||
if (this.isServerStarted) {
|
if (this._isServerStarted) {
|
||||||
if (!this.notebookManager.sessionManager.isReady) {
|
if (!this._executeManager.sessionManager.isReady) {
|
||||||
await this.notebookManager.sessionManager.ready;
|
await this._executeManager.sessionManager.ready;
|
||||||
}
|
}
|
||||||
if (this._defaultKernel) {
|
if (this._defaultKernel) {
|
||||||
await this.startSessionInstance(this._defaultKernel.name);
|
await this.startSessionInstance(this._defaultKernel.name);
|
||||||
@@ -105,7 +105,7 @@ export class ClientSession implements IClientSession {
|
|||||||
let session: nb.ISession;
|
let session: nb.ISession;
|
||||||
try {
|
try {
|
||||||
// TODO #3164 should use URI instead of path for startNew
|
// TODO #3164 should use URI instead of path for startNew
|
||||||
session = await this.notebookManager.sessionManager.startNew({
|
session = await this._executeManager.sessionManager.startNew({
|
||||||
path: this.notebookUri.fsPath,
|
path: this.notebookUri.fsPath,
|
||||||
kernelName: kernelName
|
kernelName: kernelName
|
||||||
// TODO add kernel name if saved in the document
|
// TODO add kernel name if saved in the document
|
||||||
@@ -115,7 +115,7 @@ export class ClientSession implements IClientSession {
|
|||||||
// TODO move registration
|
// TODO move registration
|
||||||
if (err && err.response && err.response.status === 501) {
|
if (err && err.response && err.response.status === 501) {
|
||||||
this.options.notificationService.warn(localize('kernelRequiresConnection', "Kernel {0} was not found. The default kernel will be used instead.", kernelName));
|
this.options.notificationService.warn(localize('kernelRequiresConnection', "Kernel {0} was not found. The default kernel will be used instead.", kernelName));
|
||||||
session = await this.notebookManager.sessionManager.startNew({
|
session = await this._executeManager.sessionManager.startNew({
|
||||||
path: this.notebookUri.fsPath,
|
path: this.notebookUri.fsPath,
|
||||||
kernelName: undefined
|
kernelName: undefined
|
||||||
});
|
});
|
||||||
@@ -304,8 +304,8 @@ export class ClientSession implements IClientSession {
|
|||||||
*/
|
*/
|
||||||
public async shutdown(): Promise<void> {
|
public async shutdown(): Promise<void> {
|
||||||
// Always try to shut down session
|
// Always try to shut down session
|
||||||
if (this._session && this._session.id && this.notebookManager && this.notebookManager.sessionManager) {
|
if (this._session && this._session.id && this._executeManager && this._executeManager.sessionManager) {
|
||||||
await this.notebookManager.sessionManager.shutdown(this._session.id);
|
await this._executeManager.sessionManager.shutdown(this._session.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { URI } from 'vs/base/common/uri';
|
|||||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||||
|
|
||||||
import { CellType, NotebookChangeType } from 'sql/workbench/services/notebook/common/contracts';
|
import { CellType, NotebookChangeType } from 'sql/workbench/services/notebook/common/contracts';
|
||||||
import { INotebookManager, ILanguageMagic } from 'sql/workbench/services/notebook/browser/notebookService';
|
import { IExecuteManager, ILanguageMagic, ISerializationManager } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||||
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
||||||
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
|
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
|
||||||
@@ -42,7 +42,7 @@ export interface ISingleNotebookEditOperation {
|
|||||||
|
|
||||||
export interface IClientSessionOptions {
|
export interface IClientSessionOptions {
|
||||||
notebookUri: URI;
|
notebookUri: URI;
|
||||||
notebookManager: INotebookManager;
|
executeManager: IExecuteManager;
|
||||||
notificationService: INotificationService;
|
notificationService: INotificationService;
|
||||||
kernelSpec: nb.IKernelSpec;
|
kernelSpec: nb.IKernelSpec;
|
||||||
}
|
}
|
||||||
@@ -254,9 +254,14 @@ export interface INotebookModel {
|
|||||||
readonly language: string;
|
readonly language: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All notebook managers applicable for a given notebook
|
* The current serialization manager applicable for a given notebook
|
||||||
*/
|
*/
|
||||||
readonly notebookManagers: INotebookManager[];
|
readonly serializationManager: ISerializationManager | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All execute managers applicable for a given notebook
|
||||||
|
*/
|
||||||
|
readonly executeManagers: IExecuteManager[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event fired on first initialization of the kernel and
|
* Event fired on first initialization of the kernel and
|
||||||
@@ -551,7 +556,7 @@ export interface IModelFactory {
|
|||||||
createClientSession(options: IClientSessionOptions): IClientSession;
|
createClientSession(options: IClientSessionOptions): IClientSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IContentManager {
|
export interface IContentLoader {
|
||||||
/**
|
/**
|
||||||
* This is a specialized method intended to load for a default context - just the current Notebook's URI
|
* This is a specialized method intended to load for a default context - just the current Notebook's URI
|
||||||
*/
|
*/
|
||||||
@@ -569,8 +574,9 @@ export interface INotebookModelOptions {
|
|||||||
*/
|
*/
|
||||||
factory: IModelFactory;
|
factory: IModelFactory;
|
||||||
|
|
||||||
contentManager: IContentManager;
|
contentLoader: IContentLoader;
|
||||||
notebookManagers: INotebookManager[];
|
serializationManagers: ISerializationManager[];
|
||||||
|
executeManagers: IExecuteManager[];
|
||||||
providerId: string;
|
providerId: string;
|
||||||
defaultKernel: nb.IKernelSpec;
|
defaultKernel: nb.IKernelSpec;
|
||||||
cellMagicMapper: ICellMagicMapper;
|
cellMagicMapper: ICellMagicMapper;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { NotebookChangeType, CellType, CellTypes } from 'sql/workbench/services/
|
|||||||
import { KernelsLanguage, nbversion } from 'sql/workbench/services/notebook/common/notebookConstants';
|
import { KernelsLanguage, nbversion } from 'sql/workbench/services/notebook/common/notebookConstants';
|
||||||
import * as notebookUtils from 'sql/workbench/services/notebook/browser/models/notebookUtils';
|
import * as notebookUtils from 'sql/workbench/services/notebook/browser/models/notebookUtils';
|
||||||
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
|
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
|
||||||
import { INotebookManager, SQL_NOTEBOOK_PROVIDER, DEFAULT_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/browser/notebookService';
|
import { IExecuteManager, SQL_NOTEBOOK_PROVIDER, DEFAULT_NOTEBOOK_PROVIDER, ISerializationManager } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||||
import { NotebookContexts } from 'sql/workbench/services/notebook/browser/models/notebookContexts';
|
import { NotebookContexts } from 'sql/workbench/services/notebook/browser/models/notebookContexts';
|
||||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||||
import { INotification, Severity, INotificationService } from 'vs/platform/notification/common/notification';
|
import { INotification, Severity, INotificationService } from 'vs/platform/notification/common/notification';
|
||||||
@@ -124,7 +124,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
|
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
if (!_notebookOptions || !_notebookOptions.notebookUri || !_notebookOptions.notebookManagers) {
|
if (!_notebookOptions || !_notebookOptions.notebookUri || !_notebookOptions.executeManagers) {
|
||||||
throw new Error('path or notebook service not defined');
|
throw new Error('path or notebook service not defined');
|
||||||
}
|
}
|
||||||
this._trustedMode = false;
|
this._trustedMode = false;
|
||||||
@@ -136,27 +136,43 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
this._defaultKernel = _notebookOptions.defaultKernel;
|
this._defaultKernel = _notebookOptions.defaultKernel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get notebookManagers(): INotebookManager[] {
|
private get serializationManagers(): ISerializationManager[] {
|
||||||
let notebookManagers = this._notebookOptions.notebookManagers.filter(manager => manager.providerId !== DEFAULT_NOTEBOOK_PROVIDER);
|
let managers = this._notebookOptions.serializationManagers.filter(manager => manager.providerId !== DEFAULT_NOTEBOOK_PROVIDER);
|
||||||
if (!notebookManagers.length) {
|
if (!managers.length) {
|
||||||
return this._notebookOptions.notebookManagers;
|
return this._notebookOptions.serializationManagers;
|
||||||
}
|
}
|
||||||
return notebookManagers;
|
return managers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get notebookManager(): INotebookManager | undefined {
|
public get serializationManager(): ISerializationManager | undefined {
|
||||||
let manager = this.notebookManagers.find(manager => manager.providerId === this._providerId);
|
let manager = this.serializationManagers.find(manager => manager.providerId === this._providerId);
|
||||||
if (!manager) {
|
if (!manager) {
|
||||||
// Note: this seems like a less than ideal scenario. We should ideally pass in the "correct" provider ID and allow there to be a default,
|
manager = this.serializationManagers.find(manager => manager.providerId === DEFAULT_NOTEBOOK_PROVIDER);
|
||||||
// instead of assuming in the NotebookModel constructor that the option is either SQL or Jupyter
|
|
||||||
manager = this.notebookManagers.find(manager => manager.providerId === DEFAULT_NOTEBOOK_PROVIDER);
|
|
||||||
}
|
}
|
||||||
return manager;
|
return manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getNotebookManager(providerId: string): INotebookManager | undefined {
|
public get executeManagers(): IExecuteManager[] {
|
||||||
|
let managers = this._notebookOptions.executeManagers.filter(manager => manager.providerId !== DEFAULT_NOTEBOOK_PROVIDER);
|
||||||
|
if (!managers.length) {
|
||||||
|
return this._notebookOptions.executeManagers;
|
||||||
|
}
|
||||||
|
return managers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get executeManager(): IExecuteManager | undefined {
|
||||||
|
let manager = this.executeManagers.find(manager => manager.providerId === this._providerId);
|
||||||
|
if (!manager) {
|
||||||
|
// Note: this seems like a less than ideal scenario. We should ideally pass in the "correct" provider ID and allow there to be a default,
|
||||||
|
// instead of assuming in the NotebookModel constructor that the option is either SQL or Jupyter
|
||||||
|
manager = this.executeManagers.find(manager => manager.providerId === DEFAULT_NOTEBOOK_PROVIDER);
|
||||||
|
}
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getExecuteManager(providerId: string): IExecuteManager | undefined {
|
||||||
if (providerId) {
|
if (providerId) {
|
||||||
return this.notebookManagers.find(manager => manager.providerId === providerId);
|
return this.executeManagers.find(manager => manager.providerId === providerId);
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -174,7 +190,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
|
|
||||||
public get hasServerManager(): boolean {
|
public get hasServerManager(): boolean {
|
||||||
// If the service has a server manager, then we can show the start button
|
// If the service has a server manager, then we can show the start button
|
||||||
return !!this.notebookManager?.serverManager;
|
return !!this.executeManager?.serverManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get contentChanged(): Event<NotebookContentChange> {
|
public get contentChanged(): Event<NotebookContentChange> {
|
||||||
@@ -247,7 +263,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
defaultKernel: '',
|
defaultKernel: '',
|
||||||
kernels: []
|
kernels: []
|
||||||
};
|
};
|
||||||
this.notebookManagers.forEach(manager => {
|
this.executeManagers.forEach(manager => {
|
||||||
if (manager.sessionManager && manager.sessionManager.specs && manager.sessionManager.specs.kernels) {
|
if (manager.sessionManager && manager.sessionManager.specs && manager.sessionManager.specs.kernels) {
|
||||||
manager.sessionManager.specs.kernels.forEach(kernel => {
|
manager.sessionManager.specs.kernels.forEach(kernel => {
|
||||||
specs.kernels.push(kernel);
|
specs.kernels.push(kernel);
|
||||||
@@ -399,8 +415,8 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
|
|
||||||
let contents: nb.INotebookContents | undefined;
|
let contents: nb.INotebookContents | undefined;
|
||||||
|
|
||||||
if (this._notebookOptions && this._notebookOptions.contentManager) {
|
if (this._notebookOptions && this._notebookOptions.contentLoader) {
|
||||||
contents = await this._notebookOptions.contentManager.loadContent();
|
contents = await this._notebookOptions.contentLoader.loadContent();
|
||||||
}
|
}
|
||||||
let factory = this._notebookOptions.factory;
|
let factory = this._notebookOptions.factory;
|
||||||
// if cells already exist, create them with language info (if it is saved)
|
// if cells already exist, create them with language info (if it is saved)
|
||||||
@@ -693,7 +709,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
this._onErrorEmitter.fire({ message: error, severity: Severity.Error });
|
this._onErrorEmitter.fire({ message: error, severity: Severity.Error });
|
||||||
}
|
}
|
||||||
|
|
||||||
public async startSession(manager: INotebookManager, displayName?: string, setErrorStateOnFail?: boolean, kernelAlias?: string): Promise<void> {
|
public async startSession(manager: IExecuteManager, displayName?: string, setErrorStateOnFail?: boolean, kernelAlias?: string): Promise<void> {
|
||||||
if (displayName) {
|
if (displayName) {
|
||||||
let standardKernel = this._standardKernels.find(kernel => kernel.displayName === displayName);
|
let standardKernel = this._standardKernels.find(kernel => kernel.displayName === displayName);
|
||||||
if (standardKernel) {
|
if (standardKernel) {
|
||||||
@@ -703,7 +719,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
if (this._defaultKernel) {
|
if (this._defaultKernel) {
|
||||||
let clientSession = this._notebookOptions.factory.createClientSession({
|
let clientSession = this._notebookOptions.factory.createClientSession({
|
||||||
notebookUri: this._notebookOptions.notebookUri,
|
notebookUri: this._notebookOptions.notebookUri,
|
||||||
notebookManager: manager,
|
executeManager: manager,
|
||||||
notificationService: this._notebookOptions.notificationService,
|
notificationService: this._notebookOptions.notificationService,
|
||||||
kernelSpec: this._defaultKernel
|
kernelSpec: this._defaultKernel
|
||||||
});
|
});
|
||||||
@@ -750,7 +766,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
if (this._activeClientSession) {
|
if (this._activeClientSession) {
|
||||||
// Old active client sessions have already been shutdown by RESTART_JUPYTER_NOTEBOOK_SESSIONS command
|
// Old active client sessions have already been shutdown by RESTART_JUPYTER_NOTEBOOK_SESSIONS command
|
||||||
this._activeClientSession = undefined;
|
this._activeClientSession = undefined;
|
||||||
await this.startSession(this.notebookManager, this._selectedKernelDisplayName, true);
|
await this.startSession(this.executeManager, this._selectedKernelDisplayName, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -777,7 +793,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
if (provider && provider !== this._providerId) {
|
if (provider && provider !== this._providerId) {
|
||||||
this._providerId = provider;
|
this._providerId = provider;
|
||||||
} else if (!provider) {
|
} else if (!provider) {
|
||||||
this.notebookOptions.notebookManagers.forEach(m => {
|
this.notebookOptions.executeManagers.forEach(m => {
|
||||||
if (m.providerId !== SQL_NOTEBOOK_PROVIDER) {
|
if (m.providerId !== SQL_NOTEBOOK_PROVIDER) {
|
||||||
// We don't know which provider it is before that provider is chosen to query its specs. Choosing the "last" one registered.
|
// We don't know which provider it is before that provider is chosen to query its specs. Choosing the "last" one registered.
|
||||||
this._providerId = m.providerId;
|
this._providerId = m.providerId;
|
||||||
@@ -1002,7 +1018,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
// Ensure that the kernel we try to switch to is a valid kernel; if not, use the default
|
// Ensure that the kernel we try to switch to is a valid kernel; if not, use the default
|
||||||
let kernelSpecs = this.getKernelSpecs();
|
let kernelSpecs = this.getKernelSpecs();
|
||||||
if (kernelSpecs && kernelSpecs.length > 0 && kernelSpecs.findIndex(k => k.display_name === spec.display_name) < 0) {
|
if (kernelSpecs && kernelSpecs.length > 0 && kernelSpecs.findIndex(k => k.display_name === spec.display_name) < 0) {
|
||||||
spec = kernelSpecs.find(spec => spec.name === this.notebookManager?.sessionManager.specs.defaultKernel);
|
spec = kernelSpecs.find(spec => spec.name === this.executeManager?.sessionManager.specs.defaultKernel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1099,11 +1115,11 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getDisplayNameFromSpecName(kernel: nb.IKernel): string | undefined {
|
public getDisplayNameFromSpecName(kernel: nb.IKernel): string | undefined {
|
||||||
let specs = this.notebookManager?.sessionManager.specs;
|
let specs = this.executeManager?.sessionManager.specs;
|
||||||
if (!specs || !specs.kernels) {
|
if (!specs || !specs.kernels) {
|
||||||
return kernel.name;
|
return kernel.name;
|
||||||
}
|
}
|
||||||
let newKernel = this.notebookManager.sessionManager.specs.kernels.find(k => k.name === kernel.name);
|
let newKernel = this.executeManager.sessionManager.specs.kernels.find(k => k.name === kernel.name);
|
||||||
let newKernelDisplayName;
|
let newKernelDisplayName;
|
||||||
if (newKernel) {
|
if (newKernel) {
|
||||||
newKernelDisplayName = newKernel.display_name;
|
newKernelDisplayName = newKernel.display_name;
|
||||||
@@ -1202,7 +1218,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
this._onProviderIdChanged.fire(this._providerId);
|
this._onProviderIdChanged.fire(this._providerId);
|
||||||
|
|
||||||
await this.shutdownActiveSession();
|
await this.shutdownActiveSession();
|
||||||
let manager = this.getNotebookManager(providerId);
|
let manager = this.getExecuteManager(providerId);
|
||||||
if (manager) {
|
if (manager) {
|
||||||
await this.startSession(manager, displayName, false, kernelAlias);
|
await this.startSession(manager, displayName, false, kernelAlias);
|
||||||
} else {
|
} else {
|
||||||
@@ -1225,8 +1241,8 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
return providerId;
|
return providerId;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (this.notebookManagers?.length) {
|
if (this.executeManagers?.length) {
|
||||||
return this.notebookManagers.map(m => m.providerId).find(p => p !== DEFAULT_NOTEBOOK_PROVIDER && p !== SQL_NOTEBOOK_PROVIDER);
|
return this.executeManagers.map(m => m.providerId).find(p => p !== DEFAULT_NOTEBOOK_PROVIDER && p !== SQL_NOTEBOOK_PROVIDER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -1234,9 +1250,9 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
|||||||
|
|
||||||
// Get kernel specs from current sessionManager
|
// Get kernel specs from current sessionManager
|
||||||
private getKernelSpecs(): nb.IKernelSpec[] {
|
private getKernelSpecs(): nb.IKernelSpec[] {
|
||||||
if (this.notebookManager && this.notebookManager.sessionManager && this.notebookManager.sessionManager.specs &&
|
if (this.executeManager && this.executeManager.sessionManager && this.executeManager.sessionManager.specs &&
|
||||||
this.notebookManager.sessionManager.specs.kernels) {
|
this.executeManager.sessionManager.specs.kernels) {
|
||||||
return this.notebookManager.sessionManager.specs.kernels;
|
return this.executeManager.sessionManager.specs.kernels;
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,15 +57,14 @@ export interface INotebookService {
|
|||||||
readonly isRegistrationComplete: boolean;
|
readonly isRegistrationComplete: boolean;
|
||||||
readonly registrationComplete: Promise<void>;
|
readonly registrationComplete: Promise<void>;
|
||||||
readonly languageMagics: ILanguageMagic[];
|
readonly languageMagics: ILanguageMagic[];
|
||||||
/**
|
|
||||||
* Register a metadata provider
|
|
||||||
*/
|
|
||||||
registerProvider(providerId: string, provider: INotebookProvider): void;
|
|
||||||
|
|
||||||
/**
|
registerSerializationProvider(providerId: string, provider: ISerializationProvider): void;
|
||||||
* Register a metadata provider
|
|
||||||
*/
|
registerExecuteProvider(providerId: string, provider: IExecuteProvider): void;
|
||||||
unregisterProvider(providerId: string): void;
|
|
||||||
|
unregisterSerializationProvider(providerId: string): void;
|
||||||
|
|
||||||
|
unregisterExecuteProvider(providerId: string): void;
|
||||||
|
|
||||||
registerNavigationProvider(provider: INavigationProvider): void;
|
registerNavigationProvider(provider: INavigationProvider): void;
|
||||||
|
|
||||||
@@ -77,14 +76,9 @@ export interface INotebookService {
|
|||||||
|
|
||||||
getStandardKernelsForProvider(provider: string): azdata.nb.IStandardKernel[];
|
getStandardKernelsForProvider(provider: string): azdata.nb.IStandardKernel[];
|
||||||
|
|
||||||
/**
|
getOrCreateSerializationManager(providerId: string, uri: URI): Promise<ISerializationManager>;
|
||||||
* Initializes and returns a Notebook manager that can handle all important calls to open, display, and
|
|
||||||
* run cells in a notebook.
|
getOrCreateExecuteManager(providerId: string, uri: URI): Thenable<IExecuteManager>;
|
||||||
* @param providerId ID for the provider to be used to instantiate a backend notebook service
|
|
||||||
* @param uri URI for a notebook that is to be opened. Based on this an existing manager may be used, or
|
|
||||||
* a new one may need to be created
|
|
||||||
*/
|
|
||||||
getOrCreateNotebookManager(providerId: string, uri: URI): Thenable<INotebookManager>;
|
|
||||||
|
|
||||||
addNotebookEditor(editor: INotebookEditor): void;
|
addNotebookEditor(editor: INotebookEditor): void;
|
||||||
|
|
||||||
@@ -148,15 +142,24 @@ export interface INotebookService {
|
|||||||
getUntitledUriPath(originalTitle: string): string;
|
getUntitledUriPath(originalTitle: string): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface INotebookProvider {
|
export interface IExecuteProvider {
|
||||||
readonly providerId: string;
|
readonly providerId: string;
|
||||||
getNotebookManager(notebookUri: URI): Thenable<INotebookManager>;
|
getExecuteManager(notebookUri: URI): Thenable<IExecuteManager>;
|
||||||
handleNotebookClosed(notebookUri: URI): void;
|
handleNotebookClosed(notebookUri: URI): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface INotebookManager {
|
export interface ISerializationProvider {
|
||||||
|
readonly providerId: string;
|
||||||
|
getSerializationManager(notebookUri: URI): Thenable<ISerializationManager>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ISerializationManager {
|
||||||
providerId: string;
|
providerId: string;
|
||||||
readonly contentManager: azdata.nb.ContentManager;
|
readonly contentManager: azdata.nb.ContentManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IExecuteManager {
|
||||||
|
providerId: string;
|
||||||
readonly sessionManager: azdata.nb.SessionManager;
|
readonly sessionManager: azdata.nb.SessionManager;
|
||||||
readonly serverManager: azdata.nb.ServerManager;
|
readonly serverManager: azdata.nb.ServerManager;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ import { URI, UriComponents } from 'vs/base/common/uri';
|
|||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
INotebookService, INotebookManager, INotebookProvider,
|
INotebookService, IExecuteManager, IExecuteProvider,
|
||||||
DEFAULT_NOTEBOOK_FILETYPE, INotebookEditor, SQL_NOTEBOOK_PROVIDER, INavigationProvider, ILanguageMagic, NavigationProviders, unsavedBooksContextKey
|
DEFAULT_NOTEBOOK_FILETYPE, INotebookEditor, SQL_NOTEBOOK_PROVIDER, INavigationProvider, ILanguageMagic, NavigationProviders, unsavedBooksContextKey, ISerializationProvider, ISerializationManager
|
||||||
} from 'sql/workbench/services/notebook/browser/notebookService';
|
} from 'sql/workbench/services/notebook/browser/notebookService';
|
||||||
import { RenderMimeRegistry } from 'sql/workbench/services/notebook/browser/outputs/registry';
|
import { RenderMimeRegistry } from 'sql/workbench/services/notebook/browser/outputs/registry';
|
||||||
import { standardRendererFactories } from 'sql/workbench/services/notebook/browser/outputs/factories';
|
import { standardRendererFactories } from 'sql/workbench/services/notebook/browser/outputs/factories';
|
||||||
import { Extensions, INotebookProviderRegistry, NotebookProviderRegistration } from 'sql/workbench/services/notebook/common/notebookRegistry';
|
import { Extensions, INotebookProviderRegistry, NotebookProviderRegistryId, ProviderDescriptionRegistration } from 'sql/workbench/services/notebook/common/notebookRegistry';
|
||||||
import { Emitter, Event } from 'vs/base/common/event';
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
import { Memento } from 'vs/workbench/common/memento';
|
import { Memento } from 'vs/workbench/common/memento';
|
||||||
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||||
@@ -26,7 +26,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
|||||||
import { IQueryManagementService } from 'sql/workbench/services/query/common/queryManagement';
|
import { IQueryManagementService } from 'sql/workbench/services/query/common/queryManagement';
|
||||||
import { ICellModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
import { ICellModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||||
import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||||
import { SqlNotebookProvider } from 'sql/workbench/services/notebook/browser/sql/sqlNotebookProvider';
|
import { SqlExecuteProvider } from 'sql/workbench/services/notebook/browser/sql/sqlExecuteProvider';
|
||||||
import { IFileService, IFileStatWithMetadata } from 'vs/platform/files/common/files';
|
import { IFileService, IFileStatWithMetadata } from 'vs/platform/files/common/files';
|
||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
@@ -50,8 +50,9 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor
|
|||||||
import { IEditorInput, IEditorPane } from 'vs/workbench/common/editor';
|
import { IEditorInput, IEditorPane } from 'vs/workbench/common/editor';
|
||||||
import { isINotebookInput } from 'sql/workbench/services/notebook/browser/interface';
|
import { isINotebookInput } from 'sql/workbench/services/notebook/browser/interface';
|
||||||
import { INotebookShowOptions } from 'sql/workbench/api/common/sqlExtHost.protocol';
|
import { INotebookShowOptions } from 'sql/workbench/api/common/sqlExtHost.protocol';
|
||||||
import { NotebookLanguage } from 'sql/workbench/common/constants';
|
import { JUPYTER_PROVIDER_ID, NotebookLanguage } from 'sql/workbench/common/constants';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
|
import { SqlSerializationProvider } from 'sql/workbench/services/notebook/browser/sql/sqlSerializationProvider';
|
||||||
|
|
||||||
const languageAssociationRegistry = Registry.as<ILanguageAssociationRegistry>(LanguageAssociationExtensions.LanguageAssociations);
|
const languageAssociationRegistry = Registry.as<ILanguageAssociationRegistry>(LanguageAssociationExtensions.LanguageAssociations);
|
||||||
|
|
||||||
@@ -65,7 +66,8 @@ interface NotebookProviderCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface NotebookProvidersMemento {
|
export interface NotebookProvidersMemento {
|
||||||
notebookProviderCache: NotebookProviderCache;
|
notebookSerializationProviderCache: NotebookProviderCache;
|
||||||
|
notebookExecuteProviderCache: NotebookProviderCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TrustedNotebookMetadata {
|
interface TrustedNotebookMetadata {
|
||||||
@@ -80,24 +82,53 @@ export interface TrustedNotebooksMemento {
|
|||||||
trustedNotebooksCache: TrustedNotebookCache;
|
trustedNotebooksCache: TrustedNotebookCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
const notebookRegistry = Registry.as<INotebookProviderRegistry>(Extensions.NotebookProviderContribution);
|
const notebookRegistry = Registry.as<INotebookProviderRegistry>(NotebookProviderRegistryId);
|
||||||
|
|
||||||
export class ProviderDescriptor {
|
export class SerializationProviderDescriptor {
|
||||||
private _instanceReady = new Deferred<INotebookProvider>();
|
private _instanceReady = new Deferred<ISerializationProvider>();
|
||||||
constructor(private _instance?: INotebookProvider) {
|
constructor(private readonly _providerId: string, private _instance?: ISerializationProvider) {
|
||||||
if (_instance) {
|
if (_instance) {
|
||||||
this._instanceReady.resolve(_instance);
|
this._instanceReady.resolve(_instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public get instanceReady(): Promise<INotebookProvider> {
|
public get providerId(): string {
|
||||||
|
return this._providerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get instanceReady(): Promise<ISerializationProvider> {
|
||||||
return this._instanceReady.promise;
|
return this._instanceReady.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get instance(): INotebookProvider {
|
public get instance(): ISerializationProvider | undefined {
|
||||||
return this._instance;
|
return this._instance;
|
||||||
}
|
}
|
||||||
public set instance(value: INotebookProvider) {
|
public set instance(value: ISerializationProvider) {
|
||||||
|
this._instance = value;
|
||||||
|
this._instanceReady.resolve(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ExecuteProviderDescriptor {
|
||||||
|
private _instanceReady = new Deferred<IExecuteProvider>();
|
||||||
|
constructor(private readonly _providerId: string, private _instance?: IExecuteProvider) {
|
||||||
|
if (_instance) {
|
||||||
|
this._instanceReady.resolve(_instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public get providerId(): string {
|
||||||
|
return this._providerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get instanceReady(): Promise<IExecuteProvider> {
|
||||||
|
return this._instanceReady.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get instance(): IExecuteProvider | undefined {
|
||||||
|
return this._instance;
|
||||||
|
}
|
||||||
|
public set instance(value: IExecuteProvider) {
|
||||||
this._instance = value;
|
this._instance = value;
|
||||||
this._instanceReady.resolve(value);
|
this._instanceReady.resolve(value);
|
||||||
}
|
}
|
||||||
@@ -113,14 +144,16 @@ export class NotebookService extends Disposable implements INotebookService {
|
|||||||
private _providersMemento: Memento;
|
private _providersMemento: Memento;
|
||||||
private _trustedNotebooksMemento: Memento;
|
private _trustedNotebooksMemento: Memento;
|
||||||
private _mimeRegistry: RenderMimeRegistry;
|
private _mimeRegistry: RenderMimeRegistry;
|
||||||
private _providers: Map<string, ProviderDescriptor> = new Map();
|
private _serializationProviders: Map<string, SerializationProviderDescriptor> = new Map();
|
||||||
|
private _executeProviders: Map<string, ExecuteProviderDescriptor> = new Map();
|
||||||
private _navigationProviders: Map<string, INavigationProvider> = new Map();
|
private _navigationProviders: Map<string, INavigationProvider> = new Map();
|
||||||
private _managersMap: Map<string, INotebookManager[]> = new Map();
|
private _serializationManagersMap: Map<string, ISerializationManager[]> = new Map();
|
||||||
|
private _executeManagersMap: Map<string, IExecuteManager[]> = new Map();
|
||||||
private _onNotebookEditorAdd = new Emitter<INotebookEditor>();
|
private _onNotebookEditorAdd = new Emitter<INotebookEditor>();
|
||||||
private _onNotebookEditorRemove = new Emitter<INotebookEditor>();
|
private _onNotebookEditorRemove = new Emitter<INotebookEditor>();
|
||||||
private _onNotebookEditorRename = new Emitter<INotebookEditor>();
|
private _onNotebookEditorRename = new Emitter<INotebookEditor>();
|
||||||
private _editors = new Map<string, INotebookEditor>();
|
private _editors = new Map<string, INotebookEditor>();
|
||||||
private _fileToProviders = new Map<string, NotebookProviderRegistration[]>();
|
private _fileToProviderDescriptions = new Map<string, ProviderDescriptionRegistration[]>();
|
||||||
private _providerToStandardKernels = new Map<string, nb.IStandardKernel[]>();
|
private _providerToStandardKernels = new Map<string, nb.IStandardKernel[]>();
|
||||||
private _registrationComplete = new Deferred<void>();
|
private _registrationComplete = new Deferred<void>();
|
||||||
private _isRegistrationComplete = false;
|
private _isRegistrationComplete = false;
|
||||||
@@ -147,19 +180,24 @@ export class NotebookService extends Disposable implements INotebookService {
|
|||||||
super();
|
super();
|
||||||
this._providersMemento = new Memento('notebookProviders', this._storageService);
|
this._providersMemento = new Memento('notebookProviders', this._storageService);
|
||||||
this._trustedNotebooksMemento = new Memento(TrustedNotebooksMementoId, this._storageService);
|
this._trustedNotebooksMemento = new Memento(TrustedNotebooksMementoId, this._storageService);
|
||||||
if (this._storageService !== undefined && this.providersMemento.notebookProviderCache === undefined) {
|
if (this._storageService !== undefined) {
|
||||||
this.providersMemento.notebookProviderCache = <NotebookProviderCache>{};
|
if (this.providersMemento.notebookSerializationProviderCache === undefined) {
|
||||||
|
this.providersMemento.notebookSerializationProviderCache = <NotebookProviderCache>{};
|
||||||
|
}
|
||||||
|
if (this.providersMemento.notebookExecuteProviderCache === undefined) {
|
||||||
|
this.providersMemento.notebookExecuteProviderCache = <NotebookProviderCache>{};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this._register(notebookRegistry.onNewRegistration(this.updateRegisteredProviders, this));
|
this._register(notebookRegistry.onNewDescriptionRegistration(this.handleNewProviderDescriptions, this));
|
||||||
this.registerBuiltInProvider();
|
this.registerBuiltInProviders();
|
||||||
|
|
||||||
// If a provider has been already registered, the onNewRegistration event will not have a listener attached yet
|
// If a provider has been already registered, the onNewRegistration event will not have a listener attached yet
|
||||||
// So, explicitly updating registered providers here.
|
// So, explicitly updating registered providers here.
|
||||||
if (notebookRegistry.providers.length > 0) {
|
if (notebookRegistry.providerDescriptions.length > 0) {
|
||||||
notebookRegistry.providers.forEach(p => {
|
notebookRegistry.providerDescriptions.forEach(p => {
|
||||||
// Don't need to re-register SQL_NOTEBOOK_PROVIDER
|
// Don't need to re-register SQL_NOTEBOOK_PROVIDER
|
||||||
if (p.provider !== SQL_NOTEBOOK_PROVIDER) {
|
if (p.provider !== SQL_NOTEBOOK_PROVIDER) {
|
||||||
this.updateRegisteredProviders({ id: p.provider, registration: p });
|
this.handleNewProviderDescriptions({ id: p.provider, registration: p });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -266,12 +304,15 @@ export class NotebookService extends Disposable implements INotebookService {
|
|||||||
this._registrationComplete.resolve();
|
this._registrationComplete.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateRegisteredProviders(p: { id: string; registration: NotebookProviderRegistration }) {
|
private handleNewProviderDescriptions(p: { id: string; registration: ProviderDescriptionRegistration }) {
|
||||||
let registration = p.registration;
|
// Skip adding a Serialization descriptor for Jupyter, since we use the default notebook Serialization provider for jupyter
|
||||||
|
if (!this._serializationProviders.has(p.id) && p.id !== JUPYTER_PROVIDER_ID) {
|
||||||
if (!this._providers.has(p.id)) {
|
this._serializationProviders.set(p.id, new SerializationProviderDescriptor(p.id));
|
||||||
this._providers.set(p.id, new ProviderDescriptor());
|
|
||||||
}
|
}
|
||||||
|
if (!this._executeProviders.has(p.id)) {
|
||||||
|
this._executeProviders.set(p.id, new ExecuteProviderDescriptor(p.id));
|
||||||
|
}
|
||||||
|
let registration = p.registration;
|
||||||
if (registration.fileExtensions) {
|
if (registration.fileExtensions) {
|
||||||
if (Array.isArray(registration.fileExtensions)) {
|
if (Array.isArray(registration.fileExtensions)) {
|
||||||
for (let fileType of registration.fileExtensions) {
|
for (let fileType of registration.fileExtensions) {
|
||||||
@@ -287,18 +328,32 @@ export class NotebookService extends Disposable implements INotebookService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
registerProvider(providerId: string, instance: INotebookProvider): void {
|
registerSerializationProvider(providerId: string, instance: ISerializationProvider): void {
|
||||||
let providerDescriptor = this._providers.get(providerId);
|
let providerDescriptor = this._serializationProviders.get(providerId);
|
||||||
if (providerDescriptor) {
|
if (providerDescriptor) {
|
||||||
// Update, which will resolve the promise for anyone waiting on the instance to be registered
|
// Update, which will resolve the promise for anyone waiting on the instance to be registered
|
||||||
providerDescriptor.instance = instance;
|
providerDescriptor.instance = instance;
|
||||||
} else {
|
} else {
|
||||||
this._providers.set(providerId, new ProviderDescriptor(instance));
|
this._serializationProviders.set(providerId, new SerializationProviderDescriptor(providerId, instance));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unregisterProvider(providerId: string): void {
|
registerExecuteProvider(providerId: string, instance: IExecuteProvider): void {
|
||||||
this._providers.delete(providerId);
|
let providerDescriptor = this._executeProviders.get(providerId);
|
||||||
|
if (providerDescriptor) {
|
||||||
|
// Update, which will resolve the promise for anyone waiting on the instance to be registered
|
||||||
|
providerDescriptor.instance = instance;
|
||||||
|
} else {
|
||||||
|
this._executeProviders.set(providerId, new ExecuteProviderDescriptor(providerId, instance));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unregisterSerializationProvider(providerId: string): void {
|
||||||
|
this._serializationProviders.delete(providerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
unregisterExecuteProvider(providerId: string): void {
|
||||||
|
this._executeProviders.delete(providerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
registerNavigationProvider(provider: INavigationProvider): void {
|
registerNavigationProvider(provider: INavigationProvider): void {
|
||||||
@@ -322,20 +377,20 @@ export class NotebookService extends Disposable implements INotebookService {
|
|||||||
return this._registrationComplete.promise;
|
return this._registrationComplete.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
private addFileProvider(fileType: string, provider: NotebookProviderRegistration) {
|
private addFileProvider(fileType: string, provider: ProviderDescriptionRegistration) {
|
||||||
let providers = this._fileToProviders.get(fileType.toUpperCase());
|
let providers = this._fileToProviderDescriptions.get(fileType.toUpperCase());
|
||||||
if (!providers) {
|
if (!providers) {
|
||||||
providers = [];
|
providers = [];
|
||||||
}
|
}
|
||||||
providers.push(provider);
|
providers.push(provider);
|
||||||
this._fileToProviders.set(fileType.toUpperCase(), providers);
|
this._fileToProviderDescriptions.set(fileType.toUpperCase(), providers);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Standard kernels are contributed where a list of kernels are defined that can be shown
|
// Standard kernels are contributed where a list of kernels are defined that can be shown
|
||||||
// in the kernels dropdown list before a SessionManager has been started; this way,
|
// in the kernels dropdown list before a SessionManager has been started; this way,
|
||||||
// every NotebookProvider doesn't need to have an active SessionManager in order to contribute
|
// every NotebookProvider doesn't need to have an active SessionManager in order to contribute
|
||||||
// kernels to the dropdown
|
// kernels to the dropdown
|
||||||
private addStandardKernels(provider: NotebookProviderRegistration) {
|
private addStandardKernels(provider: ProviderDescriptionRegistration) {
|
||||||
let providerUpperCase = provider.provider.toUpperCase();
|
let providerUpperCase = provider.provider.toUpperCase();
|
||||||
let standardKernels = this._providerToStandardKernels.get(providerUpperCase);
|
let standardKernels = this._providerToStandardKernels.get(providerUpperCase);
|
||||||
if (!standardKernels) {
|
if (!standardKernels) {
|
||||||
@@ -356,12 +411,12 @@ export class NotebookService extends Disposable implements INotebookService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getSupportedFileExtensions(): string[] {
|
getSupportedFileExtensions(): string[] {
|
||||||
return Array.from(this._fileToProviders.keys());
|
return Array.from(this._fileToProviderDescriptions.keys());
|
||||||
}
|
}
|
||||||
|
|
||||||
getProvidersForFileType(fileType: string): string[] {
|
getProvidersForFileType(fileType: string): string[] {
|
||||||
fileType = fileType.toUpperCase();
|
fileType = fileType.toUpperCase();
|
||||||
let providers = this._fileToProviders.get(fileType);
|
let providers = this._fileToProviderDescriptions.get(fileType);
|
||||||
|
|
||||||
return providers ? providers.map(provider => provider.provider) : undefined;
|
return providers ? providers.map(provider => provider.provider) : undefined;
|
||||||
}
|
}
|
||||||
@@ -371,7 +426,7 @@ export class NotebookService extends Disposable implements INotebookService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private shutdown(): void {
|
private shutdown(): void {
|
||||||
this._managersMap.forEach(manager => {
|
this._executeManagersMap.forEach(manager => {
|
||||||
manager.forEach(m => {
|
manager.forEach(m => {
|
||||||
if (m.serverManager) {
|
if (m.serverManager) {
|
||||||
// TODO should this thenable be awaited?
|
// TODO should this thenable be awaited?
|
||||||
@@ -381,12 +436,12 @@ export class NotebookService extends Disposable implements INotebookService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getOrCreateNotebookManager(providerId: string, uri: URI): Promise<INotebookManager> {
|
async getOrCreateSerializationManager(providerId: string, uri: URI): Promise<ISerializationManager> {
|
||||||
if (!uri) {
|
if (!uri) {
|
||||||
throw new Error(NotebookUriNotDefined);
|
throw new Error(NotebookUriNotDefined);
|
||||||
}
|
}
|
||||||
let uriString = uri.toString();
|
let uriString = uri.toString();
|
||||||
let managers: INotebookManager[] = this._managersMap.get(uriString);
|
let managers: ISerializationManager[] = this._serializationManagersMap.get(uriString);
|
||||||
// If manager already exists for a given notebook, return it
|
// If manager already exists for a given notebook, return it
|
||||||
if (managers) {
|
if (managers) {
|
||||||
let index = managers.findIndex(m => m.providerId === providerId);
|
let index = managers.findIndex(m => m.providerId === providerId);
|
||||||
@@ -394,11 +449,32 @@ export class NotebookService extends Disposable implements INotebookService {
|
|||||||
return managers[index];
|
return managers[index];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let newManager = await this.doWithProvider(providerId, (provider) => provider.getNotebookManager(uri));
|
let newManager = await this.doWithSerializationProvider(providerId, (provider) => provider.getSerializationManager(uri));
|
||||||
|
|
||||||
managers = managers || [];
|
managers = managers || [];
|
||||||
managers.push(newManager);
|
managers.push(newManager);
|
||||||
this._managersMap.set(uriString, managers);
|
this._serializationManagersMap.set(uriString, managers);
|
||||||
|
return newManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getOrCreateExecuteManager(providerId: string, uri: URI): Promise<IExecuteManager> {
|
||||||
|
if (!uri) {
|
||||||
|
throw new Error(NotebookUriNotDefined);
|
||||||
|
}
|
||||||
|
let uriString = uri.toString();
|
||||||
|
let managers: IExecuteManager[] = this._executeManagersMap.get(uriString);
|
||||||
|
// If manager already exists for a given notebook, return it
|
||||||
|
if (managers) {
|
||||||
|
let index = managers.findIndex(m => m.providerId === providerId);
|
||||||
|
if (index >= 0) {
|
||||||
|
return managers[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let newManager = await this.doWithExecuteProvider(providerId, (provider) => provider.getExecuteManager(uri));
|
||||||
|
|
||||||
|
managers = managers || [];
|
||||||
|
managers.push(newManager);
|
||||||
|
this._executeManagersMap.set(uriString, managers);
|
||||||
return newManager;
|
return newManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,26 +537,32 @@ export class NotebookService extends Disposable implements INotebookService {
|
|||||||
private sendNotebookCloseToProvider(editor: INotebookEditor): void {
|
private sendNotebookCloseToProvider(editor: INotebookEditor): void {
|
||||||
let notebookUri = editor.notebookParams.notebookUri;
|
let notebookUri = editor.notebookParams.notebookUri;
|
||||||
let uriString = notebookUri.toString();
|
let uriString = notebookUri.toString();
|
||||||
let managers = this._managersMap.get(uriString);
|
let managers = this._executeManagersMap.get(uriString);
|
||||||
if (managers) {
|
if (managers) {
|
||||||
// As we have a manager, we can assume provider is ready
|
// As we have a manager, we can assume provider is ready
|
||||||
this._managersMap.delete(uriString);
|
this._executeManagersMap.delete(uriString);
|
||||||
managers.forEach(m => {
|
managers.forEach(m => {
|
||||||
let provider = this._providers.get(m.providerId);
|
let provider = this._executeProviders.get(m.providerId);
|
||||||
provider.instance.handleNotebookClosed(notebookUri);
|
provider?.instance?.handleNotebookClosed(notebookUri);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async doWithProvider<T>(providerId: string, op: (provider: INotebookProvider) => Thenable<T>): Promise<T> {
|
private async doWithSerializationProvider<T>(providerId: string, op: (provider: ISerializationProvider) => Thenable<T>): Promise<T> {
|
||||||
// Make sure the provider exists before attempting to retrieve accounts
|
// Make sure the provider exists before attempting to retrieve accounts
|
||||||
let provider: INotebookProvider = await this.getProviderInstance(providerId);
|
let provider: ISerializationProvider = await this.getSerializationProviderInstance(providerId);
|
||||||
return op(provider);
|
return op(provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getProviderInstance(providerId: string, timeout?: number): Promise<INotebookProvider> {
|
private async doWithExecuteProvider<T>(providerId: string, op: (provider: IExecuteProvider) => Thenable<T>): Promise<T> {
|
||||||
let providerDescriptor = this._providers.get(providerId);
|
// Make sure the provider exists before attempting to retrieve accounts
|
||||||
let instance: INotebookProvider;
|
let provider: IExecuteProvider = await this.getExecuteProviderInstance(providerId);
|
||||||
|
return op(provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getSerializationProviderInstance(providerId: string, timeout?: number): Promise<ISerializationProvider> {
|
||||||
|
let providerDescriptor = this._serializationProviders.get(providerId);
|
||||||
|
let instance: ISerializationProvider;
|
||||||
|
|
||||||
// Try get from actual provider, waiting on its registration
|
// Try get from actual provider, waiting on its registration
|
||||||
if (providerDescriptor) {
|
if (providerDescriptor) {
|
||||||
@@ -491,7 +573,7 @@ export class NotebookService extends Disposable implements INotebookService {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
this._logService.error(error);
|
this._logService.error(error);
|
||||||
}
|
}
|
||||||
instance = await this.waitOnProviderAvailability(providerDescriptor, timeout);
|
instance = await this.waitOnSerializationProviderAvailability(providerDescriptor, timeout);
|
||||||
} else {
|
} else {
|
||||||
instance = providerDescriptor.instance;
|
instance = providerDescriptor.instance;
|
||||||
}
|
}
|
||||||
@@ -499,7 +581,7 @@ export class NotebookService extends Disposable implements INotebookService {
|
|||||||
|
|
||||||
// Fall back to default (SQL) if this failed
|
// Fall back to default (SQL) if this failed
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
providerDescriptor = this._providers.get(SQL_NOTEBOOK_PROVIDER);
|
providerDescriptor = this._serializationProviders.get(SQL_NOTEBOOK_PROVIDER);
|
||||||
instance = providerDescriptor ? providerDescriptor.instance : undefined;
|
instance = providerDescriptor ? providerDescriptor.instance : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,12 +592,60 @@ export class NotebookService extends Disposable implements INotebookService {
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private waitOnProviderAvailability(providerDescriptor: ProviderDescriptor, timeout?: number): Promise<INotebookProvider> {
|
private async getExecuteProviderInstance(providerId: string, timeout?: number): Promise<IExecuteProvider> {
|
||||||
// Wait up to 30 seconds for the provider to be registered
|
let providerDescriptor = this._executeProviders.get(providerId);
|
||||||
timeout = timeout ?? 30000;
|
let instance: IExecuteProvider;
|
||||||
let promises: Promise<INotebookProvider>[] = [
|
|
||||||
|
// Try get from actual provider, waiting on its registration
|
||||||
|
if (providerDescriptor) {
|
||||||
|
if (!providerDescriptor.instance) {
|
||||||
|
// Await extension registration before awaiting provider registration
|
||||||
|
try {
|
||||||
|
await this._extensionService.whenInstalledExtensionsRegistered();
|
||||||
|
} catch (error) {
|
||||||
|
this._logService.error(error);
|
||||||
|
}
|
||||||
|
instance = await this.waitOnExecuteProviderAvailability(providerDescriptor, timeout);
|
||||||
|
} else {
|
||||||
|
instance = providerDescriptor.instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to default (SQL) if this failed
|
||||||
|
if (!instance) {
|
||||||
|
providerDescriptor = this._executeProviders.get(SQL_NOTEBOOK_PROVIDER);
|
||||||
|
instance = providerDescriptor ? providerDescriptor.instance : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should never happen, but if default wasn't registered we should throw
|
||||||
|
if (!instance) {
|
||||||
|
throw new Error(NotebookServiceNoProviderRegistered);
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private waitOnSerializationProviderAvailability(providerDescriptor: SerializationProviderDescriptor, timeout?: number): Promise<ISerializationProvider | undefined> {
|
||||||
|
// Wait up to 10 seconds for the provider to be registered
|
||||||
|
timeout = timeout ?? 10000;
|
||||||
|
let promises: Promise<ISerializationProvider>[] = [
|
||||||
providerDescriptor.instanceReady,
|
providerDescriptor.instanceReady,
|
||||||
new Promise<INotebookProvider>((resolve, reject) => setTimeout(() => resolve(undefined), timeout))
|
new Promise<ISerializationProvider>((resolve, reject) => setTimeout(() => {
|
||||||
|
this._serializationProviders.delete(providerDescriptor.providerId);
|
||||||
|
return resolve(undefined);
|
||||||
|
}, timeout))
|
||||||
|
];
|
||||||
|
return Promise.race(promises);
|
||||||
|
}
|
||||||
|
|
||||||
|
private waitOnExecuteProviderAvailability(providerDescriptor: ExecuteProviderDescriptor, timeout?: number): Promise<IExecuteProvider | undefined> {
|
||||||
|
// Wait up to 10 seconds for the provider to be registered
|
||||||
|
timeout = timeout ?? 10000;
|
||||||
|
let promises: Promise<IExecuteProvider>[] = [
|
||||||
|
providerDescriptor.instanceReady,
|
||||||
|
new Promise<IExecuteProvider>((resolve, reject) => setTimeout(() => {
|
||||||
|
this._executeProviders.delete(providerDescriptor.providerId);
|
||||||
|
return resolve(undefined);
|
||||||
|
}, timeout))
|
||||||
];
|
];
|
||||||
return Promise.race(promises);
|
return Promise.race(promises);
|
||||||
}
|
}
|
||||||
@@ -543,36 +673,48 @@ export class NotebookService extends Disposable implements INotebookService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private cleanupProviders(): void {
|
private cleanupProviders(): void {
|
||||||
let knownProviders = Object.keys(notebookRegistry.providers);
|
let knownProviders = notebookRegistry.providerDescriptions.map(d => d.provider);
|
||||||
let cache = this.providersMemento.notebookProviderCache;
|
let executeCache = this.providersMemento.notebookExecuteProviderCache;
|
||||||
for (let key in cache) {
|
for (let key in executeCache) {
|
||||||
if (!knownProviders.some(x => x === key)) {
|
if (!knownProviders.some(x => x === key)) {
|
||||||
this._providers.delete(key);
|
this._executeProviders.delete(key);
|
||||||
delete cache[key];
|
delete executeCache[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let serializationCache = this.providersMemento.notebookSerializationProviderCache;
|
||||||
|
for (let key in serializationCache) {
|
||||||
|
if (!knownProviders.some(x => x === key)) {
|
||||||
|
this._serializationProviders.delete(key);
|
||||||
|
delete serializationCache[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private registerBuiltInProvider() {
|
private registerBuiltInProviders() {
|
||||||
let sqlProvider = new SqlNotebookProvider(this._instantiationService);
|
let serializationProvider = new SqlSerializationProvider(this._instantiationService);
|
||||||
this.registerProvider(sqlProvider.providerId, sqlProvider);
|
this.registerSerializationProvider(serializationProvider.providerId, serializationProvider);
|
||||||
notebookRegistry.registerNotebookProvider({
|
|
||||||
provider: sqlProvider.providerId,
|
let executeProvider = new SqlExecuteProvider(this._instantiationService);
|
||||||
|
this.registerExecuteProvider(executeProvider.providerId, executeProvider);
|
||||||
|
|
||||||
|
notebookRegistry.registerProviderDescription({
|
||||||
|
provider: serializationProvider.providerId,
|
||||||
fileExtensions: DEFAULT_NOTEBOOK_FILETYPE,
|
fileExtensions: DEFAULT_NOTEBOOK_FILETYPE,
|
||||||
standardKernels: { name: notebookConstants.SQL, displayName: notebookConstants.SQL, connectionProviderIds: [notebookConstants.SQL_CONNECTION_PROVIDER] }
|
standardKernels: { name: notebookConstants.SQL, displayName: notebookConstants.SQL, connectionProviderIds: [notebookConstants.SQL_CONNECTION_PROVIDER] }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async removeContributedProvidersFromCache(identifier: IExtensionIdentifier, extensionService: IExtensionService): Promise<void> {
|
protected async removeContributedProvidersFromCache(identifier: IExtensionIdentifier, extensionService: IExtensionService): Promise<void> {
|
||||||
const notebookProvider = 'notebookProvider';
|
|
||||||
try {
|
try {
|
||||||
const extensionDescriptions = await extensionService.getExtensions();
|
const extensionDescriptions = await extensionService.getExtensions();
|
||||||
let extensionDescription = extensionDescriptions.find(c => c.identifier.value.toLowerCase() === identifier.id.toLowerCase());
|
let extensionDescription = extensionDescriptions.find(c => c.identifier.value.toLowerCase() === identifier.id.toLowerCase());
|
||||||
if (extensionDescription && extensionDescription.contributes
|
if (extensionDescription && extensionDescription.contributes
|
||||||
&& extensionDescription.contributes[notebookProvider] //'notebookProvider' isn't a field defined on IExtensionContributions so contributes[notebookProvider] is 'any'. TODO: Code cleanup
|
&& extensionDescription.contributes[Extensions.NotebookProviderDescriptionContribution]
|
||||||
&& extensionDescription.contributes[notebookProvider].providerId) {
|
&& extensionDescription.contributes[Extensions.NotebookProviderDescriptionContribution].providerId) {
|
||||||
let id = extensionDescription.contributes[notebookProvider].providerId;
|
let id = extensionDescription.contributes[Extensions.NotebookProviderDescriptionContribution].providerId;
|
||||||
delete this.providersMemento.notebookProviderCache[id];
|
delete this.providersMemento.notebookSerializationProviderCache[id];
|
||||||
|
delete this.providersMemento.notebookExecuteProviderCache[id];
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
onUnexpectedError(err);
|
onUnexpectedError(err);
|
||||||
|
|||||||
+1
-12
@@ -7,15 +7,12 @@ import { nb } from 'azdata';
|
|||||||
|
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { SQL_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/browser/notebookService';
|
import { SQL_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||||
import { LocalContentManager } from 'sql/workbench/services/notebook/common/localContentManager';
|
|
||||||
import { SqlSessionManager } from 'sql/workbench/services/notebook/browser/sql/sqlSessionManager';
|
import { SqlSessionManager } from 'sql/workbench/services/notebook/browser/sql/sqlSessionManager';
|
||||||
|
|
||||||
export class SqlNotebookManager implements nb.NotebookManager {
|
export class SqlExecuteManager implements nb.ExecuteManager {
|
||||||
private _contentManager: nb.ContentManager;
|
|
||||||
private _sessionManager: nb.SessionManager;
|
private _sessionManager: nb.SessionManager;
|
||||||
|
|
||||||
constructor(instantiationService: IInstantiationService) {
|
constructor(instantiationService: IInstantiationService) {
|
||||||
this._contentManager = instantiationService.createInstance(LocalContentManager);
|
|
||||||
this._sessionManager = new SqlSessionManager(instantiationService);
|
this._sessionManager = new SqlSessionManager(instantiationService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,10 +20,6 @@ export class SqlNotebookManager implements nb.NotebookManager {
|
|||||||
return SQL_NOTEBOOK_PROVIDER;
|
return SQL_NOTEBOOK_PROVIDER;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get contentManager(): nb.ContentManager {
|
|
||||||
return this._contentManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get serverManager(): nb.ServerManager | undefined {
|
public get serverManager(): nb.ServerManager | undefined {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -34,8 +27,4 @@ export class SqlNotebookManager implements nb.NotebookManager {
|
|||||||
public get sessionManager(): nb.SessionManager {
|
public get sessionManager(): nb.SessionManager {
|
||||||
return this._sessionManager;
|
return this._sessionManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get standardKernels(): nb.IStandardKernel[] {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+7
-7
@@ -6,21 +6,21 @@
|
|||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { INotebookManager, INotebookProvider, SQL_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/browser/notebookService';
|
import { IExecuteManager, IExecuteProvider, SQL_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||||
import { SqlNotebookManager } from 'sql/workbench/services/notebook/browser/sql/sqlNotebookManager';
|
import { SqlExecuteManager } from 'sql/workbench/services/notebook/browser/sql/sqlExecuteManager';
|
||||||
|
|
||||||
export class SqlNotebookProvider implements INotebookProvider {
|
export class SqlExecuteProvider implements IExecuteProvider {
|
||||||
private manager: SqlNotebookManager;
|
private manager: SqlExecuteManager;
|
||||||
|
|
||||||
constructor(private _instantiationService: IInstantiationService) {
|
constructor(instantiationService: IInstantiationService) {
|
||||||
this.manager = new SqlNotebookManager(this._instantiationService);
|
this.manager = new SqlExecuteManager(instantiationService);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get providerId(): string {
|
public get providerId(): string {
|
||||||
return SQL_NOTEBOOK_PROVIDER;
|
return SQL_NOTEBOOK_PROVIDER;
|
||||||
}
|
}
|
||||||
|
|
||||||
getNotebookManager(notebookUri: URI): Thenable<INotebookManager> {
|
getExecuteManager(notebookUri: URI): Thenable<IExecuteManager> {
|
||||||
return Promise.resolve(this.manager);
|
return Promise.resolve(this.manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { nb } from 'azdata';
|
||||||
|
|
||||||
|
import { ISerializationManager, SQL_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||||
|
import { LocalContentManager } from 'sql/workbench/services/notebook/common/localContentManager';
|
||||||
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
|
||||||
|
export class SqlSerializationManager implements ISerializationManager {
|
||||||
|
private _manager: LocalContentManager;
|
||||||
|
|
||||||
|
constructor(instantiationService: IInstantiationService) {
|
||||||
|
this._manager = instantiationService.createInstance(LocalContentManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get providerId(): string {
|
||||||
|
return SQL_NOTEBOOK_PROVIDER;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get contentManager(): nb.ContentManager {
|
||||||
|
return this._manager;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
|
||||||
|
import { ISerializationManager, ISerializationProvider, SQL_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||||
|
import { SqlSerializationManager } from 'sql/workbench/services/notebook/browser/sql/sqlSerializationManager';
|
||||||
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
|
||||||
|
export class SqlSerializationProvider implements ISerializationProvider {
|
||||||
|
private _manager: SqlSerializationManager;
|
||||||
|
|
||||||
|
constructor(instantiationService: IInstantiationService) {
|
||||||
|
this._manager = new SqlSerializationManager(instantiationService);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get providerId(): string {
|
||||||
|
return SQL_NOTEBOOK_PROVIDER;
|
||||||
|
}
|
||||||
|
|
||||||
|
getSerializationManager(notebookUri: URI): Thenable<ISerializationManager> {
|
||||||
|
return Promise.resolve(this._manager);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,81 +8,45 @@
|
|||||||
import { nb } from 'azdata';
|
import { nb } from 'azdata';
|
||||||
|
|
||||||
import * as json from 'vs/base/common/json';
|
import * as json from 'vs/base/common/json';
|
||||||
import { URI } from 'vs/base/common/uri';
|
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import { IFileService } from 'vs/platform/files/common/files';
|
|
||||||
|
|
||||||
import { JSONObject } from 'sql/workbench/services/notebook/common/jsonext';
|
import { JSONObject } from 'sql/workbench/services/notebook/common/jsonext';
|
||||||
import { OutputTypes } from 'sql/workbench/services/notebook/common/contracts';
|
import { OutputTypes } from 'sql/workbench/services/notebook/common/contracts';
|
||||||
import { nbversion } from 'sql/workbench/services/notebook/common/notebookConstants';
|
import { nbversion } from 'sql/workbench/services/notebook/common/notebookConstants';
|
||||||
import { nbformat } from 'sql/workbench/services/notebook/common/nbformat';
|
import { nbformat } from 'sql/workbench/services/notebook/common/nbformat';
|
||||||
import { VSBuffer } from 'vs/base/common/buffer';
|
|
||||||
|
|
||||||
type MimeBundle = { [key: string]: string | string[] | undefined };
|
type MimeBundle = { [key: string]: string | string[] | undefined };
|
||||||
|
|
||||||
export class LocalContentManager implements nb.ContentManager {
|
export class LocalContentManager implements nb.ContentManager {
|
||||||
|
|
||||||
constructor(@IFileService private readonly fileService: IFileService) { }
|
constructor() { }
|
||||||
|
|
||||||
public async loadFromContentString(contentString: string): Promise<nb.INotebookContents> {
|
public async deserializeNotebook(contents: string): Promise<nb.INotebookContents> {
|
||||||
let contents: JSONObject;
|
let jsonContents: JSONObject;
|
||||||
if (contentString === '' || contentString === undefined) {
|
if (contents === '' || contents === undefined) {
|
||||||
return v4.createEmptyNotebook();
|
return v4.createEmptyNotebook();
|
||||||
} else {
|
} else {
|
||||||
contents = this.parseFromJson(contentString);
|
jsonContents = this.parseFromJson(contents);
|
||||||
}
|
}
|
||||||
if (contents) {
|
if (jsonContents) {
|
||||||
if (contents.nbformat === 4) {
|
if (jsonContents.nbformat === 4) {
|
||||||
return v4.readNotebook(<any>contents);
|
return v4.readNotebook(<any>jsonContents);
|
||||||
} else if (contents.nbformat === 3) {
|
} else if (jsonContents.nbformat === 3) {
|
||||||
return v3.readNotebook(<any>contents);
|
return v3.readNotebook(<any>jsonContents);
|
||||||
}
|
}
|
||||||
if (contents.nbformat) {
|
if (jsonContents.nbformat) {
|
||||||
throw new TypeError(localize('nbformatNotRecognized', "nbformat v{0}.{1} not recognized", contents.nbformat as any, contents.nbformat_minor as any));
|
throw new TypeError(localize('nbformatNotRecognized', "nbformat v{0}.{1} not recognized", jsonContents.nbformat as any, jsonContents.nbformat_minor as any));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// else, fallthrough condition
|
// else, fallthrough condition
|
||||||
throw new TypeError(localize('nbNotSupported', "This file does not have a valid notebook format"));
|
throw new TypeError(localize('nbNotSupported', "This file does not have a valid notebook format"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getNotebookContents(notebookUri: URI): Promise<nb.INotebookContents> {
|
public async serializeNotebook(notebook: nb.INotebookContents): Promise<string> {
|
||||||
if (!notebookUri) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
// Note: intentionally letting caller handle exceptions
|
|
||||||
let notebookFileBuffer = await this.fileService.readFile(notebookUri);
|
|
||||||
let stringContents = notebookFileBuffer.value.toString();
|
|
||||||
let contents: JSONObject;
|
|
||||||
if (stringContents === '' || stringContents === undefined) {
|
|
||||||
// Empty?
|
|
||||||
return v4.createEmptyNotebook();
|
|
||||||
} else {
|
|
||||||
contents = this.parseFromJson(stringContents);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (contents) {
|
|
||||||
if (contents.nbformat === 4) {
|
|
||||||
return v4.readNotebook(<any>contents);
|
|
||||||
} else if (contents.nbformat === 3) {
|
|
||||||
return v3.readNotebook(<any>contents);
|
|
||||||
}
|
|
||||||
if (contents.nbformat) {
|
|
||||||
throw new TypeError(localize('nbformatNotRecognized', "nbformat v{0}.{1} not recognized", contents.nbformat as any, contents.nbformat_minor as any));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// else, fallthrough condition
|
|
||||||
throw new TypeError(localize('nbNotSupported', "This file does not have a valid notebook format"));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public async save(notebookUri: URI, notebook: nb.INotebookContents): Promise<nb.INotebookContents> {
|
|
||||||
// Convert to JSON with pretty-print functionality
|
// Convert to JSON with pretty-print functionality
|
||||||
let contents = JSON.stringify(notebook, undefined, ' ');
|
let contents = JSON.stringify(notebook, undefined, ' ');
|
||||||
await this.fileService.writeFile(notebookUri, VSBuffer.fromString(contents));
|
return contents;
|
||||||
return notebook;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseFromJson(contentString: string): JSONObject {
|
private parseFromJson(contentString: string): JSONObject {
|
||||||
|
|||||||
@@ -4,24 +4,26 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||||
import { ExtensionsRegistry, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import * as platform from 'vs/platform/registry/common/platform';
|
import * as platform from 'vs/platform/registry/common/platform';
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
import { Event, Emitter } from 'vs/base/common/event';
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
|
|
||||||
|
export const NotebookProviderRegistryId = 'notebooks.providers.registry';
|
||||||
|
|
||||||
export const Extensions = {
|
export const Extensions = {
|
||||||
NotebookProviderContribution: 'notebook.providers',
|
NotebookProviderDescriptionContribution: 'notebook.providers',
|
||||||
NotebookLanguageMagicContribution: 'notebook.languagemagics'
|
NotebookLanguageMagicContribution: 'notebook.languagemagics'
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface NotebookProviderRegistration {
|
export interface ProviderDescriptionRegistration {
|
||||||
provider: string;
|
provider: string;
|
||||||
fileExtensions: string | string[];
|
fileExtensions: string | string[];
|
||||||
standardKernels: azdata.nb.IStandardKernel | azdata.nb.IStandardKernel[];
|
standardKernels: azdata.nb.IStandardKernel | azdata.nb.IStandardKernel[];
|
||||||
}
|
}
|
||||||
|
|
||||||
let notebookProviderType: IJSONSchema = {
|
let providerDescriptionType: IJSONSchema = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
default: { provider: '', fileExtensions: [], standardKernels: [] },
|
default: { provider: '', fileExtensions: [], standardKernels: [] },
|
||||||
properties: {
|
properties: {
|
||||||
@@ -86,13 +88,13 @@ let notebookProviderType: IJSONSchema = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let notebookContrib: IJSONSchema = {
|
let providerDescriptionContrib: IJSONSchema = {
|
||||||
description: localize('vscode.extension.contributes.notebook.providers', "Contributes notebook providers."),
|
description: localize('vscode.extension.contributes.notebook.providersDescriptions', "Contributes notebook provider descriptions."),
|
||||||
oneOf: [
|
oneOf: [
|
||||||
notebookProviderType,
|
providerDescriptionType,
|
||||||
{
|
{
|
||||||
type: 'array',
|
type: 'array',
|
||||||
items: notebookProviderType
|
items: providerDescriptionType
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
@@ -146,81 +148,69 @@ export interface NotebookLanguageMagicRegistration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface INotebookProviderRegistry {
|
export interface INotebookProviderRegistry {
|
||||||
readonly providers: NotebookProviderRegistration[];
|
readonly providerDescriptions: ProviderDescriptionRegistration[];
|
||||||
readonly languageMagics: NotebookLanguageMagicRegistration[];
|
readonly languageMagics: NotebookLanguageMagicRegistration[];
|
||||||
readonly onNewRegistration: Event<{ id: string, registration: NotebookProviderRegistration }>;
|
|
||||||
|
|
||||||
registerNotebookProvider(provider: NotebookProviderRegistration): void;
|
readonly onNewDescriptionRegistration: Event<{ id: string, registration: ProviderDescriptionRegistration }>;
|
||||||
|
|
||||||
|
registerProviderDescription(provider: ProviderDescriptionRegistration): void;
|
||||||
registerNotebookLanguageMagic(magic: NotebookLanguageMagicRegistration): void;
|
registerNotebookLanguageMagic(magic: NotebookLanguageMagicRegistration): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
class NotebookProviderRegistry implements INotebookProviderRegistry {
|
class NotebookProviderRegistry implements INotebookProviderRegistry {
|
||||||
private providerIdToRegistration = new Map<string, NotebookProviderRegistration>();
|
private _providerDescriptionRegistration = new Map<string, ProviderDescriptionRegistration>();
|
||||||
private magicToRegistration = new Map<string, NotebookLanguageMagicRegistration>();
|
private _magicToRegistration = new Map<string, NotebookLanguageMagicRegistration>();
|
||||||
private _onNewRegistration = new Emitter<{ id: string, registration: NotebookProviderRegistration }>();
|
|
||||||
public readonly onNewRegistration: Event<{ id: string, registration: NotebookProviderRegistration }> = this._onNewRegistration.event;
|
|
||||||
|
|
||||||
registerNotebookProvider(registration: NotebookProviderRegistration): void {
|
private _onNewDescriptionRegistration = new Emitter<{ id: string, registration: ProviderDescriptionRegistration }>();
|
||||||
// Note: this method intentionally overrides default provider for a file type.
|
public readonly onNewDescriptionRegistration: Event<{ id: string, registration: ProviderDescriptionRegistration }> = this._onNewDescriptionRegistration.event;
|
||||||
// This means that any built-in provider will be overridden by registered extensions
|
|
||||||
this.providerIdToRegistration.set(registration.provider, registration);
|
registerProviderDescription(registration: ProviderDescriptionRegistration): void {
|
||||||
this._onNewRegistration.fire({ id: registration.provider, registration: registration });
|
this._providerDescriptionRegistration.set(registration.provider, registration);
|
||||||
|
this._onNewDescriptionRegistration.fire({ id: registration.provider, registration: registration });
|
||||||
}
|
}
|
||||||
|
|
||||||
public get providers(): NotebookProviderRegistration[] {
|
public get providerDescriptions(): ProviderDescriptionRegistration[] {
|
||||||
let registrationArray: NotebookProviderRegistration[] = [];
|
let registrationArray: ProviderDescriptionRegistration[] = [];
|
||||||
this.providerIdToRegistration.forEach(p => registrationArray.push(p));
|
this._providerDescriptionRegistration.forEach(p => registrationArray.push(p));
|
||||||
return registrationArray;
|
return registrationArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
registerNotebookLanguageMagic(magicRegistration: NotebookLanguageMagicRegistration): void {
|
registerNotebookLanguageMagic(magicRegistration: NotebookLanguageMagicRegistration): void {
|
||||||
this.magicToRegistration.set(magicRegistration.magic, magicRegistration);
|
this._magicToRegistration.set(magicRegistration.magic, magicRegistration);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get languageMagics(): NotebookLanguageMagicRegistration[] {
|
public get languageMagics(): NotebookLanguageMagicRegistration[] {
|
||||||
let registrationArray: NotebookLanguageMagicRegistration[] = [];
|
let registrationArray: NotebookLanguageMagicRegistration[] = [];
|
||||||
this.magicToRegistration.forEach(p => registrationArray.push(p));
|
this._magicToRegistration.forEach(p => registrationArray.push(p));
|
||||||
return registrationArray;
|
return registrationArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const notebookProviderRegistry = new NotebookProviderRegistry();
|
const notebookProviderRegistry = new NotebookProviderRegistry();
|
||||||
platform.Registry.add(Extensions.NotebookProviderContribution, notebookProviderRegistry);
|
platform.Registry.add(NotebookProviderRegistryId, notebookProviderRegistry);
|
||||||
|
|
||||||
|
|
||||||
ExtensionsRegistry.registerExtensionPoint<NotebookProviderRegistration | NotebookProviderRegistration[]>({ extensionPoint: Extensions.NotebookProviderContribution, jsonSchema: notebookContrib }).setHandler(extensions => {
|
|
||||||
|
|
||||||
function handleExtension(contrib: NotebookProviderRegistration, extension: IExtensionPointUser<any>) {
|
|
||||||
notebookProviderRegistry.registerNotebookProvider(contrib);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
ExtensionsRegistry.registerExtensionPoint<ProviderDescriptionRegistration | ProviderDescriptionRegistration[]>({ extensionPoint: Extensions.NotebookProviderDescriptionContribution, jsonSchema: providerDescriptionContrib }).setHandler(extensions => {
|
||||||
for (let extension of extensions) {
|
for (let extension of extensions) {
|
||||||
const { value } = extension;
|
const { value } = extension;
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
for (let command of value) {
|
for (let command of value) {
|
||||||
handleExtension(command, extension);
|
notebookProviderRegistry.registerProviderDescription(command);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
handleExtension(value, extension);
|
notebookProviderRegistry.registerProviderDescription(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ExtensionsRegistry.registerExtensionPoint<NotebookLanguageMagicRegistration | NotebookLanguageMagicRegistration[]>({ extensionPoint: Extensions.NotebookLanguageMagicContribution, jsonSchema: languageMagicContrib }).setHandler(extensions => {
|
ExtensionsRegistry.registerExtensionPoint<NotebookLanguageMagicRegistration | NotebookLanguageMagicRegistration[]>({ extensionPoint: Extensions.NotebookLanguageMagicContribution, jsonSchema: languageMagicContrib }).setHandler(extensions => {
|
||||||
|
|
||||||
function handleExtension(contrib: NotebookLanguageMagicRegistration, extension: IExtensionPointUser<any>) {
|
|
||||||
notebookProviderRegistry.registerNotebookLanguageMagic(contrib);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let extension of extensions) {
|
for (let extension of extensions) {
|
||||||
const { value } = extension;
|
const { value } = extension;
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
for (let command of value) {
|
for (let command of value) {
|
||||||
handleExtension(command, extension);
|
notebookProviderRegistry.registerNotebookLanguageMagic(command);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
handleExtension(value, extension);
|
notebookProviderRegistry.registerNotebookLanguageMagic(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,19 +13,21 @@ import { IMainContext } from 'vs/workbench/api/common/extHost.protocol';
|
|||||||
|
|
||||||
import { ExtHostNotebook } from 'sql/workbench/api/common/extHostNotebook';
|
import { ExtHostNotebook } from 'sql/workbench/api/common/extHostNotebook';
|
||||||
import { MainThreadNotebookShape } from 'sql/workbench/api/common/sqlExtHost.protocol';
|
import { MainThreadNotebookShape } from 'sql/workbench/api/common/sqlExtHost.protocol';
|
||||||
import { INotebookManagerDetails } from 'sql/workbench/api/common/sqlExtHostTypes';
|
import { IExecuteManagerDetails, ISerializationManagerDetails } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
import { mssqlProviderName } from 'sql/platform/connection/common/constants';
|
|
||||||
|
|
||||||
suite('ExtHostNotebook Tests', () => {
|
suite('ExtHostNotebook Tests', () => {
|
||||||
|
|
||||||
let extHostNotebook: ExtHostNotebook;
|
let extHostNotebook: ExtHostNotebook;
|
||||||
let mockProxy: TypeMoq.Mock<MainThreadNotebookShape>;
|
let mockProxy: TypeMoq.Mock<MainThreadNotebookShape>;
|
||||||
let notebookUri: URI;
|
let notebookUri: URI;
|
||||||
let notebookProviderMock: TypeMoq.Mock<NotebookProviderStub>;
|
let serializationProviderMock: TypeMoq.Mock<SerializationProviderStub>;
|
||||||
|
let executeProviderMock: TypeMoq.Mock<ExecuteProviderStub>;
|
||||||
setup(() => {
|
setup(() => {
|
||||||
mockProxy = TypeMoq.Mock.ofInstance(<MainThreadNotebookShape>{
|
mockProxy = TypeMoq.Mock.ofInstance(<MainThreadNotebookShape>{
|
||||||
$registerNotebookProvider: (providerId, handle) => undefined,
|
$registerSerializationProvider: (providerId, handle) => undefined,
|
||||||
$unregisterNotebookProvider: (handle) => undefined,
|
$registerExecuteProvider: (providerId, handle) => undefined,
|
||||||
|
$unregisterSerializationProvider: (handle) => undefined,
|
||||||
|
$unregisterExecuteProvider: (handle) => undefined,
|
||||||
dispose: () => undefined
|
dispose: () => undefined
|
||||||
});
|
});
|
||||||
let mainContext = <IMainContext>{
|
let mainContext = <IMainContext>{
|
||||||
@@ -33,71 +35,115 @@ suite('ExtHostNotebook Tests', () => {
|
|||||||
};
|
};
|
||||||
extHostNotebook = new ExtHostNotebook(mainContext);
|
extHostNotebook = new ExtHostNotebook(mainContext);
|
||||||
notebookUri = URI.parse('file:/user/default/my.ipynb');
|
notebookUri = URI.parse('file:/user/default/my.ipynb');
|
||||||
notebookProviderMock = TypeMoq.Mock.ofType(NotebookProviderStub, TypeMoq.MockBehavior.Loose);
|
serializationProviderMock = TypeMoq.Mock.ofType(SerializationProviderStub, TypeMoq.MockBehavior.Loose);
|
||||||
notebookProviderMock.callBase = true;
|
serializationProviderMock.callBase = true;
|
||||||
|
executeProviderMock = TypeMoq.Mock.ofType(ExecuteProviderStub, TypeMoq.MockBehavior.Loose);
|
||||||
|
executeProviderMock.callBase = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
suite('getNotebookManager', () => {
|
suite('get notebook managers', () => {
|
||||||
test('Should throw if no matching provider is defined', async () => {
|
test('Should throw if no matching serialization provider is defined', async () => {
|
||||||
try {
|
try {
|
||||||
await extHostNotebook.$getNotebookManager(-1, notebookUri);
|
await extHostNotebook.$getSerializationManagerDetails(-1, notebookUri);
|
||||||
|
assert.fail('expected to throw');
|
||||||
|
} catch (e) { }
|
||||||
|
});
|
||||||
|
test('Should throw if no matching execute provider is defined', async () => {
|
||||||
|
try {
|
||||||
|
await extHostNotebook.$getExecuteManagerDetails(-1, notebookUri);
|
||||||
assert.fail('expected to throw');
|
assert.fail('expected to throw');
|
||||||
} catch (e) { }
|
} catch (e) { }
|
||||||
});
|
});
|
||||||
suite('with provider', () => {
|
suite('with provider', () => {
|
||||||
let providerHandle: number = -1;
|
let serializationProviderHandle: number = -1;
|
||||||
|
let executeProviderHandle: number = -1;
|
||||||
|
|
||||||
setup(() => {
|
setup(() => {
|
||||||
mockProxy.setup(p =>
|
mockProxy.setup(p =>
|
||||||
p.$registerNotebookProvider(TypeMoq.It.isValue(notebookProviderMock.object.providerId), TypeMoq.It.isAnyNumber()))
|
p.$registerSerializationProvider(TypeMoq.It.isValue(serializationProviderMock.object.providerId), TypeMoq.It.isAnyNumber()))
|
||||||
.returns((providerId, handle) => {
|
.returns((providerId, handle) => {
|
||||||
providerHandle = handle;
|
serializationProviderHandle = handle;
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
mockProxy.setup(p =>
|
||||||
|
p.$registerExecuteProvider(TypeMoq.It.isValue(executeProviderMock.object.providerId), TypeMoq.It.isAnyNumber()))
|
||||||
|
.returns((providerId, handle) => {
|
||||||
|
executeProviderHandle = handle;
|
||||||
return undefined;
|
return undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Register the provider so we can test behavior with this present
|
// Register the provider so we can test behavior with this present
|
||||||
extHostNotebook.registerNotebookProvider(notebookProviderMock.object);
|
extHostNotebook.registerSerializationProvider(serializationProviderMock.object);
|
||||||
|
extHostNotebook.registerExecuteProvider(executeProviderMock.object);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Should return a notebook manager with correct info on content and server manager existence', async () => {
|
test('Should return a serialization manager with correct info on content manager existence', async () => {
|
||||||
// Given the provider returns a manager with no
|
// Given the provider returns a manager with no
|
||||||
let expectedManager = new NotebookManagerStub();
|
let expectedManager = new SerializationManagerStub();
|
||||||
notebookProviderMock.setup(p => p.getNotebookManager(TypeMoq.It.isAny())).returns(() => Promise.resolve(expectedManager));
|
serializationProviderMock.setup(p => p.getSerializationManager(TypeMoq.It.isAny())).returns(() => Promise.resolve(expectedManager));
|
||||||
|
|
||||||
// When I call through using the handle provided during registration
|
// When I call through using the handle provided during registration
|
||||||
let managerDetails: INotebookManagerDetails = await extHostNotebook.$getNotebookManager(providerHandle, notebookUri);
|
let managerDetails: ISerializationManagerDetails = await extHostNotebook.$getSerializationManagerDetails(serializationProviderHandle, notebookUri);
|
||||||
|
|
||||||
// Then I expect the same manager to be returned
|
// Then I expect the same manager to be returned
|
||||||
assert.ok(managerDetails.hasContentManager === false, 'Expect no content manager defined');
|
assert.ok(managerDetails.hasContentManager === false, 'Expect no content manager defined');
|
||||||
|
assert.ok(managerDetails.handle > 0, 'Expect a valid handle defined');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should return an execute manager with correct info on whether server manager exists', async () => {
|
||||||
|
// An execute manager with no server manager
|
||||||
|
let expectedManager = new ExecuteManagerStub();
|
||||||
|
executeProviderMock.setup(p => p.getExecuteManager(TypeMoq.It.isAny())).returns(() => Promise.resolve(expectedManager));
|
||||||
|
|
||||||
|
// When I call through using the handle provided during registration
|
||||||
|
let managerDetails: IExecuteManagerDetails = await extHostNotebook.$getExecuteManagerDetails(executeProviderHandle, notebookUri);
|
||||||
|
|
||||||
|
// Then I expect the same manager to be returned
|
||||||
assert.ok(managerDetails.hasServerManager === false, 'Expect no server manager defined');
|
assert.ok(managerDetails.hasServerManager === false, 'Expect no server manager defined');
|
||||||
assert.ok(managerDetails.handle > 0, 'Expect a valid handle defined');
|
assert.ok(managerDetails.handle > 0, 'Expect a valid handle defined');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Should have a unique handle for each notebook URI', async () => {
|
test('Should have a unique serialization provider handle for each notebook URI', async () => {
|
||||||
// Given the we request 2 URIs
|
// Given the we request 2 URIs
|
||||||
let expectedManager = new NotebookManagerStub();
|
let expectedManager = new SerializationManagerStub();
|
||||||
notebookProviderMock.setup(p => p.getNotebookManager(TypeMoq.It.isAny())).returns(() => Promise.resolve(expectedManager));
|
serializationProviderMock.setup(p => p.getSerializationManager(TypeMoq.It.isAny())).returns(() => Promise.resolve(expectedManager));
|
||||||
|
|
||||||
// When I call through using the handle provided during registration
|
// When I call through using the handle provided during registration
|
||||||
let originalManagerDetails = await extHostNotebook.$getNotebookManager(providerHandle, notebookUri);
|
let originalManagerDetails = await extHostNotebook.$getSerializationManagerDetails(serializationProviderHandle, notebookUri);
|
||||||
let differentDetails = await extHostNotebook.$getNotebookManager(providerHandle, URI.parse('file://other/file.ipynb'));
|
let differentDetails = await extHostNotebook.$getSerializationManagerDetails(serializationProviderHandle, URI.parse('file://other/file.ipynb'));
|
||||||
let sameDetails = await extHostNotebook.$getNotebookManager(providerHandle, notebookUri);
|
let sameDetails = await extHostNotebook.$getSerializationManagerDetails(serializationProviderHandle, notebookUri);
|
||||||
|
|
||||||
// Then I expect the 2 different handles in the managers returned.
|
// Then I expect the 2 different handles in the managers returned.
|
||||||
// This is because we can't easily track identity of the managers, so just track which one is assigned to
|
// This is because we can't easily track identity of the managers, so just track which one is assigned to
|
||||||
// a notebook by the handle ID
|
// a notebook by the handle ID
|
||||||
assert.notStrictEqual(originalManagerDetails.handle, differentDetails.handle, 'Should have unique handle for each manager');
|
assert.notStrictEqual(originalManagerDetails.handle, differentDetails.handle, 'Should have unique handle for each manager');
|
||||||
assert.strictEqual(originalManagerDetails.handle, sameDetails.handle, 'Should have same handle when same URI is passed in');
|
assert.strictEqual(originalManagerDetails.handle, sameDetails.handle, 'Should have same handle when same URI is passed in');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should have a unique execute provider handle for each notebook URI', async () => {
|
||||||
|
// Given the we request 2 URIs
|
||||||
|
let expectedManager = new ExecuteManagerStub();
|
||||||
|
executeProviderMock.setup(p => p.getExecuteManager(TypeMoq.It.isAny())).returns(() => Promise.resolve(expectedManager));
|
||||||
|
|
||||||
|
// When I call through using the handle provided during registration
|
||||||
|
let originalManagerDetails = await extHostNotebook.$getExecuteManagerDetails(executeProviderHandle, notebookUri);
|
||||||
|
let differentDetails = await extHostNotebook.$getExecuteManagerDetails(executeProviderHandle, URI.parse('file://other/file.ipynb'));
|
||||||
|
let sameDetails = await extHostNotebook.$getExecuteManagerDetails(executeProviderHandle, notebookUri);
|
||||||
|
|
||||||
|
// Then I expect the 2 different handles in the managers returned.
|
||||||
|
// This is because we can't easily track identity of the managers, so just track which one is assigned to
|
||||||
|
// a notebook by the handle ID
|
||||||
|
assert.notStrictEqual(originalManagerDetails.handle, differentDetails.handle, 'Should have unique handle for each manager');
|
||||||
|
assert.strictEqual(originalManagerDetails.handle, sameDetails.handle, 'Should have same handle when same URI is passed in');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
suite('registerNotebookProvider', () => {
|
suite('registerSerializationProvider', () => {
|
||||||
let savedHandle: number = -1;
|
let savedHandle: number = -1;
|
||||||
setup(() => {
|
setup(() => {
|
||||||
mockProxy.setup(p =>
|
mockProxy.setup(p =>
|
||||||
p.$registerNotebookProvider(TypeMoq.It.isValue(notebookProviderMock.object.providerId), TypeMoq.It.isAnyNumber()))
|
p.$registerSerializationProvider(TypeMoq.It.isValue(serializationProviderMock.object.providerId), TypeMoq.It.isAnyNumber()))
|
||||||
.returns((providerId, handle) => {
|
.returns((providerId, handle) => {
|
||||||
savedHandle = handle;
|
savedHandle = handle;
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -105,28 +151,61 @@ suite('ExtHostNotebook Tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Should register with a new handle to the proxy', () => {
|
test('Should register with a new handle to the proxy', () => {
|
||||||
extHostNotebook.registerNotebookProvider(notebookProviderMock.object);
|
extHostNotebook.registerSerializationProvider(serializationProviderMock.object);
|
||||||
mockProxy.verify(p =>
|
mockProxy.verify(p =>
|
||||||
p.$registerNotebookProvider(TypeMoq.It.isValue(notebookProviderMock.object.providerId),
|
p.$registerSerializationProvider(TypeMoq.It.isValue(serializationProviderMock.object.providerId),
|
||||||
TypeMoq.It.isAnyNumber()), TypeMoq.Times.once());
|
TypeMoq.It.isAnyNumber()), TypeMoq.Times.once());
|
||||||
// It shouldn't unregister until requested
|
// It shouldn't unregister until requested
|
||||||
mockProxy.verify(p => p.$unregisterNotebookProvider(TypeMoq.It.isValue(savedHandle)), TypeMoq.Times.never());
|
mockProxy.verify(p => p.$unregisterSerializationProvider(TypeMoq.It.isValue(savedHandle)), TypeMoq.Times.never());
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Should not call unregister on disposing', () => {
|
test('Should not call unregister on disposing', () => {
|
||||||
let disposable = extHostNotebook.registerNotebookProvider(notebookProviderMock.object);
|
let disposable = extHostNotebook.registerSerializationProvider(serializationProviderMock.object);
|
||||||
disposable.dispose();
|
disposable.dispose();
|
||||||
mockProxy.verify(p => p.$unregisterNotebookProvider(TypeMoq.It.isValue(savedHandle)), TypeMoq.Times.never());
|
mockProxy.verify(p => p.$unregisterSerializationProvider(TypeMoq.It.isValue(savedHandle)), TypeMoq.Times.never());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
suite('registerExecuteProvider', () => {
|
||||||
|
let savedHandle: number = -1;
|
||||||
|
setup(() => {
|
||||||
|
mockProxy.setup(p =>
|
||||||
|
p.$registerExecuteProvider(TypeMoq.It.isValue(executeProviderMock.object.providerId), TypeMoq.It.isAnyNumber()))
|
||||||
|
.returns((providerId, handle) => {
|
||||||
|
savedHandle = handle;
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should register with a new handle to the proxy', () => {
|
||||||
|
extHostNotebook.registerExecuteProvider(executeProviderMock.object);
|
||||||
|
mockProxy.verify(p =>
|
||||||
|
p.$registerExecuteProvider(TypeMoq.It.isValue(executeProviderMock.object.providerId),
|
||||||
|
TypeMoq.It.isAnyNumber()), TypeMoq.Times.once());
|
||||||
|
// It shouldn't unregister until requested
|
||||||
|
mockProxy.verify(p => p.$unregisterExecuteProvider(TypeMoq.It.isValue(savedHandle)), TypeMoq.Times.never());
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should not call unregister on disposing', () => {
|
||||||
|
let disposable = extHostNotebook.registerExecuteProvider(executeProviderMock.object);
|
||||||
|
disposable.dispose();
|
||||||
|
mockProxy.verify(p => p.$unregisterExecuteProvider(TypeMoq.It.isValue(savedHandle)), TypeMoq.Times.never());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
class NotebookProviderStub implements azdata.nb.NotebookProvider {
|
class SerializationProviderStub implements azdata.nb.NotebookSerializationProvider {
|
||||||
providerId: string = 'TestProvider';
|
providerId: string = 'TestProvider';
|
||||||
standardKernels: azdata.nb.IStandardKernel[] = [{ name: 'fakeKernel', displayName: 'fakeKernel', connectionProviderIds: [mssqlProviderName] }];
|
|
||||||
|
|
||||||
getNotebookManager(notebookUri: vscode.Uri): Thenable<azdata.nb.NotebookManager> {
|
getSerializationManager(notebookUri: vscode.Uri): Thenable<azdata.nb.SerializationManager> {
|
||||||
|
throw new Error('Method not implemented.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExecuteProviderStub implements azdata.nb.NotebookExecuteProvider {
|
||||||
|
providerId: string = 'TestProvider';
|
||||||
|
|
||||||
|
getExecuteManager(notebookUri: vscode.Uri): Thenable<azdata.nb.ExecuteManager> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
handleNotebookClosed(notebookUri: vscode.Uri): void {
|
handleNotebookClosed(notebookUri: vscode.Uri): void {
|
||||||
@@ -134,11 +213,13 @@ class NotebookProviderStub implements azdata.nb.NotebookProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class NotebookManagerStub implements azdata.nb.NotebookManager {
|
class SerializationManagerStub implements azdata.nb.SerializationManager {
|
||||||
get contentManager(): azdata.nb.ContentManager {
|
get contentManager(): azdata.nb.ContentManager {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExecuteManagerStub implements azdata.nb.ExecuteManager {
|
||||||
get sessionManager(): azdata.nb.SessionManager {
|
get sessionManager(): azdata.nb.SessionManager {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import { IExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
|
|||||||
|
|
||||||
import { MainThreadNotebook } from 'sql/workbench/api/browser/mainThreadNotebook';
|
import { MainThreadNotebook } from 'sql/workbench/api/browser/mainThreadNotebook';
|
||||||
import { NotebookService } from 'sql/workbench/services/notebook/browser/notebookServiceImpl';
|
import { NotebookService } from 'sql/workbench/services/notebook/browser/notebookServiceImpl';
|
||||||
import { INotebookProvider } from 'sql/workbench/services/notebook/browser/notebookService';
|
import { IExecuteProvider, ISerializationProvider } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||||
import { INotebookManagerDetails, INotebookSessionDetails, INotebookKernelDetails, INotebookFutureDetails } from 'sql/workbench/api/common/sqlExtHostTypes';
|
import { IExecuteManagerDetails, INotebookSessionDetails, INotebookKernelDetails, INotebookFutureDetails, ISerializationManagerDetails } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
import { LocalContentManager } from 'sql/workbench/services/notebook/common/localContentManager';
|
import { LocalContentManager } from 'sql/workbench/services/notebook/common/localContentManager';
|
||||||
import { TestLifecycleService } from 'vs/workbench/test/browser/workbenchTestServices';
|
import { TestLifecycleService } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||||
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
|
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
|
||||||
@@ -57,80 +57,123 @@ suite('MainThreadNotebook Tests', () => {
|
|||||||
mainThreadNotebook = new MainThreadNotebook(extContext, mockNotebookService.object, instantiationService);
|
mainThreadNotebook = new MainThreadNotebook(extContext, mockNotebookService.object, instantiationService);
|
||||||
});
|
});
|
||||||
|
|
||||||
suite('On registering a provider', () => {
|
suite('On registering a serialization provider', () => {
|
||||||
let provider: INotebookProvider;
|
let provider: ISerializationProvider;
|
||||||
setup(() => {
|
setup(() => {
|
||||||
mockNotebookService.setup(s => s.registerProvider(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns((id, providerImpl) => {
|
mockNotebookService.setup(s => s.registerSerializationProvider(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns((id, providerImpl) => {
|
||||||
provider = providerImpl;
|
provider = providerImpl;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should call through to notebook service', () => {
|
test('should call through to notebook service', () => {
|
||||||
// When I register a provider
|
// When I register a provider
|
||||||
mainThreadNotebook.$registerNotebookProvider(providerId, 1);
|
mainThreadNotebook.$registerSerializationProvider(providerId, 1);
|
||||||
// Then I expect a provider implementation to be passed to the service
|
// Then I expect a provider implementation to be passed to the service
|
||||||
mockNotebookService.verify(s => s.registerProvider(TypeMoq.It.isAnyString(), TypeMoq.It.isAny()), TypeMoq.Times.once());
|
mockNotebookService.verify(s => s.registerSerializationProvider(TypeMoq.It.isAnyString(), TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||||
assert.strictEqual(provider.providerId, providerId);
|
assert.strictEqual(provider.providerId, providerId);
|
||||||
});
|
});
|
||||||
test('should unregister in service', () => {
|
test('should unregister in service', () => {
|
||||||
// Given we have a provider
|
// Given we have a provider
|
||||||
mainThreadNotebook.$registerNotebookProvider(providerId, 1);
|
mainThreadNotebook.$registerSerializationProvider(providerId, 1);
|
||||||
// When I unregister a provider twice
|
// When I unregister a provider twice
|
||||||
mainThreadNotebook.$unregisterNotebookProvider(1);
|
mainThreadNotebook.$unregisterSerializationProvider(1);
|
||||||
mainThreadNotebook.$unregisterNotebookProvider(1);
|
mainThreadNotebook.$unregisterSerializationProvider(1);
|
||||||
// Then I expect it to be unregistered in the service just 1 time
|
// Then I expect it to be unregistered in the service just 1 time
|
||||||
mockNotebookService.verify(s => s.unregisterProvider(TypeMoq.It.isValue(providerId)), TypeMoq.Times.once());
|
mockNotebookService.verify(s => s.unregisterSerializationProvider(TypeMoq.It.isValue(providerId)), TypeMoq.Times.once());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
suite('getNotebookManager', () => {
|
suite('On registering an execute provider', () => {
|
||||||
let managerWithAllFeatures: INotebookManagerDetails;
|
let provider: IExecuteProvider;
|
||||||
let provider: INotebookProvider;
|
|
||||||
|
|
||||||
setup(() => {
|
setup(() => {
|
||||||
managerWithAllFeatures = {
|
mockNotebookService.setup(s => s.registerExecuteProvider(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns((id, providerImpl) => {
|
||||||
handle: 2,
|
|
||||||
hasContentManager: true,
|
|
||||||
hasServerManager: true
|
|
||||||
};
|
|
||||||
mockNotebookService.setup(s => s.registerProvider(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns((id, providerImpl) => {
|
|
||||||
provider = providerImpl;
|
provider = providerImpl;
|
||||||
});
|
});
|
||||||
mainThreadNotebook.$registerNotebookProvider(providerId, 1);
|
});
|
||||||
|
|
||||||
|
test('should call through to notebook service', () => {
|
||||||
|
// When I register a provider
|
||||||
|
mainThreadNotebook.$registerExecuteProvider(providerId, 1);
|
||||||
|
// Then I expect a provider implementation to be passed to the service
|
||||||
|
mockNotebookService.verify(s => s.registerExecuteProvider(TypeMoq.It.isAnyString(), TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||||
|
assert.strictEqual(provider.providerId, providerId);
|
||||||
|
});
|
||||||
|
test('should unregister in service', () => {
|
||||||
|
// Given we have a provider
|
||||||
|
mainThreadNotebook.$registerExecuteProvider(providerId, 1);
|
||||||
|
// When I unregister a provider twice
|
||||||
|
mainThreadNotebook.$unregisterExecuteProvider(1);
|
||||||
|
mainThreadNotebook.$unregisterExecuteProvider(1);
|
||||||
|
// Then I expect it to be unregistered in the service just 1 time
|
||||||
|
mockNotebookService.verify(s => s.unregisterExecuteProvider(TypeMoq.It.isValue(providerId)), TypeMoq.Times.once());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
suite('get notebook managers', () => {
|
||||||
|
let serializationManagerWithAllFeatures: ISerializationManagerDetails;
|
||||||
|
let executeManagerWithAllFeatures: IExecuteManagerDetails;
|
||||||
|
let serializationProvider: ISerializationProvider;
|
||||||
|
let executeProvider: IExecuteProvider;
|
||||||
|
|
||||||
|
setup(() => {
|
||||||
|
serializationManagerWithAllFeatures = {
|
||||||
|
handle: 3,
|
||||||
|
hasContentManager: true,
|
||||||
|
};
|
||||||
|
executeManagerWithAllFeatures = {
|
||||||
|
handle: 4,
|
||||||
|
hasServerManager: true
|
||||||
|
};
|
||||||
|
mockNotebookService.setup(s => s.registerSerializationProvider(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns((id, providerImpl) => {
|
||||||
|
serializationProvider = providerImpl;
|
||||||
|
});
|
||||||
|
mainThreadNotebook.$registerSerializationProvider(providerId, 1);
|
||||||
|
mockNotebookService.setup(s => s.registerExecuteProvider(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns((id, providerImpl) => {
|
||||||
|
executeProvider = providerImpl;
|
||||||
|
});
|
||||||
|
mainThreadNotebook.$registerExecuteProvider(providerId, 2);
|
||||||
|
|
||||||
// Always return empty specs in this test suite
|
// Always return empty specs in this test suite
|
||||||
mockProxy.setup(p => p.$refreshSpecs(TypeMoq.It.isAnyNumber())).returns(() => Promise.resolve(undefined));
|
mockProxy.setup(p => p.$refreshSpecs(TypeMoq.It.isAnyNumber())).returns(() => Promise.resolve(undefined));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should return manager with default content manager & undefined server manager if extension host has none', async () => {
|
test('should return execute manager with undefined server manager if extension host has none', async () => {
|
||||||
// Given the extension provider doesn't have acontent or server manager
|
// Given the extension provider doesn't have acontent or server manager
|
||||||
let details: INotebookManagerDetails = {
|
let details: IExecuteManagerDetails = {
|
||||||
handle: 2,
|
handle: 2,
|
||||||
hasContentManager: false,
|
|
||||||
hasServerManager: false
|
hasServerManager: false
|
||||||
};
|
};
|
||||||
mockProxy.setup(p => p.$getNotebookManager(TypeMoq.It.isAnyNumber(), TypeMoq.It.isValue(notebookUri)))
|
mockProxy.setup(p => p.$getExecuteManagerDetails(TypeMoq.It.isAnyNumber(), TypeMoq.It.isValue(notebookUri)))
|
||||||
.returns(() => Promise.resolve(details));
|
.returns(() => Promise.resolve(details));
|
||||||
|
|
||||||
// When I get the notebook manager
|
// When I get the notebook manager
|
||||||
let manager = await provider.getNotebookManager(notebookUri);
|
let manager = await executeProvider.getExecuteManager(notebookUri);
|
||||||
|
|
||||||
// Then it should use the built-in content manager
|
|
||||||
assert.ok(manager.contentManager instanceof LocalContentManager);
|
|
||||||
// And it should not define a server manager
|
// And it should not define a server manager
|
||||||
assert.strictEqual(manager.serverManager, undefined);
|
assert.strictEqual(manager.serverManager, undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should return manager with a content & server manager if extension host has these', async () => {
|
test('should return serialization manager with a content manager if extension host has these', async () => {
|
||||||
// Given the extension provider doesn't have acontent or server manager
|
// Given the extension provider doesn't have acontent or server manager
|
||||||
mockProxy.setup(p => p.$getNotebookManager(TypeMoq.It.isAnyNumber(), TypeMoq.It.isValue(notebookUri)))
|
mockProxy.setup(p => p.$getSerializationManagerDetails(TypeMoq.It.isAnyNumber(), TypeMoq.It.isValue(notebookUri)))
|
||||||
.returns(() => Promise.resolve(managerWithAllFeatures));
|
.returns(() => Promise.resolve(serializationManagerWithAllFeatures));
|
||||||
|
|
||||||
// When I get the notebook manager
|
// When I get the notebook manager
|
||||||
let manager = await provider.getNotebookManager(notebookUri);
|
let manager = await serializationProvider.getSerializationManager(notebookUri);
|
||||||
|
|
||||||
// Then it shouldn't have wrappers for the content or server manager
|
// Then it shouldn't have wrappers for the content manager
|
||||||
assert.ok(!(manager.contentManager instanceof LocalContentManager));
|
assert.ok(!(manager.contentManager instanceof LocalContentManager));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return execute manager with a server manager if extension host has these', async () => {
|
||||||
|
// Given the extension provider doesn't have a content or server manager
|
||||||
|
mockProxy.setup(p => p.$getExecuteManagerDetails(TypeMoq.It.isAnyNumber(), TypeMoq.It.isValue(notebookUri)))
|
||||||
|
.returns(() => Promise.resolve(executeManagerWithAllFeatures));
|
||||||
|
|
||||||
|
// When I get the notebook manager
|
||||||
|
let manager = await executeProvider.getExecuteManager(notebookUri);
|
||||||
|
|
||||||
|
// Then it shouldn't have wrappers for the server manager
|
||||||
assert.notStrictEqual(manager.serverManager, undefined);
|
assert.notStrictEqual(manager.serverManager, undefined);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -138,7 +181,10 @@ suite('MainThreadNotebook Tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
class ExtHostNotebookStub implements ExtHostNotebookShape {
|
class ExtHostNotebookStub implements ExtHostNotebookShape {
|
||||||
$getNotebookManager(providerHandle: number, notebookUri: UriComponents): Thenable<INotebookManagerDetails> {
|
$getSerializationManagerDetails(providerHandle: number, notebookUri: UriComponents): Thenable<ISerializationManagerDetails> {
|
||||||
|
throw new Error('Method not implemented.');
|
||||||
|
}
|
||||||
|
$getExecuteManagerDetails(providerHandle: number, notebookUri: UriComponents): Thenable<IExecuteManagerDetails> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
$handleNotebookClosed(notebookUri: UriComponents): void {
|
$handleNotebookClosed(notebookUri: UriComponents): void {
|
||||||
@@ -150,10 +196,10 @@ class ExtHostNotebookStub implements ExtHostNotebookShape {
|
|||||||
$doStopServer(managerHandle: number): Thenable<void> {
|
$doStopServer(managerHandle: number): Thenable<void> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
$getNotebookContents(managerHandle: number, notebookUri: UriComponents): Thenable<azdata.nb.INotebookContents> {
|
$deserializeNotebook(managerHandle: number, contents: string): Thenable<azdata.nb.INotebookContents> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
$save(managerHandle: number, notebookUri: UriComponents, notebook: azdata.nb.INotebookContents): Thenable<azdata.nb.INotebookContents> {
|
$serializeNotebook(managerHandle: number, notebook: azdata.nb.INotebookContents): Thenable<string> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
$refreshSpecs(managerHandle: number): Thenable<azdata.nb.IAllKernels> {
|
$refreshSpecs(managerHandle: number): Thenable<azdata.nb.IAllKernels> {
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/ur
|
|||||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||||
import { IPathService } from 'vs/workbench/services/path/common/pathService';
|
import { IPathService } from 'vs/workbench/services/path/common/pathService';
|
||||||
import { diffSets, diffMaps } from 'vs/base/common/collections';
|
import { diffSets, diffMaps } from 'vs/base/common/collections';
|
||||||
|
import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||||
|
|
||||||
|
|
||||||
class TextEditorSnapshot {
|
class TextEditorSnapshot {
|
||||||
@@ -301,14 +302,15 @@ export class MainThreadDocumentsAndEditors {
|
|||||||
@IWorkingCopyFileService workingCopyFileService: IWorkingCopyFileService,
|
@IWorkingCopyFileService workingCopyFileService: IWorkingCopyFileService,
|
||||||
@IUriIdentityService uriIdentityService: IUriIdentityService,
|
@IUriIdentityService uriIdentityService: IUriIdentityService,
|
||||||
@IClipboardService private readonly _clipboardService: IClipboardService,
|
@IClipboardService private readonly _clipboardService: IClipboardService,
|
||||||
@IPathService pathService: IPathService
|
@IPathService pathService: IPathService,
|
||||||
|
@INotebookService private readonly _notebookService: INotebookService // {{SQL CARBON EDIT}}
|
||||||
) {
|
) {
|
||||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentsAndEditors);
|
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentsAndEditors);
|
||||||
|
|
||||||
this._mainThreadDocuments = this._toDispose.add(new MainThreadDocuments(this, extHostContext, this._modelService, this._textFileService, fileService, textModelResolverService, environmentService, uriIdentityService, workingCopyFileService, pathService));
|
this._mainThreadDocuments = this._toDispose.add(new MainThreadDocuments(this, extHostContext, this._modelService, this._textFileService, fileService, textModelResolverService, environmentService, uriIdentityService, workingCopyFileService, pathService));
|
||||||
extHostContext.set(MainContext.MainThreadDocuments, this._mainThreadDocuments);
|
extHostContext.set(MainContext.MainThreadDocuments, this._mainThreadDocuments);
|
||||||
|
|
||||||
const mainThreadTextEditors = this._toDispose.add(new MainThreadTextEditors(this, extHostContext, codeEditorService, bulkEditService, this._editorService, this._editorGroupService));
|
const mainThreadTextEditors = this._toDispose.add(new MainThreadTextEditors(this, extHostContext, codeEditorService, bulkEditService, this._editorService, this._editorGroupService, this._notebookService));
|
||||||
extHostContext.set(MainContext.MainThreadTextEditors, mainThreadTextEditors);
|
extHostContext.set(MainContext.MainThreadTextEditors, mainThreadTextEditors);
|
||||||
|
|
||||||
// It is expected that the ctor of the state computer calls our `_onDelta`.
|
// It is expected that the ctor of the state computer calls our `_onDelta`.
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/wo
|
|||||||
import { revive } from 'vs/base/common/marshalling';
|
import { revive } from 'vs/base/common/marshalling';
|
||||||
import { ResourceNotebookCellEdit } from 'vs/workbench/contrib/bulkEdit/browser/bulkCellEdits';
|
import { ResourceNotebookCellEdit } from 'vs/workbench/contrib/bulkEdit/browser/bulkCellEdits';
|
||||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||||
|
import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService'; // {{SQL CARBON EDIT}}
|
||||||
|
|
||||||
export function reviveWorkspaceEditDto2(data: IWorkspaceEditDto | undefined): ResourceEdit[] {
|
export function reviveWorkspaceEditDto2(data: IWorkspaceEditDto | undefined): ResourceEdit[] {
|
||||||
if (!data?.edits) {
|
if (!data?.edits) {
|
||||||
@@ -64,7 +65,8 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
|||||||
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
|
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
|
||||||
@IBulkEditService private readonly _bulkEditService: IBulkEditService,
|
@IBulkEditService private readonly _bulkEditService: IBulkEditService,
|
||||||
@IEditorService private readonly _editorService: IEditorService,
|
@IEditorService private readonly _editorService: IEditorService,
|
||||||
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService
|
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
|
||||||
|
@INotebookService private readonly _notebookService: INotebookService // {{SQL CARBON EDIT}}
|
||||||
) {
|
) {
|
||||||
this._instanceId = String(++MainThreadTextEditors.INSTANCE_COUNT);
|
this._instanceId = String(++MainThreadTextEditors.INSTANCE_COUNT);
|
||||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostEditors);
|
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostEditors);
|
||||||
@@ -136,6 +138,8 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
|||||||
async $tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): Promise<string | undefined> {
|
async $tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): Promise<string | undefined> {
|
||||||
const uri = URI.revive(resource);
|
const uri = URI.revive(resource);
|
||||||
|
|
||||||
|
let notebookFileTypes = this._notebookService.getSupportedFileExtensions().map(s => s.toLowerCase()); // {{SQL CARBON EDIT}}
|
||||||
|
|
||||||
const editorOptions: ITextEditorOptions = {
|
const editorOptions: ITextEditorOptions = {
|
||||||
preserveFocus: options.preserveFocus,
|
preserveFocus: options.preserveFocus,
|
||||||
pinned: options.pinned,
|
pinned: options.pinned,
|
||||||
@@ -143,7 +147,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
|||||||
// preserve pre 1.38 behaviour to not make group active when preserveFocus: true
|
// preserve pre 1.38 behaviour to not make group active when preserveFocus: true
|
||||||
// but make sure to restore the editor to fix https://github.com/microsoft/vscode/issues/79633
|
// but make sure to restore the editor to fix https://github.com/microsoft/vscode/issues/79633
|
||||||
activation: options.preserveFocus ? EditorActivation.RESTORE : undefined,
|
activation: options.preserveFocus ? EditorActivation.RESTORE : undefined,
|
||||||
override: uri?.fsPath?.toLowerCase().endsWith('ipynb') || uri?.fsPath?.toLowerCase().endsWith('sql') ? undefined : EditorOverride.DISABLED // {{SQL CARBON EDIT}}
|
override: notebookFileTypes?.some(ext => uri?.fsPath?.toLowerCase().endsWith(ext)) || uri?.fsPath?.toLowerCase().endsWith('sql') ? undefined : EditorOverride.DISABLED // {{SQL CARBON EDIT}}
|
||||||
};
|
};
|
||||||
|
|
||||||
const input: IResourceEditorInput = {
|
const input: IResourceEditorInput = {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import { TestNotificationService } from 'vs/platform/notification/test/common/te
|
|||||||
import { TestTextResourcePropertiesService, TestWorkingCopyFileService } from 'vs/workbench/test/common/workbenchTestServices';
|
import { TestTextResourcePropertiesService, TestWorkingCopyFileService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||||
import { UriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentityService';
|
import { UriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentityService';
|
||||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||||
|
import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||||
|
|
||||||
suite('MainThreadDocumentsAndEditors', () => {
|
suite('MainThreadDocumentsAndEditors', () => {
|
||||||
|
|
||||||
@@ -100,7 +101,10 @@ suite('MainThreadDocumentsAndEditors', () => {
|
|||||||
return Promise.resolve('clipboard_contents');
|
return Promise.resolve('clipboard_contents');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new TestPathService()
|
new TestPathService(),
|
||||||
|
<INotebookService>{ // {{SQL CARBON EDIT}}
|
||||||
|
getSupportedFileExtensions: () => ['ipynb']
|
||||||
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user