ratatui_ruby 1.5.2-arm64-darwin

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 (295) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +15 -0
  3. data/LICENSES/AGPL-3.0-or-later.txt +661 -0
  4. data/LICENSES/CC-BY-SA-4.0.txt +427 -0
  5. data/LICENSES/CC0-1.0.txt +121 -0
  6. data/LICENSES/LGPL-3.0-or-later.txt +304 -0
  7. data/LICENSES/MIT-0.txt +16 -0
  8. data/LICENSES/MIT.txt +21 -0
  9. data/REUSE.toml +42 -0
  10. data/exe/.gitkeep +0 -0
  11. data/ext/ratatui_ruby/.cargo/config.toml +13 -0
  12. data/ext/ratatui_ruby/.gitignore +4 -0
  13. data/ext/ratatui_ruby/Cargo.lock +1730 -0
  14. data/ext/ratatui_ruby/Cargo.toml +23 -0
  15. data/ext/ratatui_ruby/clippy.toml +7 -0
  16. data/ext/ratatui_ruby/extconf.rb +21 -0
  17. data/ext/ratatui_ruby/src/color.rs +82 -0
  18. data/ext/ratatui_ruby/src/errors.rs +28 -0
  19. data/ext/ratatui_ruby/src/events.rs +706 -0
  20. data/ext/ratatui_ruby/src/frame.rs +241 -0
  21. data/ext/ratatui_ruby/src/lib.rs +343 -0
  22. data/ext/ratatui_ruby/src/lib_header.rs +11 -0
  23. data/ext/ratatui_ruby/src/rendering.rs +158 -0
  24. data/ext/ratatui_ruby/src/string_width.rs +26 -0
  25. data/ext/ratatui_ruby/src/style.rs +469 -0
  26. data/ext/ratatui_ruby/src/terminal/capabilities.rs +46 -0
  27. data/ext/ratatui_ruby/src/terminal/init.rs +233 -0
  28. data/ext/ratatui_ruby/src/terminal/mod.rs +42 -0
  29. data/ext/ratatui_ruby/src/terminal/mutations.rs +158 -0
  30. data/ext/ratatui_ruby/src/terminal/queries.rs +249 -0
  31. data/ext/ratatui_ruby/src/terminal/query.rs +400 -0
  32. data/ext/ratatui_ruby/src/terminal/storage.rs +109 -0
  33. data/ext/ratatui_ruby/src/terminal/wrapper.rs +16 -0
  34. data/ext/ratatui_ruby/src/text.rs +225 -0
  35. data/ext/ratatui_ruby/src/widgets/barchart.rs +169 -0
  36. data/ext/ratatui_ruby/src/widgets/block.rs +41 -0
  37. data/ext/ratatui_ruby/src/widgets/calendar.rs +84 -0
  38. data/ext/ratatui_ruby/src/widgets/canvas.rs +183 -0
  39. data/ext/ratatui_ruby/src/widgets/center.rs +79 -0
  40. data/ext/ratatui_ruby/src/widgets/chart.rs +222 -0
  41. data/ext/ratatui_ruby/src/widgets/clear.rs +39 -0
  42. data/ext/ratatui_ruby/src/widgets/cursor.rs +32 -0
  43. data/ext/ratatui_ruby/src/widgets/gauge.rs +65 -0
  44. data/ext/ratatui_ruby/src/widgets/layout.rs +379 -0
  45. data/ext/ratatui_ruby/src/widgets/line_gauge.rs +100 -0
  46. data/ext/ratatui_ruby/src/widgets/list.rs +378 -0
  47. data/ext/ratatui_ruby/src/widgets/list_state.rs +173 -0
  48. data/ext/ratatui_ruby/src/widgets/mod.rs +26 -0
  49. data/ext/ratatui_ruby/src/widgets/overlay.rs +24 -0
  50. data/ext/ratatui_ruby/src/widgets/paragraph.rs +87 -0
  51. data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +40 -0
  52. data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +55 -0
  53. data/ext/ratatui_ruby/src/widgets/scrollbar.rs +214 -0
  54. data/ext/ratatui_ruby/src/widgets/scrollbar_state.rs +169 -0
  55. data/ext/ratatui_ruby/src/widgets/sparkline.rs +127 -0
  56. data/ext/ratatui_ruby/src/widgets/table.rs +415 -0
  57. data/ext/ratatui_ruby/src/widgets/table_state.rs +203 -0
  58. data/ext/ratatui_ruby/src/widgets/tabs.rs +194 -0
  59. data/lib/ratatui_ruby/3.2/ratatui_ruby.bundle +0 -0
  60. data/lib/ratatui_ruby/3.3/ratatui_ruby.bundle +0 -0
  61. data/lib/ratatui_ruby/3.4/ratatui_ruby.bundle +0 -0
  62. data/lib/ratatui_ruby/4.0/ratatui_ruby.bundle +0 -0
  63. data/lib/ratatui_ruby/backend/window_size.rb +50 -0
  64. data/lib/ratatui_ruby/backend.rb +59 -0
  65. data/lib/ratatui_ruby/buffer/cell.rb +212 -0
  66. data/lib/ratatui_ruby/buffer.rb +149 -0
  67. data/lib/ratatui_ruby/cell.rb +208 -0
  68. data/lib/ratatui_ruby/debug.rb +215 -0
  69. data/lib/ratatui_ruby/draw.rb +63 -0
  70. data/lib/ratatui_ruby/event/focus_gained.rb +125 -0
  71. data/lib/ratatui_ruby/event/focus_lost.rb +127 -0
  72. data/lib/ratatui_ruby/event/key/character.rb +53 -0
  73. data/lib/ratatui_ruby/event/key/dwim.rb +301 -0
  74. data/lib/ratatui_ruby/event/key/media.rb +46 -0
  75. data/lib/ratatui_ruby/event/key/modifier.rb +107 -0
  76. data/lib/ratatui_ruby/event/key/navigation.rb +72 -0
  77. data/lib/ratatui_ruby/event/key/system.rb +47 -0
  78. data/lib/ratatui_ruby/event/key.rb +479 -0
  79. data/lib/ratatui_ruby/event/mouse.rb +291 -0
  80. data/lib/ratatui_ruby/event/none.rb +53 -0
  81. data/lib/ratatui_ruby/event/paste.rb +130 -0
  82. data/lib/ratatui_ruby/event/resize.rb +221 -0
  83. data/lib/ratatui_ruby/event/sync.rb +52 -0
  84. data/lib/ratatui_ruby/event.rb +163 -0
  85. data/lib/ratatui_ruby/frame.rb +257 -0
  86. data/lib/ratatui_ruby/labs/a11y.rb +182 -0
  87. data/lib/ratatui_ruby/labs/frame_a11y_capture.rb +50 -0
  88. data/lib/ratatui_ruby/labs.rb +47 -0
  89. data/lib/ratatui_ruby/layout/alignment.rb +91 -0
  90. data/lib/ratatui_ruby/layout/constraint.rb +337 -0
  91. data/lib/ratatui_ruby/layout/layout.rb +258 -0
  92. data/lib/ratatui_ruby/layout/position.rb +81 -0
  93. data/lib/ratatui_ruby/layout/rect.rb +733 -0
  94. data/lib/ratatui_ruby/layout/size.rb +62 -0
  95. data/lib/ratatui_ruby/layout.rb +29 -0
  96. data/lib/ratatui_ruby/list_state.rb +201 -0
  97. data/lib/ratatui_ruby/output_guard.rb +171 -0
  98. data/lib/ratatui_ruby/scrollbar_state.rb +122 -0
  99. data/lib/ratatui_ruby/style/color.rb +149 -0
  100. data/lib/ratatui_ruby/style/style.rb +147 -0
  101. data/lib/ratatui_ruby/style.rb +19 -0
  102. data/lib/ratatui_ruby/symbols.rb +435 -0
  103. data/lib/ratatui_ruby/synthetic_events.rb +106 -0
  104. data/lib/ratatui_ruby/table_state.rb +251 -0
  105. data/lib/ratatui_ruby/terminal/capabilities.rb +316 -0
  106. data/lib/ratatui_ruby/terminal/viewport.rb +80 -0
  107. data/lib/ratatui_ruby/terminal.rb +66 -0
  108. data/lib/ratatui_ruby/terminal_lifecycle.rb +303 -0
  109. data/lib/ratatui_ruby/terminal_lifecycle.rb.bak +197 -0
  110. data/lib/ratatui_ruby/test_helper/event_injection.rb +244 -0
  111. data/lib/ratatui_ruby/test_helper/global_state.rb +111 -0
  112. data/lib/ratatui_ruby/test_helper/snapshot.rb +568 -0
  113. data/lib/ratatui_ruby/test_helper/snapshots/axis_labels_alignment.ansi +24 -0
  114. data/lib/ratatui_ruby/test_helper/snapshots/axis_labels_alignment.txt +24 -0
  115. data/lib/ratatui_ruby/test_helper/snapshots/barchart_styled_label.ansi +5 -0
  116. data/lib/ratatui_ruby/test_helper/snapshots/barchart_styled_label.txt +5 -0
  117. data/lib/ratatui_ruby/test_helper/snapshots/chart_rendering.ansi +24 -0
  118. data/lib/ratatui_ruby/test_helper/snapshots/chart_rendering.txt +24 -0
  119. data/lib/ratatui_ruby/test_helper/snapshots/half_block_marker.ansi +12 -0
  120. data/lib/ratatui_ruby/test_helper/snapshots/half_block_marker.txt +12 -0
  121. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_bottom.ansi +12 -0
  122. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_bottom.txt +12 -0
  123. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_left.ansi +12 -0
  124. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_left.txt +12 -0
  125. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_right.ansi +12 -0
  126. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_right.txt +12 -0
  127. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_top.ansi +12 -0
  128. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_top.txt +12 -0
  129. data/lib/ratatui_ruby/test_helper/snapshots/my_snapshot.txt +1 -0
  130. data/lib/ratatui_ruby/test_helper/snapshots/styled_axis_title.ansi +10 -0
  131. data/lib/ratatui_ruby/test_helper/snapshots/styled_axis_title.txt +10 -0
  132. data/lib/ratatui_ruby/test_helper/snapshots/styled_dataset_name.ansi +10 -0
  133. data/lib/ratatui_ruby/test_helper/snapshots/styled_dataset_name.txt +10 -0
  134. data/lib/ratatui_ruby/test_helper/style_assertions.rb +449 -0
  135. data/lib/ratatui_ruby/test_helper/subprocess_timeout.rb +35 -0
  136. data/lib/ratatui_ruby/test_helper/terminal.rb +187 -0
  137. data/lib/ratatui_ruby/test_helper/test_doubles.rb +86 -0
  138. data/lib/ratatui_ruby/test_helper.rb +115 -0
  139. data/lib/ratatui_ruby/text/line.rb +245 -0
  140. data/lib/ratatui_ruby/text/span.rb +158 -0
  141. data/lib/ratatui_ruby/text.rb +99 -0
  142. data/lib/ratatui_ruby/tui/buffer_factories.rb +22 -0
  143. data/lib/ratatui_ruby/tui/canvas_factories.rb +149 -0
  144. data/lib/ratatui_ruby/tui/core.rb +67 -0
  145. data/lib/ratatui_ruby/tui/layout_factories.rb +153 -0
  146. data/lib/ratatui_ruby/tui/state_factories.rb +77 -0
  147. data/lib/ratatui_ruby/tui/style_factories.rb +22 -0
  148. data/lib/ratatui_ruby/tui/text_factories.rb +86 -0
  149. data/lib/ratatui_ruby/tui/widget_factories.rb +272 -0
  150. data/lib/ratatui_ruby/tui.rb +106 -0
  151. data/lib/ratatui_ruby/version.rb +12 -0
  152. data/lib/ratatui_ruby/widgets/bar_chart/bar.rb +51 -0
  153. data/lib/ratatui_ruby/widgets/bar_chart/bar_group.rb +29 -0
  154. data/lib/ratatui_ruby/widgets/bar_chart.rb +308 -0
  155. data/lib/ratatui_ruby/widgets/block.rb +266 -0
  156. data/lib/ratatui_ruby/widgets/calendar.rb +88 -0
  157. data/lib/ratatui_ruby/widgets/canvas.rb +297 -0
  158. data/lib/ratatui_ruby/widgets/cell.rb +59 -0
  159. data/lib/ratatui_ruby/widgets/center.rb +71 -0
  160. data/lib/ratatui_ruby/widgets/chart.rb +172 -0
  161. data/lib/ratatui_ruby/widgets/clear.rb +66 -0
  162. data/lib/ratatui_ruby/widgets/coerceable_widget.rb +77 -0
  163. data/lib/ratatui_ruby/widgets/cursor.rb +54 -0
  164. data/lib/ratatui_ruby/widgets/gauge.rb +146 -0
  165. data/lib/ratatui_ruby/widgets/line_gauge.rb +158 -0
  166. data/lib/ratatui_ruby/widgets/list.rb +252 -0
  167. data/lib/ratatui_ruby/widgets/list_item.rb +55 -0
  168. data/lib/ratatui_ruby/widgets/overlay.rb +55 -0
  169. data/lib/ratatui_ruby/widgets/paragraph.rb +113 -0
  170. data/lib/ratatui_ruby/widgets/ratatui_logo.rb +35 -0
  171. data/lib/ratatui_ruby/widgets/ratatui_mascot.rb +40 -0
  172. data/lib/ratatui_ruby/widgets/row.rb +123 -0
  173. data/lib/ratatui_ruby/widgets/scrollbar.rb +147 -0
  174. data/lib/ratatui_ruby/widgets/shape/label.rb +80 -0
  175. data/lib/ratatui_ruby/widgets/sparkline.rb +153 -0
  176. data/lib/ratatui_ruby/widgets/table.rb +213 -0
  177. data/lib/ratatui_ruby/widgets/tabs.rb +91 -0
  178. data/lib/ratatui_ruby/widgets.rb +43 -0
  179. data/lib/ratatui_ruby.rb +556 -0
  180. data/sig/examples/app_all_events/app.rbs +11 -0
  181. data/sig/examples/app_all_events/model/app_model.rbs +23 -0
  182. data/sig/examples/app_all_events/model/event_entry.rbs +23 -0
  183. data/sig/examples/app_all_events/model/timestamp.rbs +11 -0
  184. data/sig/examples/app_all_events/view/app_view.rbs +8 -0
  185. data/sig/examples/app_all_events/view/controls_view.rbs +6 -0
  186. data/sig/examples/app_all_events/view/counts_view.rbs +6 -0
  187. data/sig/examples/app_all_events/view/live_view.rbs +6 -0
  188. data/sig/examples/app_all_events/view/log_view.rbs +6 -0
  189. data/sig/examples/app_all_events/view.rbs +14 -0
  190. data/sig/examples/app_cli_rich_moments/app.rbs +12 -0
  191. data/sig/examples/app_color_picker/app.rbs +17 -0
  192. data/sig/examples/app_external_editor/app.rbs +12 -0
  193. data/sig/examples/app_login_form/app.rbs +11 -0
  194. data/sig/examples/app_stateful_interaction/app.rbs +39 -0
  195. data/sig/examples/verify_quickstart_dsl/app.rbs +17 -0
  196. data/sig/examples/verify_quickstart_lifecycle/app.rbs +17 -0
  197. data/sig/examples/verify_readme_usage/app.rbs +17 -0
  198. data/sig/examples/widget_block_demo/app.rbs +38 -0
  199. data/sig/examples/widget_box_demo/app.rbs +17 -0
  200. data/sig/examples/widget_calendar_demo/app.rbs +17 -0
  201. data/sig/examples/widget_cell_demo/app.rbs +17 -0
  202. data/sig/examples/widget_chart_demo/app.rbs +17 -0
  203. data/sig/examples/widget_gauge_demo/app.rbs +17 -0
  204. data/sig/examples/widget_layout_split/app.rbs +16 -0
  205. data/sig/examples/widget_line_gauge_demo/app.rbs +17 -0
  206. data/sig/examples/widget_list_demo/app.rbs +17 -0
  207. data/sig/examples/widget_map_demo/app.rbs +17 -0
  208. data/sig/examples/widget_popup_demo/app.rbs +17 -0
  209. data/sig/examples/widget_ratatui_logo_demo/app.rbs +17 -0
  210. data/sig/examples/widget_ratatui_mascot_demo/app.rbs +17 -0
  211. data/sig/examples/widget_rect/app.rbs +18 -0
  212. data/sig/examples/widget_render/app.rbs +16 -0
  213. data/sig/examples/widget_rich_text/app.rbs +17 -0
  214. data/sig/examples/widget_scroll_text/app.rbs +17 -0
  215. data/sig/examples/widget_scrollbar_demo/app.rbs +17 -0
  216. data/sig/examples/widget_sparkline_demo/app.rbs +16 -0
  217. data/sig/examples/widget_style_colors/app.rbs +20 -0
  218. data/sig/examples/widget_table_demo/app.rbs +17 -0
  219. data/sig/examples/widget_text_width/app.rbs +16 -0
  220. data/sig/generated/event_key_predicates.rbs +1348 -0
  221. data/sig/manifest.yaml +5 -0
  222. data/sig/patches/data.rbs +26 -0
  223. data/sig/patches/debugger__.rbs +8 -0
  224. data/sig/ratatui_ruby/backend/window_size.rbs +17 -0
  225. data/sig/ratatui_ruby/backend.rbs +12 -0
  226. data/sig/ratatui_ruby/buffer/cell.rbs +46 -0
  227. data/sig/ratatui_ruby/buffer.rbs +18 -0
  228. data/sig/ratatui_ruby/cell.rbs +44 -0
  229. data/sig/ratatui_ruby/clear.rbs +18 -0
  230. data/sig/ratatui_ruby/constraint.rbs +26 -0
  231. data/sig/ratatui_ruby/debug.rbs +45 -0
  232. data/sig/ratatui_ruby/draw.rbs +30 -0
  233. data/sig/ratatui_ruby/event.rbs +249 -0
  234. data/sig/ratatui_ruby/frame.rbs +23 -0
  235. data/sig/ratatui_ruby/interfaces.rbs +25 -0
  236. data/sig/ratatui_ruby/labs.rbs +90 -0
  237. data/sig/ratatui_ruby/layout/alignment.rbs +26 -0
  238. data/sig/ratatui_ruby/layout/constraint.rbs +39 -0
  239. data/sig/ratatui_ruby/layout/layout.rbs +45 -0
  240. data/sig/ratatui_ruby/layout/position.rbs +18 -0
  241. data/sig/ratatui_ruby/layout/rect.rbs +64 -0
  242. data/sig/ratatui_ruby/layout/size.rbs +18 -0
  243. data/sig/ratatui_ruby/list_state.rbs +23 -0
  244. data/sig/ratatui_ruby/output_guard.rbs +23 -0
  245. data/sig/ratatui_ruby/ratatui_ruby.rbs +113 -0
  246. data/sig/ratatui_ruby/rect.rbs +17 -0
  247. data/sig/ratatui_ruby/scrollbar_state.rbs +24 -0
  248. data/sig/ratatui_ruby/session.rbs +93 -0
  249. data/sig/ratatui_ruby/style/color.rbs +22 -0
  250. data/sig/ratatui_ruby/style/style.rbs +29 -0
  251. data/sig/ratatui_ruby/symbols.rbs +141 -0
  252. data/sig/ratatui_ruby/synthetic_events.rbs +24 -0
  253. data/sig/ratatui_ruby/table_state.rbs +27 -0
  254. data/sig/ratatui_ruby/terminal/capabilities.rbs +38 -0
  255. data/sig/ratatui_ruby/terminal/viewport.rbs +33 -0
  256. data/sig/ratatui_ruby/terminal_lifecycle.rbs +39 -0
  257. data/sig/ratatui_ruby/test_helper/event_injection.rbs +22 -0
  258. data/sig/ratatui_ruby/test_helper/snapshot.rbs +37 -0
  259. data/sig/ratatui_ruby/test_helper/style_assertions.rbs +77 -0
  260. data/sig/ratatui_ruby/test_helper/terminal.rbs +20 -0
  261. data/sig/ratatui_ruby/test_helper/test_doubles.rbs +32 -0
  262. data/sig/ratatui_ruby/test_helper.rbs +18 -0
  263. data/sig/ratatui_ruby/text/line.rbs +27 -0
  264. data/sig/ratatui_ruby/text/span.rbs +23 -0
  265. data/sig/ratatui_ruby/text.rbs +12 -0
  266. data/sig/ratatui_ruby/tui/buffer_factories.rbs +16 -0
  267. data/sig/ratatui_ruby/tui/canvas_factories.rbs +38 -0
  268. data/sig/ratatui_ruby/tui/core.rbs +23 -0
  269. data/sig/ratatui_ruby/tui/layout_factories.rbs +39 -0
  270. data/sig/ratatui_ruby/tui/state_factories.rbs +23 -0
  271. data/sig/ratatui_ruby/tui/style_factories.rbs +18 -0
  272. data/sig/ratatui_ruby/tui/text_factories.rbs +23 -0
  273. data/sig/ratatui_ruby/tui/widget_factories.rbs +138 -0
  274. data/sig/ratatui_ruby/tui.rbs +25 -0
  275. data/sig/ratatui_ruby/version.rbs +12 -0
  276. data/sig/ratatui_ruby/widgets/bar_chart.rbs +95 -0
  277. data/sig/ratatui_ruby/widgets/block.rbs +51 -0
  278. data/sig/ratatui_ruby/widgets/calendar.rbs +45 -0
  279. data/sig/ratatui_ruby/widgets/canvas.rbs +95 -0
  280. data/sig/ratatui_ruby/widgets/chart.rbs +91 -0
  281. data/sig/ratatui_ruby/widgets/coerceable_widget.rbs +26 -0
  282. data/sig/ratatui_ruby/widgets/gauge.rbs +44 -0
  283. data/sig/ratatui_ruby/widgets/line_gauge.rbs +48 -0
  284. data/sig/ratatui_ruby/widgets/list.rbs +63 -0
  285. data/sig/ratatui_ruby/widgets/misc.rbs +158 -0
  286. data/sig/ratatui_ruby/widgets/paragraph.rbs +45 -0
  287. data/sig/ratatui_ruby/widgets/row.rbs +43 -0
  288. data/sig/ratatui_ruby/widgets/scrollbar.rbs +53 -0
  289. data/sig/ratatui_ruby/widgets/shape/label.rbs +37 -0
  290. data/sig/ratatui_ruby/widgets/sparkline.rbs +45 -0
  291. data/sig/ratatui_ruby/widgets/table.rbs +78 -0
  292. data/sig/ratatui_ruby/widgets/tabs.rbs +44 -0
  293. data/sig/ratatui_ruby/widgets.rbs +16 -0
  294. data/vendor/goodcop/base.yml +1047 -0
  295. metadata +738 -0
