ratatui_ruby 0.6.0 → 0.7.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 (171) 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 +4 -4
  7. data/CHANGELOG.md +35 -0
  8. data/README.md +26 -1
  9. data/doc/application_architecture.md +16 -16
  10. data/doc/application_testing.md +1 -1
  11. data/doc/contributors/architectural_overhaul/chat_conversations.md +4952 -0
  12. data/doc/contributors/architectural_overhaul/implementation_plan.md +60 -0
  13. data/doc/contributors/architectural_overhaul/task.md +37 -0
  14. data/doc/contributors/design/ruby_frontend.md +277 -81
  15. data/doc/contributors/design/rust_backend.md +349 -55
  16. data/doc/contributors/developing_examples.md +5 -5
  17. data/doc/contributors/index.md +7 -5
  18. data/doc/contributors/v1.0.0_blockers.md +1729 -0
  19. data/doc/index.md +11 -6
  20. data/doc/interactive_design.md +2 -2
  21. data/doc/quickstart.md +66 -97
  22. data/doc/v0.7.0_migration.md +236 -0
  23. data/doc/why.md +93 -0
  24. data/examples/app_all_events/README.md +6 -4
  25. data/examples/app_all_events/app.rb +1 -1
  26. data/examples/app_all_events/model/app_model.rb +1 -1
  27. data/examples/app_all_events/model/msg.rb +1 -1
  28. data/examples/app_all_events/update.rb +1 -1
  29. data/examples/app_all_events/view/app_view.rb +1 -1
  30. data/examples/app_all_events/view/controls_view.rb +1 -1
  31. data/examples/app_all_events/view/counts_view.rb +1 -1
  32. data/examples/app_all_events/view/live_view.rb +1 -1
  33. data/examples/app_all_events/view/log_view.rb +1 -1
  34. data/examples/app_color_picker/README.md +7 -5
  35. data/examples/app_color_picker/app.rb +1 -1
  36. data/examples/app_login_form/README.md +2 -0
  37. data/examples/app_stateful_interaction/README.md +2 -0
  38. data/examples/app_stateful_interaction/app.rb +1 -1
  39. data/examples/verify_quickstart_dsl/README.md +4 -3
  40. data/examples/verify_quickstart_dsl/app.rb +1 -1
  41. data/examples/verify_quickstart_layout/README.md +1 -1
  42. data/examples/verify_quickstart_lifecycle/README.md +3 -3
  43. data/examples/verify_quickstart_lifecycle/app.rb +2 -2
  44. data/examples/verify_readme_usage/README.md +1 -1
  45. data/examples/widget_barchart_demo/README.md +2 -1
  46. data/examples/widget_block_demo/README.md +2 -0
  47. data/examples/widget_box_demo/README.md +3 -3
  48. data/examples/widget_calendar_demo/README.md +3 -3
  49. data/examples/widget_calendar_demo/app.rb +5 -1
  50. data/examples/widget_canvas_demo/README.md +3 -3
  51. data/examples/widget_cell_demo/README.md +3 -3
  52. data/examples/widget_center_demo/README.md +3 -3
  53. data/examples/widget_chart_demo/README.md +3 -3
  54. data/examples/widget_gauge_demo/README.md +3 -3
  55. data/examples/widget_layout_split/README.md +3 -3
  56. data/examples/widget_line_gauge_demo/README.md +3 -3
  57. data/examples/widget_list_demo/README.md +3 -3
  58. data/examples/widget_map_demo/README.md +3 -3
  59. data/examples/widget_map_demo/app.rb +2 -2
  60. data/examples/widget_overlay_demo/README.md +36 -0
  61. data/examples/widget_popup_demo/README.md +3 -3
  62. data/examples/widget_ratatui_logo_demo/README.md +3 -3
  63. data/examples/widget_ratatui_logo_demo/app.rb +1 -1
  64. data/examples/widget_ratatui_mascot_demo/README.md +3 -3
  65. data/examples/widget_rect/README.md +3 -3
  66. data/examples/widget_render/README.md +3 -3
  67. data/examples/widget_render/app.rb +3 -3
  68. data/examples/widget_rich_text/README.md +3 -3
  69. data/examples/widget_scroll_text/README.md +3 -3
  70. data/examples/widget_scrollbar_demo/README.md +3 -3
  71. data/examples/widget_sparkline_demo/README.md +3 -3
  72. data/examples/widget_style_colors/README.md +3 -3
  73. data/examples/widget_table_demo/README.md +3 -3
  74. data/examples/widget_table_demo/app.rb +19 -4
  75. data/examples/widget_tabs_demo/README.md +3 -3
  76. data/examples/widget_text_width/README.md +3 -3
  77. data/examples/widget_text_width/app.rb +8 -1
  78. data/ext/ratatui_ruby/Cargo.lock +1 -1
  79. data/ext/ratatui_ruby/Cargo.toml +1 -1
  80. data/ext/ratatui_ruby/src/frame.rs +6 -5
  81. data/ext/ratatui_ruby/src/lib.rs +3 -2
  82. data/ext/ratatui_ruby/src/rendering.rs +22 -21
  83. data/ext/ratatui_ruby/src/text.rs +12 -3
  84. data/ext/ratatui_ruby/src/widgets/canvas.rs +5 -5
  85. data/ext/ratatui_ruby/src/widgets/table.rs +81 -36
  86. data/lib/ratatui_ruby/buffer/cell.rb +168 -0
  87. data/lib/ratatui_ruby/buffer.rb +15 -0
  88. data/lib/ratatui_ruby/frame.rb +8 -8
  89. data/lib/ratatui_ruby/layout/constraint.rb +95 -0
  90. data/lib/ratatui_ruby/layout/layout.rb +106 -0
  91. data/lib/ratatui_ruby/layout/rect.rb +118 -0
  92. data/lib/ratatui_ruby/layout.rb +19 -0
  93. data/lib/ratatui_ruby/list_state.rb +2 -2
  94. data/lib/ratatui_ruby/schema/layout.rb +1 -1
  95. data/lib/ratatui_ruby/schema/row.rb +66 -0
  96. data/lib/ratatui_ruby/schema/table.rb +10 -10
  97. data/lib/ratatui_ruby/schema/text.rb +27 -2
  98. data/lib/ratatui_ruby/style/style.rb +81 -0
  99. data/lib/ratatui_ruby/style.rb +15 -0
  100. data/lib/ratatui_ruby/table_state.rb +1 -1
  101. data/lib/ratatui_ruby/test_helper/snapshot.rb +24 -0
  102. data/lib/ratatui_ruby/test_helper/style_assertions.rb +1 -1
  103. data/lib/ratatui_ruby/tui/buffer_factories.rb +20 -0
  104. data/lib/ratatui_ruby/tui/canvas_factories.rb +44 -0
  105. data/lib/ratatui_ruby/tui/core.rb +38 -0
  106. data/lib/ratatui_ruby/tui/layout_factories.rb +74 -0
  107. data/lib/ratatui_ruby/tui/state_factories.rb +33 -0
  108. data/lib/ratatui_ruby/tui/style_factories.rb +20 -0
  109. data/lib/ratatui_ruby/tui/text_factories.rb +44 -0
  110. data/lib/ratatui_ruby/tui/widget_factories.rb +195 -0
  111. data/lib/ratatui_ruby/tui.rb +75 -0
  112. data/lib/ratatui_ruby/version.rb +1 -1
  113. data/lib/ratatui_ruby/widgets/bar_chart/bar.rb +47 -0
  114. data/lib/ratatui_ruby/widgets/bar_chart/bar_group.rb +25 -0
  115. data/lib/ratatui_ruby/widgets/bar_chart.rb +239 -0
  116. data/lib/ratatui_ruby/widgets/block.rb +192 -0
  117. data/lib/ratatui_ruby/widgets/calendar.rb +84 -0
  118. data/lib/ratatui_ruby/widgets/canvas.rb +231 -0
  119. data/lib/ratatui_ruby/widgets/cell.rb +47 -0
  120. data/lib/ratatui_ruby/widgets/center.rb +59 -0
  121. data/lib/ratatui_ruby/widgets/chart.rb +185 -0
  122. data/lib/ratatui_ruby/widgets/clear.rb +54 -0
  123. data/lib/ratatui_ruby/widgets/cursor.rb +42 -0
  124. data/lib/ratatui_ruby/widgets/gauge.rb +72 -0
  125. data/lib/ratatui_ruby/widgets/line_gauge.rb +80 -0
  126. data/lib/ratatui_ruby/widgets/list.rb +127 -0
  127. data/lib/ratatui_ruby/widgets/list_item.rb +43 -0
  128. data/lib/ratatui_ruby/widgets/overlay.rb +43 -0
  129. data/lib/ratatui_ruby/widgets/paragraph.rb +99 -0
  130. data/lib/ratatui_ruby/widgets/ratatui_logo.rb +31 -0
  131. data/lib/ratatui_ruby/widgets/ratatui_mascot.rb +36 -0
  132. data/lib/ratatui_ruby/widgets/row.rb +68 -0
  133. data/lib/ratatui_ruby/widgets/scrollbar.rb +143 -0
  134. data/lib/ratatui_ruby/widgets/shape/label.rb +68 -0
  135. data/lib/ratatui_ruby/widgets/sparkline.rb +134 -0
  136. data/lib/ratatui_ruby/widgets/table.rb +141 -0
  137. data/lib/ratatui_ruby/widgets/tabs.rb +85 -0
  138. data/lib/ratatui_ruby/widgets.rb +40 -0
  139. data/lib/ratatui_ruby.rb +23 -39
  140. data/sig/examples/app_all_events/view.rbs +1 -1
  141. data/sig/examples/app_all_events/view_state.rbs +1 -1
  142. data/sig/ratatui_ruby/schema/row.rbs +22 -0
  143. data/sig/ratatui_ruby/schema/table.rbs +1 -1
  144. data/sig/ratatui_ruby/schema/text.rbs +1 -0
  145. data/sig/ratatui_ruby/session.rbs +29 -49
  146. data/sig/ratatui_ruby/tui/buffer_factories.rbs +10 -0
  147. data/sig/ratatui_ruby/tui/canvas_factories.rbs +14 -0
  148. data/sig/ratatui_ruby/tui/core.rbs +14 -0
  149. data/sig/ratatui_ruby/tui/layout_factories.rbs +19 -0
  150. data/sig/ratatui_ruby/tui/state_factories.rbs +12 -0
  151. data/sig/ratatui_ruby/tui/style_factories.rbs +10 -0
  152. data/sig/ratatui_ruby/tui/text_factories.rbs +14 -0
  153. data/sig/ratatui_ruby/tui/widget_factories.rbs +39 -0
  154. data/sig/ratatui_ruby/tui.rbs +19 -0
  155. data/tasks/autodoc.rake +1 -35
  156. data/tasks/sourcehut.rake +4 -1
  157. metadata +62 -15
  158. data/doc/contributors/dwim_dx.md +0 -366
  159. data/doc/contributors/examples_audit/p1_high.md +0 -21
  160. data/doc/contributors/examples_audit/p2_moderate.md +0 -81
  161. data/doc/contributors/examples_audit.md +0 -41
  162. data/doc/images/app_analytics.png +0 -0
  163. data/doc/images/app_custom_widget.png +0 -0
  164. data/doc/images/app_mouse_events.png +0 -0
  165. data/doc/images/widget_table_flex.png +0 -0
  166. data/lib/ratatui_ruby/session/autodoc.rb +0 -482
  167. data/lib/ratatui_ruby/session.rb +0 -178
  168. data/tasks/autodoc/inventory.rb +0 -63
  169. data/tasks/autodoc/notice.rb +0 -26
  170. data/tasks/autodoc/rbs.rb +0 -38
  171. data/tasks/autodoc/rdoc.rb +0 -45
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
+ # SPDX-License-Identifier: AGPL-3.0-or-later
5
+
6
+ module RatatuiRuby
7
+ module Widgets
8
+ # Displays structured data in rows and columns.
9
+ #
10
+ # Data is often multidimensional. You need to show relationships between fields (Name, Age, ID).
11
+ # Aligning columns manually in a monospaced environment is painful and error-prone.
12
+ #
13
+ # This widget creates a grid. It enforces column widths using constraints. It renders headers, rows, and footers aligned perfectly.
14
+ #
15
+ # Use it to display database records, logs, or file lists.
16
+ #
17
+ # {rdoc-image:/doc/images/widget_table_flex.png}[link:/examples/widget_table_flex/app_rb.html]
18
+ #
19
+ # === Example
20
+ #
21
+ # Run the interactive demo from the terminal:
22
+ #
23
+ # ruby examples/widget_table_flex/app.rb
24
+ 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)
25
+ ##
26
+ # :attr_reader: header
27
+ # Header row content (Array of Strings, Text::Spans, Text::Lines, or Paragraphs).
28
+
29
+ ##
30
+ # :attr_reader: rows
31
+ # Data rows (Array of Arrays). Each cell can be String, Text::Span, Text::Line, Paragraph, or Cell.
32
+
33
+ ##
34
+ # :attr_reader: widths
35
+ # Column width constraints (Array of Constraint).
36
+
37
+ ##
38
+ # :attr_reader: row_highlight_style
39
+ # Style for the selected row.
40
+
41
+ ##
42
+ # :attr_reader: highlight_symbol
43
+ # Symbol for the selected row.
44
+
45
+ ##
46
+ # :attr_reader: highlight_spacing
47
+ # When to show the highlight symbol column (<tt>:always</tt>, <tt>:when_selected</tt>, <tt>:never</tt>).
48
+
49
+ ##
50
+ # :attr_reader: column_highlight_style
51
+ # Style for the selected column.
52
+
53
+ ##
54
+ # :attr_reader: cell_highlight_style
55
+ # Style for the selected cell (intersection of row and column).
56
+
57
+ ##
58
+ # :attr_reader: selected_row
59
+ # Index of the selected row (Integer or nil).
60
+
61
+ ##
62
+ # :attr_reader: selected_column
63
+ # Index of the selected column (Integer or nil).
64
+
65
+ ##
66
+ # :attr_reader: offset
67
+ # Scroll offset (Integer or nil).
68
+ #
69
+ # Controls the viewport's starting row position in the table.
70
+ #
71
+ # When +nil+ (default), Ratatui auto-scrolls to keep the selection visible ("natural scrolling").
72
+ #
73
+ # When set, forces the viewport to start at this row index. Use this for:
74
+ # - **Passive scrolling**: Scroll through a log table without selecting rows.
75
+ # - **Click-to-select math**: Calculate which row index corresponds to a click coordinate.
76
+ #
77
+ # *Important*: When both +offset+ and +selected_row+ are set, Ratatui may still adjust
78
+ # the viewport during rendering to ensure the selection stays visible. Set +selected_row+
79
+ # to +nil+ for fully manual scroll control.
80
+
81
+ ##
82
+ # :attr_reader: block
83
+ # Optional wrapping block.
84
+
85
+ ##
86
+ # :attr_reader: footer
87
+ # Footer row content (Array of Strings, Text::Spans, Text::Lines, or Paragraphs).
88
+
89
+ ##
90
+ # :attr_reader: flex
91
+ # Flex mode for column distribution.
92
+
93
+ ##
94
+ # :attr_reader: style
95
+ # Base style for the entire table.
96
+
97
+ ##
98
+ # :attr_reader: column_spacing
99
+ # Spacing between columns (Integer, default 1).
100
+
101
+ # Creates a new Table.
102
+ #
103
+ # [header] Array of strings, Text::Spans, Text::Lines, or paragraphs.
104
+ # [rows] 2D Array where each cell is String, Text::Span, Text::Line, Paragraph, or Cell.
105
+ # [widths] Array of Constraints.
106
+ # [row_highlight_style] Style object.
107
+ # [highlight_symbol] String.
108
+ # [highlight_spacing] Symbol (optional, default: <tt>:when_selected</tt>).
109
+ # [column_highlight_style] Style object.
110
+ # [cell_highlight_style] Style object.
111
+ # [selected_row] Integer (nullable).
112
+ # [selected_column] Integer (nullable).
113
+ # [offset] Numeric (nullable, coerced to Integer). Forces scroll position when set.
114
+ # [block] Block (optional).
115
+ # [footer] Array of strings/paragraphs (optional).
116
+ # [flex] Symbol (optional, default: <tt>:legacy</tt>).
117
+ # [style] Style object or Hash (optional).
118
+ # [column_spacing] Integer (optional, default: 1).
119
+ 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)
120
+ super(
121
+ header:,
122
+ rows:,
123
+ widths:,
124
+ row_highlight_style:,
125
+ highlight_symbol:,
126
+ highlight_spacing:,
127
+ column_highlight_style:,
128
+ cell_highlight_style:,
129
+ selected_row: selected_row.nil? ? nil : Integer(selected_row),
130
+ selected_column: selected_column.nil? ? nil : Integer(selected_column),
131
+ offset: offset.nil? ? nil : Integer(offset),
132
+ block:,
133
+ footer:,
134
+ flex:,
135
+ style:,
136
+ column_spacing: Integer(column_spacing)
137
+ )
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
+ # SPDX-License-Identifier: AGPL-3.0-or-later
5
+
6
+ module RatatuiRuby
7
+ module Widgets
8
+ # Displays a tab bar for navigation.
9
+ #
10
+ # Screen real estate is limited. You cannot show everything at once. Segregating content into views is necessary for complex apps.
11
+ #
12
+ # This widget separates dimensions. It displays a row of titles, indicating which view is active.
13
+ #
14
+ # Use it at the top of your interface to switch between major modes or contexts.
15
+ #
16
+ # {rdoc-image:/doc/images/widget_tabs_demo.png}[link:/examples/widget_tabs_demo/app_rb.html]
17
+ #
18
+ # === Example
19
+ #
20
+ # Run the interactive demo from the terminal:
21
+ #
22
+ # ruby examples/widget_tabs_demo/app.rb
23
+ class Tabs < Data.define(:titles, :selected_index, :block, :divider, :highlight_style, :style, :padding_left, :padding_right)
24
+ ##
25
+ # :attr_reader: titles
26
+ # Tab titles (Array of Strings).
27
+
28
+ ##
29
+ # :attr_reader: selected_index
30
+ # Index of the active tab.
31
+
32
+ ##
33
+ # :attr_reader: block
34
+ # Optional wrapping block.
35
+
36
+ ##
37
+ # :attr_reader: divider
38
+ # Separator string between tabs.
39
+
40
+ ##
41
+ # :attr_reader: highlight_style
42
+ # Style for the selected tab title.
43
+
44
+ ##
45
+ # :attr_reader: style
46
+ # Base style for the tabs area.
47
+
48
+ ##
49
+ # :attr_reader: padding_left
50
+ # Left padding for the tabs area (Integer, default: 0).
51
+
52
+ ##
53
+ # :attr_reader: padding_right
54
+ # Right padding for the tabs area (Integer, default: 0).
55
+
56
+ # Creates a new Tabs widget.
57
+ #
58
+ # [titles] Array of Strings/Lines.
59
+ # [selected_index] Integer (default: 0).
60
+ # [block] Block (optional).
61
+ # [divider] String (optional).
62
+ # [highlight_style] Style (optional).
63
+ # [style] Style (optional).
64
+ # [padding_left] Integer (default: 0).
65
+ # [padding_right] Integer (default: 0).
66
+ def initialize(titles: [], selected_index: 0, block: nil, divider: nil, highlight_style: nil, style: nil, padding_left: 0, padding_right: 0)
67
+ super(
68
+ titles:,
69
+ selected_index: Integer(selected_index),
70
+ block:,
71
+ divider:,
72
+ highlight_style:,
73
+ style:,
74
+ padding_left: Integer(padding_left),
75
+ padding_right: Integer(padding_right)
76
+ )
77
+ end
78
+
79
+ # Returns the total width of the tabs.
80
+ def width
81
+ RatatuiRuby._tabs_width(self)
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
+ # SPDX-License-Identifier: AGPL-3.0-or-later
5
+
6
+ module RatatuiRuby
7
+ # Widget classes for building terminal UIs.
8
+ #
9
+ # This module mirrors +ratatui::widgets+ and contains all renderable
10
+ # widget types: Block, Paragraph, List, Table, Gauge, Chart, etc.
11
+ module Widgets
12
+ end
13
+ end
14
+
15
+ # Core widgets
16
+ require_relative "widgets/block"
17
+ require_relative "widgets/paragraph"
18
+ require_relative "widgets/list"
19
+ require_relative "widgets/list_item"
20
+ require_relative "widgets/table"
21
+ require_relative "widgets/row"
22
+ require_relative "widgets/cell"
23
+ require_relative "widgets/tabs"
24
+ require_relative "widgets/gauge"
25
+ require_relative "widgets/line_gauge"
26
+ require_relative "widgets/sparkline"
27
+ require_relative "widgets/bar_chart"
28
+ require_relative "widgets/bar_chart/bar"
29
+ require_relative "widgets/bar_chart/bar_group"
30
+ require_relative "widgets/chart"
31
+ require_relative "widgets/scrollbar"
32
+ require_relative "widgets/calendar"
33
+ require_relative "widgets/canvas"
34
+ require_relative "widgets/clear"
35
+ require_relative "widgets/cursor"
36
+ require_relative "widgets/overlay"
37
+ require_relative "widgets/center"
38
+ require_relative "widgets/ratatui_logo"
39
+ require_relative "widgets/ratatui_mascot"
40
+ require_relative "widgets/shape/label"
data/lib/ratatui_ruby.rb CHANGED
@@ -4,42 +4,27 @@
4
4
  # SPDX-License-Identifier: AGPL-3.0-or-later
