src/vs/editor/common/services/textModelSync/textModelSync.impl.ts

427 LOC · 261 covered · 166 uncovered · 56 ranges · 37 concepts · 17 introducers · 16 tests

File neighbourhood

The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the filesrc/vs/editor/common/core/position.ts · 184 LOCcore/position.tssrc/vs/editor/common/diff/externalLinesDiffComputer.ts · 98 LOCdiff/externalLinesDiffCo…src/vs/editor/common/diff/linesDiffComputers.ts · 16 LOCdiff/linesDiffComputers.…src/vs/editor/common/languages/supports/inplaceReplaceSupport.ts · 99 LOCsupports/inplaceReplaceS…src/vs/editor/common/services/editorBaseApi.ts · 44 LOCservices/editorBaseApi.t…src/vs/editor/common/services/editorWebWorker.ts · 567 LOCservices/editorWebWorker…src/vs/editor/common/standalone/standaloneEnums.ts · 1017 LOCstandalone/standaloneEnu…editorWebWorker.test|title=EditorWebWorker [Bug] Getting Message "Overlapping ranges are not allowed" and nothing happens with Inline-Chat|occurrence=1 · 0 introduced LOCeditorWebWorker.test|tit…editorWebWorker.test|title=EditorWebWorker computeHumanReadableDiff 2|occurrence=1 · 0 introduced LOCeditorWebWorker.test|tit…editorWebWorker.test|title=EditorWebWorker computeHumanReadableDiff 4|occurrence=1 · 0 introduced LOCeditorWebWorker.test|tit…editorWebWorker.ts ×1 · 1 introduced LOCeditorWebWorker.ts ×1editorWebWorker.test|title=EditorWebWorker computeHumanReadableDiff 3|occurrence=1 · 0 introduced LOCeditorWebWorker.test|tit…textModelSync.impl.ts ×1 · 3 introduced LOCtextModelSync.impl.ts ×1editorWebWorker.ts ×3 · 14 introduced LOCeditorWebWorker.ts ×3editorWebWorker.test|title=EditorWebWorker MoreMinimal, issue #15385 newline changes and other|occurrence=1 · 0 introduced LOCeditorWebWorker.test|tit…editorWebWorker.test|title=EditorWebWorker MoreMinimal|occurrence=1 · 0 introduced LOCeditorWebWorker.test|tit…2|occurrence=1 · 0 introduced LOC2|occurrence=1editorWebWorker.ts ×2 · 23 introduced LOCeditorWebWorker.ts ×2editorWebWorker.ts ×1 · 2 introduced LOCeditorWebWorker.ts ×1editorWebWorker.ts ×1 · 4 introduced LOCeditorWebWorker.ts ×1editorWebWorker.ts ×11 · 67 introduced LOCeditorWebWorker.ts ×11editorWebWorker.ts ×1 · 3 introduced LOCeditorWebWorker.ts ×1editorWebWorker.ts ×8 · 29 introduced LOCeditorWebWorker.ts ×8textModelSync.impl.ts ×1 · 2 introduced LOCtextModelSync.impl.ts ×1textModelSync.impl.ts ×2 · 11 introduced LOCtextModelSync.impl.ts ×2textModelSync.impl.ts ×1 · 2 introduced LOCtextModelSync.impl.ts ×1textModelSync.impl.ts ×1 · 2 introduced LOCtextModelSync.impl.ts ×1editorWebWorker.ts ×3 · 20 introduced LOCeditorWebWorker.ts ×3editorWebWorker.test|title=EditorWebWorker ICommonModel#offsetAt|occurrence=1 · 0 introduced LOCeditorWebWorker.test|tit…textModelSync.impl.ts ×1 · 2 introduced LOCtextModelSync.impl.ts ×1editorWebWorker.test|title=EditorWebWorker ICommonModel#positionAt|occurrence=1 · 0 introduced LOCeditorWebWorker.test|tit…textModelSync.impl.ts ×1 · 13 introduced LOCtextModelSync.impl.ts ×1editorWebWorker.test|title=EditorWebWorker ICommonModel#getValueInRange, issue #17424|occurrence=1 · 0 introduced LOCeditorWebWorker.test|tit…prefixSumComputer.ts ×1 · 2 introduced LOCprefixSumComputer.ts ×1textModelSync.impl.ts ×1 · 8 introduced LOCtextModelSync.impl.ts ×1textModelSync.impl.ts ×1 · 2 introduced LOCtextModelSync.impl.ts ×1textModelSync.impl.ts ×1 · 4 introduced LOCtextModelSync.impl.ts ×1textModelSync.impl.ts ×4 · 13 introduced LOCtextModelSync.impl.ts ×4textModelSync.impl.ts ×1 · 4 introduced LOCtextModelSync.impl.ts ×1textModelSync.impl.ts ×1 · 2 introduced LOCtextModelSync.impl.ts ×1textModelSync.impl.ts ×7 · 22 introduced LOCtextModelSync.impl.ts ×7textModelSync.impl.ts ×3 · 41 introduced LOCtextModelSync.impl.ts ×3mirrorTextModel.ts ×1 · 10 introduced LOCmirrorTextModel.ts ×1textModelSync.impl.ts ×28 · 1416 introduced LOCtextModelSync.impl.ts ×2…editorWebWorker.test|title=EditorWebWorker ICommonModel#getValueInRange, issue #17424|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/services/editorWebWorker.test|title=EditorWebWorker ICommonModel#getValueInRange, issue #17424|occurrence=1editorWebWorker.test|tit…editorWebWorker.test|title=EditorWebWorker ICommonModel#offsetAt|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/services/editorWebWorker.test|title=EditorWebWorker ICommonModel#offsetAt|occurrence=1editorWebWorker.test|tit…editorWebWorker.test|title=EditorWebWorker ICommonModel#positionAt|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/services/editorWebWorker.test|title=EditorWebWorker ICommonModel#positionAt|occurrence=1editorWebWorker.test|tit…editorWebWorker.test|title=EditorWebWorker ICommonModel#validatePosition, issue #15882|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/services/editorWebWorker.test|title=EditorWebWorker ICommonModel#validatePosition, issue #15882|occurrence=1editorWebWorker.test|tit…2|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/services/editorWebWorker.test|title=EditorWebWorker MoreMinimal, issue #15385 newline changes and other 2/2|occurrence=12|occurrence=1editorWebWorker.test|title=EditorWebWorker MoreMinimal, issue #15385 newline changes and other|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/services/editorWebWorker.test|title=EditorWebWorker MoreMinimal, issue #15385 newline changes and other|occurrence=1editorWebWorker.test|tit…editorWebWorker.test|title=EditorWebWorker MoreMinimal, issue #15385 newline changes only|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/services/editorWebWorker.test|title=EditorWebWorker MoreMinimal, issue #15385 newline changes only|occurrence=1editorWebWorker.test|tit…editorWebWorker.test|title=EditorWebWorker MoreMinimal, merge adjacent edits|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/services/editorWebWorker.test|title=EditorWebWorker MoreMinimal, merge adjacent edits|occurrence=1editorWebWorker.test|tit…editorWebWorker.test|title=EditorWebWorker MoreMinimal|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/services/editorWebWorker.test|title=EditorWebWorker MoreMinimal|occurrence=1editorWebWorker.test|tit…editorWebWorker.test|title=EditorWebWorker [Bug] Getting Message "Overlapping ranges are not allowed" and nothing happens with Inline-Chat|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/services/editorWebWorker.test|title=EditorWebWorker [Bug] Getting Message "Overlapping ranges are not allowed" and nothing happens with Inline-Chat|occurrence=1editorWebWorker.test|tit…editorWebWorker.test|title=EditorWebWorker computeHumanReadableDiff 1|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/services/editorWebWorker.test|title=EditorWebWorker computeHumanReadableDiff 1|occurrence=1editorWebWorker.test|tit…editorWebWorker.test|title=EditorWebWorker computeHumanReadableDiff 2|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/services/editorWebWorker.test|title=EditorWebWorker computeHumanReadableDiff 2|occurrence=1editorWebWorker.test|tit…editorWebWorker.test|title=EditorWebWorker computeHumanReadableDiff 3|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/services/editorWebWorker.test|title=EditorWebWorker computeHumanReadableDiff 3|occurrence=1editorWebWorker.test|tit…editorWebWorker.test|title=EditorWebWorker computeHumanReadableDiff 4|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/services/editorWebWorker.test|title=EditorWebWorker computeHumanReadableDiff 4|occurrence=1editorWebWorker.test|tit…editorWebWorker.test|title=EditorWebWorker get words via iterator, issue #46930|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/services/editorWebWorker.test|title=EditorWebWorker get words via iterator, issue #46930|occurrence=1editorWebWorker.test|tit…editorWebWorker.test|title=EditorWebWorker textualSuggest, issue #17785|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/editor/test/common/services/editorWebWorker.test|title=EditorWebWorker textualSuggest, issue #17785|occurrence=1editorWebWorker.test|tit…Focused file · src/vs/editor/common/services/textModelSync/textModelSync.impl.ts · 427 LOCtextModelSync/textModelS…

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.

