Skip to content

Instantly share code, notes, and snippets.

@glinesbdev
Last active January 23, 2026 06:58
Show Gist options
  • Select an option

  • Save glinesbdev/d40f9d7b9ed1e18ff1a074b83454cbc8 to your computer and use it in GitHub Desktop.

Select an option

Save glinesbdev/d40f9d7b9ed1e18ff1a074b83454cbc8 to your computer and use it in GitHub Desktop.
Ratatui Ruby
source 'https://rubygems.org'
gem 'ratatui_ruby'
require 'bundler/setup'
require 'ratatui_ruby'
class DukeTui
STYLES = {
active: { fg: :green },
inactive: { fg: :grey }
}.freeze
def initialize
@input = ''
@render_history = false
@tui = RatatuiRuby::TUI.new
@mode = :form
@selected_column = 0
@selected_row = 0
@items = [
{
name: 'https://zombo.com/',
value: 'https://zombo.com/',
tags: %w[fun]
},
{
name: 'something',
value: 'this does nothing',
tags: %w[these are whatever]
}
]
@selected_item = @items.first
end
def run
render_app
end
private
def render_app
RatatuiRuby.run(viewport: :inline, height: 50) do
loop do
render_layout
if handle_input == :quit
area = @tui.viewport_area
RatatuiRuby.cursor_position = [0, area.y + area.height]
break
end
end
end
end
def render_layout
@tui.draw do |frame|
content_area, form_area = @tui.layout_split(
frame.area,
direction: :vertical,
constraints: [
@tui.constraint_fill(1),
@tui.constraint_length(3)
]
)
render_form_area(frame, form_area)
render_content_area(frame, content_area)
end
end
def render_form_area(frame, form_area)
border_color = @mode == :form ? :green : :grey
cursor_x = 1 + @input.length
cursor_y = 1
form = @tui.overlay(layers: [
@tui.paragraph(
text: @input,
block: @tui.block(borders: :all, title: 'Duke Of Url', border_style: @tui.style(fg: border_color)),
alignment: :left
),
@tui.cursor(x: cursor_x, y: cursor_y)
])
frame.render_widget(form, form_area)
end
def render_content_area(frame, content_area)
border_color = @mode == :content ? :green : :grey
widths = [
@tui.constraint_percentage(75),
@tui.constraint_percentage(50),
]
content = @tui.table(
rows: build_rows,
widths: widths,
selected_row: @selected_row,
selected_column: @selected_column,
row_highlight_style: @tui.style(bg: :dark_grey),
highlight_symbol: '> ',
flex: :flex,
block: @tui.block(title: 'Look at all this content!', borders: :all, border_style: @tui.style(fg: border_color))
)
frame.render_widget(content, content_area)
end
def build_rows
@items.map do |item|
@tui.table_row(cells: [item[:name], item[:tags]])
end
end
def handle_input
case @mode
when :form then handle_form_input
when :content then handle_content_input
end
end
def handle_form_input
case @tui.poll_event
in { type: :key, code: "c", modifiers: ["ctrl"] }
:quit
in { type: :key, code: "q" }
:quit
in { type: :key, code: "esc" }
:quit
in { type: :key, code: "enter" }
@mode = :content
nil
in { type: :key, code: "backspace" }
@input.chop!
nil
in { type: :key, code: "up" }
@mode = :content
nil
in { type: :key, code:, modifiers: [] } if code.length == 1
@input += code
nil
else
nil
end
end
def handle_content_input
case @tui.poll_event
in { type: :key, code: "q" }
@mode = :form
nil
in { type: :key, code: "esc" }
@mode = :form
nil
in { type: :key, code: "up" }
@selected_row = (@selected_row - 1) % @items.length
nil
in { type: :key, code: "down" }
@selected_row += 1
@mode = :form if @selected_row >= @items.length
nil
in { type: :key, code: "left" }
@selected_column = (@selected_column - 1) % @items.length
nil
in { type: :key, code: "right" }
@selected_column = (@selected_column + 1) % @items.length
nil
else
nil
end
end
end
DukeTui.new.run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment