textModel.ts 35.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';

J
Johannes Rieken 已提交
7
import { OrderGuaranteeEventEmitter } from 'vs/base/common/eventEmitter';
A
Alex Dima 已提交
8
import * as strings from 'vs/base/common/strings';
J
Johannes Rieken 已提交
9 10
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
A
Alex Dima 已提交
11
import * as editorCommon from 'vs/editor/common/editorCommon';
J
Johannes Rieken 已提交
12 13 14 15 16 17
import { ModelLine } from 'vs/editor/common/model/modelLine';
import { guessIndentation } from 'vs/editor/common/model/indentationGuesser';
import { DEFAULT_INDENTATION, DEFAULT_TRIM_AUTO_WHITESPACE } from 'vs/editor/common/config/defaultConfig';
import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer';
import { IndentRange, computeRanges } from 'vs/editor/common/model/indentRanges';
import { CharCode } from 'vs/base/common/charCode';
E
Erich Gamma 已提交
18

A
Alex Dima 已提交
19
const LIMIT_FIND_COUNT = 999;
A
Alex Dima 已提交
20
export const LONG_LINE_BOUNDARY = 1000;
E
Erich Gamma 已提交
21

A
Alex Dima 已提交
22
export class TextModel extends OrderGuaranteeEventEmitter implements editorCommon.ITextModel {
23 24
	private static MODEL_SYNC_LIMIT = 5 * 1024 * 1024; // 5 MB
	private static MODEL_TOKENIZATION_LIMIT = 20 * 1024 * 1024; // 20 MB
E
Erich Gamma 已提交
25

26 27 28 29
	public static DEFAULT_CREATION_OPTIONS: editorCommon.ITextModelCreationOptions = {
		tabSize: DEFAULT_INDENTATION.tabSize,
		insertSpaces: DEFAULT_INDENTATION.insertSpaces,
		detectIndentation: false,
A
Alex Dima 已提交
30
		defaultEOL: editorCommon.DefaultEndOfLine.LF,
31
		trimAutoWhitespace: DEFAULT_TRIM_AUTO_WHITESPACE,
32 33
	};

J
Johannes Rieken 已提交
34 35 36 37
	/*protected*/ _lines: ModelLine[];
	protected _EOL: string;
	protected _isDisposed: boolean;
	protected _isDisposing: boolean;
38
	protected _options: editorCommon.TextModelResolvedOptions;
39
	protected _lineStarts: PrefixSumComputer;
A
Alex Dima 已提交
40
	private _indentRanges: IndentRange[];
E
Erich Gamma 已提交
41

J
Johannes Rieken 已提交
42
	private _versionId: number;
E
Erich Gamma 已提交
43 44 45 46
	/**
	 * Unlike, versionId, this can go down (via undo) or go to previous values (via redo)
	 */
	private _alternativeVersionId: number;
J
Johannes Rieken 已提交
47
	private _BOM: string;
E
Erich Gamma 已提交
48

49 50 51
	private _shouldSimplifyMode: boolean;
	private _shouldDenyMode: boolean;

J
Johannes Rieken 已提交
52
	constructor(allowedEventTypes: string[], rawText: editorCommon.IRawText) {
A
Alex Dima 已提交
53
		allowedEventTypes.push(editorCommon.EventType.ModelRawContentChanged, editorCommon.EventType.ModelOptionsChanged);
E
Erich Gamma 已提交
54 55
		super(allowedEventTypes);

56 57 58
		this._shouldSimplifyMode = (rawText.length > TextModel.MODEL_SYNC_LIMIT);
		this._shouldDenyMode = (rawText.length > TextModel.MODEL_TOKENIZATION_LIMIT);

59
		this._options = new editorCommon.TextModelResolvedOptions(rawText.options);
E
Erich Gamma 已提交
60 61 62 63 64 65
		this._constructLines(rawText);
		this._setVersionId(1);
		this._isDisposed = false;
		this._isDisposing = false;
	}

66 67 68 69 70 71
	protected _assertNotDisposed(): void {
		if (this._isDisposed) {
			throw new Error('Model is disposed!');
		}
	}

72
	public isTooLargeForHavingAMode(): boolean {
73
		this._assertNotDisposed();
74 75 76 77
		return this._shouldDenyMode;
	}

	public isTooLargeForHavingARichMode(): boolean {
78
		this._assertNotDisposed();
79 80 81
		return this._shouldSimplifyMode;
	}

82
	public getOptions(): editorCommon.TextModelResolvedOptions {
83
		this._assertNotDisposed();
84 85 86
		return this._options;
	}

87
	public updateOptions(_newOpts: editorCommon.ITextModelUpdateOptions): void {
88
		this._assertNotDisposed();
89 90 91
		let tabSize = (typeof _newOpts.tabSize !== 'undefined') ? _newOpts.tabSize : this._options.tabSize;
		let insertSpaces = (typeof _newOpts.insertSpaces !== 'undefined') ? _newOpts.insertSpaces : this._options.insertSpaces;
		let trimAutoWhitespace = (typeof _newOpts.trimAutoWhitespace !== 'undefined') ? _newOpts.trimAutoWhitespace : this._options.trimAutoWhitespace;
92

93 94 95 96 97 98
		let newOpts = new editorCommon.TextModelResolvedOptions({
			tabSize: tabSize,
			insertSpaces: insertSpaces,
			defaultEOL: this._options.defaultEOL,
			trimAutoWhitespace: trimAutoWhitespace
		});
99

100 101
		if (this._options.equals(newOpts)) {
			return;
102
		}
103 104 105 106 107 108 109 110

		let e = this._options.createChangeEvent(newOpts);
		this._options = newOpts;

		if (e.tabSize) {
			let newTabSize = this._options.tabSize;
			for (let i = 0, len = this._lines.length; i < len; i++) {
				this._lines[i].updateTabSize(newTabSize);
111 112
			}
		}
113

114
		this.emit(editorCommon.EventType.ModelOptionsChanged, e);
115 116
	}

J
Johannes Rieken 已提交
117
	public detectIndentation(defaultInsertSpaces: boolean, defaultTabSize: number): void {
118
		this._assertNotDisposed();
119 120 121 122 123 124 125 126
		let lines = this._lines.map(line => line.text);
		let guessedIndentation = guessIndentation(lines, defaultTabSize, defaultInsertSpaces);
		this.updateOptions({
			insertSpaces: guessedIndentation.insertSpaces,
			tabSize: guessedIndentation.tabSize
		});
	}

J
Johannes Rieken 已提交
127
	private _normalizeIndentationFromWhitespace(str: string): string {
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
		let tabSize = this._options.tabSize;
		let insertSpaces = this._options.insertSpaces;

		let spacesCnt = 0;
		for (let i = 0; i < str.length; i++) {
			if (str.charAt(i) === '\t') {
				spacesCnt += tabSize;
			} else {
				spacesCnt++;
			}
		}

		let result = '';
		if (!insertSpaces) {
			let tabsCnt = Math.floor(spacesCnt / tabSize);
			spacesCnt = spacesCnt % tabSize;
			for (let i = 0; i < tabsCnt; i++) {
				result += '\t';
			}
		}

		for (let i = 0; i < spacesCnt; i++) {
			result += ' ';
		}

		return result;
	}

J
Johannes Rieken 已提交
156
	public normalizeIndentation(str: string): string {
157
		this._assertNotDisposed();
158 159 160 161 162 163 164 165
		let firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(str);
		if (firstNonWhitespaceIndex === -1) {
			firstNonWhitespaceIndex = str.length;
		}
		return this._normalizeIndentationFromWhitespace(str.substring(0, firstNonWhitespaceIndex)) + str.substring(firstNonWhitespaceIndex);
	}

