modelServiceImpl.ts 15.5 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

A
Alex Dima 已提交
7
import * as nls from 'vs/nls';
S
Sandeep Somavarapu 已提交
8
import network = require('vs/base/common/network');
A
Alex Dima 已提交
9
import Event, {Emitter} from 'vs/base/common/event';
A
Alex Dima 已提交
10
import {EmitterEvent} from 'vs/base/common/eventEmitter';
11
import {MarkedString, textAsCodeBlock} from 'vs/base/common/htmlContent';
A
tslint  
Alex Dima 已提交
12
import {IDisposable} from 'vs/base/common/lifecycle';
A
Alex Dima 已提交
13 14
import Severity from 'vs/base/common/severity';
import URI from 'vs/base/common/uri';
E
Erich Gamma 已提交
15
import {TPromise} from 'vs/base/common/winjs.base';
A
Alex Dima 已提交
16
import {IMarker, IMarkerService} from 'vs/platform/markers/common/markers';
E
Erich Gamma 已提交
17
import {anonymize} from 'vs/platform/telemetry/common/telemetry';
A
Alex Dima 已提交
18 19
import {Range} from 'vs/editor/common/core/range';
import * as editorCommon from 'vs/editor/common/editorCommon';
E
Erich Gamma 已提交
20
import {Model} from 'vs/editor/common/model/model';
A
Alex Dima 已提交
21 22
import {IMode} from 'vs/editor/common/modes';
import {IModelService} from 'vs/editor/common/services/modelService';
23
import * as platform from 'vs/base/common/platform';
24
import {IConfigurationService} from 'vs/platform/configuration/common/configuration';
25
import {DEFAULT_INDENTATION, DEFAULT_TRIM_AUTO_WHITESPACE} from 'vs/editor/common/config/defaultConfig';
A
Alex Dima 已提交
26
import {IMessageService} from 'vs/platform/message/common/message';
E
Erich Gamma 已提交
27 28

export interface IRawModelData {
B
Benjamin Pasero 已提交
29 30 31 32
	url: URI;
	versionId: number;
	value: editorCommon.IRawText;
	modeId: string;
E
Erich Gamma 已提交
33 34
}

B
Benjamin Pasero 已提交
35
function MODEL_ID(resource: URI): string {
A
Alex Dima 已提交
36 37 38 39
	return resource.toString();
}

class ModelData implements IDisposable {
A
Alex Dima 已提交
40
	model: editorCommon.IModel;
E
Erich Gamma 已提交
41

A
Alex Dima 已提交
42 43
	private _markerDecorations: string[];
	private _modelEventsListener: IDisposable;
E
Erich Gamma 已提交
44

A
Alex Dima 已提交
45
	constructor(model: editorCommon.IModel, eventsHandler: (modelData: ModelData, events: EmitterEvent[]) => void) {
E
Erich Gamma 已提交
46
		this.model = model;
A
Alex Dima 已提交
47 48

		this._markerDecorations = [];
A
Alex Dima 已提交
49
		this._modelEventsListener = model.addBulkListener((events) => eventsHandler(this, events));
E
Erich Gamma 已提交
50 51 52
	}

	public dispose(): void {
A
Alex Dima 已提交
53 54 55
		this._markerDecorations = this.model.deltaDecorations(this._markerDecorations, []);
		this._modelEventsListener.dispose();
		this._modelEventsListener = null;
E
Erich Gamma 已提交
56
		this.model = null;
A
Alex Dima 已提交
57
	}
E
Erich Gamma 已提交
58

A
Alex Dima 已提交
59
	public getModelId(): string {
60
		return MODEL_ID(this.model.uri);
A
Alex Dima 已提交
61 62
	}

B
Benjamin Pasero 已提交
63
	public acceptMarkerDecorations(newDecorations: editorCommon.IModelDeltaDecoration[]): void {
A
Alex Dima 已提交
64
		this._markerDecorations = this.model.deltaDecorations(this._markerDecorations, newDecorations);
E
Erich Gamma 已提交
65
	}
A
Alex Dima 已提交
66
}
E
Erich Gamma 已提交
67

