Class: Rigor::CLI::TraceRenderer

Inherits:
Object
  • Object
show all
Defined in:
lib/rigor/cli/trace_renderer.rb

Overview

Replays a ‘Rigor::Inference::FlowTracer` event stream as a terminal animation for `rigor trace`. Each frame draws a box-drawn screen: the source panel (syntax-coloured, current node range underlined) side-by-side with the scope panel (locals accumulated from :bind events), and an event panel describing the current step and the expression stack.

The frame is fitted to the measured terminal: the source panel scrolls vertically (a window centred on the line under evaluation) instead of overflowing the screen height, over-long rows are clipped with an ellipsis instead of wrapping, and the event panel keeps a minimum height of EVENT_PANE_MIN rows so the narration never collapses to a sliver.

Pure ANSI + ‘io/console` (both stdlib) per ADR-0’s zero-runtime- dependency policy. When the output is not a TTY the frames are printed sequentially without cursor control against a default 80×24 layout, which keeps the renderer deterministic under test.

Constant Summary collapse

RESET =
"\e[0m"
DIM =
"\e[90m"
BOLD =
"\e[1m"
HIGHLIGHT =

reverse video for the frame’s source range

"\e[7m"
EVENT_PANE_MIN =

minimum event-panel rows

2
SCOPE_WIDTH_MIN =

minimum scope-column width

19
BODY_HEIGHT_MIN =

never shrink the source window below this

3
DEFAULT_SIZE =
[24, 80].freeze

Instance Method Summary collapse

Constructor Details

#initialize(out:, source:, file:) ⇒ TraceRenderer

Returns a new instance of TraceRenderer.

Parameters:

  • out (IO)
  • source (String)

    the traced file’s source.

  • file (String)

    display path.



39
40
41
42
43
44
# File 'lib/rigor/cli/trace_renderer.rb', line 39

def initialize(out:, source:, file:)
  @out = out
  @source = source
  @file = file
  @lines = source.lines.map(&:chomp)
end

Instance Method Details

#play(events, delay: nil, interactive: false) ⇒ Object

Parameters:

  • events (Array<Rigor::Inference::FlowTracer::Event>)

    the pre-filtered frame list (the command owns kind filtering).

  • delay (Float, nil) (defaults to: nil)

    seconds between frames (autoplay); nil = step on key press when interactive.

  • interactive (Boolean) (defaults to: false)

    whether to clear/redraw and wait.



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/rigor/cli/trace_renderer.rb', line 51

def play(events, delay: nil, interactive: false)
  @rows, @cols = interactive ? terminal_size : DEFAULT_SIZE
  @interactive = interactive
  locals_per_frame = accumulate_locals(events)
  events.each_with_index do |event, index|
    @out.print("\e[H\e[2J") if interactive
    render_frame(event, index: index, total: events.size, locals: locals_per_frame[index])
    @out.puts unless interactive
    next if index == events.size - 1

    if delay
      sleep(delay)
    elsif interactive
      break unless next_frame?
    end
  end
end