mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-08 17:19:48 +01:00
#18132 - Improve settings editor layout
- Extend search across left and right editors - Show tabs inside settings editor to show user and workspace settings - Improve highlighting of settings
This commit is contained in:
@@ -88,6 +88,7 @@ export interface INavigator<T> extends IIterator<T> {
|
||||
parent(): T;
|
||||
first(): T;
|
||||
last(): T;
|
||||
next(): T;
|
||||
}
|
||||
|
||||
export class MappedNavigator<T, R> extends MappedIterator<T, R> implements INavigator<R> {
|
||||
@@ -101,4 +102,5 @@ export class MappedNavigator<T, R> extends MappedIterator<T, R> implements INavi
|
||||
parent() { return this.fn(this.navigator.parent()); }
|
||||
first() { return this.fn(this.navigator.first()); }
|
||||
last() { return this.fn(this.navigator.last()); }
|
||||
next() { return this.fn(this.navigator.next()); }
|
||||
}
|
||||
|
||||
@@ -452,8 +452,7 @@ export class VSCodeMenu {
|
||||
}
|
||||
|
||||
private getPreferencesMenu(): Electron.MenuItem {
|
||||
const userSettings = this.createMenuItem(nls.localize({ key: 'miOpenSettings', comment: ['&& denotes a mnemonic'] }, "&&User Settings"), 'workbench.action.openGlobalSettings');
|
||||
const workspaceSettings = this.createMenuItem(nls.localize({ key: 'miOpenWorkspaceSettings', comment: ['&& denotes a mnemonic'] }, "&&Workspace Settings"), 'workbench.action.openWorkspaceSettings');
|
||||
const settings = this.createMenuItem(nls.localize({ key: 'miOpenSettings', comment: ['&& denotes a mnemonic'] }, "&&Settings"), 'workbench.action.openSettings');
|
||||
const kebindingSettings = this.createMenuItem(nls.localize({ key: 'miOpenKeymap', comment: ['&& denotes a mnemonic'] }, "&&Keyboard Shortcuts"), 'workbench.action.openGlobalKeybindings');
|
||||
const keymapExtensions = this.createMenuItem(nls.localize({ key: 'miOpenKeymapExtensions', comment: ['&& denotes a mnemonic'] }, "&&Keymap Extensions"), 'workbench.extensions.action.showRecommendedKeymapExtensions');
|
||||
const snippetsSettings = this.createMenuItem(nls.localize({ key: 'miOpenSnippets', comment: ['&& denotes a mnemonic'] }, "User &&Snippets"), 'workbench.action.openSnippets');
|
||||
@@ -461,8 +460,7 @@ export class VSCodeMenu {
|
||||
const iconThemeSelection = this.createMenuItem(nls.localize({ key: 'miSelectIconTheme', comment: ['&& denotes a mnemonic'] }, "File &&Icon Theme"), 'workbench.action.selectIconTheme');
|
||||
|
||||
const preferencesMenu = new Menu();
|
||||
preferencesMenu.append(userSettings);
|
||||
preferencesMenu.append(workspaceSettings);
|
||||
preferencesMenu.append(settings);
|
||||
preferencesMenu.append(__separator__());
|
||||
preferencesMenu.append(kebindingSettings);
|
||||
preferencesMenu.append(keymapExtensions);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { toResource } from 'vs/workbench/common/editor';
|
||||
@@ -21,12 +22,16 @@ export class RangeHighlightDecorations implements IDisposable {
|
||||
private editor: editorCommon.ICommonCodeEditor = null;
|
||||
private editorDisposables: IDisposable[] = [];
|
||||
|
||||
private _onHighlightRemoved: Emitter<void> = new Emitter<void>();
|
||||
public readonly onHighlghtRemoved: Event<void> = this._onHighlightRemoved.event;
|
||||
|
||||
constructor( @IWorkbenchEditorService private editorService: IWorkbenchEditorService) {
|
||||
}
|
||||
|
||||
public removeHighlightRange() {
|
||||
if (this.editor && this.rangeHighlightDecorationId) {
|
||||
this.doRemoveRangeHighlight(this.editor, this.rangeHighlightDecorationId);
|
||||
if (this.editor && this.editor.getModel() && this.rangeHighlightDecorationId) {
|
||||
this.editor.deltaDecorations([this.rangeHighlightDecorationId], []);
|
||||
this._onHighlightRemoved.fire();
|
||||
}
|
||||
this.rangeHighlightDecorationId = null;
|
||||
}
|
||||
@@ -67,12 +72,12 @@ export class RangeHighlightDecorations implements IDisposable {
|
||||
|| e.reason === editorCommon.CursorChangeReason.Undo
|
||||
|| e.reason === editorCommon.CursorChangeReason.Redo
|
||||
) {
|
||||
this.doRemoveRangeHighlight(this.editor, this.rangeHighlightDecorationId);
|
||||
this.removeHighlightRange();
|
||||
}
|
||||
}));
|
||||
this.editorDisposables.push(this.editor.onDidChangeModel(() => { this.doRemoveRangeHighlight(this.editor, this.rangeHighlightDecorationId); }));
|
||||
this.editorDisposables.push(this.editor.onDidChangeModel(() => { this.removeHighlightRange(); }));
|
||||
this.editorDisposables.push(this.editor.onDidDispose(() => {
|
||||
this.doRemoveRangeHighlight(this.editor, this.rangeHighlightDecorationId);
|
||||
this.removeHighlightRange();
|
||||
this.editor = null;
|
||||
}));
|
||||
}
|
||||
@@ -83,10 +88,6 @@ export class RangeHighlightDecorations implements IDisposable {
|
||||
this.editorDisposables = [];
|
||||
}
|
||||
|
||||
private doRemoveRangeHighlight(model: editorCommon.ICommonCodeEditor, rangeHighlightDecorationId: string) {
|
||||
model.deltaDecorations([rangeHighlightDecorationId], []);
|
||||
}
|
||||
|
||||
private createRangeHighlightDecoration(isWholeLine: boolean = true): editorCommon.IModelDecorationOptions {
|
||||
return {
|
||||
stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
|
||||
@@ -3,57 +3,83 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.settings-header-widget {
|
||||
border-bottom: 1px solid #efefef;
|
||||
.preferences-editor > .preferences-header {
|
||||
border-bottom: 1px solid #efeff2;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding-left: 27px;
|
||||
padding-right: 32px;
|
||||
padding-bottom: 11px;
|
||||
padding-top: 11px;
|
||||
}
|
||||
|
||||
.vs-dark .settings-header-widget {
|
||||
.vs-dark .preferences-editor > .preferences-header {
|
||||
border-bottom: 1px solid #2d2d2d;
|
||||
}
|
||||
|
||||
.settings-tabs-widget {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.settings-tabs-widget > .settings-tab {
|
||||
text-transform: uppercase;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
margin-left: 20px;
|
||||
padding-top: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.settings-tabs-widget > .settings-tab.active {
|
||||
border-bottom: 2px solid #ccc;
|
||||
}
|
||||
|
||||
.settings-tabs-widget > .settings-tab.disabled {
|
||||
opacity: 0.5;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.preferences-header > .settings-header-widget {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.settings-header-widget > .settings-header-container {
|
||||
padding-top: 8px;
|
||||
padding-left: 27px;
|
||||
padding-right: 32px;
|
||||
}
|
||||
|
||||
.settings-header-widget > .settings-count-widget {
|
||||
margin: 5px 0px;
|
||||
padding: 0px 8px;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.settings-header-widget > .settings-count-widget:not(.no-results) {
|
||||
background-color: #EFEFF2;
|
||||
}
|
||||
|
||||
.hc-black .settings-header-widget > .settings-count-widget:not(.no-results),
|
||||
.vs-dark .settings-header-widget > .settings-count-widget:not(.no-results) {
|
||||
background-color: #2D2D30;
|
||||
}
|
||||
|
||||
.settings-header-widget > .settings-count-widget.no-results {
|
||||
background-color: rgba(255,0,0,0.5);
|
||||
}
|
||||
|
||||
.hc-black .settings-header-widget > .settings-count-widget.no-results,
|
||||
.vs-dark .settings-header-widget > .settings-count-widget.no-results {
|
||||
background-color: rgba(255,0,0,0.3);
|
||||
}
|
||||
|
||||
.settings-header-widget > .settings-search-container {
|
||||
padding-left: 27px;
|
||||
padding-right: 32px;
|
||||
padding-bottom: 11px;
|
||||
padding-top: 11px;
|
||||
}
|
||||
|
||||
.vs .settings-header-widget > .settings-search-container {
|
||||
background: #efeff2;
|
||||
}
|
||||
.vs-dark .settings-header-widget > .settings-search-container {
|
||||
background: #2d2d30;
|
||||
}
|
||||
|
||||
.settings-header-widget > .settings-header-container > .settings-title-container {
|
||||
display: flex
|
||||
}
|
||||
|
||||
.settings-header-widget > .settings-header-container > .settings-title-container > .settings-info-container {
|
||||
white-space: pre-wrap;
|
||||
margin-bottom: 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.vs .settings-header-widget > .settings-header-container > .settings-title-container > .settings-info-container {
|
||||
color: #6f6f6f;
|
||||
}
|
||||
.vs-dark .settings-header-widget > .settings-header-container > .settings-title-container > .settings-info-container {
|
||||
color: #bbbbbb;
|
||||
}
|
||||
.hc-black .settings-header-widget > .settings-header-container > .settings-title-container > .settings-info-container {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.settings-header-widget > .settings-header-container > .settings-title-container > .settings-info-container .title-label {
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.settings-header-widget > .settings-search-container > .settings-search-input {
|
||||
@@ -62,6 +88,7 @@
|
||||
|
||||
.settings-header-widget > .settings-search-container > .settings-search-input > .monaco-inputbox {
|
||||
height: 30px;
|
||||
min-width: 350px;
|
||||
}
|
||||
|
||||
.vs .settings-header-widget > .settings-search-container > .settings-search-input > .monaco-inputbox {
|
||||
@@ -80,6 +107,14 @@
|
||||
background-image: url('search_inverse.svg');
|
||||
}
|
||||
|
||||
.vs-dark .preferences-editor .side-by-side-preferences-editor > .editable-preferences-editor-container {
|
||||
box-shadow: -6px 0 5px -5px black;
|
||||
}
|
||||
|
||||
.preferences-editor .side-by-side-preferences-editor > .editable-preferences-editor-container {
|
||||
box-shadow: -6px 0 5px -5px #DDD;
|
||||
}
|
||||
|
||||
.monaco-editor .settings-group-title-widget {
|
||||
z-index: 1;
|
||||
}
|
||||
@@ -102,7 +137,6 @@
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
||||
.monaco-editor.vs-dark .settings-group-title-widget .title-container.focused,
|
||||
.monaco-editor.vs .settings-group-title-widget .title-container.focused {
|
||||
outline: none !important;
|
||||
@@ -182,36 +216,4 @@
|
||||
.vs-dark .title-actions .action-item .icon.collapseAll,
|
||||
.vs-dark .editor-actions .action-item .icon.collapseAll {
|
||||
background: url('collapseAll_inverse.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.monaco-editor .settings-count-widget {
|
||||
padding: 4px 10px 4px 10px;
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 28px;
|
||||
border-radius: 2px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.monaco-editor .settings-count-widget.show {
|
||||
display: inherit;
|
||||
}
|
||||
|
||||
.monaco-editor .settings-count-widget.show:not(.no-results) {
|
||||
background-color: #EFEFF2;
|
||||
}
|
||||
|
||||
.monaco-editor.hc-black .settings-count-widget.show:not(.no-results),
|
||||
.monaco-editor.vs-dark .settings-count-widget.show:not(.no-results) {
|
||||
background-color: #2D2D30;
|
||||
}
|
||||
|
||||
.monaco-editor .settings-count-widget.show.no-results {
|
||||
background-color: rgba(255,0,0,0.5);
|
||||
}
|
||||
|
||||
.monaco-editor.hc-black .settings-count-widget.show.no-results,
|
||||
.monaco-editor.vs-dark .settings-count-widget.show.no-results {
|
||||
background-color: rgba(255,0,0,0.3);
|
||||
}
|
||||
@@ -14,8 +14,8 @@ import { MenuId, MenuRegistry, SyncActionDescriptor } from 'vs/platform/actions/
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { DefaultPreferencesEditor, DefaultPreferencesEditorInput } from 'vs/workbench/parts/preferences/browser/preferencesEditor';
|
||||
import { OpenGlobalSettingsAction, OpenGlobalKeybindingsAction, OpenWorkspaceSettingsAction } from 'vs/workbench/parts/preferences/browser/preferencesActions';
|
||||
import { DefaultPreferencesEditorInput, PreferencesEditor, PreferencesEditorInput } from 'vs/workbench/parts/preferences/browser/preferencesEditor';
|
||||
import { OpenSettingsAction, OpenGlobalSettingsAction, OpenGlobalKeybindingsAction, OpenWorkspaceSettingsAction } from 'vs/workbench/parts/preferences/browser/preferencesActions';
|
||||
import { IPreferencesService, CONTEXT_DEFAULT_SETTINGS_EDITOR, DEFAULT_EDITOR_COMMAND_COLLAPSE_ALL } from 'vs/workbench/parts/preferences/common/preferences';
|
||||
import { PreferencesService } from 'vs/workbench/parts/preferences/browser/preferencesService';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
@@ -27,21 +27,84 @@ registerSingleton(IPreferencesService, PreferencesService);
|
||||
|
||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
|
||||
new EditorDescriptor(
|
||||
DefaultPreferencesEditor.ID,
|
||||
PreferencesEditor.ID,
|
||||
nls.localize('defaultPreferencesEditor', "Default Preferences Editor"),
|
||||
'vs/workbench/parts/preferences/browser/preferencesEditor',
|
||||
'DefaultPreferencesEditor'
|
||||
'PreferencesEditor'
|
||||
),
|
||||
[
|
||||
new SyncDescriptor(DefaultPreferencesEditorInput)
|
||||
new SyncDescriptor(PreferencesEditorInput)
|
||||
]
|
||||
);
|
||||
|
||||
interface ISerializedPreferencesEditorInput {
|
||||
name: string;
|
||||
description: string;
|
||||
|
||||
detailsSerialized: string;
|
||||
masterSerialized: string;
|
||||
|
||||
detailsTypeId: string;
|
||||
masterTypeId: string;
|
||||
}
|
||||
|
||||
// Register Preferences Editor Input Factory
|
||||
class PreferencesEditorInputFactory implements IEditorInputFactory {
|
||||
|
||||
public serialize(editorInput: EditorInput): string {
|
||||
const input = <PreferencesEditorInput>editorInput;
|
||||
|
||||
if (input.details && input.master) {
|
||||
const registry = Registry.as<IEditorRegistry>(EditorExtensions.Editors);
|
||||
const detailsInputFactory = registry.getEditorInputFactory(input.details.getTypeId());
|
||||
const masterInputFactory = registry.getEditorInputFactory(input.master.getTypeId());
|
||||
|
||||
if (detailsInputFactory && masterInputFactory) {
|
||||
const detailsSerialized = detailsInputFactory.serialize(input.details);
|
||||
const masterSerialized = masterInputFactory.serialize(input.master);
|
||||
|
||||
if (detailsSerialized && masterSerialized) {
|
||||
return JSON.stringify(<ISerializedPreferencesEditorInput>{
|
||||
name: input.getName(),
|
||||
description: input.getDescription(),
|
||||
detailsSerialized,
|
||||
masterSerialized,
|
||||
detailsTypeId: input.details.getTypeId(),
|
||||
masterTypeId: input.master.getTypeId()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput {
|
||||
const deserialized: ISerializedPreferencesEditorInput = JSON.parse(serializedEditorInput);
|
||||
|
||||
const registry = Registry.as<IEditorRegistry>(EditorExtensions.Editors);
|
||||
const detailsInputFactory = registry.getEditorInputFactory(deserialized.detailsTypeId);
|
||||
const masterInputFactory = registry.getEditorInputFactory(deserialized.masterTypeId);
|
||||
|
||||
if (detailsInputFactory && masterInputFactory) {
|
||||
const detailsInput = detailsInputFactory.deserialize(instantiationService, deserialized.detailsSerialized);
|
||||
const masterInput = masterInputFactory.deserialize(instantiationService, deserialized.masterSerialized);
|
||||
|
||||
if (detailsInput && masterInput) {
|
||||
return new PreferencesEditorInput(deserialized.name, deserialized.description, detailsInput, masterInput);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface ISerializedDefaultPreferencesEditorInput {
|
||||
resource: string;
|
||||
}
|
||||
|
||||
// Register Editor Input Factory for Default Preferences Input
|
||||
// Register Default Preferences Editor Input Factory
|
||||
class DefaultPreferencesEditorInputFactory implements IEditorInputFactory {
|
||||
|
||||
public serialize(editorInput: EditorInput): string {
|
||||
@@ -59,17 +122,19 @@ class DefaultPreferencesEditorInputFactory implements IEditorInputFactory {
|
||||
}
|
||||
}
|
||||
|
||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditorInputFactory(PreferencesEditorInput.ID, PreferencesEditorInputFactory);
|
||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditorInputFactory(DefaultPreferencesEditorInput.ID, DefaultPreferencesEditorInputFactory);
|
||||
|
||||
// Contribute Global Actions
|
||||
const category = nls.localize('preferences', "Preferences");
|
||||
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenGlobalSettingsAction, OpenGlobalSettingsAction.ID, OpenGlobalSettingsAction.LABEL, {
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenSettingsAction, OpenSettingsAction.ID, OpenSettingsAction.LABEL, {
|
||||
primary: null,
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyCode.US_COMMA }
|
||||
}), 'Preferences: Open User Settings', category);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenGlobalKeybindingsAction, OpenGlobalKeybindingsAction.ID, OpenGlobalKeybindingsAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_S) }), 'Preferences: Open Keyboard Shortcuts', category);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenGlobalSettingsAction, OpenGlobalSettingsAction.ID, OpenGlobalSettingsAction.LABEL), 'Preferences: Open User Settings', category);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenWorkspaceSettingsAction, OpenWorkspaceSettingsAction.ID, OpenWorkspaceSettingsAction.LABEL), 'Preferences: Open Workspace Settings', category);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenGlobalKeybindingsAction, OpenGlobalKeybindingsAction.ID, OpenGlobalKeybindingsAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_S) }), 'Preferences: Open Keyboard Shortcuts', category);
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
|
||||
command: {
|
||||
|
||||
@@ -9,6 +9,24 @@ import * as nls from 'vs/nls';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { IPreferencesService } from 'vs/workbench/parts/preferences/common/preferences';
|
||||
|
||||
export class OpenSettingsAction extends Action {
|
||||
|
||||
public static ID = 'workbench.action.openSettings';
|
||||
public static LABEL = nls.localize('openSettings', "Open Settings");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IPreferencesService private preferencesService: IPreferencesService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
public run(event?: any): TPromise<void> {
|
||||
return this.preferencesService.openSettings();
|
||||
}
|
||||
}
|
||||
|
||||
export class OpenGlobalSettingsAction extends Action {
|
||||
|
||||
public static ID = 'workbench.action.openGlobalSettings';
|
||||
|
||||
@@ -10,16 +10,18 @@ import * as DOM from 'vs/base/browser/dom';
|
||||
import { Delayer } from 'vs/base/common/async';
|
||||
import { Dimension, Builder } from 'vs/base/browser/builder';
|
||||
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { flatten } from 'vs/base/common/arrays';
|
||||
import { ArrayIterator } from 'vs/base/common/iterator';
|
||||
import { flatten, distinct } from 'vs/base/common/arrays';
|
||||
import { ArrayNavigator, IIterator } from 'vs/base/common/iterator';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { SideBySideEditor } from 'vs/workbench/browser/parts/editor/sideBySideEditor';
|
||||
import { Registry } from 'vs/platform/platform';
|
||||
import { EditorOptions, toResource } from 'vs/workbench/common/editor';
|
||||
import { toResource, SideBySideEditorInput, EditorOptions, EditorInput, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor';
|
||||
import { BaseEditor, EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorModel';
|
||||
import { IEditorControl, IEditor } from 'vs/platform/editor/common/editor';
|
||||
import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
|
||||
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
@@ -35,7 +37,7 @@ import { SettingsEditorModel, DefaultSettingsEditorModel } from 'vs/workbench/pa
|
||||
import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions';
|
||||
import { ICodeEditor, IEditorMouseEvent, IEditorContributionCtor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IContextMenuService, ContextSubMenu } from 'vs/platform/contextview/browser/contextView';
|
||||
import { DefaultSettingsHeaderWidget, SettingsGroupTitleWidget, SettingsCountWidget, EditPreferenceWidget } from 'vs/workbench/parts/preferences/browser/preferencesWidgets';
|
||||
import { SearchWidget, SettingsTabsWidget, SettingsGroupTitleWidget, EditPreferenceWidget } from 'vs/workbench/parts/preferences/browser/preferencesWidgets';
|
||||
import { IContextKeyService, IContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { CommonEditorRegistry, EditorCommand, Command } from 'vs/editor/common/editorCommonExtensions';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
@@ -49,21 +51,26 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi
|
||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||
import { ITextModelResolverService } from 'vs/editor/common/services/resolverService';
|
||||
import { RangeHighlightDecorations } from 'vs/workbench/common/editor/rangeDecorations';
|
||||
import { IConfigurationEditingService } from 'vs/workbench/services/configuration/common/configurationEditing';
|
||||
import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { VSash } from 'vs/base/browser/ui/sash/sash';
|
||||
import { Widget } from 'vs/base/browser/ui/widget';
|
||||
|
||||
// Ignore following contributions
|
||||
import { FoldingController } from 'vs/editor/contrib/folding/browser/folding';
|
||||
import { FindController } from 'vs/editor/contrib/find/browser/find';
|
||||
import { SelectionHighlighter } from 'vs/editor/contrib/find/common/findController';
|
||||
|
||||
export class PreferencesEditorInput extends SideBySideEditorInput {
|
||||
public static ID: string = 'workbench.editorinputs.preferencesEditorInput';
|
||||
|
||||
getTypeId(): string {
|
||||
return PreferencesEditorInput.ID;
|
||||
}
|
||||
}
|
||||
|
||||
export class DefaultPreferencesEditorInput extends ResourceEditorInput {
|
||||
|
||||
public static ID = 'workbench.editorinputs.defaultpreferences';
|
||||
|
||||
private _willDispose = new Emitter<void>();
|
||||
public willDispose: Event<void> = this._willDispose.event;
|
||||
|
||||
constructor(defaultSettingsResource: URI,
|
||||
@ITextModelResolverService textModelResolverService: ITextModelResolverService
|
||||
) {
|
||||
@@ -74,10 +81,6 @@ export class DefaultPreferencesEditorInput extends ResourceEditorInput {
|
||||
return DefaultPreferencesEditorInput.ID;
|
||||
}
|
||||
|
||||
supportsSplitEditor(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
matches(other: any): boolean {
|
||||
if (!super.matches(other)) {
|
||||
return false;
|
||||
@@ -87,10 +90,268 @@ export class DefaultPreferencesEditorInput extends ResourceEditorInput {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._willDispose.fire();
|
||||
this._willDispose.dispose();
|
||||
export class PreferencesEditor extends BaseEditor {
|
||||
|
||||
public static ID: string = 'workbench.editor.preferencesEditor';
|
||||
|
||||
private headerContainer: HTMLElement;
|
||||
private searchWidget: SearchWidget;
|
||||
private settingsTabsWidget: SettingsTabsWidget;
|
||||
private sideBySidePreferencesWidget: SideBySidePreferencesWidget;
|
||||
|
||||
private delayedFilterLogging: Delayer<void>;
|
||||
private disposablesByInput: IDisposable[] = [];
|
||||
|
||||
constructor(
|
||||
@IPreferencesService private preferencesService: IPreferencesService,
|
||||
@IEnvironmentService private environmentService: IEnvironmentService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService
|
||||
) {
|
||||
super(PreferencesEditor.ID, telemetryService);
|
||||
this.delayedFilterLogging = new Delayer<void>(1000);
|
||||
}
|
||||
|
||||
public createEditor(parent: Builder): void {
|
||||
const parentElement = parent.getHTMLElement();
|
||||
DOM.addClass(parentElement, 'preferences-editor');
|
||||
|
||||
this.headerContainer = DOM.append(parentElement, DOM.$('.preferences-header'));
|
||||
|
||||
this.searchWidget = this._register(this.instantiationService.createInstance(SearchWidget, this.headerContainer));
|
||||
this._register(this.searchWidget.onDidChange(value => this.filterPreferences(value.trim())));
|
||||
this._register(this.searchWidget.onEnter(value => this.focusNextPreference()));
|
||||
|
||||
this.settingsTabsWidget = this._register(this.instantiationService.createInstance(SettingsTabsWidget, this.headerContainer));
|
||||
this._register(this.settingsTabsWidget.onSwitch(() => this.switchSettings()));
|
||||
|
||||
const editorsContainer = DOM.append(parentElement, DOM.$('.preferences-editors-container'));
|
||||
this.sideBySidePreferencesWidget = this._register(this.instantiationService.createInstance(SideBySidePreferencesWidget, editorsContainer));
|
||||
}
|
||||
|
||||
public setInput(newInput: PreferencesEditorInput, options?: EditorOptions): TPromise<void> {
|
||||
const oldInput = <PreferencesEditorInput>this.input;
|
||||
return super.setInput(newInput, options)
|
||||
.then(() => this.updateInput(oldInput, newInput, options));
|
||||
}
|
||||
|
||||
public layout(dimension: Dimension): void {
|
||||
const headerHeight = DOM.getTotalHeight(this.headerContainer);
|
||||
this.sideBySidePreferencesWidget.layout(new Dimension(dimension.width, dimension.height - headerHeight));
|
||||
}
|
||||
|
||||
public getControl(): IEditorControl {
|
||||
const editablePreferencesEditor = this.sideBySidePreferencesWidget.getEditablePreferencesEditor();
|
||||
return editablePreferencesEditor ? editablePreferencesEditor.getControl() : null;
|
||||
}
|
||||
|
||||
public focus(): void {
|
||||
this.searchWidget.focus();
|
||||
}
|
||||
|
||||
private updateInput(oldInput: PreferencesEditorInput, newInput: PreferencesEditorInput, options?: EditorOptions): TPromise<void> {
|
||||
const editablePreferencesUri = toResource(newInput.master);
|
||||
this.settingsTabsWidget.show(editablePreferencesUri.toString() === this.preferencesService.userSettingsResource.toString() ? ConfigurationTarget.USER : ConfigurationTarget.WORKSPACE);
|
||||
|
||||
this.disposablesByInput = dispose(this.disposablesByInput);
|
||||
return this.sideBySidePreferencesWidget.setInput(<DefaultPreferencesEditorInput>newInput.details, newInput.master, options).then(() => {
|
||||
this.showTotalCount();
|
||||
if (!this.getDefaultPreferencesRenderer()) {
|
||||
return;
|
||||
}
|
||||
this.getDefaultPreferencesRenderer().onFocusPreference(setting => this.getEditablePreferencesRenderer().focusPreference(setting), this.disposablesByInput);
|
||||
this.getDefaultPreferencesRenderer().onClearFocusPreference(setting => this.getEditablePreferencesRenderer().clearFocus(setting), this.disposablesByInput);
|
||||
this.filterPreferences(this.searchWidget.value());
|
||||
});
|
||||
}
|
||||
|
||||
private switchSettings(): void {
|
||||
const promise = this.input.isDirty() ? this.input.save() : TPromise.as(true);
|
||||
promise.done(value => this.preferencesService.switchSettings());
|
||||
}
|
||||
|
||||
private filterPreferences(filter: string) {
|
||||
if (!this.getDefaultPreferencesRenderer()) {
|
||||
return;
|
||||
}
|
||||
const defaultPreferencesRenderer = this.getDefaultPreferencesRenderer();
|
||||
const editablePreferencesRender = this.getEditablePreferencesRenderer();
|
||||
if (filter) {
|
||||
this.delayedFilterLogging.trigger(() => this.reportFilteringUsed(filter));
|
||||
const filterResult = defaultPreferencesRenderer.preferencesModel.filterSettings(filter);
|
||||
defaultPreferencesRenderer.filterPreferences(filterResult);
|
||||
editablePreferencesRender.filterPreferences(filterResult);
|
||||
const count = this.getCount(filterResult.filteredGroups);
|
||||
this.searchWidget.showMessage(this.showSearchResultsMessage(count), count);
|
||||
} else {
|
||||
defaultPreferencesRenderer.filterPreferences(null);
|
||||
editablePreferencesRender.filterPreferences(null);
|
||||
this.showTotalCount();
|
||||
}
|
||||
}
|
||||
|
||||
private showTotalCount(): void {
|
||||
if (this.getDefaultPreferencesRenderer()) {
|
||||
const count = this.getCount(this.getDefaultPreferencesRenderer().preferencesModel.settingsGroups);
|
||||
this.searchWidget.showMessage(nls.localize('totalSettingsMessage', "Total {0} Settings", count), count);
|
||||
}
|
||||
}
|
||||
|
||||
private showSearchResultsMessage(count: number): string {
|
||||
return count === 0 ? nls.localize('noSettingsFound', "No Settings matched") :
|
||||
count === 1 ? nls.localize('oneSettingFound', "1 Setting matched") :
|
||||
nls.localize('settingsFound', "{0} Settings matched", count);
|
||||
}
|
||||
|
||||
private focusNextPreference() {
|
||||
const defaultPreferencesRenderer = this.getDefaultPreferencesRenderer();
|
||||
if (defaultPreferencesRenderer) {
|
||||
const setting = defaultPreferencesRenderer.iterator.next();
|
||||
if (setting) {
|
||||
defaultPreferencesRenderer.focusPreference(setting);
|
||||
this.getEditablePreferencesRenderer().focusPreference(setting);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getDefaultPreferencesRenderer(): IPreferencesRenderer {
|
||||
const detailsEditor = this.sideBySidePreferencesWidget.getDefaultPreferencesEditor();
|
||||
if (detailsEditor) {
|
||||
return (<CodeEditor>this.sideBySidePreferencesWidget.getDefaultPreferencesEditor().getControl()).getContribution<PreferencesEditorContribution>(DefaultSettingsEditorContribution.ID).getPreferencesRenderer();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private getEditablePreferencesRenderer(): IPreferencesRenderer {
|
||||
if (this.sideBySidePreferencesWidget.getEditablePreferencesEditor()) {
|
||||
return (<CodeEditor>this.sideBySidePreferencesWidget.getEditablePreferencesEditor().getControl()).getContribution<PreferencesEditorContribution>(SettingsEditorContribution.ID).getPreferencesRenderer();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private reportFilteringUsed(filter: string): void {
|
||||
let data = {};
|
||||
data['filter'] = filter;
|
||||
this.telemetryService.publicLog('defaultSettings.filter', data);
|
||||
}
|
||||
|
||||
private getCount(settingsGroups: ISettingsGroup[]): number {
|
||||
let count = 0;
|
||||
for (const group of settingsGroups) {
|
||||
for (const section of group.sections) {
|
||||
count += section.settings.length;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
export class SideBySidePreferencesWidget extends Widget {
|
||||
|
||||
private dimension: Dimension;
|
||||
|
||||
private defaultPreferencesEditor: DefaultPreferencesEditor;
|
||||
private defaultPreferencesEditorContainer: HTMLElement;
|
||||
private editablePreferencesEditor: BaseEditor;
|
||||
private editablePreferencesEditorContainer: HTMLElement;
|
||||
|
||||
private sash: VSash;
|
||||
|
||||
constructor(parent: HTMLElement, @IInstantiationService private instantiationService: IInstantiationService) {
|
||||
super();
|
||||
this.create(parent);
|
||||
}
|
||||
|
||||
private create(parentElement: HTMLElement): void {
|
||||
DOM.addClass(parentElement, 'side-by-side-preferences-editor');
|
||||
this.createSash(parentElement);
|
||||
|
||||
this.defaultPreferencesEditorContainer = DOM.append(parentElement, DOM.$('.default-preferences-editor-container'));
|
||||
this.defaultPreferencesEditorContainer.style.position = 'absolute';
|
||||
this.defaultPreferencesEditor = this.instantiationService.createInstance(DefaultPreferencesEditor);
|
||||
this.defaultPreferencesEditor.create(new Builder(this.defaultPreferencesEditorContainer));
|
||||
|
||||
this.editablePreferencesEditorContainer = DOM.append(parentElement, DOM.$('.editable-preferences-editor-container'));
|
||||
this.editablePreferencesEditorContainer.style.position = 'absolute';
|
||||
}
|
||||
|
||||
public setInput(defaultPreferencesEditorInput: DefaultPreferencesEditorInput, editablePreferencesEditorInput: EditorInput, options?: EditorOptions): TPromise<void> {
|
||||
return this.getOrCreateEditablePreferencesEditor(editablePreferencesEditorInput)
|
||||
.then(() => {
|
||||
this.dolayout(this.sash.getVerticalSashLeft());
|
||||
return TPromise.join([this.defaultPreferencesEditor.updateInput(defaultPreferencesEditorInput, options, toResource(editablePreferencesEditorInput), this.editablePreferencesEditor),
|
||||
this.editablePreferencesEditor.setInput(editablePreferencesEditorInput, options)])
|
||||
.then(() => null);
|
||||
});
|
||||
}
|
||||
|
||||
public layout(dimension: Dimension): void {
|
||||
this.dimension = dimension;
|
||||
this.sash.setDimenesion(this.dimension);
|
||||
}
|
||||
|
||||
public getEditablePreferencesEditor(): IEditor {
|
||||
return this.editablePreferencesEditor;
|
||||
}
|
||||
|
||||
public getDefaultPreferencesEditor(): DefaultPreferencesEditor {
|
||||
return this.defaultPreferencesEditor;
|
||||
}
|
||||
|
||||
private getOrCreateEditablePreferencesEditor(editorInput: EditorInput): TPromise<BaseEditor> {
|
||||
if (this.editablePreferencesEditor) {
|
||||
return TPromise.as(this.editablePreferencesEditor);
|
||||
}
|
||||
const descriptor = Registry.as<IEditorRegistry>(EditorExtensions.Editors).getEditor(editorInput);
|
||||
return this.instantiationService.createInstance(<EditorDescriptor>descriptor)
|
||||
.then((editor: BaseEditor) => {
|
||||
this.editablePreferencesEditor = editor;
|
||||
this.editablePreferencesEditor.create(new Builder(this.editablePreferencesEditorContainer));
|
||||
this.editablePreferencesEditor.setVisible(true);
|
||||
return editor;
|
||||
});
|
||||
}
|
||||
|
||||
private createSash(parentElement: HTMLElement): void {
|
||||
this.sash = this._register(new VSash(parentElement, 220));
|
||||
this._register(this.sash.onPositionChange(position => this.dolayout(position)));
|
||||
}
|
||||
|
||||
private dolayout(splitPoint: number): void {
|
||||
if (!this.editablePreferencesEditor || !this.dimension) {
|
||||
return;
|
||||
}
|
||||
const masterEditorWidth = this.dimension.width - splitPoint;
|
||||
const detailsEditorWidth = this.dimension.width - masterEditorWidth;
|
||||
|
||||
this.defaultPreferencesEditorContainer.style.width = `${detailsEditorWidth}px`;
|
||||
this.defaultPreferencesEditorContainer.style.height = `${this.dimension.height}px`;
|
||||
this.defaultPreferencesEditorContainer.style.left = '0px';
|
||||
|
||||
this.editablePreferencesEditorContainer.style.width = `${masterEditorWidth}px`;
|
||||
this.editablePreferencesEditorContainer.style.height = `${this.dimension.height}px`;
|
||||
this.editablePreferencesEditorContainer.style.left = `${splitPoint}px`;
|
||||
|
||||
this.defaultPreferencesEditor.layout(new Dimension(detailsEditorWidth, this.dimension.height));
|
||||
this.editablePreferencesEditor.layout(new Dimension(masterEditorWidth, this.dimension.height));
|
||||
}
|
||||
|
||||
private disposeEditors(): void {
|
||||
if (this.defaultPreferencesEditor) {
|
||||
this.defaultPreferencesEditor.dispose();
|
||||
this.defaultPreferencesEditor = null;
|
||||
}
|
||||
if (this.editablePreferencesEditor) {
|
||||
this.editablePreferencesEditor.dispose();
|
||||
this.editablePreferencesEditor = null;
|
||||
}
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this.disposeEditors();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -99,9 +360,6 @@ export class DefaultPreferencesEditor extends BaseTextEditor {
|
||||
|
||||
public static ID: string = 'workbench.editor.defaultPreferences';
|
||||
|
||||
private defaultSettingHeaderWidget: DefaultSettingsHeaderWidget;
|
||||
private delayedFilterLogging: Delayer<void>;
|
||||
|
||||
constructor(
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
|
||||
@@ -115,19 +373,10 @@ export class DefaultPreferencesEditor extends BaseTextEditor {
|
||||
@IModeService modeService: IModeService,
|
||||
) {
|
||||
super(DefaultPreferencesEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, modeService);
|
||||
this.delayedFilterLogging = new Delayer<void>(1000);
|
||||
}
|
||||
|
||||
public createEditorControl(parent: Builder, configuration: editorCommon.IEditorOptions): editorCommon.IEditor {
|
||||
const parentContainer = parent.getHTMLElement();
|
||||
|
||||
this.defaultSettingHeaderWidget = this._register(this.instantiationService.createInstance(DefaultSettingsHeaderWidget, parentContainer));
|
||||
this._register(this.defaultSettingHeaderWidget.onDidChange(value => this.filterPreferences(value)));
|
||||
this._register(this.defaultSettingHeaderWidget.onEnter(value => this.focusNextPreference()));
|
||||
|
||||
const defaultPreferencesEditor = this.instantiationService.createInstance(DefaultPreferencesCodeEditor, parentContainer, configuration);
|
||||
|
||||
return defaultPreferencesEditor;
|
||||
return this.instantiationService.createInstance(DefaultPreferencesCodeEditor, parent.getHTMLElement(), configuration);
|
||||
}
|
||||
|
||||
protected getConfigurationOverrides(): editorCommon.IEditorOptions {
|
||||
@@ -146,66 +395,30 @@ export class DefaultPreferencesEditor extends BaseTextEditor {
|
||||
return options;
|
||||
}
|
||||
|
||||
setInput(input: DefaultPreferencesEditorInput, options: EditorOptions): TPromise<void> {
|
||||
return super.setInput(input, options).then(() => this.updateInput());
|
||||
updateInput(input: DefaultPreferencesEditorInput, options: EditorOptions, editablePreferencesUri: URI, settingsEditor: BaseEditor): TPromise<void> {
|
||||
return this.setInput(input, options)
|
||||
.then(() => this.input.resolve()
|
||||
.then(editorModel => TPromise.join<any>([
|
||||
editorModel.load(),
|
||||
this.preferencesService.resolvePreferencesEditorModel(editablePreferencesUri)
|
||||
]))
|
||||
.then(([editorModel, preferencesModel]) => (<DefaultPreferencesCodeEditor>this.getControl()).setModels((<ResourceEditorModel>editorModel).textEditorModel, <SettingsEditorModel>preferencesModel, settingsEditor)));
|
||||
}
|
||||
|
||||
public layout(dimension: Dimension) {
|
||||
this.defaultSettingHeaderWidget.layout(dimension);
|
||||
const headerHeight = DOM.getTotalHeight(this.defaultSettingHeaderWidget.domNode);
|
||||
this.getControl().layout({
|
||||
height: dimension.height - headerHeight,
|
||||
width: dimension.width
|
||||
});
|
||||
}
|
||||
|
||||
public focus(): void {
|
||||
if (this.input) {
|
||||
this.defaultSettingHeaderWidget.focus();
|
||||
} else {
|
||||
super.focus();
|
||||
}
|
||||
}
|
||||
|
||||
private updateInput(): TPromise<void> {
|
||||
return this.input.resolve()
|
||||
.then(editorModel => TPromise.join<any>([
|
||||
editorModel.load(),
|
||||
// Default preferences editor is always part of side by side editor hence getting the master preferences model from active editor
|
||||
// TODO:@sandy check with Ben
|
||||
this.preferencesService.resolvePreferencesEditorModel(toResource(this.editorService.getActiveEditorInput(), { supportSideBySide: true }))
|
||||
]))
|
||||
.then(([editorModel, preferencesModel]) => (<DefaultPreferencesCodeEditor>this.getControl()).setModels((<ResourceEditorModel>editorModel).textEditorModel, <SettingsEditorModel>preferencesModel));
|
||||
}
|
||||
|
||||
private filterPreferences(filter: string) {
|
||||
this.delayedFilterLogging.trigger(() => this.reportFilteringUsed(filter));
|
||||
(<DefaultSettingsRenderer>this.getDefaultPreferencesContribution().getPreferencesRenderer()).filterPreferences(filter.trim());
|
||||
}
|
||||
|
||||
private focusNextPreference() {
|
||||
(<DefaultSettingsRenderer>this.getDefaultPreferencesContribution().getPreferencesRenderer()).focusNextSetting();
|
||||
this.getControl().layout(dimension);
|
||||
}
|
||||
|
||||
public clearInput(): void {
|
||||
this.getControl().setModel(null);
|
||||
super.clearInput();
|
||||
}
|
||||
|
||||
private getDefaultPreferencesContribution(): PreferencesEditorContribution {
|
||||
return (<CodeEditor>this.getControl()).getContribution<PreferencesEditorContribution>(DefaultSettingsEditorContribution.ID);
|
||||
}
|
||||
|
||||
private reportFilteringUsed(filter: string): void {
|
||||
let data = {};
|
||||
data['filter'] = filter;
|
||||
this.telemetryService.publicLog('defaultSettings.filter', data);
|
||||
}
|
||||
}
|
||||
|
||||
class DefaultPreferencesCodeEditor extends CodeEditor {
|
||||
|
||||
private _settingsModel: SettingsEditorModel;
|
||||
private _settingsEditor: BaseEditor;
|
||||
|
||||
protected _getContributions(): IEditorContributionCtor[] {
|
||||
let contributions = super._getContributions();
|
||||
@@ -215,19 +428,31 @@ class DefaultPreferencesCodeEditor extends CodeEditor {
|
||||
return contributions;
|
||||
}
|
||||
|
||||
setModels(model: editorCommon.IModel, settingsModel: SettingsEditorModel): void {
|
||||
setModels(model: editorCommon.IModel, settingsModel: SettingsEditorModel, settingsEditor: BaseEditor): void {
|
||||
this._settingsModel = settingsModel;
|
||||
this._settingsEditor = settingsEditor;
|
||||
return super.setModel(model);
|
||||
}
|
||||
|
||||
get settingsModel(): SettingsEditorModel {
|
||||
return this._settingsModel;
|
||||
}
|
||||
|
||||
get settingsEditor(): BaseEditor {
|
||||
return this._settingsEditor;
|
||||
}
|
||||
}
|
||||
|
||||
export interface IPreferencesRenderer {
|
||||
render();
|
||||
iterator: IIterator<ISetting>;
|
||||
onFocusPreference: Event<ISetting>;
|
||||
onClearFocusPreference: Event<ISetting>;
|
||||
preferencesModel: ISettingsEditorModel;
|
||||
render(): void;
|
||||
updatePreference(setting: ISetting, value: any): void;
|
||||
filterPreferences(filterResult: IFilterResult): void;
|
||||
focusPreference(setting: ISetting): void;
|
||||
clearFocus(setting: ISetting): void;
|
||||
dispose();
|
||||
}
|
||||
|
||||
@@ -285,7 +510,7 @@ export class DefaultSettingsEditorContribution extends PreferencesEditorContribu
|
||||
|
||||
protected createPreferencesRenderer(editorModel: IPreferencesEditorModel): IPreferencesRenderer {
|
||||
if (editorModel instanceof DefaultSettingsEditorModel) {
|
||||
return this.instantiationService.createInstance(DefaultSettingsRenderer, this.editor, editorModel, (<DefaultPreferencesCodeEditor>this.editor).settingsModel);
|
||||
return this.instantiationService.createInstance(DefaultSettingsRenderer, this.editor, editorModel);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -317,9 +542,17 @@ export class SettingsRenderer extends Disposable implements IPreferencesRenderer
|
||||
private initializationPromise: TPromise<void>;
|
||||
private settingHighlighter: SettingHighlighter;
|
||||
private editSettingActionRenderer: EditSettingRenderer;
|
||||
private highlightPreferencesRenderer: HighlightPreferencesRenderer;
|
||||
private defaultSettingsModel: DefaultSettingsEditorModel;
|
||||
private modelChangeDelayer: Delayer<void> = new Delayer<void>(200);
|
||||
|
||||
constructor(protected editor: ICodeEditor, protected settingsEditorModel: SettingsEditorModel,
|
||||
private _onFocusPreference: Emitter<ISetting> = new Emitter<ISetting>();
|
||||
public readonly onFocusPreference: Event<ISetting> = this._onFocusPreference.event;
|
||||
|
||||
private _onClearFocusPreference: Emitter<ISetting> = new Emitter<ISetting>();
|
||||
public readonly onClearFocusPreference: Event<ISetting> = this._onClearFocusPreference.event;
|
||||
|
||||
constructor(protected editor: ICodeEditor, public readonly preferencesModel: SettingsEditorModel,
|
||||
@IPreferencesService protected preferencesService: IPreferencesService,
|
||||
@ITelemetryService private telemetryService: ITelemetryService,
|
||||
@IConfigurationEditingService private configurationEditingService: IConfigurationEditingService,
|
||||
@@ -327,18 +560,26 @@ export class SettingsRenderer extends Disposable implements IPreferencesRenderer
|
||||
@IInstantiationService protected instantiationService: IInstantiationService
|
||||
) {
|
||||
super();
|
||||
this.settingHighlighter = this._register(instantiationService.createInstance(SettingHighlighter, editor));
|
||||
this.settingHighlighter = this._register(instantiationService.createInstance(SettingHighlighter, editor, this._onFocusPreference, this._onClearFocusPreference));
|
||||
this.highlightPreferencesRenderer = this._register(instantiationService.createInstance(HighlightPreferencesRenderer, editor));
|
||||
this.initializationPromise = this.initialize();
|
||||
}
|
||||
|
||||
public get iterator(): IIterator<ISetting> {
|
||||
return null;
|
||||
}
|
||||
|
||||
public render(): void {
|
||||
this.initializationPromise.then(() => this.editSettingActionRenderer.render(this.settingsEditorModel.settingsGroups));
|
||||
this.initializationPromise.then(() => {
|
||||
this.editSettingActionRenderer.render(this.preferencesModel.settingsGroups);
|
||||
});
|
||||
}
|
||||
|
||||
private initialize(): TPromise<void> {
|
||||
return this.preferencesService.createDefaultPreferencesEditorModel(this.preferencesService.defaultSettingsResource)
|
||||
.then(defaultSettingsModel => {
|
||||
this.editSettingActionRenderer = this._register(this.instantiationService.createInstance(EditSettingRenderer, this.editor, this.settingsEditorModel, defaultSettingsModel, this.settingHighlighter));
|
||||
this.defaultSettingsModel = <DefaultSettingsEditorModel>defaultSettingsModel;
|
||||
this.editSettingActionRenderer = this._register(this.instantiationService.createInstance(EditSettingRenderer, this.editor, this.preferencesModel, () => defaultSettingsModel, this.settingHighlighter));
|
||||
this._register(this.editor.getModel().onDidChangeContent(() => this.modelChangeDelayer.trigger(() => this.onModelChanged())));
|
||||
this._register(this.editSettingActionRenderer.onUpdateSetting(({setting, value}) => this.updatePreference(setting, value)));
|
||||
return null;
|
||||
@@ -355,16 +596,48 @@ export class SettingsRenderer extends Disposable implements IPreferencesRenderer
|
||||
|
||||
public updatePreference(setting: ISetting, value: any): void {
|
||||
this.telemetryService.publicLog('defaultSettingsActions.copySetting', { userConfigurationKeys: [setting.key] });
|
||||
this.configurationEditingService.writeConfiguration(this.settingsEditorModel.configurationTarget, { key: setting.key, value }, { writeToBuffer: true, autoSave: true })
|
||||
this.configurationEditingService.writeConfiguration(this.preferencesModel.configurationTarget, { key: setting.key, value }, { writeToBuffer: true, autoSave: true })
|
||||
.then(() => this.onSettingUpdated(setting), error => this.messageService.show(Severity.Error, error));
|
||||
}
|
||||
|
||||
private onSettingUpdated(setting: ISetting) {
|
||||
this.editor.focus();
|
||||
setting = this.settingsEditorModel.getSetting(setting.key);
|
||||
setting = this.preferencesModel.getSetting(setting.key);
|
||||
// TODO:@sandy Selection range should be template range
|
||||
this.editor.setSelection(setting.valueRange);
|
||||
this.settingHighlighter.highlight(this.settingsEditorModel.getSetting(setting.key), true);
|
||||
this.settingHighlighter.highlight(this.preferencesModel.getSetting(setting.key), true);
|
||||
}
|
||||
|
||||
public filterPreferences(filterResult: IFilterResult): void {
|
||||
this.highlightPreferencesRenderer.render([]);
|
||||
this.settingHighlighter.clear(true);
|
||||
if (this.defaultSettingsModel && filterResult) {
|
||||
const settings = distinct(filterResult.filteredGroups.reduce((settings: ISetting[], settingsGroup: ISettingsGroup) => {
|
||||
for (const section of settingsGroup.sections) {
|
||||
for (const setting of section.settings) {
|
||||
const s = this.preferencesModel.getSetting(setting.key);
|
||||
if (s) {
|
||||
settings.push(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
return settings;
|
||||
}, []));
|
||||
this.highlightPreferencesRenderer.render(settings);
|
||||
}
|
||||
}
|
||||
|
||||
public focusPreference(setting: ISetting): void {
|
||||
const s = this.preferencesModel.getSetting(setting.key);
|
||||
if (s) {
|
||||
this.settingHighlighter.highlight(s, true);
|
||||
} else {
|
||||
this.settingHighlighter.clear(true);
|
||||
}
|
||||
}
|
||||
|
||||
public clearFocus(setting: ISetting): void {
|
||||
this.settingHighlighter.clear(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,10 +651,14 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR
|
||||
private filteredSettingsNavigationRenderer: FilteredSettingsNavigationRenderer;
|
||||
private hiddenAreasRenderer: HiddenAreasRenderer;
|
||||
private editSettingActionRenderer: EditSettingRenderer;
|
||||
private settingsCountWidget: SettingsCountWidget;
|
||||
|
||||
constructor(protected editor: ICodeEditor, protected defaultSettingsEditorModel: DefaultSettingsEditorModel,
|
||||
private settingsEditorModel: SettingsEditorModel,
|
||||
private _onFocusPreference: Emitter<ISetting> = new Emitter<ISetting>();
|
||||
public readonly onFocusPreference: Event<ISetting> = this._onFocusPreference.event;
|
||||
|
||||
private _onClearFocusPreference: Emitter<ISetting> = new Emitter<ISetting>();
|
||||
public readonly onClearFocusPreference: Event<ISetting> = this._onClearFocusPreference.event;
|
||||
|
||||
constructor(protected editor: ICodeEditor, public readonly preferencesModel: DefaultSettingsEditorModel,
|
||||
@IPreferencesService protected preferencesService: IPreferencesService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
|
||||
@@ -389,50 +666,53 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR
|
||||
) {
|
||||
super();
|
||||
this.defaultSettingsEditorContextKey = CONTEXT_DEFAULT_SETTINGS_EDITOR.bindTo(contextKeyService);
|
||||
this.settingHighlighter = this._register(instantiationService.createInstance(SettingHighlighter, editor));
|
||||
this.settingHighlighter = this._register(instantiationService.createInstance(SettingHighlighter, editor, this._onFocusPreference, this._onClearFocusPreference));
|
||||
this.settingsGroupTitleRenderer = this._register(instantiationService.createInstance(SettingsGroupTitleRenderer, editor));
|
||||
this.filteredMatchesRenderer = this._register(instantiationService.createInstance(FilteredMatchesRenderer, editor));
|
||||
this.filteredSettingsNavigationRenderer = this._register(instantiationService.createInstance(FilteredSettingsNavigationRenderer, editor, this.settingHighlighter));
|
||||
this.editSettingActionRenderer = this._register(instantiationService.createInstance(EditSettingRenderer, editor, defaultSettingsEditorModel, settingsEditorModel, this.settingHighlighter));
|
||||
this.editSettingActionRenderer = this._register(instantiationService.createInstance(EditSettingRenderer, editor, preferencesModel, () => (<DefaultPreferencesCodeEditor>this.editor).settingsModel, this.settingHighlighter));
|
||||
this._register(this.editSettingActionRenderer.onUpdateSetting(({setting, value}) => this.updatePreference(setting, value)));
|
||||
this.settingsCountWidget = this._register(instantiationService.createInstance(SettingsCountWidget, editor, this.getCount(defaultSettingsEditorModel.settingsGroups)));
|
||||
const paranthesisHidingRenderer = this._register(instantiationService.createInstance(StaticContentHidingRenderer, editor, defaultSettingsEditorModel.settingsGroups));
|
||||
const paranthesisHidingRenderer = this._register(instantiationService.createInstance(StaticContentHidingRenderer, editor, preferencesModel.settingsGroups));
|
||||
this.hiddenAreasRenderer = this._register(instantiationService.createInstance(HiddenAreasRenderer, editor, [this.settingsGroupTitleRenderer, this.filteredMatchesRenderer, paranthesisHidingRenderer]));
|
||||
|
||||
this._register(this.settingsGroupTitleRenderer.onHiddenAreasChanged(() => this.hiddenAreasRenderer.render()));
|
||||
}
|
||||
|
||||
public get iterator(): IIterator<ISetting> {
|
||||
return this.filteredSettingsNavigationRenderer;
|
||||
}
|
||||
|
||||
public render() {
|
||||
this.defaultSettingsEditorContextKey.set(true);
|
||||
this.settingsGroupTitleRenderer.render(this.defaultSettingsEditorModel.settingsGroups);
|
||||
this.editSettingActionRenderer.render(this.defaultSettingsEditorModel.settingsGroups);
|
||||
this.settingsCountWidget.render();
|
||||
this.settingsGroupTitleRenderer.render(this.preferencesModel.settingsGroups);
|
||||
this.editSettingActionRenderer.render(this.preferencesModel.settingsGroups);
|
||||
this.hiddenAreasRenderer.render();
|
||||
this.filteredSettingsNavigationRenderer.render([]);
|
||||
this.settingsGroupTitleRenderer.showGroup(1);
|
||||
this.hiddenAreasRenderer.render();
|
||||
}
|
||||
|
||||
public filterPreferences(filter: string) {
|
||||
const filterResult = this.defaultSettingsEditorModel.filterSettings(filter);
|
||||
this.filteredMatchesRenderer.render(filterResult);
|
||||
this.settingsGroupTitleRenderer.render(filterResult.filteredGroups);
|
||||
this.settingsCountWidget.show(this.getCount(filterResult.filteredGroups));
|
||||
|
||||
if (!filter) {
|
||||
public filterPreferences(filterResult: IFilterResult): void {
|
||||
if (!filterResult) {
|
||||
this.filteredSettingsNavigationRenderer.render([]);
|
||||
this.filteredMatchesRenderer.render(null);
|
||||
this.settingsGroupTitleRenderer.render(this.preferencesModel.settingsGroups);
|
||||
this.settingsGroupTitleRenderer.showGroup(1);
|
||||
} else {
|
||||
this.filteredMatchesRenderer.render(filterResult);
|
||||
this.settingsGroupTitleRenderer.render(filterResult.filteredGroups);
|
||||
this.filteredSettingsNavigationRenderer.render(filterResult.filteredGroups);
|
||||
}
|
||||
this.hiddenAreasRenderer.render();
|
||||
}
|
||||
|
||||
public focusNextSetting(): void {
|
||||
const setting = this.filteredSettingsNavigationRenderer.next();
|
||||
if (setting) {
|
||||
this.settingsGroupTitleRenderer.showSetting(setting);
|
||||
}
|
||||
public focusPreference(setting: ISetting): void {
|
||||
this.settingsGroupTitleRenderer.showSetting(setting);
|
||||
this.settingHighlighter.highlight(setting, true);
|
||||
}
|
||||
|
||||
public clearFocus(setting: ISetting): void {
|
||||
this.settingHighlighter.clear(true);
|
||||
}
|
||||
|
||||
public collapseAll() {
|
||||
@@ -447,23 +727,7 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR
|
||||
}
|
||||
|
||||
private getEditableSettingsEditor(): editorCommon.ICommonCodeEditor {
|
||||
return this.editorService.getVisibleEditors()
|
||||
.filter(editor => {
|
||||
if (editorCommon.isCommonCodeEditor(editor.getControl())) {
|
||||
return (<editorCommon.ICommonCodeEditor>editor.getControl()).getModel().uri.fsPath === this.settingsEditorModel.uri.fsPath;
|
||||
}
|
||||
})
|
||||
.map(editor => <editorCommon.ICommonCodeEditor>editor.getControl())[0];
|
||||
}
|
||||
|
||||
private getCount(settingsGroups: ISettingsGroup[]): number {
|
||||
let count = 0;
|
||||
for (const group of settingsGroups) {
|
||||
for (const section of group.sections) {
|
||||
count += section.settings.length;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
return <editorCommon.ICommonCodeEditor>(<DefaultPreferencesCodeEditor>this.editor).settingsEditor.getControl();
|
||||
}
|
||||
|
||||
dispose() {
|
||||
@@ -722,21 +986,58 @@ export class FilteredMatchesRenderer extends Disposable implements HiddenAreasPr
|
||||
}
|
||||
}
|
||||
|
||||
class FilteredSettingsNavigationRenderer extends Disposable {
|
||||
export class HighlightPreferencesRenderer extends Disposable {
|
||||
|
||||
private iterator: ArrayIterator<ISetting>;
|
||||
private decorationIds: string[] = [];
|
||||
|
||||
constructor(private editor: ICodeEditor,
|
||||
@IInstantiationService private instantiationService: IInstantiationService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
public render(settings: ISetting[]): void {
|
||||
const model = this.editor.getModel();
|
||||
this.editor.changeDecorations(changeAccessor => {
|
||||
this.decorationIds = changeAccessor.deltaDecorations(this.decorationIds, []);
|
||||
});
|
||||
if (settings.length) {
|
||||
this.editor.changeDecorations(changeAccessor => {
|
||||
this.decorationIds = changeAccessor.deltaDecorations(this.decorationIds, settings.map(setting => this.createDecoration(setting.keyRange, model)));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private createDecoration(range: editorCommon.IRange, model: editorCommon.IModel): editorCommon.IModelDeltaDecoration {
|
||||
return {
|
||||
range,
|
||||
options: {
|
||||
stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
className: 'findMatch'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
if (this.decorationIds) {
|
||||
this.decorationIds = this.editor.changeDecorations(changeAccessor => {
|
||||
return changeAccessor.deltaDecorations(this.decorationIds, []);
|
||||
});
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class FilteredSettingsNavigationRenderer extends Disposable implements IIterator<ISetting> {
|
||||
|
||||
private iterator: ArrayNavigator<ISetting>;
|
||||
|
||||
constructor(private editor: ICodeEditor, private settingHighlighter: SettingHighlighter) {
|
||||
super();
|
||||
}
|
||||
|
||||
public next(): ISetting {
|
||||
let setting = this.iterator.next() || this.iterator.first();
|
||||
if (setting) {
|
||||
this.settingHighlighter.highlight(setting, true);
|
||||
return setting;
|
||||
}
|
||||
return null;
|
||||
return this.iterator.next() || this.iterator.first();
|
||||
}
|
||||
|
||||
public render(filteredGroups: ISettingsGroup[]) {
|
||||
@@ -747,7 +1048,7 @@ class FilteredSettingsNavigationRenderer extends Disposable {
|
||||
settings.push(...section.settings);
|
||||
}
|
||||
}
|
||||
this.iterator = new ArrayIterator<ISetting>(settings);
|
||||
this.iterator = new ArrayNavigator<ISetting>(settings);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -763,7 +1064,7 @@ class EditSettingRenderer extends Disposable {
|
||||
public readonly onUpdateSetting: Event<{ setting: ISetting, value: any }> = this._onUpdateSetting.event;
|
||||
|
||||
constructor(private editor: ICodeEditor, private masterSettingsModel: ISettingsEditorModel,
|
||||
private otherSettingsModel: ISettingsEditorModel,
|
||||
private otherSettingsModel: () => ISettingsEditorModel,
|
||||
private settingHighlighter: SettingHighlighter,
|
||||
@IPreferencesService private preferencesService: IPreferencesService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@@ -921,7 +1222,7 @@ class EditSettingRenderer extends Disposable {
|
||||
}
|
||||
|
||||
private getDefaultActions(setting: ISetting): IAction[] {
|
||||
const settingInOtherModel = this.otherSettingsModel.getSetting(setting.key);
|
||||
const settingInOtherModel = this.otherSettingsModel().getSetting(setting.key);
|
||||
if (this.isDefaultSettings()) {
|
||||
return [<IAction>{
|
||||
id: 'setDefaultValue',
|
||||
@@ -942,14 +1243,20 @@ class SettingHighlighter extends Disposable {
|
||||
|
||||
private fixedHighlighter: RangeHighlightDecorations;
|
||||
private volatileHighlighter: RangeHighlightDecorations;
|
||||
private highlightedSetting: ISetting;
|
||||
|
||||
constructor(private editor: editorCommon.ICommonCodeEditor, @IInstantiationService instantiationService: IInstantiationService) {
|
||||
constructor(private editor: editorCommon.ICommonCodeEditor, private focusEventEmitter: Emitter<ISetting>, private clearFocusEventEmitter: Emitter<ISetting>,
|
||||
@IInstantiationService instantiationService: IInstantiationService
|
||||
) {
|
||||
super();
|
||||
this.fixedHighlighter = this._register(instantiationService.createInstance(RangeHighlightDecorations));
|
||||
this.volatileHighlighter = this._register(instantiationService.createInstance(RangeHighlightDecorations));
|
||||
this.fixedHighlighter.onHighlghtRemoved(() => this.clearFocusEventEmitter.fire(this.highlightedSetting));
|
||||
this.volatileHighlighter.onHighlghtRemoved(() => this.clearFocusEventEmitter.fire(this.highlightedSetting));
|
||||
}
|
||||
|
||||
highlight(setting: ISetting, fix: boolean = false) {
|
||||
this.highlightedSetting = setting;
|
||||
this.volatileHighlighter.removeHighlightRange();
|
||||
this.fixedHighlighter.removeHighlightRange();
|
||||
|
||||
@@ -960,6 +1267,7 @@ class SettingHighlighter extends Disposable {
|
||||
}, this.editor);
|
||||
|
||||
this.editor.revealLinesInCenterIfOutsideViewport(setting.valueRange.startLineNumber, setting.valueRange.endLineNumber - 1);
|
||||
this.focusEventEmitter.fire(setting);
|
||||
}
|
||||
|
||||
clear(fix: boolean = false): void {
|
||||
@@ -967,6 +1275,7 @@ class SettingHighlighter extends Disposable {
|
||||
if (fix) {
|
||||
this.fixedHighlighter.removeHighlightRange();
|
||||
}
|
||||
this.clearFocusEventEmitter.fire(this.highlightedSetting);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@ import URI from 'vs/base/common/uri';
|
||||
import { LinkedMap as Map } from 'vs/base/common/map';
|
||||
import * as labels from 'vs/base/common/labels';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { SideBySideEditorInput, EditorInput } from 'vs/workbench/common/editor';
|
||||
import { EditorInput, toResource } from 'vs/workbench/common/editor';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { IWorkspaceConfigurationService, WORKSPACE_CONFIG_DEFAULT_PATH } from 'vs/workbench/services/configuration/common/configuration';
|
||||
import { Position, IEditor } from 'vs/platform/editor/common/editor';
|
||||
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
|
||||
import { Position } from 'vs/platform/editor/common/editor';
|
||||
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { IFileService, IFileOperationResult, FileOperationResult } from 'vs/platform/files/common/files';
|
||||
import { IMessageService, Severity, IChoiceService } from 'vs/platform/message/common/message';
|
||||
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
|
||||
@@ -26,11 +26,9 @@ import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/
|
||||
import { IPreferencesService, IPreferencesEditorModel } from 'vs/workbench/parts/preferences/common/preferences';
|
||||
import { SettingsEditorModel, DefaultSettingsEditorModel, DefaultKeybindingsEditorModel } from 'vs/workbench/parts/preferences/common/preferencesModels';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { DefaultPreferencesEditorInput } from 'vs/workbench/parts/preferences/browser/preferencesEditor';
|
||||
import { DefaultPreferencesEditorInput, PreferencesEditorInput } from 'vs/workbench/parts/preferences/browser/preferencesEditor';
|
||||
import { ITextModelResolverService } from 'vs/editor/common/services/resolverService';
|
||||
|
||||
const SETTINGS_INFO_IGNORE_KEY = 'settings.workspace.info.ignore';
|
||||
|
||||
interface IWorkbenchSettingsConfiguration {
|
||||
workbench: {
|
||||
settings: {
|
||||
@@ -45,8 +43,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||
|
||||
// TODO:@sandy merge these models into editor inputs by extending resource editor model
|
||||
private defaultPreferencesEditorModels: Map<URI, IPreferencesEditorModel>;
|
||||
private defaultSettingsEditorInputForUser: DefaultPreferencesEditorInput;
|
||||
private defaultSettingsEditorInputForWorkspace: DefaultPreferencesEditorInput;
|
||||
private lastOpenedSettingsInput: PreferencesEditorInput = null;
|
||||
|
||||
constructor(
|
||||
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
|
||||
@@ -66,11 +63,25 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||
) {
|
||||
super();
|
||||
this.defaultPreferencesEditorModels = new Map<URI, IPreferencesEditorModel>();
|
||||
this.editorGroupService.onEditorsChanged(() => {
|
||||
const activeEditorInput = this.editorService.getActiveEditorInput();
|
||||
if (activeEditorInput instanceof PreferencesEditorInput) {
|
||||
this.lastOpenedSettingsInput = activeEditorInput;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
readonly defaultSettingsResource = URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: '/settings.json' });
|
||||
readonly defaultKeybindingsResource = URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: '/keybindings.json' });
|
||||
|
||||
get userSettingsResource(): URI {
|
||||
return this.getEditableSettingsURI(ConfigurationTarget.USER);
|
||||
}
|
||||
|
||||
get workspaceSettingsResource(): URI {
|
||||
return this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE);
|
||||
}
|
||||
|
||||
createDefaultPreferencesEditorModel(uri: URI): TPromise<IPreferencesEditorModel> {
|
||||
const editorModel = this.defaultPreferencesEditorModels.get(uri);
|
||||
if (editorModel) {
|
||||
@@ -114,12 +125,12 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||
return TPromise.wrap(null);
|
||||
}
|
||||
|
||||
openSettings(): TPromise<void> {
|
||||
return this.doOpenSettings(this.getSettingsConfigurationTarget(this.lastOpenedSettingsInput), false);
|
||||
}
|
||||
|
||||
openGlobalSettings(): TPromise<void> {
|
||||
if (this.configurationService.hasWorkspaceConfiguration() && !this.storageService.getBoolean(SETTINGS_INFO_IGNORE_KEY, StorageScope.WORKSPACE)) {
|
||||
this.promptToOpenWorkspaceSettings();
|
||||
}
|
||||
// Open settings
|
||||
return this.openSettings(ConfigurationTarget.USER);
|
||||
return this.doOpenSettings(ConfigurationTarget.USER);
|
||||
}
|
||||
|
||||
openWorkspaceSettings(): TPromise<void> {
|
||||
@@ -127,7 +138,27 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||
this.messageService.show(Severity.Info, nls.localize('openFolderFirst', "Open a folder first to create workspace settings"));
|
||||
return TPromise.as(null);
|
||||
}
|
||||
return this.openSettings(ConfigurationTarget.WORKSPACE);
|
||||
return this.doOpenSettings(ConfigurationTarget.WORKSPACE);
|
||||
}
|
||||
|
||||
switchSettings(): TPromise<void> {
|
||||
const activeEditorInput = this.editorService.getActiveEditorInput();
|
||||
if (activeEditorInput instanceof PreferencesEditorInput) {
|
||||
const fromTarget = this.getSettingsConfigurationTarget(activeEditorInput);
|
||||
const toTarget = ConfigurationTarget.USER === fromTarget ? ConfigurationTarget.WORKSPACE : ConfigurationTarget.USER;
|
||||
return this.getOrCreateEditableSettingsEditorInput(toTarget)
|
||||
.then(toInput => {
|
||||
const replaceWith = new PreferencesEditorInput(toInput.getName(), toInput.getDescription(), this.instantiationService.createInstance(DefaultPreferencesEditorInput, this.defaultSettingsResource), toInput);
|
||||
return this.editorService.replaceEditors([{
|
||||
toReplace: this.lastOpenedSettingsInput,
|
||||
replaceWith
|
||||
}]).then(() => {
|
||||
this.lastOpenedSettingsInput = replaceWith;
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.openSettings();
|
||||
}
|
||||
}
|
||||
|
||||
openGlobalKeybindingSettings(): TPromise<void> {
|
||||
@@ -135,13 +166,25 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||
return this.openTwoEditors(this.defaultKeybindingsResource, URI.file(this.environmentService.appKeybindingsPath), emptyContents).then(() => null);
|
||||
}
|
||||
|
||||
private openEditableSettings(configurationTarget: ConfigurationTarget): TPromise<IEditor> {
|
||||
const emptySettingsContents = this.getEmptyEditableSettingsContent(configurationTarget);
|
||||
const settingsResource = this.getEditableSettingsURI(configurationTarget);
|
||||
return this.createIfNotExists(settingsResource, emptySettingsContents).then(() => this.editorService.openEditor({
|
||||
resource: settingsResource,
|
||||
options: { pinned: true }
|
||||
}));
|
||||
private doOpenSettings(configurationTarget: ConfigurationTarget, checkToOpenDefaultSettings: boolean = true): TPromise<void> {
|
||||
const openDefaultSettings = !checkToOpenDefaultSettings || !!this.configurationService.getConfiguration<IWorkbenchSettingsConfiguration>().workbench.settings.openDefaultSettings;
|
||||
return this.getOrCreateEditableSettingsEditorInput(configurationTarget)
|
||||
.then(editableSettingsEditorInput => {
|
||||
if (openDefaultSettings) {
|
||||
const defaultPreferencesEditorInput = this.instantiationService.createInstance(DefaultPreferencesEditorInput, this.defaultSettingsResource);
|
||||
const preferencesEditorInput = new PreferencesEditorInput(editableSettingsEditorInput.getName(), editableSettingsEditorInput.getDescription(), defaultPreferencesEditorInput, <EditorInput>editableSettingsEditorInput);
|
||||
this.lastOpenedSettingsInput = preferencesEditorInput;
|
||||
return this.editorService.openEditor(preferencesEditorInput, { pinned: true });
|
||||
}
|
||||
return this.editorService.openEditor(editableSettingsEditorInput, { pinned: true });
|
||||
}).then(() => null);
|
||||
}
|
||||
|
||||
private getOrCreateEditableSettingsEditorInput(configurationTarget: ConfigurationTarget): TPromise<EditorInput> {
|
||||
const resource = this.getEditableSettingsURI(configurationTarget);
|
||||
const editableSettingsEmptyContent = this.getEmptyEditableSettingsContent(configurationTarget);
|
||||
return this.createIfNotExists(resource, editableSettingsEmptyContent)
|
||||
.then(() => this.editorService.createInput({ resource }));
|
||||
}
|
||||
|
||||
private resolveSettingsEditorModel(configurationTarget: ConfigurationTarget): TPromise<SettingsEditorModel> {
|
||||
@@ -179,58 +222,6 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||
return null;
|
||||
}
|
||||
|
||||
private promptToOpenWorkspaceSettings() {
|
||||
this.choiceService.choose(Severity.Info, nls.localize('workspaceHasSettings', "The currently opened folder contains workspace settings that may override user settings"),
|
||||
[nls.localize('openWorkspaceSettings', "Open Workspace Settings"), nls.localize('neverShowAgain', "Don't show again"), nls.localize('close', "Close")]
|
||||
).then(choice => {
|
||||
switch (choice) {
|
||||
case 0:
|
||||
const editorCount = this.editorService.getVisibleEditors().length;
|
||||
return this.editorService.openEditor({ resource: this.contextService.toResource(WORKSPACE_CONFIG_DEFAULT_PATH), options: { pinned: true } }, editorCount === 2 ? Position.THREE : editorCount === 1 ? Position.TWO : void 0);
|
||||
case 1:
|
||||
this.storageService.store(SETTINGS_INFO_IGNORE_KEY, true, StorageScope.WORKSPACE);
|
||||
default:
|
||||
return TPromise.as(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private openSettings(configurationTarget: ConfigurationTarget): TPromise<void> {
|
||||
const openDefaultSettings = !!this.configurationService.getConfiguration<IWorkbenchSettingsConfiguration>().workbench.settings.openDefaultSettings;
|
||||
if (openDefaultSettings) {
|
||||
const emptySettingsContents = this.getEmptyEditableSettingsContent(configurationTarget);
|
||||
const settingsResource = this.getEditableSettingsURI(configurationTarget);
|
||||
return this.openSideBySideEditor(this.getDefaultSettingsEditorInput(configurationTarget), settingsResource, emptySettingsContents);
|
||||
}
|
||||
return this.openEditableSettings(configurationTarget).then(() => null);
|
||||
}
|
||||
|
||||
private getDefaultSettingsEditorInput(configurationTarget: ConfigurationTarget): DefaultPreferencesEditorInput {
|
||||
switch (configurationTarget) {
|
||||
case ConfigurationTarget.USER:
|
||||
if (!this.defaultSettingsEditorInputForUser) {
|
||||
this.defaultSettingsEditorInputForUser = this._register(this.instantiationService.createInstance(DefaultPreferencesEditorInput, this.defaultSettingsResource));
|
||||
}
|
||||
return this.defaultSettingsEditorInputForUser;
|
||||
case ConfigurationTarget.WORKSPACE:
|
||||
if (!this.defaultSettingsEditorInputForWorkspace) {
|
||||
this.defaultSettingsEditorInputForWorkspace = this._register(this.instantiationService.createInstance(DefaultPreferencesEditorInput, this.defaultSettingsResource));
|
||||
}
|
||||
return this.defaultSettingsEditorInputForWorkspace;
|
||||
}
|
||||
}
|
||||
|
||||
private openSideBySideEditor(leftHandDefaultInput: EditorInput, editableResource: URI, defaultEditableContents: string): TPromise<void> {
|
||||
// Create as needed and open in editor
|
||||
return this.createIfNotExists(editableResource, defaultEditableContents).then(() => {
|
||||
return this.editorService.createInput({ resource: editableResource }).then(typedRightHandEditableInput => {
|
||||
const sideBySideInput = new SideBySideEditorInput(typedRightHandEditableInput.getName(), typedRightHandEditableInput.getDescription(), leftHandDefaultInput, <EditorInput>typedRightHandEditableInput);
|
||||
this.editorService.openEditor(sideBySideInput, { pinned: true });
|
||||
return;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private openTwoEditors(leftHandDefault: URI, editableResource: URI, defaultEditableContents: string): TPromise<void> {
|
||||
// Create as needed and open in editor
|
||||
return this.createIfNotExists(editableResource, defaultEditableContents).then(() => {
|
||||
@@ -255,6 +246,14 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||
});
|
||||
}
|
||||
|
||||
private getSettingsConfigurationTarget(preferencesEditorInput: PreferencesEditorInput): ConfigurationTarget {
|
||||
if (preferencesEditorInput) {
|
||||
const resource = toResource(preferencesEditorInput.master);
|
||||
return resource.toString() === this.userSettingsResource.toString() ? ConfigurationTarget.USER : ConfigurationTarget.WORKSPACE;
|
||||
}
|
||||
return ConfigurationTarget.USER;
|
||||
}
|
||||
|
||||
private fetchMostCommonlyUsedSettings(): TPromise<string[]> {
|
||||
return TPromise.wrap([
|
||||
'editor.fontSize',
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { Dimension } from 'vs/base/browser/builder';
|
||||
import { Widget } from 'vs/base/browser/ui/widget';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
@@ -17,6 +16,8 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { ISettingsGroup } from 'vs/workbench/parts/preferences/common/preferences';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing';
|
||||
|
||||
export class SettingsGroupTitleWidget extends Widget implements IViewZone {
|
||||
|
||||
@@ -176,11 +177,51 @@ export class SettingsGroupTitleWidget extends Widget implements IViewZone {
|
||||
}
|
||||
}
|
||||
|
||||
export class DefaultSettingsHeaderWidget extends Widget {
|
||||
export class SettingsTabsWidget extends Widget {
|
||||
|
||||
private userSettingsTab: HTMLElement;
|
||||
private workspaceSettingsTab: HTMLElement;
|
||||
|
||||
private _onSwitch: Emitter<void> = new Emitter<void>();
|
||||
public readonly onSwitch: Event<void> = this._onSwitch.event;
|
||||
|
||||
constructor(parent: HTMLElement, @IWorkspaceContextService private contextService: IWorkspaceContextService, ) {
|
||||
super();
|
||||
this.create(parent);
|
||||
}
|
||||
|
||||
private create(parent: HTMLElement): void {
|
||||
const settingsTabsWidget = DOM.append(parent, DOM.$('.settings-tabs-widget'));
|
||||
this.userSettingsTab = DOM.append(settingsTabsWidget, DOM.$('.settings-tab'));
|
||||
DOM.append(this.userSettingsTab, DOM.$('')).textContent = localize('userSettings', "User Settings");
|
||||
this.onclick(this.userSettingsTab, () => this.onClick(this.userSettingsTab));
|
||||
|
||||
this.workspaceSettingsTab = DOM.append(settingsTabsWidget, DOM.$('.settings-tab'));
|
||||
DOM.append(this.workspaceSettingsTab, DOM.$('')).textContent = localize('workspaceSettings', "Workspace Settings");
|
||||
if (!this.contextService.hasWorkspace()) {
|
||||
DOM.addClass(this.workspaceSettingsTab, 'disabled');
|
||||
} else {
|
||||
this.onclick(this.workspaceSettingsTab, () => this.onClick(this.workspaceSettingsTab));
|
||||
}
|
||||
}
|
||||
|
||||
public show(configurationTarget: ConfigurationTarget): void {
|
||||
DOM.toggleClass(this.userSettingsTab, 'active', ConfigurationTarget.USER === configurationTarget);
|
||||
DOM.toggleClass(this.workspaceSettingsTab, 'active', ConfigurationTarget.WORKSPACE === configurationTarget);
|
||||
}
|
||||
|
||||
private onClick(element: HTMLElement): void {
|
||||
if (!DOM.hasClass(element, 'active')) {
|
||||
this._onSwitch.fire();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class SearchWidget extends Widget {
|
||||
|
||||
public domNode: HTMLElement;
|
||||
|
||||
private headerContainer: HTMLElement;
|
||||
private countElement: HTMLElement;
|
||||
private searchContainer: HTMLElement;
|
||||
private inputBox: InputBox;
|
||||
|
||||
@@ -201,40 +242,38 @@ export class DefaultSettingsHeaderWidget extends Widget {
|
||||
|
||||
private create(parent: HTMLElement) {
|
||||
this.domNode = DOM.append(parent, DOM.$('div.settings-header-widget'));
|
||||
this.headerContainer = DOM.append(this.domNode, DOM.$('div.settings-header-container'));
|
||||
const titleContainer = DOM.append(this.headerContainer, DOM.$('div.settings-title-container'));
|
||||
this.createInfoContainer(DOM.append(titleContainer, DOM.$('div.settings-info-container')));
|
||||
this.createSearchContainer(DOM.append(this.domNode, DOM.$('div.settings-search-container')));
|
||||
}
|
||||
|
||||
private createInfoContainer(infoContainer: HTMLElement) {
|
||||
DOM.append(infoContainer, DOM.$('span.title-label')).textContent = localize('defaultSettingsTitle', "Default Settings");
|
||||
DOM.append(infoContainer, DOM.$('span')).textContent = localize('defaultSettingsInfo', " - Overwrite these by placing them into your settings file to the right");
|
||||
this.countElement = DOM.append(this.domNode, DOM.$('.settings-count-widget'));
|
||||
}
|
||||
|
||||
private createSearchContainer(searchContainer: HTMLElement) {
|
||||
this.searchContainer = searchContainer;
|
||||
const searchInput = DOM.append(this.searchContainer, DOM.$('div.settings-search-input'));
|
||||
this.inputBox = this._register(new InputBox(searchInput, this.contextViewService, {
|
||||
ariaLabel: localize('SearchSettingsWidget.AriaLabel', "Search default settings"),
|
||||
placeholder: localize('SearchSettingsWidget.Placeholder', "Search Default Settings")
|
||||
ariaLabel: localize('SearchSettingsWidget.AriaLabel', "Search settings"),
|
||||
placeholder: localize('SearchSettingsWidget.Placeholder', "Search Settings")
|
||||
}));
|
||||
this.inputBox.onDidChange(value => this._onDidChange.fire(value));
|
||||
this.onkeyup(this.inputBox.inputElement, (e) => this._onKeyUp(e));
|
||||
}
|
||||
|
||||
public showMessage(message: string, count: number): void {
|
||||
this.countElement.textContent = message;
|
||||
DOM.toggleClass(this.countElement, 'no-results', count === 0);
|
||||
}
|
||||
|
||||
public focus() {
|
||||
this.inputBox.focus();
|
||||
}
|
||||
|
||||
public layout(dimension: Dimension): void {
|
||||
this.inputBox.width = dimension.width - 62;
|
||||
}
|
||||
|
||||
public clear() {
|
||||
this.inputBox.value = '';
|
||||
}
|
||||
|
||||
public value(): string {
|
||||
return this.inputBox.value;
|
||||
}
|
||||
|
||||
private _onKeyUp(keyboardEvent: IKeyboardEvent): void {
|
||||
let handled = false;
|
||||
switch (keyboardEvent.keyCode) {
|
||||
@@ -300,55 +339,6 @@ export class FloatingClickWidget extends Widget implements IOverlayWidget {
|
||||
}
|
||||
}
|
||||
|
||||
export class SettingsCountWidget extends Widget implements IOverlayWidget {
|
||||
|
||||
private _domNode: HTMLElement;
|
||||
|
||||
constructor(private editor: ICodeEditor, private total: number
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
public render() {
|
||||
this._domNode = DOM.$('.settings-count-widget');
|
||||
this.editor.addOverlayWidget(this);
|
||||
}
|
||||
|
||||
public show(count: number) {
|
||||
if (count === this.total) {
|
||||
DOM.removeClass(this._domNode, 'show');
|
||||
} else {
|
||||
if (count === 0) {
|
||||
this._domNode.textContent = localize('noSettings', "No settings found");
|
||||
DOM.addClass(this._domNode, 'no-results');
|
||||
} else {
|
||||
this._domNode.textContent = localize('showCount', "Showing {0} of {1} Settings", count, this.total);
|
||||
DOM.removeClass(this._domNode, 'no-results');
|
||||
}
|
||||
DOM.addClass(this._domNode, 'show');
|
||||
}
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this.editor.removeOverlayWidget(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return 'editor.overlayWidget.settingsCountWidget';
|
||||
}
|
||||
|
||||
public getDomNode(): HTMLElement {
|
||||
return this._domNode;
|
||||
}
|
||||
|
||||
public getPosition(): IOverlayWidgetPosition {
|
||||
return {
|
||||
preference: null
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class EditPreferenceWidget<T> extends Widget implements IOverlayWidget {
|
||||
|
||||
private static counter: number = 1;
|
||||
|
||||
@@ -61,11 +61,15 @@ export interface IPreferencesService {
|
||||
_serviceBrand: any;
|
||||
|
||||
defaultSettingsResource: URI;
|
||||
userSettingsResource: URI;
|
||||
workspaceSettingsResource: URI;
|
||||
defaultKeybindingsResource: URI;
|
||||
|
||||
createDefaultPreferencesEditorModel(uri: URI): TPromise<IPreferencesEditorModel>;
|
||||
resolvePreferencesEditorModel(uri: URI): TPromise<IPreferencesEditorModel>;
|
||||
|
||||
openSettings(): TPromise<void>;
|
||||
switchSettings(): TPromise<void>;
|
||||
openGlobalSettings(): TPromise<void>;
|
||||
openWorkspaceSettings(): TPromise<void>;
|
||||
openGlobalKeybindingSettings(): TPromise<void>;
|
||||
|
||||
@@ -459,7 +459,7 @@ export class DefaultSettingsEditorModel extends AbstractSettingsModel implements
|
||||
return <ISettingsGroup>{
|
||||
id: 'mostCommonlyUsed',
|
||||
range: null,
|
||||
title: nls.localize('commonlyUsed', "Most Commonly Used"),
|
||||
title: nls.localize('commonlyUsed', "Commonly Used"),
|
||||
titleRange: null,
|
||||
sections: [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user