Skip to content

Commit d586f70

Browse files
committed
kernel provider settings.
1 parent caa05dd commit d586f70

8 files changed

Lines changed: 199 additions & 19 deletions

File tree

src/vs/workbench/api/browser/mainThreadNotebook.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,8 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
529529
const emitter = new Emitter<void>();
530530
const that = this;
531531
const provider = this._notebookService.registerNotebookKernelProvider({
532+
providerExtensionId: extension.id.value,
533+
providerDescription: extension.description,
532534
onDidChangeKernels: emitter.event,
533535
selector: documentFilter,
534536
provideKernels: async (uri: URI, token: CancellationToken) => {

src/vs/workbench/api/common/extHost.protocol.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,7 @@ export interface WebviewExtensionDescription {
597597
export interface NotebookExtensionDescription {
598598
readonly id: ExtensionIdentifier;
599599
readonly location: UriComponents;
600+
readonly description?: string;
600601
}
601602

602603
export enum WebviewEditorCapabilities {

src/vs/workbench/api/common/extHostNotebook.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -958,7 +958,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
958958

959959
let extHostRenderer = new ExtHostNotebookOutputRenderer(type, filter, renderer);
960960
this._notebookOutputRenderers.set(extHostRenderer.type, extHostRenderer);
961-
this._proxy.$registerNotebookRenderer({ id: extension.identifier, location: extension.extensionLocation }, type, filter, renderer.preloads || []);
961+
this._proxy.$registerNotebookRenderer({ id: extension.identifier, location: extension.extensionLocation, description: extension.description }, type, filter, renderer.preloads || []);
962962
return new extHostTypes.Disposable(() => {
963963
this._notebookOutputRenderers.delete(extHostRenderer.type);
964964
this._proxy.$unregisterNotebookRenderer(extHostRenderer.type);
@@ -1083,7 +1083,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
10831083

10841084
const supportBackup = !!provider.backupNotebook;
10851085

1086-
this._proxy.$registerNotebookProvider({ id: extension.identifier, location: extension.extensionLocation }, viewType, supportBackup, provider.kernel ? { id: viewType, label: provider.kernel.label, extensionLocation: extension.extensionLocation, preloads: provider.kernel.preloads } : undefined);
1086+
this._proxy.$registerNotebookProvider({ id: extension.identifier, location: extension.extensionLocation, description: extension.description }, viewType, supportBackup, provider.kernel ? { id: viewType, label: provider.kernel.label, extensionLocation: extension.extensionLocation, preloads: provider.kernel.preloads } : undefined);
10871087

10881088
return new extHostTypes.Disposable(() => {
10891089
listener.dispose();
@@ -1096,7 +1096,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
10961096
const handle = ExtHostNotebookController._notebookKernelProviderHandlePool++;
10971097
const adapter = new ExtHostNotebookKernelProviderAdapter(this._proxy, handle, extension, provider);
10981098
this._notebookKernelProviders.set(handle, adapter);
1099-
this._proxy.$registerNotebookKernelProvider({ id: extension.identifier, location: extension.extensionLocation }, handle, {
1099+
this._proxy.$registerNotebookKernelProvider({ id: extension.identifier, location: extension.extensionLocation, description: extension.description }, handle, {
11001100
viewType: selector.viewType,
11011101
filenamePattern: selector.filenamePattern ? typeConverters.GlobPattern.from(selector.filenamePattern) : undefined,
11021102
excludeFileNamePattern: selector.excludeFileNamePattern ? typeConverters.GlobPattern.from(selector.excludeFileNamePattern) : undefined,
@@ -1149,7 +1149,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
11491149
this._notebookKernels.set(id, { kernel, extension });
11501150
const transformedSelectors = selectors.map(selector => typeConverters.GlobPattern.from(selector));
11511151

1152-
this._proxy.$registerNotebookKernel({ id: extension.identifier, location: extension.extensionLocation }, id, kernel.label, transformedSelectors, kernel.preloads || []);
1152+
this._proxy.$registerNotebookKernel({ id: extension.identifier, location: extension.extensionLocation, description: extension.description }, id, kernel.label, transformedSelectors, kernel.preloads || []);
11531153
return new extHostTypes.Disposable(() => {
11541154
this._notebookKernels.delete(id);
11551155
this._proxy.$unregisterNotebookKernel(id);

src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ import { URI } from 'vs/base/common/uri';
4949
import { PANEL_BORDER } from 'vs/workbench/common/theme';
5050
import { debugIconStartForeground } from 'vs/workbench/contrib/debug/browser/debugToolBar';
5151
import { CellContextKeyManager } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellContextKeys';
52+
import { NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider';
53+
import { notebookKernelProviderAssociationsSettingId, NotebookKernelProviderAssociations } from 'vs/workbench/contrib/notebook/browser/notebookKernelAssociation';
5254

5355
const $ = DOM.$;
5456

@@ -586,6 +588,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
586588
this.multipleKernelsAvailable = false;
587589
}
588590

591+
// @deprecated
589592
if (provider && provider.kernel) {
590593
// it has a builtin kernel, don't automatically choose a kernel
591594
this._loadKernelPreloads(provider.providerExtensionLocation, provider.kernel);
@@ -596,25 +599,61 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
596599
const activeKernelStillExist = [...availableKernels2, ...availableKernels].find(kernel => kernel.id === this.activeKernel?.id && this.activeKernel?.id !== undefined);
597600

598601
if (activeKernelStillExist) {
602+
// the kernel still exist, we don't want to modify the selection otherwise user's temporary preference is lost
603+
return;
604+
}
605+
606+
if (availableKernels2.length) {
607+
return this._setKernelsFromProviders(provider, availableKernels2, tokenSource);
608+
}
609+
610+
// the provider doesn't have a builtin kernel, choose a kernel
611+
this.activeKernel = availableKernels[0];
612+
if (this.activeKernel) {
613+
this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
614+
}
615+
616+
tokenSource.dispose();
617+
}
618+
619+
private async _setKernelsFromProviders(provider: NotebookProviderInfo, kernels: INotebookKernelInfo2[], tokenSource: CancellationTokenSource) {
620+
const rawAssociations = this.configurationService.getValue<NotebookKernelProviderAssociations>(notebookKernelProviderAssociationsSettingId) || [];
621+
const userSetKernelProvider = rawAssociations.filter(e => e.viewType === this.viewModel?.viewType)[0]?.kernelProvider;
622+
623+
if (userSetKernelProvider) {
624+
const filteredKernels = kernels.filter(kernel => kernel.extension.value === userSetKernelProvider);
625+
626+
if (filteredKernels.length) {
627+
this.activeKernel = filteredKernels.find(kernel => kernel.isPreferred) || filteredKernels[0];
628+
} else {
629+
this.activeKernel = undefined;
630+
}
631+
632+
if (this.activeKernel) {
633+
this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
634+
await this.activeKernel.resolve(this.viewModel!.uri, this.getId(), tokenSource.token);
635+
}
636+
637+
tokenSource.dispose();
599638
return;
600639
}
601640

602641
// choose a preferred kernel
603-
const kernelsFromSameExtension = availableKernels2.filter(kernel => kernel.extension.value === provider.providerId);
642+
const kernelsFromSameExtension = kernels.filter(kernel => kernel.extension.value === provider.providerExtensionId);
604643
if (kernelsFromSameExtension.length) {
605644
const preferedKernel = kernelsFromSameExtension.find(kernel => kernel.isPreferred) || kernelsFromSameExtension[0];
606645
this.activeKernel = preferedKernel;
646+
this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
607647
await preferedKernel.resolve(this.viewModel!.uri, this.getId(), tokenSource.token);
608-
609648
tokenSource.dispose();
610649
return;
611650
}
612651

613-
614652
// the provider doesn't have a builtin kernel, choose a kernel
615-
this.activeKernel = availableKernels[0];
653+
this.activeKernel = kernels[0];
616654
if (this.activeKernel) {
617655
this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
656+
await this.activeKernel.resolve(this.viewModel!.uri, this.getId(), tokenSource.token);
618657
}
619658

620659
tokenSource.dispose();
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import * as nls from 'vs/nls';
7+
import { IJSONSchema } from 'vs/base/common/jsonSchema';
8+
import { IConfigurationNode, IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry';
9+
import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration';
10+
import { Registry } from 'vs/platform/registry/common/platform';
11+
12+
export class NotebookKernelProviderAssociationRegistry {
13+
static extensionIds: (string | null)[] = [];
14+
static extensionDescriptions: string[] = [];
15+
}
16+
17+
export class NotebookViewTypesExtensionRegistry {
18+
static viewTypes: string[] = [];
19+
static viewTypeDescriptions: string[] = [];
20+
}
21+
22+
export type NotebookKernelProviderAssociation = {
23+
readonly viewType: string;
24+
readonly kernelProvider?: string;
25+
};
26+
27+
export type NotebookKernelProviderAssociations = readonly NotebookKernelProviderAssociation[];
28+
29+
30+
export const notebookKernelProviderAssociationsSettingId = 'notebook.kernelProviderAssociations';
31+
32+
export const viewTypeSchamaAddition: IJSONSchema = {
33+
type: 'string',
34+
enum: []
35+
};
36+
37+
export const notebookKernelProviderAssociationsConfigurationNode: IConfigurationNode = {
38+
...workbenchConfigurationNodeBase,
39+
properties: {
40+
[notebookKernelProviderAssociationsSettingId]: {
41+
type: 'array',
42+
markdownDescription: nls.localize('notebook.kernelProviderAssociations', "Defines a default kernel provider which takes precedence over all other kernel providers settings. Must be the identifier of an extension contributing a kernel provider."),
43+
items: {
44+
type: 'object',
45+
defaultSnippets: [{
46+
body: {
47+
'viewType': '$1',
48+
'kernelProvider': '$2'
49+
}
50+
}],
51+
properties: {
52+
'viewType': {
53+
type: ['string', 'null'],
54+
default: null,
55+
enum: NotebookViewTypesExtensionRegistry.viewTypes,
56+
markdownEnumDescriptions: NotebookViewTypesExtensionRegistry.viewTypeDescriptions
57+
},
58+
'kernelProvider': {
59+
type: ['string', 'null'],
60+
default: null,
61+
enum: NotebookKernelProviderAssociationRegistry.extensionIds,
62+
markdownEnumDescriptions: NotebookKernelProviderAssociationRegistry.extensionDescriptions
63+
}
64+
}
65+
}
66+
}
67+
}
68+
};
69+
70+
export function updateNotebookKernelProvideAssociationSchema(): void {
71+
Registry.as<IConfigurationRegistry>(Extensions.Configuration)
72+
.notifyConfigurationSchemaUpdated(notebookKernelProviderAssociationsConfigurationNode);
73+
}
74+
75+
Registry.as<IConfigurationRegistry>(Extensions.Configuration)
76+
.registerConfiguration(notebookKernelProviderAssociationsConfigurationNode);

src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,50 @@ import { IExtensionPointUser } from 'vs/workbench/services/extensions/common/ext
3030
import { generateUuid } from 'vs/base/common/uuid';
3131
import { flatten } from 'vs/base/common/arrays';
3232
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
33+
import { NotebookKernelProviderAssociationRegistry, updateNotebookKernelProvideAssociationSchema, NotebookViewTypesExtensionRegistry } from 'vs/workbench/contrib/notebook/browser/notebookKernelAssociation';
3334

3435
function MODEL_ID(resource: URI): string {
3536
return resource.toString();
3637
}
3738

39+
export class NotebookKernelProviderInfoStore extends Disposable {
40+
private readonly _notebookKernelProviders: INotebookKernelProvider[] = [];
41+
42+
constructor() {
43+
super();
44+
}
45+
46+
add(provider: INotebookKernelProvider) {
47+
this._notebookKernelProviders.push(provider);
48+
this._updateProviderExtensionsInfo();
49+
50+
return toDisposable(() => {
51+
let idx = this._notebookKernelProviders.indexOf(provider);
52+
if (idx >= 0) {
53+
this._notebookKernelProviders.splice(idx, 1);
54+
}
55+
56+
this._updateProviderExtensionsInfo();
57+
});
58+
}
59+
60+
get(viewType: string, resource: URI) {
61+
return this._notebookKernelProviders.filter(provider => notebookDocumentFilterMatch(provider.selector, viewType, resource));
62+
}
63+
64+
private _updateProviderExtensionsInfo() {
65+
NotebookKernelProviderAssociationRegistry.extensionIds.length = 0;
66+
NotebookKernelProviderAssociationRegistry.extensionDescriptions.length = 0;
67+
68+
this._notebookKernelProviders.forEach(provider => {
69+
NotebookKernelProviderAssociationRegistry.extensionIds.push(provider.providerExtensionId);
70+
NotebookKernelProviderAssociationRegistry.extensionDescriptions.push(provider.providerDescription || '');
71+
});
72+
73+
updateNotebookKernelProvideAssociationSchema();
74+
}
75+
}
76+
3877
export class NotebookProviderInfoStore extends Disposable {
3978
private static readonly CUSTOM_EDITORS_STORAGE_ID = 'notebookEditors';
4079
private static readonly CUSTOM_EDITORS_ENTRY_ID = 'editors';
@@ -54,13 +93,17 @@ export class NotebookProviderInfoStore extends Disposable {
5493
this.add(new NotebookProviderInfo(info));
5594
}
5695

96+
this._updateProviderExtensionsInfo();
97+
5798
this._register(extensionService.onDidRegisterExtensions(() => {
5899
if (!this._handled) {
59100
// there is no extension point registered for notebook content provider
60101
// clear the memento and cache
61102
this.clear();
62103
mementoObject[NotebookProviderInfoStore.CUSTOM_EDITORS_ENTRY_ID] = [];
63104
this._memento.saveMemento();
105+
106+
this._updateProviderExtensionsInfo();
64107
}
65108
}));
66109
}
@@ -76,7 +119,8 @@ export class NotebookProviderInfoStore extends Disposable {
76119
displayName: notebookContribution.displayName,
77120
selector: notebookContribution.selector || [],
78121
priority: this._convertPriority(notebookContribution.priority),
79-
providerId: extension.description.identifier.value,
122+
providerExtensionId: extension.description.identifier.value,
123+
providerDescription: extension.description.description,
80124
providerDisplayName: extension.description.isBuiltin ? nls.localize('builtinProviderDisplayName', "Built-in") : extension.description.displayName || extension.description.identifier.value,
81125
providerExtensionLocation: extension.description.extensionLocation
82126
}));
@@ -86,6 +130,22 @@ export class NotebookProviderInfoStore extends Disposable {
86130
const mementoObject = this._memento.getMemento(StorageScope.GLOBAL);
87131
mementoObject[NotebookProviderInfoStore.CUSTOM_EDITORS_ENTRY_ID] = Array.from(this._contributedEditors.values());
88132
this._memento.saveMemento();
133+
134+
this._updateProviderExtensionsInfo();
135+
}
136+
137+
private _updateProviderExtensionsInfo() {
138+
NotebookViewTypesExtensionRegistry.viewTypes.length = 0;
139+
NotebookViewTypesExtensionRegistry.viewTypeDescriptions.length = 0;
140+
141+
for (const contribute of this._contributedEditors) {
142+
if (contribute[1].providerExtensionId) {
143+
NotebookViewTypesExtensionRegistry.viewTypes.push(contribute[1].id);
144+
NotebookViewTypesExtensionRegistry.viewTypeDescriptions.push(`${contribute[1].displayName}`);
145+
}
146+
}
147+
148+
updateNotebookKernelProvideAssociationSchema();
89149
}
90150

91151
private _convertPriority(priority?: string) {
@@ -173,6 +233,7 @@ export class NotebookService extends Disposable implements INotebookService, ICu
173233
private readonly _notebookKernels = new Map<string, INotebookKernelInfo>();
174234
notebookProviderInfoStore: NotebookProviderInfoStore;
175235
notebookRenderersInfoStore: NotebookOutputRendererInfoStore = new NotebookOutputRendererInfoStore();
236+
notebookKernelProviderInfoStore: NotebookKernelProviderInfoStore = new NotebookKernelProviderInfoStore();
176237
private readonly _models = new Map<string, ModelData>();
177238
private _onDidChangeActiveEditor = new Emitter<string | null>();
178239
onDidChangeActiveEditor: Event<string | null> = this._onDidChangeActiveEditor.event;
@@ -200,7 +261,6 @@ export class NotebookService extends Disposable implements INotebookService, ICu
200261
private _lastClipboardIsCopy: boolean = true;
201262

202263
private _displayOrder: { userOrder: string[], defaultOrder: string[] } = Object.create(null);
203-
private readonly _notebookKernelProviders: INotebookKernelProvider[] = [];
204264

205265
constructor(
206266
@IExtensionService private readonly _extensionService: IExtensionService,
@@ -307,21 +367,18 @@ export class NotebookService extends Disposable implements INotebookService, ICu
307367
}
308368

309369
registerNotebookKernelProvider(provider: INotebookKernelProvider): IDisposable {
310-
this._notebookKernelProviders.push(provider);
370+
const d = this.notebookKernelProviderInfoStore.add(provider);
311371
const kernelChangeEventListener = provider.onDidChangeKernels(() => {
312372
this._onDidChangeKernels.fire();
313373
});
314374
return toDisposable(() => {
315375
kernelChangeEventListener.dispose();
316-
let idx = this._notebookKernelProviders.indexOf(provider);
317-
if (idx >= 0) {
318-
this._notebookKernelProviders.splice(idx, 1);
319-
}
376+
d.dispose();
320377
});
321378
}
322379

323380
async getContributedNotebookKernels2(viewType: string, resource: URI, token: CancellationToken): Promise<INotebookKernelInfo2[]> {
324-
const filteredProvider = this._notebookKernelProviders.filter(provider => notebookDocumentFilterMatch(provider.selector, viewType, resource));
381+
const filteredProvider = this.notebookKernelProviderInfoStore.get(viewType, resource);
325382
const result = new Array<INotebookKernelInfo2[]>(filteredProvider.length);
326383

327384
const promises = filteredProvider.map(async (provider, index) => {

src/vs/workbench/contrib/notebook/common/notebookCommon.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,8 @@ export interface INotebookKernelInfo2 extends INotebookKernelInfoDto2 {
663663
}
664664

665665
export interface INotebookKernelProvider {
666+
providerExtensionId: string;
667+
providerDescription?: string;
666668
selector: INotebookDocumentFilter;
667669
onDidChangeKernels: Event<void>;
668670
provideKernels(uri: URI, token: CancellationToken): Promise<INotebookKernelInfoDto2[]>;

src/vs/workbench/contrib/notebook/common/notebookProvider.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ export interface NotebookEditorDescriptor {
1818
readonly displayName: string;
1919
readonly selector: readonly NotebookSelector[];
2020
readonly priority: NotebookEditorPriority;
21-
readonly providerId?: string;
21+
readonly providerExtensionId?: string;
22+
readonly providerDescription?: string;
2223
readonly providerDisplayName: string;
2324
readonly providerExtensionLocation: URI;
2425
kernel?: INotebookKernelInfoDto;
@@ -31,7 +32,8 @@ export class NotebookProviderInfo implements NotebookEditorDescriptor {
3132
readonly selector: readonly NotebookSelector[];
3233
readonly priority: NotebookEditorPriority;
3334
// it's optional as the memento might not have it
34-
readonly providerId?: string;
35+
readonly providerExtensionId?: string;
36+
readonly providerDescription?: string;
3537
readonly providerDisplayName: string;
3638
readonly providerExtensionLocation: URI;
3739
kernel?: INotebookKernelInfoDto;
@@ -41,7 +43,8 @@ export class NotebookProviderInfo implements NotebookEditorDescriptor {
4143
this.displayName = descriptor.displayName;
4244
this.selector = descriptor.selector;
4345
this.priority = descriptor.priority;
44-
this.providerId = descriptor.providerId;
46+
this.providerExtensionId = descriptor.providerExtensionId;
47+
this.providerDescription = descriptor.providerDescription;
4548
this.providerDisplayName = descriptor.providerDisplayName;
4649
this.providerExtensionLocation = descriptor.providerExtensionLocation;
4750
}

0 commit comments

Comments
 (0)