ratatui_ruby 0.9.1 → 0.10.1

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 (268) 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 +113 -0
  8. data/README.md +17 -0
  9. data/REUSE.toml +5 -0
  10. data/Rakefile +1 -1
  11. data/Steepfile +49 -0
  12. data/doc/concepts/debugging.md +401 -0
  13. data/doc/getting_started/quickstart.md +8 -3
  14. data/doc/images/app_all_events.png +0 -0
  15. data/doc/images/app_color_picker.png +0 -0
  16. data/doc/images/app_debugging_showcase.gif +0 -0
  17. data/doc/images/app_debugging_showcase.png +0 -0
  18. data/doc/images/app_login_form.png +0 -0
  19. data/doc/images/app_stateful_interaction.png +0 -0
  20. data/doc/images/verify_quickstart_dsl.png +0 -0
  21. data/doc/images/verify_quickstart_layout.png +0 -0
  22. data/doc/images/verify_quickstart_lifecycle.png +0 -0
  23. data/doc/images/verify_readme_usage.png +0 -0
  24. data/doc/images/widget_barchart.png +0 -0
  25. data/doc/images/widget_block.png +0 -0
  26. data/doc/images/widget_box.png +0 -0
  27. data/doc/images/widget_calendar.png +0 -0
  28. data/doc/images/widget_canvas.png +0 -0
  29. data/doc/images/widget_cell.png +0 -0
  30. data/doc/images/widget_center.png +0 -0
  31. data/doc/images/widget_chart.png +0 -0
  32. data/doc/images/widget_gauge.png +0 -0
  33. data/doc/images/widget_layout_split.png +0 -0
  34. data/doc/images/widget_line_gauge.png +0 -0
  35. data/doc/images/widget_list.png +0 -0
  36. data/doc/images/widget_map.png +0 -0
  37. data/doc/images/widget_overlay.png +0 -0
  38. data/doc/images/widget_popup.png +0 -0
  39. data/doc/images/widget_ratatui_logo.png +0 -0
  40. data/doc/images/widget_ratatui_mascot.png +0 -0
  41. data/doc/images/widget_rect.png +0 -0
  42. data/doc/images/widget_render.png +0 -0
  43. data/doc/images/widget_rich_text.png +0 -0
  44. data/doc/images/widget_scroll_text.png +0 -0
  45. data/doc/images/widget_scrollbar.png +0 -0
  46. data/doc/images/widget_sparkline.png +0 -0
  47. data/doc/images/widget_style_colors.png +0 -0
  48. data/doc/images/widget_table.png +0 -0
  49. data/doc/images/widget_tabs.png +0 -0
  50. data/doc/images/widget_text_width.png +0 -0
  51. data/doc/troubleshooting/async.md +4 -0
  52. data/examples/app_debugging_showcase/README.md +119 -0
  53. data/examples/app_debugging_showcase/app.rb +318 -0
  54. data/examples/widget_canvas/app.rb +19 -14
  55. data/examples/widget_gauge/app.rb +18 -3
  56. data/examples/widget_layout_split/app.rb +10 -4
  57. data/examples/widget_list/app.rb +22 -6
  58. data/examples/widget_rect/app.rb +7 -6
  59. data/examples/widget_rich_text/app.rb +62 -37
  60. data/examples/widget_style_colors/app.rb +26 -47
  61. data/examples/widget_table/app.rb +28 -5
  62. data/examples/widget_text_width/app.rb +6 -4
  63. data/ext/ratatui_ruby/Cargo.lock +48 -1
  64. data/ext/ratatui_ruby/Cargo.toml +6 -2
  65. data/ext/ratatui_ruby/src/color.rs +82 -0
  66. data/ext/ratatui_ruby/src/errors.rs +28 -0
  67. data/ext/ratatui_ruby/src/events.rs +15 -14
  68. data/ext/ratatui_ruby/src/lib.rs +56 -0
  69. data/ext/ratatui_ruby/src/rendering.rs +3 -1
  70. data/ext/ratatui_ruby/src/style.rs +48 -21
  71. data/ext/ratatui_ruby/src/terminal.rs +40 -9
  72. data/ext/ratatui_ruby/src/text.rs +21 -9
  73. data/ext/ratatui_ruby/src/widgets/chart.rs +2 -1
  74. data/ext/ratatui_ruby/src/widgets/layout.rs +90 -2
  75. data/ext/ratatui_ruby/src/widgets/list.rs +6 -5
  76. data/ext/ratatui_ruby/src/widgets/overlay.rs +2 -1
  77. data/ext/ratatui_ruby/src/widgets/table.rs +7 -6
  78. data/ext/ratatui_ruby/src/widgets/table_state.rs +55 -0
  79. data/ext/ratatui_ruby/src/widgets/tabs.rs +3 -2
  80. data/lib/ratatui_ruby/buffer/cell.rb +25 -15
  81. data/lib/ratatui_ruby/buffer.rb +134 -2
  82. data/lib/ratatui_ruby/cell.rb +13 -5
  83. data/lib/ratatui_ruby/debug.rb +215 -0
  84. data/lib/ratatui_ruby/event/key.rb +3 -2
  85. data/lib/ratatui_ruby/event.rb +1 -1
  86. data/lib/ratatui_ruby/layout/constraint.rb +49 -0
  87. data/lib/ratatui_ruby/layout/layout.rb +119 -13
  88. data/lib/ratatui_ruby/layout/position.rb +55 -0
  89. data/lib/ratatui_ruby/layout/rect.rb +188 -0
  90. data/lib/ratatui_ruby/layout/size.rb +55 -0
  91. data/lib/ratatui_ruby/layout.rb +4 -0
  92. data/lib/ratatui_ruby/style/color.rb +149 -0
  93. data/lib/ratatui_ruby/style/style.rb +51 -4
  94. data/lib/ratatui_ruby/style.rb +2 -0
  95. data/lib/ratatui_ruby/symbols.rb +435 -0
  96. data/lib/ratatui_ruby/synthetic_events.rb +1 -1
  97. data/lib/ratatui_ruby/table_state.rb +51 -0
  98. data/lib/ratatui_ruby/terminal_lifecycle.rb +2 -1
  99. data/lib/ratatui_ruby/test_helper/event_injection.rb +6 -1
  100. data/lib/ratatui_ruby/test_helper.rb +9 -0
  101. data/lib/ratatui_ruby/text/line.rb +245 -0
  102. data/lib/ratatui_ruby/text/span.rb +158 -0
  103. data/lib/ratatui_ruby/text.rb +99 -0
  104. data/lib/ratatui_ruby/tui/canvas_factories.rb +103 -0
  105. data/lib/ratatui_ruby/tui/core.rb +13 -2
  106. data/lib/ratatui_ruby/tui/layout_factories.rb +50 -3
  107. data/lib/ratatui_ruby/tui/state_factories.rb +42 -0
  108. data/lib/ratatui_ruby/tui/text_factories.rb +40 -0
  109. data/lib/ratatui_ruby/tui/widget_factories.rb +135 -60
  110. data/lib/ratatui_ruby/tui.rb +22 -1
  111. data/lib/ratatui_ruby/version.rb +1 -1
  112. data/lib/ratatui_ruby/widgets/bar_chart/bar.rb +2 -0
  113. data/lib/ratatui_ruby/widgets/bar_chart/bar_group.rb +2 -0
  114. data/lib/ratatui_ruby/widgets/bar_chart.rb +30 -20
  115. data/lib/ratatui_ruby/widgets/block.rb +14 -6
  116. data/lib/ratatui_ruby/widgets/calendar.rb +2 -0
  117. data/lib/ratatui_ruby/widgets/canvas.rb +56 -0
  118. data/lib/ratatui_ruby/widgets/cell.rb +2 -0
  119. data/lib/ratatui_ruby/widgets/center.rb +2 -0
  120. data/lib/ratatui_ruby/widgets/chart.rb +6 -0
  121. data/lib/ratatui_ruby/widgets/clear.rb +2 -0
  122. data/lib/ratatui_ruby/widgets/coerceable_widget.rb +77 -0
  123. data/lib/ratatui_ruby/widgets/cursor.rb +2 -0
  124. data/lib/ratatui_ruby/widgets/gauge.rb +61 -3
  125. data/lib/ratatui_ruby/widgets/line_gauge.rb +66 -4
  126. data/lib/ratatui_ruby/widgets/list.rb +87 -3
  127. data/lib/ratatui_ruby/widgets/list_item.rb +2 -0
  128. data/lib/ratatui_ruby/widgets/overlay.rb +2 -0
  129. data/lib/ratatui_ruby/widgets/paragraph.rb +4 -0
  130. data/lib/ratatui_ruby/widgets/ratatui_logo.rb +2 -0
  131. data/lib/ratatui_ruby/widgets/ratatui_mascot.rb +2 -0
  132. data/lib/ratatui_ruby/widgets/row.rb +45 -0
  133. data/lib/ratatui_ruby/widgets/scrollbar.rb +2 -0
  134. data/lib/ratatui_ruby/widgets/shape/label.rb +2 -0
  135. data/lib/ratatui_ruby/widgets/sparkline.rb +21 -13
  136. data/lib/ratatui_ruby/widgets/table.rb +13 -3
  137. data/lib/ratatui_ruby/widgets/tabs.rb +6 -4
  138. data/lib/ratatui_ruby/widgets.rb +1 -0
  139. data/lib/ratatui_ruby.rb +42 -11
  140. data/sig/examples/app_all_events/model/app_model.rbs +23 -0
  141. data/sig/examples/app_all_events/model/event_entry.rbs +15 -8
  142. data/sig/examples/app_all_events/model/timestamp.rbs +1 -1
  143. data/sig/examples/app_all_events/view.rbs +1 -1
  144. data/sig/examples/app_stateful_interaction/app.rbs +5 -5
  145. data/sig/examples/widget_block_demo/app.rbs +6 -6
  146. data/sig/manifest.yaml +5 -0
  147. data/sig/patches/data.rbs +26 -0
  148. data/sig/patches/debugger__.rbs +8 -0
  149. data/sig/ratatui_ruby/buffer/cell.rbs +46 -0
  150. data/sig/ratatui_ruby/buffer.rbs +18 -0
  151. data/sig/ratatui_ruby/cell.rbs +44 -0
  152. data/sig/ratatui_ruby/clear.rbs +18 -0
  153. data/sig/ratatui_ruby/constraint.rbs +26 -0
  154. data/sig/ratatui_ruby/debug.rbs +45 -0
  155. data/sig/ratatui_ruby/draw.rbs +30 -0
  156. data/sig/ratatui_ruby/event.rbs +68 -8
  157. data/sig/ratatui_ruby/frame.rbs +4 -4
  158. data/sig/ratatui_ruby/interfaces.rbs +25 -0
  159. data/sig/ratatui_ruby/layout/constraint.rbs +39 -0
  160. data/sig/ratatui_ruby/layout/layout.rbs +45 -0
  161. data/sig/ratatui_ruby/layout/position.rbs +18 -0
  162. data/sig/ratatui_ruby/layout/rect.rbs +64 -0
  163. data/sig/ratatui_ruby/layout/size.rbs +18 -0
  164. data/sig/ratatui_ruby/output_guard.rbs +23 -0
  165. data/sig/ratatui_ruby/ratatui_ruby.rbs +84 -5
  166. data/sig/ratatui_ruby/rect.rbs +17 -0
  167. data/sig/ratatui_ruby/style/color.rbs +22 -0
  168. data/sig/ratatui_ruby/style/style.rbs +29 -0
  169. data/sig/ratatui_ruby/symbols.rbs +141 -0
  170. data/sig/ratatui_ruby/synthetic_events.rbs +21 -0
  171. data/sig/ratatui_ruby/table_state.rbs +6 -0
  172. data/sig/ratatui_ruby/terminal_lifecycle.rbs +31 -0
  173. data/sig/ratatui_ruby/test_helper/event_injection.rbs +2 -2
  174. data/sig/ratatui_ruby/test_helper/snapshot.rbs +22 -3
  175. data/sig/ratatui_ruby/test_helper/style_assertions.rbs +8 -1
  176. data/sig/ratatui_ruby/test_helper/test_doubles.rbs +7 -3
  177. data/sig/ratatui_ruby/text/line.rbs +27 -0
  178. data/sig/ratatui_ruby/text/span.rbs +23 -0
  179. data/sig/ratatui_ruby/text.rbs +12 -0
  180. data/sig/ratatui_ruby/tui/buffer_factories.rbs +1 -1
  181. data/sig/ratatui_ruby/tui/canvas_factories.rbs +23 -5
  182. data/sig/ratatui_ruby/tui/core.rbs +2 -2
  183. data/sig/ratatui_ruby/tui/layout_factories.rbs +16 -2
  184. data/sig/ratatui_ruby/tui/state_factories.rbs +8 -3
  185. data/sig/ratatui_ruby/tui/style_factories.rbs +3 -1
  186. data/sig/ratatui_ruby/tui/text_factories.rbs +7 -4
  187. data/sig/ratatui_ruby/tui/widget_factories.rbs +123 -30
  188. data/sig/ratatui_ruby/widgets/bar_chart.rbs +95 -0
  189. data/sig/ratatui_ruby/widgets/block.rbs +51 -0
  190. data/sig/ratatui_ruby/widgets/calendar.rbs +45 -0
  191. data/sig/ratatui_ruby/widgets/canvas.rbs +95 -0
  192. data/sig/ratatui_ruby/widgets/chart.rbs +91 -0
  193. data/sig/ratatui_ruby/widgets/coerceable_widget.rbs +26 -0
  194. data/sig/ratatui_ruby/widgets/gauge.rbs +44 -0
  195. data/sig/ratatui_ruby/widgets/line_gauge.rbs +48 -0
  196. data/sig/ratatui_ruby/widgets/list.rbs +63 -0
  197. data/sig/ratatui_ruby/widgets/misc.rbs +158 -0
  198. data/sig/ratatui_ruby/widgets/paragraph.rbs +45 -0
  199. data/sig/ratatui_ruby/widgets/row.rbs +43 -0
  200. data/sig/ratatui_ruby/widgets/scrollbar.rbs +53 -0
  201. data/sig/ratatui_ruby/widgets/shape/label.rbs +37 -0
  202. data/sig/ratatui_ruby/widgets/sparkline.rbs +45 -0
  203. data/sig/ratatui_ruby/widgets/table.rbs +78 -0
  204. data/sig/ratatui_ruby/widgets/tabs.rbs +44 -0
  205. data/sig/ratatui_ruby/{schema/list_item.rbs → widgets.rbs} +4 -4
  206. data/tasks/steep.rake +11 -0
  207. metadata +80 -63
  208. data/doc/contributors/v1.0.0_blockers.md +0 -870
  209. data/doc/troubleshooting/debugging.md +0 -101
  210. data/lib/ratatui_ruby/schema/bar_chart/bar.rb +0 -47
  211. data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +0 -25
  212. data/lib/ratatui_ruby/schema/bar_chart.rb +0 -287
  213. data/lib/ratatui_ruby/schema/block.rb +0 -198
  214. data/lib/ratatui_ruby/schema/calendar.rb +0 -84
  215. data/lib/ratatui_ruby/schema/canvas.rb +0 -239
  216. data/lib/ratatui_ruby/schema/center.rb +0 -67
  217. data/lib/ratatui_ruby/schema/chart.rb +0 -159
  218. data/lib/ratatui_ruby/schema/clear.rb +0 -62
  219. data/lib/ratatui_ruby/schema/constraint.rb +0 -151
  220. data/lib/ratatui_ruby/schema/cursor.rb +0 -50
  221. data/lib/ratatui_ruby/schema/gauge.rb +0 -72
  222. data/lib/ratatui_ruby/schema/layout.rb +0 -122
  223. data/lib/ratatui_ruby/schema/line_gauge.rb +0 -80
  224. data/lib/ratatui_ruby/schema/list.rb +0 -135
  225. data/lib/ratatui_ruby/schema/list_item.rb +0 -51
  226. data/lib/ratatui_ruby/schema/overlay.rb +0 -51
  227. data/lib/ratatui_ruby/schema/paragraph.rb +0 -107
  228. data/lib/ratatui_ruby/schema/ratatui_logo.rb +0 -31
  229. data/lib/ratatui_ruby/schema/ratatui_mascot.rb +0 -36
  230. data/lib/ratatui_ruby/schema/rect.rb +0 -174
  231. data/lib/ratatui_ruby/schema/row.rb +0 -76
  232. data/lib/ratatui_ruby/schema/scrollbar.rb +0 -143
  233. data/lib/ratatui_ruby/schema/shape/label.rb +0 -76
  234. data/lib/ratatui_ruby/schema/sparkline.rb +0 -142
  235. data/lib/ratatui_ruby/schema/style.rb +0 -97
  236. data/lib/ratatui_ruby/schema/table.rb +0 -141
  237. data/lib/ratatui_ruby/schema/tabs.rb +0 -85
  238. data/lib/ratatui_ruby/schema/text.rb +0 -217
  239. data/sig/examples/app_all_events/model/events.rbs +0 -15
  240. data/sig/examples/app_all_events/view_state.rbs +0 -21
  241. data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +0 -22
  242. data/sig/ratatui_ruby/schema/bar_chart/bar_group.rbs +0 -19
  243. data/sig/ratatui_ruby/schema/bar_chart.rbs +0 -38
  244. data/sig/ratatui_ruby/schema/block.rbs +0 -18
  245. data/sig/ratatui_ruby/schema/calendar.rbs +0 -23
  246. data/sig/ratatui_ruby/schema/canvas.rbs +0 -81
  247. data/sig/ratatui_ruby/schema/center.rbs +0 -17
  248. data/sig/ratatui_ruby/schema/chart.rbs +0 -39
  249. data/sig/ratatui_ruby/schema/constraint.rbs +0 -30
  250. data/sig/ratatui_ruby/schema/cursor.rbs +0 -16
  251. data/sig/ratatui_ruby/schema/draw.rbs +0 -33
  252. data/sig/ratatui_ruby/schema/gauge.rbs +0 -23
  253. data/sig/ratatui_ruby/schema/layout.rbs +0 -27
  254. data/sig/ratatui_ruby/schema/line_gauge.rbs +0 -24
  255. data/sig/ratatui_ruby/schema/list.rbs +0 -28
  256. data/sig/ratatui_ruby/schema/overlay.rbs +0 -15
  257. data/sig/ratatui_ruby/schema/paragraph.rbs +0 -20
  258. data/sig/ratatui_ruby/schema/ratatui_logo.rbs +0 -14
  259. data/sig/ratatui_ruby/schema/ratatui_mascot.rbs +0 -17
  260. data/sig/ratatui_ruby/schema/rect.rbs +0 -48
  261. data/sig/ratatui_ruby/schema/row.rbs +0 -28
  262. data/sig/ratatui_ruby/schema/scrollbar.rbs +0 -42
  263. data/sig/ratatui_ruby/schema/sparkline.rbs +0 -22
  264. data/sig/ratatui_ruby/schema/style.rbs +0 -19
  265. data/sig/ratatui_ruby/schema/table.rbs +0 -32
  266. data/sig/ratatui_ruby/schema/tabs.rbs +0 -21
  267. data/sig/ratatui_ruby/schema/text.rbs +0 -31
  268. /data/lib/ratatui_ruby/{schema/draw.rb → draw.rb} +0 -0