5
5
 
6
6
  require_relative "ratatui_ruby/version"
7
- require_relative "ratatui_ruby/schema/rect"
8
- require_relative "ratatui_ruby/schema/paragraph"
9
- require_relative "ratatui_ruby/schema/layout"
10
- require_relative "ratatui_ruby/schema/block"
11
- require_relative "ratatui_ruby/schema/constraint"
12
- require_relative "ratatui_ruby/schema/list"
13
- require_relative "ratatui_ruby/schema/list_item"
14
- require_relative "ratatui_ruby/schema/style"
15
- require_relative "ratatui_ruby/schema/gauge"
16
- require_relative "ratatui_ruby/schema/line_gauge"
17
- require_relative "ratatui_ruby/schema/table"
18
- require_relative "ratatui_ruby/schema/tabs"
19
- require_relative "ratatui_ruby/schema/bar_chart"
20
- require_relative "ratatui_ruby/schema/bar_chart/bar"
21
- require_relative "ratatui_ruby/schema/bar_chart/bar_group"
22
- require_relative "ratatui_ruby/schema/sparkline"
23
- require_relative "ratatui_ruby/schema/chart"
24
- require_relative "ratatui_ruby/schema/clear"
25
- require_relative "ratatui_ruby/schema/cursor"
26
- require_relative "ratatui_ruby/schema/overlay"
27
- require_relative "ratatui_ruby/schema/center"
28
- require_relative "ratatui_ruby/schema/scrollbar"
29
- require_relative "ratatui_ruby/schema/canvas"
30
- require_relative "ratatui_ruby/schema/shape/label"
31
- require_relative "ratatui_ruby/schema/calendar"
32
- require_relative "ratatui_ruby/schema/ratatui_logo"
33
- require_relative "ratatui_ruby/schema/ratatui_mascot"
34
- require_relative "ratatui_ruby/schema/text"
35
- require_relative "ratatui_ruby/schema/draw"
7
+
8
+ # New modularized structure (mirrors ratatui Rust crate)
9
+ require_relative "ratatui_ruby/layout" # Layout::Rect, Layout::Constraint, Layout::Layout
10
+ require_relative "ratatui_ruby/style" # Style::Style
11
+ require_relative "ratatui_ruby/widgets" # Widgets::Block, Widgets::Paragraph, etc.
12
+ require_relative "ratatui_ruby/buffer" # Buffer::Cell (for inspection)
13
+ require_relative "ratatui_ruby/schema/text" # Text::Span, Text::Line
14
+ require_relative "ratatui_ruby/schema/draw" # Draw commands
15
+
16
+ # Event types
36
17
  require_relative "ratatui_ruby/event"
