ratatui_ruby 0.8.0 → 0.9.0

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 (352) hide show
  1. checksums.yaml +4 -4
  2. data/.builds/ruby-3.2.yml +2 -2
  3. data/.builds/ruby-3.3.yml +2 -2
  4. data/.builds/ruby-3.4.yml +2 -2
  5. data/.builds/ruby-4.0.0.yml +2 -2
  6. data/.pre-commit-config.yaml +1 -1
  7. data/AGENTS.md +3 -3
  8. data/CHANGELOG.md +53 -1
  9. data/LICENSES/LGPL-3.0-or-later.txt +304 -0
  10. data/LICENSES/MIT-0.txt +16 -0
  11. data/README.md +33 -5
  12. data/Rakefile +1 -1
  13. data/doc/concepts/application_architecture.md +44 -3
  14. data/doc/concepts/application_testing.md +43 -1
  15. data/doc/concepts/async.md +32 -2
  16. data/doc/concepts/custom_widgets.md +247 -0
  17. data/doc/concepts/event_handling.md +32 -3
  18. data/doc/concepts/interactive_design.md +32 -2
  19. data/doc/contributors/auditing/parity.md +7 -1
  20. data/doc/contributors/design/ruby_frontend.md +85 -1
  21. data/doc/contributors/design/rust_backend.md +67 -1
  22. data/doc/contributors/developing_examples.md +56 -2
  23. data/doc/contributors/documentation_style.md +20 -3
  24. data/doc/contributors/future_work.md +169 -0
  25. data/doc/contributors/index.md +1 -1
  26. data/doc/contributors/v1.0.0_blockers.md +15 -175
  27. data/doc/getting_started/quickstart.md +22 -4
  28. data/doc/getting_started/why.md +1 -1
  29. data/doc/index.md +2 -1
  30. data/doc/troubleshooting/debugging.md +32 -2
  31. data/doc/troubleshooting/terminal_limitations.md +8 -2
  32. data/doc/troubleshooting/tui_output.md +42 -0
  33. data/examples/app_all_events/README.md +14 -2
  34. data/examples/app_all_events/app.rb +1 -1
  35. data/examples/app_all_events/model/app_model.rb +1 -1
  36. data/examples/app_all_events/model/event_color_cycle.rb +1 -1
  37. data/examples/app_all_events/model/event_entry.rb +1 -1
  38. data/examples/app_all_events/model/msg.rb +1 -1
  39. data/examples/app_all_events/model/timestamp.rb +1 -1
  40. data/examples/app_all_events/update.rb +1 -1
  41. data/examples/app_all_events/view/app_view.rb +1 -1
  42. data/examples/app_all_events/view/controls_view.rb +1 -1
  43. data/examples/app_all_events/view/counts_view.rb +1 -1
  44. data/examples/app_all_events/view/live_view.rb +1 -1
  45. data/examples/app_all_events/view/log_view.rb +1 -1
  46. data/examples/app_all_events/view.rb +1 -1
  47. data/examples/app_color_picker/README.md +20 -2
  48. data/examples/app_color_picker/app.rb +1 -1
  49. data/examples/app_color_picker/clipboard.rb +1 -1
  50. data/examples/app_color_picker/color.rb +1 -1
  51. data/examples/app_color_picker/controls.rb +1 -1
  52. data/examples/app_color_picker/copy_dialog.rb +1 -1
  53. data/examples/app_color_picker/export_pane.rb +1 -1
  54. data/examples/app_color_picker/harmony.rb +1 -1
  55. data/examples/app_color_picker/input.rb +1 -1
  56. data/examples/app_color_picker/main_container.rb +1 -1
  57. data/examples/app_color_picker/palette.rb +1 -1
  58. data/examples/app_login_form/README.md +8 -2
  59. data/examples/app_login_form/app.rb +1 -1
  60. data/examples/app_stateful_interaction/README.md +2 -2
  61. data/examples/app_stateful_interaction/app.rb +71 -17
  62. data/examples/timeout_demo.rb +1 -1
  63. data/examples/verify_quickstart_dsl/README.md +6 -0
  64. data/examples/verify_quickstart_dsl/app.rb +3 -3
  65. data/examples/verify_quickstart_layout/README.md +6 -0
  66. data/examples/verify_quickstart_layout/app.rb +3 -3
  67. data/examples/verify_quickstart_lifecycle/README.md +6 -0
  68. data/examples/verify_quickstart_lifecycle/app.rb +3 -3
  69. data/examples/verify_readme_usage/README.md +6 -0
  70. data/examples/verify_readme_usage/app.rb +3 -3
  71. data/examples/widget_barchart/README.md +6 -0
  72. data/examples/widget_barchart/app.rb +2 -2
  73. data/examples/widget_block/README.md +7 -1
  74. data/examples/widget_block/app.rb +2 -2
  75. data/examples/widget_box/README.md +6 -0
  76. data/examples/widget_box/app.rb +9 -6
  77. data/examples/widget_calendar/README.md +6 -0
  78. data/examples/widget_calendar/app.rb +2 -2
  79. data/examples/widget_canvas/README.md +4 -0
  80. data/examples/widget_canvas/app.rb +2 -2
  81. data/examples/widget_cell/README.md +6 -0
  82. data/examples/widget_cell/app.rb +2 -3
  83. data/examples/widget_center/README.md +4 -0
  84. data/examples/widget_center/app.rb +2 -2
  85. data/examples/widget_chart/README.md +6 -0
  86. data/examples/widget_chart/app.rb +2 -2
  87. data/examples/widget_gauge/README.md +6 -0
  88. data/examples/widget_gauge/app.rb +2 -2
  89. data/examples/widget_layout_split/README.md +6 -0
  90. data/examples/widget_layout_split/app.rb +3 -3
  91. data/examples/widget_line_gauge/README.md +6 -0
  92. data/examples/widget_line_gauge/app.rb +2 -2
  93. data/examples/widget_list/README.md +6 -0
  94. data/examples/widget_list/app.rb +2 -2
  95. data/examples/widget_map/README.md +8 -2
  96. data/examples/widget_map/app.rb +2 -2
  97. data/examples/widget_overlay/README.md +7 -1
  98. data/examples/widget_overlay/app.rb +2 -2
  99. data/examples/widget_popup/README.md +6 -0
  100. data/examples/widget_popup/app.rb +2 -2
  101. data/examples/widget_ratatui_logo/README.md +6 -0
  102. data/examples/widget_ratatui_logo/app.rb +2 -3
  103. data/examples/widget_ratatui_mascot/README.md +6 -0
  104. data/examples/widget_ratatui_mascot/app.rb +2 -2
  105. data/examples/widget_rect/README.md +12 -0
  106. data/examples/widget_rect/app.rb +40 -26
  107. data/examples/widget_render/README.md +6 -0
  108. data/examples/widget_render/app.rb +2 -2
  109. data/examples/widget_render/app.rbs +41 -0
  110. data/examples/widget_rich_text/README.md +6 -0
  111. data/examples/widget_rich_text/app.rb +2 -2
  112. data/examples/widget_scroll_text/README.md +6 -0
  113. data/examples/widget_scroll_text/app.rb +2 -2
  114. data/examples/widget_scrollbar/README.md +6 -0
  115. data/examples/widget_scrollbar/app.rb +2 -2
  116. data/examples/widget_sparkline/README.md +6 -0
  117. data/examples/widget_sparkline/app.rb +2 -2
  118. data/examples/widget_style_colors/README.md +6 -0
  119. data/examples/widget_style_colors/app.rb +2 -2
  120. data/examples/widget_table/README.md +8 -2
  121. data/examples/widget_table/app.rb +2 -2
  122. data/examples/widget_tabs/README.md +6 -0
  123. data/examples/widget_tabs/app.rb +2 -2
  124. data/examples/widget_text_width/README.md +6 -0
  125. data/examples/widget_text_width/app.rb +4 -4
  126. data/ext/ratatui_ruby/Cargo.lock +1 -1
  127. data/ext/ratatui_ruby/Cargo.toml +1 -1
  128. data/ext/ratatui_ruby/extconf.rb +2 -2
  129. data/ext/ratatui_ruby/src/rendering.rs +1 -1
  130. data/ext/ratatui_ruby/src/style.rs +0 -8
  131. data/ext/ratatui_ruby/src/widgets/chart.rs +0 -118
  132. data/ext/ratatui_ruby/src/widgets/list_state.rs +36 -0
  133. data/lib/ratatui_ruby/buffer/cell.rb +34 -2
  134. data/lib/ratatui_ruby/buffer.rb +2 -2
  135. data/lib/ratatui_ruby/cell.rb +34 -2
  136. data/lib/ratatui_ruby/event/focus_gained.rb +26 -2
  137. data/lib/ratatui_ruby/event/focus_lost.rb +26 -2
  138. data/lib/ratatui_ruby/event/key/character.rb +18 -2
  139. data/lib/ratatui_ruby/event/key/media.rb +2 -2
  140. data/lib/ratatui_ruby/event/key/modifier.rb +10 -2
  141. data/lib/ratatui_ruby/event/key/navigation.rb +2 -2
  142. data/lib/ratatui_ruby/event/key/system.rb +2 -2
  143. data/lib/ratatui_ruby/event/key.rb +114 -2
  144. data/lib/ratatui_ruby/event/mouse.rb +42 -2
  145. data/lib/ratatui_ruby/event/none.rb +10 -2
  146. data/lib/ratatui_ruby/event/paste.rb +34 -2
  147. data/lib/ratatui_ruby/event/resize.rb +34 -2
  148. data/lib/ratatui_ruby/event.rb +26 -2
  149. data/lib/ratatui_ruby/frame.rb +74 -2
  150. data/lib/ratatui_ruby/layout/constraint.rb +58 -2
  151. data/lib/ratatui_ruby/layout/layout.rb +47 -2
  152. data/lib/ratatui_ruby/layout/rect.rb +403 -2
  153. data/lib/ratatui_ruby/layout.rb +2 -2
  154. data/lib/ratatui_ruby/list_state.rb +113 -2
  155. data/lib/ratatui_ruby/output_guard.rb +26 -3
  156. data/lib/ratatui_ruby/schema/bar_chart/bar.rb +2 -2
  157. data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +2 -2
  158. data/lib/ratatui_ruby/schema/bar_chart.rb +50 -2
  159. data/lib/ratatui_ruby/schema/block.rb +21 -15
  160. data/lib/ratatui_ruby/schema/calendar.rb +2 -2
  161. data/lib/ratatui_ruby/schema/canvas.rb +10 -2
  162. data/lib/ratatui_ruby/schema/center.rb +10 -2
  163. data/lib/ratatui_ruby/schema/chart.rb +2 -28
  164. data/lib/ratatui_ruby/schema/clear.rb +10 -2
  165. data/lib/ratatui_ruby/schema/constraint.rb +58 -2
  166. data/lib/ratatui_ruby/schema/cursor.rb +10 -2
  167. data/lib/ratatui_ruby/schema/draw.rb +10 -2
  168. data/lib/ratatui_ruby/schema/gauge.rb +2 -2
  169. data/lib/ratatui_ruby/schema/layout.rb +18 -2
  170. data/lib/ratatui_ruby/schema/line_gauge.rb +2 -2
  171. data/lib/ratatui_ruby/schema/list.rb +10 -2
  172. data/lib/ratatui_ruby/schema/list_item.rb +10 -2
  173. data/lib/ratatui_ruby/schema/overlay.rb +10 -2
  174. data/lib/ratatui_ruby/schema/paragraph.rb +10 -2
  175. data/lib/ratatui_ruby/schema/ratatui_logo.rb +2 -2
  176. data/lib/ratatui_ruby/schema/ratatui_mascot.rb +2 -2
  177. data/lib/ratatui_ruby/schema/rect.rb +58 -2
  178. data/lib/ratatui_ruby/schema/row.rb +10 -2
  179. data/lib/ratatui_ruby/schema/scrollbar.rb +2 -2
  180. data/lib/ratatui_ruby/schema/shape/label.rb +10 -2
  181. data/lib/ratatui_ruby/schema/sparkline.rb +10 -2
  182. data/lib/ratatui_ruby/schema/style.rb +18 -2
  183. data/lib/ratatui_ruby/schema/table.rb +2 -2
  184. data/lib/ratatui_ruby/schema/tabs.rb +2 -2
  185. data/lib/ratatui_ruby/schema/text.rb +34 -2
  186. data/lib/ratatui_ruby/scrollbar_state.rb +10 -2
  187. data/lib/ratatui_ruby/style/style.rb +18 -2
  188. data/lib/ratatui_ruby/style.rb +2 -2
  189. data/lib/ratatui_ruby/table_state.rb +10 -2
  190. data/lib/ratatui_ruby/terminal_lifecycle.rb +18 -3
  191. data/lib/ratatui_ruby/test_helper/event_injection.rb +34 -2
  192. data/lib/ratatui_ruby/test_helper/snapshot.rb +74 -9
  193. data/lib/ratatui_ruby/test_helper/style_assertions.rb +98 -2
  194. data/lib/ratatui_ruby/test_helper/terminal.rb +50 -2
  195. data/lib/ratatui_ruby/test_helper/test_doubles.rb +18 -2
  196. data/lib/ratatui_ruby/test_helper.rb +10 -2
  197. data/lib/ratatui_ruby/tui/buffer_factories.rb +2 -2
  198. data/lib/ratatui_ruby/tui/canvas_factories.rb +2 -2
  199. data/lib/ratatui_ruby/tui/core.rb +2 -2
  200. data/lib/ratatui_ruby/tui/layout_factories.rb +32 -2
  201. data/lib/ratatui_ruby/tui/state_factories.rb +2 -2
  202. data/lib/ratatui_ruby/tui/style_factories.rb +2 -2
  203. data/lib/ratatui_ruby/tui/text_factories.rb +2 -2
  204. data/lib/ratatui_ruby/tui/widget_factories.rb +2 -2
  205. data/lib/ratatui_ruby/tui.rb +11 -3
  206. data/lib/ratatui_ruby/version.rb +3 -3
  207. data/lib/ratatui_ruby/widgets/bar_chart/bar.rb +2 -2
  208. data/lib/ratatui_ruby/widgets/bar_chart/bar_group.rb +2 -2
  209. data/lib/ratatui_ruby/widgets/bar_chart.rb +58 -2
  210. data/lib/ratatui_ruby/widgets/block.rb +37 -15
  211. data/lib/ratatui_ruby/widgets/calendar.rb +2 -2
  212. data/lib/ratatui_ruby/widgets/canvas.rb +10 -2
  213. data/lib/ratatui_ruby/widgets/cell.rb +10 -2
  214. data/lib/ratatui_ruby/widgets/center.rb +10 -2
  215. data/lib/ratatui_ruby/widgets/chart.rb +2 -28
  216. data/lib/ratatui_ruby/widgets/clear.rb +10 -2
  217. data/lib/ratatui_ruby/widgets/cursor.rb +10 -2
  218. data/lib/ratatui_ruby/widgets/gauge.rb +16 -2
  219. data/lib/ratatui_ruby/widgets/line_gauge.rb +16 -2
  220. data/lib/ratatui_ruby/widgets/list.rb +41 -2
  221. data/lib/ratatui_ruby/widgets/list_item.rb +10 -2
  222. data/lib/ratatui_ruby/widgets/overlay.rb +10 -2
  223. data/lib/ratatui_ruby/widgets/paragraph.rb +10 -2
  224. data/lib/ratatui_ruby/widgets/ratatui_logo.rb +2 -2
  225. data/lib/ratatui_ruby/widgets/ratatui_mascot.rb +2 -2
  226. data/lib/ratatui_ruby/widgets/row.rb +10 -2
  227. data/lib/ratatui_ruby/widgets/scrollbar.rb +2 -2
  228. data/lib/ratatui_ruby/widgets/shape/label.rb +10 -2
  229. data/lib/ratatui_ruby/widgets/sparkline.rb +10 -2
  230. data/lib/ratatui_ruby/widgets/table.rb +62 -2
  231. data/lib/ratatui_ruby/widgets/tabs.rb +2 -2
  232. data/lib/ratatui_ruby/widgets.rb +2 -2
  233. data/lib/ratatui_ruby.rb +90 -2
  234. data/sig/examples/app_all_events/view.rbs +7 -1
  235. data/sig/examples/app_all_events/view_state.rbs +7 -1
  236. data/sig/examples/app_color_picker/app.rbs +5 -0
  237. data/sig/examples/app_stateful_interaction/app.rbs +7 -1
  238. data/sig/examples/verify_quickstart_dsl/app.rbs +7 -1
  239. data/sig/examples/verify_quickstart_lifecycle/app.rbs +7 -1
  240. data/sig/examples/verify_readme_usage/app.rbs +7 -1
  241. data/sig/examples/widget_block_demo/app.rbs +6 -0
  242. data/sig/examples/widget_box_demo/app.rbs +7 -1
  243. data/sig/examples/widget_calendar_demo/app.rbs +7 -1
  244. data/sig/examples/widget_cell_demo/app.rbs +7 -1
  245. data/sig/examples/widget_chart_demo/app.rbs +7 -1
  246. data/sig/examples/widget_gauge_demo/app.rbs +7 -1
  247. data/sig/examples/widget_layout_split/app.rbs +7 -1
  248. data/sig/examples/widget_line_gauge_demo/app.rbs +7 -1
  249. data/sig/examples/widget_list_demo/app.rbs +5 -0
  250. data/sig/examples/widget_map_demo/app.rbs +7 -1
  251. data/sig/examples/widget_popup_demo/app.rbs +7 -1
  252. data/sig/examples/widget_ratatui_logo_demo/app.rbs +7 -1
  253. data/sig/examples/widget_ratatui_mascot_demo/app.rbs +7 -1
  254. data/sig/examples/widget_rect/app.rbs +7 -1
  255. data/sig/examples/widget_render/app.rbs +7 -1
  256. data/sig/examples/widget_rich_text/app.rbs +7 -1
  257. data/sig/examples/widget_scroll_text/app.rbs +7 -1
  258. data/sig/examples/widget_scrollbar_demo/app.rbs +7 -1
  259. data/sig/examples/widget_sparkline_demo/app.rbs +7 -1
  260. data/sig/examples/widget_style_colors/app.rbs +7 -1
  261. data/sig/examples/widget_table_demo/app.rbs +7 -1
  262. data/sig/examples/widget_text_width/app.rbs +7 -1
  263. data/sig/ratatui_ruby/event.rbs +7 -1
  264. data/sig/ratatui_ruby/frame.rbs +15 -3
  265. data/sig/ratatui_ruby/list_state.rbs +11 -1
  266. data/sig/ratatui_ruby/ratatui_ruby.rbs +8 -2
  267. data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +7 -1
  268. data/sig/ratatui_ruby/schema/bar_chart/bar_group.rbs +6 -0
  269. data/sig/ratatui_ruby/schema/bar_chart.rbs +6 -0
  270. data/sig/ratatui_ruby/schema/block.rbs +7 -1
  271. data/sig/ratatui_ruby/schema/calendar.rbs +6 -0
  272. data/sig/ratatui_ruby/schema/canvas.rbs +6 -0
  273. data/sig/ratatui_ruby/schema/center.rbs +6 -0
  274. data/sig/ratatui_ruby/schema/chart.rbs +6 -9
  275. data/sig/ratatui_ruby/schema/constraint.rbs +6 -0
  276. data/sig/ratatui_ruby/schema/cursor.rbs +6 -0
  277. data/sig/ratatui_ruby/schema/draw.rbs +6 -0
  278. data/sig/ratatui_ruby/schema/gauge.rbs +9 -1
  279. data/sig/ratatui_ruby/schema/layout.rbs +6 -0
  280. data/sig/ratatui_ruby/schema/line_gauge.rbs +9 -1
  281. data/sig/ratatui_ruby/schema/list.rbs +9 -1
  282. data/sig/ratatui_ruby/schema/list_item.rbs +7 -1
  283. data/sig/ratatui_ruby/schema/overlay.rbs +6 -0
  284. data/sig/ratatui_ruby/schema/paragraph.rbs +6 -0
  285. data/sig/ratatui_ruby/schema/ratatui_logo.rbs +6 -0
  286. data/sig/ratatui_ruby/schema/ratatui_mascot.rbs +5 -0
  287. data/sig/ratatui_ruby/schema/rect.rbs +30 -0
  288. data/sig/ratatui_ruby/schema/row.rbs +7 -1
  289. data/sig/ratatui_ruby/schema/scrollbar.rbs +6 -0
  290. data/sig/ratatui_ruby/schema/sparkline.rbs +6 -0
  291. data/sig/ratatui_ruby/schema/style.rbs +7 -1
  292. data/sig/ratatui_ruby/schema/table.rbs +11 -1
  293. data/sig/ratatui_ruby/schema/tabs.rbs +6 -0
  294. data/sig/ratatui_ruby/schema/text.rbs +7 -1
  295. data/sig/ratatui_ruby/scrollbar_state.rbs +7 -1
  296. data/sig/ratatui_ruby/session.rbs +7 -1
  297. data/sig/ratatui_ruby/table_state.rbs +7 -1
  298. data/sig/ratatui_ruby/test_helper/event_injection.rbs +7 -1
  299. data/sig/ratatui_ruby/test_helper/snapshot.rbs +7 -1
  300. data/sig/ratatui_ruby/test_helper/style_assertions.rbs +7 -1
  301. data/sig/ratatui_ruby/test_helper/terminal.rbs +7 -1
  302. data/sig/ratatui_ruby/test_helper/test_doubles.rbs +7 -1
  303. data/sig/ratatui_ruby/test_helper.rbs +7 -1
  304. data/sig/ratatui_ruby/tui/buffer_factories.rbs +7 -1
  305. data/sig/ratatui_ruby/tui/canvas_factories.rbs +7 -1
  306. data/sig/ratatui_ruby/tui/core.rbs +7 -1
  307. data/sig/ratatui_ruby/tui/layout_factories.rbs +7 -1
  308. data/sig/ratatui_ruby/tui/state_factories.rbs +7 -1
  309. data/sig/ratatui_ruby/tui/style_factories.rbs +7 -1
  310. data/sig/ratatui_ruby/tui/text_factories.rbs +7 -1
  311. data/sig/ratatui_ruby/tui/widget_factories.rbs +7 -1
  312. data/sig/ratatui_ruby/tui.rbs +7 -1
  313. data/sig/ratatui_ruby/version.rbs +6 -0
  314. data/tasks/autodoc/examples.rb +1 -1
  315. data/tasks/autodoc/member.rb +1 -1
  316. data/tasks/autodoc/name.rb +1 -1
  317. data/tasks/bump/cargo_lockfile.rb +1 -1
  318. data/tasks/bump/changelog.rb +1 -1
  319. data/tasks/bump/header.rb +1 -1
  320. data/tasks/bump/history.rb +1 -1
  321. data/tasks/bump/links.rb +1 -1
  322. data/tasks/bump/manifest.rb +1 -1
  323. data/tasks/bump/ruby_gem.rb +1 -1
  324. data/tasks/bump/sem_ver.rb +1 -1
  325. data/tasks/bump/unreleased_section.rb +1 -1
  326. data/tasks/license/headers_md.rb +223 -0
  327. data/tasks/license/headers_rb.rb +210 -0
  328. data/tasks/license/license_utils.rb +130 -0
  329. data/tasks/license/snippets_md.rb +315 -0
  330. data/tasks/license/snippets_rdoc.rb +150 -0
  331. data/tasks/license.rake +91 -0
  332. data/tasks/rdoc_config.rb +1 -1
  333. data/tasks/resources/build.yml.erb +13 -7
  334. data/tasks/sourcehut.rake +3 -1
  335. data/tasks/terminal_preview/app_screenshot.rb +1 -1
  336. data/tasks/terminal_preview/crash_report.rb +1 -1
  337. data/tasks/terminal_preview/example_app.rb +1 -1
  338. data/tasks/terminal_preview/launcher_script.rb +1 -1
  339. data/tasks/terminal_preview/preview_collection.rb +1 -1
  340. data/tasks/terminal_preview/preview_timing.rb +1 -1
  341. data/tasks/terminal_preview/safety_confirmation.rb +1 -1
  342. data/tasks/terminal_preview/saved_screenshot.rb +1 -1
  343. data/tasks/terminal_preview/system_appearance.rb +1 -1
  344. data/tasks/terminal_preview/terminal_window.rb +1 -1
  345. data/tasks/terminal_preview/window_id.rb +1 -1
  346. data/tasks/website/index_page.rb +1 -1
  347. data/tasks/website/version.rb +1 -1
  348. data/tasks/website/version_menu.rb +1 -1
  349. data/tasks/website/versioned_documentation.rb +1 -1
  350. data/tasks/website/website.rb +1 -1
  351. metadata +13 -3
  352. data/doc/migration/v0_7_0.md +0 -236
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #--
4
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: AGPL-3.0-or-later
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
6
  #++