A
Alex Dima 已提交
68 69
class ModelMarkerHandler {

B
Benjamin Pasero 已提交
70
	public static setMarkers(modelData: ModelData, markers: IMarker[]): void {
E
Erich Gamma 已提交
71 72 73 74

		// Limit to the first 500 errors/warnings
		markers = markers.slice(0, 500);

B
Benjamin Pasero 已提交
75
		let newModelDecorations: editorCommon.IModelDeltaDecoration[] = markers.map((marker) => {
A
Alex Dima 已提交
76 77
			return {
				range: this._createDecorationRange(modelData.model, marker),
E
Erich Gamma 已提交
78 79 80
				options: this._createDecorationOption(marker)
			};
		});
A
Alex Dima 已提交
81 82

		modelData.acceptMarkerDecorations(newModelDecorations);
E
Erich Gamma 已提交
83 84
	}

B
Benjamin Pasero 已提交
85
	private static _createDecorationRange(model: editorCommon.IModel, rawMarker: IMarker): editorCommon.IRange {
A
Alex Dima 已提交
86
		let marker = model.validateRange(new Range(rawMarker.startLineNumber, rawMarker.startColumn, rawMarker.endLineNumber, rawMarker.endColumn));
87
		let ret: Range = new Range(marker.startLineNumber, marker.startColumn, marker.endLineNumber, marker.endColumn);
E
Erich Gamma 已提交
88
		if (ret.isEmpty()) {
A
Alex Dima 已提交
89
			let word = model.getWordAtPosition(ret.getStartPosition());
E
Erich Gamma 已提交
90 91 92 93
			if (word) {
				ret.startColumn = word.startColumn;
				ret.endColumn = word.endColumn;
			} else {
A
Alex Dima 已提交
94 95
				let maxColumn = model.getLineLastNonWhitespaceColumn(marker.startLineNumber) ||
					model.getLineMaxColumn(marker.startLineNumber);
E
Erich Gamma 已提交
96 97 98

				if (maxColumn === 1) {
					// empty line
B
Benjamin Pasero 已提交
99
					//					console.warn('marker on empty line:', marker);
E
Erich Gamma 已提交
100 101 102 103 104 105 106 107 108 109
				} else if (ret.endColumn >= maxColumn) {
					// behind eol
					ret.endColumn = maxColumn;
					ret.startColumn = maxColumn - 1;
				} else {
					// extend marker to width = 1
					ret.endColumn += 1;
				}
			}
		} else if (rawMarker.endColumn === Number.MAX_VALUE && rawMarker.startColumn === 1 && ret.startLineNumber === ret.endLineNumber) {
A
Alex Dima 已提交
110
			let minColumn = model.getLineFirstNonWhitespaceColumn(rawMarker.startLineNumber);
E
Erich Gamma 已提交
111 112 113 114 115 116 117 118
			if (minColumn < ret.endColumn) {
				ret.startColumn = minColumn;
				rawMarker.startColumn = minColumn;
			}
		}
		return ret;
	}

B
Benjamin Pasero 已提交
119
	private static _createDecorationOption(marker: IMarker): editorCommon.IModelDecorationOptions {
E
Erich Gamma 已提交
120 121 122 123 124 125 126 127 128 129 130

		let className: string;
		let color: string;
		let darkColor: string;

		switch (marker.severity) {
			case Severity.Ignore:
				// do something
				break;
			case Severity.Warning:
			case Severity.Info:
A
Alex Dima 已提交
131
				className = editorCommon.ClassName.EditorWarningDecoration;
E
Erich Gamma 已提交
132 133 134 135 136
				color = 'rgba(18,136,18,0.7)';
				darkColor = 'rgba(18,136,18,0.7)';
				break;
			case Severity.Error:
			default:
A
Alex Dima 已提交
137
				className = editorCommon.ClassName.EditorErrorDecoration;
E
Erich Gamma 已提交
138 139 140 141 142
				color = 'rgba(255,18,18,0.7)';
				darkColor = 'rgba(255,18,18,0.7)';
				break;
		}

143 144
		let hoverMessage: MarkedString[] = null;
		let {message, source} = marker;
E
Erich Gamma 已提交
145

146 147 148 149 150
		if (typeof message === 'string') {
			if (source) {
				message = nls.localize('sourceAndDiagMessage', "[{0}] {1}", source, message);
			}
			hoverMessage = [textAsCodeBlock(message)];
151 152
		}

E
Erich Gamma 已提交
153
		return {
A
Alex Dima 已提交
154
			stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
E
Erich Gamma 已提交
155
			className,
156
			hoverMessage,
E
Erich Gamma 已提交
157 158 159
			overviewRuler: {
				color,
				darkColor,
A
Alex Dima 已提交
160
				position: editorCommon.OverviewRulerLane.Right
E
Erich Gamma 已提交
161 162 163 164 165
			}
		};
	}
}

