languageConfiguration.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  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._standardTokenMask = 0;
  40. if (Array.isArray(source.notIn)) {
  41. for (let i = 0, len = source.notIn.length; i < len; i++) {
  42. const notIn = source.notIn[i];
  43. switch (notIn) {
  44. case 'string':
  45. this._standardTokenMask |= 2 /* String */;
  46. break;
  47. case 'comment':
  48. this._standardTokenMask |= 1 /* Comment */;
  49. break;
  50. case 'regex':
  51. this._standardTokenMask |= 4 /* RegEx */;
  52. break;
  53. }
  54. }
  55. }
  56. }
  57. isOK(standardToken) {
  58. return (this._standardTokenMask & standardToken) === 0;
  59. }
  60. shouldAutoClose(context, column) {
  61. // Always complete on empty line
  62. if (context.getTokenCount() === 0) {
  63. return true;
  64. }
  65. const tokenIndex = context.findTokenIndexAtOffset(column - 2);
  66. const standardTokenType = context.getStandardTokenType(tokenIndex);
  67. return this.isOK(standardTokenType);
  68. }
  69. _findNeutralCharacterInRange(fromCharCode, toCharCode) {
  70. for (let charCode = fromCharCode; charCode <= toCharCode; charCode++) {
  71. const character = String.fromCharCode(charCode);
  72. if (!this.open.includes(character) && !this.close.includes(character)) {
  73. return character;
  74. }
  75. }
  76. return null;
  77. }
  78. /**
  79. * Find a character in the range [0-9a-zA-Z] that does not appear in the open or close
  80. */
  81. findNeutralCharacter() {
  82. if (!this._neutralCharacterSearched) {
  83. this._neutralCharacterSearched = true;
  84. if (!this._neutralCharacter) {
  85. this._neutralCharacter = this._findNeutralCharacterInRange(48 /* Digit0 */, 57 /* Digit9 */);
  86. }
  87. if (!this._neutralCharacter) {
  88. this._neutralCharacter = this._findNeutralCharacterInRange(97 /* a */, 122 /* z */);
  89. }
  90. if (!this._neutralCharacter) {
  91. this._neutralCharacter = this._findNeutralCharacterInRange(65 /* A */, 90 /* Z */);
  92. }
  93. }
  94. return this._neutralCharacter;
  95. }
  96. }
  97. /**
  98. * @internal
  99. */
  100. export class AutoClosingPairs {
  101. constructor(autoClosingPairs) {
  102. this.autoClosingPairsOpenByStart = new Map();
  103. this.autoClosingPairsOpenByEnd = new Map();
  104. this.autoClosingPairsCloseByStart = new Map();
  105. this.autoClosingPairsCloseByEnd = new Map();
  106. this.autoClosingPairsCloseSingleChar = new Map();
  107. for (const pair of autoClosingPairs) {
  108. appendEntry(this.autoClosingPairsOpenByStart, pair.open.charAt(0), pair);
  109. appendEntry(this.autoClosingPairsOpenByEnd, pair.open.charAt(pair.open.length - 1), pair);
  110. appendEntry(this.autoClosingPairsCloseByStart, pair.close.charAt(0), pair);
  111. appendEntry(this.autoClosingPairsCloseByEnd, pair.close.charAt(pair.close.length - 1), pair);
  112. if (pair.close.length === 1 && pair.open.length === 1) {
  113. appendEntry(this.autoClosingPairsCloseSingleChar, pair.close, pair);
  114. }
  115. }
  116. }
  117. }
  118. function appendEntry(target, key, value) {
  119. if (target.has(key)) {
  120. target.get(key).push(value);
  121. }
  122. else {
  123. target.set(key, [value]);
  124. }
  125. }