Path: blob/main/src/vs/editor/common/languages/supports/onEnter.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 { onUnexpectedError } from '../../../../base/common/errors.js';6import * as strings from '../../../../base/common/strings.js';7import { CharacterPair, EnterAction, IndentAction, OnEnterRule } from '../languageConfiguration.js';8import { EditorAutoIndentStrategy } from '../../config/editorOptions.js';910export interface IOnEnterSupportOptions {11brackets?: CharacterPair[];12onEnterRules?: OnEnterRule[];13}1415interface IProcessedBracketPair {16open: string;17close: string;18openRegExp: RegExp;19closeRegExp: RegExp;20}2122export class OnEnterSupport {2324private readonly _brackets: IProcessedBracketPair[];25private readonly _regExpRules: OnEnterRule[];2627constructor(opts: IOnEnterSupportOptions) {28opts = opts || {};29opts.brackets = opts.brackets || [30['(', ')'],31['{', '}'],32['[', ']']33];3435this._brackets = [];36opts.brackets.forEach((bracket) => {37const openRegExp = OnEnterSupport._createOpenBracketRegExp(bracket[0]);38const closeRegExp = OnEnterSupport._createCloseBracketRegExp(bracket[1]);39if (openRegExp && closeRegExp) {40this._brackets.push({41open: bracket[0],42openRegExp: openRegExp,43close: bracket[1],44closeRegExp: closeRegExp,45});46}47});48this._regExpRules = opts.onEnterRules || [];49}5051public onEnter(autoIndent: EditorAutoIndentStrategy, previousLineText: string, beforeEnterText: string, afterEnterText: string): EnterAction | null {52// (1): `regExpRules`53if (autoIndent >= EditorAutoIndentStrategy.Advanced) {54for (let i = 0, len = this._regExpRules.length; i < len; i++) {55const rule = this._regExpRules[i];56const regResult = [{57reg: rule.beforeText,58text: beforeEnterText59}, {60reg: rule.afterText,61text: afterEnterText62}, {63reg: rule.previousLineText,64text: previousLineText65}].every((obj): boolean => {66if (!obj.reg) {67return true;68}6970obj.reg.lastIndex = 0; // To disable the effect of the "g" flag.71return obj.reg.test(obj.text);72});7374if (regResult) {75return rule.action;76}77}78}7980// (2): Special indent-outdent81if (autoIndent >= EditorAutoIndentStrategy.Brackets) {82if (beforeEnterText.length > 0 && afterEnterText.length > 0) {83for (let i = 0, len = this._brackets.length; i < len; i++) {84const bracket = this._brackets[i];85if (bracket.openRegExp.test(beforeEnterText) && bracket.closeRegExp.test(afterEnterText)) {86return { indentAction: IndentAction.IndentOutdent };87}88}89}90}919293// (4): Open bracket based logic94if (autoIndent >= EditorAutoIndentStrategy.Brackets) {95if (beforeEnterText.length > 0) {96for (let i = 0, len = this._brackets.length; i < len; i++) {97const bracket = this._brackets[i];98if (bracket.openRegExp.test(beforeEnterText)) {99return { indentAction: IndentAction.Indent };100}101}102}103}104105return null;106}107108private static _createOpenBracketRegExp(bracket: string): RegExp | null {109let str = strings.escapeRegExpCharacters(bracket);110if (!/\B/.test(str.charAt(0))) {111str = '\\b' + str;112}113str += '\\s*$';114return OnEnterSupport._safeRegExp(str);115}116117private static _createCloseBracketRegExp(bracket: string): RegExp | null {118let str = strings.escapeRegExpCharacters(bracket);119if (!/\B/.test(str.charAt(str.length - 1))) {120str = str + '\\b';121}122str = '^\\s*' + str;123return OnEnterSupport._safeRegExp(str);124}125126private static _safeRegExp(def: string): RegExp | null {127try {128return new RegExp(def);129} catch (err) {130onUnexpectedError(err);131return null;132}133}134}135136137