未验证 提交 42ff04d1 编写于 作者: P Pine 提交者: GitHub

Merge pull request #77296 from microsoft/pine/array-settings

Use different label for array/exclude widget
......@@ -3,105 +3,105 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-item-value > .setting-item-control {
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-item-value > .setting-item-control {
width: 100%;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-pattern {
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-value {
margin-right: 3px;
margin-left: 2px;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-pattern,
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-sibling {
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-value,
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-sibling {
display: inline-block;
line-height: 22px;
font-family: var(--monaco-monospace-font);
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-sibling {
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-sibling {
opacity: 0.7;
margin-left: 0.5em;
font-size: 0.9em;
white-space: pre;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row .monaco-action-bar {
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row .monaco-action-bar {
display: none;
position: absolute;
right: 0px;
margin-top: 1px;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row {
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row {
position: relative;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row:focus {
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row:focus {
outline: none;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row:hover .monaco-action-bar,
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row.selected .monaco-action-bar {
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row:hover .monaco-action-bar,
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row.selected .monaco-action-bar {
display: block;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row .monaco-action-bar .action-label {
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row .monaco-action-bar .action-label {
width: 16px;
height: 16px;
padding: 2px;
margin-right: 2px;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row .monaco-action-bar .setting-excludeAction-edit {
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row .monaco-action-bar .setting-listAction-edit {
margin-right: 4px;
}
.vs .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row .monaco-action-bar .setting-excludeAction-edit {
.vs .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row .monaco-action-bar .setting-listAction-edit {
background: url("edit-light.svg") center center no-repeat;
}
.vs-dark .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row .monaco-action-bar .setting-excludeAction-edit {
.vs-dark .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row .monaco-action-bar .setting-listAction-edit {
background: url("edit-dark.svg") center center no-repeat;
}
.vs .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row .monaco-action-bar .setting-excludeAction-remove {
.vs .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row .monaco-action-bar .setting-listAction-remove {
background: url("remove-light.svg") center center no-repeat;
}
.vs-dark .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row .monaco-action-bar .setting-excludeAction-remove {
.vs-dark .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row .monaco-action-bar .setting-listAction-remove {
background: url("remove-dark.svg") center center no-repeat;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .monaco-text-button {
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .monaco-text-button {
width: initial;
padding: 2px 14px;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-item-control.setting-exclude-new-mode .setting-exclude-new-row {
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-item-control.setting-list-new-mode .setting-list-new-row {
display: none;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .monaco-text-button.setting-exclude-addButton {
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .monaco-text-button.setting-list-addButton {
margin-right: 10px;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-edit-row {
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-edit-row {
display: flex
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-patternInput,
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-siblingInput {
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-valueInput,
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-siblingInput {
height: 22px;
max-width: 320px;
flex: 1;
margin-right: 10px;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-okButton {
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-okButton {
margin-right: 10px;
}
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-widget {
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-widget {
margin-bottom: 1px;
}
......@@ -79,6 +79,7 @@ export class SettingsEditor2 extends BaseEditor {
return false;
}
return type === SettingValueType.Enum ||
type === SettingValueType.ArrayOfString ||
type === SettingValueType.Complex ||
type === SettingValueType.Boolean ||
type === SettingValueType.Exclude;
......@@ -968,7 +969,7 @@ export class SettingsEditor2 extends BaseEditor {
if (key) {
const focusedKey = focusedSetting.getAttribute(AbstractSettingRenderer.SETTING_KEY_ATTR);
if (focusedKey === key &&
!DOM.hasClass(focusedSetting, 'setting-item-exclude')) { // update `exclude`s live, as they have a separate "submit edit" step built in before this
!DOM.hasClass(focusedSetting, 'setting-item-list')) { // update `list`s live, as they have a separate "submit edit" step built in before this
this.updateModifiedLabelForKey(key);
this.scheduleRefresh(focusedSetting, key);
......
......@@ -42,14 +42,15 @@ import { attachButtonStyler, attachInputBoxStyler, attachSelectBoxStyler, attach
import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { ITOCEntry } from 'vs/workbench/contrib/preferences/browser/settingsLayout';
import { ISettingsEditorViewState, settingKeyToDisplayFormat, SettingsTreeElement, SettingsTreeGroupChild, SettingsTreeGroupElement, SettingsTreeNewExtensionsElement, SettingsTreeSettingElement } from 'vs/workbench/contrib/preferences/browser/settingsTreeModels';
import { ExcludeSettingWidget, IExcludeChangeEvent, IExcludeDataItem, settingsHeaderForeground, settingsNumberInputBackground, settingsNumberInputBorder, settingsNumberInputForeground, settingsSelectBackground, settingsSelectBorder, settingsSelectForeground, settingsSelectListBorder, settingsTextInputBackground, settingsTextInputBorder, settingsTextInputForeground } from 'vs/workbench/contrib/preferences/browser/settingsWidgets';
import { ListSettingWidget, IListChangeEvent, IListDataItem, settingsHeaderForeground, settingsNumberInputBackground, settingsNumberInputBorder, settingsNumberInputForeground, settingsSelectBackground, settingsSelectBorder, settingsSelectForeground, settingsSelectListBorder, settingsTextInputBackground, settingsTextInputBorder, settingsTextInputForeground, ExcludeSettingWidget } from 'vs/workbench/contrib/preferences/browser/settingsWidgets';
import { SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU } from 'vs/workbench/contrib/preferences/common/preferences';
import { ISetting, ISettingsGroup, SettingValueType } from 'vs/workbench/services/preferences/common/preferences';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { isArray } from 'vs/base/common/types';
const $ = DOM.$;
function getExcludeDisplayValue(element: SettingsTreeSettingElement): IExcludeDataItem[] {
function getExcludeDisplayValue(element: SettingsTreeSettingElement): IListDataItem[] {
const data = element.isConfigured ?
{ ...element.defaultValue, ...element.scopeValue } :
element.defaultValue;
......@@ -62,12 +63,20 @@ function getExcludeDisplayValue(element: SettingsTreeSettingElement): IExcludeDa
return {
id: key,
pattern: key,
value: key,
sibling
};
});
}
function getListDisplayValue(element: SettingsTreeSettingElement): IListDataItem[] {
return element.value.map((key: string) => {
return {
value: key
};
});
}
export function resolveSettingsTree(tocData: ITOCEntry, coreSettingsGroups: ISettingsGroup[]): { tree: ITOCEntry, leftoverSettings: Set<ISetting> } {
const allSettings = getFlatSettings(coreSettingsGroups);
return {
......@@ -211,8 +220,12 @@ interface ISettingComplexItemTemplate extends ISettingItemTemplate<void> {
button: Button;
}
interface ISettingListItemTemplate extends ISettingItemTemplate<void> {
listWidget: ListSettingWidget;
}
interface ISettingExcludeItemTemplate extends ISettingItemTemplate<void> {
excludeWidget: ExcludeSettingWidget;
excludeWidget: ListSettingWidget;
}
interface ISettingNewExtensionsTemplate extends IDisposableTemplate {
......@@ -229,6 +242,7 @@ const SETTINGS_TEXT_TEMPLATE_ID = 'settings.text.template';
const SETTINGS_NUMBER_TEMPLATE_ID = 'settings.number.template';
const SETTINGS_ENUM_TEMPLATE_ID = 'settings.enum.template';
const SETTINGS_BOOL_TEMPLATE_ID = 'settings.bool.template';
const SETTINGS_ARRAY_TEMPLATE_ID = 'settings.array.template';
const SETTINGS_EXCLUDE_TEMPLATE_ID = 'settings.exclude.template';
const SETTINGS_COMPLEX_TEMPLATE_ID = 'settings.complex.template';
const SETTINGS_NEW_EXTENSIONS_TEMPLATE_ID = 'settings.newExtensions.template';
......@@ -656,11 +670,81 @@ export class SettingComplexRenderer extends AbstractSettingRenderer implements I
}
}
export class SettingArrayRenderer extends AbstractSettingRenderer implements ITreeRenderer<SettingsTreeSettingElement, never, ISettingListItemTemplate> {
templateId = SETTINGS_ARRAY_TEMPLATE_ID;
renderTemplate(container: HTMLElement): ISettingListItemTemplate {
const common = this.renderCommonTemplate(null, container, 'list');
const listWidget = this._instantiationService.createInstance(ListSettingWidget, common.controlElement);
listWidget.domNode.classList.add(AbstractSettingRenderer.CONTROL_CLASS);
common.toDispose.push(listWidget);
const template: ISettingListItemTemplate = {
...common,
listWidget
};
this.addSettingElementFocusHandler(template);
common.toDispose.push(listWidget.onDidChangeList(e => this.onDidChangeList(template, e)));
return template;
}
private onDidChangeList(template: ISettingListItemTemplate, e: IListChangeEvent): void {
if (template.context) {
const newValue: any[] | undefined = isArray(template.context.scopeValue)
? [...template.context.scopeValue]
: [...template.context.value];
// Delete value
if (e.removeIndex) {
if (!e.value && e.originalValue && e.removeIndex > -1) {
newValue.splice(e.removeIndex, 1);
}
}
// Add value
else if (e.value && !e.originalValue) {
newValue.push(e.value);
}
// Update value
else if (e.value && e.originalValue) {
const valueIndex = newValue.indexOf(e.originalValue);
if (valueIndex > -1) {
newValue[valueIndex] = e.value;
}
// For some reason, we are updating and cannot find original value
// Just append the value in this case
else {
newValue.push(e.value);
}
}
this._onDidChangeSetting.fire({
key: template.context.setting.key,
value: newValue,
type: template.context.valueType
});
}
}
renderElement(element: ITreeNode<SettingsTreeSettingElement, never>, index: number, templateData: ISettingListItemTemplate): void {
super.renderSettingElement(element, index, templateData);
}
protected renderValue(dataElement: SettingsTreeSettingElement, template: ISettingListItemTemplate, onChange: (value: string) => void): void {
const value = getListDisplayValue(dataElement);
template.listWidget.setValue(value);
template.context = dataElement;
}
}
export class SettingExcludeRenderer extends AbstractSettingRenderer implements ITreeRenderer<SettingsTreeSettingElement, never, ISettingExcludeItemTemplate> {
templateId = SETTINGS_EXCLUDE_TEMPLATE_ID;
renderTemplate(container: HTMLElement): ISettingExcludeItemTemplate {
const common = this.renderCommonTemplate(null, container, 'exclude');
const common = this.renderCommonTemplate(null, container, 'list');
const excludeWidget = this._instantiationService.createInstance(ExcludeSettingWidget, common.controlElement);
excludeWidget.domNode.classList.add(AbstractSettingRenderer.CONTROL_CLASS);
......@@ -673,32 +757,32 @@ export class SettingExcludeRenderer extends AbstractSettingRenderer implements I
this.addSettingElementFocusHandler(template);
common.toDispose.push(excludeWidget.onDidChangeExclude(e => this.onDidChangeExclude(template, e)));
common.toDispose.push(excludeWidget.onDidChangeList(e => this.onDidChangeExclude(template, e)));
return template;
}
private onDidChangeExclude(template: ISettingExcludeItemTemplate, e: IExcludeChangeEvent): void {
private onDidChangeExclude(template: ISettingExcludeItemTemplate, e: IListChangeEvent): void {
if (template.context) {
const newValue = { ...template.context.scopeValue };
// first delete the existing entry, if present
if (e.originalPattern) {
if (e.originalPattern in template.context.defaultValue) {
if (e.originalValue) {
if (e.originalValue in template.context.defaultValue) {
// delete a default by overriding it
newValue[e.originalPattern] = false;
newValue[e.originalValue] = false;
} else {
delete newValue[e.originalPattern];
delete newValue[e.originalValue];
}
}
// then add the new or updated entry, if present
if (e.pattern) {
if (e.pattern in template.context.defaultValue && !e.sibling) {
if (e.value) {
if (e.value in template.context.defaultValue && !e.sibling) {
// add a default by deleting its override
delete newValue[e.pattern];
delete newValue[e.value];
} else {
newValue[e.pattern] = e.sibling ? { when: e.sibling } : true;
newValue[e.value] = e.sibling ? { when: e.sibling } : true;
}
}
......@@ -1056,6 +1140,7 @@ export class SettingTreeRenderers {
this._instantiationService.createInstance(SettingBoolRenderer, this.settingActions),
this._instantiationService.createInstance(SettingNumberRenderer, this.settingActions),
this._instantiationService.createInstance(SettingBoolRenderer, this.settingActions),
this._instantiationService.createInstance(SettingArrayRenderer, this.settingActions),
this._instantiationService.createInstance(SettingComplexRenderer, this.settingActions),
this._instantiationService.createInstance(SettingTextRenderer, this.settingActions),
this._instantiationService.createInstance(SettingExcludeRenderer, this.settingActions),
......@@ -1254,23 +1339,27 @@ class SettingsTreeDelegate implements IListVirtualDelegate<SettingsTreeGroupChil
}
if (element instanceof SettingsTreeSettingElement) {
if (element.valueType === 'boolean') {
if (element.valueType === SettingValueType.Boolean) {
return SETTINGS_BOOL_TEMPLATE_ID;
}
if (element.valueType === 'integer' || element.valueType === 'number' || element.valueType === 'nullable-integer' || element.valueType === 'nullable-number') {
if (element.valueType === SettingValueType.Integer || element.valueType === SettingValueType.Number || element.valueType === SettingValueType.NullableInteger || element.valueType === SettingValueType.NullableNumber) {
return SETTINGS_NUMBER_TEMPLATE_ID;
}
if (element.valueType === 'string') {
if (element.valueType === SettingValueType.String) {
return SETTINGS_TEXT_TEMPLATE_ID;
}
if (element.valueType === 'enum') {
if (element.valueType === SettingValueType.Enum) {
return SETTINGS_ENUM_TEMPLATE_ID;
}
if (element.valueType === 'exclude') {
if (element.valueType === SettingValueType.ArrayOfString) {
return SETTINGS_ARRAY_TEMPLATE_ID;
}
if (element.valueType === SettingValueType.Exclude) {
return SETTINGS_EXCLUDE_TEMPLATE_ID;
}
......
......@@ -193,6 +193,8 @@ export class SettingsTreeSettingElement extends SettingsTreeElement {
this.valueType = SettingValueType.Number;
} else if (this.setting.type === 'boolean') {
this.valueType = SettingValueType.Boolean;
} else if (this.setting.type === 'array' && this.setting.arrayItemType === 'string') {
this.valueType = SettingValueType.ArrayOfString;
} else if (isArray(this.setting.type) && this.setting.type.indexOf(SettingValueType.Null) > -1 && this.setting.type.length === 2) {
if (this.setting.type.indexOf(SettingValueType.Integer) > -1) {
this.valueType = SettingValueType.NullableInteger;
......
......@@ -87,35 +87,35 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
collector.addRule(`.settings-editor > .settings-header > .settings-header-controls .settings-tabs-widget .action-label { color: ${foregroundColor}; }`);
}
// Exclude control
// List control
const listHoverBackgroundColor = theme.getColor(listHoverBackground);
if (listHoverBackgroundColor) {
collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row:hover { background-color: ${listHoverBackgroundColor}; }`);
collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row:hover { background-color: ${listHoverBackgroundColor}; }`);
}
const listHoverForegroundColor = theme.getColor(listHoverForeground);
if (listHoverForegroundColor) {
collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row:hover { color: ${listHoverForegroundColor}; }`);
collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row:hover { color: ${listHoverForegroundColor}; }`);
}
const listSelectBackgroundColor = theme.getColor(listActiveSelectionBackground);
if (listSelectBackgroundColor) {
collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row.selected:focus { background-color: ${listSelectBackgroundColor}; }`);
collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row.selected:focus { background-color: ${listSelectBackgroundColor}; }`);
}
const listInactiveSelectionBackgroundColor = theme.getColor(listInactiveSelectionBackground);
if (listInactiveSelectionBackgroundColor) {
collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row.selected:not(:focus) { background-color: ${listInactiveSelectionBackgroundColor}; }`);
collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row.selected:not(:focus) { background-color: ${listInactiveSelectionBackgroundColor}; }`);
}
const listInactiveSelectionForegroundColor = theme.getColor(listInactiveSelectionForeground);
if (listInactiveSelectionForegroundColor) {
collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row.selected:not(:focus) { color: ${listInactiveSelectionForegroundColor}; }`);
collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row.selected:not(:focus) { color: ${listInactiveSelectionForegroundColor}; }`);
}
const listSelectForegroundColor = theme.getColor(listActiveSelectionForeground);
if (listSelectForegroundColor) {
collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-exclude .setting-exclude-row.selected:focus { color: ${listSelectForegroundColor}; }`);
collector.addRule(`.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-row.selected:focus { color: ${listSelectForegroundColor}; }`);
}
const codeTextForegroundColor = theme.getColor(textPreformatForeground);
......@@ -131,15 +131,15 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
}
});
export class ExcludeSettingListModel {
private _dataItems: IExcludeDataItem[] = [];
export class ListSettingListModel {
private _dataItems: IListDataItem[] = [];
private _editKey: string | null;
private _selectedIdx: number | null;
get items(): IExcludeViewItem[] {
get items(): IListViewItem[] {
const items = this._dataItems.map((item, i) => {
const editing = item.pattern === this._editKey;
return <IExcludeViewItem>{
const editing = item.value === this._editKey;
return <IListViewItem>{
...item,
editing,
selected: i === this._selectedIdx || editing
......@@ -150,7 +150,7 @@ export class ExcludeSettingListModel {
items.push({
editing: true,
selected: true,
pattern: '',
value: '',
sibling: ''
});
}
......@@ -162,8 +162,8 @@ export class ExcludeSettingListModel {
this._editKey = key;
}
setValue(excludeData: IExcludeDataItem[]): void {
this._dataItems = excludeData;
setValue(listData: IListDataItem[]): void {
this._dataItems = listData;
}
select(idx: number): void {
......@@ -191,20 +191,21 @@ export class ExcludeSettingListModel {
}
}
export interface IExcludeChangeEvent {
originalPattern: string;
pattern?: string;
export interface IListChangeEvent {
originalValue: string;
value?: string;
sibling?: string;
removeIndex?: number;
}
export class ExcludeSettingWidget extends Disposable {
export class ListSettingWidget extends Disposable {
private listElement: HTMLElement;
private readonly listDisposables = this._register(new DisposableStore());
private model = new ExcludeSettingListModel();
private model = new ListSettingListModel();
private readonly _onDidChangeExclude = this._register(new Emitter<IExcludeChangeEvent>());
readonly onDidChangeExclude: Event<IExcludeChangeEvent> = this._onDidChangeExclude.event;
private readonly _onDidChangeList = this._register(new Emitter<IListChangeEvent>());
readonly onDidChangeList: Event<IListChangeEvent> = this._onDidChangeList.event;
get domNode(): HTMLElement {
return this.listElement;
......@@ -217,7 +218,7 @@ export class ExcludeSettingWidget extends Disposable {
) {
super();
this.listElement = DOM.append(container, $('.setting-exclude-widget'));
this.listElement = DOM.append(container, $('.setting-list-widget'));
this.listElement.setAttribute('tabindex', '0');
DOM.append(container, this.renderAddButton());
this.renderList();
......@@ -240,8 +241,26 @@ export class ExcludeSettingWidget extends Disposable {
}));
}
setValue(excludeData: IExcludeDataItem[]): void {
this.model.setValue(excludeData);
protected getLocalizedStrings() {
return {
deleteActionTooltip: localize('removeItem', "Remove Item"),
editActionTooltip: localize('editItem', "Edit Item"),
complexEditActionTooltip: localize('editItemInSettingsJson', "Edit Item in settings.json"),
addButtonLabel: localize('addItem', "Add Item"),
inputPlaceholder: localize('itemInputPlaceholder', "String Item..."),
siblingInputPlaceholder: localize('listSiblingInputPlaceholder', "Sibling...")
};
}
protected getSettingListRowLocalizedStrings(value?: string, sibling?: string) {
return {
settingListRowValueHintLabel: localize('listValueHintLabel', "List item `{0}`", value),
settingListRowSiblingHintLabel: localize('listSiblingHintLabel', "List item `{0}` with sibling `${1}`", value)
};
}
setValue(listData: IListDataItem[]): void {
this.model.setValue(listData);
this.renderList();
}
......@@ -269,7 +288,7 @@ export class ExcludeSettingWidget extends Disposable {
const item = this.model.items[targetIdx];
if (item) {
this.editSetting(item.pattern);
this.editSetting(item.value);
e.preventDefault();
e.stopPropagation();
}
......@@ -286,7 +305,7 @@ export class ExcludeSettingWidget extends Disposable {
return -1;
}
const element = DOM.findParentWithClass((<any>e.target), 'setting-exclude-row');
const element = DOM.findParentWithClass((<any>e.target), 'setting-list-row');
if (!element) {
return -1;
}
......@@ -306,8 +325,8 @@ export class ExcludeSettingWidget extends Disposable {
DOM.clearNode(this.listElement);
this.listDisposables.clear();
const newMode = this.model.items.some(item => !!(item.editing && !item.pattern));
DOM.toggleClass(this.container, 'setting-exclude-new-mode', newMode);
const newMode = this.model.items.some(item => !!(item.editing && !item.value));
DOM.toggleClass(this.container, 'setting-list-new-mode', newMode);
this.model.items
.map((item, i) => this.renderItem(item, i, focused))
......@@ -317,22 +336,22 @@ export class ExcludeSettingWidget extends Disposable {
this.listElement.style.height = listHeight + 'px';
}
private createDeleteAction(key: string): IAction {
private createDeleteAction(key: string, idx: number): IAction {
return <IAction>{
class: 'setting-excludeAction-remove',
class: 'setting-listAction-remove',
enabled: true,
id: 'workbench.action.removeExcludeItem',
tooltip: localize('removeExcludeItem', "Remove Exclude Item"),
run: () => this._onDidChangeExclude.fire({ originalPattern: key, pattern: undefined })
id: 'workbench.action.removeListItem',
tooltip: this.getLocalizedStrings().deleteActionTooltip,
run: () => this._onDidChangeList.fire({ originalValue: key, value: undefined, removeIndex: idx })
};
}
private createEditAction(key: string): IAction {
return <IAction>{
class: 'setting-excludeAction-edit',
class: 'setting-listAction-edit',
enabled: true,
id: 'workbench.action.editExcludeItem',
tooltip: localize('editExcludeItem', "Edit Exclude Item"),
id: 'workbench.action.editListItem',
tooltip: this.getLocalizedStrings().editActionTooltip,
run: () => {
this.editSetting(key);
}
......@@ -344,14 +363,14 @@ export class ExcludeSettingWidget extends Disposable {
this.renderList();
}
private renderItem(item: IExcludeViewItem, idx: number, listFocused: boolean): HTMLElement {
private renderItem(item: IListViewItem, idx: number, listFocused: boolean): HTMLElement {
return item.editing ?
this.renderEditItem(item) :
this.renderDataItem(item, idx, listFocused);
}
private renderDataItem(item: IExcludeViewItem, idx: number, listFocused: boolean): HTMLElement {
const rowElement = $('.setting-exclude-row');
private renderDataItem(item: IListViewItem, idx: number, listFocused: boolean): HTMLElement {
const rowElement = $('.setting-list-row');
rowElement.setAttribute('data-index', idx + '');
rowElement.setAttribute('tabindex', item.selected ? '0' : '-1');
DOM.toggleClass(rowElement, 'selected', item.selected);
......@@ -359,19 +378,19 @@ export class ExcludeSettingWidget extends Disposable {
const actionBar = new ActionBar(rowElement);
this.listDisposables.add(actionBar);
const patternElement = DOM.append(rowElement, $('.setting-exclude-pattern'));
const siblingElement = DOM.append(rowElement, $('.setting-exclude-sibling'));
patternElement.textContent = item.pattern;
const valueElement = DOM.append(rowElement, $('.setting-list-value'));
const siblingElement = DOM.append(rowElement, $('.setting-list-sibling'));
valueElement.textContent = item.value;
siblingElement.textContent = item.sibling ? ('when: ' + item.sibling) : null;
actionBar.push([
this.createEditAction(item.pattern),
this.createDeleteAction(item.pattern)
this.createEditAction(item.value),
this.createDeleteAction(item.value, idx)
], { icon: true, label: false });
rowElement.title = item.sibling ?
localize('excludeSiblingHintLabel', "Exclude files matching `{0}`, only when a file matching `{1}` is present", item.pattern, item.sibling) :
localize('excludePatternHintLabel', "Exclude files matching `{0}`", item.pattern);
rowElement.title = item.sibling
? this.getSettingListRowLocalizedStrings(item.value, item.sibling).settingListRowSiblingHintLabel
: this.getSettingListRowLocalizedStrings(item.value, item.sibling).settingListRowValueHintLabel;
if (item.selected) {
if (listFocused) {
......@@ -385,11 +404,11 @@ export class ExcludeSettingWidget extends Disposable {
}
private renderAddButton(): HTMLElement {
const rowElement = $('.setting-exclude-new-row');
const rowElement = $('.setting-list-new-row');
const startAddButton = this._register(new Button(rowElement));
startAddButton.label = localize('addPattern', "Add Pattern");
startAddButton.element.classList.add('setting-exclude-addButton');
startAddButton.label = this.getLocalizedStrings().addButtonLabel;
startAddButton.element.classList.add('setting-list-addButton');
this._register(attachButtonStyler(startAddButton, this.themeService));
this._register(startAddButton.onDidClick(() => {
......@@ -400,16 +419,16 @@ export class ExcludeSettingWidget extends Disposable {
return rowElement;
}
private renderEditItem(item: IExcludeViewItem): HTMLElement {
const rowElement = $('.setting-exclude-edit-row');
private renderEditItem(item: IListViewItem): HTMLElement {
const rowElement = $('.setting-list-edit-row');
const onSubmit = (edited: boolean) => {
this.model.setEditKey(null);
const pattern = patternInput.value.trim();
if (edited && pattern) {
this._onDidChangeExclude.fire({
originalPattern: item.pattern,
pattern,
const value = valueInput.value.trim();
if (edited && value) {
this._onDidChangeList.fire({
originalValue: item.value,
value: value,
sibling: siblingInput && siblingInput.value.trim()
});
}
......@@ -425,25 +444,26 @@ export class ExcludeSettingWidget extends Disposable {
}
};
const patternInput = new InputBox(rowElement, this.contextViewService, {
placeholder: localize('excludePatternInputPlaceholder', "Exclude Pattern...")
const valueInput = new InputBox(rowElement, this.contextViewService, {
placeholder: this.getLocalizedStrings().inputPlaceholder
});
patternInput.element.classList.add('setting-exclude-patternInput');
this.listDisposables.add(attachInputBoxStyler(patternInput, this.themeService, {
valueInput.element.classList.add('setting-list-valueInput');
this.listDisposables.add(attachInputBoxStyler(valueInput, this.themeService, {
inputBackground: settingsTextInputBackground,
inputForeground: settingsTextInputForeground,
inputBorder: settingsTextInputBorder
}));
this.listDisposables.add(patternInput);
patternInput.value = item.pattern;
this.listDisposables.add(DOM.addStandardDisposableListener(patternInput.inputElement, DOM.EventType.KEY_DOWN, onKeydown));
this.listDisposables.add(valueInput);
valueInput.value = item.value;
this.listDisposables.add(DOM.addStandardDisposableListener(valueInput.inputElement, DOM.EventType.KEY_DOWN, onKeydown));
let siblingInput: InputBox;
if (item.sibling) {
siblingInput = new InputBox(rowElement, this.contextViewService, {
placeholder: localize('excludeSiblingInputPlaceholder', "When Pattern Is Present...")
placeholder: this.getLocalizedStrings().siblingInputPlaceholder
});
siblingInput.element.classList.add('setting-exclude-siblingInput');
siblingInput.element.classList.add('setting-list-siblingInput');
this.listDisposables.add(siblingInput);
this.listDisposables.add(attachInputBoxStyler(siblingInput, this.themeService, {
inputBackground: settingsTextInputBackground,
......@@ -456,32 +476,52 @@ export class ExcludeSettingWidget extends Disposable {
const okButton = this._register(new Button(rowElement));
okButton.label = localize('okButton', "OK");
okButton.element.classList.add('setting-exclude-okButton');
okButton.element.classList.add('setting-list-okButton');
this.listDisposables.add(attachButtonStyler(okButton, this.themeService));
this.listDisposables.add(okButton.onDidClick(() => onSubmit(true)));
const cancelButton = this._register(new Button(rowElement));
cancelButton.label = localize('cancelButton', "Cancel");
cancelButton.element.classList.add('setting-exclude-cancelButton');
cancelButton.element.classList.add('setting-list-okButton');
this.listDisposables.add(attachButtonStyler(cancelButton, this.themeService));
this.listDisposables.add(cancelButton.onDidClick(() => onSubmit(false)));
this.listDisposables.add(
disposableTimeout(() => {
patternInput.focus();
patternInput.select();
valueInput.focus();
valueInput.select();
}));
return rowElement;
}
}
export interface IExcludeDataItem {
pattern: string;
export class ExcludeSettingWidget extends ListSettingWidget {
protected getLocalizedStrings() {
return {
deleteActionTooltip: localize('removeExcludeItem', "Remove Exclude Item"),
editActionTooltip: localize('editExcludeItem', "Edit Exclude Item"),
complexEditActionTooltip: localize('editExcludeItemInSettingsJson', "Edit Exclude Item in settings.json"),
addButtonLabel: localize('addPattern', "Add Pattern"),
inputPlaceholder: localize('excludePatternInputPlaceholder', "Exclude Pattern..."),
siblingInputPlaceholder: localize('excludeSiblingInputPlaceholder', "When Pattern Is Present...")
};
}
protected getSettingListRowLocalizedStrings(pattern?: string, sibling?: string) {
return {
settingListRowValueHintLabel: localize('excludePatternHintLabel', "Exclude files matching `{0}`", pattern),
settingListRowSiblingHintLabel: localize('excludeSiblingHintLabel', "Exclude files matching `{0}`, only when a file matching `{1}` is present", pattern, sibling)
};
}
}
export interface IListDataItem {
value: string;
sibling?: string;
}
interface IExcludeViewItem extends IExcludeDataItem {
interface IListViewItem extends IListDataItem {
editing?: boolean;
selected?: boolean;
}
......@@ -25,6 +25,7 @@ export enum SettingValueType {
Integer = 'integer',
Number = 'number',
Boolean = 'boolean',
ArrayOfString = 'array-of-string',
Exclude = 'exclude',
Complex = 'complex',
NullableInteger = 'nullable-integer',
......@@ -61,6 +62,7 @@ export interface ISetting {
scope?: ConfigurationScope;
type?: string | string[];
arrayItemType?: string;
enum?: string[];
enumDescriptions?: string[];
enumDescriptionsAreMarkdown?: boolean;
......
......@@ -22,7 +22,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { Registry } from 'vs/platform/registry/common/platform';
import { EditorModel } from 'vs/workbench/common/editor';
import { IFilterMetadata, IFilterResult, IGroupFilter, IKeybindingsEditorModel, ISearchResultGroup, ISetting, ISettingMatch, ISettingMatcher, ISettingsEditorModel, ISettingsGroup } from 'vs/workbench/services/preferences/common/preferences';
import { withNullAsUndefined } from 'vs/base/common/types';
import { withNullAsUndefined, isArray } from 'vs/base/common/types';
export const nullRange: IRange = { startLineNumber: -1, startColumn: -1, endLineNumber: -1, endColumn: -1 };
export function isNullRange(range: IRange): boolean { return range.startLineNumber === -1 && range.startColumn === -1 && range.endLineNumber === -1 && range.endColumn === -1; }
......@@ -613,6 +613,10 @@ export class DefaultSettings extends Disposable {
const value = prop.default;
const description = (prop.description || prop.markdownDescription || '').split('\n');
const overrides = OVERRIDE_PROPERTY_PATTERN.test(key) ? this.parseOverrideSettings(prop.default) : [];
const listItemType = prop.type === 'array' && prop.items && !isArray(prop.items) && prop.items.type && !isArray(prop.items.type)
? prop.items.type
: undefined;
result.push({
key,
value,
......@@ -625,6 +629,7 @@ export class DefaultSettings extends Disposable {
overrides,
scope: prop.scope,
type: prop.type,
arrayItemType: listItemType,
enum: prop.enum,
enumDescriptions: prop.enumDescriptions || prop.markdownEnumDescriptions,
enumDescriptionsAreMarkdown: !prop.enumDescriptions,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册