Merge from vscode 81d7885dc2e9dc617e1522697a2966bc4025a45d (#5949)

* Merge from vscode 81d7885dc2e9dc617e1522697a2966bc4025a45d

* Fix vs unit tests and hygiene issue

* Fix strict null check issue
This commit is contained in:
Chris LaFreniere
2019-06-10 18:27:09 -07:00
committed by GitHub
parent ff38bc8143
commit d15a3fcc98
926 changed files with 19529 additions and 11383 deletions

View File

@@ -8,7 +8,7 @@ import { localize } from 'vs/nls';
import { Delayer } from 'vs/base/common/async';
import * as DOM from 'vs/base/browser/dom';
import { OS } from 'vs/base/common/platform';
import { dispose, Disposable, toDisposable, IDisposable } from 'vs/base/common/lifecycle';
import { dispose, Disposable, toDisposable, IDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
import { CheckboxActionViewItem } from 'vs/base/browser/ui/checkbox/checkbox';
import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
import { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel';
@@ -804,7 +804,7 @@ class KeybindingItemRenderer implements IListRenderer<IKeybindingItemEntry, Keyb
const source = this.instantiationService.createInstance(SourceColumn, parent, this.keybindingsEditor);
const columns: Column[] = [actions, command, keybinding, when, source];
const disposables: IDisposable[] = [...columns];
const disposables = combinedDisposable(...columns);
const elements = columns.map(({ element }) => element);
this.keybindingsEditor.layoutColumns(elements);
@@ -814,7 +814,7 @@ class KeybindingItemRenderer implements IListRenderer<IKeybindingItemEntry, Keyb
return {
parent,
columns,
disposable: toDisposable(() => dispose(disposables))
disposable: disposables
};
}

View File

@@ -23,11 +23,13 @@ import { parseTree, Node } from 'vs/base/common/json';
import { ScanCodeBinding } from 'vs/base/common/scanCode';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { WindowsNativeResolvedKeybinding } from 'vs/workbench/services/keybinding/common/windowsKeyboardMapper';
import { themeColorFromId, ThemeColor } from 'vs/platform/theme/common/themeService';
import { themeColorFromId, ThemeColor, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { overviewRulerInfo, overviewRulerError } from 'vs/editor/common/view/editorColorRegistry';
import { IModelDeltaDecoration, ITextModel, TrackedRangeStickiness, OverviewRulerLane } from 'vs/editor/common/model';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { KeybindingParser } from 'vs/base/common/keybindingParser';
import Severity from 'vs/base/common/severity';
import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon';
const NLS_LAUNCH_MESSAGE = nls.localize('defineKeybinding.start', "Define Keybinding");
const NLS_KB_LAYOUT_ERROR_MESSAGE = nls.localize('defineKeybinding.kbLayoutErrorMessage', "You won't be able to produce this key combination under your current keyboard layout.");
@@ -400,3 +402,8 @@ function isInterestingEditorModel(editor: ICodeEditor): boolean {
registerEditorContribution(DefineKeybindingController);
registerEditorCommand(new DefineKeybindingCommand());
registerThemingParticipant((theme, collector) => {
collector.addRule(`.monaco-editor .inlineKeybindingInfo:before { background: url("data:image/svg+xml,${SeverityIcon.getSVGData(Severity.Info, theme)}") -0.1em -0.2em no-repeat; }`);
collector.addRule(`.monaco-editor .inlineKeybindingError:before { background: url("data:image/svg+xml,${SeverityIcon.getSVGData(Severity.Error, theme)}") -0.1em -0.2em no-repeat; }`);
});

View File

Before

Width:  |  Height:  |  Size: 194 B

After

Width:  |  Height:  |  Size: 194 B

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M8 1c-3.865 0-7 3.135-7 7s3.135 7 7 7 7-3.135 7-7-3.135-7-7-7zm1 12h-2v-7h2v7zm0-8h-2v-2h2v2z" fill="#1BA1E2"/><path d="M7 6h2v7h-2v-7zm0-1h2v-2h-2v2z" fill="#fff"/></svg>

Before

Width:  |  Height:  |  Size: 243 B

View File

@@ -47,7 +47,6 @@
display:inline-block;
height:0.8em;
width:1em;
background: url(info.svg) 0px -0.1em no-repeat;
background-size: 0.9em;
}
@@ -57,7 +56,6 @@
display:inline-block;
height:0.8em;
width:1em;
background: url(status-error.svg) 0px -0.1em no-repeat;
background-size: 1em;
}

View File

@@ -236,15 +236,6 @@
background: url('edit_inverse.svg') center center no-repeat;
}
.monaco-editor .unsupportedWorkbenhSettingInfo:before {
content:" ";
display:inline-block;
height:1em;
width:1em;
background: url(info.svg) 50% 50% no-repeat;
background-size: 0.9em;
}
.monaco-editor .dim-configuration {
color: #b1b1b1;
}

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" enable-background="new 0 0 16 16" height="16" width="16"><circle cx="8" cy="8" r="6" fill="#F6F6F6"/><path d="M8 3C5.238 3 3 5.238 3 8s2.238 5 5 5 5-2.238 5-5-2.238-5-5-5zm3 7l-1 1-2-2-2 2-1-1 2-2.027L5 6l1-1 2 2 2-2 1 1-2 1.973L11 10z" fill="#E51400"/><path fill="#fff" d="M11 6l-1-1-2 2-2-2-1 1 2 1.973L5 10l1 1 2-2 2 2 1-1-2-2.027z"/></svg>

Before

Width:  |  Height:  |  Size: 403 B

View File

@@ -16,7 +16,6 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { WorkbenchStateContext, RemoteAuthorityContext } from 'vs/workbench/browser/contextkeys';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
@@ -30,10 +29,9 @@ import { ResourceContextKey } from 'vs/workbench/common/resources';
import { KeybindingsEditor } from 'vs/workbench/contrib/preferences/browser/keybindingsEditor';
import { ConfigureLanguageBasedSettingsAction, OpenDefaultKeybindingsFileAction, OpenFolderSettingsAction, OpenGlobalKeybindingsAction, OpenGlobalKeybindingsFileAction, OpenGlobalSettingsAction, OpenRawDefaultSettingsAction, OpenSettings2Action, OpenSettingsJsonAction, OpenWorkspaceSettingsAction, OPEN_FOLDER_SETTINGS_COMMAND, OPEN_FOLDER_SETTINGS_LABEL, OpenRemoteSettingsAction } from 'vs/workbench/contrib/preferences/browser/preferencesActions';
import { PreferencesEditor } from 'vs/workbench/contrib/preferences/browser/preferencesEditor';
import { CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS, CONTEXT_KEYBINDING_FOCUS, CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_JSON_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, IKeybindingsEditor, IPreferencesSearchService, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND, KEYBINDINGS_EDITOR_COMMAND_DEFINE, KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS, KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, KEYBINDINGS_EDITOR_COMMAND_REMOVE, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_SEARCH, KEYBINDINGS_EDITOR_COMMAND_SHOW_SIMILAR, KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE, KEYBINDINGS_EDITOR_SHOW_DEFAULT_KEYBINDINGS, KEYBINDINGS_EDITOR_SHOW_USER_KEYBINDINGS, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_EDIT_FOCUSED_SETTING, SETTINGS_EDITOR_COMMAND_FILTER_MODIFIED, SETTINGS_EDITOR_COMMAND_FILTER_ONLINE, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_FROM_SEARCH, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_LIST, SETTINGS_EDITOR_COMMAND_SEARCH, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU, SETTINGS_EDITOR_COMMAND_SWITCH_TO_JSON, SETTINGS_COMMAND_OPEN_SETTINGS, KEYBINDINGS_EDITOR_COMMAND_DEFINE_WHEN } from 'vs/workbench/contrib/preferences/common/preferences';
import { CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS, CONTEXT_KEYBINDING_FOCUS, CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_JSON_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, IKeybindingsEditor, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND, KEYBINDINGS_EDITOR_COMMAND_DEFINE, KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS, KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, KEYBINDINGS_EDITOR_COMMAND_REMOVE, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_SEARCH, KEYBINDINGS_EDITOR_COMMAND_SHOW_SIMILAR, KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE, KEYBINDINGS_EDITOR_SHOW_DEFAULT_KEYBINDINGS, KEYBINDINGS_EDITOR_SHOW_USER_KEYBINDINGS, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_EDIT_FOCUSED_SETTING, SETTINGS_EDITOR_COMMAND_FILTER_MODIFIED, SETTINGS_EDITOR_COMMAND_FILTER_ONLINE, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_FROM_SEARCH, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_LIST, SETTINGS_EDITOR_COMMAND_SEARCH, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU, SETTINGS_EDITOR_COMMAND_SWITCH_TO_JSON, SETTINGS_COMMAND_OPEN_SETTINGS, KEYBINDINGS_EDITOR_COMMAND_DEFINE_WHEN } from 'vs/workbench/contrib/preferences/common/preferences';
import { PreferencesContribution } from 'vs/workbench/contrib/preferences/common/preferencesContribution';
import { PreferencesSearchService } from 'vs/workbench/contrib/preferences/electron-browser/preferencesSearch';
import { SettingsEditor2 } from 'vs/workbench/contrib/preferences/electron-browser/settingsEditor2';
import { SettingsEditor2 } from 'vs/workbench/contrib/preferences/browser/settingsEditor2';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
import { DefaultPreferencesEditorInput, KeybindingsEditorInput, PreferencesEditorInput, SettingsEditor2Input } from 'vs/workbench/services/preferences/common/preferencesEditorInput';
@@ -42,8 +40,6 @@ import { ILabelService } from 'vs/platform/label/common/label';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
registerSingleton(IPreferencesSearchService, PreferencesSearchService, true);
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
new EditorDescriptor(
PreferencesEditor,
@@ -385,8 +381,8 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon
id: OpenGlobalKeybindingsAction.ID,
title: OpenGlobalKeybindingsAction.LABEL,
iconLocation: {
light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor.svg`)),
dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor-inverse.svg`))
light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor.svg`)),
dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-inverse.svg`))
}
},
when: ResourceContextKey.Resource.isEqualTo(URI.file(environmentService.appKeybindingsPath).toString()),
@@ -401,11 +397,11 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon
id: commandId,
title: OpenSettings2Action.LABEL,
iconLocation: {
light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor.svg`)),
dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor-inverse.svg`))
light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor.svg`)),
dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-inverse.svg`))
}
},
when: ResourceContextKey.Resource.isEqualTo(URI.file(environmentService.appSettingsPath).toString()),
when: ResourceContextKey.Resource.isEqualTo(environmentService.settingsResource.toString()),
group: 'navigation',
order: 1
});
@@ -442,8 +438,8 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon
id: commandId,
title: OpenSettings2Action.LABEL,
iconLocation: {
light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor.svg`)),
dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor-inverse.svg`))
light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor.svg`)),
dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-inverse.svg`))
}
},
when: ContextKeyExpr.and(ResourceContextKey.Resource.isEqualTo(this.preferencesService.workspaceSettingsResource!.toString()), WorkbenchStateContext.isEqualTo('workspace')),
@@ -470,8 +466,8 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon
id: commandId,
title: OpenSettings2Action.LABEL,
iconLocation: {
light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor.svg`)),
dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor-inverse.svg`))
light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor.svg`)),
dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-inverse.svg`))
}
},
when: ContextKeyExpr.and(ResourceContextKey.Resource.isEqualTo(this.preferencesService.getFolderSettingsResource(folder.uri)!.toString())),
@@ -537,8 +533,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
id: OpenGlobalKeybindingsFileAction.ID,
title: OpenGlobalKeybindingsFileAction.LABEL,
iconLocation: {
light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/edit-json.svg`)),
dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/edit-json-inverse.svg`))
light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/edit-json.svg`)),
dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/edit-json-inverse.svg`))
}
},
when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR),
@@ -775,8 +771,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
id: SETTINGS_EDITOR_COMMAND_SWITCH_TO_JSON,
title: nls.localize('openSettingsJson', "Open Settings (JSON)"),
iconLocation: {
dark: URI.parse(require.toUrl('vs/workbench/contrib/preferences/electron-browser/media/edit-json-inverse.svg')),
light: URI.parse(require.toUrl('vs/workbench/contrib/preferences/electron-browser/media/edit-json.svg'))
dark: URI.parse(require.toUrl('vs/workbench/contrib/preferences/browser/media/edit-json-inverse.svg')),
light: URI.parse(require.toUrl('vs/workbench/contrib/preferences/browser/media/edit-json.svg'))
}
},
group: 'navigation',

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Action } from 'vs/base/common/actions';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { getIconClasses } from 'vs/editor/common/services/getIconClasses';
import { IModelService } from 'vs/editor/common/services/modelService';
@@ -164,7 +164,7 @@ export class OpenWorkspaceSettingsAction extends Action {
static readonly ID = 'workbench.action.openWorkspaceSettings';
static readonly LABEL = nls.localize('openWorkspaceSettings', "Open Workspace Settings");
private disposables: IDisposable[] = [];
private readonly disposables = new DisposableStore();
constructor(
id: string,
@@ -174,7 +174,7 @@ export class OpenWorkspaceSettingsAction extends Action {
) {
super(id, label);
this.update();
this.workspaceContextService.onDidChangeWorkbenchState(() => this.update(), this, this.disposables);
this.disposables.add(this.workspaceContextService.onDidChangeWorkbenchState(() => this.update(), this));
}
private update(): void {
@@ -186,7 +186,7 @@ export class OpenWorkspaceSettingsAction extends Action {
}
dispose(): void {
this.disposables = dispose(this.disposables);
this.disposables.dispose();
super.dispose();
}
}

View File

@@ -31,7 +31,7 @@ import { ConfigurationTarget } from 'vs/platform/configuration/common/configurat
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ILogService } from 'vs/platform/log/common/log';
import { IProgressService } from 'vs/platform/progress/common/progress';
import { ILocalProgressService } from 'vs/platform/progress/common/progress';
import { Registry } from 'vs/platform/registry/common/platform';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
@@ -84,7 +84,7 @@ export class PreferencesEditor extends BaseEditor {
readonly minimumHeight = 260;
private _onDidCreateWidget = new Emitter<{ width: number; height: number; } | undefined>();
private _onDidCreateWidget = this._register(new Emitter<{ width: number; height: number; } | undefined>());
readonly onDidSizeConstraintsChange: Event<{ width: number; height: number; } | undefined> = this._onDidCreateWidget.event;
constructor(
@@ -94,7 +94,7 @@ export class PreferencesEditor extends BaseEditor {
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IThemeService themeService: IThemeService,
@IProgressService private readonly progressService: IProgressService,
@ILocalProgressService private readonly progressService: ILocalProgressService,
@IStorageService storageService: IStorageService
) {
super(PreferencesEditor.ID, telemetryService, themeService, storageService);
@@ -330,11 +330,6 @@ export class PreferencesEditor extends BaseEditor {
this._lastReportedFilter = filter;
}
}
dispose(): void {
this._onDidCreateWidget.dispose();
super.dispose();
}
}
class SettingsNavigator extends ArrayNavigator<ISetting> {
@@ -774,10 +769,10 @@ class SideBySidePreferencesWidget extends Widget {
private settingsTargetsWidget: SettingsTargetsWidget;
private readonly _onFocus = new Emitter<void>();
private readonly _onFocus = this._register(new Emitter<void>());
readonly onFocus: Event<void> = this._onFocus.event;
private readonly _onDidSettingsTargetChange = new Emitter<SettingsTarget>();
private readonly _onDidSettingsTargetChange = this._register(new Emitter<SettingsTarget>());
readonly onDidSettingsTargetChange: Event<SettingsTarget> = this._onDidSettingsTargetChange.event;
private splitview: SplitView;

View File

@@ -56,13 +56,13 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend
private modelChangeDelayer: Delayer<void> = new Delayer<void>(200);
private associatedPreferencesModel: IPreferencesEditorModel<ISetting>;
private readonly _onFocusPreference = new Emitter<ISetting>();
private readonly _onFocusPreference = this._register(new Emitter<ISetting>());
readonly onFocusPreference: Event<ISetting> = this._onFocusPreference.event;
private readonly _onClearFocusPreference = new Emitter<ISetting>();
private readonly _onClearFocusPreference = this._register(new Emitter<ISetting>());
readonly onClearFocusPreference: Event<ISetting> = this._onClearFocusPreference.event;
private readonly _onUpdatePreference: Emitter<{ key: string, value: any, source: IIndexedSetting }> = new Emitter<{ key: string, value: any, source: IIndexedSetting }>();
private readonly _onUpdatePreference = this._register(new Emitter<{ key: string, value: any, source: IIndexedSetting }>());
readonly onUpdatePreference: Event<{ key: string, value: any, source: IIndexedSetting }> = this._onUpdatePreference.event;
private filterResult: IFilterResult | undefined;
@@ -233,13 +233,13 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR
private bracesHidingRenderer: BracesHidingRenderer;
private filterResult: IFilterResult | undefined;
private readonly _onUpdatePreference: Emitter<{ key: string, value: any, source: IIndexedSetting }> = new Emitter<{ key: string, value: any, source: IIndexedSetting }>();
private readonly _onUpdatePreference = this._register(new Emitter<{ key: string, value: any, source: IIndexedSetting }>());
readonly onUpdatePreference: Event<{ key: string, value: any, source: IIndexedSetting }> = this._onUpdatePreference.event;
private readonly _onFocusPreference = new Emitter<ISetting>();
private readonly _onFocusPreference = this._register(new Emitter<ISetting>());
readonly onFocusPreference: Event<ISetting> = this._onFocusPreference.event;
private readonly _onClearFocusPreference = new Emitter<ISetting>();
private readonly _onClearFocusPreference = this._register(new Emitter<ISetting>());
readonly onClearFocusPreference: Event<ISetting> = this._onClearFocusPreference.event;
constructor(protected editor: ICodeEditor, readonly preferencesModel: DefaultSettingsEditorModel,
@@ -436,13 +436,13 @@ class DefaultSettingsHeaderRenderer extends Disposable {
export class SettingsGroupTitleRenderer extends Disposable implements HiddenAreasProvider {
private readonly _onHiddenAreasChanged = new Emitter<void>();
private readonly _onHiddenAreasChanged = this._register(new Emitter<void>());
get onHiddenAreasChanged(): Event<void> { return this._onHiddenAreasChanged.event; }
private settingsGroups: ISettingsGroup[];
private hiddenGroups: ISettingsGroup[] = [];
private settingsGroupTitleWidgets: SettingsGroupTitleWidget[];
private disposables: IDisposable[] = [];
private renderDisposables: IDisposable[] = [];
constructor(private editor: ICodeEditor,
@IInstantiationService private readonly instantiationService: IInstantiationService
@@ -474,8 +474,8 @@ export class SettingsGroupTitleRenderer extends Disposable implements HiddenArea
const settingsGroupTitleWidget = this.instantiationService.createInstance(SettingsGroupTitleWidget, this.editor, group);
settingsGroupTitleWidget.render();
this.settingsGroupTitleWidgets.push(settingsGroupTitleWidget);
this.disposables.push(settingsGroupTitleWidget);
this.disposables.push(settingsGroupTitleWidget.onToggled(collapsed => this.onToggled(collapsed, settingsGroupTitleWidget.settingsGroup)));
this.renderDisposables.push(settingsGroupTitleWidget);
this.renderDisposables.push(settingsGroupTitleWidget.onToggled(collapsed => this.onToggled(collapsed, settingsGroupTitleWidget.settingsGroup)));
}
this.settingsGroupTitleWidgets.reverse();
}
@@ -515,7 +515,7 @@ export class SettingsGroupTitleRenderer extends Disposable implements HiddenArea
private disposeWidgets() {
this.hiddenGroups = [];
this.disposables = dispose(this.disposables);
this.renderDisposables = dispose(this.renderDisposables);
}
dispose() {

View File

@@ -0,0 +1,219 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ISettingsEditorModel, ISetting, ISettingsGroup, ISearchResult, IGroupFilter } from 'vs/workbench/services/preferences/common/preferences';
import { IRange } from 'vs/editor/common/core/range';
import { distinct } from 'vs/base/common/arrays';
import * as strings from 'vs/base/common/strings';
import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { Registry } from 'vs/platform/registry/common/platform';
import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry';
import { IMatch, or, matchesContiguousSubString, matchesPrefix, matchesCamelCase, matchesWords } from 'vs/base/common/filters';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Disposable } from 'vs/base/common/lifecycle';
import { IPreferencesSearchService, ISearchProvider } from 'vs/workbench/contrib/preferences/common/preferences';
import { CancellationToken } from 'vs/base/common/cancellation';
export interface IEndpointDetails {
urlBase?: string;
key?: string;
}
export class PreferencesSearchService extends Disposable implements IPreferencesSearchService {
_serviceBrand: any;
constructor(
@IInstantiationService protected readonly instantiationService: IInstantiationService,
) {
super();
}
getRemoteSearchProvider(filter: string, newExtensionsOnly = false): ISearchProvider | undefined {
return undefined;
}
getLocalSearchProvider(filter: string): LocalSearchProvider {
return this.instantiationService.createInstance(LocalSearchProvider, filter);
}
}
export class LocalSearchProvider implements ISearchProvider {
static readonly EXACT_MATCH_SCORE = 10000;
static readonly START_SCORE = 1000;
constructor(private _filter: string) {
// Remove " and : which are likely to be copypasted as part of a setting name.
// Leave other special characters which the user might want to search for.
this._filter = this._filter
.replace(/[":]/g, ' ')
.replace(/ /g, ' ')
.trim();
}
searchModel(preferencesModel: ISettingsEditorModel, token?: CancellationToken): Promise<ISearchResult | null> {
if (!this._filter) {
return Promise.resolve(null);
}
let orderedScore = LocalSearchProvider.START_SCORE; // Sort is not stable
const settingMatcher = (setting: ISetting) => {
const matches = new SettingMatches(this._filter, setting, true, true, (filter, setting) => preferencesModel.findValueMatches(filter, setting)).matches;
const score = this._filter === setting.key ?
LocalSearchProvider.EXACT_MATCH_SCORE :
orderedScore--;
return matches && matches.length ?
{
matches,
score
} :
null;
};
const filterMatches = preferencesModel.filterSettings(this._filter, this.getGroupFilter(this._filter), settingMatcher);
if (filterMatches[0] && filterMatches[0].score === LocalSearchProvider.EXACT_MATCH_SCORE) {
return Promise.resolve({
filterMatches: filterMatches.slice(0, 1),
exactMatch: true
});
} else {
return Promise.resolve({
filterMatches
});
}
}
private getGroupFilter(filter: string): IGroupFilter {
const regex = strings.createRegExp(filter, false, { global: true });
return (group: ISettingsGroup) => {
return regex.test(group.title);
};
}
}
export class SettingMatches {
private readonly descriptionMatchingWords: Map<string, IRange[]> = new Map<string, IRange[]>();
private readonly keyMatchingWords: Map<string, IRange[]> = new Map<string, IRange[]>();
private readonly valueMatchingWords: Map<string, IRange[]> = new Map<string, IRange[]>();
readonly matches: IRange[];
constructor(searchString: string, setting: ISetting, private requireFullQueryMatch: boolean, private searchDescription: boolean, private valuesMatcher: (filter: string, setting: ISetting) => IRange[]) {
this.matches = distinct(this._findMatchesInSetting(searchString, setting), (match) => `${match.startLineNumber}_${match.startColumn}_${match.endLineNumber}_${match.endColumn}_`);
}
private _findMatchesInSetting(searchString: string, setting: ISetting): IRange[] {
const result = this._doFindMatchesInSetting(searchString, setting);
if (setting.overrides && setting.overrides.length) {
for (const subSetting of setting.overrides) {
const subSettingMatches = new SettingMatches(searchString, subSetting, this.requireFullQueryMatch, this.searchDescription, this.valuesMatcher);
const words = searchString.split(' ');
const descriptionRanges: IRange[] = this.getRangesForWords(words, this.descriptionMatchingWords, [subSettingMatches.descriptionMatchingWords, subSettingMatches.keyMatchingWords, subSettingMatches.valueMatchingWords]);
const keyRanges: IRange[] = this.getRangesForWords(words, this.keyMatchingWords, [subSettingMatches.descriptionMatchingWords, subSettingMatches.keyMatchingWords, subSettingMatches.valueMatchingWords]);
const subSettingKeyRanges: IRange[] = this.getRangesForWords(words, subSettingMatches.keyMatchingWords, [this.descriptionMatchingWords, this.keyMatchingWords, subSettingMatches.valueMatchingWords]);
const subSettinValueRanges: IRange[] = this.getRangesForWords(words, subSettingMatches.valueMatchingWords, [this.descriptionMatchingWords, this.keyMatchingWords, subSettingMatches.keyMatchingWords]);
result.push(...descriptionRanges, ...keyRanges, ...subSettingKeyRanges, ...subSettinValueRanges);
result.push(...subSettingMatches.matches);
}
}
return result;
}
private _doFindMatchesInSetting(searchString: string, setting: ISetting): IRange[] {
const registry: { [qualifiedKey: string]: IJSONSchema } = Registry.as<IConfigurationRegistry>(Extensions.Configuration).getConfigurationProperties();
const schema: IJSONSchema = registry[setting.key];
const words = searchString.split(' ');
const settingKeyAsWords: string = setting.key.split('.').join(' ');
for (const word of words) {
if (this.searchDescription) {
for (let lineIndex = 0; lineIndex < setting.description.length; lineIndex++) {
const descriptionMatches = matchesWords(word, setting.description[lineIndex], true);
if (descriptionMatches) {
this.descriptionMatchingWords.set(word, descriptionMatches.map(match => this.toDescriptionRange(setting, match, lineIndex)));
}
}
}
const keyMatches = or(matchesWords, matchesCamelCase)(word, settingKeyAsWords);
if (keyMatches) {
this.keyMatchingWords.set(word, keyMatches.map(match => this.toKeyRange(setting, match)));
}
const valueMatches = typeof setting.value === 'string' ? matchesContiguousSubString(word, setting.value) : null;
if (valueMatches) {
this.valueMatchingWords.set(word, valueMatches.map(match => this.toValueRange(setting, match)));
} else if (schema && schema.enum && schema.enum.some(enumValue => typeof enumValue === 'string' && !!matchesContiguousSubString(word, enumValue))) {
this.valueMatchingWords.set(word, []);
}
}
const descriptionRanges: IRange[] = [];
if (this.searchDescription) {
for (let lineIndex = 0; lineIndex < setting.description.length; lineIndex++) {
const matches = or(matchesContiguousSubString)(searchString, setting.description[lineIndex] || '') || [];
descriptionRanges.push(...matches.map(match => this.toDescriptionRange(setting, match, lineIndex)));
}
if (descriptionRanges.length === 0) {
descriptionRanges.push(...this.getRangesForWords(words, this.descriptionMatchingWords, [this.keyMatchingWords, this.valueMatchingWords]));
}
}
const keyMatches = or(matchesPrefix, matchesContiguousSubString)(searchString, setting.key);
const keyRanges: IRange[] = keyMatches ? keyMatches.map(match => this.toKeyRange(setting, match)) : this.getRangesForWords(words, this.keyMatchingWords, [this.descriptionMatchingWords, this.valueMatchingWords]);
let valueRanges: IRange[] = [];
if (setting.value && typeof setting.value === 'string') {
const valueMatches = or(matchesPrefix, matchesContiguousSubString)(searchString, setting.value);
valueRanges = valueMatches ? valueMatches.map(match => this.toValueRange(setting, match)) : this.getRangesForWords(words, this.valueMatchingWords, [this.keyMatchingWords, this.descriptionMatchingWords]);
} else {
valueRanges = this.valuesMatcher ? this.valuesMatcher(searchString, setting) : [];
}
return [...descriptionRanges, ...keyRanges, ...valueRanges];
}
private getRangesForWords(words: string[], from: Map<string, IRange[]>, others: Map<string, IRange[]>[]): IRange[] {
const result: IRange[] = [];
for (const word of words) {
const ranges = from.get(word);
if (ranges) {
result.push(...ranges);
} else if (this.requireFullQueryMatch && others.every(o => !o.has(word))) {
return [];
}
}
return result;
}
private toKeyRange(setting: ISetting, match: IMatch): IRange {
return {
startLineNumber: setting.keyRange.startLineNumber,
startColumn: setting.keyRange.startColumn + match.start,
endLineNumber: setting.keyRange.startLineNumber,
endColumn: setting.keyRange.startColumn + match.end
};
}
private toDescriptionRange(setting: ISetting, match: IMatch, lineIndex: number): IRange {
return {
startLineNumber: setting.descriptionRanges[lineIndex].startLineNumber,
startColumn: setting.descriptionRanges[lineIndex].startColumn + match.start,
endLineNumber: setting.descriptionRanges[lineIndex].endLineNumber,
endColumn: setting.descriptionRanges[lineIndex].startColumn + match.end
};
}
private toValueRange(setting: ISetting, match: IMatch): IRange {
return {
startLineNumber: setting.valueRange.startLineNumber,
startColumn: setting.valueRange.startColumn + match.start + 1,
endLineNumber: setting.valueRange.startLineNumber,
endColumn: setting.valueRange.startColumn + match.end + 1
};
}
}

View File

@@ -484,7 +484,7 @@ export class SettingsTargetsWidget extends Widget {
private _settingsTarget: SettingsTarget;
private readonly _onDidTargetChange = new Emitter<SettingsTarget>();
private readonly _onDidTargetChange = this._register(new Emitter<SettingsTarget>());
readonly onDidTargetChange: Event<SettingsTarget> = this._onDidTargetChange.event;
constructor(
@@ -517,7 +517,7 @@ export class SettingsTargetsWidget extends Widget {
const remoteAuthority = this.environmentService.configuration.remoteAuthority;
const hostLabel = remoteAuthority && this.labelService.getHostLabel(REMOTE_HOST_SCHEME, remoteAuthority);
const remoteSettingsLabel = localize('userSettingsRemote', "Remote") +
(hostLabel ? ` (${hostLabel})` : '');
(hostLabel ? ` [${hostLabel}]` : '');
this.userRemoteSettings = new Action('userSettingsRemote', remoteSettingsLabel, '.settings-tab', true, () => this.updateTarget(ConfigurationTarget.USER_REMOTE));
this.userRemoteSettings.tooltip = this.userRemoteSettings.label;
@@ -751,7 +751,7 @@ export class EditPreferenceWidget<T> extends Disposable {
private _editPreferenceDecoration: string[];
private readonly _onClick = new Emitter<IEditorMouseEvent>();
private readonly _onClick = this._register(new Emitter<IEditorMouseEvent>());
get onClick(): Event<IEditorMouseEvent> { return this._onClick.event; }
constructor(private editor: ICodeEditor

View File

@@ -6,7 +6,7 @@
import * as DOM from 'vs/base/browser/dom';
import { ITreeElement } from 'vs/base/browser/ui/tree/tree';
import * as arrays from 'vs/base/common/arrays';
import { Delayer, ThrottledDelayer } from 'vs/base/common/async';
import { Delayer, ThrottledDelayer, timeout } from 'vs/base/common/async';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import * as collections from 'vs/base/common/collections';
import { getErrorMessage, isPromiseCanceledError } from 'vs/base/common/errors';
@@ -211,7 +211,7 @@ export class SettingsEditor2 extends BaseEditor {
setInput(input: SettingsEditor2Input, options: SettingsEditorOptions | null, token: CancellationToken): Promise<void> {
this.inSettingsEditorContextKey.set(true);
return super.setInput(input, options, token)
.then(() => new Promise(process.nextTick)) // Force setInput to be async
.then(() => timeout(0)) // Force setInput to be async
.then(() => {
return this.render(token);
})
@@ -251,10 +251,12 @@ export class SettingsEditor2 extends BaseEditor {
}
}
setOptions(options: SettingsEditorOptions): void {
setOptions(options: SettingsEditorOptions | null): void {
super.setOptions(options);
this._setOptions(options);
if (options) {
this._setOptions(options);
}
}
private _setOptions(options: SettingsEditorOptions): void {
@@ -565,7 +567,7 @@ export class SettingsEditor2 extends BaseEditor {
}
private createTOC(parent: HTMLElement): void {
this.tocTreeModel = new TOCTreeModel(this.viewState);
this.tocTreeModel = this.instantiationService.createInstance(TOCTreeModel, this.viewState);
this.tocTreeContainer = DOM.append(parent, $('.settings-toc-container'));
this.tocTree = this._register(this.instantiationService.createInstance(TOCTree,

View File

@@ -25,7 +25,7 @@ import { Color, RGBA } from 'vs/base/common/color';
import { onUnexpectedError } from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
import { KeyCode } from 'vs/base/common/keyCodes';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { dispose, IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { ISpliceable } from 'vs/base/common/sequence';
import { escapeRegExpCharacters, startsWith } from 'vs/base/common/strings';
import { URI } from 'vs/base/common/uri';
@@ -45,6 +45,7 @@ import { ISettingsEditorViewState, settingKeyToDisplayFormat, SettingsTreeElemen
import { ExcludeSettingWidget, IExcludeChangeEvent, IExcludeDataItem, settingsHeaderForeground, settingsNumberInputBackground, settingsNumberInputBorder, settingsNumberInputForeground, settingsSelectBackground, settingsSelectBorder, settingsSelectForeground, settingsSelectListBorder, settingsTextInputBackground, settingsTextInputBorder, settingsTextInputForeground } 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';
const $ = DOM.$;
@@ -249,7 +250,7 @@ export interface ISettingOverrideClickEvent {
targetKey: string;
}
export abstract class AbstractSettingRenderer implements ITreeRenderer<SettingsTreeElement, never, any> {
export abstract class AbstractSettingRenderer extends Disposable implements ITreeRenderer<SettingsTreeElement, never, any> {
/** To override */
abstract get templateId(): string;
@@ -261,19 +262,19 @@ export abstract class AbstractSettingRenderer implements ITreeRenderer<SettingsT
static readonly SETTING_KEY_ATTR = 'data-key';
static readonly SETTING_ID_ATTR = 'data-id';
private readonly _onDidClickOverrideElement = new Emitter<ISettingOverrideClickEvent>();
private readonly _onDidClickOverrideElement = this._register(new Emitter<ISettingOverrideClickEvent>());
readonly onDidClickOverrideElement: Event<ISettingOverrideClickEvent> = this._onDidClickOverrideElement.event;
protected readonly _onDidChangeSetting = new Emitter<ISettingChangeEvent>();
protected readonly _onDidChangeSetting = this._register(new Emitter<ISettingChangeEvent>());
readonly onDidChangeSetting: Event<ISettingChangeEvent> = this._onDidChangeSetting.event;
protected readonly _onDidOpenSettings = new Emitter<string>();
protected readonly _onDidOpenSettings = this._register(new Emitter<string>());
readonly onDidOpenSettings: Event<string> = this._onDidOpenSettings.event;
private readonly _onDidClickSettingLink = new Emitter<ISettingLinkClickEvent>();
private readonly _onDidClickSettingLink = this._register(new Emitter<ISettingLinkClickEvent>());
readonly onDidClickSettingLink: Event<ISettingLinkClickEvent> = this._onDidClickSettingLink.event;
private readonly _onDidFocusSetting = new Emitter<SettingsTreeSettingElement>();
private readonly _onDidFocusSetting = this._register(new Emitter<SettingsTreeSettingElement>());
readonly onDidFocusSetting: Event<SettingsTreeSettingElement> = this._onDidFocusSetting.event;
// Put common injections back here
@@ -287,6 +288,7 @@ export abstract class AbstractSettingRenderer implements ITreeRenderer<SettingsT
@IContextMenuService protected readonly _contextMenuService: IContextMenuService,
@IKeybindingService protected readonly _keybindingService: IKeybindingService,
) {
super();
}
renderTemplate(container: HTMLElement): any {
@@ -939,11 +941,11 @@ export class SettingBoolRenderer extends AbstractSettingRenderer implements ITre
const deprecationWarningElement = DOM.append(container, $('.setting-item-deprecation-message'));
const toDispose: IDisposable[] = [];
const toDispose = new DisposableStore();
const checkbox = new Checkbox({ actionClassName: 'setting-value-checkbox', isChecked: true, title: '', inputActiveOptionBorder: undefined });
controlElement.appendChild(checkbox.domNode);
toDispose.push(checkbox);
toDispose.push(checkbox.onChange(() => {
toDispose.add(checkbox);
toDispose.add(checkbox.onChange(() => {
if (template.onChange) {
template.onChange(checkbox.checked);
}
@@ -951,7 +953,7 @@ export class SettingBoolRenderer extends AbstractSettingRenderer implements ITre
// Need to listen for mouse clicks on description and toggle checkbox - use target ID for safety
// Also have to ignore embedded links - too buried to stop propagation
toDispose.push(DOM.addDisposableListener(descriptionElement, DOM.EventType.MOUSE_DOWN, (e) => {
toDispose.add(DOM.addDisposableListener(descriptionElement, DOM.EventType.MOUSE_DOWN, (e) => {
const targetElement = <HTMLElement>e.target;
const targetId = descriptionElement.getAttribute('checkbox_label_target_id');
@@ -968,10 +970,10 @@ export class SettingBoolRenderer extends AbstractSettingRenderer implements ITre
checkbox.domNode.classList.add(AbstractSettingRenderer.CONTROL_CLASS);
const toolbarContainer = DOM.append(container, $('.setting-toolbar-container'));
const toolbar = this.renderSettingToolbar(toolbarContainer);
toDispose.push(toolbar);
toDispose.add(toolbar);
const template: ISettingBoolItemTemplate = {
toDispose,
toDispose: [toDispose],
containerElement: container,
categoryElement,
@@ -987,16 +989,16 @@ export class SettingBoolRenderer extends AbstractSettingRenderer implements ITre
this.addSettingElementFocusHandler(template);
// Prevent clicks from being handled by list
toDispose.push(DOM.addDisposableListener(controlElement, 'mousedown', (e: IMouseEvent) => e.stopPropagation()));
toDispose.add(DOM.addDisposableListener(controlElement, 'mousedown', (e: IMouseEvent) => e.stopPropagation()));
toDispose.push(DOM.addStandardDisposableListener(controlElement, 'keydown', (e: StandardKeyboardEvent) => {
toDispose.add(DOM.addStandardDisposableListener(controlElement, 'keydown', (e: StandardKeyboardEvent) => {
if (e.keyCode === KeyCode.Escape) {
e.browserEvent.stopPropagation();
}
}));
toDispose.push(DOM.addDisposableListener(titleElement, DOM.EventType.MOUSE_ENTER, e => container.classList.add('mouseover')));
toDispose.push(DOM.addDisposableListener(titleElement, DOM.EventType.MOUSE_LEAVE, e => container.classList.remove('mouseover')));
toDispose.add(DOM.addDisposableListener(titleElement, DOM.EventType.MOUSE_ENTER, e => container.classList.add('mouseover')));
toDispose.add(DOM.addDisposableListener(titleElement, DOM.EventType.MOUSE_LEAVE, e => container.classList.remove('mouseover')));
return template;
}
@@ -1163,6 +1165,7 @@ function escapeInvisibleChars(enumValue: string): string {
export class SettingsTreeFilter implements ITreeFilter<SettingsTreeElement> {
constructor(
private viewState: ISettingsEditorViewState,
@IWorkbenchEnvironmentService private environmentService: IWorkbenchEnvironmentService,
) { }
filter(element: SettingsTreeElement, parentVisibility: TreeVisibility): TreeFilterResult<void> {
@@ -1175,7 +1178,8 @@ export class SettingsTreeFilter implements ITreeFilter<SettingsTreeElement> {
// Non-user scope selected
if (element instanceof SettingsTreeSettingElement && this.viewState.settingsTarget !== ConfigurationTarget.USER_LOCAL) {
if (!element.matchesScope(this.viewState.settingsTarget)) {
const isRemote = !!this.environmentService.configuration.remoteAuthority;
if (!element.matchesScope(this.viewState.settingsTarget, isRemote)) {
return false;
}
}
@@ -1303,7 +1307,8 @@ export class SettingsTree extends ObjectTree<SettingsTreeElement> {
container: HTMLElement,
viewState: ISettingsEditorViewState,
renderers: ITreeRenderer<any, void, any>[],
@IThemeService themeService: IThemeService
@IThemeService themeService: IThemeService,
@IInstantiationService instantiationService: IInstantiationService,
) {
const treeClass = 'settings-editor-tree';
@@ -1320,7 +1325,7 @@ export class SettingsTree extends ObjectTree<SettingsTreeElement> {
}
},
styleController: new DefaultStyleController(DOM.createStyleSheet(container), treeClass),
filter: new SettingsTreeFilter(viewState)
filter: instantiationService.createInstance(SettingsTreeFilter, viewState)
});
this.disposables = [];

View File

@@ -14,6 +14,7 @@ import { SettingsTarget } from 'vs/workbench/contrib/preferences/browser/prefere
import { ITOCEntry, knownAcronyms, knownTermMappings } from 'vs/workbench/contrib/preferences/browser/settingsLayout';
import { MODIFIED_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';
export const ONLINE_SERVICES_SETTING_TAG = 'usesOnlineServices';
@@ -221,7 +222,7 @@ export class SettingsTreeSettingElement extends SettingsTreeElement {
}
}
matchesScope(scope: SettingsTarget): boolean {
matchesScope(scope: SettingsTarget, isRemote: boolean): boolean {
const configTarget = URI.isUri(scope) ? ConfigurationTarget.WORKSPACE_FOLDER : scope;
if (configTarget === ConfigurationTarget.WORKSPACE_FOLDER) {
@@ -236,6 +237,10 @@ export class SettingsTreeSettingElement extends SettingsTreeElement {
return this.setting.scope === ConfigurationScope.MACHINE || this.setting.scope === ConfigurationScope.WINDOW || this.setting.scope === ConfigurationScope.RESOURCE;
}
if (configTarget === ConfigurationTarget.USER_LOCAL && isRemote) {
return this.setting.scope !== ConfigurationScope.MACHINE;
}
return true;
}
@@ -479,7 +484,8 @@ export class SearchResultModel extends SettingsTreeModel {
constructor(
viewState: ISettingsEditorViewState,
@IConfigurationService configurationService: IConfigurationService
@IConfigurationService configurationService: IConfigurationService,
@IWorkbenchEnvironmentService private environmentService: IWorkbenchEnvironmentService,
) {
super(viewState, configurationService);
this.update({ id: 'searchResultModel', label: '' });
@@ -537,8 +543,9 @@ export class SearchResultModel extends SettingsTreeModel {
});
// Save time, filter children in the search model instead of relying on the tree filter, which still requires heights to be calculated.
const isRemote = !!this.environmentService.configuration.remoteAuthority;
this.root.children = this.root.children
.filter(child => child instanceof SettingsTreeSettingElement && child.matchesAllTags(this._viewState.tagFilters) && child.matchesScope(this._viewState.settingsTarget) && child.matchesAnyExtension(this._viewState.extensionFilters));
.filter(child => child instanceof SettingsTreeSettingElement && child.matchesAllTags(this._viewState.tagFilters) && child.matchesScope(this._viewState.settingsTarget, isRemote) && child.matchesAnyExtension(this._viewState.extensionFilters));
if (this.newExtensionSearchResults && this.newExtensionSearchResults.filterMatches.length) {
const newExtElement = new SettingsTreeNewExtensionsElement();

View File

@@ -203,7 +203,7 @@ export class ExcludeSettingWidget extends Disposable {
private model = new ExcludeSettingListModel();
private readonly _onDidChangeExclude = new Emitter<IExcludeChangeEvent>();
private readonly _onDidChangeExclude = this._register(new Emitter<IExcludeChangeEvent>());
readonly onDidChangeExclude: Event<IExcludeChangeEvent> = this._onDidChangeExclude.event;
get domNode(): HTMLElement {

View File

@@ -17,6 +17,7 @@ import { SettingsTreeFilter } from 'vs/workbench/contrib/preferences/browser/set
import { ISettingsEditorViewState, SearchResultModel, SettingsTreeElement, SettingsTreeGroupElement, SettingsTreeSettingElement } from 'vs/workbench/contrib/preferences/browser/settingsTreeModels';
import { settingsHeaderForeground } from 'vs/workbench/contrib/preferences/browser/settingsWidgets';
import { localize } from 'vs/nls';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
const $ = DOM.$;
@@ -25,7 +26,10 @@ export class TOCTreeModel {
private _currentSearchModel: SearchResultModel | null;
private _settingsTreeRoot: SettingsTreeGroupElement;
constructor(private _viewState: ISettingsEditorViewState) {
constructor(
private _viewState: ISettingsEditorViewState,
@IWorkbenchEnvironmentService private environmentService: IWorkbenchEnvironmentService
) {
}
get settingsTreeRoot(): SettingsTreeGroupElement {
@@ -81,7 +85,8 @@ export class TOCTreeModel {
}
// Check everything that the SettingsFilter checks except whether it's filtered by a category
return child.matchesScope(this._viewState.settingsTarget) && child.matchesAllTags(this._viewState.tagFilters) && child.matchesAnyExtension(this._viewState.extensionFilters);
const isRemote = !!this.environmentService.configuration.remoteAuthority;
return child.matchesScope(this._viewState.settingsTarget, isRemote) && child.matchesAllTags(this._viewState.tagFilters) && child.matchesAnyExtension(this._viewState.extensionFilters);
}).length;
}
}

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { isLinux } from 'vs/base/common/platform';
import { isEqual } from 'vs/base/common/resources';
import { endsWith } from 'vs/base/common/strings';
@@ -79,7 +79,7 @@ export class PreferencesContribution implements IWorkbenchContribution {
}
// Global User Settings File
if (isEqual(resource, URI.file(this.environmentService.appSettingsPath), !isLinux)) {
if (isEqual(resource, this.environmentService.settingsResource, !isLinux)) {
return { override: this.preferencesService.openGlobalSettings(true, options, group) };
}
@@ -129,14 +129,14 @@ export class PreferencesContribution implements IWorkbenchContribution {
const modelContent = JSON.stringify(schema);
const languageSelection = this.modeService.create('jsonc');
const model = this.modelService.createModel(modelContent, languageSelection, uri);
const disposables: IDisposable[] = [];
disposables.push(schemaRegistry.onDidChangeSchema(schemaUri => {
const disposables = new DisposableStore();
disposables.add(schemaRegistry.onDidChangeSchema(schemaUri => {
if (schemaUri === uri.toString()) {
schema = schemaRegistry.getSchemaContributions().schemas[uri.toString()];
model.setValue(JSON.stringify(schema));
}
}));
disposables.push(model.onWillDispose(() => dispose(disposables)));
disposables.add(model.onWillDispose(() => disposables.dispose()));
return model;
}

View File

@@ -4,18 +4,12 @@
*--------------------------------------------------------------------------------------------*/
import { ISettingsEditorModel, ISetting, ISettingsGroup, IFilterMetadata, ISearchResult, IGroupFilter, ISettingMatcher, IScoredResults, ISettingMatch, IRemoteSetting, IExtensionSetting } from 'vs/workbench/services/preferences/common/preferences';
import { IRange } from 'vs/editor/common/core/range';
import { distinct, top } from 'vs/base/common/arrays';
import { top } from 'vs/base/common/arrays';
import * as strings from 'vs/base/common/strings';
import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { Registry } from 'vs/platform/registry/common/platform';
import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry';
import { IMatch, or, matchesContiguousSubString, matchesPrefix, matchesCamelCase, matchesWords } from 'vs/base/common/filters';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IRequestService } from 'vs/platform/request/node/request';
import { asJson } from 'vs/base/node/request';
import { Disposable } from 'vs/base/common/lifecycle';
import { IExtensionManagementService, ILocalExtension, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ILogService } from 'vs/platform/log/common/log';
import { IPreferencesSearchService, ISearchProvider, IWorkbenchSettingsConfiguration } from 'vs/workbench/contrib/preferences/common/preferences';
@@ -24,25 +18,26 @@ import { canceled } from 'vs/base/common/errors';
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
import { nullRange } from 'vs/workbench/services/preferences/common/preferencesModels';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { PreferencesSearchService as LocalPreferencesSearchService, SettingMatches } from 'vs/workbench/contrib/preferences/browser/preferencesSearch';
export interface IEndpointDetails {
urlBase?: string;
key?: string;
}
export class PreferencesSearchService extends Disposable implements IPreferencesSearchService {
export class PreferencesSearchService extends LocalPreferencesSearchService implements IPreferencesSearchService {
_serviceBrand: any;
private _installedExtensions: Promise<ILocalExtension[]>;
constructor(
@IInstantiationService instantiationService: IInstantiationService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService
) {
super();
super(instantiationService);
// This request goes to the shared process but results won't change during a window's lifetime, so cache the results.
this._installedExtensions = this.extensionManagementService.getInstalled(ExtensionType.User).then(exts => {
@@ -86,10 +81,6 @@ export class PreferencesSearchService extends Disposable implements IPreferences
return this.remoteSearchAllowed ? this.instantiationService.createInstance(RemoteSearchProvider, opts, this._installedExtensions) : undefined;
}
getLocalSearchProvider(filter: string): LocalSearchProvider {
return this.instantiationService.createInstance(LocalSearchProvider, filter);
}
}
export class LocalSearchProvider implements ISearchProvider {
@@ -437,129 +428,4 @@ function remoteSettingToISetting(remoteSetting: IRemoteSetting): IExtensionSetti
extensionName: remoteSetting.extensionName,
extensionPublisher: remoteSetting.extensionPublisher
};
}
class SettingMatches {
private readonly descriptionMatchingWords: Map<string, IRange[]> = new Map<string, IRange[]>();
private readonly keyMatchingWords: Map<string, IRange[]> = new Map<string, IRange[]>();
private readonly valueMatchingWords: Map<string, IRange[]> = new Map<string, IRange[]>();
readonly matches: IRange[];
constructor(searchString: string, setting: ISetting, private requireFullQueryMatch: boolean, private searchDescription: boolean, private valuesMatcher: (filter: string, setting: ISetting) => IRange[]) {
this.matches = distinct(this._findMatchesInSetting(searchString, setting), (match) => `${match.startLineNumber}_${match.startColumn}_${match.endLineNumber}_${match.endColumn}_`);
}
private _findMatchesInSetting(searchString: string, setting: ISetting): IRange[] {
const result = this._doFindMatchesInSetting(searchString, setting);
if (setting.overrides && setting.overrides.length) {
for (const subSetting of setting.overrides) {
const subSettingMatches = new SettingMatches(searchString, subSetting, this.requireFullQueryMatch, this.searchDescription, this.valuesMatcher);
const words = searchString.split(' ');
const descriptionRanges: IRange[] = this.getRangesForWords(words, this.descriptionMatchingWords, [subSettingMatches.descriptionMatchingWords, subSettingMatches.keyMatchingWords, subSettingMatches.valueMatchingWords]);
const keyRanges: IRange[] = this.getRangesForWords(words, this.keyMatchingWords, [subSettingMatches.descriptionMatchingWords, subSettingMatches.keyMatchingWords, subSettingMatches.valueMatchingWords]);
const subSettingKeyRanges: IRange[] = this.getRangesForWords(words, subSettingMatches.keyMatchingWords, [this.descriptionMatchingWords, this.keyMatchingWords, subSettingMatches.valueMatchingWords]);
const subSettinValueRanges: IRange[] = this.getRangesForWords(words, subSettingMatches.valueMatchingWords, [this.descriptionMatchingWords, this.keyMatchingWords, subSettingMatches.keyMatchingWords]);
result.push(...descriptionRanges, ...keyRanges, ...subSettingKeyRanges, ...subSettinValueRanges);
result.push(...subSettingMatches.matches);
}
}
return result;
}
private _doFindMatchesInSetting(searchString: string, setting: ISetting): IRange[] {
const registry: { [qualifiedKey: string]: IJSONSchema } = Registry.as<IConfigurationRegistry>(Extensions.Configuration).getConfigurationProperties();
const schema: IJSONSchema = registry[setting.key];
const words = searchString.split(' ');
const settingKeyAsWords: string = setting.key.split('.').join(' ');
for (const word of words) {
if (this.searchDescription) {
for (let lineIndex = 0; lineIndex < setting.description.length; lineIndex++) {
const descriptionMatches = matchesWords(word, setting.description[lineIndex], true);
if (descriptionMatches) {
this.descriptionMatchingWords.set(word, descriptionMatches.map(match => this.toDescriptionRange(setting, match, lineIndex)));
}
}
}
const keyMatches = or(matchesWords, matchesCamelCase)(word, settingKeyAsWords);
if (keyMatches) {
this.keyMatchingWords.set(word, keyMatches.map(match => this.toKeyRange(setting, match)));
}
const valueMatches = typeof setting.value === 'string' ? matchesContiguousSubString(word, setting.value) : null;
if (valueMatches) {
this.valueMatchingWords.set(word, valueMatches.map(match => this.toValueRange(setting, match)));
} else if (schema && schema.enum && schema.enum.some(enumValue => typeof enumValue === 'string' && !!matchesContiguousSubString(word, enumValue))) {
this.valueMatchingWords.set(word, []);
}
}
const descriptionRanges: IRange[] = [];
if (this.searchDescription) {
for (let lineIndex = 0; lineIndex < setting.description.length; lineIndex++) {
const matches = or(matchesContiguousSubString)(searchString, setting.description[lineIndex] || '') || [];
descriptionRanges.push(...matches.map(match => this.toDescriptionRange(setting, match, lineIndex)));
}
if (descriptionRanges.length === 0) {
descriptionRanges.push(...this.getRangesForWords(words, this.descriptionMatchingWords, [this.keyMatchingWords, this.valueMatchingWords]));
}
}
const keyMatches = or(matchesPrefix, matchesContiguousSubString)(searchString, setting.key);
const keyRanges: IRange[] = keyMatches ? keyMatches.map(match => this.toKeyRange(setting, match)) : this.getRangesForWords(words, this.keyMatchingWords, [this.descriptionMatchingWords, this.valueMatchingWords]);
let valueRanges: IRange[] = [];
if (setting.value && typeof setting.value === 'string') {
const valueMatches = or(matchesPrefix, matchesContiguousSubString)(searchString, setting.value);
valueRanges = valueMatches ? valueMatches.map(match => this.toValueRange(setting, match)) : this.getRangesForWords(words, this.valueMatchingWords, [this.keyMatchingWords, this.descriptionMatchingWords]);
} else {
valueRanges = this.valuesMatcher ? this.valuesMatcher(searchString, setting) : [];
}
return [...descriptionRanges, ...keyRanges, ...valueRanges];
}
private getRangesForWords(words: string[], from: Map<string, IRange[]>, others: Map<string, IRange[]>[]): IRange[] {
const result: IRange[] = [];
for (const word of words) {
const ranges = from.get(word);
if (ranges) {
result.push(...ranges);
} else if (this.requireFullQueryMatch && others.every(o => !o.has(word))) {
return [];
}
}
return result;
}
private toKeyRange(setting: ISetting, match: IMatch): IRange {
return {
startLineNumber: setting.keyRange.startLineNumber,
startColumn: setting.keyRange.startColumn + match.start,
endLineNumber: setting.keyRange.startLineNumber,
endColumn: setting.keyRange.startColumn + match.end
};
}
private toDescriptionRange(setting: ISetting, match: IMatch, lineIndex: number): IRange {
return {
startLineNumber: setting.descriptionRanges[lineIndex].startLineNumber,
startColumn: setting.descriptionRanges[lineIndex].startColumn + match.start,
endLineNumber: setting.descriptionRanges[lineIndex].endLineNumber,
endColumn: setting.descriptionRanges[lineIndex].startColumn + match.end
};
}
private toValueRange(setting: ISetting, match: IMatch): IRange {
return {
startLineNumber: setting.valueRange.startLineNumber,
startColumn: setting.valueRange.startColumn + match.start + 1,
endLineNumber: setting.valueRange.startLineNumber,
endColumn: setting.valueRange.startColumn + match.end + 1
};
}
}
}