ratatui_ruby 0.4.0 → 0.6.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 (441) 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 +98 -176
  7. data/CHANGELOG.md +80 -6
  8. data/README.md +19 -7
  9. data/REUSE.toml +15 -0
  10. data/doc/application_architecture.md +179 -45
  11. data/doc/application_testing.md +80 -32
  12. data/doc/contributors/design/ruby_frontend.md +48 -8
  13. data/doc/contributors/design/rust_backend.md +1 -0
  14. data/doc/contributors/developing_examples.md +191 -48
  15. data/doc/contributors/documentation_style.md +7 -0
  16. data/doc/contributors/examples_audit/p1_high.md +21 -0
  17. data/doc/contributors/examples_audit/p2_moderate.md +81 -0
  18. data/doc/contributors/examples_audit.md +41 -0
  19. data/doc/contributors/index.md +2 -0
  20. data/doc/event_handling.md +21 -7
  21. data/doc/images/app_all_events.png +0 -0
  22. data/doc/images/app_color_picker.png +0 -0
  23. data/doc/images/app_login_form.png +0 -0
  24. data/doc/images/app_stateful_interaction.png +0 -0
  25. data/doc/images/verify_quickstart_dsl.png +0 -0
  26. data/doc/images/verify_quickstart_layout.png +0 -0
  27. data/doc/images/verify_quickstart_lifecycle.png +0 -0
  28. data/doc/images/verify_readme_usage.png +0 -0
  29. data/doc/images/widget_barchart_demo.png +0 -0
  30. data/doc/images/widget_block_demo.png +0 -0
  31. data/doc/images/widget_box_demo.png +0 -0
  32. data/doc/images/widget_calendar_demo.png +0 -0
  33. data/doc/images/widget_canvas_demo.png +0 -0
  34. data/doc/images/widget_cell_demo.png +0 -0
  35. data/doc/images/widget_center_demo.png +0 -0
  36. data/doc/images/widget_chart_demo.png +0 -0
  37. data/doc/images/widget_gauge_demo.png +0 -0
  38. data/doc/images/widget_layout_split.png +0 -0
  39. data/doc/images/widget_line_gauge_demo.png +0 -0
  40. data/doc/images/widget_list_demo.png +0 -0
  41. data/doc/images/widget_overlay_demo.png +0 -0
  42. data/doc/images/widget_ratatui_logo_demo.png +0 -0
  43. data/doc/images/widget_ratatui_mascot_demo.png +0 -0
  44. data/doc/images/widget_render.png +0 -0
  45. data/doc/images/widget_rich_text.png +0 -0
  46. data/doc/images/widget_scroll_text.png +0 -0
  47. data/doc/images/widget_scrollbar_demo.png +0 -0
  48. data/doc/images/widget_sparkline_demo.png +0 -0
  49. data/doc/images/widget_style_colors.png +0 -0
  50. data/doc/images/widget_table_demo.png +0 -0
  51. data/doc/images/widget_table_flex.png +0 -0
  52. data/doc/images/widget_tabs_demo.png +0 -0
  53. data/doc/images/widget_text_width.png +0 -0
  54. data/doc/interactive_design.md +25 -30
  55. data/doc/quickstart.md +150 -130
  56. data/doc/terminal_limitations.md +92 -0
  57. data/examples/app_all_events/README.md +99 -0
  58. data/examples/app_all_events/app.rb +96 -0
  59. data/examples/app_all_events/model/app_model.rb +157 -0
  60. data/examples/app_all_events/model/event_color_cycle.rb +41 -0
  61. data/examples/app_all_events/model/event_entry.rb +92 -0
  62. data/examples/app_all_events/model/msg.rb +37 -0
  63. data/examples/app_all_events/model/timestamp.rb +54 -0
  64. data/examples/app_all_events/update.rb +73 -0
  65. data/examples/app_all_events/view/app_view.rb +78 -0
  66. data/examples/app_all_events/view/controls_view.rb +52 -0
  67. data/examples/app_all_events/view/counts_view.rb +59 -0
  68. data/examples/app_all_events/view/live_view.rb +70 -0
  69. data/examples/app_all_events/view/log_view.rb +55 -0
  70. data/examples/app_all_events/view.rb +7 -0
  71. data/examples/app_color_picker/README.md +134 -0
  72. data/examples/app_color_picker/app.rb +74 -0
  73. data/examples/app_color_picker/clipboard.rb +84 -0
  74. data/examples/app_color_picker/color.rb +191 -0
  75. data/examples/app_color_picker/controls.rb +90 -0
  76. data/examples/app_color_picker/copy_dialog.rb +166 -0
  77. data/examples/app_color_picker/export_pane.rb +126 -0
  78. data/examples/app_color_picker/harmony.rb +56 -0
  79. data/examples/app_color_picker/input.rb +174 -0
  80. data/examples/app_color_picker/main_container.rb +178 -0
  81. data/examples/app_color_picker/palette.rb +109 -0
  82. data/examples/app_login_form/README.md +47 -0
  83. data/examples/{login_form → app_login_form}/app.rb +38 -42
  84. data/examples/app_stateful_interaction/README.md +31 -0
  85. data/examples/app_stateful_interaction/app.rb +272 -0
  86. data/examples/timeout_demo.rb +43 -0
  87. data/examples/verify_quickstart_dsl/README.md +48 -0
  88. data/examples/{quickstart_dsl → verify_quickstart_dsl}/app.rb +17 -6
  89. data/examples/verify_quickstart_layout/README.md +71 -0
  90. data/examples/verify_quickstart_layout/app.rb +71 -0
  91. data/examples/verify_quickstart_lifecycle/README.md +56 -0
  92. data/examples/verify_quickstart_lifecycle/app.rb +54 -0
  93. data/examples/verify_readme_usage/README.md +43 -0
  94. data/examples/verify_readme_usage/app.rb +40 -0
  95. data/examples/widget_barchart_demo/README.md +49 -0
  96. data/examples/widget_barchart_demo/app.rb +238 -0
  97. data/examples/widget_block_demo/README.md +34 -0
  98. data/examples/widget_block_demo/app.rb +256 -0
  99. data/examples/widget_box_demo/README.md +45 -0
  100. data/examples/{box_demo → widget_box_demo}/app.rb +99 -65
  101. data/examples/widget_calendar_demo/README.md +39 -0
  102. data/examples/widget_calendar_demo/app.rb +109 -0
  103. data/examples/widget_canvas_demo/README.md +27 -0
  104. data/examples/widget_canvas_demo/app.rb +123 -0
  105. data/examples/widget_cell_demo/README.md +36 -0
  106. data/examples/widget_cell_demo/app.rb +111 -0
  107. data/examples/widget_center_demo/README.md +29 -0
  108. data/examples/widget_center_demo/app.rb +116 -0
  109. data/examples/widget_chart_demo/README.md +41 -0
  110. data/examples/widget_chart_demo/app.rb +218 -0
  111. data/examples/widget_gauge_demo/README.md +41 -0
  112. data/examples/widget_gauge_demo/app.rb +212 -0
  113. data/examples/widget_layout_split/README.md +44 -0
  114. data/examples/widget_layout_split/app.rb +246 -0
  115. data/examples/widget_line_gauge_demo/README.md +41 -0
  116. data/examples/widget_line_gauge_demo/app.rb +217 -0
  117. data/examples/widget_list_demo/README.md +49 -0
  118. data/examples/widget_list_demo/app.rb +366 -0
  119. data/examples/widget_map_demo/README.md +39 -0
  120. data/examples/{map_demo → widget_map_demo}/app.rb +24 -21
  121. data/examples/widget_overlay_demo/app.rb +248 -0
  122. data/examples/widget_popup_demo/README.md +36 -0
  123. data/examples/widget_popup_demo/app.rb +104 -0
  124. data/examples/widget_ratatui_logo_demo/README.md +34 -0
  125. data/examples/widget_ratatui_logo_demo/app.rb +103 -0
  126. data/examples/widget_ratatui_mascot_demo/README.md +34 -0
  127. data/examples/widget_ratatui_mascot_demo/app.rb +93 -0
  128. data/examples/widget_rect/README.md +38 -0
  129. data/examples/widget_rect/app.rb +205 -0
  130. data/examples/widget_render/README.md +37 -0
  131. data/examples/widget_render/app.rb +184 -0
  132. data/examples/widget_rich_text/README.md +35 -0
  133. data/examples/widget_rich_text/app.rb +166 -0
  134. data/examples/widget_scroll_text/README.md +37 -0
  135. data/examples/widget_scroll_text/app.rb +107 -0
  136. data/examples/widget_scrollbar_demo/README.md +37 -0
  137. data/examples/widget_scrollbar_demo/app.rb +153 -0
  138. data/examples/widget_sparkline_demo/README.md +42 -0
  139. data/examples/widget_sparkline_demo/app.rb +275 -0
  140. data/examples/widget_style_colors/README.md +34 -0
  141. data/examples/widget_style_colors/app.rb +19 -21
  142. data/examples/widget_table_demo/README.md +48 -0
  143. data/examples/widget_table_demo/app.rb +239 -0
  144. data/examples/widget_tabs_demo/README.md +41 -0
  145. data/examples/widget_tabs_demo/app.rb +181 -0
  146. data/examples/widget_text_width/README.md +35 -0
  147. data/examples/widget_text_width/app.rb +106 -0
  148. data/ext/ratatui_ruby/Cargo.lock +11 -4
  149. data/ext/ratatui_ruby/Cargo.toml +2 -1
  150. data/ext/ratatui_ruby/src/events.rs +359 -62
  151. data/ext/ratatui_ruby/src/frame.rs +227 -0
  152. data/ext/ratatui_ruby/src/lib.rs +110 -27
  153. data/ext/ratatui_ruby/src/rendering.rs +8 -4
  154. data/ext/ratatui_ruby/src/string_width.rs +101 -0
  155. data/ext/ratatui_ruby/src/style.rs +138 -57
  156. data/ext/ratatui_ruby/src/terminal.rs +42 -22
  157. data/ext/ratatui_ruby/src/text.rs +14 -7
  158. data/ext/ratatui_ruby/src/widgets/barchart.rs +74 -54
  159. data/ext/ratatui_ruby/src/widgets/block.rs +7 -6
  160. data/ext/ratatui_ruby/src/widgets/canvas.rs +21 -3
  161. data/ext/ratatui_ruby/src/widgets/chart.rs +20 -10
  162. data/ext/ratatui_ruby/src/widgets/gauge.rs +9 -2
  163. data/ext/ratatui_ruby/src/widgets/layout.rs +9 -4
  164. data/ext/ratatui_ruby/src/widgets/line_gauge.rs +9 -2
  165. data/ext/ratatui_ruby/src/widgets/list.rs +211 -12
  166. data/ext/ratatui_ruby/src/widgets/list_state.rs +137 -0
  167. data/ext/ratatui_ruby/src/widgets/mod.rs +3 -0
  168. data/ext/ratatui_ruby/src/widgets/overlay.rs +2 -1
  169. data/ext/ratatui_ruby/src/widgets/paragraph.rs +1 -1
  170. data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +19 -8
  171. data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +17 -10
  172. data/ext/ratatui_ruby/src/widgets/scrollbar.rs +97 -3
  173. data/ext/ratatui_ruby/src/widgets/scrollbar_state.rs +169 -0
  174. data/ext/ratatui_ruby/src/widgets/sparkline.rs +14 -11
  175. data/ext/ratatui_ruby/src/widgets/table.rs +121 -5
  176. data/ext/ratatui_ruby/src/widgets/table_state.rs +121 -0
  177. data/ext/ratatui_ruby/src/widgets/tabs.rs +11 -11
  178. data/lib/ratatui_ruby/cell.rb +7 -7
  179. data/lib/ratatui_ruby/event/key/character.rb +35 -0
  180. data/lib/ratatui_ruby/event/key/media.rb +44 -0
  181. data/lib/ratatui_ruby/event/key/modifier.rb +95 -0
  182. data/lib/ratatui_ruby/event/key/navigation.rb +55 -0
  183. data/lib/ratatui_ruby/event/key/system.rb +45 -0
  184. data/lib/ratatui_ruby/event/key.rb +112 -52
  185. data/lib/ratatui_ruby/event/mouse.rb +3 -3
  186. data/lib/ratatui_ruby/event/none.rb +43 -0
  187. data/lib/ratatui_ruby/event/paste.rb +1 -1
  188. data/lib/ratatui_ruby/event.rb +56 -4
  189. data/lib/ratatui_ruby/frame.rb +183 -0
  190. data/lib/ratatui_ruby/list_state.rb +88 -0
  191. data/lib/ratatui_ruby/schema/bar_chart/bar.rb +13 -13
  192. data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +1 -5
  193. data/lib/ratatui_ruby/schema/bar_chart.rb +217 -217
  194. data/lib/ratatui_ruby/schema/block.rb +163 -168
  195. data/lib/ratatui_ruby/schema/calendar.rb +66 -67
  196. data/lib/ratatui_ruby/schema/canvas.rb +63 -63
  197. data/lib/ratatui_ruby/schema/center.rb +46 -46
  198. data/lib/ratatui_ruby/schema/chart.rb +135 -143
  199. data/lib/ratatui_ruby/schema/clear.rb +42 -42
  200. data/lib/ratatui_ruby/schema/constraint.rb +76 -76
  201. data/lib/ratatui_ruby/schema/cursor.rb +30 -25
  202. data/lib/ratatui_ruby/schema/gauge.rb +54 -52
  203. data/lib/ratatui_ruby/schema/layout.rb +87 -87
  204. data/lib/ratatui_ruby/schema/line_gauge.rb +62 -62
  205. data/lib/ratatui_ruby/schema/list.rb +103 -80
  206. data/lib/ratatui_ruby/schema/list_item.rb +41 -0
  207. data/lib/ratatui_ruby/schema/overlay.rb +31 -31
  208. data/lib/ratatui_ruby/schema/paragraph.rb +80 -80
  209. data/lib/ratatui_ruby/schema/ratatui_logo.rb +10 -6
  210. data/lib/ratatui_ruby/schema/ratatui_mascot.rb +10 -5
  211. data/lib/ratatui_ruby/schema/rect.rb +99 -56
  212. data/lib/ratatui_ruby/schema/scrollbar.rb +119 -119
  213. data/lib/ratatui_ruby/schema/shape/label.rb +1 -1
  214. data/lib/ratatui_ruby/schema/sparkline.rb +111 -110
  215. data/lib/ratatui_ruby/schema/style.rb +66 -46
  216. data/lib/ratatui_ruby/schema/table.rb +126 -115
  217. data/lib/ratatui_ruby/schema/tabs.rb +66 -67
  218. data/lib/ratatui_ruby/schema/text.rb +69 -1
  219. data/lib/ratatui_ruby/scrollbar_state.rb +112 -0
  220. data/lib/ratatui_ruby/session/autodoc.rb +482 -0
  221. data/lib/ratatui_ruby/session.rb +55 -23
  222. data/lib/ratatui_ruby/table_state.rb +90 -0
  223. data/lib/ratatui_ruby/test_helper/event_injection.rb +169 -0
  224. data/lib/ratatui_ruby/test_helper/snapshot.rb +390 -0
  225. data/lib/ratatui_ruby/test_helper/style_assertions.rb +351 -0
  226. data/lib/ratatui_ruby/test_helper/terminal.rb +127 -0
  227. data/lib/ratatui_ruby/test_helper/test_doubles.rb +68 -0
  228. data/lib/ratatui_ruby/test_helper.rb +66 -193
  229. data/lib/ratatui_ruby/version.rb +1 -1
  230. data/lib/ratatui_ruby.rb +100 -51
  231. data/{examples/sparkline_demo → sig/examples/app_all_events}/app.rbs +3 -2
  232. data/sig/examples/app_all_events/model/event_entry.rbs +16 -0
  233. data/sig/examples/app_all_events/model/events.rbs +15 -0
  234. data/sig/examples/app_all_events/model/timestamp.rbs +11 -0
  235. data/sig/examples/app_all_events/view/app_view.rbs +8 -0
  236. data/sig/examples/app_all_events/view/controls_view.rbs +6 -0
  237. data/sig/examples/app_all_events/view/counts_view.rbs +6 -0
  238. data/sig/examples/app_all_events/view/live_view.rbs +6 -0
  239. data/sig/examples/app_all_events/view/log_view.rbs +6 -0
  240. data/sig/examples/app_all_events/view.rbs +8 -0
  241. data/sig/examples/app_all_events/view_state.rbs +15 -0
  242. data/{examples/list_demo → sig/examples/app_color_picker}/app.rbs +2 -2
  243. data/sig/examples/app_login_form/app.rbs +11 -0
  244. data/sig/examples/app_stateful_interaction/app.rbs +33 -0
  245. data/sig/examples/verify_quickstart_dsl/app.rbs +11 -0
  246. data/sig/examples/verify_quickstart_lifecycle/app.rbs +11 -0
  247. data/sig/examples/verify_readme_usage/app.rbs +11 -0
  248. data/sig/examples/widget_block_demo/app.rbs +32 -0
  249. data/sig/examples/widget_box_demo/app.rbs +11 -0
  250. data/sig/examples/widget_calendar_demo/app.rbs +11 -0
  251. data/sig/examples/widget_cell_demo/app.rbs +11 -0
  252. data/sig/examples/widget_chart_demo/app.rbs +11 -0
  253. data/{examples/gauge_demo → sig/examples/widget_gauge_demo}/app.rbs +4 -0
  254. data/sig/examples/widget_layout_split/app.rbs +10 -0
  255. data/sig/examples/widget_line_gauge_demo/app.rbs +11 -0
  256. data/sig/examples/widget_list_demo/app.rbs +12 -0
  257. data/sig/examples/widget_map_demo/app.rbs +11 -0
  258. data/sig/examples/widget_popup_demo/app.rbs +11 -0
  259. data/sig/examples/widget_ratatui_logo_demo/app.rbs +11 -0
  260. data/sig/examples/widget_ratatui_mascot_demo/app.rbs +11 -0
  261. data/sig/examples/widget_rect/app.rbs +12 -0
  262. data/sig/examples/widget_render/app.rbs +10 -0
  263. data/sig/examples/widget_rich_text/app.rbs +11 -0
  264. data/sig/examples/widget_scroll_text/app.rbs +11 -0
  265. data/sig/examples/widget_scrollbar_demo/app.rbs +11 -0
  266. data/sig/examples/widget_sparkline_demo/app.rbs +10 -0
  267. data/{examples → sig/examples}/widget_style_colors/app.rbs +1 -1
  268. data/sig/examples/widget_table_demo/app.rbs +11 -0
  269. data/sig/examples/widget_text_width/app.rbs +10 -0
  270. data/sig/ratatui_ruby/event.rbs +11 -1
  271. data/sig/ratatui_ruby/frame.rbs +11 -0
  272. data/sig/ratatui_ruby/list_state.rbs +13 -0
  273. data/sig/ratatui_ruby/ratatui_ruby.rbs +5 -4
  274. data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +3 -3
  275. data/sig/ratatui_ruby/schema/draw.rbs +4 -0
  276. data/sig/ratatui_ruby/schema/gauge.rbs +2 -2
  277. data/sig/ratatui_ruby/schema/layout.rbs +1 -1
  278. data/sig/ratatui_ruby/schema/line_gauge.rbs +2 -2
  279. data/sig/ratatui_ruby/schema/list.rbs +4 -2
  280. data/sig/ratatui_ruby/schema/list_item.rbs +10 -0
  281. data/sig/ratatui_ruby/schema/rect.rbs +3 -0
  282. data/sig/ratatui_ruby/schema/style.rbs +3 -3
  283. data/sig/ratatui_ruby/schema/table.rbs +3 -1
  284. data/sig/ratatui_ruby/schema/text.rbs +8 -6
  285. data/sig/ratatui_ruby/scrollbar_state.rbs +18 -0
  286. data/sig/ratatui_ruby/session.rbs +107 -0
  287. data/sig/ratatui_ruby/table_state.rbs +15 -0
  288. data/sig/ratatui_ruby/test_helper/event_injection.rbs +16 -0
  289. data/sig/ratatui_ruby/test_helper/snapshot.rbs +12 -0
  290. data/sig/ratatui_ruby/test_helper/style_assertions.rbs +64 -0
  291. data/sig/ratatui_ruby/test_helper/terminal.rbs +14 -0
  292. data/sig/ratatui_ruby/test_helper/test_doubles.rbs +22 -0
  293. data/sig/ratatui_ruby/test_helper.rbs +5 -4
  294. data/tasks/autodoc/examples.rb +79 -0
  295. data/tasks/autodoc/inventory.rb +63 -0
  296. data/tasks/autodoc/member.rb +56 -0
  297. data/tasks/autodoc/name.rb +19 -0
  298. data/tasks/autodoc/notice.rb +26 -0
  299. data/tasks/autodoc/rbs.rb +38 -0
  300. data/tasks/autodoc/rdoc.rb +45 -0
  301. data/tasks/autodoc.rake +53 -0
  302. data/tasks/bump/changelog.rb +3 -3
  303. data/tasks/bump/history.rb +2 -2
  304. data/tasks/bump/links.rb +67 -0
  305. data/tasks/doc.rake +600 -6
  306. data/tasks/example_viewer.html.erb +172 -0
  307. data/tasks/lint.rake +8 -4
  308. data/tasks/resources/index.html.erb +6 -0
  309. data/tasks/sourcehut.rake +70 -30
  310. data/tasks/terminal_preview/app_screenshot.rb +14 -6
  311. data/tasks/terminal_preview/crash_report.rb +7 -9
  312. data/tasks/terminal_preview/launcher_script.rb +4 -6
  313. data/tasks/terminal_preview/preview_collection.rb +4 -6
  314. data/tasks/terminal_preview/safety_confirmation.rb +3 -5
  315. data/tasks/terminal_preview/saved_screenshot.rb +10 -11
  316. data/tasks/terminal_preview/terminal_window.rb +7 -9
  317. data/tasks/test.rake +1 -1
  318. data/tasks/website/index_page.rb +3 -3
  319. data/tasks/website/version.rb +10 -10
  320. data/tasks/website/version_menu.rb +10 -12
  321. data/tasks/website/versioned_documentation.rb +49 -17
  322. data/tasks/website/website.rb +6 -8
  323. data/tasks/website.rake +4 -4
  324. metadata +232 -127
  325. data/LICENSES/BSD-2-Clause.txt +0 -9
  326. data/doc/contributors/better_dx.md +0 -543
  327. data/doc/contributors/example_analysis.md +0 -82
  328. data/doc/images/all_events.png +0 -0
  329. data/doc/images/block_padding.png +0 -0
  330. data/doc/images/block_titles.png +0 -0
  331. data/doc/images/box_demo.png +0 -0
  332. data/doc/images/calendar_demo.png +0 -0
  333. data/doc/images/cell_demo.png +0 -0
  334. data/doc/images/chart_demo.png +0 -0
  335. data/doc/images/flex_layout.png +0 -0
  336. data/doc/images/gauge_demo.png +0 -0
  337. data/doc/images/line_gauge_demo.png +0 -0
  338. data/doc/images/list_demo.png +0 -0
  339. data/doc/images/list_styles.png +0 -0
  340. data/doc/images/login_form.png +0 -0
  341. data/doc/images/quickstart_dsl.png +0 -0
  342. data/doc/images/quickstart_lifecycle.png +0 -0
  343. data/doc/images/readme_usage.png +0 -0
  344. data/doc/images/rich_text.png +0 -0
  345. data/doc/images/scroll_text.png +0 -0
  346. data/doc/images/scrollbar_demo.png +0 -0
  347. data/doc/images/sparkline_demo.png +0 -0
  348. data/doc/images/table_flex.png +0 -0
  349. data/doc/images/table_select.png +0 -0
  350. data/examples/all_events/app.rb +0 -169
  351. data/examples/all_events/app.rbs +0 -7
  352. data/examples/all_events/test_app.rb +0 -139
  353. data/examples/analytics/app.rb +0 -258
  354. data/examples/analytics/app.rbs +0 -7
  355. data/examples/analytics/test_app.rb +0 -132
  356. data/examples/block_padding/app.rb +0 -63
  357. data/examples/block_padding/app.rbs +0 -7
  358. data/examples/block_padding/test_app.rb +0 -31
  359. data/examples/block_titles/app.rb +0 -61
  360. data/examples/block_titles/app.rbs +0 -7
  361. data/examples/block_titles/test_app.rb +0 -34
  362. data/examples/box_demo/app.rbs +0 -7
  363. data/examples/box_demo/test_app.rb +0 -88
  364. data/examples/calendar_demo/app.rb +0 -101
  365. data/examples/calendar_demo/app.rbs +0 -7
  366. data/examples/calendar_demo/test_app.rb +0 -108
  367. data/examples/cell_demo/app.rb +0 -108
  368. data/examples/cell_demo/app.rbs +0 -7
  369. data/examples/cell_demo/test_app.rb +0 -36
  370. data/examples/chart_demo/app.rb +0 -203
  371. data/examples/chart_demo/app.rbs +0 -7
  372. data/examples/chart_demo/test_app.rb +0 -102
  373. data/examples/custom_widget/app.rb +0 -51
  374. data/examples/custom_widget/app.rbs +0 -7
  375. data/examples/custom_widget/test_app.rb +0 -30
  376. data/examples/flex_layout/app.rb +0 -156
  377. data/examples/flex_layout/app.rbs +0 -7
  378. data/examples/flex_layout/test_app.rb +0 -65
  379. data/examples/gauge_demo/app.rb +0 -182
  380. data/examples/gauge_demo/test_app.rb +0 -120
  381. data/examples/hit_test/app.rb +0 -175
  382. data/examples/hit_test/app.rbs +0 -7
  383. data/examples/hit_test/test_app.rb +0 -102
  384. data/examples/line_gauge_demo/app.rb +0 -190
  385. data/examples/line_gauge_demo/app.rbs +0 -7
  386. data/examples/line_gauge_demo/test_app.rb +0 -129
  387. data/examples/list_demo/app.rb +0 -253
  388. data/examples/list_demo/test_app.rb +0 -237
  389. data/examples/list_styles/app.rb +0 -140
  390. data/examples/list_styles/app.rbs +0 -7
  391. data/examples/list_styles/test_app.rb +0 -157
  392. data/examples/login_form/app.rbs +0 -7
  393. data/examples/login_form/test_app.rb +0 -51
  394. data/examples/map_demo/app.rbs +0 -7
  395. data/examples/map_demo/test_app.rb +0 -149
  396. data/examples/mouse_events/app.rb +0 -97
  397. data/examples/mouse_events/app.rbs +0 -7
  398. data/examples/mouse_events/test_app.rb +0 -53
  399. data/examples/popup_demo/app.rb +0 -103
  400. data/examples/popup_demo/app.rbs +0 -7
  401. data/examples/popup_demo/test_app.rb +0 -54
  402. data/examples/quickstart_dsl/app.rbs +0 -7
  403. data/examples/quickstart_dsl/test_app.rb +0 -29
  404. data/examples/quickstart_lifecycle/app.rb +0 -39
  405. data/examples/quickstart_lifecycle/app.rbs +0 -7
  406. data/examples/quickstart_lifecycle/test_app.rb +0 -29
  407. data/examples/ratatui_logo_demo/app.rb +0 -79
  408. data/examples/ratatui_logo_demo/app.rbs +0 -7
  409. data/examples/ratatui_logo_demo/test_app.rb +0 -51
  410. data/examples/ratatui_mascot_demo/app.rb +0 -84
  411. data/examples/ratatui_mascot_demo/app.rbs +0 -7
  412. data/examples/ratatui_mascot_demo/test_app.rb +0 -47
  413. data/examples/readme_usage/app.rb +0 -29
  414. data/examples/readme_usage/app.rbs +0 -7
  415. data/examples/readme_usage/test_app.rb +0 -29
  416. data/examples/rich_text/app.rb +0 -141
  417. data/examples/rich_text/app.rbs +0 -7
  418. data/examples/rich_text/test_app.rb +0 -166
  419. data/examples/scroll_text/app.rb +0 -103
  420. data/examples/scroll_text/app.rbs +0 -7
  421. data/examples/scroll_text/test_app.rb +0 -110
  422. data/examples/scrollbar_demo/app.rb +0 -143
  423. data/examples/scrollbar_demo/app.rbs +0 -7
  424. data/examples/scrollbar_demo/test_app.rb +0 -77
  425. data/examples/sparkline_demo/app.rb +0 -240
  426. data/examples/sparkline_demo/test_app.rb +0 -107
  427. data/examples/table_flex/app.rb +0 -65
  428. data/examples/table_flex/app.rbs +0 -7
  429. data/examples/table_flex/test_app.rb +0 -36
  430. data/examples/table_select/app.rb +0 -198
  431. data/examples/table_select/app.rbs +0 -7
  432. data/examples/table_select/test_app.rb +0 -180
  433. data/examples/widget_style_colors/test_app.rb +0 -48
  434. data/tasks/bump/comparison_links.rb +0 -41
  435. /data/doc/images/{analytics.png → app_analytics.png} +0 -0
  436. /data/doc/images/{custom_widget.png → app_custom_widget.png} +0 -0
  437. /data/doc/images/{mouse_events.png → app_mouse_events.png} +0 -0
  438. /data/doc/images/{map_demo.png → widget_map_demo.png} +0 -0
  439. /data/doc/images/{popup_demo.png → widget_popup_demo.png} +0 -0
  440. /data/doc/images/{hit_test.png → widget_rect.png} +0 -0
  441. /data/{doc/images/ratatui_logo_demo.png → exe/.gitkeep} +0 -0