	public getOneIndent(): string {
166
		this._assertNotDisposed();
167 168 169 170 171 172 173 174 175 176 177 178 179 180
		let tabSize = this._options.tabSize;
		let insertSpaces = this._options.insertSpaces;

		if (insertSpaces) {
			let result = '';
			for (let i = 0; i < tabSize; i++) {
				result += ' ';
			}
			return result;
		} else {
			return '\t';
		}
	}

E
Erich Gamma 已提交
181
	public getVersionId(): number {
182
		this._assertNotDisposed();
E
Erich Gamma 已提交
183 184 185 186
		return this._versionId;
	}

	public getAlternativeVersionId(): number {
187
		this._assertNotDisposed();
E
Erich Gamma 已提交
188 189 190
		return this._alternativeVersionId;
	}

191 192
	private _ensureLineStarts(): void {
		if (!this._lineStarts) {
J
Johannes Rieken 已提交
193
			const lineStartValues: number[] = [];
194 195 196 197 198 199 200 201 202
			const eolLength = this._EOL.length;
			for (let i = 0, len = this._lines.length; i < len; i++) {
				lineStartValues.push(this._lines[i].text.length + eolLength);
			}
			this._lineStarts = new PrefixSumComputer(lineStartValues);
		}
	}

	public getOffsetAt(rawPosition: editorCommon.IPosition): number {
203
		this._assertNotDisposed();
204
		let position = this._validatePosition(rawPosition.lineNumber, rawPosition.column, false);
205 206 207 208 209
		this._ensureLineStarts();
		return this._lineStarts.getAccumulatedValue(position.lineNumber - 2) + position.column - 1;
	}

	public getPositionAt(offset: number): Position {
210
		this._assertNotDisposed();
211 212 213 214 215 216 217 218 219 220 221 222
		offset = Math.floor(offset);
		offset = Math.max(0, offset);

		this._ensureLineStarts();
		let out = this._lineStarts.getIndexOf(offset);

		let lineLength = this._lines[out.index].text.length;

		// Ensure we return a valid position
		return new Position(out.index + 1, Math.min(out.remainder + 1, lineLength + 1));
	}

A
Alex Dima 已提交
223
	protected _increaseVersionId(): void {
E
Erich Gamma 已提交
224 225 226
		this._setVersionId(this._versionId + 1);
	}

J
Johannes Rieken 已提交
227
	protected _setVersionId(newVersionId: number): void {
E
Erich Gamma 已提交
228 229 230 231
		this._versionId = newVersionId;
		this._alternativeVersionId = this._versionId;
	}

J
Johannes Rieken 已提交
232
	protected _overwriteAlternativeVersionId(newAlternativeVersionId: number): void {
E
Erich Gamma 已提交
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
		this._alternativeVersionId = newAlternativeVersionId;
	}

	public isDisposed(): boolean {
		return this._isDisposed;
	}

