ratatui_ruby 0.3.1 → 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 (350) hide show
  1. checksums.yaml +4 -4
  2. data/.builds/ruby-3.2.yml +14 -12
  3. data/.builds/ruby-3.3.yml +14 -12
  4. data/.builds/ruby-3.4.yml +14 -12
  5. data/.builds/ruby-4.0.0.yml +14 -12
  6. data/AGENTS.md +89 -132
  7. data/CHANGELOG.md +223 -1
  8. data/README.md +23 -16
  9. data/REUSE.toml +20 -0
  10. data/doc/application_architecture.md +176 -0
  11. data/doc/application_testing.md +17 -10
  12. data/doc/contributors/design/ruby_frontend.md +11 -7
  13. data/doc/contributors/developing_examples.md +261 -0
  14. data/doc/contributors/documentation_style.md +104 -0
  15. data/doc/contributors/dwim_dx.md +366 -0
  16. data/doc/contributors/index.md +2 -0
  17. data/doc/custom.css +14 -0
  18. data/doc/event_handling.md +125 -0
  19. data/doc/images/app_all_events.png +0 -0
  20. data/doc/images/app_analytics.png +0 -0
  21. data/doc/images/app_color_picker.png +0 -0
  22. data/doc/images/app_custom_widget.png +0 -0
  23. data/doc/images/app_login_form.png +0 -0
  24. data/doc/images/app_map_demo.png +0 -0
  25. data/doc/images/app_mouse_events.png +0 -0
  26. data/doc/images/app_table_select.png +0 -0
  27. data/doc/images/verify_quickstart_dsl.png +0 -0
  28. data/doc/images/verify_quickstart_layout.png +0 -0
  29. data/doc/images/verify_quickstart_lifecycle.png +0 -0
  30. data/doc/images/verify_readme_usage.png +0 -0
  31. data/doc/images/widget_barchart_demo.png +0 -0
  32. data/doc/images/widget_block_padding.png +0 -0
  33. data/doc/images/widget_block_titles.png +0 -0
  34. data/doc/images/widget_box_demo.png +0 -0
  35. data/doc/images/widget_calendar_demo.png +0 -0
  36. data/doc/images/widget_cell_demo.png +0 -0
  37. data/doc/images/widget_chart_demo.png +0 -0
  38. data/doc/images/widget_gauge_demo.png +0 -0
  39. data/doc/images/widget_layout_split.png +0 -0
  40. data/doc/images/widget_line_gauge_demo.png +0 -0
  41. data/doc/images/widget_list_demo.png +0 -0
  42. data/doc/images/widget_list_styles.png +0 -0
  43. data/doc/images/widget_popup_demo.png +0 -0
  44. data/doc/images/widget_ratatui_logo_demo.png +0 -0
  45. data/doc/images/widget_ratatui_mascot_demo.png +0 -0
  46. data/doc/images/widget_rect.png +0 -0
  47. data/doc/images/widget_render.png +0 -0
  48. data/doc/images/widget_rich_text.png +0 -0
  49. data/doc/images/widget_scroll_text.png +0 -0
  50. data/doc/images/widget_scrollbar_demo.png +0 -0
  51. data/doc/images/widget_sparkline_demo.png +0 -0
  52. data/doc/images/widget_style_colors.png +0 -0
  53. data/doc/images/widget_table_flex.png +0 -0
  54. data/doc/images/widget_tabs_demo.png +0 -0
  55. data/doc/index.md +1 -0
  56. data/doc/interactive_design.md +116 -0
  57. data/doc/quickstart.md +186 -84
  58. data/examples/app_all_events/README.md +81 -0
  59. data/examples/app_all_events/app.rb +93 -0
  60. data/examples/app_all_events/model/event_color_cycle.rb +41 -0
  61. data/examples/app_all_events/model/event_entry.rb +75 -0
  62. data/examples/app_all_events/model/events.rb +180 -0
  63. data/examples/app_all_events/model/highlight.rb +57 -0
  64. data/examples/app_all_events/model/timestamp.rb +54 -0
  65. data/examples/app_all_events/test/snapshots/after_focus_lost.txt +24 -0
  66. data/examples/app_all_events/test/snapshots/after_focus_regained.txt +24 -0
  67. data/examples/app_all_events/test/snapshots/after_horizontal_resize.txt +24 -0
  68. data/examples/app_all_events/test/snapshots/after_key_a.txt +24 -0
  69. data/examples/app_all_events/test/snapshots/after_key_ctrl_x.txt +24 -0
  70. data/examples/app_all_events/test/snapshots/after_mouse_click.txt +24 -0
  71. data/examples/app_all_events/test/snapshots/after_mouse_drag.txt +24 -0
  72. data/examples/app_all_events/test/snapshots/after_multiple_events.txt +24 -0
  73. data/examples/app_all_events/test/snapshots/after_paste.txt +24 -0
  74. data/examples/app_all_events/test/snapshots/after_resize.txt +24 -0
  75. data/examples/app_all_events/test/snapshots/after_right_click.txt +24 -0
  76. data/examples/app_all_events/test/snapshots/after_vertical_resize.txt +24 -0
  77. data/examples/app_all_events/test/snapshots/initial_state.txt +24 -0
  78. data/examples/app_all_events/view/app_view.rb +78 -0
  79. data/examples/app_all_events/view/controls_view.rb +50 -0
  80. data/examples/app_all_events/view/counts_view.rb +55 -0
  81. data/examples/app_all_events/view/live_view.rb +69 -0
  82. data/examples/app_all_events/view/log_view.rb +60 -0
  83. data/{lib/ratatui_ruby/output.rb → examples/app_all_events/view.rb} +1 -1
  84. data/examples/app_all_events/view_state.rb +42 -0
  85. data/examples/app_color_picker/README.md +94 -0
  86. data/examples/app_color_picker/app.rb +112 -0
  87. data/examples/app_color_picker/clipboard.rb +84 -0
  88. data/examples/app_color_picker/color.rb +191 -0
  89. data/examples/app_color_picker/copy_dialog.rb +170 -0
  90. data/examples/app_color_picker/harmony.rb +56 -0
  91. data/examples/app_color_picker/input.rb +142 -0
  92. data/examples/app_color_picker/palette.rb +80 -0
  93. data/examples/app_color_picker/scene.rb +201 -0
  94. data/examples/app_login_form/app.rb +108 -0
  95. data/examples/app_map_demo/app.rb +93 -0
  96. data/examples/app_table_select/app.rb +201 -0
  97. data/examples/verify_quickstart_dsl/app.rb +45 -0
  98. data/examples/verify_quickstart_layout/app.rb +69 -0
  99. data/examples/verify_quickstart_lifecycle/app.rb +48 -0
  100. data/examples/verify_readme_usage/app.rb +34 -0
  101. data/examples/widget_barchart_demo/app.rb +238 -0
  102. data/examples/widget_block_padding/app.rb +67 -0
  103. data/examples/widget_block_titles/app.rb +69 -0
  104. data/examples/widget_box_demo/app.rb +250 -0
  105. data/examples/widget_calendar_demo/app.rb +109 -0
  106. data/examples/widget_cell_demo/app.rb +104 -0
  107. data/examples/widget_chart_demo/app.rb +213 -0
  108. data/examples/widget_gauge_demo/app.rb +212 -0
  109. data/examples/widget_layout_split/app.rb +246 -0
  110. data/examples/widget_line_gauge_demo/app.rb +217 -0
  111. data/examples/widget_list_demo/app.rb +382 -0
  112. data/examples/widget_list_styles/app.rb +141 -0
  113. data/examples/widget_popup_demo/app.rb +104 -0
  114. data/examples/widget_ratatui_logo_demo/app.rb +103 -0
  115. data/examples/widget_ratatui_mascot_demo/app.rb +93 -0
  116. data/examples/widget_rect/app.rb +205 -0
  117. data/examples/widget_render/app.rb +184 -0
  118. data/examples/widget_rich_text/app.rb +137 -0
  119. data/examples/widget_scroll_text/app.rb +108 -0
  120. data/examples/widget_scrollbar_demo/app.rb +153 -0
  121. data/examples/widget_sparkline_demo/app.rb +274 -0
  122. data/examples/widget_style_colors/app.rb +102 -0
  123. data/examples/widget_table_flex/app.rb +95 -0
  124. data/examples/widget_tabs_demo/app.rb +167 -0
  125. data/ext/ratatui_ruby/Cargo.lock +889 -115
  126. data/ext/ratatui_ruby/Cargo.toml +4 -3
  127. data/ext/ratatui_ruby/clippy.toml +7 -0
  128. data/ext/ratatui_ruby/extconf.rb +7 -0
  129. data/ext/ratatui_ruby/src/events.rs +293 -219
  130. data/ext/ratatui_ruby/src/frame.rs +115 -0
  131. data/ext/ratatui_ruby/src/lib.rs +105 -24
  132. data/ext/ratatui_ruby/src/rendering.rs +94 -10
  133. data/ext/ratatui_ruby/src/style.rs +357 -93
  134. data/ext/ratatui_ruby/src/terminal.rs +121 -31
  135. data/ext/ratatui_ruby/src/text.rs +178 -0
  136. data/ext/ratatui_ruby/src/widgets/barchart.rs +99 -24
  137. data/ext/ratatui_ruby/src/widgets/block.rs +32 -3
  138. data/ext/ratatui_ruby/src/widgets/calendar.rs +45 -44
  139. data/ext/ratatui_ruby/src/widgets/canvas.rs +44 -9
  140. data/ext/ratatui_ruby/src/widgets/chart.rs +79 -27
  141. data/ext/ratatui_ruby/src/widgets/clear.rs +3 -1
  142. data/ext/ratatui_ruby/src/widgets/gauge.rs +11 -4
  143. data/ext/ratatui_ruby/src/widgets/layout.rs +223 -15
  144. data/ext/ratatui_ruby/src/widgets/line_gauge.rs +92 -0
  145. data/ext/ratatui_ruby/src/widgets/list.rs +114 -11
  146. data/ext/ratatui_ruby/src/widgets/mod.rs +3 -0
  147. data/ext/ratatui_ruby/src/widgets/overlay.rs +4 -2
  148. data/ext/ratatui_ruby/src/widgets/paragraph.rs +35 -13
  149. data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +40 -0
  150. data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +51 -0
  151. data/ext/ratatui_ruby/src/widgets/scrollbar.rs +61 -7
  152. data/ext/ratatui_ruby/src/widgets/sparkline.rs +73 -6
  153. data/ext/ratatui_ruby/src/widgets/table.rs +177 -64
  154. data/ext/ratatui_ruby/src/widgets/tabs.rs +105 -5
  155. data/lib/ratatui_ruby/cell.rb +166 -0
  156. data/lib/ratatui_ruby/event/focus_gained.rb +49 -0
  157. data/lib/ratatui_ruby/event/focus_lost.rb +50 -0
  158. data/lib/ratatui_ruby/event/key.rb +211 -0
  159. data/lib/ratatui_ruby/event/mouse.rb +124 -0
  160. data/lib/ratatui_ruby/event/none.rb +43 -0
  161. data/lib/ratatui_ruby/event/paste.rb +71 -0
  162. data/lib/ratatui_ruby/event/resize.rb +80 -0
  163. data/lib/ratatui_ruby/event.rb +131 -0
  164. data/lib/ratatui_ruby/frame.rb +87 -0
  165. data/lib/ratatui_ruby/schema/bar_chart/bar.rb +45 -0
  166. data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +23 -0
  167. data/lib/ratatui_ruby/schema/bar_chart.rb +226 -17
  168. data/lib/ratatui_ruby/schema/block.rb +178 -11
  169. data/lib/ratatui_ruby/schema/calendar.rb +70 -14
  170. data/lib/ratatui_ruby/schema/canvas.rb +213 -46
  171. data/lib/ratatui_ruby/schema/center.rb +46 -8
  172. data/lib/ratatui_ruby/schema/chart.rb +134 -32
  173. data/lib/ratatui_ruby/schema/clear.rb +22 -53
  174. data/lib/ratatui_ruby/schema/constraint.rb +72 -12
  175. data/lib/ratatui_ruby/schema/cursor.rb +23 -5
  176. data/lib/ratatui_ruby/schema/draw.rb +53 -0
  177. data/lib/ratatui_ruby/schema/gauge.rb +56 -12
  178. data/lib/ratatui_ruby/schema/layout.rb +91 -9
  179. data/lib/ratatui_ruby/schema/line_gauge.rb +78 -0
  180. data/lib/ratatui_ruby/schema/list.rb +92 -16
  181. data/lib/ratatui_ruby/schema/overlay.rb +29 -3
  182. data/lib/ratatui_ruby/schema/paragraph.rb +82 -25
  183. data/lib/ratatui_ruby/schema/ratatui_logo.rb +29 -0
  184. data/lib/ratatui_ruby/schema/ratatui_mascot.rb +34 -0
  185. data/lib/ratatui_ruby/schema/rect.rb +59 -10
  186. data/lib/ratatui_ruby/schema/scrollbar.rb +127 -19
  187. data/lib/ratatui_ruby/schema/shape/label.rb +66 -0
  188. data/lib/ratatui_ruby/schema/sparkline.rb +120 -12
  189. data/lib/ratatui_ruby/schema/style.rb +39 -11
  190. data/lib/ratatui_ruby/schema/table.rb +109 -18
  191. data/lib/ratatui_ruby/schema/tabs.rb +71 -10
  192. data/lib/ratatui_ruby/schema/text.rb +90 -0
  193. data/lib/ratatui_ruby/session/autodoc.rb +417 -0
  194. data/lib/ratatui_ruby/session.rb +163 -0
  195. data/lib/ratatui_ruby/test_helper.rb +322 -13
  196. data/lib/ratatui_ruby/version.rb +1 -1
  197. data/lib/ratatui_ruby.rb +184 -38
  198. data/sig/examples/app_all_events/app.rbs +11 -0
  199. data/sig/examples/app_all_events/model/event_entry.rbs +16 -0
  200. data/sig/examples/app_all_events/model/events.rbs +15 -0
  201. data/sig/examples/app_all_events/model/timestamp.rbs +11 -0
  202. data/sig/examples/app_all_events/view/app_view.rbs +8 -0
  203. data/sig/examples/app_all_events/view/controls_view.rbs +6 -0
  204. data/sig/examples/app_all_events/view/counts_view.rbs +6 -0
  205. data/sig/examples/app_all_events/view/live_view.rbs +6 -0
  206. data/sig/examples/app_all_events/view/log_view.rbs +6 -0
  207. data/sig/examples/app_all_events/view.rbs +8 -0
  208. data/sig/examples/app_all_events/view_state.rbs +15 -0
  209. data/sig/examples/app_color_picker/app.rbs +12 -0
  210. data/sig/examples/app_login_form/app.rbs +11 -0
  211. data/sig/examples/app_map_demo/app.rbs +11 -0
  212. data/sig/examples/app_table_select/app.rbs +11 -0
  213. data/sig/examples/verify_quickstart_dsl/app.rbs +11 -0
  214. data/sig/examples/verify_quickstart_lifecycle/app.rbs +11 -0
  215. data/sig/examples/verify_readme_usage/app.rbs +11 -0
  216. data/sig/examples/widget_block_padding/app.rbs +11 -0
  217. data/sig/examples/widget_block_titles/app.rbs +11 -0
  218. data/sig/examples/widget_box_demo/app.rbs +11 -0
  219. data/sig/examples/widget_calendar_demo/app.rbs +11 -0
  220. data/sig/examples/widget_cell_demo/app.rbs +11 -0
  221. data/sig/examples/widget_chart_demo/app.rbs +11 -0
  222. data/sig/examples/widget_gauge_demo/app.rbs +11 -0
  223. data/sig/examples/widget_layout_split/app.rbs +10 -0
  224. data/sig/examples/widget_line_gauge_demo/app.rbs +11 -0
  225. data/sig/examples/widget_list_demo/app.rbs +12 -0
  226. data/sig/examples/widget_list_styles/app.rbs +11 -0
  227. data/sig/examples/widget_popup_demo/app.rbs +11 -0
  228. data/sig/examples/widget_ratatui_logo_demo/app.rbs +11 -0
  229. data/sig/examples/widget_ratatui_mascot_demo/app.rbs +11 -0
  230. data/sig/examples/widget_rect/app.rbs +12 -0
  231. data/sig/examples/widget_render/app.rbs +10 -0
  232. data/sig/examples/widget_rich_text/app.rbs +11 -0
  233. data/sig/examples/widget_scroll_text/app.rbs +11 -0
  234. data/sig/examples/widget_scrollbar_demo/app.rbs +11 -0
  235. data/sig/examples/widget_sparkline_demo/app.rbs +10 -0
  236. data/sig/examples/widget_style_colors/app.rbs +14 -0
  237. data/sig/examples/widget_table_flex/app.rbs +11 -0
  238. data/sig/ratatui_ruby/event.rbs +69 -0
  239. data/sig/ratatui_ruby/frame.rbs +9 -0
  240. data/sig/ratatui_ruby/ratatui_ruby.rbs +5 -3
  241. data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +16 -0
  242. data/sig/ratatui_ruby/schema/bar_chart/bar_group.rbs +13 -0
  243. data/sig/ratatui_ruby/schema/bar_chart.rbs +20 -2
  244. data/sig/ratatui_ruby/schema/block.rbs +5 -4
  245. data/sig/ratatui_ruby/schema/calendar.rbs +6 -2
  246. data/sig/ratatui_ruby/schema/canvas.rbs +52 -39
  247. data/sig/ratatui_ruby/schema/center.rbs +3 -3
  248. data/sig/ratatui_ruby/schema/chart.rbs +8 -5
  249. data/sig/ratatui_ruby/schema/constraint.rbs +8 -5
  250. data/sig/ratatui_ruby/schema/cursor.rbs +1 -1
  251. data/sig/ratatui_ruby/schema/draw.rbs +27 -0
  252. data/sig/ratatui_ruby/schema/gauge.rbs +4 -2
  253. data/sig/ratatui_ruby/schema/layout.rbs +11 -1
  254. data/sig/ratatui_ruby/schema/line_gauge.rbs +16 -0
  255. data/sig/ratatui_ruby/schema/list.rbs +5 -1
  256. data/sig/ratatui_ruby/schema/paragraph.rbs +4 -1
  257. data/sig/ratatui_ruby/schema/ratatui_logo.rbs +8 -0
  258. data/sig/ratatui_ruby/{buffer.rbs → schema/ratatui_mascot.rbs} +4 -3
  259. data/sig/ratatui_ruby/schema/rect.rbs +2 -1
  260. data/sig/ratatui_ruby/schema/scrollbar.rbs +18 -2
  261. data/sig/ratatui_ruby/schema/sparkline.rbs +6 -2
  262. data/sig/ratatui_ruby/schema/table.rbs +8 -1
  263. data/sig/ratatui_ruby/schema/tabs.rbs +5 -1
  264. data/sig/ratatui_ruby/schema/text.rbs +22 -0
  265. data/sig/ratatui_ruby/session.rbs +94 -0
  266. data/tasks/autodoc/inventory.rb +61 -0
  267. data/tasks/autodoc/member.rb +56 -0
  268. data/tasks/autodoc/name.rb +19 -0
  269. data/tasks/autodoc/notice.rb +26 -0
  270. data/tasks/autodoc/rbs.rb +38 -0
  271. data/tasks/autodoc/rdoc.rb +45 -0
  272. data/tasks/autodoc.rake +47 -0
  273. data/tasks/bump/history.rb +2 -2
  274. data/tasks/doc.rake +600 -6
  275. data/tasks/example_viewer.html.erb +172 -0
  276. data/tasks/lint.rake +8 -4
  277. data/tasks/resources/build.yml.erb +13 -11
  278. data/tasks/resources/index.html.erb +6 -0
  279. data/tasks/sourcehut.rake +4 -4
  280. data/tasks/terminal_preview/app_screenshot.rb +33 -0
  281. data/tasks/terminal_preview/crash_report.rb +52 -0
  282. data/tasks/terminal_preview/example_app.rb +25 -0
  283. data/tasks/terminal_preview/launcher_script.rb +46 -0
  284. data/tasks/terminal_preview/preview_collection.rb +58 -0
  285. data/tasks/terminal_preview/preview_timing.rb +22 -0
  286. data/tasks/terminal_preview/safety_confirmation.rb +56 -0
  287. data/tasks/terminal_preview/saved_screenshot.rb +53 -0
  288. data/tasks/terminal_preview/system_appearance.rb +11 -0
  289. data/tasks/terminal_preview/terminal_window.rb +136 -0
  290. data/tasks/terminal_preview/window_id.rb +14 -0
  291. data/tasks/terminal_preview.rake +28 -0
  292. data/tasks/test.rake +2 -2
  293. data/tasks/website/index_page.rb +3 -3
  294. data/tasks/website/version.rb +10 -10
  295. data/tasks/website/version_menu.rb +10 -12
  296. data/tasks/website/versioned_documentation.rb +49 -17
  297. data/tasks/website/website.rb +6 -8
  298. data/tasks/website.rake +4 -4
  299. metadata +206 -54
  300. data/LICENSES/BSD-2-Clause.txt +0 -9
  301. data/doc/images/examples-analytics.rb.png +0 -0
  302. data/doc/images/examples-box_demo.rb.png +0 -0
  303. data/doc/images/examples-calendar_demo.rb.png +0 -0
  304. data/doc/images/examples-chart_demo.rb.png +0 -0
  305. data/doc/images/examples-custom_widget.rb.png +0 -0
  306. data/doc/images/examples-dashboard.rb.png +0 -0
  307. data/doc/images/examples-list_styles.rb.png +0 -0
  308. data/doc/images/examples-login_form.rb.png +0 -0
  309. data/doc/images/examples-map_demo.rb.png +0 -0
  310. data/doc/images/examples-mouse_events.rb.png +0 -0
  311. data/doc/images/examples-popup_demo.rb.gif +0 -0
  312. data/doc/images/examples-quickstart_lifecycle.rb.png +0 -0
  313. data/doc/images/examples-scroll_text.rb.png +0 -0
  314. data/doc/images/examples-scrollbar_demo.rb.png +0 -0
  315. data/doc/images/examples-stock_ticker.rb.png +0 -0
  316. data/doc/images/examples-system_monitor.rb.png +0 -0
  317. data/doc/images/examples-table_select.rb.png +0 -0
  318. data/examples/analytics.rb +0 -88
  319. data/examples/box_demo.rb +0 -71
  320. data/examples/calendar_demo.rb +0 -55
  321. data/examples/chart_demo.rb +0 -84
  322. data/examples/custom_widget.rb +0 -43
  323. data/examples/dashboard.rb +0 -72
  324. data/examples/list_styles.rb +0 -66
  325. data/examples/login_form.rb +0 -115
  326. data/examples/map_demo.rb +0 -58
  327. data/examples/mouse_events.rb +0 -95
  328. data/examples/popup_demo.rb +0 -105
  329. data/examples/quickstart_dsl.rb +0 -30
  330. data/examples/quickstart_lifecycle.rb +0 -40
  331. data/examples/readme_usage.rb +0 -21
  332. data/examples/scroll_text.rb +0 -74
  333. data/examples/scrollbar_demo.rb +0 -75
  334. data/examples/stock_ticker.rb +0 -93
  335. data/examples/system_monitor.rb +0 -94
  336. data/examples/table_select.rb +0 -70
  337. data/examples/test_analytics.rb +0 -65
  338. data/examples/test_box_demo.rb +0 -38
  339. data/examples/test_calendar_demo.rb +0 -66
  340. data/examples/test_dashboard.rb +0 -38
  341. data/examples/test_list_styles.rb +0 -61
  342. data/examples/test_login_form.rb +0 -63
  343. data/examples/test_map_demo.rb +0 -100
  344. data/examples/test_popup_demo.rb +0 -62
  345. data/examples/test_scroll_text.rb +0 -130
  346. data/examples/test_stock_ticker.rb +0 -39
  347. data/examples/test_system_monitor.rb +0 -40
  348. data/examples/test_table_select.rb +0 -37
  349. data/ext/ratatui_ruby/src/buffer.rs +0 -54
  350. data/lib/ratatui_ruby/dsl.rb +0 -64