1 > /*--------------------------------------------------------------------------------------------- textModelSync.impl.ts ×28
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 >
6 > import { IntervalTimer } from '../../../../base/common/async.js';
7 > import { Disposable, DisposableStore, dispose, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
8 > import { URI } from '../../../../base/common/uri.js';
9 > import { IWebWorkerClient, IWebWorkerServer } from '../../../../base/common/worker/webWorker.js';
10 > import { IPosition, Position } from '../../core/position.js';
11 > import { IRange, Range } from '../../core/range.js';
12 > import { ensureValidWordDefinition, getWordAtText, IWordAtPosition } from '../../core/wordHelper.js';
13 > import { IDocumentColorComputerTarget } from '../../languages/defaultDocumentColorsComputer.js';
14 > import { ILinkComputerTarget } from '../../languages/linkComputer.js';
15 > import { MirrorTextModel as BaseMirrorModel, IModelChangedEvent } from '../../model/mirrorTextModel.js';
16 > import { IMirrorModel, IWordRange } from '../editorWebWorker.js';
17 > import { IModelService } from '../model.js';
18 > import { IRawModelData, IWorkerTextModelSyncChannelServer } from './textModelSync.protocol.js';
19 >
20 > /**
21 > * Stop syncing a model to the worker if it was not needed for 1 min.
22 > */
23 > export const STOP_SYNC_MODEL_DELTA_TIME_MS = 60 * 1000;
24 >
25 > export const WORKER_TEXT_MODEL_SYNC_CHANNEL = 'workerTextModelSync';
26 >
27 > export class WorkerTextModelSyncClient extends Disposable {
28 >
29 > public static create(workerClient: IWebWorkerClient<unknown>, modelService: IModelService): WorkerTextModelSyncClient {
30 > return new WorkerTextModelSyncClient(
31 > workerClient.getChannel<IWorkerTextModelSyncChannelServer>(WORKER_TEXT_MODEL_SYNC_CHANNEL),
32 > modelService
33 > );
34 > }
35 >
36 > private readonly _proxy: IWorkerTextModelSyncChannelServer;
37 > private readonly _modelService: IModelService;
38 > private _syncedModels: { [modelUrl: string]: IDisposable } = Object.create(null);
39 > private _syncedModelsLastUsedTime: { [modelUrl: string]: number } = Object.create(null);
40 >
41 > constructor(proxy: IWorkerTextModelSyncChannelServer, modelService: IModelService, keepIdleModels: boolean = false) {
42 super();
43 this._proxy = proxy;
44 this._modelService = modelService;
45
46 if (!keepIdleModels) {
47 const timer = new IntervalTimer();
48 timer.cancelAndSet(() => this._checkStopModelSync(), Math.round(STOP_SYNC_MODEL_DELTA_TIME_MS / 2));
49 this._register(timer);
50 }
51 }
53 > public override dispose(): void {
54 for (const modelUrl in this._syncedModels) {
55 dispose(this._syncedModels[modelUrl]);
56 }
57 this._syncedModels = Object.create(null);
58 this._syncedModelsLastUsedTime = Object.create(null);
59 super.dispose();
60 }
62 > public ensureSyncedResources(resources: URI[], forceLargeModels: boolean = false): void {
63 for (const resource of resources) {
64 const resourceStr = resource.toString();
65
66 if (!this._syncedModels[resourceStr]) {
67 this._beginModelSync(resource, forceLargeModels);
68 }
69 if (this._syncedModels[resourceStr]) {
70 this._syncedModelsLastUsedTime[resourceStr] = (new Date()).getTime();
71 }
72 }
73 }
75 > private _checkStopModelSync(): void {
76 const currentTime = (new Date()).getTime();
77
78 const toRemove: string[] = [];
79 for (const modelUrl in this._syncedModelsLastUsedTime) {
80 const elapsedTime = currentTime - this._syncedModelsLastUsedTime[modelUrl];
81 if (elapsedTime > STOP_SYNC_MODEL_DELTA_TIME_MS) {
82 toRemove.push(modelUrl);
83 }
84 }
85
86 for (const e of toRemove) {
87 this._stopModelSync(e);
88 }
89 }
91 > private _beginModelSync(resource: URI, forceLargeModels: boolean): void {
92 const model = this._modelService.getModel(resource);
93 if (!model) {
94 return;
95 }
96 if (!forceLargeModels && model.isTooLargeForSyncing()) {
97 return;
98 }
99
100 const modelUrl = resource.toString();
101
102 this._proxy.$acceptNewModel({
103 url: model.uri.toString(),
104 lines: model.getLinesContent(),
105 EOL: model.getEOL(),
106 versionId: model.getVersionId()
107 });
108
109 const toDispose = new DisposableStore();
110 toDispose.add(model.onDidChangeContent((e) => {
111 this._proxy.$acceptModelChanged(modelUrl.toString(), e);
112 }));
113 toDispose.add(model.onWillDispose(() => {
114 this._stopModelSync(modelUrl);
115 }));
116 toDispose.add(toDisposable(() => {
117 this._proxy.$acceptRemovedModel(modelUrl);
118 }));
119
120 this._syncedModels[modelUrl] = toDispose;
121 }
123 > private _stopModelSync(modelUrl: string): void {
124 const toDispose = this._syncedModels[modelUrl];
125 delete this._syncedModels[modelUrl];
126 delete this._syncedModelsLastUsedTime[modelUrl];
127 dispose(toDispose);
128 }
130 >
131 > export class WorkerTextModelSyncServer implements IWorkerTextModelSyncChannelServer {
132 >
133 > private readonly _models: { [uri: string]: MirrorModel };
134 >
135 > constructor() {
136 > this._models = Object.create(null);
137 > }
138 >
139 > public bindToServer(workerServer: IWebWorkerServer): void {
140 workerServer.setChannel(WORKER_TEXT_MODEL_SYNC_CHANNEL, this);
141 }
143 > public getModel(uri: string): ICommonModel | undefined {
144 > return this._models[uri];
145 > }
146 >
147 > public getModels(): ICommonModel[] {
148 const all: MirrorModel[] = [];
149 Object.keys(this._models).forEach((key) => all.push(this._models[key]));
150 return all;
151 }
153 > $acceptNewModel(data: IRawModelData): void {
154 > this._models[data.url] = new MirrorModel(URI.parse(data.url), data.lines, data.EOL, data.versionId);
155 > }
156 >
157 > $acceptModelChanged(uri: string, e: IModelChangedEvent): void {
158 if (!this._models[uri]) {
159 return;
160 }
161 const model = this._models[uri];
162 model.onEvents(e);
163 }
165 > $acceptRemovedModel(uri: string): void {
166 if (!this._models[uri]) {
167 return;
168 }
169 delete this._models[uri];
170 }
172 >
173 > export class MirrorModel extends BaseMirrorModel implements ICommonModel {
174 >
175 > public get uri(): URI {
176 > return this._uri; textModelSync.impl.ts ×1
177 > }
179 > public get eol(): string {
180 > return this._eol; textModelSync.impl.ts ×1
181 > }
183 > public getValue(): string {
184 > return this.getText(); editorWebWorker.ts ×11
185 > }
187 > public findMatches(regex: RegExp): RegExpMatchArray[] {
188 const matches = [];
189 for (let i = 0; i < this._lines.length; i++) {
190 const line = this._lines[i];
191 const offsetToAdd = this.offsetAt(new Position(i + 1, 1));
192 const iteratorOverMatches = line.matchAll(regex);
193 for (const match of iteratorOverMatches) {
194 if (match.index || match.index === 0) {
195 match.index = match.index + offsetToAdd;
196 }
197 matches.push(match);
198 }
199 }
200 return matches;
201 }
203 > public getLinesContent(): string[] {
204 return this._lines.slice(0);
205 }
207 > public getLineCount(): number {
208 return this._lines.length;
209 }
211 > public getLineContent(lineNumber: number): string {
212 return this._lines[lineNumber - 1];
213 }
215 > public getWordAtPosition(position: IPosition, wordDefinition: RegExp): Range | null {
216
217 const wordAtText = getWordAtText(
218 position.column,
219 ensureValidWordDefinition(wordDefinition),
220 this._lines[position.lineNumber - 1],
221 0
222 );
223
224 if (wordAtText) {
225 return new Range(position.lineNumber, wordAtText.startColumn, position.lineNumber, wordAtText.endColumn);
226 }
227
228 return null;
229 }
231 > public getWordUntilPosition(position: IPosition, wordDefinition: RegExp): IWordAtPosition {
232 const wordAtPosition = this.getWordAtPosition(position, wordDefinition);
233 if (!wordAtPosition) {
234 return {
235 word: '',
236 startColumn: position.column,
237 endColumn: position.column
238 };
239 }
240 return {
241 word: this._lines[position.lineNumber - 1].substring(wordAtPosition.startColumn - 1, position.column - 1),
242 startColumn: wordAtPosition.startColumn,
243 endColumn: position.column
244 };
245 }
247 >
248 > public words(wordDefinition: RegExp): Iterable<string> {
250 > const lines = this._lines;
251 > const wordenize = this._wordenize.bind(this);
252 >
253 > let lineNumber = 0;
254 > let lineText = '';
255 > let wordRangesIdx = 0;
256 > let wordRanges: IWordRange[] = [];
257 >
258 > return {
259 > *[Symbol.iterator]() {
260 > while (true) {
261 > if (wordRangesIdx < wordRanges.length) {
262 > const value = lineText.substring(wordRanges[wordRangesIdx].start, wordRanges[wordRangesIdx].end);
263 > wordRangesIdx += 1;
264 > yield value;
265 > } else {
266 > if (lineNumber < lines.length) {
267 > lineText = lines[lineNumber];
268 > wordRanges = wordenize(lineText, wordDefinition);
269 > wordRangesIdx = 0;
270 > lineNumber += 1;
271 > } else {
272 > break;
273 > }
274 > }
275 > }
276 > }
277 > };
278 > }
280 > public getLineWords(lineNumber: number, wordDefinition: RegExp): IWordAtPosition[] {
281 const content = this._lines[lineNumber - 1];
282 const ranges = this._wordenize(content, wordDefinition);
283 const words: IWordAtPosition[] = [];
284 for (const range of ranges) {
285 words.push({
286 word: content.substring(range.start, range.end),
287 startColumn: range.start + 1,
288 endColumn: range.end + 1
289 });
290 }
291 return words;
292 }
294 > private _wordenize(content: string, wordDefinition: RegExp): IWordRange[] {
295 > const result: IWordRange[] = []; textModelSync.impl.ts ×3
296 > let match: RegExpExecArray | null;
297 >
298 > wordDefinition.lastIndex = 0; // reset lastIndex just to be sure
299 >
300 > while (match = wordDefinition.exec(content)) {
301 > if (match[0].length === 0) {
302 // it did match the empty string
303 break;
304 }
305 > result.push({ start: match.index, end: match.index + match[0].length }); textModelSync.impl.ts ×3
306 > }
307 > return result;
308 > }
310 > public getValueInRange(range: IRange): string {
311 > range = this._validateRange(range); textModelSync.impl.ts ×4
312 >
313 > if (range.startLineNumber === range.endLineNumber) {
314 > return this._lines[range.startLineNumber - 1].substring(range.startColumn - 1, range.endColumn - 1); textModelSync.impl.ts ×1
315 > }
317 > const lineEnding = this._eol;
318 > const startLineIndex = range.startLineNumber - 1;
319 > const endLineIndex = range.endLineNumber - 1;
320 > const resultLines: string[] = [];
321 >
322 > resultLines.push(this._lines[startLineIndex].substring(range.startColumn - 1));
323 > for (let i = startLineIndex + 1; i < endLineIndex; i++) {
324 > resultLines.push(this._lines[i]); textModelSync.impl.ts ×1
325 > }
326 > resultLines.push(this._lines[endLineIndex].substring(0, range.endColumn - 1)); textModelSync.impl.ts ×2
327 >
328 > return resultLines.join(lineEnding);
331 > public offsetAt(position: IPosition): number {
332 > position = this._validatePosition(position); textModelSync.impl.ts ×1
333 > this._ensureLineStarts();
334 > return this._lineStarts!.getPrefixSum(position.lineNumber - 2) + (position.column - 1);
335 > }
337 > public positionAt(offset: number): IPosition {
338 > offset = Math.floor(offset); textModelSync.impl.ts ×1
339 > offset = Math.max(0, offset);
340 >
341 > this._ensureLineStarts();
342 > const out = this._lineStarts!.getIndexOf(offset);
343 > const lineLength = this._lines[out.index].length;
344 >
345 > // Ensure we return a valid position
346 > return {
347 > lineNumber: 1 + out.index,
348 > column: 1 + Math.min(out.remainder, lineLength)
349 > };
350 > }
352 > private _validateRange(range: IRange): IRange {
354 > const start = this._validatePosition({ lineNumber: range.startLineNumber, column: range.startColumn });
355 > const end = this._validatePosition({ lineNumber: range.endLineNumber, column: range.endColumn });
356 >
357 > if (start.lineNumber !== range.startLineNumber
358 > || start.column !== range.startColumn
359 > || end.lineNumber !== range.endLineNumber
360 > || end.column !== range.endColumn) {
362 > return {
363 > startLineNumber: start.lineNumber,
364 > startColumn: start.column,
365 > endLineNumber: end.lineNumber,
366 > endColumn: end.column
367 > };
368 > }
370 > return range;
373 > private _validatePosition(position: IPosition): IPosition {
374 > if (!Position.isIPosition(position)) { textModelSync.impl.ts ×7
375 throw new Error('bad position');
376 }
377 > let { lineNumber, column } = position; textModelSync.impl.ts ×7
378 > let hasChanged = false;
379 >
380 > if (lineNumber < 1) {
381 lineNumber = 1;
382 column = 1;
383 hasChanged = true;
384
385 > } else if (lineNumber > this._lines.length) { textModelSync.impl.ts ×7
386 > lineNumber = this._lines.length; textModelSync.impl.ts ×1
387 > column = this._lines[lineNumber - 1].length + 1;
388 > hasChanged = true;
389 >
390 > } else { textModelSync.impl.ts ×7
391 > const maxCharacter = this._lines[lineNumber - 1].length + 1;
392 > if (column < 1) {
393 column = 1;
394 hasChanged = true;
395 }
396 > else if (column > maxCharacter) { textModelSync.impl.ts ×7
397 > column = maxCharacter; textModelSync.impl.ts ×1
398 > hasChanged = true;
399 > }
401 >
402 > if (!hasChanged) {
403 > return position;
404 > } else {
405 > return { lineNumber, column }; textModelSync.impl.ts ×1
406 > }
409 >
410 > export interface ICommonModel extends ILinkComputerTarget, IDocumentColorComputerTarget, IMirrorModel {
411 > uri: URI;
412 > version: number;
413 > eol: string;
414 > getValue(): string;
415 >
416 > getLinesContent(): string[];
417 > getLineCount(): number;
418 > getLineContent(lineNumber: number): string;
419 > getLineWords(lineNumber: number, wordDefinition: RegExp): IWordAtPosition[];
420 > words(wordDefinition: RegExp): Iterable<string>;
421 > getWordUntilPosition(position: IPosition, wordDefinition: RegExp): IWordAtPosition;
422 > getValueInRange(range: IRange): string;
423 > getWordAtPosition(position: IPosition, wordDefinition: RegExp): Range | null;
424 > offsetAt(position: IPosition): number;
425 > positionAt(offset: number): IPosition;
426 > findMatches(regex: RegExp): RegExpMatchArray[];
427 > }