ratatui_ruby 1.0.0 → 1.0.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/ext/ratatui_ruby/Cargo.lock +1 -1
- data/ext/ratatui_ruby/Cargo.toml +1 -1
- data/lib/ratatui_ruby/version.rb +1 -1
- metadata +1 -232
- data/.builds/ruby-3.2.yml +0 -54
- data/.builds/ruby-3.3.yml +0 -54
- data/.builds/ruby-3.4.yml +0 -54
- data/.builds/ruby-4.0.0.yml +0 -54
- data/.pre-commit-config.yaml +0 -16
- data/.rubocop.yml +0 -10
- data/AGENTS.md +0 -146
- data/CHANGELOG.md +0 -710
- data/README.md +0 -187
- data/README.rdoc +0 -302
- data/Rakefile +0 -11
- data/Steepfile +0 -49
- data/doc/concepts/application_architecture.md +0 -321
- data/doc/concepts/application_testing.md +0 -193
- data/doc/concepts/async.md +0 -190
- data/doc/concepts/custom_widgets.md +0 -247
- data/doc/concepts/debugging.md +0 -401
- data/doc/concepts/event_handling.md +0 -162
- data/doc/concepts/interactive_design.md +0 -146
- data/doc/contributors/auditing/parity.md +0 -239
- data/doc/contributors/design/ruby_frontend.md +0 -420
- data/doc/contributors/design/rust_backend.md +0 -422
- data/doc/contributors/design.md +0 -11
- data/doc/contributors/developing_examples.md +0 -400
- data/doc/contributors/documentation_style.md +0 -121
- data/doc/contributors/index.md +0 -21
- data/doc/contributors/todo/align/api_completeness_audit-finished.md +0 -375
- data/doc/contributors/todo/align/api_completeness_audit-unfinished.md +0 -206
- data/doc/contributors/todo/align/terminal.md +0 -647
- data/doc/contributors/todo/future_work.md +0 -169
- data/doc/contributors/upstream_requests/tab_rects.md +0 -173
- data/doc/contributors/upstream_requests/title_rects.md +0 -132
- data/doc/custom.css +0 -22
- data/doc/getting_started/quickstart.md +0 -291
- data/doc/getting_started/why.md +0 -93
- data/doc/images/app_all_events.png +0 -0
- data/doc/images/app_cli_rich_moments.gif +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/index.md +0 -39
- data/doc/troubleshooting/async.md +0 -4
- data/doc/troubleshooting/terminal_limitations.md +0 -131
- data/doc/troubleshooting/tui_output.md +0 -197
- data/examples/app_all_events/README.md +0 -114
- data/examples/app_all_events/app.rb +0 -98
- data/examples/app_all_events/model/app_model.rb +0 -159
- data/examples/app_all_events/model/event_color_cycle.rb +0 -43
- data/examples/app_all_events/model/event_entry.rb +0 -94
- data/examples/app_all_events/model/msg.rb +0 -39
- data/examples/app_all_events/model/timestamp.rb +0 -56
- data/examples/app_all_events/update.rb +0 -75
- data/examples/app_all_events/view/app_view.rb +0 -80
- data/examples/app_all_events/view/controls_view.rb +0 -54
- data/examples/app_all_events/view/counts_view.rb +0 -61
- data/examples/app_all_events/view/live_view.rb +0 -72
- data/examples/app_all_events/view/log_view.rb +0 -57
- data/examples/app_all_events/view.rb +0 -9
- data/examples/app_cli_rich_moments/README.md +0 -81
- data/examples/app_cli_rich_moments/app.rb +0 -189
- data/examples/app_color_picker/README.md +0 -156
- data/examples/app_color_picker/app.rb +0 -76
- data/examples/app_color_picker/clipboard.rb +0 -86
- data/examples/app_color_picker/color.rb +0 -193
- data/examples/app_color_picker/controls.rb +0 -92
- data/examples/app_color_picker/copy_dialog.rb +0 -168
- data/examples/app_color_picker/export_pane.rb +0 -128
- data/examples/app_color_picker/harmony.rb +0 -58
- data/examples/app_color_picker/input.rb +0 -176
- data/examples/app_color_picker/main_container.rb +0 -180
- data/examples/app_color_picker/palette.rb +0 -111
- data/examples/app_debugging_showcase/README.md +0 -119
- data/examples/app_debugging_showcase/app.rb +0 -318
- data/examples/app_login_form/README.md +0 -58
- data/examples/app_login_form/app.rb +0 -109
- data/examples/app_stateful_interaction/README.md +0 -35
- data/examples/app_stateful_interaction/app.rb +0 -328
- data/examples/timeout_demo.rb +0 -45
- data/examples/verify_quickstart_dsl/README.md +0 -55
- data/examples/verify_quickstart_dsl/app.rb +0 -49
- data/examples/verify_quickstart_layout/README.md +0 -77
- data/examples/verify_quickstart_layout/app.rb +0 -73
- data/examples/verify_quickstart_lifecycle/README.md +0 -68
- data/examples/verify_quickstart_lifecycle/app.rb +0 -62
- data/examples/verify_readme_usage/README.md +0 -49
- data/examples/verify_readme_usage/app.rb +0 -42
- data/examples/verify_website_managed/README.md +0 -48
- data/examples/verify_website_managed/app.rb +0 -36
- data/examples/verify_website_menu/README.md +0 -60
- data/examples/verify_website_menu/app.rb +0 -84
- data/examples/verify_website_spinner/README.md +0 -44
- data/examples/verify_website_spinner/app.rb +0 -34
- data/examples/widget_barchart/README.md +0 -58
- data/examples/widget_barchart/app.rb +0 -240
- data/examples/widget_block/README.md +0 -44
- data/examples/widget_block/app.rb +0 -258
- data/examples/widget_box/README.md +0 -54
- data/examples/widget_box/app.rb +0 -255
- data/examples/widget_calendar/README.md +0 -48
- data/examples/widget_calendar/app.rb +0 -115
- data/examples/widget_canvas/README.md +0 -31
- data/examples/widget_canvas/app.rb +0 -130
- data/examples/widget_cell/README.md +0 -45
- data/examples/widget_cell/app.rb +0 -112
- data/examples/widget_center/README.md +0 -33
- data/examples/widget_center/app.rb +0 -118
- data/examples/widget_chart/README.md +0 -50
- data/examples/widget_chart/app.rb +0 -220
- data/examples/widget_gauge/README.md +0 -50
- data/examples/widget_gauge/app.rb +0 -229
- data/examples/widget_layout_split/README.md +0 -53
- data/examples/widget_layout_split/app.rb +0 -260
- data/examples/widget_line_gauge/README.md +0 -50
- data/examples/widget_line_gauge/app.rb +0 -219
- data/examples/widget_list/README.md +0 -58
- data/examples/widget_list/app.rb +0 -384
- data/examples/widget_map/README.md +0 -48
- data/examples/widget_map/app.rb +0 -95
- data/examples/widget_overlay/README.md +0 -45
- data/examples/widget_overlay/app.rb +0 -250
- data/examples/widget_popup/README.md +0 -45
- data/examples/widget_popup/app.rb +0 -106
- data/examples/widget_ratatui_logo/README.md +0 -43
- data/examples/widget_ratatui_logo/app.rb +0 -104
- data/examples/widget_ratatui_mascot/README.md +0 -43
- data/examples/widget_ratatui_mascot/app.rb +0 -95
- data/examples/widget_rect/README.md +0 -53
- data/examples/widget_rect/app.rb +0 -222
- data/examples/widget_render/README.md +0 -46
- data/examples/widget_render/app.rb +0 -186
- data/examples/widget_render/app.rbs +0 -41
- data/examples/widget_rich_text/README.md +0 -44
- data/examples/widget_rich_text/app.rb +0 -193
- data/examples/widget_scroll_text/README.md +0 -46
- data/examples/widget_scroll_text/app.rb +0 -109
- data/examples/widget_scrollbar/README.md +0 -46
- data/examples/widget_scrollbar/app.rb +0 -155
- data/examples/widget_sparkline/README.md +0 -51
- data/examples/widget_sparkline/app.rb +0 -277
- data/examples/widget_style_colors/README.md +0 -43
- data/examples/widget_style_colors/app.rb +0 -83
- data/examples/widget_table/README.md +0 -57
- data/examples/widget_table/app.rb +0 -279
- data/examples/widget_tabs/README.md +0 -50
- data/examples/widget_tabs/app.rb +0 -183
- data/examples/widget_text_width/README.md +0 -44
- data/examples/widget_text_width/app.rb +0 -117
- data/migrate_to_buffer.rb +0 -145
- data/mise.toml +0 -8
- data/tasks/autodoc/examples.rb +0 -87
- data/tasks/autodoc/member.rb +0 -58
- data/tasks/autodoc/name.rb +0 -21
- data/tasks/autodoc.rake +0 -21
- data/tasks/bump/cargo_lockfile.rb +0 -21
- data/tasks/bump/changelog.rb +0 -47
- data/tasks/bump/header.rb +0 -32
- data/tasks/bump/history.rb +0 -32
- data/tasks/bump/links.rb +0 -69
- data/tasks/bump/manifest.rb +0 -33
- data/tasks/bump/ruby_gem.rb +0 -49
- data/tasks/bump/sem_ver.rb +0 -40
- data/tasks/bump/unreleased_section.rb +0 -56
- data/tasks/bump.rake +0 -51
- data/tasks/doc.rake +0 -887
- data/tasks/example_viewer.html.erb +0 -172
- data/tasks/extension.rake +0 -14
- data/tasks/license/headers_md.rb +0 -223
- data/tasks/license/headers_rb.rb +0 -210
- data/tasks/license/license_utils.rb +0 -130
- data/tasks/license/snippets_md.rb +0 -315
- data/tasks/license/snippets_rdoc.rb +0 -150
- data/tasks/license.rake +0 -91
- data/tasks/lint.rake +0 -170
- data/tasks/rdoc_config.rb +0 -29
- data/tasks/resources/build.yml.erb +0 -60
- data/tasks/resources/index.html.erb +0 -141
- data/tasks/resources/rubies.yml +0 -7
- data/tasks/sourcehut.rake +0 -110
- data/tasks/steep.rake +0 -11
- data/tasks/terminal_preview/app_screenshot.rb +0 -45
- data/tasks/terminal_preview/crash_report.rb +0 -54
- data/tasks/terminal_preview/example_app.rb +0 -27
- data/tasks/terminal_preview/launcher_script.rb +0 -48
- data/tasks/terminal_preview/preview_collection.rb +0 -60
- data/tasks/terminal_preview/preview_timing.rb +0 -24
- data/tasks/terminal_preview/safety_confirmation.rb +0 -58
- data/tasks/terminal_preview/saved_screenshot.rb +0 -56
- data/tasks/terminal_preview/system_appearance.rb +0 -13
- data/tasks/terminal_preview/terminal_window.rb +0 -138
- data/tasks/terminal_preview/window_id.rb +0 -16
- data/tasks/terminal_preview.rake +0 -30
- data/tasks/test.rake +0 -33
- data/tasks/website/index_page.rb +0 -30
- data/tasks/website/version.rb +0 -127
- data/tasks/website/version_menu.rb +0 -68
- data/tasks/website/versioned_documentation.rb +0 -83
- data/tasks/website/website.rb +0 -53
- data/tasks/website.rake +0 -28
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
require_relative "input"
|
|
9
|
-
require_relative "palette"
|
|
10
|
-
require_relative "export_pane"
|
|
11
|
-
require_relative "controls"
|
|
12
|
-
require_relative "clipboard"
|
|
13
|
-
require_relative "copy_dialog"
|
|
14
|
-
|
|
15
|
-
# The root container that owns all child components and orchestrates the UI.
|
|
16
|
-
#
|
|
17
|
-
# Building a complete color picker UI involves layout calculation, widget
|
|
18
|
-
# composition, event routing, and cross-component communication. The Container
|
|
19
|
-
# pattern centralizes this orchestration while keeping components decoupled.
|
|
20
|
-
#
|
|
21
|
-
# This container:
|
|
22
|
-
# - **Layout Phase**: Calculates Rects using tui.layout_split
|
|
23
|
-
# - **Delegation Phase**: Calls child.render(tui, frame, area) for each component
|
|
24
|
-
# - **Event Routing (Chain of Responsibility)**: Delegates events front-to-back
|
|
25
|
-
# - **Mediator Pattern**: Manages cross-component communication via symbolic signals
|
|
26
|
-
#
|
|
27
|
-
# === Component Contract
|
|
28
|
-
#
|
|
29
|
-
# - `render(tui, frame, area)`: Lays out and renders all children
|
|
30
|
-
# - `handle_event(event) -> Symbol | nil`: Routes events to children
|
|
31
|
-
# - `tick`: Delegates lifecycle updates (clipboard timer)
|
|
32
|
-
#
|
|
33
|
-
# === Example
|
|
34
|
-
#
|
|
35
|
-
# container = MainContainer.new(tui)
|
|
36
|
-
# container.render(tui, frame, frame.area)
|
|
37
|
-
# result = container.handle_event(event)
|
|
38
|
-
# container.tick
|
|
39
|
-
class MainContainer
|
|
40
|
-
def initialize(tui)
|
|
41
|
-
@tui = tui
|
|
42
|
-
@input = Input.new
|
|
43
|
-
@palette = Palette.new(@input.parsed_color)
|
|
44
|
-
@export_pane = ExportPane.new
|
|
45
|
-
@controls = Controls.new
|
|
46
|
-
@clipboard = Clipboard.new
|
|
47
|
-
@dialog = CopyDialog.new(@clipboard)
|
|
48
|
-
|
|
49
|
-
# Parse initial color
|
|
50
|
-
initial_result = simulate_initial_parse
|
|
51
|
-
@palette.update_color(initial_result) if initial_result
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# Renders all child components into the given area.
|
|
55
|
-
#
|
|
56
|
-
# Calculates layout once per frame. Delegates rendering to each component.
|
|
57
|
-
# Renders the dialog overlay last for z-ordering.
|
|
58
|
-
#
|
|
59
|
-
# [tui] Session or TUI factory object
|
|
60
|
-
# [frame] Frame object from RatatuiRuby.draw block
|
|
61
|
-
# [area] Rect area to draw into
|
|
62
|
-
#
|
|
63
|
-
# === Example
|
|
64
|
-
#
|
|
65
|
-
# tui.draw { |frame| container.render(tui, frame, frame.area) }
|
|
66
|
-
def render(tui, frame, area)
|
|
67
|
-
# Layout Phase: calculate all areas
|
|
68
|
-
input_area, rest = tui.layout_split(
|
|
69
|
-
area,
|
|
70
|
-
direction: :vertical,
|
|
71
|
-
constraints: [
|
|
72
|
-
tui.constraint_length(3),
|
|
73
|
-
tui.constraint_fill(1),
|
|
74
|
-
]
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
color_area, control_area = tui.layout_split(
|
|
78
|
-
rest,
|
|
79
|
-
direction: :vertical,
|
|
80
|
-
constraints: [
|
|
81
|
-
tui.constraint_length(14),
|
|
82
|
-
tui.constraint_fill(1),
|
|
83
|
-
]
|
|
84
|
-
)
|
|
85
|
-
|
|
86
|
-
harmony_area, export_area = tui.layout_split(
|
|
87
|
-
color_area,
|
|
88
|
-
direction: :vertical,
|
|
89
|
-
constraints: [
|
|
90
|
-
tui.constraint_length(7),
|
|
91
|
-
tui.constraint_fill(1),
|
|
92
|
-
]
|
|
93
|
-
)
|
|
94
|
-
|
|
95
|
-
# Delegation Phase: render each component
|
|
96
|
-
@input.render(tui, frame, input_area)
|
|
97
|
-
@palette.render(tui, frame, harmony_area)
|
|
98
|
-
@export_pane.render(tui, frame, export_area, palette: @palette)
|
|
99
|
-
@controls.render(tui, frame, control_area, clipboard: @clipboard)
|
|
100
|
-
|
|
101
|
-
# Overlay Logic: dialog rendered last for z-ordering
|
|
102
|
-
if @dialog.active?
|
|
103
|
-
dialog_area = calculate_center_area(area, 40, 8)
|
|
104
|
-
frame.render_widget(tui.clear, area)
|
|
105
|
-
@dialog.render(tui, frame, dialog_area)
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
# Routes events to child components in visual order (front-to-back).
|
|
110
|
-
#
|
|
111
|
-
# Implements Chain of Responsibility:
|
|
112
|
-
# 1. If dialog is active, offer it the event first
|
|
113
|
-
# 2. Then Input, ExportPane (which may trigger dialog)
|
|
114
|
-
# 3. Mediator pattern: interprets symbolic signals for cross-component effects
|
|
115
|
-
#
|
|
116
|
-
# Returns:
|
|
117
|
-
# - `:consumed` when any component handled the event
|
|
118
|
-
# - `nil` when no component handled the event
|
|
119
|
-
#
|
|
120
|
-
# [event] Event from RatatuiRuby.poll_event
|
|
121
|
-
#
|
|
122
|
-
# === Example
|
|
123
|
-
#
|
|
124
|
-
# result = container.handle_event(event)
|
|
125
|
-
def handle_event(event)
|
|
126
|
-
# Clear input error when not in dialog mode
|
|
127
|
-
@input.clear_error unless @dialog.active?
|
|
128
|
-
|
|
129
|
-
# Front-to-back: dialog has priority when active
|
|
130
|
-
if @dialog.active?
|
|
131
|
-
result = @dialog.handle_event(event)
|
|
132
|
-
return :consumed if result == :consumed
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
# Input component
|
|
136
|
-
result = @input.handle_event(event)
|
|
137
|
-
case result
|
|
138
|
-
when :submitted
|
|
139
|
-
# Mediator: sync Input -> Palette
|
|
140
|
-
@palette.update_color(@input.parsed_color)
|
|
141
|
-
return :consumed
|
|
142
|
-
when :consumed
|
|
143
|
-
return :consumed
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
# ExportPane: may request copy dialog
|
|
147
|
-
result = @export_pane.handle_event(event)
|
|
148
|
-
if result == :copy_requested && @palette.main
|
|
149
|
-
@dialog.open(@palette.main.hex)
|
|
150
|
-
return :consumed
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
# Palette and Controls are display-only
|
|
154
|
-
nil
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
# Delegates lifecycle tick to time-sensitive components.
|
|
158
|
-
#
|
|
159
|
-
# Currently handles clipboard feedback timer.
|
|
160
|
-
#
|
|
161
|
-
# === Example
|
|
162
|
-
#
|
|
163
|
-
# container.tick
|
|
164
|
-
def tick
|
|
165
|
-
@controls.tick(@clipboard)
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
private def calculate_center_area(parent_area, width, height)
|
|
169
|
-
x = (parent_area.width - width) / 2
|
|
170
|
-
y = (parent_area.height - height) / 2
|
|
171
|
-
@tui.rect(x:, y:, width:, height:)
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
# Simulates the initial parse that happens when the app starts.
|
|
175
|
-
# Input is initialized with a default color, so we need to parse it.
|
|
176
|
-
private def simulate_initial_parse
|
|
177
|
-
require_relative "color"
|
|
178
|
-
Color.parse(@input.value)
|
|
179
|
-
end
|
|
180
|
-
end
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
require_relative "color"
|
|
9
|
-
|
|
10
|
-
# A self-contained component displaying a color palette with harmonies.
|
|
11
|
-
#
|
|
12
|
-
# Color pickers need to show related colors: shades, tints, complements. This
|
|
13
|
-
# component owns a primary color and renders its harmonies.
|
|
14
|
-
#
|
|
15
|
-
# === Component Contract
|
|
16
|
-
#
|
|
17
|
-
# - `render(tui, frame, area)`: Draws the harmony blocks; stores `area`
|
|
18
|
-
# - `handle_event(event) -> nil`: Display-only, always returns nil
|
|
19
|
-
# - `update_color(color)`: Updates the primary color (called by MainContainer)
|
|
20
|
-
#
|
|
21
|
-
# === Example
|
|
22
|
-
#
|
|
23
|
-
# palette = Palette.new
|
|
24
|
-
# palette.update_color(Color.parse("#FF0000"))
|
|
25
|
-
# palette.render(tui, frame, palette_area)
|
|
26
|
-
class Palette
|
|
27
|
-
def initialize(primary_color = nil)
|
|
28
|
-
@primary = primary_color
|
|
29
|
-
@area = nil
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# The cached render area.
|
|
33
|
-
attr_reader :area
|
|
34
|
-
|
|
35
|
-
# The primary (main) color, or nil if no color is set.
|
|
36
|
-
#
|
|
37
|
-
# === Example
|
|
38
|
-
#
|
|
39
|
-
# palette.main.hex # => "#FF0000"
|
|
40
|
-
def main
|
|
41
|
-
@primary
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# Updates the primary color.
|
|
45
|
-
#
|
|
46
|
-
# Called by the MainContainer when Input submits a new color.
|
|
47
|
-
#
|
|
48
|
-
# [color] Color object or nil
|
|
49
|
-
def update_color(color)
|
|
50
|
-
@primary = color
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# All harmonies: main, shade, tint, complement, split 1, split 2, split-complement.
|
|
54
|
-
#
|
|
55
|
-
# Returns an empty array if no primary color is set.
|
|
56
|
-
def all
|
|
57
|
-
return [] if @primary.nil?
|
|
58
|
-
|
|
59
|
-
@primary.harmonies
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
# Renders the palette into the given area.
|
|
63
|
-
#
|
|
64
|
-
# Shows all harmony blocks in a horizontal layout. If no color is set,
|
|
65
|
-
# displays a placeholder message.
|
|
66
|
-
#
|
|
67
|
-
# [tui] Session or TUI factory object
|
|
68
|
-
# [frame] Frame object from RatatuiRuby.draw block
|
|
69
|
-
# [area] Rect area to draw into
|
|
70
|
-
#
|
|
71
|
-
# === Example
|
|
72
|
-
#
|
|
73
|
-
# palette.render(tui, frame, palette_area)
|
|
74
|
-
def render(tui, frame, area)
|
|
75
|
-
@area = area
|
|
76
|
-
widget = build_widget(tui)
|
|
77
|
-
frame.render_widget(widget, area)
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
# Display-only component; always returns nil.
|
|
81
|
-
def handle_event(_event)
|
|
82
|
-
nil
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
private def build_widget(tui)
|
|
86
|
-
if @primary.nil?
|
|
87
|
-
tui.paragraph(text: "No color selected")
|
|
88
|
-
else
|
|
89
|
-
blocks = as_blocks(tui)
|
|
90
|
-
tui.layout(
|
|
91
|
-
direction: :horizontal,
|
|
92
|
-
constraints: Array.new(blocks.size) { tui.constraint_fill(1) },
|
|
93
|
-
children: blocks
|
|
94
|
-
)
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
private def as_blocks(tui)
|
|
99
|
-
return [] if @primary.nil?
|
|
100
|
-
|
|
101
|
-
all.map do |harmony|
|
|
102
|
-
tui.block(
|
|
103
|
-
title: harmony.label,
|
|
104
|
-
borders: [:all],
|
|
105
|
-
children: [
|
|
106
|
-
tui.paragraph(text: harmony.color_swatch_lines(tui)),
|
|
107
|
-
]
|
|
108
|
-
)
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
end
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
-
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
-
-->
|
|
5
|
-
|
|
6
|
-
# Debugging Showcase
|
|
7
|
-
|
|
8
|
-
[](app.rb)
|
|
9
|
-
|
|
10
|
-
Interactive demonstration of RatatuiRuby's debugging features.
|
|
11
|
-
|
|
12
|
-
For comprehensive documentation, see the [Debugging Guide](../../doc/concepts/debugging.md).
|
|
13
|
-
|
|
14
|
-
## What This Example Does
|
|
15
|
-
|
|
16
|
-
This app lets you trigger each debugging feature with a hotkey. Test your setup before encountering a real bug.
|
|
17
|
-
|
|
18
|
-
| Key | Action |
|
|
19
|
-
|-----|--------|
|
|
20
|
-
| `d` | Enable `debug_mode!` programmatically |
|
|
21
|
-
| `p` | Trigger a Rust panic |
|
|
22
|
-
| `t` | Trigger a Rust `TypeError` |
|
|
23
|
-
| `b` | Refresh debug status |
|
|
24
|
-
| `q` | Quit |
|
|
25
|
-
|
|
26
|
-
## Library Features Showcased
|
|
27
|
-
|
|
28
|
-
Reading this code will teach you how to:
|
|
29
|
-
|
|
30
|
-
* **Enable Remote Debugging**: Call `RatatuiRuby.debug_mode!` and receive the socket path
|
|
31
|
-
* **Detect Debug State**: Query `Debug.enabled?`, `Debug.rust_backtrace_enabled?`, and `Debug.remote_debugging_mode`
|
|
32
|
-
* **Trigger Test Panics**: Use `Debug.test_panic!` to verify Rust backtrace visibility
|
|
33
|
-
* **See Improved Error Messages**: Bypass DWIM coercion to see `TypeError` messages with value context
|
|
34
|
-
|
|
35
|
-
**Note:** Rust backtraces only appear for panics (`[p]`). Exceptions (`[t]`) show Ruby backtraces with improved error messages from Rust.
|
|
36
|
-
|
|
37
|
-
## Environment Variables
|
|
38
|
-
|
|
39
|
-
The example behaves differently depending on which environment variables you set.
|
|
40
|
-
|
|
41
|
-
### No Environment Variables
|
|
42
|
-
|
|
43
|
-
<!-- SPDX-SnippetBegin -->
|
|
44
|
-
<!--
|
|
45
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
46
|
-
SPDX-License-Identifier: MIT-0
|
|
47
|
-
-->
|
|
48
|
-
```bash
|
|
49
|
-
ruby examples/app_debugging_showcase/app.rb
|
|
50
|
-
```
|
|
51
|
-
<!-- SPDX-SnippetEnd -->
|
|
52
|
-
|
|
53
|
-
The TUI starts normally. Rust backtraces are disabled. Press `[d]` to enable remote debugging mid-session.
|
|
54
|
-
|
|
55
|
-
### `RUST_BACKTRACE=1`
|
|
56
|
-
|
|
57
|
-
<!-- SPDX-SnippetBegin -->
|
|
58
|
-
<!--
|
|
59
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
60
|
-
SPDX-License-Identifier: MIT-0
|
|
61
|
-
-->
|
|
62
|
-
```bash
|
|
63
|
-
RUST_BACKTRACE=1 ruby examples/app_debugging_showcase/app.rb
|
|
64
|
-
```
|
|
65
|
-
<!-- SPDX-SnippetEnd -->
|
|
66
|
-
|
|
67
|
-
Enables Rust backtraces. Press `[p]` to see the full Rust stack trace with file names and line numbers.
|
|
68
|
-
|
|
69
|
-
### `RR_DEBUG=1`
|
|
70
|
-
|
|
71
|
-
<!-- SPDX-SnippetBegin -->
|
|
72
|
-
<!--
|
|
73
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
74
|
-
SPDX-License-Identifier: MIT-0
|
|
75
|
-
-->
|
|
76
|
-
```bash
|
|
77
|
-
RR_DEBUG=1 ruby examples/app_debugging_showcase/app.rb
|
|
78
|
-
```
|
|
79
|
-
<!-- SPDX-SnippetEnd -->
|
|
80
|
-
|
|
81
|
-
Full debug mode at startup. The debugger opens a socket and **waits for a connection** before the TUI starts. You'll see the socket path printed before the app runs.
|
|
82
|
-
|
|
83
|
-
In another terminal:
|
|
84
|
-
|
|
85
|
-
<!-- SPDX-SnippetBegin -->
|
|
86
|
-
<!--
|
|
87
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
88
|
-
SPDX-License-Identifier: MIT-0
|
|
89
|
-
-->
|
|
90
|
-
```bash
|
|
91
|
-
rdbg --attach
|
|
92
|
-
```
|
|
93
|
-
<!-- SPDX-SnippetEnd -->
|
|
94
|
-
|
|
95
|
-
When you attach, you'll see "Stop by SIGURG" — that's normal! SIGURG is how the debug gem signals the app to pause. Type `continue` to resume.
|
|
96
|
-
|
|
97
|
-
This uses the [ruby/debug](https://github.com/ruby/debug?tab=readme-ov-file#readme) gem for remote debugging.
|
|
98
|
-
|
|
99
|
-
### When to Use Which
|
|
100
|
-
|
|
101
|
-
`RR_DEBUG=1` includes Rust backtraces automatically (it calls `enable_rust_backtrace!` internally).
|
|
102
|
-
|
|
103
|
-
Use `RUST_BACKTRACE=1` alone when you want backtraces but **don't** want the debugger to stop and wait for a connection at startup.
|
|
104
|
-
|
|
105
|
-
## What Problems Does This Solve?
|
|
106
|
-
|
|
107
|
-
### "Is my Rust backtrace setup working?"
|
|
108
|
-
|
|
109
|
-
Press `[p]`. If you see a stack trace with file names and line numbers, you're good. If not, you need `RUST_BACKTRACE=1`.
|
|
110
|
-
|
|
111
|
-
### "How do I attach a debugger to a TUI?"
|
|
112
|
-
|
|
113
|
-
TUIs run in raw mode — you can't type into a REPL. Press `[d]` to enable remote debugging. The socket path appears in the UI. Run `rdbg --attach` from another terminal.
|
|
114
|
-
|
|
115
|
-
### "What does a Rust TypeError look like?"
|
|
116
|
-
|
|
117
|
-
Press `[t]`. The error message shows the expected type and the actual value you passed (e.g., `expected array for rows, got 42`). Note: This shows Ruby's backtrace — only panics (`[p]`) show Rust backtraces.
|
|
118
|
-
|
|
119
|
-
[Read the source code →](app.rb)
|