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,110 +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 "minitest/autorun"
9
- require "ratatui_ruby/test_helper"
10
-
11
- require_relative "app"
12
-
13
- class TestScrollTextApp < Minitest::Test
14
- include RatatuiRuby::TestHelper
15
-
16
- def setup
17
- @app = ScrollTextApp.new
18
- end
19
-
20
- def test_demo_initialization
21
- assert_instance_of ScrollTextApp, @app
22
- end
23
-
24
- def test_initial_rendering
25
- with_test_terminal do
26
- # Queue quit
27
- inject_key(:q)
28
-
29
- @app.run
30
-
31
- content = buffer_content
32
-
33
- # Should show Line 1 somewhere in the output
34
- assert content.any? { |line| line.include?("Line 1") }
35
- # Should show controls
36
- assert content.any? { |line| line.include?("Controls") }
37
- assert content.any? { |line| line.include?("Vert Scroll (0/102)") }
38
- end
39
- end
40
-
41
- def test_scroll_down
42
- with_test_terminal do
43
- # Scroll down then quit
44
- inject_keys(:down, :q)
45
-
46
- @app.run
47
-
48
- content = buffer_content
49
-
50
- # Should show controls with updated Y position
51
- assert content.any? { |line| line.include?("Vert Scroll (1/102)") }
52
- end
53
- end
54
-
55
- def test_scroll_right
56
- with_test_terminal do
57
- # Scroll right then quit
58
- inject_keys(:right, :q)
59
-
60
- @app.run
61
-
62
- content = buffer_content
63
-
64
- # Should render without error
65
- assert content.any? { |line| line.include?("Controls") }
66
- end
67
- end
68
-
69
- def test_scroll_left_at_edge
70
- with_test_terminal do
71
- # Scroll left then quit (boundary test)
72
- inject_keys(:left, :q)
73
-
74
- @app.run
75
-
76
- content = buffer_content
77
-
78
- # Should still show the controls
79
- assert content.any? { |line| line.include?("Vert Scroll") }
80
- end
81
- end
82
-
83
- def test_scroll_up_at_top
84
- with_test_terminal do
85
- # Scroll up then quit (boundary test)
86
- inject_keys(:up, :q)
87
-
88
- @app.run
89
-
90
- content = buffer_content
91
-
92
- # Should still show the controls
93
- assert content.any? { |line| line.include?("Controls") }
94
- end
95
- end
96
-
97
- def test_multiple_scrolls
98
- with_test_terminal do
99
- # Scroll down and right multiple times
100
- inject_keys(:down, :down, :right, :right, :right, :q)
101
-
102
- @app.run
103
-
104
- content = buffer_content
105
-
106
- # Should render without error
107
- assert content.any? { |line| line.include?("Scrollable Text") }
108
- end
109
- end
110
- end
@@ -1,143 +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 ScrollbarDemoApp
11
- def initialize
12
- @scroll_position = 0
13
- @content_length = 50
14
- @lines = (1..@content_length).map { |i| "Line #{i}" }
15
- @orientation_index = 0
16
- @orientations = [
17
- :vertical,
18
- :vertical_right,
19
- :vertical_left,
20
- :horizontal,
21
- :horizontal_bottom,
22
- :horizontal_top
23
- ]
24
- @theme_index = 0
25
- @themes = [
26
- {
27
- name: "Standard",
28
- track_symbol: nil,
29
- thumb_symbol: "█",
30
- track_style: nil,
31
- thumb_style: nil,
32
- begin_symbol: nil,
33
- end_symbol: nil
34
- },
35
- {
36
- name: "Rounded",
37
- track_symbol: "│",
38
- thumb_symbol: "┃",
39
- track_style: { fg: "dark_gray" },
40
- thumb_style: { fg: "cyan" },
41
- begin_symbol: "▲",
42
- end_symbol: "▼"
43
- },
44
- {
45
- name: "ASCII",
46
- track_symbol: "|",
47
- thumb_symbol: "#",
48
- track_style: { fg: "white" },
49
- thumb_style: { fg: "red" },
50
- begin_symbol: "^",
51
- end_symbol: "v"
52
- },
53
- {
54
- name: "Minimal",
55
- track_symbol: " ",
56
- thumb_symbol: "▐",
57
- track_style: nil,
58
- thumb_style: { fg: "yellow" },
59
- begin_symbol: nil,
60
- end_symbol: nil
61
- }
62
- ]
63
- end
64
-
65
- def run
66
- RatatuiRuby.run do
67
- loop do
68
- draw
69
- event = RatatuiRuby.poll_event
70
- break if event == "q" || event == :ctrl_c
71
-
72
- handle_event(event)
73
- end
74
- end
75
- end
76
-
77
- private def handle_event(event)
78
- return unless event
79
-
80
- if event.mouse?
81
- case event.kind
82
- when "scroll_up"
83
- @scroll_position = [@scroll_position - 1, 0].max
84
- when "scroll_down"
85
- @scroll_position = [@scroll_position + 1, @content_length].min
86
- end
87
- end
88
-
89
- if event.key? && event.to_s == "s"
90
- @theme_index = (@theme_index + 1) % @themes.length
91
- end
92
-
93
- if event.key? && event.to_s == "o"
94
- @orientation_index = (@orientation_index + 1) % @orientations.length
95
- end
96
- end
97
-
98
- private def draw
99
- # Calculate visible lines based on scroll position
100
- # In a real app, you'd want to know the height of the available area.
101
- # For this demo, we'll just show all lines but offset the text.
102
- visible_lines = @lines[@scroll_position..-1] || []
103
-
104
- # Paragraph with content
105
- theme = @themes[@theme_index]
106
- orientation = @orientations[@orientation_index]
107
-
108
- p = RatatuiRuby::Paragraph.new(
109
- text: visible_lines.join("\n"),
110
- block: RatatuiRuby::Block.new(
111
- titles: [
112
- { content: "Scroll with Mouse Wheel | Theme: #{theme[:name]} | Orientation: #{orientation}" },
113
- { content: "Press 's' to cycle theme, 'o' to cycle orientation", position: :bottom, alignment: :center }
114
- ],
115
- borders: [:all]
116
- )
117
- )
118
-
119
- # Scrollbar
120
- s = RatatuiRuby::Scrollbar.new(
121
- content_length: @content_length,
122
- position: @scroll_position,
123
- orientation: orientation,
124
- track_symbol: theme[:track_symbol],
125
- thumb_symbol: theme[:thumb_symbol],
126
- track_style: theme[:track_style],
127
- thumb_style: theme[:thumb_style],
128
- begin_symbol: theme[:begin_symbol],
129
- end_symbol: theme[:end_symbol]
130
- )
131
-
132
- # Use Overlay to stack Scrollbar on top of Paragraph.
133
- # The Scrollbar will position itself on the correct edge (top/bottom/left/right)
134
- # based on its orientation, demonstrating that the property works independently of layout.
135
- overlay = RatatuiRuby::Overlay.new(
136
- layers: [p, s]
137
- )
138
-
139
- RatatuiRuby.draw(overlay)
140
- end
141
- end
142
-
143
- ScrollbarDemoApp.new.run if __FILE__ == $PROGRAM_NAME
@@ -1,7 +0,0 @@
1
- class ScrollbarDemoApp
2
- # @public
3
- def self.new: () -> ScrollbarDemoApp
4
-
5
- # @public
6
- def run: () -> void
7
- end
@@ -1,77 +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 "test_helper"
7
- require_relative "app"
8
-
9
- class TestScrollbarDemoApp < Minitest::Test
10
- include RatatuiRuby::TestHelper
11
-
12
- def setup
13
- @app = ScrollbarDemoApp.new
14
- end
15
-
16
- def test_initial_render
17
- with_test_terminal do
18
- # Queue quit event to exit loop immediately
19
- inject_key(:q)
20
-
21
- # Stub init_terminal/restore_terminal to use test terminal
22
- @app.run
23
-
24
- content = buffer_content
25
-
26
- # Top border with title (truncated due to small width)
27
- assert_includes content[0], "Scroll"
28
- # First line of content
29
- assert_includes content[1], "Line 1"
30
- # Scrollbar area (far right)
31
- assert_equal "█", content[1][-1]
32
- end
33
- end
34
-
35
- def test_scroll_down
36
- with_test_terminal do
37
- # Queue scroll down + quit
38
- inject_event(RatatuiRuby::Event::Mouse.new(kind: "scroll_down", x: 0, y: 0, button: "none"))
39
- inject_key(:q)
40
-
41
- @app.run
42
-
43
- content = buffer_content
44
-
45
- # Now it should start from Line 2
46
- assert_includes content[1], "Line 2"
47
- refute_includes content[1], "Line 1"
48
- end
49
- end
50
-
51
- def test_scroll_up
52
- with_test_terminal do
53
- # Queue scroll down + scroll up + quit
54
- inject_event(RatatuiRuby::Event::Mouse.new(kind: "scroll_down", x: 0, y: 0, button: "none"))
55
- inject_event(RatatuiRuby::Event::Mouse.new(kind: "scroll_up", x: 0, y: 0, button: "none"))
56
- inject_key(:q)
57
-
58
- @app.run
59
-
60
- content = buffer_content
61
-
62
- assert_includes content[1], "Line 1"
63
- end
64
- end
65
-
66
- def test_theme_cycling
67
- with_test_terminal do
68
- # Queue 's' + quit
69
- inject_keys(:s, :q)
70
-
71
- @app.run
72
-
73
- content = buffer_content
74
- assert_match(/Theme: Rounded/, content[0])
75
- end
76
- end
77
- end
@@ -1,240 +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
- # Demonstrates Sparkline widget with interactive attribute cycling.
10
- class SparklineDemoApp
11
- def initialize
12
- # Data sets with different characteristics
13
- @data_sets = [
14
- {
15
- name: "Steady Growth",
16
- data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
17
- },
18
- {
19
- name: "With Gaps",
20
- data: [5, nil, 8, nil, 6, nil, 9, nil, 7, nil, 10, nil]
21
- },
22
- {
23
- name: "Random",
24
- data: [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8]
25
- },
26
- {
27
- name: "Sawtooth",
28
- data: [1, 2, 3, 4, 5, 4, 3, 2, 1, 2, 3, 4]
29
- },
30
- {
31
- name: "Peaks",
32
- data: [1, 5, 1, 8, 1, 6, 1, 9, 1, 7, 1, 10]
33
- }
34
- ]
35
- @data_index = 0
36
-
37
- @directions = [
38
- { name: "Left to Right", direction: :left_to_right },
39
- { name: "Right to Left", direction: :right_to_left }
40
- ]
41
- @direction_index = 0
42
-
43
- @styles = [
44
- { name: "Green", style: RatatuiRuby::Style.new(fg: :green) },
45
- { name: "Yellow", style: RatatuiRuby::Style.new(fg: :yellow) },
46
- { name: "Red", style: RatatuiRuby::Style.new(fg: :red) },
47
- { name: "Cyan", style: RatatuiRuby::Style.new(fg: :cyan) },
48
- { name: "Magenta", style: RatatuiRuby::Style.new(fg: :magenta) }
49
- ]
50
- @style_index = 0
51
-
52
- @absent_symbols = [
53
- { name: "None", symbol: nil },
54
- { name: "Dot (·)", symbol: "·" },
55
- { name: "Square (▫)", symbol: "▫" },
56
- { name: "Dash (-)", symbol: "-" },
57
- { name: "Underscore (_)", symbol: "_" }
58
- ]
59
- @absent_symbol_index = 1
60
-
61
- @absent_styles = [
62
- { name: "Default", style: nil },
63
- { name: "Dark Gray", style: RatatuiRuby::Style.new(fg: :dark_gray) },
64
- { name: "Dim Red", style: RatatuiRuby::Style.new(fg: :red, modifiers: [:dim]) },
65
- { name: "Dim Yellow", style: RatatuiRuby::Style.new(fg: :yellow, modifiers: [:dim]) }
66
- ]
67
- @absent_style_index = 0
68
-
69
- @bar_sets = [
70
- { name: "Default (Block)", set: nil },
71
- { name: "Numbers (0-8)", set: {
72
- 0 => "0", 1 => "1", 2 => "2", 3 => "3", 4 => "4", 5 => "5", 6 => "6", 7 => "7", 8 => "8"
73
- }},
74
- { name: "ASCII (Heights)", set: [" ", "_", ".", "-", "=", "+", "*", "#", "@"] }
75
- ]
76
- @bar_set_index = 0
77
-
78
- @counter = 0
79
- @hotkey_style = RatatuiRuby::Style.new(modifiers: [:bold, :underlined])
80
- end
81
-
82
- def run
83
- RatatuiRuby.run do
84
- loop do
85
- render
86
- break if handle_input == :quit
87
- end
88
- end
89
- end
90
-
91
- private
92
-
93
- def render
94
- @counter += 1
95
-
96
- data_set = @data_sets[@data_index]
97
- direction = @directions[@direction_index][:direction]
98
- style = @styles[@style_index][:style]
99
- absent_symbol = @absent_symbols[@absent_symbol_index][:symbol]
100
- absent_value_style = @absent_styles[@absent_style_index][:style]
101
- bar_set = @bar_sets[@bar_set_index][:set]
102
-
103
- # Use static data for clarity when cycling options
104
- current_data = data_set[:data]
105
-
106
- layout = RatatuiRuby::Layout.new(
107
- direction: :vertical,
108
- constraints: [
109
- RatatuiRuby::Constraint.fill(1),
110
- RatatuiRuby::Constraint.length(6),
111
- ],
112
- children: [
113
- # Main content area with multiple sparkline examples
114
- RatatuiRuby::Layout.new(
115
- direction: :vertical,
116
- constraints: [
117
- RatatuiRuby::Constraint.length(1),
118
- RatatuiRuby::Constraint.length(3),
119
- RatatuiRuby::Constraint.length(3),
120
- RatatuiRuby::Constraint.length(3),
121
- RatatuiRuby::Constraint.length(3),
122
- RatatuiRuby::Constraint.fill(1)
123
- ],
124
- children: [
125
- RatatuiRuby::Paragraph.new(
126
- text: "Sparkline Widget Demo - Cycle attributes with hotkeys"
127
- ),
128
- # Sparkline 1: Main interactive sparkline
129
- RatatuiRuby::Sparkline.new(
130
- data: current_data,
131
- direction:,
132
- style:,
133
- absent_value_symbol: absent_symbol,
134
- absent_value_style:,
135
- bar_set:,
136
- block: RatatuiRuby::Block.new(title: "Interactive Sparkline")
137
- ),
138
- # Sparkline 2: Same data, opposite direction
139
- RatatuiRuby::Sparkline.new(
140
- data: current_data.reverse,
141
- direction:,
142
- style:,
143
- absent_value_symbol: absent_symbol,
144
- absent_value_style:,
145
- bar_set:,
146
- block: RatatuiRuby::Block.new(title: "Reversed Data")
147
- ),
148
- # Sparkline 3: Without absent value symbol (for comparison)
149
- RatatuiRuby::Sparkline.new(
150
- data: current_data,
151
- direction:,
152
- style:,
153
- bar_set:,
154
- block: RatatuiRuby::Block.new(title: "Without Absent Marker")
155
- ),
156
- # Sparkline 4: Gap pattern responsive to absent marker controls
157
- RatatuiRuby::Sparkline.new(
158
- data: [5, nil, 8, nil, 6, nil, 9, nil, 7, nil, 10, nil],
159
- direction:,
160
- style: RatatuiRuby::Style.new(fg: :blue),
161
- absent_value_symbol: absent_symbol,
162
- absent_value_style:,
163
- bar_set:,
164
- block: RatatuiRuby::Block.new(title: "Gap Pattern (Responsive)")
165
- ),
166
- RatatuiRuby::Paragraph.new(text: "")
167
- ]
168
- ),
169
- # Bottom control panel
170
- RatatuiRuby::Block.new(
171
- title: "Controls",
172
- borders: [:all],
173
- children: [
174
- RatatuiRuby::Paragraph.new(
175
- text: [
176
- # Line 1: Data
177
- RatatuiRuby::Text::Line.new(spans: [
178
- RatatuiRuby::Text::Span.new(content: "↑/↓", style: @hotkey_style),
179
- RatatuiRuby::Text::Span.new(content: ": Data (#{@data_sets[@data_index][:name]})")
180
- ]),
181
- # Line 2: View
182
- RatatuiRuby::Text::Line.new(spans: [
183
- RatatuiRuby::Text::Span.new(content: "d", style: @hotkey_style),
184
- RatatuiRuby::Text::Span.new(content: ": Direction (#{@directions[@direction_index][:name]}) "),
185
- RatatuiRuby::Text::Span.new(content: "c", style: @hotkey_style),
186
- RatatuiRuby::Text::Span.new(content: ": Color (#{@styles[@style_index][:name]})")
187
- ]),
188
- # Line 3: Markers
189
- RatatuiRuby::Text::Line.new(spans: [
190
- RatatuiRuby::Text::Span.new(content: "m", style: @hotkey_style),
191
- RatatuiRuby::Text::Span.new(content: ": Absent Value Symbol (#{@absent_symbols[@absent_symbol_index][:name]}) "),
192
- RatatuiRuby::Text::Span.new(content: "s", style: @hotkey_style),
193
- RatatuiRuby::Text::Span.new(content: ": Absent Value Style (#{@absent_styles[@absent_style_index][:name]})")
194
- ]),
195
- # Line 4: General
196
- RatatuiRuby::Text::Line.new(spans: [
197
- RatatuiRuby::Text::Span.new(content: "b", style: @hotkey_style),
198
- RatatuiRuby::Text::Span.new(content: ": Bar Set (#{@bar_sets[@bar_set_index][:name]}) "),
199
- RatatuiRuby::Text::Span.new(content: "q", style: @hotkey_style),
200
- RatatuiRuby::Text::Span.new(content: ": Quit")
201
- ])
202
- ]
203
- )
204
- ]
205
- )
206
- ]
207
- )
208
-
209
-
210
- RatatuiRuby.draw(layout)
211
- end
212
-
213
- def handle_input
214
- event = RatatuiRuby.poll_event
215
- return unless event
216
-
217
- case event
218
- in {type: :key, code: "q"} | {type: :key, code: "c", modifiers: ["ctrl"]}
219
- :quit
220
- in type: :key, code: "up"
221
- @data_index = (@data_index - 1) % @data_sets.length
222
- in type: :key, code: "down"
223
- @data_index = (@data_index + 1) % @data_sets.length
224
- in type: :key, code: "d"
225
- @direction_index = (@direction_index + 1) % @directions.length
226
- in type: :key, code: "c"
227
- @style_index = (@style_index + 1) % @styles.length
228
- in type: :key, code: "m"
229
- @absent_symbol_index = (@absent_symbol_index + 1) % @absent_symbols.length
230
- in type: :key, code: "s"
231
- @absent_style_index = (@absent_style_index + 1) % @absent_styles.length
232
- in type: :key, code: "b"
233
- @bar_set_index = (@bar_set_index + 1) % @bar_sets.length
234
- else
235
- nil
236
- end
237
- end
238
- end
239
-
240
- SparklineDemoApp.new.run if __FILE__ == $PROGRAM_NAME
@@ -1,107 +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 TestSparklineDemoApp < Minitest::Test
13
- include RatatuiRuby::TestHelper
14
-
15
- def setup
16
- @app = SparklineDemoApp.new
17
- end
18
-
19
- def test_initial_render
20
- with_test_terminal do
21
- inject_key(:q)
22
- @app.run
23
-
24
- content = buffer_content.join("\n")
25
- assert_includes content, "Sparkline Widget Demo"
26
- assert_includes content, "Interactive Sparkline"
27
- assert_includes content, "Reversed Data"
28
- end
29
- end
30
-
31
- def test_cycle_data_set_up
32
- with_test_terminal do
33
- inject_keys(:up, :q)
34
- @app.run
35
-
36
- content = buffer_content.join("\n")
37
- # Should still render after cycling
38
- assert_includes content, "Sparkline Widget Demo"
39
- end
40
- end
41
-
42
- def test_cycle_data_set_down
43
- with_test_terminal do
44
- inject_keys(:down, :down, :q)
45
- @app.run
46
-
47
- content = buffer_content.join("\n")
48
- assert_includes content, "Sparkline Widget Demo"
49
- end
50
- end
51
-
52
- def test_cycle_direction
53
- with_test_terminal do
54
- inject_keys(:d, :q)
55
- @app.run
56
-
57
- content = buffer_content.join("\n")
58
- assert_includes content, "Sparkline Widget Demo"
59
- end
60
- end
61
-
62
- def test_cycle_color
63
- with_test_terminal do
64
- inject_keys(:c, :c, :q)
65
- @app.run
66
-
67
- content = buffer_content.join("\n")
68
- assert_includes content, "Sparkline Widget Demo"
69
- end
70
- end
71
-
72
- def test_cycle_absent_marker
73
- with_test_terminal do
74
- inject_keys(:m, :m, :m, :q)
75
- @app.run
76
-
77
- content = buffer_content.join("\n")
78
- assert_includes content, "Sparkline Widget Demo"
79
- end
80
- end
81
-
82
- def test_cycle_absent_style
83
- with_test_terminal do
84
- inject_keys(:s, :s, :q)
85
- @app.run
86
-
87
- content = buffer_content.join("\n")
88
- assert_includes content, "Sparkline Widget Demo"
89
- end
90
- end
91
-
92
- def test_cycle_bar_set
93
- with_test_terminal do
94
- inject_keys(:b, :q)
95
- @app.run
96
-
97
- content = buffer_content.join("\n")
98
- assert_includes content, "Sparkline Widget Demo"
99
- # Verify render with Numbers set (one_eighth="1", etc.)
100
- # Input data [1..12] with implicit max 12.
101
- # With Numbers set, we expect digits 1-8 to appear.
102
- # Just asserting no crash is a start, but let's check for the label update if possible
103
- # The controls footer should update.
104
- # assert_includes content, ": Bar Set" # Included in controls
105
- end
106
- end
107
- end