Class: TuiTui::Runtime

Inherits:
Object
  • Object
show all
Defined in:
lib/tui_tui/runtime.rb

Overview

Small Elm-style loop: render, read one event, fold it through the app, repeat. update returns the next app, [app, *commands] to also request one-shot effects (see Command), or :quit/nil to stop; [:quit, *commands] performs the commands and then stops.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app) ⇒ Runtime

Returns a new instance of Runtime.



13
14
15
# File 'lib/tui_tui/runtime.rb', line 13

def initialize(app)
  @app = app
end

Class Method Details

.inert_tick?(app, event) ⇒ Boolean

Ticks are opt-in: a TickEvent is inert unless the app explicitly wants it (so a plain app like counter.rb never redraws on the timer).

Returns:

  • (Boolean)


64
65
66
# File 'lib/tui_tui/runtime.rb', line 64

def self.inert_tick?(app, event)
  event.is_a?(TickEvent) && !(app.respond_to?(:wants_tick?) && app.wants_tick?)
end

.step(app, event) ⇒ Object

The canonical pure part of one loop iteration: drop an inert tick (returning nil), otherwise fold the event through update, validate the requested commands, and return [next_app_or_nil, commands]. Runtime and TestRuntime both fold through this, so their semantics cannot drift.



54
55
56
57
58
59
60
# File 'lib/tui_tui/runtime.rb', line 54

def self.step(app, event)
  return nil if inert_tick?(app, event)

  app, commands = unwrap(app.update(event))
  commands.each { |command| Command.validate!(command) }
  [app, commands]
end

.unwrap(result) ⇒ Object

Normalizes the update result to [app, commands]; a quit (bare or as the array head) becomes a nil app. An app is never itself an Array. Shared with TestRuntime so both read update's contract the same way.



45
46
47
48
# File 'lib/tui_tui/runtime.rb', line 45

def self.unwrap(result)
  app, commands = result.is_a?(Array) ? [result.first, result.drop(1)] : [result, []]
  [app == :quit ? nil : app, commands]
end

Instance Method Details

#run(input: $stdin, output: $stdout, depth: ColorDepth.detect, tick: 0.1, mouse: Screen.mouse_default, box: ENV["TUITUI_BOX"]) ⇒ Object

tick: is the TickEvent period in seconds: ticks arrive on that fixed cadence (between input events too), not after idle gaps.



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/tui_tui/runtime.rb', line 19

def run(input: $stdin, output: $stdout, depth: ColorDepth.detect, tick: 0.1, mouse: Screen.mouse_default, box: ENV["TUITUI_BOX"])
  Screen.run(input: input, output: output, depth: depth, mouse: mouse, box: box) do |screen|
    raise "tui_tui: not a terminal" if screen.nil?

    screen.render(view(screen))
    loop do
      event = screen.events.next_event(tick: tick)
      break if event.is_a?(EofEvent)

      folded = Runtime.step(@app, event)
      next if folded.nil?

      app, commands = folded
      commands.each { |command| perform(command, screen) }
      break if app.nil?

      @app = app
      flush_mouse(screen)
      screen.render(view(screen))
    end
  end
end