@@ -2,8 +2,9 @@
2
2
  // SPDX-License-Identifier: AGPL-3.0-or-later
3
3
 
4
4
  use crate::style::{parse_bar_set, parse_block, parse_style};
5
+ use crate::text::{parse_line, parse_span};
5
6
  use bumpalo::Bump;
6
- use magnus::{prelude::*, Error, Symbol, Value, RArray};
7
+ use magnus::{prelude::*, Error, RArray, Symbol, Value};
7
8
  use ratatui::{
8
9
  layout::{Direction, Rect},
9
10
  text::Line,
@@ -11,6 +12,7 @@ use ratatui::{
11
12
  Frame,
12
13
  };
13
14
 
15
+ #[allow(clippy::too_many_lines)]
14
16
  pub fn render(frame: &mut Frame, area: Rect, node: Value) -> Result<(), Error> {
15
17
  let bump = Bump::new();
16
18
  let data_val: Value = node.funcall("data", ())?;
@@ -41,59 +43,77 @@ pub fn render(frame: &mut Frame, area: Rect, node: Value) -> Result<(), Error> {
41
43
  let ruby = magnus::Ruby::get().unwrap();
42
44
  if let Some(array) = RArray::from_value(data_val) {
43
45
  for i in 0..array.len() {
44
- let index = isize::try_from(i).map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
45
- let group_obj: Value = array.entry(index)?;
46
-
47
- let label_val: Value = group_obj.funcall("label", ())?;
48
- let label_str: String = if !label_val.is_nil() {
49
- label_val.funcall("to_s", ())?
50
- } else {
51
- String::new()
52
- };
53
- let label_ref = bump.alloc_str(&label_str) as &str;
54
-
55
- let bars_array: RArray = group_obj.funcall("bars", ())?;
56
- let mut bars: Vec<Bar> = Vec::new();
57
-
58
- for j in 0..bars_array.len() {
59
- let bar_idx = isize::try_from(j).map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
60
- let bar_obj: Value = bars_array.entry(bar_idx)?;
61
-
62
- let value: u64 = bar_obj.funcall("value", ())?;
63
- let mut bar = Bar::default().value(value);
64
-
65
- let label_val: Value = bar_obj.funcall("label", ())?;
66
- if !label_val.is_nil() {
67
- let s: String = label_val.funcall("to_s", ())?;
68
- let s_ref = bump.alloc_str(&s) as &str;
69
- bar = bar.label(Line::from(s_ref));
70
- }
71
-
72
- let text_val: Value = bar_obj.funcall("text_value", ())?;
73
- if !text_val.is_nil() {
74
- let s: String = text_val.funcall("to_s", ())?;
75
- let s_ref = bump.alloc_str(&s) as &str;
76
- bar = bar.text_value(s_ref);
77
- }
78
-
79
- let style_val: Value = bar_obj.funcall("style", ())?;
80
- if !style_val.is_nil() {
81
- bar = bar.style(parse_style(style_val)?);
82
- }
83
-
84
- let val_style_val: Value = bar_obj.funcall("value_style", ())?;
85
- if !val_style_val.is_nil() {
86
- bar = bar.value_style(parse_style(val_style_val)?);
87
- }
88
-
89
- bars.push(bar);
90
- }
91
-
92
- let mut group = BarGroup::new(bars);
93
- if !label_ref.is_empty() {
94
- group = group.label(Line::from(label_ref));
95
- }
96
- bar_chart = bar_chart.data(group);
46
+ let index = isize::try_from(i)
47
+ .map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
48
+ let group_obj: Value = array.entry(index)?;
49
+
50
+ let label_val: Value = group_obj.funcall("label", ())?;
51
+ let label_str: String = if label_val.is_nil() {
52
+ String::new()
53
+ } else {
54
+ label_val.funcall("to_s", ())?
55
+ };
56
+ let label_ref = bump.alloc_str(&label_str) as &str;
57
+
58
+ let bars_array: RArray = group_obj.funcall("bars", ())?;
59
+ let mut bars: Vec<Bar> = Vec::new();
60
+
61
+ for j in 0..bars_array.len() {
62
+ let bar_idx = isize::try_from(j)
63
+ .map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
64
+ let bar_obj: Value = bars_array.entry(bar_idx)?;
65
+
66
+ let value: u64 = bar_obj.funcall("value", ())?;
67
+ let mut bar = Bar::default().value(value);
68
+
69
+ let label_val: Value = bar_obj.funcall("label", ())?;
70
+ if !label_val.is_nil() {
71
+ // Try to parse as Line (rich text)
72
+ if let Ok(line) = parse_line(label_val) {
73
+ bar = bar.label(line);
74
+ } else if let Ok(span) = parse_span(label_val) {
75
+ bar = bar.label(Line::from(vec![span]));
76
+ } else {
77
+ // Fallback to string
78
+ let s: String = label_val.funcall("to_s", ())?;
79
+ let s_ref = bump.alloc_str(&s) as &str;
80
+ bar = bar.label(Line::from(s_ref));
81
+ }
82
+ }
83
+
84
+ let text_val: Value = bar_obj.funcall("text_value", ())?;
85
+ if !text_val.is_nil() {
86
+ // Try to parse as Line (rich text)
87
+ if let Ok(line) = parse_line(text_val) {
88
+ bar = bar.text_value(line);
89
+ } else if let Ok(span) = parse_span(text_val) {
90
+ bar = bar.text_value(Line::from(vec![span]));
91
+ } else {
92
+ // Fallback to string
93
+ let s: String = text_val.funcall("to_s", ())?;
94
+ let s_ref = bump.alloc_str(&s) as &str;
95
+ bar = bar.text_value(s_ref);
96
+ }
97
+ }
98
+
99
+ let style_val: Value = bar_obj.funcall("style", ())?;
100
+ if !style_val.is_nil() {
101
+ bar = bar.style(parse_style(style_val)?);
102
+ }
103
+
104
+ let val_style_val: Value = bar_obj.funcall("value_style", ())?;
105
+ if !val_style_val.is_nil() {
106
+ bar = bar.value_style(parse_style(val_style_val)?);
107
+ }
108
+
109
+ bars.push(bar);
110
+ }
111
+
112
+ let mut group = BarGroup::new(bars);
113
+ if !label_ref.is_empty() {
114
+ group = group.label(Line::from(label_ref));
115
+ }
116
+ bar_chart = bar_chart.data(group);
97
117
  }
98
118
  }
99
119
 
@@ -11,23 +11,24 @@ pub fn render(frame: &mut Frame, area: Rect, node: Value) -> Result<(), Error> {
11
11
  let bump = Bump::new();
12
12
  let block = parse_block(node, &bump)?;
13
13
  let block_clone = block.clone();
14
-
14
+
15
15
  // Render the block itself (borders, styling)
16
16
  block_clone.render(area, frame.buffer_mut());
17
-
17
+
18
18
  // Get children and render them within the block's inner area
19
19
  let children_val: Value = node.funcall("children", ())?;
20
20
  let children_array = magnus::RArray::from_value(children_val);
21
-
21
+
22
22
  if let Some(arr) = children_array {
23
23
  if !arr.is_empty() {
24
24
  // Calculate the inner area of the block (excluding borders and padding)
25
25
  let inner = block.inner(area);
26
-
26
+
27
27
  // Render each child in the block's inner area
28
28
  for i in 0..arr.len() {
29
29
  let ruby = magnus::Ruby::get().unwrap();
30
- let index = isize::try_from(i).map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
30
+ let index = isize::try_from(i)
31
+ .map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
31
32
  let child: Value = arr.entry(index)?;
32
33
  if let Err(e) = render_node(frame, inner, child) {
33
34
  eprintln!("Error rendering block child {i}: {e:?}");
@@ -35,6 +36,6 @@ pub fn render(frame: &mut Frame, area: Rect, node: Value) -> Result<(), Error> {
35
36
  }
36
37
  }
37
38
  }
38
-
39
+
39
40
  Ok(())
40
41
  }
@@ -11,6 +11,7 @@ use ratatui::{
11
11
  Frame,
12
12
  };
13
13
 
14
+ #[allow(clippy::too_many_lines)]
14
15
  pub fn render(frame: &mut Frame, area: ratatui::layout::Rect, node: Value) -> Result<(), Error> {
15
16
  let bump = Bump::new();
16
17
  let shapes_val: RArray = node.funcall("shapes", ())?;
@@ -64,7 +65,13 @@ pub fn render(frame: &mut Frame, area: ratatui::layout::Rect, node: Value) -> Re
64
65
  let color_val: Value = shape_val.funcall("color", ()).unwrap();
65
66
  let color =
66
67
  parse_color(&color_val.to_string()).unwrap_or(ratatui::style::Color::Reset);
67
- ctx.draw(&Line { x1, y1, x2, y2, color });
68
+ ctx.draw(&Line {
69
+ x1,
70
+ y1,
71
+ x2,
72
+ y2,
73
+ color,
74
+ });
68
75
  }
69
76
  "RatatuiRuby::Shape::Rectangle" => {
70
77
  let x: f64 = shape_val.funcall("x", ()).unwrap_or(0.0);
@@ -74,7 +81,13 @@ pub fn render(frame: &mut Frame, area: ratatui::layout::Rect, node: Value) -> Re
74
81
  let color_val: Value = shape_val.funcall("color", ()).unwrap();
75
82
  let color =
76
83
  parse_color(&color_val.to_string()).unwrap_or(ratatui::style::Color::Reset);
77
- ctx.draw(&Rectangle { x, y, width, height, color });
84
+ ctx.draw(&Rectangle {
85
+ x,
86
+ y,
87
+ width,
88
+ height,
89
+ color,
90
+ });
78
91
  }
79
92
  "RatatuiRuby::Shape::Circle" => {
80
93
  let x: f64 = shape_val.funcall("x", ()).unwrap_or(0.0);
@@ -83,7 +96,12 @@ pub fn render(frame: &mut Frame, area: ratatui::layout::Rect, node: Value) -> Re
83
96
  let color_val: Value = shape_val.funcall("color", ()).unwrap();
84
97
  let color =
85
98
  parse_color(&color_val.to_string()).unwrap_or(ratatui::style::Color::Reset);
86
- ctx.draw(&Circle { x, y, radius, color });
99
+ ctx.draw(&Circle {
100
+ x,
101
+ y,
102
+ radius,
103
+ color,
104
+ });
87
105
  }
88
106
  "RatatuiRuby::Shape::Map" => {
89
107
  let color_val: Value = shape_val.funcall("color", ()).unwrap();
@@ -35,13 +35,15 @@ pub fn render(frame: &mut Frame, area: Rect, node: Value) -> Result<(), Error> {
35
35
  let mut data_storage: Vec<Vec<(f64, f64)>> = Vec::new();
36
36
 
37
37
  for i in 0..datasets_val.len() {
38
- let index = isize::try_from(i).map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
38
+ let index = isize::try_from(i)
39
+ .map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
39
40
  let ds_val: Value = datasets_val.entry(index)?;
40
41
  let data_array: magnus::RArray = ds_val.funcall("data", ())?;
41
42
 
42
43
  let mut points = Vec::new();
43
44
  for j in 0..data_array.len() {
44
- let index = isize::try_from(j).map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
45
+ let index = isize::try_from(j)
46
+ .map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
45
47
  let point_array_val: Value = data_array.entry(index)?;
46
48
  let point_array = magnus::RArray::from_value(point_array_val).ok_or_else(|| {
47
49
  Error::new(ruby.exception_type_error(), "expected array for point")
@@ -54,7 +56,8 @@ pub fn render(frame: &mut Frame, area: Rect, node: Value) -> Result<(), Error> {
54
56
  }
55
57
 
56
58
  for (i, points) in data_storage.iter().enumerate() {
57
- let index = isize::try_from(i).map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
59
+ let index = isize::try_from(i)
60
+ .map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
58
61
  let ds_val: Value = datasets_val.entry(index)?;
59
62
  let name: String = ds_val.funcall("name", ())?;
60
63
  let marker_sym: Symbol = ds_val.funcall("marker", ())?;
@@ -112,7 +115,8 @@ pub fn render(frame: &mut Frame, area: Rect, node: Value) -> Result<(), Error> {
112
115
  }
113
116
 
114
117
  if !hidden_legend_constraints_val.is_nil() {
115
- let constraints_array: magnus::RArray = hidden_legend_constraints_val.funcall("to_a", ())?;
118
+ let constraints_array: magnus::RArray =
119
+ hidden_legend_constraints_val.funcall("to_a", ())?;
116
120
  if constraints_array.len() == 2 {
117
121
  let width_val: Value = constraints_array.entry(0)?;
118
122
  let height_val: Value = constraints_array.entry(1)?;
@@ -138,7 +142,8 @@ fn parse_axis(axis_val: Value) -> Result<Axis<'static>, Error> {
138
142
 
139
143
  let mut labels = Vec::new();
140
144
  for i in 0..labels_val.len() {
141
- let index = isize::try_from(i).map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
145
+ let index = isize::try_from(i)
146
+ .map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
142
147
  let label: String = labels_val.entry(index)?;
143
148
  labels.push(Span::from(label));
144
149
  }
@@ -175,13 +180,15 @@ fn render_line_chart(frame: &mut Frame, area: Rect, node: Value) -> Result<(), E
175
180
  let mut data_storage: Vec<Vec<(f64, f64)>> = Vec::new();
176
181
 
177
182
  for i in 0..datasets_val.len() {
178
- let index = isize::try_from(i).map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
183
+ let index = isize::try_from(i)
184
+ .map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
179
185
  let ds_val: Value = datasets_val.entry(index)?;
180
186
  let data_array: magnus::RArray = ds_val.funcall("data", ())?;
181
187
 
182
188
  let mut points = Vec::new();
183
189
  for j in 0..data_array.len() {
184
- let index = isize::try_from(j).map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
190
+ let index = isize::try_from(j)
191
+ .map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
185
192
  let point_array_val: Value = data_array.entry(index)?;
186
193
  let point_array = magnus::RArray::from_value(point_array_val).ok_or_else(|| {
187
194
  Error::new(ruby.exception_type_error(), "expected array for point")
@@ -194,7 +201,8 @@ fn render_line_chart(frame: &mut Frame, area: Rect, node: Value) -> Result<(), E
194
201
  }
195
202
 
196
203
  for (i, points) in data_storage.iter().enumerate() {
197
- let index = isize::try_from(i).map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
204
+ let index = isize::try_from(i)
205
+ .map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
198
206
  let ds_val: Value = datasets_val.entry(index)?;
199
207
  let name: String = ds_val.funcall("name", ())?;
200
208
 
@@ -214,14 +222,16 @@ fn render_line_chart(frame: &mut Frame, area: Rect, node: Value) -> Result<(), E
214
222
 
215
223
  let mut x_labels = Vec::new();
216
224
  for i in 0..x_labels_val.len() {
217
- let index = isize::try_from(i).map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
225
+ let index = isize::try_from(i)
226
+ .map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
218
227
  let label: String = x_labels_val.entry(index)?;
219
228
  x_labels.push(Span::from(label));
220
229
  }
221
230
 
222
231
  let mut y_labels = Vec::new();
223
232
  for i in 0..y_labels_val.len() {
224
- let index = isize::try_from(i).map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
233
+ let index = isize::try_from(i)
234
+ .map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
225
235
  let label: String = y_labels_val.entry(index)?;
226
236
  y_labels.push(Span::from(label));
227
237
  }
@@ -2,6 +2,7 @@
2
2
  // SPDX-License-Identifier: AGPL-3.0-or-later
3
3
 
4
4
  use crate::style::{parse_block, parse_style};
5
+ use crate::text::parse_span;
5
6
  use bumpalo::Bump;
6
7
  use magnus::{prelude::*, Error, Value};
7
8
  use ratatui::{layout::Rect, widgets::Gauge, Frame};
@@ -17,8 +18,14 @@ pub fn render(frame: &mut Frame, area: Rect, node: Value) -> Result<(), Error> {
17
18
  let mut gauge = Gauge::default().ratio(ratio).use_unicode(use_unicode);
18
19
 
19
20
  if !label_val.is_nil() {
20
- let label_str: String = label_val.funcall("to_s", ())?;
21
- gauge = gauge.label(label_str);
21
+ // Try to parse as a Span (rich text)
22
+ if let Ok(span) = parse_span(label_val) {
23
+ gauge = gauge.label(span);
24
+ } else {
25
+ // Fallback to string
26
+ let label_str: String = label_val.funcall("to_s", ())?;
27
+ gauge = gauge.label(label_str);
28
+ }
22
29
  }
23
30
 
24
31
  if !style_val.is_nil() {
@@ -42,7 +42,8 @@ pub fn render(frame: &mut Frame, area: Rect, node: Value) -> Result<(), Error> {
42
42
 
43
43
  if let Some(arr) = constraints_array {
44
44
  for i in 0..arr.len() {
45
- let index = isize::try_from(i).map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
45
+ let index = isize::try_from(i)
46
+ .map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
46
47
  let constraint_obj: Value = arr.entry(index)?;
47
48
  if let Ok(constraint) = parse_constraint(constraint_obj) {
48
49
  ratatui_constraints.push(constraint);
@@ -53,7 +54,9 @@ pub fn render(frame: &mut Frame, area: Rect, node: Value) -> Result<(), Error> {
53
54
  // If constraints don't match children, adjust or default
54
55
  if ratatui_constraints.len() != len {
55
56
  ratatui_constraints = (0..len)
56
- .map(|_| Constraint::Percentage(100 / u16::try_from(len).unwrap_or(u16::MAX).max(1)))
57
+ .map(|_| {
58
+ Constraint::Percentage(100 / u16::try_from(len).unwrap_or(u16::MAX).max(1))
59
+ })
57
60
  .collect();
58
61
  }
59
62
 
@@ -64,7 +67,8 @@ pub fn render(frame: &mut Frame, area: Rect, node: Value) -> Result<(), Error> {
64
67
  .split(area);
65
68
 
66
69
  for i in 0..len {
67
- let index = isize::try_from(i).map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
70
+ let index = isize::try_from(i)
71
+ .map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
68
72
  let child: Value = children_array.entry(index)?;
69
73
  if let Err(e) = render_node(frame, chunks[i], child) {
70
74
  eprintln!("Error rendering child {i}: {e:?}");
@@ -168,7 +172,8 @@ pub fn split_layout(
168
172
  // Parse constraints
169
173
  let mut ratatui_constraints = Vec::new();
170
174
  for i in 0..constraints.len() {
171
- let index = isize::try_from(i).map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
175
+ let index = isize::try_from(i)
176
+ .map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
172
177
  let constraint_obj: Value = constraints.entry(index)?;
173
178
  if let Ok(constraint) = parse_constraint(constraint_obj) {
174
179
  ratatui_constraints.push(constraint);
@@ -2,6 +2,7 @@
2
2
  // SPDX-License-Identifier: AGPL-3.0-or-later
3
3
 
4
4
  use crate::style::{parse_block, parse_style};
5
+ use crate::text::parse_span;
5
6
  use bumpalo::Bump;
6
7
  use magnus::{prelude::*, Error, Value};
7
8
  use ratatui::{layout::Rect, widgets::LineGauge, Frame};
@@ -23,8 +24,14 @@ pub fn render(frame: &mut Frame, area: Rect, node: Value) -> Result<(), Error> {
23
24
  .unfilled_symbol(&unfilled_symbol_val);
24
25
 
25
26
  if !label_val.is_nil() {
26
- let label_str: String = label_val.funcall("to_s", ())?;
27
- gauge = gauge.label(label_str);
27
+ // Try to parse as a Span (rich text)
28
+ if let Ok(span) = parse_span(label_val) {
29
+ gauge = gauge.label(span);
30
+ } else {
31
+ // Fallback to string
32
+ let label_str: String = label_val.funcall("to_s", ())?;
33
+ gauge = gauge.label(label_str);
34
+ }
28
35
  }
29
36
 
30
37
  if !style_val.is_nil() {