	public dispose(): void {
		this._isDisposed = true;
		// Null out members, such that any use of a disposed model will throw exceptions sooner rather than later
		this._lines = null;
		this._EOL = null;
		this._BOM = null;

		super.dispose();
	}

A
Alex Dima 已提交
250
	protected _createContentChangedFlushEvent(): editorCommon.IModelContentChangedFlushEvent {
E
Erich Gamma 已提交
251
		return {
A
Alex Dima 已提交
252
			changeType: editorCommon.EventType.ModelRawContentChangedFlush,
253 254
			detail: this.toRawText(),
			versionId: this._versionId,
E
Erich Gamma 已提交
255 256 257 258 259 260
			// TODO@Alex -> remove these fields from here
			isUndoing: false,
			isRedoing: false
		};
	}

J
Johannes Rieken 已提交
261 262
	protected _emitContentChanged2(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, rangeLength: number, text: string, isUndoing: boolean, isRedoing: boolean): void {
		var e: editorCommon.IModelContentChangedEvent2 = {
E
Erich Gamma 已提交
263 264 265
			range: new Range(startLineNumber, startColumn, endLineNumber, endColumn),
			rangeLength: rangeLength,
			text: text,
266
			eol: this._EOL,
E
Erich Gamma 已提交
267 268 269 270 271
			versionId: this.getVersionId(),
			isUndoing: isUndoing,
			isRedoing: isRedoing
		};
		if (!this._isDisposing) {
A
Alex Dima 已提交
272
			this.emit(editorCommon.EventType.ModelContentChanged2, e);
E
Erich Gamma 已提交
273 274 275
		}
	}

276
	protected _resetValue(newValue: editorCommon.IRawText): void {
277
		this._constructLines(newValue);
E
Erich Gamma 已提交
278 279 280
		this._increaseVersionId();
	}

A
Alex Dima 已提交
281
	public toRawText(): editorCommon.IRawText {
282
		this._assertNotDisposed();
E
Erich Gamma 已提交
283 284 285 286
		return {
			BOM: this._BOM,
			EOL: this._EOL,
			lines: this.getLinesContent(),
287
			length: this.getValueLength(),
288
			options: this._options
E
Erich Gamma 已提交
289 290 291
		};
	}

292
	public equals(other: editorCommon.IRawText): boolean {
293
		this._assertNotDisposed();
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
		if (this._BOM !== other.BOM) {
			return false;
		}
		if (this._EOL !== other.EOL) {
			return false;
		}
		if (this._lines.length !== other.lines.length) {
			return false;
		}
		for (let i = 0, len = this._lines.length; i < len; i++) {
			if (this._lines[i].text !== other.lines[i]) {
				return false;
			}
		}
		return true;
	}

J
Johannes Rieken 已提交
311
	public setValue(value: string): void {
312
		this._assertNotDisposed();
A
Alex Dima 已提交
313 314 315
		if (value === null) {
			// There's nothing to do
			return;
316
		}
A
Alex Dima 已提交
317 318 319 320 321 322 323 324
		let rawText: editorCommon.IRawText = null;
		rawText = TextModel.toRawText(value, {
			tabSize: this._options.tabSize,
			insertSpaces: this._options.insertSpaces,
			trimAutoWhitespace: this._options.trimAutoWhitespace,
			detectIndentation: false,
			defaultEOL: this._options.defaultEOL
		});
325 326 327
		this.setValueFromRawText(rawText);
	}

J
Johannes Rieken 已提交
328
	public setValueFromRawText(newValue: editorCommon.IRawText): void {
329
		this._assertNotDisposed();
E
Erich Gamma 已提交
330 331 332 333 334 335 336 337
		if (newValue === null) {
			// There's nothing to do
			return;
		}
		var oldFullModelRange = this.getFullModelRange();
		var oldModelValueLength = this.getValueLengthInRange(oldFullModelRange);
		var endLineNumber = this.getLineCount();
		var endColumn = this.getLineMaxColumn(endLineNumber);
338

339 340 341 342
		this._resetValue(newValue);

		this._emitModelContentChangedFlushEvent(this._createContentChangedFlushEvent());

E
Erich Gamma 已提交
343 344 345
		this._emitContentChanged2(1, 1, endLineNumber, endColumn, oldModelValueLength, this.getValue(), false, false);
	}

J
Johannes Rieken 已提交
346
	public getValue(eol?: editorCommon.EndOfLinePreference, preserveBOM: boolean = false): string {
347
		this._assertNotDisposed();
E
Erich Gamma 已提交
348 349 350 351 352 353 354 355 356 357
		var fullModelRange = this.getFullModelRange();
		var fullModelValue = this.getValueInRange(fullModelRange, eol);

		if (preserveBOM) {
			return this._BOM + fullModelValue;
		}

		return fullModelValue;
	}

A
Alex Dima 已提交
358
	public getValueLength(eol?: editorCommon.EndOfLinePreference, preserveBOM: boolean = false): number {
359
		this._assertNotDisposed();
E
Erich Gamma 已提交
360 361 362 363 364 365 366 367 368 369
		var fullModelRange = this.getFullModelRange();
		var fullModelValue = this.getValueLengthInRange(fullModelRange, eol);

		if (preserveBOM) {
			return this._BOM.length + fullModelValue;
		}

		return fullModelValue;
	}

J
Johannes Rieken 已提交
370
	public getEmptiedValueInRange(rawRange: editorCommon.IRange, fillCharacter: string = '', eol: editorCommon.EndOfLinePreference = editorCommon.EndOfLinePreference.TextDefined): string {
371
		this._assertNotDisposed();
E
Erich Gamma 已提交
372 373 374 375 376 377 378 379 380 381 382 383 384
		var range = this.validateRange(rawRange);

		if (range.isEmpty()) {
			return '';
		}

		if (range.startLineNumber === range.endLineNumber) {
			return this._repeatCharacter(fillCharacter, range.endColumn - range.startColumn);
		}

		var lineEnding = this._getEndOfLine(eol),
			startLineIndex = range.startLineNumber - 1,
			endLineIndex = range.endLineNumber - 1,
J
Johannes Rieken 已提交
385
			resultLines: string[] = [];
E
Erich Gamma 已提交
386 387 388 389 390 391 392 393 394 395

		resultLines.push(this._repeatCharacter(fillCharacter, this._lines[startLineIndex].text.length - range.startColumn + 1));
		for (var i = startLineIndex + 1; i < endLineIndex; i++) {
			resultLines.push(this._repeatCharacter(fillCharacter, this._lines[i].text.length));
		}
		resultLines.push(this._repeatCharacter(fillCharacter, range.endColumn - 1));

		return resultLines.join(lineEnding);
	}

J
Johannes Rieken 已提交
396
	private _repeatCharacter(fillCharacter: string, count: number): string {
E
Erich Gamma 已提交
397 398 399 400 401 402 403
		var r = '';
		for (var i = 0; i < count; i++) {
			r += fillCharacter;
		}
		return r;
	}

J
Johannes Rieken 已提交
404
	public getValueInRange(rawRange: editorCommon.IRange, eol: editorCommon.EndOfLinePreference = editorCommon.EndOfLinePreference.TextDefined): string {
405
		this._assertNotDisposed();
E
Erich Gamma 已提交
406 407 408 409 410 411 412 413 414 415 416 417 418
		var range = this.validateRange(rawRange);

		if (range.isEmpty()) {
			return '';
		}

		if (range.startLineNumber === range.endLineNumber) {
			return this._lines[range.startLineNumber - 1].text.substring(range.startColumn - 1, range.endColumn - 1);
		}

		var lineEnding = this._getEndOfLine(eol),
			startLineIndex = range.startLineNumber - 1,
			endLineIndex = range.endLineNumber - 1,
J
Johannes Rieken 已提交
419
			resultLines: string[] = [];
E
Erich Gamma 已提交
420 421 422 423 424 425 426 427 428 429

		resultLines.push(this._lines[startLineIndex].text.substring(range.startColumn - 1));
		for (var i = startLineIndex + 1; i < endLineIndex; i++) {
			resultLines.push(this._lines[i].text);
		}
		resultLines.push(this._lines[endLineIndex].text.substring(0, range.endColumn - 1));

		return resultLines.join(lineEnding);
	}

J
Johannes Rieken 已提交
430
	public getValueLengthInRange(rawRange: editorCommon.IRange, eol: editorCommon.EndOfLinePreference = editorCommon.EndOfLinePreference.TextDefined): number {
431
		this._assertNotDisposed();
E
Erich Gamma 已提交
432 433 434 435 436 437 438 439 440 441
		var range = this.validateRange(rawRange);

		if (range.isEmpty()) {
			return 0;
		}

		if (range.startLineNumber === range.endLineNumber) {
			return (range.endColumn - range.startColumn);
		}

442 443 444
		let startOffset = this.getOffsetAt(new Position(range.startLineNumber, range.startColumn));
		let endOffset = this.getOffsetAt(new Position(range.endLineNumber, range.endColumn));
		return endOffset - startOffset;
E
Erich Gamma 已提交
445 446
	}

A
Alex Dima 已提交
447
	public isDominatedByLongLines(): boolean {
448
		this._assertNotDisposed();
E
Erich Gamma 已提交
449 450 451 452 453 454 455 456 457
		var smallLineCharCount = 0,
			longLineCharCount = 0,
			i: number,
			len: number,
			lines = this._lines,
			lineLength: number;

		for (i = 0, len = this._lines.length; i < len; i++) {
			lineLength = lines[i].text.length;
A
Alex Dima 已提交
458
			if (lineLength >= LONG_LINE_BOUNDARY) {
E
Erich Gamma 已提交
459 460 461 462 463 464 465 466 467 468
				longLineCharCount += lineLength;
			} else {
				smallLineCharCount += lineLength;
			}
		}

		return (longLineCharCount > smallLineCharCount);
	}

