ratatui_ruby 1.4.0-x86_64-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (292) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +15 -0
  3. data/LICENSES/AGPL-3.0-or-later.txt +661 -0
  4. data/LICENSES/CC-BY-SA-4.0.txt +427 -0
  5. data/LICENSES/CC0-1.0.txt +121 -0
  6. data/LICENSES/LGPL-3.0-or-later.txt +304 -0
  7. data/LICENSES/MIT-0.txt +16 -0
  8. data/LICENSES/MIT.txt +21 -0
  9. data/REUSE.toml +42 -0
  10. data/exe/.gitkeep +0 -0
  11. data/ext/ratatui_ruby/.cargo/config.toml +13 -0
  12. data/ext/ratatui_ruby/.gitignore +4 -0
  13. data/ext/ratatui_ruby/Cargo.lock +1737 -0
  14. data/ext/ratatui_ruby/Cargo.toml +24 -0
  15. data/ext/ratatui_ruby/clippy.toml +7 -0
  16. data/ext/ratatui_ruby/extconf.rb +21 -0
  17. data/ext/ratatui_ruby/src/color.rs +82 -0
  18. data/ext/ratatui_ruby/src/errors.rs +28 -0
  19. data/ext/ratatui_ruby/src/events.rs +700 -0
  20. data/ext/ratatui_ruby/src/frame.rs +241 -0
  21. data/ext/ratatui_ruby/src/lib.rs +343 -0
  22. data/ext/ratatui_ruby/src/lib_header.rs +11 -0
  23. data/ext/ratatui_ruby/src/rendering.rs +158 -0
  24. data/ext/ratatui_ruby/src/string_width.rs +101 -0
  25. data/ext/ratatui_ruby/src/style.rs +469 -0
  26. data/ext/ratatui_ruby/src/terminal/capabilities.rs +46 -0
  27. data/ext/ratatui_ruby/src/terminal/init.rs +233 -0
  28. data/ext/ratatui_ruby/src/terminal/mod.rs +42 -0
  29. data/ext/ratatui_ruby/src/terminal/mutations.rs +158 -0
  30. data/ext/ratatui_ruby/src/terminal/queries.rs +231 -0
  31. data/ext/ratatui_ruby/src/terminal/query.rs +400 -0
  32. data/ext/ratatui_ruby/src/terminal/storage.rs +109 -0
  33. data/ext/ratatui_ruby/src/terminal/wrapper.rs +16 -0
  34. data/ext/ratatui_ruby/src/text.rs +225 -0
  35. data/ext/ratatui_ruby/src/widgets/barchart.rs +169 -0
  36. data/ext/ratatui_ruby/src/widgets/block.rs +41 -0
  37. data/ext/ratatui_ruby/src/widgets/calendar.rs +84 -0
  38. data/ext/ratatui_ruby/src/widgets/canvas.rs +183 -0
  39. data/ext/ratatui_ruby/src/widgets/center.rs +79 -0
  40. data/ext/ratatui_ruby/src/widgets/chart.rs +222 -0
  41. data/ext/ratatui_ruby/src/widgets/clear.rs +39 -0
  42. data/ext/ratatui_ruby/src/widgets/cursor.rs +32 -0
  43. data/ext/ratatui_ruby/src/widgets/gauge.rs +65 -0
  44. data/ext/ratatui_ruby/src/widgets/layout.rs +379 -0
  45. data/ext/ratatui_ruby/src/widgets/line_gauge.rs +100 -0
  46. data/ext/ratatui_ruby/src/widgets/list.rs +378 -0
  47. data/ext/ratatui_ruby/src/widgets/list_state.rs +173 -0
  48. data/ext/ratatui_ruby/src/widgets/mod.rs +26 -0
  49. data/ext/ratatui_ruby/src/widgets/overlay.rs +24 -0
  50. data/ext/ratatui_ruby/src/widgets/paragraph.rs +87 -0
  51. data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +40 -0
  52. data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +55 -0
  53. data/ext/ratatui_ruby/src/widgets/scrollbar.rs +214 -0
  54. data/ext/ratatui_ruby/src/widgets/scrollbar_state.rs +169 -0
  55. data/ext/ratatui_ruby/src/widgets/sparkline.rs +127 -0
  56. data/ext/ratatui_ruby/src/widgets/table.rs +415 -0
  57. data/ext/ratatui_ruby/src/widgets/table_state.rs +203 -0
  58. data/ext/ratatui_ruby/src/widgets/tabs.rs +194 -0
  59. data/lib/ratatui_ruby/backend/window_size.rb +50 -0
  60. data/lib/ratatui_ruby/backend.rb +59 -0
  61. data/lib/ratatui_ruby/buffer/cell.rb +212 -0
  62. data/lib/ratatui_ruby/buffer.rb +149 -0
  63. data/lib/ratatui_ruby/cell.rb +208 -0
  64. data/lib/ratatui_ruby/debug.rb +215 -0
  65. data/lib/ratatui_ruby/draw.rb +63 -0
  66. data/lib/ratatui_ruby/event/focus_gained.rb +125 -0
  67. data/lib/ratatui_ruby/event/focus_lost.rb +127 -0
  68. data/lib/ratatui_ruby/event/key/character.rb +53 -0
  69. data/lib/ratatui_ruby/event/key/dwim.rb +301 -0
  70. data/lib/ratatui_ruby/event/key/media.rb +46 -0
  71. data/lib/ratatui_ruby/event/key/modifier.rb +107 -0
  72. data/lib/ratatui_ruby/event/key/navigation.rb +72 -0
  73. data/lib/ratatui_ruby/event/key/system.rb +47 -0
  74. data/lib/ratatui_ruby/event/key.rb +479 -0
  75. data/lib/ratatui_ruby/event/mouse.rb +291 -0
  76. data/lib/ratatui_ruby/event/none.rb +53 -0
  77. data/lib/ratatui_ruby/event/paste.rb +130 -0
  78. data/lib/ratatui_ruby/event/resize.rb +221 -0
  79. data/lib/ratatui_ruby/event/sync.rb +52 -0
  80. data/lib/ratatui_ruby/event.rb +163 -0
  81. data/lib/ratatui_ruby/frame.rb +257 -0
  82. data/lib/ratatui_ruby/labs/a11y.rb +182 -0
  83. data/lib/ratatui_ruby/labs/frame_a11y_capture.rb +50 -0
  84. data/lib/ratatui_ruby/labs.rb +47 -0
  85. data/lib/ratatui_ruby/layout/alignment.rb +91 -0
  86. data/lib/ratatui_ruby/layout/constraint.rb +337 -0
  87. data/lib/ratatui_ruby/layout/layout.rb +258 -0
  88. data/lib/ratatui_ruby/layout/position.rb +81 -0
  89. data/lib/ratatui_ruby/layout/rect.rb +733 -0
  90. data/lib/ratatui_ruby/layout/size.rb +62 -0
  91. data/lib/ratatui_ruby/layout.rb +29 -0
  92. data/lib/ratatui_ruby/list_state.rb +201 -0
  93. data/lib/ratatui_ruby/output_guard.rb +171 -0
  94. data/lib/ratatui_ruby/ratatui_ruby.so +0 -0
  95. data/lib/ratatui_ruby/scrollbar_state.rb +122 -0
  96. data/lib/ratatui_ruby/style/color.rb +149 -0
  97. data/lib/ratatui_ruby/style/style.rb +147 -0
  98. data/lib/ratatui_ruby/style.rb +19 -0
  99. data/lib/ratatui_ruby/symbols.rb +435 -0
  100. data/lib/ratatui_ruby/synthetic_events.rb +106 -0
  101. data/lib/ratatui_ruby/table_state.rb +251 -0
  102. data/lib/ratatui_ruby/terminal/capabilities.rb +316 -0
  103. data/lib/ratatui_ruby/terminal/viewport.rb +80 -0
  104. data/lib/ratatui_ruby/terminal.rb +66 -0
  105. data/lib/ratatui_ruby/terminal_lifecycle.rb +303 -0
  106. data/lib/ratatui_ruby/terminal_lifecycle.rb.bak +197 -0
  107. data/lib/ratatui_ruby/test_helper/event_injection.rb +241 -0
  108. data/lib/ratatui_ruby/test_helper/global_state.rb +111 -0
  109. data/lib/ratatui_ruby/test_helper/snapshot.rb +568 -0
  110. data/lib/ratatui_ruby/test_helper/snapshots/axis_labels_alignment.ansi +24 -0
  111. data/lib/ratatui_ruby/test_helper/snapshots/axis_labels_alignment.txt +24 -0
  112. data/lib/ratatui_ruby/test_helper/snapshots/barchart_styled_label.ansi +5 -0
  113. data/lib/ratatui_ruby/test_helper/snapshots/barchart_styled_label.txt +5 -0
  114. data/lib/ratatui_ruby/test_helper/snapshots/chart_rendering.ansi +24 -0
  115. data/lib/ratatui_ruby/test_helper/snapshots/chart_rendering.txt +24 -0
  116. data/lib/ratatui_ruby/test_helper/snapshots/half_block_marker.ansi +12 -0
  117. data/lib/ratatui_ruby/test_helper/snapshots/half_block_marker.txt +12 -0
  118. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_bottom.ansi +12 -0
  119. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_bottom.txt +12 -0
  120. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_left.ansi +12 -0
  121. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_left.txt +12 -0
  122. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_right.ansi +12 -0
  123. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_right.txt +12 -0
  124. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_top.ansi +12 -0
  125. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_top.txt +12 -0
  126. data/lib/ratatui_ruby/test_helper/snapshots/my_snapshot.txt +1 -0
  127. data/lib/ratatui_ruby/test_helper/snapshots/styled_axis_title.ansi +10 -0
  128. data/lib/ratatui_ruby/test_helper/snapshots/styled_axis_title.txt +10 -0
  129. data/lib/ratatui_ruby/test_helper/snapshots/styled_dataset_name.ansi +10 -0
  130. data/lib/ratatui_ruby/test_helper/snapshots/styled_dataset_name.txt +10 -0
  131. data/lib/ratatui_ruby/test_helper/style_assertions.rb +449 -0
  132. data/lib/ratatui_ruby/test_helper/subprocess_timeout.rb +35 -0
  133. data/lib/ratatui_ruby/test_helper/terminal.rb +187 -0
  134. data/lib/ratatui_ruby/test_helper/test_doubles.rb +86 -0
  135. data/lib/ratatui_ruby/test_helper.rb +115 -0
  136. data/lib/ratatui_ruby/text/line.rb +245 -0
  137. data/lib/ratatui_ruby/text/span.rb +158 -0
  138. data/lib/ratatui_ruby/text.rb +99 -0
  139. data/lib/ratatui_ruby/tui/buffer_factories.rb +22 -0
  140. data/lib/ratatui_ruby/tui/canvas_factories.rb +149 -0
  141. data/lib/ratatui_ruby/tui/core.rb +67 -0
  142. data/lib/ratatui_ruby/tui/layout_factories.rb +153 -0
  143. data/lib/ratatui_ruby/tui/state_factories.rb +77 -0
  144. data/lib/ratatui_ruby/tui/style_factories.rb +22 -0
  145. data/lib/ratatui_ruby/tui/text_factories.rb +86 -0
  146. data/lib/ratatui_ruby/tui/widget_factories.rb +272 -0
  147. data/lib/ratatui_ruby/tui.rb +106 -0
  148. data/lib/ratatui_ruby/version.rb +12 -0
  149. data/lib/ratatui_ruby/widgets/bar_chart/bar.rb +51 -0
  150. data/lib/ratatui_ruby/widgets/bar_chart/bar_group.rb +29 -0
  151. data/lib/ratatui_ruby/widgets/bar_chart.rb +308 -0
  152. data/lib/ratatui_ruby/widgets/block.rb +266 -0
  153. data/lib/ratatui_ruby/widgets/calendar.rb +88 -0
  154. data/lib/ratatui_ruby/widgets/canvas.rb +297 -0
  155. data/lib/ratatui_ruby/widgets/cell.rb +59 -0
  156. data/lib/ratatui_ruby/widgets/center.rb +71 -0
  157. data/lib/ratatui_ruby/widgets/chart.rb +172 -0
  158. data/lib/ratatui_ruby/widgets/clear.rb +66 -0
  159. data/lib/ratatui_ruby/widgets/coerceable_widget.rb +77 -0
  160. data/lib/ratatui_ruby/widgets/cursor.rb +54 -0
  161. data/lib/ratatui_ruby/widgets/gauge.rb +146 -0
  162. data/lib/ratatui_ruby/widgets/line_gauge.rb +158 -0
  163. data/lib/ratatui_ruby/widgets/list.rb +252 -0
  164. data/lib/ratatui_ruby/widgets/list_item.rb +55 -0
  165. data/lib/ratatui_ruby/widgets/overlay.rb +55 -0
  166. data/lib/ratatui_ruby/widgets/paragraph.rb +113 -0
  167. data/lib/ratatui_ruby/widgets/ratatui_logo.rb +35 -0
  168. data/lib/ratatui_ruby/widgets/ratatui_mascot.rb +40 -0
  169. data/lib/ratatui_ruby/widgets/row.rb +123 -0
  170. data/lib/ratatui_ruby/widgets/scrollbar.rb +147 -0
  171. data/lib/ratatui_ruby/widgets/shape/label.rb +80 -0
  172. data/lib/ratatui_ruby/widgets/sparkline.rb +153 -0
  173. data/lib/ratatui_ruby/widgets/table.rb +213 -0
  174. data/lib/ratatui_ruby/widgets/tabs.rb +91 -0
  175. data/lib/ratatui_ruby/widgets.rb +43 -0
  176. data/lib/ratatui_ruby.rb +555 -0
  177. data/sig/examples/app_all_events/app.rbs +11 -0
  178. data/sig/examples/app_all_events/model/app_model.rbs +23 -0
  179. data/sig/examples/app_all_events/model/event_entry.rbs +23 -0
  180. data/sig/examples/app_all_events/model/timestamp.rbs +11 -0
  181. data/sig/examples/app_all_events/view/app_view.rbs +8 -0
  182. data/sig/examples/app_all_events/view/controls_view.rbs +6 -0
  183. data/sig/examples/app_all_events/view/counts_view.rbs +6 -0
  184. data/sig/examples/app_all_events/view/live_view.rbs +6 -0
  185. data/sig/examples/app_all_events/view/log_view.rbs +6 -0
  186. data/sig/examples/app_all_events/view.rbs +14 -0
  187. data/sig/examples/app_cli_rich_moments/app.rbs +12 -0
  188. data/sig/examples/app_color_picker/app.rbs +17 -0
  189. data/sig/examples/app_external_editor/app.rbs +12 -0
  190. data/sig/examples/app_login_form/app.rbs +11 -0
  191. data/sig/examples/app_stateful_interaction/app.rbs +39 -0
  192. data/sig/examples/verify_quickstart_dsl/app.rbs +17 -0
  193. data/sig/examples/verify_quickstart_lifecycle/app.rbs +17 -0
  194. data/sig/examples/verify_readme_usage/app.rbs +17 -0
  195. data/sig/examples/widget_block_demo/app.rbs +38 -0
  196. data/sig/examples/widget_box_demo/app.rbs +17 -0
  197. data/sig/examples/widget_calendar_demo/app.rbs +17 -0
  198. data/sig/examples/widget_cell_demo/app.rbs +17 -0
  199. data/sig/examples/widget_chart_demo/app.rbs +17 -0
  200. data/sig/examples/widget_gauge_demo/app.rbs +17 -0
  201. data/sig/examples/widget_layout_split/app.rbs +16 -0
  202. data/sig/examples/widget_line_gauge_demo/app.rbs +17 -0
  203. data/sig/examples/widget_list_demo/app.rbs +17 -0
  204. data/sig/examples/widget_map_demo/app.rbs +17 -0
  205. data/sig/examples/widget_popup_demo/app.rbs +17 -0
  206. data/sig/examples/widget_ratatui_logo_demo/app.rbs +17 -0
  207. data/sig/examples/widget_ratatui_mascot_demo/app.rbs +17 -0
  208. data/sig/examples/widget_rect/app.rbs +18 -0
  209. data/sig/examples/widget_render/app.rbs +16 -0
  210. data/sig/examples/widget_rich_text/app.rbs +17 -0
  211. data/sig/examples/widget_scroll_text/app.rbs +17 -0
  212. data/sig/examples/widget_scrollbar_demo/app.rbs +17 -0
  213. data/sig/examples/widget_sparkline_demo/app.rbs +16 -0
  214. data/sig/examples/widget_style_colors/app.rbs +20 -0
  215. data/sig/examples/widget_table_demo/app.rbs +17 -0
  216. data/sig/examples/widget_text_width/app.rbs +16 -0
  217. data/sig/generated/event_key_predicates.rbs +1348 -0
  218. data/sig/manifest.yaml +5 -0
  219. data/sig/patches/data.rbs +26 -0
  220. data/sig/patches/debugger__.rbs +8 -0
  221. data/sig/ratatui_ruby/backend/window_size.rbs +17 -0
  222. data/sig/ratatui_ruby/backend.rbs +12 -0
  223. data/sig/ratatui_ruby/buffer/cell.rbs +46 -0
  224. data/sig/ratatui_ruby/buffer.rbs +18 -0
  225. data/sig/ratatui_ruby/cell.rbs +44 -0
  226. data/sig/ratatui_ruby/clear.rbs +18 -0
  227. data/sig/ratatui_ruby/constraint.rbs +26 -0
  228. data/sig/ratatui_ruby/debug.rbs +45 -0
  229. data/sig/ratatui_ruby/draw.rbs +30 -0
  230. data/sig/ratatui_ruby/event.rbs +249 -0
  231. data/sig/ratatui_ruby/frame.rbs +23 -0
  232. data/sig/ratatui_ruby/interfaces.rbs +25 -0
  233. data/sig/ratatui_ruby/labs.rbs +90 -0
  234. data/sig/ratatui_ruby/layout/alignment.rbs +26 -0
  235. data/sig/ratatui_ruby/layout/constraint.rbs +39 -0
  236. data/sig/ratatui_ruby/layout/layout.rbs +45 -0
  237. data/sig/ratatui_ruby/layout/position.rbs +18 -0
  238. data/sig/ratatui_ruby/layout/rect.rbs +64 -0
  239. data/sig/ratatui_ruby/layout/size.rbs +18 -0
  240. data/sig/ratatui_ruby/list_state.rbs +23 -0
  241. data/sig/ratatui_ruby/output_guard.rbs +23 -0
  242. data/sig/ratatui_ruby/ratatui_ruby.rbs +113 -0
  243. data/sig/ratatui_ruby/rect.rbs +17 -0
  244. data/sig/ratatui_ruby/scrollbar_state.rbs +24 -0
  245. data/sig/ratatui_ruby/session.rbs +93 -0
  246. data/sig/ratatui_ruby/style/color.rbs +22 -0
  247. data/sig/ratatui_ruby/style/style.rbs +29 -0
  248. data/sig/ratatui_ruby/symbols.rbs +141 -0
  249. data/sig/ratatui_ruby/synthetic_events.rbs +24 -0
  250. data/sig/ratatui_ruby/table_state.rbs +27 -0
  251. data/sig/ratatui_ruby/terminal/capabilities.rbs +38 -0
  252. data/sig/ratatui_ruby/terminal/viewport.rbs +33 -0
  253. data/sig/ratatui_ruby/terminal_lifecycle.rbs +39 -0
  254. data/sig/ratatui_ruby/test_helper/event_injection.rbs +22 -0
  255. data/sig/ratatui_ruby/test_helper/snapshot.rbs +37 -0
  256. data/sig/ratatui_ruby/test_helper/style_assertions.rbs +77 -0
  257. data/sig/ratatui_ruby/test_helper/terminal.rbs +20 -0
  258. data/sig/ratatui_ruby/test_helper/test_doubles.rbs +32 -0
  259. data/sig/ratatui_ruby/test_helper.rbs +18 -0
  260. data/sig/ratatui_ruby/text/line.rbs +27 -0
  261. data/sig/ratatui_ruby/text/span.rbs +23 -0
  262. data/sig/ratatui_ruby/text.rbs +12 -0
  263. data/sig/ratatui_ruby/tui/buffer_factories.rbs +16 -0
  264. data/sig/ratatui_ruby/tui/canvas_factories.rbs +38 -0
  265. data/sig/ratatui_ruby/tui/core.rbs +23 -0
  266. data/sig/ratatui_ruby/tui/layout_factories.rbs +39 -0
  267. data/sig/ratatui_ruby/tui/state_factories.rbs +23 -0
  268. data/sig/ratatui_ruby/tui/style_factories.rbs +18 -0
  269. data/sig/ratatui_ruby/tui/text_factories.rbs +23 -0
  270. data/sig/ratatui_ruby/tui/widget_factories.rbs +138 -0
  271. data/sig/ratatui_ruby/tui.rbs +25 -0
  272. data/sig/ratatui_ruby/version.rbs +12 -0
  273. data/sig/ratatui_ruby/widgets/bar_chart.rbs +95 -0
  274. data/sig/ratatui_ruby/widgets/block.rbs +51 -0
  275. data/sig/ratatui_ruby/widgets/calendar.rbs +45 -0
  276. data/sig/ratatui_ruby/widgets/canvas.rbs +95 -0
  277. data/sig/ratatui_ruby/widgets/chart.rbs +91 -0
  278. data/sig/ratatui_ruby/widgets/coerceable_widget.rbs +26 -0
  279. data/sig/ratatui_ruby/widgets/gauge.rbs +44 -0
  280. data/sig/ratatui_ruby/widgets/line_gauge.rbs +48 -0
  281. data/sig/ratatui_ruby/widgets/list.rbs +63 -0
  282. data/sig/ratatui_ruby/widgets/misc.rbs +158 -0
  283. data/sig/ratatui_ruby/widgets/paragraph.rbs +45 -0
  284. data/sig/ratatui_ruby/widgets/row.rbs +43 -0
  285. data/sig/ratatui_ruby/widgets/scrollbar.rbs +53 -0
  286. data/sig/ratatui_ruby/widgets/shape/label.rbs +37 -0
  287. data/sig/ratatui_ruby/widgets/sparkline.rbs +45 -0
  288. data/sig/ratatui_ruby/widgets/table.rbs +78 -0
  289. data/sig/ratatui_ruby/widgets/tabs.rbs +44 -0
  290. data/sig/ratatui_ruby/widgets.rbs +16 -0
  291. data/vendor/goodcop/base.yml +1047 -0
  292. metadata +729 -0
