99a27746ac9c6bdcf462ffdcf385494e570dfc2dbf96bb1b57fdb156c2ade5d3f23ed22b304c5011129824aae2fc376363eff5652f02e76ef5ba36e463d959 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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. * Describes what to do with the indentation when pressing Enter.
  7. */
  8. export var IndentAction;
  9. (function (IndentAction) {
  10. /**
  11. * Insert new line and copy the previous line's indentation.
  12. */
  13. IndentAction[IndentAction["None"] = 0] = "None";
  14. /**
  15. * Insert new line and indent once (relative to the previous line's indentation).
  16. */
  17. IndentAction[IndentAction["Indent"] = 1] = "Indent";
  18. /**
  19. * Insert two new lines:
  20. * - the first one indented which will hold the cursor
  21. * - the second one at the same indentation level
  22. */
  23. IndentAction[IndentAction["IndentOutdent"] = 2] = "IndentOutdent";
  24. /**
  25. * Insert new line and outdent once (relative to the previous line's indentation).
  26. */
  27. IndentAction[IndentAction["Outdent"] = 3] = "Outdent";
  28. })(IndentAction || (IndentAction = {}));
  29. /**
  30. * @internal
  31. */
  32. export class StandardAutoClosingPairConditional {
  33. constructor(source) {
  34. this._neutralCharacter = null;
  35. this._neutralCharacterSearched = false;
  36. this.open = source.open;
  37. this.close = source.close;
  38. // initially allowed in all tokens
  39. this._inString = true;
  40. this._inComment = true;
  41. this._inRegEx = true;
  42. if (Array.isArray(source.notIn)) {
  43. for (let i = 0, len = source.notIn.length; i < len; i++) {
  44. const notIn = source.notIn[i];
  45. switch (notIn) {
  46. case 'string':
  47. this._inString = false;
  48. break;
  49. case 'comment':
  50. this._inComment = false;
  51. break;
  52. case 'regex':
  53. this._inRegEx = false;
  54. break;
  55. }
  56. }
  57. }
  58. }
  59. isOK(standardToken) {
  60. switch (standardToken) {
  61. case 0 /* StandardTokenType.Other */:
  62. return true;
  63. case 1 /* StandardTokenType.Comment */:
  64. return this._inComment;
  65. case 2 /* StandardTokenType.String */:
  66. return this._inString;
  67. case 3 /* StandardTokenType.RegEx */:
  68. return this._inRegEx;
  69. }
  70. }
  71. shouldAutoClose(context, column) {
  72. // Always complete on empty line
  73. if (context.getTokenCount() === 0) {
  74. return true;
  75. }
  76. const tokenIndex = context.findTokenIndexAtOffset(column - 2);
  77. const standardTokenType = context.getStandardTokenType(tokenIndex);
  78. return this.isOK(standardTokenType);
  79. }
  80. _findNeutralCharacterInRange(fromCharCode, toCharCode) {
  81. for (let charCode = fromCharCode; charCode <= toCharCode; charCode++) {
  82. const character = String.fromCharCode(charCode);
  83. if (!this.open.includes(character) && !this.close.includes(character)) {
  84. return character;
  85. }
  86. }
  87. return null;
  88. }
  89. /**
  90. * Find a character in the range [0-9a-zA-Z] that does not appear in the open or close
  91. */
  92. findNeutralCharacter() {
  93. if (!this._neutralCharacterSearched) {
  94. this._neutralCharacterSearched = true;
  95. if (!this._neutralCharacter) {
  96. this._neutralCharacter = this._findNeutralCharacterInRange(48 /* CharCode.Digit0 */, 57 /* CharCode.Digit9 */);
  97. }
  98. if (!this._neutralCharacter) {
  99. this._neutralCharacter = this._findNeutralCharacterInRange(97 /* CharCode.a */, 122 /* CharCode.z */);
  100. }
  101. if (!this._neutralCharacter) {
  102. this._neutralCharacter = this._findNeutralCharacterInRange(65 /* CharCode.A */, 90 /* CharCode.Z */);
  103. }
  104. }
  105. return this._neutralCharacter;
  106. }
  107. }
  108. /**
  109. * @internal
  110. */
  111. export class AutoClosingPairs {
  112. constructor(autoClosingPairs) {
  113. this.autoClosingPairsOpenByStart = new Map();
  114. this.autoClosingPairsOpenByEnd = new Map();
  115. this.autoClosingPairsCloseByStart = new Map();
  116. this.autoClosingPairsCloseByEnd = new Map();
  117. this.autoClosingPairsCloseSingleChar = new Map();
  118. for (const pair of autoClosingPairs) {
  119. appendEntry(this.autoClosingPairsOpenByStart, pair.open.charAt(0), pair);
  120. appendEntry(this.autoClosingPairsOpenByEnd, pair.open.charAt(pair.open.length - 1), pair);
  121. appendEntry(this.autoClosingPairsCloseByStart, pair.close.charAt(0), pair);
  122. appendEntry(this.autoClosingPairsCloseByEnd, pair.close.charAt(pair.close.length - 1), pair);
  123. if (pair.close.length === 1 && pair.open.length === 1) {
  124. appendEntry(this.autoClosingPairsCloseSingleChar, pair.close, pair);
  125. }
  126. }
  127. }
  128. }
  129. function appendEntry(target, key, value) {
  130. if (target.has(key)) {
  131. target.get(key).push(value);
  132. }
  133. else {
  134. target.set(key, [value]);
  135. }
  136. }