@@ -12,7 +12,6 @@ import { ITreeElement } from 'vs/base/browser/ui/tree/tree';
12
12
import { Action } from 'vs/base/common/actions' ;
13
13
import { Delayer , IntervalTimer , ThrottledDelayer , timeout } from 'vs/base/common/async' ;
14
14
import { CancellationToken , CancellationTokenSource } from 'vs/base/common/cancellation' ;
15
- import * as collections from 'vs/base/common/collections' ;
16
15
import { fromNow } from 'vs/base/common/date' ;
17
16
import { isCancellationError } from 'vs/base/common/errors' ;
18
17
import { Emitter , Event } from 'vs/base/common/event' ;
@@ -39,16 +38,16 @@ import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
39
38
import { IEditorMemento , IEditorOpenContext , IEditorPane } from 'vs/workbench/common/editor' ;
40
39
import { SuggestEnabledInput } from 'vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput' ;
41
40
import { SettingsTarget , SettingsTargetsWidget } from 'vs/workbench/contrib/preferences/browser/preferencesWidgets' ;
42
- import { commonlyUsedData , tocData } from 'vs/workbench/contrib/preferences/browser/settingsLayout' ;
41
+ import { getCommonlyUsedData , tocData } from 'vs/workbench/contrib/preferences/browser/settingsLayout' ;
43
42
import { AbstractSettingRenderer , HeightChangeParams , ISettingLinkClickEvent , resolveConfiguredUntrustedSettings , createTocTreeForExtensionSettings , resolveSettingsTree , SettingsTree , SettingTreeRenderers } from 'vs/workbench/contrib/preferences/browser/settingsTree' ;
44
43
import { ISettingsEditorViewState , parseQuery , SearchResultIdx , SearchResultModel , SettingsTreeElement , SettingsTreeGroupChild , SettingsTreeGroupElement , SettingsTreeModel , SettingsTreeSettingElement } from 'vs/workbench/contrib/preferences/browser/settingsTreeModels' ;
45
44
import { createTOCIterator , TOCTree , TOCTreeModel } from 'vs/workbench/contrib/preferences/browser/tocTree' ;
46
- import { CONTEXT_SETTINGS_EDITOR , CONTEXT_SETTINGS_ROW_FOCUS , CONTEXT_SETTINGS_SEARCH_FOCUS , CONTEXT_TOC_ROW_FOCUS , ENABLE_LANGUAGE_FILTER , EXTENSION_SETTING_TAG , FEATURE_SETTING_TAG , ID_SETTING_TAG , IPreferencesSearchService , ISearchProvider , LANGUAGE_SETTING_TAG , MODIFIED_SETTING_TAG , POLICY_SETTING_TAG , REQUIRE_TRUSTED_WORKSPACE_SETTING_TAG , SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS , SETTINGS_EDITOR_COMMAND_SUGGEST_FILTERS , WORKSPACE_TRUST_SETTING_TAG } from 'vs/workbench/contrib/preferences/common/preferences' ;
45
+ import { CONTEXT_SETTINGS_EDITOR , CONTEXT_SETTINGS_ROW_FOCUS , CONTEXT_SETTINGS_SEARCH_FOCUS , CONTEXT_TOC_ROW_FOCUS , ENABLE_LANGUAGE_FILTER , EXTENSION_SETTING_TAG , FEATURE_SETTING_TAG , ID_SETTING_TAG , IPreferencesSearchService , ISearchProvider , LANGUAGE_SETTING_TAG , MODIFIED_SETTING_TAG , POLICY_SETTING_TAG , REQUIRE_TRUSTED_WORKSPACE_SETTING_TAG , SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS , SETTINGS_EDITOR_COMMAND_SUGGEST_FILTERS , WORKSPACE_TRUST_SETTING_TAG , getExperimentalExtensionToggleData } from 'vs/workbench/contrib/preferences/common/preferences' ;
47
46
import { settingsHeaderBorder , settingsSashBorder , settingsTextInputBorder } from 'vs/workbench/contrib/preferences/common/settingsEditorColorRegistry' ;
48
47
import { IEditorGroup , IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService' ;
49
- import { IOpenSettingsOptions , IPreferencesService , ISearchResult , ISettingsEditorModel , ISettingsEditorOptions , SettingMatchType , SettingValueType , validateSettingsEditorOptions } from 'vs/workbench/services/preferences/common/preferences' ;
48
+ import { IOpenSettingsOptions , IPreferencesService , ISearchResult , ISetting , ISettingsEditorModel , ISettingsEditorOptions , ISettingsGroup , SettingMatchType , SettingValueType , validateSettingsEditorOptions } from 'vs/workbench/services/preferences/common/preferences' ;
50
49
import { SettingsEditor2Input } from 'vs/workbench/services/preferences/common/preferencesEditorInput' ;
51
- import { Settings2EditorModel } from 'vs/workbench/services/preferences/common/preferencesModels' ;
50
+ import { Settings2EditorModel , nullRange } from 'vs/workbench/services/preferences/common/preferencesModels' ;
52
51
import { IUserDataSyncWorkbenchService } from 'vs/workbench/services/userDataSync/common/userDataSync' ;
53
52
import { preferencesClearInputIcon , preferencesFilterIcon } from 'vs/workbench/contrib/preferences/browser/preferencesIcons' ;
54
53
import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust' ;
@@ -59,11 +58,14 @@ import { Orientation, Sizing, SplitView } from 'vs/base/browser/ui/splitview/spl
59
58
import { Color } from 'vs/base/common/color' ;
60
59
import { ILanguageService } from 'vs/editor/common/languages/language' ;
61
60
import { SettingsSearchFilterDropdownMenuActionViewItem } from 'vs/workbench/contrib/preferences/browser/settingsSearchMenu' ;
62
- import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement' ;
61
+ import { IExtensionGalleryService , IExtensionManagementService , IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement' ;
63
62
import { ISettingOverrideClickEvent } from 'vs/workbench/contrib/preferences/browser/settingsEditorSettingIndicators' ;
64
63
import { ConfigurationScope , Extensions , IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry' ;
65
64
import { Registry } from 'vs/platform/registry/common/platform' ;
66
65
import { defaultButtonStyles } from 'vs/platform/theme/browser/defaultStyles' ;
66
+ import { IWorkbenchAssignmentService } from 'vs/workbench/services/assignment/common/assignmentService' ;
67
+ import { IProductService } from 'vs/platform/product/common/productService' ;
68
+ import { IEnvironmentService } from 'vs/platform/environment/common/environment' ;
67
69
68
70
export const enum SettingsFocusContext {
69
71
Search ,
@@ -229,7 +231,11 @@ export class SettingsEditor2 extends EditorPane {
229
231
@IWorkspaceTrustManagementService private readonly workspaceTrustManagementService : IWorkspaceTrustManagementService ,
230
232
@IExtensionService private readonly extensionService : IExtensionService ,
231
233
@ILanguageService private readonly languageService : ILanguageService ,
232
- @IExtensionManagementService extensionManagementService : IExtensionManagementService
234
+ @IExtensionManagementService extensionManagementService : IExtensionManagementService ,
235
+ @IWorkbenchAssignmentService private readonly workbenchAssignmentService : IWorkbenchAssignmentService ,
236
+ @IProductService private readonly productService : IProductService ,
237
+ @IEnvironmentService private readonly environmentService : IEnvironmentService ,
238
+ @IExtensionGalleryService private readonly extensionGalleryService : IExtensionGalleryService ,
233
239
) {
234
240
super ( SettingsEditor2 . ID , telemetryService , themeService , storageService ) ;
235
241
this . delayedFilterLogging = new Delayer < void > ( 1000 ) ;
@@ -1189,14 +1195,49 @@ export class SettingsEditor2 extends EditorPane {
1189
1195
} ) ;
1190
1196
}
1191
1197
1198
+ private addOrRemoveManageExtensionSetting ( setting : ISetting , extension : IGalleryExtension , groups : ISettingsGroup [ ] ) : ISettingsGroup | undefined {
1199
+ const extensionId = setting . extensionId ! ;
1200
+ const matchingGroups = groups . filter ( g => g . extensionInfo ?. id . toLowerCase ( ) === extensionId . toLowerCase ( ) ) ;
1201
+ if ( ! matchingGroups . length ) {
1202
+ const newGroup : ISettingsGroup = {
1203
+ sections : [ {
1204
+ settings : [ setting ] ,
1205
+ } ] ,
1206
+ id : extensionId ,
1207
+ title : setting . extensionGroupTitle ! ,
1208
+ titleRange : nullRange ,
1209
+ range : nullRange ,
1210
+ extensionInfo : {
1211
+ id : extensionId ,
1212
+ displayName : extension ?. displayName ,
1213
+ }
1214
+ } ;
1215
+ groups . push ( newGroup ) ;
1216
+ return newGroup ;
1217
+ } else if ( matchingGroups . length >= 2 ) {
1218
+ // Remove the group with the manage extension setting.
1219
+ const matchingGroupIndex = matchingGroups . findIndex ( group =>
1220
+ group . sections . length === 1 && group . sections [ 0 ] . settings . length === 1 && group . sections [ 0 ] . settings [ 0 ] . extensionId ) ;
1221
+ if ( matchingGroupIndex !== - 1 ) {
1222
+ groups . splice ( matchingGroupIndex , 1 ) ;
1223
+ }
1224
+ }
1225
+ return undefined ;
1226
+ }
1227
+
1192
1228
private async onConfigUpdate ( keys ?: ReadonlySet < string > , forceRefresh = false , schemaChange = false ) : Promise < void > {
1193
1229
if ( keys && this . settingsTreeModel ) {
1194
1230
return this . updateElementsByKey ( keys ) ;
1195
1231
}
1196
1232
1233
+ if ( ! this . defaultSettingsEditorModel ) {
1234
+ return ;
1235
+ }
1236
+
1197
1237
const groups = this . defaultSettingsEditorModel . settingsGroups . slice ( 1 ) ; // Without commonlyUsed
1198
- const dividedGroups = collections . groupBy ( groups , g => g . extensionInfo ? 'extension' : 'core' ) ;
1199
- const settingsResult = resolveSettingsTree ( tocData , dividedGroups . core , this . logService ) ;
1238
+
1239
+ const coreSettings = groups . filter ( g => ! g . extensionInfo ) ;
1240
+ const settingsResult = resolveSettingsTree ( tocData , coreSettings , this . logService ) ;
1200
1241
const resolvedSettingsRoot = settingsResult . tree ;
1201
1242
1202
1243
// Warn for settings not included in layout
@@ -1210,10 +1251,61 @@ export class SettingsEditor2 extends EditorPane {
1210
1251
this . hasWarnedMissingSettings = true ;
1211
1252
}
1212
1253
1213
- const commonlyUsed = resolveSettingsTree ( commonlyUsedData , dividedGroups . core , this . logService ) ;
1254
+ const additionalGroups : ISettingsGroup [ ] = [ ] ;
1255
+ const toggleData = await getExperimentalExtensionToggleData ( this . workbenchAssignmentService , this . environmentService , this . productService ) ;
1256
+ if ( toggleData && groups . filter ( g => g . extensionInfo ) . length ) {
1257
+ for ( const key in toggleData . settingsEditorRecommendedExtensions ) {
1258
+ const prerelease = toggleData . settingsEditorRecommendedExtensions [ key ] . onSettingsEditorOpen ! . prerelease ;
1259
+
1260
+ const extensionId = ( typeof prerelease === 'string' && this . productService . quality !== 'stable' ) ? prerelease : key ;
1261
+ const [ extension ] = await this . extensionGalleryService . getExtensions ( [ { id : extensionId } ] , CancellationToken . None ) ;
1262
+ if ( ! extension ) {
1263
+ continue ;
1264
+ }
1265
+
1266
+ let groupTitle : string | undefined ;
1267
+ const manifest = await this . extensionGalleryService . getManifest ( extension , CancellationToken . None ) ;
1268
+ const contributesConfiguration = manifest ?. contributes ?. configuration ;
1269
+ if ( ! Array . isArray ( contributesConfiguration ) ) {
1270
+ groupTitle = contributesConfiguration ?. title ;
1271
+ } else if ( contributesConfiguration . length === 1 ) {
1272
+ groupTitle = contributesConfiguration [ 0 ] . title ;
1273
+ }
1274
+
1275
+ const extensionName = extension ?. displayName ?? extension ?. name ?? extensionId ;
1276
+ const settingKey = `${ key } .manageExtension` ;
1277
+ const setting : ISetting = {
1278
+ range : nullRange ,
1279
+ key : settingKey ,
1280
+ keyRange : nullRange ,
1281
+ value : null ,
1282
+ valueRange : nullRange ,
1283
+ description : [ extension ?. description || '' ] ,
1284
+ descriptionIsMarkdown : false ,
1285
+ descriptionRanges : [ ] ,
1286
+ title : localize ( 'manageExtension' , "Manage {0}" , extensionName ) ,
1287
+ scope : ConfigurationScope . WINDOW ,
1288
+ type : 'null' ,
1289
+ extensionId : extensionId ,
1290
+ extensionGroupTitle : groupTitle ?? extensionName
1291
+ } ;
1292
+ const additionalGroup = this . addOrRemoveManageExtensionSetting ( setting , extension , groups ) ;
1293
+ if ( additionalGroup ) {
1294
+ additionalGroups . push ( additionalGroup ) ;
1295
+ }
1296
+ }
1297
+ }
1298
+
1299
+ resolvedSettingsRoot . children ! . push ( await createTocTreeForExtensionSettings ( this . extensionService , groups . filter ( g => g . extensionInfo ) ) ) ;
1300
+
1301
+ const commonlyUsedDataToUse = await getCommonlyUsedData ( this . workbenchAssignmentService , this . environmentService , this . productService ) ;
1302
+ const commonlyUsed = resolveSettingsTree ( commonlyUsedDataToUse , groups , this . logService ) ;
1214
1303
resolvedSettingsRoot . children ! . unshift ( commonlyUsed . tree ) ;
1215
1304
1216
- resolvedSettingsRoot . children ! . push ( await createTocTreeForExtensionSettings ( this . extensionService , dividedGroups . extension || [ ] ) ) ;
1305
+ if ( toggleData ) {
1306
+ // Add the additional groups to the model to help with searching.
1307
+ this . defaultSettingsEditorModel . setAdditionalGroups ( additionalGroups ) ;
1308
+ }
1217
1309
1218
1310
if ( ! this . workspaceTrustManagementService . isWorkspaceTrusted ( ) && ( this . viewState . settingsTarget instanceof URI || this . viewState . settingsTarget === ConfigurationTarget . WORKSPACE ) ) {
1219
1311
const configuredUntrustedWorkspaceSettings = resolveConfiguredUntrustedSettings ( groups , this . viewState . settingsTarget , this . viewState . languageFilter , this . configurationService ) ;
0 commit comments