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,90 @@
|
|
|
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
|
+
# An example of the Canvas widget showing a world map and animated shapes.
|
|
10
|
+
class MapDemoApp
|
|
11
|
+
include RatatuiRuby
|
|
12
|
+
|
|
13
|
+
COLORS = [:black, :blue, :white, nil].freeze
|
|
14
|
+
MARKERS = [:braille, :half_block, :dot, :block, :bar, :quadrant, :sextant, :octant].freeze
|
|
15
|
+
|
|
16
|
+
# Returns a Canvas view for the map demo with the given circle radius.
|
|
17
|
+
#
|
|
18
|
+
# +radius+:: The radius of the animated circle.
|
|
19
|
+
# +marker+:: The marker type.
|
|
20
|
+
# +background_color+:: The background color of the canvas.
|
|
21
|
+
# +show_labels+:: Whether to show city labels.
|
|
22
|
+
def view(radius, marker = :braille, background_color = nil, show_labels: true)
|
|
23
|
+
shapes = [
|
|
24
|
+
Shape::Map.new(color: :green, resolution: :high),
|
|
25
|
+
Shape::Circle.new(x: 0.0, y: 0.0, radius:, color: :red),
|
|
26
|
+
Shape::Line.new(x1: 0.0, y1: 0.0, x2: 50.0, y2: 25.0, color: :yellow),
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
if show_labels
|
|
30
|
+
shapes += [
|
|
31
|
+
Shape::Label.new(x: -0.1, y: 51.5, text: "London", style: Style.new(fg: :cyan)),
|
|
32
|
+
Shape::Label.new(x: 139.7, y: 35.7, text: "Tokyo", style: Style.new(fg: :magenta)),
|
|
33
|
+
Shape::Label.new(x: -74.0, y: 40.7, text: "New York", style: Style.new(fg: :yellow)),
|
|
34
|
+
Shape::Label.new(x: -122.4, y: 37.8, text: "San Francisco", style: Style.new(fg: :blue)),
|
|
35
|
+
Shape::Label.new(x: 151.2, y: -33.9, text: "Sydney", style: Style.new(fg: :green)),
|
|
36
|
+
]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
Canvas.new(
|
|
40
|
+
shapes: shapes,
|
|
41
|
+
x_bounds: [-180.0, 180.0],
|
|
42
|
+
y_bounds: [-90.0, 90.0],
|
|
43
|
+
marker: marker,
|
|
44
|
+
block: Block.new(title: "World Map ['b' bg, 'm' marker: #{marker}, 'l' labels: #{show_labels ? 'on' : 'off'}]", borders: :all),
|
|
45
|
+
background_color: background_color
|
|
46
|
+
)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Runs the map demo loop.
|
|
50
|
+
def run
|
|
51
|
+
RatatuiRuby.run do
|
|
52
|
+
radius = 0.0
|
|
53
|
+
direction = 1
|
|
54
|
+
bg_index = 0
|
|
55
|
+
marker_index = 0
|
|
56
|
+
show_labels = true
|
|
57
|
+
|
|
58
|
+
loop do
|
|
59
|
+
# Animate the circle radius
|
|
60
|
+
radius += 0.5 * direction
|
|
61
|
+
if radius > 10.0 || radius < 0.0
|
|
62
|
+
direction *= -1
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Define the view
|
|
66
|
+
v = view(radius, MARKERS[marker_index], COLORS[bg_index], show_labels:)
|
|
67
|
+
|
|
68
|
+
RatatuiRuby.draw(v)
|
|
69
|
+
|
|
70
|
+
event = RatatuiRuby.poll_event
|
|
71
|
+
case event
|
|
72
|
+
in {type: :key, code: "q"} | {type: :key, code: :ctrl_c}
|
|
73
|
+
break
|
|
74
|
+
in type: :key, code: "b"
|
|
75
|
+
bg_index = (bg_index + 1) % COLORS.size
|
|
76
|
+
in type: :key, code: "m"
|
|
77
|
+
marker_index = (marker_index + 1) % MARKERS.size
|
|
78
|
+
in type: :key, code: "l"
|
|
79
|
+
show_labels = !show_labels
|
|
80
|
+
else
|
|
81
|
+
# Ignore other events
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
sleep 0.05
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
MapDemoApp.new.run if __FILE__ == $PROGRAM_NAME
|
|
@@ -0,0 +1,149 @@
|
|
|
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 "minitest/mock"
|
|
11
|
+
require_relative "app"
|
|
12
|
+
|
|
13
|
+
class TestMapDemoApp < Minitest::Test
|
|
14
|
+
include RatatuiRuby::TestHelper
|
|
15
|
+
|
|
16
|
+
def setup
|
|
17
|
+
@app = MapDemoApp.new
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def test_map_demo_renders
|
|
21
|
+
with_test_terminal do
|
|
22
|
+
# Queue events: turn off labels so buffer matches original, then quit
|
|
23
|
+
inject_keys("l", "q")
|
|
24
|
+
|
|
25
|
+
# Stub sleep to speed up test
|
|
26
|
+
@app.stub :sleep, nil do
|
|
27
|
+
@app.run
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Verify the buffer content reflects the rendered map (with labels off)
|
|
31
|
+
expected_buffer = [
|
|
32
|
+
"┌World Map ['b' bg, 'm' marker: braille, 'l' labels: off]──────────────────────┐",
|
|
33
|
+
"│ ⣀⢀⣀⣀⡀ ⢀⣀⡀ ⡀ │",
|
|
34
|
+
"│ ⢠⣤⣰⣦⣶⣶⣿⣭⣿⣣⠶⠶⣿⣉⣉⠉⠉⠁ ⠁⠉⢽⠎⠁ ⠲⠶⠶⠖ ⠐⠛⢃⡀⣀⢤ ⢀⣐⣋⣷⠶⡤⣀ ⣀⡀⣀⡀ │",
|
|
35
|
+
"│⢖⡀⡀⣤⡖⠒⠒⠤⠤⠤⠤⠶⠿⠿⣿⣹⢿⣿⣿⢿⣭⣽⣿⡒⣦⣀⠘⣷⠄ ⢀⡀⢼⣏⢀ ⡠⠤⠒⠶⡤⢀⣄⡀⢻⠯⠤⢾⣻⡗⠛⠉ ⠈⠉⠈⠈⠙⠒⠚⠋ ⠒⠐⠦⠤⠤⠤⠶│",
|
|
36
|
+
"│⠉⠉⠻⣿⣃⣀⣤⡤⣄⣀⡀ ⢠⠒⠛⠳⡟⠳⣿⣏ ⠙⠦⠴⠋⠁ ⠈⠛⠋⠁⢀⡀ ⣖⡉⢰⢾⣥⡄⠙⠉⠁ ⠈ ⢀⣀⣀⡠⣤⣦⢤⠤⠛│",
|
|
37
|
+
"│ ⠒⠛⠉⠁ ⠿⣄⡀ ⠉⠓⢖⠎ ⢀⣘⣲⡄ ⠰⣾⣟⣄⠼⠛⠟⠚⠁ ⠺⣶ ⢪⠜⠁ │",
|
|
38
|
+
"│ ⠈⡟ ⢸⠭⠿⠛⠛ ⢀⡤⣿⢀⣠⣴⣆⡀⢀⣴⣶⢆ ⡶⣆ ⢀⣀⡔⣽⡅ │",
|
|
39
|
+
"│ ⠳⣀ ⢀⣺⠉ ⠘⣧⢴⠧⠼⡿⠟⠻⣿⢭⣬⠉ ⠸⠿ ⢺⠟⣿⣠⣶⡟ │",
|
|
40
|
+
"│ ⠘⢿⣄ ⡔⠒⠒⣿⡄ ⢀⡼ ⠈⠙⠋⠉⠛⣿⡀ ⢶⣤⣄⣀⡀ ⢠⡇⠈⠋ │",
|
|
41
|
+
"│ ⠐⠦ ⠈⠉⢧⣘⢆⣴⡞⠛⣷⣤⣄ ⣯ ⣸⣷⡊⠉⣉⡽ ⠙⢲ ⢀⡴⠻⣄ ⢰⣶⠚⢙⡁ │",
|
|
42
|
+
"│ ⠈⠉⠛⢯⣇⣠⣴⢤⣤⡀ ⢧⡀ ⡠⠔⠊ ⠙⠷⢮⠅ ⠈⣇⣏ ⠉⣷⢄⠵ ⣸⣷⡄ │",
|
|
43
|
+
"│ ⢉⡇ ⠙⠲⡄ ⠙⠒⢒⣊⡲⡔⠉ ⣀⠎ ⠈⠋ ⠰⡿⡆⣠⠔⣗⣙⣣ │",
|
|
44
|
+
"│ ⢼ ⠉⠓⠲⣄ ⠈⠁⠈⢢ ⡼⠁ ⠘⢽⣝⣒⣻⡯⡛⢻⣮⢒⣦⡶⣄⡀ │",
|
|
45
|
+
"│⡀ ⠈⢢⡀ ⢰⠃ ⢸ ⢹⢀⣴ ⠉⠉⣙⣥⠖⣎⣽⡌⠃ ⠙⢀⡀ ⢀│",
|
|
46
|
+
"│⠁ ⢸ ⢀⣀⠏ ⠸⡄ ⣲⠁⡝⡞ ⣤⠖⠋ ⠈⠁⠑⣆ ⠶⠁ ⠉│",
|
|
47
|
+
"│ ⢸ ⢀⠞ ⢳ ⡰⠃ ⠉⠁ ⢹ ⢀⣀⣀⢀ ⢸⠆ │",
|
|
48
|
+
"│ ⡎⢀⣠⠽⠉ ⠈⠉⠉ ⠈⠉⠉ ⠈⠛⠦⣤⠎ ⣷⡄│",
|
|
49
|
+
"│ ⢸⠇⢴⠁ ⢀⡀ ⠛ ⠰⠾⠋ │",
|
|
50
|
+
"│ ⠘⠶⠧⠐⠛ ⠈⠁ │",
|
|
51
|
+
"│ ⢀⣠⡤ ⣀⡀ ⡀ ⣀ ⡀ │",
|
|
52
|
+
"│ ⢀⣀⣀⣀⣀⣀⡀⢠⣤⣄⣀⣀⣀⣠⣴⡿⢳ ⣀⡤⠤⠤⠤⠔⠶⠖⠲⠤⠒⠒⠒⠋⠉⠁⠉⠉⠹⠶⠒⠋⠉⠉⠉⠉⠈⠉⠈⠉⠉⠉⠉⠉⠉⠉⠒⠒⠲⢤⣤ │",
|
|
53
|
+
"│ ⠰⠶⣶⣶⠏⠉⠉ ⠉ ⠈⠉⠉⠁ ⠶⢞⣩⣥⡄⣤⣶⣶⣀⣶⡶⠉⠉⠉ ⣠⣿ │",
|
|
54
|
+
"│⠉⠉⠉⠉⠒⠘⠙⠓⠃ ⠉ ⠈⠁⠉⠉│",
|
|
55
|
+
"└──────────────────────────────────────────────────────────────────────────────┘",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
expected_buffer.each_with_index do |line, i|
|
|
59
|
+
assert_equal line, buffer_content[i], "Line #{i} should match"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Verify the background color is set on the view (Unit test of the view method)
|
|
63
|
+
view = @app.view(0.0, :braille, nil)
|
|
64
|
+
assert_nil view.background_color
|
|
65
|
+
|
|
66
|
+
# Verify labels are included in the shapes (default show_labels: true)
|
|
67
|
+
label_shapes = view.shapes.select { |s| s.is_a?(RatatuiRuby::Shape::Label) }
|
|
68
|
+
assert_equal 5, label_shapes.size, "Should have 5 city labels"
|
|
69
|
+
assert label_shapes.any? { |l| l.text == "London" }, "Should have London label"
|
|
70
|
+
assert label_shapes.any? { |l| l.text == "Tokyo" }, "Should have Tokyo label"
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def test_labels_visible
|
|
75
|
+
with_test_terminal do
|
|
76
|
+
# Don't toggle labels - they're on by default
|
|
77
|
+
inject_keys("q")
|
|
78
|
+
@app.stub :sleep, nil do
|
|
79
|
+
@app.run
|
|
80
|
+
end
|
|
81
|
+
# Labels should be visible - check for a city name in the buffer
|
|
82
|
+
buffer_text = buffer_content.join
|
|
83
|
+
assert_includes buffer_text, "London", "London label should be visible"
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def test_labels_toggle
|
|
88
|
+
with_test_terminal do
|
|
89
|
+
inject_keys("l", "q")
|
|
90
|
+
@app.stub :sleep, nil do
|
|
91
|
+
@app.run
|
|
92
|
+
end
|
|
93
|
+
# After pressing 'l', labels should be off - check title
|
|
94
|
+
assert_includes buffer_content[0], "labels: off"
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def test_background_default
|
|
99
|
+
with_test_terminal(timeout: 5) do
|
|
100
|
+
inject_keys("q")
|
|
101
|
+
@app.stub :sleep, nil do
|
|
102
|
+
@app.run
|
|
103
|
+
end
|
|
104
|
+
# View is roughly at (1,1) to (18,8) inside borders. (10, 5) is safely inside.
|
|
105
|
+
assert_cell_style(10, 5, bg: :black)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def test_background_blue
|
|
110
|
+
with_test_terminal(timeout: 5) do
|
|
111
|
+
inject_keys("b", "q")
|
|
112
|
+
@app.stub :sleep, nil do
|
|
113
|
+
@app.run
|
|
114
|
+
end
|
|
115
|
+
assert_cell_style(10, 5, bg: :blue)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def test_background_white
|
|
120
|
+
with_test_terminal(timeout: 5) do
|
|
121
|
+
inject_keys("b", "b", "q")
|
|
122
|
+
@app.stub :sleep, nil do
|
|
123
|
+
@app.run
|
|
124
|
+
end
|
|
125
|
+
assert_cell_style(10, 5, bg: :white)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def test_background_transparent
|
|
130
|
+
with_test_terminal(timeout: 5) do
|
|
131
|
+
inject_keys("b", "b", "b", "q")
|
|
132
|
+
@app.stub :sleep, nil do
|
|
133
|
+
@app.run
|
|
134
|
+
end
|
|
135
|
+
# Transparent typically means no bg color set on the cell
|
|
136
|
+
assert_cell_style(10, 5, bg: nil)
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def test_quit
|
|
141
|
+
with_test_terminal do
|
|
142
|
+
inject_key(:q)
|
|
143
|
+
|
|
144
|
+
@app.stub :sleep, nil do
|
|
145
|
+
@app.run
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
4
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
5
|
|
|
6
|
-
$LOAD_PATH.unshift File.expand_path("
|
|
6
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
7
7
|
require "ratatui_ruby"
|
|
8
8
|
|
|
9
9
|
class MouseEventsApp
|
|
@@ -14,17 +14,16 @@ class MouseEventsApp
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def run
|
|
17
|
-
RatatuiRuby.
|
|
18
|
-
begin
|
|
17
|
+
RatatuiRuby.run do
|
|
19
18
|
loop do
|
|
20
19
|
render
|
|
21
20
|
break if handle_input == :quit
|
|
22
21
|
end
|
|
23
|
-
ensure
|
|
24
|
-
RatatuiRuby.restore_terminal
|
|
25
22
|
end
|
|
26
23
|
end
|
|
27
24
|
|
|
25
|
+
private
|
|
26
|
+
|
|
28
27
|
def render
|
|
29
28
|
# Create a centered block with the mouse event details
|
|
30
29
|
block = RatatuiRuby::Block.new(
|
|
@@ -35,7 +34,7 @@ class MouseEventsApp
|
|
|
35
34
|
|
|
36
35
|
content = RatatuiRuby::Paragraph.new(
|
|
37
36
|
text: "#{@message}\n#{@details}",
|
|
38
|
-
|
|
37
|
+
alignment: :center,
|
|
39
38
|
block:
|
|
40
39
|
)
|
|
41
40
|
|
|
@@ -61,32 +60,35 @@ class MouseEventsApp
|
|
|
61
60
|
event = RatatuiRuby.poll_event
|
|
62
61
|
return unless event
|
|
63
62
|
|
|
64
|
-
|
|
63
|
+
case event
|
|
64
|
+
in {type: :key, code: "q"} | {type: :key, code: "c", modifiers: ["ctrl"]}
|
|
65
65
|
return :quit
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if event[:type] == :mouse
|
|
66
|
+
in type: :mouse, kind:, button:, x:, y:, modifiers:
|
|
69
67
|
@color = "green"
|
|
70
|
-
case
|
|
71
|
-
when
|
|
72
|
-
@message = "#{
|
|
73
|
-
@details = "Modifiers: #{
|
|
74
|
-
when
|
|
75
|
-
@message = "#{
|
|
76
|
-
@details = "Modifiers: #{
|
|
77
|
-
when
|
|
78
|
-
@message = "Dragging #{
|
|
79
|
-
@details = "Modifiers: #{
|
|
80
|
-
when
|
|
81
|
-
@message = "Mouse Moved to [#{
|
|
82
|
-
@details = "Modifiers: #{
|
|
83
|
-
when
|
|
68
|
+
case kind
|
|
69
|
+
when "down"
|
|
70
|
+
@message = "#{button.capitalize} Click at [#{x}, #{y}]"
|
|
71
|
+
@details = "Modifiers: #{modifiers.join(', ')}"
|
|
72
|
+
when "up"
|
|
73
|
+
@message = "#{button.capitalize} Release at [#{x}, #{y}]"
|
|
74
|
+
@details = "Modifiers: #{modifiers.join(', ')}"
|
|
75
|
+
when "drag"
|
|
76
|
+
@message = "Dragging #{button.capitalize} Button at [#{x}, #{y}]"
|
|
77
|
+
@details = "Modifiers: #{modifiers.join(', ')}"
|
|
78
|
+
when "moved"
|
|
79
|
+
@message = "Mouse Moved to [#{x}, #{y}]"
|
|
80
|
+
@details = "Modifiers: #{modifiers.join(', ')}"
|
|
81
|
+
when "scroll_down"
|
|
84
82
|
@message = "Scrolled Down"
|
|
85
|
-
@details = "Position: [#{
|
|
86
|
-
when
|
|
83
|
+
@details = "Position: [#{x}, #{y}]"
|
|
84
|
+
when "scroll_up"
|
|
87
85
|
@message = "Scrolled Up"
|
|
88
|
-
@details = "Position: [#{
|
|
86
|
+
@details = "Position: [#{x}, #{y}]"
|
|
87
|
+
else
|
|
88
|
+
nil
|
|
89
89
|
end
|
|
90
|
+
else
|
|
91
|
+
nil
|
|
90
92
|
end
|
|
91
93
|
nil
|
|
92
94
|
end
|
|
@@ -0,0 +1,53 @@
|
|
|
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 TestMouseEvents < Minitest::Test
|
|
13
|
+
include RatatuiRuby::TestHelper
|
|
14
|
+
|
|
15
|
+
def setup
|
|
16
|
+
@app = MouseEventsApp.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, "Mouse Event Plumbing"
|
|
26
|
+
assert_includes content, "Waiting for Mouse..."
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_mouse_click
|
|
31
|
+
with_test_terminal do
|
|
32
|
+
# Click left button at 10, 5
|
|
33
|
+
inject_event(RatatuiRuby::Event::Mouse.new(kind: "down", button: "left", x: 10, y: 5))
|
|
34
|
+
inject_key(:q)
|
|
35
|
+
@app.run
|
|
36
|
+
|
|
37
|
+
content = buffer_content.join("\n")
|
|
38
|
+
assert_includes content, "Left Click at [10, 5]"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def test_mouse_scroll
|
|
43
|
+
with_test_terminal do
|
|
44
|
+
inject_event(RatatuiRuby::Event::Mouse.new(kind: "scroll_down", button: "none", x: 20, y: 15))
|
|
45
|
+
inject_key(:q)
|
|
46
|
+
@app.run
|
|
47
|
+
|
|
48
|
+
content = buffer_content.join("\n")
|
|
49
|
+
assert_includes content, "Scrolled Down"
|
|
50
|
+
assert_includes content, "Position: [20, 15]"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -3,30 +3,29 @@
|
|
|
3
3
|
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
4
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
5
|
|
|
6
|
-
$LOAD_PATH.unshift File.expand_path("
|
|
6
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
7
7
|
require "ratatui_ruby"
|
|
8
8
|
|
|
9
9
|
# Popup Demo Example
|
|
10
10
|
# Demonstrates the Clear widget for creating opaque popups.
|
|
11
11
|
|
|
12
|
-
class
|
|
12
|
+
class PopupDemoApp
|
|
13
13
|
def initialize
|
|
14
14
|
@clear_enabled = false
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def run
|
|
18
|
-
RatatuiRuby.
|
|
19
|
-
begin
|
|
18
|
+
RatatuiRuby.run do
|
|
20
19
|
loop do
|
|
21
20
|
render
|
|
22
21
|
break if handle_input == :quit
|
|
23
22
|
sleep 0.05
|
|
24
23
|
end
|
|
25
|
-
ensure
|
|
26
|
-
RatatuiRuby.restore_terminal
|
|
27
24
|
end
|
|
28
25
|
end
|
|
29
26
|
|
|
27
|
+
private
|
|
28
|
+
|
|
30
29
|
def render
|
|
31
30
|
# 1. Background: Loud Red Background
|
|
32
31
|
# This demonstrates "Style Bleed" where the background color persists
|
|
@@ -47,9 +46,9 @@ class PopupDemo
|
|
|
47
46
|
|
|
48
47
|
popup_content = RatatuiRuby::Paragraph.new(
|
|
49
48
|
text: popup_text,
|
|
50
|
-
|
|
49
|
+
alignment: :center,
|
|
51
50
|
block: RatatuiRuby::Block.new(
|
|
52
|
-
title: "Popup Demo (
|
|
51
|
+
title: "Popup Demo (q to quit, space to toggle)",
|
|
53
52
|
borders: [:all]
|
|
54
53
|
)
|
|
55
54
|
)
|
|
@@ -90,16 +89,15 @@ class PopupDemo
|
|
|
90
89
|
end
|
|
91
90
|
|
|
92
91
|
def handle_input
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
end
|
|
92
|
+
case RatatuiRuby.poll_event
|
|
93
|
+
in {type: :key, code: "q"} | {type: :key, code: "c", modifiers: ["ctrl"]}
|
|
94
|
+
:quit
|
|
95
|
+
in type: :key, code: " "
|
|
96
|
+
@clear_enabled = !@clear_enabled
|
|
97
|
+
else
|
|
98
|
+
nil
|
|
101
99
|
end
|
|
102
100
|
end
|
|
103
101
|
end
|
|
104
102
|
|
|
105
|
-
|
|
103
|
+
PopupDemoApp.new.run if __FILE__ == $0
|
|
@@ -3,24 +3,25 @@
|
|
|
3
3
|
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
4
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
5
|
|
|
6
|
-
$LOAD_PATH.unshift File.expand_path("
|
|
6
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
7
7
|
require "ratatui_ruby"
|
|
8
8
|
require "ratatui_ruby/test_helper"
|
|
9
9
|
require "minitest/autorun"
|
|
10
|
-
require_relative "
|
|
10
|
+
require_relative "app"
|
|
11
11
|
|
|
12
|
-
class Minitest::Test
|
|
12
|
+
class TestPopupDemoApp < Minitest::Test
|
|
13
13
|
include RatatuiRuby::TestHelper
|
|
14
|
-
end
|
|
15
14
|
|
|
16
|
-
class TestPopupDemo < Minitest::Test
|
|
17
15
|
def setup
|
|
18
|
-
@app =
|
|
16
|
+
@app = PopupDemoApp.new
|
|
19
17
|
end
|
|
20
18
|
|
|
21
19
|
def test_render_initial_state
|
|
22
|
-
with_test_terminal
|
|
23
|
-
|
|
20
|
+
with_test_terminal do
|
|
21
|
+
# Queue quit
|
|
22
|
+
inject_key(:q)
|
|
23
|
+
|
|
24
|
+
@app.run
|
|
24
25
|
|
|
25
26
|
# Should have background text
|
|
26
27
|
assert buffer_content.any? { |line| line.include?("BACKGROUND RED") }
|
|
@@ -32,31 +33,22 @@ class TestPopupDemo < Minitest::Test
|
|
|
32
33
|
end
|
|
33
34
|
|
|
34
35
|
def test_toggle_clear
|
|
35
|
-
with_test_terminal
|
|
36
|
-
#
|
|
37
|
-
|
|
38
|
-
assert buffer_content.any? { |line| line.include?("Clear is DISABLED") }
|
|
36
|
+
with_test_terminal do
|
|
37
|
+
# Toggle Clear on then quit
|
|
38
|
+
inject_keys(" ", :q)
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
inject_event("key", { code: " " })
|
|
42
|
-
@app.handle_input
|
|
40
|
+
@app.run
|
|
43
41
|
|
|
44
|
-
@app.render
|
|
45
42
|
assert buffer_content.any? { |line| line.include?("Clear is ENABLED") }
|
|
46
43
|
assert buffer_content.any? { |line| line.include?("Resets background to default") }
|
|
47
|
-
|
|
48
|
-
# Toggle Clear off
|
|
49
|
-
inject_event("key", { code: " " })
|
|
50
|
-
@app.handle_input
|
|
51
|
-
|
|
52
|
-
@app.render
|
|
53
|
-
assert buffer_content.any? { |line| line.include?("Clear is DISABLED") }
|
|
54
44
|
end
|
|
55
45
|
end
|
|
56
46
|
|
|
57
47
|
def test_quit
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
48
|
+
with_test_terminal do
|
|
49
|
+
inject_key(:q)
|
|
50
|
+
@app.run
|
|
51
|
+
# Success
|
|
52
|
+
end
|
|
61
53
|
end
|
|
62
54
|
end
|
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
|
|
10
|
+
class QuickstartDslApp
|
|
11
|
+
def run
|
|
12
|
+
# 1. Initialize the terminal, start the run loop, and ensure the terminal is restored.
|
|
13
|
+
RatatuiRuby.run do |tui|
|
|
14
|
+
loop do
|
|
15
|
+
# 2. Create your UI with methods instead of classes.
|
|
16
|
+
view = tui.paragraph(
|
|
17
|
+
text: "Hello, Ratatui! Press 'q' to quit.",
|
|
18
|
+
alignment: :center,
|
|
19
|
+
block: tui.block(
|
|
20
|
+
title: "My Ruby TUI App",
|
|
21
|
+
borders: [:all],
|
|
22
|
+
border_color: "cyan"
|
|
23
|
+
)
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
# 3. Use RatatuiRuby methods, too.
|
|
27
|
+
tui.draw(view)
|
|
28
|
+
event = tui.poll_event
|
|
29
|
+
|
|
30
|
+
break if event == "q" || event == :ctrl_c
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
QuickstartDslApp.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 TestQuickstartDsl < Minitest::Test
|
|
13
|
+
include RatatuiRuby::TestHelper
|
|
14
|
+
|
|
15
|
+
def setup
|
|
16
|
+
@app = QuickstartDslApp.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,39 @@
|
|
|
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
|
+
|
|
10
|
+
class QuickstartLifecycleApp
|
|
11
|
+
def run
|
|
12
|
+
# Using the RatatuiRuby.run block for automatic terminal setup/teardown
|
|
13
|
+
RatatuiRuby.run do |tui|
|
|
14
|
+
# The Main Loop
|
|
15
|
+
loop do
|
|
16
|
+
# 1. Create your UI (Immediate Mode)
|
|
17
|
+
# We define a Paragraph widget inside a Block with a title and borders.
|
|
18
|
+
view = RatatuiRuby::Paragraph.new(
|
|
19
|
+
text: "Hello, Ratatui! Press 'q' to quit.",
|
|
20
|
+
alignment: :center,
|
|
21
|
+
block: RatatuiRuby::Block.new(
|
|
22
|
+
title: "My Ruby TUI App",
|
|
23
|
+
borders: [:all],
|
|
24
|
+
border_color: "cyan"
|
|
25
|
+
)
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
# 2. Draw the UI
|
|
29
|
+
tui.draw(view)
|
|
30
|
+
|
|
31
|
+
# 3. Poll for events
|
|
32
|
+
event = RatatuiRuby.poll_event
|
|
33
|
+
break if event == "q" || event == :ctrl_c
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
QuickstartLifecycleApp.new.run if __FILE__ == $PROGRAM_NAME
|