166 167 168 169 170 171 172 173
interface IRawConfig {
	files?: {
		eol?: any;
	};
	editor?: {
		tabSize?: any;
		insertSpaces?: any;
		detectIndentation?: any;
174
		trimAutoWhitespace?: any;
175 176 177
	};
}

E
Erich Gamma 已提交
178
export class ModelServiceImpl implements IModelService {
179
	public _serviceBrand: any;
E
Erich Gamma 已提交
180 181 182

	private _markerService: IMarkerService;
	private _markerServiceSubscription: IDisposable;
A
Alex Dima 已提交
183
	private _messageService: IMessageService;
184 185
	private _configurationService: IConfigurationService;
	private _configurationServiceSubscription: IDisposable;
E
Erich Gamma 已提交
186

A
Alex Dima 已提交
187 188 189
	private _onModelAdded: Emitter<editorCommon.IModel>;
	private _onModelRemoved: Emitter<editorCommon.IModel>;
	private _onModelModeChanged: Emitter<{ model: editorCommon.IModel; oldModeId: string; }>;
190 191

	private _modelCreationOptions: editorCommon.ITextModelCreationOptions;
A
Alex Dima 已提交
192

A
Alex Dima 已提交
193 194
	private _hasShownMigrationMessage: boolean;

A
Alex Dima 已提交
195 196 197
	/**
	 * All the models known in the system.
	 */
B
Benjamin Pasero 已提交
198
	private _models: { [modelId: string]: ModelData; };
E
Erich Gamma 已提交
199

200
	constructor(
201 202 203
		@IMarkerService markerService: IMarkerService,
		@IConfigurationService configurationService: IConfigurationService,
		@IMessageService messageService: IMessageService
204
	) {
205
		this._modelCreationOptions = {
206 207 208
			tabSize: DEFAULT_INDENTATION.tabSize,
			insertSpaces: DEFAULT_INDENTATION.insertSpaces,
			detectIndentation: DEFAULT_INDENTATION.detectIndentation,
209
			defaultEOL: (platform.isLinux || platform.isMacintosh) ? editorCommon.DefaultEndOfLine.LF : editorCommon.DefaultEndOfLine.CRLF,
210
			trimAutoWhitespace: DEFAULT_TRIM_AUTO_WHITESPACE
211
		};
E
Erich Gamma 已提交
212
		this._markerService = markerService;
213
		this._configurationService = configurationService;
A
Alex Dima 已提交
214 215
		this._messageService = messageService;
		this._hasShownMigrationMessage = false;
B
Benjamin Pasero 已提交
216 217 218 219 220 221 222 223 224 225
		this._models = {};


		this._onModelAdded = new Emitter<editorCommon.IModel>();
		this._onModelRemoved = new Emitter<editorCommon.IModel>();
		this._onModelModeChanged = new Emitter<{ model: editorCommon.IModel; oldModeId: string; }>();

		if (this._markerService) {
			this._markerServiceSubscription = this._markerService.onMarkerChanged(this._handleMarkerChange, this);
		}
226

B
Benjamin Pasero 已提交
227
		let readConfig = (config: IRawConfig) => {
J
Joao Moreno 已提交
228

A
Alex Dima 已提交
229 230
			let shouldShowMigrationMessage = false;

231
			let tabSize = DEFAULT_INDENTATION.tabSize;
232 233 234
			if (config.editor && typeof config.editor.tabSize !== 'undefined') {
				let parsedTabSize = parseInt(config.editor.tabSize, 10);
				if (!isNaN(parsedTabSize)) {
235
					tabSize = parsedTabSize;
236
				}
A
Alex Dima 已提交
237
				shouldShowMigrationMessage = shouldShowMigrationMessage || (config.editor.tabSize === 'auto');
238 239
			}

240
			let insertSpaces = DEFAULT_INDENTATION.insertSpaces;
241
			if (config.editor && typeof config.editor.insertSpaces !== 'undefined') {
242
				insertSpaces = (config.editor.insertSpaces === 'false' ? false : Boolean(config.editor.insertSpaces));
A
Alex Dima 已提交
243
				shouldShowMigrationMessage = shouldShowMigrationMessage || (config.editor.insertSpaces === 'auto');
244 245 246
			}

			let newDefaultEOL = this._modelCreationOptions.defaultEOL;
247
			const eol = config.files && config.files.eol;
J
Joao Moreno 已提交
248
			if (eol === '\r\n') {
249
				newDefaultEOL = editorCommon.DefaultEndOfLine.CRLF;
J
Joao Moreno 已提交
250
			} else if (eol === '\n') {
251
				newDefaultEOL = editorCommon.DefaultEndOfLine.LF;
252
			}
253

254 255 256 257 258
			let trimAutoWhitespace = this._modelCreationOptions.trimAutoWhitespace;
			if (config.editor && typeof config.editor.trimAutoWhitespace !== 'undefined') {
				trimAutoWhitespace = (config.editor.trimAutoWhitespace === 'false' ? false : Boolean(config.editor.trimAutoWhitespace));
			}

259
			let detectIndentation = DEFAULT_INDENTATION.detectIndentation;
260 261 262
			if (config.editor && typeof config.editor.detectIndentation !== 'undefined') {
				detectIndentation = (config.editor.detectIndentation === 'false' ? false : Boolean(config.editor.detectIndentation));
			}
263

264 265 266
			this._setModelOptions({
				tabSize: tabSize,
				insertSpaces: insertSpaces,
267
				detectIndentation: detectIndentation,
268 269
				defaultEOL: newDefaultEOL,
				trimAutoWhitespace: trimAutoWhitespace
270 271
			});

A
Alex Dima 已提交
272 273 274 275 276

			if (shouldShowMigrationMessage && !this._hasShownMigrationMessage) {
				this._hasShownMigrationMessage = true;
				this._messageService.show(Severity.Info, nls.localize('indentAutoMigrate', "Please update your settings: `editor.detectIndentation` replaces `editor.tabSize`: \"auto\" or `editor.insertSpaces`: \"auto\""));
			}
277
		};
278 279

		this._configurationServiceSubscription = this._configurationService.onDidUpdateConfiguration(e => {
280
			readConfig(e.config);
281
		});
282
		readConfig(this._configurationService.getConfiguration());
E
Erich Gamma 已提交
283 284
	}

285 286 287 288 289 290 291 292 293
	public getCreationOptions(): editorCommon.ITextModelCreationOptions {
		return this._modelCreationOptions;
	}

