Source code for pysnap.report.highlight

"""Highlighting of prompts and entered commands in a transcript.

The ``report`` prompt is recorded without colors, so PySnap styles its parts
like a typical colored bash prompt and shows entered commands in bold. The
result is a list of styled runs per line that any front end can draw.
"""

from __future__ import annotations

from pysnap.report.models import (
    CellStyle,
    CommandRecord,
    StyledRun,
    Transcript,
    TranscriptLine,
)
from pysnap.report.render import PROMPT_PATTERN

PROMPT_USER_STYLE = CellStyle(fg="green", bold=True)
PROMPT_HOST_STYLE = CellStyle(fg="cyan", bold=True)
PROMPT_DIRECTORY_STYLE = CellStyle(fg="blue", bold=True)
PROMPT_MARK_STYLE = CellStyle(bold=True)
COMMAND_STYLE = CellStyle(bold=True)


[docs] def highlight_transcript(transcript: Transcript) -> list[tuple[StyledRun, ...]]: """Return the transcript lines with highlighted prompts and commands. Lines without a command keep the styles produced by the guest. :param transcript: Rendered session. :returns: Styled runs for every transcript line. """ first_lines = {command.line: command for command in transcript.commands} continuation: set[int] = set() for command in transcript.commands: continuation.update(range(command.line + 1, command.output_start)) highlighted: list[tuple[StyledRun, ...]] = [] for number, line in enumerate(transcript.lines): if number in first_lines: highlighted.append(_command_line_runs(line, first_lines[number])) elif number in continuation: highlighted.append((StyledRun(line.text, COMMAND_STYLE),)) else: highlighted.append(line.runs) return highlighted
def _command_line_runs(line: TranscriptLine, command: CommandRecord) -> tuple[StyledRun, ...]: """Style the first line of a command: prompt parts and the input.""" text = line.text prompt_text, input_text = text[: command.column], text[command.column:] runs: list[StyledRun] = [] stripped = prompt_text.rstrip() match = PROMPT_PATTERN.match(stripped) if match is not None: runs.extend( [ StyledRun("["), StyledRun(match["user"], PROMPT_USER_STYLE), StyledRun("@"), StyledRun(f"{match['task']}-{match['host']}", PROMPT_HOST_STYLE), StyledRun(" "), StyledRun(match["dir"], PROMPT_DIRECTORY_STYLE), StyledRun("]"), StyledRun(stripped[-1], PROMPT_MARK_STYLE), StyledRun(prompt_text[len(stripped):]), ] ) elif prompt_text: runs.append(StyledRun(prompt_text)) runs.append(StyledRun(input_text, COMMAND_STYLE)) return tuple(run for run in runs if run.text)