7f1ce11df50cc88da4ce3fc4ee3397fabe0def72292f0567e0c73fa547d88e55a8c471c05b6d166e9c952905860ef6258fc8dbf93443f64261d15a979ec350 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  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. import { onUnexpectedError } from '../../../../base/common/errors.js';
  6. import * as strings from '../../../../base/common/strings.js';
  7. import { IndentAction } from '../languageConfiguration.js';
  8. export class OnEnterSupport {
  9. constructor(opts) {
  10. opts = opts || {};
  11. opts.brackets = opts.brackets || [
  12. ['(', ')'],
  13. ['{', '}'],
  14. ['[', ']']
  15. ];
  16. this._brackets = [];
  17. opts.brackets.forEach((bracket) => {
  18. const openRegExp = OnEnterSupport._createOpenBracketRegExp(bracket[0]);
  19. const closeRegExp = OnEnterSupport._createCloseBracketRegExp(bracket[1]);
  20. if (openRegExp && closeRegExp) {
  21. this._brackets.push({
  22. open: bracket[0],
  23. openRegExp: openRegExp,
  24. close: bracket[1],
  25. closeRegExp: closeRegExp,
  26. });
  27. }
  28. });
  29. this._regExpRules = opts.onEnterRules || [];
  30. }
  31. onEnter(autoIndent, previousLineText, beforeEnterText, afterEnterText) {
  32. // (1): `regExpRules`
  33. if (autoIndent >= 3 /* EditorAutoIndentStrategy.Advanced */) {
  34. for (let i = 0, len = this._regExpRules.length; i < len; i++) {
  35. const rule = this._regExpRules[i];
  36. const regResult = [{
  37. reg: rule.beforeText,
  38. text: beforeEnterText
  39. }, {
  40. reg: rule.afterText,
  41. text: afterEnterText
  42. }, {
  43. reg: rule.previousLineText,
  44. text: previousLineText
  45. }].every((obj) => {
  46. if (!obj.reg) {
  47. return true;
  48. }
  49. obj.reg.lastIndex = 0; // To disable the effect of the "g" flag.
  50. return obj.reg.test(obj.text);
  51. });
  52. if (regResult) {
  53. return rule.action;
  54. }
  55. }
  56. }
  57. // (2): Special indent-outdent
  58. if (autoIndent >= 2 /* EditorAutoIndentStrategy.Brackets */) {
  59. if (beforeEnterText.length > 0 && afterEnterText.length > 0) {
  60. for (let i = 0, len = this._brackets.length; i < len; i++) {
  61. const bracket = this._brackets[i];
  62. if (bracket.openRegExp.test(beforeEnterText) && bracket.closeRegExp.test(afterEnterText)) {
  63. return { indentAction: IndentAction.IndentOutdent };
  64. }
  65. }
  66. }
  67. }
  68. // (4): Open bracket based logic
  69. if (autoIndent >= 2 /* EditorAutoIndentStrategy.Brackets */) {
  70. if (beforeEnterText.length > 0) {
  71. for (let i = 0, len = this._brackets.length; i < len; i++) {
  72. const bracket = this._brackets[i];
  73. if (bracket.openRegExp.test(beforeEnterText)) {
  74. return { indentAction: IndentAction.Indent };
  75. }
  76. }
  77. }
  78. }
  79. return null;
  80. }
  81. static _createOpenBracketRegExp(bracket) {
  82. let str = strings.escapeRegExpCharacters(bracket);
  83. if (!/\B/.test(str.charAt(0))) {
  84. str = '\\b' + str;
  85. }
  86. str += '\\s*$';
  87. return OnEnterSupport._safeRegExp(str);
  88. }
  89. static _createCloseBracketRegExp(bracket) {
  90. let str = strings.escapeRegExpCharacters(bracket);
  91. if (!/\B/.test(str.charAt(str.length - 1))) {
  92. str = str + '\\b';
  93. }
  94. str = '^\\s*' + str;
  95. return OnEnterSupport._safeRegExp(str);
  96. }
  97. static _safeRegExp(def) {
  98. try {
  99. return new RegExp(def);
  100. }
  101. catch (err) {
  102. onUnexpectedError(err);
  103. return null;
  104. }
  105. }
  106. }