2 if (typeof module === "object" && typeof module.exports === "object") {
3 var v = factory(require, exports);
4 if (v !== undefined) module.exports = v;
6 else if (typeof define === "function" && define.amd) {
7 define(["require", "exports"], factory);
9 })(function (require, exports) {
10 /* --------------------------------------------------------------------------------------------
11 * Copyright (c) Microsoft Corporation. All rights reserved.
12 * Licensed under the MIT License. See License.txt in the project root for license information.
13 * ------------------------------------------------------------------------------------------ */
15 Object.defineProperty(exports, "__esModule", { value: true });
16 var FullTextDocument = /** @class */ (function () {
17 function FullTextDocument(uri, languageId, version, content) {
19 this._languageId = languageId;
20 this._version = version;
21 this._content = content;
22 this._lineOffsets = undefined;
24 Object.defineProperty(FullTextDocument.prototype, "uri", {
31 Object.defineProperty(FullTextDocument.prototype, "languageId", {
33 return this._languageId;
38 Object.defineProperty(FullTextDocument.prototype, "version", {
45 FullTextDocument.prototype.getText = function (range) {
47 var start = this.offsetAt(range.start);
48 var end = this.offsetAt(range.end);
49 return this._content.substring(start, end);
53 FullTextDocument.prototype.update = function (changes, version) {
54 for (var _i = 0, changes_1 = changes; _i < changes_1.length; _i++) {
55 var change = changes_1[_i];
56 if (FullTextDocument.isIncremental(change)) {
57 // makes sure start is before end
58 var range = getWellformedRange(change.range);
60 var startOffset = this.offsetAt(range.start);
61 var endOffset = this.offsetAt(range.end);
62 this._content = this._content.substring(0, startOffset) + change.text + this._content.substring(endOffset, this._content.length);
64 var startLine = Math.max(range.start.line, 0);
65 var endLine = Math.max(range.end.line, 0);
66 var lineOffsets = this._lineOffsets;
67 var addedLineOffsets = computeLineOffsets(change.text, false, startOffset);
68 if (endLine - startLine === addedLineOffsets.length) {
69 for (var i = 0, len = addedLineOffsets.length; i < len; i++) {
70 lineOffsets[i + startLine + 1] = addedLineOffsets[i];
74 if (addedLineOffsets.length < 10000) {
75 lineOffsets.splice.apply(lineOffsets, [startLine + 1, endLine - startLine].concat(addedLineOffsets));
77 else { // avoid too many arguments for splice
78 this._lineOffsets = lineOffsets = lineOffsets.slice(0, startLine + 1).concat(addedLineOffsets, lineOffsets.slice(endLine + 1));
81 var diff = change.text.length - (endOffset - startOffset);
83 for (var i = startLine + 1 + addedLineOffsets.length, len = lineOffsets.length; i < len; i++) {
84 lineOffsets[i] = lineOffsets[i] + diff;
88 else if (FullTextDocument.isFull(change)) {
89 this._content = change.text;
90 this._lineOffsets = undefined;
93 throw new Error('Unknown change event received');
96 this._version = version;
98 FullTextDocument.prototype.getLineOffsets = function () {
99 if (this._lineOffsets === undefined) {
100 this._lineOffsets = computeLineOffsets(this._content, true);
102 return this._lineOffsets;
104 FullTextDocument.prototype.positionAt = function (offset) {
105 offset = Math.max(Math.min(offset, this._content.length), 0);
106 var lineOffsets = this.getLineOffsets();
107 var low = 0, high = lineOffsets.length;
109 return { line: 0, character: offset };
112 var mid = Math.floor((low + high) / 2);
113 if (lineOffsets[mid] > offset) {
120 // low is the least x for which the line offset is larger than the current offset
121 // or array.length if no line offset is larger than the current offset
123 return { line: line, character: offset - lineOffsets[line] };
125 FullTextDocument.prototype.offsetAt = function (position) {
126 var lineOffsets = this.getLineOffsets();
127 if (position.line >= lineOffsets.length) {
128 return this._content.length;
130 else if (position.line < 0) {
133 var lineOffset = lineOffsets[position.line];
134 var nextLineOffset = (position.line + 1 < lineOffsets.length) ? lineOffsets[position.line + 1] : this._content.length;
135 return Math.max(Math.min(lineOffset + position.character, nextLineOffset), lineOffset);
137 Object.defineProperty(FullTextDocument.prototype, "lineCount", {
139 return this.getLineOffsets().length;
144 FullTextDocument.isIncremental = function (event) {
145 var candidate = event;
146 return candidate !== undefined && candidate !== null &&
147 typeof candidate.text === 'string' && candidate.range !== undefined &&
148 (candidate.rangeLength === undefined || typeof candidate.rangeLength === 'number');
150 FullTextDocument.isFull = function (event) {
151 var candidate = event;
152 return candidate !== undefined && candidate !== null &&
153 typeof candidate.text === 'string' && candidate.range === undefined && candidate.rangeLength === undefined;
155 return FullTextDocument;
158 (function (TextDocument) {
160 * Creates a new text document.
162 * @param uri The document's uri.
163 * @param languageId The document's language Id.
164 * @param version The document's initial version number.
165 * @param content The document's content.
167 function create(uri, languageId, version, content) {
168 return new FullTextDocument(uri, languageId, version, content);
170 TextDocument.create = create;
172 * Updates a TextDocument by modifing its content.
174 * @param document the document to update. Only documents created by TextDocument.create are valid inputs.
175 * @param changes the changes to apply to the document.
176 * @returns The updated TextDocument. Note: That's the same document instance passed in as first parameter.
179 function update(document, changes, version) {
180 if (document instanceof FullTextDocument) {
181 document.update(changes, version);
185 throw new Error('TextDocument.update: document must be created by TextDocument.create');
188 TextDocument.update = update;
189 function applyEdits(document, edits) {
190 var text = document.getText();
191 var sortedEdits = mergeSort(edits.map(getWellformedEdit), function (a, b) {
192 var diff = a.range.start.line - b.range.start.line;
194 return a.range.start.character - b.range.start.character;
198 var lastModifiedOffset = 0;
200 for (var _i = 0, sortedEdits_1 = sortedEdits; _i < sortedEdits_1.length; _i++) {
201 var e = sortedEdits_1[_i];
202 var startOffset = document.offsetAt(e.range.start);
203 if (startOffset < lastModifiedOffset) {
204 throw new Error('Overlapping edit');
206 else if (startOffset > lastModifiedOffset) {
207 spans.push(text.substring(lastModifiedOffset, startOffset));
209 if (e.newText.length) {
210 spans.push(e.newText);
212 lastModifiedOffset = document.offsetAt(e.range.end);
214 spans.push(text.substr(lastModifiedOffset));
215 return spans.join('');
217 TextDocument.applyEdits = applyEdits;
218 })(TextDocument = exports.TextDocument || (exports.TextDocument = {}));
219 function mergeSort(data, compare) {
220 if (data.length <= 1) {
224 var p = (data.length / 2) | 0;
225 var left = data.slice(0, p);
226 var right = data.slice(p);
227 mergeSort(left, compare);
228 mergeSort(right, compare);
232 while (leftIdx < left.length && rightIdx < right.length) {
233 var ret = compare(left[leftIdx], right[rightIdx]);
235 // smaller_equal -> take left to preserve order
236 data[i++] = left[leftIdx++];
239 // greater -> take right
240 data[i++] = right[rightIdx++];
243 while (leftIdx < left.length) {
244 data[i++] = left[leftIdx++];
246 while (rightIdx < right.length) {
247 data[i++] = right[rightIdx++];
251 function computeLineOffsets(text, isAtLineStart, textOffset) {
252 if (textOffset === void 0) { textOffset = 0; }
253 var result = isAtLineStart ? [textOffset] : [];
254 for (var i = 0; i < text.length; i++) {
255 var ch = text.charCodeAt(i);
256 if (ch === 13 /* CarriageReturn */ || ch === 10 /* LineFeed */) {
257 if (ch === 13 /* CarriageReturn */ && i + 1 < text.length && text.charCodeAt(i + 1) === 10 /* LineFeed */) {
260 result.push(textOffset + i + 1);
265 function getWellformedRange(range) {
266 var start = range.start;
268 if (start.line > end.line || (start.line === end.line && start.character > end.character)) {
269 return { start: end, end: start };
273 function getWellformedEdit(textEdit) {
274 var range = getWellformedRange(textEdit.range);
275 if (range !== textEdit.range) {
276 return { newText: textEdit.newText, range: range };