37
- require_relative "ratatui_ruby/cell"
18
+
19
+ # Frame and state objects
38
20
  require_relative "ratatui_ruby/frame"
39
21
  require_relative "ratatui_ruby/list_state"
40
22
  require_relative "ratatui_ruby/table_state"
41
23
  require_relative "ratatui_ruby/scrollbar_state"
42
24
 
25
+ # TUI facade (for external instantiation and caching)
26
+ require_relative "ratatui_ruby/tui"
27
+
43
28
  begin
44
29
  require "ratatui_ruby/ratatui_ruby"
45
30
  rescue LoadError
@@ -129,19 +114,19 @@ module RatatuiRuby
129
114
  # pass a block to manipulate the frame directly. The block receives a
130
115
  # {Frame} object for imperative drawing.
131
116
  #
132
- # [tree] A widget tree (Paragraph, Layout, etc.) to render. Optional if
117
+ # [tree] A widget tree (Widgets::Paragraph, Layout::Layout, etc.) to render. Optional if
133
118
  # a block is given.
134
119
  #
135
120
  # === Examples
136
121
  #
137
122
  # Legacy declarative style (tree-based):
138
123
  #
139
- # RatatuiRuby.draw(Paragraph.new(text: "Hello"))
124
+ # RatatuiRuby.draw(Widgets::Paragraph.new(text: "Hello"))
140
125
  #
