7f581fba34fbe6d50bb5988d07095fd09c9160f0b14eb221f542860b3bd4f58159538e74fdb7968785dfacdcd0fa125a0a9deec20bd5acc56f2dc87fceb8f1 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  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 { Emitter } from '../../../../../base/common/event.js';
  6. import { Disposable } from '../../../../../base/common/lifecycle.js';
  7. import { Range } from '../../../core/range.js';
  8. import { BracketInfo, BracketPairWithMinIndentationInfo } from '../../../textModelBracketPairs.js';
  9. import { TextEditInfo } from './beforeEditPositionMapper.js';
  10. import { LanguageAgnosticBracketTokens } from './brackets.js';
  11. import { lengthAdd, lengthGreaterThanEqual, lengthLessThan, lengthLessThanEqual, lengthOfString, lengthsToRange, lengthZero, positionToLength, toLength } from './length.js';
  12. import { parseDocument } from './parser.js';
  13. import { DenseKeyProvider } from './smallImmutableSet.js';
  14. import { FastTokenizer, TextBufferTokenizer } from './tokenizer.js';
  15. export class BracketPairsTree extends Disposable {
  16. constructor(textModel, getLanguageConfiguration) {
  17. super();
  18. this.textModel = textModel;
  19. this.getLanguageConfiguration = getLanguageConfiguration;
  20. this.didChangeEmitter = new Emitter();
  21. this.denseKeyProvider = new DenseKeyProvider();
  22. this.brackets = new LanguageAgnosticBracketTokens(this.denseKeyProvider, this.getLanguageConfiguration);
  23. this.onDidChange = this.didChangeEmitter.event;
  24. if (textModel.tokenization.backgroundTokenizationState === 0 /* BackgroundTokenizationState.Uninitialized */) {
  25. // There are no token information yet
  26. const brackets = this.brackets.getSingleLanguageBracketTokens(this.textModel.getLanguageId());
  27. const tokenizer = new FastTokenizer(this.textModel.getValue(), brackets);
  28. this.initialAstWithoutTokens = parseDocument(tokenizer, [], undefined, true);
  29. this.astWithTokens = this.initialAstWithoutTokens;
  30. }
  31. else if (textModel.tokenization.backgroundTokenizationState === 2 /* BackgroundTokenizationState.Completed */) {
  32. // Skip the initial ast, as there is no flickering.
  33. // Directly create the tree with token information.
  34. this.initialAstWithoutTokens = undefined;
  35. this.astWithTokens = this.parseDocumentFromTextBuffer([], undefined, false);
  36. }
  37. else if (textModel.tokenization.backgroundTokenizationState === 1 /* BackgroundTokenizationState.InProgress */) {
  38. this.initialAstWithoutTokens = this.parseDocumentFromTextBuffer([], undefined, true);
  39. this.astWithTokens = this.initialAstWithoutTokens;
  40. }
  41. }
  42. didLanguageChange(languageId) {
  43. return this.brackets.didLanguageChange(languageId);
  44. }
  45. //#region TextModel events
  46. handleDidChangeBackgroundTokenizationState() {
  47. if (this.textModel.tokenization.backgroundTokenizationState === 2 /* BackgroundTokenizationState.Completed */) {
  48. const wasUndefined = this.initialAstWithoutTokens === undefined;
  49. // Clear the initial tree as we can use the tree with token information now.
  50. this.initialAstWithoutTokens = undefined;
  51. if (!wasUndefined) {
  52. this.didChangeEmitter.fire();
  53. }
  54. }
  55. }
  56. handleDidChangeTokens({ ranges }) {
  57. const edits = ranges.map(r => new TextEditInfo(toLength(r.fromLineNumber - 1, 0), toLength(r.toLineNumber, 0), toLength(r.toLineNumber - r.fromLineNumber + 1, 0)));
  58. this.astWithTokens = this.parseDocumentFromTextBuffer(edits, this.astWithTokens, false);
  59. if (!this.initialAstWithoutTokens) {
  60. this.didChangeEmitter.fire();
  61. }
  62. }
  63. handleContentChanged(change) {
  64. const edits = change.changes.map(c => {
  65. const range = Range.lift(c.range);
  66. return new TextEditInfo(positionToLength(range.getStartPosition()), positionToLength(range.getEndPosition()), lengthOfString(c.text));
  67. }).reverse();
  68. this.astWithTokens = this.parseDocumentFromTextBuffer(edits, this.astWithTokens, false);
  69. if (this.initialAstWithoutTokens) {
  70. this.initialAstWithoutTokens = this.parseDocumentFromTextBuffer(edits, this.initialAstWithoutTokens, false);
  71. }
  72. }
  73. //#endregion
  74. /**
  75. * @pure (only if isPure = true)
  76. */
  77. parseDocumentFromTextBuffer(edits, previousAst, immutable) {
  78. // Is much faster if `isPure = false`.
  79. const isPure = false;
  80. const previousAstClone = isPure ? previousAst === null || previousAst === void 0 ? void 0 : previousAst.deepClone() : previousAst;
  81. const tokenizer = new TextBufferTokenizer(this.textModel, this.brackets);
  82. const result = parseDocument(tokenizer, edits, previousAstClone, immutable);
  83. return result;
  84. }
  85. getBracketsInRange(range) {
  86. const startOffset = toLength(range.startLineNumber - 1, range.startColumn - 1);
  87. const endOffset = toLength(range.endLineNumber - 1, range.endColumn - 1);
  88. const result = new Array();
  89. const node = this.initialAstWithoutTokens || this.astWithTokens;
  90. collectBrackets(node, lengthZero, node.length, startOffset, endOffset, result, 0, new Map());
  91. return result;
  92. }
  93. getBracketPairsInRange(range, includeMinIndentation) {
  94. const result = new Array();
  95. const startLength = positionToLength(range.getStartPosition());
  96. const endLength = positionToLength(range.getEndPosition());
  97. const node = this.initialAstWithoutTokens || this.astWithTokens;
  98. const context = new CollectBracketPairsContext(result, includeMinIndentation, this.textModel);
  99. collectBracketPairs(node, lengthZero, node.length, startLength, endLength, context, 0, new Map());
  100. return result;
  101. }
  102. getFirstBracketAfter(position) {
  103. const node = this.initialAstWithoutTokens || this.astWithTokens;
  104. return getFirstBracketAfter(node, lengthZero, node.length, positionToLength(position));
  105. }
  106. getFirstBracketBefore(position) {
  107. const node = this.initialAstWithoutTokens || this.astWithTokens;
  108. return getFirstBracketBefore(node, lengthZero, node.length, positionToLength(position));
  109. }
  110. }
  111. function getFirstBracketBefore(node, nodeOffsetStart, nodeOffsetEnd, position) {
  112. if (node.kind === 4 /* AstNodeKind.List */ || node.kind === 2 /* AstNodeKind.Pair */) {
  113. const lengths = [];
  114. for (const child of node.children) {
  115. nodeOffsetEnd = lengthAdd(nodeOffsetStart, child.length);
  116. lengths.push({ nodeOffsetStart, nodeOffsetEnd });
  117. nodeOffsetStart = nodeOffsetEnd;
  118. }
  119. for (let i = lengths.length - 1; i >= 0; i--) {
  120. const { nodeOffsetStart, nodeOffsetEnd } = lengths[i];
  121. if (lengthLessThan(nodeOffsetStart, position)) {
  122. const result = getFirstBracketBefore(node.children[i], nodeOffsetStart, nodeOffsetEnd, position);
  123. if (result) {
  124. return result;
  125. }
  126. }
  127. }
  128. return null;
  129. }
  130. else if (node.kind === 3 /* AstNodeKind.UnexpectedClosingBracket */) {
  131. return null;
  132. }
  133. else if (node.kind === 1 /* AstNodeKind.Bracket */) {
  134. const range = lengthsToRange(nodeOffsetStart, nodeOffsetEnd);
  135. return {
  136. bracketInfo: node.bracketInfo,
  137. range
  138. };
  139. }
  140. return null;
  141. }
  142. function getFirstBracketAfter(node, nodeOffsetStart, nodeOffsetEnd, position) {
  143. if (node.kind === 4 /* AstNodeKind.List */ || node.kind === 2 /* AstNodeKind.Pair */) {
  144. for (const child of node.children) {
  145. nodeOffsetEnd = lengthAdd(nodeOffsetStart, child.length);
  146. if (lengthLessThan(position, nodeOffsetEnd)) {
  147. const result = getFirstBracketAfter(child, nodeOffsetStart, nodeOffsetEnd, position);
  148. if (result) {
  149. return result;
  150. }
  151. }
  152. nodeOffsetStart = nodeOffsetEnd;
  153. }
  154. return null;
  155. }
  156. else if (node.kind === 3 /* AstNodeKind.UnexpectedClosingBracket */) {
  157. return null;
  158. }
  159. else if (node.kind === 1 /* AstNodeKind.Bracket */) {
  160. const range = lengthsToRange(nodeOffsetStart, nodeOffsetEnd);
  161. return {
  162. bracketInfo: node.bracketInfo,
  163. range
  164. };
  165. }
  166. return null;
  167. }
  168. function collectBrackets(node, nodeOffsetStart, nodeOffsetEnd, startOffset, endOffset, result, level, levelPerBracketType) {
  169. if (level > 200) {
  170. return;
  171. }
  172. if (node.kind === 4 /* AstNodeKind.List */) {
  173. for (const child of node.children) {
  174. nodeOffsetEnd = lengthAdd(nodeOffsetStart, child.length);
  175. if (lengthLessThanEqual(nodeOffsetStart, endOffset) &&
  176. lengthGreaterThanEqual(nodeOffsetEnd, startOffset)) {
  177. collectBrackets(child, nodeOffsetStart, nodeOffsetEnd, startOffset, endOffset, result, level, levelPerBracketType);
  178. }
  179. nodeOffsetStart = nodeOffsetEnd;
  180. }
  181. }
  182. else if (node.kind === 2 /* AstNodeKind.Pair */) {
  183. let levelPerBracket = 0;
  184. if (levelPerBracketType) {
  185. let existing = levelPerBracketType.get(node.openingBracket.text);
  186. if (existing === undefined) {
  187. existing = 0;
  188. }
  189. levelPerBracket = existing;
  190. existing++;
  191. levelPerBracketType.set(node.openingBracket.text, existing);
  192. }
  193. // Don't use node.children here to improve performance
  194. {
  195. const child = node.openingBracket;
  196. nodeOffsetEnd = lengthAdd(nodeOffsetStart, child.length);
  197. if (lengthLessThanEqual(nodeOffsetStart, endOffset) &&
  198. lengthGreaterThanEqual(nodeOffsetEnd, startOffset)) {
  199. const range = lengthsToRange(nodeOffsetStart, nodeOffsetEnd);
  200. result.push(new BracketInfo(range, level, levelPerBracket, !node.closingBracket));
  201. }
  202. nodeOffsetStart = nodeOffsetEnd;
  203. }
  204. if (node.child) {
  205. const child = node.child;
  206. nodeOffsetEnd = lengthAdd(nodeOffsetStart, child.length);
  207. if (lengthLessThanEqual(nodeOffsetStart, endOffset) &&
  208. lengthGreaterThanEqual(nodeOffsetEnd, startOffset)) {
  209. collectBrackets(child, nodeOffsetStart, nodeOffsetEnd, startOffset, endOffset, result, level + 1, levelPerBracketType);
  210. }
  211. nodeOffsetStart = nodeOffsetEnd;
  212. }
  213. if (node.closingBracket) {
  214. const child = node.closingBracket;
  215. nodeOffsetEnd = lengthAdd(nodeOffsetStart, child.length);
  216. if (lengthLessThanEqual(nodeOffsetStart, endOffset) &&
  217. lengthGreaterThanEqual(nodeOffsetEnd, startOffset)) {
  218. const range = lengthsToRange(nodeOffsetStart, nodeOffsetEnd);
  219. result.push(new BracketInfo(range, level, levelPerBracket, false));
  220. }
  221. nodeOffsetStart = nodeOffsetEnd;
  222. }
  223. levelPerBracketType === null || levelPerBracketType === void 0 ? void 0 : levelPerBracketType.set(node.openingBracket.text, levelPerBracket);
  224. }
  225. else if (node.kind === 3 /* AstNodeKind.UnexpectedClosingBracket */) {
  226. const range = lengthsToRange(nodeOffsetStart, nodeOffsetEnd);
  227. result.push(new BracketInfo(range, level - 1, 0, true));
  228. }
  229. else if (node.kind === 1 /* AstNodeKind.Bracket */) {
  230. const range = lengthsToRange(nodeOffsetStart, nodeOffsetEnd);
  231. result.push(new BracketInfo(range, level - 1, 0, false));
  232. }
  233. }
  234. class CollectBracketPairsContext {
  235. constructor(result, includeMinIndentation, textModel) {
  236. this.result = result;
  237. this.includeMinIndentation = includeMinIndentation;
  238. this.textModel = textModel;
  239. }
  240. }
  241. function collectBracketPairs(node, nodeOffsetStart, nodeOffsetEnd, startOffset, endOffset, context, level, levelPerBracketType) {
  242. var _a;
  243. if (level > 200) {
  244. return;
  245. }
  246. if (node.kind === 2 /* AstNodeKind.Pair */) {
  247. let levelPerBracket = 0;
  248. if (levelPerBracketType) {
  249. let existing = levelPerBracketType.get(node.openingBracket.text);
  250. if (existing === undefined) {
  251. existing = 0;
  252. }
  253. levelPerBracket = existing;
  254. existing++;
  255. levelPerBracketType.set(node.openingBracket.text, existing);
  256. }
  257. const openingBracketEnd = lengthAdd(nodeOffsetStart, node.openingBracket.length);
  258. let minIndentation = -1;
  259. if (context.includeMinIndentation) {
  260. minIndentation = node.computeMinIndentation(nodeOffsetStart, context.textModel);
  261. }
  262. context.result.push(new BracketPairWithMinIndentationInfo(lengthsToRange(nodeOffsetStart, nodeOffsetEnd), lengthsToRange(nodeOffsetStart, openingBracketEnd), node.closingBracket
  263. ? lengthsToRange(lengthAdd(openingBracketEnd, ((_a = node.child) === null || _a === void 0 ? void 0 : _a.length) || lengthZero), nodeOffsetEnd)
  264. : undefined, level, levelPerBracket, node, minIndentation));
  265. nodeOffsetStart = openingBracketEnd;
  266. if (node.child) {
  267. const child = node.child;
  268. nodeOffsetEnd = lengthAdd(nodeOffsetStart, child.length);
  269. if (lengthLessThanEqual(nodeOffsetStart, endOffset) &&
  270. lengthGreaterThanEqual(nodeOffsetEnd, startOffset)) {
  271. collectBracketPairs(child, nodeOffsetStart, nodeOffsetEnd, startOffset, endOffset, context, level + 1, levelPerBracketType);
  272. }
  273. }
  274. levelPerBracketType === null || levelPerBracketType === void 0 ? void 0 : levelPerBracketType.set(node.openingBracket.text, levelPerBracket);
  275. }
  276. else {
  277. let curOffset = nodeOffsetStart;
  278. for (const child of node.children) {
  279. const childOffset = curOffset;
  280. curOffset = lengthAdd(curOffset, child.length);
  281. if (lengthLessThanEqual(childOffset, endOffset) &&
  282. lengthLessThanEqual(startOffset, curOffset)) {
  283. collectBracketPairs(child, childOffset, curOffset, startOffset, endOffset, context, level, levelPerBracketType);
  284. }
  285. }
  286. }
  287. }