Class: Charming::Runtime

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

Overview

Runtime manages a terminal UI application’s lifecycle: setting up an alternative-screen terminal with cursor hiding, running an event loop that reads keyboard, mouse, timer, and task events, dispatching them to controllers, rendering responses, and tearing down cleanly on exit.

Constant Summary collapse

DEFAULT_READ_TIMEOUT =
0.05

Instance Method Summary collapse

Constructor Details

#initialize(application, backend: nil, renderer: nil, clock: nil, task_executor: nil) ⇒ Runtime

Returns a new instance of Runtime.



11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/charming/runtime.rb', line 11

def initialize(application, backend: nil, renderer: nil, clock: nil, task_executor: nil)
  @application = application
  @backend = backend || Internal::Terminal::TTYBackend.new
  @renderer = renderer || Internal::Renderer::Differential.new(@backend)
  @clock = clock || -> { Process.clock_gettime(Process::CLOCK_MONOTONIC) }
  @task_queue = Thread::Queue.new
  @task_executor = build_task_executor(task_executor)
  @application.task_executor = @task_executor
  @route = @application.routes.resolve("/")
  @screen = backend_screen
  @timers = build_timers
end

Instance Method Details

#runObject

Runs the event loop: enters alt-screen, dispatches incoming events (key, mouse, timer, async task), renders controller responses, and restores terminal state on exit. Unhandled exceptions from controller actions render an ErrorScreen instead of crashing the terminal.



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/charming/runtime.rb', line 28

def run
  setup_terminal
  install_interrupt_handler
  with_raw_input do
    render(initial_response)
    loop do
      break if @interrupted

      event = next_task_event || next_timer_event || @backend.read_event(timeout: read_timeout)
      unless event
        break if backend_exhausted?
        next
      end
      break if process(event) == :quit
    end
  end
ensure
  restore_interrupt_handler
  @task_executor&.shutdown(timeout: 2.0)
  @application.save_session if @application.respond_to?(:save_session)
  restore_terminal
end