Skip to content

Commit 48eb908

Browse files
authored
Categorize kernels in the notebook kernel picker (microsoft#135502)
* Categorize kernels in the notebook kernel picker * rename property * address review comments * more changes * fix liner * address review comments
1 parent f5f0b2b commit 48eb908

File tree

11 files changed

+68
-18
lines changed

11 files changed

+68
-18
lines changed

src/vs/vscode.proposed.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1575,6 +1575,10 @@ declare module 'vscode' {
15751575
}
15761576

15771577
export interface NotebookController {
1578+
/**
1579+
* The human-readable label used to categorise controllers.
1580+
*/
1581+
kind?: string;
15781582

15791583
// todo@API allow add, not remove
15801584
readonly rendererScripts: NotebookRendererScript[];

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ abstract class MainThreadKernel implements INotebookKernel {
3333
label: string;
3434
description?: string;
3535
detail?: string;
36+
kind?: string;
3637
supportedLanguages: string[];
3738
implementsExecutionOrder: boolean;
3839
localResourceRoot: URI;
@@ -54,6 +55,7 @@ abstract class MainThreadKernel implements INotebookKernel {
5455
this.label = data.label;
5556
this.description = data.description;
5657
this.detail = data.detail;
58+
this.kind = data.kind;
5759
this.supportedLanguages = isNonEmptyArray(data.supportedLanguages) ? data.supportedLanguages : _modeService.getRegisteredModes();
5860
this.implementsExecutionOrder = data.supportsExecutionOrder ?? false;
5961
this.localResourceRoot = URI.revive(data.extensionLocation);
@@ -76,6 +78,10 @@ abstract class MainThreadKernel implements INotebookKernel {
7678
this.detail = data.detail;
7779
event.detail = true;
7880
}
81+
if (data.kind !== undefined) {
82+
this.kind = data.kind;
83+
event.kind = true;
84+
}
7985
if (data.supportedLanguages !== undefined) {
8086
this.supportedLanguages = isNonEmptyArray(data.supportedLanguages) ? data.supportedLanguages : this._modeService.getRegisteredModes();
8187
event.supportedLanguages = true;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,7 @@ export interface INotebookKernelDto2 {
908908
label: string;
909909
detail?: string;
910910
description?: string;
911+
kind?: string;
911912
supportedLanguages?: string[];
912913
supportsInterrupt?: boolean;
913914
supportsExecutionOrder?: boolean;

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,15 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
166166
data.description = value;
167167
_update();
168168
},
169+
get kind() {
170+
checkProposedApiEnabled(extension);
171+
return data.kind ?? '';
172+
},
173+
set kind(value) {
174+
checkProposedApiEnabled(extension);
175+
data.kind = value;
176+
_update();
177+
},
169178
get supportedLanguages() {
170179
return data.supportedLanguages;
171180
},

src/vs/workbench/contrib/interactive/browser/interactiveEditor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ export class InteractiveEditor extends EditorPane {
483483
}
484484

485485
const info = this.#notebookKernelService.getMatchingKernel(notebook);
486-
const selectedOrSuggested = info.selected ?? info.suggested;
486+
const selectedOrSuggested = info.selected ?? info.suggestions[0];
487487

488488
if (selectedOrSuggested) {
489489
const language = selectedOrSuggested.supportedLanguages[0];

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

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6+
import { groupBy } from 'vs/base/common/arrays';
67
import { Disposable, DisposableStore, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
78
import { Schemas } from 'vs/base/common/network';
8-
import { uppercaseFirstLetter } from 'vs/base/common/strings';
9+
import { compareIgnoreCase, uppercaseFirstLetter } from 'vs/base/common/strings';
910
import { HoverProviderRegistry } from 'vs/editor/common/modes';
1011
import * as nls from 'vs/nls';
1112
import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
@@ -14,7 +15,7 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
1415
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
1516
import { ILabelService } from 'vs/platform/label/common/label';
1617
import { ILogService } from 'vs/platform/log/common/log';
17-
import { IQuickInputButton, IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
18+
import { IQuickInputButton, IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/quickinput/common/quickInput';
1819
import { Registry } from 'vs/platform/registry/common/platform';
1920
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
2021
import type { SelectKernelReturnArgs } from 'vs/workbench/api/common/extHostNotebookKernels';
@@ -128,7 +129,7 @@ registerAction2(class extends Action2 {
128129
}
129130

130131
const notebook = editor.textModel;
131-
const { selected, all } = notebookKernelService.getMatchingKernel(notebook);
132+
const { selected, all, suggestions } = notebookKernelService.getMatchingKernel(notebook);
132133

133134
if (selected && controllerId && selected.id === controllerId && ExtensionIdentifier.equals(selected.extension, extensionId)) {
134135
// current kernel is wanted kernel -> done
@@ -156,7 +157,7 @@ registerAction2(class extends Action2 {
156157
iconClass: ThemeIcon.asClassName(configureKernelIcon),
157158
tooltip: nls.localize('notebook.promptKernel.setDefaultTooltip', "Set as default for '{0}' notebooks", editor.textModel.viewType)
158159
};
159-
const picks: (KernelPick | IQuickPickItem)[] = all.map(kernel => {
160+
function toQuickPick(kernel: INotebookKernel) {
160161
const res = <KernelPick>{
161162
kernel,
162163
picked: kernel.id === selected?.id,
@@ -172,16 +173,38 @@ registerAction2(class extends Action2 {
172173
res.description = nls.localize('current2', "{0} - Currently Selected", res.description);
173174
}
174175
}
175-
{ return res; }
176-
});
176+
return res;
177+
}
178+
const quickPickItems: QuickPickInput<IQuickPickItem | KernelPick>[] = [];
177179
if (!all.length) {
178-
picks.push({
180+
quickPickItems.push({
179181
id: 'install',
180182
label: nls.localize('installKernels', "Install kernels from the marketplace"),
181183
});
184+
} else {
185+
// Always display suggested kernels on the top.
186+
if (suggestions.length) {
187+
quickPickItems.push({
188+
type: 'separator',
189+
label: nls.localize('suggestedKernels', "Suggested")
190+
});
191+
quickPickItems.push(...suggestions.map(toQuickPick));
192+
}
193+
194+
// Next display all of the kernels grouped by categories or extensions.
195+
// If we don't have a kind, always display those at the bottom.
196+
const picks = all.filter(item => item !== selected && !suggestions.includes(item)).map(toQuickPick);
197+
const kernelsPerCategory = groupBy(picks, (a, b) => compareIgnoreCase(a.kernel.kind || 'z', b.kernel.kind || 'z'));
198+
kernelsPerCategory.forEach(items => {
199+
quickPickItems.push({
200+
type: 'separator',
201+
label: items[0].kernel.kind || nls.localize('otherKernelKinds', "Other")
202+
});
203+
quickPickItems.push(...items);
204+
});
182205
}
183206

184-
const pick = await quickInputService.pick(picks, {
207+
const pick = await quickInputService.pick(quickPickItems, {
185208
placeHolder: selected
186209
? nls.localize('prompt.placeholder.change', "Change kernel for '{0}'", labelService.getUriLabel(notebook.uri, { relative: true }))
187210
: nls.localize('prompt.placeholder.select', "Select kernel for '{0}'", labelService.getUriLabel(notebook.uri, { relative: true })),
@@ -323,7 +346,8 @@ export class KernelStatus extends Disposable implements IWorkbenchContribution {
323346

324347
this._kernelInfoElement.clear();
325348

326-
let { selected, suggested, all } = this._notebookKernelService.getMatchingKernel(notebook);
349+
let { selected, suggestions, all } = this._notebookKernelService.getMatchingKernel(notebook);
350+
const suggested = suggestions[0];
327351
let isSuggested = false;
328352

329353
if (all.length === 0) {

src/vs/workbench/contrib/notebook/browser/controller/apiActions.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ CommandsRegistry.registerCommand('_resolveNotebookKernels', async (accessor, arg
6969
return kernels.all.map(provider => ({
7070
id: provider.id,
7171
label: provider.label,
72+
kind: provider.kind,
7273
description: provider.description,
7374
detail: provider.detail,
7475
isPreferred: false, // todo@jrieken,@rebornix

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export class NotebookEditorKernelManager extends Disposable {
2525
getSelectedOrSuggestedKernel(notebook: INotebookTextModel): INotebookKernel | undefined {
2626
// returns SELECTED or the ONLY available kernel
2727
const info = this._notebookKernelService.getMatchingKernel(notebook);
28-
return info.selected ?? info.suggested;
28+
return info.selected ?? info.suggestions[0];
2929
}
3030

3131
async executeNotebookCells(notebook: INotebookTextModel, cells: Iterable<ICellViewModel>): Promise<void> {

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -180,15 +180,18 @@ export class NotebookKernelService extends Disposable implements INotebookKernel
180180
}
181181
}
182182

183-
const all = kernels
184-
.sort((a, b) => b.instanceAffinity - a.instanceAffinity || b.typeAffinity - a.typeAffinity || a.score - b.score || a.kernel.label.localeCompare(b.kernel.label))
185-
.map(obj => obj.kernel);
183+
kernels
184+
.sort((a, b) => b.instanceAffinity - a.instanceAffinity || b.typeAffinity - a.typeAffinity || a.score - b.score || a.kernel.label.localeCompare(b.kernel.label));
185+
const all = kernels.map(obj => obj.kernel);
186186

187187
// bound kernel
188188
const selectedId = this._notebookBindings.get(NotebookTextModelLikeId.str(notebook));
189189
const selected = selectedId ? this._kernels.get(selectedId)?.kernel : undefined;
190-
191-
return { all, selected, suggested: all.length === 1 ? all[0] : undefined };
190+
const suggestions = kernels.filter(item => item.instanceAffinity > 1 && item.kernel !== selected).map(item => item.kernel);
191+
if (!suggestions.length && all.length) {
192+
suggestions.push(all[0]);
193+
}
194+
return { all, selected, suggestions };
192195
}
193196

194197
// default kernel for notebookType

src/vs/workbench/contrib/notebook/browser/viewParts/notebookKernelActionViewItem.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export class NotebooKernelActionViewItem extends ActionViewItem {
7272
private _updateActionFromKernelInfo(info: INotebookKernelMatchResult): void {
7373

7474
this._action.enabled = true;
75-
const selectedOrSuggested = info.selected ?? info.suggested;
75+
const selectedOrSuggested = info.selected ?? info.suggestions[0];
7676
if (selectedOrSuggested) {
7777
// selected or suggested kernel
7878
this._action.label = selectedOrSuggested.label;

0 commit comments

Comments
 (0)