Class: Przn::Renderer

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

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

Instance Method Summary collapse

Constructor Details

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

Returns a new instance of Renderer.



18
19
20
21
22
23
24
25
# File 'lib/przn/renderer.rb', line 18

def initialize(terminal, base_dir: '.', theme: nil)
  @terminal = terminal
  @base_dir = base_dir
  @theme = theme || Theme.default
  @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.



65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/przn/renderer.rb', line 65

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:) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/przn/renderer.rb', line 27

def render(slide, current:, total:)
  @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

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

    @terminal.flush
  end
end