ratatui_ruby 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.builds/ruby-3.2.yml +14 -12
- data/.builds/ruby-3.3.yml +14 -12
- data/.builds/ruby-3.4.yml +14 -12
- data/.builds/ruby-4.0.0.yml +14 -12
- data/AGENTS.md +54 -13
- data/CHANGELOG.md +186 -1
- data/README.md +17 -15
- data/doc/application_architecture.md +116 -0
- data/doc/application_testing.md +12 -7
- data/doc/contributors/better_dx.md +543 -0
- data/doc/contributors/design/ruby_frontend.md +1 -1
- data/doc/contributors/developing_examples.md +203 -0
- data/doc/contributors/documentation_style.md +97 -0
- data/doc/contributors/dwim_dx.md +366 -0
- data/doc/contributors/example_analysis.md +82 -0
- data/doc/custom.css +14 -0
- data/doc/event_handling.md +119 -0
- data/doc/images/all_events.png +0 -0
- data/doc/images/analytics.png +0 -0
- data/doc/images/block_padding.png +0 -0
- data/doc/images/block_titles.png +0 -0
- data/doc/images/box_demo.png +0 -0
- data/doc/images/calendar_demo.png +0 -0
- data/doc/images/cell_demo.png +0 -0
- data/doc/images/chart_demo.png +0 -0
- data/doc/images/custom_widget.png +0 -0
- data/doc/images/flex_layout.png +0 -0
- data/doc/images/gauge_demo.png +0 -0
- data/doc/images/hit_test.png +0 -0
- data/doc/images/line_gauge_demo.png +0 -0
- data/doc/images/list_demo.png +0 -0
- data/doc/images/list_styles.png +0 -0
- data/doc/images/login_form.png +0 -0
- data/doc/images/map_demo.png +0 -0
- data/doc/images/mouse_events.png +0 -0
- data/doc/images/popup_demo.png +0 -0
- data/doc/images/quickstart_dsl.png +0 -0
- data/doc/images/quickstart_lifecycle.png +0 -0
- data/doc/images/ratatui_logo_demo.png +0 -0
- data/doc/images/readme_usage.png +0 -0
- data/doc/images/rich_text.png +0 -0
- data/doc/images/scroll_text.png +0 -0
- data/doc/images/scrollbar_demo.png +0 -0
- data/doc/images/sparkline_demo.png +0 -0
- data/doc/images/table_flex.png +0 -0
- data/doc/images/table_select.png +0 -0
- data/doc/images/widget_style_colors.png +0 -0
- data/doc/index.md +1 -0
- data/doc/interactive_design.md +121 -0
- data/doc/quickstart.md +147 -72
- data/examples/all_events/app.rb +169 -0
- data/examples/all_events/app.rbs +7 -0
- data/examples/all_events/test_app.rb +139 -0
- data/examples/analytics/app.rb +258 -0
- data/examples/analytics/app.rbs +7 -0
- data/examples/analytics/test_app.rb +132 -0
- data/examples/block_padding/app.rb +63 -0
- data/examples/block_padding/app.rbs +7 -0
- data/examples/block_padding/test_app.rb +31 -0
- data/examples/block_titles/app.rb +61 -0
- data/examples/block_titles/app.rbs +7 -0
- data/examples/block_titles/test_app.rb +34 -0
- data/examples/box_demo/app.rb +216 -0
- data/examples/box_demo/app.rbs +7 -0
- data/examples/box_demo/test_app.rb +88 -0
- data/examples/calendar_demo/app.rb +101 -0
- data/examples/calendar_demo/app.rbs +7 -0
- data/examples/calendar_demo/test_app.rb +108 -0
- data/examples/cell_demo/app.rb +108 -0
- data/examples/cell_demo/app.rbs +7 -0
- data/examples/cell_demo/test_app.rb +36 -0
- data/examples/chart_demo/app.rb +203 -0
- data/examples/chart_demo/app.rbs +7 -0
- data/examples/chart_demo/test_app.rb +102 -0
- data/examples/custom_widget/app.rb +51 -0
- data/examples/custom_widget/app.rbs +7 -0
- data/examples/custom_widget/test_app.rb +30 -0
- data/examples/flex_layout/app.rb +156 -0
- data/examples/flex_layout/app.rbs +7 -0
- data/examples/flex_layout/test_app.rb +65 -0
- data/examples/gauge_demo/app.rb +182 -0
- data/examples/gauge_demo/app.rbs +7 -0
- data/examples/gauge_demo/test_app.rb +120 -0
- data/examples/hit_test/app.rb +175 -0
- data/examples/hit_test/app.rbs +7 -0
- data/examples/hit_test/test_app.rb +102 -0
- data/examples/line_gauge_demo/app.rb +190 -0
- data/examples/line_gauge_demo/app.rbs +7 -0
- data/examples/line_gauge_demo/test_app.rb +129 -0
- data/examples/list_demo/app.rb +253 -0
- data/examples/list_demo/app.rbs +12 -0
- data/examples/list_demo/test_app.rb +237 -0
- data/examples/list_styles/app.rb +140 -0
- data/examples/list_styles/app.rbs +7 -0
- data/examples/list_styles/test_app.rb +157 -0
- data/examples/{login_form.rb → login_form/app.rb} +12 -16
- data/examples/login_form/app.rbs +7 -0
- data/examples/login_form/test_app.rb +51 -0
- data/examples/map_demo/app.rb +90 -0
- data/examples/map_demo/app.rbs +7 -0
- data/examples/map_demo/test_app.rb +149 -0
- data/examples/{mouse_events.rb → mouse_events/app.rb} +29 -27
- data/examples/mouse_events/app.rbs +7 -0
- data/examples/mouse_events/test_app.rb +53 -0
- data/examples/{popup_demo.rb → popup_demo/app.rb} +15 -17
- data/examples/popup_demo/app.rbs +7 -0
- data/examples/{test_popup_demo.rb → popup_demo/test_app.rb} +18 -26
- data/examples/quickstart_dsl/app.rb +36 -0
- data/examples/quickstart_dsl/app.rbs +7 -0
- data/examples/quickstart_dsl/test_app.rb +29 -0
- data/examples/quickstart_lifecycle/app.rb +39 -0
- data/examples/quickstart_lifecycle/app.rbs +7 -0
- data/examples/quickstart_lifecycle/test_app.rb +29 -0
- data/examples/ratatui_logo_demo/app.rb +79 -0
- data/examples/ratatui_logo_demo/app.rbs +7 -0
- data/examples/ratatui_logo_demo/test_app.rb +51 -0
- data/examples/ratatui_mascot_demo/app.rb +84 -0
- data/examples/ratatui_mascot_demo/app.rbs +7 -0
- data/examples/ratatui_mascot_demo/test_app.rb +47 -0
- data/examples/readme_usage/app.rb +29 -0
- data/examples/readme_usage/app.rbs +7 -0
- data/examples/readme_usage/test_app.rb +29 -0
- data/examples/rich_text/app.rb +141 -0
- data/examples/rich_text/app.rbs +7 -0
- data/examples/rich_text/test_app.rb +166 -0
- data/examples/scroll_text/app.rb +103 -0
- data/examples/scroll_text/app.rbs +7 -0
- data/examples/scroll_text/test_app.rb +110 -0
- data/examples/scrollbar_demo/app.rb +143 -0
- data/examples/scrollbar_demo/app.rbs +7 -0
- data/examples/scrollbar_demo/test_app.rb +77 -0
- data/examples/sparkline_demo/app.rb +240 -0
- data/examples/sparkline_demo/app.rbs +10 -0
- data/examples/sparkline_demo/test_app.rb +107 -0
- data/examples/table_flex/app.rb +65 -0
- data/examples/table_flex/app.rbs +7 -0
- data/examples/table_flex/test_app.rb +36 -0
- data/examples/table_select/app.rb +198 -0
- data/examples/table_select/app.rbs +7 -0
- data/examples/table_select/test_app.rb +180 -0
- data/examples/widget_style_colors/app.rb +104 -0
- data/examples/widget_style_colors/app.rbs +14 -0
- data/examples/widget_style_colors/test_app.rb +48 -0
- data/ext/ratatui_ruby/Cargo.lock +889 -115
- data/ext/ratatui_ruby/Cargo.toml +4 -3
- data/ext/ratatui_ruby/clippy.toml +7 -0
- data/ext/ratatui_ruby/extconf.rb +7 -0
- data/ext/ratatui_ruby/src/events.rs +218 -229
- data/ext/ratatui_ruby/src/lib.rs +38 -10
- data/ext/ratatui_ruby/src/rendering.rs +90 -10
- data/ext/ratatui_ruby/src/style.rs +281 -98
- data/ext/ratatui_ruby/src/terminal.rs +119 -25
- data/ext/ratatui_ruby/src/text.rs +171 -0
- data/ext/ratatui_ruby/src/widgets/barchart.rs +97 -24
- data/ext/ratatui_ruby/src/widgets/block.rs +31 -3
- data/ext/ratatui_ruby/src/widgets/calendar.rs +45 -44
- data/ext/ratatui_ruby/src/widgets/canvas.rs +46 -29
- data/ext/ratatui_ruby/src/widgets/chart.rs +69 -27
- data/ext/ratatui_ruby/src/widgets/clear.rs +3 -1
- data/ext/ratatui_ruby/src/widgets/gauge.rs +11 -4
- data/ext/ratatui_ruby/src/widgets/layout.rs +218 -15
- data/ext/ratatui_ruby/src/widgets/line_gauge.rs +92 -0
- data/ext/ratatui_ruby/src/widgets/list.rs +91 -11
- data/ext/ratatui_ruby/src/widgets/mod.rs +3 -0
- data/ext/ratatui_ruby/src/widgets/overlay.rs +3 -2
- data/ext/ratatui_ruby/src/widgets/paragraph.rs +35 -13
- data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +29 -0
- data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +44 -0
- data/ext/ratatui_ruby/src/widgets/scrollbar.rs +59 -7
- data/ext/ratatui_ruby/src/widgets/sparkline.rs +70 -6
- data/ext/ratatui_ruby/src/widgets/table.rs +173 -64
- data/ext/ratatui_ruby/src/widgets/tabs.rs +105 -5
- data/lib/ratatui_ruby/cell.rb +166 -0
- data/lib/ratatui_ruby/event/focus_gained.rb +49 -0
- data/lib/ratatui_ruby/event/focus_lost.rb +50 -0
- data/lib/ratatui_ruby/event/key.rb +211 -0
- data/lib/ratatui_ruby/event/mouse.rb +124 -0
- data/lib/ratatui_ruby/event/paste.rb +71 -0
- data/lib/ratatui_ruby/event/resize.rb +80 -0
- data/lib/ratatui_ruby/event.rb +79 -0
- data/lib/ratatui_ruby/schema/bar_chart/bar.rb +45 -0
- data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +27 -0
- data/lib/ratatui_ruby/schema/bar_chart.rb +228 -19
- data/lib/ratatui_ruby/schema/block.rb +186 -14
- data/lib/ratatui_ruby/schema/calendar.rb +74 -17
- data/lib/ratatui_ruby/schema/canvas.rb +215 -48
- data/lib/ratatui_ruby/schema/center.rb +49 -11
- data/lib/ratatui_ruby/schema/chart.rb +151 -41
- data/lib/ratatui_ruby/schema/clear.rb +41 -72
- data/lib/ratatui_ruby/schema/constraint.rb +82 -22
- data/lib/ratatui_ruby/schema/cursor.rb +27 -9
- data/lib/ratatui_ruby/schema/draw.rb +53 -0
- data/lib/ratatui_ruby/schema/gauge.rb +59 -15
- data/lib/ratatui_ruby/schema/layout.rb +95 -13
- data/lib/ratatui_ruby/schema/line_gauge.rb +78 -0
- data/lib/ratatui_ruby/schema/list.rb +93 -19
- data/lib/ratatui_ruby/schema/overlay.rb +34 -8
- data/lib/ratatui_ruby/schema/paragraph.rb +87 -30
- data/lib/ratatui_ruby/schema/ratatui_logo.rb +25 -0
- data/lib/ratatui_ruby/schema/ratatui_mascot.rb +29 -0
- data/lib/ratatui_ruby/schema/rect.rb +64 -15
- data/lib/ratatui_ruby/schema/scrollbar.rb +132 -24
- data/lib/ratatui_ruby/schema/shape/label.rb +66 -0
- data/lib/ratatui_ruby/schema/sparkline.rb +122 -15
- data/lib/ratatui_ruby/schema/style.rb +49 -21
- data/lib/ratatui_ruby/schema/table.rb +119 -21
- data/lib/ratatui_ruby/schema/tabs.rb +75 -13
- data/lib/ratatui_ruby/schema/text.rb +90 -0
- data/lib/ratatui_ruby/session.rb +146 -0
- data/lib/ratatui_ruby/test_helper.rb +156 -13
- data/lib/ratatui_ruby/version.rb +1 -1
- data/lib/ratatui_ruby.rb +143 -23
- data/sig/ratatui_ruby/event.rbs +69 -0
- data/sig/ratatui_ruby/ratatui_ruby.rbs +2 -1
- data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +16 -0
- data/sig/ratatui_ruby/schema/bar_chart/bar_group.rbs +13 -0
- data/sig/ratatui_ruby/schema/bar_chart.rbs +20 -2
- data/sig/ratatui_ruby/schema/block.rbs +5 -4
- data/sig/ratatui_ruby/schema/calendar.rbs +6 -2
- data/sig/ratatui_ruby/schema/canvas.rbs +52 -39
- data/sig/ratatui_ruby/schema/center.rbs +3 -3
- data/sig/ratatui_ruby/schema/chart.rbs +8 -5
- data/sig/ratatui_ruby/schema/constraint.rbs +8 -5
- data/sig/ratatui_ruby/schema/cursor.rbs +1 -1
- data/sig/ratatui_ruby/schema/draw.rbs +23 -0
- data/sig/ratatui_ruby/schema/gauge.rbs +4 -2
- data/sig/ratatui_ruby/schema/layout.rbs +11 -1
- data/sig/ratatui_ruby/schema/line_gauge.rbs +16 -0
- data/sig/ratatui_ruby/schema/list.rbs +5 -1
- data/sig/ratatui_ruby/schema/paragraph.rbs +4 -1
- data/{lib/ratatui_ruby/output.rb → sig/ratatui_ruby/schema/ratatui_logo.rbs} +3 -2
- data/sig/ratatui_ruby/{buffer.rbs → schema/ratatui_mascot.rbs} +4 -3
- data/sig/ratatui_ruby/schema/rect.rbs +2 -1
- data/sig/ratatui_ruby/schema/scrollbar.rbs +18 -2
- data/sig/ratatui_ruby/schema/sparkline.rbs +6 -2
- data/sig/ratatui_ruby/schema/table.rbs +8 -1
- data/sig/ratatui_ruby/schema/tabs.rbs +5 -1
- data/sig/ratatui_ruby/schema/text.rbs +22 -0
- data/tasks/resources/build.yml.erb +13 -11
- data/tasks/terminal_preview/app_screenshot.rb +35 -0
- data/tasks/terminal_preview/crash_report.rb +54 -0
- data/tasks/terminal_preview/example_app.rb +25 -0
- data/tasks/terminal_preview/launcher_script.rb +48 -0
- data/tasks/terminal_preview/preview_collection.rb +60 -0
- data/tasks/terminal_preview/preview_timing.rb +22 -0
- data/tasks/terminal_preview/safety_confirmation.rb +58 -0
- data/tasks/terminal_preview/saved_screenshot.rb +55 -0
- data/tasks/terminal_preview/system_appearance.rb +11 -0
- data/tasks/terminal_preview/terminal_window.rb +138 -0
- data/tasks/terminal_preview/window_id.rb +14 -0
- data/tasks/terminal_preview.rake +28 -0
- data/tasks/test.rake +1 -1
- metadata +174 -53
- data/doc/images/examples-analytics.rb.png +0 -0
- data/doc/images/examples-box_demo.rb.png +0 -0
- data/doc/images/examples-calendar_demo.rb.png +0 -0
- data/doc/images/examples-chart_demo.rb.png +0 -0
- data/doc/images/examples-custom_widget.rb.png +0 -0
- data/doc/images/examples-dashboard.rb.png +0 -0
- data/doc/images/examples-list_styles.rb.png +0 -0
- data/doc/images/examples-login_form.rb.png +0 -0
- data/doc/images/examples-map_demo.rb.png +0 -0
- data/doc/images/examples-mouse_events.rb.png +0 -0
- data/doc/images/examples-popup_demo.rb.gif +0 -0
- data/doc/images/examples-quickstart_lifecycle.rb.png +0 -0
- data/doc/images/examples-scroll_text.rb.png +0 -0
- data/doc/images/examples-scrollbar_demo.rb.png +0 -0
- data/doc/images/examples-stock_ticker.rb.png +0 -0
- data/doc/images/examples-system_monitor.rb.png +0 -0
- data/doc/images/examples-table_select.rb.png +0 -0
- data/examples/analytics.rb +0 -88
- data/examples/box_demo.rb +0 -71
- data/examples/calendar_demo.rb +0 -55
- data/examples/chart_demo.rb +0 -84
- data/examples/custom_widget.rb +0 -43
- data/examples/dashboard.rb +0 -72
- data/examples/list_styles.rb +0 -66
- data/examples/map_demo.rb +0 -58
- data/examples/quickstart_dsl.rb +0 -30
- data/examples/quickstart_lifecycle.rb +0 -40
- data/examples/readme_usage.rb +0 -21
- data/examples/scroll_text.rb +0 -74
- data/examples/scrollbar_demo.rb +0 -75
- data/examples/stock_ticker.rb +0 -93
- data/examples/system_monitor.rb +0 -94
- data/examples/table_select.rb +0 -70
- data/examples/test_analytics.rb +0 -65
- data/examples/test_box_demo.rb +0 -38
- data/examples/test_calendar_demo.rb +0 -66
- data/examples/test_dashboard.rb +0 -38
- data/examples/test_list_styles.rb +0 -61
- data/examples/test_login_form.rb +0 -63
- data/examples/test_map_demo.rb +0 -100
- data/examples/test_scroll_text.rb +0 -130
- data/examples/test_stock_ticker.rb +0 -39
- data/examples/test_system_monitor.rb +0 -40
- data/examples/test_table_select.rb +0 -37
- data/ext/ratatui_ruby/src/buffer.rs +0 -54
- data/lib/ratatui_ruby/dsl.rb +0 -64
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
7
|
+
require "ratatui_ruby"
|
|
8
|
+
require "ratatui_ruby/test_helper"
|
|
9
|
+
require "minitest/autorun"
|
|
10
|
+
require_relative "app"
|
|
11
|
+
|
|
12
|
+
class TestQuickstartLifecycle < Minitest::Test
|
|
13
|
+
include RatatuiRuby::TestHelper
|
|
14
|
+
|
|
15
|
+
def setup
|
|
16
|
+
@app = QuickstartLifecycleApp.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_render
|
|
20
|
+
with_test_terminal do
|
|
21
|
+
inject_key(:q)
|
|
22
|
+
@app.run
|
|
23
|
+
|
|
24
|
+
content = buffer_content.join("\n")
|
|
25
|
+
assert_includes content, "Hello, Ratatui!"
|
|
26
|
+
assert_includes content, "My Ruby TUI App"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
4
|
+
require "ratatui_ruby"
|
|
5
|
+
|
|
6
|
+
class RatatuiLogoDemoApp
|
|
7
|
+
def run
|
|
8
|
+
RatatuiRuby.run do
|
|
9
|
+
loop do
|
|
10
|
+
render
|
|
11
|
+
break if handle_input == :quit
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def render
|
|
19
|
+
# Main content: The Logo
|
|
20
|
+
logo = RatatuiRuby::RatatuiLogo.new
|
|
21
|
+
|
|
22
|
+
# Center the logo using nested Layouts
|
|
23
|
+
# Logo is roughly 47x8
|
|
24
|
+
centered_logo = RatatuiRuby::Layout.new(
|
|
25
|
+
direction: :vertical,
|
|
26
|
+
flex: :center,
|
|
27
|
+
constraints: [RatatuiRuby::Constraint.length(10)], # Height + margin
|
|
28
|
+
children: [
|
|
29
|
+
RatatuiRuby::Layout.new(
|
|
30
|
+
direction: :horizontal,
|
|
31
|
+
flex: :center,
|
|
32
|
+
constraints: [RatatuiRuby::Constraint.length(50)], # Width + margin
|
|
33
|
+
children: [logo]
|
|
34
|
+
)
|
|
35
|
+
]
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# Control Panel
|
|
39
|
+
control_text = RatatuiRuby::Text::Line.new(spans: [
|
|
40
|
+
RatatuiRuby::Text::Span.new(content: "q", style: RatatuiRuby::Style.new(modifiers: [:bold, :underlined])),
|
|
41
|
+
RatatuiRuby::Text::Span.new(content: ": Quit")
|
|
42
|
+
])
|
|
43
|
+
|
|
44
|
+
control_panel = RatatuiRuby::Paragraph.new(
|
|
45
|
+
text: [control_text],
|
|
46
|
+
block: RatatuiRuby::Block.new(
|
|
47
|
+
title: "Controls",
|
|
48
|
+
borders: [:top],
|
|
49
|
+
style: RatatuiRuby::Style.new(fg: :dark_gray)
|
|
50
|
+
)
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# Layout
|
|
54
|
+
layout = RatatuiRuby::Layout.new(
|
|
55
|
+
direction: :vertical,
|
|
56
|
+
constraints: [
|
|
57
|
+
RatatuiRuby::Constraint.fill(1), # Fill remaining space
|
|
58
|
+
RatatuiRuby::Constraint.length(3)
|
|
59
|
+
],
|
|
60
|
+
children: [
|
|
61
|
+
centered_logo,
|
|
62
|
+
control_panel
|
|
63
|
+
]
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
RatatuiRuby.draw(layout)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def handle_input
|
|
70
|
+
case RatatuiRuby.poll_event
|
|
71
|
+
in {type: :key, code: "q"} | {type: :key, code: "c", modifiers: ["ctrl"]}
|
|
72
|
+
:quit
|
|
73
|
+
else
|
|
74
|
+
nil
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
RatatuiLogoDemoApp.new.run if __FILE__ == $0
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
4
|
+
require "ratatui_ruby"
|
|
5
|
+
require "ratatui_ruby/test_helper"
|
|
6
|
+
require "minitest/autorun"
|
|
7
|
+
require_relative "app"
|
|
8
|
+
|
|
9
|
+
class TestRatatuiLogoDemoApp < Minitest::Test
|
|
10
|
+
include RatatuiRuby::TestHelper
|
|
11
|
+
|
|
12
|
+
def setup
|
|
13
|
+
@app = RatatuiLogoDemoApp.new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_initial_render
|
|
17
|
+
with_test_terminal do
|
|
18
|
+
inject_key(:q)
|
|
19
|
+
@app.run
|
|
20
|
+
|
|
21
|
+
content = buffer_content.join("\n")
|
|
22
|
+
|
|
23
|
+
# Verify the logo is rendered.
|
|
24
|
+
# The Ratatui logo usually contains "ratatui" text or similar shapes.
|
|
25
|
+
# Since we can't easily match the exact ASCII art in a cross-platform/version way without brittleness,
|
|
26
|
+
# we verify that the center of the screen is NOT empty.
|
|
27
|
+
|
|
28
|
+
# The logo is centered.
|
|
29
|
+
center_x = 40
|
|
30
|
+
center_y = 10
|
|
31
|
+
RatatuiRuby.get_cell_at(center_x, center_y)
|
|
32
|
+
|
|
33
|
+
# It might not be exactly at 40, 10, but the logo is large enough that checking a region is safe.
|
|
34
|
+
# Or simpler: verify the buffer contains non-whitespace lines in the middle.
|
|
35
|
+
|
|
36
|
+
# Checking for "Controls" proves the app rendered.
|
|
37
|
+
assert_includes content, "Controls"
|
|
38
|
+
assert_includes content, "Quit"
|
|
39
|
+
|
|
40
|
+
# Capture the "visual" presence of the logo by ensuring the buffer isn't just known text + whitespace.
|
|
41
|
+
# The logo uses unicode block characters or specific letters.
|
|
42
|
+
# Let's check for a known character from the logo if possible, or just significant non-whitespace count.
|
|
43
|
+
refute_empty content.gsub(/\s+/, ""), "Buffer should not be empty"
|
|
44
|
+
|
|
45
|
+
# We know the controls text. Let's ensure there is MORE text than just controls.
|
|
46
|
+
controls_length = "Controls".length + "q: Quit".length + 20 # aprox buffer
|
|
47
|
+
non_whitespace_count = content.gsub(/\s/, "").length
|
|
48
|
+
assert non_whitespace_count > controls_length, "Should render more than just controls (the logo)"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: CC-BY-SA-4.0
|
|
5
|
+
|
|
6
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
7
|
+
require "ratatui_ruby"
|
|
8
|
+
|
|
9
|
+
class RatatuiMascotDemoApp
|
|
10
|
+
def initialize
|
|
11
|
+
@show_block = true
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def run
|
|
15
|
+
RatatuiRuby.run do |tui|
|
|
16
|
+
loop do
|
|
17
|
+
render(tui)
|
|
18
|
+
break if handle_input(tui) == :quit
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def render(tui)
|
|
26
|
+
# Layout: Top (Mascot), Bottom (Controls)
|
|
27
|
+
# Mascot Widget
|
|
28
|
+
block = if @show_block
|
|
29
|
+
tui.block(
|
|
30
|
+
title: "Ratatui Mascot",
|
|
31
|
+
borders: [:all],
|
|
32
|
+
border_type: :rounded,
|
|
33
|
+
border_style: { fg: :green }
|
|
34
|
+
)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
mascot = tui.ratatui_mascot(block: block)
|
|
38
|
+
|
|
39
|
+
# Controls
|
|
40
|
+
controls_text = [
|
|
41
|
+
tui.text_span(content: "q", style: tui.style(modifiers: [:bold, :underlined])),
|
|
42
|
+
tui.text_span(content: " Quit"),
|
|
43
|
+
tui.text_span(content: " "),
|
|
44
|
+
tui.text_span(content: "b", style: tui.style(modifiers: [:bold, :underlined])),
|
|
45
|
+
tui.text_span(content: " Toggle Block #{@show_block ? '(On)' : '(Off)'}")
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
controls_paragraph = tui.paragraph(
|
|
49
|
+
text: tui.text_line(spans: controls_text),
|
|
50
|
+
block: tui.block(borders: [:top], title: "Controls")
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# Layout: Top (Mascot), Bottom (Controls)
|
|
54
|
+
layout = tui.layout(
|
|
55
|
+
direction: :vertical,
|
|
56
|
+
constraints: [
|
|
57
|
+
RatatuiRuby::Constraint.fill(1),
|
|
58
|
+
RatatuiRuby::Constraint.length(4)
|
|
59
|
+
],
|
|
60
|
+
children: [
|
|
61
|
+
mascot,
|
|
62
|
+
controls_paragraph
|
|
63
|
+
]
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
tui.draw(layout)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def handle_input(tui)
|
|
70
|
+
event = tui.poll_event
|
|
71
|
+
return unless event
|
|
72
|
+
|
|
73
|
+
if event.key?
|
|
74
|
+
case event.char
|
|
75
|
+
when "q" then return :quit
|
|
76
|
+
when "b" then @show_block = !@show_block
|
|
77
|
+
end
|
|
78
|
+
elsif event.ctrl_c?
|
|
79
|
+
return :quit
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
RatatuiMascotDemoApp.new.run if __FILE__ == $PROGRAM_NAME
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
7
|
+
require "ratatui_ruby"
|
|
8
|
+
require "ratatui_ruby/test_helper"
|
|
9
|
+
require "minitest/autorun"
|
|
10
|
+
require_relative "app"
|
|
11
|
+
|
|
12
|
+
class TestRatatuiMascotDemoApp < Minitest::Test
|
|
13
|
+
include RatatuiRuby::TestHelper
|
|
14
|
+
|
|
15
|
+
def setup
|
|
16
|
+
@app = RatatuiMascotDemoApp.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_initial_render
|
|
20
|
+
with_test_terminal do
|
|
21
|
+
inject_key(:q)
|
|
22
|
+
@app.run
|
|
23
|
+
|
|
24
|
+
content = buffer_content.join("\n")
|
|
25
|
+
assert_includes content, "Ratatui Mascot" # Title implying block is on
|
|
26
|
+
assert_includes content, "Toggle Block (On)"
|
|
27
|
+
# Mascot contains block characters
|
|
28
|
+
assert_includes content, "█"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def test_toggle_block
|
|
33
|
+
with_test_terminal do
|
|
34
|
+
inject_key("b")
|
|
35
|
+
inject_key(:q)
|
|
36
|
+
@app.run
|
|
37
|
+
|
|
38
|
+
content = buffer_content.join("\n")
|
|
39
|
+
assert_includes content, "Toggle Block (Off)"
|
|
40
|
+
# Title should be gone if block is gone (unless internal rendering keeps it, but our logic removes the block)
|
|
41
|
+
# Wait, if block is nil, no border/title.
|
|
42
|
+
refute_includes content, "Ratatui Mascot"
|
|
43
|
+
# Mascot should still be there
|
|
44
|
+
assert_includes content, "█"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
7
|
+
|
|
8
|
+
require "ratatui_ruby"
|
|
9
|
+
class ReadmeUsageApp
|
|
10
|
+
def run
|
|
11
|
+
RatatuiRuby.run do |tui|
|
|
12
|
+
loop do
|
|
13
|
+
tui.draw \
|
|
14
|
+
tui.paragraph \
|
|
15
|
+
text: "Hello, Ratatui! Press 'q' to quit.",
|
|
16
|
+
alignment: :center,
|
|
17
|
+
block: tui.block(
|
|
18
|
+
title: "My Ruby TUI App",
|
|
19
|
+
borders: [:all],
|
|
20
|
+
border_color: "cyan"
|
|
21
|
+
)
|
|
22
|
+
event = tui.poll_event
|
|
23
|
+
break if event == "q" || event == :ctrl_c
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
ReadmeUsageApp.new.run if __FILE__ == $PROGRAM_NAME
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
7
|
+
require "ratatui_ruby"
|
|
8
|
+
require "ratatui_ruby/test_helper"
|
|
9
|
+
require "minitest/autorun"
|
|
10
|
+
require_relative "app"
|
|
11
|
+
|
|
12
|
+
class TestReadmeUsage < Minitest::Test
|
|
13
|
+
include RatatuiRuby::TestHelper
|
|
14
|
+
|
|
15
|
+
def setup
|
|
16
|
+
@app = ReadmeUsageApp.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_render
|
|
20
|
+
with_test_terminal do
|
|
21
|
+
inject_key(:q)
|
|
22
|
+
@app.run
|
|
23
|
+
|
|
24
|
+
content = buffer_content.join("\n")
|
|
25
|
+
assert_includes content, "Hello, Ratatui!"
|
|
26
|
+
assert_includes content, "My Ruby TUI App"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
7
|
+
require "ratatui_ruby"
|
|
8
|
+
|
|
9
|
+
# Rich Text Example
|
|
10
|
+
# Demonstrates the Span and Line objects for styling individual words
|
|
11
|
+
# within a block of text.
|
|
12
|
+
class RichTextApp
|
|
13
|
+
def initialize
|
|
14
|
+
@scroll_pos = 0
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def run
|
|
18
|
+
RatatuiRuby.run do
|
|
19
|
+
loop do
|
|
20
|
+
render
|
|
21
|
+
event = handle_input
|
|
22
|
+
break if event == :quit
|
|
23
|
+
sleep 0.05
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def render
|
|
31
|
+
RatatuiRuby.draw(
|
|
32
|
+
RatatuiRuby::Layout.new(
|
|
33
|
+
direction: :vertical,
|
|
34
|
+
constraints: [
|
|
35
|
+
RatatuiRuby::Constraint.percentage(50),
|
|
36
|
+
RatatuiRuby::Constraint.percentage(50)
|
|
37
|
+
],
|
|
38
|
+
children: [
|
|
39
|
+
simple_text_line_example,
|
|
40
|
+
complex_example
|
|
41
|
+
]
|
|
42
|
+
)
|
|
43
|
+
)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def simple_text_line_example
|
|
47
|
+
# Example 1: A line with mixed styles
|
|
48
|
+
RatatuiRuby::Paragraph.new(
|
|
49
|
+
text: RatatuiRuby::Text::Line.new(
|
|
50
|
+
spans: [
|
|
51
|
+
RatatuiRuby::Text::Span.new(
|
|
52
|
+
content: "Normal text, ",
|
|
53
|
+
style: nil
|
|
54
|
+
),
|
|
55
|
+
RatatuiRuby::Text::Span.new(
|
|
56
|
+
content: "Bold Text",
|
|
57
|
+
style: RatatuiRuby::Style.new(modifiers: [:bold])
|
|
58
|
+
),
|
|
59
|
+
RatatuiRuby::Text::Span.new(
|
|
60
|
+
content: ", ",
|
|
61
|
+
style: nil
|
|
62
|
+
),
|
|
63
|
+
RatatuiRuby::Text::Span.new(
|
|
64
|
+
content: "Italic Text",
|
|
65
|
+
style: RatatuiRuby::Style.new(modifiers: [:italic])
|
|
66
|
+
),
|
|
67
|
+
RatatuiRuby::Text::Span.new(
|
|
68
|
+
content: ", ",
|
|
69
|
+
style: nil
|
|
70
|
+
),
|
|
71
|
+
RatatuiRuby::Text::Span.new(
|
|
72
|
+
content: "Red Text",
|
|
73
|
+
style: RatatuiRuby::Style.new(fg: :red)
|
|
74
|
+
),
|
|
75
|
+
RatatuiRuby::Text::Span.new(
|
|
76
|
+
content: ".",
|
|
77
|
+
style: nil
|
|
78
|
+
)
|
|
79
|
+
]
|
|
80
|
+
),
|
|
81
|
+
block: RatatuiRuby::Block.new(
|
|
82
|
+
title: "Simple Rich Text",
|
|
83
|
+
borders: [:all]
|
|
84
|
+
)
|
|
85
|
+
)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def complex_example
|
|
89
|
+
# Example 2: Multiple lines with different styles
|
|
90
|
+
RatatuiRuby::Paragraph.new(
|
|
91
|
+
text: [
|
|
92
|
+
RatatuiRuby::Text::Line.new(
|
|
93
|
+
spans: [
|
|
94
|
+
RatatuiRuby::Text::Span.new(content: "✓ ", style: RatatuiRuby::Style.new(fg: :green, modifiers: [:bold])),
|
|
95
|
+
RatatuiRuby::Text::Span.new(content: "Feature Complete", style: nil),
|
|
96
|
+
RatatuiRuby::Text::Span.new(content: " - All tests passing", style: RatatuiRuby::Style.new(fg: :gray))
|
|
97
|
+
]
|
|
98
|
+
),
|
|
99
|
+
RatatuiRuby::Text::Line.new(
|
|
100
|
+
spans: [
|
|
101
|
+
RatatuiRuby::Text::Span.new(content: "⚠ ", style: RatatuiRuby::Style.new(fg: :yellow, modifiers: [:bold])),
|
|
102
|
+
RatatuiRuby::Text::Span.new(content: "Warning", style: nil),
|
|
103
|
+
RatatuiRuby::Text::Span.new(content: " - Documentation pending", style: RatatuiRuby::Style.new(fg: :gray))
|
|
104
|
+
]
|
|
105
|
+
),
|
|
106
|
+
RatatuiRuby::Text::Line.new(
|
|
107
|
+
spans: [
|
|
108
|
+
RatatuiRuby::Text::Span.new(content: "✗ ", style: RatatuiRuby::Style.new(fg: :red, modifiers: [:bold])),
|
|
109
|
+
RatatuiRuby::Text::Span.new(content: "Not Started", style: nil),
|
|
110
|
+
RatatuiRuby::Text::Span.new(content: " - Performance benchmarks", style: RatatuiRuby::Style.new(fg: :gray))
|
|
111
|
+
]
|
|
112
|
+
),
|
|
113
|
+
RatatuiRuby::Text::Line.new(spans: []),
|
|
114
|
+
RatatuiRuby::Text::Line.new(
|
|
115
|
+
spans: [
|
|
116
|
+
RatatuiRuby::Text::Span.new(content: "Press ", style: nil),
|
|
117
|
+
RatatuiRuby::Text::Span.new(content: "Q", style: RatatuiRuby::Style.new(modifiers: [:bold])),
|
|
118
|
+
RatatuiRuby::Text::Span.new(content: " to quit", style: nil)
|
|
119
|
+
]
|
|
120
|
+
)
|
|
121
|
+
],
|
|
122
|
+
block: RatatuiRuby::Block.new(
|
|
123
|
+
title: "Status Report",
|
|
124
|
+
borders: [:all]
|
|
125
|
+
)
|
|
126
|
+
)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def handle_input
|
|
130
|
+
event = RatatuiRuby.poll_event
|
|
131
|
+
return nil unless event
|
|
132
|
+
|
|
133
|
+
return :quit if event == "q" || event == :esc || event == :ctrl_c
|
|
134
|
+
|
|
135
|
+
nil
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
if __FILE__ == $0
|
|
140
|
+
RichTextApp.new.run
|
|
141
|
+
end
|