	private _setModelOptions(newOpts: editorCommon.ITextModelCreationOptions): void {
		if (
			(this._modelCreationOptions.detectIndentation === newOpts.detectIndentation)
			&& (this._modelCreationOptions.insertSpaces === newOpts.insertSpaces)
			&& (this._modelCreationOptions.tabSize === newOpts.tabSize)
294
			&& (this._modelCreationOptions.trimAutoWhitespace === newOpts.trimAutoWhitespace)
295 296 297 298 299 300 301
		) {
			// Same indent opts, no need to touch created models
			this._modelCreationOptions = newOpts;
			return;
		}
		this._modelCreationOptions = newOpts;

302
		// Update options on all models
A
Alex Dima 已提交
303 304 305 306
		let keys = Object.keys(this._models);
		for (let i = 0, len = keys.length; i < len; i++) {
			let modelId = keys[i];
			let modelData = this._models[modelId];
307

A
Alex Dima 已提交
308 309
			if (this._modelCreationOptions.detectIndentation) {
				modelData.model.detectIndentation(this._modelCreationOptions.insertSpaces, this._modelCreationOptions.tabSize);
310 311 312
				modelData.model.updateOptions({
					trimAutoWhitespace: this._modelCreationOptions.trimAutoWhitespace
				});
A
Alex Dima 已提交
313 314 315
			} else {
				modelData.model.updateOptions({
					insertSpaces: this._modelCreationOptions.insertSpaces,
316 317
					tabSize: this._modelCreationOptions.tabSize,
					trimAutoWhitespace: this._modelCreationOptions.trimAutoWhitespace
A
Alex Dima 已提交
318
				});
319 320
			}
		}
321 322
	}

E
Erich Gamma 已提交
323
	public dispose(): void {
B
Benjamin Pasero 已提交
324
		if (this._markerServiceSubscription) {
E
Erich Gamma 已提交
325 326
			this._markerServiceSubscription.dispose();
		}
327
		this._configurationServiceSubscription.dispose();
E
Erich Gamma 已提交
328 329 330
	}

