ratatui_ruby 0.9.0 → 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 (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 +122 -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 +16 -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 +16 -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/sync.rb +52 -0
  85. data/lib/ratatui_ruby/event.rb +7 -1
  86. data/lib/ratatui_ruby/layout/constraint.rb +184 -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 +86 -0
  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 +34 -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 +51 -16
  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 +83 -4
  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 +82 -63
  208. data/doc/contributors/v1.0.0_blockers.md +0 -876
  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 -22
  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
@@ -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"
@@ -31,6 +32,9 @@ require_relative "ratatui_ruby/terminal_lifecycle"
31
32
  # TUI facade (for external instantiation and caching)
32
33
  require_relative "ratatui_ruby/tui"
33
34
 
35
+ # Synthetic events queue (for async synchronization)
36
+ require_relative "ratatui_ruby/synthetic_events"
37
+
34
38
  begin
35
39
  require "ratatui_ruby/ratatui_ruby"
36
40
  rescue LoadError
@@ -38,6 +42,10 @@ rescue LoadError
38
42
  require_relative "ratatui_ruby/ratatui_ruby"
39
43
  end
40
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
+
41
49
  # Main entry point for the library.
42
50
  #
43
51
  # Terminal UIs require low-level control using C/Rust and high-level abstraction in Ruby.
@@ -120,16 +128,17 @@ module RatatuiRuby
120
128
  #++
121
129
  class Safety < Error; end
122
130
 
123
- # State invariant violation.
131
+ # Invariant violation.
124
132
  #
125
- # The library has rules about valid state transitions.
126
- # Calling methods in the wrong order or state breaks invariants.
133
+ # The library enforces rules about valid states and contracts.
134
+ # Breaking these rules raises this error.
127
135
  #
128
- # This error signals you violated a state machine contract.
129
- # The program state doesn't allow this operation right now.
136
+ # Common causes:
137
+ # - Calling methods in the wrong order (e.g., \`init_terminal\` twice)
138
+ # - Callable return type mismatch (e.g., view returns \`nil\` instead of a widget)
130
139
  #
131
- # To resolve, check `terminal_active?` or restructure the
132
- # code to ensure methods are called in the expected order.
140
+ # To resolve, check the method's documented contract. Ensure
141
+ # state preconditions are met and return types are correct.
133
142
  #
134
143
  # === Example
135
144
  #
@@ -150,13 +159,10 @@ module RatatuiRuby
150
159
  extend OutputGuard
151
160
  extend TerminalLifecycle
152
161
 
153
- # Re-export NullIO at module root for backward compatibility
154
- NullIO = OutputGuard::NullIO
155
-
156
162
  @experimental_warnings = true
157
163
  @tui_session_active = false
158
164
  @headless_mode = false
159
- @deferred_warnings = []
165
+ @deferred_warnings = [] #: Array[String]
160
166
 
161
167
  class << self
162
168
  ##
@@ -173,6 +179,13 @@ module RatatuiRuby
173
179
  @deferred_warnings.each { |msg| warn msg }
174
180
  @deferred_warnings.clear
175
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
176
189
  end
177
190
 
178
191
  ##
@@ -202,7 +215,7 @@ module RatatuiRuby
202
215
  def self.warn_experimental_feature(feature_name)
203
216
  return unless experimental_warnings
204
217
 
205
- @warned_features ||= {}
218
+ @warned_features ||= {} #: Hash[String, bool]
206
219
  return if @warned_features[feature_name]
207
220
 
208
221
  message = "WARNING: #{feature_name} is an experimental feature and may change in future versions. Disable this warning with RatatuiRuby.experimental_warnings = false."
@@ -215,7 +228,28 @@ module RatatuiRuby
215
228
  end
216
229
 
217
230
  # (Native methods implemented in Rust)
218
- 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
219
253
 
220
254
  ##
221
255
  # Draws the given UI node tree to the terminal.
@@ -277,7 +311,7 @@ module RatatuiRuby
277
311
 
278
312
  if tree
279
313
  _draw(tree)
280
- else
314
+ elsif block
281
315
  _draw(&block)
282
316
  end
283
317
  end
@@ -392,6 +426,7 @@ module RatatuiRuby
392
426
  char: raw["char"],
393
427
  fg: raw["fg"],
394
428
  bg: raw["bg"],
429
+ underline_color: raw["underline_color"],
395
430
  modifiers: raw["modifiers"] || []
396
431
  )
397
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
@@ -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
+ # SPDX-License-Identifier: AGPL-3.0-or-later
9
+
10
+ module RatatuiRuby
11
+ # Widget to clear/reset a terminal area before rendering.
12
+ class Clear < Data
13
+ attr_reader block: Widgets::Block?
14
+
15
+ def self.new: (?block: Widgets::Block?) -> Clear
16
+ def initialize: (?block: Widgets::Block?) -> void
17
+ end
18
+ end
@@ -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
+ module RatatuiRuby
11
+ # Schema Constraint - defined directly under RatatuiRuby namespace.
12
+ class Constraint < Data
13
+ attr_reader type: Symbol
14
+ attr_reader value: (Integer | Array[Integer])
15
+
16
+ def self.new: (type: Symbol, value: (Integer | Array[Integer])) -> Constraint
17
+ def initialize: (type: Symbol, value: (Integer | Array[Integer])) -> void
18
+
19
+ def self.length: (_ToI) -> Constraint
20
+ def self.percentage: (_ToI) -> Constraint
21
+ def self.min: (_ToI) -> Constraint
22
+ def self.max: (_ToI) -> Constraint
23
+ def self.fill: (?_ToI) -> Constraint
24
+ def self.ratio: (_ToI, _ToI) -> Constraint
25
+ end
26
+ end
@@ -0,0 +1,45 @@
1
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
2
+ # SPDX-License-Identifier: LGPL-3.0-or-later
3
+
4
+ module RatatuiRuby
5
+ # Debug mode control for RatatuiRuby.
6
+ #
7
+ # Manages Rust backtrace visibility and Ruby-side debug features.
8
+ module Debug
9
+ @rust_backtrace_enabled: bool
10
+ @debug_mode_enabled: bool
11
+ @remote_debugging_mode: (:open | :open_nonstop)?
12
+ @socket_path: String?
13
+
14
+ type source = :env | :test | :programmatic
15
+
16
+ # Enables Rust backtraces only.
17
+ def self.enable_rust_backtrace!: () -> void
18
+
19
+ # Enables full debug mode (Rust backtraces + Ruby-side features).
20
+ # Returns the socket path for remote debugging (nil on Windows or in test mode).
21
+ # source: :env (from RR_DEBUG), :test (from TestHelper), :programmatic (default)
22
+ def self.enable!: (?source: source) -> String?
23
+
24
+ # Returns whether full debug mode is enabled.
25
+ def self.enabled?: () -> bool
26
+
27
+ # Returns whether Rust backtraces are enabled.
28
+ def self.rust_backtrace_enabled?: () -> bool
29
+
30
+ # Returns the remote debugging mode for debug gem integration.
31
+ def self.remote_debugging_mode: () -> (:open | :open_nonstop)?
32
+
33
+ # Triggers a Rust panic for backtrace verification.
34
+ # WARNING: Crashes your process. Use only for debugging.
35
+ def self.test_panic!: () -> bot
36
+
37
+ # Temporarily suppresses Ruby-side debug mode checks within the block.
38
+ def self.suppress_debug_mode: [T] () { () -> T } -> T
39
+
40
+ private
41
+
42
+ # Enables remote debugging via the debug gem. Returns socket path.
43
+ def self.enable_remote_debugging!: () -> String?
44
+ end
45
+ end