7
7
 
8
8
  module RatatuiRuby
@@ -19,8 +19,16 @@ module RatatuiRuby
19
19
  #
20
20
  # === Examples
21
21
  #
22
+ #--
23
+ # SPDX-SnippetBegin
24
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
25
+ # SPDX-License-Identifier: MIT-0
26
+ #++
22
27
  # area = Layout::Rect.new(x: 0, y: 0, width: 80, height: 24)
23
28
  # puts area.width # => 80
29
+ #--
30
+ # SPDX-SnippetEnd
31
+ #++
24
32
  class Rect < Data.define(:x, :y, :width, :height)
25
33
  ##
26
34
  # :attr_reader: x
@@ -59,15 +67,31 @@ module RatatuiRuby
59
67
  #
60
68
  # Essential for hit testing mouse clicks against layout regions.
61
69
  #
70
+ #--
71
+ # SPDX-SnippetBegin
72
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
73
+ # SPDX-License-Identifier: MIT-0
74
+ #++
62
75
  # area = Layout::Rect.new(x: 10, y: 5, width: 20, height: 10)
63
76
  # area.contains?(15, 8) # => true
64
77
  # area.contains?(5, 8) # => false
65
78
  #
79
+ #--
80
+ # SPDX-SnippetEnd
81
+ #++
66
82
  # [px]
