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.
Files changed (236) hide show
  1. checksums.yaml +4 -4
  2. data/ext/ratatui_ruby/Cargo.lock +1 -1
  3. data/ext/ratatui_ruby/Cargo.toml +1 -1
  4. data/lib/ratatui_ruby/version.rb +1 -1
  5. metadata +1 -232
  6. data/.builds/ruby-3.2.yml +0 -54
  7. data/.builds/ruby-3.3.yml +0 -54
  8. data/.builds/ruby-3.4.yml +0 -54
  9. data/.builds/ruby-4.0.0.yml +0 -54
  10. data/.pre-commit-config.yaml +0 -16
  11. data/.rubocop.yml +0 -10
  12. data/AGENTS.md +0 -146
  13. data/CHANGELOG.md +0 -710
  14. data/README.md +0 -187
  15. data/README.rdoc +0 -302
  16. data/Rakefile +0 -11
  17. data/Steepfile +0 -49
  18. data/doc/concepts/application_architecture.md +0 -321
  19. data/doc/concepts/application_testing.md +0 -193
  20. data/doc/concepts/async.md +0 -190
  21. data/doc/concepts/custom_widgets.md +0 -247
  22. data/doc/concepts/debugging.md +0 -401
  23. data/doc/concepts/event_handling.md +0 -162
  24. data/doc/concepts/interactive_design.md +0 -146
  25. data/doc/contributors/auditing/parity.md +0 -239
  26. data/doc/contributors/design/ruby_frontend.md +0 -420
  27. data/doc/contributors/design/rust_backend.md +0 -422
  28. data/doc/contributors/design.md +0 -11
  29. data/doc/contributors/developing_examples.md +0 -400
  30. data/doc/contributors/documentation_style.md +0 -121
  31. data/doc/contributors/index.md +0 -21
  32. data/doc/contributors/todo/align/api_completeness_audit-finished.md +0 -375
  33. data/doc/contributors/todo/align/api_completeness_audit-unfinished.md +0 -206
  34. data/doc/contributors/todo/align/terminal.md +0 -647
  35. data/doc/contributors/todo/future_work.md +0 -169
  36. data/doc/contributors/upstream_requests/tab_rects.md +0 -173
  37. data/doc/contributors/upstream_requests/title_rects.md +0 -132
  38. data/doc/custom.css +0 -22
  39. data/doc/getting_started/quickstart.md +0 -291
  40. data/doc/getting_started/why.md +0 -93
  41. data/doc/images/app_all_events.png +0 -0
  42. data/doc/images/app_cli_rich_moments.gif +0 -0
  43. data/doc/images/app_color_picker.png +0 -0
  44. data/doc/images/app_debugging_showcase.gif +0 -0
  45. data/doc/images/app_debugging_showcase.png +0 -0
  46. data/doc/images/app_login_form.png +0 -0
  47. data/doc/images/app_stateful_interaction.png +0 -0
  48. data/doc/images/verify_quickstart_dsl.png +0 -0
  49. data/doc/images/verify_quickstart_layout.png +0 -0
  50. data/doc/images/verify_quickstart_lifecycle.png +0 -0
  51. data/doc/images/verify_readme_usage.png +0 -0
  52. data/doc/images/widget_barchart.png +0 -0
  53. data/doc/images/widget_block.png +0 -0
  54. data/doc/images/widget_box.png +0 -0
  55. data/doc/images/widget_calendar.png +0 -0
  56. data/doc/images/widget_canvas.png +0 -0
  57. data/doc/images/widget_cell.png +0 -0
  58. data/doc/images/widget_center.png +0 -0
  59. data/doc/images/widget_chart.png +0 -0
  60. data/doc/images/widget_gauge.png +0 -0
  61. data/doc/images/widget_layout_split.png +0 -0
  62. data/doc/images/widget_line_gauge.png +0 -0
  63. data/doc/images/widget_list.png +0 -0
  64. data/doc/images/widget_map.png +0 -0
  65. data/doc/images/widget_overlay.png +0 -0
  66. data/doc/images/widget_popup.png +0 -0
  67. data/doc/images/widget_ratatui_logo.png +0 -0
  68. data/doc/images/widget_ratatui_mascot.png +0 -0
  69. data/doc/images/widget_rect.png +0 -0
  70. data/doc/images/widget_render.png +0 -0
  71. data/doc/images/widget_rich_text.png +0 -0
  72. data/doc/images/widget_scroll_text.png +0 -0
  73. data/doc/images/widget_scrollbar.png +0 -0
  74. data/doc/images/widget_sparkline.png +0 -0
  75. data/doc/images/widget_style_colors.png +0 -0
  76. data/doc/images/widget_table.png +0 -0
  77. data/doc/images/widget_tabs.png +0 -0
  78. data/doc/images/widget_text_width.png +0 -0
  79. data/doc/index.md +0 -39
  80. data/doc/troubleshooting/async.md +0 -4
  81. data/doc/troubleshooting/terminal_limitations.md +0 -131
  82. data/doc/troubleshooting/tui_output.md +0 -197
  83. data/examples/app_all_events/README.md +0 -114
  84. data/examples/app_all_events/app.rb +0 -98
  85. data/examples/app_all_events/model/app_model.rb +0 -159
  86. data/examples/app_all_events/model/event_color_cycle.rb +0 -43
  87. data/examples/app_all_events/model/event_entry.rb +0 -94
  88. data/examples/app_all_events/model/msg.rb +0 -39
  89. data/examples/app_all_events/model/timestamp.rb +0 -56
  90. data/examples/app_all_events/update.rb +0 -75
  91. data/examples/app_all_events/view/app_view.rb +0 -80
  92. data/examples/app_all_events/view/controls_view.rb +0 -54
  93. data/examples/app_all_events/view/counts_view.rb +0 -61
  94. data/examples/app_all_events/view/live_view.rb +0 -72
  95. data/examples/app_all_events/view/log_view.rb +0 -57
  96. data/examples/app_all_events/view.rb +0 -9
  97. data/examples/app_cli_rich_moments/README.md +0 -81
  98. data/examples/app_cli_rich_moments/app.rb +0 -189
  99. data/examples/app_color_picker/README.md +0 -156
  100. data/examples/app_color_picker/app.rb +0 -76
  101. data/examples/app_color_picker/clipboard.rb +0 -86
  102. data/examples/app_color_picker/color.rb +0 -193
  103. data/examples/app_color_picker/controls.rb +0 -92
  104. data/examples/app_color_picker/copy_dialog.rb +0 -168
  105. data/examples/app_color_picker/export_pane.rb +0 -128
  106. data/examples/app_color_picker/harmony.rb +0 -58
  107. data/examples/app_color_picker/input.rb +0 -176
  108. data/examples/app_color_picker/main_container.rb +0 -180
  109. data/examples/app_color_picker/palette.rb +0 -111
  110. data/examples/app_debugging_showcase/README.md +0 -119
  111. data/examples/app_debugging_showcase/app.rb +0 -318
  112. data/examples/app_login_form/README.md +0 -58
  113. data/examples/app_login_form/app.rb +0 -109
  114. data/examples/app_stateful_interaction/README.md +0 -35
  115. data/examples/app_stateful_interaction/app.rb +0 -328
  116. data/examples/timeout_demo.rb +0 -45
  117. data/examples/verify_quickstart_dsl/README.md +0 -55
  118. data/examples/verify_quickstart_dsl/app.rb +0 -49
  119. data/examples/verify_quickstart_layout/README.md +0 -77
  120. data/examples/verify_quickstart_layout/app.rb +0 -73
  121. data/examples/verify_quickstart_lifecycle/README.md +0 -68
  122. data/examples/verify_quickstart_lifecycle/app.rb +0 -62
  123. data/examples/verify_readme_usage/README.md +0 -49
  124. data/examples/verify_readme_usage/app.rb +0 -42
  125. data/examples/verify_website_managed/README.md +0 -48
  126. data/examples/verify_website_managed/app.rb +0 -36
  127. data/examples/verify_website_menu/README.md +0 -60
  128. data/examples/verify_website_menu/app.rb +0 -84
  129. data/examples/verify_website_spinner/README.md +0 -44
  130. data/examples/verify_website_spinner/app.rb +0 -34
  131. data/examples/widget_barchart/README.md +0 -58
  132. data/examples/widget_barchart/app.rb +0 -240
  133. data/examples/widget_block/README.md +0 -44
  134. data/examples/widget_block/app.rb +0 -258
  135. data/examples/widget_box/README.md +0 -54
  136. data/examples/widget_box/app.rb +0 -255
  137. data/examples/widget_calendar/README.md +0 -48
  138. data/examples/widget_calendar/app.rb +0 -115
  139. data/examples/widget_canvas/README.md +0 -31
  140. data/examples/widget_canvas/app.rb +0 -130
  141. data/examples/widget_cell/README.md +0 -45
  142. data/examples/widget_cell/app.rb +0 -112
  143. data/examples/widget_center/README.md +0 -33
  144. data/examples/widget_center/app.rb +0 -118
  145. data/examples/widget_chart/README.md +0 -50
  146. data/examples/widget_chart/app.rb +0 -220
  147. data/examples/widget_gauge/README.md +0 -50
  148. data/examples/widget_gauge/app.rb +0 -229
  149. data/examples/widget_layout_split/README.md +0 -53
  150. data/examples/widget_layout_split/app.rb +0 -260
  151. data/examples/widget_line_gauge/README.md +0 -50
  152. data/examples/widget_line_gauge/app.rb +0 -219
  153. data/examples/widget_list/README.md +0 -58
  154. data/examples/widget_list/app.rb +0 -384
  155. data/examples/widget_map/README.md +0 -48
  156. data/examples/widget_map/app.rb +0 -95
  157. data/examples/widget_overlay/README.md +0 -45
  158. data/examples/widget_overlay/app.rb +0 -250
  159. data/examples/widget_popup/README.md +0 -45
  160. data/examples/widget_popup/app.rb +0 -106
  161. data/examples/widget_ratatui_logo/README.md +0 -43
  162. data/examples/widget_ratatui_logo/app.rb +0 -104
  163. data/examples/widget_ratatui_mascot/README.md +0 -43
  164. data/examples/widget_ratatui_mascot/app.rb +0 -95
  165. data/examples/widget_rect/README.md +0 -53
  166. data/examples/widget_rect/app.rb +0 -222
  167. data/examples/widget_render/README.md +0 -46
  168. data/examples/widget_render/app.rb +0 -186
  169. data/examples/widget_render/app.rbs +0 -41
  170. data/examples/widget_rich_text/README.md +0 -44
  171. data/examples/widget_rich_text/app.rb +0 -193
  172. data/examples/widget_scroll_text/README.md +0 -46
  173. data/examples/widget_scroll_text/app.rb +0 -109
  174. data/examples/widget_scrollbar/README.md +0 -46
  175. data/examples/widget_scrollbar/app.rb +0 -155
  176. data/examples/widget_sparkline/README.md +0 -51
  177. data/examples/widget_sparkline/app.rb +0 -277
  178. data/examples/widget_style_colors/README.md +0 -43
  179. data/examples/widget_style_colors/app.rb +0 -83
  180. data/examples/widget_table/README.md +0 -57
  181. data/examples/widget_table/app.rb +0 -279
  182. data/examples/widget_tabs/README.md +0 -50
  183. data/examples/widget_tabs/app.rb +0 -183
  184. data/examples/widget_text_width/README.md +0 -44
  185. data/examples/widget_text_width/app.rb +0 -117
  186. data/migrate_to_buffer.rb +0 -145
  187. data/mise.toml +0 -8
  188. data/tasks/autodoc/examples.rb +0 -87
  189. data/tasks/autodoc/member.rb +0 -58
  190. data/tasks/autodoc/name.rb +0 -21
  191. data/tasks/autodoc.rake +0 -21
  192. data/tasks/bump/cargo_lockfile.rb +0 -21
  193. data/tasks/bump/changelog.rb +0 -47
  194. data/tasks/bump/header.rb +0 -32
  195. data/tasks/bump/history.rb +0 -32
  196. data/tasks/bump/links.rb +0 -69
  197. data/tasks/bump/manifest.rb +0 -33
  198. data/tasks/bump/ruby_gem.rb +0 -49
  199. data/tasks/bump/sem_ver.rb +0 -40
  200. data/tasks/bump/unreleased_section.rb +0 -56
  201. data/tasks/bump.rake +0 -51
  202. data/tasks/doc.rake +0 -887
  203. data/tasks/example_viewer.html.erb +0 -172
  204. data/tasks/extension.rake +0 -14
  205. data/tasks/license/headers_md.rb +0 -223
  206. data/tasks/license/headers_rb.rb +0 -210
  207. data/tasks/license/license_utils.rb +0 -130
  208. data/tasks/license/snippets_md.rb +0 -315
  209. data/tasks/license/snippets_rdoc.rb +0 -150
  210. data/tasks/license.rake +0 -91
  211. data/tasks/lint.rake +0 -170
  212. data/tasks/rdoc_config.rb +0 -29
  213. data/tasks/resources/build.yml.erb +0 -60
  214. data/tasks/resources/index.html.erb +0 -141
  215. data/tasks/resources/rubies.yml +0 -7
  216. data/tasks/sourcehut.rake +0 -110
  217. data/tasks/steep.rake +0 -11
  218. data/tasks/terminal_preview/app_screenshot.rb +0 -45
  219. data/tasks/terminal_preview/crash_report.rb +0 -54
  220. data/tasks/terminal_preview/example_app.rb +0 -27
  221. data/tasks/terminal_preview/launcher_script.rb +0 -48
  222. data/tasks/terminal_preview/preview_collection.rb +0 -60
  223. data/tasks/terminal_preview/preview_timing.rb +0 -24
  224. data/tasks/terminal_preview/safety_confirmation.rb +0 -58
  225. data/tasks/terminal_preview/saved_screenshot.rb +0 -56
  226. data/tasks/terminal_preview/system_appearance.rb +0 -13
  227. data/tasks/terminal_preview/terminal_window.rb +0 -138
  228. data/tasks/terminal_preview/window_id.rb +0 -16
  229. data/tasks/terminal_preview.rake +0 -30
  230. data/tasks/test.rake +0 -33
  231. data/tasks/website/index_page.rb +0 -30
  232. data/tasks/website/version.rb +0 -127
  233. data/tasks/website/version_menu.rb +0 -68
  234. data/tasks/website/versioned_documentation.rb +0 -83
  235. data/tasks/website/website.rb +0 -53
  236. 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
- [![Debugging Showcase](../../doc/images/app_debugging_showcase.gif)](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)