	public getLineCount(): number {
469
		this._assertNotDisposed();
E
Erich Gamma 已提交
470 471 472
		return this._lines.length;
	}

J
Johannes Rieken 已提交
473
	public getLineContent(lineNumber: number): string {
474
		this._assertNotDisposed();
E
Erich Gamma 已提交
475 476 477 478 479 480 481
		if (lineNumber < 1 || lineNumber > this.getLineCount()) {
			throw new Error('Illegal value ' + lineNumber + ' for `lineNumber`');
		}

		return this._lines[lineNumber - 1].text;
	}

J
Johannes Rieken 已提交
482
	public getIndentLevel(lineNumber: number): number {
483
		this._assertNotDisposed();
484 485 486 487 488 489 490
		if (lineNumber < 1 || lineNumber > this.getLineCount()) {
			throw new Error('Illegal value ' + lineNumber + ' for `lineNumber`');
		}

		return this._lines[lineNumber - 1].getIndentLevel();
	}

A
Alex Dima 已提交
491 492 493 494
	protected _resetIndentRanges(): void {
		this._indentRanges = null;
	}

A
Alex Dima 已提交
495
	private _getIndentRanges(): IndentRange[] {
A
Alex Dima 已提交
496 497 498
		if (!this._indentRanges) {
			this._indentRanges = computeRanges(this);
		}
A
Alex Dima 已提交
499 500 501 502
		return this._indentRanges;
	}

	public getIndentRanges(): IndentRange[] {
503
		this._assertNotDisposed();
A
Alex Dima 已提交
504 505 506 507
		let indentRanges = this._getIndentRanges();
		return IndentRange.deepCloneArr(indentRanges);
	}

J
Johannes Rieken 已提交
508
	private _toValidLineIndentGuide(lineNumber: number, indentGuide: number): number {
509 510 511 512 513 514 515 516
		let lineIndentLevel = this._lines[lineNumber - 1].getIndentLevel();
		if (lineIndentLevel === -1) {
			return indentGuide;
		}
		let maxIndentGuide = Math.ceil(lineIndentLevel / this._options.tabSize);
		return Math.min(maxIndentGuide, indentGuide);
	}

J
Johannes Rieken 已提交
517
	public getLineIndentGuide(lineNumber: number): number {
518
		this._assertNotDisposed();
A
Alex Dima 已提交
519 520 521 522 523 524 525 526 527
		if (lineNumber < 1 || lineNumber > this.getLineCount()) {
			throw new Error('Illegal value ' + lineNumber + ' for `lineNumber`');
		}

		let indentRanges = this._getIndentRanges();

		for (let i = indentRanges.length - 1; i >= 0; i--) {
			let rng = indentRanges[i];

528
			if (rng.startLineNumber === lineNumber) {
529
				return this._toValidLineIndentGuide(lineNumber, Math.ceil(rng.indent / this._options.tabSize));
530
			}
A
Alex Dima 已提交
531
			if (rng.startLineNumber < lineNumber && lineNumber <= rng.endLineNumber) {
532
				return this._toValidLineIndentGuide(lineNumber, 1 + Math.floor(rng.indent / this._options.tabSize));
A
Alex Dima 已提交
533
			}
534
			if (rng.endLineNumber + 1 === lineNumber) {
535 536 537 538 539 540 541
				let bestIndent = rng.indent;
				while (i > 0) {
					i--;
					rng = indentRanges[i];
					if (rng.endLineNumber + 1 === lineNumber) {
						bestIndent = rng.indent;
					}
542
				}
543
				return this._toValidLineIndentGuide(lineNumber, Math.ceil(bestIndent / this._options.tabSize));
544
			}
A
Alex Dima 已提交
545 546 547
		}

		return 0;
A
Alex Dima 已提交
548 549
	}

E
Erich Gamma 已提交
550
	public getLinesContent(): string[] {
551
		this._assertNotDisposed();
E
Erich Gamma 已提交
552 553 554 555 556 557 558 559
		var r: string[] = [];
		for (var i = 0, len = this._lines.length; i < len; i++) {
			r[i] = this._lines[i].text;
		}
		return r;
	}

	public getEOL(): string {
560
		this._assertNotDisposed();
E
Erich Gamma 已提交
561 562 563
		return this._EOL;
	}

A
Alex Dima 已提交
564
	public setEOL(eol: editorCommon.EndOfLineSequence): void {
565
		this._assertNotDisposed();
A
Alex Dima 已提交
566
		var newEOL = (eol === editorCommon.EndOfLineSequence.CRLF ? '\r\n' : '\n');
E
Erich Gamma 已提交
567 568 569 570 571 572 573 574 575 576 577
		if (this._EOL === newEOL) {
			// Nothing to do
			return;
		}

		var oldFullModelRange = this.getFullModelRange();
		var oldModelValueLength = this.getValueLengthInRange(oldFullModelRange);
		var endLineNumber = this.getLineCount();
		var endColumn = this.getLineMaxColumn(endLineNumber);

		this._EOL = newEOL;
578
		this._lineStarts = null;
E
Erich Gamma 已提交
579 580
		this._increaseVersionId();

581
		this._emitModelContentChangedFlushEvent(this._createContentChangedFlushEvent());
E
Erich Gamma 已提交
582 583 584 585

		this._emitContentChanged2(1, 1, endLineNumber, endColumn, oldModelValueLength, this.getValue(), false, false);
	}

J
Johannes Rieken 已提交
586
	public getLineMinColumn(lineNumber: number): number {
587
		this._assertNotDisposed();
E
Erich Gamma 已提交
588 589 590
		return 1;
	}

J
Johannes Rieken 已提交
591
	public getLineMaxColumn(lineNumber: number): number {
592
		this._assertNotDisposed();
E
Erich Gamma 已提交
593 594 595 596 597 598 599 600
		if (lineNumber < 1 || lineNumber > this.getLineCount()) {
			throw new Error('Illegal value ' + lineNumber + ' for `lineNumber`');
		}

		return this._lines[lineNumber - 1].text.length + 1;
	}

