ratatui_ruby 0.9.1 → 0.10.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 (267) 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 +2 -1
  7. data/CHANGELOG.md +98 -0
  8. data/REUSE.toml +5 -0
  9. data/Rakefile +1 -1
  10. data/Steepfile +49 -0
  11. data/doc/concepts/debugging.md +401 -0
  12. data/doc/getting_started/quickstart.md +8 -3
  13. data/doc/images/app_all_events.png +0 -0
  14. data/doc/images/app_color_picker.png +0 -0
  15. data/doc/images/app_debugging_showcase.gif +0 -0
  16. data/doc/images/app_debugging_showcase.png +0 -0
  17. data/doc/images/app_login_form.png +0 -0
  18. data/doc/images/app_stateful_interaction.png +0 -0
  19. data/doc/images/verify_quickstart_dsl.png +0 -0
  20. data/doc/images/verify_quickstart_layout.png +0 -0
  21. data/doc/images/verify_quickstart_lifecycle.png +0 -0
  22. data/doc/images/verify_readme_usage.png +0 -0
  23. data/doc/images/widget_barchart.png +0 -0
  24. data/doc/images/widget_block.png +0 -0
  25. data/doc/images/widget_box.png +0 -0
  26. data/doc/images/widget_calendar.png +0 -0
  27. data/doc/images/widget_canvas.png +0 -0
  28. data/doc/images/widget_cell.png +0 -0
  29. data/doc/images/widget_center.png +0 -0
  30. data/doc/images/widget_chart.png +0 -0
  31. data/doc/images/widget_gauge.png +0 -0
  32. data/doc/images/widget_layout_split.png +0 -0
  33. data/doc/images/widget_line_gauge.png +0 -0
  34. data/doc/images/widget_list.png +0 -0
  35. data/doc/images/widget_map.png +0 -0
  36. data/doc/images/widget_overlay.png +0 -0
  37. data/doc/images/widget_popup.png +0 -0
  38. data/doc/images/widget_ratatui_logo.png +0 -0
  39. data/doc/images/widget_ratatui_mascot.png +0 -0
  40. data/doc/images/widget_rect.png +0 -0
  41. data/doc/images/widget_render.png +0 -0
  42. data/doc/images/widget_rich_text.png +0 -0
  43. data/doc/images/widget_scroll_text.png +0 -0
  44. data/doc/images/widget_scrollbar.png +0 -0
  45. data/doc/images/widget_sparkline.png +0 -0
  46. data/doc/images/widget_style_colors.png +0 -0
  47. data/doc/images/widget_table.png +0 -0
  48. data/doc/images/widget_tabs.png +0 -0
  49. data/doc/images/widget_text_width.png +0 -0
  50. data/doc/troubleshooting/async.md +4 -0
  51. data/examples/app_debugging_showcase/README.md +119 -0
  52. data/examples/app_debugging_showcase/app.rb +318 -0
  53. data/examples/widget_canvas/app.rb +19 -14
  54. data/examples/widget_gauge/app.rb +18 -3
  55. data/examples/widget_layout_split/app.rb +10 -4
  56. data/examples/widget_list/app.rb +22 -6
  57. data/examples/widget_rect/app.rb +7 -6
  58. data/examples/widget_rich_text/app.rb +62 -37
  59. data/examples/widget_style_colors/app.rb +26 -47
  60. data/examples/widget_table/app.rb +28 -5
  61. data/examples/widget_text_width/app.rb +6 -4
  62. data/ext/ratatui_ruby/Cargo.lock +48 -1
  63. data/ext/ratatui_ruby/Cargo.toml +6 -2
  64. data/ext/ratatui_ruby/src/color.rs +82 -0
  65. data/ext/ratatui_ruby/src/errors.rs +28 -0
  66. data/ext/ratatui_ruby/src/events.rs +15 -14
  67. data/ext/ratatui_ruby/src/lib.rs +56 -0
  68. data/ext/ratatui_ruby/src/rendering.rs +3 -1
  69. data/ext/ratatui_ruby/src/style.rs +48 -21
  70. data/ext/ratatui_ruby/src/terminal.rs +40 -9
  71. data/ext/ratatui_ruby/src/text.rs +21 -9
  72. data/ext/ratatui_ruby/src/widgets/chart.rs +2 -1
  73. data/ext/ratatui_ruby/src/widgets/layout.rs +90 -2
  74. data/ext/ratatui_ruby/src/widgets/list.rs +6 -5
  75. data/ext/ratatui_ruby/src/widgets/overlay.rs +2 -1
  76. data/ext/ratatui_ruby/src/widgets/table.rs +7 -6
  77. data/ext/ratatui_ruby/src/widgets/table_state.rs +55 -0
  78. data/ext/ratatui_ruby/src/widgets/tabs.rs +3 -2
  79. data/lib/ratatui_ruby/buffer/cell.rb +25 -15
  80. data/lib/ratatui_ruby/buffer.rb +134 -2
  81. data/lib/ratatui_ruby/cell.rb +13 -5
  82. data/lib/ratatui_ruby/debug.rb +215 -0
  83. data/lib/ratatui_ruby/event/key.rb +3 -2
  84. data/lib/ratatui_ruby/event.rb +1 -1
  85. data/lib/ratatui_ruby/layout/constraint.rb +49 -0
  86. data/lib/ratatui_ruby/layout/layout.rb +119 -13
  87. data/lib/ratatui_ruby/layout/position.rb +55 -0
  88. data/lib/ratatui_ruby/layout/rect.rb +188 -0
  89. data/lib/ratatui_ruby/layout/size.rb +55 -0
  90. data/lib/ratatui_ruby/layout.rb +4 -0
  91. data/lib/ratatui_ruby/style/color.rb +149 -0
  92. data/lib/ratatui_ruby/style/style.rb +51 -4
  93. data/lib/ratatui_ruby/style.rb +2 -0
  94. data/lib/ratatui_ruby/symbols.rb +435 -0
  95. data/lib/ratatui_ruby/synthetic_events.rb +1 -1
  96. data/lib/ratatui_ruby/table_state.rb +51 -0
  97. data/lib/ratatui_ruby/terminal_lifecycle.rb +2 -1
  98. data/lib/ratatui_ruby/test_helper/event_injection.rb +6 -1
  99. data/lib/ratatui_ruby/test_helper.rb +9 -0
  100. data/lib/ratatui_ruby/text/line.rb +245 -0
  101. data/lib/ratatui_ruby/text/span.rb +158 -0
  102. data/lib/ratatui_ruby/text.rb +99 -0
  103. data/lib/ratatui_ruby/tui/canvas_factories.rb +103 -0
  104. data/lib/ratatui_ruby/tui/core.rb +13 -2
  105. data/lib/ratatui_ruby/tui/layout_factories.rb +50 -3
  106. data/lib/ratatui_ruby/tui/state_factories.rb +42 -0
  107. data/lib/ratatui_ruby/tui/text_factories.rb +40 -0
  108. data/lib/ratatui_ruby/tui/widget_factories.rb +135 -60
  109. data/lib/ratatui_ruby/tui.rb +22 -1
  110. data/lib/ratatui_ruby/version.rb +1 -1
  111. data/lib/ratatui_ruby/widgets/bar_chart/bar.rb +2 -0
  112. data/lib/ratatui_ruby/widgets/bar_chart/bar_group.rb +2 -0
  113. data/lib/ratatui_ruby/widgets/bar_chart.rb +30 -20
  114. data/lib/ratatui_ruby/widgets/block.rb +14 -6
  115. data/lib/ratatui_ruby/widgets/calendar.rb +2 -0
  116. data/lib/ratatui_ruby/widgets/canvas.rb +56 -0
  117. data/lib/ratatui_ruby/widgets/cell.rb +2 -0
  118. data/lib/ratatui_ruby/widgets/center.rb +2 -0
  119. data/lib/ratatui_ruby/widgets/chart.rb +6 -0
  120. data/lib/ratatui_ruby/widgets/clear.rb +2 -0
  121. data/lib/ratatui_ruby/widgets/coerceable_widget.rb +77 -0
  122. data/lib/ratatui_ruby/widgets/cursor.rb +2 -0
  123. data/lib/ratatui_ruby/widgets/gauge.rb +61 -3
  124. data/lib/ratatui_ruby/widgets/line_gauge.rb +66 -4
  125. data/lib/ratatui_ruby/widgets/list.rb +87 -3
  126. data/lib/ratatui_ruby/widgets/list_item.rb +2 -0
  127. data/lib/ratatui_ruby/widgets/overlay.rb +2 -0
  128. data/lib/ratatui_ruby/widgets/paragraph.rb +4 -0
  129. data/lib/ratatui_ruby/widgets/ratatui_logo.rb +2 -0
  130. data/lib/ratatui_ruby/widgets/ratatui_mascot.rb +2 -0
  131. data/lib/ratatui_ruby/widgets/row.rb +45 -0
  132. data/lib/ratatui_ruby/widgets/scrollbar.rb +2 -0
  133. data/lib/ratatui_ruby/widgets/shape/label.rb +2 -0
  134. data/lib/ratatui_ruby/widgets/sparkline.rb +21 -13
  135. data/lib/ratatui_ruby/widgets/table.rb +13 -3
  136. data/lib/ratatui_ruby/widgets/tabs.rb +6 -4
  137. data/lib/ratatui_ruby/widgets.rb +1 -0
  138. data/lib/ratatui_ruby.rb +40 -9
  139. data/sig/examples/app_all_events/model/app_model.rbs +23 -0
  140. data/sig/examples/app_all_events/model/event_entry.rbs +15 -8
  141. data/sig/examples/app_all_events/model/timestamp.rbs +1 -1
  142. data/sig/examples/app_all_events/view.rbs +1 -1
  143. data/sig/examples/app_stateful_interaction/app.rbs +5 -5
  144. data/sig/examples/widget_block_demo/app.rbs +6 -6
  145. data/sig/manifest.yaml +5 -0
  146. data/sig/patches/data.rbs +26 -0
  147. data/sig/patches/debugger__.rbs +8 -0
  148. data/sig/ratatui_ruby/buffer/cell.rbs +46 -0
  149. data/sig/ratatui_ruby/buffer.rbs +18 -0
  150. data/sig/ratatui_ruby/cell.rbs +44 -0
  151. data/sig/ratatui_ruby/clear.rbs +18 -0
  152. data/sig/ratatui_ruby/constraint.rbs +26 -0
  153. data/sig/ratatui_ruby/debug.rbs +45 -0
  154. data/sig/ratatui_ruby/draw.rbs +30 -0
  155. data/sig/ratatui_ruby/event.rbs +68 -8
  156. data/sig/ratatui_ruby/frame.rbs +4 -4
  157. data/sig/ratatui_ruby/interfaces.rbs +25 -0
  158. data/sig/ratatui_ruby/layout/constraint.rbs +39 -0
  159. data/sig/ratatui_ruby/layout/layout.rbs +45 -0
  160. data/sig/ratatui_ruby/layout/position.rbs +18 -0
  161. data/sig/ratatui_ruby/layout/rect.rbs +64 -0
  162. data/sig/ratatui_ruby/layout/size.rbs +18 -0
  163. data/sig/ratatui_ruby/output_guard.rbs +23 -0
  164. data/sig/ratatui_ruby/ratatui_ruby.rbs +83 -4
  165. data/sig/ratatui_ruby/rect.rbs +17 -0
  166. data/sig/ratatui_ruby/style/color.rbs +22 -0
  167. data/sig/ratatui_ruby/style/style.rbs +29 -0
  168. data/sig/ratatui_ruby/symbols.rbs +141 -0
  169. data/sig/ratatui_ruby/synthetic_events.rbs +21 -0
  170. data/sig/ratatui_ruby/table_state.rbs +6 -0
  171. data/sig/ratatui_ruby/terminal_lifecycle.rbs +31 -0
  172. data/sig/ratatui_ruby/test_helper/event_injection.rbs +2 -2
  173. data/sig/ratatui_ruby/test_helper/snapshot.rbs +22 -3
  174. data/sig/ratatui_ruby/test_helper/style_assertions.rbs +8 -1
  175. data/sig/ratatui_ruby/test_helper/test_doubles.rbs +7 -3
  176. data/sig/ratatui_ruby/text/line.rbs +27 -0
  177. data/sig/ratatui_ruby/text/span.rbs +23 -0
  178. data/sig/ratatui_ruby/text.rbs +12 -0
  179. data/sig/ratatui_ruby/tui/buffer_factories.rbs +1 -1
  180. data/sig/ratatui_ruby/tui/canvas_factories.rbs +23 -5
  181. data/sig/ratatui_ruby/tui/core.rbs +2 -2
  182. data/sig/ratatui_ruby/tui/layout_factories.rbs +16 -2
  183. data/sig/ratatui_ruby/tui/state_factories.rbs +8 -3
  184. data/sig/ratatui_ruby/tui/style_factories.rbs +3 -1
  185. data/sig/ratatui_ruby/tui/text_factories.rbs +7 -4
  186. data/sig/ratatui_ruby/tui/widget_factories.rbs +123 -30
  187. data/sig/ratatui_ruby/widgets/bar_chart.rbs +95 -0
  188. data/sig/ratatui_ruby/widgets/block.rbs +51 -0
  189. data/sig/ratatui_ruby/widgets/calendar.rbs +45 -0
  190. data/sig/ratatui_ruby/widgets/canvas.rbs +95 -0
  191. data/sig/ratatui_ruby/widgets/chart.rbs +91 -0
  192. data/sig/ratatui_ruby/widgets/coerceable_widget.rbs +26 -0
  193. data/sig/ratatui_ruby/widgets/gauge.rbs +44 -0
  194. data/sig/ratatui_ruby/widgets/line_gauge.rbs +48 -0
  195. data/sig/ratatui_ruby/widgets/list.rbs +63 -0
  196. data/sig/ratatui_ruby/widgets/misc.rbs +158 -0
  197. data/sig/ratatui_ruby/widgets/paragraph.rbs +45 -0
  198. data/sig/ratatui_ruby/widgets/row.rbs +43 -0
  199. data/sig/ratatui_ruby/widgets/scrollbar.rbs +53 -0
  200. data/sig/ratatui_ruby/widgets/shape/label.rbs +37 -0
  201. data/sig/ratatui_ruby/widgets/sparkline.rbs +45 -0
  202. data/sig/ratatui_ruby/widgets/table.rbs +78 -0
  203. data/sig/ratatui_ruby/widgets/tabs.rbs +44 -0
  204. data/sig/ratatui_ruby/{schema/list_item.rbs → widgets.rbs} +4 -4
  205. data/tasks/steep.rake +11 -0
  206. metadata +80 -63
  207. data/doc/contributors/v1.0.0_blockers.md +0 -870
  208. data/doc/troubleshooting/debugging.md +0 -101
  209. data/lib/ratatui_ruby/schema/bar_chart/bar.rb +0 -47
  210. data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +0 -25
  211. data/lib/ratatui_ruby/schema/bar_chart.rb +0 -287
  212. data/lib/ratatui_ruby/schema/block.rb +0 -198
  213. data/lib/ratatui_ruby/schema/calendar.rb +0 -84
  214. data/lib/ratatui_ruby/schema/canvas.rb +0 -239
  215. data/lib/ratatui_ruby/schema/center.rb +0 -67
  216. data/lib/ratatui_ruby/schema/chart.rb +0 -159
  217. data/lib/ratatui_ruby/schema/clear.rb +0 -62
  218. data/lib/ratatui_ruby/schema/constraint.rb +0 -151
  219. data/lib/ratatui_ruby/schema/cursor.rb +0 -50
  220. data/lib/ratatui_ruby/schema/gauge.rb +0 -72
  221. data/lib/ratatui_ruby/schema/layout.rb +0 -122
  222. data/lib/ratatui_ruby/schema/line_gauge.rb +0 -80
  223. data/lib/ratatui_ruby/schema/list.rb +0 -135
  224. data/lib/ratatui_ruby/schema/list_item.rb +0 -51
  225. data/lib/ratatui_ruby/schema/overlay.rb +0 -51
  226. data/lib/ratatui_ruby/schema/paragraph.rb +0 -107
  227. data/lib/ratatui_ruby/schema/ratatui_logo.rb +0 -31
  228. data/lib/ratatui_ruby/schema/ratatui_mascot.rb +0 -36
  229. data/lib/ratatui_ruby/schema/rect.rb +0 -174
  230. data/lib/ratatui_ruby/schema/row.rb +0 -76
  231. data/lib/ratatui_ruby/schema/scrollbar.rb +0 -143
  232. data/lib/ratatui_ruby/schema/shape/label.rb +0 -76
  233. data/lib/ratatui_ruby/schema/sparkline.rb +0 -142
  234. data/lib/ratatui_ruby/schema/style.rb +0 -97
  235. data/lib/ratatui_ruby/schema/table.rb +0 -141
  236. data/lib/ratatui_ruby/schema/tabs.rb +0 -85
  237. data/lib/ratatui_ruby/schema/text.rb +0 -217
  238. data/sig/examples/app_all_events/model/events.rbs +0 -15
  239. data/sig/examples/app_all_events/view_state.rbs +0 -21
  240. data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +0 -22
  241. data/sig/ratatui_ruby/schema/bar_chart/bar_group.rbs +0 -19
  242. data/sig/ratatui_ruby/schema/bar_chart.rbs +0 -38
  243. data/sig/ratatui_ruby/schema/block.rbs +0 -18
  244. data/sig/ratatui_ruby/schema/calendar.rbs +0 -23
  245. data/sig/ratatui_ruby/schema/canvas.rbs +0 -81
  246. data/sig/ratatui_ruby/schema/center.rbs +0 -17
  247. data/sig/ratatui_ruby/schema/chart.rbs +0 -39
  248. data/sig/ratatui_ruby/schema/constraint.rbs +0 -30
  249. data/sig/ratatui_ruby/schema/cursor.rbs +0 -16
  250. data/sig/ratatui_ruby/schema/draw.rbs +0 -33
  251. data/sig/ratatui_ruby/schema/gauge.rbs +0 -23
  252. data/sig/ratatui_ruby/schema/layout.rbs +0 -27
  253. data/sig/ratatui_ruby/schema/line_gauge.rbs +0 -24
  254. data/sig/ratatui_ruby/schema/list.rbs +0 -28
  255. data/sig/ratatui_ruby/schema/overlay.rbs +0 -15
  256. data/sig/ratatui_ruby/schema/paragraph.rbs +0 -20
  257. data/sig/ratatui_ruby/schema/ratatui_logo.rbs +0 -14
  258. data/sig/ratatui_ruby/schema/ratatui_mascot.rbs +0 -17
  259. data/sig/ratatui_ruby/schema/rect.rbs +0 -48
  260. data/sig/ratatui_ruby/schema/row.rbs +0 -28
  261. data/sig/ratatui_ruby/schema/scrollbar.rbs +0 -42
  262. data/sig/ratatui_ruby/schema/sparkline.rbs +0 -22
  263. data/sig/ratatui_ruby/schema/style.rbs +0 -19
  264. data/sig/ratatui_ruby/schema/table.rbs +0 -32
  265. data/sig/ratatui_ruby/schema/tabs.rbs +0 -21
  266. data/sig/ratatui_ruby/schema/text.rbs +0 -31
  267. /data/lib/ratatui_ruby/{schema/draw.rb → draw.rb} +0 -0
