modelServiceImpl.ts 21.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';
8
import * as network from 'vs/base/common/network';
M
Matt Bierner 已提交
9
import { Event, Emitter } from 'vs/base/common/event';
J
Johannes Rieken 已提交
10
import { MarkdownString } from 'vs/base/common/htmlContent';
11
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
A
Alex Dima 已提交
12
import URI from 'vs/base/common/uri';
J
Johannes Rieken 已提交
13
import { TPromise } from 'vs/base/common/winjs.base';
14
import { IMarker, IMarkerService, MarkerSeverity, MarkerTag } from 'vs/platform/markers/common/markers';
J
Johannes Rieken 已提交
15
import { Range } from 'vs/editor/common/core/range';
16
import { TextModel, createTextBuffer } from 'vs/editor/common/model/textModel';
A
Alex Dima 已提交
17
import { IMode, LanguageIdentifier } from 'vs/editor/common/modes';
18
import { IModelService } from 'vs/editor/common/services/modelService';
19
import * as platform from 'vs/base/common/platform';
J
Johannes Rieken 已提交
20
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
21
import { EDITOR_MODEL_DEFAULTS } from 'vs/editor/common/config/editorOptions';
A
Alex Dima 已提交
22
import { PLAINTEXT_LANGUAGE_IDENTIFIER } from 'vs/editor/common/modes/modesRegistry';
23
import { IModelLanguageChangedEvent } from 'vs/editor/common/model/textModelEvents';
A
Alex Dima 已提交
24
import { ClassName } from 'vs/editor/common/model/intervalTree';
25
import { EditOperation } from 'vs/editor/common/core/editOperation';
26
import { themeColorFromId, ThemeColor } from 'vs/platform/theme/common/themeService';
27
import { overviewRulerWarning, overviewRulerError, overviewRulerInfo } from 'vs/editor/common/view/editorColorRegistry';
28
import { ITextModel, IModelDeltaDecoration, IModelDecorationOptions, TrackedRangeStickiness, OverviewRulerLane, DefaultEndOfLine, ITextModelCreationOptions, EndOfLineSequence, IIdentifiedSingleEditOperation, ITextBufferFactory, ITextBuffer, EndOfLinePreference } from 'vs/editor/common/model';
29 30
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { basename } from 'vs/base/common/paths';
E
Erich Gamma 已提交
31

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

class ModelData implements IDisposable {
A
Alex Dima 已提交
37
	model: ITextModel;
E
Erich Gamma 已提交
38

A
Alex Dima 已提交
39
	private _markerDecorations: string[];
40
	private _modelEventListeners: IDisposable[];
E
Erich Gamma 已提交
41

42
	constructor(
A
Alex Dima 已提交
43 44 45
		model: ITextModel,
		onWillDispose: (model: ITextModel) => void,
		onDidChangeLanguage: (model: ITextModel, e: IModelLanguageChangedEvent) => void
46
	) {
E
Erich Gamma 已提交
47
		this.model = model;
A
Alex Dima 已提交
48 49

		this._markerDecorations = [];
50 51 52 53

		this._modelEventListeners = [];
		this._modelEventListeners.push(model.onWillDispose(() => onWillDispose(model)));
		this._modelEventListeners.push(model.onDidChangeLanguage((e) => onDidChangeLanguage(model, e)));
E
Erich Gamma 已提交
54 55 56
	}