	public getLineFirstNonWhitespaceColumn(lineNumber: number): number {
601
		this._assertNotDisposed();
E
Erich Gamma 已提交
602 603 604 605
		if (lineNumber < 1 || lineNumber > this.getLineCount()) {
			throw new Error('Illegal value ' + lineNumber + ' for `lineNumber`');
		}

A
Alex Dima 已提交
606
		var result = strings.firstNonWhitespaceIndex(this._lines[lineNumber - 1].text);
E
Erich Gamma 已提交
607 608 609 610 611 612 613
		if (result === -1) {
			return 0;
		}
		return result + 1;
	}

	public getLineLastNonWhitespaceColumn(lineNumber: number): number {
614
		this._assertNotDisposed();
E
Erich Gamma 已提交
615 616 617 618
		if (lineNumber < 1 || lineNumber > this.getLineCount()) {
			throw new Error('Illegal value ' + lineNumber + ' for `lineNumber`');
		}

A
Alex Dima 已提交
619
		var result = strings.lastNonWhitespaceIndex(this._lines[lineNumber - 1].text);
E
Erich Gamma 已提交
620 621 622 623 624 625
		if (result === -1) {
			return 0;
		}
		return result + 2;
	}

J
Johannes Rieken 已提交
626
	public validateLineNumber(lineNumber: number): number {
627
		this._assertNotDisposed();
E
Erich Gamma 已提交
628 629 630 631 632 633 634 635 636
		if (lineNumber < 1) {
			lineNumber = 1;
		}
		if (lineNumber > this._lines.length) {
			lineNumber = this._lines.length;
		}
		return lineNumber;
	}

637 638 639
	/**
	 * @param strict Do NOT allow a position inside a high-low surrogate pair
	 */
J
Johannes Rieken 已提交
640
	private _validatePosition(_lineNumber: number, _column: number, strict: boolean): Position {
641 642
		const lineNumber = Math.floor(typeof _lineNumber === 'number' ? _lineNumber : 1);
		const column = Math.floor(typeof _column === 'number' ? _column : 1);
E
Erich Gamma 已提交
643 644

		if (lineNumber < 1) {
645
			return new Position(1, 1);
E
Erich Gamma 已提交
646
		}
647 648 649

		if (lineNumber > this._lines.length) {
			return new Position(this._lines.length, this.getLineMaxColumn(this._lines.length));
E
Erich Gamma 已提交
650
		}
651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667

		if (column <= 1) {
			return new Position(lineNumber, 1);
		}

		const maxColumn = this.getLineMaxColumn(lineNumber);
		if (column >= maxColumn) {
			return new Position(lineNumber, maxColumn);
		}

		if (strict) {
			// If the position would end up in the middle of a high-low surrogate pair,
			// we move it to before the pair
			// !!At this point, column > 1
			const charCodeBefore = this._lines[lineNumber - 1].text.charCodeAt(column - 2);
			if (strings.isHighSurrogate(charCodeBefore)) {
				return new Position(lineNumber, column - 1);
A
aioute Gao 已提交
668
			}
E
Erich Gamma 已提交
669 670 671 672 673
		}

		return new Position(lineNumber, column);
	}

J
Johannes Rieken 已提交
674
	public validatePosition(position: editorCommon.IPosition): Position {
675
		this._assertNotDisposed();
676 677 678
		return this._validatePosition(position.lineNumber, position.column, true);
	}

J
Johannes Rieken 已提交
679
	public validateRange(_range: editorCommon.IRange): Range {
680
		this._assertNotDisposed();
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
		const start = this._validatePosition(_range.startLineNumber, _range.startColumn, false);
		const end = this._validatePosition(_range.endLineNumber, _range.endColumn, false);

		const startLineNumber = start.lineNumber;
		const startColumn = start.column;
		const endLineNumber = end.lineNumber;
		const endColumn = end.column;

		const startLineText = this._lines[startLineNumber - 1].text;
		const endLineText = this._lines[endLineNumber - 1].text;

		const charCodeBeforeStart = (startColumn > 1 ? startLineText.charCodeAt(startColumn - 2) : 0);
		const charCodeBeforeEnd = (endColumn > 1 && endColumn <= endLineText.length ? endLineText.charCodeAt(endColumn - 2) : 0);

		const startInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeStart);
		const endInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeEnd);

		if (!startInsideSurrogatePair && !endInsideSurrogatePair) {
			return new Range(startLineNumber, startColumn, endLineNumber, endColumn);
		}

		if (startLineNumber === endLineNumber && startColumn === endColumn) {
			// do not expand a collapsed range, simply move it to a valid location
			return new Range(startLineNumber, startColumn - 1, endLineNumber, endColumn - 1);
		}

		if (startInsideSurrogatePair && endInsideSurrogatePair) {
			// expand range at both ends
			return new Range(startLineNumber, startColumn - 1, endLineNumber, endColumn + 1);
		}

		if (startInsideSurrogatePair) {
			// only expand range at the start
			return new Range(startLineNumber, startColumn - 1, endLineNumber, endColumn);
		}

		// only expand range at the end
		return new Range(startLineNumber, startColumn, endLineNumber, endColumn + 1);
E
Erich Gamma 已提交
719 720
	}

J
Johannes Rieken 已提交
721
	public modifyPosition(rawPosition: editorCommon.IPosition, offset: number): Position {
722
		this._assertNotDisposed();
723
		return this.getPositionAt(this.getOffsetAt(rawPosition) + offset);
E
Erich Gamma 已提交
724 725
	}

726
	public getFullModelRange(): Range {
727
		this._assertNotDisposed();
E
Erich Gamma 已提交
728 729 730 731
		var lineCount = this.getLineCount();
		return new Range(1, 1, lineCount, this.getLineMaxColumn(lineCount));
	}

