e3f73be13d59b5e8b4947c8d8ec4aea89d4e87b3eb927046637a89a4f775851aadb7158bf6f48fcba71fb7ca3005bde19f1251a57638939b75a30918a404a7 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  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 { escapeRegExpCharacters } from '../../../../../base/common/strings.js';
  6. import { BracketAstNode } from './ast.js';
  7. import { toLength } from './length.js';
  8. import { identityKeyProvider, SmallImmutableSet } from './smallImmutableSet.js';
  9. import { Token } from './tokenizer.js';
  10. export class BracketTokens {
  11. constructor(map) {
  12. this.map = map;
  13. this.hasRegExp = false;
  14. this._regExpGlobal = null;
  15. }
  16. static createFromLanguage(configuration, denseKeyProvider) {
  17. function getId(bracketInfo) {
  18. return denseKeyProvider.getKey(`${bracketInfo.languageId}:::${bracketInfo.bracketText}`);
  19. }
  20. const map = new Map();
  21. for (const openingBracket of configuration.bracketsNew.openingBrackets) {
  22. const length = toLength(0, openingBracket.bracketText.length);
  23. const openingTextId = getId(openingBracket);
  24. const bracketIds = SmallImmutableSet.getEmpty().add(openingTextId, identityKeyProvider);
  25. map.set(openingBracket.bracketText, new Token(length, 1 /* TokenKind.OpeningBracket */, openingTextId, bracketIds, BracketAstNode.create(length, openingBracket, bracketIds)));
  26. }
  27. for (const closingBracket of configuration.bracketsNew.closingBrackets) {
  28. const length = toLength(0, closingBracket.bracketText.length);
  29. let bracketIds = SmallImmutableSet.getEmpty();
  30. const closingBrackets = closingBracket.getClosedBrackets();
  31. for (const bracket of closingBrackets) {
  32. bracketIds = bracketIds.add(getId(bracket), identityKeyProvider);
  33. }
  34. map.set(closingBracket.bracketText, new Token(length, 2 /* TokenKind.ClosingBracket */, getId(closingBrackets[0]), bracketIds, BracketAstNode.create(length, closingBracket, bracketIds)));
  35. }
  36. return new BracketTokens(map);
  37. }
  38. getRegExpStr() {
  39. if (this.isEmpty) {
  40. return null;
  41. }
  42. else {
  43. const keys = [...this.map.keys()];
  44. keys.sort();
  45. keys.reverse();
  46. return keys.map(k => prepareBracketForRegExp(k)).join('|');
  47. }
  48. }
  49. /**
  50. * Returns null if there is no such regexp (because there are no brackets).
  51. */
  52. get regExpGlobal() {
  53. if (!this.hasRegExp) {
  54. const regExpStr = this.getRegExpStr();
  55. this._regExpGlobal = regExpStr ? new RegExp(regExpStr, 'gi') : null;
  56. this.hasRegExp = true;
  57. }
  58. return this._regExpGlobal;
  59. }
  60. getToken(value) {
  61. return this.map.get(value.toLowerCase());
  62. }
  63. findClosingTokenText(openingBracketIds) {
  64. for (const [closingText, info] of this.map) {
  65. if (info.kind === 2 /* TokenKind.ClosingBracket */ && info.bracketIds.intersects(openingBracketIds)) {
  66. return closingText;
  67. }
  68. }
  69. return undefined;
  70. }
  71. get isEmpty() {
  72. return this.map.size === 0;
  73. }
  74. }
  75. function prepareBracketForRegExp(str) {
  76. let escaped = escapeRegExpCharacters(str);
  77. // These bracket pair delimiters start or end with letters
  78. // see https://github.com/microsoft/vscode/issues/132162 https://github.com/microsoft/vscode/issues/150440
  79. if (/^[\w ]+/.test(str)) {
  80. escaped = `\\b${escaped}`;
  81. }
  82. if (/[\w ]+$/.test(str)) {
  83. escaped = `${escaped}\\b`;
  84. }
  85. return escaped;
  86. }
  87. export class LanguageAgnosticBracketTokens {
  88. constructor(denseKeyProvider, getLanguageConfiguration) {
  89. this.denseKeyProvider = denseKeyProvider;
  90. this.getLanguageConfiguration = getLanguageConfiguration;
  91. this.languageIdToBracketTokens = new Map();
  92. }
  93. didLanguageChange(languageId) {
  94. // Report a change whenever the language configuration updates.
  95. return this.languageIdToBracketTokens.has(languageId);
  96. }
  97. getSingleLanguageBracketTokens(languageId) {
  98. let singleLanguageBracketTokens = this.languageIdToBracketTokens.get(languageId);
  99. if (!singleLanguageBracketTokens) {
  100. singleLanguageBracketTokens = BracketTokens.createFromLanguage(this.getLanguageConfiguration(languageId), this.denseKeyProvider);
  101. this.languageIdToBracketTokens.set(languageId, singleLanguageBracketTokens);
  102. }
  103. return singleLanguageBracketTokens;
  104. }
  105. }