Update kernels dropdown after installing a notebook extension (#20759)

This commit is contained in:
Cory Rivera
2022-10-12 14:44:31 -07:00
committed by GitHub
parent 03fcaf837c
commit acc9780f04
17 changed files with 253 additions and 68 deletions

View File

@@ -27,7 +27,6 @@ import { ITextResourcePropertiesService } from 'vs/editor/common/services/textRe
import { TextResourceEditorModel } from 'vs/workbench/common/editor/textResourceEditorModel';
import { UntitledTextEditorModel, IUntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
import { AbstractResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
import { FileEditorInput } from 'vs/workbench/contrib/files/browser/editors/fileEditorInput';
import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel';
import { NotebookFindModel } from 'sql/workbench/contrib/notebook/browser/find/notebookFindModel';
@@ -216,7 +215,7 @@ export class NotebookEditorModel extends EditorModel {
}
}
type TextInput = AbstractResourceEditorInput | UntitledTextEditorInput | FileEditorInput;
type TextInput = UntitledTextEditorInput | FileEditorInput;
export abstract class NotebookInput extends EditorInput implements INotebookInput {
private _providerId: string;
@@ -259,6 +258,10 @@ export abstract class NotebookInput extends EditorInput implements INotebookInpu
}
}
public get languageMode(): string {
return this._textInput.getMode();
}
public get textInput(): TextInput {
return this._textInput;
}

View File

@@ -597,6 +597,9 @@ export class KernelsDropdown extends SelectBox {
this._register(this.model.kernelChanged((changedArgs: azdata.nb.IKernelChangedArgs) => {
this.updateKernel(changedArgs.newValue, changedArgs.nbKernelAlias);
}));
this._register(this.model.kernelsChanged(kernel => {
this.updateKernel(kernel);
}));
let kernel = this.model.clientSession && this.model.clientSession.kernel;
this.updateKernel(kernel);
}

View File

@@ -12,8 +12,6 @@ import { IConnectionManagementService } from 'sql/platform/connection/common/con
import { CellMagicMapper } from 'sql/workbench/contrib/notebook/browser/models/cellMagicMapper';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
import { ILogService } from 'vs/platform/log/common/log';
import { IModelFactory, ViewMode, NotebookContentChange, INotebookModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -23,12 +21,10 @@ import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common
import { IAction, SubmenuAction } from 'vs/base/common/actions';
import { IMenuService, MenuId } from 'vs/platform/actions/common/actions';
import { fillInActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { NotebookViewsExtension } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViewsExtension';
import { INotebookView } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViews';
import { Deferred } from 'sql/base/common/promise';
import { NotebookChangeType } from 'sql/workbench/services/notebook/common/contracts';
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { localize } from 'vs/nls';
import * as path from 'vs/base/common/path';
@@ -53,19 +49,15 @@ export class NotebookEditorComponent extends AngularDisposable {
public ViewMode = ViewMode; //For use of the enum in the template
constructor(
@Inject(ILogService) private readonly logService: ILogService,
@Inject(IBootstrapParams) private _notebookParams: INotebookParams,
@Inject(INotebookService) private notebookService: INotebookService,
@Inject(ICapabilitiesService) private capabilitiesService: ICapabilitiesService,
@Inject(IContextKeyService) private contextKeyService: IContextKeyService,
@Inject(IMenuService) private menuService: IMenuService,
@Inject(INotificationService) private notificationService: INotificationService,
@Inject(IAdsTelemetryService) private adstelemetryService: IAdsTelemetryService,
@Inject(IInstantiationService) private instantiationService: IInstantiationService,
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
@Inject(IConfigurationService) private _configurationService: IConfigurationService,
@Inject(IConnectionManagementService) private connectionManagementService: IConnectionManagementService,
@Inject(IUndoRedoService) private _undoService: IUndoRedoService,
) {
super();
this.updateProfile();
@@ -128,7 +120,7 @@ export class NotebookEditorComponent extends AngularDisposable {
private async createModelAndLoadContents(): Promise<void> {
let providerInfo = await this._notebookParams.providerInfo;
let model = new NotebookModel({
let model = this.instantiationService.createInstance(NotebookModel, {
factory: this.modelFactory,
notebookUri: this._notebookParams.notebookUri,
connectionService: this.connectionManagementService,
@@ -141,8 +133,9 @@ export class NotebookEditorComponent extends AngularDisposable {
defaultKernel: this._notebookParams.input.defaultKernel,
layoutChanged: this._notebookParams.input.layoutChanged,
capabilitiesService: this.capabilitiesService,
editorLoadedTimestamp: this._notebookParams.input.editorOpenedTimestamp
}, this.profile, this.logService, this.notificationService, this.adstelemetryService, this.connectionManagementService, this._configurationService, this._undoService, this.capabilitiesService);
editorLoadedTimestamp: this._notebookParams.input.editorOpenedTimestamp,
getInputLanguageMode: () => this._notebookParams.input.languageMode // Can't pass in languageMode directly since it can change after the editor loads
}, this.profile);
let trusted = await this.notebookService.isNotebookTrustCached(this._notebookParams.notebookUri, this.isDirty());
this.model = this._register(model);

View File

@@ -31,10 +31,12 @@ import { CellTypes } from 'sql/workbench/services/notebook/common/contracts';
import { nb } from 'azdata';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { ExecuteManagerStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
import { ExecuteManagerStub, NotebookServiceStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService';
import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants';
import { Emitter } from 'vs/base/common/event';
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
suite('CellToolbarActions', function (): void {
suite('removeDuplicatedAndStartingSeparators', function (): void {
@@ -236,7 +238,11 @@ export async function createandLoadNotebookModel(codeContent?: nb.INotebookConte
cellMagicMapper: undefined,
defaultKernel: undefined,
layoutChanged: undefined,
capabilitiesService: undefined
capabilitiesService: undefined,
getInputLanguageMode: () => undefined
};
return new NotebookModel(defaultModelOptions, undefined, undefined, undefined, new NullAdsTelemetryService(), undefined, undefined, undoRedoService);
let mockNotebookService = TypeMoq.Mock.ofType(NotebookServiceStub);
mockNotebookService.setup(s => s.onNotebookKernelsAdded).returns(() => new Emitter<IStandardKernelWithProvider[]>().event);
return new NotebookModel(defaultModelOptions, undefined, undefined, undefined, new NullAdsTelemetryService(), undefined, undefined, undoRedoService, mockNotebookService.object, undefined, undefined);
}

View File

@@ -11,7 +11,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
import { URI } from 'vs/base/common/uri';
import { ExecuteManagerStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
import { ExecuteManagerStub, NotebookServiceStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory';
import { INotebookModelOptions } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
@@ -34,6 +34,8 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { NotebookViewModel } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViewModel';
import { SQL_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/browser/notebookService';
import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants';
import { Emitter } from 'vs/base/common/event';
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
let initialNotebookContent: nb.INotebookContents = {
cells: [{
@@ -239,7 +241,8 @@ suite('NotebookViewModel', function (): void {
cellMagicMapper: undefined,
defaultKernel: undefined,
layoutChanged: undefined,
capabilitiesService: capabilitiesService.object
capabilitiesService: capabilitiesService.object,
getInputLanguageMode: () => undefined
};
}
@@ -247,8 +250,10 @@ suite('NotebookViewModel', function (): void {
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(contents));
defaultModelOptions.contentLoader = mockContentManager.object;
let mockNotebookService = TypeMoq.Mock.ofType(NotebookServiceStub);
mockNotebookService.setup(s => s.onNotebookKernelsAdded).returns(() => new Emitter<IStandardKernelWithProvider[]>().event);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undefined);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undefined, mockNotebookService.object, undefined, undefined);
await model.loadContents();
await model.requestModelLoad();

View File

@@ -11,7 +11,7 @@ import { NullAdsTelemetryService } from 'sql/platform/telemetry/common/adsTeleme
import { NotebookEditorContentLoader } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
import { DeleteViewAction, InsertCellAction } from 'sql/workbench/contrib/notebook/browser/notebookViews/notebookViewsActions';
import { SessionManager } from 'sql/workbench/contrib/notebook/test/emptySessionClasses';
import { ExecuteManagerStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
import { ExecuteManagerStub, NotebookServiceStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory';
import { ICellModel, INotebookModelOptions, ViewMode } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
@@ -35,6 +35,8 @@ import { InsertCellsModal } from 'sql/workbench/contrib/notebook/browser/noteboo
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
import { SQL_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/browser/notebookService';
import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants';
import { Emitter } from 'vs/base/common/event';
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
let initialNotebookContent: nb.INotebookContents = {
cells: [{
@@ -190,7 +192,8 @@ suite('Notebook Views Actions', function (): void {
cellMagicMapper: undefined,
defaultKernel: undefined,
layoutChanged: undefined,
capabilitiesService: capabilitiesService.object
capabilitiesService: capabilitiesService.object,
getInputLanguageMode: () => undefined
};
}
@@ -198,8 +201,10 @@ suite('Notebook Views Actions', function (): void {
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(contents));
defaultModelOptions.contentLoader = mockContentManager.object;
let mockNotebookService = TypeMoq.Mock.ofType(NotebookServiceStub);
mockNotebookService.setup(s => s.onNotebookKernelsAdded).returns(() => new Emitter<IStandardKernelWithProvider[]>().event);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undefined);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undefined, mockNotebookService.object, undefined, undefined);
await model.loadContents();
await model.requestModelLoad();

View File

@@ -11,7 +11,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
import { URI } from 'vs/base/common/uri';
import { ExecuteManagerStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
import { ExecuteManagerStub, NotebookServiceStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory';
import { INotebookModelOptions } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
@@ -37,6 +37,8 @@ import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService';
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { SQL_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/browser/notebookService';
import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants';
import { Emitter } from 'vs/base/common/event';
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
let initialNotebookContent: nb.INotebookContents = {
cells: [{
@@ -171,7 +173,8 @@ suite('NotebookViews', function (): void {
cellMagicMapper: undefined,
defaultKernel: undefined,
layoutChanged: undefined,
capabilitiesService: capabilitiesService.object
capabilitiesService: capabilitiesService.object,
getInputLanguageMode: () => undefined
};
}
@@ -179,8 +182,10 @@ suite('NotebookViews', function (): void {
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(initialNotebookContent));
defaultModelOptions.contentLoader = mockContentManager.object;
let mockNotebookService = TypeMoq.Mock.ofType(NotebookServiceStub);
mockNotebookService.setup(s => s.onNotebookKernelsAdded).returns(() => new Emitter<IStandardKernelWithProvider[]>().event);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, undefined);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, mockNotebookService.object, undefined, undefined);
await model.loadContents();
await model.requestModelLoad();

View File

@@ -42,6 +42,8 @@ import { NullAdsTelemetryService } from 'sql/platform/telemetry/common/adsTeleme
import { IProductService } from 'vs/platform/product/common/productService';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService';
import { NotebookServiceStub } from 'sql/workbench/contrib/notebook/test/stubs';
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
class ServiceAccessor {
@@ -175,7 +177,8 @@ suite('Notebook Editor Model', function (): void {
cellMagicMapper: undefined,
defaultKernel: undefined,
layoutChanged: undefined,
capabilitiesService: capabilitiesService.object
capabilitiesService: capabilitiesService.object,
getInputLanguageMode: () => undefined
};
});
@@ -983,7 +986,10 @@ suite('Notebook Editor Model', function (): void {
let options: INotebookModelOptions = Object.assign({}, defaultModelOptions, <Partial<INotebookModelOptions>><unknown>{
factory: mockModelFactory.object
});
notebookModel = new NotebookModel(options, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, undefined);
let mockNotebookService = TypeMoq.Mock.ofType(NotebookServiceStub);
mockNotebookService.setup(s => s.onNotebookKernelsAdded).returns(() => new Emitter<IStandardKernelWithProvider[]>().event);
notebookModel = new NotebookModel(options, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, mockNotebookService.object, undefined, undefined);
await notebookModel.loadContents();
}

View File

@@ -7,7 +7,7 @@ import { nb } from 'azdata';
import * as assert from 'assert';
import { URI } from 'vs/base/common/uri';
import { ExecuteManagerStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
import { ExecuteManagerStub, NotebookServiceStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
import { CellTypes } from 'sql/workbench/services/notebook/common/contracts';
import { IClientSession, INotebookModelOptions } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
@@ -34,6 +34,8 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { TestConfigurationService } from 'sql/platform/connection/test/common/testConfigurationService';
import { SessionManager } from 'sql/workbench/contrib/notebook/test/emptySessionClasses';
import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants';
import { Emitter } from 'vs/base/common/event';
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
let expectedNotebookContent: nb.INotebookContents = {
cells: [{
@@ -106,7 +108,8 @@ suite('Notebook Find Model', function (): void {
cellMagicMapper: undefined,
defaultKernel: undefined,
layoutChanged: undefined,
capabilitiesService: capabilitiesService.object
capabilitiesService: capabilitiesService.object,
getInputLanguageMode: () => undefined
};
mockClientSession = TypeMoq.Mock.ofType<IClientSession>(ClientSession, undefined, defaultModelOptions);
mockClientSession.setup(c => c.initialize()).returns(() => {
@@ -603,8 +606,11 @@ suite('Notebook Find Model', function (): void {
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(contents));
defaultModelOptions.contentLoader = mockContentManager.object;
let mockNotebookService = TypeMoq.Mock.ofType(NotebookServiceStub);
mockNotebookService.setup(s => s.onNotebookKernelsAdded).returns(() => new Emitter<IStandardKernelWithProvider[]>().event);
// Initialize the model
model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undefined);
model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undefined, mockNotebookService.object, undefined, undefined);
await model.loadContents();
await model.requestModelLoad();
}

View File

@@ -14,7 +14,7 @@ import { TestDialogService } from 'vs/platform/dialogs/test/common/testDialogSer
import { URI } from 'vs/base/common/uri';
import { ExecuteManagerStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
import { ExecuteManagerStub, NotebookServiceStub, SerializationManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
import { NotebookModel, SplitCell } from 'sql/workbench/services/notebook/browser/models/notebookModel';
import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory';
import { IClientSession, INotebookModelOptions, NotebookContentChange, IClientSessionOptions, ICellModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
@@ -42,8 +42,10 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService';
import { SQL_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/browser/notebookService';
import { DEFAULT_NOTEBOOK_FILETYPE, IExecuteManager, INotebookService, SQL_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/browser/notebookService';
import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants';
import { Emitter } from 'vs/base/common/event';
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
let expectedNotebookContent: nb.INotebookContents = {
cells: [{
@@ -145,6 +147,7 @@ let undoRedoService: IUndoRedoService;
let capabilitiesService: ICapabilitiesService;
let instantiationService: IInstantiationService;
let configurationService: IConfigurationService;
let notebookService: INotebookService;
suite('notebook model', function (): void {
let serializationManagers = [new SerializationManagerStub()];
@@ -163,6 +166,9 @@ suite('notebook model', function (): void {
dialogService = TypeMoq.Mock.ofType<IDialogService>(TestDialogService, TypeMoq.MockBehavior.Loose);
undoRedoService = new UndoRedoService(dialogService.object, notificationService.object);
capabilitiesService = new TestCapabilitiesService();
let mockNotebookService = TypeMoq.Mock.ofType(NotebookServiceStub);
mockNotebookService.setup(s => s.onNotebookKernelsAdded).returns(() => new Emitter<IStandardKernelWithProvider[]>().event);
notebookService = mockNotebookService.object;
memento = TypeMoq.Mock.ofType(Memento, TypeMoq.MockBehavior.Loose, '');
memento.setup(x => x.getMemento(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => void 0);
queryConnectionService = TypeMoq.Mock.ofType(TestConnectionManagementService, TypeMoq.MockBehavior.Loose, memento.object, undefined, new TestStorageService());
@@ -182,7 +188,8 @@ suite('notebook model', function (): void {
cellMagicMapper: undefined,
defaultKernel: undefined,
layoutChanged: undefined,
capabilitiesService: capabilitiesService
capabilitiesService: capabilitiesService,
getInputLanguageMode: () => 'notebook'
};
clientSessionOptions = {
executeManager: defaultModelOptions.executeManagers[0],
@@ -218,7 +225,7 @@ suite('notebook model', function (): void {
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(emptyNotebook));
defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents();
// Then I expect to have 0 code cell as the contents
@@ -234,7 +241,7 @@ suite('notebook model', function (): void {
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents(true);
await model.requestModelLoad();
@@ -251,7 +258,7 @@ suite('notebook model', function (): void {
// When I initalize the model
// Then it should throw
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
assert.strictEqual(model.inErrorState, false);
await assert.rejects(async () => { await model.loadContents(); });
assert.strictEqual(model.inErrorState, true);
@@ -264,7 +271,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object;
// When I initalize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents();
// Then I expect all cells to be in the model
@@ -292,7 +299,7 @@ suite('notebook model', function (): void {
defaultModelOptions.providerId = 'jupyter';
// When I initalize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents();
// I expect the default provider to be jupyter
@@ -302,7 +309,7 @@ suite('notebook model', function (): void {
defaultModelOptions.providerId = 'SQL';
// When I initalize the model
model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents();
// I expect the default provider to be SQL
@@ -327,7 +334,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object;
// When I initalize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents();
let activeCellChangeCount = 0;
@@ -384,7 +391,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents();
assert.strictEqual(model.notebookUri, defaultModelOptions.notebookUri, 'Notebook model has incorrect URI');
@@ -412,7 +419,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents();
assert.strictEqual(model.notebookUri, defaultModelOptions.notebookUri, 'Notebook model has incorrect URI');
@@ -436,7 +443,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents();
assert.strictEqual(model.notebookUri, defaultModelOptions.notebookUri, 'Notebook model has incorrect URI');
@@ -457,7 +464,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents();
assert.strictEqual(model.notebookUri, defaultModelOptions.notebookUri, 'Notebook model has incorrect URI');
@@ -476,7 +483,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents();
assert.strictEqual(model.notebookUri, defaultModelOptions.notebookUri, 'Notebook model has incorrect URI');
@@ -496,7 +503,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents();
assert.strictEqual(model.notebookUri, defaultModelOptions.notebookUri, 'Notebook model has incorrect URI');
@@ -517,7 +524,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object;
// When I initalize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents();
// Count number of times onError event is fired
@@ -569,7 +576,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object;
// When I initalize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents();
// Then I expect all cells to be in the model
@@ -591,7 +598,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents();
let firstCell = model.cells[0];
@@ -637,7 +644,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents();
let splitCells: SplitCell[] = [
@@ -657,7 +664,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object;
// When I initalize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents();
let notebookContentChange: NotebookContentChange;
@@ -673,7 +680,7 @@ suite('notebook model', function (): void {
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
defaultModelOptions.contentLoader = mockContentManager.object;
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents();
let newCell: ICellModel;
@@ -705,7 +712,7 @@ suite('notebook model', function (): void {
sessionReady.resolve();
let sessionFired = false;
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
model.onClientSessionReady((session) => sessionFired = true);
await model.loadContents();
await model.requestModelLoad();
@@ -735,7 +742,7 @@ suite('notebook model', function (): void {
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
defaultModelOptions.contentLoader = mockContentManager.object;
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.requestModelLoad();
let actualChanged: NotebookContentChange;
@@ -804,7 +811,7 @@ suite('notebook model', function (): void {
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, undefined, queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, undefined, queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents();
let output = model.toJSON();
@@ -937,7 +944,7 @@ suite('notebook model', function (): void {
sinon.stub(configurationService, 'getValue').returns(true);
// When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents();
// I expect the saved connection name to be read
@@ -966,7 +973,7 @@ suite('notebook model', function (): void {
defaultModelOptions.contentLoader = mockContentManager.object;
// When I initialize the model
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents();
// I expect multiConnectionMode to be set to true
@@ -997,7 +1004,7 @@ suite('notebook model', function (): void {
// Given I have a session that fails to start
sessionReady.resolve();
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents();
await model.requestModelLoad();
@@ -1011,7 +1018,7 @@ suite('notebook model', function (): void {
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
defaultModelOptions.contentLoader = mockContentManager.object;
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents();
const newLanguage = 'CustomCellLanguage';
@@ -1025,7 +1032,7 @@ suite('notebook model', function (): void {
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
defaultModelOptions.contentLoader = mockContentManager.object;
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService);
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, undefined, undefined);
await model.loadContents();
let cell = model.addCell(CellTypes.Code);
@@ -1033,6 +1040,81 @@ suite('notebook model', function (): void {
assert.strictEqual(cell.language, expectedNotebookContent.metadata.language_info.name);
});
test('Should update kernels list when new kernels are installed', async function () {
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(expectedNotebookContent));
defaultModelOptions.contentLoader = mockContentManager.object;
let kernelsAddedEmitter = new Emitter<IStandardKernelWithProvider[]>();
let mockNotebookService = TypeMoq.Mock.ofType(NotebookServiceStub);
mockNotebookService.setup(s => s.onNotebookKernelsAdded).returns(() => kernelsAddedEmitter.event);
let mockExecuteManager = TypeMoq.Mock.ofType<IExecuteManager>(ExecuteManagerStub);
mockNotebookService.setup(s => s.getOrCreateExecuteManager(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns(() => Promise.resolve(mockExecuteManager.object));
let model = new NotebookModel(defaultModelOptions, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, mockNotebookService.object, undefined, undefined);
model.standardKernels = [{
name: 'SQL',
displayName: 'SQL',
connectionProviderIds: [],
notebookProvider: 'sql',
supportedLanguages: ['sql'],
supportedFileExtensions: ['.ipynb']
}];
await model.loadContents();
assert.strictEqual(model.standardKernels.length, 1, 'Should start with only 1 kernel in the notebook model.');
assert.strictEqual(model.executeManagers.length, 1, 'Should start with only 1 execute manager in the notebook model.');
let expectedKernel: IStandardKernelWithProvider = {
name: 'csharp-test',
displayName: 'CSharpTest',
connectionProviderIds: undefined,
notebookProvider: 'csharp-test',
supportedLanguages: ['csharp'],
supportedFileExtensions: [DEFAULT_NOTEBOOK_FILETYPE]
};
let kernelsAddedPromise = new Promise<void>(resolve => {
model.kernelsChanged(kernel => {
resolve();
});
});
let timeoutPromise = new Promise<void>((resolve, reject) => setTimeout(() => {
reject('KernelsAdded event failed to fire within expected time.');
}, 4000));
kernelsAddedEmitter.fire([expectedKernel]);
await Promise.race([kernelsAddedPromise, timeoutPromise]);
assert.strictEqual(model.standardKernels.length, 2, 'New kernel was not registered.');
assert.strictEqual(model.executeManagers.length, 2, 'Should create another execute manager when adding a new provider\'s kernel.');
assert.deepStrictEqual(model.standardKernels[1], expectedKernel, 'Did not add expected kernel.');
// Shouldn't add kernel if it's for a different file extension
let invalidKernel = {
name: 'html-test',
displayName: 'HtmlTest',
connectionProviderIds: undefined,
notebookProvider: 'html-test',
supportedLanguages: ['html'],
supportedFileExtensions: ['.html']
};
kernelsAddedPromise = new Promise<void>((resolve, reject) => {
model.kernelsChanged(kernel => {
reject('Should not have added a new kernel');
});
});
timeoutPromise = new Promise<void>((resolve, reject) => setTimeout(() => {
resolve();
}, 1000));
kernelsAddedEmitter.fire([invalidKernel]);
await Promise.race([kernelsAddedPromise, timeoutPromise]);
assert.strictEqual(model.standardKernels.length, 2, 'Should not have registered invalid kernel.');
assert.strictEqual(model.executeManagers.length, 2, 'Should not have created another execute manager for invalid kernel.');
assert.deepStrictEqual(model.standardKernels[1], expectedKernel, 'Did not keep old kernel.');
});
async function loadModelAndStartClientSession(notebookContent: nb.INotebookContents): Promise<NotebookModel> {
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentLoader);
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(notebookContent));
@@ -1046,7 +1128,7 @@ suite('notebook model', function (): void {
let options: INotebookModelOptions = Object.assign({}, defaultModelOptions, <Partial<INotebookModelOptions>>{
factory: mockModelFactory.object
});
let model = new NotebookModel(options, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, capabilitiesService);
let model = new NotebookModel(options, undefined, logService, undefined, new NullAdsTelemetryService(), queryConnectionService.object, configurationService, undoRedoService, notebookService, capabilitiesService, undefined);
model.onClientSessionReady((session) => actualSession = session);
await model.requestModelLoad();

View File

@@ -236,6 +236,9 @@ export class ServerManagerStub implements nb.ServerManager {
}
export class NotebookServiceStub implements INotebookService {
get onNotebookKernelsAdded(): vsEvent.Event<IStandardKernelWithProvider[]> {
throw new Error('Method not implemented.');
}
getNotebookURIForCell(cellUri: URI): URI {
throw new Error('Method not implemented.');
}

View File

@@ -23,6 +23,7 @@ export abstract class INotebookInput extends EditorInput {
readonly standardKernels: IStandardKernelWithProvider[];
readonly providersLoaded: Promise<void>;
readonly showActions: boolean;
readonly languageMode: string;
}
export function isINotebookInput(value: any): value is INotebookInput {

View File

@@ -622,6 +622,7 @@ export interface INotebookModelOptions {
notificationService: INotificationService;
connectionService: IConnectionManagementService;
capabilitiesService: ICapabilitiesService;
getInputLanguageMode: () => string;
editorLoadedTimestamp?: number;
}

View File

@@ -23,7 +23,7 @@ import { INotebookEditOperation, NotebookEditOperationType } from 'sql/workbench
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
import { uriPrefixes } from 'sql/platform/connection/common/utils';
import { ILogService } from 'vs/platform/log/common/log';
import { getErrorMessage } from 'vs/base/common/errors';
import { getErrorMessage, onUnexpectedError } from 'vs/base/common/errors';
import { notebookConstants } from 'sql/workbench/services/notebook/browser/interfaces';
import { IAdsTelemetryService, ITelemetryEvent, ITelemetryEventProperties } from 'sql/platform/telemetry/common/telemetry';
import { Deferred } from 'sql/base/common/promise';
@@ -40,6 +40,8 @@ import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { deepClone } from 'vs/base/common/objects';
import { DotnetInteractiveDisplayName } from 'sql/workbench/api/common/notebooks/notebookUtils';
import { IPYKERNEL_DISPLAY_NAME } from 'sql/workbench/common/constants';
import * as path from 'vs/base/common/path';
import { IModeService } from 'vs/editor/common/services/modeService';
/*
* Used to control whether a message in a dialog/wizard is displayed as an error,
@@ -134,7 +136,9 @@ export class NotebookModel extends Disposable implements INotebookModel {
@IConnectionManagementService private connectionManagementService: IConnectionManagementService,
@IConfigurationService private configurationService: IConfigurationService,
@IUndoRedoService private undoService: IUndoRedoService,
@ICapabilitiesService private _capabilitiesService?: ICapabilitiesService,
@INotebookService private _notebookService: INotebookService,
@ICapabilitiesService private _capabilitiesService: ICapabilitiesService,
@IModeService private _modeService: IModeService,
) {
super();
if (!_notebookOptions || !_notebookOptions.notebookUri || !_notebookOptions.executeManagers) {
@@ -147,6 +151,45 @@ export class NotebookModel extends Disposable implements INotebookModel {
this._notebookOptions.layoutChanged(() => this._layoutChanged.fire());
}
this._defaultKernel = _notebookOptions.defaultKernel;
this._register(this._notebookService.onNotebookKernelsAdded(async kernels => this.handleNewKernelsAdded(kernels).catch(error => onUnexpectedError(error))));
}
// Add new kernels to the model's list as they're registered so that we don't
// need to restart the notebook to select them in the kernel dropdown.
private async handleNewKernelsAdded(kernels: notebookUtils.IStandardKernelWithProvider[]): Promise<void> {
// Kernels are file-specific, so we need to check the file extension
// to see if the kernel is supported for this notebook.
let extensions: string[];
let fileExt = path.extname(this._notebookOptions.notebookUri.path);
if (!fileExt) {
let languageMode = this._notebookOptions.getInputLanguageMode();
if (languageMode) {
let languageName = this._modeService.getLanguageName(languageMode);
let fileExtensions = this._modeService.getExtensions(languageName);
if (fileExtensions?.length > 0) {
extensions = fileExtensions;
} else {
this.logService.warn(`Could not retrieve file extensions for language mode '${languageMode}' in notebook '${this._notebookOptions.notebookUri.toString()}'`);
}
} else {
this.logService.warn(`Could not determine language mode for notebook '${this._notebookOptions.notebookUri.toString()}'`);
}
} else {
extensions = [fileExt];
}
// All kernels from the same provider share the same supported file extensions,
// so we only need to check the first one here.
if (extensions?.some(ext => kernels[0]?.supportedFileExtensions?.includes(ext))) {
this._standardKernels.push(...kernels);
this.setDisplayNameMapsForKernels(kernels);
// Also add corresponding execute manager so that we can change to the new kernels
let manager = await this._notebookService.getOrCreateExecuteManager(kernels[0].notebookProvider, this.notebookUri);
this._notebookOptions.executeManagers.push(manager);
this._kernelsChangedEmitter.fire(this._activeClientSession?.kernel);
}
}
private get serializationManagers(): ISerializationManager[] {
@@ -401,7 +444,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
public set standardKernels(kernels: notebookUtils.IStandardKernelWithProvider[]) {
this._standardKernels = kernels;
this.setKernelDisplayNameMapsWithStandardKernels();
this.setDisplayNameMapsForKernels(kernels);
}
public getApplicableConnectionProviderIds(kernelDisplayName: string): string[] {
@@ -1567,8 +1610,8 @@ export class NotebookModel extends Disposable implements INotebookModel {
* Set maps with values to have a way to determine the connection
* provider and notebook provider ids from a kernel display name
*/
private setKernelDisplayNameMapsWithStandardKernels(): void {
this._standardKernels.forEach(kernel => {
private setDisplayNameMapsForKernels(kernels: notebookUtils.IStandardKernelWithProvider[]): void {
kernels.forEach(kernel => {
let displayName = kernel.displayName;
if (!displayName) {
displayName = kernel.name;

View File

@@ -65,6 +65,7 @@ export interface IStandardKernelWithProvider {
readonly connectionProviderIds: string[];
readonly notebookProvider: string;
readonly supportedLanguages: string[];
readonly supportedFileExtensions?: string[];
}
export interface IEndpoint {

View File

@@ -23,6 +23,7 @@ import { INotebookShowOptions } from 'sql/workbench/api/common/sqlExtHost.protoc
import { NotebookViewsExtension } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViewsExtension';
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { ICodeEditorViewState } from 'vs/editor/common/editorCommon';
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
export const SERVICE_ID = 'sqlNotebookService';
export const INotebookService = createDecorator<INotebookService>(SERVICE_ID);
@@ -55,6 +56,7 @@ export interface INotebookService {
readonly onNotebookEditorAdd: Event<INotebookEditor>;
readonly onNotebookEditorRemove: Event<INotebookEditor>;
onNotebookEditorRename: Event<INotebookEditor>;
readonly onNotebookKernelsAdded: Event<IStandardKernelWithProvider[]>;
readonly isRegistrationComplete: boolean;
readonly registrationComplete: Promise<void>;

View File

@@ -54,6 +54,7 @@ import { DEFAULT_NB_LANGUAGE_MODE, INTERACTIVE_LANGUAGE_MODE, INTERACTIVE_PROVID
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { SqlSerializationProvider } from 'sql/workbench/services/notebook/browser/sql/sqlSerializationProvider';
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
const languageAssociationRegistry = Registry.as<ILanguageAssociationRegistry>(LanguageAssociationExtensions.LanguageAssociations);
@@ -178,6 +179,7 @@ export class NotebookService extends Disposable implements INotebookService {
private _onNotebookEditorAdd = new Emitter<INotebookEditor>();
private _onNotebookEditorRemove = new Emitter<INotebookEditor>();
private _onNotebookEditorRename = new Emitter<INotebookEditor>();
private _onNotebookKernelsAdded = new Emitter<IStandardKernelWithProvider[]>();
private _editors = new Map<string, INotebookEditor>();
private _fileToProviderDescriptions = new Map<string, ProviderDescriptionRegistration[]>();
private _providerToStandardKernels = new Map<string, StandardKernelsDescriptor>(); // Note: providerId key here should be in upper case
@@ -426,7 +428,7 @@ export class NotebookService extends Disposable implements INotebookService {
if (!this._executeProviders.has(p.id)) {
this._executeProviders.set(p.id, new ExecuteProviderDescriptor(p.id));
}
this.addStandardKernels(registration);
this.addStandardKernels(registration, registration.fileExtensions);
} else {
// Standard kernels might get registered later for VSCode notebooks, so add a descriptor to wait on
if (!this._providerToStandardKernels.has(p.id)) {
@@ -506,7 +508,7 @@ export class NotebookService extends Disposable implements INotebookService {
// 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
// kernels to the dropdown
private addStandardKernels(provider: ProviderDescriptionRegistration) {
private addStandardKernels(provider: ProviderDescriptionRegistration, supportedFileExtensions?: string[]) {
let providerUpperCase = provider.provider.toUpperCase();
let descriptor = this._providerToStandardKernels.get(providerUpperCase);
if (!descriptor) {
@@ -526,6 +528,20 @@ export class NotebookService extends Disposable implements INotebookService {
}
descriptor.instance = standardKernels;
this._providerToStandardKernels.set(providerUpperCase, descriptor);
// Emit update event if the provider is not one of the default options
if (provider.provider !== SQL_NOTEBOOK_PROVIDER && provider.provider !== JUPYTER_PROVIDER_ID && standardKernels.length > 0) {
this._onNotebookKernelsAdded.fire(standardKernels.map(kernel => {
return {
name: kernel.name,
displayName: kernel.displayName,
connectionProviderIds: kernel.connectionProviderIds,
notebookProvider: provider.provider,
supportedLanguages: kernel.supportedLanguages,
supportedFileExtensions: supportedFileExtensions
};
}));
}
}
getSupportedFileExtensions(): string[] {
@@ -632,6 +648,10 @@ export class NotebookService extends Disposable implements INotebookService {
return this._onNotebookEditorRename.event;
}
get onNotebookKernelsAdded(): Event<IStandardKernelWithProvider[]> {
return this._onNotebookKernelsAdded.event;
}
addNotebookEditor(editor: INotebookEditor): void {
this._editors.set(editor.id, editor);
this._onNotebookEditorAdd.fire(editor);