142
return aTokens;
143
}
145
>
const pieceIndex = SparseTokensStore._findFirstPieceWithLine(pieces, lineNumber);
146
>
const bTokens = pieces[pieceIndex].getLineTokens(lineNumber);
147
>
148
>
if (!bTokens) {
149
return aTokens;
150
}
152
>
const aLen = aTokens.getCount();
153
>
const bLen = bTokens.getCount();
154
>
155
>
let aIndex = 0;
156
>
const result: number[] = [];
157
>
let resultLen = 0;
158
>
let lastEndOffset = 0;
159
>
160
>
const emitToken = (endOffset: number, metadata: number) => {
161
>
if (endOffset <= lastEndOffset) {
162
return;
163
}
165
>
result[resultLen++] = endOffset;
166
>
result[resultLen++] = metadata;
167
>
};
168
>
169
>
for (let bIndex = 0; bIndex < bLen; bIndex++) {
170
>
// bTokens is not validated yet, but aTokens is. We want to make sure that the LineTokens we return
171
>
// are valid, so we clamp the ranges to ensure that.
172
>
const bStartCharacter = Math.min(bTokens.getStartCharacter(bIndex), aTokens.getTextLength());
173
>
const bEndCharacter = Math.min(bTokens.getEndCharacter(bIndex), aTokens.getTextLength());
174
>
const bMetadata = bTokens.getMetadata(bIndex);
175
>
176
>
const bMask = (
177
>
((bMetadata & MetadataConsts.SEMANTIC_USE_ITALIC) ? MetadataConsts.ITALIC_MASK : 0)
178
>
| ((bMetadata & MetadataConsts.SEMANTIC_USE_BOLD) ? MetadataConsts.BOLD_MASK : 0)
179
>
| ((bMetadata & MetadataConsts.SEMANTIC_USE_UNDERLINE) ? MetadataConsts.UNDERLINE_MASK : 0)
180
>
| ((bMetadata & MetadataConsts.SEMANTIC_USE_STRIKETHROUGH) ? MetadataConsts.STRIKETHROUGH_MASK : 0)
181
>
| ((bMetadata & MetadataConsts.SEMANTIC_USE_FOREGROUND) ? MetadataConsts.FOREGROUND_MASK : 0)
182
>
| ((bMetadata & MetadataConsts.SEMANTIC_USE_BACKGROUND) ? MetadataConsts.BACKGROUND_MASK : 0)
183
>
) >>> 0;
184
>
const aMask = (~bMask) >>> 0;
185
>
186
>
// push any token from `a` that is before `b`
187
>
while (aIndex < aLen && aTokens.getEndOffset(aIndex) <= bStartCharacter) {
188
emitToken(aTokens.getEndOffset(aIndex), aTokens.getMetadata(aIndex));
189
aIndex++;
190
}
192
>
// push the token from `a` if it intersects the token from `b`
193
>
if (aIndex < aLen && aTokens.getStartOffset(aIndex) < bStartCharacter) {
194
>
emitToken(bStartCharacter, aTokens.getMetadata(aIndex));
195
>
}
196
>
197
>
// skip any tokens from `a` that are contained inside `b`
198
>
while (aIndex < aLen && aTokens.getEndOffset(aIndex) < bEndCharacter) {
199
emitToken(aTokens.getEndOffset(aIndex), (aTokens.getMetadata(aIndex) & aMask) | (bMetadata & bMask));
200
aIndex++;
201
}
203
>
if (aIndex < aLen) {
204
>
emitToken(bEndCharacter, (aTokens.getMetadata(aIndex) & aMask) | (bMetadata & bMask));
205
>
if (aTokens.getEndOffset(aIndex) === bEndCharacter) {
206
// `a` ends exactly at the same spot as `b`!
207
aIndex++;
208
}
210
const aMergeIndex = Math.min(Math.max(0, aIndex - 1), aLen - 1);
211