$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
require "ratatui_ruby"
class WidgetTextWidth
def initialize
@text_samples = [
{ label: "ASCII", text: "Hello, World!", desc: "Simple English text" },
{ label: "CJK", text: "δ½ ε₯½δΈη", desc: "Chinese (full-width characters)" },
{ label: "Emoji", text: "Hello π World π", desc: "Mixed text with emoji (2 cells each)" },
{ label: "Mixed", text: "Hi δ½ ε₯½ π", desc: "ASCII + CJK + emoji" },
{ label: "Empty", text: "", desc: "Empty string" },
]
@selected_index = 0
end
def run
RatatuiRuby.run do |tui|
@tui = tui
loop do
render
break if handle_input == :quit
end
end
end
private def render
@tui.draw do |frame|
areas = @tui.layout_split(
frame.area,
direction: :vertical,
constraints: [@tui.constraint_fill(1), @tui.constraint_length(7)]
)
render_content(frame, areas[0])
render_controls(frame, areas[1])
end
end
private def render_content(frame, area)
sample = @text_samples[@selected_index]
measured_width = @tui.text_width(sample[:text])
styled_span = @tui.text_span(content: sample[:text], style: @tui.style(fg: :cyan))
span_width = styled_span.width
styled_line = @tui.text_line(spans: [styled_span])
line_width = styled_line.width
content = []
content << "Sample: #{sample[:text]}"
content << ""
content << "Display Width (text_width): #{measured_width} cells"
content << "Display Width (span.width): #{span_width} cells"
content << "Display Width (line.width): #{line_width} cells"
content << "Character Count: #{sample[:text].length}"
content << ""
content << sample[:desc]
text = content.join("\n")
widget = @tui.paragraph(
text:,
block: @tui.block(
title: "Text Width Calculator",
borders: [:all],
border_style: { fg: "cyan" }
),
alignment: :left
)
frame.render_widget(widget, area)
end
private def render_controls(frame, area)
info = "Sample #{@selected_index + 1}/#{@text_samples.length}: #{@text_samples[@selected_index][:label]}"
controls = "β/β Select q Quit"
text = "#{info}\n#{controls}"
widget = @tui.paragraph(
text:,
block: @tui.block(borders: [:top], border_style: { fg: "gray" }),
alignment: :center
)
frame.render_widget(widget, area)
end
private def handle_input
event = @tui.poll_event
case event
in { type: :key, code: "q" }
:quit
in { type: :key, code: "up" }
@selected_index = (@selected_index - 1) % @text_samples.length
nil
in { type: :key, code: "down" }
@selected_index = (@selected_index + 1) % @text_samples.length
nil
else
nil
end
end
end
WidgetTextWidth.new.run if __FILE__ == $PROGRAM_NAME