Skip to content

Commit 585350e

Browse files
authored
Merge pull request microsoft#165947 from microsoft/rebornix/stuck-worm
Kernel picker respond to kernel and action changes
2 parents 3c2bd3c + 5f1f40b commit 585350e

File tree

1 file changed

+127
-51
lines changed

1 file changed

+127
-51
lines changed

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

Lines changed: 127 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@
66
import { groupBy } from 'vs/base/common/arrays';
77
import { CancellationToken } from 'vs/base/common/cancellation';
88
import { Codicon } from 'vs/base/common/codicons';
9+
import { Event } from 'vs/base/common/event';
910
import { Disposable, DisposableStore, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
1011
import { Schemas } from 'vs/base/common/network';
1112
import { compareIgnoreCase, uppercaseFirstLetter } from 'vs/base/common/strings';
1213
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
1314
import * as nls from 'vs/nls';
1415
import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
15-
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
16+
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
1617
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
1718
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
1819
import { ILabelService } from 'vs/platform/label/common/label';
@@ -32,13 +33,23 @@ import { selectKernelIcon } from 'vs/workbench/contrib/notebook/browser/notebook
3233
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
3334
import { NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
3435
import { NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_KERNEL_COUNT } from 'vs/workbench/contrib/notebook/common/notebookContextKeys';
35-
import { INotebookKernel, INotebookKernelService, ISourceAction } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
36+
import { INotebookKernel, INotebookKernelMatchResult, INotebookKernelService, ISourceAction } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
3637
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
3738
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
3839
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
3940
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
4041
import { IStatusbarEntry, IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment } from 'vs/workbench/services/statusbar/browser/statusbar';
4142

43+
type KernelPick = IQuickPickItem & { kernel: INotebookKernel };
44+
function isKernelPick(item: QuickPickInput<IQuickPickItem>): item is KernelPick {
45+
return 'kernel' in item;
46+
}
47+
type SourcePick = IQuickPickItem & { action: ISourceAction };
48+
function isSourcePick(item: QuickPickInput<IQuickPickItem>): item is SourcePick {
49+
return 'action' in item;
50+
}
51+
type KernelQuickPickItem = IQuickPickItem | KernelPick | SourcePick;
52+
4253
registerAction2(class extends Action2 {
4354
constructor() {
4455
super({
@@ -138,7 +149,9 @@ registerAction2(class extends Action2 {
138149
}
139150

140151
const notebook = editor.textModel;
141-
const { selected, all, suggestions, hidden } = notebookKernelService.getMatchingKernel(notebook);
152+
const scopedContextKeyService = editor.scopedContextKeyService;
153+
const matchResult = notebookKernelService.getMatchingKernel(notebook);
154+
const { selected, all } = matchResult;
142155

143156
if (selected && controllerId && selected.id === controllerId && ExtensionIdentifier.equals(selected.extension, extensionId)) {
144157
// current kernel is wanted kernel -> done
@@ -165,8 +178,109 @@ registerAction2(class extends Action2 {
165178
return true;
166179
}
167180

168-
type KernelPick = IQuickPickItem & { kernel: INotebookKernel };
169-
type SourcePick = IQuickPickItem & { action: ISourceAction };
181+
const quickPick = quickInputService.createQuickPick<KernelQuickPickItem>();
182+
const quickPickItemSuggestions = this._getKernelPickerQuickPickItems(notebook, matchResult, notebookKernelService, scopedContextKeyService);
183+
let suggestedExtension = quickPickItemSuggestions.suggestedExtension;
184+
quickPick.items = quickPickItemSuggestions.quickPickItems;
185+
quickPick.canSelectMany = false;
186+
quickPick.placeholder = selected
187+
? nls.localize('prompt.placeholder.change', "Change kernel for '{0}'", labelService.getUriLabel(notebook.uri, { relative: true }))
188+
: nls.localize('prompt.placeholder.select', "Select kernel for '{0}'", labelService.getUriLabel(notebook.uri, { relative: true }));
189+
190+
const kernelChangeEventListener = Event.any(
191+
notebookKernelService.onDidChangeSourceActions,
192+
notebookKernelService.onDidAddKernel,
193+
notebookKernelService.onDidRemoveKernel,
194+
notebookKernelService.onDidChangeNotebookAffinity
195+
)(() => {
196+
const currentActiveItems = quickPick.activeItems;
197+
const matchResult = notebookKernelService.getMatchingKernel(notebook);
198+
const quickPickItemSuggestions = this._getKernelPickerQuickPickItems(notebook, matchResult, notebookKernelService, scopedContextKeyService);
199+
suggestedExtension = quickPickItemSuggestions.suggestedExtension;
200+
quickPick.keepScrollPosition = true;
201+
202+
// recalcuate active items
203+
const activeItems: KernelQuickPickItem[] = [];
204+
for (const item of currentActiveItems) {
205+
if (isKernelPick(item)) {
206+
const kernelId = item.kernel.id;
207+
const sameItem = quickPickItemSuggestions.quickPickItems.find(pi => isKernelPick(pi) && pi.kernel.id === kernelId) as KernelPick | undefined;
208+
if (sameItem) {
209+
activeItems.push(sameItem);
210+
}
211+
} else if (isSourcePick(item)) {
212+
const sameItem = quickPickItemSuggestions.quickPickItems.find(pi => isSourcePick(pi) && pi.action.action.id === item.action.action.id) as SourcePick | undefined;
213+
if (sameItem) {
214+
activeItems.push(sameItem);
215+
}
216+
}
217+
}
218+
219+
quickPick.items = quickPickItemSuggestions.quickPickItems;
220+
quickPick.activeItems = activeItems;
221+
});
222+
223+
const pick = await new Promise<KernelQuickPickItem>((resolve, reject) => {
224+
quickPick.onDidAccept(() => {
225+
const item = quickPick.selectedItems[0];
226+
if (item) {
227+
resolve(item);
228+
} else {
229+
reject();
230+
}
231+
232+
quickPick.hide();
233+
});
234+
235+
quickPick.onDidHide(() => () => {
236+
kernelChangeEventListener.dispose();
237+
quickPick.dispose();
238+
reject();
239+
});
240+
quickPick.show();
241+
});
242+
243+
if (pick) {
244+
if (isKernelPick(pick)) {
245+
newKernel = pick.kernel;
246+
notebookKernelService.selectKernelForNotebook(newKernel, notebook);
247+
return true;
248+
}
249+
250+
// actions
251+
if (pick.id === 'install') {
252+
await this._showKernelExtension(
253+
paneCompositeService,
254+
extensionWorkbenchService,
255+
extensionHostService,
256+
notebook.viewType
257+
);
258+
// suggestedExtension must be defined for this option to be shown, but still check to make TS happy
259+
} else if (pick.id === 'installSuggested' && suggestedExtension) {
260+
await this._showKernelExtension(
261+
paneCompositeService,
262+
extensionWorkbenchService,
263+
extensionHostService,
264+
notebook.viewType,
265+
suggestedExtension.extensionId,
266+
productService.quality !== 'stable'
267+
);
268+
} else if (isSourcePick(pick)) {
269+
// selected explicilty, it should trigger the execution?
270+
pick.action.runAction();
271+
}
272+
}
273+
274+
return false;
275+
}
276+
277+
private _getKernelPickerQuickPickItems(
278+
notebookTextModel: NotebookTextModel,
279+
matchResult: INotebookKernelMatchResult,
280+
notebookKernelService: INotebookKernelService,
281+
scopedContextKeyService: IContextKeyService
282+
): { quickPickItems: QuickPickInput<KernelQuickPickItem>[]; suggestedExtension: INotebookExtensionRecommendation | undefined } {
283+
const { selected, all, suggestions, hidden } = matchResult;
170284

171285
function toQuickPick(kernel: INotebookKernel) {
172286
const res = <KernelPick>{
@@ -185,7 +299,7 @@ registerAction2(class extends Action2 {
185299
}
186300
return res;
187301
}
188-
const quickPickItems: QuickPickInput<IQuickPickItem | KernelPick | SourcePick>[] = [];
302+
const quickPickItems: QuickPickInput<KernelQuickPickItem>[] = [];
189303
if (all.length) {
190304
// Always display suggested kernels on the top.
191305
if (suggestions.length) {
@@ -209,7 +323,7 @@ registerAction2(class extends Action2 {
209323
});
210324
}
211325

212-
const sourceActions = notebookKernelService.getSourceActions(notebook, editor.scopedContextKeyService);
326+
const sourceActions = notebookKernelService.getSourceActions(notebookTextModel, scopedContextKeyService);
213327
if (sourceActions.length) {
214328
quickPickItems.push({
215329
type: 'separator',
@@ -229,11 +343,8 @@ registerAction2(class extends Action2 {
229343

230344
let suggestedExtension: INotebookExtensionRecommendation | undefined;
231345
if (!all.length && !sourceActions.length) {
232-
const activeNotebookModel = getNotebookEditorFromEditorPane(editorService.activeEditorPane)?.textModel;
233-
if (activeNotebookModel) {
234-
const language = this.getSuggestedLanguage(activeNotebookModel);
235-
suggestedExtension = language ? this.getSuggestedKernelFromLanguage(activeNotebookModel.viewType, language) : undefined;
236-
}
346+
const language = this.getSuggestedLanguage(notebookTextModel);
347+
suggestedExtension = language ? this.getSuggestedKernelFromLanguage(notebookTextModel.viewType, language) : undefined;
237348
if (suggestedExtension) {
238349
// We have a suggested kernel, show an option to install it
239350
quickPickItems.push({
@@ -249,45 +360,10 @@ registerAction2(class extends Action2 {
249360
});
250361
}
251362

252-
const pick = await quickInputService.pick(quickPickItems, {
253-
placeHolder: selected
254-
? nls.localize('prompt.placeholder.change', "Change kernel for '{0}'", labelService.getUriLabel(notebook.uri, { relative: true }))
255-
: nls.localize('prompt.placeholder.select', "Select kernel for '{0}'", labelService.getUriLabel(notebook.uri, { relative: true }))
256-
});
257-
258-
if (pick) {
259-
if ('kernel' in pick) {
260-
newKernel = pick.kernel;
261-
notebookKernelService.selectKernelForNotebook(newKernel, notebook);
262-
return true;
263-
}
264-
265-
// actions
266-
267-
if (pick.id === 'install') {
268-
await this._showKernelExtension(
269-
paneCompositeService,
270-
extensionWorkbenchService,
271-
extensionHostService,
272-
notebook.viewType
273-
);
274-
// suggestedExtension must be defined for this option to be shown, but still check to make TS happy
275-
} else if (pick.id === 'installSuggested' && suggestedExtension) {
276-
await this._showKernelExtension(
277-
paneCompositeService,
278-
extensionWorkbenchService,
279-
extensionHostService,
280-
notebook.viewType,
281-
suggestedExtension.extensionId,
282-
productService.quality !== 'stable'
283-
);
284-
} else if ('action' in pick) {
285-
// selected explicilty, it should trigger the execution?
286-
pick.action.runAction();
287-
}
288-
}
289-
290-
return false;
363+
return {
364+
quickPickItems,
365+
suggestedExtension
366+
};
291367
}
292368

293369
/**

0 commit comments

Comments
 (0)