6
6
import { groupBy } from 'vs/base/common/arrays' ;
7
7
import { CancellationToken } from 'vs/base/common/cancellation' ;
8
8
import { Codicon } from 'vs/base/common/codicons' ;
9
+ import { Event } from 'vs/base/common/event' ;
9
10
import { Disposable , DisposableStore , IDisposable , MutableDisposable } from 'vs/base/common/lifecycle' ;
10
11
import { Schemas } from 'vs/base/common/network' ;
11
12
import { compareIgnoreCase , uppercaseFirstLetter } from 'vs/base/common/strings' ;
12
13
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures' ;
13
14
import * as nls from 'vs/nls' ;
14
15
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' ;
16
17
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions' ;
17
18
import { IInstantiationService , ServicesAccessor } from 'vs/platform/instantiation/common/instantiation' ;
18
19
import { ILabelService } from 'vs/platform/label/common/label' ;
@@ -32,13 +33,23 @@ import { selectKernelIcon } from 'vs/workbench/contrib/notebook/browser/notebook
32
33
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel' ;
33
34
import { NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon' ;
34
35
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' ;
36
37
import { IEditorService } from 'vs/workbench/services/editor/common/editorService' ;
37
38
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions' ;
38
39
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle' ;
39
40
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite' ;
40
41
import { IStatusbarEntry , IStatusbarEntryAccessor , IStatusbarService , StatusbarAlignment } from 'vs/workbench/services/statusbar/browser/statusbar' ;
41
42
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
+
42
53
registerAction2 ( class extends Action2 {
43
54
constructor ( ) {
44
55
super ( {
@@ -138,7 +149,9 @@ registerAction2(class extends Action2 {
138
149
}
139
150
140
151
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 ;
142
155
143
156
if ( selected && controllerId && selected . id === controllerId && ExtensionIdentifier . equals ( selected . extension , extensionId ) ) {
144
157
// current kernel is wanted kernel -> done
@@ -165,8 +178,109 @@ registerAction2(class extends Action2 {
165
178
return true ;
166
179
}
167
180
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 ;
170
284
171
285
function toQuickPick ( kernel : INotebookKernel ) {
172
286
const res = < KernelPick > {
@@ -185,7 +299,7 @@ registerAction2(class extends Action2 {
185
299
}
186
300
return res ;
187
301
}
188
- const quickPickItems : QuickPickInput < IQuickPickItem | KernelPick | SourcePick > [ ] = [ ] ;
302
+ const quickPickItems : QuickPickInput < KernelQuickPickItem > [ ] = [ ] ;
189
303
if ( all . length ) {
190
304
// Always display suggested kernels on the top.
191
305
if ( suggestions . length ) {
@@ -209,7 +323,7 @@ registerAction2(class extends Action2 {
209
323
} ) ;
210
324
}
211
325
212
- const sourceActions = notebookKernelService . getSourceActions ( notebook , editor . scopedContextKeyService ) ;
326
+ const sourceActions = notebookKernelService . getSourceActions ( notebookTextModel , scopedContextKeyService ) ;
213
327
if ( sourceActions . length ) {
214
328
quickPickItems . push ( {
215
329
type : 'separator' ,
@@ -229,11 +343,8 @@ registerAction2(class extends Action2 {
229
343
230
344
let suggestedExtension : INotebookExtensionRecommendation | undefined ;
231
345
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 ;
237
348
if ( suggestedExtension ) {
238
349
// We have a suggested kernel, show an option to install it
239
350
quickPickItems . push ( {
@@ -249,45 +360,10 @@ registerAction2(class extends Action2 {
249
360
} ) ;
250
361
}
251
362
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
+ } ;
291
367
}
292
368
293
369
/**
0 commit comments