@@ -15,6 +15,8 @@ module RatatuiRuby
15
15
  #
16
16
  # Use it for everything from simple labels to complex, multi-paragraph documents.
17
17
  #
18
+ # See also: <tt>examples/widget_scroll_text/app.rb</tt> for scrollable paragraphs.
19
+ #
18
20
  # === Examples
19
21
  #
20
22
  #--
@@ -39,6 +41,8 @@ module RatatuiRuby
39
41
  # SPDX-SnippetEnd
40
42
  #++
41
43
  class Paragraph < Data.define(:text, :style, :block, :wrap, :alignment, :scroll)
44
+ include CoerceableWidget
45
+
42
46
  ##
43
47
  # :attr_reader: text
44
48
  # The content to display.
@@ -23,6 +23,8 @@ module RatatuiRuby
23
23
  #
24
24
  # ruby examples/widget_ratatui_logo/app.rb
25
25
  class RatatuiLogo < Data.define
26
+ include CoerceableWidget
27
+
26
28
  ##
27
29
  # :method: new
28
30
  # :call-seq: new -> RatatuiLogo
@@ -23,6 +23,8 @@ module RatatuiRuby
23
23
  #
24
24
  # ruby examples/widget_ratatui_mascot/app.rb
25
25
  class RatatuiMascot < Data.define(:block)
