ratatui_ruby 1.1.0 → 1.1.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 (259) 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 -255
  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 -147
  13. data/CHANGELOG.md +0 -736
  14. data/README.md +0 -187
  15. data/README.rdoc +0 -302
  16. data/Rakefile +0 -11
  17. data/Steepfile +0 -50
  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 -448
  27. data/doc/contributors/design/rust_backend.md +0 -434
  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/releasing.md +0 -215
  33. data/doc/contributors/todo/align/api_completeness_audit-finished.md +0 -381
  34. data/doc/contributors/todo/align/api_completeness_audit-unfinished.md +0 -200
  35. data/doc/contributors/todo/align/term.md +0 -351
  36. data/doc/contributors/todo/align/terminal.md +0 -647
  37. data/doc/contributors/todo/future_work.md +0 -169
  38. data/doc/contributors/upstream_requests/paragraph_span_rects.md +0 -259
  39. data/doc/contributors/upstream_requests/tab_rects.md +0 -173
  40. data/doc/contributors/upstream_requests/title_rects.md +0 -132
  41. data/doc/custom.css +0 -22
  42. data/doc/getting_started/quickstart.md +0 -291
  43. data/doc/getting_started/why.md +0 -93
  44. data/doc/images/app_all_events.png +0 -0
  45. data/doc/images/app_cli_rich_moments.gif +0 -0
  46. data/doc/images/app_color_picker.png +0 -0
  47. data/doc/images/app_debugging_showcase.gif +0 -0
  48. data/doc/images/app_debugging_showcase.png +0 -0
  49. data/doc/images/app_external_editor.gif +0 -0
  50. data/doc/images/app_login_form.png +0 -0
  51. data/doc/images/app_stateful_interaction.png +0 -0
  52. data/doc/images/verify_quickstart_dsl.png +0 -0
  53. data/doc/images/verify_quickstart_layout.png +0 -0
  54. data/doc/images/verify_quickstart_lifecycle.png +0 -0
  55. data/doc/images/verify_readme_usage.png +0 -0
  56. data/doc/images/widget_barchart.png +0 -0
  57. data/doc/images/widget_block.png +0 -0
  58. data/doc/images/widget_box.png +0 -0
  59. data/doc/images/widget_calendar.png +0 -0
  60. data/doc/images/widget_canvas.png +0 -0
  61. data/doc/images/widget_cell.png +0 -0
  62. data/doc/images/widget_center.png +0 -0
  63. data/doc/images/widget_chart.png +0 -0
  64. data/doc/images/widget_gauge.png +0 -0
  65. data/doc/images/widget_layout_split.png +0 -0
  66. data/doc/images/widget_line_gauge.png +0 -0
  67. data/doc/images/widget_list.png +0 -0
  68. data/doc/images/widget_map.png +0 -0
  69. data/doc/images/widget_overlay.png +0 -0
  70. data/doc/images/widget_popup.png +0 -0
  71. data/doc/images/widget_ratatui_logo.png +0 -0
  72. data/doc/images/widget_ratatui_mascot.png +0 -0
  73. data/doc/images/widget_rect.png +0 -0
  74. data/doc/images/widget_render.png +0 -0
  75. data/doc/images/widget_rich_text.png +0 -0
  76. data/doc/images/widget_scroll_text.png +0 -0
  77. data/doc/images/widget_scrollbar.png +0 -0
  78. data/doc/images/widget_sparkline.png +0 -0
  79. data/doc/images/widget_style_colors.png +0 -0
  80. data/doc/images/widget_table.png +0 -0
  81. data/doc/images/widget_tabs.png +0 -0
  82. data/doc/images/widget_text_width.png +0 -0
  83. data/doc/index.md +0 -34
  84. data/doc/troubleshooting/async.md +0 -4
  85. data/doc/troubleshooting/terminal_limitations.md +0 -131
  86. data/doc/troubleshooting/tui_output.md +0 -197
  87. data/examples/app_all_events/README.md +0 -114
  88. data/examples/app_all_events/app.rb +0 -98
  89. data/examples/app_all_events/model/app_model.rb +0 -159
  90. data/examples/app_all_events/model/event_color_cycle.rb +0 -43
  91. data/examples/app_all_events/model/event_entry.rb +0 -94
  92. data/examples/app_all_events/model/msg.rb +0 -39
  93. data/examples/app_all_events/model/timestamp.rb +0 -56
  94. data/examples/app_all_events/update.rb +0 -75
  95. data/examples/app_all_events/view/app_view.rb +0 -80
  96. data/examples/app_all_events/view/controls_view.rb +0 -54
  97. data/examples/app_all_events/view/counts_view.rb +0 -61
  98. data/examples/app_all_events/view/live_view.rb +0 -72
  99. data/examples/app_all_events/view/log_view.rb +0 -57
  100. data/examples/app_all_events/view.rb +0 -9
  101. data/examples/app_cli_rich_moments/README.md +0 -81
  102. data/examples/app_cli_rich_moments/app.rb +0 -189
  103. data/examples/app_color_picker/README.md +0 -156
  104. data/examples/app_color_picker/app.rb +0 -76
  105. data/examples/app_color_picker/clipboard.rb +0 -86
  106. data/examples/app_color_picker/color.rb +0 -193
  107. data/examples/app_color_picker/controls.rb +0 -92
  108. data/examples/app_color_picker/copy_dialog.rb +0 -168
  109. data/examples/app_color_picker/export_pane.rb +0 -128
  110. data/examples/app_color_picker/harmony.rb +0 -58
  111. data/examples/app_color_picker/input.rb +0 -176
  112. data/examples/app_color_picker/main_container.rb +0 -180
  113. data/examples/app_color_picker/palette.rb +0 -111
  114. data/examples/app_debugging_showcase/README.md +0 -119
  115. data/examples/app_debugging_showcase/app.rb +0 -318
  116. data/examples/app_external_editor/README.md +0 -62
  117. data/examples/app_external_editor/app.rb +0 -344
  118. data/examples/app_login_form/README.md +0 -58
  119. data/examples/app_login_form/app.rb +0 -109
  120. data/examples/app_stateful_interaction/README.md +0 -35
  121. data/examples/app_stateful_interaction/app.rb +0 -328
  122. data/examples/timeout_demo.rb +0 -45
  123. data/examples/verify_quickstart_dsl/README.md +0 -55
  124. data/examples/verify_quickstart_dsl/app.rb +0 -49
  125. data/examples/verify_quickstart_layout/README.md +0 -77
  126. data/examples/verify_quickstart_layout/app.rb +0 -73
  127. data/examples/verify_quickstart_lifecycle/README.md +0 -68
  128. data/examples/verify_quickstart_lifecycle/app.rb +0 -62
  129. data/examples/verify_readme_usage/README.md +0 -49
  130. data/examples/verify_readme_usage/app.rb +0 -42
  131. data/examples/verify_website_managed/README.md +0 -48
  132. data/examples/verify_website_managed/app.rb +0 -36
  133. data/examples/verify_website_menu/README.md +0 -60
  134. data/examples/verify_website_menu/app.rb +0 -84
  135. data/examples/verify_website_spinner/README.md +0 -44
  136. data/examples/verify_website_spinner/app.rb +0 -34
  137. data/examples/widget_barchart/README.md +0 -58
  138. data/examples/widget_barchart/app.rb +0 -240
  139. data/examples/widget_block/README.md +0 -44
  140. data/examples/widget_block/app.rb +0 -258
  141. data/examples/widget_box/README.md +0 -54
  142. data/examples/widget_box/app.rb +0 -255
  143. data/examples/widget_calendar/README.md +0 -48
  144. data/examples/widget_calendar/app.rb +0 -115
  145. data/examples/widget_canvas/README.md +0 -31
  146. data/examples/widget_canvas/app.rb +0 -130
  147. data/examples/widget_cell/README.md +0 -45
  148. data/examples/widget_cell/app.rb +0 -112
  149. data/examples/widget_center/README.md +0 -33
  150. data/examples/widget_center/app.rb +0 -118
  151. data/examples/widget_chart/README.md +0 -50
  152. data/examples/widget_chart/app.rb +0 -220
  153. data/examples/widget_gauge/README.md +0 -50
  154. data/examples/widget_gauge/app.rb +0 -229
  155. data/examples/widget_layout_split/README.md +0 -53
  156. data/examples/widget_layout_split/app.rb +0 -260
  157. data/examples/widget_line_gauge/README.md +0 -50
  158. data/examples/widget_line_gauge/app.rb +0 -219
  159. data/examples/widget_list/README.md +0 -58
  160. data/examples/widget_list/app.rb +0 -382
  161. data/examples/widget_map/README.md +0 -48
  162. data/examples/widget_map/app.rb +0 -95
  163. data/examples/widget_overlay/README.md +0 -45
  164. data/examples/widget_overlay/app.rb +0 -250
  165. data/examples/widget_popup/README.md +0 -45
  166. data/examples/widget_popup/app.rb +0 -106
  167. data/examples/widget_ratatui_logo/README.md +0 -43
  168. data/examples/widget_ratatui_logo/app.rb +0 -104
  169. data/examples/widget_ratatui_mascot/README.md +0 -43
  170. data/examples/widget_ratatui_mascot/app.rb +0 -95
  171. data/examples/widget_rect/README.md +0 -53
  172. data/examples/widget_rect/app.rb +0 -222
  173. data/examples/widget_render/README.md +0 -46
  174. data/examples/widget_render/app.rb +0 -186
  175. data/examples/widget_render/app.rbs +0 -41
  176. data/examples/widget_rich_text/README.md +0 -44
  177. data/examples/widget_rich_text/app.rb +0 -193
  178. data/examples/widget_scroll_text/README.md +0 -46
  179. data/examples/widget_scroll_text/app.rb +0 -109
  180. data/examples/widget_scrollbar/README.md +0 -46
  181. data/examples/widget_scrollbar/app.rb +0 -155
  182. data/examples/widget_sparkline/README.md +0 -51
  183. data/examples/widget_sparkline/app.rb +0 -277
  184. data/examples/widget_style_colors/README.md +0 -43
  185. data/examples/widget_style_colors/app.rb +0 -83
  186. data/examples/widget_table/README.md +0 -57
  187. data/examples/widget_table/app.rb +0 -285
  188. data/examples/widget_tabs/README.md +0 -50
  189. data/examples/widget_tabs/app.rb +0 -183
  190. data/examples/widget_text_width/README.md +0 -44
  191. data/examples/widget_text_width/app.rb +0 -117
  192. data/migrate_to_buffer.rb +0 -145
  193. data/mise.toml +0 -8
  194. data/tasks/autodoc/examples.rb +0 -87
  195. data/tasks/autodoc/member.rb +0 -58
  196. data/tasks/autodoc/name.rb +0 -21
  197. data/tasks/autodoc.rake +0 -21
  198. data/tasks/bump/bump_workflow.rb +0 -49
  199. data/tasks/bump/cargo_lockfile.rb +0 -21
  200. data/tasks/bump/changelog.rb +0 -104
  201. data/tasks/bump/header.rb +0 -32
  202. data/tasks/bump/history.rb +0 -32
  203. data/tasks/bump/links.rb +0 -69
  204. data/tasks/bump/manifest.rb +0 -33
  205. data/tasks/bump/patch_release.rb +0 -19
  206. data/tasks/bump/release_branch.rb +0 -17
  207. data/tasks/bump/release_from_trunk.rb +0 -49
  208. data/tasks/bump/repository.rb +0 -54
  209. data/tasks/bump/ruby_gem.rb +0 -29
  210. data/tasks/bump/sem_ver.rb +0 -44
  211. data/tasks/bump/unreleased_section.rb +0 -73
  212. data/tasks/bump.rake +0 -61
  213. data/tasks/doc/documentation.rb +0 -59
  214. data/tasks/doc/link/file_url.rb +0 -30
  215. data/tasks/doc/link/relative_path.rb +0 -61
  216. data/tasks/doc/link/web_url.rb +0 -55
  217. data/tasks/doc/link.rb +0 -52
  218. data/tasks/doc/link_audit.rb +0 -116
  219. data/tasks/doc/problem.rb +0 -40
  220. data/tasks/doc/source_file.rb +0 -93
  221. data/tasks/doc.rake +0 -905
  222. data/tasks/example_viewer.html.erb +0 -172
  223. data/tasks/extension.rake +0 -14
  224. data/tasks/license/headers_md.rb +0 -223
  225. data/tasks/license/headers_rb.rb +0 -210
  226. data/tasks/license/license_utils.rb +0 -130
  227. data/tasks/license/snippets_md.rb +0 -315
  228. data/tasks/license/snippets_rdoc.rb +0 -150
  229. data/tasks/license.rake +0 -91
  230. data/tasks/lint.rake +0 -170
  231. data/tasks/rbs_predicates/predicate_catalog.rb +0 -52
  232. data/tasks/rbs_predicates/predicate_tests.rb +0 -124
  233. data/tasks/rbs_predicates/rbs_signature.rb +0 -63
  234. data/tasks/rbs_predicates.rake +0 -31
  235. data/tasks/rdoc_config.rb +0 -29
  236. data/tasks/resources/build.yml.erb +0 -60
  237. data/tasks/resources/index.html.erb +0 -141
  238. data/tasks/resources/rubies.yml +0 -7
  239. data/tasks/sourcehut.rake +0 -110
  240. data/tasks/steep.rake +0 -11
  241. data/tasks/terminal_preview/app_screenshot.rb +0 -45
  242. data/tasks/terminal_preview/crash_report.rb +0 -54
  243. data/tasks/terminal_preview/example_app.rb +0 -27
  244. data/tasks/terminal_preview/launcher_script.rb +0 -48
  245. data/tasks/terminal_preview/preview_collection.rb +0 -60
  246. data/tasks/terminal_preview/preview_timing.rb +0 -24
  247. data/tasks/terminal_preview/safety_confirmation.rb +0 -58
  248. data/tasks/terminal_preview/saved_screenshot.rb +0 -56
  249. data/tasks/terminal_preview/system_appearance.rb +0 -13
  250. data/tasks/terminal_preview/terminal_window.rb +0 -138
  251. data/tasks/terminal_preview/window_id.rb +0 -16
  252. data/tasks/terminal_preview.rake +0 -30
  253. data/tasks/test.rake +0 -36
  254. data/tasks/website/index_page.rb +0 -30
  255. data/tasks/website/version.rb +0 -122
  256. data/tasks/website/version_menu.rb +0 -68
  257. data/tasks/website/versioned_documentation.rb +0 -83
  258. data/tasks/website/website.rb +0 -53
  259. data/tasks/website.rake +0 -28
