async provideDecorationsForPrettifiedAnsi()

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('') };
  }