26
+ include CoerceableWidget
27
+
26
28
  ##
27
29
  # :method: new
28
30
  # :call-seq: new(block: nil) -> RatatuiMascot
@@ -37,6 +37,8 @@ module RatatuiRuby
37
37
  # SPDX-SnippetEnd
38
38
  #++
39
39
  class Row < Data.define(:cells, :style, :height, :top_margin, :bottom_margin)
40
+ include CoerceableWidget
41
+
40
42
  ##
41
43
  # :attr_reader: cells
42
44
  # The cells to display (Array of Strings, Text::Spans, Text::Lines, Paragraphs, or Cells).
@@ -73,6 +75,49 @@ module RatatuiRuby
73
75
  bottom_margin: bottom_margin.nil? ? nil : Integer(bottom_margin)
74
76
  )
75
77
  end
78
+
79
+ # Returns a new Row with strikethrough styling enabled.
80
+ #
81
+ # Table rows sometimes need strikethrough styling to indicate
82
+ # deleted, deprecated, or cancelled items. Manually managing
83
+ # style modifiers is tedious.
84
+ #
85
+ # This method adds the <tt>:crossed_out</tt> modifier to the row's
86
+ # style. If the row has no existing style, a new style is created.
87
+ #
88
+ # Use it to visually mark rows as cancelled, completed, or invalid.
89
+ #
90
+ # *Terminal Compatibility:* Strikethrough (SGR 9) is not universally
91
+ # supported. macOS Terminal.app notably lacks support. Modern terminals
92
+ # like Kitty, iTerm2, Alacritty, and WezTerm render it correctly.
93
+ # Consider pairing with <tt>:dim</tt> as a fallback for visibility.
94
+ #
95
+ # Returns a new Row instance with strikethrough enabled.
96
+ #
97
+ # === Example
98
+ #
99
+ #--
100
+ # SPDX-SnippetBegin
101
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
102
+ # SPDX-License-Identifier: MIT-0
103
+ #++
104
+ # row = Row.new(cells: ["Cancelled Task", "2024-01-15"])
105
+ # strikethrough_row = row.enable_strikethrough
106
+ # # Row style now includes :crossed_out modifier
107
+ #--
108
+ # SPDX-SnippetEnd
109
+ #++
110
+ def enable_strikethrough
111
+ current_style = style || Style::Style.new
112
+ current_modifiers = current_style.modifiers || []
113
+ new_modifiers = current_modifiers.include?(:crossed_out) ? current_modifiers : current_modifiers + [:crossed_out]
114
+
115
+ new_style = current_style.with(modifiers: new_modifiers)
116
+ with(style: new_style)
117
+ end
118
+
119
+ # Ruby-idiomatic alias
120
+ alias strikethrough enable_strikethrough
76
121
  end