J
Johannes Rieken 已提交
732
	protected _emitModelContentChangedFlushEvent(e: editorCommon.IModelContentChangedFlushEvent): void {
E
Erich Gamma 已提交
733
		if (!this._isDisposing) {
A
Alex Dima 已提交
734
			this.emit(editorCommon.EventType.ModelRawContentChanged, e);
E
Erich Gamma 已提交
735 736 737
		}
	}

J
Johannes Rieken 已提交
738
	public static toRawText(rawText: string, opts: editorCommon.ITextModelCreationOptions): editorCommon.IRawText {
E
Erich Gamma 已提交
739 740 741 742 743 744 745
		// Count the number of lines that end with \r\n
		var carriageReturnCnt = 0,
			lastCarriageReturnIndex = -1;
		while ((lastCarriageReturnIndex = rawText.indexOf('\r', lastCarriageReturnIndex + 1)) !== -1) {
			carriageReturnCnt++;
		}

A
Alex Dima 已提交
746
		// Split the text into lines
E
Erich Gamma 已提交
747 748 749 750
		var lines = rawText.split(/\r\n|\r|\n/);

		// Remove the BOM (if present)
		var BOM = '';
A
Alex Dima 已提交
751 752
		if (strings.startsWithUTF8BOM(lines[0])) {
			BOM = strings.UTF8_BOM_CHARACTER;
E
Erich Gamma 已提交
753 754 755 756 757 758 759
			lines[0] = lines[0].substr(1);
		}

		var lineFeedCnt = lines.length - 1;
		var EOL = '';
		if (lineFeedCnt === 0) {
			// This is an empty file or a file with precisely one line
760
			EOL = (opts.defaultEOL === editorCommon.DefaultEndOfLine.LF ? '\n' : '\r\n');
E
Erich Gamma 已提交
761 762 763 764 765 766 767 768
		} else if (carriageReturnCnt > lineFeedCnt / 2) {
			// More than half of the file contains \r\n ending lines
			EOL = '\r\n';
		} else {
			// At least one line more ends in \n
			EOL = '\n';
		}

769
		let resolvedOpts: editorCommon.TextModelResolvedOptions;
770
		if (opts.detectIndentation) {
771
			let guessedIndentation = guessIndentation(lines, opts.tabSize, opts.insertSpaces);
772
			resolvedOpts = new editorCommon.TextModelResolvedOptions({
773 774
				tabSize: guessedIndentation.tabSize,
				insertSpaces: guessedIndentation.insertSpaces,
775
				trimAutoWhitespace: opts.trimAutoWhitespace,
776
				defaultEOL: opts.defaultEOL
777
			});
778
		} else {
779
			resolvedOpts = new editorCommon.TextModelResolvedOptions({
780 781
				tabSize: opts.tabSize,
				insertSpaces: opts.insertSpaces,
782
				trimAutoWhitespace: opts.trimAutoWhitespace,
783
				defaultEOL: opts.defaultEOL
784
			});
785 786
		}

E
Erich Gamma 已提交
787 788 789 790
		return {
			BOM: BOM,
			EOL: EOL,
			lines: lines,
791
			length: rawText.length,
792
			options: resolvedOpts
E
Erich Gamma 已提交
793 794 795
		};
	}

J
Johannes Rieken 已提交
796
	protected _constructLines(rawText: editorCommon.IRawText): void {
797 798 799
		const tabSize = rawText.options.tabSize;
		let rawLines = rawText.lines;
		let modelLines: ModelLine[] = [];
E
Erich Gamma 已提交
800

801 802
		for (let i = 0, len = rawLines.length; i < len; i++) {
			modelLines[i] = new ModelLine(i + 1, rawLines[i], tabSize);
E
Erich Gamma 已提交
803 804 805 806
		}
		this._BOM = rawText.BOM;
		this._EOL = rawText.EOL;
		this._lines = modelLines;
807
		this._lineStarts = null;
A
Alex Dima 已提交
808
		this._resetIndentRanges();
E
Erich Gamma 已提交
809 810
	}

J
Johannes Rieken 已提交
811
	private _getEndOfLine(eol: editorCommon.EndOfLinePreference): string {
E
Erich Gamma 已提交
812
		switch (eol) {
A
Alex Dima 已提交
813
			case editorCommon.EndOfLinePreference.LF:
E
Erich Gamma 已提交
814
				return '\n';
A
Alex Dima 已提交
815
			case editorCommon.EndOfLinePreference.CRLF:
E
Erich Gamma 已提交
816
				return '\r\n';
A
Alex Dima 已提交
817
			case editorCommon.EndOfLinePreference.TextDefined:
E
Erich Gamma 已提交
818 819 820 821 822
				return this.getEOL();
		}
		throw new Error('Unknown EOL preference');
	}

J
Johannes Rieken 已提交
823
	private static _isMultiline(searchString: string): boolean {
824 825 826 827 828 829 830
		if (!searchString || searchString.length === 0) {
			return false;
		}

		for (let i = 0, len = searchString.length; i < len; i++) {
			let chCode = searchString.charCodeAt(i);

A
Alex Dima 已提交
831
			if (chCode === CharCode.Backslash) {
832 833 834 835 836 837 838 839 840 841

				// move to next char
				i++;

				if (i >= len) {
					// string ends with a \
					break;
				}

				let nextChCode = searchString.charCodeAt(i);
A
Alex Dima 已提交
842
				if (nextChCode === CharCode.n || nextChCode === CharCode.r) {
843 844 845 846 847 848 849 850
					return true;
				}
			}
		}

		return false;
	}

J
Johannes Rieken 已提交
851
	public static parseSearchRequest(searchString: string, isRegex: boolean, matchCase: boolean, wholeWord: boolean): RegExp {
852 853 854 855 856
		if (searchString === '') {
			return null;
		}

		// Try to create a RegExp out of the params
S
Sandeep Somavarapu 已提交
857 858
		var regex: RegExp = null;
		var multiline = isRegex && TextModel._isMultiline(searchString);
859
		try {
J
Johannes Rieken 已提交
860
			regex = strings.createRegExp(searchString, isRegex, { matchCase, wholeWord, multiline, global: true });
861 862 863 864
		} catch (err) {
			return null;
		}

E
Erich Gamma 已提交
865
		if (!regex) {
866 867 868
			return null;
		}

S
Sandeep Somavarapu 已提交
869
		return regex;
870 871
	}