141
126
  # New imperative style (block-based):
142
127
  #
143
128
  # RatatuiRuby.draw do |frame|
144
- # frame.render_widget(Paragraph.new(text: "Hello"), frame.area)
129
+ # frame.render_widget(Widgets::Paragraph.new(text: "Hello"), frame.area)
145
130
  # end
146
131
  #
147
132
  def self.draw(tree = nil, &block)
@@ -227,7 +212,7 @@ module RatatuiRuby
227
212
  #
228
213
  # Managing generic setup/teardown (raw mode, alternate screen) manualy is error-prone. If your app crashes, the terminal might be left in a broken state.
229
214
  #
230
- # This method handles the safety net. It initializes the terminal, yields a {Session}, and ensures the terminal state is restored even if exceptions occur.
215
+ # This method handles the safety net. It initializes the terminal, yields a {TUI}, and ensures the terminal state is restored even if exceptions occur.
231
216
  #
232
217
  # === Example
233
218
  #
@@ -236,9 +221,8 @@ module RatatuiRuby
236
221
  # sleep 1
237
222
  # end
238
223
  def self.run(focus_events: true, bracketed_paste: true)
239
- require_relative "ratatui_ruby/session"
240
224
  init_terminal(focus_events:, bracketed_paste:)
241
- yield Session.new
225
+ yield TUI.new
242
226
  ensure