67
83
  # X coordinate to test (column).
68
84
  # [py]
85
+ #--
86
+ # SPDX-SnippetBegin
87
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
88
+ # SPDX-License-Identifier: MIT-0
89
+ #++
69
90
  # Y coordinate to test (row).
70
91
  #
92
+ #--
93
+ # SPDX-SnippetEnd
94
+ #++
71
95
  # Returns true if the point (px, py) is within the rectangle bounds.
72
96
  def contains?(px, py)
73
97
  px >= x && px < x + width && py >= y && py < y + height
@@ -77,13 +101,29 @@ module RatatuiRuby
77
101
  #
78
102
  # Essential for determining if a widget is visible within a viewport or clipping area.
79
103
  #
104
+ #--
105
+ # SPDX-SnippetBegin
106
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
107
+ # SPDX-License-Identifier: MIT-0
108
+ #++
80
109
  # viewport = Layout::Rect.new(x: 0, y: 0, width: 80, height: 24)
81
110
  # widget = Layout::Rect.new(x: 70, y: 20, width: 20, height: 10)
82
111
  # viewport.intersects?(widget) # => true (partial overlap)
83
112
  #
113
+ #--
114
+ # SPDX-SnippetEnd
115
+ #++
84
116
  # [other]
117
+ #--
118
+ # SPDX-SnippetBegin
119
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
120
+ # SPDX-License-Identifier: MIT-0
121
+ #++
85
122
  # Another Rect to test against.
