preferencesRenderers.ts 44.9 KB
Newer Older
1 2 3 4 5
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

R
Rob Lourens 已提交
6
import { ContextSubMenu } from 'vs/base/browser/contextmenu';
7
import { EventHelper, getDomNodePagePosition } from 'vs/base/browser/dom';
8
import { IAction } from 'vs/base/common/actions';
R
Rob Lourens 已提交
9 10
import { Delayer } from 'vs/base/common/async';
import { Emitter, Event } from 'vs/base/common/event';
11
import { IJSONSchema } from 'vs/base/common/jsonSchema';
12
import { Disposable, IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
A
Alex Dima 已提交
13
import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';
14
import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
R
Rob Lourens 已提交
15 16 17
import { Position } from 'vs/editor/common/core/position';
import { IRange, Range } from 'vs/editor/common/core/range';
import * as editorCommon from 'vs/editor/common/editorCommon';
18
import { IModelDeltaDecoration, TrackedRangeStickiness } from 'vs/editor/common/model';
A
Alex Dima 已提交
19
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
R
Rob Lourens 已提交
20 21
import * as nls from 'vs/nls';
import { ConfigurationTarget, IConfigurationService, overrideIdentifierFromKey } from 'vs/platform/configuration/common/configuration';
S
Sandeep Somavarapu 已提交
22
import { ConfigurationScope, Extensions as ConfigurationExtensions, IConfigurationPropertySchema, IConfigurationRegistry, IConfigurationNode, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry';
R
Rob Lourens 已提交
23 24 25 26 27 28
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Registry } from 'vs/platform/registry/common/platform';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { RangeHighlightDecorations } from 'vs/workbench/browser/parts/editor/rangeDecorations';
29
import { DefaultSettingsHeaderWidget, EditPreferenceWidget, SettingsGroupTitleWidget, SettingsHeaderWidget } from 'vs/workbench/contrib/preferences/browser/preferencesWidgets';
30
import { IFilterResult, IPreferencesEditorModel, IPreferencesService, ISetting, ISettingsEditorModel, ISettingsGroup } from 'vs/workbench/services/preferences/common/preferences';
R
Rob Lourens 已提交
31
import { DefaultSettingsEditorModel, SettingsEditorModel, WorkspaceConfigurationEditorModel } from 'vs/workbench/services/preferences/common/preferencesModels';
S
Sandeep Somavarapu 已提交
32 33
import { IMarkerService, IMarkerData, MarkerSeverity, MarkerTag } from 'vs/platform/markers/common/markers';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
34 35

export interface IPreferencesRenderer<T> extends IDisposable {
S
Sandeep Somavarapu 已提交
36 37 38 39
	readonly preferencesModel: IPreferencesEditorModel<T>;

	getAssociatedPreferencesModel(): IPreferencesEditorModel<T>;
	setAssociatedPreferencesModel(associatedPreferencesModel: IPreferencesEditorModel<T>): void;
40

41 42
	onFocusPreference: Event<T>;
	onClearFocusPreference: Event<T>;
43
	onUpdatePreference: Event<{ key: string, value: any, source: T }>;
44

45
	render(): void;
46
	updatePreference(key: string, value: any, source: T): void;
47 48
	focusPreference(setting: T): void;
	clearFocus(setting: T): void;
49
	filterPreferences(filterResult: IFilterResult | undefined): void;
50
	editPreference(setting: T): boolean;
51 52 53 54 55 56
}

export class UserSettingsRenderer extends Disposable implements IPreferencesRenderer<ISetting> {

	private settingHighlighter: SettingHighlighter;
	private editSettingActionRenderer: EditSettingRenderer;
57
	private highlightMatchesRenderer: HighlightMatchesRenderer;
58
	private modelChangeDelayer: Delayer<void> = new Delayer<void>(200);
S
Sandeep Somavarapu 已提交
59
	private associatedPreferencesModel: IPreferencesEditorModel<ISetting>;
60

61
	private readonly _onFocusPreference = this._register(new Emitter<ISetting>());
R
Rob Lourens 已提交
62
	readonly onFocusPreference: Event<ISetting> = this._onFocusPreference.event;
63

64
	private readonly _onClearFocusPreference = this._register(new Emitter<ISetting>());
R
Rob Lourens 已提交
65
	readonly onClearFocusPreference: Event<ISetting> = this._onClearFocusPreference.event;
66

67
	private readonly _onUpdatePreference = this._register(new Emitter<{ key: string, value: any, source: IIndexedSetting }>());
R
Rob Lourens 已提交
68
	readonly onUpdatePreference: Event<{ key: string, value: any, source: IIndexedSetting }> = this._onUpdatePreference.event;
69

S
Sandeep Somavarapu 已提交
70 71
	private unsupportedSettingsRenderer: UnsupportedSettingsRenderer;

72
	private filterResult: IFilterResult | undefined;
73

R
Rob Lourens 已提交
74
	constructor(protected editor: ICodeEditor, readonly preferencesModel: SettingsEditorModel,
75
		@IPreferencesService protected preferencesService: IPreferencesService,
76
		@IConfigurationService private readonly configurationService: IConfigurationService,
77 78 79 80
		@IInstantiationService protected instantiationService: IInstantiationService
	) {
		super();
		this.settingHighlighter = this._register(instantiationService.createInstance(SettingHighlighter, editor, this._onFocusPreference, this._onClearFocusPreference));
81
		this.highlightMatchesRenderer = this._register(instantiationService.createInstance(HighlightMatchesRenderer, editor));
82
		this.editSettingActionRenderer = this._register(this.instantiationService.createInstance(EditSettingRenderer, this.editor, this.preferencesModel, this.settingHighlighter));
83
		this._register(this.editSettingActionRenderer.onUpdateSetting(({ key, value, source }) => this._updatePreference(key, value, source)));
84
		this._register(this.editor.getModel()!.onDidChangeContent(() => this.modelChangeDelayer.trigger(() => this.onModelChanged())));
S
Sandeep Somavarapu 已提交
85
		this.unsupportedSettingsRenderer = this._register(instantiationService.createInstance(UnsupportedSettingsRenderer, editor, preferencesModel));
S
Sandeep Somavarapu 已提交
86 87
	}

R
Rob Lourens 已提交
88
	getAssociatedPreferencesModel(): IPreferencesEditorModel<ISetting> {
S
Sandeep Somavarapu 已提交
89
		return this.associatedPreferencesModel;
S
Sandeep Somavarapu 已提交
90 91
	}

R
Rob Lourens 已提交
92
	setAssociatedPreferencesModel(associatedPreferencesModel: IPreferencesEditorModel<ISetting>): void {
S
Sandeep Somavarapu 已提交
93
		this.associatedPreferencesModel = associatedPreferencesModel;
S
Sandeep Somavarapu 已提交
94
		this.editSettingActionRenderer.associatedPreferencesModel = associatedPreferencesModel;
S
Sandeep Somavarapu 已提交
95 96 97

		// Create header only in Settings editor mode
		this.createHeader();
S
Sandeep Somavarapu 已提交
98 99
	}

S
Sandeep Somavarapu 已提交
100
	protected createHeader(): void {
101
		this._register(new SettingsHeaderWidget(this.editor, '')).setMessage(nls.localize('emptyUserSettingsHeader', "Place your settings here to override the Default Settings."));
102 103
	}

R
Rob Lourens 已提交
104
	render(): void {
105
		this.editSettingActionRenderer.render(this.preferencesModel.settingsGroups, this.associatedPreferencesModel);
106 107 108
		if (this.filterResult) {
			this.filterPreferences(this.filterResult);
		}
S
Sandeep Somavarapu 已提交
109
		this.unsupportedSettingsRenderer.render();
110 111
	}

112 113 114 115
	private _updatePreference(key: string, value: any, source: IIndexedSetting): void {
		this._onUpdatePreference.fire({ key, value, source });
		this.updatePreference(key, value, source);
	}
116

R
Rob Lourens 已提交
117
	updatePreference(key: string, value: any, source: IIndexedSetting): void {
118
		const overrideIdentifier = source.overrideOf ? overrideIdentifierFromKey(source.overrideOf.key) : null;
119
		const resource = this.preferencesModel.uri;
120 121
		this.configurationService.updateValue(key, value, { overrideIdentifier, resource }, this.preferencesModel.configurationTarget)
			.then(() => this.onSettingUpdated(source));
122 123 124
	}

	private onModelChanged(): void {
M
Matt Bierner 已提交
125
		if (!this.editor.hasModel()) {
126 127 128 129 130 131 132 133
			// model could have been disposed during the delay
			return;
		}
		this.render();
	}

	private onSettingUpdated(setting: ISetting) {
		this.editor.focus();
134
		setting = this.getSetting(setting)!;
135 136 137 138 139 140 141
		if (setting) {
			// TODO:@sandy Selection range should be template range
			this.editor.setSelection(setting.valueRange);
			this.settingHighlighter.highlight(setting, true);
		}
	}

142
	private getSetting(setting: ISetting): ISetting | undefined {
A
Alex Dima 已提交
143
		const { key, overrideOf } = setting;
144 145
		if (overrideOf) {
			const setting = this.getSetting(overrideOf);
146
			for (const override of setting!.overrides!) {
147 148 149 150
				if (override.key === key) {
					return override;
				}
			}
151
			return undefined;
152
		}
153

154 155 156
		return this.preferencesModel.getPreference(key);
	}

157
	filterPreferences(filterResult: IFilterResult | undefined): void {
158 159
		this.filterResult = filterResult;
		this.settingHighlighter.clear(true);
160
		this.highlightMatchesRenderer.render(filterResult ? filterResult.matches : []);
161 162
	}

R
Rob Lourens 已提交
163
	focusPreference(setting: ISetting): void {
164 165 166
		const s = this.getSetting(setting);
		if (s) {
			this.settingHighlighter.highlight(s, true);
S
Sandeep Somavarapu 已提交
167
			this.editor.setPosition({ lineNumber: s.keyRange.startLineNumber, column: s.keyRange.startColumn });
168 169 170 171 172
		} else {
			this.settingHighlighter.clear(true);
		}
	}

R
Rob Lourens 已提交
173
	clearFocus(setting: ISetting): void {
174 175
		this.settingHighlighter.clear(true);
	}
176

R
Rob Lourens 已提交
177
	editPreference(setting: ISetting): boolean {
R
Rob Lourens 已提交
178
		const editableSetting = this.getSetting(setting);
179
		return !!(editableSetting && this.editSettingActionRenderer.activateOnSetting(editableSetting));
180
	}
181 182 183 184
}

export class WorkspaceSettingsRenderer extends UserSettingsRenderer implements IPreferencesRenderer<ISetting> {

S
Sandeep Somavarapu 已提交
185
	private workspaceConfigurationRenderer: WorkspaceConfigurationRenderer;
186

187
	constructor(editor: ICodeEditor, preferencesModel: SettingsEditorModel,
188 189
		@IPreferencesService preferencesService: IPreferencesService,
		@ITelemetryService telemetryService: ITelemetryService,
190
		@IConfigurationService configurationService: IConfigurationService,
191 192
		@IInstantiationService instantiationService: IInstantiationService
	) {
193
		super(editor, preferencesModel, preferencesService, configurationService, instantiationService);
S
Sandeep Somavarapu 已提交
194
		this.workspaceConfigurationRenderer = this._register(instantiationService.createInstance(WorkspaceConfigurationRenderer, editor, preferencesModel));
195 196
	}

S
Sandeep Somavarapu 已提交
197
	protected createHeader(): void {
198
		this._register(new SettingsHeaderWidget(this.editor, '')).setMessage(nls.localize('emptyWorkspaceSettingsHeader', "Place your settings here to override the User Settings."));
S
Sandeep Somavarapu 已提交
199 200
	}

R
Rob Lourens 已提交
201
	setAssociatedPreferencesModel(associatedPreferencesModel: IPreferencesEditorModel<ISetting>): void {
S
Sandeep Somavarapu 已提交
202 203 204 205
		super.setAssociatedPreferencesModel(associatedPreferencesModel);
		this.workspaceConfigurationRenderer.render(this.getAssociatedPreferencesModel());
	}

R
Rob Lourens 已提交
206
	render(): void {
207
		super.render();
S
Sandeep Somavarapu 已提交
208
		this.workspaceConfigurationRenderer.render(this.getAssociatedPreferencesModel());
209 210 211
	}
}

212 213
export class FolderSettingsRenderer extends UserSettingsRenderer implements IPreferencesRenderer<ISetting> {

214
	constructor(editor: ICodeEditor, preferencesModel: SettingsEditorModel,
215 216
		@IPreferencesService preferencesService: IPreferencesService,
		@ITelemetryService telemetryService: ITelemetryService,
217
		@IConfigurationService configurationService: IConfigurationService,
218 219
		@IInstantiationService instantiationService: IInstantiationService
	) {
220
		super(editor, preferencesModel, preferencesService, configurationService, instantiationService);
221 222
	}

S
Sandeep Somavarapu 已提交
223
	protected createHeader(): void {
224
		this._register(new SettingsHeaderWidget(this.editor, '')).setMessage(nls.localize('emptyFolderSettingsHeader', "Place your folder settings here to override those from the Workspace Settings."));
S
Sandeep Somavarapu 已提交
225 226
	}

227 228
}

229 230
export class DefaultSettingsRenderer extends Disposable implements IPreferencesRenderer<ISetting> {

231
	private _associatedPreferencesModel: IPreferencesEditorModel<ISetting>;
232
	private settingHighlighter: SettingHighlighter;
S
Sandeep Somavarapu 已提交
233
	private settingsHeaderRenderer: DefaultSettingsHeaderRenderer;
234 235 236 237
	private settingsGroupTitleRenderer: SettingsGroupTitleRenderer;
	private filteredMatchesRenderer: FilteredMatchesRenderer;
	private hiddenAreasRenderer: HiddenAreasRenderer;
	private editSettingActionRenderer: EditSettingRenderer;
238
	private bracesHidingRenderer: BracesHidingRenderer;
239
	private filterResult: IFilterResult | undefined;
240

241
	private readonly _onUpdatePreference = this._register(new Emitter<{ key: string, value: any, source: IIndexedSetting }>());
R
Rob Lourens 已提交
242
	readonly onUpdatePreference: Event<{ key: string, value: any, source: IIndexedSetting }> = this._onUpdatePreference.event;
243

244
	private readonly _onFocusPreference = this._register(new Emitter<ISetting>());
R
Rob Lourens 已提交
245
	readonly onFocusPreference: Event<ISetting> = this._onFocusPreference.event;
246

247
	private readonly _onClearFocusPreference = this._register(new Emitter<ISetting>());
R
Rob Lourens 已提交
248
	readonly onClearFocusPreference: Event<ISetting> = this._onClearFocusPreference.event;
249

R
Rob Lourens 已提交
250
	constructor(protected editor: ICodeEditor, readonly preferencesModel: DefaultSettingsEditorModel,
251
		@IPreferencesService protected preferencesService: IPreferencesService,
252
		@IInstantiationService protected instantiationService: IInstantiationService,
253 254 255
	) {
		super();
		this.settingHighlighter = this._register(instantiationService.createInstance(SettingHighlighter, editor, this._onFocusPreference, this._onClearFocusPreference));
S
Sandeep Somavarapu 已提交
256
		this.settingsHeaderRenderer = this._register(instantiationService.createInstance(DefaultSettingsHeaderRenderer, editor));
257 258
		this.settingsGroupTitleRenderer = this._register(instantiationService.createInstance(SettingsGroupTitleRenderer, editor));
		this.filteredMatchesRenderer = this._register(instantiationService.createInstance(FilteredMatchesRenderer, editor));
259
		this.editSettingActionRenderer = this._register(instantiationService.createInstance(EditSettingRenderer, editor, preferencesModel, this.settingHighlighter));
260 261
		this.bracesHidingRenderer = this._register(instantiationService.createInstance(BracesHidingRenderer, editor, preferencesModel));
		this.hiddenAreasRenderer = this._register(instantiationService.createInstance(HiddenAreasRenderer, editor, [this.settingsGroupTitleRenderer, this.filteredMatchesRenderer, this.bracesHidingRenderer]));
R
Rob Lourens 已提交
262

263 264
		this._register(this.editSettingActionRenderer.onUpdateSetting(e => this._onUpdatePreference.fire(e)));
		this._register(this.settingsGroupTitleRenderer.onHiddenAreasChanged(() => this.hiddenAreasRenderer.render()));
S
Sandeep Somavarapu 已提交
265
		this._register(preferencesModel.onDidChangeGroups(() => this.render()));
266 267
	}

R
Rob Lourens 已提交
268
	getAssociatedPreferencesModel(): IPreferencesEditorModel<ISetting> {
269 270 271
		return this._associatedPreferencesModel;
	}

R
Rob Lourens 已提交
272
	setAssociatedPreferencesModel(associatedPreferencesModel: IPreferencesEditorModel<ISetting>): void {
273 274 275 276
		this._associatedPreferencesModel = associatedPreferencesModel;
		this.editSettingActionRenderer.associatedPreferencesModel = associatedPreferencesModel;
	}

R
Rob Lourens 已提交
277
	render() {
278
		this.settingsGroupTitleRenderer.render(this.preferencesModel.settingsGroups);
279
		this.editSettingActionRenderer.render(this.preferencesModel.settingsGroups, this._associatedPreferencesModel);
280
		this.settingHighlighter.clear(true);
281
		this.bracesHidingRenderer.render(undefined, this.preferencesModel.settingsGroups);
282
		this.settingsGroupTitleRenderer.showGroup(0);
283 284 285
		this.hiddenAreasRenderer.render();
	}

286
	filterPreferences(filterResult: IFilterResult | undefined): void {
287
		this.filterResult = filterResult;
288

R
Rob Lourens 已提交
289
		if (filterResult) {
290
			this.filteredMatchesRenderer.render(filterResult, this.preferencesModel.settingsGroups);
291
			this.settingsGroupTitleRenderer.render(undefined);
292
			this.settingsHeaderRenderer.render(filterResult);
R
Rob Lourens 已提交
293
			this.settingHighlighter.clear(true);
294
			this.bracesHidingRenderer.render(filterResult, this.preferencesModel.settingsGroups);
R
Rob Lourens 已提交
295 296
			this.editSettingActionRenderer.render(filterResult.filteredGroups, this._associatedPreferencesModel);
		} else {
297
			this.settingHighlighter.clear(true);
298 299
			this.filteredMatchesRenderer.render(undefined, this.preferencesModel.settingsGroups);
			this.settingsHeaderRenderer.render(undefined);
300
			this.settingsGroupTitleRenderer.render(this.preferencesModel.settingsGroups);
301
			this.settingsGroupTitleRenderer.showGroup(0);
302
			this.bracesHidingRenderer.render(undefined, this.preferencesModel.settingsGroups);
303
			this.editSettingActionRenderer.render(this.preferencesModel.settingsGroups, this._associatedPreferencesModel);
304
		}
R
Rob Lourens 已提交
305

306 307 308
		this.hiddenAreasRenderer.render();
	}

R
Rob Lourens 已提交
309
	focusPreference(s: ISetting): void {
310 311 312 313 314 315 316 317 318
		const setting = this.getSetting(s);
		if (setting) {
			this.settingsGroupTitleRenderer.showSetting(setting);
			this.settingHighlighter.highlight(setting, true);
		} else {
			this.settingHighlighter.clear(true);
		}
	}

319
	private getSetting(setting: ISetting): ISetting | undefined {
320 321 322
		const { key, overrideOf } = setting;
		if (overrideOf) {
			const setting = this.getSetting(overrideOf);
323
			for (const override of setting!.overrides!) {
324 325 326 327
				if (override.key === key) {
					return override;
				}
			}
328
			return undefined;
329 330 331 332 333
		}
		const settingsGroups = this.filterResult ? this.filterResult.filteredGroups : this.preferencesModel.settingsGroups;
		return this.getPreference(key, settingsGroups);
	}

334
	private getPreference(key: string, settingsGroups: ISettingsGroup[]): ISetting | undefined {
335 336 337 338 339 340 341 342 343
		for (const group of settingsGroups) {
			for (const section of group.sections) {
				for (const setting of section.settings) {
					if (setting.key === key) {
						return setting;
					}
				}
			}
		}
344
		return undefined;
345 346
	}

R
Rob Lourens 已提交
347
	clearFocus(setting: ISetting): void {
348 349 350
		this.settingHighlighter.clear(true);
	}

R
Rob Lourens 已提交
351
	updatePreference(key: string, value: any, source: ISetting): void {
352
	}
353

R
Rob Lourens 已提交
354
	editPreference(setting: ISetting): boolean {
355 356
		return this.editSettingActionRenderer.activateOnSetting(setting);
	}
357 358 359
}

export interface HiddenAreasProvider {
A
Alex Dima 已提交
360
	hiddenAreas: IRange[];
361 362
}

363
export class BracesHidingRenderer extends Disposable implements HiddenAreasProvider {
364
	private _result: IFilterResult | undefined;
365
	private _settingsGroups: ISettingsGroup[];
366

367
	constructor(private editor: ICodeEditor) {
368 369 370
		super();
	}

371
	render(result: IFilterResult | undefined, settingsGroups: ISettingsGroup[]): void {
372 373 374
		this._result = result;
		this._settingsGroups = settingsGroups;
	}
R
Rob Lourens 已提交
375

376 377 378
	get hiddenAreas(): IRange[] {
		// Opening square brace
		const hiddenAreas = [
379 380
			{
				startLineNumber: 1,
381
				startColumn: 1,
382
				endLineNumber: 2,
383
				endColumn: 1
384 385
			}
		];
386

387
		const hideBraces = (group: ISettingsGroup, hideExtraLine?: boolean) => {
388 389 390 391
			// Opening curly brace
			hiddenAreas.push({
				startLineNumber: group.range.startLineNumber - 3,
				startColumn: 1,
392
				endLineNumber: group.range.startLineNumber - (hideExtraLine ? 1 : 3),
393 394 395 396 397 398 399 400 401 402 403 404
				endColumn: 1
			});

			// Closing curly brace
			hiddenAreas.push({
				startLineNumber: group.range.endLineNumber + 1,
				startColumn: 1,
				endLineNumber: group.range.endLineNumber + 4,
				endColumn: 1
			});
		};

405
		this._settingsGroups.forEach(g => hideBraces(g));
406
		if (this._result) {
407
			this._result.filteredGroups.forEach((g, i) => hideBraces(g, true));
408 409 410
		}

		// Closing square brace
411
		const lineCount = this.editor.getModel()!.getLineCount();
412 413 414 415 416 417 418 419 420
		hiddenAreas.push({
			startLineNumber: lineCount,
			startColumn: 1,
			endLineNumber: lineCount,
			endColumn: 1
		});


		return hiddenAreas;
421 422 423 424
	}

}

S
Sandeep Somavarapu 已提交
425
class DefaultSettingsHeaderRenderer extends Disposable {
S
Sandeep Somavarapu 已提交
426

427
	private settingsHeaderWidget: DefaultSettingsHeaderWidget;
R
Rob Lourens 已提交
428
	readonly onClick: Event<void>;
S
Sandeep Somavarapu 已提交
429

S
Sandeep Somavarapu 已提交
430
	constructor(editor: ICodeEditor) {
S
Sandeep Somavarapu 已提交
431
		super();
S
Sandeep Somavarapu 已提交
432
		this.settingsHeaderWidget = this._register(new DefaultSettingsHeaderWidget(editor, ''));
433
		this.onClick = this.settingsHeaderWidget.onClick;
S
Sandeep Somavarapu 已提交
434 435
	}

436
	render(filterResult: IFilterResult | undefined) {
437
		const hasSettings = !filterResult || filterResult.filteredGroups.length > 0;
438
		this.settingsHeaderWidget.toggleMessage(hasSettings);
S
Sandeep Somavarapu 已提交
439 440 441
	}
}

442 443
export class SettingsGroupTitleRenderer extends Disposable implements HiddenAreasProvider {

444
	private readonly _onHiddenAreasChanged = this._register(new Emitter<void>());
445
	readonly onHiddenAreasChanged: Event<void> = this._onHiddenAreasChanged.event;
446 447 448 449

	private settingsGroups: ISettingsGroup[];
	private hiddenGroups: ISettingsGroup[] = [];
	private settingsGroupTitleWidgets: SettingsGroupTitleWidget[];
450
	private readonly renderDisposables = this._register(new DisposableStore());
451 452

	constructor(private editor: ICodeEditor,
453
		@IInstantiationService private readonly instantiationService: IInstantiationService
454 455 456 457
	) {
		super();
	}

R
Rob Lourens 已提交
458
	get hiddenAreas(): IRange[] {
A
Alex Dima 已提交
459
		const hiddenAreas: IRange[] = [];
460 461 462 463 464 465
		for (const group of this.hiddenGroups) {
			hiddenAreas.push(group.range);
		}
		return hiddenAreas;
	}

466
	render(settingsGroups: ISettingsGroup[] | undefined) {
467
		this.disposeWidgets();
R
Rob Lourens 已提交
468 469 470 471
		if (!settingsGroups) {
			return;
		}

472 473 474
		this.settingsGroups = settingsGroups.slice();
		this.settingsGroupTitleWidgets = [];
		for (const group of this.settingsGroups.slice().reverse()) {
475 476 477 478
			if (group.sections.every(sect => sect.settings.length === 0)) {
				continue;
			}

479 480 481
			const settingsGroupTitleWidget = this.instantiationService.createInstance(SettingsGroupTitleWidget, this.editor, group);
			settingsGroupTitleWidget.render();
			this.settingsGroupTitleWidgets.push(settingsGroupTitleWidget);
482 483
			this.renderDisposables.add(settingsGroupTitleWidget);
			this.renderDisposables.add(settingsGroupTitleWidget.onToggled(collapsed => this.onToggled(collapsed, settingsGroupTitleWidget.settingsGroup)));
484 485 486 487
		}
		this.settingsGroupTitleWidgets.reverse();
	}

R
Rob Lourens 已提交
488
	showGroup(groupIdx: number) {
489 490 491 492
		const shownGroup = this.settingsGroupTitleWidgets[groupIdx].settingsGroup;

		this.hiddenGroups = this.settingsGroups.filter(g => g !== shownGroup);
		for (const groupTitleWidget of this.settingsGroupTitleWidgets.filter(widget => widget.settingsGroup !== shownGroup)) {
493 494 495 496 497
			groupTitleWidget.toggleCollapse(true);
		}
		this._onHiddenAreasChanged.fire();
	}

R
Rob Lourens 已提交
498
	showSetting(setting: ISetting): void {
499 500 501 502 503 504 505 506 507 508 509 510
		const settingsGroupTitleWidget = this.settingsGroupTitleWidgets.filter(widget => Range.containsRange(widget.settingsGroup.range, setting.range))[0];
		if (settingsGroupTitleWidget && settingsGroupTitleWidget.isCollapsed()) {
			settingsGroupTitleWidget.toggleCollapse(false);
			this.hiddenGroups.splice(this.hiddenGroups.indexOf(settingsGroupTitleWidget.settingsGroup), 1);
			this._onHiddenAreasChanged.fire();
		}
	}

	private onToggled(collapsed: boolean, group: ISettingsGroup) {
		const index = this.hiddenGroups.indexOf(group);
		if (collapsed) {
			const currentPosition = this.editor.getPosition();
511
			if (group.range.startLineNumber <= currentPosition!.lineNumber && group.range.endLineNumber >= currentPosition!.lineNumber) {
512 513 514 515 516 517 518 519 520 521 522
				this.editor.setPosition({ lineNumber: group.range.startLineNumber - 1, column: 1 });
			}
			this.hiddenGroups.push(group);
		} else {
			this.hiddenGroups.splice(index, 1);
		}
		this._onHiddenAreasChanged.fire();
	}

	private disposeWidgets() {
		this.hiddenGroups = [];
523
		this.renderDisposables.clear();
524 525
	}

R
Rob Lourens 已提交
526
	dispose() {
527 528 529 530 531 532 533
		this.disposeWidgets();
		super.dispose();
	}
}

export class HiddenAreasRenderer extends Disposable {

S
Sandeep Somavarapu 已提交
534
	constructor(private editor: ICodeEditor, private hiddenAreasProviders: HiddenAreasProvider[]
535 536 537 538
	) {
		super();
	}

R
Rob Lourens 已提交
539
	render() {
A
Alex Dima 已提交
540
		const ranges: IRange[] = [];
541 542 543 544 545 546
		for (const hiddenAreaProvider of this.hiddenAreasProviders) {
			ranges.push(...hiddenAreaProvider.hiddenAreas);
		}
		this.editor.setHiddenAreas(ranges);
	}

R
Rob Lourens 已提交
547
	dispose() {
548 549 550 551 552 553 554 555
		this.editor.setHiddenAreas([]);
		super.dispose();
	}
}

export class FilteredMatchesRenderer extends Disposable implements HiddenAreasProvider {

	private decorationIds: string[] = [];
R
Rob Lourens 已提交
556
	hiddenAreas: IRange[] = [];
557

S
Sandeep Somavarapu 已提交
558
	constructor(private editor: ICodeEditor
559 560 561 562
	) {
		super();
	}

563
	render(result: IFilterResult | undefined, allSettingsGroups: ISettingsGroup[]): void {
564 565
		this.hiddenAreas = [];
		if (result) {
566 567
			this.hiddenAreas = this.computeHiddenRanges(result.filteredGroups, result.allGroups);
			this.decorationIds = this.editor.deltaDecorations(this.decorationIds, result.matches.map(match => this.createDecoration(match)));
568
		} else {
569
			this.hiddenAreas = this.computeHiddenRanges(undefined, allSettingsGroups);
570
			this.decorationIds = this.editor.deltaDecorations(this.decorationIds, []);
571 572 573
		}
	}

574
	private createDecoration(range: IRange): IModelDeltaDecoration {
575 576
		return {
			range,
A
Alex Dima 已提交
577
			options: FilteredMatchesRenderer._FIND_MATCH
578 579 580
		};
	}

A
Alex Dima 已提交
581 582 583 584 585
	private static readonly _FIND_MATCH = ModelDecorationOptions.register({
		stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
		className: 'findMatch'
	});

586
	private computeHiddenRanges(filteredGroups: ISettingsGroup[] | undefined, allSettingsGroups: ISettingsGroup[]): IRange[] {
587
		// Hide the contents of hidden groups
A
Alex Dima 已提交
588
		const notMatchesRanges: IRange[] = [];
589 590
		if (filteredGroups) {
			allSettingsGroups.forEach((group, i) => {
591 592
				notMatchesRanges.push({
					startLineNumber: group.range.startLineNumber - 1,
593
					startColumn: group.range.startColumn,
594
					endLineNumber: group.range.endLineNumber,
595
					endColumn: group.range.endColumn
596
				});
597
			});
598 599
		}

600
		return notMatchesRanges;
601 602
	}

R
Rob Lourens 已提交
603
	dispose() {
604
		this.decorationIds = this.editor.deltaDecorations(this.decorationIds, []);
605 606 607 608
		super.dispose();
	}
}

609
export class HighlightMatchesRenderer extends Disposable {
610 611 612

	private decorationIds: string[] = [];

S
Sandeep Somavarapu 已提交
613
	constructor(private editor: ICodeEditor
614 615 616 617
	) {
		super();
	}

R
Rob Lourens 已提交
618
	render(matches: IRange[]): void {
619
		this.decorationIds = this.editor.deltaDecorations(this.decorationIds, matches.map(match => this.createDecoration(match)));
620 621
	}

622
	private static readonly _FIND_MATCH = ModelDecorationOptions.register({
623
		stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
624 625 626
		className: 'findMatch'
	});

627
	private createDecoration(range: IRange): IModelDeltaDecoration {
628 629
		return {
			range,
630
			options: HighlightMatchesRenderer._FIND_MATCH
631 632 633
		};
	}

R
Rob Lourens 已提交
634
	dispose() {
635
		this.decorationIds = this.editor.deltaDecorations(this.decorationIds, []);
636 637 638 639
		super.dispose();
	}
}

640
export interface IIndexedSetting extends ISetting {
641
	index: number;
642
	groupId: string;
643 644
}

645 646
class EditSettingRenderer extends Disposable {

647
	private editPreferenceWidgetForCursorPosition: EditPreferenceWidget<IIndexedSetting>;
648
	private editPreferenceWidgetForMouseMove: EditPreferenceWidget<IIndexedSetting>;
649

S
Sandeep Somavarapu 已提交
650
	private settingsGroups: ISettingsGroup[] = [];
R
Rob Lourens 已提交
651
	associatedPreferencesModel: IPreferencesEditorModel<ISetting>;
652 653
	private toggleEditPreferencesForMouseMoveDelayer: Delayer<void>;

M
Matt Bierner 已提交
654
	private readonly _onUpdateSetting: Emitter<{ key: string, value: any, source: IIndexedSetting }> = new Emitter<{ key: string, value: any, source: IIndexedSetting }>();
R
Rob Lourens 已提交
655
	readonly onUpdateSetting: Event<{ key: string, value: any, source: IIndexedSetting }> = this._onUpdateSetting.event;
656 657 658

	constructor(private editor: ICodeEditor, private masterSettingsModel: ISettingsEditorModel,
		private settingHighlighter: SettingHighlighter,
659 660
		@IInstantiationService private readonly instantiationService: IInstantiationService,
		@IContextMenuService private readonly contextMenuService: IContextMenuService
661 662 663
	) {
		super();

664 665
		this.editPreferenceWidgetForCursorPosition = <EditPreferenceWidget<IIndexedSetting>>this._register(this.instantiationService.createInstance(EditPreferenceWidget, editor));
		this.editPreferenceWidgetForMouseMove = <EditPreferenceWidget<IIndexedSetting>>this._register(this.instantiationService.createInstance(EditPreferenceWidget, editor));
666 667
		this.toggleEditPreferencesForMouseMoveDelayer = new Delayer<void>(75);

668
		this._register(this.editPreferenceWidgetForCursorPosition.onClick(e => this.onEditSettingClicked(this.editPreferenceWidgetForCursorPosition, e)));
S
Sandeep Somavarapu 已提交
669
		this._register(this.editPreferenceWidgetForMouseMove.onClick(e => this.onEditSettingClicked(this.editPreferenceWidgetForMouseMove, e)));
670 671 672 673 674 675

		this._register(this.editor.onDidChangeCursorPosition(positionChangeEvent => this.onPositionChanged(positionChangeEvent)));
		this._register(this.editor.onMouseMove(mouseMoveEvent => this.onMouseMoved(mouseMoveEvent)));
		this._register(this.editor.onDidChangeConfiguration(() => this.onConfigurationChanged()));
	}

R
Rob Lourens 已提交
676
	render(settingsGroups: ISettingsGroup[], associatedPreferencesModel: IPreferencesEditorModel<ISetting>): void {
677
		this.editPreferenceWidgetForCursorPosition.hide();
678 679
		this.editPreferenceWidgetForMouseMove.hide();
		this.settingsGroups = settingsGroups;
680
		this.associatedPreferencesModel = associatedPreferencesModel;
681

682
		const settings = this.getSettings(this.editor.getPosition()!.lineNumber);
683
		if (settings.length) {
684
			this.showEditPreferencesWidget(this.editPreferenceWidgetForCursorPosition, settings);
685 686 687 688 689 690 691 692
		}
	}

	private isDefaultSettings(): boolean {
		return this.masterSettingsModel instanceof DefaultSettingsEditorModel;
	}

	private onConfigurationChanged(): void {
693
		if (!this.editor.getConfiguration().viewInfo.glyphMargin) {
694
			this.editPreferenceWidgetForCursorPosition.hide();
695 696 697 698
			this.editPreferenceWidgetForMouseMove.hide();
		}
	}

699
	private onPositionChanged(positionChangeEvent: ICursorPositionChangedEvent) {
700 701 702
		this.editPreferenceWidgetForMouseMove.hide();
		const settings = this.getSettings(positionChangeEvent.position.lineNumber);
		if (settings.length) {
703
			this.showEditPreferencesWidget(this.editPreferenceWidgetForCursorPosition, settings);
704
		} else {
705
			this.editPreferenceWidgetForCursorPosition.hide();
706 707 708 709 710 711 712 713 714 715
		}
	}

	private onMouseMoved(mouseMoveEvent: IEditorMouseEvent): void {
		const editPreferenceWidget = this.getEditPreferenceWidgetUnderMouse(mouseMoveEvent);
		if (editPreferenceWidget) {
			this.onMouseOver(editPreferenceWidget);
			return;
		}
		this.settingHighlighter.clear();
716
		this.toggleEditPreferencesForMouseMoveDelayer.trigger(() => this.toggleEditPreferenceWidgetForMouseMove(mouseMoveEvent));
717 718
	}

719
	private getEditPreferenceWidgetUnderMouse(mouseMoveEvent: IEditorMouseEvent): EditPreferenceWidget<ISetting> | undefined {
A
Alex Dima 已提交
720
		if (mouseMoveEvent.target.type === MouseTargetType.GUTTER_GLYPH_MARGIN) {
721
			const line = mouseMoveEvent.target.position!.lineNumber;
S
Sandeep Somavarapu 已提交
722 723 724
			if (this.editPreferenceWidgetForMouseMove.getLine() === line && this.editPreferenceWidgetForMouseMove.isVisible()) {
				return this.editPreferenceWidgetForMouseMove;
			}
725 726
			if (this.editPreferenceWidgetForCursorPosition.getLine() === line && this.editPreferenceWidgetForCursorPosition.isVisible()) {
				return this.editPreferenceWidgetForCursorPosition;
S
Sandeep Somavarapu 已提交
727
			}
728
		}
729
		return undefined;
730 731
	}

732
	private toggleEditPreferenceWidgetForMouseMove(mouseMoveEvent: IEditorMouseEvent): void {
733 734 735 736 737 738 739 740
		const settings = mouseMoveEvent.target.position ? this.getSettings(mouseMoveEvent.target.position.lineNumber) : null;
		if (settings && settings.length) {
			this.showEditPreferencesWidget(this.editPreferenceWidgetForMouseMove, settings);
		} else {
			this.editPreferenceWidgetForMouseMove.hide();
		}
	}

741
	private showEditPreferencesWidget(editPreferencesWidget: EditPreferenceWidget<ISetting>, settings: IIndexedSetting[]) {
S
Sandeep Somavarapu 已提交
742
		const line = settings[0].valueRange.startLineNumber;
743
		if (this.editor.getConfiguration().viewInfo.glyphMargin && this.marginFreeFromOtherDecorations(line)) {
S
Sandeep Somavarapu 已提交
744
			editPreferencesWidget.show(line, nls.localize('editTtile', "Edit"), settings);
745
			const editPreferenceWidgetToHide = editPreferencesWidget === this.editPreferenceWidgetForCursorPosition ? this.editPreferenceWidgetForMouseMove : this.editPreferenceWidgetForCursorPosition;
746 747 748 749
			editPreferenceWidgetToHide.hide();
		}
	}

S
Sandeep Somavarapu 已提交
750 751 752
	private marginFreeFromOtherDecorations(line: number): boolean {
		const decorations = this.editor.getLineDecorations(line);
		if (decorations) {
A
Alex Dima 已提交
753
			for (const { options } of decorations) {
S
Sandeep Somavarapu 已提交
754 755 756 757 758 759 760 761
				if (options.glyphMarginClassName && options.glyphMarginClassName.indexOf(EditPreferenceWidget.GLYPH_MARGIN_CLASS_NAME) === -1) {
					return false;
				}
			}
		}
		return true;
	}

762
	private getSettings(lineNumber: number): IIndexedSetting[] {
763 764
		const configurationMap = this.getConfigurationsMap();
		return this.getSettingsAtLineNumber(lineNumber).filter(setting => {
R
Rob Lourens 已提交
765
			const configurationNode = configurationMap[setting.key];
S
Sandeep Somavarapu 已提交
766 767
			if (configurationNode) {
				if (this.isDefaultSettings()) {
S
Sandeep Somavarapu 已提交
768 769 770 771
					if (setting.key === 'launch') {
						// Do not show because of https://github.com/Microsoft/vscode/issues/32593
						return false;
					}
S
Sandeep Somavarapu 已提交
772 773 774
					return true;
				}
				if (configurationNode.type === 'boolean' || configurationNode.enum) {
775
					if ((<SettingsEditorModel>this.masterSettingsModel).configurationTarget !== ConfigurationTarget.WORKSPACE_FOLDER) {
S
Sandeep Somavarapu 已提交
776 777 778 779 780 781 782 783
						return true;
					}
					if (configurationNode.scope === ConfigurationScope.RESOURCE) {
						return true;
					}
				}
			}
			return false;
784 785 786
		});
	}

787 788 789 790
	private getSettingsAtLineNumber(lineNumber: number): IIndexedSetting[] {
		// index of setting, across all groups/sections
		let index = 0;

791
		const settings: IIndexedSetting[] = [];
792 793 794 795 796 797 798 799 800 801 802
		for (const group of this.settingsGroups) {
			if (group.range.startLineNumber > lineNumber) {
				break;
			}
			if (lineNumber >= group.range.startLineNumber && lineNumber <= group.range.endLineNumber) {
				for (const section of group.sections) {
					for (const setting of section.settings) {
						if (setting.range.startLineNumber > lineNumber) {
							break;
						}
						if (lineNumber >= setting.range.startLineNumber && lineNumber <= setting.range.endLineNumber) {
803
							if (!this.isDefaultSettings() && setting.overrides!.length) {
804
								// Only one level because override settings cannot have override settings
805
								for (const overrideSetting of setting.overrides!) {
806
									if (lineNumber >= overrideSetting.range.startLineNumber && lineNumber <= overrideSetting.range.endLineNumber) {
807
										settings.push({ ...overrideSetting, index, groupId: group.id });
808 809 810
									}
								}
							} else {
811
								settings.push({ ...setting, index, groupId: group.id });
812 813
							}
						}
814 815

						index++;
816 817 818 819 820 821 822 823 824 825 826
					}
				}
			}
		}
		return settings;
	}

	private onMouseOver(editPreferenceWidget: EditPreferenceWidget<ISetting>): void {
		this.settingHighlighter.highlight(editPreferenceWidget.preferences[0]);
	}

827
	private onEditSettingClicked(editPreferenceWidget: EditPreferenceWidget<IIndexedSetting>, e: IEditorMouseEvent): void {
828 829
		EventHelper.stop(e.event, true);

B
Benjamin Pasero 已提交
830
		const anchor = { x: e.event.posx, y: e.event.posy + 10 };
831
		const actions = this.getSettings(editPreferenceWidget.getLine()).length === 1 ? this.getActions(editPreferenceWidget.preferences[0], this.getConfigurationsMap()[editPreferenceWidget.preferences[0].key])
832 833 834
			: editPreferenceWidget.preferences.map(setting => new ContextSubMenu(setting.key, this.getActions(setting, this.getConfigurationsMap()[setting.key])));
		this.contextMenuService.showContextMenu({
			getAnchor: () => anchor,
835
			getActions: () => actions
836 837 838
		});
	}

R
Rob Lourens 已提交
839
	activateOnSetting(setting: ISetting): boolean {
840 841 842 843 844 845 846 847 848 849
		const startLine = setting.keyRange.startLineNumber;
		const settings = this.getSettings(startLine);
		if (!settings.length) {
			return false;
		}

		this.editPreferenceWidgetForMouseMove.show(startLine, '', settings);
		const actions = this.getActions(this.editPreferenceWidgetForMouseMove.preferences[0], this.getConfigurationsMap()[this.editPreferenceWidgetForMouseMove.preferences[0].key]);
		this.contextMenuService.showContextMenu({
			getAnchor: () => this.toAbsoluteCoords(new Position(startLine, 1)),
850
			getActions: () => actions
851 852 853 854 855 856 857
		});

		return true;
	}

	private toAbsoluteCoords(position: Position): { x: number, y: number } {
		const positionCoords = this.editor.getScrolledVisiblePosition(position);
858 859 860
		const editorCoords = getDomNodePagePosition(this.editor.getDomNode()!);
		const x = editorCoords.left + positionCoords!.left;
		const y = editorCoords.top + positionCoords!.top + positionCoords!.height;
861 862 863 864

		return { x, y: y + 10 };
	}

S
Sandeep Somavarapu 已提交
865
	private getConfigurationsMap(): { [qualifiedKey: string]: IConfigurationPropertySchema } {
866 867 868
		return Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).getConfigurationProperties();
	}

869
	private getActions(setting: IIndexedSetting, jsonSchema: IJSONSchema): IAction[] {
870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895
		if (jsonSchema.type === 'boolean') {
			return [<IAction>{
				id: 'truthyValue',
				label: 'true',
				enabled: true,
				run: () => this.updateSetting(setting.key, true, setting)
			}, <IAction>{
				id: 'falsyValue',
				label: 'false',
				enabled: true,
				run: () => this.updateSetting(setting.key, false, setting)
			}];
		}
		if (jsonSchema.enum) {
			return jsonSchema.enum.map(value => {
				return <IAction>{
					id: value,
					label: JSON.stringify(value),
					enabled: true,
					run: () => this.updateSetting(setting.key, value, setting)
				};
			});
		}
		return this.getDefaultActions(setting);
	}

896
	private getDefaultActions(setting: IIndexedSetting): IAction[] {
897
		if (this.isDefaultSettings()) {
898
			const settingInOtherModel = this.associatedPreferencesModel.getPreference(setting.key);
899 900 901 902 903 904 905 906 907 908
			return [<IAction>{
				id: 'setDefaultValue',
				label: settingInOtherModel ? nls.localize('replaceDefaultValue', "Replace in Settings") : nls.localize('copyDefaultValue', "Copy to Settings"),
				enabled: true,
				run: () => this.updateSetting(setting.key, setting.value, setting)
			}];
		}
		return [];
	}

909
	private updateSetting(key: string, value: any, source: IIndexedSetting): void {
910
		this._onUpdateSetting.fire({ key, value, source });
911 912 913 914 915 916 917 918 919
	}
}