	private _handleMarkerChange(changedResources: URI[]): void {
A
Alex Dima 已提交
331 332 333 334
		changedResources.forEach((resource) => {
			let modelId = MODEL_ID(resource);
			let modelData = this._models[modelId];
			if (!modelData) {
E
Erich Gamma 已提交
335 336
				return;
			}
A
Alex Dima 已提交
337
			ModelMarkerHandler.setMarkers(modelData, this._markerService.read({ resource: resource, take: 500 }));
E
Erich Gamma 已提交
338 339 340
		});
	}

S
Sandeep Somavarapu 已提交
341 342 343
	private _cleanUp(model: editorCommon.IModel): void {
		// clean up markers for internal, transient models
		if (model.uri.scheme === network.Schemas.inMemory
B
Benjamin Pasero 已提交
344 345 346 347 348
			|| model.uri.scheme === network.Schemas.internal
			|| model.uri.scheme === network.Schemas.vscode) {
			if (this._markerService) {
				this._markerService.read({ resource: model.uri }).map(marker => marker.owner).forEach(owner => this._markerService.remove(owner, [model.uri]));
			}
S
Sandeep Somavarapu 已提交
349 350 351
		}
	}

E
Erich Gamma 已提交
352 353
	// --- begin IModelService

354
	private _createModelData(value: string | editorCommon.IRawText, modeOrPromise: TPromise<IMode> | IMode, resource: URI): ModelData {
A
Alex Dima 已提交
355
		// create & save the model
356 357 358 359 360 361
		let model:Model;
		if (typeof value === 'string') {
			model = Model.createFromString(value, this._modelCreationOptions, modeOrPromise, resource);
		} else {
			model = new Model(value, modeOrPromise, resource);
		}
362
		let modelId = MODEL_ID(model.uri);
E
Erich Gamma 已提交
363 364 365

		if (this._models[modelId]) {
			// There already exists a model with this id => this is a programmer error
A
Alex Dima 已提交
366
			throw new Error('ModelService: Cannot add model ' + anonymize(modelId) + ' because it already exists!');
E
Erich Gamma 已提交
367 368
		}

A
Alex Dima 已提交
369 370
		let modelData = new ModelData(model, (modelData, events) => this._onModelEvents(modelData, events));
		this._models[modelId] = modelData;
E
Erich Gamma 已提交
371

A
Alex Dima 已提交
372
		return modelData;
E
Erich Gamma 已提交
373 374
	}

375
	public createModel(value: string | editorCommon.IRawText, modeOrPromise: TPromise<IMode> | IMode, resource: URI): editorCommon.IModel {
A
Alex Dima 已提交
376
		let modelData = this._createModelData(value, modeOrPromise, resource);
E
Erich Gamma 已提交
377

A
Alex Dima 已提交
378 379
		// handle markers (marker service => model)
		if (this._markerService) {
380
			ModelMarkerHandler.setMarkers(modelData, this._markerService.read({ resource: modelData.model.uri }));
E
Erich Gamma 已提交
381 382
		}

A
Alex Dima 已提交
383
		this._onModelAdded.fire(modelData.model);
E
Erich Gamma 已提交
384

A
Alex Dima 已提交
385
		return modelData.model;
E
Erich Gamma 已提交
386 387
	}

J
Johannes Rieken 已提交
388
	public destroyModel(resource: URI): void {
A
Alex Dima 已提交
389 390 391 392
		// We need to support that not all models get disposed through this service (i.e. model.dispose() should work!)
		let modelData = this._models[MODEL_ID(resource)];
		if (!modelData) {
			return;
E
Erich Gamma 已提交
393
		}
A
Alex Dima 已提交
394
		modelData.model.dispose();
E
Erich Gamma 已提交
395 396
	}

A
Alex Dima 已提交
397 398
	public getModels(): editorCommon.IModel[] {
		let ret: editorCommon.IModel[] = [];
A
Alex Dima 已提交
399 400 401 402 403

		let keys = Object.keys(this._models);
		for (let i = 0, len = keys.length; i < len; i++) {
			let modelId = keys[i];
			ret.push(this._models[modelId].model);
E
Erich Gamma 已提交
404
		}
A
Alex Dima 已提交
405

E
Erich Gamma 已提交
406 407 408
		return ret;
	}

A
Alex Dima 已提交
409
	public getModel(resource: URI): editorCommon.IModel {
A
Alex Dima 已提交
410 411 412 413
		let modelId = MODEL_ID(resource);
		let modelData = this._models[modelId];
		if (!modelData) {
			return null;
E
Erich Gamma 已提交
414
		}
A
Alex Dima 已提交
415
		return modelData.model;
E
Erich Gamma 已提交
416 417
	}

A
Alex Dima 已提交
418
	public get onModelAdded(): Event<editorCommon.IModel> {
419
		return this._onModelAdded ? this._onModelAdded.event : null;
E
Erich Gamma 已提交
420 421
	}

A
Alex Dima 已提交
422
	public get onModelRemoved(): Event<editorCommon.IModel> {
423
		return this._onModelRemoved ? this._onModelRemoved.event : null;
E
Erich Gamma 已提交
424 425
	}

A
Alex Dima 已提交
426
	public get onModelModeChanged(): Event<{ model: editorCommon.IModel; oldModeId: string; }> {
427
		return this._onModelModeChanged ? this._onModelModeChanged.event : null;
E
Erich Gamma 已提交
428 429 430 431
	}