@@ -1,151 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #--
4
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: LGPL-3.0-or-later
6
- #++
7
-
8
- module RatatuiRuby
9
- # Defines the sizing rule for a layout section.
10
- #
11
- # Flexible layouts need rules. You can't just place widgets at absolute coordinates; they must adapt to changing terminal sizes.
12
- #
13
- # This class defines the rules of engagement. It tells the layout engine exactly how much space a section requires relative to others.
14
- #
15
- # Mix and match fixed lengths, percentages, ratios, and minimums. Build layouts that breathe.
16
- #
17
- # === Examples
18
- #
19
- #--
20
- # SPDX-SnippetBegin
21
- # SPDX-FileCopyrightText: 2025 Kerrick Long
22
- # SPDX-License-Identifier: MIT-0
23
- #++
24
- # Constraint.length(5) # Exactly 5 cells
25
- # Constraint.percentage(50) # Half the available space
26
- # Constraint.min(10) # At least 10 cells, maybe more
27
- # Constraint.fill(1) # Fill remaining space (weight 1)
28
- #--
29
- # SPDX-SnippetEnd
30
- #++
31
- class Constraint < Data.define(:type, :value)
32
- ##
33
- # :attr_reader: type
34
- # The type of constraint.
35
- #
36
- # <tt>:length</tt>, <tt>:percentage</tt>, <tt>:min</tt>, <tt>:max</tt>, <tt>:fill</tt>, or <tt>:ratio</tt>.
37
-
38
- ##
39
- # :attr_reader: value
40
- # The numeric value (or array for ratio) associated with the rule.
41
-
42
- # Requests a fixed size.
43
- #
44
- #--
45
- # SPDX-SnippetBegin
46
- # SPDX-FileCopyrightText: 2025 Kerrick Long
47
- # SPDX-License-Identifier: MIT-0
48
- #++
49
- # Constraint.length(10) # 10 characters wide/high
50
- #
51
- #--
52
- # SPDX-SnippetEnd
53
- #++
54
- # [v] Number of cells (Integer).
55
- def self.length(v)
56
- new(type: :length, value: Integer(v))
57
- end
58
-
59
- # Requests a percentage of available space.
60
- #
61
- #--
62
- # SPDX-SnippetBegin
63
- # SPDX-FileCopyrightText: 2025 Kerrick Long
64
- # SPDX-License-Identifier: MIT-0
65
- #++
66
- # Constraint.percentage(25) # 25% of the area
67
- #
68
- #--
69
- # SPDX-SnippetEnd
70
- #++
71
- # [v] Percentage 0-100 (Integer).
72
- def self.percentage(v)
73
- new(type: :percentage, value: Integer(v))
74
- end
75
-
76
- # Enforces a minimum size.
77
- #
78
- #--
79
- # SPDX-SnippetBegin
80
- # SPDX-FileCopyrightText: 2025 Kerrick Long
81
- # SPDX-License-Identifier: MIT-0
82
- #++
83
- # Constraint.min(5) # At least 5 cells
84
- #
85
- #--
86
- # SPDX-SnippetEnd
87
- #++
88
- # This section will grow if space permits, but never shrink below +v+.
89
- #
90
- # [v] Minimum cells (Integer).
91
- def self.min(v)
92
- new(type: :min, value: Integer(v))
93
- end
94
-
95
- # Enforces a maximum size.
96
- #
97
- #--
98
- # SPDX-SnippetBegin
99
- # SPDX-FileCopyrightText: 2025 Kerrick Long
100
- # SPDX-License-Identifier: MIT-0
101
- #++
102
- # Constraint.max(10) # At most 10 cells
103
- #
104
- #--
105
- # SPDX-SnippetEnd
106
- #++
107
- # [v] Maximum cells (Integer).
108
- def self.max(v)
109
- new(type: :max, value: Integer(v))
110
- end
111
-
112
- # Fills remaining space proportionally.
113
- #
114
- #--
115
- # SPDX-SnippetBegin
116
- # SPDX-FileCopyrightText: 2025 Kerrick Long
117
- # SPDX-License-Identifier: MIT-0
118
- #++
119
- # Constraint.fill(1) # Equal share
120
- # Constraint.fill(2) # Double share
121
- #
122
- #--
123
- # SPDX-SnippetEnd
124
- #++
125
- # Fill constraints distribute any space left after satisfying strict rules.
126
- # They behave like flex-grow. A fill(2) takes twice as much space as a fill(1).
127
- #
128
- # [v] Proportional weight (Integer, default: 1).
129
- def self.fill(v = 1)
130
- new(type: :fill, value: Integer(v))
131
- end
132
-
133
- # Requests a specific ratio of the total space.
134
- #
135
- #--
136
- # SPDX-SnippetBegin
137
- # SPDX-FileCopyrightText: 2025 Kerrick Long
138
- # SPDX-License-Identifier: MIT-0
139
- #++
140
- # Constraint.ratio(1, 3) # 1/3rd of the area
141
- #
142
- #--
143
- # SPDX-SnippetEnd
144
- #++
145
- # [numerator] Top part of fraction (Integer).
146
- # [denominator] Bottom part of fraction (Integer).
147
- def self.ratio(numerator, denominator)
148
- new(type: :ratio, value: [Integer(numerator), Integer(denominator)])
149
- end
150
- end
151
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #--
4
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: LGPL-3.0-or-later
6
- #++
7
-
8
- module RatatuiRuby
9
- # Controls the terminal cursor position.
10
- #
11
- # Interfaces are not just output; they require input. Users need a visual cue—a blinking block or line—to know where their keystrokes will appear.
12
- #
13
- # This widget renders a ghost. It does not draw a character but instructs the terminal to place the hardware cursor at specific coordinates.
14
- #
15
- # Use it for text editors, input fields, or command prompts.
16
- #
17
- # === Examples
18
- #
19
- #--
20
- # SPDX-SnippetBegin
21
- # SPDX-FileCopyrightText: 2026 Kerrick Long
22
- # SPDX-License-Identifier: MIT-0
23
- #++
24
- # Cursor.new(x: 10, y: 5)
25
- #
26
- #--
27
- # SPDX-SnippetEnd
28
- #++
29
- # See also:
30
- # - {Declarative implementation using Tree API}[link:/examples/app_login_form/app_rb.html]
31
- # - {Component-based implementation using Frame API}[link:/examples/app_color_picker/app_rb.html]
32
- # - RatatuiRuby::Frame#set_cursor_position (Frame API alternative)
33
- class Cursor < Data.define(:x, :y)
34
- ##
35
- # :attr_reader: x
36
- # X coordinate (column).
37
-
38
- ##
39
- # :attr_reader: y
40
- # Y coordinate (row).
41
-
42
- # Creates a new Cursor.
43
- #
44
- # [x] Integer.
45
- # [y] Integer.
46
- def initialize(x:, y:)
47
- super(x: Integer(x), y: Integer(y))
48
- end
49
- end
50
- end
@@ -1,72 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #--
4
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: LGPL-3.0-or-later
6
- #++
7
-
8
- module RatatuiRuby
9
- # Displays a standard progress bar.
10
- #
11
- # Long-running tasks create anxiety. Users need to know that the system is working and how much is left to do.
12
- #
13
- # This widget visualizes completion. It fills a bar based on a percentage.
14
- #
15
- # Use it for downloads, installations, or processing jobs.
16
- #
17
- # {rdoc-image:/doc/images/widget_gauge.png}[link:/examples/widget_gauge/app_rb.html]
18
- #
19
- # === Example
20
- #
21
- # Run the interactive demo from the terminal:
22
- #
23
- # ruby examples/widget_gauge/app.rb
24
- class Gauge < Data.define(:ratio, :label, :style, :gauge_style, :block, :use_unicode)
25
- ##
26
- # :attr_reader: ratio
27
- # Progress ratio from 0.0 to 1.0.
28
-
29
- ##
30
- # :attr_reader: label
31
- # Text label to display (optional).
32
- #
33
- # Accepts String or Text::Span for rich styling.
34
- #
35
- # If nil, it often displays the percentage automatically depending on renderer logic,
36
- # but explicit labels are preferred.
37
-
38
- ##
39
- # :attr_reader: style
40
- # Base style applied to the entire gauge background (optional).
41
-
42
- ##
43
- # :attr_reader: gauge_style
44
- # Style applied specifically to the filled bar portion (optional).
45
-
46
- ##
47
- # :attr_reader: block
48
- # Optional wrapping block.
49
-
50
- ##
51
- # :attr_reader: use_unicode
52
- # Whether to use Unicode block characters (true) or ASCII characters (false).
53
- # Default is false (ASCII) to be conservative, though Ratatui defaults to true.
54
-
55
- # Creates a new Gauge.
56
- #
57
- # [ratio] Float (0.0 - 1.0).
58
- # [percent] Integer (0 - 100), alternative to ratio.
59
- # [label] String or Text::Span (optional).
60
- # [style] Style object for the background (optional).
61
- # [gauge_style] Style object for the filled bar (optional).
62
- # [block] Block widget (optional).
63
- # [use_unicode] Boolean (default: true).
64
- def initialize(ratio: nil, percent: nil, label: nil, style: nil, gauge_style: nil, block: nil, use_unicode: true)
65
- if percent
66
- ratio = Float(percent) / 100.0
67
- end
68
- ratio = Float(ratio || 0.0)
69
- super(ratio:, label:, style:, gauge_style:, block:, use_unicode:)
70
- end
71
- end
72
- end
@@ -1,122 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #--
4
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: LGPL-3.0-or-later
6
- #++
7
-
8
- module RatatuiRuby
9
- # Divides an area into smaller chunks.
10
- #
11
- # Terminal screens vary in size. Hardcoded positions break when the window resizes. You need a way to organize space dynamically.
12
- #
13
- # This class manages geometry. It splits a given area into multiple sections based on a list of constraints.
14
- #
15
- # Use layouts to build responsive grids. Stack sections vertically for a sidebar-main structure. Partition them horizontally for headers and footers. Let the layout engine do the math.
16
- #
17
- # {rdoc-image:/doc/images/widget_layout_split.png}[link:/examples/widget_layout_split/app_rb.html]
18
- #
19
- # === Example
20
- #
21
- # Run the interactive demo from the terminal:
22
- #
23
- # ruby examples/widget_layout_split/app.rb
24
- class Layout < Data.define(:direction, :constraints, :children, :flex)
25
- ##
26
- # :attr_reader: direction
27
- # Direction of the split.
28
- #
29
- # Either <tt>:vertical</tt> (top to bottom) or <tt>:horizontal</tt> (left to right).
30
- #
31
- # layout.direction # => :vertical
32
-
33
- ##
34
- # :attr_reader: constraints
35
- # Array of rules defining section sizes.
36
- #
37
- # See RatatuiRuby::Layout::Constraint.
38
-
39
- ##
40
- # :attr_reader: children
41
- # Widgets to render in each section (optional).
42
- #
43
- # If provided, `children[i]` is rendered into the area defined by `constraints[i]`.
44
-
45
- ##
46
- # :attr_reader: flex
47
- # Strategy for distributing extra space.
48
- #
49
- # One of <tt>:legacy</tt>, <tt>:start</tt>, <tt>:center</tt>, <tt>:end</tt>, <tt>:space_between</tt>, <tt>:space_around</tt>.
50
-
51
- # :nodoc:
52
- FLEX_MODES = %i[legacy start center end space_between space_around space_evenly].freeze
53
-
54
- # Creates a new Layout.
55
- #
56
- # [direction]
57
- # <tt>:vertical</tt> or <tt>:horizontal</tt> (default: <tt>:vertical</tt>).
58
- # [constraints]
59
- # list of Constraint objects.
60
- # [children]
61
- # List of widgets to render (optional).
62
- # [flex]
63
- # Flex mode for spacing (default: <tt>:legacy</tt>).
64
- def initialize(direction: :vertical, constraints: [], children: [], flex: :legacy)
65
- super
66
- end
67
-
68
- # Splits an area into multiple rectangles.
69
- #
70
- # This is a pure calculation helper for hit testing. It computes where
71
- # widgets *would* be placed without actually rendering them.
72
- #
73
- #--
74
- # SPDX-SnippetBegin
75
- # SPDX-FileCopyrightText: 2025 Kerrick Long
76
- # SPDX-License-Identifier: MIT-0
77
- #++
78
- # rects = Layout.split(
79
- # area,
80
- # direction: :horizontal,
81
- # constraints: [Constraint.percentage(50), Constraint.percentage(50)]
82
- # )
83
- # left, right = rects
84
- #
85
- #--
86
- # SPDX-SnippetEnd
87
- #++
88
- # [area]
89
- # The area to split. Can be a <tt>Rect</tt> or a <tt>Hash</tt> containing <tt>:x</tt>, <tt>:y</tt>, <tt>:width</tt>, and <tt>:height</tt>.
90
- # [direction]
91
- # <tt>:vertical</tt> or <tt>:horizontal</tt> (default: <tt>:vertical</tt>).
92
- # [constraints]
93
- # Array of <tt>Constraint</tt> objects defining section sizes.
94
- # [flex]
95
- #--
96
- # SPDX-SnippetBegin
97
- # SPDX-FileCopyrightText: 2025 Kerrick Long
98
- # SPDX-License-Identifier: MIT-0
99
- #++
100
- # Flex mode for spacing (default: <tt>:legacy</tt>).
101
- #
102
- #--
103
- # SPDX-SnippetEnd
104
- #++
105
- # Returns an Array of <tt>Rect</tt> objects.
106
- def self.split(area, direction: :vertical, constraints:, flex: :legacy)
107
- # Duck-typing: If it lacks geometry methods but can be a Hash, convert it.
108
- if !area.respond_to?(:x) && area.respond_to?(:to_h)
109
- # Assume it's a Hash-like object with :x, :y, etc.
110
- hash = area.to_h
111
- area = Rect.new(
112
- x: hash.fetch(:x, 0),
113
- y: hash.fetch(:y, 0),
114
- width: hash.fetch(:width, 0),
115
- height: hash.fetch(:height, 0)
116
- )
117
- end
118
- raw_rects = _split(area, direction, constraints, flex)
119
- raw_rects.map { |r| Rect.new(x: r[:x], y: r[:y], width: r[:width], height: r[:height]) }
120
- end
121
- end
122
- end
@@ -1,80 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #--
4
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: LGPL-3.0-or-later
6
- #++
7
-
8
- module RatatuiRuby
9
- # Displays a compact, single-line progress bar.
10
- #
11
- # Screen space is precious. Standard block gauges are bulky and consume multiple rows.
12
- #
13
- # This widget compresses the feedback. It draws a progress bar using line characters, fitting perfectly into tight layouts or lists.
14
- #
15
- # Use it when you need to show status without stealing focus or space.
16
- #
17
- # {rdoc-image:/doc/images/widget_line_gauge.png}[link:/examples/widget_line_gauge/app_rb.html]
18
- #
19
- # === Example
20
- #
21
- # Run the interactive demo from the terminal:
22
- #
23
- # ruby examples/widget_line_gauge/app.rb
24
- class LineGauge < Data.define(:ratio, :label, :style, :filled_style, :unfilled_style, :block, :filled_symbol, :unfilled_symbol)
25
- ##
26
- # :attr_reader: ratio
27
- # Progress ratio from 0.0 to 1.0.
28
-
29
- ##
30
- # :attr_reader: label
31
- # Optional label (String or Text::Span for rich styling).
32
-
33
- ##
34
- # :attr_reader: style
35
- # Base style applied to the entire gauge.
36
-
37
- ##
38
- # :attr_reader: filled_style
39
- # Style for the completed portion.
40
-
41
- ##
42
- # :attr_reader: unfilled_style
43
- # Style for the remainder.
44
-
45
- ##
46
- # :attr_reader: block
47
- # Optional wrapping block.
48
-
49
- ##
50
- # :attr_reader: filled_symbol
51
- # Character for filled segments.
52
-
53
- ##
54
- # :attr_reader: unfilled_symbol
55
- # Character for empty segments.
56
-
57
- # Creates a new LineGauge.
58
- #
59
- # [ratio] Float (0.0 - 1.0).
60
- # [label] String or Text::Span (optional).
61
- # [style] Style (optional, base style for the gauge).
62
- # [filled_style] Style.
63
- # [unfilled_style] Style.
64
- # [block] Block.
65
- # [filled_symbol] String (default: <tt>"█"</tt>).
66
- # [unfilled_symbol] String (default: <tt>"░"</tt>).
67
- def initialize(ratio: 0.0, label: nil, style: nil, filled_style: nil, unfilled_style: nil, block: nil, filled_symbol: "█", unfilled_symbol: "░")
68
- super(
69
- ratio: Float(ratio),
70
- label:,
71
- style:,
72
- filled_style:,
73
- unfilled_style:,
74
- block:,
75
- filled_symbol:,
76
- unfilled_symbol:
77
- )
78
- end
79
- end
80
- end
@@ -1,135 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #--
4
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: LGPL-3.0-or-later
6
- #++
7
-
8
- module RatatuiRuby
9
- # Displays a selectable list of items.
10
- #
11
- # Users need to choose from options. Menus, file explorers, and selectors are everywhere.
12
- # Implementing navigation, highlighting, and scrolling state from scratch is tedious.
13
- #
14
- # This widget manages the list. It renders the items. It highlights the selection. It handles the scrolling window.
15
- #
16
- # Use it to build main menus, navigation sidebars, or logs.
17
- #
18
- # {rdoc-image:/doc/images/widget_list.png}[link:/examples/widget_list/app_rb.html]
19
- #
20
- # === Examples
21
- #
22
- #--
23
- # SPDX-SnippetBegin
24
- # SPDX-FileCopyrightText: 2025 Kerrick Long
25
- # SPDX-License-Identifier: MIT-0
26
- #++
27
- # # Basic List
28
- # List.new(items: ["Item 1", "Item 2"])
29
- #
30
- # # Navigation Menu
31
- # List.new(
32
- # items: ["New Game", "Load Game", "Options", "Quit"],
33
- # selected_index: 0,
34
- # highlight_style: Style.new(bg: :blue),
35
- # highlight_symbol: ">> "
36
- # )
37
- #--
38
- # SPDX-SnippetEnd
39
- #++
40
- class List < Data.define(:items, :selected_index, :offset, :style, :highlight_style, :highlight_symbol, :repeat_highlight_symbol, :highlight_spacing, :direction, :scroll_padding, :block)
41
- ##
42
- # :attr_reader: items
43
- # The items to display.
44
- #
45
- # Accepts Array of Strings, Text::Spans, Text::Lines, or ListItem objects.
46
- # For styled individual rows, use ListItem with a style.
47
-
48
- ##
49
- # :attr_reader: selected_index
50
- # Index of the active selection (Integer or nil).
51
-
52
- ##
53
- # :attr_reader: offset
54
- # Scroll offset (Integer or nil).
55
- #
56
- # Controls the viewport's starting position in the list.
57
- #
58
- # When +nil+ (default), Ratatui auto-scrolls to keep the selection visible ("natural scrolling").
59
- #
60
- # When set, forces the viewport to start at this item index. Use this for:
61
- # - **Passive scrolling**: Scroll through a log viewer without selecting items.
62
- # - **Click-to-select math**: Calculate which item index corresponds to a click coordinate.
63
- #
64
- # *Important*: When both +offset+ and +selected_index+ are set, Ratatui may still adjust
65
- # the viewport during rendering to ensure the selection stays visible. Set +selected_index+
66
- # to +nil+ for fully manual scroll control.
67
-
68
- ##
69
- # :attr_reader: style
70
- # Base style for unselected items.
71
-
72
- ##
73
- # :attr_reader: highlight_style
74
- # Style for the selected item.
75
-
76
- ##
77
- # :attr_reader: highlight_symbol
78
- # Symbol drawn before the selected item.
79
-
80
- ##
81
- # :attr_reader: repeat_highlight_symbol
82
- # Whether to repeat the highlight symbol for each line of the selected item.
83
-
84
- ##
85
- # :attr_reader: highlight_spacing
86
- # When to show the highlight symbol column.
87
- #
88
- # <tt>:always</tt>, <tt>:when_selected</tt>, or <tt>:never</tt>.
89
-
90
- ##
91
- # :attr_reader: direction
92
- # Render direction.
93
- #
94
- # <tt>:top_to_bottom</tt> or <tt>:bottom_to_top</tt>.
95
-
96
- ##
97
- # :attr_reader: scroll_padding
98
- # Number of items to keep visible above/below the selected item when scrolling (Integer or nil).
99
-
100
- ##
101
- # :attr_reader: block
102
- # Optional wrapping block.
103
-
104
- # Creates a new List.
105
- #
106
- # Integer parameters accept any object responding to +to_int+ or +to_i+ (duck-typed).
107
- #
108
- # [items] Array of Strings, Text::Spans, Text::Lines, or ListItem objects.
109
- # [selected_index] Numeric (nullable, coerced to Integer).
110
- # [offset] Numeric (nullable, coerced to Integer). Forces scroll position when set.
111
- # [style] Style object.
112
- # [highlight_style] Style object.
113
- # [highlight_symbol] String (default: <tt>"> "</tt>).
114
- # [repeat_highlight_symbol] Boolean (default: <tt>false</tt>).
115
- # [highlight_spacing] Symbol (default: <tt>:when_selected</tt>).
116
- # [direction] Symbol (default: <tt>:top_to_bottom</tt>).
117
- # [scroll_padding] Numeric (nullable, coerced to Integer, default: <tt>nil</tt>).
118
- # [block] Block (optional).
119
- def initialize(items: [], selected_index: nil, offset: nil, style: nil, highlight_style: nil, highlight_symbol: "> ", repeat_highlight_symbol: false, highlight_spacing: :when_selected, direction: :top_to_bottom, scroll_padding: nil, block: nil)
120
- super(
121
- items:,
122
- selected_index: selected_index.nil? ? nil : Integer(selected_index),
123
- offset: offset.nil? ? nil : Integer(offset),
124
- style:,
125
- highlight_style:,
126
- highlight_symbol:,
127
- repeat_highlight_symbol:,
128
- highlight_spacing:,
129
- direction:,
130
- scroll_padding: scroll_padding.nil? ? nil : Integer(scroll_padding),
131
- block:
132
- )
133
- end
134
- end
135
- end
@@ -1,51 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #--
4
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: LGPL-3.0-or-later
6
- #++
7
-
8
- module RatatuiRuby
9
- # A styled list item combining content with optional style.
10
- #
11
- # By default, List items are strings. For more control over styling individual rows,
12
- # wrap the content in a ListItem to apply a style specific to that item.
13
- #
14
- # The content can be a String, Text::Span, or Text::Line. The style applies to the
15
- # entire row background.
16
- #
17
- # === Examples
18
- #
19
- #--
20
- # SPDX-SnippetBegin
21
- # SPDX-FileCopyrightText: 2026 Kerrick Long
22
- # SPDX-License-Identifier: MIT-0
23
- #++
24
- # # Item with red background
25
- # ListItem.new(content: "Error", style: Style.new(bg: :red))
26
- #
27
- # # Item with styled content
28
- # ListItem.new(
29
- # content: Text::Span.new(content: "Status: OK", style: Style.new(fg: :green, modifiers: [:bold]))
30
- # )
31
- #--
32
- # SPDX-SnippetEnd
33
- #++
34
- class ListItem < Data.define(:content, :style)
35
- ##
36
- # :attr_reader: content
37
- # The content to display (String, Text::Span, or Text::Line).
38
-
39
- ##
40
- # :attr_reader: style
41
- # The style to apply to the item (optional Style).
42
-
43
- # Creates a new ListItem.
44
- #
45
- # [content] String, Text::Span, or Text::Line.
46
- # [style] Style object (optional).
47
- def initialize(content:, style: nil)
48
- super
49
- end
50
- end
51
- end