7f14a611a8a6abc98f6af30238ec2d2f2b336d35d29fddab487f7eebc8ae7fab1e07481f641b4bf4d6e9a91c754e72ef9e65c8c078508b4ead31537c7d25d8 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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 { TokenMetadata } from '../encodedTokenAttributes.js';
  6. export class LineTokens {
  7. constructor(tokens, text, decoder) {
  8. this._lineTokensBrand = undefined;
  9. this._tokens = tokens;
  10. this._tokensCount = (this._tokens.length >>> 1);
  11. this._text = text;
  12. this._languageIdCodec = decoder;
  13. }
  14. static createEmpty(lineContent, decoder) {
  15. const defaultMetadata = LineTokens.defaultTokenMetadata;
  16. const tokens = new Uint32Array(2);
  17. tokens[0] = lineContent.length;
  18. tokens[1] = defaultMetadata;
  19. return new LineTokens(tokens, lineContent, decoder);
  20. }
  21. equals(other) {
  22. if (other instanceof LineTokens) {
  23. return this.slicedEquals(other, 0, this._tokensCount);
  24. }
  25. return false;
  26. }
  27. slicedEquals(other, sliceFromTokenIndex, sliceTokenCount) {
  28. if (this._text !== other._text) {
  29. return false;
  30. }
  31. if (this._tokensCount !== other._tokensCount) {
  32. return false;
  33. }
  34. const from = (sliceFromTokenIndex << 1);
  35. const to = from + (sliceTokenCount << 1);
  36. for (let i = from; i < to; i++) {
  37. if (this._tokens[i] !== other._tokens[i]) {
  38. return false;
  39. }
  40. }
  41. return true;
  42. }
  43. getLineContent() {
  44. return this._text;
  45. }
  46. getCount() {
  47. return this._tokensCount;
  48. }
  49. getStartOffset(tokenIndex) {
  50. if (tokenIndex > 0) {
  51. return this._tokens[(tokenIndex - 1) << 1];
  52. }
  53. return 0;
  54. }
  55. getMetadata(tokenIndex) {
  56. const metadata = this._tokens[(tokenIndex << 1) + 1];
  57. return metadata;
  58. }
  59. getLanguageId(tokenIndex) {
  60. const metadata = this._tokens[(tokenIndex << 1) + 1];
  61. const languageId = TokenMetadata.getLanguageId(metadata);
  62. return this._languageIdCodec.decodeLanguageId(languageId);
  63. }
  64. getStandardTokenType(tokenIndex) {
  65. const metadata = this._tokens[(tokenIndex << 1) + 1];
  66. return TokenMetadata.getTokenType(metadata);
  67. }
  68. getForeground(tokenIndex) {
  69. const metadata = this._tokens[(tokenIndex << 1) + 1];
  70. return TokenMetadata.getForeground(metadata);
  71. }
  72. getClassName(tokenIndex) {
  73. const metadata = this._tokens[(tokenIndex << 1) + 1];
  74. return TokenMetadata.getClassNameFromMetadata(metadata);
  75. }
  76. getInlineStyle(tokenIndex, colorMap) {
  77. const metadata = this._tokens[(tokenIndex << 1) + 1];
  78. return TokenMetadata.getInlineStyleFromMetadata(metadata, colorMap);
  79. }
  80. getPresentation(tokenIndex) {
  81. const metadata = this._tokens[(tokenIndex << 1) + 1];
  82. return TokenMetadata.getPresentationFromMetadata(metadata);
  83. }
  84. getEndOffset(tokenIndex) {
  85. return this._tokens[tokenIndex << 1];
  86. }
  87. /**
  88. * Find the token containing offset `offset`.
  89. * @param offset The search offset
  90. * @return The index of the token containing the offset.
  91. */
  92. findTokenIndexAtOffset(offset) {
  93. return LineTokens.findIndexInTokensArray(this._tokens, offset);
  94. }
  95. inflate() {
  96. return this;
  97. }
  98. sliceAndInflate(startOffset, endOffset, deltaOffset) {
  99. return new SliceLineTokens(this, startOffset, endOffset, deltaOffset);
  100. }
  101. static convertToEndOffset(tokens, lineTextLength) {
  102. const tokenCount = (tokens.length >>> 1);
  103. const lastTokenIndex = tokenCount - 1;
  104. for (let tokenIndex = 0; tokenIndex < lastTokenIndex; tokenIndex++) {
  105. tokens[tokenIndex << 1] = tokens[(tokenIndex + 1) << 1];
  106. }
  107. tokens[lastTokenIndex << 1] = lineTextLength;
  108. }
  109. static findIndexInTokensArray(tokens, desiredIndex) {
  110. if (tokens.length <= 2) {
  111. return 0;
  112. }
  113. let low = 0;
  114. let high = (tokens.length >>> 1) - 1;
  115. while (low < high) {
  116. const mid = low + Math.floor((high - low) / 2);
  117. const endOffset = tokens[(mid << 1)];
  118. if (endOffset === desiredIndex) {
  119. return mid + 1;
  120. }
  121. else if (endOffset < desiredIndex) {
  122. low = mid + 1;
  123. }
  124. else if (endOffset > desiredIndex) {
  125. high = mid;
  126. }
  127. }
  128. return low;
  129. }
  130. /**
  131. * @pure
  132. * @param insertTokens Must be sorted by offset.
  133. */
  134. withInserted(insertTokens) {
  135. if (insertTokens.length === 0) {
  136. return this;
  137. }
  138. let nextOriginalTokenIdx = 0;
  139. let nextInsertTokenIdx = 0;
  140. let text = '';
  141. const newTokens = new Array();
  142. let originalEndOffset = 0;
  143. while (true) {
  144. const nextOriginalTokenEndOffset = nextOriginalTokenIdx < this._tokensCount ? this._tokens[nextOriginalTokenIdx << 1] : -1;
  145. const nextInsertToken = nextInsertTokenIdx < insertTokens.length ? insertTokens[nextInsertTokenIdx] : null;
  146. if (nextOriginalTokenEndOffset !== -1 && (nextInsertToken === null || nextOriginalTokenEndOffset <= nextInsertToken.offset)) {
  147. // original token ends before next insert token
  148. text += this._text.substring(originalEndOffset, nextOriginalTokenEndOffset);
  149. const metadata = this._tokens[(nextOriginalTokenIdx << 1) + 1];
  150. newTokens.push(text.length, metadata);
  151. nextOriginalTokenIdx++;
  152. originalEndOffset = nextOriginalTokenEndOffset;
  153. }
  154. else if (nextInsertToken) {
  155. if (nextInsertToken.offset > originalEndOffset) {
  156. // insert token is in the middle of the next token.
  157. text += this._text.substring(originalEndOffset, nextInsertToken.offset);
  158. const metadata = this._tokens[(nextOriginalTokenIdx << 1) + 1];
  159. newTokens.push(text.length, metadata);
  160. originalEndOffset = nextInsertToken.offset;
  161. }
  162. text += nextInsertToken.text;
  163. newTokens.push(text.length, nextInsertToken.tokenMetadata);
  164. nextInsertTokenIdx++;
  165. }
  166. else {
  167. break;
  168. }
  169. }
  170. return new LineTokens(new Uint32Array(newTokens), text, this._languageIdCodec);
  171. }
  172. }
  173. LineTokens.defaultTokenMetadata = ((0 /* FontStyle.None */ << 11 /* MetadataConsts.FONT_STYLE_OFFSET */)
  174. | (1 /* ColorId.DefaultForeground */ << 15 /* MetadataConsts.FOREGROUND_OFFSET */)
  175. | (2 /* ColorId.DefaultBackground */ << 24 /* MetadataConsts.BACKGROUND_OFFSET */)) >>> 0;
  176. class SliceLineTokens {
  177. constructor(source, startOffset, endOffset, deltaOffset) {
  178. this._source = source;
  179. this._startOffset = startOffset;
  180. this._endOffset = endOffset;
  181. this._deltaOffset = deltaOffset;
  182. this._firstTokenIndex = source.findTokenIndexAtOffset(startOffset);
  183. this._tokensCount = 0;
  184. for (let i = this._firstTokenIndex, len = source.getCount(); i < len; i++) {
  185. const tokenStartOffset = source.getStartOffset(i);
  186. if (tokenStartOffset >= endOffset) {
  187. break;
  188. }
  189. this._tokensCount++;
  190. }
  191. }
  192. getMetadata(tokenIndex) {
  193. return this._source.getMetadata(this._firstTokenIndex + tokenIndex);
  194. }
  195. getLanguageId(tokenIndex) {
  196. return this._source.getLanguageId(this._firstTokenIndex + tokenIndex);
  197. }
  198. getLineContent() {
  199. return this._source.getLineContent().substring(this._startOffset, this._endOffset);
  200. }
  201. equals(other) {
  202. if (other instanceof SliceLineTokens) {
  203. return (this._startOffset === other._startOffset
  204. && this._endOffset === other._endOffset
  205. && this._deltaOffset === other._deltaOffset
  206. && this._source.slicedEquals(other._source, this._firstTokenIndex, this._tokensCount));
  207. }
  208. return false;
  209. }
  210. getCount() {
  211. return this._tokensCount;
  212. }
  213. getForeground(tokenIndex) {
  214. return this._source.getForeground(this._firstTokenIndex + tokenIndex);
  215. }
  216. getEndOffset(tokenIndex) {
  217. const tokenEndOffset = this._source.getEndOffset(this._firstTokenIndex + tokenIndex);
  218. return Math.min(this._endOffset, tokenEndOffset) - this._startOffset + this._deltaOffset;
  219. }
  220. getClassName(tokenIndex) {
  221. return this._source.getClassName(this._firstTokenIndex + tokenIndex);
  222. }
  223. getInlineStyle(tokenIndex, colorMap) {
  224. return this._source.getInlineStyle(this._firstTokenIndex + tokenIndex, colorMap);
  225. }
  226. getPresentation(tokenIndex) {
  227. return this._source.getPresentation(this._firstTokenIndex + tokenIndex);
  228. }
  229. findTokenIndexAtOffset(offset) {
  230. return this._source.findTokenIndexAtOffset(offset + this._startOffset - this._deltaOffset) - this._firstTokenIndex;
  231. }
  232. }