	// --- end IModelService

B
Benjamin Pasero 已提交
432
	private _onModelDisposing(model: editorCommon.IModel): void {
433
		let modelId = MODEL_ID(model.uri);
A
Alex Dima 已提交
434 435
		let modelData = this._models[modelId];

S
Sandeep Somavarapu 已提交
436 437
		this._cleanUp(model);

A
Alex Dima 已提交
438 439 440 441 442 443
		delete this._models[modelId];
		modelData.dispose();

		this._onModelRemoved.fire(model);
	}

A
Alex Dima 已提交
444
	private _onModelEvents(modelData: ModelData, events: EmitterEvent[]): void {
E
Erich Gamma 已提交
445

446
		// First look for dispose
A
Alex Dima 已提交
447 448
		for (let i = 0, len = events.length; i < len; i++) {
			let e = events[i];
A
Alex Dima 已提交
449
			if (e.getType() === editorCommon.EventType.ModelDispose) {
450 451 452 453 454
				this._onModelDisposing(modelData.model);
				// no more processing since model got disposed
				return;
			}
		}
E
Erich Gamma 已提交
455

456 457 458
		// Second, look for mode change
		for (let i = 0, len = events.length; i < len; i++) {
			let e = events[i];
A
Alex Dima 已提交
459
			if (e.getType() === editorCommon.EventType.ModelModeChanged) {
460 461
				this._onModelModeChanged.fire({
					model: modelData.model,
A
Alex Dima 已提交
462
					oldModeId: (<editorCommon.IModelModeChangedEvent>e.getData()).oldMode.getId()
463
				});
E
Erich Gamma 已提交
464 465 466 467
			}
		}
	}
}