class SettingHighlighter extends Disposable {

	private fixedHighlighter: RangeHighlightDecorations;
	private volatileHighlighter: RangeHighlightDecorations;
	private highlightedSetting: ISetting;

M
Matt Bierner 已提交
920
	constructor(private editor: ICodeEditor, private readonly focusEventEmitter: Emitter<ISetting>, private readonly clearFocusEventEmitter: Emitter<ISetting>,
921 922 923 924 925
		@IInstantiationService instantiationService: IInstantiationService
	) {
		super();
		this.fixedHighlighter = this._register(instantiationService.createInstance(RangeHighlightDecorations));
		this.volatileHighlighter = this._register(instantiationService.createInstance(RangeHighlightDecorations));
926 927
		this.fixedHighlighter.onHighlightRemoved(() => this.clearFocusEventEmitter.fire(this.highlightedSetting));
		this.volatileHighlighter.onHighlightRemoved(() => this.clearFocusEventEmitter.fire(this.highlightedSetting));
928 929 930 931 932 933 934 935 936 937
	}

	highlight(setting: ISetting, fix: boolean = false) {
		this.highlightedSetting = setting;
		this.volatileHighlighter.removeHighlightRange();
		this.fixedHighlighter.removeHighlightRange();

		const highlighter = fix ? this.fixedHighlighter : this.volatileHighlighter;
		highlighter.highlightRange({
			range: setting.valueRange,
938
			resource: this.editor.getModel()!.uri
939 940
		}, this.editor);

S
Sandeep Somavarapu 已提交
941
		this.editor.revealLineInCenterIfOutsideViewport(setting.valueRange.startLineNumber, editorCommon.ScrollType.Smooth);
942 943 944 945 946 947 948 949 950 951 952 953
		this.focusEventEmitter.fire(setting);
	}

