ratatui_ruby 1.4.0-x86_64-linux

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