massive update, probably broken
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-json / node_modules / vscode-languageserver-textdocument / lib / esm / main.js
1 /* --------------------------------------------------------------------------------------------
2  * Copyright (c) Microsoft Corporation. All rights reserved.
3  * Licensed under the MIT License. See License.txt in the project root for license information.
4  * ------------------------------------------------------------------------------------------ */
5 'use strict';
6 class FullTextDocument {
7     constructor(uri, languageId, version, content) {
8         this._uri = uri;
9         this._languageId = languageId;
10         this._version = version;
11         this._content = content;
12         this._lineOffsets = undefined;
13     }
14     get uri() {
15         return this._uri;
16     }
17     get languageId() {
18         return this._languageId;
19     }
20     get version() {
21         return this._version;
22     }
23     getText(range) {
24         if (range) {
25             const start = this.offsetAt(range.start);
26             const end = this.offsetAt(range.end);
27             return this._content.substring(start, end);
28         }
29         return this._content;
30     }
31     update(changes, version) {
32         for (let change of changes) {
33             if (FullTextDocument.isIncremental(change)) {
34                 // makes sure start is before end
35                 const range = getWellformedRange(change.range);
36                 // update content
37                 const startOffset = this.offsetAt(range.start);
38                 const endOffset = this.offsetAt(range.end);
39                 this._content = this._content.substring(0, startOffset) + change.text + this._content.substring(endOffset, this._content.length);
40                 // update the offsets
41                 const startLine = Math.max(range.start.line, 0);
42                 const endLine = Math.max(range.end.line, 0);
43                 let lineOffsets = this._lineOffsets;
44                 const addedLineOffsets = computeLineOffsets(change.text, false, startOffset);
45                 if (endLine - startLine === addedLineOffsets.length) {
46                     for (let i = 0, len = addedLineOffsets.length; i < len; i++) {
47                         lineOffsets[i + startLine + 1] = addedLineOffsets[i];
48                     }
49                 }
50                 else {
51                     if (addedLineOffsets.length < 10000) {
52                         lineOffsets.splice(startLine + 1, endLine - startLine, ...addedLineOffsets);
53                     }
54                     else { // avoid too many arguments for splice
55                         this._lineOffsets = lineOffsets = lineOffsets.slice(0, startLine + 1).concat(addedLineOffsets, lineOffsets.slice(endLine + 1));
56                     }
57                 }
58                 const diff = change.text.length - (endOffset - startOffset);
59                 if (diff !== 0) {
60                     for (let i = startLine + 1 + addedLineOffsets.length, len = lineOffsets.length; i < len; i++) {
61                         lineOffsets[i] = lineOffsets[i] + diff;
62                     }
63                 }
64             }
65             else if (FullTextDocument.isFull(change)) {
66                 this._content = change.text;
67                 this._lineOffsets = undefined;
68             }
69             else {
70                 throw new Error('Unknown change event received');
71             }
72         }
73         this._version = version;
74     }
75     getLineOffsets() {
76         if (this._lineOffsets === undefined) {
77             this._lineOffsets = computeLineOffsets(this._content, true);
78         }
79         return this._lineOffsets;
80     }
81     positionAt(offset) {
82         offset = Math.max(Math.min(offset, this._content.length), 0);
83         let lineOffsets = this.getLineOffsets();
84         let low = 0, high = lineOffsets.length;
85         if (high === 0) {
86             return { line: 0, character: offset };
87         }
88         while (low < high) {
89             let mid = Math.floor((low + high) / 2);
90             if (lineOffsets[mid] > offset) {
91                 high = mid;
92             }
93             else {
94                 low = mid + 1;
95             }
96         }
97         // low is the least x for which the line offset is larger than the current offset
98         // or array.length if no line offset is larger than the current offset
99         let line = low - 1;
100         return { line, character: offset - lineOffsets[line] };
101     }
102     offsetAt(position) {
103         let lineOffsets = this.getLineOffsets();
104         if (position.line >= lineOffsets.length) {
105             return this._content.length;
106         }
107         else if (position.line < 0) {
108             return 0;
109         }
110         let lineOffset = lineOffsets[position.line];
111         let nextLineOffset = (position.line + 1 < lineOffsets.length) ? lineOffsets[position.line + 1] : this._content.length;
112         return Math.max(Math.min(lineOffset + position.character, nextLineOffset), lineOffset);
113     }
114     get lineCount() {
115         return this.getLineOffsets().length;
116     }
117     static isIncremental(event) {
118         let candidate = event;
119         return candidate !== undefined && candidate !== null &&
120             typeof candidate.text === 'string' && candidate.range !== undefined &&
121             (candidate.rangeLength === undefined || typeof candidate.rangeLength === 'number');
122     }
123     static isFull(event) {
124         let candidate = event;
125         return candidate !== undefined && candidate !== null &&
126             typeof candidate.text === 'string' && candidate.range === undefined && candidate.rangeLength === undefined;
127     }
128 }
129 export var TextDocument;
130 (function (TextDocument) {
131     /**
132      * Creates a new text document.
133      *
134      * @param uri The document's uri.
135      * @param languageId  The document's language Id.
136      * @param version The document's initial version number.
137      * @param content The document's content.
138      */
139     function create(uri, languageId, version, content) {
140         return new FullTextDocument(uri, languageId, version, content);
141     }
142     TextDocument.create = create;
143     /**
144      * Updates a TextDocument by modifying its content.
145      *
146      * @param document the document to update. Only documents created by TextDocument.create are valid inputs.
147      * @param changes the changes to apply to the document.
148      * @param version the changes version for the document.
149      * @returns The updated TextDocument. Note: That's the same document instance passed in as first parameter.
150      *
151      */
152     function update(document, changes, version) {
153         if (document instanceof FullTextDocument) {
154             document.update(changes, version);
155             return document;
156         }
157         else {
158             throw new Error('TextDocument.update: document must be created by TextDocument.create');
159         }
160     }
161     TextDocument.update = update;
162     function applyEdits(document, edits) {
163         let text = document.getText();
164         let sortedEdits = mergeSort(edits.map(getWellformedEdit), (a, b) => {
165             let diff = a.range.start.line - b.range.start.line;
166             if (diff === 0) {
167                 return a.range.start.character - b.range.start.character;
168             }
169             return diff;
170         });
171         let lastModifiedOffset = 0;
172         const spans = [];
173         for (const e of sortedEdits) {
174             let startOffset = document.offsetAt(e.range.start);
175             if (startOffset < lastModifiedOffset) {
176                 throw new Error('Overlapping edit');
177             }
178             else if (startOffset > lastModifiedOffset) {
179                 spans.push(text.substring(lastModifiedOffset, startOffset));
180             }
181             if (e.newText.length) {
182                 spans.push(e.newText);
183             }
184             lastModifiedOffset = document.offsetAt(e.range.end);
185         }
186         spans.push(text.substr(lastModifiedOffset));
187         return spans.join('');
188     }
189     TextDocument.applyEdits = applyEdits;
190 })(TextDocument || (TextDocument = {}));
191 function mergeSort(data, compare) {
192     if (data.length <= 1) {
193         // sorted
194         return data;
195     }
196     const p = (data.length / 2) | 0;
197     const left = data.slice(0, p);
198     const right = data.slice(p);
199     mergeSort(left, compare);
200     mergeSort(right, compare);
201     let leftIdx = 0;
202     let rightIdx = 0;
203     let i = 0;
204     while (leftIdx < left.length && rightIdx < right.length) {
205         let ret = compare(left[leftIdx], right[rightIdx]);
206         if (ret <= 0) {
207             // smaller_equal -> take left to preserve order
208             data[i++] = left[leftIdx++];
209         }
210         else {
211             // greater -> take right
212             data[i++] = right[rightIdx++];
213         }
214     }
215     while (leftIdx < left.length) {
216         data[i++] = left[leftIdx++];
217     }
218     while (rightIdx < right.length) {
219         data[i++] = right[rightIdx++];
220     }
221     return data;
222 }
223 function computeLineOffsets(text, isAtLineStart, textOffset = 0) {
224     const result = isAtLineStart ? [textOffset] : [];
225     for (let i = 0; i < text.length; i++) {
226         let ch = text.charCodeAt(i);
227         if (ch === 13 /* CarriageReturn */ || ch === 10 /* LineFeed */) {
228             if (ch === 13 /* CarriageReturn */ && i + 1 < text.length && text.charCodeAt(i + 1) === 10 /* LineFeed */) {
229                 i++;
230             }
231             result.push(textOffset + i + 1);
232         }
233     }
234     return result;
235 }
236 function getWellformedRange(range) {
237     const start = range.start;
238     const end = range.end;
239     if (start.line > end.line || (start.line === end.line && start.character > end.character)) {
240         return { start: end, end: start };
241     }
242     return range;
243 }
244 function getWellformedEdit(textEdit) {
245     const range = getWellformedRange(textEdit.range);
246     if (range !== textEdit.range) {
247         return { newText: textEdit.newText, range };
248     }
249     return textEdit;
250 }