	clear(fix: boolean = false): void {
		this.volatileHighlighter.removeHighlightRange();
		if (fix) {
			this.fixedHighlighter.removeHighlightRange();
		}
		this.clearFocusEventEmitter.fire(this.highlightedSetting);
	}
}

S
Sandeep Somavarapu 已提交
954 955 956 957 958 959 960 961 962
class UnsupportedSettingsRenderer extends Disposable {

	private renderingDelayer: Delayer<void> = new Delayer<void>(200);

	constructor(
		private editor: ICodeEditor,
		private settingsEditorModel: SettingsEditorModel,
		@IMarkerService private markerService: IMarkerService,
		@IWorkbenchEnvironmentService private workbenchEnvironmentService: IWorkbenchEnvironmentService,
S
Sandeep Somavarapu 已提交
963
		@IConfigurationService private configurationService: IConfigurationService,
S
Sandeep Somavarapu 已提交
964 965
	) {
		super();
S
Sandeep Somavarapu 已提交
966 967 968 969 970 971
		this._register(this.editor.getModel()!.onDidChangeContent(() => this.delayedRender()));
		this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.source === ConfigurationTarget.DEFAULT)(() => this.delayedRender()));
	}

	private delayedRender(): void {
		this.renderingDelayer.trigger(() => this.render());
S
Sandeep Somavarapu 已提交
972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004
	}

	public render(): void {
		const markerData: IMarkerData[] = this.generateMarkerData();
		if (markerData.length) {
			this.markerService.changeOne('preferencesEditor', this.settingsEditorModel.uri, markerData);
		} else {
			this.markerService.remove('preferencesEditor', [this.settingsEditorModel.uri]);
		}
	}

	private generateMarkerData(): IMarkerData[] {
		const markerData: IMarkerData[] = [];
		const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).getConfigurationProperties();
		for (const settingsGroup of this.settingsEditorModel.settingsGroups) {
			for (const section of settingsGroup.sections) {
				for (const setting of section.settings) {
					const configuration = configurationRegistry[setting.key];
					if (configuration) {
						switch (this.settingsEditorModel.configurationTarget) {
							case ConfigurationTarget.USER_LOCAL:
								this.handleLocalUserConfiguration(setting, configuration, markerData);
								break;
							case ConfigurationTarget.USER_REMOTE:
								this.handleRemoteUserConfiguration(setting, configuration, markerData);
								break;
							case ConfigurationTarget.WORKSPACE:
								this.handleWorkspaceConfiguration(setting, configuration, markerData);
								break;
							case ConfigurationTarget.WORKSPACE_FOLDER:
								this.handleWorkspaceFolderConfiguration(setting, configuration, markerData);
								break;
						}
S
Sandeep Somavarapu 已提交
1005
					} else if (!OVERRIDE_PROPERTY_PATTERN.test(setting.key)) { // Ignore override settings (language specific settings)
S
Sandeep Somavarapu 已提交
1006 1007 1008
						markerData.push({
							severity: MarkerSeverity.Hint,
							tags: [MarkerTag.Unnecessary],
S
Sandeep Somavarapu 已提交
1009
							...setting.range,
S
Sandeep Somavarapu 已提交
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
							message: nls.localize('unknown configuration setting', "Unknown Configuration Setting")
						});
					}
				}
			}
		}
		return markerData;
	}

	private handleLocalUserConfiguration(setting: ISetting, configuration: IConfigurationNode, markerData: IMarkerData[]): void {
		if (this.workbenchEnvironmentService.configuration.remote && configuration.scope === ConfigurationScope.MACHINE) {
			markerData.push({
				severity: MarkerSeverity.Hint,
				tags: [MarkerTag.Unnecessary],
S
Sandeep Somavarapu 已提交
1024
				...setting.range,
S
Sandeep Somavarapu 已提交
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058
				message: nls.localize('unsupportedRemoteMachineSetting', "This setting can be applied only in remote machine settings")
			});
		}
	}

	private handleRemoteUserConfiguration(setting: ISetting, configuration: IConfigurationNode, markerData: IMarkerData[]): void {
		if (configuration.scope === ConfigurationScope.APPLICATION) {
			markerData.push(this.generateUnsupportedApplicationSettingMarker(setting));
		}
	}

	private handleWorkspaceConfiguration(setting: ISetting, configuration: IConfigurationNode, markerData: IMarkerData[]): void {
		if (configuration.scope === ConfigurationScope.APPLICATION) {
			markerData.push(this.generateUnsupportedApplicationSettingMarker(setting));
		}

		if (configuration.scope === ConfigurationScope.MACHINE) {
			markerData.push(this.generateUnsupportedMachineSettingMarker(setting));
		}
	}

	private handleWorkspaceFolderConfiguration(setting: ISetting, configuration: IConfigurationNode, markerData: IMarkerData[]): void {
		if (configuration.scope === ConfigurationScope.APPLICATION) {
			markerData.push(this.generateUnsupportedApplicationSettingMarker(setting));
		}

		if (configuration.scope === ConfigurationScope.MACHINE) {
			markerData.push(this.generateUnsupportedMachineSettingMarker(setting));
		}

		if (configuration.scope === ConfigurationScope.WINDOW) {
			markerData.push({
				severity: MarkerSeverity.Hint,
				tags: [MarkerTag.Unnecessary],
S
Sandeep Somavarapu 已提交
1059
				...setting.range,
S
Sandeep Somavarapu 已提交
1060 1061 1062 1063 1064 1065 1066 1067 1068
				message: nls.localize('unsupportedWindowSetting', "This setting cannot be applied now. It will be applied when you open this folder directly.")
			});
		}
	}

	private generateUnsupportedApplicationSettingMarker(setting: ISetting): IMarkerData {
		return {
			severity: MarkerSeverity.Hint,
			tags: [MarkerTag.Unnecessary],
S
Sandeep Somavarapu 已提交
1069
			...setting.range,
S
Sandeep Somavarapu 已提交
1070 1071 1072 1073 1074 1075 1076 1077
			message: nls.localize('unsupportedApplicationSetting', "This setting can be applied only in application user settings")
		};
	}

	private generateUnsupportedMachineSettingMarker(setting: ISetting): IMarkerData {
		return {
			severity: MarkerSeverity.Hint,
			tags: [MarkerTag.Unnecessary],
S
Sandeep Somavarapu 已提交
1078
			...setting.range,
S
Sandeep Somavarapu 已提交
1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089
			message: nls.localize('unsupportedMachineSetting', "This setting can be applied only in user settings")
		};
	}

	public dispose(): void {
		this.markerService.remove('preferencesEditor', [this.settingsEditorModel.uri]);
		super.dispose();
	}

}

