Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/common/services/languageService.ts
3294 views
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
6
import { Emitter, Event } from '../../../base/common/event.js';
7
import { Disposable, IDisposable } from '../../../base/common/lifecycle.js';
8
import { URI } from '../../../base/common/uri.js';
9
import { LanguagesRegistry } from './languagesRegistry.js';
10
import { ILanguageNameIdPair, ILanguageSelection, ILanguageService, ILanguageIcon, ILanguageExtensionPoint } from '../languages/language.js';
11
import { ILanguageIdCodec, TokenizationRegistry } from '../languages.js';
12
import { PLAINTEXT_LANGUAGE_ID } from '../languages/modesRegistry.js';
13
import { IObservable, observableFromEvent } from '../../../base/common/observable.js';
14
15
export class LanguageService extends Disposable implements ILanguageService {
16
public _serviceBrand: undefined;
17
18
static instanceCount = 0;
19
20
private readonly _onDidRequestBasicLanguageFeatures = this._register(new Emitter<string>());
21
public readonly onDidRequestBasicLanguageFeatures = this._onDidRequestBasicLanguageFeatures.event;
22
23
private readonly _onDidRequestRichLanguageFeatures = this._register(new Emitter<string>());
24
public readonly onDidRequestRichLanguageFeatures = this._onDidRequestRichLanguageFeatures.event;
25
26
protected readonly _onDidChange = this._register(new Emitter<void>({ leakWarningThreshold: 200 /* https://github.com/microsoft/vscode/issues/119968 */ }));
27
public readonly onDidChange: Event<void> = this._onDidChange.event;
28
29
private readonly _requestedBasicLanguages = new Set<string>();
30
private readonly _requestedRichLanguages = new Set<string>();
31
32
protected readonly _registry: LanguagesRegistry;
33
public readonly languageIdCodec: ILanguageIdCodec;
34
35
constructor(warnOnOverwrite = false) {
36
super();
37
LanguageService.instanceCount++;
38
this._registry = this._register(new LanguagesRegistry(true, warnOnOverwrite));
39
this.languageIdCodec = this._registry.languageIdCodec;
40
this._register(this._registry.onDidChange(() => this._onDidChange.fire()));
41
}
42
43
public override dispose(): void {
44
LanguageService.instanceCount--;
45
super.dispose();
46
}
47
48
public registerLanguage(def: ILanguageExtensionPoint): IDisposable {
49
return this._registry.registerLanguage(def);
50
}
51
52
public isRegisteredLanguageId(languageId: string | null | undefined): boolean {
53
return this._registry.isRegisteredLanguageId(languageId);
54
}
55
56
public getRegisteredLanguageIds(): string[] {
57
return this._registry.getRegisteredLanguageIds();
58
}
59
60
public getSortedRegisteredLanguageNames(): ILanguageNameIdPair[] {
61
return this._registry.getSortedRegisteredLanguageNames();
62
}
63
64
public getLanguageName(languageId: string): string | null {
65
return this._registry.getLanguageName(languageId);
66
}
67
68
public getMimeType(languageId: string): string | null {
69
return this._registry.getMimeType(languageId);
70
}
71
72
public getIcon(languageId: string): ILanguageIcon | null {
73
return this._registry.getIcon(languageId);
74
}
75
76
public getExtensions(languageId: string): ReadonlyArray<string> {
77
return this._registry.getExtensions(languageId);
78
}
79
80
public getFilenames(languageId: string): ReadonlyArray<string> {
81
return this._registry.getFilenames(languageId);
82
}
83
84
public getConfigurationFiles(languageId: string): ReadonlyArray<URI> {
85
return this._registry.getConfigurationFiles(languageId);
86
}
87
88
public getLanguageIdByLanguageName(languageName: string): string | null {
89
return this._registry.getLanguageIdByLanguageName(languageName);
90
}
91
92
public getLanguageIdByMimeType(mimeType: string | null | undefined): string | null {
93
return this._registry.getLanguageIdByMimeType(mimeType);
94
}
95
96
public guessLanguageIdByFilepathOrFirstLine(resource: URI | null, firstLine?: string): string | null {
97
const languageIds = this._registry.guessLanguageIdByFilepathOrFirstLine(resource, firstLine);
98
return languageIds.at(0) ?? null;
99
}
100
101
public createById(languageId: string | null | undefined): ILanguageSelection {
102
return new LanguageSelection(this.onDidChange, () => {
103
return this._createAndGetLanguageIdentifier(languageId);
104
});
105
}
106
107
public createByMimeType(mimeType: string | null | undefined): ILanguageSelection {
108
return new LanguageSelection(this.onDidChange, () => {
109
const languageId = this.getLanguageIdByMimeType(mimeType);
110
return this._createAndGetLanguageIdentifier(languageId);
111
});
112
}
113
114
public createByFilepathOrFirstLine(resource: URI | null, firstLine?: string): ILanguageSelection {
115
return new LanguageSelection(this.onDidChange, () => {
116
const languageId = this.guessLanguageIdByFilepathOrFirstLine(resource, firstLine);
117
return this._createAndGetLanguageIdentifier(languageId);
118
});
119
}
120
121
private _createAndGetLanguageIdentifier(languageId: string | null | undefined): string {
122
if (!languageId || !this.isRegisteredLanguageId(languageId)) {
123
// Fall back to plain text if language is unknown
124
languageId = PLAINTEXT_LANGUAGE_ID;
125
}
126
127
return languageId;
128
}
129
130
public requestBasicLanguageFeatures(languageId: string): void {
131
if (!this._requestedBasicLanguages.has(languageId)) {
132
this._requestedBasicLanguages.add(languageId);
133
this._onDidRequestBasicLanguageFeatures.fire(languageId);
134
}
135
}
136
137
public requestRichLanguageFeatures(languageId: string): void {
138
if (!this._requestedRichLanguages.has(languageId)) {
139
this._requestedRichLanguages.add(languageId);
140
141
// Ensure basic features are requested
142
this.requestBasicLanguageFeatures(languageId);
143
144
// Ensure tokenizers are created
145
TokenizationRegistry.getOrCreate(languageId);
146
147
this._onDidRequestRichLanguageFeatures.fire(languageId);
148
}
149
}
150
}
151
152
class LanguageSelection implements ILanguageSelection {
153
private readonly _value: IObservable<string>;
154
public readonly onDidChange: Event<string>;
155
156
constructor(onDidChangeLanguages: Event<void>, selector: () => string) {
157
this._value = observableFromEvent(this, onDidChangeLanguages, () => selector());
158
this.onDidChange = Event.fromObservable(this._value);
159
}
160
161
public get languageId(): string {
162
return this._value.get();
163
}
164
}
165
166