languageConfigurationRegistry.ts ×28

Frontier kind: Code frontier

unlabeled · c_cca7786ddd3b

873 tests · 16196 LOC · 63 files · introduces 0 tests · 260 LOC · 3 files

Introduces — evidence that enters the hierarchy at this concept

Code
52 ranges260 lines · 3 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
1579 ranges16196 lines · 63 files · Browse complete extent
All tests (intent)
873 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.

3 files ranked by introduced lines: 260 introduced LOC across 52 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/editor/common/languages/languageConfigurationRegistry.ts 160 introduced LOC · 28 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- languageConfigurationRegistry.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 { Disposable, IDisposable, markAsSingleton, toDisposable } from '../../../base/common/lifecycle.js';
8 > import * as strings from '../../../base/common/strings.js';
9 > import { ITextModel } from '../model.js';
10 > import { DEFAULT_WORD_REGEXP, ensureValidWordDefinition } from '../core/wordHelper.js';
11 > import { EnterAction, FoldingRules, IAutoClosingPair, IndentationRule, LanguageConfiguration, AutoClosingPairs, CharacterPair, ExplicitLanguageConfiguration } from './languageConfiguration.js';
12 > import { CharacterPairSupport } from './supports/characterPair.js';
13 > import { BracketElectricCharacterSupport } from './supports/electricCharacter.js';
14 > import { IndentRulesSupport } from './supports/indentRules.js';
15 > import { OnEnterSupport } from './supports/onEnter.js';
16 > import { RichEditBrackets } from './supports/richEditBrackets.js';
17 > import { EditorAutoIndentStrategy } from '../config/editorOptions.js';
18 > import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';
19 > import { IConfigurationService } from '../../../platform/configuration/common/configuration.js';
20 > import { ILanguageService } from './language.js';
21 > import { InstantiationType, registerSingleton } from '../../../platform/instantiation/common/extensions.js';
22 > import { PLAINTEXT_LANGUAGE_ID } from './modesRegistry.js';
23 > import { LanguageBracketsConfiguration } from './supports/languageBracketsConfiguration.js';
24 >
25 > /**
26 > * Interface used to support insertion of mode specific comments.
27 > */
28 > export interface ICommentsConfiguration {
29 > lineCommentToken?: string;
30 > lineCommentNoIndent?: boolean;
31 > blockCommentStartToken?: string;
32 > blockCommentEndToken?: string;
33 > }
34 >
35 > export interface ILanguageConfigurationService {
36 > readonly _serviceBrand: undefined;
37 >
38 > readonly onDidChange: Event<LanguageConfigurationServiceChangeEvent>;
39 >
40 > /**
41 > * @param priority Use a higher number for higher priority
42 > */
43 > register(languageId: string, configuration: LanguageConfiguration, priority?: number): IDisposable;
44 >
45 > getLanguageConfiguration(languageId: string): ResolvedLanguageConfiguration;
46 >
47 > }
48 >
49 > export class LanguageConfigurationServiceChangeEvent {
50 > constructor(public readonly languageId: string | undefined) { }
51 >
52 > public affects(languageId: string): boolean {
53 return !this.languageId ? true : this.languageId === languageId;
54 }
56 >
57 > export const ILanguageConfigurationService = createDecorator<ILanguageConfigurationService>('languageConfigurationService');
58 >
59 > export class LanguageConfigurationService extends Disposable implements ILanguageConfigurationService {
60 > _serviceBrand: undefined;
61 >
62 > private readonly _registry = this._register(new LanguageConfigurationRegistry());
63 >
64 > private readonly onDidChangeEmitter = this._register(new Emitter<LanguageConfigurationServiceChangeEvent>());
65 > public readonly onDidChange = this.onDidChangeEmitter.event;
66 >
67 > private readonly configurations = new Map<string, ResolvedLanguageConfiguration>();
68 >
69 > constructor(
70 @IConfigurationService private readonly configurationService: IConfigurationService,
71 @ILanguageService private readonly languageService: ILanguageService
103 }));
104 }
106 > public register(languageId: string, configuration: LanguageConfiguration, priority?: number): IDisposable {
107 return this._registry.register(languageId, configuration, priority);
108 }
110 > public getLanguageConfiguration(languageId: string): ResolvedLanguageConfiguration {
111 let result = this.configurations.get(languageId);
112 if (!result) {
140 return config;
141 }
143 > const customizedLanguageConfigKeys = {
144 > brackets: 'editor.language.brackets',
145 > colorizedBracketPairs: 'editor.language.colorizedBracketPairs'
146 > };
147 >
148 function getCustomizedLanguageConfig(languageId: string, configurationService: IConfigurationService): LanguageConfiguration {
149 const brackets = configurationService.getValue(customizedLanguageConfigKeys.brackets, {
160 };
161 }
163 function validateBracketPairs(data: unknown): CharacterPair[] | undefined {
164 if (!Array.isArray(data)) {
172 }).filter((p): p is CharacterPair => !!p);
173 }
175 > export function getIndentationAtPosition(model: ITextModel, lineNumber: number, column: number): string {
176 const lineText = model.getLineContent(lineNumber);
177 let indentation = strings.getLeadingWhitespace(lineText);
181 return indentation;
182 }
184 > class ComposedLanguageConfiguration {
185 > private readonly _entries: LanguageConfigurationContribution[];
186 > private _order: number;
187 > private _resolved: ResolvedLanguageConfiguration | null = null;
188 >
189 > constructor(public readonly languageId: string) {
190 this._entries = [];
191 this._order = 0;
192 this._resolved = null;
193 }
195 > public register(
196 configuration: LanguageConfiguration,
197 priority: number
214 }));
215 }
217 > public getResolvedConfiguration(): ResolvedLanguageConfiguration | null {
218 if (!this._resolved) {
219 const config = this._resolve();
227 return this._resolved;
228 }
230 > private _resolve(): LanguageConfiguration | null {
231 if (this._entries.length === 0) {
232 return null;
235 return combineLanguageConfigurations(this._entries.map(e => e.configuration));
236 }
238 >
239 function combineLanguageConfigurations(configs: LanguageConfiguration[]): LanguageConfiguration {
240 let result: ExplicitLanguageConfiguration = {
269 return result;
270 }
272 > class LanguageConfigurationContribution {
273 > constructor(
274 public readonly configuration: LanguageConfiguration,
275 public readonly priority: number,
276 public readonly order: number
277 ) { }
279 > public static cmp(a: LanguageConfigurationContribution, b: LanguageConfigurationContribution) {
280 if (a.priority === b.priority) {
281 // higher order last
285 return a.priority - b.priority;
286 }
288 >
289 > export class LanguageConfigurationChangeEvent {
290 > constructor(public readonly languageId: string) { }
291 > }
292 >
293 > export class LanguageConfigurationRegistry extends Disposable {
294 > private readonly _entries = new Map<string, ComposedLanguageConfiguration>();
295 >
296 > private readonly _onDidChange = this._register(new Emitter<LanguageConfigurationChangeEvent>());
297 > public readonly onDidChange: Event<LanguageConfigurationChangeEvent> = this._onDidChange.event;
298 >
299 > constructor() {
300 super();
301 this._register(this.register(PLAINTEXT_LANGUAGE_ID, {
320 }, 0));
321 }
323 > /**
324 > * @param priority Use a higher number for higher priority
325 > */
326 > public register(languageId: string, configuration: LanguageConfiguration, priority: number = 0): IDisposable {
327 let entries = this._entries.get(languageId);
328 if (!entries) {
339 }));
340 }
342 > public getLanguageConfiguration(languageId: string): ResolvedLanguageConfiguration | null {
343 const entries = this._entries.get(languageId);
344 return entries?.getResolvedConfiguration() || null;
345 }
347 >
348 > /**
349 > * Immutable.
350 > */
351 > export class ResolvedLanguageConfiguration {
352 > private _brackets: RichEditBrackets | null;
353 > private _electricCharacter: BracketElectricCharacterSupport | null;
354 > private readonly _onEnterSupport: OnEnterSupport | null;
355 >
356 > public readonly comments: ICommentsConfiguration | null;
357 > public readonly characterPair: CharacterPairSupport;
358 > public readonly wordDefinition: RegExp;
359 > public readonly indentRulesSupport: IndentRulesSupport | null;
360 > public readonly indentationRules: IndentationRule | undefined;
361 > public readonly foldingRules: FoldingRules;
362 > public readonly bracketsNew: LanguageBracketsConfiguration;
363 >
364 > constructor(
365 public readonly languageId: string,
366 public readonly underlyingConfig: LanguageConfiguration
393 );
394 }
396 > public getWordDefinition(): RegExp {
397 return ensureValidWordDefinition(this.wordDefinition);
398 }
400 > public get brackets(): RichEditBrackets | null {
401 if (!this._brackets && this.underlyingConfig.brackets) {
402 this._brackets = new RichEditBrackets(
407 return this._brackets;
408 }
410 > public get electricCharacter(): BracketElectricCharacterSupport | null {
411 if (!this._electricCharacter) {
412 this._electricCharacter = new BracketElectricCharacterSupport(
416 return this._electricCharacter;
417 }
419 > public onEnter(
420 autoIndent: EditorAutoIndentStrategy,
421 previousLineText: string,
433 );
434 }
436 > public getAutoClosingPairs(): AutoClosingPairs {
437 return new AutoClosingPairs(this.characterPair.getAutoClosingPairs());
438 }
440 > public getAutoCloseBeforeSet(forQuotes: boolean): string {
441 return this.characterPair.getAutoCloseBeforeSet(forQuotes);
442 }
444 > public getSurroundingPairs(): IAutoClosingPair[] {
445 return this.characterPair.getSurroundingPairs();
446 }
448 > private static _handleComments(
449 conf: LanguageConfiguration
450 ): ICommentsConfiguration | null {
473 return comments;
474 }
476 >
477 > registerSingleton(ILanguageConfigurationService, LanguageConfigurationService, InstantiationType.Delayed);
src/vs/editor/common/languages/supports/languageBracketsConfiguration.ts 69 introduced LOC · 16 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- languageBracketsConfiguration.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 { CachedFunction } from '../../../../base/common/cache.js';
7 > import { RegExpOptions } from '../../../../base/common/strings.js';
8 > import { LanguageConfiguration } from '../languageConfiguration.js';
9 > import { createBracketOrRegExp } from './richEditBrackets.js';
10 >
11 > /**
12 > * Captures all bracket related configurations for a single language.
13 > * Immutable.
14 > */
15 > export class LanguageBracketsConfiguration {
16 > private readonly _openingBrackets: ReadonlyMap<string, OpeningBracketKind>;
17 > private readonly _closingBrackets: ReadonlyMap<string, ClosingBracketKind>;
18 >
19 > constructor(
20 public readonly languageId: string,
21 config: LanguageConfiguration,
68 this._closingBrackets = new Map([...closingBracketInfos.cachedValues].map(([k, v]) => [k, v.info]));
69 }
71 > /**
72 > * No two brackets have the same bracket text.
73 > */
74 > public get openingBrackets(): readonly OpeningBracketKind[] {
75 return [...this._openingBrackets.values()];
76 }
78 > /**
79 > * No two brackets have the same bracket text.
80 > */
81 > public get closingBrackets(): readonly ClosingBracketKind[] {
82 return [...this._closingBrackets.values()];
83 }
85 > public getOpeningBracketInfo(bracketText: string): OpeningBracketKind | undefined {
86 return this._openingBrackets.get(bracketText);
87 }
89 > public getClosingBracketInfo(bracketText: string): ClosingBracketKind | undefined {
90 return this._closingBrackets.get(bracketText);
91 }
93 > public getBracketInfo(bracketText: string): BracketKind | undefined {
94 return this.getOpeningBracketInfo(bracketText) || this.getClosingBracketInfo(bracketText);
95 }
97 > public getBracketRegExp(options?: RegExpOptions): RegExp {
98 const brackets = Array.from([...this._openingBrackets.keys(), ...this._closingBrackets.keys()]);
99 return createBracketOrRegExp(brackets, options);
100 }
102 >
103 function filterValidBrackets(bracketPairs: [string, string][]): [string, string][] {
104 return bracketPairs.filter(([open, close]) => open !== '' && close !== '');
105 }
107 > export type BracketKind = OpeningBracketKind | ClosingBracketKind;
108 >
109 > export class BracketKindBase {
110 > constructor(
111 protected readonly config: LanguageBracketsConfiguration,
112 public readonly bracketText: string,
113 ) { }
115 > public get languageId(): string {
116 return this.config.languageId;
117 }
119 >
120 > export class OpeningBracketKind extends BracketKindBase {
121 > public readonly isOpeningBracket = true;
122 >
123 > constructor(
124 config: LanguageBracketsConfiguration,
125 bracketText: string,
128 super(config, bracketText);
129 }
131 >
132 > export class ClosingBracketKind extends BracketKindBase {
133 > public readonly isOpeningBracket = false;
134 >
135 > constructor(
136 config: LanguageBracketsConfiguration,
137 bracketText: string,
144 super(config, bracketText);
145 }
147 > /**
148 > * Checks if this bracket closes the given other bracket.
149 > * If the bracket infos come from different configurations, this method will return false.
150 > */
151 > public closes(other: OpeningBracketKind): boolean {
152 if (other['config'] !== this.config) {
153 return false;
155 return this.openingBrackets.has(other);
156 }
158 > public closesColorized(other: OpeningBracketKind): boolean {
159 if (other['config'] !== this.config) {
160 return false;
src/vs/editor/common/languages/supports/indentRules.ts 31 introduced LOC · 8 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- indentRules.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 { IndentationRule } from '../languageConfiguration.js';
7 >
8 > export const enum IndentConsts {
9 > INCREASE_MASK = 0b00000001,
10 > DECREASE_MASK = 0b00000010,
11 > INDENT_NEXTLINE_MASK = 0b00000100,
12 > UNINDENT_MASK = 0b00001000,
13 > }
14 >
15 function resetGlobalRegex(reg: RegExp) {
16 if (reg.global) {
20 return true;
21 }
23 > export class IndentRulesSupport {
24 >
25 > private readonly _indentationRules: IndentationRule;
26 >
27 > constructor(indentationRules: IndentationRule) {
28 this._indentationRules = indentationRules;
29 }
31 > public shouldIncrease(text: string): boolean {
32 if (this._indentationRules) {
33 if (this._indentationRules.increaseIndentPattern && resetGlobalRegex(this._indentationRules.increaseIndentPattern) && this._indentationRules.increaseIndentPattern.test(text)) {
40 return false;
41 }
43 > public shouldDecrease(text: string): boolean {
44 if (this._indentationRules && this._indentationRules.decreaseIndentPattern && resetGlobalRegex(this._indentationRules.decreaseIndentPattern) && this._indentationRules.decreaseIndentPattern.test(text)) {
45 return true;
47 return false;
48 }
50 > public shouldIndentNextLine(text: string): boolean {
51 if (this._indentationRules && this._indentationRules.indentNextLinePattern && resetGlobalRegex(this._indentationRules.indentNextLinePattern) && this._indentationRules.indentNextLinePattern.test(text)) {
52 return true;
55 return false;
56 }
58 > public shouldIgnore(text: string): boolean {
59 // the text matches `unIndentedLinePattern`
60 if (this._indentationRules && this._indentationRules.unIndentedLinePattern && resetGlobalRegex(this._indentationRules.unIndentedLinePattern) && this._indentationRules.unIndentedLinePattern.test(text)) {
64 return false;
65 }
67 > public getIndentMetadata(text: string): number {
68 let ret = 0;
69 if (this.shouldIncrease(text)) {