J
Johannes Rieken 已提交
872
	public findMatches(searchString: string, rawSearchScope: any, isRegex: boolean, matchCase: boolean, wholeWord: boolean, limitResultCount: number = LIMIT_FIND_COUNT): Range[] {
873
		this._assertNotDisposed();
S
Sandeep Somavarapu 已提交
874 875
		let regex = TextModel.parseSearchRequest(searchString, isRegex, matchCase, wholeWord);
		if (!regex) {
E
Erich Gamma 已提交
876 877 878
			return [];
		}

J
Johannes Rieken 已提交
879
		let searchRange: Range;
E
Erich Gamma 已提交
880
		if (Range.isIRange(rawSearchScope)) {
A
Alex Dima 已提交
881
			searchRange = this.validateRange(rawSearchScope);
E
Erich Gamma 已提交
882 883 884 885
		} else {
			searchRange = this.getFullModelRange();
		}

S
Sandeep Somavarapu 已提交
886 887
		if (regex.multiline) {
			return this._doFindMatchesMultiline(searchRange, regex, limitResultCount);
888
		}
S
Sandeep Somavarapu 已提交
889
		return this._doFindMatchesLineByLine(searchRange, regex, limitResultCount);
890 891
	}

J
Johannes Rieken 已提交
892
	private _doFindMatchesMultiline(searchRange: Range, searchRegex: RegExp, limitResultCount: number): Range[] {
893 894 895 896 897 898 899 900
		let deltaOffset = this.getOffsetAt(searchRange.getStartPosition());
		let text = this.getValueInRange(searchRange);

		let result: Range[] = [];
		let prevStartOffset = 0;
		let prevEndOffset = 0;
		let counter = 0;

J
Johannes Rieken 已提交
901
		let m: RegExpExecArray;
902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
		while ((m = searchRegex.exec(text))) {
			let startOffset = deltaOffset + m.index;
			let endOffset = startOffset + m[0].length;

			if (prevStartOffset === startOffset && prevEndOffset === endOffset) {
				// Exit early if the regex matches the same range
				return result;
			}

			let startPosition = this.getPositionAt(startOffset);
			let endPosition = this.getPositionAt(endOffset);

			result[counter++] = new Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column);
			if (counter >= limitResultCount) {
				return result;
			}

			prevStartOffset = startOffset;
			prevEndOffset = endOffset;
		}

		return result;
	}

J
Johannes Rieken 已提交
926 927
	private _doFindMatchesLineByLine(searchRange: Range, searchRegex: RegExp, limitResultCount: number): Range[] {
		let result: Range[] = [];
928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953
		let text: string;
		let counter = 0;

		// Early case for a search range that starts & stops on the same line number
		if (searchRange.startLineNumber === searchRange.endLineNumber) {
			text = this._lines[searchRange.startLineNumber - 1].text.substring(searchRange.startColumn - 1, searchRange.endColumn - 1);
			counter = this._findMatchesInLine(searchRegex, text, searchRange.startLineNumber, searchRange.startColumn - 1, counter, result, limitResultCount);
			return result;
		}

		// Collect results from first line
		text = this._lines[searchRange.startLineNumber - 1].text.substring(searchRange.startColumn - 1);
		counter = this._findMatchesInLine(searchRegex, text, searchRange.startLineNumber, searchRange.startColumn - 1, counter, result, limitResultCount);

		// Collect results from middle lines
		for (let lineNumber = searchRange.startLineNumber + 1; lineNumber < searchRange.endLineNumber && counter < limitResultCount; lineNumber++) {
			counter = this._findMatchesInLine(searchRegex, this._lines[lineNumber - 1].text, lineNumber, 0, counter, result, limitResultCount);
		}

		// Collect results from last line
		if (counter < limitResultCount) {
			text = this._lines[searchRange.endLineNumber - 1].text.substring(0, searchRange.endColumn - 1);
			counter = this._findMatchesInLine(searchRegex, text, searchRange.endLineNumber, 0, counter, result, limitResultCount);
		}

		return result;
E
Erich Gamma 已提交
954 955
	}

J
Johannes Rieken 已提交
956
	public findNextMatch(searchString: string, rawSearchStart: editorCommon.IPosition, isRegex: boolean, matchCase: boolean, wholeWord: boolean): Range {
957
		this._assertNotDisposed();
S
Sandeep Somavarapu 已提交
958 959
		let regex = TextModel.parseSearchRequest(searchString, isRegex, matchCase, wholeWord);
		if (!regex) {
E
Erich Gamma 已提交
960 961 962
			return null;
		}

963
		let searchStart = this.validatePosition(rawSearchStart);
S
Sandeep Somavarapu 已提交
964 965
		if (regex.multiline) {
			return this._doFindNextMatchMultiline(searchStart, regex);
966
		}
S
Sandeep Somavarapu 已提交
967
		return this._doFindNextMatchLineByLine(searchStart, regex);
968 969 970

	}

S
Sandeep Somavarapu 已提交
971 972 973 974 975
	private _doFindNextMatchMultiline(searchStart: Position, searchRegex: RegExp): Range {
		let searchTextStart: editorCommon.IPosition = { lineNumber: searchStart.lineNumber, column: 1 };
		let deltaOffset = this.getOffsetAt(searchTextStart);
		let text = this.getValueInRange(new Range(searchTextStart.lineNumber, searchTextStart.column, this.getLineCount(), this.getLineMaxColumn(this.getLineCount())));
		searchRegex.lastIndex = searchStart.column - 1;
976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992
		let m = searchRegex.exec(text);
		if (m) {
			let startOffset = deltaOffset + m.index;
			let endOffset = startOffset + m[0].length;
			let startPosition = this.getPositionAt(startOffset);
			let endPosition = this.getPositionAt(endOffset);
			return new Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column);
		}

		if (searchStart.lineNumber !== 1 || searchStart.column !== -1) {
			// Try again from the top
			return this._doFindNextMatchMultiline(new Position(1, 1), searchRegex);
		}

		return null;
	}

J
Johannes Rieken 已提交
993
	private _doFindNextMatchLineByLine(searchStart: Position, searchRegex: RegExp): Range {
994 995 996 997
		let lineCount = this.getLineCount();
		let startLineNumber = searchStart.lineNumber;
		let text: string;
		let r: Range;
E
Erich Gamma 已提交
998 999

		// Look in first line
S
Sandeep Somavarapu 已提交
1000 1001
		text = this._lines[startLineNumber - 1].text;
		r = this._findFirstMatchInLine(searchRegex, text, startLineNumber, searchStart.column);
E
Erich Gamma 已提交
1002 1003 1004 1005
		if (r) {
			return r;
		}

1006 1007
		for (let i = 1; i <= lineCount; i++) {
			let lineIndex = (startLineNumber + i - 1) % lineCount;
E
Erich Gamma 已提交
1008
			text = this._lines[lineIndex].text;
S
Sandeep Somavarapu 已提交
1009
			r = this._findFirstMatchInLine(searchRegex, text, lineIndex + 1, 1);
E
Erich Gamma 已提交
1010 1011 1012 1013 1014 1015 1016 1017
			if (r) {
				return r;
			}
		}

		return null;
	}