@@ -0,0 +1,183 @@
1
+ // SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
+ // SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ use crate::style::{parse_block, parse_color, parse_style};
5
+ use crate::text::parse_text;
6
+ use bumpalo::Bump;
7
+ use magnus::{prelude::*, Error, RArray, Symbol, Value};
8
+ use ratatui::buffer::Buffer;
9
+ use ratatui::{
10
+ symbols::Marker,
11
+ widgets::{
12
+ canvas::{Canvas, Circle, Line, Map, MapResolution, Rectangle},
13
+ Widget,
14
+ },
15
+ };
16
+
17
+ #[allow(clippy::too_many_lines)]
18
+ pub fn render(buffer: &mut Buffer, area: ratatui::layout::Rect, node: Value) -> Result<(), Error> {
19
+ let bump = Bump::new();
20
+ let shapes_val: RArray = node.funcall("shapes", ())?;
21
+ let x_bounds_val: RArray = node.funcall("x_bounds", ())?;
22
+ let y_bounds_val: RArray = node.funcall("y_bounds", ())?;
23
+ let marker_sym: Symbol = node.funcall("marker", ())?;
24
+ let block_val: Value = node.funcall("block", ())?;
25
+
26
+ let x_bounds: [f64; 2] = [x_bounds_val.entry::<f64>(0)?, x_bounds_val.entry::<f64>(1)?];
27
+ let y_bounds: [f64; 2] = [y_bounds_val.entry::<f64>(0)?, y_bounds_val.entry::<f64>(1)?];
28
+
29
+ let marker = match marker_sym.to_string().as_str() {
30
+ "dot" => Marker::Dot,
31
+ "block" => Marker::Block,
32
+ "bar" => Marker::Bar,
33
+ "half_block" => Marker::HalfBlock,
34
+ "quadrant" => Marker::Quadrant,
35
+ "sextant" => Marker::Sextant,
36
+ "octant" => Marker::Octant,
37
+ _ => Marker::Braille,
38
+ };
39
+
40
+ let mut canvas = Canvas::default()
41
+ .x_bounds(x_bounds)
42
+ .y_bounds(y_bounds)
43
+ .marker(marker);
44
+
45
+ if !block_val.is_nil() {
46
+ canvas = canvas.block(parse_block(block_val, &bump)?);
47
+ }
48
+
49
+ let background_color_val: Value = node.funcall("background_color", ())?;
50
+ if !background_color_val.is_nil() {
51
+ let background_color =
52
+ parse_color(&background_color_val.to_string()).unwrap_or(ratatui::style::Color::Reset);
53
+ canvas = canvas.background_color(background_color);
54
+ }
55
+
56
+ let canvas = canvas.paint(|ctx| {
57
+ for shape_val in shapes_val {
58
+ let class = shape_val.class();
59
+ // SAFETY: Immediate conversion to owned string avoids GC-unsafe borrowed reference.
60
+ let class_name = unsafe { class.name() }.into_owned();
61
+
62
+ match class_name.as_str() {
63
+ "RatatuiRuby::Widgets::Shape::Line" => {
64
+ let x1: f64 = shape_val.funcall("x1", ()).unwrap_or(0.0);
65
+ let y1: f64 = shape_val.funcall("y1", ()).unwrap_or(0.0);
66
+ let x2: f64 = shape_val.funcall("x2", ()).unwrap_or(0.0);
67
+ let y2: f64 = shape_val.funcall("y2", ()).unwrap_or(0.0);
68
+ let color_val: Value = shape_val.funcall("color", ()).unwrap();
69
+ let color =
70
+ parse_color(&color_val.to_string()).unwrap_or(ratatui::style::Color::Reset);
71
+ ctx.draw(&Line {
72
+ x1,
73
+ y1,
74
+ x2,
75
+ y2,
76
+ color,
77
+ });
78
+ }
79
+ "RatatuiRuby::Widgets::Shape::Rectangle" => {
80
+ let x: f64 = shape_val.funcall("x", ()).unwrap_or(0.0);
81
+ let y: f64 = shape_val.funcall("y", ()).unwrap_or(0.0);
82
+ let width: f64 = shape_val.funcall("width", ()).unwrap_or(0.0);
83
+ let height: f64 = shape_val.funcall("height", ()).unwrap_or(0.0);
84
+ let color_val: Value = shape_val.funcall("color", ()).unwrap();
85
+ let color =
86
+ parse_color(&color_val.to_string()).unwrap_or(ratatui::style::Color::Reset);
87
+ ctx.draw(&Rectangle {
88
+ x,
89
+ y,
90
+ width,
91
+ height,
92
+ color,
93
+ });
94
+ }
95
+ "RatatuiRuby::Widgets::Shape::Circle" => {
96
+ let x: f64 = shape_val.funcall("x", ()).unwrap_or(0.0);
97
+ let y: f64 = shape_val.funcall("y", ()).unwrap_or(0.0);
98
+ let radius: f64 = shape_val.funcall("radius", ()).unwrap_or(0.0);
99
+ let color_val: Value = shape_val.funcall("color", ()).unwrap();
100
+ let color =
101
+ parse_color(&color_val.to_string()).unwrap_or(ratatui::style::Color::Reset);
102
+ ctx.draw(&Circle {
103
+ x,
104
+ y,
105
+ radius,
106
+ color,
107
+ });
108
+ }
109
+ "RatatuiRuby::Widgets::Shape::Map" => {
110
+ let color_val: Value = shape_val.funcall("color", ()).unwrap();
111
+ let color =
112
+ parse_color(&color_val.to_string()).unwrap_or(ratatui::style::Color::Reset);
113
+ let resolution_sym: Symbol = shape_val.funcall("resolution", ()).unwrap();
114
+ let resolution = match resolution_sym.to_string().as_str() {
115
+ "high" => MapResolution::High,
116
+ _ => MapResolution::Low,
117
+ };
118
+ ctx.draw(&Map { color, resolution });
119
+ }
120
+ "RatatuiRuby::Widgets::Shape::Label" => {
121
+ let x: f64 = shape_val.funcall("x", ()).unwrap_or(0.0);
122
+ let y: f64 = shape_val.funcall("y", ()).unwrap_or(0.0);
123
+ let text_val: Value = shape_val.funcall("text", ()).unwrap();
124
+ let style_val: Value = shape_val.funcall("style", ()).unwrap();
125
+
126
+ // Parse text - take first line if multiple
127
+ if let Ok(lines) = parse_text(text_val) {
128
+ let mut line = lines.into_iter().next().unwrap_or_default();
129
+
130
+ // Apply style if provided
131
+ if !style_val.is_nil() {
132
+ if let Ok(style) = parse_style(style_val) {
133
+ line = line.style(style);
134
+ }
135
+ }
136
+
137
+ ctx.print(x, y, line);
138
+ }
139
+ }
140
+ _ => {}
141
+ }
142
+ }
143
+ });
144
+
145
+ Widget::render(canvas, area, buffer);
146
+ Ok(())
147
+ }
148
+
149
+ #[cfg(test)]
150
+ mod tests {
151
+ use super::*;
152
+ use ratatui::buffer::Buffer;
153
+ use ratatui::layout::Rect;
154
+ use ratatui::widgets::Widget;
155
+
156
+ #[test]
157
+ fn test_canvas_rendering() {
158
+ let canvas = Canvas::default()
159
+ .x_bounds([0.0, 10.0])
160
+ .y_bounds([0.0, 10.0])
161
+ .marker(Marker::Braille)
162
+ .paint(|ctx| {
163
+ ctx.draw(&Line {
164
+ x1: 0.0,
165
+ y1: 0.0,
166
+ x2: 10.0,
167
+ y2: 10.0,
168
+ color: ratatui::style::Color::Red,
169
+ });
170
+ });
171
+ let mut buf = Buffer::empty(Rect::new(0, 0, 5, 5));
172
+ canvas.render(Rect::new(0, 0, 5, 5), &mut buf);
173
+
174
+ let mut found_braille = false;
175
+ for cell in buf.content() {
176
+ if !cell.symbol().trim().is_empty() {
177
+ found_braille = true;
178
+ break;
179
+ }
180
+ }
181
+ assert!(found_braille, "Canvas should render Braille characters");
182
+ }
183
+ }
@@ -0,0 +1,79 @@
1
+ // SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
+ // SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ use crate::rendering::render_node;
5
+ use magnus::{prelude::*, Error, Value};
6
+ use ratatui::{
7
+ buffer::Buffer,
8
+ layout::{Constraint, Direction, Layout, Rect},
9
+ };
10
+
11
+ pub fn render(buffer: &mut Buffer, area: Rect, node: Value) -> Result<(), Error> {
12
+ let child: Value = node.funcall("child", ())?;
13
+ let width_percent: u16 = node.funcall("width_percent", ())?;
14
+ let height_percent: u16 = node.funcall("height_percent", ())?;
15
+
16
+ let popup_layout = Layout::default()
17
+ .direction(Direction::Vertical)
18
+ .constraints([
19
+ Constraint::Percentage((100 - height_percent) / 2),
20
+ Constraint::Percentage(height_percent),
21
+ Constraint::Percentage((100 - height_percent) / 2),
22
+ ])
23
+ .split(area);
24
+
25
+ let vertical_center_area = popup_layout[1];
26
+
27
+ let popup_layout_horizontal = Layout::default()
28
+ .direction(Direction::Horizontal)
29
+ .constraints([
30
+ Constraint::Percentage((100 - width_percent) / 2),
31
+ Constraint::Percentage(width_percent),
32
+ Constraint::Percentage((100 - width_percent) / 2),
33
+ ])
34
+ .split(vertical_center_area);
35
+
36
+ let center_area = popup_layout_horizontal[1];
37
+
38
+ render_node(buffer, center_area, child)?;
39
+ Ok(())
40
+ }
41
+
42
+ #[cfg(test)]
43
+ mod tests {
44
+
45
+ use ratatui::layout::{Constraint, Direction, Layout, Rect};
46
+
47
+ #[test]
48
+ fn test_center_logic() {
49
+ let area = Rect::new(0, 0, 100, 100);
50
+ let width_percent = 50;
51
+ let height_percent = 50;
52
+
53
+ let popup_layout = Layout::default()
54
+ .direction(Direction::Vertical)
55
+ .constraints([
56
+ Constraint::Percentage((100 - height_percent) / 2),
57
+ Constraint::Percentage(height_percent),
58
+ Constraint::Percentage((100 - height_percent) / 2),
59
+ ])
60
+ .split(area);
61
+ let vertical_center = popup_layout[1];
62
+
63
+ // Vertical check
64
+ assert_eq!(vertical_center.height, 50);
65
+
66
+ let popup_layout_horizontal = Layout::default()
67
+ .direction(Direction::Horizontal)
68
+ .constraints([
69
+ Constraint::Percentage((100 - width_percent) / 2),
70
+ Constraint::Percentage(width_percent),
71
+ Constraint::Percentage((100 - width_percent) / 2),
72
+ ])
73
+ .split(vertical_center);
74
+ let center = popup_layout_horizontal[1];
75
+
76
+ // Horizontal check
77
+ assert_eq!(center.width, 50);
78
+ }
79
+ }
@@ -0,0 +1,222 @@
1
+ // SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
+ // SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ use crate::errors::type_error_with_context;
5
+ use crate::style::{parse_block, parse_style};
6
+ use crate::text::parse_line;
7
+ use bumpalo::Bump;
8
+ use magnus::{prelude::*, Error, Symbol, Value};
9
+ use ratatui::buffer::Buffer;
10
+ use ratatui::{
11
+ layout::Rect,
12
+ symbols,
13
+ widgets::{Axis, Chart, Dataset, GraphType, LegendPosition, Widget},
14
+ };
15
+
16
+ #[allow(clippy::too_many_lines)]
17
+ pub fn render(buffer: &mut Buffer, area: Rect, node: Value) -> Result<(), Error> {
18
+ let bump = Bump::new();
19
+ let ruby = magnus::Ruby::get().unwrap();
20
+
21
+ let datasets_val: magnus::RArray = node.funcall("datasets", ())?;
22
+ let x_axis_val: Value = node.funcall("x_axis", ())?;
23
+ let y_axis_val: Value = node.funcall("y_axis", ())?;
24
+ let block_val: Value = node.funcall("block", ())?;
25
+ let style_val: Value = node.funcall("style", ())?;
26
+ let legend_position_val: Value = node.funcall("legend_position", ())?;
27
+ let hidden_legend_constraints_val: Value = node.funcall("hidden_legend_constraints", ())?;
28
+
29
+ let mut datasets = Vec::new();
30
+ // We need to keep the data alive until the chart is rendered
31
+ let mut data_storage: Vec<Vec<(f64, f64)>> = Vec::new();
32
+
33
+ for i in 0..datasets_val.len() {
34
+ let index = isize::try_from(i)
35
+ .map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
36
+ let ds_val: Value = datasets_val.entry(index)?;
37
+ let data_array: magnus::RArray = ds_val.funcall("data", ())?;
38
+
39
+ let mut points = Vec::new();
40
+ for j in 0..data_array.len() {
41
+ let index = isize::try_from(j)
42
+ .map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
43
+ let point_array_val: Value = data_array.entry(index)?;
44
+ let point_array = magnus::RArray::from_value(point_array_val).ok_or_else(|| {
45
+ type_error_with_context(&ruby, "expected array for point", point_array_val)
46
+ })?;
47
+ let x: f64 = point_array.entry(0)?;
48
+ let y: f64 = point_array.entry(1)?;
49
+ points.push((x, y));
50
+ }
51
+ data_storage.push(points);
52
+ }
53
+
54
+ for (i, points) in data_storage.iter().enumerate() {
55
+ let index = isize::try_from(i)
56
+ .map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
57
+ let ds_val: Value = datasets_val.entry(index)?;
58
+ let name_val: Value = ds_val.funcall("name", ())?;
59
+ let name = if let Ok(line) = parse_line(name_val) {
60
+ line
61
+ } else {
62
+ let name_str: String = name_val.funcall("to_s", ())?;
63
+ ratatui::text::Line::from(name_str)
64
+ };
65
+ let marker_sym: Symbol = ds_val.funcall("marker", ())?;
66
+ let graph_type_sym: Symbol = ds_val.funcall("graph_type", ())?;
67
+
68
+ let marker = match marker_sym.to_string().as_str() {
69
+ "braille" => symbols::Marker::Braille,
70
+ "block" => symbols::Marker::Block,
71
+ "bar" => symbols::Marker::Bar,
72
+ "half_block" => symbols::Marker::HalfBlock,
73
+ _ => symbols::Marker::Dot,
74
+ };
75
+
76
+ let graph_type = match graph_type_sym.to_string().as_str() {
77
+ "scatter" => GraphType::Scatter,
78
+ _ => GraphType::Line,
79
+ };
80
+
81
+ let mut ds_style = ratatui::style::Style::default();
82
+ let style_val: Value = ds_val.funcall("style", ())?;
83
+ if !style_val.is_nil() {
84
+ ds_style = parse_style(style_val)?;
85
+ }
86
+
87
+ let ds = Dataset::default()
88
+ .name(name)
89
+ .marker(marker)
90
+ .graph_type(graph_type)
91
+ .style(ds_style)
92
+ .data(points);
93
+ datasets.push(ds);
94
+ }
95
+
96
+ let x_axis = parse_axis(x_axis_val)?;
97
+ let y_axis = parse_axis(y_axis_val)?;
98
+
99
+ let mut chart = Chart::new(datasets).x_axis(x_axis).y_axis(y_axis);
100
+
101
+ if !block_val.is_nil() {
102
+ chart = chart.block(parse_block(block_val, &bump)?);
103
+ }
104
+
105
+ if !style_val.is_nil() {
106
+ chart = chart.style(parse_style(style_val)?);
107
+ }
108
+
109
+ if !legend_position_val.is_nil() {
110
+ let pos_sym: Symbol = legend_position_val.funcall("to_sym", ())?;
111
+ let pos = match pos_sym.to_string().as_str() {
112
+ "top_left" => LegendPosition::TopLeft,
113
+ "top" => LegendPosition::Top,
114
+ "bottom_left" => LegendPosition::BottomLeft,
115
+ "bottom" => LegendPosition::Bottom,
116
+ "bottom_right" => LegendPosition::BottomRight,
117
+ "left" => LegendPosition::Left,
118
+ "right" => LegendPosition::Right,
119
+ _ => LegendPosition::TopRight,
120
+ };
121
+ chart = chart.legend_position(Some(pos));
122
+ }
123
+
124
+ if !hidden_legend_constraints_val.is_nil() {
125
+ let constraints_array: magnus::RArray =
126
+ hidden_legend_constraints_val.funcall("to_a", ())?;
127
+ if constraints_array.len() == 2 {
128
+ let width_val: Value = constraints_array.entry(0)?;
129
+ let height_val: Value = constraints_array.entry(1)?;
130
+ let width_constraint = super::layout::parse_constraint(width_val)?;
131
+ let height_constraint = super::layout::parse_constraint(height_val)?;
132
+ chart = chart.hidden_legend_constraints((width_constraint, height_constraint));
133
+ }
134
+ }
135
+
136
+ Widget::render(chart, area, buffer);
137
+ Ok(())
138
+ }
139
+
140
+ fn parse_axis(axis_val: Value) -> Result<Axis<'static>, Error> {
141
+ let ruby = magnus::Ruby::get().unwrap();
142
+ let title_val: Value = axis_val.funcall("title", ())?;
143
+ let title = if title_val.is_nil() {
144
+ ratatui::text::Line::from("")
145
+ } else if let Ok(line) = parse_line(title_val) {
146
+ line
147
+ } else {
148
+ let title_str: String = title_val.funcall("to_s", ())?;
149
+ ratatui::text::Line::from(title_str)
150
+ };
151
+ let bounds_val: magnus::RArray = axis_val.funcall("bounds", ())?;
152
+ let labels_val: magnus::RArray = axis_val.funcall("labels", ())?;
153
+ let style_val: Value = axis_val.funcall("style", ())?;
154
+ let labels_alignment_val: Value = axis_val.funcall("labels_alignment", ())?;
155
+
156
+ let bounds: [f64; 2] = [bounds_val.entry(0)?, bounds_val.entry(1)?];
157
+
158
+ let mut labels = Vec::new();
159
+ for i in 0..labels_val.len() {
160
+ let index = isize::try_from(i)
161
+ .map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
162
+ let entry_val: Value = labels_val.entry(index)?;
163
+ let label = if let Ok(line) = parse_line(entry_val) {
164
+ line
165
+ } else {
166
+ let label_str: String = entry_val.funcall("to_s", ())?;
167
+ ratatui::text::Line::from(label_str)
168
+ };
169
+ labels.push(label);
170
+ }
171
+
172
+ let mut axis = Axis::default().title(title).bounds(bounds).labels(labels);
173
+
174
+ if !style_val.is_nil() {
175
+ axis = axis.style(parse_style(style_val)?);
176
+ }
177
+
178
+ if !labels_alignment_val.is_nil() {
179
+ let alignment_sym: Symbol = labels_alignment_val.funcall("to_sym", ())?;
180
+ let alignment = match alignment_sym.to_string().as_str() {
181
+ "left" => ratatui::layout::HorizontalAlignment::Left,
182
+ "right" => ratatui::layout::HorizontalAlignment::Right,
183
+ _ => ratatui::layout::HorizontalAlignment::Center,
184
+ };
185
+ axis = axis.labels_alignment(alignment);
186
+ }
187
+
188
+ Ok(axis)
189
+ }
190
+
191
+ #[cfg(test)]
192
+ mod tests {
193
+ use super::*;
194
+ use ratatui::buffer::Buffer;
195
+ use ratatui::widgets::Widget;
196
+
197
+ #[test]
198
+ fn test_chart_rendering() {
199
+ let data = vec![(0.0, 0.0), (1.0, 1.0)];
200
+ let datasets = vec![Dataset::default().name("TestDS").data(&data)];
201
+ let chart = Chart::new(datasets)
202
+ .x_axis(
203
+ Axis::default()
204
+ .bounds([0.0, 1.0])
205
+ .labels(vec!["XMIN".into(), "XMAX".into()] as Vec<ratatui::text::Line>),
206
+ )
207
+ .y_axis(
208
+ Axis::default()
209
+ .bounds([0.0, 1.0])
210
+ .labels(vec!["YMIN".into(), "YMAX".into()] as Vec<ratatui::text::Line>),
211
+ );
212
+ let mut buf = Buffer::empty(Rect::new(0, 0, 40, 20));
213
+ chart.render(Rect::new(0, 0, 40, 20), &mut buf);
214
+ assert!(buf.content().iter().any(|c| c.symbol() != " "));
215
+ let content = buf.content().iter().map(|c| c.symbol()).collect::<String>();
216
+ assert!(content.contains("XMIN"));
217
+ assert!(content.contains("XMAX"));
218
+ assert!(content.contains("YMIN"));
219
+ assert!(content.contains("YMAX"));
220
+ assert!(content.contains("TestDS"));
221
+ }
222
+ }
@@ -0,0 +1,39 @@
1
+ // SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
+ // SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ use bumpalo::Bump;
5
+ use magnus::{prelude::*, Error, Value};
6
+ use ratatui::{buffer::Buffer, layout::Rect, widgets::Widget};
7
+
8
+ pub fn render(buffer: &mut Buffer, area: Rect, node: Value) -> Result<(), Error> {
9
+ ratatui::widgets::Clear.render(area, buffer);
10
+
11
+ // If a block is provided, render it on top of the cleared area
12
+ if let Ok(block_val) = node.funcall::<_, _, Value>("block", ()) {
13
+ if !block_val.is_nil() {
14
+ let bump = Bump::new();
15
+ let block = crate::style::parse_block(block_val, &bump)?;
16
+ block.render(area, buffer);
17
+ }
18
+ }
19
+
20
+ Ok(())
21
+ }
22
+
23
+ #[cfg(test)]
24
+ mod tests {
25
+ use ratatui::{backend::TestBackend, layout::Rect, widgets::Widget, Terminal};
26
+
27
+ #[test]
28
+ fn test_clear_renders_without_error() {
29
+ let backend = TestBackend::new(10, 5);
30
+ let mut terminal = Terminal::new(backend).unwrap();
31
+
32
+ terminal
33
+ .draw(|frame| {
34
+ let area = Rect::new(0, 0, 10, 5);
35
+ ratatui::widgets::Clear.render(area, frame.buffer_mut());
36
+ })
37
+ .unwrap();
38
+ }
39
+ }
@@ -0,0 +1,32 @@
1
+ // SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
+ // SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ use magnus::{Error, Value};
5
+ use ratatui::{buffer::Buffer, layout::Rect};
6
+
7
+ /// Cursor widget requires Frame for `set_cursor_position` - cannot be rendered to buffer alone
8
+ /// This is a no-op when rendering to buffer directly (e.g., in `insert_before`)
9
+ /// For Frame-based rendering, use `frame.set_cursor_position()` directly
10
+ #[allow(dead_code, clippy::unnecessary_wraps)]
11
+ pub fn render(_buffer: &mut Buffer, _area: Rect, _node: Value) -> Result<(), Error> {
12
+ // Cursor positioning requires Frame.set_cursor_position(), not Buffer
13
+ // This is intentionally a no-op for buffer-only rendering
14
+ // The Frame wrapper in frame.rs should handle Cursor widgets specially
15
+ Ok(())
16
+ }
17
+
18
+ #[cfg(test)]
19
+ mod tests {
20
+ use ratatui::layout::Rect;
21
+
22
+ #[test]
23
+ fn test_cursor_math() {
24
+ let area = Rect::new(10, 10, 50, 50);
25
+ let x = 5;
26
+ let y = 5;
27
+ let abs_x = area.x + x;
28
+ let abs_y = area.y + y;
29
+ assert_eq!(abs_x, 15);
30
+ assert_eq!(abs_y, 15);
31
+ }
32
+ }
@@ -0,0 +1,65 @@
1
+ // SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
+ // SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ use crate::style::{parse_block, parse_style};
5
+ use crate::text::parse_span;
6
+ use bumpalo::Bump;
7
+ use magnus::{prelude::*, Error, Value};
8
+ use ratatui::buffer::Buffer;
9
+ use ratatui::{layout::Rect, widgets::Gauge, widgets::Widget};
10
+
11
+ pub fn render(buffer: &mut Buffer, area: Rect, node: Value) -> Result<(), Error> {
12
+ let bump = Bump::new();
13
+ let ratio: f64 = node.funcall("ratio", ())?;
14
+ let label_val: Value = node.funcall("label", ())?;
15
+ let style_val: Value = node.funcall("style", ())?;
16
+ let gauge_style_val: Value = node.funcall("gauge_style", ())?;
17
+ let block_val: Value = node.funcall("block", ())?;
18
+ let use_unicode: bool = node.funcall("use_unicode", ())?;
19
+ let mut gauge = Gauge::default().ratio(ratio).use_unicode(use_unicode);
20
+
21
+ if !label_val.is_nil() {
22
+ // Try to parse as a Span (rich text)
23
+ if let Ok(span) = parse_span(label_val) {
24
+ gauge = gauge.label(span);
25
+ } else {
26
+ // Fallback to string
27
+ let label_str: String = label_val.funcall("to_s", ())?;
28
+ gauge = gauge.label(label_str);
29
+ }
30
+ }
31
+
32
+ if !style_val.is_nil() {
33
+ gauge = gauge.style(parse_style(style_val)?);
34
+ }
35
+
36
+ if !gauge_style_val.is_nil() {
37
+ gauge = gauge.gauge_style(parse_style(gauge_style_val)?);
38
+ }
39
+
40
+ if !block_val.is_nil() {
41
+ gauge = gauge.block(parse_block(block_val, &bump)?);
42
+ }
43
+
44
+ gauge.render(area, buffer);
45
+ Ok(())
46
+ }
47
+
48
+ #[cfg(test)]
49
+ mod tests {
50
+ use super::*;
51
+ use ratatui::buffer::Buffer;
52
+ use ratatui::widgets::{Gauge, Widget};
53
+
54
+ #[test]
55
+ fn test_gauge_rendering() {
56
+ let gauge = Gauge::default().ratio(0.5).label("50%");
57
+ let mut buf = Buffer::empty(Rect::new(0, 0, 10, 1));
58
+ gauge.render(Rect::new(0, 0, 10, 1), &mut buf);
59
+ // Gauge renders block characters
60
+ assert!(buf.content().iter().any(|c| c.symbol() != " "));
61
+ // Should contain label
62
+ assert!(buf.content().iter().any(|c| c.symbol() == "5"));
63
+ assert!(buf.content().iter().any(|c| c.symbol() == "%"));
64
+ }
65
+ }