Path: blob/main/src/vs/editor/common/languages/supports/languageBracketsConfiguration.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { CachedFunction } from '../../../../base/common/cache.js';6import { RegExpOptions } from '../../../../base/common/strings.js';7import { LanguageConfiguration } from '../languageConfiguration.js';8import { createBracketOrRegExp } from './richEditBrackets.js';910/**11* Captures all bracket related configurations for a single language.12* Immutable.13*/14export class LanguageBracketsConfiguration {15private readonly _openingBrackets: ReadonlyMap<string, OpeningBracketKind>;16private readonly _closingBrackets: ReadonlyMap<string, ClosingBracketKind>;1718constructor(19public readonly languageId: string,20config: LanguageConfiguration,21) {22const bracketPairs = config.brackets ? filterValidBrackets(config.brackets) : [];23const openingBracketInfos = new CachedFunction((bracket: string) => {24const closing = new Set<ClosingBracketKind>();2526return {27info: new OpeningBracketKind(this, bracket, closing),28closing,29};30});31const closingBracketInfos = new CachedFunction((bracket: string) => {32const opening = new Set<OpeningBracketKind>();33const openingColorized = new Set<OpeningBracketKind>();34return {35info: new ClosingBracketKind(this, bracket, opening, openingColorized),36opening,37openingColorized,38};39});4041for (const [open, close] of bracketPairs) {42const opening = openingBracketInfos.get(open);43const closing = closingBracketInfos.get(close);4445opening.closing.add(closing.info);46closing.opening.add(opening.info);47}4849// Treat colorized brackets as brackets, and mark them as colorized.50const colorizedBracketPairs = config.colorizedBracketPairs51? filterValidBrackets(config.colorizedBracketPairs)52// If not configured: Take all brackets except `<` ... `>`53// Many languages set < ... > as bracket pair, even though they also use it as comparison operator.54// This leads to problems when colorizing this bracket, so we exclude it if not explicitly configured otherwise.55// https://github.com/microsoft/vscode/issues/13247656: bracketPairs.filter((p) => !(p[0] === '<' && p[1] === '>'));57for (const [open, close] of colorizedBracketPairs) {58const opening = openingBracketInfos.get(open);59const closing = closingBracketInfos.get(close);6061opening.closing.add(closing.info);62closing.openingColorized.add(opening.info);63closing.opening.add(opening.info);64}6566this._openingBrackets = new Map([...openingBracketInfos.cachedValues].map(([k, v]) => [k, v.info]));67this._closingBrackets = new Map([...closingBracketInfos.cachedValues].map(([k, v]) => [k, v.info]));68}6970/**71* No two brackets have the same bracket text.72*/73public get openingBrackets(): readonly OpeningBracketKind[] {74return [...this._openingBrackets.values()];75}7677/**78* No two brackets have the same bracket text.79*/80public get closingBrackets(): readonly ClosingBracketKind[] {81return [...this._closingBrackets.values()];82}8384public getOpeningBracketInfo(bracketText: string): OpeningBracketKind | undefined {85return this._openingBrackets.get(bracketText);86}8788public getClosingBracketInfo(bracketText: string): ClosingBracketKind | undefined {89return this._closingBrackets.get(bracketText);90}9192public getBracketInfo(bracketText: string): BracketKind | undefined {93return this.getOpeningBracketInfo(bracketText) || this.getClosingBracketInfo(bracketText);94}9596public getBracketRegExp(options?: RegExpOptions): RegExp {97const brackets = Array.from([...this._openingBrackets.keys(), ...this._closingBrackets.keys()]);98return createBracketOrRegExp(brackets, options);99}100}101102function filterValidBrackets(bracketPairs: [string, string][]): [string, string][] {103return bracketPairs.filter(([open, close]) => open !== '' && close !== '');104}105106export type BracketKind = OpeningBracketKind | ClosingBracketKind;107108export class BracketKindBase {109constructor(110protected readonly config: LanguageBracketsConfiguration,111public readonly bracketText: string,112) { }113114public get languageId(): string {115return this.config.languageId;116}117}118119export class OpeningBracketKind extends BracketKindBase {120public readonly isOpeningBracket = true;121122constructor(123config: LanguageBracketsConfiguration,124bracketText: string,125public readonly openedBrackets: ReadonlySet<ClosingBracketKind>,126) {127super(config, bracketText);128}129}130131export class ClosingBracketKind extends BracketKindBase {132public readonly isOpeningBracket = false;133134constructor(135config: LanguageBracketsConfiguration,136bracketText: string,137/**138* Non empty array of all opening brackets this bracket closes.139*/140public readonly openingBrackets: ReadonlySet<OpeningBracketKind>,141private readonly openingColorizedBrackets: ReadonlySet<OpeningBracketKind>,142) {143super(config, bracketText);144}145146/**147* Checks if this bracket closes the given other bracket.148* If the bracket infos come from different configurations, this method will return false.149*/150public closes(other: OpeningBracketKind): boolean {151if (other['config'] !== this.config) {152return false;153}154return this.openingBrackets.has(other);155}156157public closesColorized(other: OpeningBracketKind): boolean {158if (other['config'] !== this.config) {159return false;160}161return this.openingColorizedBrackets.has(other);162}163164public getOpeningBrackets(): readonly OpeningBracketKind[] {165return [...this.openingBrackets];166}167}168169170