ratatui_ruby 1.3.0 → 1.3.3

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