	public dispose(): void {
A
Alex Dima 已提交
57
		this._markerDecorations = this.model.deltaDecorations(this._markerDecorations, []);
58
		this._modelEventListeners = dispose(this._modelEventListeners);
E
Erich Gamma 已提交
59
		this.model = null;
A
Alex Dima 已提交
60
	}
E
Erich Gamma 已提交
61

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

A
Alex Dima 已提交
67 68
class ModelMarkerHandler {

69
	public static setMarkers(modelData: ModelData, markerService: IMarkerService): void {
E
Erich Gamma 已提交
70 71

		// Limit to the first 500 errors/warnings
72
		const markers = markerService.read({ resource: modelData.model.uri, take: 500 });
E
Erich Gamma 已提交
73

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

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

A
Alex Dima 已提交
84
	private static _createDecorationRange(model: ITextModel, rawMarker: IMarker): Range {
J
Johannes Rieken 已提交
85 86 87 88 89 90 91 92 93 94

		let ret = Range.lift(rawMarker);

		if (rawMarker.severity === MarkerSeverity.Hint && Range.spansMultipleLines(ret)) {
			// never render hints on multiple lines
			ret = ret.setEndPosition(ret.startLineNumber, ret.startColumn);
		}

		ret = model.validateRange(ret);

E
Erich Gamma 已提交
95
		if (ret.isEmpty()) {
A
Alex Dima 已提交
96
			let word = model.getWordAtPosition(ret.getStartPosition());
E
Erich Gamma 已提交
97
			if (word) {
98
				ret = new Range(ret.startLineNumber, word.startColumn, ret.endLineNumber, word.endColumn);
E
Erich Gamma 已提交
99
			} else {
J
Johannes Rieken 已提交
100 101
				let maxColumn = model.getLineLastNonWhitespaceColumn(ret.startLineNumber) ||
					model.getLineMaxColumn(ret.startLineNumber);
E
Erich Gamma 已提交
102 103 104

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

124
	private static _createDecorationOption(marker: IMarker): IModelDecorationOptions {
E
Erich Gamma 已提交
125 126

		let className: string;
127 128
		let color: ThemeColor;
		let darkColor: ThemeColor;
129
		let zIndex: number;
130
		let inlineClassName: string;
E
Erich Gamma 已提交
131 132

		switch (marker.severity) {
J
Johannes Rieken 已提交
133
			case MarkerSeverity.Hint:
134 135 136
				if (marker.customTags && marker.customTags.indexOf(MarkerTag.Unnecessary) >= 0) {
					className = ClassName.EditorUnnecessaryDecoration;
				} else {
137 138
					className = ClassName.EditorHintDecoration;
				}
139
				zIndex = 0;
E
Erich Gamma 已提交
140
				break;
J
Johannes Rieken 已提交
141
			case MarkerSeverity.Warning:
A
Alex Dima 已提交
142
				className = ClassName.EditorWarningDecoration;
143 144
				color = themeColorFromId(overviewRulerWarning);
				darkColor = themeColorFromId(overviewRulerWarning);
145
				zIndex = 20;
E
Erich Gamma 已提交
146
				break;
J
Johannes Rieken 已提交
147
			case MarkerSeverity.Info:
148 149 150
				className = ClassName.EditorInfoDecoration;
				color = themeColorFromId(overviewRulerInfo);
				darkColor = themeColorFromId(overviewRulerInfo);
151
				zIndex = 10;
152
				break;
J
Johannes Rieken 已提交
153
			case MarkerSeverity.Error:
E
Erich Gamma 已提交
154
			default:
A
Alex Dima 已提交
155
				className = ClassName.EditorErrorDecoration;
156 157
				color = themeColorFromId(overviewRulerError);
				darkColor = themeColorFromId(overviewRulerError);
158
				zIndex = 30;
E
Erich Gamma 已提交
159 160 161
				break;
		}

162 163
		if (marker.customTags) {
			if (marker.customTags.indexOf(MarkerTag.Unnecessary) !== -1) {
164
				inlineClassName = ClassName.EditorUnnecessaryInlineDecoration;
165 166 167
			}
		}

J
Johannes Rieken 已提交
168
		let hoverMessage: MarkdownString = null;
169
		let { message, source, relatedInformation } = marker;
E
Erich Gamma 已提交
170

171
		if (typeof message === 'string') {
J
Joao Moreno 已提交
172 173
			message = message.trim();

174
			if (source) {
J
Joao Moreno 已提交
175 176 177 178 179
				if (/\n/g.test(message)) {
					message = nls.localize('diagAndSourceMultiline', "[{0}]\n{1}", source, message);
				} else {
					message = nls.localize('diagAndSource', "[{0}] {1}", source, message);
				}
180
			}
J
Joao Moreno 已提交
181

J
Johannes Rieken 已提交
182
			hoverMessage = new MarkdownString().appendCodeblock('_', message);
183 184 185 186 187

			if (!isFalsyOrEmpty(relatedInformation)) {
				hoverMessage.appendMarkdown('\n');
				for (const { message, resource, startLineNumber, startColumn } of relatedInformation) {
					hoverMessage.appendMarkdown(
188
						`* [${basename(resource.path)}(${startLineNumber}, ${startColumn})](${resource.toString(false)}#${startLineNumber},${startColumn}): `
189
					);
190 191
					hoverMessage.appendText(`${message}`);
					hoverMessage.appendMarkdown('\n');
192 193 194
				}
				hoverMessage.appendMarkdown('\n');
			}
195 196
		}

E
Erich Gamma 已提交
197
		return {
198
			stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
E
Erich Gamma 已提交
199
			className,
200
			hoverMessage,
201
			showIfCollapsed: true,
E
Erich Gamma 已提交
202 203 204
			overviewRuler: {
				color,
				darkColor,
205
				position: OverviewRulerLane.Right
206
			},
207 208
			zIndex,
			inlineClassName,
E
Erich Gamma 已提交
209 210 211 212
		};
	}
}

213 214 215 216 217 218 219 220
interface IRawConfig {
	files?: {
		eol?: any;
	};
	editor?: {
		tabSize?: any;
		insertSpaces?: any;
		detectIndentation?: any;
221
		trimAutoWhitespace?: any;
222 223
		creationOptions?: any;
		largeFileOptimizations?: any;
224 225 226
	};
}

227
const DEFAULT_EOL = (platform.isLinux || platform.isMacintosh) ? DefaultEndOfLine.LF : DefaultEndOfLine.CRLF;
228

E
Erich Gamma 已提交
229
export class ModelServiceImpl implements IModelService {
230
	public _serviceBrand: any;
E
Erich Gamma 已提交
231 232 233

	private _markerService: IMarkerService;
	private _markerServiceSubscription: IDisposable;
234 235
	private _configurationService: IConfigurationService;
	private _configurationServiceSubscription: IDisposable;
E
Erich Gamma 已提交
236

M
Matt Bierner 已提交
237 238 239
	private readonly _onModelAdded: Emitter<ITextModel>;
	private readonly _onModelRemoved: Emitter<ITextModel>;
	private readonly _onModelModeChanged: Emitter<{ model: ITextModel; oldModeId: string; }>;
240

241
	private _modelCreationOptionsByLanguageAndResource: {
242
		[languageAndResource: string]: ITextModelCreationOptions;
243
	};
A
Alex Dima 已提交
244 245 246 247

	/**
	 * All the models known in the system.
	 */
B
Benjamin Pasero 已提交
248
	private _models: { [modelId: string]: ModelData; };
E
Erich Gamma 已提交
249

250
	constructor(
251 252
		@IMarkerService markerService: IMarkerService,
		@IConfigurationService configurationService: IConfigurationService,
253
	) {
E
Erich Gamma 已提交
254
		this._markerService = markerService;
255
		this._configurationService = configurationService;
B
Benjamin Pasero 已提交
256
		this._models = {};
257
		this._modelCreationOptionsByLanguageAndResource = Object.create(null);
A
Alex Dima 已提交
258 259 260
		this._onModelAdded = new Emitter<ITextModel>();
		this._onModelRemoved = new Emitter<ITextModel>();
		this._onModelModeChanged = new Emitter<{ model: ITextModel; oldModeId: string; }>();
B
Benjamin Pasero 已提交
261 262 263 264

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

266
		this._configurationServiceSubscription = this._configurationService.onDidChangeConfiguration(e => this._updateModelOptions());
267 268
		this._updateModelOptions();
	}
J
Joao Moreno 已提交
269

270
	private static _readModelOptions(config: IRawConfig, isForSimpleWidget: boolean): ITextModelCreationOptions {
271
		let tabSize = EDITOR_MODEL_DEFAULTS.tabSize;
272 273 274 275
		if (config.editor && typeof config.editor.tabSize !== 'undefined') {
			let parsedTabSize = parseInt(config.editor.tabSize, 10);
			if (!isNaN(parsedTabSize)) {
				tabSize = parsedTabSize;
276
			}
A
Alex Dima 已提交
277 278 279
			if (tabSize < 1) {
				tabSize = 1;
			}
280
		}
281

282
		let insertSpaces = EDITOR_MODEL_DEFAULTS.insertSpaces;
283 284 285
		if (config.editor && typeof config.editor.insertSpaces !== 'undefined') {
			insertSpaces = (config.editor.insertSpaces === 'false' ? false : Boolean(config.editor.insertSpaces));
		}
286

287
		let newDefaultEOL = DEFAULT_EOL;
288
		const eol = config.files && config.files.eol;
289
		if (eol === '\r\n') {
290
			newDefaultEOL = DefaultEndOfLine.CRLF;
291
		} else if (eol === '\n') {
292
			newDefaultEOL = DefaultEndOfLine.LF;
293
		}
294

295
		let trimAutoWhitespace = EDITOR_MODEL_DEFAULTS.trimAutoWhitespace;
296 297 298
		if (config.editor && typeof config.editor.trimAutoWhitespace !== 'undefined') {
			trimAutoWhitespace = (config.editor.trimAutoWhitespace === 'false' ? false : Boolean(config.editor.trimAutoWhitespace));
		}
299

300
		let detectIndentation = EDITOR_MODEL_DEFAULTS.detectIndentation;
301 302 303
		if (config.editor && typeof config.editor.detectIndentation !== 'undefined') {
			detectIndentation = (config.editor.detectIndentation === 'false' ? false : Boolean(config.editor.detectIndentation));
		}
304

305 306 307
		let largeFileOptimizations = EDITOR_MODEL_DEFAULTS.largeFileOptimizations;
		if (config.editor && typeof config.editor.largeFileOptimizations !== 'undefined') {
			largeFileOptimizations = (config.editor.largeFileOptimizations === 'false' ? false : Boolean(config.editor.largeFileOptimizations));
308 309
		}

310
		return {
311
			isForSimpleWidget: isForSimpleWidget,
312 313 314 315
			tabSize: tabSize,
			insertSpaces: insertSpaces,
			detectIndentation: detectIndentation,
			defaultEOL: newDefaultEOL,
316
			trimAutoWhitespace: trimAutoWhitespace,
317
			largeFileOptimizations: largeFileOptimizations
318
		};
E
Erich Gamma 已提交
319 320
	}

321
	public getCreationOptions(language: string, resource: URI, isForSimpleWidget: boolean): ITextModelCreationOptions {
322
		let creationOptions = this._modelCreationOptionsByLanguageAndResource[language + resource];
323
		if (!creationOptions) {
324
			creationOptions = ModelServiceImpl._readModelOptions(this._configurationService.getValue({ overrideIdentifier: language, resource }), isForSimpleWidget);
325
			this._modelCreationOptionsByLanguageAndResource[language + resource] = creationOptions;
326 327
		}
		return creationOptions;
328 329
	}

330
	private _updateModelOptions(): void {
331 332
		let oldOptionsByLanguageAndResource = this._modelCreationOptionsByLanguageAndResource;
		this._modelCreationOptionsByLanguageAndResource = Object.create(null);
333

334
		// Update options on all models
A
Alex Dima 已提交
335 336 337 338
		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];
339
			const language = modelData.model.getLanguageIdentifier().language;
340 341
			const uri = modelData.model.uri;
			const oldOptions = oldOptionsByLanguageAndResource[language + uri];
342
			const newOptions = this.getCreationOptions(language, uri, modelData.model.isForSimpleWidget);
343 344 345
			ModelServiceImpl._setModelOptionsForModel(modelData.model, newOptions, oldOptions);
		}
	}
346

A
Alex Dima 已提交
347
	private static _setModelOptionsForModel(model: ITextModel, newOptions: ITextModelCreationOptions, currentOptions: ITextModelCreationOptions): void {
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
		if (currentOptions
			&& (currentOptions.detectIndentation === newOptions.detectIndentation)
			&& (currentOptions.insertSpaces === newOptions.insertSpaces)
			&& (currentOptions.tabSize === newOptions.tabSize)
			&& (currentOptions.trimAutoWhitespace === newOptions.trimAutoWhitespace)
		) {
			// Same indent opts, no need to touch the model
			return;
		}

		if (newOptions.detectIndentation) {
			model.detectIndentation(newOptions.insertSpaces, newOptions.tabSize);
			model.updateOptions({
				trimAutoWhitespace: newOptions.trimAutoWhitespace
			});
		} else {
			model.updateOptions({
				insertSpaces: newOptions.insertSpaces,
				tabSize: newOptions.tabSize,
				trimAutoWhitespace: newOptions.trimAutoWhitespace
			});
369
		}
370 371
	}

E
Erich Gamma 已提交
372
	public dispose(): void {
B
Benjamin Pasero 已提交
373
		if (this._markerServiceSubscription) {
E
Erich Gamma 已提交
374 375
			this._markerServiceSubscription.dispose();
		}
376
		this._configurationServiceSubscription.dispose();
E
Erich Gamma 已提交
377 378 379
	}

	private _handleMarkerChange(changedResources: URI[]): void {
A
Alex Dima 已提交
380 381 382 383
		changedResources.forEach((resource) => {
			let modelId = MODEL_ID(resource);
			let modelData = this._models[modelId];
			if (!modelData) {
E
Erich Gamma 已提交
384 385
				return;
			}
386
			ModelMarkerHandler.setMarkers(modelData, this._markerService);
E
Erich Gamma 已提交
387 388 389
		});
	}

A
Alex Dima 已提交
390
	private _cleanUp(model: ITextModel): void {
S
Sandeep Somavarapu 已提交
391 392
		// clean up markers for internal, transient models
		if (model.uri.scheme === network.Schemas.inMemory
B
Benjamin Pasero 已提交
393 394 395 396 397
			|| 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 已提交
398
		}
399 400 401

		// clean up cache
		delete this._modelCreationOptionsByLanguageAndResource[model.getLanguageIdentifier().language + model.uri];
S
Sandeep Somavarapu 已提交
402 403
	}

E
Erich Gamma 已提交
404 405
	// --- begin IModelService

406
	private _createModelData(value: string | ITextBufferFactory, languageIdentifier: LanguageIdentifier, resource: URI, isForSimpleWidget: boolean): ModelData {
A
Alex Dima 已提交
407
		// create & save the model
408
		const options = this.getCreationOptions(languageIdentifier.language, resource, isForSimpleWidget);
409 410
		const model: TextModel = new TextModel(value, options, languageIdentifier, resource);
		const modelId = MODEL_ID(model.uri);
E
Erich Gamma 已提交
411 412 413

		if (this._models[modelId]) {
			// There already exists a model with this id => this is a programmer error
414
			throw new Error('ModelService: Cannot add model because it already exists!');
E
Erich Gamma 已提交
415 416
		}

417
		const modelData = new ModelData(
418 419 420 421
			model,
			(model) => this._onWillDispose(model),
			(model, e) => this._onDidChangeLanguage(model, e)
		);
A
Alex Dima 已提交
422
		this._models[modelId] = modelData;
E
Erich Gamma 已提交
423

A
Alex Dima 已提交
424
		return modelData;
E
Erich Gamma 已提交
425 426
	}

427
	public updateModel(model: ITextModel, value: string | ITextBufferFactory): void {
428
		const options = this.getCreationOptions(model.getLanguageIdentifier().language, model.uri, model.isForSimpleWidget);
429
		const textBuffer = createTextBuffer(value, options.defaultEOL);
430 431

		// Return early if the text is already set in that form
432
		if (model.equalsTextBuffer(textBuffer)) {
433 434
			return;
		}
435 436

		// Otherwise find a diff between the values and update model
437
		model.pushStackElement();
A
Alex Dima 已提交
438
		model.pushEOL(textBuffer.getEOL() === '\r\n' ? EndOfLineSequence.CRLF : EndOfLineSequence.LF);
439
		model.pushEditOperations(
440
			[],
441
			ModelServiceImpl._computeEdits(model, textBuffer),
442
			(inverseEditOperations: IIdentifiedSingleEditOperation[]) => []
443
		);
444
		model.pushStackElement();
445 446
	}

447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
	private static _commonPrefix(a: ILineSequence, aLen: number, aDelta: number, b: ILineSequence, bLen: number, bDelta: number): number {
		const maxResult = Math.min(aLen, bLen);

		let result = 0;
		for (let i = 0; i < maxResult && a.getLineContent(aDelta + i) === b.getLineContent(bDelta + i); i++) {
			result++;
		}
		return result;
	}

	private static _commonSuffix(a: ILineSequence, aLen: number, aDelta: number, b: ILineSequence, bLen: number, bDelta: number): number {
		const maxResult = Math.min(aLen, bLen);

		let result = 0;
		for (let i = 0; i < maxResult && a.getLineContent(aDelta + aLen - i) === b.getLineContent(bDelta + bLen - i); i++) {
			result++;
		}
		return result;
	}

467 468 469
	/**
	 * Compute edits to bring `model` to the state of `textSource`.
	 */
470
	public static _computeEdits(model: ITextModel, textBuffer: ITextBuffer): IIdentifiedSingleEditOperation[] {
471
		const modelLineCount = model.getLineCount();
472 473
		const textBufferLineCount = textBuffer.getLineCount();
		const commonPrefix = this._commonPrefix(model, modelLineCount, 1, textBuffer, textBufferLineCount, 1);
474

475 476 477 478
		if (modelLineCount === textBufferLineCount && commonPrefix === modelLineCount) {
			// equality case
			return [];
		}
479

480
		const commonSuffix = this._commonSuffix(model, modelLineCount - commonPrefix, commonPrefix, textBuffer, textBufferLineCount - commonPrefix, commonPrefix);
481

482 483 484 485 486 487 488 489 490 491
		let oldRange: Range, newRange: Range;
		if (commonSuffix > 0) {
			oldRange = new Range(commonPrefix + 1, 1, modelLineCount - commonSuffix + 1, 1);
			newRange = new Range(commonPrefix + 1, 1, textBufferLineCount - commonSuffix + 1, 1);
		} else if (commonPrefix > 0) {
			oldRange = new Range(commonPrefix, model.getLineMaxColumn(commonPrefix), modelLineCount, model.getLineMaxColumn(modelLineCount));
			newRange = new Range(commonPrefix, 1 + textBuffer.getLineLength(commonPrefix), textBufferLineCount, 1 + textBuffer.getLineLength(textBufferLineCount));
		} else {
			oldRange = new Range(1, 1, modelLineCount, model.getLineMaxColumn(modelLineCount));
			newRange = new Range(1, 1, textBufferLineCount, 1 + textBuffer.getLineLength(textBufferLineCount));
492 493
		}

494
		return [EditOperation.replaceMove(oldRange, textBuffer.getValueInRange(newRange, EndOfLinePreference.TextDefined))];
495 496
	}

497
	public createModel(value: string | ITextBufferFactory, modeOrPromise: TPromise<IMode> | IMode, resource: URI, isForSimpleWidget: boolean = false): ITextModel {
498 499 500
		let modelData: ModelData;

		if (!modeOrPromise || TPromise.is(modeOrPromise)) {
501
			modelData = this._createModelData(value, PLAINTEXT_LANGUAGE_IDENTIFIER, resource, isForSimpleWidget);
502 503
			this.setMode(modelData.model, modeOrPromise);
		} else {
504
			modelData = this._createModelData(value, modeOrPromise.getLanguageIdentifier(), resource, isForSimpleWidget);
505
		}
E
Erich Gamma 已提交
506

A
Alex Dima 已提交
507 508
		// handle markers (marker service => model)
		if (this._markerService) {
509
			ModelMarkerHandler.setMarkers(modelData, this._markerService);
E
Erich Gamma 已提交
510 511
		}

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

A
Alex Dima 已提交
514
		return modelData.model;
E
Erich Gamma 已提交
515 516
	}

A
Alex Dima 已提交
517
	public setMode(model: ITextModel, modeOrPromise: TPromise<IMode> | IMode): void {
518 519 520 521 522 523
		if (!modeOrPromise) {
			return;
		}
		if (TPromise.is(modeOrPromise)) {
			modeOrPromise.then((mode) => {
				if (!model.isDisposed()) {
A
Alex Dima 已提交
524
					model.setMode(mode.getLanguageIdentifier());
525 526 527
				}
			});
		} else {
A
Alex Dima 已提交
528
			model.setMode(modeOrPromise.getLanguageIdentifier());
529 530 531
		}
	}

J
Johannes Rieken 已提交
532
	public destroyModel(resource: URI): void {
A
Alex Dima 已提交
533 534 535 536
		// 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 已提交
537
		}
A
Alex Dima 已提交
538
		modelData.model.dispose();
E
Erich Gamma 已提交
539 540
	}

A
Alex Dima 已提交
541 542
	public getModels(): ITextModel[] {
		let ret: ITextModel[] = [];
A
Alex Dima 已提交
543 544 545 546 547

		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 已提交
548
		}
A
Alex Dima 已提交
549

E
Erich Gamma 已提交
550 551 552
		return ret;
	}

A
Alex Dima 已提交
553
	public getModel(resource: URI): ITextModel {
A
Alex Dima 已提交
554 555 556 557
		let modelId = MODEL_ID(resource);
		let modelData = this._models[modelId];
		if (!modelData) {
			return null;
E
Erich Gamma 已提交
558
		}
A
Alex Dima 已提交
559
		return modelData.model;
E
Erich Gamma 已提交
560 561
	}

A
Alex Dima 已提交
562
	public get onModelAdded(): Event<ITextModel> {
563
		return this._onModelAdded ? this._onModelAdded.event : null;
E
Erich Gamma 已提交
564 565
	}

A
Alex Dima 已提交
566
	public get onModelRemoved(): Event<ITextModel> {
567
		return this._onModelRemoved ? this._onModelRemoved.event : null;
E
Erich Gamma 已提交
568 569
	}

A
Alex Dima 已提交
570
	public get onModelModeChanged(): Event<{ model: ITextModel; oldModeId: string; }> {
571
		return this._onModelModeChanged ? this._onModelModeChanged.event : null;
E
Erich Gamma 已提交
572 573 574 575
	}

	// --- end IModelService

A
Alex Dima 已提交
576
	private _onWillDispose(model: ITextModel): void {
577
		let modelId = MODEL_ID(model.uri);
A
Alex Dima 已提交
578 579 580 581 582
		let modelData = this._models[modelId];

		delete this._models[modelId];
		modelData.dispose();

583
		this._cleanUp(model);
A
Alex Dima 已提交
584 585 586
		this._onModelRemoved.fire(model);
	}

A
Alex Dima 已提交
587
	private _onDidChangeLanguage(model: ITextModel, e: IModelLanguageChangedEvent): void {
588 589
		const oldModeId = e.oldLanguage;
		const newModeId = model.getLanguageIdentifier().language;
590 591
		const oldOptions = this.getCreationOptions(oldModeId, model.uri, model.isForSimpleWidget);
		const newOptions = this.getCreationOptions(newModeId, model.uri, model.isForSimpleWidget);
592 593
		ModelServiceImpl._setModelOptionsForModel(model, newOptions, oldOptions);
		this._onModelModeChanged.fire({ model, oldModeId });
E
Erich Gamma 已提交
594 595
	}
}
596 597 598 599

export interface ILineSequence {
	getLineContent(lineNumber: number): string;
}