ratatui_ruby 0.4.0 → 0.5.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 (351) hide show
  1. checksums.yaml +4 -4
  2. data/.builds/ruby-3.2.yml +1 -1
  3. data/.builds/ruby-3.3.yml +1 -1
  4. data/.builds/ruby-3.4.yml +1 -1
  5. data/.builds/ruby-4.0.0.yml +1 -1
  6. data/AGENTS.md +87 -171
  7. data/CHANGELOG.md +38 -1
  8. data/README.md +8 -3
  9. data/REUSE.toml +20 -0
  10. data/doc/application_architecture.md +105 -45
  11. data/doc/application_testing.md +5 -3
  12. data/doc/contributors/design/ruby_frontend.md +9 -5
  13. data/doc/contributors/developing_examples.md +76 -18
  14. data/doc/contributors/documentation_style.md +7 -0
  15. data/doc/contributors/index.md +2 -0
  16. data/doc/event_handling.md +10 -4
  17. data/doc/images/app_all_events.png +0 -0
  18. data/doc/images/app_color_picker.png +0 -0
  19. data/doc/images/verify_readme_usage.png +0 -0
  20. data/doc/images/widget_barchart_demo.png +0 -0
  21. data/doc/images/widget_block_padding.png +0 -0
  22. data/doc/images/widget_block_titles.png +0 -0
  23. data/doc/images/widget_box_demo.png +0 -0
  24. data/doc/images/widget_calendar_demo.png +0 -0
  25. data/doc/images/widget_cell_demo.png +0 -0
  26. data/doc/images/widget_chart_demo.png +0 -0
  27. data/doc/images/widget_gauge_demo.png +0 -0
  28. data/doc/images/widget_layout_split.png +0 -0
  29. data/doc/images/widget_line_gauge_demo.png +0 -0
  30. data/doc/images/widget_list_demo.png +0 -0
  31. data/doc/images/widget_ratatui_logo_demo.png +0 -0
  32. data/doc/images/widget_ratatui_mascot_demo.png +0 -0
  33. data/doc/images/widget_render.png +0 -0
  34. data/doc/images/widget_scrollbar_demo.png +0 -0
  35. data/doc/images/widget_sparkline_demo.png +0 -0
  36. data/doc/images/widget_style_colors.png +0 -0
  37. data/doc/images/widget_table_flex.png +0 -0
  38. data/doc/images/widget_tabs_demo.png +0 -0
  39. data/doc/interactive_design.md +25 -30
  40. data/doc/quickstart.md +147 -120
  41. data/examples/app_all_events/README.md +81 -0
  42. data/examples/app_all_events/app.rb +93 -0
  43. data/examples/app_all_events/model/event_color_cycle.rb +41 -0
  44. data/examples/app_all_events/model/event_entry.rb +75 -0
  45. data/examples/app_all_events/model/events.rb +180 -0
  46. data/examples/app_all_events/model/highlight.rb +57 -0
  47. data/examples/app_all_events/model/timestamp.rb +54 -0
  48. data/examples/app_all_events/test/snapshots/after_focus_lost.txt +24 -0
  49. data/examples/app_all_events/test/snapshots/after_focus_regained.txt +24 -0
  50. data/examples/app_all_events/test/snapshots/after_horizontal_resize.txt +24 -0
  51. data/examples/app_all_events/test/snapshots/after_key_a.txt +24 -0
  52. data/examples/app_all_events/test/snapshots/after_key_ctrl_x.txt +24 -0
  53. data/examples/app_all_events/test/snapshots/after_mouse_click.txt +24 -0
  54. data/examples/app_all_events/test/snapshots/after_mouse_drag.txt +24 -0
  55. data/examples/app_all_events/test/snapshots/after_multiple_events.txt +24 -0
  56. data/examples/app_all_events/test/snapshots/after_paste.txt +24 -0
  57. data/examples/app_all_events/test/snapshots/after_resize.txt +24 -0
  58. data/examples/app_all_events/test/snapshots/after_right_click.txt +24 -0
  59. data/examples/app_all_events/test/snapshots/after_vertical_resize.txt +24 -0
  60. data/examples/app_all_events/test/snapshots/initial_state.txt +24 -0
  61. data/examples/app_all_events/view/app_view.rb +78 -0
  62. data/examples/app_all_events/view/controls_view.rb +50 -0
  63. data/examples/app_all_events/view/counts_view.rb +55 -0
  64. data/examples/app_all_events/view/live_view.rb +69 -0
  65. data/examples/app_all_events/view/log_view.rb +60 -0
  66. data/examples/app_all_events/view.rb +7 -0
  67. data/examples/app_all_events/view_state.rb +42 -0
  68. data/examples/app_color_picker/README.md +94 -0
  69. data/examples/app_color_picker/app.rb +112 -0
  70. data/examples/app_color_picker/clipboard.rb +84 -0
  71. data/examples/app_color_picker/color.rb +191 -0
  72. data/examples/app_color_picker/copy_dialog.rb +170 -0
  73. data/examples/app_color_picker/harmony.rb +56 -0
  74. data/examples/app_color_picker/input.rb +142 -0
  75. data/examples/app_color_picker/palette.rb +80 -0
  76. data/examples/app_color_picker/scene.rb +201 -0
  77. data/examples/{login_form → app_login_form}/app.rb +39 -42
  78. data/examples/{map_demo → app_map_demo}/app.rb +24 -21
  79. data/examples/{table_select → app_table_select}/app.rb +68 -65
  80. data/examples/{quickstart_dsl → verify_quickstart_dsl}/app.rb +15 -6
  81. data/examples/verify_quickstart_layout/app.rb +69 -0
  82. data/examples/{quickstart_lifecycle → verify_quickstart_lifecycle}/app.rb +19 -10
  83. data/examples/verify_readme_usage/app.rb +34 -0
  84. data/examples/widget_barchart_demo/app.rb +238 -0
  85. data/examples/{block_padding → widget_block_padding}/app.rb +17 -13
  86. data/examples/{block_titles → widget_block_titles}/app.rb +25 -17
  87. data/examples/{box_demo → widget_box_demo}/app.rb +99 -65
  88. data/examples/widget_calendar_demo/app.rb +109 -0
  89. data/examples/widget_cell_demo/app.rb +104 -0
  90. data/examples/widget_chart_demo/app.rb +213 -0
  91. data/examples/widget_gauge_demo/app.rb +212 -0
  92. data/examples/widget_layout_split/app.rb +246 -0
  93. data/examples/widget_line_gauge_demo/app.rb +217 -0
  94. data/examples/widget_list_demo/app.rb +382 -0
  95. data/examples/widget_list_styles/app.rb +141 -0
  96. data/examples/widget_popup_demo/app.rb +104 -0
  97. data/examples/widget_ratatui_logo_demo/app.rb +103 -0
  98. data/examples/widget_ratatui_mascot_demo/app.rb +93 -0
  99. data/examples/widget_rect/app.rb +205 -0
  100. data/examples/widget_render/app.rb +184 -0
  101. data/examples/widget_rich_text/app.rb +137 -0
  102. data/examples/widget_scroll_text/app.rb +108 -0
  103. data/examples/widget_scrollbar_demo/app.rb +153 -0
  104. data/examples/widget_sparkline_demo/app.rb +274 -0
  105. data/examples/widget_style_colors/app.rb +19 -21
  106. data/examples/widget_table_flex/app.rb +95 -0
  107. data/examples/widget_tabs_demo/app.rb +167 -0
  108. data/ext/ratatui_ruby/Cargo.lock +1 -1
  109. data/ext/ratatui_ruby/Cargo.toml +1 -1
  110. data/ext/ratatui_ruby/src/events.rs +121 -36
  111. data/ext/ratatui_ruby/src/frame.rs +115 -0
  112. data/ext/ratatui_ruby/src/lib.rs +79 -26
  113. data/ext/ratatui_ruby/src/rendering.rs +8 -4
  114. data/ext/ratatui_ruby/src/style.rs +138 -57
  115. data/ext/ratatui_ruby/src/terminal.rs +5 -9
  116. data/ext/ratatui_ruby/src/text.rs +13 -6
  117. data/ext/ratatui_ruby/src/widgets/barchart.rs +56 -54
  118. data/ext/ratatui_ruby/src/widgets/block.rs +7 -6
  119. data/ext/ratatui_ruby/src/widgets/canvas.rs +21 -3
  120. data/ext/ratatui_ruby/src/widgets/chart.rs +20 -10
  121. data/ext/ratatui_ruby/src/widgets/layout.rs +9 -4
  122. data/ext/ratatui_ruby/src/widgets/list.rs +32 -9
  123. data/ext/ratatui_ruby/src/widgets/overlay.rs +2 -1
  124. data/ext/ratatui_ruby/src/widgets/paragraph.rs +1 -1
  125. data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +19 -8
  126. data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +17 -10
  127. data/ext/ratatui_ruby/src/widgets/scrollbar.rs +4 -2
  128. data/ext/ratatui_ruby/src/widgets/sparkline.rs +14 -11
  129. data/ext/ratatui_ruby/src/widgets/table.rs +8 -4
  130. data/ext/ratatui_ruby/src/widgets/tabs.rs +11 -11
  131. data/lib/ratatui_ruby/cell.rb +3 -3
  132. data/lib/ratatui_ruby/event/key.rb +1 -1
  133. data/lib/ratatui_ruby/event/none.rb +43 -0
  134. data/lib/ratatui_ruby/event.rb +56 -4
  135. data/lib/ratatui_ruby/frame.rb +87 -0
  136. data/lib/ratatui_ruby/schema/bar_chart/bar.rb +11 -11
  137. data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +1 -5
  138. data/lib/ratatui_ruby/schema/bar_chart.rb +217 -217
  139. data/lib/ratatui_ruby/schema/block.rb +163 -168
  140. data/lib/ratatui_ruby/schema/calendar.rb +66 -67
  141. data/lib/ratatui_ruby/schema/canvas.rb +63 -63
  142. data/lib/ratatui_ruby/schema/center.rb +46 -46
  143. data/lib/ratatui_ruby/schema/chart.rb +135 -143
  144. data/lib/ratatui_ruby/schema/clear.rb +42 -42
  145. data/lib/ratatui_ruby/schema/constraint.rb +76 -76
  146. data/lib/ratatui_ruby/schema/cursor.rb +25 -25
  147. data/lib/ratatui_ruby/schema/gauge.rb +53 -53
  148. data/lib/ratatui_ruby/schema/layout.rb +87 -87
  149. data/lib/ratatui_ruby/schema/line_gauge.rb +62 -62
  150. data/lib/ratatui_ruby/schema/list.rb +86 -84
  151. data/lib/ratatui_ruby/schema/overlay.rb +31 -31
  152. data/lib/ratatui_ruby/schema/paragraph.rb +80 -80
  153. data/lib/ratatui_ruby/schema/ratatui_logo.rb +10 -6
  154. data/lib/ratatui_ruby/schema/ratatui_mascot.rb +10 -5
  155. data/lib/ratatui_ruby/schema/rect.rb +60 -60
  156. data/lib/ratatui_ruby/schema/scrollbar.rb +119 -119
  157. data/lib/ratatui_ruby/schema/shape/label.rb +1 -1
  158. data/lib/ratatui_ruby/schema/sparkline.rb +111 -110
  159. data/lib/ratatui_ruby/schema/style.rb +46 -46
  160. data/lib/ratatui_ruby/schema/table.rb +112 -119
  161. data/lib/ratatui_ruby/schema/tabs.rb +66 -67
  162. data/lib/ratatui_ruby/session/autodoc.rb +417 -0
  163. data/lib/ratatui_ruby/session.rb +40 -23
  164. data/lib/ratatui_ruby/test_helper.rb +185 -19
  165. data/lib/ratatui_ruby/version.rb +1 -1
  166. data/lib/ratatui_ruby.rb +65 -39
  167. data/{examples/sparkline_demo → sig/examples/app_all_events}/app.rbs +3 -2
  168. data/sig/examples/app_all_events/model/event_entry.rbs +16 -0
  169. data/sig/examples/app_all_events/model/events.rbs +15 -0
  170. data/sig/examples/app_all_events/model/timestamp.rbs +11 -0
  171. data/sig/examples/app_all_events/view/app_view.rbs +8 -0
  172. data/sig/examples/app_all_events/view/controls_view.rbs +6 -0
  173. data/sig/examples/app_all_events/view/counts_view.rbs +6 -0
  174. data/sig/examples/app_all_events/view/live_view.rbs +6 -0
  175. data/sig/examples/app_all_events/view/log_view.rbs +6 -0
  176. data/sig/examples/app_all_events/view.rbs +8 -0
  177. data/sig/examples/app_all_events/view_state.rbs +15 -0
  178. data/{examples/list_demo → sig/examples/app_color_picker}/app.rbs +2 -2
  179. data/sig/examples/app_login_form/app.rbs +11 -0
  180. data/sig/examples/app_map_demo/app.rbs +11 -0
  181. data/sig/examples/app_table_select/app.rbs +11 -0
  182. data/sig/examples/verify_quickstart_dsl/app.rbs +11 -0
  183. data/sig/examples/verify_quickstart_lifecycle/app.rbs +11 -0
  184. data/sig/examples/verify_readme_usage/app.rbs +11 -0
  185. data/sig/examples/widget_block_padding/app.rbs +11 -0
  186. data/sig/examples/widget_block_titles/app.rbs +11 -0
  187. data/sig/examples/widget_box_demo/app.rbs +11 -0
  188. data/sig/examples/widget_calendar_demo/app.rbs +11 -0
  189. data/sig/examples/widget_cell_demo/app.rbs +11 -0
  190. data/sig/examples/widget_chart_demo/app.rbs +11 -0
  191. data/{examples/gauge_demo → sig/examples/widget_gauge_demo}/app.rbs +4 -0
  192. data/sig/examples/widget_layout_split/app.rbs +10 -0
  193. data/sig/examples/widget_line_gauge_demo/app.rbs +11 -0
  194. data/sig/examples/widget_list_demo/app.rbs +12 -0
  195. data/sig/examples/widget_list_styles/app.rbs +11 -0
  196. data/sig/examples/widget_popup_demo/app.rbs +11 -0
  197. data/sig/examples/widget_ratatui_logo_demo/app.rbs +11 -0
  198. data/sig/examples/widget_ratatui_mascot_demo/app.rbs +11 -0
  199. data/sig/examples/widget_rect/app.rbs +12 -0
  200. data/sig/examples/widget_render/app.rbs +10 -0
  201. data/sig/examples/widget_rich_text/app.rbs +11 -0
  202. data/sig/examples/widget_scroll_text/app.rbs +11 -0
  203. data/sig/examples/widget_scrollbar_demo/app.rbs +11 -0
  204. data/sig/examples/widget_sparkline_demo/app.rbs +10 -0
  205. data/{examples → sig/examples}/widget_style_colors/app.rbs +1 -1
  206. data/sig/examples/widget_table_flex/app.rbs +11 -0
  207. data/sig/ratatui_ruby/frame.rbs +9 -0
  208. data/sig/ratatui_ruby/ratatui_ruby.rbs +3 -2
  209. data/sig/ratatui_ruby/schema/draw.rbs +4 -0
  210. data/sig/ratatui_ruby/schema/layout.rbs +1 -1
  211. data/sig/ratatui_ruby/session.rbs +94 -0
  212. data/tasks/autodoc/inventory.rb +61 -0
  213. data/tasks/autodoc/member.rb +56 -0
  214. data/tasks/autodoc/name.rb +19 -0
  215. data/tasks/autodoc/notice.rb +26 -0
  216. data/tasks/autodoc/rbs.rb +38 -0
  217. data/tasks/autodoc/rdoc.rb +45 -0
  218. data/tasks/autodoc.rake +47 -0
  219. data/tasks/bump/history.rb +2 -2
  220. data/tasks/doc.rake +600 -6
  221. data/tasks/example_viewer.html.erb +172 -0
  222. data/tasks/lint.rake +8 -4
  223. data/tasks/resources/index.html.erb +6 -0
  224. data/tasks/sourcehut.rake +4 -4
  225. data/tasks/terminal_preview/app_screenshot.rb +1 -3
  226. data/tasks/terminal_preview/crash_report.rb +7 -9
  227. data/tasks/terminal_preview/launcher_script.rb +4 -6
  228. data/tasks/terminal_preview/preview_collection.rb +4 -6
  229. data/tasks/terminal_preview/safety_confirmation.rb +3 -5
  230. data/tasks/terminal_preview/saved_screenshot.rb +7 -9
  231. data/tasks/terminal_preview/terminal_window.rb +7 -9
  232. data/tasks/test.rake +1 -1
  233. data/tasks/website/index_page.rb +3 -3
  234. data/tasks/website/version.rb +10 -10
  235. data/tasks/website/version_menu.rb +10 -12
  236. data/tasks/website/versioned_documentation.rb +49 -17
  237. data/tasks/website/website.rb +6 -8
  238. data/tasks/website.rake +4 -4
  239. metadata +156 -125
  240. data/LICENSES/BSD-2-Clause.txt +0 -9
  241. data/doc/contributors/better_dx.md +0 -543
  242. data/doc/contributors/example_analysis.md +0 -82
  243. data/doc/images/all_events.png +0 -0
  244. data/doc/images/block_padding.png +0 -0
  245. data/doc/images/block_titles.png +0 -0
  246. data/doc/images/box_demo.png +0 -0
  247. data/doc/images/calendar_demo.png +0 -0
  248. data/doc/images/cell_demo.png +0 -0
  249. data/doc/images/chart_demo.png +0 -0
  250. data/doc/images/flex_layout.png +0 -0
  251. data/doc/images/gauge_demo.png +0 -0
  252. data/doc/images/line_gauge_demo.png +0 -0
  253. data/doc/images/list_demo.png +0 -0
  254. data/doc/images/readme_usage.png +0 -0
  255. data/doc/images/scrollbar_demo.png +0 -0
  256. data/doc/images/sparkline_demo.png +0 -0
  257. data/doc/images/table_flex.png +0 -0
  258. data/examples/all_events/app.rb +0 -169
  259. data/examples/all_events/app.rbs +0 -7
  260. data/examples/all_events/test_app.rb +0 -139
  261. data/examples/analytics/app.rb +0 -258
  262. data/examples/analytics/app.rbs +0 -7
  263. data/examples/analytics/test_app.rb +0 -132
  264. data/examples/block_padding/app.rbs +0 -7
  265. data/examples/block_padding/test_app.rb +0 -31
  266. data/examples/block_titles/app.rbs +0 -7
  267. data/examples/block_titles/test_app.rb +0 -34
  268. data/examples/box_demo/app.rbs +0 -7
  269. data/examples/box_demo/test_app.rb +0 -88
  270. data/examples/calendar_demo/app.rb +0 -101
  271. data/examples/calendar_demo/app.rbs +0 -7
  272. data/examples/calendar_demo/test_app.rb +0 -108
  273. data/examples/cell_demo/app.rb +0 -108
  274. data/examples/cell_demo/app.rbs +0 -7
  275. data/examples/cell_demo/test_app.rb +0 -36
  276. data/examples/chart_demo/app.rb +0 -203
  277. data/examples/chart_demo/app.rbs +0 -7
  278. data/examples/chart_demo/test_app.rb +0 -102
  279. data/examples/custom_widget/app.rb +0 -51
  280. data/examples/custom_widget/app.rbs +0 -7
  281. data/examples/custom_widget/test_app.rb +0 -30
  282. data/examples/flex_layout/app.rb +0 -156
  283. data/examples/flex_layout/app.rbs +0 -7
  284. data/examples/flex_layout/test_app.rb +0 -65
  285. data/examples/gauge_demo/app.rb +0 -182
  286. data/examples/gauge_demo/test_app.rb +0 -120
  287. data/examples/hit_test/app.rb +0 -175
  288. data/examples/hit_test/app.rbs +0 -7
  289. data/examples/hit_test/test_app.rb +0 -102
  290. data/examples/line_gauge_demo/app.rb +0 -190
  291. data/examples/line_gauge_demo/app.rbs +0 -7
  292. data/examples/line_gauge_demo/test_app.rb +0 -129
  293. data/examples/list_demo/app.rb +0 -253
  294. data/examples/list_demo/test_app.rb +0 -237
  295. data/examples/list_styles/app.rb +0 -140
  296. data/examples/list_styles/app.rbs +0 -7
  297. data/examples/list_styles/test_app.rb +0 -157
  298. data/examples/login_form/app.rbs +0 -7
  299. data/examples/login_form/test_app.rb +0 -51
  300. data/examples/map_demo/app.rbs +0 -7
  301. data/examples/map_demo/test_app.rb +0 -149
  302. data/examples/mouse_events/app.rb +0 -97
  303. data/examples/mouse_events/app.rbs +0 -7
  304. data/examples/mouse_events/test_app.rb +0 -53
  305. data/examples/popup_demo/app.rb +0 -103
  306. data/examples/popup_demo/app.rbs +0 -7
  307. data/examples/popup_demo/test_app.rb +0 -54
  308. data/examples/quickstart_dsl/app.rbs +0 -7
  309. data/examples/quickstart_dsl/test_app.rb +0 -29
  310. data/examples/quickstart_lifecycle/app.rbs +0 -7
  311. data/examples/quickstart_lifecycle/test_app.rb +0 -29
  312. data/examples/ratatui_logo_demo/app.rb +0 -79
  313. data/examples/ratatui_logo_demo/app.rbs +0 -7
  314. data/examples/ratatui_logo_demo/test_app.rb +0 -51
  315. data/examples/ratatui_mascot_demo/app.rb +0 -84
  316. data/examples/ratatui_mascot_demo/app.rbs +0 -7
  317. data/examples/ratatui_mascot_demo/test_app.rb +0 -47
  318. data/examples/readme_usage/app.rb +0 -29
  319. data/examples/readme_usage/app.rbs +0 -7
  320. data/examples/readme_usage/test_app.rb +0 -29
  321. data/examples/rich_text/app.rb +0 -141
  322. data/examples/rich_text/app.rbs +0 -7
  323. data/examples/rich_text/test_app.rb +0 -166
  324. data/examples/scroll_text/app.rb +0 -103
  325. data/examples/scroll_text/app.rbs +0 -7
  326. data/examples/scroll_text/test_app.rb +0 -110
  327. data/examples/scrollbar_demo/app.rb +0 -143
  328. data/examples/scrollbar_demo/app.rbs +0 -7
  329. data/examples/scrollbar_demo/test_app.rb +0 -77
  330. data/examples/sparkline_demo/app.rb +0 -240
  331. data/examples/sparkline_demo/test_app.rb +0 -107
  332. data/examples/table_flex/app.rb +0 -65
  333. data/examples/table_flex/app.rbs +0 -7
  334. data/examples/table_flex/test_app.rb +0 -36
  335. data/examples/table_select/app.rbs +0 -7
  336. data/examples/table_select/test_app.rb +0 -180
  337. data/examples/widget_style_colors/test_app.rb +0 -48
  338. /data/doc/images/{analytics.png → app_analytics.png} +0 -0
  339. /data/doc/images/{custom_widget.png → app_custom_widget.png} +0 -0
  340. /data/doc/images/{login_form.png → app_login_form.png} +0 -0
  341. /data/doc/images/{map_demo.png → app_map_demo.png} +0 -0
  342. /data/doc/images/{mouse_events.png → app_mouse_events.png} +0 -0
  343. /data/doc/images/{table_select.png → app_table_select.png} +0 -0
  344. /data/doc/images/{quickstart_dsl.png → verify_quickstart_dsl.png} +0 -0
  345. /data/doc/images/{ratatui_logo_demo.png → verify_quickstart_layout.png} +0 -0
  346. /data/doc/images/{quickstart_lifecycle.png → verify_quickstart_lifecycle.png} +0 -0
  347. /data/doc/images/{list_styles.png → widget_list_styles.png} +0 -0
  348. /data/doc/images/{popup_demo.png → widget_popup_demo.png} +0 -0
  349. /data/doc/images/{hit_test.png → widget_rect.png} +0 -0
  350. /data/doc/images/{rich_text.png → widget_rich_text.png} +0 -0
  351. /data/doc/images/{scroll_text.png → widget_scroll_text.png} +0 -0
