diff --git a/src/vs/workbench/parts/preferences/browser/settingsEditor2.ts b/src/vs/workbench/parts/preferences/browser/settingsEditor2.ts index c3e4eed201bbdd3b7a040cfd82b700f3aea3f6cc..0c59d96a99dd9502530262f420f23de654c6f1e0 100644 --- a/src/vs/workbench/parts/preferences/browser/settingsEditor2.ts +++ b/src/vs/workbench/parts/preferences/browser/settingsEditor2.ts @@ -11,8 +11,9 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { Color } from 'vs/base/common/color'; import { getErrorMessage, isPromiseCanceledError } from 'vs/base/common/errors'; import { KeyCode } from 'vs/base/common/keyCodes'; +import { escapeRegExpCharacters } from 'vs/base/common/strings'; import { TPromise } from 'vs/base/common/winjs.base'; -import { ITreeConfiguration, ITree } from 'vs/base/parts/tree/browser/tree'; +import { ITree, ITreeConfiguration } from 'vs/base/parts/tree/browser/tree'; import { DefaultTreestyler } from 'vs/base/parts/tree/browser/treeDefaults'; import 'vs/css!./media/settingsEditor2'; import { localize } from 'vs/nls'; @@ -29,14 +30,13 @@ import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { EditorOptions, IEditor } from 'vs/workbench/common/editor'; import { SearchWidget, SettingsTarget, SettingsTargetsWidget } from 'vs/workbench/parts/preferences/browser/preferencesWidgets'; -import { ISettingsEditorViewState, SearchResultIdx, SearchResultModel, SettingsAccessibilityProvider, SettingsDataSource, SettingsRenderer, SettingsTreeController, SettingsTreeFilter, TreeElement } from 'vs/workbench/parts/preferences/browser/settingsTree'; +import { tocData } from 'vs/workbench/parts/preferences/browser/settingsLayout'; +import { ISettingsEditorViewState, SearchResultIdx, SearchResultModel, SettingsAccessibilityProvider, SettingsDataSource, SettingsRenderer, SettingsTreeController, SettingsTreeFilter, TreeElement, isTOCLeaf } from 'vs/workbench/parts/preferences/browser/settingsTree'; import { TOCDataSource, TOCRenderer } from 'vs/workbench/parts/preferences/browser/tocTree'; import { CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, IPreferencesSearchService, ISearchProvider } from 'vs/workbench/parts/preferences/common/preferences'; import { IPreferencesService, ISearchResult, ISetting, ISettingsEditorModel } from 'vs/workbench/services/preferences/common/preferences'; import { SettingsEditor2Input } from 'vs/workbench/services/preferences/common/preferencesEditorInput'; import { DefaultSettingsEditorModel } from 'vs/workbench/services/preferences/common/preferencesModels'; -import { tocData } from 'vs/workbench/parts/preferences/browser/settingsLayout'; -import { escapeRegExpCharacters } from 'vs/base/common/strings'; const $ = DOM.$; @@ -638,19 +638,25 @@ export class SettingsEditor2 extends BaseEditor { export interface ITOCEntry { id: string; label: string; +} + +export interface ITOCGroupEntry extends ITOCEntry { children?: ITOCEntry[]; +} + +export interface ITOCLeafEntry extends ITOCEntry { settings?: T[]; } -export type IRawTOCEntry = ITOCEntry; -export type IResolvedTOCEntry = ITOCEntry; +export type IRawTOCEntry = ITOCGroupEntry | ITOCLeafEntry; +export type IResolvedTOCEntry = ITOCGroupEntry | ITOCLeafEntry; function resolveSettingsTree(tocData: IRawTOCEntry, defaultSettings: DefaultSettingsEditorModel): IResolvedTOCEntry { return _resolveSettingsTree(tocData, getAllSettings(defaultSettings)); } function _resolveSettingsTree(tocData: IRawTOCEntry, allSettings: Set): IResolvedTOCEntry { - if (tocData.settings) { + if (isTOCLeaf(tocData)) { return { id: tocData.id, label: tocData.label, diff --git a/src/vs/workbench/parts/preferences/browser/settingsTree.ts b/src/vs/workbench/parts/preferences/browser/settingsTree.ts index d29a8f3d6bd6136f1d4ebc57b861b18a0fd92cd0..9b81e662bea5cf39d0eb3125ec26066375453ea5 100644 --- a/src/vs/workbench/parts/preferences/browser/settingsTree.ts +++ b/src/vs/workbench/parts/preferences/browser/settingsTree.ts @@ -25,8 +25,8 @@ import { editorActiveLinkForeground, registerColor } from 'vs/platform/theme/com import { attachButtonStyler, attachInputBoxStyler, attachSelectBoxStyler } from 'vs/platform/theme/common/styler'; import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { SettingsTarget } from 'vs/workbench/parts/preferences/browser/preferencesWidgets'; +import { IResolvedTOCEntry, ITOCGroupEntry, ITOCLeafEntry, ITOCEntry } from 'vs/workbench/parts/preferences/browser/settingsEditor2'; import { ISearchResult, ISetting } from 'vs/workbench/services/preferences/common/preferences'; -import { IResolvedTOCEntry } from 'vs/workbench/parts/preferences/browser/settingsEditor2'; const $ = DOM.$; @@ -56,6 +56,7 @@ export interface ISettingElement extends ITreeItem { type: TreeItemType.setting; setting: ISetting; + parent: IGroupElement | SearchResultModel; displayCategory: string; displayLabel: string; value: any; @@ -68,6 +69,7 @@ export interface ISettingElement extends ITreeItem { export interface IGroupElement extends ITreeItem { type: TreeItemType.groupTitle; + parent: IGroupElement | IResolvedTOCEntry; group: IResolvedTOCEntry; index: number; } @@ -92,16 +94,17 @@ export class SettingsDataSource implements IDataSource { @IConfigurationService private configurationService: IConfigurationService ) { } - getGroupElement(group: IResolvedTOCEntry, index: number): IGroupElement { + getGroupElement(group: IResolvedTOCEntry, parent: IGroupElement | IResolvedTOCEntry, index: number): IGroupElement { return { type: TreeItemType.groupTitle, group, + parent, id: sanitizeElementId(group.id), index }; } - getSettingElement(setting: ISetting, group: IResolvedTOCEntry): ISettingElement { + getSettingElement(setting: ISetting, parent: IGroupElement | SearchResultModel, category: string): ISettingElement { const { isConfigured, inspected, targetSelector } = inspectSetting(setting.key, this.viewState.settingsTarget, this.configurationService); const displayValue = isConfigured ? inspected[targetSelector] : inspected.default; @@ -114,10 +117,10 @@ export class SettingsDataSource implements IDataSource { overriddenScopeList.push(localize('user', "User")); } - const displayKeyFormat = settingKeyToDisplayFormat(setting.key, group); + const displayKeyFormat = settingKeyToDisplayFormat(setting.key, category); return { type: TreeItemType.setting, - parent: group, + parent, id: sanitizeElementId(setting.key), setting, @@ -139,7 +142,7 @@ export class SettingsDataSource implements IDataSource { } hasChildren(tree: ITree, element: TreeElementOrRoot): boolean { - if (isRoot(element)) { + if (isTOCRoot(element)) { return true; } @@ -154,36 +157,44 @@ export class SettingsDataSource implements IDataSource { return false; } - _getChildren(element: TreeElementOrRoot): TreeElement[] { - if (isRoot(element)) { + private _getChildren(element: TreeElementOrRoot): TreeElement[] { + if (isTOCRoot(element)) { return this.getRootChildren(element); } else if (element instanceof SearchResultModel) { - return this.getGroupChildren(element.resultsAsGroup()); + return this.getSearchResultChildren(element); } else if (element.type === TreeItemType.groupTitle) { - return this.getGroupChildren(element.group); + return this.getGroupChildren(element); } else { // No children... return null; } } + private getSearchResultChildren(searchResult: SearchResultModel): ISettingElement[] { + return searchResult.getFlatSettings() + .map(s => this.getSettingElement(s, searchResult, 'searchResult')); + } + getChildren(tree: ITree, element: TreeElementOrRoot): TPromise { return TPromise.as(this._getChildren(element)); } - private getRootChildren(root: IResolvedTOCEntry): TreeElement[] { + private getRootChildren(root: ITOCGroupEntry): TreeElement[] { return root.children - .map((g, i) => this.getGroupElement(g, i)); + .map((g, i) => this.getGroupElement(g, root, i)); } - private getGroupChildren(group: IResolvedTOCEntry): TreeElement[] { - return group.children ? - group.children.map((child, i) => this.getGroupElement(child, i)) : - group.settings.map(s => this.getSettingElement(s, group)); + private getGroupChildren(groupElement: IGroupElement): TreeElement[] { + return isTOCLeaf(groupElement.group) ? + groupElement.group.settings.map(s => this.getSettingElement(s, groupElement, groupElement.id)) : + groupElement.group.children.map((child, i) => this.getGroupElement(child, groupElement, i)); } - getParent(tree: ITree, element: TreeElement): TPromise { - return TPromise.wrap(null); + getParent(tree: ITree, element: TreeElementOrRoot): TPromise { + return TPromise.wrap( + isTOCRoot(element) ? null : + element instanceof SearchResultModel ? null : + element.parent); } } @@ -191,11 +202,11 @@ function sanitizeElementId(id: string): string { return id.replace(/\./g, '_'); } -function isRoot(element: TreeElementOrRoot): element is IResolvedTOCEntry { +function isTOCRoot(element: TreeElementOrRoot): element is IResolvedTOCEntry { return element.id === 'root'; } -export function settingKeyToDisplayFormat(key: string, group: IResolvedTOCEntry): { category: string, label: string } { +export function settingKeyToDisplayFormat(key: string, groupId: string): { category: string, label: string } { let label = key .replace(/\.([a-z])/g, (match, p1) => `.${p1.toUpperCase()}`) .replace(/([a-z])([A-Z])/g, '$1 $2') // fooBar => foo Bar @@ -208,14 +219,14 @@ export function settingKeyToDisplayFormat(key: string, group: IResolvedTOCEntry) label = label.substr(lastDotIdx + 1); } - category = trimCategoryForGroup(category, group); + category = trimCategoryForGroup(category, groupId); return { category, label }; } -function trimCategoryForGroup(category: string, group: IResolvedTOCEntry): string { +function trimCategoryForGroup(category: string, groupId: string): string { const doTrim = forward => { - const parts = group.id.split('.'); + const parts = groupId.split('.'); while (parts.length) { const reg = new RegExp(`^${parts.join('\\.')}(\\.|$)`, 'i'); if (reg.test(category)) { @@ -571,16 +582,16 @@ export class SettingsTreeFilter implements IFilter { return true; } - private groupHasConfiguredSetting(group: IResolvedTOCEntry): boolean { - if (group.children) { - return group.children.some(c => this.groupHasConfiguredSetting(c)); - } - - for (let setting of group.settings) { - const { isConfigured } = inspectSetting(setting.key, this.viewState.settingsTarget, this.configurationService); - if (isConfigured) { - return true; + private groupHasConfiguredSetting(element: IResolvedTOCEntry): boolean { + if (isTOCLeaf(element)) { + for (let setting of element.settings) { + const { isConfigured } = inspectSetting(setting.key, this.viewState.settingsTarget, this.configurationService); + if (isConfigured) { + return true; + } } + } else { + return element.children.some(c => this.groupHasConfiguredSetting(c)); } return false; @@ -658,7 +669,7 @@ export class SearchResultModel { this.rawSearchResults[type] = result; } - resultsAsGroup(): IResolvedTOCEntry { + getFlatSettings(): ISetting[] { const flatSettings: ISetting[] = []; this.getUniqueResults() .filter(r => !!r) @@ -667,10 +678,10 @@ export class SearchResultModel { ...r.filterMatches.map(m => m.setting)); }); - return { - id: 'settingsSearchResultGroup', - settings: flatSettings, - label: 'searchResults' - }; + return flatSettings; } } + +export function isTOCLeaf(entry: ITOCEntry): entry is ITOCLeafEntry { + return !!(>entry).settings; +} diff --git a/src/vs/workbench/parts/preferences/browser/tocTree.ts b/src/vs/workbench/parts/preferences/browser/tocTree.ts index 8cdceb9e3fd2882f6e7e07a68c516ed1c659a905..f38680200d57a636be5359f3ce847d56132cc1ff 100644 --- a/src/vs/workbench/parts/preferences/browser/tocTree.ts +++ b/src/vs/workbench/parts/preferences/browser/tocTree.ts @@ -6,7 +6,9 @@ import * as DOM from 'vs/base/browser/dom'; import { TPromise } from 'vs/base/common/winjs.base'; import { IDataSource, IRenderer, ITree } from 'vs/base/parts/tree/browser/tree'; -import { IResolvedTOCEntry } from 'vs/workbench/parts/preferences/browser/settingsEditor2'; +import { IResolvedTOCEntry, ITOCGroupEntry } from 'vs/workbench/parts/preferences/browser/settingsEditor2'; +import { ISetting } from 'vs/workbench/services/preferences/common/preferences'; +import { isTOCLeaf } from 'vs/workbench/parts/preferences/browser/settingsTree'; const $ = DOM.$; @@ -21,10 +23,10 @@ export class TOCDataSource implements IDataSource { } hasChildren(tree: ITree, element: IResolvedTOCEntry): boolean { - return element.children && element.children.length && typeof element.children[0] !== 'string'; + return !isTOCLeaf(element) && element.children.length && typeof element.children[0] !== 'string'; } - getChildren(tree: ITree, element: IResolvedTOCEntry): TPromise { + getChildren(tree: ITree, element: ITOCGroupEntry): TPromise { return TPromise.as(element.children); }