@@ -0,0 +1,556 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
+ #++
7
+
8
+ require_relative "ratatui_ruby/version"
9
+
10
+ # Core types (mirrors ratatui Rust crate)
11
+ require_relative "ratatui_ruby/layout" # Layout::Rect, Layout::Constraint, Layout::Layout
12
+ require_relative "ratatui_ruby/style" # Style::Style
13
+ require_relative "ratatui_ruby/widgets" # Widgets::Block, Widgets::Paragraph, etc.
14
+ require_relative "ratatui_ruby/buffer" # Buffer::Cell (for inspection)
15
+ require_relative "ratatui_ruby/text" # Text::Span, Text::Line, Text.width
16
+ require_relative "ratatui_ruby/draw" # Draw commands
17
+ require_relative "ratatui_ruby/symbols" # Symbols::Shade, etc.
18
+ require_relative "ratatui_ruby/backend" # Backend::WindowSize
19
+ require_relative "ratatui_ruby/terminal/viewport" # Terminal::Viewport
20
+ require_relative "ratatui_ruby/terminal" # Terminal class
21
+
22
+ # Event types
23
+ require_relative "ratatui_ruby/event"
24
+
25
+ # Frame and state objects
26
+ require_relative "ratatui_ruby/frame"
27
+ require_relative "ratatui_ruby/list_state"
28
+ require_relative "ratatui_ruby/table_state"
29
+ require_relative "ratatui_ruby/scrollbar_state"
30
+
31
+ # Behavioral mixins
32
+ require_relative "ratatui_ruby/output_guard"
33
+ require_relative "ratatui_ruby/terminal_lifecycle"
34
+
35
+ # TUI facade (for external instantiation and caching)
36
+ require_relative "ratatui_ruby/tui"
37
+
38
+ # Synthetic events queue (for async synchronization)
39
+ require_relative "ratatui_ruby/synthetic_events"
40
+
41
+ # Precompiled gems store binaries in versioned subdirectories
42
+ begin
43
+ RUBY_VERSION =~ /(\d+\.\d+)/
44
+ require "ratatui_ruby/#{$1}/ratatui_ruby"
45
+ rescue LoadError
46
+ require "ratatui_ruby/ratatui_ruby"
47
+ end
48
+
49
+ # Debug mode (for Rust backtraces and diagnostic features)
50
+ # Loaded after native extension so _enable_rust_backtrace is defined
51
+ require_relative "ratatui_ruby/debug"
52
+
53
+ # Experimental lab features (RR_LABS env var)
54
+ require_relative "ratatui_ruby/labs"
55
+
56
+ # Main entry point for the library.
57
+ #
58
+ # Terminal UIs require low-level control using C/Rust and high-level abstraction in Ruby.
59
+ #
60
+ # This module bridges the gap. It provides the native methods to initialize the terminal, handle raw mode, and render the widget tree.
61
+ #
62
+ # Use `RatatuiRuby.run` to start your application.
63
+ module RatatuiRuby
64
+ # Base error class for RatatuiRuby.
65
+ #
66
+ # All library-specific exceptions inherit from this class.
67
+ # Catch this to handle any RatatuiRuby error generically.
68
+ #
69
+ # === Example
70
+ #
71
+ #--
72
+ # SPDX-SnippetBegin
73
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
74
+ # SPDX-License-Identifier: MIT-0
75
+ #++
76
+ # begin
77
+ # RatatuiRuby.run { |tui| ... }
78
+ # rescue RatatuiRuby::Error => e
79
+ # puts "RatatuiRuby error: #{e.message}"
80
+ # end
81
+ #--
82
+ # SPDX-SnippetEnd
83
+ #++
84
+ class Error < StandardError
85
+ # Operational failure during terminal I/O.
86
+ #
87
+ # Terminals are finnicky. I/O can fail. Backends can crash.
88
+ # These are runtime problems outside your control.
89
+ #
90
+ # This error signals the terminal operation itself failed.
91
+ # The library tried to do something with the terminal and couldn't.
92
+ #
93
+ # Catch this to handle terminal failures gracefully.
94
+ #
95
+ # === Example
96
+ #
97
+ #--
98
+ # SPDX-SnippetBegin
99
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
100
+ # SPDX-License-Identifier: MIT-0
101
+ #++
102
+ # begin
103
+ # RatatuiRuby.init_terminal
104
+ # rescue RatatuiRuby::Error::Terminal => e
105
+ # puts "Terminal failed: #{e.message}"
106
+ # end
107
+ #--
108
+ # SPDX-SnippetEnd
109
+ #++
110
+ class Terminal < Error; end
111
+
112
+ # Object lifetime violation.
113
+ #
114
+ # Some objects are only valid during specific scopes.
115
+ # Using them after their scope ends causes undefined behavior.
116
+ #
117
+ # This error prevents use-after-scope bugs.
118
+ # The object you're accessing is no longer valid.
119
+ #
120
+ # To resolve, ensure scoped objects are used only within their
121
+ # valid lifetime (e.g., inside the block where they're created).
122
+ #
123
+ # === Example
124
+ #
125
+ #--
126
+ # SPDX-SnippetBegin
127
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
128
+ # SPDX-License-Identifier: MIT-0
129
+ #++
130
+ # stored_frame = nil
131
+ # RatatuiRuby.draw { |frame| stored_frame = frame }
132
+ # stored_frame.area # => raises Error::Safety
133
+ #--
134
+ # SPDX-SnippetEnd
135
+ #++
136
+ class Safety < Error; end
137
+
138
+ # Invariant violation.
139
+ #
140
+ # The library enforces rules about valid states and contracts.
141
+ # Breaking these rules raises this error.
142
+ #
143
+ # Common causes:
144
+ # - Calling methods in the wrong order (e.g., <tt>init_terminal</tt> twice)
145
+ # - Callable return type mismatch (e.g., view returns <tt>nil</tt> instead of a widget)
146
+ #
147
+ # To resolve, check the method's documented contract. Ensure
148
+ # state preconditions are met and return types are correct.
149
+ #
150
+ # === Example
151
+ #
152
+ #--
153
+ # SPDX-SnippetBegin
154
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
155
+ # SPDX-License-Identifier: MIT-0
156
+ #++
157
+ # RatatuiRuby.init_terminal
158
+ # RatatuiRuby.init_terminal # => raises Error::Invariant
159
+ #--
160
+ # SPDX-SnippetEnd
161
+ #++
162
+ class Invariant < Error; end
163
+
164
+ # Framework bug.
165
+ #
166
+ # This error indicates a bug within the RatatuiRuby framework itself.
167
+ # If you encounter this, the framework is broken — please report it.
168
+ #
169
+ # Normal application errors use standard exceptions like ArgumentError.
170
+ # This exception class distinguishes "our bug" from "your bug".
171
+ class Internal < Error; end
172
+ end
173
+
174
+ # Mix in terminal lifecycle and output protection methods
175
+ extend OutputGuard
176
+ extend TerminalLifecycle
177
+
178
+ @experimental_warnings = true
179
+ @tui_session_active = false
180
+ @headless_mode = false
181
+ @deferred_warnings = [] #: Array[String]
182
+
183
+ class << self
184
+ ##
185
+ # :attr_accessor: experimental_warnings
186
+ # Whether to show warnings when using experimental features (default: true).
187
+ attr_accessor :experimental_warnings
188
+
189
+ private def queue_warning(message)
190
+ @deferred_warnings << message
191
+ end
192
+
193
+ private def flush_warnings
194
+ return if @deferred_warnings.empty?
195
+ @deferred_warnings.each { |msg| warn msg }
196
+ @deferred_warnings.clear
197
+ end
198
+
199
+ private def flush_panic_info
200
+ return unless Debug.rust_backtrace_enabled?
201
+ panic_info = _get_last_panic
202
+ return unless panic_info
203
+ warn panic_info
204
+ end
205
+ end
206
+
207
+ ##
208
+ # :singleton-method: inject_test_event
209
+ # Injects a mock event into the event queue for testing purposes.
210
+ # [event_type] "key" or "mouse"
211
+ # [data] a Hash containing event data
212
+ #
213
+ #--
214
+ # SPDX-SnippetBegin
215
+ # SPDX-FileCopyrightText: 2025 Kerrick Long
216
+ # SPDX-License-Identifier: MIT-0
217
+ #++
218
+ # inject_test_event("key", { code: "a" })
219
+ #
220
+ #--
221
+ # SPDX-SnippetEnd
222
+ #++
223
+ # (Native method implemented in Rust)
224
+
225
+ ##
226
+ # Warns about usage of an experimental feature unless warnings are suppressed.
227
+ #
228
+ # [feature_name] String name of the feature (e.g., "Paragraph#line_count")
229
+ #
230
+ # This warns only once per feature name per session.
231
+ def self.warn_experimental_feature(feature_name)
232
+ return unless experimental_warnings
233
+
234
+ @warned_features ||= {} #: Hash[String, bool]
235
+ return if @warned_features[feature_name]
236
+
237
+ message = "WARNING: #{feature_name} is an experimental feature and may change in future versions. Disable this warning with RatatuiRuby.experimental_warnings = false."
238
+ if terminal_active?
239
+ queue_warning(message)
240
+ else
241
+ warn message
242
+ end
243
+ @warned_features[feature_name] = true
244
+ end
245
+
246
+ # (Native methods implemented in Rust)
247
+ private_class_method :_init_terminal, :_restore_terminal, :_init_test_terminal, :_enable_rust_backtrace, :_get_last_panic
248
+
249
+ ##
250
+ # Enables full debug mode.
251
+ #
252
+ # Convenience alias for Debug.enable!.
253
+ #
254
+ # === Example
255
+ #
256
+ #--
257
+ # SPDX-SnippetBegin
258
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
259
+ # SPDX-License-Identifier: MIT-0
260
+ #++
261
+ # RatatuiRuby.debug_mode!
262
+ #
263
+ #--
264
+ # SPDX-SnippetEnd
265
+ #++
266
+ def self.debug_mode!
267
+ Debug.enable!
268
+ end
269
+
270
+ ##
271
+ # Draws the given UI node tree to the terminal.
272
+ #
273
+ # TUI applications need to render widgets to the screen. Rendering could
274
+ # happen all at once with a pre-built tree, or incrementally with direct
275
+ # frame access.
276
+ #
277
+ # This method handles both. Pass a tree for declarative rendering, or
278
+ # pass a block to manipulate the frame directly. The block receives a
279
+ # {Frame} object for imperative drawing.
280
+ #
281
+ # [tree] A widget tree (Widgets::Paragraph, Layout::Layout, etc.) to render. Optional if
282
+ #--
283
+ # SPDX-SnippetBegin
284
+ # SPDX-FileCopyrightText: 2025 Kerrick Long
285
+ # SPDX-License-Identifier: MIT-0
286
+ #++
287
+ # a block is given.
288
+ #
289
+ #--
290
+ # SPDX-SnippetEnd
291
+ #++
292
+ # === Examples
293
+ #
294
+ # Legacy declarative style (tree-based):
295
+ #
296
+ #--
297
+ # SPDX-SnippetBegin
298
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
299
+ # SPDX-License-Identifier: MIT-0
300
+ #++
301
+ # RatatuiRuby.draw(Widgets::Paragraph.new(text: "Hello"))
302
+ #
303
+ #--
304
+ # SPDX-SnippetEnd
305
+ #++
306
+ # New imperative style (block-based):
307
+ #
308
+ #--
309
+ # SPDX-SnippetBegin
310
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
311
+ # SPDX-License-Identifier: MIT-0
312
+ #++
313
+ # RatatuiRuby.draw do |frame|
314
+ # frame.render_widget(Widgets::Paragraph.new(text: "Hello"), frame.area)
315
+ # end
316
+ #
317
+ #--
318
+ # SPDX-SnippetEnd
319
+ #++
320
+ def self.draw(tree = nil, &block)
321
+ if tree && block
322
+ raise ArgumentError, "Cannot provide both a tree and a block to draw"
323
+ end
324
+ unless tree || block
325
+ raise ArgumentError, "Must provide either a tree or a block to draw"
326
+ end
327
+
328
+ if tree
329
+ _draw(tree)
330
+ elsif block
331
+ # Wrap user block to flush A11Y capture after user code
332
+ if Labs.enabled?(:a11y)
333
+ _draw do |frame|
334
+ block.call(frame)
335
+ frame.flush_a11y_capture
336
+ end
337
+ else
338
+ _draw(&block)
339
+ end
340
+ end
341
+ end
342
+
343
+ # (Native method _draw implemented in Rust)
344
+ private_class_method :_draw
345
+
346
+ ##
347
+ # Checks for user input.
348
+ #
349
+ # Interactive apps must respond to input. Loops need to poll without burning CPU.
350
+ #
351
+ # This method checks for an event. It returns the event if one is found. It returns {RatatuiRuby::Event::None} if the timeout expires.
352
+ #
353
+ # [timeout] Float seconds to wait (default: 0.016).
354
+ #--
355
+ # SPDX-SnippetBegin
356
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
357
+ # SPDX-License-Identifier: MIT-0
358
+ #++
359
+ # Pass <tt>nil</tt> to block indefinitely (wait forever).
360
+ # Pass <tt>0.0</tt> for a non-blocking check.
361
+ #
362
+ #--
363
+ # SPDX-SnippetEnd
364
+ #++
365
+ # === Examples
366
+ #
367
+ #--
368
+ # SPDX-SnippetBegin
369
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
370
+ # SPDX-License-Identifier: MIT-0
371
+ #++
372
+ # # Standard loop (approx 60 FPS)
373
+ # event = RatatuiRuby.poll_event
374
+ #
375
+ # # Block until event (pauses execution)
376
+ # event = RatatuiRuby.poll_event(timeout: nil)
377
+ #
378
+ # # Non-blocking check (returns immediately)
379
+ # event = RatatuiRuby.poll_event(timeout: 0.0)
380
+ #
381
+ #--
382
+ # SPDX-SnippetEnd
383
+ #++
384
+ def self.poll_event(timeout: 0.016)
385
+ raise ArgumentError, "timeout must be non-negative" if timeout && timeout < 0
386
+
387
+ raw = _poll_event(timeout)
388
+ return Event::None.new.freeze if raw.nil?
389
+
390
+ case raw[:type]
391
+ when :key
392
+ Event::Key.new(
393
+ code: raw[:code],
394
+ modifiers: (raw[:modifiers] || []).freeze,
395
+ kind: raw[:kind] || :standard
396
+ ).freeze
397
+ when :mouse
398
+ Event::Mouse.new(
399
+ kind: raw[:kind].to_s,
400
+ x: raw[:x],
401
+ y: raw[:y],
402
+ button: raw[:button].to_s,
403
+ modifiers: (raw[:modifiers] || []).freeze
404
+ ).freeze
405
+ when :resize
406
+ Event::Resize.new(width: raw[:width], height: raw[:height]).freeze
407
+ when :paste
408
+ Event::Paste.new(content: raw[:content]).freeze
409
+ when :focus_gained
410
+ Event::FocusGained.new.freeze
411
+ when :focus_lost
412
+ Event::FocusLost.new.freeze
413
+ when :sync
414
+ Event::Sync.new.freeze
415
+ else
416
+ # Return None for unknown event types
417
+ Event::None.new.freeze
418
+ end
419
+ end
420
+
421
+ # (Native method _poll_event implemented in Rust)
422
+ private_class_method :_poll_event
423
+
424
+ ##
425
+ # Inspects the terminal buffer at specific coordinates.
426
+ #
427
+ # When writing tests, you need to verify that your widget drew the correct characters and styles.
428
+ # This method provides deep inspection of the cell's state (symbol, colors, modifiers).
429
+ #
430
+ # Returns a {Buffer::Cell} object.
431
+ #
432
+ # Values depend on what the backend has rendered. If nothing has been rendered to a cell, it may contain defaults (empty symbol, nil colors).
433
+ #
434
+ # === Example
435
+ #
436
+ #--
437
+ # SPDX-SnippetBegin
438
+ # SPDX-FileCopyrightText: 2025 Kerrick Long
439
+ # SPDX-License-Identifier: MIT-0
440
+ #++
441
+ # cell = RatatuiRuby.get_cell_at(10, 5)
442
+ # expect(cell.symbol).to eq("X")
443
+ # expect(cell.fg).to eq(:red)
444
+ # expect(cell).to be_bold
445
+ #
446
+ #--
447
+ # SPDX-SnippetEnd
448
+ #++
449
+ def self.get_cell_at(x, y)
450
+ raw = _get_cell_at(x, y)
451
+ Buffer::Cell.new(
452
+ char: raw["char"],
453
+ fg: raw["fg"],
454
+ bg: raw["bg"],
455
+ underline_color: raw["underline_color"],
456
+ modifiers: raw["modifiers"] || []
457
+ )
458
+ end
459
+
460
+ ##
461
+ # Returns the current terminal viewport area.
462
+ #
463
+ # In inline viewports, this returns the viewport dimensions.
464
+ # In fullscreen mode, this returns the full terminal size.
465
+ #
466
+ # @return [Layout::Rect] The rendering viewport area
467
+ def self.get_viewport_area
468
+ raw = _get_terminal_area
469
+ Layout::Rect.new(
470
+ x: raw["x"],
471
+ y: raw["y"],
472
+ width: raw["width"],
473
+ height: raw["height"]
474
+ )
475
+ end
476
+
477
+ ##
478
+ # Returns the full terminal backend size.
479
+ #
480
+ # This is always the full terminal dimensions, regardless of viewport mode.
481
+ #
482
+ # === Example
483
+ #
484
+ #--
485
+ # SPDX-SnippetBegin
486
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
487
+ # SPDX-License-Identifier: MIT-0
488
+ #++
489
+ # size = RatatuiRuby.get_terminal_size
490
+ # puts "Terminal: #{size.width}x#{size.height}"
491
+ #
492
+ #--
493
+ # SPDX-SnippetEnd
494
+ #++
495
+ # @return [Layout::Rect] The full terminal size
496
+ def self.get_terminal_size
497
+ raw = _get_terminal_size
498
+ Layout::Rect.new(
499
+ x: raw["x"],
500
+ y: raw["y"],
501
+ width: raw["width"],
502
+ height: raw["height"]
503
+ )
504
+ end
505
+
506
+ # Ruby-idiomatic aliases (TIMTOWTDI)
507
+ class << self
508
+ # Aliases for get_terminal_size (full backend size)
509
+ alias get_terminal_area get_terminal_size
510
+ alias terminal_area get_terminal_size
511
+ alias terminal_size get_terminal_size
512
+ # Aliases for get_viewport_area (viewport rendering area)
513
+ alias get_viewport_size get_viewport_area
514
+ alias viewport_area get_viewport_area
515
+ alias viewport_size get_viewport_area
516
+ end
517
+
518
+ ##
519
+ # Number of frames drawn since terminal initialization.
520
+ #
521
+ # TUI applications track render cycles for animations, FPS counters, or
522
+ # debugging. Manually counting draws is error-prone and clutters app logic.
523
+ #
524
+ # This method queries the terminal's internal frame counter. It starts at 0
525
+ # when the terminal initializes and increments by 1 after each successful
526
+ # draw. Restoring and re-initializing resets the counter.
527
+ #
528
+ # Raises RatatuiRuby::Error::Invariant if terminal not initialized.
529
+ def self.frame_count
530
+ _frame_count
531
+ end
532
+
533
+ # (Native methods implemented in Rust)
534
+ private_class_method :_get_cell_at, :_get_terminal_size, :_frame_count
535
+
536
+ # Hide native Layout._split helper
537
+ Layout::Layout.singleton_class.__send__(:private, :_split)
538
+
539
+ # Raw Terminal bindings - use public wrappers (they have timeout guards)
540
+ Terminal.singleton_class.__send__(:private, :_available_color_count)
541
+ Terminal.singleton_class.__send__(:private, :_supports_keyboard_enhancement)
542
+
543
+ # --- Terminal Safety Hooks ---
544
+ # These ensure the terminal is restored even on unexpected exits.
545
+
546
+ at_exit do
547
+ restore_terminal if terminal_active?
548
+ end
549
+
550
+ %i[INT TERM].each do |signal|
551
+ trap(signal) do
552
+ restore_terminal if terminal_active?
553
+ exit(128 + Signal.list[signal.to_s])
554
+ end
555
+ end
556
+ end
@@ -0,0 +1,11 @@
1
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
+ #
3
+ # SPDX-License-Identifier: AGPL-3.0-or-later
4
+
5
+ class AppAllEvents
6
+ # @public
7
+ def self.new: () -> AppAllEvents
8
+
9
+ # @public
10
+ def run: () -> void
11
+ end
@@ -0,0 +1,23 @@
1
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ # MVU application model for the All Events example.
5
+ class AppModel < Data
6
+ HIGHLIGHT_DURATION_MS: Integer
7
+
8
+ attr_reader entries: Array[EventEntry]
9
+ attr_reader focused: bool
10
+ attr_reader window_size: [Integer, Integer]
11
+ attr_reader lit_types: Hash[Symbol, Timestamp]
12
+ attr_reader none_count: Integer
13
+ attr_reader color_cycle_index: Integer
14
+
15
+ def self.initial: () -> instance
16
+ def count: (Symbol type) -> Integer
17
+ def sub_counts: (Symbol type) -> Hash[String, Integer]
18
+ def lit?: (Symbol type) -> bool
19
+ def visible: (Integer max_entries) -> Array[EventEntry]
20
+ def empty?: () -> bool
21
+ def live_event: (Symbol type) -> { time: Time, description: String }?
22
+ def next_color: () -> Symbol
23
+ end
@@ -0,0 +1,23 @@
1
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ # Type alias for any Event subtype.
5
+ type event_type = RatatuiRuby::Event::Key
6
+ | RatatuiRuby::Event::Mouse
7
+ | RatatuiRuby::Event::Resize
8
+ | RatatuiRuby::Event::Paste
9
+ | RatatuiRuby::Event::FocusGained
10
+ | RatatuiRuby::Event::FocusLost
11
+ | RatatuiRuby::Event::None
12
+
13
+ class EventEntry < Data
14
+ attr_reader event: event_type
15
+ attr_reader color: Symbol
16
+ attr_reader timestamp: Timestamp
17
+
18
+ def self.create: (event_type event, Symbol color, Timestamp timestamp) -> instance
19
+ def type: () -> Symbol
20
+ def description: () -> String
21
+ def matches_type?: (Symbol check_type) -> bool
22
+ def live_type: () -> Symbol
23
+ end
@@ -0,0 +1,11 @@
1
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ class Timestamp < Data
5
+ attr_reader milliseconds: Integer
6
+
7
+ def self.now: () -> instance
8
+ def self.current: () -> Integer
9
+ def elapsed?: (Integer duration_ms) -> bool
10
+ def self.new: (?milliseconds: _ToI) -> instance
11
+ end
@@ -0,0 +1,8 @@
1
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ class View::App
5
+ include View::_View
6
+
7
+ def initialize: () -> void
8
+ end
@@ -0,0 +1,6 @@
1
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ class View::Controls
5
+ include View::_View
6
+ end
@@ -0,0 +1,6 @@
1
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ class View::Counts
5
+ include View::_View
6
+ end
@@ -0,0 +1,6 @@
1
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ class View::Live
5
+ include View::_View
6
+ end
@@ -0,0 +1,6 @@
1
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ class View::Log
5
+ include View::_View
6
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: AGPL-3.0-or-later
6
+ #++
7
+
8
+ # SPDX-License-Identifier: AGPL-3.0-or-later
9
+
10
+ module View
11
+ interface _View
12
+ def call: (AppModel model, RatatuiRuby::TUI tui, RatatuiRuby::Frame frame, RatatuiRuby::Layout::Rect area) -> void
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ #--
2
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
+ # SPDX-License-Identifier: LGPL-3.0-or-later
4
+ #++
5
+
6
+ class AppCliRichMoments
7
+ # @public
8
+ def self.new: () -> AppCliRichMoments
9
+
10
+ # @public
11
+ def run: () -> void
12
+ end