86
123
  #
124
+ #--
125
+ # SPDX-SnippetEnd
126
+ #++
87
127
  # Returns true if the rectangles overlap.
88
128
  def intersects?(other)
89
129
  x < other.x + other.width &&
@@ -96,14 +136,30 @@ module RatatuiRuby
96
136
  #
97
137
  # Essential for calculating visible portions of widgets inside scroll views.
98
138
  #
139
+ #--
140
+ # SPDX-SnippetBegin
141
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
142
+ # SPDX-License-Identifier: MIT-0
143
+ #++
99
144
  # viewport = Layout::Rect.new(x: 0, y: 0, width: 80, height: 24)
100
145
  # widget = Layout::Rect.new(x: 70, y: 20, width: 20, height: 10)
101
146
  # visible = viewport.intersection(widget)
102
147
  # # => Rect(x: 70, y: 20, width: 10, height: 4)
103
148
  #
149
+ #--
150
+ # SPDX-SnippetEnd
151
+ #++
104
152
  # [other]
153
+ #--
154
+ # SPDX-SnippetBegin
155
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
156
+ # SPDX-License-Identifier: MIT-0
157
+ #++
105
158
  # Another Rect to intersect with.
106
159
  #
160
+ #--
161
+ # SPDX-SnippetEnd
162
+ #++
107
163
  # Returns a new Rect representing the intersection, or +nil+ if no overlap.
