Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/common/languages/supports/onEnter.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 { onUnexpectedError } from '../../../../base/common/errors.js';
7
import * as strings from '../../../../base/common/strings.js';
8
import { CharacterPair, EnterAction, IndentAction, OnEnterRule } from '../languageConfiguration.js';
9
import { EditorAutoIndentStrategy } from '../../config/editorOptions.js';
10
11
export interface IOnEnterSupportOptions {
12
brackets?: CharacterPair[];
13
onEnterRules?: OnEnterRule[];
14
}
15
16
interface IProcessedBracketPair {
17
open: string;
18
close: string;
19
openRegExp: RegExp;
20
closeRegExp: RegExp;
21
}
22
23
export class OnEnterSupport {
24
25
private readonly _brackets: IProcessedBracketPair[];
26
private readonly _regExpRules: OnEnterRule[];
27
28
constructor(opts: IOnEnterSupportOptions) {
29
opts = opts || {};
30
opts.brackets = opts.brackets || [
31
['(', ')'],
32
['{', '}'],
33
['[', ']']
34
];
35
36
this._brackets = [];
37
opts.brackets.forEach((bracket) => {
38
const openRegExp = OnEnterSupport._createOpenBracketRegExp(bracket[0]);
39
const closeRegExp = OnEnterSupport._createCloseBracketRegExp(bracket[1]);
40
if (openRegExp && closeRegExp) {
41
this._brackets.push({
42
open: bracket[0],
43
openRegExp: openRegExp,
44
close: bracket[1],
45
closeRegExp: closeRegExp,
46
});
47
}
48
});
49
this._regExpRules = opts.onEnterRules || [];
50
}
51
52
public onEnter(autoIndent: EditorAutoIndentStrategy, previousLineText: string, beforeEnterText: string, afterEnterText: string): EnterAction | null {
53
// (1): `regExpRules`
54
if (autoIndent >= EditorAutoIndentStrategy.Advanced) {
55
for (let i = 0, len = this._regExpRules.length; i < len; i++) {
56
const rule = this._regExpRules[i];
57
const regResult = [{
58
reg: rule.beforeText,
59
text: beforeEnterText
60
}, {
61
reg: rule.afterText,
62
text: afterEnterText
63
}, {
64
reg: rule.previousLineText,
65
text: previousLineText
66
}].every((obj): boolean => {
67
if (!obj.reg) {
68
return true;
69
}
70
71
obj.reg.lastIndex = 0; // To disable the effect of the "g" flag.
72
return obj.reg.test(obj.text);
73
});
74
75
if (regResult) {
76
return rule.action;
77
}
78
}
79
}
80
81
// (2): Special indent-outdent
82
if (autoIndent >= EditorAutoIndentStrategy.Brackets) {
83
if (beforeEnterText.length > 0 && afterEnterText.length > 0) {
84
for (let i = 0, len = this._brackets.length; i < len; i++) {
85
const bracket = this._brackets[i];
86
if (bracket.openRegExp.test(beforeEnterText) && bracket.closeRegExp.test(afterEnterText)) {
87
return { indentAction: IndentAction.IndentOutdent };
88
}
89
}
90
}
91
}
92
93
94
// (4): Open bracket based logic
95
if (autoIndent >= EditorAutoIndentStrategy.Brackets) {
96
if (beforeEnterText.length > 0) {
97
for (let i = 0, len = this._brackets.length; i < len; i++) {
98
const bracket = this._brackets[i];
99
if (bracket.openRegExp.test(beforeEnterText)) {
100
return { indentAction: IndentAction.Indent };
101
}
102
}
103
}
104
}
105
106
return null;
107
}
108
109
private static _createOpenBracketRegExp(bracket: string): RegExp | null {
110
let str = strings.escapeRegExpCharacters(bracket);
111
if (!/\B/.test(str.charAt(0))) {
112
str = '\\b' + str;
113
}
114
str += '\\s*$';
115
return OnEnterSupport._safeRegExp(str);
116
}
117
118
private static _createCloseBracketRegExp(bracket: string): RegExp | null {
119
let str = strings.escapeRegExpCharacters(bracket);
120
if (!/\B/.test(str.charAt(str.length - 1))) {
121
str = str + '\\b';
122
}
123
str = '^\\s*' + str;
124
return OnEnterSupport._safeRegExp(str);
125
}
126
127
private static _safeRegExp(def: string): RegExp | null {
128
try {
129
return new RegExp(def);
130
} catch (err) {
131
onUnexpectedError(err);
132
return null;
133
}
134
}
135
}
136
137