@@ -1,318 +0,0 @@
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
@@ -1,62 +0,0 @@
1
- <!--
2
- SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
- SPDX-License-Identifier: CC-BY-SA-4.0
4
- -->
5
-
6
- # External Editor Example
7
-
8
- [![External Editor](../../doc/images/app_external_editor.gif)](app.rb)
9
-
10
- Demonstrates temporarily exiting the TUI to invoke an external editor, then seamlessly re-entering—like editing a commit message in lazygit or tig.
11
-
12
- Most applications use `RatatuiRuby.run { }` which handles terminal setup and teardown automatically. But some workflows require **repeatedly leaving and re-entering raw mode** during a single session. This example shows the low-level lifecycle API that makes this possible.
13
-
14
- ## Features Demonstrated
15
-
16
- - **Full Lifecycle Control**: Using `init_terminal` and `restore_terminal` directly instead of the `run` block.
17
- - **External Process Invocation**: Safely restoring the terminal before spawning an interactive subprocess.
18
- - **Session Re-entry**: Returning to the TUI after the external process exits, with state preserved.
19
- - **Split-Pane Layout**: Dynamically splitting the display when scratch content exists.
20
- - **Focus-Aware Scrolling**: Keyboard scrolling affects the focused pane; mouse scroll affects the hovered pane.
21
- - **Wrapped Line Clamping**: Scroll limits based on wrapped (not raw) line count using `paragraph.line_count`.
22
- - **Mouse Hit Testing**: Using `area.contains?(x, y)` to detect which pane is hovered.
23
-
24
- ## Hotkeys
25
-
26
- | Key | Action |
27
- |-----|--------|
28
- | `↑`/`↓` or `j`/`k` | Scroll one line |
29
- | `PgUp`/`PgDn` | Scroll one page |
30
- | `Home`/`End` | Jump to top/bottom |
31
- | Mouse wheel | Scroll hovered pane |
32
- | `Tab` or `←`/`→` or `h`/`l` | Switch focus between panes |
33
- | `e` | Edit this README.md in `$EDITOR` |
34
- | `s` | Edit scratch file; saved content appears in split pane |
35
- | `q` | Quit |
36
-
37
- ## Usage
38
-
39
- <!-- SPDX-SnippetBegin -->
40
- <!--
41
- SPDX-FileCopyrightText: 2026 Kerrick Long
42
- SPDX-License-Identifier: MIT-0
43
- -->
44
- ```bash
45
- ruby examples/app_external_editor/app.rb
46
- ```
47
- <!-- SPDX-SnippetEnd -->
48
-
49
- Press `e` to edit this README. Press `s` to open a scratch file—when you save content, it appears beside the README in a split view.
50
-
51
- ## Learning Outcomes
52
-
53
- Use this example if you need to...
54
-
55
- - Implement commit message editing (like lazygit, tig, or git rebase -i).
56
- - Spawn an external config editor from a TUI settings menu.
57
- - Build a workflow that alternates between TUI and external tools.
58
- - Create a split-pane layout with focus-aware scrolling.
59
- - Calculate wrapped line counts for proper scroll clamping.
60
- - Implement mouse hit testing for pane-specific interactions.
61
-
62
- [Read the source code →](app.rb)