108
164
  def intersection(other)
109
165
  return nil unless intersects?(other)
@@ -115,6 +171,351 @@ module RatatuiRuby
115
171
 
116
172
  Rect.new(x: new_x, y: new_y, width: new_right - new_x, height: new_bottom - new_y)
117
173
  end
174
+
175
+ # Left edge coordinate.
176
+ #
177
+ # Layout algorithms compute bounding boxes and check overlaps.
178
+ # Reading <tt>rect.x</tt> forces you to remember that x means "left."
179
+ #
180
+ # Call <tt>left</tt> instead. Your code reads like prose.
181
+ #
182
+ # === Example
183
+ #
184
+ #--
185
+ # SPDX-SnippetBegin
186
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
187
+ # SPDX-License-Identifier: MIT-0
188
+ #++
189
+ # rect = Layout::Rect.new(x: 10, y: 5, width: 80, height: 24)
190
+ # rect.left # => 10
191
+ #--
192
+ # SPDX-SnippetEnd
193
+ #++
194
+ def left
195
+ x
196
+ end
197
+
198
+ # Right edge coordinate.
199
+ #
200
+ # Bounds checks compare edges. Writing <tt>x + width</tt> inline clutters conditions.
201
+ # Errors creep in when you forget the addition.
202
+ #
203
+ # This method computes and names the boundary. Returns the first column outside the rect.
204
+ #
205
+ # === Example
206
+ #
207
+ #--
208
+ # SPDX-SnippetBegin
209
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
210
+ # SPDX-License-Identifier: MIT-0
211
+ #++
212
+ # rect = Layout::Rect.new(x: 10, y: 5, width: 80, height: 24)
213
+ # rect.right # => 90
214
+ #--
215
+ # SPDX-SnippetEnd
216
+ #++
217
+ def right
218
+ x + width
219
+ end
220
+
221
+ # Top edge coordinate.
222
+ #
223
+ # Layout algorithms compute bounding boxes and check overlaps.
224
+ # Reading <tt>rect.y</tt> forces you to remember that y means "top."
225
+ #
226
+ # Call <tt>top</tt> instead. Your code reads like prose.
227
+ #
228
+ # === Example
229
+ #
230
+ #--
231
+ # SPDX-SnippetBegin
232
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
233
+ # SPDX-License-Identifier: MIT-0
234
+ #++
235
+ # rect = Layout::Rect.new(x: 10, y: 5, width: 80, height: 24)
236
+ # rect.top # => 5
237
+ #--
238
+ # SPDX-SnippetEnd
239
+ #++
240
+ def top
241
+ y
242
+ end
243
+
244
+ # Bottom edge coordinate.
245
+ #
246
+ # Bounds checks compare edges. Writing <tt>y + height</tt> inline clutters conditions.
247
+ # Errors creep in when you forget the addition.
248
+ #
249
+ # This method computes and names the boundary. Returns the first row outside the rect.
250
+ #
251
+ # === Example
252
+ #
253
+ #--
254
+ # SPDX-SnippetBegin
255
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
256
+ # SPDX-License-Identifier: MIT-0
257
+ #++
258
+ # rect = Layout::Rect.new(x: 10, y: 5, width: 80, height: 24)
259
+ # rect.bottom # => 29
260
+ #--
261
+ # SPDX-SnippetEnd
262
+ #++
263
+ def bottom
264
+ y + height
265
+ end
266
+
267
+ # Total area in cells.
268
+ #
269
+ # Size comparisons and allocation calculations need area.
270
+ # Computing <tt>width * height</tt> inline is noisy and error-prone.
271
+ #
272
+ # This method does the multiplication once.
273
+ #
274
+ # === Example
275
+ #
276
+ #--
277
+ # SPDX-SnippetBegin
278
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
279
+ # SPDX-License-Identifier: MIT-0
280
+ #++
281
+ # rect = Layout::Rect.new(x: 0, y: 0, width: 10, height: 5)
282
+ # rect.area # => 50
283
+ #--
284
+ # SPDX-SnippetEnd
285
+ #++
286
+ def area
287
+ width * height
288
+ end
289
+
290
+ # True when the rect has zero area.
291
+ #
292
+ # Zero-width or zero-height rects break layout math.
293
+ # Checking <tt>width == 0 || height == 0</tt> inline is tedious and easy to forget.
294
+ #
295
+ # Guard clauses call <tt>empty?</tt> to skip degenerate rects.
296
+ #
297
+ # === Example
298
+ #
299
+ #--
300
+ # SPDX-SnippetBegin
301
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
302
+ # SPDX-License-Identifier: MIT-0
303
+ #++
304
+ # Layout::Rect.new(width: 0, height: 10).empty? # => true
305
+ # Layout::Rect.new(width: 10, height: 5).empty? # => false
306
+ #--
307
+ # SPDX-SnippetEnd
308
+ #++
309
+ def empty?
310
+ width.zero? || height.zero?
311
+ end
312
+
313
+ # Bounding box containing both rectangles.
314
+ #
315
+ # Damage tracking and hit testing combine rects.
316
+ # Computing min/max of all four edges inline is tedious and error-prone.
317
+ #
318
+ # This method returns the smallest rect that encloses both.
319
+ #
320
+ # [other] Rect to merge.
321
+ #
322
+ # === Example
323
+ #
324
+ #--
325
+ # SPDX-SnippetBegin
326
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
327
+ # SPDX-License-Identifier: MIT-0
328
+ #++
329
+ # r1 = Layout::Rect.new(x: 0, y: 0, width: 10, height: 10)
330
+ # r2 = Layout::Rect.new(x: 5, y: 5, width: 10, height: 10)
331
+ # r1.union(r2) # => Rect(x: 0, y: 0, width: 15, height: 15)
332
+ #--
333
+ # SPDX-SnippetEnd
334
+ #++
335
+ def union(other)
336
+ new_x = [left, other.left].min
337
+ new_y = [top, other.top].min
338
+ new_right = [right, other.right].max
339
+ new_bottom = [bottom, other.bottom].max
340
+
341
+ Rect.new(
342
+ x: new_x,
343
+ y: new_y,
344
+ width: new_right - new_x,
345
+ height: new_bottom - new_y
346
+ )
347
+ end
348
+
349
+ # Shrinks the rect by a uniform margin on all sides.
350
+ #
351
+ # Widgets render text inside borders. Subtracting margin from all four edges inline is verbose.
352
+ # Off-by-one errors happen when you forget to double the margin.
353
+ #
354
+ # This method computes the content area. Returns a zero-area rect if margin exceeds dimensions.
355
+ #
356
+ # [margin] Integer padding on all sides.
357
+ #
358
+ # === Example
359
+ #
360
+ #--
361
+ # SPDX-SnippetBegin
362
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
363
+ # SPDX-License-Identifier: MIT-0
364
+ #++
365
+ # rect = Layout::Rect.new(x: 0, y: 0, width: 20, height: 10)
366
+ # rect.inner(2) # => Rect(x: 2, y: 2, width: 16, height: 6)
367
+ #--
368
+ # SPDX-SnippetEnd
369
+ #++
370
+ def inner(margin)
371
+ doubled = margin * 2
372
+ return Rect.new(x: 0, y: 0, width: 0, height: 0) if width < doubled || height < doubled
373
+
374
+ Rect.new(
375
+ x: x + margin,
376
+ y: y + margin,
377
+ width: width - doubled,
378
+ height: height - doubled
379
+ )
380
+ end
381
+
382
+ # Moves the rect without changing size.
383
+ #
384
+ # Animations and drag-and-drop shift widgets.
385
+ # Adding offsets to x and y inline clutters the code.
386
+ #
387
+ # This method returns a translated copy.
388
+ #
389
+ # [dx] Horizontal shift (positive moves right).
390
+ # [dy] Vertical shift (positive moves down).
391
+ #
392
+ # === Example
393
+ #
394
+ #--
395
+ # SPDX-SnippetBegin
396
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
397
+ # SPDX-License-Identifier: MIT-0
398
+ #++
399
+ # rect = Layout::Rect.new(x: 10, y: 5, width: 20, height: 10)
400
+ # rect.offset(5, 3) # => Rect(x: 15, y: 8, width: 20, height: 10)
401
+ #--
402
+ # SPDX-SnippetEnd
403
+ #++
404
+ def offset(dx, dy)
405
+ Rect.new(x: x + dx, y: y + dy, width:, height:)
406
+ end
407
+
408
+ # Constrains the rect to fit inside bounds.
409
+ #
410
+ # Popups and tooltips may extend beyond screen edges.
411
+ # Manually clamping x, y, width, and height is verbose and error-prone.
412
+ #
413
+ # This method repositions and shrinks the rect to stay within bounds.
414
+ #
415
+ # [other] Bounding Rect.
416
+ #
417
+ # === Example
418
+ #
419
+ #--
420
+ # SPDX-SnippetBegin
421
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
422
+ # SPDX-License-Identifier: MIT-0
423
+ #++
424
+ # screen = Layout::Rect.new(x: 0, y: 0, width: 100, height: 100)
425
+ # popup = Layout::Rect.new(x: 80, y: 80, width: 30, height: 30)
426
+ # popup.clamp(screen) # => Rect(x: 70, y: 70, width: 30, height: 30)
427
+ #--
428
+ # SPDX-SnippetEnd
429
+ #++
430
+ def clamp(other)
431
+ clamped_width = [width, other.width].min
432
+ clamped_height = [height, other.height].min
433
+ clamped_x = x.clamp(other.left, other.right - clamped_width)
434
+ clamped_y = y.clamp(other.top, other.bottom - clamped_height)
435
+
436
+ Rect.new(x: clamped_x, y: clamped_y, width: clamped_width, height: clamped_height)
437
+ end
438
+
439
+ # Iterates over horizontal slices.
440
+ #
441
+ # Lists render line by line. Looping <tt>height.times</tt> and constructing rects inline is noisy.
442
+ #
443
+ # This method yields each row as a Rect with height 1. Returns an Enumerator if no block given.
444
+ #
445
+ # === Example
446
+ #
447
+ #--
448
+ # SPDX-SnippetBegin
449
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
450
+ # SPDX-License-Identifier: MIT-0
451
+ #++
452
+ # rect = Layout::Rect.new(x: 0, y: 0, width: 5, height: 3)
453
+ # rect.rows.map { |r| r.y } # => [0, 1, 2]
454
+ #--
455
+ # SPDX-SnippetEnd
456
+ #++
457
+ def rows
458
+ return to_enum(:rows) unless block_given?
459
+
460
+ height.times do |i|
461
+ yield Rect.new(x:, y: y + i, width:, height: 1)
462
+ end
463
+ end
464
+
465
+ # Iterates over vertical slices.
466
+ #
467
+ # Grids render column by column. Looping <tt>width.times</tt> and constructing rects inline is noisy.
468
+ #
469
+ # This method yields each column as a Rect with width 1. Returns an Enumerator if no block given.
470
+ #
471
+ # === Example
472
+ #
473
+ #--
474
+ # SPDX-SnippetBegin
475
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
476
+ # SPDX-License-Identifier: MIT-0
477
+ #++
478
+ # rect = Layout::Rect.new(x: 0, y: 0, width: 5, height: 3)
479
+ # rect.columns.map { |c| c.x } # => [0, 1, 2, 3, 4]
480
+ #--
481
+ # SPDX-SnippetEnd
482
+ #++
483
+ def columns
484
+ return to_enum(:columns) unless block_given?
485
+
486
+ width.times do |i|
487
+ yield Rect.new(x: x + i, y:, width: 1, height:)
488
+ end
489
+ end
490
+
491
+ # Iterates over every cell in row-major order.
492
+ #
493
+ # Hit testing and pixel rendering touch every position.
494
+ # Nested loops with manual coordinate math are verbose.
495
+ #
496
+ # This method yields <tt>[x, y]</tt> pairs. Returns an Enumerator if no block given.
497
+ #
498
+ # === Example
499
+ #
500
+ #--
501
+ # SPDX-SnippetBegin
502
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
503
+ # SPDX-License-Identifier: MIT-0
504
+ #++
505
+ # rect = Layout::Rect.new(x: 0, y: 0, width: 2, height: 2)
506
+ # rect.positions.to_a # => [[0, 0], [1, 0], [0, 1], [1, 1]]
507
+ #--
508
+ # SPDX-SnippetEnd
509
+ #++
510
+ def positions
511
+ return to_enum(:positions) unless block_given?
512
+
513
+ height.times do |row|
514
+ width.times do |col|
515
+ yield [x + col, y + row]
516
+ end
517
+ end
518
+ end
118
519
  end