@@ -1,21 +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
-
8
- require "ratatui_ruby"
9
- RatatuiRuby.main_loop do |tui|
10
- tui.draw \
11
- tui.paragraph \
12
- text: "Hello, Ratatui! Press 'q' to quit.",
13
- align: :center,
14
- block: tui.block(
15
- title: "My Ruby TUI App",
16
- borders: [:all],
17
- border_color: "cyan"
18
- )
19
- event = tui.poll_event
20
- break if event && event[:type] == :key && event[:code] == "q"
21
- end
@@ -1,74 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: AGPL-3.0-or-later
6
-
7
- $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
8
- require "ratatui_ruby"
9
-
10
- # Demo: Scrollable Paragraph
11
- # Shows how to scroll through long text content using arrow keys
12
- class ScrollTextDemo
13
- def initialize
14
- @scroll_x = 0
15
- @scroll_y = 0
16
- @lines = (1..100).map { |i| "Line #{i}: This is a long line of text that can be scrolled horizontally" }
17
- end
18
-
19
- def run
20
- RatatuiRuby.init_terminal
21
- begin
22
- loop do
23
- draw
24
- break if handle_input == :quit
25
- end
26
- ensure
27
- RatatuiRuby.restore_terminal
28
- end
29
- end
30
-
31
- def render
32
- draw
33
- end
34
-
35
- def handle_input
36
- event = RatatuiRuby.poll_event
37
- return nil unless event
38
-
39
- if event[:type] == :key
40
- case event[:code]
41
- when "up"
42
- @scroll_y = [@scroll_y - 1, 0].max
43
- when "down"
44
- @scroll_y = [@scroll_y + 1, @lines.length].min
45
- when "left"
46
- @scroll_x = [@scroll_x - 1, 0].max
47
- when "right"
48
- @scroll_x = [@scroll_x + 1, 100].min
49
- when "q"
50
- return :quit
51
- end
52
- end
53
- nil
54
- end
55
-
56
- private
57
-
58
- def draw
59
- text = @lines.join("\n")
60
-
61
- paragraph = RatatuiRuby::Paragraph.new(
62
- text: text,
63
- scroll: [@scroll_y, @scroll_x],
64
- block: RatatuiRuby::Block.new(
65
- title: "Scrollable Text (X: #{@scroll_x}, Y: #{@scroll_y}) - Arrow keys to scroll, 'q' to quit",
66
- borders: [:all]
67
- )
68
- )
69
-
70
- RatatuiRuby.draw(paragraph)
71
- end
72
- end
73
-
74
- ScrollTextDemo.new.run if __FILE__ == $PROGRAM_NAME
@@ -1,75 +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
- # Simple Scrollbar Demo
10
- class ScrollbarDemo
11
- def initialize
12
- @scroll_position = 0
13
- @content_length = 50
14
- @lines = (1..@content_length).map { |i| "Line #{i}" }
15
- end
16
-
17
- def run
18
- RatatuiRuby.init_terminal
19
- begin
20
- loop do
21
- draw
22
- event = RatatuiRuby.poll_event
23
- break if event && event[:type] == :key && event[:code] == "q"
24
-
25
- handle_event(event)
26
- end
27
- ensure
28
- RatatuiRuby.restore_terminal
29
- end
30
- end
31
-
32
- private def handle_event(event)
33
- return unless event && event[:type] == :mouse
34
-
35
- case event[:kind]
36
- when :scroll_up
37
- @scroll_position = [@scroll_position - 1, 0].max
38
- when :scroll_down
39
- @scroll_position = [@scroll_position + 1, @content_length].min
40
- end
41
- end
42
-
43
- private def draw
44
- # Calculate visible lines based on scroll position
45
- # In a real app, you'd want to know the height of the available area.
46
- # For this demo, we'll just show all lines but offset the text.
47
- visible_lines = @lines[@scroll_position..-1] || []
48
-
49
- # Paragraph with content
50
- p = RatatuiRuby::Paragraph.new(
51
- text: visible_lines.join("\n"),
52
- block: RatatuiRuby::Block.new(title: "Scroll with Mouse Wheel", borders: [:all])
53
- )
54
-
55
- # Scrollbar on the right
56
- s = RatatuiRuby::Scrollbar.new(
57
- content_length: @content_length,
58
- position: @scroll_position
59
- )
60
-
61
- # Use a Layout to place scrollbar on the right
62
- layout = RatatuiRuby::Layout.new(
63
- direction: :horizontal,
64
- constraints: [
65
- RatatuiRuby::Constraint.percentage(95),
66
- RatatuiRuby::Constraint.percentage(5),
67
- ],
68
- children: [p, s]
69
- )
70
-
71
- RatatuiRuby.draw(layout)
72
- end
73
- end
74
-
75
- ScrollbarDemo.new.run if __FILE__ == $PROGRAM_NAME
@@ -1,93 +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
- # Simulate a stock ticker
10
- class StockTickerApp
11
- def initialize
12
- @network_data = Array.new(50) { rand(0..10) }
13
- @ruby_stock = []
14
- @rust_stock = []
15
- @counter = 0
16
- end
17
-
18
- def run
19
- RatatuiRuby.init_terminal
20
- begin
21
- loop do
22
- render
23
- break if handle_input == :quit
24
- sleep 0.1
25
- end
26
- ensure
27
- RatatuiRuby.restore_terminal
28
- end
29
- end
30
-
31
- def render
32
- # Update data
33
- @counter += 1
34
- @network_data.shift
35
- @network_data << rand(0..10)
36
-
37
- ruby_val = 50.0 + (Math.sin(@counter * 0.1) * 20.0) + (rand * 5.0)
38
- rust_val = 40.0 + (Math.cos(@counter * 0.2) * 15.0) + (rand * 10.0)
39
-
40
- @ruby_stock << [@counter.to_f, ruby_val]
41
- @rust_stock << [@counter.to_f, rust_val]
42
-
43
- # Keep only last 100 points
44
- if @ruby_stock.length > 100
45
- @ruby_stock.shift
46
- @rust_stock.shift
47
- end
48
-
49
- # Define UI
50
- ui = RatatuiRuby::Layout.new(
51
- direction: :vertical,
52
- constraints: [
53
- RatatuiRuby::Constraint.new(type: :percentage, value: 20),
54
- RatatuiRuby::Constraint.new(type: :percentage, value: 80),
55
- ],
56
- children: [
57
- RatatuiRuby::Sparkline.new(
58
- data: @network_data,
59
- style: RatatuiRuby::Style.new(fg: :cyan),
60
- block: RatatuiRuby::Block.new(title: "Network Activity", borders: :all)
61
- ),
62
- RatatuiRuby::Chart.new(
63
- datasets: [
64
- RatatuiRuby::Dataset.new(name: "RBY", data: @ruby_stock, color: :green),
65
- RatatuiRuby::Dataset.new(name: "RST", data: @rust_stock, color: :red),
66
- ],
67
- x_axis: RatatuiRuby::Axis.new(
68
- title: "Time",
69
- bounds: [((@counter > 100) ? @counter - 100.0 : 0.0), @counter.to_f],
70
- labels: [@counter.to_s]
71
- ),
72
- y_axis: RatatuiRuby::Axis.new(
73
- title: "Price",
74
- bounds: [0.0, 100.0],
75
- labels: %w[0 50 100]
76
- ),
77
- block: RatatuiRuby::Block.new(title: "Stock Ticker", borders: :all),
78
- ),
79
- ]
80
- )
81
-
82
- RatatuiRuby.draw(ui)
83
- end
84
-
85
- def handle_input
86
- event = RatatuiRuby.poll_event
87
- if event && event[:code] == "q"
88
- :quit
89
- end
90
- end
91
- end
92
-
93
- StockTickerApp.new.run if __FILE__ == $0
@@ -1,94 +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
- class SystemMonitorApp
10
- def initialize
11
- @percentage = 50
12
- end
13
-
14
- def run
15
- RatatuiRuby.init_terminal
16
- begin
17
- loop do
18
- render
19
- break if handle_input == :quit
20
- end
21
- ensure
22
- RatatuiRuby.restore_terminal
23
- end
24
- end
25
-
26
- def render
27
- # System Monitor Layout
28
- # Top: Table (50%)
29
- # Bottom: Gauge (50%)
30
-
31
- header_style = RatatuiRuby::Style.new(fg: :blue, modifiers: [:bold])
32
-
33
- header = [
34
- RatatuiRuby::Paragraph.new(text: "PID", style: header_style),
35
- RatatuiRuby::Paragraph.new(text: "Name", style: header_style),
36
- RatatuiRuby::Paragraph.new(text: "CPU%", style: header_style),
37
- RatatuiRuby::Paragraph.new(text: "Mem%", style: header_style),
38
- ]
39
-
40
- rows = [
41
- ["1234", "ruby", "0.5", "1.2"],
42
- ["5678", "rust", "10.2", "4.5"],
43
- ["9012", "system", "1.1", "0.8"],
44
- ]
45
-
46
- widths = [
47
- RatatuiRuby::Constraint.length(10),
48
- RatatuiRuby::Constraint.min(20),
49
- RatatuiRuby::Constraint.length(10),
50
- RatatuiRuby::Constraint.length(10),
51
- ]
52
-
53
- table = RatatuiRuby::Table.new(
54
- header:,
55
- rows:,
56
- widths:,
57
- block: RatatuiRuby::Block.new(title: "Processes", borders: [:all])
58
- )
59
-
60
- gauge = RatatuiRuby::Gauge.new(
61
- ratio: @percentage / 100.0,
62
- label: "#{@percentage}%",
63
- style: RatatuiRuby::Style.new(fg: :green),
64
- block: RatatuiRuby::Block.new(title: "Memory Usage", borders: [:all])
65
- )
66
-
67
- layout = RatatuiRuby::Layout.new(
68
- direction: :vertical,
69
- children: [table, gauge],
70
- constraints: [
71
- RatatuiRuby::Constraint.percentage(50),
72
- RatatuiRuby::Constraint.percentage(50),
73
- ]
74
- )
75
-
76
- RatatuiRuby.draw(layout)
77
- end
78
-
79
- def handle_input
80
- event = RatatuiRuby.poll_event
81
- if event
82
- case event[:code]
83
- when "q"
84
- :quit
85
- when "up"
86
- @percentage = [@percentage + 5, 100].min
87
- when "down"
88
- @percentage = [@percentage - 5, 0].max
89
- end
90
- end
91
- end
92
- end
93
-
94
- SystemMonitorApp.new.run if __FILE__ == $0
@@ -1,70 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: AGPL-3.0-or-later
6
-
7
- $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
8
- require "bundler/setup"
9
- require "ratatui_ruby"
10
-
11
- # Sample process data
12
- PROCESSES = [
13
- { pid: 1234, name: "ruby", cpu: 15.2 },
14
- { pid: 5678, name: "postgres", cpu: 8.7 },
15
- { pid: 9012, name: "nginx", cpu: 3.1 },
16
- { pid: 3456, name: "redis", cpu: 12.4 },
17
- { pid: 7890, name: "sidekiq", cpu: 22.8 },
18
- { pid: 2345, name: "webpack", cpu: 45.3 },
19
- { pid: 6789, name: "node", cpu: 18.9 }
20
- ].freeze
21
-
22
- selected_index = 0
23
-
24
- RatatuiRuby.init_terminal
25
-
26
- begin
27
- loop do
28
- # Create table rows from process data
29
- rows = PROCESSES.map { |p| [p[:pid].to_s, p[:name], "#{p[:cpu]}%"] }
30
-
31
- # Define column widths
32
- widths = [
33
- RatatuiRuby::Constraint.length(8),
34
- RatatuiRuby::Constraint.length(15),
35
- RatatuiRuby::Constraint.length(10)
36
- ]
37
-
38
- # Create highlight style (yellow text)
39
- highlight_style = RatatuiRuby::Style.new(fg: :yellow)
40
-
41
- # Create table with selection
42
- table = RatatuiRuby::Table.new(
43
- header: ["PID", "Name", "CPU"],
44
- rows: rows,
45
- widths: widths,
46
- selected_row: selected_index,
47
- highlight_style: highlight_style,
48
- highlight_symbol: "> ",
49
- block: RatatuiRuby::Block.new(title: "Process Monitor (↑/↓ to select, q to quit)", borders: :all)
50
- )
51
-
52
- # Draw the table
53
- RatatuiRuby.draw(table)
54
-
55
- # Handle events
56
- event = RatatuiRuby.poll_event
57
- next unless event
58
-
59
- case event[:code]
60
- when "q"
61
- break
62
- when "down", "j"
63
- selected_index = (selected_index + 1) % PROCESSES.length
64
- when "up", "k"
65
- selected_index = (selected_index - 1) % PROCESSES.length
66
- end
67
- end
68
- ensure
69
- RatatuiRuby.restore_terminal
70
- end
@@ -1,65 +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 "analytics"
11
-
12
- class Minitest::Test
13
- include RatatuiRuby::TestHelper
14
- end
15
-
16
- class TestAnalytics < Minitest::Test
17
- def setup
18
- @app = AnalyticsApp.new
19
- end
20
-
21
- def test_render_initial_state
22
- with_test_terminal(50, 20) do
23
- @app.render
24
-
25
- # Check Tabs
26
- assert buffer_content.any? { |line| line.include?("Revenue") }
27
- assert buffer_content.any? { |line| line.include?("Traffic") }
28
- assert buffer_content.any? { |line| line.include?("Errors") }
29
-
30
- # Check initial selected tab content
31
- assert buffer_content.any? { |line| line.include?("Analytics: Revenue") }
32
- end
33
- end
34
-
35
- def test_navigation_right
36
- inject_event("key", { code: "right" })
37
- @app.handle_input
38
-
39
- with_test_terminal(50, 20) do
40
- @app.render
41
- assert buffer_content.any? { |line| line.include?("Analytics: Traffic") }
42
- end
43
- end
44
-
45
- def test_navigation_left
46
- # Move right to Traffic
47
- inject_event("key", { code: "right" })
48
- @app.handle_input
49
-
50
- # Move left back to Revenue
51
- inject_event("key", { code: "left" })
52
- @app.handle_input
53
-
54
- with_test_terminal(50, 20) do
55
- @app.render
56
- assert buffer_content.any? { |line| line.include?("Analytics: Revenue") }
57
- end
58
- end
59
-
60
- def test_quit
61
- inject_event("key", { code: "q" })
62
- status = @app.handle_input
63
- assert_equal :quit, status
64
- end
65
- end
@@ -1,38 +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 "box_demo"
11
-
12
- class Minitest::Test
13
- include RatatuiRuby::TestHelper
14
- end
15
-
16
- class TestBoxDemo < Minitest::Test
17
- def setup
18
- @app = BoxDemoApp.new
19
- end
20
-
21
- def test_render_initial_state
22
- with_test_terminal(40, 10) do
23
- @app.render
24
- assert buffer_content.any? { |line| line.include?("Box Demo") }
25
- assert buffer_content.any? { |line| line.include?("Press Arrow Keys") }
26
- end
27
- end
28
-
29
- def test_interaction
30
- inject_event("key", { code: "up" })
31
- @app.handle_input
32
-
33
- with_test_terminal(40, 10) do
34
- @app.render
35
- assert buffer_content.any? { |line| line.include?("Up Pressed!") }
36
- end
37
- end
38
- end
@@ -1,66 +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
- require "minitest/autorun"
7
- require "ratatui_ruby"
8
-
9
- module CalendarDemo
10
- class TestCalendarDemo < Minitest::Test
11
- def setup
12
- RatatuiRuby.init_test_terminal(40, 20)
13
- end
14
-
15
- def test_demo_renders
16
- # We can't easily test the loop in run, but we can test the rendering logic
17
- now = Time.now
18
- calendar = RatatuiRuby::Calendar.new(
19
- year: now.year,
20
- month: now.month,
21
- header_style: RatatuiRuby::Style.new(fg: "yellow", modifiers: [:bold]),
22
- block: RatatuiRuby::Block.new(title: " Calendar (q = quit) ", borders: [:all]),
23
- )
24
-
25
- # Constrain the calendar to 24x10 characters
26
- view = RatatuiRuby::Layout.new(
27
- direction: :vertical,
28
- constraints: [
29
- RatatuiRuby::Constraint.length(10),
30
- RatatuiRuby::Constraint.min(0),
31
- ],
32
- children: [
33
- RatatuiRuby::Layout.new(
34
- direction: :horizontal,
35
- constraints: [
36
- RatatuiRuby::Constraint.length(24),
37
- RatatuiRuby::Constraint.min(0),
38
- ],
39
- children: [calendar, nil],
40
- ),
41
- nil,
42
- ],
43
- )
44
-
45
- RatatuiRuby.draw(view)
46
- content = RatatuiRuby.get_buffer_content
47
-
48
- assert_match(/Calendar \(q = quit\)/, content)
49
- assert_match(/#{now.year}/, content)
50
-
51
- # Verify the size constraint: the terminal is 40x20
52
- # But the layout should be constrained to 24x10.
53
- lines = content.split("\n")
54
-
55
- # First 10 rows: first 24 chars can have content, 24..39 should be empty
56
- 10.times do |i|
57
- assert_equal " " * 16, lines[i][24..39], "Row #{i} should be empty after column 24"
58
- end
59
-
60
- # Rows 10..19 should be completely empty
61
- (10..19).each do |i|
62
- assert_equal " " * 40, lines[i], "Row #{i} should be completely empty"
63
- end
64
- end
65
- end
66
- end
@@ -1,38 +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 "dashboard"
11
-
12
- class Minitest::Test
13
- include RatatuiRuby::TestHelper
14
- end
15
-
16
- class TestDashboard < Minitest::Test
17
- def setup
18
- @app = DashboardApp.new
19
- end
20
-
21
- def test_render_initial_state
22
- with_test_terminal(60, 20) do
23
- @app.render
24
- assert buffer_content.any? { |line| line.include?("Item 1") }
25
- assert buffer_content.any? { |line| line.include?("You selected: Item 1") }
26
- end
27
- end
28
-
29
- def test_navigation
30
- inject_event("key", { code: "down" })
31
- @app.handle_input
32
-
33
- with_test_terminal(60, 20) do
34
- @app.render
35
- assert buffer_content.any? { |line| line.include?("You selected: Item 2") }
36
- end
37
- end
38
- end
@@ -1,61 +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 "list_styles"
11
-
12
- class Minitest::Test
13
- include RatatuiRuby::TestHelper
14
- end
15
-
16
- class TestListStyles < Minitest::Test
17
- def setup
18
- @app = ListStylesApp.new
19
- end
20
-
21
- def test_render_initial_state
22
- with_test_terminal(50, 20) do
23
- @app.render
24
-
25
- assert buffer_content.any? { |line| line.include?(">> Item 1") }
26
- assert buffer_content.any? { |line| line.include?(" Item 2") }
27
- end
28
- end
29
-
30
- def test_navigation_down
31
- inject_event("key", { code: "down" })
32
- @app.handle_input
33
-
34
- with_test_terminal(50, 20) do
35
- @app.render
36
- assert buffer_content.any? { |line| line.include?(" Item 1") }
37
- assert buffer_content.any? { |line| line.include?(">> Item 2") }
38
- end
39
- end
40
-
41
- def test_navigation_up
42
- # Move down to Item 2
43
- inject_event("key", { code: "down" })
44
- @app.handle_input
45
-
46
- # Move up back to Item 1
47
- inject_event("key", { code: "up" })
48
- @app.handle_input
49
-
50
- with_test_terminal(50, 20) do
51
- @app.render
52
- assert buffer_content.any? { |line| line.include?(">> Item 1") }
53
- end
54
- end
55
-
56
- def test_quit
57
- inject_event("key", { code: "q" })
58
- status = @app.handle_input
59
- assert_equal :quit, status
60
- end
61
- end