77
122
  end
78
123
  end
@@ -37,6 +37,8 @@ module RatatuiRuby
37
37
  :style,
38
38
  :block
39
39
  )
40
+ include CoerceableWidget
41
+
40
42
  ##
41
43
  # :attr_reader: content_length
42
44
  # Total items or lines in the content.
@@ -47,6 +47,8 @@ module RatatuiRuby
47
47
  # SPDX-SnippetEnd
48
48
  #++
49
49
  class Label < Data.define(:x, :y, :text, :style)
50
+ include CoerceableWidget
51
+
50
52
  ##
51
53
  # :attr_reader: x
52
54
  # X coordinate in canvas space (Float, duck-typed via +to_f+).
@@ -24,6 +24,8 @@ module RatatuiRuby
24
24
  #
25
25
  # ruby examples/widget_sparkline/app.rb
26
26
  class Sparkline < Data.define(:data, :max, :style, :block, :direction, :absent_value_symbol, :absent_value_style, :bar_set)
27
+ include CoerceableWidget
28
+
27
29
  ##
28
30
  # :attr_reader: data
29
31
  # Array of integer values to plot.
@@ -114,19 +116,25 @@ module RatatuiRuby
114
116
  # [bar_set] Symbol, Hash, or Array of custom characters (optional).
