Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/common/languages/supports/languageBracketsConfiguration.ts
3296 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 { 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,
22
) {
23
const bracketPairs = config.brackets ? filterValidBrackets(config.brackets) : [];
24
const openingBracketInfos = new CachedFunction((bracket: string) => {
25
const closing = new Set<ClosingBracketKind>();
26
27
return {
28
info: new OpeningBracketKind(this, bracket, closing),
29
closing,
30
};
31
});
32
const closingBracketInfos = new CachedFunction((bracket: string) => {
33
const opening = new Set<OpeningBracketKind>();
34
const openingColorized = new Set<OpeningBracketKind>();
35
return {
36
info: new ClosingBracketKind(this, bracket, opening, openingColorized),
37
opening,
38
openingColorized,
39
};
40
});
41
42
for (const [open, close] of bracketPairs) {
43
const opening = openingBracketInfos.get(open);
44
const closing = closingBracketInfos.get(close);
45
46
opening.closing.add(closing.info);
47
closing.opening.add(opening.info);
48
}
49
50
// Treat colorized brackets as brackets, and mark them as colorized.
51
const colorizedBracketPairs = config.colorizedBracketPairs
52
? filterValidBrackets(config.colorizedBracketPairs)
53
// If not configured: Take all brackets except `<` ... `>`
54
// Many languages set < ... > as bracket pair, even though they also use it as comparison operator.
55
// This leads to problems when colorizing this bracket, so we exclude it if not explicitly configured otherwise.
56
// https://github.com/microsoft/vscode/issues/132476
57
: bracketPairs.filter((p) => !(p[0] === '<' && p[1] === '>'));
58
for (const [open, close] of colorizedBracketPairs) {
59
const opening = openingBracketInfos.get(open);
60
const closing = closingBracketInfos.get(close);
61
62
opening.closing.add(closing.info);
63
closing.openingColorized.add(opening.info);
64
closing.opening.add(opening.info);
65
}
66
67
this._openingBrackets = new Map([...openingBracketInfos.cachedValues].map(([k, v]) => [k, v.info]));
68
this._closingBrackets = new Map([...closingBracketInfos.cachedValues].map(([k, v]) => [k, v.info]));
69
}
70
71
/**
72
* No two brackets have the same bracket text.
73
*/
74
public get openingBrackets(): readonly OpeningBracketKind[] {
75
return [...this._openingBrackets.values()];
76
}
77
78
/**
79
* No two brackets have the same bracket text.
80
*/
81
public get closingBrackets(): readonly ClosingBracketKind[] {
82
return [...this._closingBrackets.values()];
83
}
84
85
public getOpeningBracketInfo(bracketText: string): OpeningBracketKind | undefined {
86
return this._openingBrackets.get(bracketText);
87
}
88
89
public getClosingBracketInfo(bracketText: string): ClosingBracketKind | undefined {
90
return this._closingBrackets.get(bracketText);
91
}
92
93
public getBracketInfo(bracketText: string): BracketKind | undefined {
94
return this.getOpeningBracketInfo(bracketText) || this.getClosingBracketInfo(bracketText);
95
}
96
97
public getBracketRegExp(options?: RegExpOptions): RegExp {
98
const brackets = Array.from([...this._openingBrackets.keys(), ...this._closingBrackets.keys()]);
99
return createBracketOrRegExp(brackets, options);
100
}
101
}
102
103
function filterValidBrackets(bracketPairs: [string, string][]): [string, string][] {
104
return bracketPairs.filter(([open, close]) => open !== '' && close !== '');
105
}
106
107
export type BracketKind = OpeningBracketKind | ClosingBracketKind;
108
109
export class BracketKindBase {
110
constructor(
111
protected readonly config: LanguageBracketsConfiguration,
112
public readonly bracketText: string,
113
) { }
114
115
public get languageId(): string {
116
return this.config.languageId;
117
}
118
}
119
120
export class OpeningBracketKind extends BracketKindBase {
121
public readonly isOpeningBracket = true;
122
123
constructor(
124
config: LanguageBracketsConfiguration,
125
bracketText: string,
126
public readonly openedBrackets: ReadonlySet<ClosingBracketKind>,
127
) {
128
super(config, bracketText);
129
}
130
}
131
132
export class ClosingBracketKind extends BracketKindBase {
133
public readonly isOpeningBracket = false;
134
135
constructor(
136
config: LanguageBracketsConfiguration,
137
bracketText: string,
138
/**
139
* Non empty array of all opening brackets this bracket closes.
140
*/
141
public readonly openingBrackets: ReadonlySet<OpeningBracketKind>,
142
private readonly openingColorizedBrackets: ReadonlySet<OpeningBracketKind>,
143
) {
144
super(config, bracketText);
145
}
146
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;
154
}
155
return this.openingBrackets.has(other);
156
}
157
158
public closesColorized(other: OpeningBracketKind): boolean {
159
if (other['config'] !== this.config) {
160
return false;
161
}
162
return this.openingColorizedBrackets.has(other);
163
}
164
165
public getOpeningBrackets(): readonly OpeningBracketKind[] {
166
return [...this.openingBrackets];
167
}
168
}
169
170