@@ -1,169 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
- # SPDX-License-Identifier: AGPL-3.0-or-later
5
-
6
- $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
7
- require "ratatui_ruby"
8
-
9
- # All Events Demo
10
- # Demonstrates every event type: Key, Mouse, Resize, Paste, Focus.
11
- class AllEventsApp
12
- attr_reader :key_info, :mouse_info, :resize_info, :special_info, :focused
13
-
14
- def initialize
15
- @key_info = "Press any key..."
16
- @mouse_info = "Click or scroll..."
17
- @resize_info = "Resize the terminal..."
18
- @special_info = "Paste text or change focus..."
19
- @focused = true
20
- end
21
-
22
- def run
23
- RatatuiRuby.run do
24
- # Capture initial terminal size
25
- @resize_info = "#{terminal_width}×#{terminal_height}"
26
- loop do
27
- render
28
- break if handle_input == :quit
29
- sleep 0.016
30
- end
31
- end
32
- end
33
-
34
- private
35
-
36
- def terminal_width
37
- 80 # Approximation; actual size comes from Resize events
38
- end
39
-
40
- def terminal_height
41
- 24
42
- end
43
-
44
- def render
45
- border_color = @focused ? "green" : "gray"
46
-
47
- key_panel = RatatuiRuby::Paragraph.new(
48
- text: @key_info,
49
- alignment: :center,
50
- block: RatatuiRuby::Block.new(
51
- title: "⌨️ Key Events",
52
- borders: [:all],
53
- border_color: border_color
54
- )
55
- )
56
-
57
- mouse_panel = RatatuiRuby::Paragraph.new(
58
- text: @mouse_info,
59
- alignment: :center,
60
- block: RatatuiRuby::Block.new(
61
- title: "🖱️ Mouse Events",
62
- borders: [:all],
63
- border_color: border_color
64
- )
65
- )
66
-
67
- resize_panel = RatatuiRuby::Paragraph.new(
68
- text: @resize_info,
69
- alignment: :center,
70
- block: RatatuiRuby::Block.new(
71
- title: "📐 Resize Events",
72
- borders: [:all],
73
- border_color: border_color
74
- )
75
- )
76
-
77
- special_panel = RatatuiRuby::Paragraph.new(
78
- text: @special_info,
79
- alignment: :center,
80
- block: RatatuiRuby::Block.new(
81
- title: "✨ Paste & Focus Events",
82
- borders: [:all],
83
- border_color: border_color
84
- )
85
- )
86
-
87
- # 2x2 grid layout
88
- top_row = RatatuiRuby::Layout.new(
89
- direction: :horizontal,
90
- constraints: [
91
- RatatuiRuby::Constraint.percentage(50),
92
- RatatuiRuby::Constraint.percentage(50)
93
- ],
94
- children: [key_panel, mouse_panel]
95
- )
96
-
97
- bottom_row = RatatuiRuby::Layout.new(
98
- direction: :horizontal,
99
- constraints: [
100
- RatatuiRuby::Constraint.percentage(50),
101
- RatatuiRuby::Constraint.percentage(50)
102
- ],
103
- children: [resize_panel, special_panel]
104
- )
105
-
106
- # Header with instructions
107
- header = RatatuiRuby::Paragraph.new(
108
- text: "All Event Types Demo — Press 'q' or Ctrl+C to quit",
109
- alignment: :center,
110
- style: { fg: :cyan, modifiers: [:bold] }
111
- )
112
-
113
- layout = RatatuiRuby::Layout.new(
114
- direction: :vertical,
115
- constraints: [
116
- RatatuiRuby::Constraint.length(1),
117
- RatatuiRuby::Constraint.percentage(50),
118
- RatatuiRuby::Constraint.percentage(50)
119
- ],
120
- children: [header, top_row, bottom_row]
121
- )
122
-
123
- RatatuiRuby.draw(layout)
124
- end
125
-
126
- def handle_input
127
- event = RatatuiRuby.poll_event
128
- return unless event
129
-
130
- case event
131
- # Quit
132
- in {type: :key, code: "q"} | {type: :key, code: "c", modifiers: ["ctrl"]}
133
- return :quit
134
-
135
- # Key events
136
- in type: :key, code:, modifiers:
137
- mods = modifiers.empty? ? "" : " [#{modifiers.join('+')}]"
138
- @key_info = "Key: #{code}#{mods}"
139
-
140
- # Mouse events
141
- in type: :mouse, kind:, button:, x:, y:
142
- @mouse_info = "#{kind}: #{button} at (#{x}, #{y})"
143
-
144
- # Resize events
145
- in type: :resize, width:, height:
146
- @resize_info = "#{width}×#{height}"
147
-
148
- # Paste events
149
- in type: :paste, content:
150
- display_content = content.length > 30 ? "#{content[0..27]}..." : content
151
- @special_info = "Pasted: #{display_content.inspect}"
152
-
153
- # Focus events
154
- in type: :focus_gained
155
- @focused = true
156
- @special_info = "Focus gained! ✓"
157
-
158
- in type: :focus_lost
159
- @focused = false
160
- @special_info = "Focus lost..."
161
- else
162
- nil
163
- end
164
-
165
- nil
166
- end
167
- end
168
-
169
- AllEventsApp.new.run if __FILE__ == $PROGRAM_NAME
@@ -1,7 +0,0 @@
1
- class AllEventsApp
2
- # @public
3
- def self.new: () -> AllEventsApp
4
-
5
- # @public
6
- def run: () -> void
7
- end
@@ -1,139 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
- # SPDX-License-Identifier: AGPL-3.0-or-later
5
-
6
- $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
7
- require "ratatui_ruby"
8
- require "ratatui_ruby/test_helper"
9
- require "minitest/autorun"
10
- require_relative "app"
11
-
12
- class TestAllEvents < Minitest::Test
13
- include RatatuiRuby::TestHelper
14
-
15
- def setup
16
- @app = AllEventsApp.new
17
- end
18
-
19
- def test_initial_state
20
- with_test_terminal do
21
- # Queue quit event
22
- inject_key(:q)
23
-
24
- @app.run
25
-
26
- content = buffer_content.join("\n")
27
- assert_includes content, "Press any key..."
28
- assert_includes content, "Click or scroll..."
29
- assert_includes content, "80×24"
30
- assert_includes content, "Paste text or change focus..."
31
- end
32
- end
33
-
34
- def test_key_event_updates_panel
35
- with_test_terminal do
36
- inject_keys(:a, :q)
37
-
38
- @app.run
39
-
40
- assert_includes buffer_content.join("\n"), "Key: a"
41
- end
42
- end
43
-
44
- def test_key_event_with_modifiers
45
- with_test_terminal do
46
- inject_keys(:ctrl_s, :q)
47
-
48
- @app.run
49
-
50
- assert_includes buffer_content.join("\n"), "Key: s [ctrl]"
51
- end
52
- end
53
-
54
- def test_mouse_event_updates_panel
55
- with_test_terminal do
56
- inject_event(RatatuiRuby::Event::Mouse.new(kind: "down", button: "left", x: 10, y: 5))
57
- inject_key(:q)
58
-
59
- @app.run
60
-
61
- assert_includes buffer_content.join("\n"), "down: left at (10, 5)"
62
- end
63
- end
64
-
65
- def test_resize_event_updates_panel
66
- with_test_terminal do
67
- inject_event(RatatuiRuby::Event::Resize.new(width: 120, height: 40))
68
- inject_key(:q)
69
-
70
- @app.run
71
-
72
- assert_includes buffer_content.join("\n"), "120×40"
73
- end
74
- end
75
-
76
- def test_paste_event_updates_panel
77
- with_test_terminal do
78
- inject_event(RatatuiRuby::Event::Paste.new(content: "Hello, World!"))
79
- inject_key(:q)
80
-
81
- @app.run
82
-
83
- assert_includes buffer_content.join("\n"), 'Pasted: "Hello, World!"'
84
- end
85
- end
86
-
87
- def test_paste_event_truncates_long_content
88
- with_test_terminal do
89
- inject_event(RatatuiRuby::Event::Paste.new(content: "This is a very long string that should be truncated"))
90
- inject_key(:q)
91
-
92
- @app.run
93
-
94
- content = buffer_content.join("\n")
95
- assert_includes content, "Pasted: "
96
- assert_includes content, "..."
97
- end
98
- end
99
-
100
- def test_focus_gained_updates_panel
101
- with_test_terminal do
102
- # Initial state is focused, so we lose then gain
103
- @app.instance_variable_set(:@focused, false)
104
- inject_event(RatatuiRuby::Event::FocusGained.new)
105
- inject_key(:q)
106
-
107
- @app.run
108
-
109
- assert_includes buffer_content.join("\n"), "Focus gained! ✓"
110
- end
111
- end
112
-
113
- def test_focus_lost_updates_panel
114
- with_test_terminal do
115
- inject_event(RatatuiRuby::Event::FocusLost.new)
116
- inject_key(:q)
117
-
118
- @app.run
119
-
120
- assert_includes buffer_content.join("\n"), "Focus lost..."
121
- end
122
- end
123
-
124
- def test_quit_on_q
125
- with_test_terminal do
126
- inject_key(:q)
127
- # Wait... run should just return normally
128
- @app.run
129
- # If it returns, the test passes (no timeout/hang)
130
- end
131
- end
132
-
133
- def test_quit_on_ctrl_c
134
- with_test_terminal do
135
- inject_key(:ctrl_c)
136
- @app.run
137
- end
138
- end
139
- end
@@ -1,258 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
- # SPDX-License-Identifier: AGPL-3.0-or-later
5
-
6
- $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
7
- require "ratatui_ruby"
8
-
9
- # Analytics Dashboard Example
10
- # Demonstrates Tabs and BarChart widgets.
11
-
12
- class AnalyticsApp
13
- def initialize
14
- @selected_tab = 0
15
- @tabs = ["Revenue", "Traffic", "Errors", "Quarterly"]
16
- @styles = [
17
- { name: "Yellow Bold", style: RatatuiRuby::Style.new(fg: :yellow, modifiers: [:bold]) },
18
- { name: "Italic Blue on White", style: RatatuiRuby::Style.new(fg: :blue, bg: :white, modifiers: [:italic]) },
19
- { name: "Underlined Red", style: RatatuiRuby::Style.new(fg: :red, modifiers: [:underlined]) },
20
- { name: "Reversed", style: RatatuiRuby::Style.new(modifiers: [:reversed]) }
21
- ]
22
- @style_index = 0
23
- @divider_index = 0
24
- @dividers = [" | ", " • ", " > ", " / "]
25
- @base_styles = [
26
- { name: "Default", style: nil },
27
- { name: "White on Gray", style: RatatuiRuby::Style.new(fg: :white, bg: :dark_gray) },
28
- { name: "White on Blue", style: RatatuiRuby::Style.new(fg: :white, bg: :blue) },
29
- { name: "Italic", style: RatatuiRuby::Style.new(modifiers: [:italic]) }
30
- ]
31
- @base_style_index = 0
32
- @padding_left = 0
33
- @padding_right = 0
34
- @direction = :vertical
35
- @label_style_index = 0
36
- @value_style_index = 0
37
- @bar_sets = [
38
- { name: "Default", set: nil },
39
- { name: "Numbers (Short)", set: { 8 => "8", 7 => "7", 6 => "6", 5 => "5", 4 => "4", 3 => "3", 2 => "2", 1 => "1", 0 => "0" } },
40
- { name: "Letters (Long)", set: { full: "H", seven_eighths: "G", three_quarters: "F", five_eighths: "E", half: "D", three_eighths: "C", one_quarter: "B", one_eighth: "A", empty: " " } },
41
- { name: "ASCII (Heights)", set: [" ", "_", ".", "-", "=", "+", "*", "#", "@"] }
42
- ]
43
- @bar_set_index = 0
44
- @height_mode = :full # :full or :mini
45
- @group_gap = 0
46
-
47
- @hotkey_style = RatatuiRuby::Style.new(modifiers: [:bold, :underlined])
48
- end
49
-
50
- def run
51
- RatatuiRuby.run do
52
- loop do
53
- render
54
- break if handle_input == :quit
55
- end
56
- end
57
- end
58
-
59
- private
60
-
61
- def render
62
- # Data for different tabs
63
- data = case @selected_tab
64
- when 0 # Revenue
65
- {
66
- "Q1" => 50, "Q2" => 80, "Q3" => 45, "Q4" => 60,
67
- "Q1'" => 55, "Q2'" => 85, "Q3'" => 50, "Q4'" => 65
68
- }
69
- when 1 # Traffic
70
- [
71
- ["Mon", 120], ["Tue", 150], ["Wed", 130], ["Thu", 160],
72
- ["Fri", 140],
73
- ["Sat", 110, RatatuiRuby::Style.new(fg: :red)],
74
- ["Sun", 100, RatatuiRuby::Style.new(fg: :red)]
75
- ]
76
- when 2 # Errors
77
- { DB: 5, UI: 2, API: 8, Auth: 3, Net: 4, "I/O": 1, Mem: 6, CPU: 7 }
78
- when 3 # Quarterly
79
- [
80
- RatatuiRuby::BarChart::BarGroup.new(label: "2024", bars: [
81
- RatatuiRuby::BarChart::Bar.new(value: 40, label: "Q1"),
82
- RatatuiRuby::BarChart::Bar.new(value: 45, label: "Q2"),
83
- RatatuiRuby::BarChart::Bar.new(value: 50, label: "Q3"),
84
- RatatuiRuby::BarChart::Bar.new(value: 55, label: "Q4")
85
- ]),
86
- RatatuiRuby::BarChart::BarGroup.new(label: "2025", bars: [
87
- RatatuiRuby::BarChart::Bar.new(value: 60, label: "Q1", style: RatatuiRuby::Style.new(fg: :yellow)),
88
- RatatuiRuby::BarChart::Bar.new(value: 65, label: "Q2", style: RatatuiRuby::Style.new(fg: :yellow)),
89
- RatatuiRuby::BarChart::Bar.new(value: 70, label: "Q3", style: RatatuiRuby::Style.new(fg: :yellow)),
90
- RatatuiRuby::BarChart::Bar.new(value: 75, label: "Q4", style: RatatuiRuby::Style.new(fg: :yellow))
91
- ])
92
- ]
93
- end
94
-
95
- bar_style = case @selected_tab
96
- when 0 then RatatuiRuby::Style.new(fg: "green")
97
- when 1 then RatatuiRuby::Style.new(fg: "blue")
98
- when 2 then RatatuiRuby::Style.new(fg: "red")
99
- when 3 then RatatuiRuby::Style.new(fg: "cyan")
100
- end
101
-
102
- # Define the BarChart widget
103
- bar_chart = RatatuiRuby::BarChart.new(
104
- data:,
105
- bar_width: @direction == :vertical ? 8 : 1,
106
- style: bar_style,
107
- bar_gap: 1,
108
- group_gap: @group_gap,
109
- direction: @direction,
110
- label_style: @styles[@label_style_index][:style],
111
- value_style: @styles[@value_style_index][:style],
112
- bar_set: @bar_sets[@bar_set_index][:set],
113
- block: RatatuiRuby::Block.new(
114
- title: "Analytics: #{@tabs[@selected_tab]}",
115
- borders: [:all]
116
- )
117
- )
118
-
119
- # Wrap chart in a layout to control height if in mini mode
120
- chart_area = if @height_mode == :mini
121
- # Height 3: 1 row content + 2 borders
122
- RatatuiRuby::Layout.new(
123
- direction: :vertical,
124
- constraints: [RatatuiRuby::Constraint.length(3), RatatuiRuby::Constraint.fill(1)],
125
- children: [bar_chart, RatatuiRuby::Block.new] # Empty block to fill rest
126
- )
127
- else
128
- bar_chart
129
- end
130
-
131
- # Build the UI
132
- ui = RatatuiRuby::Layout.new(
133
- direction: :vertical,
134
- constraints: [
135
- RatatuiRuby::Constraint.fill(1),
136
- RatatuiRuby::Constraint.length(6),
137
- ],
138
- children: [
139
- # Main Area
140
- RatatuiRuby::Layout.new(
141
- direction: :vertical,
142
- constraints: [
143
- RatatuiRuby::Constraint.new(type: :length, value: 3),
144
- RatatuiRuby::Constraint.new(type: :min, value: 0),
145
- ],
146
- children: [
147
- tabs = RatatuiRuby::Tabs.new(
148
- titles: @tabs,
149
- selected_index: @selected_tab,
150
- block: RatatuiRuby::Block.new(title: "Views", borders: [:all]),
151
- divider: @dividers[@divider_index],
152
- highlight_style: @styles[@style_index][:style],
153
- style: @base_styles[@base_style_index][:style],
154
- padding_left: @padding_left,
155
- padding_right: @padding_right
156
- ),
157
- chart_area
158
- ]
159
- ),
160
- # Bottom control panel
161
- RatatuiRuby::Block.new(
162
- title: "Controls",
163
- borders: [:all],
164
- children: [
165
- RatatuiRuby::Paragraph.new(
166
- text: [
167
- # Line 1: Navigation & General
168
- RatatuiRuby::Text::Line.new(spans: [
169
- RatatuiRuby::Text::Span.new(content: "←/→", style: @hotkey_style),
170
- RatatuiRuby::Text::Span.new(content: ": Navigate Tab "),
171
- RatatuiRuby::Text::Span.new(content: "v", style: @hotkey_style),
172
- RatatuiRuby::Text::Span.new(content: ": Direction (#{@direction}) "),
173
- RatatuiRuby::Text::Span.new(content: "q", style: @hotkey_style),
174
- RatatuiRuby::Text::Span.new(content: ": Quit")
175
- ]),
176
- # Line 2: Padding & Divider
177
- RatatuiRuby::Text::Line.new(spans: [
178
- RatatuiRuby::Text::Span.new(content: "h/l", style: @hotkey_style),
179
- RatatuiRuby::Text::Span.new(content: ": Pad Left (#{@padding_left}) "),
180
- RatatuiRuby::Text::Span.new(content: "j/k", style: @hotkey_style),
181
- RatatuiRuby::Text::Span.new(content: ": Pad Right (#{@padding_right}) "),
182
- RatatuiRuby::Text::Span.new(content: "d", style: @hotkey_style),
183
- RatatuiRuby::Text::Span.new(content: ": Divider (#{@dividers[@divider_index]}) "),
184
- RatatuiRuby::Text::Span.new(content: "Width: #{tabs.width}")
185
- ]),
186
- # Line 3: Styles
187
- RatatuiRuby::Text::Line.new(spans: [
188
- RatatuiRuby::Text::Span.new(content: "space", style: @hotkey_style),
189
- RatatuiRuby::Text::Span.new(content: ": Highlight (#{@styles[@style_index][:name]}) "),
190
- RatatuiRuby::Text::Span.new(content: "x", style: @hotkey_style),
191
- RatatuiRuby::Text::Span.new(content: ": Label (#{@styles[@label_style_index][:name]}) "),
192
- RatatuiRuby::Text::Span.new(content: "space", style: @hotkey_style),
193
- RatatuiRuby::Text::Span.new(content: ": Highlight (#{@styles[@style_index][:name]}) "),
194
- RatatuiRuby::Text::Span.new(content: "x", style: @hotkey_style),
195
- RatatuiRuby::Text::Span.new(content: ": Label (#{@styles[@label_style_index][:name]})")
196
- ]),
197
- # Line 4: More Styles
198
- RatatuiRuby::Text::Line.new(spans: [
199
- RatatuiRuby::Text::Span.new(content: "z", style: @hotkey_style),
200
- RatatuiRuby::Text::Span.new(content: ": Value (#{@styles[@value_style_index][:name]}) "),
201
- RatatuiRuby::Text::Span.new(content: "b", style: @hotkey_style),
202
- RatatuiRuby::Text::Span.new(content: ": Bar Set (#{@bar_sets[@bar_set_index][:name]}) "),
203
- RatatuiRuby::Text::Span.new(content: "m", style: @hotkey_style),
204
- RatatuiRuby::Text::Span.new(content: ": Mode (#{@height_mode == :full ? 'Full' : 'Mini'}) "),
205
- RatatuiRuby::Text::Span.new(content: "g", style: @hotkey_style),
206
- RatatuiRuby::Text::Span.new(content: ": Group Gap (#{@group_gap})")
207
- ])
208
- ]
209
- )
210
- ]
211
- )
212
- ]
213
- )
214
-
215
- RatatuiRuby.draw(ui)
216
- end
217
-
218
- def handle_input
219
- case RatatuiRuby.poll_event
220
- in {type: :key, code: "q"} | {type: :key, code: "c", modifiers: ["ctrl"]}
221
- :quit
222
- in type: :key, code: "right"
223
- @selected_tab = (@selected_tab + 1) % @tabs.size
224
- in type: :key, code: "left"
225
- @selected_tab = (@selected_tab - 1) % @tabs.size
226
- in type: :key, code: " "
227
- @style_index = (@style_index + 1) % @styles.size
228
- in type: :key, code: "d"
229
- @divider_index = (@divider_index + 1) % @dividers.size
230
- in type: :key, code: "s"
231
- @base_style_index = (@base_style_index + 1) % @base_styles.size
232
- in type: :key, code: "h"
233
- @padding_left = [@padding_left - 1, 0].max
234
- in type: :key, code: "l"
235
- @padding_left += 1
236
- in type: :key, code: "v"
237
- @direction = @direction == :vertical ? :horizontal : :vertical
238
- in type: :key, code: "j"
239
- @padding_right = [@padding_right - 1, 0].max
240
- in type: :key, code: "k"
241
- @padding_right += 1
242
- in type: :key, code: "x"
243
- @label_style_index = (@label_style_index + 1) % @styles.size
244
- in type: :key, code: "z"
245
- @value_style_index = (@value_style_index + 1) % @styles.size
246
- in type: :key, code: "b"
247
- @bar_set_index = (@bar_set_index + 1) % @bar_sets.size
248
- in type: :key, code: "m"
249
- @height_mode = @height_mode == :full ? :mini : :full
250
- in type: :key, code: "g"
251
- @group_gap = (@group_gap + 1) % 4
252
- else
253
- # Ignore other events
254
- end
255
- end
256
- end
257
-
258
- AnalyticsApp.new.run if __FILE__ == $0
@@ -1,7 +0,0 @@
1
- class AnalyticsApp
2
- # @public
3
- def self.new: () -> AnalyticsApp
4
-
5
- # @public
6
- def run: () -> void
7
- end