src/vs/editor/common/textModelEvents.ts

594 LOC · 471 covered · 123 uncovered · 34 ranges · 1751 concepts · 9 introducers · 879 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.

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 > /*--------------------------------------------------------------------------------------------- textModelEvents.ts ×25
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 { IPosition } from './core/position.js';
7 > import { IRange, Range } from './core/range.js';
8 > import { Selection } from './core/selection.js';
9 > import { IModelDecoration, InjectedTextOptions } from './model.js';
10 > import { IModelContentChange } from './model/mirrorTextModel.js';
11 > import { AnnotationsUpdate } from './model/tokens/annotations.js';
12 > import { TextModelEditSource } from './textModelEditSource.js';
13 >
14 > /**
15 > * An event describing that the current language associated with a model has changed.
16 > */
17 > export interface IModelLanguageChangedEvent {
18 > /**
19 > * Previous language
20 > */
21 > readonly oldLanguage: string;
22 > /**
23 > * New language
24 > */
25 > readonly newLanguage: string;
26 >
27 > /**
28 > * Source of the call that caused the event.
29 > */
30 > readonly source: string;
31 > }
32 >
33 > /**
34 > * An event describing that the language configuration associated with a model has changed.
35 > */
36 > export interface IModelLanguageConfigurationChangedEvent {
37 > }
38 >
39 > /**
40 > * An event describing a change in the text of a model.
41 > */
42 > export interface IModelContentChangedEvent {
43 > /**
44 > * The changes are ordered from the end of the document to the beginning, so they should be safe to apply in sequence.
45 > */
46 > readonly changes: IModelContentChange[];
47 > /**
48 > * The (new) end-of-line character.
49 > */
50 > readonly eol: string;
51 > /**
52 > * The new version id the model has transitioned to.
53 > */
54 > readonly versionId: number;
55 > /**
56 > * Flag that indicates that this event was generated while undoing.
57 > */
58 > readonly isUndoing: boolean;
59 > /**
60 > * Flag that indicates that this event was generated while redoing.
61 > */
62 > readonly isRedoing: boolean;
63 > /**
64 > * Flag that indicates that all decorations were lost with this edit.
65 > * The model has been reset to a new value.
66 > */
67 > readonly isFlush: boolean;
68 >
69 > /**
70 > * Flag that indicates that this event describes an eol change.
71 > */
72 > readonly isEolChange: boolean;
73 >
74 > /**
75 > * Detailed reason information for the change
76 > * @internal
77 > */
78 > readonly detailedReasons: TextModelEditSource[];
79 >
80 > /**
81 > * The sum of these lengths equals changes.length.
82 > * The length of this array must equal the length of detailedReasons.
83 > */
84 > readonly detailedReasonsChangeLengths: number[];
85 > }
86 >
87 > export interface ISerializedModelContentChangedEvent {
88 > /**
89 > * The changes are ordered from the end of the document to the beginning, so they should be safe to apply in sequence.
90 > */
91 > readonly changes: IModelContentChange[];
92 > /**
93 > * The (new) end-of-line character.
94 > */
95 > readonly eol: string;
96 > /**
97 > * The new version id the model has transitioned to.
98 > */
99 > readonly versionId: number;
100 > /**
101 > * Flag that indicates that this event was generated while undoing.
102 > */
103 > readonly isUndoing: boolean;
104 > /**
105 > * Flag that indicates that this event was generated while redoing.
106 > */
107 > readonly isRedoing: boolean;
108 > /**
109 > * Flag that indicates that all decorations were lost with this edit.
110 > * The model has been reset to a new value.
111 > */
112 > readonly isFlush: boolean;
113 >
114 > /**
115 > * Flag that indicates that this event describes an eol change.
116 > */
117 > readonly isEolChange: boolean;
118 >
119 > /**
120 > * Detailed reason information for the change
121 > * @internal
122 > */
123 > readonly detailedReason: Record<string, unknown> | undefined;
124 > }
125 >
126 > /**
127 > * An event describing that model decorations have changed.
128 > */
129 > export interface IModelDecorationsChangedEvent {
130 > readonly affectsMinimap: boolean;
131 > readonly affectsOverviewRuler: boolean;
132 > readonly affectsGlyphMargin: boolean;
133 > readonly affectsLineNumber: boolean;
134 > }
135 >
136 > /**
137 > * An event describing that some ranges of lines have been tokenized (their tokens have changed).
138 > * @internal
139 > */
140 > export interface IModelTokensChangedEvent {
141 > readonly semanticTokensApplied: boolean;
142 > readonly ranges: {
143 > /**
144 > * The start of the range (inclusive)
145 > */
146 > readonly fromLineNumber: number;
147 > /**
148 > * The end of the range (inclusive)
149 > */
150 > readonly toLineNumber: number;
151 > }[];
152 > }
153 >
154 > /**
155 > * @internal
156 > */
157 > export interface IFontTokenOption {
158 > /**
159 > * Font family of the token.
160 > */
161 > readonly fontFamily?: string;
162 > /**
163 > * Font size of the token.
164 > */
165 > readonly fontSizeMultiplier?: number;
166 > /**
167 > * Line height of the token.
168 > */
169 > readonly lineHeightMultiplier?: number;
170 > }
171 >
172 > /**
173 > * An event describing a token font change event
174 > * @internal
175 > */
176 > export interface IModelFontTokensChangedEvent {
177 > changes: FontTokensUpdate;
178 > }
179 >
180 > /**
181 > * @internal
182 > */
183 > export type FontTokensUpdate = AnnotationsUpdate<IFontTokenOption | undefined>;
184 >
185 > /**
186 > * @internal
187 > */
188 > export function serializeFontTokenOptions(): (options: IFontTokenOption) => IFontTokenOption {
189 return (annotation: IFontTokenOption) => {
190 return {
191 fontFamily: annotation.fontFamily ?? '',
192 fontSizeMultiplier: annotation.fontSizeMultiplier ?? 0,
193 lineHeightMultiplier: annotation.lineHeightMultiplier ?? 0
194 };
195 };
196 }
198 > /**
199 > * @internal
200 > */
201 > export function deserializeFontTokenOptions(): (options: IFontTokenOption) => IFontTokenOption {
202 return (annotation: IFontTokenOption) => {
203 return {
204 fontFamily: annotation.fontFamily ? String(annotation.fontFamily) : undefined,
205 fontSizeMultiplier: annotation.fontSizeMultiplier ? Number(annotation.fontSizeMultiplier) : undefined,
206 lineHeightMultiplier: annotation.lineHeightMultiplier ? Number(annotation.lineHeightMultiplier) : undefined
207 };
208 };
209 }
211 > export interface IModelOptionsChangedEvent {
212 > readonly tabSize: boolean;
213 > readonly indentSize: boolean;
214 > readonly insertSpaces: boolean;
215 > readonly trimAutoWhitespace: boolean;
216 > }
217 >
218 > /**
219 > * @internal
220 > */
221 > export const enum RawContentChangedType {
222 > Flush = 1,
223 > LineChanged = 2,
224 > LinesDeleted = 3,
225 > LinesInserted = 4,
226 > EOLChanged = 5
227 > }
228 >
229 > /**
230 > * An event describing that a model has been reset to a new value.
231 > * @internal
232 > */
233 > export class ModelRawFlush {
234 > public readonly changeType = RawContentChangedType.Flush; textModel.ts ×3
236 >
237 > /**
238 > * Represents text injected on a line
239 > * @internal
240 > */
241 > export class LineInjectedText {
242 > public static applyInjectedText(lineText: string, injectedTexts: LineInjectedText[] | null): string {
243 > if (!injectedTexts || injectedTexts.length === 0) {
244 > return lineText;
245 > }
246 > let result = ''; textModel.ts ×190
247 > let lastOriginalOffset = 0;
248 > for (const injectedText of injectedTexts) {
249 > result += lineText.substring(lastOriginalOffset, injectedText.column - 1);
250 > lastOriginalOffset = injectedText.column - 1;
251 > result += injectedText.options.content;
252 > }
253 > result += lineText.substring(lastOriginalOffset);
254 > return result;
256 >
257 > public static fromDecorations(decorations: IModelDecoration[]): LineInjectedText[] {
258 const result: LineInjectedText[] = [];
259 for (const decoration of decorations) {
260 if (decoration.options.before && decoration.options.before.content.length > 0) {
261 result.push(new LineInjectedText(
262 decoration.ownerId,
263 decoration.range.startLineNumber,
264 decoration.range.startColumn,
265 decoration.options.before,
266 0,
267 ));
268 }
269 if (decoration.options.after && decoration.options.after.content.length > 0) {
270 result.push(new LineInjectedText(
271 decoration.ownerId,
272 decoration.range.endLineNumber,
273 decoration.range.endColumn,
274 decoration.options.after,
275 1,
276 ));
277 }
278 }
279 result.sort((a, b) => {
280 if (a.lineNumber === b.lineNumber) {
281 if (a.column === b.column) {
282 return a.order - b.order;
283 }
284 return a.column - b.column;
285 }
286 return a.lineNumber - b.lineNumber;
287 });
288 return result;
289 }
291 > constructor(
292 public readonly ownerId: number,
293 public readonly lineNumber: number,
294 public readonly column: number,
295 public readonly options: InjectedTextOptions,
296 public readonly order: number
297 ) { }
299 > public withText(text: string): LineInjectedText {
300 return new LineInjectedText(this.ownerId, this.lineNumber, this.column, { ...this.options, content: text }, this.order);
301 }
303 >
304 > /**
305 > * An event describing that a line has changed in a model.
306 > * @internal
307 > */
308 > export class ModelRawLineChanged {
309 > public readonly changeType = RawContentChangedType.LineChanged;
310 > /**
311 > * The line number that has changed (before the change was applied).
312 > */
313 > public readonly lineNumber: number;
314 > /**
315 > * The new line number the old one is mapped to (after the change was applied).
316 > */
317 > public readonly lineNumberPostEdit: number;
318 >
319 > constructor(lineNumber: number, lineNumberPostEdit: number) {
320 > this.lineNumber = lineNumber; intervalTree.ts ×7
321 > this.lineNumberPostEdit = lineNumberPostEdit;
322 > }
324 >
325 >
326 > /**
327 > * An event describing that a line height has changed in the model.
328 > * @internal
329 > */
330 > export class ModelLineHeightChanged {
331 > /**
332 > * Editor owner ID
333 > */
334 > public readonly ownerId: number;
335 > /**
336 > * The decoration ID that has changed.
337 > */
338 > public readonly decorationId: string;
339 > /**
340 > * The line that has changed.
341 > */
342 > public readonly lineNumber: number;
343 > /**
344 > * The line height on the line.
345 > */
346 > public readonly lineHeightMultiplier: number | null;
347 >
348 > constructor(ownerId: number, decorationId: string, lineNumber: number, lineHeightMultiplier: number | null) {
349 this.ownerId = ownerId;
350 this.decorationId = decorationId;
351 this.lineNumber = lineNumber;
352 this.lineHeightMultiplier = lineHeightMultiplier;
353 }
355 >
356 > /**
357 > * An event describing that a line height has changed in the model.
358 > * @internal
359 > */
360 > export class ModelFontChanged {
361 > /**
362 > * Editor owner ID
363 > */
364 > public readonly ownerId: number;
365 > /**
366 > * The line that has changed.
367 > */
368 > public readonly lineNumber: number;
369 >
370 > constructor(ownerId: number, lineNumber: number) {
371 this.ownerId = ownerId;
372 this.lineNumber = lineNumber;
373 }
375 >
376 > /**
377 > * An event describing that line(s) have been deleted in a model.
378 > * @internal
379 > */
380 > export class ModelRawLinesDeleted {
381 > public readonly changeType = RawContentChangedType.LinesDeleted;
382 > /**
383 > * At what line the deletion began (inclusive).
384 > */
385 > public readonly fromLineNumber: number;
386 > /**
387 > * At what line the deletion stopped (inclusive).
388 > */
389 > public readonly toLineNumber: number;
390 > /**
391 > * The last unmodified line in the updated buffer after the deletion is made.
392 > */
393 > public readonly lastUntouchedLinePostEdit: number;
394 >
395 > constructor(fromLineNumber: number, toLineNumber: number, lastUntouchedLinePostEdit: number) {
396 > this.fromLineNumber = fromLineNumber; textModel.ts ×1
397 > this.toLineNumber = toLineNumber;
398 > this.lastUntouchedLinePostEdit = lastUntouchedLinePostEdit;
399 > }
401 >
402 > /**
403 > * An event describing that line(s) have been inserted in a model.
404 > * @internal
405 > */
406 > export class ModelRawLinesInserted {
407 > public readonly changeType = RawContentChangedType.LinesInserted;
408 > /**
409 > * Before what line did the insertion begin
410 > */
411 > public readonly fromLineNumber: number;
412 > /**
413 > * The actual start line number in the updated buffer where the newly inserted content can be found.
414 > */
415 > public readonly fromLineNumberPostEdit: number;
416 > /**
417 > * The count of inserted lines.
418 > */
419 > public readonly count: number;
420 > /**
421 > * `toLineNumber` - `fromLineNumber` + 1 denotes the number of lines that were inserted
422 > */
423 > public get toLineNumber(): number {
424 > return this.fromLineNumber + this.count - 1;
425 > }
426 > /**
427 > * The actual end line number of the insertion in the updated buffer.
428 > */
429 > public get toLineNumberPostEdit(): number {
430 return this.fromLineNumberPostEdit + this.count - 1;
431 }
433 > constructor(fromLineNumber: number, fromLineNumberPostEdit: number, count: number) {
434 > this.fromLineNumber = fromLineNumber; textModel.ts ×1
435 > this.fromLineNumberPostEdit = fromLineNumberPostEdit;
436 > this.count = count;
437 > }
439 >
440 > /**
441 > * An event describing that a model has had its EOL changed.
442 > * @internal
443 > */
444 > export class ModelRawEOLChanged {
445 > public readonly changeType = RawContentChangedType.EOLChanged; textModel.ts ×6
447 >
448 > /**
449 > * @internal
450 > */
451 > export type ModelRawChange = ModelRawFlush | ModelRawLineChanged | ModelRawLinesDeleted | ModelRawLinesInserted | ModelRawEOLChanged;
452 >
453 > /**
454 > * An event describing a change in the text of a model.
455 > * @internal
456 > */
457 > export class ModelRawContentChangedEvent {
458 >
459 > public readonly changes: ModelRawChange[];
460 > /**
461 > * The new version id the model has transitioned to.
462 > */
463 > public readonly versionId: number;
464 > /**
465 > * Flag that indicates that this event was generated while undoing.
466 > */
467 > public readonly isUndoing: boolean;
468 > /**
469 > * Flag that indicates that this event was generated while redoing.
470 > */
471 > public readonly isRedoing: boolean;
472 >
473 > public resultingSelection: Selection[] | null;
474 >
475 > constructor(changes: ModelRawChange[], versionId: number, isUndoing: boolean, isRedoing: boolean) {
476 > this.changes = changes; textModel.ts ×9
477 > this.versionId = versionId;
478 > this.isUndoing = isUndoing;
479 > this.isRedoing = isRedoing;
480 > this.resultingSelection = null;
481 > }
483 > public containsEvent(type: RawContentChangedType): boolean {
484 for (let i = 0, len = this.changes.length; i < len; i++) {
485 const change = this.changes[i];
486 if (change.changeType === type) {
487 return true;
488 }
489 }
490 return false;
491 }
493 > public static merge(a: ModelRawContentChangedEvent, b: ModelRawContentChangedEvent): ModelRawContentChangedEvent {
494 const changes = ([] as ModelRawChange[]).concat(a.changes).concat(b.changes);
495 const versionId = b.versionId;
496 const isUndoing = (a.isUndoing || b.isUndoing);
497 const isRedoing = (a.isRedoing || b.isRedoing);
498 return new ModelRawContentChangedEvent(changes, versionId, isUndoing, isRedoing);
499 }
501 >
502 > /**
503 > * An event describing a change in injected text.
504 > * @internal
505 > */
506 > export class ModelInjectedTextChangedEvent {
507 >
508 > public readonly changes: ModelRawLineChanged[];
509 >
510 > constructor(changes: ModelRawLineChanged[]) {
511 > this.changes = changes; textModel.ts ×6
512 > }
514 >
515 > /**
516 > * An event describing a change of a line height.
517 > * @internal
518 > */
519 > export class ModelLineHeightChangedEvent {
520 >
521 > public readonly changes: ModelLineHeightChanged[];
522 >
523 > constructor(changes: ModelLineHeightChanged[]) {
524 this.changes = changes;
525 }
527 > public affects(rangeOrPosition: IRange | IPosition) {
528 if (Range.isIRange(rangeOrPosition)) {
529 for (const change of this.changes) {
530 if (change.lineNumber >= rangeOrPosition.startLineNumber && change.lineNumber <= rangeOrPosition.endLineNumber) {
531 return true;
532 }
533 }
534 return false;
535 } else {
536 for (const change of this.changes) {
537 if (change.lineNumber === rangeOrPosition.lineNumber) {
538 return true;
539 }
540 }
541 return false;
542 }
543 }
545 >
546 > /**
547 > * An event describing a change in fonts.
548 > * @internal
549 > */
550 > export class ModelFontChangedEvent {
551 >
552 > public readonly changes: ModelFontChanged[];
553 >
554 > constructor(changes: ModelFontChanged[]) {
555 this.changes = changes;
556 }
558 >
559 > /**
560 > * @internal
561 > */
562 > export class InternalModelContentChangeEvent {
563 > constructor(
564 > public readonly rawContentChangedEvent: ModelRawContentChangedEvent, textModel.ts ×9
565 > public readonly contentChangedEvent: IModelContentChangedEvent,
566 > ) { }
568 > public merge(other: InternalModelContentChangeEvent): InternalModelContentChangeEvent {
569 const rawContentChangedEvent = ModelRawContentChangedEvent.merge(this.rawContentChangedEvent, other.rawContentChangedEvent);
570 const contentChangedEvent = InternalModelContentChangeEvent._mergeChangeEvents(this.contentChangedEvent, other.contentChangedEvent);
571 return new InternalModelContentChangeEvent(rawContentChangedEvent, contentChangedEvent);
572 }
574 > private static _mergeChangeEvents(a: IModelContentChangedEvent, b: IModelContentChangedEvent): IModelContentChangedEvent {
575 const changes = ([] as IModelContentChange[]).concat(a.changes).concat(b.changes);
576 const eol = b.eol;
577 const versionId = b.versionId;
578 const isUndoing = (a.isUndoing || b.isUndoing);
579 const isRedoing = (a.isRedoing || b.isRedoing);
580 const isFlush = (a.isFlush || b.isFlush);
581 const isEolChange = a.isEolChange && b.isEolChange; // both must be true to not confuse listeners who skip such edits
582 return {
583 changes: changes,
584 eol: eol,
585 isEolChange: isEolChange,
586 versionId: versionId,
587 isUndoing: isUndoing,
588 isRedoing: isRedoing,
589 isFlush: isFlush,
590 detailedReasons: a.detailedReasons.concat(b.detailedReasons),
591 detailedReasonsChangeLengths: a.detailedReasonsChangeLengths.concat(b.detailedReasonsChangeLengths),
592 };
593 }