Class: TuiTui::Runtime
- Inherits:
-
Object
- Object
- TuiTui::Runtime
- 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
-
.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).
-
.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]. -
.unwrap(result) ⇒ Object
Normalizes the update result to [app, commands]; a quit (bare or as the array head) becomes a nil app.
Instance Method Summary collapse
-
#initialize(app) ⇒ Runtime
constructor
A new instance of Runtime.
-
#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.
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).
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 |