243
227
  restore_terminal
244
228
  end
@@ -249,7 +233,7 @@ module RatatuiRuby
249
233
  # When writing tests, you need to verify that your widget drew the correct characters and styles.
250
234
  # This method provides deep inspection of the cell's state (symbol, colors, modifiers).
251
235
  #
252
- # Returns a {Cell} object.
236
+ # Returns a {Buffer::Cell} object.
253
237
  #
254
238
  # Values depend on what the backend has rendered. If nothing has been rendered to a cell, it may contain defaults (empty symbol, nil colors).
255
239
  #
@@ -262,7 +246,7 @@ module RatatuiRuby
262
246
  #
263
247
  def self.get_cell_at(x, y)
264
248
  raw = _get_cell_at(x, y)
265
- Cell.new(
249
+ Buffer::Cell.new(
266
250
  char: raw["char"],
267
251
  fg: raw["fg"],
268
252
  bg: raw["bg"],
@@ -274,5 +258,5 @@ module RatatuiRuby
274
258
  private_class_method :_get_cell_at
275
259
 
276
260
  # Hide native Layout._split helper
277
- Layout.singleton_class.__send__(:private, :_split)
261
+ Layout::Layout.singleton_class.__send__(:private, :_split)
278
262
  end
@@ -3,6 +3,6 @@
3
3
 
4
4
  module View
5
5
  interface _View
6
- def call(state: ViewState, tui: RatatuiRuby::Session, frame: RatatuiRuby::Frame, area: RatatuiRuby::Rect) -> void
6
+ def call(state: ViewState, tui: RatatuiRuby::TUI, frame: RatatuiRuby::Frame, area: RatatuiRuby::Rect) -> void
7
7
  end
8
8
  end
@@ -10,6 +10,6 @@ class ViewState < Data
10
10
  attr_reader border_color: Symbol
11
11
  attr_reader area: RatatuiRuby::Rect?
12
12
 
13
- def self.build(events: Events, focused: bool, tui: RatatuiRuby::Session, _resize_sub_counter: untyped) -> instance
13
+ def self.build(events: Events, focused: bool, tui: RatatuiRuby::TUI, _resize_sub_counter: untyped) -> instance
14
14
  def self.new: (?events: Events, ?focused: bool, ?hotkey_style: RatatuiRuby::Style, ?dimmed_style: RatatuiRuby::Style, ?lit_style: RatatuiRuby::Style, ?border_color: Symbol, ?area: RatatuiRuby::Rect | nil) -> instance
15
15
  end
@@ -0,0 +1,22 @@
1
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ module RatatuiRuby
5
+ class Row < Data
6
+ type cell_content = String | Text::Span | Text::Line | Paragraph | Cell
7
+
8
+ attr_reader cells: Array[cell_content]
9
+ attr_reader style: Style?
10
+ attr_reader height: Integer?
11
+ attr_reader top_margin: Integer?
12
+ attr_reader bottom_margin: Integer?
13
+
14
+ def self.new: (
15
+ cells: Array[cell_content],
16
+ ?style: Style?,
17
+ ?height: Integer?,
18
+ ?top_margin: Integer?,
19
+ ?bottom_margin: Integer?
20
+ ) -> Row
21
+ end
22
+ end
@@ -16,7 +16,7 @@ module RatatuiRuby
16
16
  attr_reader selected_column: Integer?
17
17
  attr_reader offset: Integer?
18
18
 
19
- def self.new: (?header: Array[String | Paragraph]?, ?rows: Array[Array[String | Paragraph | Style | _ToS]], ?widths: Array[Constraint], ?highlight_style: Style?, ?highlight_symbol: String, ?highlight_spacing: Symbol, ?column_highlight_style: Style?, ?cell_highlight_style: Style?, ?selected_row: Numeric?, ?selected_column: Numeric?, ?offset: Numeric?, ?block: Block?, ?footer: Array[String | Paragraph]?, ?flex: Symbol, ?style: (Style | Hash[Symbol, untyped])?, ?column_spacing: Numeric) -> Table
19
+ def self.new: (?header: Array[String | Paragraph]?, ?rows: Array[Array[String | Paragraph | Style | _ToS]], ?widths: Array[Constraint], ?row_highlight_style: Style?, ?highlight_symbol: String, ?highlight_spacing: Symbol, ?column_highlight_style: Style?, ?cell_highlight_style: Style?, ?selected_row: Numeric?, ?selected_column: Numeric?, ?offset: Numeric?, ?block: Block?, ?footer: Array[String | Paragraph]?, ?flex: Symbol, ?style: (Style | Hash[Symbol, untyped])?, ?column_spacing: Numeric) -> Table
20
20
  end
21
21
  end
22
22
 
@@ -17,6 +17,7 @@ module RatatuiRuby
17
17
 
18
18
  def initialize: (spans: Array[Span], alignment: Symbol | nil) -> void
19
19
  def self.from_string: (String, alignment: Symbol | nil) -> Line
20
+ def width: () -> Integer
20
21
  end
21
22
 
22
23
  def self.width: (String) -> Integer
@@ -29,30 +29,6 @@ module RatatuiRuby
29
29
  def restore_terminal: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
30
30
  def run: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
31
31
  def warn_experimental_feature: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
32
- def axis: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
33
- def bar_chart: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
34
- def bar_chart_bar: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
35
- def bar_chart_bar_group: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
36
- def block: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
37
- def calendar: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
38
- def canvas: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
39
- def cell: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
40
- def cell_char: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
41
- def cell_default: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
42
- def cell_empty: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
43
- def cell_symbol: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
44
- def center: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
45
- def chart: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
46
- def clear: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
47
- def constraint: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
48
- def constraint_fill: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
49
- def constraint_length: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
50
- def constraint_max: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
51
- def constraint_min: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
52
- def constraint_percentage: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
53
- def constraint_ratio: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
54
- def cursor: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
55
- def dataset: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
56
32
  def draw_cell: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
57
33
  def draw_string: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
58
34
  def draw_cell_cmd: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
@@ -69,39 +45,43 @@ module RatatuiRuby
69
45
  def event_paste: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
70
46
  def event_resize: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
71
47
  def frame: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
72
- def gauge: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
73
- def layout: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
74
- def layout_split: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
75
- def line_chart: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
76
- def line_gauge: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
77
- def list: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
78
- def list_item: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
48
+ def layout_constraint: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
49
+ def layout_layout: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
50
+ def layout_rect: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
79
51
  def list_state: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
80
52
  def list_state_new: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
81
- def overlay: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
82
- def paragraph: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
83
- def paragraph_new: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
84
- def ratatui_logo: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
85
- def ratatui_mascot: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
86
- def rect: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
87
- def scrollbar: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
88
53
  def scrollbar_state: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
89
54
  def scrollbar_state_new: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
90
- def shape_circle: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
91
- def shape_label: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
92
- def shape_line: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
93
- def shape_map: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
94
- def shape_point: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
95
- def shape_rectangle: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
96
- def sparkline: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
97
- def style: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
98
- def style_default: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
99
- def table: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
55
+ def style_style: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
100
56
  def table_state: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
101
57
  def table_state_new: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
102
- def tabs: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
103
58
  def text_width: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
104
59
  def text_line: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
105
60
  def text_span: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
61
+ def widgets_axis: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
62
+ def widgets_bar_chart: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
63
+ def widgets_block: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
64
+ def widgets_calendar: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
65
+ def widgets_canvas: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
66
+ def widgets_cell: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
67
+ def widgets_center: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
68
+ def widgets_chart: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
69
+ def widgets_clear: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
70
+ def widgets_cursor: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
71
+ def widgets_dataset: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
72
+ def widgets_gauge: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
73
+ def widgets_line_chart: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
74
+ def widgets_line_gauge: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
75
+ def widgets_list: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
76
+ def widgets_list_item: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
77
+ def widgets_overlay: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
78
+ def widgets_paragraph: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
79
+ def widgets_ratatui_logo: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
80
+ def widgets_ratatui_mascot: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
81
+ def widgets_row: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
82
+ def widgets_scrollbar: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
83
+ def widgets_sparkline: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
84
+ def widgets_table: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
85
+ def widgets_tabs: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped
106
86
  end
107
87
  end
@@ -0,0 +1,10 @@
1
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ module RatatuiRuby
5
+ class TUI
6
+ module BufferFactories
7
+ def cell: (?char: String?, ?fg: Symbol?, ?bg: Symbol?, ?modifiers: Array[Symbol]?) -> Buffer::Cell
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,14 @@
1
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ module RatatuiRuby
5
+ class TUI
6
+ module CanvasFactories
7
+ def shape_map: (**top) -> Widgets::Shape::Map
8
+ def shape_line: (**top) -> Widgets::Shape::Line
9
+ def shape_point: (**top) -> Widgets::Shape::Point
10
+ def shape_circle: (**top) -> Widgets::Shape::Circle
11
+ def shape_rectangle: (**top) -> Widgets::Shape::Rectangle
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ module RatatuiRuby
5
+ class TUI
6
+ module Core
7
+ def draw: (?Widgets::_Widget? tree) -> void
8
+ | () { (Frame) -> void } -> void
9
+ def poll_event: (?timeout: Float) -> Event::event
10
+ def get_cell_at: (Integer x, Integer y) -> Buffer::Cell
11
+ def draw_cell: (Integer x, Integer y, Buffer::Cell cell) -> Draw::CellCmd
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,19 @@
1
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ module RatatuiRuby
5
+ class TUI
6
+ module LayoutFactories
7
+ def rect: (?x: Integer, ?y: Integer, ?width: Integer, ?height: Integer) -> Layout::Rect
8
+ def constraint: (**top) -> Layout::Constraint
9
+ def constraint_length: (Integer n) -> Layout::Constraint
10
+ def constraint_percentage: (Integer n) -> Layout::Constraint
11
+ def constraint_min: (Integer n) -> Layout::Constraint
12
+ def constraint_max: (Integer n) -> Layout::Constraint
13
+ def constraint_fill: (?Integer n) -> Layout::Constraint
14
+ def constraint_ratio: (Integer numerator, Integer denominator) -> Layout::Constraint
15
+ def layout: (**top) -> Layout::Layout
16
+ def layout_split: (Layout::Rect area, ?direction: Symbol, constraints: Array[Layout::Constraint], ?flex: Symbol) -> Array[Layout::Rect]
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ module RatatuiRuby
5
+ class TUI
6
+ module StateFactories
7
+ def list_state: (**top) -> ListState
8
+ def table_state: (**top) -> TableState
9
+ def scrollbar_state: (**top) -> ScrollbarState
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ module RatatuiRuby
5
+ class TUI
6
+ module StyleFactories
7
+ def style: (?fg: Symbol?, ?bg: Symbol?, ?modifiers: Array[Symbol]?) -> Style::Style
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,14 @@
1
+ # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
+ # SPDX-License-Identifier: AGPL-3.0-or-later
3
+
4
+ module RatatuiRuby
5
+ class TUI
6
+ module TextFactories
7
+ def text_span: (?content: String, ?style: Style::Style?) -> Text::Span
8
+ def span: (?content: String, ?style: Style::Style?) -> Text::Span
9
+ def text_line: (?spans: Array[Text::Span], ?alignment: Symbol?) -> Text::Line
10
+ def line: (?spans: Array[Text::Span], ?alignment: Symbol?) -> Text::Line
11
+ def text_width: (String string) -> Integer
12
+ end
13
+ end
14
+ end