Class: Przn::Renderer

Inherits:
Object
  • Object
show all
Defined in:
lib/przn/renderer.rb

Direct Known Subclasses

PresenterRenderer

Constant Summary collapse

ANSI =
{
  bold:          "\e[1m",
  italic:        "\e[3m",
  reverse:       "\e[7m",
  strikethrough: "\e[9m",
  dim:           "\e[2m",
  cyan:          "\e[36m",
  gray_bg:       "\e[48;5;236m",
  reset:         "\e[0m"
}.freeze
DEFAULT_SCALE =
2
DEFAULT_IMAGE_RELATIVE_HEIGHT_PERCENT =

Default ‘relative_height` (as a percent of terminal height) applied to image blocks that don’t carry an explicit one. Caps how much of the screen a single image can occupy; the rest leaves predictable margin for the slide footer and avoids placement-clearing edge cases in some terminals when an image lands right against the bottom row.

70

Instance Method Summary collapse

Constructor Details

#initialize(terminal, base_dir: '.', theme: nil, mode: :solo) ⇒ Renderer

‘mode:` controls whether `note` / `<note>` segments are rendered:

:solo      — dim-inline (today's behavior), default for stand-alone runs.
:audience  — stripped from output; the projector view never shows notes.
:presenter — dim-inline (so the presenter sees them in context) and
             ALSO aggregated separately for the side panel via
             Slide#notes; this renderer just keeps the inline copy.


31
32
33
34
35
36
37
38
39
# File 'lib/przn/renderer.rb', line 31

def initialize(terminal, base_dir: '.', theme: nil, mode: :solo)
  @terminal = terminal
  @base_dir = base_dir
  @theme = theme || Theme.default
  @mode = mode
  @image_cache = {}
  @kitty_uploads = {}
  @mutex = Mutex.new
end

Instance Method Details

#preload(slide) ⇒ Object

Warm caches for a slide we expect to navigate to soon. Uploads any PNG images on the Kitty Graphics Protocol so the next render only needs a placement command. Safe to call from a background thread; serialized against ‘render` via the renderer’s mutex so terminal writes don’t interleave.



83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/przn/renderer.rb', line 83

def preload(slide)
  return unless ImageUtil.kitty_terminal?

  @mutex.synchronize do
    slide.blocks.each do |block|
      next unless block[:type] == :image
      path = resolve_image_path(block[:path])
      next unless File.exist?(path) && ImageUtil.png?(path)
      ensure_kitty_uploaded(path)
    end
    @terminal.flush
  end
end

#render(slide, current:, total:, started_at: nil) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/przn/renderer.rb', line 41

def render(slide, current:, total:, started_at: nil)
  @mutex.synchronize do
    @terminal.clear
    apply_slide_background(slide)
    w = @terminal.width
    h = @terminal.height

    row = if current == 0
      content_height = calculate_height(slide.blocks, w)
      usable_height = h - 1
      [(usable_height - content_height) / 2 + 1, 1].max
    else
      2
    end

    pending_align = nil
    slide.blocks.each do |block|
      if block[:type] == :align
        pending_align = block[:align]
      else
        row = render_block(block, w, row, align: pending_align)
        pending_align = nil
      end
    end

    if @theme.rabbit
      draw_runner_bar(h, w, current, total, started_at)
    else
      status = " #{current + 1} / #{total} "
      @terminal.move_to(h, w - status.size)
      @terminal.write "#{ANSI[:dim]}#{status}#{ANSI[:reset]}"
    end

    @terminal.flush
  end
end