Build terminal apps in pure ruby.
A pure Ruby TUI framework. Core runtime, styling, and components — all in one gem.
Powers the Lazyrails TUI.
gem install chamomile
require "chamomile"
class Counter
include Chamomile::Application
def initialize
@count = 0
@seconds = 0
end
on_key(:up, "k") { @count += 1 }
on_key(:down, "j") { @count -= 1 }
on_key("r") { @count = 0 }
on_key("q") { quit }
on_tick { @seconds += 1; tick(1.0) }
def on_start
tick(1.0)
end
def view
vertical(align: :left) do
text "Counter", bold: true, color: "#7d56f4"
text ""
text "Count: #{@count}"
text "Uptime: #{@seconds}s"
text ""
status_bar "up/k increment | down/j decrement | r reset | q quit"
end
end
end
Chamomile.run(Counter.new)
Event-driven architecture, the Ruby way.
Your class is the app. Include Chamomile::Application and define view.
Declare callbacks with on_key, on_mouse, on_tick, on_resize. Or override update for full control.
Returns a string. The renderer diffs it and only redraws what changed.
Lambdas on a thread pool. They return events that feed back into your callbacks.
Everything is a command. Async by default, composable by design.
def on_start
tick(1.0) # fire a TickEvent after 1s
end
on_tick {
@seconds += 1
tick(1.0) # keep ticking
}
# Run a command, get typed results
shell("git status", envelope: :git)
# Suspend the TUI, run an editor
exec("vim", "file.rb")
# Handle the result in update
when Chamomile::ShellResult
if msg.envelope == :git
@output = msg.stdout
end
# Cooperative cancellation
token, cmd = cancellable { |t|
until t.cancelled?
do_work
end
}
cancel(token)
# Streaming — emit many messages
token, cmd = stream { |push, t|
lines.each { |l| push.(l) }
}
13 ready-made components, built in. Same handle/view protocol.