mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 21:09:43 +00:00
Merge branch 'main' into aamunger/scratchpadHotExit
This commit is contained in:
commit
df4e852295
58
.configurations/configuration.dsc.yaml
Normal file
58
.configurations/configuration.dsc.yaml
Normal file
|
@ -0,0 +1,58 @@
|
|||
# yaml-language-server: $schema=https://aka.ms/configuration-dsc-schema/0.2
|
||||
# Reference: https://github.com/microsoft/vscode/wiki/How-to-Contribute
|
||||
properties:
|
||||
resources:
|
||||
- resource: Microsoft.WinGet.DSC/WinGetPackage
|
||||
directives:
|
||||
description: Install Git
|
||||
allowPrerelease: true
|
||||
settings:
|
||||
id: Git.Git
|
||||
source: winget
|
||||
- resource: Microsoft.WinGet.DSC/WinGetPackage
|
||||
id: npm
|
||||
directives:
|
||||
description: Install NodeJS version >=16.17.x and <17
|
||||
allowPrerelease: true
|
||||
settings:
|
||||
id: OpenJS.NodeJS.LTS
|
||||
version: "16.20.0"
|
||||
source: winget
|
||||
- resource: NpmDsc/NpmPackage
|
||||
id: yarn
|
||||
dependsOn:
|
||||
- npm
|
||||
directives:
|
||||
description: Install Yarn
|
||||
allowPrerelease: true
|
||||
settings:
|
||||
Name: 'yarn'
|
||||
Global: true
|
||||
- resource: Microsoft.WinGet.DSC/WinGetPackage
|
||||
directives:
|
||||
description: Install Python 3.10
|
||||
allowPrerelease: true
|
||||
settings:
|
||||
id: Python.Python.3.10
|
||||
source: winget
|
||||
- resource: Microsoft.WinGet.DSC/WinGetPackage
|
||||
id: vsPackage
|
||||
directives:
|
||||
description: Install Visual Studio 2022 (any edition is OK)
|
||||
allowPrerelease: true
|
||||
settings:
|
||||
id: Microsoft.VisualStudio.2022.BuildTools
|
||||
source: winget
|
||||
- resource: Microsoft.VisualStudio.DSC/VSComponents
|
||||
dependsOn:
|
||||
- vsPackage
|
||||
directives:
|
||||
description: Install required VS workloads
|
||||
allowPrerelease: true
|
||||
settings:
|
||||
productId: Microsoft.VisualStudio.Product.BuildTools
|
||||
channelId: VisualStudio.17.Release
|
||||
includeRecommended: true
|
||||
components:
|
||||
- Microsoft.VisualStudio.Workload.VCTools
|
||||
configurationVersion: 0.2.0
|
|
@ -290,6 +290,10 @@
|
|||
"name": "vs/workbench/contrib/welcomeWalkthrough",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/contrib/welcomeDialog",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/contrib/outline",
|
||||
"project": "vscode-workbench"
|
||||
|
|
|
@ -742,7 +742,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi
|
|||
return label;
|
||||
},
|
||||
getWidgetAriaLabel: () => localize({ key: 'selectBox', comment: ['Behave like native select dropdown element.'] }, "Select Box"),
|
||||
getRole: () => 'option',
|
||||
getRole: () => isMacintosh ? '' : 'option',
|
||||
getWidgetRole: () => 'listbox'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -191,6 +191,8 @@ export interface IProductConfiguration {
|
|||
readonly 'editSessions.store'?: Omit<ConfigurationSyncStore, 'insidersUrl' | 'stableUrl'>;
|
||||
readonly darwinUniversalAssetId?: string;
|
||||
readonly profileTemplatesUrl?: string;
|
||||
|
||||
readonly commonlyUsedSettings?: string[];
|
||||
}
|
||||
|
||||
export interface ITunnelApplicationConfig {
|
||||
|
@ -201,6 +203,11 @@ export interface ITunnelApplicationConfig {
|
|||
|
||||
export interface IExtensionRecommendations {
|
||||
readonly onFileOpen: IFileOpenCondition[];
|
||||
readonly onSettingsEditorOpen?: ISettingsEditorOpenCondition;
|
||||
}
|
||||
|
||||
export interface ISettingsEditorOpenCondition {
|
||||
readonly prerelease: boolean | string;
|
||||
}
|
||||
|
||||
export interface IExtensionRecommendationCondition {
|
||||
|
|
|
@ -343,7 +343,7 @@ export interface IWorkbenchConstructionOptions {
|
|||
readonly initialColorTheme?: IInitialColorTheme;
|
||||
|
||||
/**
|
||||
* Welcome view dialog on first launch. Can be dismissed by the user.
|
||||
* Welcome dialog. Can be dismissed by the user.
|
||||
*/
|
||||
readonly welcomeDialog?: IWelcomeDialog;
|
||||
|
||||
|
@ -639,14 +639,24 @@ export interface IWelcomeDialog {
|
|||
buttonText: string;
|
||||
|
||||
/**
|
||||
* Message text and icon for the welcome dialog.
|
||||
* Button command to execute from the welcome dialog.
|
||||
*/
|
||||
messages: { message: string; icon: string }[];
|
||||
buttonCommand: string;
|
||||
|
||||
/**
|
||||
* Optional action to appear as links at the bottom of the welcome dialog.
|
||||
* Message text for the welcome dialog.
|
||||
*/
|
||||
action?: IWelcomeLinkAction;
|
||||
message: string;
|
||||
|
||||
/**
|
||||
* Context key expression to control the visibility of the welcome dialog.
|
||||
*/
|
||||
when: string;
|
||||
|
||||
/**
|
||||
* Media to include in the welcome dialog.
|
||||
*/
|
||||
media: { altText: string; path: string };
|
||||
}
|
||||
|
||||
export interface IDefaultView {
|
||||
|
|
|
@ -11,7 +11,8 @@ export const enum AccessibilityVerbositySettingId {
|
|||
Terminal = 'accessibility.verbosity.terminal',
|
||||
DiffEditor = 'accessibility.verbosity.diff-editor',
|
||||
Chat = 'accessibility.verbosity.chat',
|
||||
InteractiveEditor = 'accessibility.verbosity.interactiveEditor'
|
||||
InteractiveEditor = 'accessibility.verbosity.interactiveEditor',
|
||||
KeybindingsEditor = 'accessibility.verbosity.keybindingsEditor'
|
||||
}
|
||||
|
||||
const configuration: IConfigurationNode = {
|
||||
|
@ -42,6 +43,12 @@ const configuration: IConfigurationNode = {
|
|||
type: 'boolean',
|
||||
default: true,
|
||||
tags: ['accessibility']
|
||||
},
|
||||
[AccessibilityVerbositySettingId.KeybindingsEditor]: {
|
||||
description: localize('verbosity.keybindingsEditor.description', 'Provide information about how to change a keybinding in the keybindings editor when a row is focused'),
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
tags: ['accessibility']
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -54,6 +54,8 @@ import { isString } from 'vs/base/common/types';
|
|||
import { SuggestEnabledInput } from 'vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput';
|
||||
import { CompletionItemKind } from 'vs/editor/common/languages';
|
||||
import { settingsTextInputBorder } from 'vs/workbench/contrib/preferences/common/settingsEditorColorRegistry';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution';
|
||||
|
||||
const $ = DOM.$;
|
||||
|
||||
|
@ -112,7 +114,8 @@ export class KeybindingsEditor extends EditorPane implements IKeybindingsEditorP
|
|||
@IClipboardService private readonly clipboardService: IClipboardService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IStorageService storageService: IStorageService
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService
|
||||
) {
|
||||
super(KeybindingsEditor.ID, telemetryService, themeService, storageService);
|
||||
this.delayedFiltering = new Delayer<void>(300);
|
||||
|
@ -474,7 +477,7 @@ export class KeybindingsEditor extends EditorPane implements IKeybindingsEditorP
|
|||
{
|
||||
identityProvider: { getId: (e: IKeybindingItemEntry) => e.id },
|
||||
horizontalScrolling: false,
|
||||
accessibilityProvider: new AccessibilityProvider(),
|
||||
accessibilityProvider: new AccessibilityProvider(this.configurationService),
|
||||
keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IKeybindingItemEntry) => e.keybindingItem.commandLabel || e.keybindingItem.command },
|
||||
overrideStyles: {
|
||||
listBackground: editorBackground
|
||||
|
@ -1178,6 +1181,8 @@ class WhenColumnRenderer implements ITableRenderer<IKeybindingItemEntry, IWhenCo
|
|||
|
||||
class AccessibilityProvider implements IListAccessibilityProvider<IKeybindingItemEntry> {
|
||||
|
||||
constructor(private readonly configurationService: IConfigurationService) { }
|
||||
|
||||
getWidgetAriaLabel(): string {
|
||||
return localize('keybindingsLabel', "Keybindings");
|
||||
}
|
||||
|
@ -1187,6 +1192,7 @@ class AccessibilityProvider implements IListAccessibilityProvider<IKeybindingIte
|
|||
ariaLabel += ', ' + (keybindingItemEntry.keybindingItem.keybinding?.getAriaLabel() || localize('noKeybinding', "No Keybinding assigned."));
|
||||
ariaLabel += ', ' + keybindingItemEntry.keybindingItem.when ? keybindingItemEntry.keybindingItem.when : localize('noWhen', "No when context.");
|
||||
ariaLabel += ', ' + (isString(keybindingItemEntry.keybindingItem.source) ? keybindingItemEntry.keybindingItem.source : keybindingItemEntry.keybindingItem.source.description ?? keybindingItemEntry.keybindingItem.source.identifier.value);
|
||||
ariaLabel += this.configurationService.getValue(AccessibilityVerbositySettingId.KeybindingsEditor) ? localize('keyboard shortcuts arial label', ", use space or enter to change the keybinding.") : '';
|
||||
return ariaLabel;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -160,6 +160,11 @@
|
|||
color: var(--vscode-settings-headerForeground);
|
||||
}
|
||||
|
||||
.settings-editor > .settings-body .settings-tree-container .setting-item-extension-toggle .setting-item-extension-toggle-button {
|
||||
display: block;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.settings-editor.no-results > .settings-body .settings-toc-container,
|
||||
.settings-editor.no-results > .settings-body .settings-tree-container {
|
||||
display: none;
|
||||
|
@ -481,6 +486,7 @@
|
|||
.settings-editor > .settings-body .settings-tree-container .setting-item.setting-item-number input[type=number] {
|
||||
/* Hide arrow button that shows in type=number fields */
|
||||
-moz-appearance: textfield !important;
|
||||
appearance: textfield !important;
|
||||
}
|
||||
|
||||
.settings-editor > .settings-body .settings-tree-container .setting-item-contents .setting-item-markdown * {
|
||||
|
@ -556,7 +562,7 @@
|
|||
padding: 0px;
|
||||
}
|
||||
|
||||
.settings-editor > .settings-body .settings-tree-container .setting-item-bool .setting-value-checkbox.codicon:not(.checked)::before {
|
||||
.settings-editor > .settings-body .settings-tree-container .setting-item-bool .setting-value-checkbox.codicon:not(.checked)::before {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@ import { ITreeElement } from 'vs/base/browser/ui/tree/tree';
|
|||
import { Action } from 'vs/base/common/actions';
|
||||
import { Delayer, IntervalTimer, ThrottledDelayer, timeout } from 'vs/base/common/async';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import * as collections from 'vs/base/common/collections';
|
||||
import { fromNow } from 'vs/base/common/date';
|
||||
import { isCancellationError } from 'vs/base/common/errors';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
|
@ -39,16 +38,16 @@ import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
|
|||
import { IEditorMemento, IEditorOpenContext, IEditorPane } from 'vs/workbench/common/editor';
|
||||
import { SuggestEnabledInput } from 'vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput';
|
||||
import { SettingsTarget, SettingsTargetsWidget } from 'vs/workbench/contrib/preferences/browser/preferencesWidgets';
|
||||
import { commonlyUsedData, tocData } from 'vs/workbench/contrib/preferences/browser/settingsLayout';
|
||||
import { getCommonlyUsedData, tocData } from 'vs/workbench/contrib/preferences/browser/settingsLayout';
|
||||
import { AbstractSettingRenderer, HeightChangeParams, ISettingLinkClickEvent, resolveConfiguredUntrustedSettings, createTocTreeForExtensionSettings, resolveSettingsTree, SettingsTree, SettingTreeRenderers } from 'vs/workbench/contrib/preferences/browser/settingsTree';
|
||||
import { ISettingsEditorViewState, parseQuery, SearchResultIdx, SearchResultModel, SettingsTreeElement, SettingsTreeGroupChild, SettingsTreeGroupElement, SettingsTreeModel, SettingsTreeSettingElement } from 'vs/workbench/contrib/preferences/browser/settingsTreeModels';
|
||||
import { createTOCIterator, TOCTree, TOCTreeModel } from 'vs/workbench/contrib/preferences/browser/tocTree';
|
||||
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';
|
||||
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';
|
||||
import { settingsHeaderBorder, settingsSashBorder, settingsTextInputBorder } from 'vs/workbench/contrib/preferences/common/settingsEditorColorRegistry';
|
||||
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IOpenSettingsOptions, IPreferencesService, ISearchResult, ISettingsEditorModel, ISettingsEditorOptions, SettingMatchType, SettingValueType, validateSettingsEditorOptions } from 'vs/workbench/services/preferences/common/preferences';
|
||||
import { IOpenSettingsOptions, IPreferencesService, ISearchResult, ISetting, ISettingsEditorModel, ISettingsEditorOptions, ISettingsGroup, SettingMatchType, SettingValueType, validateSettingsEditorOptions } from 'vs/workbench/services/preferences/common/preferences';
|
||||
import { SettingsEditor2Input } from 'vs/workbench/services/preferences/common/preferencesEditorInput';
|
||||
import { Settings2EditorModel } from 'vs/workbench/services/preferences/common/preferencesModels';
|
||||
import { Settings2EditorModel, nullRange } from 'vs/workbench/services/preferences/common/preferencesModels';
|
||||
import { IUserDataSyncWorkbenchService } from 'vs/workbench/services/userDataSync/common/userDataSync';
|
||||
import { preferencesClearInputIcon, preferencesFilterIcon } from 'vs/workbench/contrib/preferences/browser/preferencesIcons';
|
||||
import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust';
|
||||
|
@ -59,11 +58,14 @@ import { Orientation, Sizing, SplitView } from 'vs/base/browser/ui/splitview/spl
|
|||
import { Color } from 'vs/base/common/color';
|
||||
import { ILanguageService } from 'vs/editor/common/languages/language';
|
||||
import { SettingsSearchFilterDropdownMenuActionViewItem } from 'vs/workbench/contrib/preferences/browser/settingsSearchMenu';
|
||||
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IExtensionGalleryService, IExtensionManagementService, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { ISettingOverrideClickEvent } from 'vs/workbench/contrib/preferences/browser/settingsEditorSettingIndicators';
|
||||
import { ConfigurationScope, Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { defaultButtonStyles } from 'vs/platform/theme/browser/defaultStyles';
|
||||
import { IWorkbenchAssignmentService } from 'vs/workbench/services/assignment/common/assignmentService';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
|
||||
export const enum SettingsFocusContext {
|
||||
Search,
|
||||
|
@ -229,7 +231,11 @@ export class SettingsEditor2 extends EditorPane {
|
|||
@IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService,
|
||||
@IExtensionService private readonly extensionService: IExtensionService,
|
||||
@ILanguageService private readonly languageService: ILanguageService,
|
||||
@IExtensionManagementService extensionManagementService: IExtensionManagementService
|
||||
@IExtensionManagementService extensionManagementService: IExtensionManagementService,
|
||||
@IWorkbenchAssignmentService private readonly workbenchAssignmentService: IWorkbenchAssignmentService,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@IEnvironmentService private readonly environmentService: IEnvironmentService,
|
||||
@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
|
||||
) {
|
||||
super(SettingsEditor2.ID, telemetryService, themeService, storageService);
|
||||
this.delayedFilterLogging = new Delayer<void>(1000);
|
||||
|
@ -1189,14 +1195,49 @@ export class SettingsEditor2 extends EditorPane {
|
|||
});
|
||||
}
|
||||
|
||||
private addOrRemoveManageExtensionSetting(setting: ISetting, extension: IGalleryExtension, groups: ISettingsGroup[]): ISettingsGroup | undefined {
|
||||
const extensionId = setting.extensionId!;
|
||||
const matchingGroups = groups.filter(g => g.extensionInfo?.id.toLowerCase() === extensionId.toLowerCase());
|
||||
if (!matchingGroups.length) {
|
||||
const newGroup: ISettingsGroup = {
|
||||
sections: [{
|
||||
settings: [setting],
|
||||
}],
|
||||
id: extensionId,
|
||||
title: setting.extensionGroupTitle!,
|
||||
titleRange: nullRange,
|
||||
range: nullRange,
|
||||
extensionInfo: {
|
||||
id: extensionId,
|
||||
displayName: extension?.displayName,
|
||||
}
|
||||
};
|
||||
groups.push(newGroup);
|
||||
return newGroup;
|
||||
} else if (matchingGroups.length >= 2) {
|
||||
// Remove the group with the manage extension setting.
|
||||
const matchingGroupIndex = matchingGroups.findIndex(group =>
|
||||
group.sections.length === 1 && group.sections[0].settings.length === 1 && group.sections[0].settings[0].extensionId);
|
||||
if (matchingGroupIndex !== -1) {
|
||||
groups.splice(matchingGroupIndex, 1);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private async onConfigUpdate(keys?: ReadonlySet<string>, forceRefresh = false, schemaChange = false): Promise<void> {
|
||||
if (keys && this.settingsTreeModel) {
|
||||
return this.updateElementsByKey(keys);
|
||||
}
|
||||
|
||||
if (!this.defaultSettingsEditorModel) {
|
||||
return;
|
||||
}
|
||||
|
||||
const groups = this.defaultSettingsEditorModel.settingsGroups.slice(1); // Without commonlyUsed
|
||||
const dividedGroups = collections.groupBy(groups, g => g.extensionInfo ? 'extension' : 'core');
|
||||
const settingsResult = resolveSettingsTree(tocData, dividedGroups.core, this.logService);
|
||||
|
||||
const coreSettings = groups.filter(g => !g.extensionInfo);
|
||||
const settingsResult = resolveSettingsTree(tocData, coreSettings, this.logService);
|
||||
const resolvedSettingsRoot = settingsResult.tree;
|
||||
|
||||
// Warn for settings not included in layout
|
||||
|
@ -1210,10 +1251,61 @@ export class SettingsEditor2 extends EditorPane {
|
|||
this.hasWarnedMissingSettings = true;
|
||||
}
|
||||
|
||||
const commonlyUsed = resolveSettingsTree(commonlyUsedData, dividedGroups.core, this.logService);
|
||||
const additionalGroups: ISettingsGroup[] = [];
|
||||
const toggleData = await getExperimentalExtensionToggleData(this.workbenchAssignmentService, this.environmentService, this.productService);
|
||||
if (toggleData && groups.filter(g => g.extensionInfo).length) {
|
||||
for (const key in toggleData.settingsEditorRecommendedExtensions) {
|
||||
const prerelease = toggleData.settingsEditorRecommendedExtensions[key].onSettingsEditorOpen!.prerelease;
|
||||
|
||||
const extensionId = (typeof prerelease === 'string' && this.productService.quality !== 'stable') ? prerelease : key;
|
||||
const [extension] = await this.extensionGalleryService.getExtensions([{ id: extensionId }], CancellationToken.None);
|
||||
if (!extension) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let groupTitle: string | undefined;
|
||||
const manifest = await this.extensionGalleryService.getManifest(extension, CancellationToken.None);
|
||||
const contributesConfiguration = manifest?.contributes?.configuration;
|
||||
if (!Array.isArray(contributesConfiguration)) {
|
||||
groupTitle = contributesConfiguration?.title;
|
||||
} else if (contributesConfiguration.length === 1) {
|
||||
groupTitle = contributesConfiguration[0].title;
|
||||
}
|
||||
|
||||
const extensionName = extension?.displayName ?? extension?.name ?? extensionId;
|
||||
const settingKey = `${key}.manageExtension`;
|
||||
const setting: ISetting = {
|
||||
range: nullRange,
|
||||
key: settingKey,
|
||||
keyRange: nullRange,
|
||||
value: null,
|
||||
valueRange: nullRange,
|
||||
description: [extension?.description || ''],
|
||||
descriptionIsMarkdown: false,
|
||||
descriptionRanges: [],
|
||||
title: localize('manageExtension', "Manage {0}", extensionName),
|
||||
scope: ConfigurationScope.WINDOW,
|
||||
type: 'null',
|
||||
extensionId: extensionId,
|
||||
extensionGroupTitle: groupTitle ?? extensionName
|
||||
};
|
||||
const additionalGroup = this.addOrRemoveManageExtensionSetting(setting, extension, groups);
|
||||
if (additionalGroup) {
|
||||
additionalGroups.push(additionalGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resolvedSettingsRoot.children!.push(await createTocTreeForExtensionSettings(this.extensionService, groups.filter(g => g.extensionInfo)));
|
||||
|
||||
const commonlyUsedDataToUse = await getCommonlyUsedData(this.workbenchAssignmentService, this.environmentService, this.productService);
|
||||
const commonlyUsed = resolveSettingsTree(commonlyUsedDataToUse, groups, this.logService);
|
||||
resolvedSettingsRoot.children!.unshift(commonlyUsed.tree);
|
||||
|
||||
resolvedSettingsRoot.children!.push(await createTocTreeForExtensionSettings(this.extensionService, dividedGroups.extension || []));
|
||||
if (toggleData) {
|
||||
// Add the additional groups to the model to help with searching.
|
||||
this.defaultSettingsEditorModel.setAdditionalGroups(additionalGroups);
|
||||
}
|
||||
|
||||
if (!this.workspaceTrustManagementService.isWorkspaceTrusted() && (this.viewState.settingsTarget instanceof URI || this.viewState.settingsTarget === ConfigurationTarget.WORKSPACE)) {
|
||||
const configuredUntrustedWorkspaceSettings = resolveConfiguredUntrustedSettings(groups, this.viewState.settingsTarget, this.viewState.languageFilter, this.configurationService);
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { getExperimentalExtensionToggleData } from 'vs/workbench/contrib/preferences/common/preferences';
|
||||
import { IWorkbenchAssignmentService } from 'vs/workbench/services/assignment/common/assignmentService';
|
||||
export interface ITOCEntry<T> {
|
||||
id: string;
|
||||
label: string;
|
||||
|
@ -13,11 +17,29 @@ export interface ITOCEntry<T> {
|
|||
settings?: Array<T>;
|
||||
}
|
||||
|
||||
export const commonlyUsedData: ITOCEntry<string> = {
|
||||
id: 'commonlyUsed',
|
||||
label: localize('commonlyUsed', "Commonly Used"),
|
||||
settings: ['files.autoSave', 'editor.fontSize', 'editor.fontFamily', 'editor.tabSize', 'editor.renderWhitespace', 'editor.cursorStyle', 'editor.multiCursorModifier', 'editor.insertSpaces', 'editor.wordWrap', 'files.exclude', 'files.associations', 'workbench.editor.enablePreview']
|
||||
};
|
||||
const defaultCommonlyUsedSettings: string[] = [
|
||||
'files.autoSave',
|
||||
'editor.fontSize',
|
||||
'editor.fontFamily',
|
||||
'editor.tabSize',
|
||||
'editor.renderWhitespace',
|
||||
'editor.cursorStyle',
|
||||
'editor.multiCursorModifier',
|
||||
'editor.insertSpaces',
|
||||
'editor.wordWrap',
|
||||
'files.exclude',
|
||||
'files.associations',
|
||||
'workbench.editor.enablePreview'
|
||||
];
|
||||
|
||||
export async function getCommonlyUsedData(workbenchAssignmentService: IWorkbenchAssignmentService, environmentService: IEnvironmentService, productService: IProductService): Promise<ITOCEntry<string>> {
|
||||
const toggleData = await getExperimentalExtensionToggleData(workbenchAssignmentService, environmentService, productService);
|
||||
return {
|
||||
id: 'commonlyUsed',
|
||||
label: localize('commonlyUsed', "Commonly Used"),
|
||||
settings: toggleData ? toggleData.commonlyUsed : defaultCommonlyUsedSettings
|
||||
};
|
||||
}
|
||||
|
||||
export const tocData: ITOCEntry<string> = {
|
||||
id: 'root',
|
||||
|
|
|
@ -64,6 +64,9 @@ import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/use
|
|||
import { defaultButtonStyles, getInputBoxStyle, getListStyles, getSelectBoxStyles } from 'vs/platform/theme/browser/defaultStyles';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { RenderIndentGuides } from 'vs/base/browser/ui/tree/abstractTree';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
|
||||
const $ = DOM.$;
|
||||
|
||||
|
@ -502,7 +505,7 @@ function _resolveSettingsTree(tocData: ITOCEntry<string>, allSettings: Set<ISett
|
|||
if (tocData.children) {
|
||||
children = tocData.children
|
||||
.map(child => _resolveSettingsTree(child, allSettings, logService))
|
||||
.filter(child => (child.children && child.children.length) || (child.settings && child.settings.length));
|
||||
.filter(child => child.children?.length || child.settings?.length);
|
||||
}
|
||||
|
||||
let settings: ISetting[] | undefined;
|
||||
|
@ -603,6 +606,10 @@ interface ISettingBoolItemTemplate extends ISettingItemTemplate<boolean> {
|
|||
checkbox: Toggle;
|
||||
}
|
||||
|
||||
interface ISettingExtensionToggleItemTemplate extends ISettingItemTemplate<undefined> {
|
||||
actionButton: Button;
|
||||
}
|
||||
|
||||
interface ISettingTextItemTemplate extends ISettingItemTemplate<string> {
|
||||
inputBox: InputBox;
|
||||
validationErrorMessageElement: HTMLElement;
|
||||
|
@ -659,6 +666,7 @@ const SETTINGS_BOOL_OBJECT_TEMPLATE_ID = 'settings.boolObject.template';
|
|||
const SETTINGS_COMPLEX_TEMPLATE_ID = 'settings.complex.template';
|
||||
const SETTINGS_NEW_EXTENSIONS_TEMPLATE_ID = 'settings.newExtensions.template';
|
||||
const SETTINGS_ELEMENT_TEMPLATE_ID = 'settings.group.template';
|
||||
const SETTINGS_EXTENSION_TOGGLE_TEMPLATE_ID = 'settings.extensionToggle.template';
|
||||
|
||||
export interface ISettingChangeEvent {
|
||||
key: string;
|
||||
|
@ -758,6 +766,10 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre
|
|||
@IContextMenuService protected readonly _contextMenuService: IContextMenuService,
|
||||
@IKeybindingService protected readonly _keybindingService: IKeybindingService,
|
||||
@IConfigurationService protected readonly _configService: IConfigurationService,
|
||||
@IExtensionService protected readonly _extensionsService: IExtensionService,
|
||||
@IExtensionsWorkbenchService protected readonly _extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IProductService protected readonly _productService: IProductService,
|
||||
@ITelemetryService protected readonly _telemetryService: ITelemetryService,
|
||||
) {
|
||||
super();
|
||||
|
||||
|
@ -873,7 +885,7 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre
|
|||
template.containerElement.setAttribute(AbstractSettingRenderer.SETTING_ID_ATTR, element.id);
|
||||
|
||||
const titleTooltip = setting.key + (element.isConfigured ? ' - Modified' : '');
|
||||
template.categoryElement.textContent = element.displayCategory && (element.displayCategory + ': ');
|
||||
template.categoryElement.textContent = element.displayCategory ? (element.displayCategory + ': ') : '';
|
||||
template.categoryElement.title = titleTooltip;
|
||||
|
||||
template.labelElement.text = element.displayLabel;
|
||||
|
@ -1878,6 +1890,50 @@ export class SettingBoolRenderer extends AbstractSettingRenderer implements ITre
|
|||
}
|
||||
}
|
||||
|
||||
type ManageExtensionClickTelemetryClassification = {
|
||||
extensionId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The extension the user went to manage.' };
|
||||
owner: 'rzhao271';
|
||||
comment: 'Event used to gain insights into when users are using an experimental extension management setting';
|
||||
};
|
||||
|
||||
export class SettingsExtensionToggleRenderer extends AbstractSettingRenderer implements ITreeRenderer<SettingsTreeSettingElement, never, ISettingExtensionToggleItemTemplate> {
|
||||
templateId = SETTINGS_EXTENSION_TOGGLE_TEMPLATE_ID;
|
||||
|
||||
renderTemplate(_container: HTMLElement): ISettingExtensionToggleItemTemplate {
|
||||
const common = super.renderCommonTemplate(null, _container, 'extension-toggle');
|
||||
|
||||
const actionButton = new Button(common.containerElement, {
|
||||
title: false,
|
||||
...defaultButtonStyles
|
||||
});
|
||||
actionButton.element.classList.add('setting-item-extension-toggle-button');
|
||||
actionButton.label = localize('manageExtension', "Manage extension");
|
||||
|
||||
const template: ISettingExtensionToggleItemTemplate = {
|
||||
...common,
|
||||
actionButton
|
||||
};
|
||||
|
||||
this.addSettingElementFocusHandler(template);
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
renderElement(element: ITreeNode<SettingsTreeSettingElement, never>, index: number, templateData: ISettingExtensionToggleItemTemplate): void {
|
||||
super.renderSettingElement(element, index, templateData);
|
||||
}
|
||||
|
||||
protected renderValue(dataElement: SettingsTreeSettingElement, template: ISettingExtensionToggleItemTemplate, onChange: (_: undefined) => void): void {
|
||||
template.elementDisposables.clear();
|
||||
|
||||
const extensionId = dataElement.setting.extensionId!;
|
||||
template.elementDisposables.add(template.actionButton.onDidClick(async () => {
|
||||
this._telemetryService.publicLog2<{ extensionId: String }, ManageExtensionClickTelemetryClassification>('ManageExtensionClick', { extensionId });
|
||||
this._commandService.executeCommand('extension.open', extensionId);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
export class SettingTreeRenderers {
|
||||
readonly onDidClickOverrideElement: Event<ISettingOverrideClickEvent>;
|
||||
|
||||
|
@ -1924,6 +1980,7 @@ export class SettingTreeRenderers {
|
|||
];
|
||||
|
||||
const actionFactory = (setting: ISetting) => this.getActionsForSetting(setting);
|
||||
const emptyActionFactory = (_: ISetting) => [];
|
||||
const settingRenderers = [
|
||||
this._instantiationService.createInstance(SettingBoolRenderer, this.settingActions, actionFactory),
|
||||
this._instantiationService.createInstance(SettingNumberRenderer, this.settingActions, actionFactory),
|
||||
|
@ -1936,6 +1993,7 @@ export class SettingTreeRenderers {
|
|||
this._instantiationService.createInstance(SettingEnumRenderer, this.settingActions, actionFactory),
|
||||
this._instantiationService.createInstance(SettingObjectRenderer, this.settingActions, actionFactory),
|
||||
this._instantiationService.createInstance(SettingBoolObjectRenderer, this.settingActions, actionFactory),
|
||||
this._instantiationService.createInstance(SettingsExtensionToggleRenderer, [], emptyActionFactory)
|
||||
];
|
||||
|
||||
this.onDidClickOverrideElement = Event.any(...settingRenderers.map(r => r.onDidClickOverrideElement));
|
||||
|
@ -2146,6 +2204,10 @@ class SettingsTreeDelegate extends CachedListVirtualDelegate<SettingsTreeGroupCh
|
|||
}
|
||||
|
||||
if (element instanceof SettingsTreeSettingElement) {
|
||||
if (element.valueType === SettingValueType.ExtensionToggle) {
|
||||
return SETTINGS_EXTENSION_TOGGLE_TEMPLATE_ID;
|
||||
}
|
||||
|
||||
const invalidTypeError = element.isConfigured && getInvalidTypeError(element.value, element.setting.type);
|
||||
if (invalidTypeError) {
|
||||
return SETTINGS_COMPLEX_TEMPLATE_ID;
|
||||
|
|
|
@ -10,7 +10,7 @@ import { URI } from 'vs/base/common/uri';
|
|||
import { ConfigurationTarget, IConfigurationValue } from 'vs/platform/configuration/common/configuration';
|
||||
import { SettingsTarget } from 'vs/workbench/contrib/preferences/browser/preferencesWidgets';
|
||||
import { ITOCEntry, knownAcronyms, knownTermMappings, tocData } from 'vs/workbench/contrib/preferences/browser/settingsLayout';
|
||||
import { ENABLE_LANGUAGE_FILTER, MODIFIED_SETTING_TAG, POLICY_SETTING_TAG, REQUIRE_TRUSTED_WORKSPACE_SETTING_TAG } from 'vs/workbench/contrib/preferences/common/preferences';
|
||||
import { ENABLE_EXTENSION_TOGGLE_SETTINGS, ENABLE_LANGUAGE_FILTER, MODIFIED_SETTING_TAG, POLICY_SETTING_TAG, REQUIRE_TRUSTED_WORKSPACE_SETTING_TAG } from 'vs/workbench/contrib/preferences/common/preferences';
|
||||
import { IExtensionSetting, ISearchResult, ISetting, SettingValueType } from 'vs/workbench/services/preferences/common/preferences';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { FOLDER_SCOPES, WORKSPACE_SCOPES, REMOTE_MACHINE_SCOPES, LOCAL_MACHINE_SCOPES, IWorkbenchConfigurationService, APPLICATION_SCOPES } from 'vs/workbench/services/configuration/common/configuration';
|
||||
|
@ -21,6 +21,7 @@ import { ConfigurationScope, EditPresentationTypes, Extensions, IConfigurationRe
|
|||
import { ILanguageService } from 'vs/editor/common/languages/language';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
|
||||
export const ONLINE_SERVICES_SETTING_TAG = 'usesOnlineServices';
|
||||
|
||||
|
@ -168,7 +169,8 @@ export class SettingsTreeSettingElement extends SettingsTreeElement {
|
|||
parent: SettingsTreeGroupElement,
|
||||
inspectResult: IInspectResult,
|
||||
isWorkspaceTrusted: boolean,
|
||||
private readonly languageService: ILanguageService
|
||||
private readonly languageService: ILanguageService,
|
||||
private readonly productService: IProductService
|
||||
) {
|
||||
super(sanitizeId(parent.id + '_' + setting.key));
|
||||
this.setting = setting;
|
||||
|
@ -194,6 +196,11 @@ export class SettingsTreeSettingElement extends SettingsTreeElement {
|
|||
}
|
||||
|
||||
private initLabels(): void {
|
||||
if (this.setting.title) {
|
||||
this._displayLabel = this.setting.title;
|
||||
this._displayCategory = '';
|
||||
return;
|
||||
}
|
||||
const displayKeyFormat = settingKeyToDisplayFormat(this.setting.key, this.parent!.id, this.setting.isLanguageTagSetting);
|
||||
this._displayLabel = displayKeyFormat.label;
|
||||
this._displayCategory = displayKeyFormat.category;
|
||||
|
@ -303,7 +310,9 @@ export class SettingsTreeSettingElement extends SettingsTreeElement {
|
|||
this.description = this.setting.description.join('\n');
|
||||
}
|
||||
|
||||
if (this.setting.enum && (!this.setting.type || settingTypeEnumRenderable(this.setting.type))) {
|
||||
if (isExtensionToggleSetting(this.setting, this.productService)) {
|
||||
this.valueType = SettingValueType.ExtensionToggle;
|
||||
} else if (this.setting.enum && (!this.setting.type || settingTypeEnumRenderable(this.setting.type))) {
|
||||
this.valueType = SettingValueType.Enum;
|
||||
} else if (this.setting.type === 'string') {
|
||||
if (this.setting.editPresentation === EditPresentationTypes.Multiline) {
|
||||
|
@ -476,6 +485,7 @@ export class SettingsTreeModel {
|
|||
@IWorkbenchConfigurationService private readonly _configurationService: IWorkbenchConfigurationService,
|
||||
@ILanguageService private readonly _languageService: ILanguageService,
|
||||
@IUserDataProfileService private readonly _userDataProfileService: IUserDataProfileService,
|
||||
@IProductService private readonly _productService: IProductService
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -583,7 +593,7 @@ export class SettingsTreeModel {
|
|||
private createSettingsTreeSettingElement(setting: ISetting, parent: SettingsTreeGroupElement): SettingsTreeSettingElement {
|
||||
const target = this.getTargetToInspect(setting.scope);
|
||||
const inspectResult = inspectSetting(setting.key, target, this._viewState.languageFilter, this._configurationService);
|
||||
const element = new SettingsTreeSettingElement(setting, parent, inspectResult, this._isWorkspaceTrusted, this._languageService);
|
||||
const element = new SettingsTreeSettingElement(setting, parent, inspectResult, this._isWorkspaceTrusted, this._languageService, this._productService);
|
||||
|
||||
const nameElements = this._treeElementsBySettingName.get(setting.key) || [];
|
||||
nameElements.push(element);
|
||||
|
@ -737,7 +747,13 @@ function trimCategoryForGroup(category: string, groupId: string): string {
|
|||
return trimmed;
|
||||
}
|
||||
|
||||
export function isExcludeSetting(setting: ISetting): boolean {
|
||||
function isExtensionToggleSetting(setting: ISetting, productService: IProductService): boolean {
|
||||
return ENABLE_EXTENSION_TOGGLE_SETTINGS &&
|
||||
!!productService.extensionRecommendations &&
|
||||
!!setting.extensionId;
|
||||
}
|
||||
|
||||
function isExcludeSetting(setting: ISetting): boolean {
|
||||
return setting.key === 'files.exclude' ||
|
||||
setting.key === 'search.exclude' ||
|
||||
setting.key === 'workbench.localHistory.exclude' ||
|
||||
|
@ -746,7 +762,7 @@ export function isExcludeSetting(setting: ISetting): boolean {
|
|||
setting.key === 'files.watcherExclude';
|
||||
}
|
||||
|
||||
export function isIncludeSetting(setting: ISetting): boolean {
|
||||
function isIncludeSetting(setting: ISetting): boolean {
|
||||
return setting.key === 'files.readonlyInclude';
|
||||
}
|
||||
|
||||
|
@ -826,8 +842,9 @@ export class SearchResultModel extends SettingsTreeModel {
|
|||
@IWorkbenchEnvironmentService private environmentService: IWorkbenchEnvironmentService,
|
||||
@ILanguageService languageService: ILanguageService,
|
||||
@IUserDataProfileService userDataProfileService: IUserDataProfileService,
|
||||
@IProductService productService: IProductService
|
||||
) {
|
||||
super(viewState, isWorkspaceTrusted, configurationService, languageService, userDataProfileService);
|
||||
super(viewState, isWorkspaceTrusted, configurationService, languageService, userDataProfileService, productService);
|
||||
this.update({ id: 'searchResultModel', label: '' });
|
||||
}
|
||||
|
||||
|
|
|
@ -3,10 +3,15 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ISettingsEditorModel, ISearchResult } from 'vs/workbench/services/preferences/common/preferences';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IStringDictionary } from 'vs/base/common/collections';
|
||||
import { IExtensionRecommendations } from 'vs/base/common/product';
|
||||
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IWorkbenchAssignmentService } from 'vs/workbench/services/assignment/common/assignmentService';
|
||||
import { ISearchResult, ISettingsEditorModel } from 'vs/workbench/services/preferences/common/preferences';
|
||||
|
||||
export interface IWorkbenchSettingsConfiguration {
|
||||
workbench: {
|
||||
|
@ -88,3 +93,39 @@ export const REQUIRE_TRUSTED_WORKSPACE_SETTING_TAG = 'requireTrustedWorkspace';
|
|||
export const KEYBOARD_LAYOUT_OPEN_PICKER = 'workbench.action.openKeyboardLayoutPicker';
|
||||
|
||||
export const ENABLE_LANGUAGE_FILTER = true;
|
||||
|
||||
export const ENABLE_EXTENSION_TOGGLE_SETTINGS = true;
|
||||
|
||||
type ExtensionToggleData = {
|
||||
settingsEditorRecommendedExtensions: IStringDictionary<IExtensionRecommendations>;
|
||||
commonlyUsed: string[];
|
||||
};
|
||||
|
||||
let cachedExtensionToggleData: ExtensionToggleData | undefined;
|
||||
|
||||
export async function getExperimentalExtensionToggleData(workbenchAssignmentService: IWorkbenchAssignmentService, environmentService: IEnvironmentService, productService: IProductService): Promise<ExtensionToggleData | undefined> {
|
||||
if (!ENABLE_EXTENSION_TOGGLE_SETTINGS) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (cachedExtensionToggleData) {
|
||||
return cachedExtensionToggleData;
|
||||
}
|
||||
|
||||
const isTreatment = await workbenchAssignmentService.getTreatment<boolean>('ExtensionToggleSettings');
|
||||
if ((isTreatment || !environmentService.isBuilt) && productService.extensionRecommendations && productService.commonlyUsedSettings) {
|
||||
const settingsEditorRecommendedExtensions: Record<string, IExtensionRecommendations> = {};
|
||||
Object.keys(productService.extensionRecommendations).forEach(key => {
|
||||
const value = productService.extensionRecommendations![key];
|
||||
if (value.onSettingsEditorOpen) {
|
||||
settingsEditorRecommendedExtensions[key] = value;
|
||||
}
|
||||
});
|
||||
cachedExtensionToggleData = {
|
||||
settingsEditorRecommendedExtensions,
|
||||
commonlyUsed: productService.commonlyUsedSettings
|
||||
};
|
||||
return cachedExtensionToggleData;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
|||
import { IFileService, IFileStatWithPartialMetadata } from 'vs/platform/files/common/files';
|
||||
import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { ILogService, LogLevel } from 'vs/platform/log/common/log';
|
||||
import { IProgress, IProgressStep } from 'vs/platform/progress/common/progress';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { minimapFindMatch, overviewRulerFindMatchForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
|
@ -1276,8 +1275,7 @@ export class FolderMatchWorkspaceRoot extends FolderMatchWithResource {
|
|||
@IReplaceService replaceService: IReplaceService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@ILabelService labelService: ILabelService,
|
||||
@IUriIdentityService uriIdentityService: IUriIdentityService,
|
||||
@ILogService private readonly _logService: ILogService
|
||||
@IUriIdentityService uriIdentityService: IUriIdentityService
|
||||
) {
|
||||
super(_resource, _id, _index, _query, _parent, _searchModel, null, replaceService, instantiationService, labelService, uriIdentityService);
|
||||
}
|
||||
|
@ -1317,29 +1315,15 @@ export class FolderMatchWorkspaceRoot extends FolderMatchWithResource {
|
|||
const normalizedResource = this.uriIdentityService.extUri.normalizePath(this.resource);
|
||||
let uri = this.normalizedUriParent(rawFileMatch.resource);
|
||||
|
||||
const debug: string[] = ['[search model building]'];
|
||||
|
||||
if (this._logService.getLevel() === LogLevel.Trace) {
|
||||
debug.push(`Starting with normalized resource ${normalizedResource}`);
|
||||
}
|
||||
|
||||
while (!this.uriEquals(normalizedResource, uri)) {
|
||||
fileMatchParentParts.unshift(uri);
|
||||
const prevUri = uri;
|
||||
uri = this.normalizedUriParent(uri);
|
||||
if (this._logService.getLevel() === LogLevel.Trace) {
|
||||
debug.push(`current uri parent ${uri} comparing with ${prevUri}`);
|
||||
}
|
||||
if (this.uriEquals(prevUri, uri)) {
|
||||
this._logService.trace(debug.join('\n\n'));
|
||||
throw Error(`${rawFileMatch.resource} is not correctly configured as a child of its ${normalizedResource}`);
|
||||
throw Error(`${rawFileMatch.resource} is not correctly configured as a child of ${normalizedResource}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (this._logService.getLevel() === LogLevel.Trace) {
|
||||
this._logService.trace(debug.join('\n\n'));
|
||||
}
|
||||
|
||||
const root = this.closestRoot ?? this;
|
||||
let parent: FolderMatch = this;
|
||||
for (let i = 0; i < fileMatchParentParts.length; i++) {
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
.monaco-dialog-box {
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.monaco-dialog-box .dialog-message-row .dialog-message-container .dialog-message-text {
|
||||
font-size: 25px;
|
||||
min-width: max-content;
|
||||
}
|
||||
|
||||
#monaco-dialog-message-body > div > p > .codicon[class*='codicon-']::before{
|
||||
padding-right: 8px;
|
||||
max-width: 30px;
|
||||
max-height: 30px;
|
||||
position: relative;
|
||||
top: auto;
|
||||
color: var(--vscode-textLink-foreground);
|
||||
padding-right: 20px;
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
#monaco-dialog-message-body > .message-body > p {
|
||||
display: flex;
|
||||
font-size: 16px;
|
||||
background: var(--vscode-welcomePage-tileHoverBackground);
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
min-height: auto;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap:break-word;
|
||||
}
|
||||
|
||||
#monaco-dialog-message-body > .link > p {
|
||||
font-size: 16px;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
.monaco-dialog-box {
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.welcome-widget {
|
||||
height: min-content;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.dialog-message-detail-title{
|
||||
height: 22px;
|
||||
padding-bottom: 4px;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
.monaco-dialog-box .monaco-action-bar .actions-container {
|
||||
justify-content: flex-end;
|
||||
}
|
|
@ -5,24 +5,40 @@
|
|||
|
||||
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
|
||||
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry, IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
|
||||
import { IWelcomeDialogService as IWelcomeDialogService } from 'vs/workbench/contrib/welcomeDialog/browser/welcomeDialogService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { WelcomeWidget } from 'vs/workbench/contrib/welcomeDialog/browser/welcomeWidget';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
|
||||
const configurationKey = 'welcome.experimental.dialog';
|
||||
|
||||
class WelcomeDialogContribution {
|
||||
class WelcomeDialogContribution extends Disposable implements IWorkbenchContribution {
|
||||
|
||||
private static readonly WELCOME_DIALOG_DISMISSED_KEY = 'workbench.dialog.welcome.dismissed';
|
||||
private contextKeysToWatch = new Set<string>();
|
||||
|
||||
constructor(
|
||||
@IWelcomeDialogService welcomeDialogService: IWelcomeDialogService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IBrowserWorkbenchEnvironmentService environmentService: IBrowserWorkbenchEnvironmentService,
|
||||
@IConfigurationService configurationService: IConfigurationService
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IContextKeyService readonly contextService: IContextKeyService,
|
||||
@ICodeEditorService readonly codeEditorService: ICodeEditorService,
|
||||
@IInstantiationService readonly instantiationService: IInstantiationService,
|
||||
@ICommandService readonly commandService: ICommandService,
|
||||
@ITelemetryService readonly telemetryService: ITelemetryService
|
||||
) {
|
||||
super();
|
||||
|
||||
if (!storageService.isNew(StorageScope.PROFILE)) {
|
||||
return; // do not show if this is not the first session
|
||||
}
|
||||
|
||||
const setting = configurationService.inspect<boolean>(configurationKey);
|
||||
if (!setting.value) {
|
||||
return;
|
||||
|
@ -33,19 +49,23 @@ class WelcomeDialogContribution {
|
|||
return;
|
||||
}
|
||||
|
||||
if (storageService.getBoolean(WelcomeDialogContribution.WELCOME_DIALOG_DISMISSED_KEY + '#' + welcomeDialog.id, StorageScope.PROFILE, false)) {
|
||||
return;
|
||||
}
|
||||
this.contextKeysToWatch.add(welcomeDialog.when);
|
||||
|
||||
welcomeDialogService.show({
|
||||
title: welcomeDialog.title,
|
||||
buttonText: welcomeDialog.buttonText,
|
||||
messages: welcomeDialog.messages,
|
||||
action: welcomeDialog.action,
|
||||
onClose: () => {
|
||||
storageService.store(WelcomeDialogContribution.WELCOME_DIALOG_DISMISSED_KEY + '#' + welcomeDialog.id, true, StorageScope.PROFILE, StorageTarget.USER);
|
||||
this._register(this.contextService.onDidChangeContext(e => {
|
||||
if (e.affectsSome(this.contextKeysToWatch) &&
|
||||
Array.from(this.contextKeysToWatch).every(value => this.contextService.contextMatchesRules(ContextKeyExpr.deserialize(value)))) {
|
||||
const codeEditor = this.codeEditorService.getActiveCodeEditor();
|
||||
if (codeEditor?.hasModel()) {
|
||||
const welcomeWidget = new WelcomeWidget(codeEditor, instantiationService, commandService, telemetryService);
|
||||
welcomeWidget.render(welcomeDialog.title,
|
||||
welcomeDialog.message,
|
||||
welcomeDialog.buttonText,
|
||||
welcomeDialog.buttonCommand,
|
||||
welcomeDialog.media);
|
||||
this.contextKeysToWatch.delete(welcomeDialog.when);
|
||||
}
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/welcomeDialog';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { ILinkDescriptor } from 'vs/platform/opener/browser/link';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { openLinkFromMarkdown } from 'vs/editor/contrib/markdownRenderer/browser/markdownRenderer';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
|
||||
interface IWelcomeDialogItem {
|
||||
readonly title: string;
|
||||
readonly messages: { message: string; icon: string }[];
|
||||
readonly buttonText: string;
|
||||
readonly action?: ILinkDescriptor;
|
||||
readonly onClose?: () => void;
|
||||
}
|
||||
|
||||
export const IWelcomeDialogService = createDecorator<IWelcomeDialogService>('welcomeDialogService');
|
||||
|
||||
export interface IWelcomeDialogService {
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
show(item: IWelcomeDialogItem): void;
|
||||
}
|
||||
|
||||
export class WelcomeDialogService implements IWelcomeDialogService {
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
constructor(
|
||||
@IDialogService private readonly dialogService: IDialogService,
|
||||
@IOpenerService private readonly openerService: IOpenerService) {
|
||||
}
|
||||
|
||||
async show(welcomeDialogItem: IWelcomeDialogItem): Promise<void> {
|
||||
|
||||
const renderBody = (icon: string, message: string): MarkdownString => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: true, supportHtml: true });
|
||||
mds.appendMarkdown(`<a>$(${icon})</a>`);
|
||||
mds.appendMarkdown(message);
|
||||
return mds;
|
||||
};
|
||||
|
||||
const hr = new MarkdownString(undefined, { supportThemeIcons: true, supportHtml: true });
|
||||
hr.appendMarkdown('<hr>');
|
||||
|
||||
await this.dialogService.prompt({
|
||||
type: 'none',
|
||||
message: welcomeDialogItem.title,
|
||||
cancelButton: welcomeDialogItem.buttonText,
|
||||
buttons: welcomeDialogItem.action ? [{
|
||||
label: welcomeDialogItem.action.label as string,
|
||||
run: () => {
|
||||
openLinkFromMarkdown(this.openerService, welcomeDialogItem.action?.href!, true);
|
||||
welcomeDialogItem.onClose?.();
|
||||
}
|
||||
|
||||
}] : undefined,
|
||||
custom: {
|
||||
disableCloseAction: true,
|
||||
markdownDetails: [
|
||||
{ markdown: hr, classes: ['hr'] },
|
||||
...welcomeDialogItem.messages.map(value => { return { markdown: renderBody(value.icon, value.message), classes: ['message-body'] }; })
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
welcomeDialogItem.onClose?.();
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IWelcomeDialogService, WelcomeDialogService, InstantiationType.Eager);
|
||||
|
177
src/vs/workbench/contrib/welcomeDialog/browser/welcomeWidget.ts
Normal file
177
src/vs/workbench/contrib/welcomeDialog/browser/welcomeWidget.ts
Normal file
|
@ -0,0 +1,177 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/welcomeWidget';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';
|
||||
import { $, hide } from 'vs/base/browser/dom'; import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { MarkdownRenderer } from 'vs/editor/contrib/markdownRenderer/browser/markdownRenderer';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ButtonBar } from 'vs/base/browser/ui/button/button';
|
||||
import { mnemonicButtonLabel } from 'vs/base/common/labels';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { defaultButtonStyles, defaultDialogStyles } from 'vs/platform/theme/browser/defaultStyles';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { Action, WorkbenchActionExecutedClassification, WorkbenchActionExecutedEvent } from 'vs/base/common/actions';
|
||||
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ThemeIcon } from 'vs/base/common/themables';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
|
||||
export class WelcomeWidget extends Disposable implements IOverlayWidget {
|
||||
|
||||
private readonly _rootDomNode: HTMLElement;
|
||||
private readonly element: HTMLElement;
|
||||
private readonly messageContainer: HTMLElement;
|
||||
private readonly markdownRenderer = this.instantiationService.createInstance(MarkdownRenderer, {});
|
||||
|
||||
constructor(
|
||||
private readonly _editor: ICodeEditor,
|
||||
private readonly instantiationService: IInstantiationService,
|
||||
private readonly commandService: ICommandService,
|
||||
private readonly telemetryService: ITelemetryService,
|
||||
) {
|
||||
super();
|
||||
this._rootDomNode = document.createElement('div');
|
||||
this._rootDomNode.className = 'welcome-widget';
|
||||
|
||||
this.element = this._rootDomNode.appendChild($('.monaco-dialog-box'));
|
||||
this.element.setAttribute('role', 'dialog');
|
||||
|
||||
hide(this._rootDomNode);
|
||||
|
||||
this.messageContainer = this.element.appendChild($('.dialog-message-container'));
|
||||
}
|
||||
|
||||
async executeCommand(commandId: string, ...args: string[]) {
|
||||
try {
|
||||
await this.commandService.executeCommand(commandId, ...args);
|
||||
this._hide(false);
|
||||
this.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', {
|
||||
id: commandId,
|
||||
from: 'welcomeWidget'
|
||||
});
|
||||
}
|
||||
catch (ex) {
|
||||
}
|
||||
}
|
||||
|
||||
render(title: string, message: string, buttonText: string, buttonAction: string, media: { altText: string; path: string }): void {
|
||||
if (!this._editor._getViewModel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.buildWidgetContent(title, message, buttonText, buttonAction, media);
|
||||
this._editor.addOverlayWidget(this);
|
||||
this._revealTemporarily();
|
||||
this.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', {
|
||||
id: 'welcomeWidgetRendered',
|
||||
from: 'welcomeWidget'
|
||||
});
|
||||
}
|
||||
|
||||
buildWidgetContent(title: string, message: string, buttonText: string, buttonAction: string, media: { altText: string; path: string }): void {
|
||||
|
||||
const actionBar = this._register(new ActionBar(this.element, {}));
|
||||
|
||||
const action = this._register(new Action('dialog.close', localize('dialogClose', "Close Dialog"), ThemeIcon.asClassName(Codicon.dialogClose), true, async () => {
|
||||
this._hide(true);
|
||||
}));
|
||||
actionBar.push(action, { icon: true, label: false });
|
||||
|
||||
|
||||
const messageTitleElement = this.messageContainer.appendChild($('.dialog-message-title'));
|
||||
messageTitleElement.style.display = 'contents';
|
||||
messageTitleElement.style.alignContent = 'start';
|
||||
|
||||
const renderBody = (message: string): MarkdownString => {
|
||||
const mds = new MarkdownString(undefined, { supportHtml: true });
|
||||
mds.appendMarkdown(message);
|
||||
return mds;
|
||||
};
|
||||
|
||||
const titleElement = this.messageContainer.appendChild($('#monaco-dialog-message-detail.dialog-message-detail-title'));
|
||||
const titleElementMdt = this.markdownRenderer.render(renderBody(title));
|
||||
titleElement.appendChild(titleElementMdt.element);
|
||||
|
||||
const messageElement = this.messageContainer.appendChild($('#monaco-dialog-message-detail.dialog-message-detail-message'));
|
||||
const messageElementMd = this.markdownRenderer.render(renderBody(message));
|
||||
messageElement.appendChild(messageElementMd.element);
|
||||
|
||||
const buttonsRowElement = this.messageContainer.appendChild($('.dialog-buttons-row'));
|
||||
const buttonContainer = buttonsRowElement.appendChild($('.dialog-buttons'));
|
||||
|
||||
const buttonBar = this._register(new ButtonBar(buttonContainer));
|
||||
const primaryButton = this._register(buttonBar.addButtonWithDescription({ title: true, secondary: false, ...defaultButtonStyles }));
|
||||
primaryButton.label = mnemonicButtonLabel(buttonText, true);
|
||||
|
||||
this._register(primaryButton.onDidClick(async () => {
|
||||
await this.executeCommand(buttonAction);
|
||||
}));
|
||||
|
||||
buttonBar.buttons[0].focus();
|
||||
this.applyStyles();
|
||||
}
|
||||
|
||||
getId(): string {
|
||||
return 'editor.contrib.welcomeWidget';
|
||||
}
|
||||
|
||||
getDomNode(): HTMLElement {
|
||||
return this._rootDomNode;
|
||||
}
|
||||
|
||||
getPosition(): IOverlayWidgetPosition | null {
|
||||
return {
|
||||
preference: OverlayWidgetPositionPreference.TOP_RIGHT_CORNER
|
||||
};
|
||||
}
|
||||
|
||||
private _hideSoon = this._register(new RunOnceScheduler(() => this._hide(false), 30000));
|
||||
private _isVisible: boolean = false;
|
||||
|
||||
private _revealTemporarily(): void {
|
||||
this._show();
|
||||
this._hideSoon.schedule();
|
||||
}
|
||||
|
||||
private _show(): void {
|
||||
if (this._isVisible) {
|
||||
return;
|
||||
}
|
||||
this._isVisible = true;
|
||||
this._rootDomNode.style.display = 'block';
|
||||
}
|
||||
|
||||
private _hide(isUserDismissed: boolean): void {
|
||||
if (!this._isVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._isVisible = false;
|
||||
this._rootDomNode.style.display = 'none';
|
||||
this._editor.removeOverlayWidget(this);
|
||||
this.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', {
|
||||
id: isUserDismissed ? 'welcomeWidgetDismissed' : 'welcomeWidgetHidden',
|
||||
from: 'welcomeWidget'
|
||||
});
|
||||
}
|
||||
|
||||
private applyStyles(): void {
|
||||
const style = defaultDialogStyles;
|
||||
|
||||
const fgColor = style.dialogForeground;
|
||||
const bgColor = style.dialogBackground;
|
||||
const shadowColor = style.dialogShadow ? `0 0px 8px ${style.dialogShadow}` : '';
|
||||
const border = style.dialogBorder ? `1px solid ${style.dialogBorder}` : '';
|
||||
|
||||
this._rootDomNode.style.boxShadow = shadowColor;
|
||||
|
||||
this._rootDomNode.style.color = fgColor ?? '';
|
||||
this._rootDomNode.style.backgroundColor = bgColor ?? '';
|
||||
this._rootDomNode.style.border = border;
|
||||
}
|
||||
}
|
|
@ -38,7 +38,8 @@ export enum SettingValueType {
|
|||
NullableNumber = 'nullable-number',
|
||||
Object = 'object',
|
||||
BooleanObject = 'boolean-object',
|
||||
LanguageTag = 'language-tag'
|
||||
LanguageTag = 'language-tag',
|
||||
ExtensionToggle = 'extension-toggle'
|
||||
}
|
||||
|
||||
export interface ISettingsGroup {
|
||||
|
@ -94,6 +95,11 @@ export interface ISetting {
|
|||
isLanguageTagSetting?: boolean;
|
||||
categoryOrder?: number;
|
||||
categoryLabel?: string;
|
||||
|
||||
// For ExtensionToggle settings
|
||||
extensionId?: string;
|
||||
title?: string;
|
||||
extensionGroupTitle?: string;
|
||||
}
|
||||
|
||||
export interface IExtensionSetting extends ISetting {
|
||||
|
|
|
@ -16,7 +16,7 @@ import { ISingleEditOperation } from 'vs/editor/common/core/editOperation';
|
|||
import { ITextEditorModel } from 'vs/editor/common/services/resolverService';
|
||||
import * as nls from 'vs/nls';
|
||||
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ConfigurationScope, Extensions, IConfigurationNode, IConfigurationRegistry, IExtensionInfo, IRegisteredConfigurationPropertySchema, OVERRIDE_PROPERTY_REGEX } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { ConfigurationScope, Extensions, IConfigurationNode, IConfigurationPropertySchema, IConfigurationRegistry, IExtensionInfo, IRegisteredConfigurationPropertySchema, OVERRIDE_PROPERTY_REGEX } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { EditorModel } from 'vs/workbench/common/editor/editorModel';
|
||||
|
@ -256,6 +256,7 @@ export class Settings2EditorModel extends AbstractSettingsModel implements ISett
|
|||
private readonly _onDidChangeGroups: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDidChangeGroups: Event<void> = this._onDidChangeGroups.event;
|
||||
|
||||
private additionalGroups: ISettingsGroup[] | undefined;
|
||||
private dirty = false;
|
||||
|
||||
constructor(
|
||||
|
@ -276,17 +277,25 @@ export class Settings2EditorModel extends AbstractSettingsModel implements ISett
|
|||
}));
|
||||
}
|
||||
|
||||
/** Doesn't include the "Commonly Used" group */
|
||||
protected override get filterGroups(): ISettingsGroup[] {
|
||||
// Don't filter "commonly used"
|
||||
return this.settingsGroups.slice(1);
|
||||
}
|
||||
|
||||
get settingsGroups(): ISettingsGroup[] {
|
||||
const groups = this._defaultSettings.getSettingsGroups(this.dirty);
|
||||
if (this.additionalGroups?.length) {
|
||||
groups.push(...this.additionalGroups);
|
||||
}
|
||||
this.dirty = false;
|
||||
return groups;
|
||||
}
|
||||
|
||||
/** For programmatically added groups outside of registered configurations */
|
||||
setAdditionalGroups(groups: ISettingsGroup[]) {
|
||||
this.additionalGroups = groups;
|
||||
}
|
||||
|
||||
findValueMatches(filter: string, setting: ISetting): IRange[] {
|
||||
// TODO @roblou
|
||||
return [];
|
||||
|
@ -667,7 +676,7 @@ export class DefaultSettings extends Disposable {
|
|||
const categoryOrder = config.order;
|
||||
|
||||
for (const key in settingsObject) {
|
||||
const prop = settingsObject[key];
|
||||
const prop: IConfigurationPropertySchema = settingsObject[key];
|
||||
if (this.matchesScope(prop)) {
|
||||
const value = prop.default;
|
||||
let description = (prop.markdownDescription || prop.description || '');
|
||||
|
|
Loading…
Reference in a new issue