J
Johannes Rieken 已提交
1018
	public findPreviousMatch(searchString: string, rawSearchStart: editorCommon.IPosition, isRegex: boolean, matchCase: boolean, wholeWord: boolean): Range {
1019
		this._assertNotDisposed();
S
Sandeep Somavarapu 已提交
1020 1021
		let regex = TextModel.parseSearchRequest(searchString, isRegex, matchCase, wholeWord);
		if (!regex) {
1022 1023 1024
			return null;
		}

1025
		let searchStart = this.validatePosition(rawSearchStart);
S
Sandeep Somavarapu 已提交
1026 1027
		if (regex.multiline) {
			return this._doFindPreviousMatchMultiline(searchStart, regex);
1028
		}
S
Sandeep Somavarapu 已提交
1029
		return this._doFindPreviousMatchLineByLine(searchStart, regex);
1030 1031
	}

J
Johannes Rieken 已提交
1032
	private _doFindPreviousMatchMultiline(searchStart: Position, searchRegex: RegExp): Range {
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045
		let matches = this._doFindMatchesMultiline(new Range(1, 1, searchStart.lineNumber, searchStart.column), searchRegex, 10 * LIMIT_FIND_COUNT);
		if (matches.length > 0) {
			return matches[matches.length - 1];
		}

		if (searchStart.lineNumber !== this.getLineCount() || searchStart.column !== this.getLineMaxColumn(this.getLineCount())) {
			// Try again with all content
			return this._doFindPreviousMatchMultiline(new Position(this.getLineCount(), this.getLineMaxColumn(this.getLineCount())), searchRegex);
		}

		return null;
	}

J
Johannes Rieken 已提交
1046
	private _doFindPreviousMatchLineByLine(searchStart: Position, searchRegex: RegExp): Range {
1047 1048 1049 1050
		let lineCount = this.getLineCount();
		let startLineNumber = searchStart.lineNumber;
		let text: string;
		let r: Range;
1051 1052 1053

		// Look in first line
		text = this._lines[startLineNumber - 1].text.substring(0, searchStart.column - 1);
1054
		r = this._findLastMatchInLine(searchRegex, text, startLineNumber);
1055 1056 1057 1058
		if (r) {
			return r;
		}

1059
		for (var i = 1; i <= lineCount; i++) {
1060 1061
			var lineIndex = (lineCount + startLineNumber - i - 1) % lineCount;
			text = this._lines[lineIndex].text;
1062
			r = this._findLastMatchInLine(searchRegex, text, lineIndex + 1);
1063 1064 1065 1066 1067 1068 1069 1070
			if (r) {
				return r;
			}
		}

		return null;
	}

S
Sandeep Somavarapu 已提交
1071 1072 1073 1074 1075
	private _findFirstMatchInLine(searchRegex: RegExp, text: string, lineNumber: number, fromColumn: number): Range {
		// Set regex to search from column
		searchRegex.lastIndex = fromColumn - 1;
		var m: RegExpExecArray = searchRegex.exec(text);
		return m ? new Range(lineNumber, m.index + 1, lineNumber, m.index + 1 + m[0].length) : null;
E
Erich Gamma 已提交
1076 1077
	}

J
Johannes Rieken 已提交
1078
	private _findLastMatchInLine(searchRegex: RegExp, text: string, lineNumber: number): Range {
1079
		let bestResult: Range = null;
J
Johannes Rieken 已提交
1080
		let m: RegExpExecArray;
1081 1082 1083 1084 1085 1086
		while ((m = searchRegex.exec(text))) {
			let result = new Range(lineNumber, m.index + 1, lineNumber, m.index + 1 + m[0].length);
			if (result.equalsRange(bestResult)) {
				break;
			}
			bestResult = result;
1087 1088 1089 1090
			if (m.index + m[0].length === text.length) {
				// Reached the end of the line
				break;
			}
1091 1092 1093 1094
		}
		return bestResult;
	}

J
Johannes Rieken 已提交
1095 1096
	private _findMatchesInLine(searchRegex: RegExp, text: string, lineNumber: number, deltaOffset: number, counter: number, result: Range[], limitResultCount: number): number {
		var m: RegExpExecArray;
1097 1098
		// Reset regex to search from the beginning
		searchRegex.lastIndex = 0;
E
Erich Gamma 已提交
1099 1100 1101
		do {
			m = searchRegex.exec(text);
			if (m) {
1102 1103
				var range = new Range(lineNumber, m.index + 1 + deltaOffset, lineNumber, m.index + 1 + m[0].length + deltaOffset);
				if (range.equalsRange(result[result.length - 1])) {
1104
					// Exit early if the regex matches the same range
1105 1106 1107
					return counter;
				}
				result.push(range);
E
Erich Gamma 已提交
1108 1109 1110 1111
				counter++;
				if (counter >= limitResultCount) {
					return counter;
				}
1112 1113 1114 1115
				if (m.index + m[0].length === text.length) {
					// Reached the end of the line
					return counter;
				}
E
Erich Gamma 已提交
1116
			}
J
Johannes Rieken 已提交
1117
		} while (m);
E
Erich Gamma 已提交
1118 1119
		return counter;
	}
1120
}
1121 1122 1123

export class RawText {

J
Johannes Rieken 已提交
1124
	public static fromString(rawText: string, opts: editorCommon.ITextModelCreationOptions): editorCommon.IRawText {
1125 1126 1127
		return TextModel.toRawText(rawText, opts);
	}

J
Johannes Rieken 已提交
1128
	public static fromStringWithModelOptions(rawText: string, model: editorCommon.IModel): editorCommon.IRawText {
1129 1130 1131 1132
		let opts = model.getOptions();
		return TextModel.toRawText(rawText, {
			tabSize: opts.tabSize,
			insertSpaces: opts.insertSpaces,
1133
			trimAutoWhitespace: opts.trimAutoWhitespace,
1134 1135 1136 1137 1138
			detectIndentation: false,
			defaultEOL: opts.defaultEOL
		});
	}

A
aioute Gao 已提交
1139
}