115
117
  # Symbols: <tt>:nine_levels</tt> (default gradient), <tt>:three_levels</tt> (simplified).
116
118
  def initialize(data:, max: nil, style: nil, block: nil, direction: :left_to_right, absent_value_symbol: nil, absent_value_style: nil, bar_set: nil)
117
- if bar_set && !bar_set.is_a?(Symbol)
118
- if bar_set.is_a?(Array) && bar_set.size == 9
119
- # Convert Array to Hash using BAR_KEYS order
120
- bar_set = BAR_KEYS.zip(bar_set).to_h
121
- else
122
- bar_set = bar_set.dup
123
- # Normalize numeric keys (0-8) to symbolic keys
124
- BAR_KEYS.each_with_index do |key, i|
125
- if (val = bar_set.delete(i) || bar_set.delete(i.to_s))
126
- bar_set[key] = val
127
- end
128
- end
129
- end
119
+ # Normalize bar_set to Hash[Symbol, String] if provided as Array or Hash
120
+ bar_set = case bar_set
121
+ when Symbol, nil
122
+ bar_set
123
+ when Array
124
+ # Convert Array to Hash using BAR_KEYS order
125
+ BAR_KEYS.zip(bar_set).to_h
126
+ when Hash
127
+ # @type var raw_hash: Hash[untyped, untyped]
128
+ raw_hash = bar_set.dup
129
+ normalized = {} #: Hash[Symbol, String]
130
+ # Normalize numeric keys (0-8) to symbolic keys
131
+ BAR_KEYS.each_with_index do |key, i|
132
+ val = raw_hash.delete(i) || raw_hash.delete(i.to_s) || raw_hash.delete(key)
133
+ normalized[key] = val.to_s if val
134
+ end
135
+ normalized
136
+ else
137
+ bar_set
130
138
  end
131
139
  coerced_data = data.map { |v| v.nil? ? nil : Integer(v) }
