in src/desktop/ci/ansi_decoration_provider.ts [137:228]
async provideDecorationsForPrettifiedAnsi(
rawJobTrace: string,
isRunning: boolean,
): Promise<{
sections: Map<string, JobTraceSection>;
decorations: Map<string, vscode.DecorationOptions[]>;
filtered: string;
}> {
const actualDocument = splitDocumentIntoLines(rawJobTrace);
const lineCount = actualDocument.length;
const decorations = new Map<string, vscode.DecorationOptions[]>();
const sections = new Map<string, JobTraceSection>();
const parser = new ansi.Parser();
const textChunks: string[] = [];
for (let lineNumber = 0; lineNumber < lineCount; lineNumber += 1) {
let totalEscapeLength = 0;
const rawLine = actualDocument[lineNumber];
const crIndex = rawLine.lastIndexOf('\r', rawLine.length - 2);
const lineEndIndex =
rawLine[rawLine.length - 1] === '\r' ? rawLine.length - 1 : rawLine.length;
if (crIndex !== -1) {
const startTag = parseSectionDirective(rawLine, 'section_start', crIndex);
if (startTag) {
sections.set(startTag.key, {
startLine: lineNumber,
startTime: startTag.time,
});
}
const endTag = parseSectionDirective(rawLine, 'section_end', crIndex);
if (endTag) {
const sectionStart = sections.get(endTag.key);
if (sectionStart) {
sections.set(endTag.key, {
...sectionStart,
endLine: lineNumber - 1,
endTime: endTag.time,
});
}
}
}
const line = rawLine.substring(crIndex + 1, lineEndIndex);
const spans = parser.appendLine(line);
spans.forEach(span => {
const { offset, length, ...style } = span;
if (style.attributeFlags & ansi.AttributeFlags.EscapeSequence) {
totalEscapeLength += length;
return;
}
const range = new vscode.Range(
lineNumber,
offset - totalEscapeLength,
lineNumber,
offset + length - totalEscapeLength,
);
const key = JSON.stringify(style);
upsert(decorations, key, []).push({ range });
textChunks.push(line.substr(offset, length));
});
// Each file must end with at least one newline, to avoid the decoration
// containing the running animation from overlapping other text.
if (lineNumber < lineCount - 1 || line.length > 0) {
textChunks.push('\n');
}
}
if (isRunning) {
const eolRange =
actualDocument[lineCount - 1].length > 0
? new vscode.Range(lineCount, 0, lineCount, 0)
: new vscode.Range(lineCount - 1, 0, lineCount - 1, 0);
decorations.set('running', [{ range: eolRange }]);
} else {
decorations.set('running', []);
}
return { sections, decorations, filtered: textChunks.join('') };
}