ratatui_ruby 1.2.0 → 1.2.2

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