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,180 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
5
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
+
|
|
7
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
8
|
+
require "ratatui_ruby"
|
|
9
|
+
require "ratatui_ruby/test_helper"
|
|
10
|
+
require "minitest/autorun"
|
|
11
|
+
require_relative "app"
|
|
12
|
+
|
|
13
|
+
# Tests for the table_select example
|
|
14
|
+
class TestTableSelectApp < Minitest::Test
|
|
15
|
+
include RatatuiRuby::TestHelper
|
|
16
|
+
|
|
17
|
+
def setup
|
|
18
|
+
@app = TableSelectApp.new
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_initial_render_no_selection
|
|
22
|
+
with_test_terminal do
|
|
23
|
+
# By default, selection is at index 1 and highlights are on.
|
|
24
|
+
inject_key(:q)
|
|
25
|
+
@app.run
|
|
26
|
+
|
|
27
|
+
content = buffer_content.join("\n")
|
|
28
|
+
# Row 1 (postgres) should be selected.
|
|
29
|
+
# Default style is Cyan.
|
|
30
|
+
# "Toggle Row (1)" should be visible in footer.
|
|
31
|
+
assert_includes content, "Toggle Row (1)"
|
|
32
|
+
assert_includes content, "Cyan"
|
|
33
|
+
assert_includes content, "PID"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def test_style_switching
|
|
38
|
+
second_style_name = TableSelectApp::STYLES[1][:name]
|
|
39
|
+
|
|
40
|
+
with_test_terminal do
|
|
41
|
+
inject_keys(:s, :q)
|
|
42
|
+
@app.run
|
|
43
|
+
|
|
44
|
+
content = buffer_content
|
|
45
|
+
assert content.any? { |line| line.include?(second_style_name) }
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def test_toggle_selection_on
|
|
50
|
+
with_test_terminal do
|
|
51
|
+
# Default is ON (1 selected).
|
|
52
|
+
# Press x to toggle off (none), then quit
|
|
53
|
+
inject_keys(:x, :q)
|
|
54
|
+
@app.run
|
|
55
|
+
|
|
56
|
+
content = buffer_content.join("\n")
|
|
57
|
+
# "Toggle Row (none)" should be visible.
|
|
58
|
+
assert_includes content, "Toggle Row (none)"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def test_toggle_selection_off
|
|
63
|
+
with_test_terminal do
|
|
64
|
+
# Default is ON.
|
|
65
|
+
# Press x to toggle off, x again to toggle on (0 selected now because toggle logic resets to 0 if nil?), then quit
|
|
66
|
+
# Wait, app logic: @selected_index = @selected_index.nil? ? 0 : nil
|
|
67
|
+
# If default is 1, toggling off makes it nil. Toggling on makes it 0.
|
|
68
|
+
inject_keys(:x, :x, :q)
|
|
69
|
+
@app.run
|
|
70
|
+
|
|
71
|
+
content = buffer_content.join("\n")
|
|
72
|
+
assert_includes content, "Toggle Row (0)"
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def test_navigation_selects_and_moves
|
|
77
|
+
with_test_terminal do
|
|
78
|
+
# Default is 1. Down -> 2.
|
|
79
|
+
inject_keys(:down, :q)
|
|
80
|
+
@app.run
|
|
81
|
+
|
|
82
|
+
content = buffer_content.join("\n")
|
|
83
|
+
assert_includes content, "Toggle Row (2)"
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def test_navigation_wrapping
|
|
88
|
+
with_test_terminal do
|
|
89
|
+
# Start 1, down->2... wrap around logic needs check.
|
|
90
|
+
# Logic: (@selected_index + 1) % length.
|
|
91
|
+
# To test wrap, need to go to end. Length is 7.
|
|
92
|
+
# From 1, need 6 downs to wrap? No, just up from 0 wraps to last.
|
|
93
|
+
# So: up (1->0), up (0->6).
|
|
94
|
+
inject_keys(:up, :up, :q)
|
|
95
|
+
@app.run
|
|
96
|
+
|
|
97
|
+
content = buffer_content.join("\n")
|
|
98
|
+
last_index = PROCESSES.length - 1
|
|
99
|
+
assert_includes content, "Toggle Row (#{last_index})"
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def test_column_navigation
|
|
104
|
+
with_test_terminal do
|
|
105
|
+
# Default col 1. Right -> 2.
|
|
106
|
+
inject_keys(:right, :q)
|
|
107
|
+
@app.run
|
|
108
|
+
|
|
109
|
+
content = buffer_content.join("\n")
|
|
110
|
+
assert_includes content, "Nav Col"
|
|
111
|
+
# We don't have a label for selected column in the footer anymore?
|
|
112
|
+
# Wait, I added it in app.rb but removed it in previous step?
|
|
113
|
+
# In Step 115 I added `col_label` but I didn't verify if I used it in the UI.
|
|
114
|
+
# Let me check app.rb again. I might have missed adding it to the UI in Step 87 layout fix or Step 115.
|
|
115
|
+
# Step 115 added `col_label = ...` but did NOT add it to the Paragraph text.
|
|
116
|
+
# I need to check app.rb to see if `col_label` is rendered.
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def test_quit
|
|
121
|
+
with_test_terminal do
|
|
122
|
+
inject_key(:q)
|
|
123
|
+
@app.run
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def test_highlight_spacing_cycles_to_next
|
|
128
|
+
with_test_terminal do
|
|
129
|
+
# Mode order: [:when_selected, :always, :never]
|
|
130
|
+
# 'p' goes to :always
|
|
131
|
+
inject_keys(:p, :q)
|
|
132
|
+
@app.run
|
|
133
|
+
|
|
134
|
+
content = buffer_content
|
|
135
|
+
assert content.any? { |line| line.include?("Always") }
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def test_highlight_spacing_cycles_to_never
|
|
140
|
+
with_test_terminal do
|
|
141
|
+
# 'p' goes: when_selected -> always -> never
|
|
142
|
+
inject_keys(:p, :p, :q)
|
|
143
|
+
@app.run
|
|
144
|
+
|
|
145
|
+
content = buffer_content
|
|
146
|
+
assert content.any? { |line| line.include?("Never") }
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def test_highlight_spacing_cycles_back_to_when_selected
|
|
151
|
+
with_test_terminal do
|
|
152
|
+
# 'p' goes: when_selected -> always -> never -> when_selected
|
|
153
|
+
inject_keys(:p, :p, :p, :q)
|
|
154
|
+
@app.run
|
|
155
|
+
|
|
156
|
+
content = buffer_content
|
|
157
|
+
assert content.any? { |line| line.include?("When Selected") }
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def test_column_spacing_increases
|
|
162
|
+
with_test_terminal do
|
|
163
|
+
inject_keys("+", :q)
|
|
164
|
+
@app.run
|
|
165
|
+
|
|
166
|
+
content = buffer_content
|
|
167
|
+
assert content.any? { |line| line.include?("Col Space (2)") }
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def test_column_spacing_decreases
|
|
172
|
+
with_test_terminal do
|
|
173
|
+
inject_keys("+", "-", :q)
|
|
174
|
+
@app.run
|
|
175
|
+
|
|
176
|
+
content = buffer_content
|
|
177
|
+
assert content.any? { |line| line.include?("Col Space (1)") }
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
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
|
+
class ColorGradientDemo
|
|
10
|
+
def initialize
|
|
11
|
+
@width = 80
|
|
12
|
+
@height = 24
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def run
|
|
16
|
+
RatatuiRuby.run do |tui|
|
|
17
|
+
loop do
|
|
18
|
+
render(tui)
|
|
19
|
+
event = tui.poll_event
|
|
20
|
+
break if event&.key? && (event.ctrl_c? || event == :q)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def render(tui)
|
|
28
|
+
lines = []
|
|
29
|
+
|
|
30
|
+
(0...@height).each do |row|
|
|
31
|
+
spans = []
|
|
32
|
+
(0...@width).each do |col|
|
|
33
|
+
hue = (col.to_f / @width) * 360.0
|
|
34
|
+
lightness = 50.0 - ((row.to_f / @height) * 50.0)
|
|
35
|
+
|
|
36
|
+
rgb = hsl_to_rgb(hue, 100.0, lightness)
|
|
37
|
+
hex = rgb_to_hex(rgb)
|
|
38
|
+
|
|
39
|
+
span = tui.text_span(
|
|
40
|
+
content: " ",
|
|
41
|
+
style: tui.style(bg: hex)
|
|
42
|
+
)
|
|
43
|
+
spans << span
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
lines << tui.text_line(spans: spans)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
paragraph = tui.paragraph(
|
|
50
|
+
text: lines,
|
|
51
|
+
block: tui.block(
|
|
52
|
+
title: "Hex Color Gradient (Press 'q' or Ctrl+C to exit)",
|
|
53
|
+
borders: [:all],
|
|
54
|
+
border_type: :rounded
|
|
55
|
+
)
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
tui.draw(paragraph)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def hsl_to_rgb(hue, saturation, lightness)
|
|
62
|
+
h = hue / 360.0
|
|
63
|
+
s = saturation / 100.0
|
|
64
|
+
l = lightness / 100.0
|
|
65
|
+
|
|
66
|
+
if s == 0
|
|
67
|
+
r = g = b = l
|
|
68
|
+
else
|
|
69
|
+
q = l < 0.5 ? l * (1 + s) : l + s - (l * s)
|
|
70
|
+
p = 2 * l - q
|
|
71
|
+
|
|
72
|
+
r = hue_to_rgb(p, q, h + 1.0 / 3.0)
|
|
73
|
+
g = hue_to_rgb(p, q, h)
|
|
74
|
+
b = hue_to_rgb(p, q, h - 1.0 / 3.0)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
[
|
|
78
|
+
(r * 255).round,
|
|
79
|
+
(g * 255).round,
|
|
80
|
+
(b * 255).round
|
|
81
|
+
]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def hue_to_rgb(p, q, t)
|
|
85
|
+
t += 1 while t < 0
|
|
86
|
+
t -= 1 while t > 1
|
|
87
|
+
|
|
88
|
+
if t < 1.0 / 6.0
|
|
89
|
+
p + (q - p) * 6 * t
|
|
90
|
+
elsif t < 1.0 / 2.0
|
|
91
|
+
q
|
|
92
|
+
elsif t < 2.0 / 3.0
|
|
93
|
+
p + (q - p) * (2.0 / 3.0 - t) * 6
|
|
94
|
+
else
|
|
95
|
+
p
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def rgb_to_hex(rgb)
|
|
100
|
+
"##{rgb.map { |c| c.to_s(16).upcase.rjust(2, '0') }.join}"
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
ColorGradientDemo.new.run if __FILE__ == $PROGRAM_NAME
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
2
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
|
|
4
|
+
class ColorGradientDemo
|
|
5
|
+
def initialize: () -> void
|
|
6
|
+
def run: () -> void
|
|
7
|
+
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def render: (RatatuiRuby::TUI) -> void
|
|
11
|
+
def hsl_to_rgb: (Float, Float, Float) -> [Integer, Integer, Integer]
|
|
12
|
+
def hue_to_rgb: (Float, Float, Float) -> Float
|
|
13
|
+
def rgb_to_hex: ([Integer, Integer, Integer]) -> String
|
|
14
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
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 TestColorGradientDemo < Minitest::Test
|
|
13
|
+
include RatatuiRuby::TestHelper
|
|
14
|
+
|
|
15
|
+
def setup
|
|
16
|
+
@app = ColorGradientDemo.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_renders_with_title
|
|
20
|
+
with_test_terminal do
|
|
21
|
+
inject_key(:q)
|
|
22
|
+
@app.run
|
|
23
|
+
|
|
24
|
+
content = buffer_content.join("\n")
|
|
25
|
+
assert_includes content, "Hex Color Gradient"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def test_renders_gradient_cells
|
|
30
|
+
with_test_terminal do
|
|
31
|
+
inject_key(:q)
|
|
32
|
+
@app.run
|
|
33
|
+
|
|
34
|
+
content = buffer_content.join("\n")
|
|
35
|
+
# Should have many spaces (gradient cells)
|
|
36
|
+
assert content.length > 500
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def test_exit_on_q
|
|
41
|
+
with_test_terminal do
|
|
42
|
+
inject_key(:q)
|
|
43
|
+
@app.run
|
|
44
|
+
# If we get here without hanging, exit worked
|
|
45
|
+
assert true
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|