132
140
  super(
@@ -24,6 +24,8 @@ module RatatuiRuby
24
24
  #
25
25
  # ruby examples/widget_table_flex/app.rb
26
26
  class Table < Data.define(:header, :rows, :widths, :row_highlight_style, :highlight_symbol, :highlight_spacing, :column_highlight_style, :cell_highlight_style, :selected_row, :selected_column, :offset, :block, :footer, :flex, :style, :column_spacing)
27
+ include CoerceableWidget
28
+
27
29
  ##
28
30
  # Highlight spacing: always show the spacing column.
29
31
  HIGHLIGHT_ALWAYS = :always
@@ -66,7 +68,8 @@ module RatatuiRuby
66
68
 
67
69
  ##
68
70
  # :attr_reader: widths
69
- # Column width constraints (Array of Constraint).
71
+ # Column width constraints (Array of Constraint or Integer).
72
+ # Integers are automatically coerced to Constraint.length.
70
73
 
71
74
  ##
72
75
  # :attr_reader: row_highlight_style
@@ -136,7 +139,7 @@ module RatatuiRuby
136
139
  #
137
140
  # [header] Array of strings, Text::Spans, Text::Lines, or paragraphs.
138
141
  # [rows] 2D Array where each cell is String, Text::Span, Text::Line, Paragraph, or Cell.
139
- # [widths] Array of Constraints.
142
+ # [widths] Array of Constraints or Integers (integers coerce to Constraint.length).
140
143
  # [row_highlight_style] Style object.
141
144
  # [highlight_symbol] String.
142
145
  # [highlight_spacing] Symbol (optional, default: <tt>:when_selected</tt>).
@@ -151,10 +154,14 @@ module RatatuiRuby
151
154
  # [style] Style object or Hash (optional).
152
155
  # [column_spacing] Integer (optional, default: 1).
153
156
  def initialize(header: nil, rows: [], widths: [], row_highlight_style: nil, highlight_symbol: "> ", highlight_spacing: :when_selected, column_highlight_style: nil, cell_highlight_style: nil, selected_row: nil, selected_column: nil, offset: nil, block: nil, footer: nil, flex: :legacy, style: nil, column_spacing: 1)
157
+ coerced_widths = widths.map do |w|
158
+ w.is_a?(Integer) ? Layout::Constraint.length(w) : w
159
+ end
160
+
154
161
  super(
155
162
  header:,
156
163
  rows:,
157
- widths:,
164
+ widths: coerced_widths,
158
165
  row_highlight_style:,
159
166
  highlight_symbol:,
160
167
  highlight_spacing:,
@@ -198,6 +205,9 @@ module RatatuiRuby
198
205
  def empty?
199
206
  rows.empty?
200
207
  end
208
+
209
+ # NOTE: No 'selection' alias - it's ambiguous whether it returns a row or index.
210
+ # Use selected_row for the row index, selected_column for the column index.
201
211
  end
202
212
  end
203
213
  end
@@ -23,6 +23,8 @@ module RatatuiRuby
23
23
  #
24
24
  # ruby examples/widget_tabs/app.rb
25
25
  class Tabs < Data.define(:titles, :selected_index, :block, :divider, :highlight_style, :style, :padding_left, :padding_right)
26
+ include CoerceableWidget
27
+
26
28
  ##
27
29
  # :attr_reader: titles
28
30
  # Tab titles (Array of Strings).
@@ -65,8 +67,8 @@ module RatatuiRuby
65
67
  # [divider] String (optional).
66
68
  # [highlight_style] Style (optional).
67
69
  # [style] Style (optional).
68
- # [padding_left] Integer, String, or Line (default: 0).
69
- # [padding_right] Integer, String, or Line (default: 0).
70
+ # [padding_left] String, Line, or anything that responds to <tt>to_i</tt> (default: 0).
71
+ # [padding_right] String, Line, or anything that responds to <tt>to_i</tt> (default: 0).
70
72
  def initialize(titles: [], selected_index: 0, block: nil, divider: nil, highlight_style: nil, style: nil, padding_left: 0, padding_right: 0)
71
73
  super(
72
74
  titles:,
@@ -75,8 +77,8 @@ module RatatuiRuby
75
77
  divider:,
76
78
  highlight_style:,
77
79
  style:,
78
- padding_left:,
79
- padding_right:
80
+ padding_left: (padding_left.is_a?(Text::Line) || padding_left.is_a?(String)) ? padding_left : Integer(padding_left),
81
+ padding_right: (padding_right.is_a?(Text::Line) || padding_right.is_a?(String)) ? padding_right : Integer(padding_right)
80
82
  )
81
83
  end
82
84
 
@@ -15,6 +15,7 @@ module RatatuiRuby
15
15
  end
16
16
 
17
17
  # Core widgets
18
+ require_relative "widgets/coerceable_widget"
18
19
  require_relative "widgets/block"
19
20
  require_relative "widgets/paragraph"
20
21
  require_relative "widgets/list"
data/lib/ratatui_ruby.rb CHANGED
@@ -12,8 +12,9 @@ require_relative "ratatui_ruby/layout" # Layout::Rect, Layout::Constraint, Lay
12
12
  require_relative "ratatui_ruby/style" # Style::Style
13
13
  require_relative "ratatui_ruby/widgets" # Widgets::Block, Widgets::Paragraph, etc.
14
14
  require_relative "ratatui_ruby/buffer" # Buffer::Cell (for inspection)
15
- require_relative "ratatui_ruby/schema/text" # Text::Span, Text::Line
16
- require_relative "ratatui_ruby/schema/draw" # Draw commands
15
+ require_relative "ratatui_ruby/text" # Text::Span, Text::Line, Text.width
16
+ require_relative "ratatui_ruby/draw" # Draw commands
17
+ require_relative "ratatui_ruby/symbols" # Symbols::Shade, etc.
17
18
 
18
19
  # Event types
19
20
  require_relative "ratatui_ruby/event"
@@ -41,6 +42,10 @@ rescue LoadError
41
42
  require_relative "ratatui_ruby/ratatui_ruby"
42
43
  end
43
44
 
45
+ # Debug mode (for Rust backtraces and diagnostic features)
46
+ # Loaded after native extension so _enable_rust_backtrace is defined
47
+ require_relative "ratatui_ruby/debug"
48
+
44
49
  # Main entry point for the library.
45
50
  #
46
51
  # Terminal UIs require low-level control using C/Rust and high-level abstraction in Ruby.
@@ -154,13 +159,10 @@ module RatatuiRuby
154
159
  extend OutputGuard
155
160
  extend TerminalLifecycle
156
161
 
157
- # Re-export NullIO at module root for backward compatibility
158
- NullIO = OutputGuard::NullIO
159
-
160
162
  @experimental_warnings = true
161
163
  @tui_session_active = false
162
164
  @headless_mode = false
163
- @deferred_warnings = []
165
+ @deferred_warnings = [] #: Array[String]
164
166
 
165
167
  class << self
166
168
  ##
@@ -177,6 +179,13 @@ module RatatuiRuby
177
179
  @deferred_warnings.each { |msg| warn msg }
178
180
  @deferred_warnings.clear
179
181
  end
182
+
183
+ private def flush_panic_info
184
+ return unless Debug.rust_backtrace_enabled?
185
+ panic_info = _get_last_panic
186
+ return unless panic_info
187
+ warn panic_info
188
+ end
180
189
  end
181
190
 
182
191
  ##
@@ -206,7 +215,7 @@ module RatatuiRuby
206
215
  def self.warn_experimental_feature(feature_name)
207
216
  return unless experimental_warnings
208
217
 
209
- @warned_features ||= {}
218
+ @warned_features ||= {} #: Hash[String, bool]
210
219
  return if @warned_features[feature_name]
211
220
 
212
221
  message = "WARNING: #{feature_name} is an experimental feature and may change in future versions. Disable this warning with RatatuiRuby.experimental_warnings = false."
@@ -219,7 +228,28 @@ module RatatuiRuby
219
228
  end
220
229
 
221
230
  # (Native methods implemented in Rust)
222
- private_class_method :_init_terminal, :_restore_terminal, :_init_test_terminal
231
+ private_class_method :_init_terminal, :_restore_terminal, :_init_test_terminal, :_enable_rust_backtrace, :_get_last_panic
232
+
233
+ ##
234
+ # Enables full debug mode.
235
+ #
236
+ # Convenience alias for Debug.enable!.
237
+ #
238
+ # === Example
239
+ #
240
+ #--
241
+ # SPDX-SnippetBegin
242
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
243
+ # SPDX-License-Identifier: MIT-0
244
+ #++
245
+ # RatatuiRuby.debug_mode!
246
+ #
247
+ #--
248
+ # SPDX-SnippetEnd
249
+ #++
250
+ def self.debug_mode!
251
+ Debug.enable!
252
+ end
223
253
 
224
254
  ##
225
255
  # Draws the given UI node tree to the terminal.
@@ -281,7 +311,7 @@ module RatatuiRuby
281
311
 
282
312
  if tree
283
313
  _draw(tree)
284
- else
314
+ elsif block
285
315
  _draw(&block)
286
316
  end
287
317
  end
@@ -357,8 +387,8 @@ module RatatuiRuby
357
387
  when :focus_lost
358
388
  Event::FocusLost.new.freeze
359
389
  else
360
- # Fallback for unknown events, though ideally we cover them all
361
- nil
390
+ # Return None for unknown event types
391
+ Event::None.new.freeze
362
392
  end
363
393
  end
364
394
 
@@ -396,6 +426,7 @@ module RatatuiRuby
396
426
  char: raw["char"],
397
427
  fg: raw["fg"],
398
428
  bg: raw["bg"],
429
+ underline_color: raw["underline_color"],
399
430
  modifiers: raw["modifiers"] || []
400
431
  )
401
432
  end
@@ -0,0 +1,23 @@
1
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ # MVU application model for the All Events example.
5
+ class AppModel < Data
6
+ HIGHLIGHT_DURATION_MS: Integer
7
+
8
+ attr_reader entries: Array[EventEntry]
9
+ attr_reader focused: bool
10
+ attr_reader window_size: [Integer, Integer]
11
+ attr_reader lit_types: Hash[Symbol, Timestamp]
12
+ attr_reader none_count: Integer
13
+ attr_reader color_cycle_index: Integer
14
+
15
+ def self.initial: () -> instance
16
+ def count: (Symbol type) -> Integer
17
+ def sub_counts: (Symbol type) -> Hash[String, Integer]
18
+ def lit?: (Symbol type) -> bool
19
+ def visible: (Integer max_entries) -> Array[EventEntry]
20
+ def empty?: () -> bool
21
+ def live_event: (Symbol type) -> { time: Time, description: String }?
22
+ def next_color: () -> Symbol
23
+ end
@@ -1,16 +1,23 @@
1
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
1
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
2
2
  # SPDX-License-Identifier: AGPL-3.0-or-later
3
3
 
4
+ # Type alias for any Event subtype.
5
+ type event_type = RatatuiRuby::Event::Key
6
+ | RatatuiRuby::Event::Mouse
7
+ | RatatuiRuby::Event::Resize
8
+ | RatatuiRuby::Event::Paste
9
+ | RatatuiRuby::Event::FocusGained
10
+ | RatatuiRuby::Event::FocusLost
11
+ | RatatuiRuby::Event::None
12
+
4
13
  class EventEntry < Data
5
- attr_reader type: Symbol
6
- attr_reader sub_key: Symbol | String | nil
14
+ attr_reader event: event_type
7
15
  attr_reader color: Symbol
8
16
  attr_reader timestamp: Timestamp
9
- attr_reader data: Hash[Symbol, untyped]
10
17
 
11
- def self.from_event(type: Symbol, sub_key: Symbol | String | nil, color: Symbol, timestamp: Timestamp, data: Hash[Symbol, untyped]) -> instance
18
+ def self.create: (event_type event, Symbol color, Timestamp timestamp) -> instance
19
+ def type: () -> Symbol
20
+ def description: () -> String
12
21
  def matches_type?: (Symbol check_type) -> bool
13
- def matches_sub_type?: (Symbol check_type, Symbol | String check_sub_key) -> bool
14
- def matches_kind?: (String kind) -> bool
15
- def self.new: (?type: Symbol, ?sub_key: Symbol | String | nil, ?color: Symbol, ?timestamp: Timestamp, ?data: Hash[Symbol, untyped]) -> instance
22
+ def live_type: () -> Symbol
16
23
  end
@@ -7,5 +7,5 @@ class Timestamp < Data
7
7
  def self.now: () -> instance
8
8
  def self.current: () -> Integer
9
9
  def elapsed?: (Integer duration_ms) -> bool
10
- def self.new: (?milliseconds: Numeric) -> instance
10
+ def self.new: (?milliseconds: _ToI) -> instance
11
11
  end
@@ -9,6 +9,6 @@
9
9
 
10
10
  module View
11
11
  interface _View
12
- def call(state: ViewState, tui: RatatuiRuby::TUI, frame: RatatuiRuby::Frame, area: RatatuiRuby::Rect) -> void
12
+ def call: (AppModel model, RatatuiRuby::TUI tui, RatatuiRuby::Frame frame, RatatuiRuby::Layout::Rect area) -> void
13
13
  end
14
14
  end
@@ -13,12 +13,12 @@ class AppStatefulInteraction
13
13
  @list_state: RatatuiRuby::ListState
14
14
  @table_state: RatatuiRuby::TableState
15
15
  @active_pane: :list | :table
16
- @tui: untyped
16
+ @tui: RatatuiRuby::TUI
17
17
  @style_active: RatatuiRuby::Style
18
18
  @style_inactive: RatatuiRuby::Style
19
19
  @style_highlight: RatatuiRuby::Style
20
- @list_area: RatatuiRuby::Rect
21
- @table_area: RatatuiRuby::Rect
20
+ @list_area: RatatuiRuby::Layout::Rect
21
+ @table_area: RatatuiRuby::Layout::Rect
22
22
 
23
23
  # @public
24
24
  def self.new: () -> AppStatefulInteraction
@@ -29,8 +29,8 @@ class AppStatefulInteraction
29
29
  private
30
30
 
31
31
  def render: () -> void
32
- def render_list: (untyped frame, RatatuiRuby::Rect area) -> void
33
- def render_table: (untyped frame, RatatuiRuby::Rect area) -> void
32
+ def render_list: (RatatuiRuby::Frame frame, RatatuiRuby::Layout::Rect area) -> void
33
+ def render_table: (RatatuiRuby::Frame frame, RatatuiRuby::Layout::Rect area) -> void
34
34
  def handle_input: () -> (:quit | nil)
35
35
  def scroll_active: (Integer delta) -> void
36
36
  def handle_click: (Integer x, Integer y) -> void
@@ -10,25 +10,25 @@
10
10
  # SPDX-License-Identifier: AGPL-3.0-or-later
11
11
 
12
12
  class WidgetBlockDemo
13
- @tui: RatatuiRuby::Tui
13
+ @tui: RatatuiRuby::TUI
14
14
  @hotkey_style: RatatuiRuby::Style
15
15
  @title_configs: Array[{name: String, title: String?}]
16
16
  @title_index: Integer
17
- @titles_configs: Array[{name: String, titles: Array[RatatuiRuby::Block::title_input]}]
17
+ @titles_configs: Array[{name: String, titles: Array[untyped]}]
18
18
  @titles_index: Integer
19
- @alignment_configs: Array[{name: String, alignment: RatatuiRuby::Alignment}]
19
+ @alignment_configs: Array[{name: String, alignment: Symbol}]
20
20
  @alignment_index: Integer
21
21
  @title_styles: Array[{name: String, style: RatatuiRuby::Style?}]
22
22
  @title_style_index: Integer
23
- @border_configs: Array[{name: String, borders: Array[RatatuiRuby::Block::border_option]}]
23
+ @border_configs: Array[{name: String, borders: Array[Symbol]}]
24
24
  @border_index: Integer
25
- @border_type_configs: Array[{name: String, type: RatatuiRuby::Block::border_type?, set: Hash[Symbol, String]?}]
25
+ @border_type_configs: Array[{name: String, type: Symbol?, set: Hash[Symbol, String]?}]
26
26
  @border_type_index: Integer
27
27
  @border_styles: Array[{name: String, style: RatatuiRuby::Style?}]
28
28
  @border_style_index: Integer
29
29
  @base_styles: Array[{name: String, style: RatatuiRuby::Style?}]
30
30
  @base_style_index: Integer
31
- @padding_configs: Array[{name: String, padding: RatatuiRuby::Block::padding_input}]
31
+ @padding_configs: Array[{name: String, padding: (Integer | Array[Integer])}]
32
32
  @padding_index: Integer
33
33
 
34
34
  def self.new: () -> WidgetBlockDemo
data/sig/manifest.yaml ADDED
@@ -0,0 +1,5 @@
1
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
2
+ #
3
+ # SPDX-License-Identifier: AGPL-3.0-or-later
4
+
5
+ dependencies:
@@ -0,0 +1,26 @@
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
+ # SPDX-License-Identifier: AGPL-3.0-or-later
9
+
10
+ # Patch for Data class to support super() calls in Data.define subclasses.
11
+ #
12
+ # The core RBS Data class defines `self.new: (**untyped) -> Data` but not `initialize`.
13
+ # When Steep type-checks `super(items:, ...)` in a Data.define subclass, it looks for
14
+ # the parent's `initialize` method. Since Data has no `initialize` signature in core RBS,
15
+ # Steep can't match arguments and raises errors.
16
+ #
17
+ # This patch adds the missing `initialize` signatures that Data.define generates dynamically.
18
+ class Data
19
+ # Accept both positional and keyword arguments for the dynamically-generated initialize.
20
+ # This allows subclasses to call super(foo, bar, ...) or super(foo:, bar:, ...) without type errors.
21
+ def initialize: (*untyped) -> void
22
+ | (**untyped) -> void
23
+ # Allow super() calls from overridden self.new methods to work with any keyword args
24
+ def self.new: (**untyped) -> instance
25
+ end
26
+
@@ -0,0 +1,8 @@
1
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
2
+ # SPDX-License-Identifier: LGPL-3.0-or-later
3
+
4
+ # Minimal stub for debug gem's DEBUGGER__ constant
5
+ # Full library causes Steep deadlock on Ruby 4.0 (Steep 1.10.0 threading issue)
6
+ module DEBUGGER__
7
+ def self.create_unix_domain_socket_name: () -> String?
8
+ end
@@ -0,0 +1,46 @@
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
+ module Buffer
10
+ class Cell
11
+ type color = Symbol | String | nil
12
+
13
+ attr_reader symbol: String
14
+ attr_reader fg: color
15
+ attr_reader bg: color
16
+ attr_reader underline_color: color
17
+ attr_reader modifiers: Array[Symbol]
18
+
19
+ alias char symbol
20
+
21
+ def self.new: (?symbol: String?, ?char: String?, ?fg: color, ?bg: color, ?underline_color: color, ?modifiers: Array[String | Symbol]) -> Cell
22
+ def self.empty: () -> Cell
23
+ def self.default: () -> Cell
24
+ def self.symbol: (String symbol) -> Cell
25
+ def self.char: (String char) -> Cell
26
+
27
+ def initialize: (?symbol: String?, ?char: String?, ?fg: color, ?bg: color, ?underline_color: color, ?modifiers: Array[String | Symbol]) -> void
28
+
29
+ # Modifier predicates
30
+ def bold?: () -> bool
31
+ def dim?: () -> bool
32
+ def italic?: () -> bool
33
+ def underlined?: () -> bool
34
+ def slow_blink?: () -> bool
35
+ def rapid_blink?: () -> bool
36
+ def reversed?: () -> bool
37
+ def hidden?: () -> bool
38
+ def crossed_out?: () -> bool
39
+
40
+ def ==: (untyped other) -> bool
41
+ def inspect: () -> String
42
+ def to_s: () -> String
43
+ def deconstruct_keys: (Array[Symbol]? keys) -> { symbol: String, char: String, fg: color, bg: color, underline_color: color, modifiers: Array[Symbol] }
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,18 @@
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
+ module Buffer
10
+ def self.index_of: (Integer x, Integer y) -> Integer
11
+ def self.pos_of: (Integer index) -> [Integer, Integer]
12
+ def self.get: (Integer x, Integer y) -> Cell
13
+ def self.content: () -> Array[Cell]
14
+
15
+ # Ruby-idiomatic alias
16
+ alias self.[] self.get
17
+ end
18
+ end
@@ -0,0 +1,44 @@
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
+ class Cell
10
+ type color = Symbol | String | nil
11
+
12
+ attr_reader symbol: String
13
+ attr_reader fg: color
14
+ attr_reader bg: color
15
+ attr_reader underline_color: color
16
+ attr_reader modifiers: Array[String]
17
+
18
+ alias char symbol
19
+
20
+ def self.new: (?symbol: String?, ?char: String?, ?fg: color, ?bg: color, ?underline_color: color, ?modifiers: Array[String]) -> Cell
21
+ def self.empty: () -> Cell
22
+ def self.default: () -> Cell
23
+ def self.symbol: (String symbol) -> Cell
24
+ def self.char: (String char) -> Cell
25
+
26
+ def initialize: (?symbol: String?, ?char: String?, ?fg: color, ?bg: color, ?underline_color: color, ?modifiers: Array[String]) -> void
27
+
28
+ # Modifier predicates
29
+ def bold?: () -> bool
30
+ def dim?: () -> bool
31
+ def italic?: () -> bool
32
+ def underlined?: () -> bool
33
+ def slow_blink?: () -> bool
34
+ def rapid_blink?: () -> bool
35
+ def reversed?: () -> bool
36
+ def hidden?: () -> bool
37
+ def crossed_out?: () -> bool
38
+
39
+ def ==: (untyped other) -> bool
40
+ def inspect: () -> String
41
+ def to_s: () -> String
42
+ def deconstruct_keys: (Array[Symbol]? keys) -> { symbol: String, char: String, fg: color, bg: color, underline_color: color, modifiers: Array[String] }
43
+ end
44
+ end