S
Sandeep Somavarapu 已提交
1090 1091 1092
class WorkspaceConfigurationRenderer extends Disposable {

	private decorationIds: string[] = [];
S
Sandeep Somavarapu 已提交
1093
	private associatedSettingsEditorModel: IPreferencesEditorModel<ISetting>;
S
Sandeep Somavarapu 已提交
1094 1095
	private renderingDelayer: Delayer<void> = new Delayer<void>(200);

1096
	constructor(private editor: ICodeEditor, private workspaceSettingsEditorModel: SettingsEditorModel,
1097
		@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService
S
Sandeep Somavarapu 已提交
1098 1099
	) {
		super();
1100
		this._register(this.editor.getModel()!.onDidChangeContent(() => this.renderingDelayer.trigger(() => this.render(this.associatedSettingsEditorModel))));
S
Sandeep Somavarapu 已提交
1101 1102
	}

R
Rob Lourens 已提交
1103
	render(associatedSettingsEditorModel: IPreferencesEditorModel<ISetting>): void {
S
Sandeep Somavarapu 已提交
1104 1105 1106
		this.associatedSettingsEditorModel = associatedSettingsEditorModel;
		// Dim other configurations in workspace configuration file only in the context of Settings Editor
		if (this.associatedSettingsEditorModel && this.workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE && this.workspaceSettingsEditorModel instanceof WorkspaceConfigurationEditorModel) {
S
Sandeep Somavarapu 已提交
1107
			const ranges: IRange[] = [];
S
Sandeep Somavarapu 已提交
1108
			for (const settingsGroup of this.workspaceSettingsEditorModel.configurationGroups) {
S
Sandeep Somavarapu 已提交
1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
				for (const section of settingsGroup.sections) {
					for (const setting of section.settings) {
						if (setting.key !== 'settings') {
							ranges.push({
								startLineNumber: setting.keyRange.startLineNumber,
								startColumn: setting.keyRange.startColumn - 1,
								endLineNumber: setting.valueRange.endLineNumber,
								endColumn: setting.valueRange.endColumn
							});
						}
					}
				}
			}
1122
			this.decorationIds = this.editor.deltaDecorations(this.decorationIds, ranges.map(range => this.createDecoration(range)));
S
Sandeep Somavarapu 已提交
1123 1124 1125
		}
	}

1126
	private static readonly _DIM_CONFIGURATION_ = ModelDecorationOptions.register({
1127
		stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
S
Sandeep Somavarapu 已提交
1128 1129 1130
		inlineClassName: 'dim-configuration'
	});

1131
	private createDecoration(range: IRange): IModelDeltaDecoration {
S
Sandeep Somavarapu 已提交
1132 1133 1134 1135 1136 1137
		return {
			range,
			options: WorkspaceConfigurationRenderer._DIM_CONFIGURATION_
		};
	}

R
Rob Lourens 已提交
1138
	dispose(): void {
1139
		this.decorationIds = this.editor.deltaDecorations(this.decorationIds, []);
1140 1141
		super.dispose();
	}
1142
}