119
520
  end
120
521
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #--
4
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: AGPL-3.0-or-later
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
6
  #++
7
7
 
8
8
  module RatatuiRuby
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #--
4
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: AGPL-3.0-or-later
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
6
  #++
7
7
 
8
8
  module RatatuiRuby
@@ -24,6 +24,11 @@ module RatatuiRuby
24
24
  #
25
25
  # == Example
26
26
  #
27
+ #--
28
+ # SPDX-SnippetBegin
29
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
30
+ # SPDX-License-Identifier: MIT-0
31
+ #++
27
32
  # @list_state = RatatuiRuby::ListState.new
28
33
  # @list_state.select(2) # Select third item
29
34
  #
@@ -34,6 +39,9 @@ module RatatuiRuby
34
39
  #
35
40
  # puts @list_state.offset # Scroll position after render
36
41
  #
42
+ #--
43
+ # SPDX-SnippetEnd
44
+ #++
37
45
  class ListState
38
46
  ##
39
47
  # :method: new
@@ -86,5 +94,108 @@ module RatatuiRuby
86
94
  # Scrolls up by +n+ items.
87
95
  #
88
96
  # (Native method implemented in Rust)
97
+
98
+ ##
99
+ # :method: select_next
100
+ # :call-seq: select_next() -> nil
101
+ #
102
+ # Moves selection to the next item. Selects first item if nothing selected.
103
+ #
104
+ # === Optimistic Indexing
105
+ #
106
+ # Increments the index immediately, even past list bounds. The renderer
107
+ # clamps to valid range on draw. Reading <tt>selected</tt> between this
108
+ # call and render may return an out-of-bounds value.
109
+ #
110
+ # Matches upstream Ratatui behavior. See
111
+ # {ListState#select_next}[https://docs.rs/ratatui/0.30/ratatui/widgets/struct.ListState.html#method.select_next].
112
+ #
113
+ # To detect actual selection changes, check bounds first:
114
+ #
115
+ #--
116
+ # SPDX-SnippetBegin
117
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
118
+ # SPDX-License-Identifier: MIT-0
119
+ #++
120
+ # max_index = items.size - 1
121
+ # return if (state.selected || 0) >= max_index
122
+ # state.select_next
123
+ #
124
+ #--
125
+ # SPDX-SnippetEnd
126
+ #++
127
+ # (Native method implemented in Rust)
128
+
129
+ ##
130
+ # :method: select_previous
131
+ # :call-seq: select_previous() -> nil
132
+ #
133
+ # Moves selection to the previous item. Selects last item if nothing selected.
134
+ #
135
+ # === Optimistic Indexing
136
+ #
137
+ # At index 0, does nothing. With no selection, sets index to maximum value;
138
+ # the renderer clamps to actual last item on draw.
139
+ #
140
+ # To detect actual selection changes, check bounds first:
141
+ #
142
+ #--
143
+ # SPDX-SnippetBegin
144
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
145
+ # SPDX-License-Identifier: MIT-0
146
+ #++
147
+ # return if (state.selected || 0) <= 0
148
+ # state.select_previous
149
+ #
150
+ #--
151
+ # SPDX-SnippetEnd
152
+ #++
153
+ # (Native method implemented in Rust)
154
+
155
+ ##
156
+ # :method: select_first
157
+ # :call-seq: select_first() -> nil
158
+ #
159
+ # Jumps selection to the first item (index 0).
160
+ #
161
+ # To detect actual selection changes:
162
+ #
163
+ #--
164
+ # SPDX-SnippetBegin
165
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
166
+ # SPDX-License-Identifier: MIT-0
167
+ #++
168
+ # return if (state.selected || 0) == 0
169
+ # state.select_first
170
+ #
171
+ #--
172
+ # SPDX-SnippetEnd
173
+ #++
174
+ # (Native method implemented in Rust)
175
+
176
+ ##
177
+ # :method: select_last
178
+ # :call-seq: select_last() -> nil
179
+ #
180
+ # Jumps selection to the last item.
181
+ #
182
+ # === Optimistic Indexing
183
+ #
184
+ # Sets index to maximum possible value. The renderer clamps to actual last
185
+ # item on draw. To get or check the real last index, track item count:
186
+ #
187
+ #--
188
+ # SPDX-SnippetBegin
189
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
190
+ # SPDX-License-Identifier: MIT-0
191
+ #++
192
+ # max_index = items.size - 1
193
+ # return if (state.selected || 0) == max_index
194
+ # state.select(max_index)
195
+ #
196
+ #--
197
+ # SPDX-SnippetEnd
198
+ #++
199
+ # (Native method implemented in Rust)
89
200
  end
