modelService.ts ×30

Frontier kind: Code frontier

unlabeled · c_3c1c2b209773

811 tests · 37274 LOC · 219 files · introduces 0 tests · 152 LOC · 1 file

Introduces — evidence that enters the hierarchy at this concept

Code
30 ranges152 lines · 1 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
4216 ranges37274 lines · 219 files · Browse complete extent
All tests (intent)
811 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

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 native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

1 file ranked by introduced lines: 152 introduced LOC across 30 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/editor/common/services/modelService.ts 152 introduced LOC · 30 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- modelService.ts
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 { Emitter, Event } from '../../../base/common/event.js';
7 > import { StringSHA1 } from '../../../base/common/hash.js';
8 > import { Disposable, DisposableStore, IDisposable } from '../../../base/common/lifecycle.js';
9 > import { Schemas } from '../../../base/common/network.js';
10 > import { equals } from '../../../base/common/objects.js';
11 > import * as platform from '../../../base/common/platform.js';
12 > import { URI } from '../../../base/common/uri.js';
13 > import { IConfigurationChangeEvent, IConfigurationService } from '../../../platform/configuration/common/configuration.js';
14 > import { IInstantiationService } from '../../../platform/instantiation/common/instantiation.js';
15 > import { IUndoRedoService, ResourceEditStackSnapshot } from '../../../platform/undoRedo/common/undoRedo.js';
16 > import { clampedInt } from '../config/editorOptions.js';
17 > import { EditOperation, ISingleEditOperation } from '../core/editOperation.js';
18 > import { EDITOR_MODEL_DEFAULTS } from '../core/misc/textModelDefaults.js';
19 > import { Range } from '../core/range.js';
20 > import { ILanguageSelection } from '../languages/language.js';
21 > import { PLAINTEXT_LANGUAGE_ID } from '../languages/modesRegistry.js';
22 > import { DefaultEndOfLine, EndOfLinePreference, EndOfLineSequence, ITextBuffer, ITextBufferFactory, ITextModel, ITextModelCreationOptions } from '../model.js';
23 > import { isEditStackElement } from '../model/editStack.js';
24 > import { TextModel, createTextBuffer } from '../model/textModel.js';
25 > import { EditSources, TextModelEditSource } from '../textModelEditSource.js';
26 > import { IModelLanguageChangedEvent } from '../textModelEvents.js';
27 > import { IModelService } from './model.js';
28 > import { ITextResourcePropertiesService } from './textResourceConfiguration.js';
29 >
30 function MODEL_ID(resource: URI): string {
31 return resource.toString();
32 }
34 > class ModelData implements IDisposable {
35 >
36 > private readonly _modelEventListeners = new DisposableStore();
37 >
38 > constructor(
39 public readonly model: TextModel,
40 onWillDispose: (model: ITextModel) => void,
45 this._modelEventListeners.add(model.onDidChangeLanguage((e) => onDidChangeLanguage(model, e)));
46 }
48 > public dispose(): void {
49 this._modelEventListeners.dispose();
50 }
52 >
53 > interface IRawEditorConfig {
54 > tabSize?: unknown;
55 > indentSize?: unknown;
56 > insertSpaces?: unknown;
57 > detectIndentation?: unknown;
58 > trimAutoWhitespace?: unknown;
59 > creationOptions?: unknown;
60 > largeFileOptimizations?: unknown;
61 > bracketPairColorization?: unknown;
62 > }
63 >
64 > interface IRawConfig {
65 > eol?: unknown;
66 > editor?: IRawEditorConfig;
67 > }
68 >
69 > const DEFAULT_EOL = (platform.isLinux || platform.isMacintosh) ? DefaultEndOfLine.LF : DefaultEndOfLine.CRLF;
70 >
71 > class DisposedModelInfo {
72 > constructor(
73 public readonly uri: URI,
74 public readonly initialUndoRedoSnapshot: ResourceEditStackSnapshot | null,
80 public readonly alternativeVersionId: number,
81 ) { }
83 >
84 > export class ModelService extends Disposable implements IModelService {
85 >
86 > public static MAX_MEMORY_FOR_CLOSED_FILES_UNDO_STACK = 20 * 1024 * 1024;
87 >
88 > public _serviceBrand: undefined;
89 >
90 > private readonly _onModelAdded: Emitter<ITextModel> = this._register(new Emitter<ITextModel>());
91 > public readonly onModelAdded: Event<ITextModel> = this._onModelAdded.event;
92 >
93 > private readonly _onModelRemoved: Emitter<ITextModel> = this._register(new Emitter<ITextModel>());
94 > public readonly onModelRemoved: Event<ITextModel> = this._onModelRemoved.event;
95 >
96 > private readonly _onModelModeChanged = this._register(new Emitter<{ model: ITextModel; oldLanguageId: string }>());
97 > public readonly onModelLanguageChanged = this._onModelModeChanged.event;
98 >
99 > private _modelCreationOptionsByLanguageAndResource: { [languageAndResource: string]: ITextModelCreationOptions };
100 >
101 > /**
102 > * All the models known in the system.
103 > */
104 > private readonly _models: { [modelId: string]: ModelData };
105 > private readonly _disposedModels: Map<string, DisposedModelInfo>;
106 > private _disposedModelsHeapSize: number;
107 >
108 > constructor(
109 @IConfigurationService private readonly _configurationService: IConfigurationService,
110 @ITextResourcePropertiesService private readonly _resourcePropertiesService: ITextResourcePropertiesService,
121 this._updateModelOptions(undefined);
122 }
124 > private static _readModelOptions(config: IRawConfig, isForSimpleWidget: boolean): ITextModelCreationOptions {
125 let tabSize = EDITOR_MODEL_DEFAULTS.tabSize;
126 if (config.editor && typeof config.editor.tabSize !== 'undefined') {
181 };
182 }
184 > private _getEOL(resource: URI | undefined, language: string): string {
185 if (resource) {
186 return this._resourcePropertiesService.getEOL(resource, language);
192 return platform.OS === platform.OperatingSystem.Linux || platform.OS === platform.OperatingSystem.Macintosh ? '\n' : '\r\n';
193 }
195 > private _shouldRestoreUndoStack(): boolean {
196 const result = this._configurationService.getValue('files.restoreUndoStack');
197 if (typeof result === 'boolean') {
200 return true;
201 }
203 > public getCreationOptions(languageIdOrSelection: string | ILanguageSelection, resource: URI | undefined, isForSimpleWidget: boolean): ITextModelCreationOptions {
204 const language = (typeof languageIdOrSelection === 'string' ? languageIdOrSelection : languageIdOrSelection.languageId);
205 let creationOptions = this._modelCreationOptionsByLanguageAndResource[language + resource];
212 return creationOptions;
213 }
215 > private _updateModelOptions(e: IConfigurationChangeEvent | undefined): void {
216 const oldOptionsByLanguageAndResource = this._modelCreationOptionsByLanguageAndResource;
217 this._modelCreationOptionsByLanguageAndResource = Object.create(null);
234 }
235 }
237 > private static _setModelOptionsForModel(model: ITextModel, newOptions: ITextModelCreationOptions, currentOptions: ITextModelCreationOptions): void {
238 if (currentOptions && currentOptions.defaultEOL !== newOptions.defaultEOL && model.getLineCount() === 1) {
239 model.setEOL(newOptions.defaultEOL === DefaultEndOfLine.LF ? EndOfLineSequence.LF : EndOfLineSequence.CRLF);
268 }
269 }
271 > // --- begin IModelService
272 >
273 > private _insertDisposedModel(disposedModelData: DisposedModelInfo): void {
274 this._disposedModels.set(MODEL_ID(disposedModelData.uri), disposedModelData);
275 this._disposedModelsHeapSize += disposedModelData.heapSize;
276 }
278 > private _removeDisposedModel(resource: URI): DisposedModelInfo | undefined {
279 const disposedModelData = this._disposedModels.get(MODEL_ID(resource));
280 if (disposedModelData) {
284 return disposedModelData;
285 }
287 > private _ensureDisposedModelsHeapSize(maxModelsHeapSize: number): void {
288 if (this._disposedModelsHeapSize > maxModelsHeapSize) {
289 // we must remove some old undo stack elements to free up some memory
304 }
305 }
307 > private _createModelData(value: string | ITextBufferFactory, languageIdOrSelection: string | ILanguageSelection, resource: URI | undefined, isForSimpleWidget: boolean): ModelData {
308 // create & save the model
309 const options = this.getCreationOptions(languageIdOrSelection, resource, isForSimpleWidget);
362 return modelData;
363 }
365 > public updateModel(model: ITextModel, value: string | ITextBufferFactory, reason: TextModelEditSource = EditSources.unknown({ name: 'updateModel' })): void {
366 const options = this.getCreationOptions(model.getLanguageId(), model.uri, model.isForSimpleWidget);
367 const { textBuffer, disposable } = createTextBuffer(value, options.defaultEOL);
386 disposable.dispose();
387 }
389 > private static _commonPrefix(a: ITextModel, aLen: number, aDelta: number, b: ITextBuffer, bLen: number, bDelta: number): number {
390 const maxResult = Math.min(aLen, bLen);
391
396 return result;
397 }
399 > private static _commonSuffix(a: ITextModel, aLen: number, aDelta: number, b: ITextBuffer, bLen: number, bDelta: number): number {
400 const maxResult = Math.min(aLen, bLen);
401
406 return result;
407 }
409 > /**
410 > * Compute edits to bring `model` to the state of `textSource`.
411 > */
412 > public static _computeEdits(model: ITextModel, textBuffer: ITextBuffer): ISingleEditOperation[] {
413 const modelLineCount = model.getLineCount();
414 const textBufferLineCount = textBuffer.getLineCount();
437 return [EditOperation.replaceMove(oldRange, textBuffer.getValueInRange(newRange, EndOfLinePreference.TextDefined))];
438 }
440 > public createModel(value: string | ITextBufferFactory, languageSelection: ILanguageSelection | null, resource?: URI, isForSimpleWidget: boolean = false): ITextModel {
441 let modelData: ModelData;
442
451 return modelData.model;
452 }
454 > public destroyModel(resource: URI): void {
455 // We need to support that not all models get disposed through this service (i.e. model.dispose() should work!)
456 const modelData = this._models[MODEL_ID(resource)];
460 modelData.model.dispose();
461 }
463 > public getModels(): ITextModel[] {
464 const ret: ITextModel[] = [];
465
472 return ret;
473 }
475 > public getModel(resource: URI): ITextModel | null {
476 const modelId = MODEL_ID(resource);
477 const modelData = this._models[modelId];
481 return modelData.model;
482 }
484 > // --- end IModelService
485 >
486 > protected _schemaShouldMaintainUndoRedoElements(resource: URI) {
487 return (
488 resource.scheme === Schemas.file
493 );
494 }
496 > private _onWillDispose(model: ITextModel): void {
497 const modelId = MODEL_ID(model.uri);
498 const modelData = this._models[modelId];
551 this._onModelRemoved.fire(model);
552 }
554 > private _onDidChangeLanguage(model: ITextModel, e: IModelLanguageChangedEvent): void {
555 const oldLanguageId = e.oldLanguage;
556 const newLanguageId = model.getLanguageId();
560 this._onModelModeChanged.fire({ model, oldLanguageId: oldLanguageId });
561 }
563 > protected _getSHA1Computer(): ITextModelSHA1Computer {
564 return new DefaultModelSHA1Computer();
565 }
566 > } modelService.ts
567 >
568 > export interface ITextModelSHA1Computer {
569 > canComputeSHA1(model: ITextModel): boolean;
570 > computeSHA1(model: ITextModel): string;
571 > }
572 >
573 > export class DefaultModelSHA1Computer implements ITextModelSHA1Computer {
574 >
575 > public static MAX_MODEL_SIZE = 10 * 1024 * 1024; // takes 200ms to compute a sha1 on a 10MB model on a new machine
576 >
577 > canComputeSHA1(model: ITextModel): boolean {
578 return (model.getValueLength() <= DefaultModelSHA1Computer.MAX_MODEL_SIZE);
579 }
581 > computeSHA1(model: ITextModel): string {
582 // compute the sha1
583 const shaComputer = new StringSHA1();