ratatui_ruby 0.9.1 → 0.10.1
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 +1 -1
- data/.builds/ruby-3.3.yml +1 -1
- data/.builds/ruby-3.4.yml +1 -1
- data/.builds/ruby-4.0.0.yml +1 -1
- data/AGENTS.md +2 -1
- data/CHANGELOG.md +113 -0
- data/README.md +17 -0
- data/REUSE.toml +5 -0
- data/Rakefile +1 -1
- data/Steepfile +49 -0
- data/doc/concepts/debugging.md +401 -0
- data/doc/getting_started/quickstart.md +8 -3
- data/doc/images/app_all_events.png +0 -0
- data/doc/images/app_color_picker.png +0 -0
- data/doc/images/app_debugging_showcase.gif +0 -0
- data/doc/images/app_debugging_showcase.png +0 -0
- data/doc/images/app_login_form.png +0 -0
- data/doc/images/app_stateful_interaction.png +0 -0
- data/doc/images/verify_quickstart_dsl.png +0 -0
- data/doc/images/verify_quickstart_layout.png +0 -0
- data/doc/images/verify_quickstart_lifecycle.png +0 -0
- data/doc/images/verify_readme_usage.png +0 -0
- data/doc/images/widget_barchart.png +0 -0
- data/doc/images/widget_block.png +0 -0
- data/doc/images/widget_box.png +0 -0
- data/doc/images/widget_calendar.png +0 -0
- data/doc/images/widget_canvas.png +0 -0
- data/doc/images/widget_cell.png +0 -0
- data/doc/images/widget_center.png +0 -0
- data/doc/images/widget_chart.png +0 -0
- data/doc/images/widget_gauge.png +0 -0
- data/doc/images/widget_layout_split.png +0 -0
- data/doc/images/widget_line_gauge.png +0 -0
- data/doc/images/widget_list.png +0 -0
- data/doc/images/widget_map.png +0 -0
- data/doc/images/widget_overlay.png +0 -0
- data/doc/images/widget_popup.png +0 -0
- data/doc/images/widget_ratatui_logo.png +0 -0
- data/doc/images/widget_ratatui_mascot.png +0 -0
- data/doc/images/widget_rect.png +0 -0
- data/doc/images/widget_render.png +0 -0
- data/doc/images/widget_rich_text.png +0 -0
- data/doc/images/widget_scroll_text.png +0 -0
- data/doc/images/widget_scrollbar.png +0 -0
- data/doc/images/widget_sparkline.png +0 -0
- data/doc/images/widget_style_colors.png +0 -0
- data/doc/images/widget_table.png +0 -0
- data/doc/images/widget_tabs.png +0 -0
- data/doc/images/widget_text_width.png +0 -0
- data/doc/troubleshooting/async.md +4 -0
- data/examples/app_debugging_showcase/README.md +119 -0
- data/examples/app_debugging_showcase/app.rb +318 -0
- data/examples/widget_canvas/app.rb +19 -14
- data/examples/widget_gauge/app.rb +18 -3
- data/examples/widget_layout_split/app.rb +10 -4
- data/examples/widget_list/app.rb +22 -6
- data/examples/widget_rect/app.rb +7 -6
- data/examples/widget_rich_text/app.rb +62 -37
- data/examples/widget_style_colors/app.rb +26 -47
- data/examples/widget_table/app.rb +28 -5
- data/examples/widget_text_width/app.rb +6 -4
- data/ext/ratatui_ruby/Cargo.lock +48 -1
- data/ext/ratatui_ruby/Cargo.toml +6 -2
- data/ext/ratatui_ruby/src/color.rs +82 -0
- data/ext/ratatui_ruby/src/errors.rs +28 -0
- data/ext/ratatui_ruby/src/events.rs +15 -14
- data/ext/ratatui_ruby/src/lib.rs +56 -0
- data/ext/ratatui_ruby/src/rendering.rs +3 -1
- data/ext/ratatui_ruby/src/style.rs +48 -21
- data/ext/ratatui_ruby/src/terminal.rs +40 -9
- data/ext/ratatui_ruby/src/text.rs +21 -9
- data/ext/ratatui_ruby/src/widgets/chart.rs +2 -1
- data/ext/ratatui_ruby/src/widgets/layout.rs +90 -2
- data/ext/ratatui_ruby/src/widgets/list.rs +6 -5
- data/ext/ratatui_ruby/src/widgets/overlay.rs +2 -1
- data/ext/ratatui_ruby/src/widgets/table.rs +7 -6
- data/ext/ratatui_ruby/src/widgets/table_state.rs +55 -0
- data/ext/ratatui_ruby/src/widgets/tabs.rs +3 -2
- data/lib/ratatui_ruby/buffer/cell.rb +25 -15
- data/lib/ratatui_ruby/buffer.rb +134 -2
- data/lib/ratatui_ruby/cell.rb +13 -5
- data/lib/ratatui_ruby/debug.rb +215 -0
- data/lib/ratatui_ruby/event/key.rb +3 -2
- data/lib/ratatui_ruby/event.rb +1 -1
- data/lib/ratatui_ruby/layout/constraint.rb +49 -0
- data/lib/ratatui_ruby/layout/layout.rb +119 -13
- data/lib/ratatui_ruby/layout/position.rb +55 -0
- data/lib/ratatui_ruby/layout/rect.rb +188 -0
- data/lib/ratatui_ruby/layout/size.rb +55 -0
- data/lib/ratatui_ruby/layout.rb +4 -0
- data/lib/ratatui_ruby/style/color.rb +149 -0
- data/lib/ratatui_ruby/style/style.rb +51 -4
- data/lib/ratatui_ruby/style.rb +2 -0
- data/lib/ratatui_ruby/symbols.rb +435 -0
- data/lib/ratatui_ruby/synthetic_events.rb +1 -1
- data/lib/ratatui_ruby/table_state.rb +51 -0
- data/lib/ratatui_ruby/terminal_lifecycle.rb +2 -1
- data/lib/ratatui_ruby/test_helper/event_injection.rb +6 -1
- data/lib/ratatui_ruby/test_helper.rb +9 -0
- data/lib/ratatui_ruby/text/line.rb +245 -0
- data/lib/ratatui_ruby/text/span.rb +158 -0
- data/lib/ratatui_ruby/text.rb +99 -0
- data/lib/ratatui_ruby/tui/canvas_factories.rb +103 -0
- data/lib/ratatui_ruby/tui/core.rb +13 -2
- data/lib/ratatui_ruby/tui/layout_factories.rb +50 -3
- data/lib/ratatui_ruby/tui/state_factories.rb +42 -0
- data/lib/ratatui_ruby/tui/text_factories.rb +40 -0
- data/lib/ratatui_ruby/tui/widget_factories.rb +135 -60
- data/lib/ratatui_ruby/tui.rb +22 -1
- data/lib/ratatui_ruby/version.rb +1 -1
- data/lib/ratatui_ruby/widgets/bar_chart/bar.rb +2 -0
- data/lib/ratatui_ruby/widgets/bar_chart/bar_group.rb +2 -0
- data/lib/ratatui_ruby/widgets/bar_chart.rb +30 -20
- data/lib/ratatui_ruby/widgets/block.rb +14 -6
- data/lib/ratatui_ruby/widgets/calendar.rb +2 -0
- data/lib/ratatui_ruby/widgets/canvas.rb +56 -0
- data/lib/ratatui_ruby/widgets/cell.rb +2 -0
- data/lib/ratatui_ruby/widgets/center.rb +2 -0
- data/lib/ratatui_ruby/widgets/chart.rb +6 -0
- data/lib/ratatui_ruby/widgets/clear.rb +2 -0
- data/lib/ratatui_ruby/widgets/coerceable_widget.rb +77 -0
- data/lib/ratatui_ruby/widgets/cursor.rb +2 -0
- data/lib/ratatui_ruby/widgets/gauge.rb +61 -3
- data/lib/ratatui_ruby/widgets/line_gauge.rb +66 -4
- data/lib/ratatui_ruby/widgets/list.rb +87 -3
- data/lib/ratatui_ruby/widgets/list_item.rb +2 -0
- data/lib/ratatui_ruby/widgets/overlay.rb +2 -0
- data/lib/ratatui_ruby/widgets/paragraph.rb +4 -0
- data/lib/ratatui_ruby/widgets/ratatui_logo.rb +2 -0
- data/lib/ratatui_ruby/widgets/ratatui_mascot.rb +2 -0
- data/lib/ratatui_ruby/widgets/row.rb +45 -0
- data/lib/ratatui_ruby/widgets/scrollbar.rb +2 -0
- data/lib/ratatui_ruby/widgets/shape/label.rb +2 -0
- data/lib/ratatui_ruby/widgets/sparkline.rb +21 -13
- data/lib/ratatui_ruby/widgets/table.rb +13 -3
- data/lib/ratatui_ruby/widgets/tabs.rb +6 -4
- data/lib/ratatui_ruby/widgets.rb +1 -0
- data/lib/ratatui_ruby.rb +42 -11
- data/sig/examples/app_all_events/model/app_model.rbs +23 -0
- data/sig/examples/app_all_events/model/event_entry.rbs +15 -8
- data/sig/examples/app_all_events/model/timestamp.rbs +1 -1
- data/sig/examples/app_all_events/view.rbs +1 -1
- data/sig/examples/app_stateful_interaction/app.rbs +5 -5
- data/sig/examples/widget_block_demo/app.rbs +6 -6
- data/sig/manifest.yaml +5 -0
- data/sig/patches/data.rbs +26 -0
- data/sig/patches/debugger__.rbs +8 -0
- data/sig/ratatui_ruby/buffer/cell.rbs +46 -0
- data/sig/ratatui_ruby/buffer.rbs +18 -0
- data/sig/ratatui_ruby/cell.rbs +44 -0
- data/sig/ratatui_ruby/clear.rbs +18 -0
- data/sig/ratatui_ruby/constraint.rbs +26 -0
- data/sig/ratatui_ruby/debug.rbs +45 -0
- data/sig/ratatui_ruby/draw.rbs +30 -0
- data/sig/ratatui_ruby/event.rbs +68 -8
- data/sig/ratatui_ruby/frame.rbs +4 -4
- data/sig/ratatui_ruby/interfaces.rbs +25 -0
- data/sig/ratatui_ruby/layout/constraint.rbs +39 -0
- data/sig/ratatui_ruby/layout/layout.rbs +45 -0
- data/sig/ratatui_ruby/layout/position.rbs +18 -0
- data/sig/ratatui_ruby/layout/rect.rbs +64 -0
- data/sig/ratatui_ruby/layout/size.rbs +18 -0
- data/sig/ratatui_ruby/output_guard.rbs +23 -0
- data/sig/ratatui_ruby/ratatui_ruby.rbs +84 -5
- data/sig/ratatui_ruby/rect.rbs +17 -0
- data/sig/ratatui_ruby/style/color.rbs +22 -0
- data/sig/ratatui_ruby/style/style.rbs +29 -0
- data/sig/ratatui_ruby/symbols.rbs +141 -0
- data/sig/ratatui_ruby/synthetic_events.rbs +21 -0
- data/sig/ratatui_ruby/table_state.rbs +6 -0
- data/sig/ratatui_ruby/terminal_lifecycle.rbs +31 -0
- data/sig/ratatui_ruby/test_helper/event_injection.rbs +2 -2
- data/sig/ratatui_ruby/test_helper/snapshot.rbs +22 -3
- data/sig/ratatui_ruby/test_helper/style_assertions.rbs +8 -1
- data/sig/ratatui_ruby/test_helper/test_doubles.rbs +7 -3
- data/sig/ratatui_ruby/text/line.rbs +27 -0
- data/sig/ratatui_ruby/text/span.rbs +23 -0
- data/sig/ratatui_ruby/text.rbs +12 -0
- data/sig/ratatui_ruby/tui/buffer_factories.rbs +1 -1
- data/sig/ratatui_ruby/tui/canvas_factories.rbs +23 -5
- data/sig/ratatui_ruby/tui/core.rbs +2 -2
- data/sig/ratatui_ruby/tui/layout_factories.rbs +16 -2
- data/sig/ratatui_ruby/tui/state_factories.rbs +8 -3
- data/sig/ratatui_ruby/tui/style_factories.rbs +3 -1
- data/sig/ratatui_ruby/tui/text_factories.rbs +7 -4
- data/sig/ratatui_ruby/tui/widget_factories.rbs +123 -30
- data/sig/ratatui_ruby/widgets/bar_chart.rbs +95 -0
- data/sig/ratatui_ruby/widgets/block.rbs +51 -0
- data/sig/ratatui_ruby/widgets/calendar.rbs +45 -0
- data/sig/ratatui_ruby/widgets/canvas.rbs +95 -0
- data/sig/ratatui_ruby/widgets/chart.rbs +91 -0
- data/sig/ratatui_ruby/widgets/coerceable_widget.rbs +26 -0
- data/sig/ratatui_ruby/widgets/gauge.rbs +44 -0
- data/sig/ratatui_ruby/widgets/line_gauge.rbs +48 -0
- data/sig/ratatui_ruby/widgets/list.rbs +63 -0
- data/sig/ratatui_ruby/widgets/misc.rbs +158 -0
- data/sig/ratatui_ruby/widgets/paragraph.rbs +45 -0
- data/sig/ratatui_ruby/widgets/row.rbs +43 -0
- data/sig/ratatui_ruby/widgets/scrollbar.rbs +53 -0
- data/sig/ratatui_ruby/widgets/shape/label.rbs +37 -0
- data/sig/ratatui_ruby/widgets/sparkline.rbs +45 -0
- data/sig/ratatui_ruby/widgets/table.rbs +78 -0
- data/sig/ratatui_ruby/widgets/tabs.rbs +44 -0
- data/sig/ratatui_ruby/{schema/list_item.rbs → widgets.rbs} +4 -4
- data/tasks/steep.rake +11 -0
- metadata +80 -63
- data/doc/contributors/v1.0.0_blockers.md +0 -870
- data/doc/troubleshooting/debugging.md +0 -101
- data/lib/ratatui_ruby/schema/bar_chart/bar.rb +0 -47
- data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +0 -25
- data/lib/ratatui_ruby/schema/bar_chart.rb +0 -287
- data/lib/ratatui_ruby/schema/block.rb +0 -198
- data/lib/ratatui_ruby/schema/calendar.rb +0 -84
- data/lib/ratatui_ruby/schema/canvas.rb +0 -239
- data/lib/ratatui_ruby/schema/center.rb +0 -67
- data/lib/ratatui_ruby/schema/chart.rb +0 -159
- data/lib/ratatui_ruby/schema/clear.rb +0 -62
- data/lib/ratatui_ruby/schema/constraint.rb +0 -151
- data/lib/ratatui_ruby/schema/cursor.rb +0 -50
- data/lib/ratatui_ruby/schema/gauge.rb +0 -72
- data/lib/ratatui_ruby/schema/layout.rb +0 -122
- data/lib/ratatui_ruby/schema/line_gauge.rb +0 -80
- data/lib/ratatui_ruby/schema/list.rb +0 -135
- data/lib/ratatui_ruby/schema/list_item.rb +0 -51
- data/lib/ratatui_ruby/schema/overlay.rb +0 -51
- data/lib/ratatui_ruby/schema/paragraph.rb +0 -107
- data/lib/ratatui_ruby/schema/ratatui_logo.rb +0 -31
- data/lib/ratatui_ruby/schema/ratatui_mascot.rb +0 -36
- data/lib/ratatui_ruby/schema/rect.rb +0 -174
- data/lib/ratatui_ruby/schema/row.rb +0 -76
- data/lib/ratatui_ruby/schema/scrollbar.rb +0 -143
- data/lib/ratatui_ruby/schema/shape/label.rb +0 -76
- data/lib/ratatui_ruby/schema/sparkline.rb +0 -142
- data/lib/ratatui_ruby/schema/style.rb +0 -97
- data/lib/ratatui_ruby/schema/table.rb +0 -141
- data/lib/ratatui_ruby/schema/tabs.rb +0 -85
- data/lib/ratatui_ruby/schema/text.rb +0 -217
- data/sig/examples/app_all_events/model/events.rbs +0 -15
- data/sig/examples/app_all_events/view_state.rbs +0 -21
- data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +0 -22
- data/sig/ratatui_ruby/schema/bar_chart/bar_group.rbs +0 -19
- data/sig/ratatui_ruby/schema/bar_chart.rbs +0 -38
- data/sig/ratatui_ruby/schema/block.rbs +0 -18
- data/sig/ratatui_ruby/schema/calendar.rbs +0 -23
- data/sig/ratatui_ruby/schema/canvas.rbs +0 -81
- data/sig/ratatui_ruby/schema/center.rbs +0 -17
- data/sig/ratatui_ruby/schema/chart.rbs +0 -39
- data/sig/ratatui_ruby/schema/constraint.rbs +0 -30
- data/sig/ratatui_ruby/schema/cursor.rbs +0 -16
- data/sig/ratatui_ruby/schema/draw.rbs +0 -33
- data/sig/ratatui_ruby/schema/gauge.rbs +0 -23
- data/sig/ratatui_ruby/schema/layout.rbs +0 -27
- data/sig/ratatui_ruby/schema/line_gauge.rbs +0 -24
- data/sig/ratatui_ruby/schema/list.rbs +0 -28
- data/sig/ratatui_ruby/schema/overlay.rbs +0 -15
- data/sig/ratatui_ruby/schema/paragraph.rbs +0 -20
- data/sig/ratatui_ruby/schema/ratatui_logo.rbs +0 -14
- data/sig/ratatui_ruby/schema/ratatui_mascot.rbs +0 -17
- data/sig/ratatui_ruby/schema/rect.rbs +0 -48
- data/sig/ratatui_ruby/schema/row.rbs +0 -28
- data/sig/ratatui_ruby/schema/scrollbar.rbs +0 -42
- data/sig/ratatui_ruby/schema/sparkline.rbs +0 -22
- data/sig/ratatui_ruby/schema/style.rbs +0 -19
- data/sig/ratatui_ruby/schema/table.rbs +0 -32
- data/sig/ratatui_ruby/schema/tabs.rbs +0 -21
- data/sig/ratatui_ruby/schema/text.rbs +0 -31
- /data/lib/ratatui_ruby/{schema/draw.rb → draw.rb} +0 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#--
|
|
4
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
+
# SPDX-License-Identifier: MIT-0
|
|
6
|
+
#++
|
|
7
|
+
|
|
8
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
9
|
+
|
|
10
|
+
require "ratatui_ruby"
|
|
11
|
+
|
|
12
|
+
##
|
|
13
|
+
# Interactive demonstration of RatatuiRuby debugging features.
|
|
14
|
+
#
|
|
15
|
+
# This example lets you trigger each debugging feature with a hotkey to verify
|
|
16
|
+
# your setup works before encountering a real bug.
|
|
17
|
+
#
|
|
18
|
+
# == Hotkeys
|
|
19
|
+
#
|
|
20
|
+
# [d] Enable debug_mode! — Shows the debug socket path for remote attachment
|
|
21
|
+
# [p] Trigger test_panic! — Deliberately crashes to verify Rust backtrace visibility
|
|
22
|
+
# [t] Cause TypeError — Passes wrong type to widget factory to show Rust stack frames
|
|
23
|
+
# [b] Show backtrace status — Displays current debug configuration
|
|
24
|
+
# [q] Quit
|
|
25
|
+
#
|
|
26
|
+
# == Usage
|
|
27
|
+
#
|
|
28
|
+
# # Normal mode (no backtraces):
|
|
29
|
+
# ruby examples/verify_debugging_usage/app.rb
|
|
30
|
+
#
|
|
31
|
+
# # With Rust backtraces only:
|
|
32
|
+
# RUST_BACKTRACE=1 ruby examples/verify_debugging_usage/app.rb
|
|
33
|
+
#
|
|
34
|
+
# # Full debug mode (stops at startup for debugger attachment):
|
|
35
|
+
# RR_DEBUG=1 ruby examples/verify_debugging_usage/app.rb
|
|
36
|
+
#
|
|
37
|
+
# == Remote Debugging
|
|
38
|
+
#
|
|
39
|
+
# When you press [d] to enable debug_mode!, the app continues running but
|
|
40
|
+
# prints a socket path. From another terminal:
|
|
41
|
+
#
|
|
42
|
+
# rdbg --attach
|
|
43
|
+
#
|
|
44
|
+
# This gives you a full debugger REPL while the TUI keeps running.
|
|
45
|
+
class VerifyDebuggingUsage
|
|
46
|
+
def initialize
|
|
47
|
+
@status_message = "Press a key to test debugging features"
|
|
48
|
+
@show_debug_info = false
|
|
49
|
+
@quit = false
|
|
50
|
+
|
|
51
|
+
# If debug mode was enabled via RR_DEBUG=1 at startup, capture the socket path
|
|
52
|
+
if RatatuiRuby::Debug.enabled?
|
|
53
|
+
@socket_path = begin
|
|
54
|
+
::DEBUGGER__.create_unix_domain_socket_name
|
|
55
|
+
rescue NameError
|
|
56
|
+
nil
|
|
57
|
+
end
|
|
58
|
+
@show_debug_info = true
|
|
59
|
+
@status_message = "RR_DEBUG=1 detected — debug mode active"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def run
|
|
64
|
+
RatatuiRuby.run do |tui|
|
|
65
|
+
@tui = tui
|
|
66
|
+
@loop_count = 0
|
|
67
|
+
|
|
68
|
+
loop do
|
|
69
|
+
@loop_count += 1
|
|
70
|
+
|
|
71
|
+
# 🎯 Breakpoint every 250 loops. Try: p @status_message
|
|
72
|
+
if RatatuiRuby::Debug.enabled? && (@loop_count % 250).zero?
|
|
73
|
+
you_found_me = "🎉 You found me! Loop ##{@loop_count}"
|
|
74
|
+
# rubocop:disable Lint/Debugger
|
|
75
|
+
debugger
|
|
76
|
+
# rubocop:enable Lint/Debugger
|
|
77
|
+
_ = you_found_me # Suppress unused variable warning
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
render
|
|
81
|
+
break if @quit || handle_input == :quit
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
private def render
|
|
87
|
+
@tui.draw do |frame|
|
|
88
|
+
constraints = [
|
|
89
|
+
@tui.constraint_length(3), # Status
|
|
90
|
+
@tui.constraint_length(5), # Config
|
|
91
|
+
@tui.constraint_length(6), # Actions
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
if @show_debug_info
|
|
95
|
+
constraints << @tui.constraint_length(6) # Debug info
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
constraints << @tui.constraint_fill(1) # Spacer
|
|
99
|
+
constraints << @tui.constraint_length(3) # Help
|
|
100
|
+
|
|
101
|
+
chunks = @tui.layout_split(frame.area, direction: :vertical, constraints:)
|
|
102
|
+
|
|
103
|
+
idx = 0
|
|
104
|
+
render_status(frame, chunks[idx])
|
|
105
|
+
idx += 1
|
|
106
|
+
render_config(frame, chunks[idx])
|
|
107
|
+
idx += 1
|
|
108
|
+
render_actions(frame, chunks[idx])
|
|
109
|
+
idx += 1
|
|
110
|
+
|
|
111
|
+
if @show_debug_info
|
|
112
|
+
render_debug_info(frame, chunks[idx])
|
|
113
|
+
idx += 1
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Skip spacer
|
|
117
|
+
idx += 1
|
|
118
|
+
render_help(frame, chunks[idx])
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
private def render_status(frame, area)
|
|
123
|
+
frame.render_widget(
|
|
124
|
+
@tui.paragraph(
|
|
125
|
+
text: @status_message,
|
|
126
|
+
alignment: :center,
|
|
127
|
+
block: @tui.block(
|
|
128
|
+
title: " Status ",
|
|
129
|
+
title_alignment: :center,
|
|
130
|
+
borders: [:all],
|
|
131
|
+
border_style: { fg: :yellow }
|
|
132
|
+
)
|
|
133
|
+
),
|
|
134
|
+
area
|
|
135
|
+
)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
private def render_config(frame, area)
|
|
139
|
+
config_lines = [
|
|
140
|
+
"Rust Backtraces: #{flag(RatatuiRuby::Debug.rust_backtrace_enabled?)}",
|
|
141
|
+
"Full Debug Mode: #{flag(RatatuiRuby::Debug.enabled?)}",
|
|
142
|
+
"Remote Debugging: #{remote_mode_description}",
|
|
143
|
+
].join("\n")
|
|
144
|
+
|
|
145
|
+
frame.render_widget(
|
|
146
|
+
@tui.paragraph(
|
|
147
|
+
text: config_lines,
|
|
148
|
+
block: @tui.block(
|
|
149
|
+
title: " Current Debug Configuration ",
|
|
150
|
+
borders: [:all],
|
|
151
|
+
border_style: { fg: :cyan }
|
|
152
|
+
)
|
|
153
|
+
),
|
|
154
|
+
area
|
|
155
|
+
)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
private def render_actions(frame, area)
|
|
159
|
+
actions_lines = [
|
|
160
|
+
"[d] Enable debug_mode! and show socket info",
|
|
161
|
+
"[p] Trigger test_panic! to verify backtrace visibility",
|
|
162
|
+
"[t] Cause TypeError (pass wrong type to widget)",
|
|
163
|
+
"[b] Refresh debug status",
|
|
164
|
+
].join("\n")
|
|
165
|
+
|
|
166
|
+
frame.render_widget(
|
|
167
|
+
@tui.paragraph(
|
|
168
|
+
text: actions_lines,
|
|
169
|
+
block: @tui.block(
|
|
170
|
+
title: " Available Actions ",
|
|
171
|
+
borders: [:all],
|
|
172
|
+
border_style: { fg: :green }
|
|
173
|
+
)
|
|
174
|
+
),
|
|
175
|
+
area
|
|
176
|
+
)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
private def render_debug_info(frame, area)
|
|
180
|
+
socket_display = @socket_path || "(socket not available)"
|
|
181
|
+
info_lines = [
|
|
182
|
+
"Socket: #{socket_display}",
|
|
183
|
+
"Attach: rdbg --attach",
|
|
184
|
+
"Hint: type 'continue' if you see SIGURG",
|
|
185
|
+
]
|
|
186
|
+
|
|
187
|
+
frame.render_widget(
|
|
188
|
+
@tui.paragraph(
|
|
189
|
+
text: info_lines.join("\n"),
|
|
190
|
+
block: @tui.block(
|
|
191
|
+
title: " Remote Debugging ",
|
|
192
|
+
borders: [:all],
|
|
193
|
+
border_style: { fg: :magenta }
|
|
194
|
+
)
|
|
195
|
+
),
|
|
196
|
+
area
|
|
197
|
+
)
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
private def render_help(frame, area)
|
|
201
|
+
frame.render_widget(
|
|
202
|
+
@tui.paragraph(
|
|
203
|
+
text: "[d] debug_mode! [p] test_panic! [t] TypeError [b] status [q] quit",
|
|
204
|
+
alignment: :center,
|
|
205
|
+
block: @tui.block(
|
|
206
|
+
borders: [:all],
|
|
207
|
+
border_style: { fg: :dark_gray }
|
|
208
|
+
)
|
|
209
|
+
),
|
|
210
|
+
area
|
|
211
|
+
)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
private def flag(value)
|
|
215
|
+
value ? "✓ enabled" : "✗ disabled"
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
private def remote_mode_description
|
|
219
|
+
case RatatuiRuby::Debug.remote_debugging_mode
|
|
220
|
+
when :open
|
|
221
|
+
attached = debugger_attached? ? " — ATTACHED" : " — waiting"
|
|
222
|
+
"✓ open#{attached}"
|
|
223
|
+
when :open_nonstop
|
|
224
|
+
attached = debugger_attached? ? " — ATTACHED" : ""
|
|
225
|
+
"✓ open_nonstop#{attached}"
|
|
226
|
+
else
|
|
227
|
+
"✗ not configured"
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# ☣️ FRAGILE: This pokes at debug gem internals.
|
|
232
|
+
#
|
|
233
|
+
# Private instance variables can change between gem versions. This code
|
|
234
|
+
# may silently break. We accept that risk here because this showcase
|
|
235
|
+
# exists specifically to demonstrate debugger attachment status.
|
|
236
|
+
#
|
|
237
|
+
# For production apps, checking Debug.enabled? is sufficient — knowing
|
|
238
|
+
# whether a client has attached rarely matters.
|
|
239
|
+
private def debugger_attached?
|
|
240
|
+
return false unless defined?(::DEBUGGER__::SESSION)
|
|
241
|
+
|
|
242
|
+
ui = ::DEBUGGER__::SESSION.instance_variable_get(:@ui)
|
|
243
|
+
return false unless ui
|
|
244
|
+
|
|
245
|
+
# The @sock instance variable is set when a client connects
|
|
246
|
+
sock = ui.instance_variable_get(:@sock)
|
|
247
|
+
!sock.nil?
|
|
248
|
+
rescue
|
|
249
|
+
false
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
private def handle_input
|
|
253
|
+
case @tui.poll_event
|
|
254
|
+
in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
|
|
255
|
+
:quit
|
|
256
|
+
|
|
257
|
+
in { type: :key, code: "d" }
|
|
258
|
+
enable_debug_mode!
|
|
259
|
+
|
|
260
|
+
in { type: :key, code: "p" }
|
|
261
|
+
trigger_test_panic!
|
|
262
|
+
|
|
263
|
+
in { type: :key, code: "t" }
|
|
264
|
+
trigger_type_error!
|
|
265
|
+
|
|
266
|
+
in { type: :key, code: "b" }
|
|
267
|
+
@status_message = "Debug status refreshed at #{Time.now.strftime('%H:%M:%S')}"
|
|
268
|
+
|
|
269
|
+
else
|
|
270
|
+
nil
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
private def enable_debug_mode!
|
|
275
|
+
if RatatuiRuby::Debug.enabled?
|
|
276
|
+
@status_message = "Debug mode already enabled!"
|
|
277
|
+
else
|
|
278
|
+
# debug_mode! returns the socket path and suppresses the debug gem's output
|
|
279
|
+
@socket_path = RatatuiRuby.debug_mode!
|
|
280
|
+
@status_message = "debug_mode! enabled"
|
|
281
|
+
@show_debug_info = true
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
private def trigger_test_panic!
|
|
286
|
+
if RatatuiRuby::Debug.rust_backtrace_enabled?
|
|
287
|
+
@status_message = "Triggering test_panic! — check stderr for backtrace..."
|
|
288
|
+
else
|
|
289
|
+
@status_message = "Triggering test_panic! — backtrace hidden (set RUST_BACKTRACE=1)"
|
|
290
|
+
end
|
|
291
|
+
render # Show the message before crashing
|
|
292
|
+
|
|
293
|
+
# Give a moment for the render to complete
|
|
294
|
+
sleep 0.1
|
|
295
|
+
|
|
296
|
+
# This will crash the app with a Rust panic. If RUST_BACKTRACE=1 or
|
|
297
|
+
# debug mode is enabled, you'll see the full Rust stack trace after
|
|
298
|
+
# the terminal is restored.
|
|
299
|
+
RatatuiRuby::Debug.test_panic!
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
private def trigger_type_error!
|
|
303
|
+
if RatatuiRuby::Debug.rust_backtrace_enabled?
|
|
304
|
+
@status_message = "Triggering TypeError — check stderr for error message..."
|
|
305
|
+
else
|
|
306
|
+
@status_message = "Triggering TypeError — set RUST_BACKTRACE=1 for stack trace"
|
|
307
|
+
end
|
|
308
|
+
render # Show the message before crashing
|
|
309
|
+
sleep 0.1
|
|
310
|
+
|
|
311
|
+
# Bypass the factory's DWIM coercion to trigger a real Rust TypeError.
|
|
312
|
+
# Uses Widgets::Table.new directly with invalid rows type.
|
|
313
|
+
bad_table = RatatuiRuby::Widgets::Table.new(rows: 42, widths: [])
|
|
314
|
+
@tui.draw { |f| f.render_widget(bad_table, f.area) }
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
VerifyDebuggingUsage.new.run if __FILE__ == $PROGRAM_NAME
|
|
@@ -37,24 +37,26 @@ class WidgetCanvas
|
|
|
37
37
|
|
|
38
38
|
private def render
|
|
39
39
|
@tui.draw do |frame|
|
|
40
|
-
# Define shapes
|
|
40
|
+
# Define shapes using terse aliases (circle, rectangle, point, map, label)
|
|
41
|
+
# These are shorter forms of shape_circle, shape_rectangle, etc.
|
|
41
42
|
shapes = []
|
|
42
43
|
|
|
43
|
-
# 1. Static Grid (Lines)
|
|
44
|
+
# 1. Static Grid (Lines) - using shape_line (no terse alias for line)
|
|
44
45
|
(-100..100).step(20) do |i|
|
|
45
46
|
shapes << @tui.shape_line(x1: i.to_f, y1: -100.0, x2: i.to_f, y2: 100.0, color: :gray)
|
|
46
47
|
shapes << @tui.shape_line(x1: -100.0, y1: i.to_f, x2: 100.0, y2: i.to_f, color: :gray)
|
|
47
48
|
end
|
|
48
49
|
|
|
49
|
-
# 2. Moving Circle (The "Player")
|
|
50
|
-
shapes << @tui.
|
|
50
|
+
# 2. Moving Circle (The "Player") - using terse 'circle' alias
|
|
51
|
+
shapes << @tui.circle(
|
|
51
52
|
x: @x_offset,
|
|
52
53
|
y: @y_offset,
|
|
53
54
|
radius: 10.0,
|
|
54
55
|
color: :green
|
|
55
56
|
)
|
|
56
57
|
|
|
57
|
-
# 3. Static Rectangle (Target)
|
|
58
|
+
# 3. Static Rectangle (Target) - using shape_rectangle (no 'rectangle' alias
|
|
59
|
+
# to avoid confusion with Layout::Rect)
|
|
58
60
|
shapes << @tui.shape_rectangle(
|
|
59
61
|
x: 30.0,
|
|
60
62
|
y: 30.0,
|
|
@@ -63,16 +65,16 @@ class WidgetCanvas
|
|
|
63
65
|
color: :red
|
|
64
66
|
)
|
|
65
67
|
|
|
66
|
-
# 4. Points (Starfield)
|
|
68
|
+
# 4. Points (Starfield) - using terse 'point' alias
|
|
67
69
|
# Deterministic "random" points
|
|
68
70
|
10.times do |i|
|
|
69
|
-
shapes << @tui.
|
|
71
|
+
shapes << @tui.point(
|
|
70
72
|
x: ((i * 37) % 200) - 100.0,
|
|
71
73
|
y: ((i * 19) % 200) - 100.0
|
|
72
74
|
)
|
|
73
75
|
end
|
|
74
76
|
|
|
75
|
-
# 5.
|
|
77
|
+
# 5. Connecting line from origin to player position
|
|
76
78
|
shapes << @tui.shape_line(x1: 0.0, y1: 0.0, x2: @x_offset, y2: @y_offset, color: :yellow)
|
|
77
79
|
|
|
78
80
|
canvas = @tui.canvas(
|
|
@@ -89,21 +91,24 @@ class WidgetCanvas
|
|
|
89
91
|
direction: :vertical,
|
|
90
92
|
constraints: [
|
|
91
93
|
@tui.constraint_fill(1),
|
|
92
|
-
@tui.constraint_length(
|
|
94
|
+
@tui.constraint_length(2),
|
|
93
95
|
]
|
|
94
96
|
)
|
|
95
97
|
|
|
96
98
|
frame.render_widget(canvas, layout[0])
|
|
97
99
|
|
|
98
|
-
#
|
|
100
|
+
# Query: Canvas#get_point maps canvas coordinates to normalized [0.0, 1.0] grid
|
|
101
|
+
normalized = canvas.get_point(@x_offset, @y_offset)
|
|
102
|
+
norm_str = normalized ? format("[%.2f, %.2f]", normalized[0], normalized[1]) : "nil"
|
|
103
|
+
|
|
104
|
+
# Controls showing query method demonstration (single concise line)
|
|
99
105
|
controls = @tui.paragraph(
|
|
100
106
|
text: [
|
|
101
|
-
@tui.text_line(spans: [
|
|
102
|
-
@tui.text_span(content: "Canvas auto-animates.", style: @tui.style(fg: :yellow)),
|
|
103
|
-
]),
|
|
104
107
|
@tui.text_line(spans: [
|
|
105
108
|
@tui.text_span(content: "q", style: @tui.style(modifiers: [:bold, :underlined])),
|
|
106
|
-
@tui.text_span(content: ": Quit"),
|
|
109
|
+
@tui.text_span(content: ": Quit "),
|
|
110
|
+
@tui.text_span(content: "get_point → ", style: @tui.style(fg: :dark_gray)),
|
|
111
|
+
@tui.text_span(content: norm_str, style: @tui.style(fg: :cyan)),
|
|
107
112
|
]),
|
|
108
113
|
],
|
|
109
114
|
block: @tui.block(borders: [:top])
|
|
@@ -29,6 +29,10 @@ class WidgetGauge
|
|
|
29
29
|
@ratios = [0.0, 0.25, 0.5, 0.65, 0.8, 0.95, 1.0]
|
|
30
30
|
@ratio_index = 3
|
|
31
31
|
|
|
32
|
+
# Demonstrates both ratio (0.0-1.0) and percent (0-100) input modes
|
|
33
|
+
@input_modes = [:ratio, :percent]
|
|
34
|
+
@input_mode_index = 0
|
|
35
|
+
|
|
32
36
|
@gauge_colors = [
|
|
33
37
|
{ name: "Green", color: :green },
|
|
34
38
|
{ name: "Yellow", color: :yellow },
|
|
@@ -116,13 +120,20 @@ class WidgetGauge
|
|
|
116
120
|
frame.render_widget(title, title_area)
|
|
117
121
|
|
|
118
122
|
# Gauge 1: Main interactive gauge
|
|
123
|
+
# Demonstrates both ratio (0.0-1.0) and percent (0-100) input modes
|
|
124
|
+
input_mode = @input_modes[@input_mode_index]
|
|
125
|
+
gauge_opts = if input_mode == :percent
|
|
126
|
+
{ percent: (@ratio * 100).to_i } # percent: accepts 0-100
|
|
127
|
+
else
|
|
128
|
+
{ ratio: @ratio } # ratio: accepts 0.0-1.0
|
|
129
|
+
end
|
|
119
130
|
gauge1 = @tui.gauge(
|
|
120
|
-
|
|
131
|
+
**gauge_opts,
|
|
121
132
|
label:,
|
|
122
133
|
style: bg_style,
|
|
123
134
|
gauge_style:,
|
|
124
135
|
use_unicode:,
|
|
125
|
-
block: @tui.block(title: "Interactive Gauge")
|
|
136
|
+
block: @tui.block(title: "Interactive Gauge (#{input_mode}:)")
|
|
126
137
|
)
|
|
127
138
|
frame.render_widget(gauge1, gauge1_area)
|
|
128
139
|
|
|
@@ -178,7 +189,9 @@ class WidgetGauge
|
|
|
178
189
|
@tui.text_span(content: "u", style: @hotkey_style),
|
|
179
190
|
@tui.text_span(content: ": Unicode (#{use_unicode ? 'On' : 'Off'}) "),
|
|
180
191
|
@tui.text_span(content: "l", style: @hotkey_style),
|
|
181
|
-
@tui.text_span(content: ": Label (#{@label_modes[@label_mode_index][:name]})"),
|
|
192
|
+
@tui.text_span(content: ": Label (#{@label_modes[@label_mode_index][:name]}) "),
|
|
193
|
+
@tui.text_span(content: "i", style: @hotkey_style),
|
|
194
|
+
@tui.text_span(content: ": Input (#{@input_modes[@input_mode_index]}:)"),
|
|
182
195
|
]),
|
|
183
196
|
]
|
|
184
197
|
),
|
|
@@ -204,6 +217,8 @@ class WidgetGauge
|
|
|
204
217
|
@use_unicode_index = (@use_unicode_index + 1) % @use_unicode_options.length
|
|
205
218
|
in type: :key, code: "l"
|
|
206
219
|
@label_mode_index = (@label_mode_index + 1) % @label_modes.length
|
|
220
|
+
in type: :key, code: "i"
|
|
221
|
+
@input_mode_index = (@input_mode_index + 1) % @input_modes.length
|
|
207
222
|
else
|
|
208
223
|
# Ignore other events
|
|
209
224
|
nil
|
|
@@ -206,6 +206,11 @@ class WidgetLayoutSplit
|
|
|
206
206
|
end
|
|
207
207
|
|
|
208
208
|
private def render_controls(frame, area)
|
|
209
|
+
# Demonstrate Constraint#call - show computed sizes for 100 units
|
|
210
|
+
constraints = current_constraints
|
|
211
|
+
applied = constraints.map { |c| c.(100) } # proc-like invocation
|
|
212
|
+
apply_str = "constraint.(100): #{applied.join(', ')}"
|
|
213
|
+
|
|
209
214
|
controls = @tui.block(
|
|
210
215
|
title: "Controls",
|
|
211
216
|
borders: [:all],
|
|
@@ -221,13 +226,14 @@ class WidgetLayoutSplit
|
|
|
221
226
|
]),
|
|
222
227
|
@tui.text_line(spans: [
|
|
223
228
|
@tui.text_span(content: "c", style: @hotkey_style),
|
|
224
|
-
@tui.text_span(content: ": Constraints (#{current_constraint_name})"),
|
|
225
|
-
]),
|
|
226
|
-
# Row 3: Quit
|
|
227
|
-
@tui.text_line(spans: [
|
|
229
|
+
@tui.text_span(content: ": Constraints (#{current_constraint_name}) "),
|
|
228
230
|
@tui.text_span(content: "q", style: @hotkey_style),
|
|
229
231
|
@tui.text_span(content: ": Quit"),
|
|
230
232
|
]),
|
|
233
|
+
# Row 3: Apply demonstration
|
|
234
|
+
@tui.text_line(spans: [
|
|
235
|
+
@tui.text_span(content: apply_str, style: @tui.style(fg: :dark_gray)),
|
|
236
|
+
]),
|
|
231
237
|
]
|
|
232
238
|
),
|
|
233
239
|
]
|
data/examples/widget_list/app.rb
CHANGED
|
@@ -230,8 +230,6 @@ class WidgetList
|
|
|
230
230
|
# Determine selection/offset based on mode
|
|
231
231
|
effective_selection = offset_mode_config[:allow_selection] ? @selected_index : nil
|
|
232
232
|
effective_offset = offset_mode_config[:offset]
|
|
233
|
-
selection_label = effective_selection.nil? ? "none" : effective_selection.to_s
|
|
234
|
-
offset_label = effective_offset.nil? ? "auto" : effective_offset.to_s
|
|
235
233
|
|
|
236
234
|
@tui.draw do |frame|
|
|
237
235
|
# Split into main content and control panel
|
|
@@ -258,8 +256,11 @@ class WidgetList
|
|
|
258
256
|
title = @tui.paragraph(text: "List Widget - Interactive Attribute Cycling")
|
|
259
257
|
frame.render_widget(title, title_area)
|
|
260
258
|
|
|
261
|
-
#
|
|
262
|
-
|
|
259
|
+
# Build list first to demonstrate query methods:
|
|
260
|
+
# - List#len (with #length, #size aliases)
|
|
261
|
+
# - List#selection (alias for #selected_index)
|
|
262
|
+
# - List#selected_item (returns item at selection, or nil)
|
|
263
|
+
base_list = @tui.list(
|
|
263
264
|
items:,
|
|
264
265
|
selected_index: effective_selection,
|
|
265
266
|
offset: effective_offset,
|
|
@@ -269,9 +270,24 @@ class WidgetList
|
|
|
269
270
|
repeat_highlight_symbol: repeat_config[:repeat],
|
|
270
271
|
highlight_spacing: spacing_config[:spacing],
|
|
271
272
|
direction: direction_config[:direction],
|
|
272
|
-
scroll_padding: scroll_padding_config[:padding]
|
|
273
|
+
scroll_padding: scroll_padding_config[:padding]
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
# Demonstrate query methods: len, selected_index, selected_item
|
|
277
|
+
item_count = base_list.len
|
|
278
|
+
current_index = base_list.selected_index # Explicit name - returns index
|
|
279
|
+
current_item = base_list.selected_item # Explicit name - returns item
|
|
280
|
+
|
|
281
|
+
# Format the selected item for display (handle rich text objects)
|
|
282
|
+
item_preview = case current_item
|
|
283
|
+
when nil then "none"
|
|
284
|
+
when String then (current_item.length > 12) ? "#{current_item[0..11]}…" : current_item
|
|
285
|
+
else current_item.class.name.split("::").last # Show type for rich text
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
list = base_list.with(
|
|
273
289
|
block: @tui.block(
|
|
274
|
-
title: "#{@item_sets[@item_set_index][:name]}
|
|
290
|
+
title: "#{@item_sets[@item_set_index][:name]} (len: #{item_count}) | index: #{current_index.inspect} → #{item_preview}",
|
|
275
291
|
borders: [:all]
|
|
276
292
|
)
|
|
277
293
|
)
|
data/examples/widget_rect/app.rb
CHANGED
|
@@ -97,6 +97,10 @@ class WidgetRect
|
|
|
97
97
|
clamped = r.clamp(bounds)
|
|
98
98
|
union_r = r.union(@sidebar_rect)
|
|
99
99
|
|
|
100
|
+
# Extract position and size from rect
|
|
101
|
+
pos = r.position # => Position(x:, y:)
|
|
102
|
+
size = r.size # => Size(width:, height:)
|
|
103
|
+
|
|
100
104
|
text_content = [
|
|
101
105
|
@tui.text_line(spans: [
|
|
102
106
|
@tui.text_span(content: "Active View: ", style: @label_style),
|
|
@@ -112,19 +116,16 @@ class WidgetRect
|
|
|
112
116
|
]),
|
|
113
117
|
" left:#{r.left} right:#{r.right} top:#{r.top} bottom:#{r.bottom}",
|
|
114
118
|
@tui.text_line(spans: [
|
|
115
|
-
@tui.text_span(content: "
|
|
119
|
+
@tui.text_span(content: "Conversion Methods ", style: @label_style),
|
|
120
|
+
@tui.text_span(content: "(as_position/as_size):", style: @dim_style),
|
|
116
121
|
]),
|
|
117
|
-
"
|
|
122
|
+
" Position: x=#{pos.x} y=#{pos.y} Size: #{size.width}x#{size.height}",
|
|
118
123
|
@tui.text_line(spans: [
|
|
119
124
|
@tui.text_span(content: "Geometry Transformations:", style: @label_style),
|
|
120
125
|
]),
|
|
121
126
|
" inner(2): x:#{inner_r.x} y:#{inner_r.y} w:#{inner_r.width} h:#{inner_r.height}",
|
|
122
127
|
" offset(3,2): x:#{offset_r.x} y:#{offset_r.y} clamp: x:#{clamped.x} y:#{clamped.y}",
|
|
123
128
|
" union(sidebar): w:#{union_r.width} h:#{union_r.height}",
|
|
124
|
-
@tui.text_line(spans: [
|
|
125
|
-
@tui.text_span(content: "Iterators:", style: @label_style),
|
|
126
|
-
]),
|
|
127
|
-
" rows:#{r.height} columns:#{r.width} positions:#{r.area}",
|
|
128
129
|
@tui.text_line(spans: [
|
|
129
130
|
@tui.text_span(content: "Hit Testing ", style: @label_style),
|
|
130
131
|
@tui.text_span(content: "(Rect#contains?):", style: @dim_style),
|