90
201
  end
@@ -1,9 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #--
4
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
5
- #
6
- # SPDX-License-Identifier: AGPL-3.0-or-later
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
7
6
  #++
8
7
 
9
8
  module RatatuiRuby
@@ -70,13 +69,26 @@ module RatatuiRuby
70
69
  # (like lazygit does when editing a commit message), use
71
70
  # {restore_terminal} and {init_terminal} instead:
72
71
  #
72
+ #--
73
+ # SPDX-SnippetBegin
74
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
75
+ # SPDX-License-Identifier: MIT-0
76
+ #++
73
77
  # RatatuiRuby.restore_terminal
74
78
  # puts "Press enter to continue..."
75
79
  # gets
76
80
  # RatatuiRuby.init_terminal
77
81
  #
82
+ #--
83
+ # SPDX-SnippetEnd
84
+ #++
78
85
  # === Example
79
86
  #
87
+ #--
88
+ # SPDX-SnippetBegin
89
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
90
+ # SPDX-License-Identifier: MIT-0
91
+ #++
80
92
  # if ARGV.include?("--no-tui")
81
93
  # RatatuiRuby.headless!
82
94
  # process_batch_work # guard_io calls are silent no-ops
@@ -86,6 +98,9 @@ module RatatuiRuby
86
98
  # end
87
99
  # end
88
100
  #
101
+ #--
102
+ # SPDX-SnippetEnd
103
+ #++
89
104
  # Note: Calling {run} or {init_terminal} after {headless!} raises
90
105
  # {Error::Invariant}. The block is never executed.
91
106
  #
@@ -117,12 +132,20 @@ module RatatuiRuby
117
132
  #
118
133
  # === Example
119
134
  #
135
+ #--
136
+ # SPDX-SnippetBegin
137
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
138
+ # SPDX-License-Identifier: MIT-0
139
+ #++
120
140
  # RatatuiRuby.run do |tui|
121
141
  # RatatuiRuby.guard_io do
122
142
  # SomeChattyGem.do_something # Any puts/warn calls are swallowed
123
143
  # end
124
144
  # end
125
145
  #
146
+ #--
147
+ # SPDX-SnippetEnd
148
+ #++
126
149
  # @see headless!
127
150
  def guard_io
128
151
  # TUI active: guard the output
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #--
4
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: AGPL-3.0-or-later
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
6
  #++
7
7
 
8
8
  module RatatuiRuby
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #--
4
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: AGPL-3.0-or-later
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
6
  #++
7
7
 
8
8
  module RatatuiRuby