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.
- checksums.yaml +4 -4
- data/.builds/ruby-3.2.yml +1 -1
- data/.builds/ruby-3.3.yml +1 -1
- data/.builds/ruby-3.4.yml +1 -1
- data/.builds/ruby-4.0.0.yml +1 -1
- data/AGENTS.md +2 -1
- data/CHANGELOG.md +122 -0
- data/REUSE.toml +5 -0
- data/Rakefile +1 -1
- data/Steepfile +49 -0
- data/doc/concepts/debugging.md +401 -0
- data/doc/getting_started/quickstart.md +8 -3
- data/doc/images/app_all_events.png +0 -0
- data/doc/images/app_color_picker.png +0 -0
- data/doc/images/app_debugging_showcase.gif +0 -0
- data/doc/images/app_debugging_showcase.png +0 -0
- data/doc/images/app_login_form.png +0 -0
- data/doc/images/app_stateful_interaction.png +0 -0
- data/doc/images/verify_quickstart_dsl.png +0 -0
- data/doc/images/verify_quickstart_layout.png +0 -0
- data/doc/images/verify_quickstart_lifecycle.png +0 -0
- data/doc/images/verify_readme_usage.png +0 -0
- data/doc/images/widget_barchart.png +0 -0
- data/doc/images/widget_block.png +0 -0
- data/doc/images/widget_box.png +0 -0
- data/doc/images/widget_calendar.png +0 -0
- data/doc/images/widget_canvas.png +0 -0
- data/doc/images/widget_cell.png +0 -0
- data/doc/images/widget_center.png +0 -0
- data/doc/images/widget_chart.png +0 -0
- data/doc/images/widget_gauge.png +0 -0
- data/doc/images/widget_layout_split.png +0 -0
- data/doc/images/widget_line_gauge.png +0 -0
- data/doc/images/widget_list.png +0 -0
- data/doc/images/widget_map.png +0 -0
- data/doc/images/widget_overlay.png +0 -0
- data/doc/images/widget_popup.png +0 -0
- data/doc/images/widget_ratatui_logo.png +0 -0
- data/doc/images/widget_ratatui_mascot.png +0 -0
- data/doc/images/widget_rect.png +0 -0
- data/doc/images/widget_render.png +0 -0
- data/doc/images/widget_rich_text.png +0 -0
- data/doc/images/widget_scroll_text.png +0 -0
- data/doc/images/widget_scrollbar.png +0 -0
- data/doc/images/widget_sparkline.png +0 -0
- data/doc/images/widget_style_colors.png +0 -0
- data/doc/images/widget_table.png +0 -0
- data/doc/images/widget_tabs.png +0 -0
- data/doc/images/widget_text_width.png +0 -0
- data/doc/troubleshooting/async.md +4 -0
- data/examples/app_debugging_showcase/README.md +119 -0
- data/examples/app_debugging_showcase/app.rb +318 -0
- data/examples/widget_canvas/app.rb +19 -14
- data/examples/widget_gauge/app.rb +18 -3
- data/examples/widget_layout_split/app.rb +16 -4
- data/examples/widget_list/app.rb +22 -6
- data/examples/widget_rect/app.rb +7 -6
- data/examples/widget_rich_text/app.rb +62 -37
- data/examples/widget_style_colors/app.rb +26 -47
- data/examples/widget_table/app.rb +28 -5
- data/examples/widget_text_width/app.rb +6 -4
- data/ext/ratatui_ruby/Cargo.lock +48 -1
- data/ext/ratatui_ruby/Cargo.toml +6 -2
- data/ext/ratatui_ruby/src/color.rs +82 -0
- data/ext/ratatui_ruby/src/errors.rs +28 -0
- data/ext/ratatui_ruby/src/events.rs +16 -14
- data/ext/ratatui_ruby/src/lib.rs +56 -0
- data/ext/ratatui_ruby/src/rendering.rs +3 -1
- data/ext/ratatui_ruby/src/style.rs +48 -21
- data/ext/ratatui_ruby/src/terminal.rs +40 -9
- data/ext/ratatui_ruby/src/text.rs +21 -9
- data/ext/ratatui_ruby/src/widgets/chart.rs +2 -1
- data/ext/ratatui_ruby/src/widgets/layout.rs +90 -2
- data/ext/ratatui_ruby/src/widgets/list.rs +6 -5
- data/ext/ratatui_ruby/src/widgets/overlay.rs +2 -1
- data/ext/ratatui_ruby/src/widgets/table.rs +7 -6
- data/ext/ratatui_ruby/src/widgets/table_state.rs +55 -0
- data/ext/ratatui_ruby/src/widgets/tabs.rs +3 -2
- data/lib/ratatui_ruby/buffer/cell.rb +25 -15
- data/lib/ratatui_ruby/buffer.rb +134 -2
- data/lib/ratatui_ruby/cell.rb +13 -5
- data/lib/ratatui_ruby/debug.rb +215 -0
- data/lib/ratatui_ruby/event/key.rb +3 -2
- data/lib/ratatui_ruby/event/sync.rb +52 -0
- data/lib/ratatui_ruby/event.rb +7 -1
- data/lib/ratatui_ruby/layout/constraint.rb +184 -0
- data/lib/ratatui_ruby/layout/layout.rb +119 -13
- data/lib/ratatui_ruby/layout/position.rb +55 -0
- data/lib/ratatui_ruby/layout/rect.rb +188 -0
- data/lib/ratatui_ruby/layout/size.rb +55 -0
- data/lib/ratatui_ruby/layout.rb +4 -0
- data/lib/ratatui_ruby/style/color.rb +149 -0
- data/lib/ratatui_ruby/style/style.rb +51 -4
- data/lib/ratatui_ruby/style.rb +2 -0
- data/lib/ratatui_ruby/symbols.rb +435 -0
- data/lib/ratatui_ruby/synthetic_events.rb +86 -0
- data/lib/ratatui_ruby/table_state.rb +51 -0
- data/lib/ratatui_ruby/terminal_lifecycle.rb +2 -1
- data/lib/ratatui_ruby/test_helper/event_injection.rb +34 -1
- data/lib/ratatui_ruby/test_helper.rb +9 -0
- data/lib/ratatui_ruby/text/line.rb +245 -0
- data/lib/ratatui_ruby/text/span.rb +158 -0
- data/lib/ratatui_ruby/text.rb +99 -0
- data/lib/ratatui_ruby/tui/canvas_factories.rb +103 -0
- data/lib/ratatui_ruby/tui/core.rb +13 -2
- data/lib/ratatui_ruby/tui/layout_factories.rb +50 -3
- data/lib/ratatui_ruby/tui/state_factories.rb +42 -0
- data/lib/ratatui_ruby/tui/text_factories.rb +40 -0
- data/lib/ratatui_ruby/tui/widget_factories.rb +135 -60
- data/lib/ratatui_ruby/tui.rb +22 -1
- data/lib/ratatui_ruby/version.rb +1 -1
- data/lib/ratatui_ruby/widgets/bar_chart/bar.rb +2 -0
- data/lib/ratatui_ruby/widgets/bar_chart/bar_group.rb +2 -0
- data/lib/ratatui_ruby/widgets/bar_chart.rb +30 -20
- data/lib/ratatui_ruby/widgets/block.rb +14 -6
- data/lib/ratatui_ruby/widgets/calendar.rb +2 -0
- data/lib/ratatui_ruby/widgets/canvas.rb +56 -0
- data/lib/ratatui_ruby/widgets/cell.rb +2 -0
- data/lib/ratatui_ruby/widgets/center.rb +2 -0
- data/lib/ratatui_ruby/widgets/chart.rb +6 -0
- data/lib/ratatui_ruby/widgets/clear.rb +2 -0
- data/lib/ratatui_ruby/widgets/coerceable_widget.rb +77 -0
- data/lib/ratatui_ruby/widgets/cursor.rb +2 -0
- data/lib/ratatui_ruby/widgets/gauge.rb +61 -3
- data/lib/ratatui_ruby/widgets/line_gauge.rb +66 -4
- data/lib/ratatui_ruby/widgets/list.rb +87 -3
- data/lib/ratatui_ruby/widgets/list_item.rb +2 -0
- data/lib/ratatui_ruby/widgets/overlay.rb +2 -0
- data/lib/ratatui_ruby/widgets/paragraph.rb +4 -0
- data/lib/ratatui_ruby/widgets/ratatui_logo.rb +2 -0
- data/lib/ratatui_ruby/widgets/ratatui_mascot.rb +2 -0
- data/lib/ratatui_ruby/widgets/row.rb +45 -0
- data/lib/ratatui_ruby/widgets/scrollbar.rb +2 -0
- data/lib/ratatui_ruby/widgets/shape/label.rb +2 -0
- data/lib/ratatui_ruby/widgets/sparkline.rb +21 -13
- data/lib/ratatui_ruby/widgets/table.rb +13 -3
- data/lib/ratatui_ruby/widgets/tabs.rb +6 -4
- data/lib/ratatui_ruby/widgets.rb +1 -0
- data/lib/ratatui_ruby.rb +51 -16
- data/sig/examples/app_all_events/model/app_model.rbs +23 -0
- data/sig/examples/app_all_events/model/event_entry.rbs +15 -8
- data/sig/examples/app_all_events/model/timestamp.rbs +1 -1
- data/sig/examples/app_all_events/view.rbs +1 -1
- data/sig/examples/app_stateful_interaction/app.rbs +5 -5
- data/sig/examples/widget_block_demo/app.rbs +6 -6
- data/sig/manifest.yaml +5 -0
- data/sig/patches/data.rbs +26 -0
- data/sig/patches/debugger__.rbs +8 -0
- data/sig/ratatui_ruby/buffer/cell.rbs +46 -0
- data/sig/ratatui_ruby/buffer.rbs +18 -0
- data/sig/ratatui_ruby/cell.rbs +44 -0
- data/sig/ratatui_ruby/clear.rbs +18 -0
- data/sig/ratatui_ruby/constraint.rbs +26 -0
- data/sig/ratatui_ruby/debug.rbs +45 -0
- data/sig/ratatui_ruby/draw.rbs +30 -0
- data/sig/ratatui_ruby/event.rbs +68 -8
- data/sig/ratatui_ruby/frame.rbs +4 -4
- data/sig/ratatui_ruby/interfaces.rbs +25 -0
- data/sig/ratatui_ruby/layout/constraint.rbs +39 -0
- data/sig/ratatui_ruby/layout/layout.rbs +45 -0
- data/sig/ratatui_ruby/layout/position.rbs +18 -0
- data/sig/ratatui_ruby/layout/rect.rbs +64 -0
- data/sig/ratatui_ruby/layout/size.rbs +18 -0
- data/sig/ratatui_ruby/output_guard.rbs +23 -0
- data/sig/ratatui_ruby/ratatui_ruby.rbs +83 -4
- data/sig/ratatui_ruby/rect.rbs +17 -0
- data/sig/ratatui_ruby/style/color.rbs +22 -0
- data/sig/ratatui_ruby/style/style.rbs +29 -0
- data/sig/ratatui_ruby/symbols.rbs +141 -0
- data/sig/ratatui_ruby/synthetic_events.rbs +21 -0
- data/sig/ratatui_ruby/table_state.rbs +6 -0
- data/sig/ratatui_ruby/terminal_lifecycle.rbs +31 -0
- data/sig/ratatui_ruby/test_helper/event_injection.rbs +2 -2
- data/sig/ratatui_ruby/test_helper/snapshot.rbs +22 -3
- data/sig/ratatui_ruby/test_helper/style_assertions.rbs +8 -1
- data/sig/ratatui_ruby/test_helper/test_doubles.rbs +7 -3
- data/sig/ratatui_ruby/text/line.rbs +27 -0
- data/sig/ratatui_ruby/text/span.rbs +23 -0
- data/sig/ratatui_ruby/text.rbs +12 -0
- data/sig/ratatui_ruby/tui/buffer_factories.rbs +1 -1
- data/sig/ratatui_ruby/tui/canvas_factories.rbs +23 -5
- data/sig/ratatui_ruby/tui/core.rbs +2 -2
- data/sig/ratatui_ruby/tui/layout_factories.rbs +16 -2
- data/sig/ratatui_ruby/tui/state_factories.rbs +8 -3
- data/sig/ratatui_ruby/tui/style_factories.rbs +3 -1
- data/sig/ratatui_ruby/tui/text_factories.rbs +7 -4
- data/sig/ratatui_ruby/tui/widget_factories.rbs +123 -30
- data/sig/ratatui_ruby/widgets/bar_chart.rbs +95 -0
- data/sig/ratatui_ruby/widgets/block.rbs +51 -0
- data/sig/ratatui_ruby/widgets/calendar.rbs +45 -0
- data/sig/ratatui_ruby/widgets/canvas.rbs +95 -0
- data/sig/ratatui_ruby/widgets/chart.rbs +91 -0
- data/sig/ratatui_ruby/widgets/coerceable_widget.rbs +26 -0
- data/sig/ratatui_ruby/widgets/gauge.rbs +44 -0
- data/sig/ratatui_ruby/widgets/line_gauge.rbs +48 -0
- data/sig/ratatui_ruby/widgets/list.rbs +63 -0
- data/sig/ratatui_ruby/widgets/misc.rbs +158 -0
- data/sig/ratatui_ruby/widgets/paragraph.rbs +45 -0
- data/sig/ratatui_ruby/widgets/row.rbs +43 -0
- data/sig/ratatui_ruby/widgets/scrollbar.rbs +53 -0
- data/sig/ratatui_ruby/widgets/shape/label.rbs +37 -0
- data/sig/ratatui_ruby/widgets/sparkline.rbs +45 -0
- data/sig/ratatui_ruby/widgets/table.rbs +78 -0
- data/sig/ratatui_ruby/widgets/tabs.rbs +44 -0
- data/sig/ratatui_ruby/{schema/list_item.rbs → widgets.rbs} +4 -4
- data/tasks/steep.rake +11 -0
- metadata +82 -63
- data/doc/contributors/v1.0.0_blockers.md +0 -876
- data/doc/troubleshooting/debugging.md +0 -101
- data/lib/ratatui_ruby/schema/bar_chart/bar.rb +0 -47
- data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +0 -25
- data/lib/ratatui_ruby/schema/bar_chart.rb +0 -287
- data/lib/ratatui_ruby/schema/block.rb +0 -198
- data/lib/ratatui_ruby/schema/calendar.rb +0 -84
- data/lib/ratatui_ruby/schema/canvas.rb +0 -239
- data/lib/ratatui_ruby/schema/center.rb +0 -67
- data/lib/ratatui_ruby/schema/chart.rb +0 -159
- data/lib/ratatui_ruby/schema/clear.rb +0 -62
- data/lib/ratatui_ruby/schema/constraint.rb +0 -151
- data/lib/ratatui_ruby/schema/cursor.rb +0 -50
- data/lib/ratatui_ruby/schema/gauge.rb +0 -72
- data/lib/ratatui_ruby/schema/layout.rb +0 -122
- data/lib/ratatui_ruby/schema/line_gauge.rb +0 -80
- data/lib/ratatui_ruby/schema/list.rb +0 -135
- data/lib/ratatui_ruby/schema/list_item.rb +0 -51
- data/lib/ratatui_ruby/schema/overlay.rb +0 -51
- data/lib/ratatui_ruby/schema/paragraph.rb +0 -107
- data/lib/ratatui_ruby/schema/ratatui_logo.rb +0 -31
- data/lib/ratatui_ruby/schema/ratatui_mascot.rb +0 -36
- data/lib/ratatui_ruby/schema/rect.rb +0 -174
- data/lib/ratatui_ruby/schema/row.rb +0 -76
- data/lib/ratatui_ruby/schema/scrollbar.rb +0 -143
- data/lib/ratatui_ruby/schema/shape/label.rb +0 -76
- data/lib/ratatui_ruby/schema/sparkline.rb +0 -142
- data/lib/ratatui_ruby/schema/style.rb +0 -97
- data/lib/ratatui_ruby/schema/table.rb +0 -141
- data/lib/ratatui_ruby/schema/tabs.rb +0 -85
- data/lib/ratatui_ruby/schema/text.rb +0 -217
- data/sig/examples/app_all_events/model/events.rbs +0 -15
- data/sig/examples/app_all_events/view_state.rbs +0 -21
- data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +0 -22
- data/sig/ratatui_ruby/schema/bar_chart/bar_group.rbs +0 -19
- data/sig/ratatui_ruby/schema/bar_chart.rbs +0 -38
- data/sig/ratatui_ruby/schema/block.rbs +0 -18
- data/sig/ratatui_ruby/schema/calendar.rbs +0 -23
- data/sig/ratatui_ruby/schema/canvas.rbs +0 -81
- data/sig/ratatui_ruby/schema/center.rbs +0 -17
- data/sig/ratatui_ruby/schema/chart.rbs +0 -39
- data/sig/ratatui_ruby/schema/constraint.rbs +0 -22
- data/sig/ratatui_ruby/schema/cursor.rbs +0 -16
- data/sig/ratatui_ruby/schema/draw.rbs +0 -33
- data/sig/ratatui_ruby/schema/gauge.rbs +0 -23
- data/sig/ratatui_ruby/schema/layout.rbs +0 -27
- data/sig/ratatui_ruby/schema/line_gauge.rbs +0 -24
- data/sig/ratatui_ruby/schema/list.rbs +0 -28
- data/sig/ratatui_ruby/schema/overlay.rbs +0 -15
- data/sig/ratatui_ruby/schema/paragraph.rbs +0 -20
- data/sig/ratatui_ruby/schema/ratatui_logo.rbs +0 -14
- data/sig/ratatui_ruby/schema/ratatui_mascot.rbs +0 -17
- data/sig/ratatui_ruby/schema/rect.rbs +0 -48
- data/sig/ratatui_ruby/schema/row.rbs +0 -28
- data/sig/ratatui_ruby/schema/scrollbar.rbs +0 -42
- data/sig/ratatui_ruby/schema/sparkline.rbs +0 -22
- data/sig/ratatui_ruby/schema/style.rbs +0 -19
- data/sig/ratatui_ruby/schema/table.rbs +0 -32
- data/sig/ratatui_ruby/schema/tabs.rbs +0 -21
- data/sig/ratatui_ruby/schema/text.rbs +0 -31
- /data/lib/ratatui_ruby/{schema/draw.rb → draw.rb} +0 -0
|
@@ -1,876 +0,0 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
-
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
-
-->
|
|
5
|
-
|
|
6
|
-
# alignment_audit
|
|
7
|
-
## Legacy Migrations
|
|
8
|
-
|
|
9
|
-
### Outstanding
|
|
10
|
-
|
|
11
|
-
- Migrate away from `schema/` folder structure as mentioned in ruby_frontend.md
|
|
12
|
-
|
|
13
|
-
## alignment_audit
|
|
14
|
-
- Symbol Sets
|
|
15
|
-
- line::Set, block::Set, scrollbar::Set
|
|
16
|
-
- Layout
|
|
17
|
-
- Constraint batch constructors (6)
|
|
18
|
-
- Layout margin, spacing (2)
|
|
19
|
-
- Style
|
|
20
|
-
- sub_modifier, underline_color (2)
|
|
21
|
-
- Text
|
|
22
|
-
- Span methods (4)
|
|
23
|
-
- Line methods (6)
|
|
24
|
-
|
|
25
|
-
### alignment_audit_granular_level
|
|
26
|
-
##### v0.7.0 Alignment Audit (Parameter-Level)
|
|
27
|
-
|
|
28
|
-
This document audits alignment between RatatuiRuby v0.7.0 and the upstream Ratatui/Crossterm Rust libraries at the **parameter and enum value level**. Only gaps are listed.
|
|
29
|
-
|
|
30
|
-
---
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
###### MISSING — Layout Module
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
###### `Layout::Constraint` — Missing Batch Constructors
|
|
38
|
-
|
|
39
|
-
| Missing Method | Signature |
|
|
40
|
-
|----------------|-----------|
|
|
41
|
-
| `from_lengths` | `Constraint.from_lengths([10, 20, 30])` → `[Constraint]` |
|
|
42
|
-
| `from_percentages` | `Constraint.from_percentages([25, 50, 25])` → `[Constraint]` |
|
|
43
|
-
| `from_mins` | `Constraint.from_mins([5, 10, 15])` → `[Constraint]` |
|
|
44
|
-
| `from_maxes` | `Constraint.from_maxes([20, 30, 40])` → `[Constraint]` |
|
|
45
|
-
| `from_fills` | `Constraint.from_fills([1, 2, 1])` → `[Constraint]` |
|
|
46
|
-
| `from_ratios` | `Constraint.from_ratios([[1,4], [2,4], [1,4]])` → `[Constraint]` |
|
|
47
|
-
|
|
48
|
-
---
|
|
49
|
-
|
|
50
|
-
###### `Layout::Layout` — Missing Parameters
|
|
51
|
-
|
|
52
|
-
| Missing Parameter | Ratatui Type | Notes |
|
|
53
|
-
|-------------------|--------------|-------|
|
|
54
|
-
| `margin` | `Margin { horizontal, vertical }` | Edge margins |
|
|
55
|
-
| `spacing` | `u16` | Gap between segments |
|
|
56
|
-
|
|
57
|
-
---
|
|
58
|
-
|
|
59
|
-
###### MISSING — Style Module
|
|
60
|
-
|
|
61
|
-
###### `Style::Style` — Missing Parameters/Methods
|
|
62
|
-
|
|
63
|
-
###### MISSING — Text Module
|
|
64
|
-
|
|
65
|
-
###### `Text::Span` — Missing Methods
|
|
66
|
-
|
|
67
|
-
| Missing Method | Signature | Notes |
|
|
68
|
-
|----------------|-----------|-------|
|
|
69
|
-
| `width` | `span.width` → `Integer` | Display width in terminal cells |
|
|
70
|
-
| `raw` | `Span.raw(content)` → `Span` | Constructor without style (alias for `new(content:)`) |
|
|
71
|
-
| `patch_style` | `span.patch_style(style)` → `Span` | Merge style on top of existing |
|
|
72
|
-
| `reset_style` | `span.reset_style` → `Span` | Clear style |
|
|
73
|
-
|
|
74
|
-
---
|
|
75
|
-
|
|
76
|
-
###### `Text::Line` — Missing Methods
|
|
77
|
-
|
|
78
|
-
| Missing Method | Signature | Notes |
|
|
79
|
-
|----------------|-----------|-------|
|
|
80
|
-
| `left_aligned` | `line.left_aligned` → `Line` | Fluent setter for `:left` alignment |
|
|
81
|
-
| `centered` | `line.centered` → `Line` | Fluent setter for `:center` alignment |
|
|
82
|
-
| `right_aligned` | `line.right_aligned` → `Line` | Fluent setter for `:right` alignment |
|
|
83
|
-
| `push_span` | `line.push_span(span)` → `Line` | Append span |
|
|
84
|
-
| `patch_style` | `line.patch_style(style)` → `Line` | Merge style on all spans |
|
|
85
|
-
| `reset_style` | `line.reset_style` → `Line` | Clear style on all spans |
|
|
86
|
-
|
|
87
|
-
---
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
###### `Widgets::Table` — Missing Row Methods (via `Widgets::Row`)
|
|
92
|
-
|
|
93
|
-
| Missing | Ratatui API | Notes |
|
|
94
|
-
|---------|-------------|-------|
|
|
95
|
-
| `enable_strikethrough` | `row.enable_strikethrough()` | Enable strikethrough on row |
|
|
96
|
-
|
|
97
|
-
---
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
###### Widget Computation Methods — Missing
|
|
102
|
-
|
|
103
|
-
These are public `&self` methods on upstream widgets that compute/query values without rendering.
|
|
104
|
-
|
|
105
|
-
| Widget | Missing Method | Ratatui API | Notes |
|
|
106
|
-
|--------|----------------|-------------|-------|
|
|
107
|
-
|
|
108
|
-
| `List` | `len` | `list.len()` → `usize` | Number of items in the list |
|
|
109
|
-
| `List` | `is_empty` | `list.is_empty()` → `bool` | True if no items (`empty?` in Ruby) |
|
|
110
|
-
| `Canvas` | `get_point` | `canvas.get_point(x, y)` → `Option<(usize, usize)>` | Map coordinates to grid cell |
|
|
111
|
-
|
|
112
|
-
> [!NOTE]
|
|
113
|
-
> `Paragraph#line_count(width)` and `Paragraph#line_width` ARE exposed ✓
|
|
114
|
-
> `Tabs#width` IS exposed ✓
|
|
115
|
-
|
|
116
|
-
---
|
|
117
|
-
|
|
118
|
-
###### State Navigation Methods — Missing
|
|
119
|
-
|
|
120
|
-
TableState has navigation helpers that are not exposed.
|
|
121
|
-
|
|
122
|
-
| State Class | Missing Method | Ratatui API | Notes |
|
|
123
|
-
|-------------|----------------|-------------|-------|
|
|
124
|
-
| `TableState` | `selected_cell` | `state.selected_cell()` | Get (row, col) tuple |
|
|
125
|
-
| `TableState` | `with_selected_cell` | `state.with_selected_cell((r,c))` | Builder pattern |
|
|
126
|
-
| `TableState` | `select_next_column` | `state.select_next_column()` | Navigate columns |
|
|
127
|
-
| `TableState` | `select_previous_column` | `state.select_previous_column()` | Navigate columns |
|
|
128
|
-
| `TableState` | `select_first_column` | `state.select_first_column()` | Jump to first column |
|
|
129
|
-
| `TableState` | `select_last_column` | `state.select_last_column()` | Jump to last column |
|
|
130
|
-
|
|
131
|
-
---
|
|
132
|
-
|
|
133
|
-
###### Layout Module — Additional Missing
|
|
134
|
-
|
|
135
|
-
| Module | Missing | Ratatui API | Notes |
|
|
136
|
-
|--------|---------|-------------|-------|
|
|
137
|
-
| `Rect` | `as_position` | `rect.as_position()` → `Position` | Convert to Position |
|
|
138
|
-
| `Rect` | `as_size` | `rect.as_size()` → `Size` | Convert to Size |
|
|
139
|
-
| `Rect` | `outer` | `rect.outer(margin)` → `Rect` | Expand by margin (inverse of `inner`) |
|
|
140
|
-
| `Rect` | `resize` | `rect.resize(size)` → `Rect` | Change dimensions, preserve position |
|
|
141
|
-
| `Rect` | `centered_horizontally` | `rect.centered_horizontally(constraint)` → `Rect` | Center horizontally via Layout |
|
|
142
|
-
| `Rect` | `centered_vertically` | `rect.centered_vertically(constraint)` → `Rect` | Center vertically via Layout |
|
|
143
|
-
| `Rect` | `centered` | `rect.centered(h, v)` → `Rect` | Center both axes |
|
|
144
|
-
| `Constraint` | `apply` | `constraint.apply(length)` → `u16` | Compute constrained size |
|
|
145
|
-
| `Layout` | `split_with_spacers` | `layout.split_with_spacers(area)` | Returns segments AND spacers |
|
|
146
|
-
|
|
147
|
-
---
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
###### Color — Missing Constructors
|
|
152
|
-
|
|
153
|
-
| Missing | Ratatui API | Notes |
|
|
154
|
-
|---------|-------------|-------|
|
|
155
|
-
| `from_u32` | `Color::from_u32(0xRRGGBB)` | Construct from hex integer |
|
|
156
|
-
| `from_hsl` | `Color::from_hsl(hsl)` | Construct from HSL (requires palette feature) |
|
|
157
|
-
| `from_hsluv` | `Color::from_hsluv(hsluv)` | Construct from HSLuv (requires palette feature) |
|
|
158
|
-
|
|
159
|
-
---
|
|
160
|
-
|
|
161
|
-
###### Buffer — Missing Query Methods
|
|
162
|
-
|
|
163
|
-
| Missing Method | Ratatui API | Notes |
|
|
164
|
-
|----------------|-------------|-------|
|
|
165
|
-
| `content` | `buffer.content()` → `&[Cell]` | Get all cells as slice |
|
|
166
|
-
| `get` | `buffer.get(x, y)` → `&Cell` | Get cell at position |
|
|
167
|
-
| `index_of` | `buffer.index_of(x, y)` → `usize` | Position to linear index |
|
|
168
|
-
| `pos_of` | `buffer.pos_of(i)` → `(u16, u16)` | Linear index to position |
|
|
169
|
-
|
|
170
|
-
---
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
### alignment_audit_high_level
|
|
174
|
-
##### v0.7.0 Alignment Audit
|
|
175
|
-
|
|
176
|
-
This document audits strict alignment between RatatuiRuby v0.7.0 and the upstream Ratatui/Crossterm Rust libraries. The audit covers modules, classes, static methods, and constructor arguments as specified in the [Ruby Frontend Design](../design/ruby_frontend.md#1-ratatui-alignment).
|
|
177
|
-
|
|
178
|
-
> [!NOTE]
|
|
179
|
-
> The TUI facade API is explicitly excluded from this audit. It provides ergonomic shortcuts that intentionally diverge from Ratatui naming.
|
|
180
|
-
|
|
181
|
-
---
|
|
182
|
-
---
|
|
183
|
-
| `margin` | `Margin` | ❌ Missing | Gap |
|
|
184
|
-
| `spacing` | `u16` | ❌ Missing | Gap |
|
|
185
|
-
|
|
186
|
-
**Verdict**: Core layout aligned. Margin and spacing are gaps.
|
|
187
|
-
|
|
188
|
-
---
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
---
|
|
192
|
-
|
|
193
|
-
###### Gaps Analysis: MISSING vs MISALIGNED
|
|
194
|
-
|
|
195
|
-
> [!IMPORTANT]
|
|
196
|
-
> **MISSING** = Can be added as new features without breaking backwards compatibility.
|
|
197
|
-
> **MISALIGNED** = Requires breaking changes before v1.0.0 to fix API shape.
|
|
198
|
-
|
|
199
|
-
###### MISSING Features (Additive, Backwards-Compatible) ✅
|
|
200
|
-
|
|
201
|
-
These are gaps that can be filled in future minor releases without breaking existing code:
|
|
202
|
-
|
|
203
|
-
| Component | Missing Feature | Notes |
|
|
204
|
-
|-----------|-----------------|-------|
|
|
205
|
-
| `Constraint` | `from_lengths()`, `from_percentages()`, etc. | New class methods |
|
|
206
|
-
| `Layout` | `margin`, `spacing` | New optional constructor args |
|
|
207
|
-
| `Style` | `sub_modifier`, `underline_color` | New optional constructor args |
|
|
208
|
-
| `Span` | `width()` instance method | New instance method |
|
|
209
|
-
| `Span` | `raw()` constructor | New class method (alias for `new`) |
|
|
210
|
-
| `Line` | `left_aligned()`, `centered()`, `right_aligned()` | New instance methods (fluent) |
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
### alignment_audit_symbol_sets
|
|
215
|
-
Audit of symbol set alignment between Ratatui's `symbols::` module and RatatuiRuby.
|
|
216
|
-
|
|
217
|
-
> [!IMPORTANT]
|
|
218
|
-
> **MISSING** = Can be added as new features, backwards-compatible.
|
|
219
|
-
> **MISALIGNED** = Requires breaking changes before v1.0.0.
|
|
220
|
-
|
|
221
|
-
| `scrollbar::Set` | 4 predefined sets | ❌ Not exposed | MISSING |
|
|
222
|
-
| `shade` constants | 5 constants | ❌ Not exposed | MISSING |
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
###### MISSING — Marker Enum
|
|
226
|
-
|
|
227
|
-
###### `Marker::HalfBlock`
|
|
228
|
-
|
|
229
|
-
| `Marker::HalfBlock` | ❌ Not exposed | MISSING |
|
|
230
|
-
|
|
231
|
-
**Impact**: Users cannot use the `HalfBlock` marker type, which provides double-resolution square pixels using `█`, `▄`, and `▀` characters.
|
|
232
|
-
|
|
233
|
-
---
|
|
234
|
-
|
|
235
|
-
###### MISSING — Line Set Customization
|
|
236
|
-
|
|
237
|
-
Ratatui provides `symbols::line::Set` with predefined sets:
|
|
238
|
-
- `NORMAL` — Standard box-drawing characters
|
|
239
|
-
- `ROUNDED` — Rounded corners
|
|
240
|
-
- `DOUBLE` — Double-line characters
|
|
241
|
-
- `THICK` — Thick line characters
|
|
242
|
-
|
|
243
|
-
**Ruby Status**: Not directly exposed. Users cannot customize line symbols for widgets that use them internally.
|
|
244
|
-
|
|
245
|
-
---
|
|
246
|
-
|
|
247
|
-
###### MISSING — Bar Set Customization
|
|
248
|
-
|
|
249
|
-
Ratatui provides `symbols::bar::Set` with predefined sets:
|
|
250
|
-
- `THREE_LEVELS` — 3 distinct fill levels
|
|
251
|
-
- `NINE_LEVELS` — 9 distinct fill levels (default)
|
|
252
|
-
|
|
253
|
-
**Ruby Status**: Not exposed. Used internally by widgets like `Sparkline` but not configurable.
|
|
254
|
-
|
|
255
|
-
---
|
|
256
|
-
|
|
257
|
-
###### MISSING — Block Set Customization
|
|
258
|
-
|
|
259
|
-
Ratatui provides `symbols::block::Set` with predefined sets:
|
|
260
|
-
- `THREE_LEVELS` — 3 distinct fill levels
|
|
261
|
-
- `NINE_LEVELS` — 9 distinct fill levels (default)
|
|
262
|
-
|
|
263
|
-
**Ruby Status**: Not exposed. Used internally by `Gauge` widget but not configurable.
|
|
264
|
-
|
|
265
|
-
---
|
|
266
|
-
|
|
267
|
-
###### MISSING — Scrollbar Set Customization
|
|
268
|
-
|
|
269
|
-
Ratatui provides `symbols::scrollbar::Set` with predefined sets:
|
|
270
|
-
- `DOUBLE_VERTICAL` — Double-line vertical scrollbar
|
|
271
|
-
- `DOUBLE_HORIZONTAL` — Double-line horizontal scrollbar
|
|
272
|
-
- `VERTICAL` — Single-line vertical scrollbar
|
|
273
|
-
- `HORIZONTAL` — Single-line horizontal scrollbar
|
|
274
|
-
|
|
275
|
-
**Ruby Status**: Not exposed. Scrollbar widget not currently implemented in RatatuiRuby.
|
|
276
|
-
|
|
277
|
-
---
|
|
278
|
-
|
|
279
|
-
###### MISSING — Shade Constants
|
|
280
|
-
|
|
281
|
-
Ratatui provides `symbols::shade` constants:
|
|
282
|
-
- `EMPTY` — ` ` (space)
|
|
283
|
-
- `LIGHT` — `░`
|
|
284
|
-
- `MEDIUM` — `▒`
|
|
285
|
-
- `DARK` — `▓`
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
---
|
|
289
|
-
|
|
290
|
-
###### Recommendations
|
|
291
|
-
|
|
292
|
-
| Priority | Item | Notes |
|
|
293
|
-
|----------|------|-------|
|
|
294
|
-
| Low | Add `:half_block` marker | Single symbol addition |
|
|
295
|
-
| Low | Expose `line::Set` customization | For LineGauge widget |
|
|
296
|
-
| Low | Expose `bar::Set` customization | For Sparkline widget |
|
|
297
|
-
| Low | Expose `block::Set` customization | For Gauge widget |
|
|
298
|
-
| Medium | Implement Scrollbar widget | Would include scrollbar::Set |
|
|
299
|
-
|
|
300
|
-
All missing items are **additive** and do not require breaking changes.
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
---
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
### alignment_audit_tui_final
|
|
307
|
-
##### TUI API Alignment Audit
|
|
308
|
-
|
|
309
|
-
This document audits the `RatatuiRuby::TUI` facade API for method and parameter naming, with a focus on **Developer Experience (DX)** before the v1.0.0 release.
|
|
310
|
-
|
|
311
|
-
###### Design Philosophy
|
|
312
|
-
|
|
313
|
-
The TUI API follows a "Mullet Architecture": structured namespaces in the library, flat ergonomic DSL for users.
|
|
314
|
-
|
|
315
|
-
**Guiding Principles:**
|
|
316
|
-
|
|
317
|
-
1. **Terseness** — Fewer keystrokes for common operations
|
|
318
|
-
2. **DWIM** — Do What I Mean; intuitive defaults
|
|
319
|
-
3. **TIMTOWTDI** — Multiple valid ways to express the same thing
|
|
320
|
-
4. **Big Tent** — Aliases for CSS/frontend developers, Ratatui natives, and Ruby purists
|
|
321
|
-
5. **Two Levels Max** — `tui.thing` and `tui.scope_thing`, never `tui.scope.thing`, never `tui.ascope_bscope_thing`
|
|
322
|
-
|
|
323
|
-
**Breaking Changes:** Pre-1.0 with few external users. Rename aggressively for DX. Document in CHANGELOG.
|
|
324
|
-
|
|
325
|
-
---
|
|
326
|
-
|
|
327
|
-
###### Method Naming Recommendations
|
|
328
|
-
|
|
329
|
-
###### Pattern: Base Methods + Aliases + Dispatchers
|
|
330
|
-
|
|
331
|
-
Base methods align with Ratatui's module API names. Aliases provide ergonomic shortcuts.
|
|
332
|
-
|
|
333
|
-
1. **Base method** (Ratatui-aligned): `tui.shape_circle(...)` — matches `Widgets::Shape::Circle`
|
|
334
|
-
2. **Aliases** (ergonomic): `tui.circle(...)`, `tui.circle_shape(...)`
|
|
335
|
-
3. **Dispatcher**: `tui.shape(:circle, ...)` — errors helpfully on missing type
|
|
336
|
-
|
|
337
|
-
This pattern applies to: shapes, constraints, text elements.
|
|
338
|
-
|
|
339
|
-
---
|
|
340
|
-
|
|
341
|
-
###### Canvas Shapes
|
|
342
|
-
|
|
343
|
-
| Base Method | Add Aliases | Dispatcher |
|
|
344
|
-
|-------------|-------------|------------|
|
|
345
|
-
| `shape_circle` | `circle`, `circle_shape` | `shape(:circle, ...)` |
|
|
346
|
-
| `shape_line` | `line_shape` *(not bare `line` — conflicts with `Text::Line`)* | `shape(:line, ...)` |
|
|
347
|
-
| `shape_point` | `point`, `point_shape` | `shape(:point, ...)` |
|
|
348
|
-
| `shape_rectangle` | `rectangle`, `rectangle_shape` | `shape(:rectangle, ...)` |
|
|
349
|
-
| `shape_map` | `map`, `map_shape` | `shape(:map, ...)` |
|
|
350
|
-
| `shape_label` | `label`, `label_shape` | `shape(:label, ...)` |
|
|
351
|
-
|
|
352
|
-
**Dispatcher signature:**
|
|
353
|
-
```ruby
|
|
354
|
-
def shape(type, **kwargs)
|
|
355
|
-
case type
|
|
356
|
-
when :circle then shape_circle(**kwargs)
|
|
357
|
-
when :line then shape_line(**kwargs)
|
|
358
|
-
# ...
|
|
359
|
-
else
|
|
360
|
-
raise ArgumentError, "Unknown shape type: #{type.inspect}. " \
|
|
361
|
-
"Valid types: :circle, :line, :point, :rectangle, :map, :label"
|
|
362
|
-
end
|
|
363
|
-
end
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
---
|
|
367
|
-
|
|
368
|
-
###### Layout Constraints
|
|
369
|
-
|
|
370
|
-
Ratatui's constraints map well to CSS layout concepts. Offer aliases for both communities:
|
|
371
|
-
|
|
372
|
-
| Base Method | Add Aliases (CSS-Friendly) | Dispatcher |
|
|
373
|
-
|-------------|---------------------------|------------|
|
|
374
|
-
| `constraint_length(n)` | `fixed(n)`, `length(n)` | `constraint(:length, n)` |
|
|
375
|
-
| `constraint_percentage(n)` | `percent(n)`, `percentage(n)` | `constraint(:percentage, n)` |
|
|
376
|
-
| `constraint_min(n)` | `min(n)`, `min_content(n)` | `constraint(:min, n)` |
|
|
377
|
-
| `constraint_max(n)` | `max(n)`, `max_content(n)` | `constraint(:max, n)` |
|
|
378
|
-
| `constraint_fill(n)` | `fill(n)`, `flex(n)`, `fr(n)` | `constraint(:fill, n)` |
|
|
379
|
-
| `constraint_ratio(a,b)` | `ratio(a,b)`, `aspect(a,b)` | `constraint(:ratio, a, b)` |
|
|
380
|
-
|
|
381
|
-
**CSS Flexbox/Grid parallels:**
|
|
382
|
-
- `fill(1)` ≈ CSS `flex: 1` or `1fr`
|
|
383
|
-
- `fixed(100)` ≈ CSS `width: 100px`
|
|
384
|
-
- `min(50)` ≈ CSS `min-width: 50px`
|
|
385
|
-
- `percent(25)` ≈ CSS `width: 25%`
|
|
386
|
-
|
|
387
|
-
**Dispatcher signature:**
|
|
388
|
-
```ruby
|
|
389
|
-
def constraint(type, *args)
|
|
390
|
-
case type
|
|
391
|
-
when :length, :fixed then constraint_length(*args)
|
|
392
|
-
when :percentage, :percent then constraint_percentage(*args)
|
|
393
|
-
when :min then constraint_min(*args)
|
|
394
|
-
when :max then constraint_max(*args)
|
|
395
|
-
when :fill, :flex, :fr then constraint_fill(*args)
|
|
396
|
-
when :ratio, :aspect then constraint_ratio(*args)
|
|
397
|
-
else
|
|
398
|
-
raise ArgumentError, "Unknown constraint type: #{type.inspect}. " \
|
|
399
|
-
"Valid types: :length, :percentage, :min, :max, :fill, :ratio"
|
|
400
|
-
end
|
|
401
|
-
end
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
---
|
|
405
|
-
|
|
406
|
-
###### Layout Operations
|
|
407
|
-
|
|
408
|
-
| Current | Add Alias | Rationale |
|
|
409
|
-
|---------|-----------|-----------|
|
|
410
|
-
| `layout_split` | `split` | 52 usages in examples; clear in context |
|
|
411
|
-
|
|
412
|
-
---
|
|
413
|
-
|
|
414
|
-
###### Text Factories
|
|
415
|
-
|
|
416
|
-
| Current | Status | Notes |
|
|
417
|
-
|---------|--------|-------|
|
|
418
|
-
| `text_span` | ✓ Has alias `span` | |
|
|
419
|
-
| `text_line` | ✓ Has alias `line` | |
|
|
420
|
-
| `text_width` | Keep as-is | Distinct from `length` (constraint) |
|
|
421
|
-
|
|
422
|
-
Add dispatcher:
|
|
423
|
-
```ruby
|
|
424
|
-
def text(type, **kwargs)
|
|
425
|
-
case type
|
|
426
|
-
when :span then text_span(**kwargs)
|
|
427
|
-
when :line then text_line(**kwargs)
|
|
428
|
-
else
|
|
429
|
-
raise ArgumentError, "Unknown text type: #{type.inspect}. Valid types: :span, :line"
|
|
430
|
-
end
|
|
431
|
-
end
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
---
|
|
435
|
-
|
|
436
|
-
###### Widget Factories
|
|
437
|
-
|
|
438
|
-
| Current | Add Alias | Rationale |
|
|
439
|
-
|---------|-----------|-----------|
|
|
440
|
-
| `list_item` | `item` | Clear in list context |
|
|
441
|
-
| `table_row` | Keep alongside `row` | DWIM — both valid mental models |
|
|
442
|
-
| `table_cell` | Keep as-is | `cell` means `Buffer::Cell` |
|
|
443
|
-
| `bar_chart_bar` | Keep alongside `bar` | DWIM — don't deprecate |
|
|
444
|
-
| `bar_chart_bar_group` | Keep alongside `bar_group` | DWIM — don't deprecate |
|
|
445
|
-
|
|
446
|
-
Add dispatcher:
|
|
447
|
-
```ruby
|
|
448
|
-
def widget(type, **kwargs)
|
|
449
|
-
case type
|
|
450
|
-
when :block then block(**kwargs)
|
|
451
|
-
when :paragraph then paragraph(**kwargs)
|
|
452
|
-
when :list then list(**kwargs)
|
|
453
|
-
when :table then table(**kwargs)
|
|
454
|
-
# ... all widgets
|
|
455
|
-
else
|
|
456
|
-
raise ArgumentError, "Unknown widget type: #{type.inspect}."
|
|
457
|
-
end
|
|
458
|
-
end
|
|
459
|
-
```
|
|
460
|
-
|
|
461
|
-
---
|
|
462
|
-
|
|
463
|
-
###### State Factories
|
|
464
|
-
|
|
465
|
-
| Current | Status |
|
|
466
|
-
|---------|--------|
|
|
467
|
-
| `list_state` | Keep as-is |
|
|
468
|
-
| `table_state` | Keep as-is |
|
|
469
|
-
| `scrollbar_state` | Keep as-is |
|
|
470
|
-
|
|
471
|
-
Add dispatcher:
|
|
472
|
-
```ruby
|
|
473
|
-
def state(type, **kwargs)
|
|
474
|
-
case type
|
|
475
|
-
when :list then list_state(**kwargs)
|
|
476
|
-
when :table then table_state(**kwargs)
|
|
477
|
-
when :scrollbar then scrollbar_state(**kwargs)
|
|
478
|
-
else
|
|
479
|
-
raise ArgumentError, "Unknown state type: #{type.inspect}."
|
|
480
|
-
end
|
|
481
|
-
end
|
|
482
|
-
```
|
|
483
|
-
|
|
484
|
-
---
|
|
485
|
-
|
|
486
|
-
###### Parameter Names
|
|
487
|
-
|
|
488
|
-
All current parameter names are well-chosen. No changes recommended.
|
|
489
|
-
|
|
490
|
-
| Widget | Parameter | Status |
|
|
491
|
-
|--------|-----------|--------|
|
|
492
|
-
| `List` | `selected_index`, `highlight_style`, etc. | ✓ |
|
|
493
|
-
| `Table` | `row_highlight_style`, `selected_row`, etc. | ✓ |
|
|
494
|
-
| `Scrollbar` | `content_length`, `position`, etc. | ✓ |
|
|
495
|
-
| All | `block`, `style`, `offset` | ✓ Consistent |
|
|
496
|
-
|
|
497
|
-
---
|
|
498
|
-
|
|
499
|
-
###### Summary of Changes
|
|
500
|
-
|
|
501
|
-
###### High Priority (Immediate DX Wins)
|
|
502
|
-
|
|
503
|
-
1. **Add `item` alias** for `list_item`
|
|
504
|
-
2. **Add terse shape aliases**: `circle`, `point`, `rectangle`, `map`, `label`
|
|
505
|
-
|
|
506
|
-
###### Medium Priority (Pattern Completion)
|
|
507
|
-
|
|
508
|
-
5. **Add dispatcher methods**: `shape(type, ...)`, `constraint(type, ...)`, `text(type, ...)`, `widget(type, ...)`, `state(type, ...)`
|
|
509
|
-
6. **Add bidirectional shape aliases**: `circle_shape`, `point_shape`, etc.
|
|
510
|
-
|
|
511
|
-
###### Not Changing
|
|
512
|
-
|
|
513
|
-
- Don't deprecate verbose forms (`table_row`, `bar_chart_bar`, etc.) — DWIM
|
|
514
|
-
- Don't rename parameters — already optimal
|
|
515
|
-
- Don't add third level aliases (`tui.widgets.paragraph`) — two levels max
|
|
516
|
-
|
|
517
|
-
---
|
|
518
|
-
|
|
519
|
-
###### Implementation Checklist
|
|
520
|
-
|
|
521
|
-
- [ ] Add `item` alias to `WidgetFactories`
|
|
522
|
-
- [ ] Add terse shape aliases to `CanvasFactories`
|
|
523
|
-
- [ ] Add `shape(type, ...)` dispatcher
|
|
524
|
-
- [ ] Add `constraint(type, ...)` dispatcher
|
|
525
|
-
- [ ] Add bidirectional shape aliases (`*_shape`)
|
|
526
|
-
- [ ] Add `text(type, ...)`, `widget(type, ...)`, `state(type, ...)` dispatchers
|
|
527
|
-
- [ ] Update RBS signatures for all new methods
|
|
528
|
-
- [ ] Update RDoc for all new methods
|
|
529
|
-
- [ ] Update CHANGELOG.md
|
|
530
|
-
|
|
531
|
-
---
|
|
532
|
-
|
|
533
|
-
###### Breaking Changes Analysis
|
|
534
|
-
|
|
535
|
-
If all recommendations in this audit are adopted, **none constitute breaking changes** under semver.
|
|
536
|
-
|
|
537
|
-
| Recommendation | Breaking? | Rationale |
|
|
538
|
-
|----------------|-----------|-----------|
|
|
539
|
-
| Add `item` alias | No | Additive; `list_item` unchanged |
|
|
540
|
-
| Add terse shape aliases (`circle`, etc.) | No | Additive; `shape_*` methods unchanged |
|
|
541
|
-
| Add bidirectional aliases (`*_shape`) | No | Additive; does not remove existing forms |
|
|
542
|
-
| Add dispatcher methods | No | Additive; new methods only |
|
|
543
|
-
| Keep verbose forms (`table_row`, etc.) | No | No removal or rename |
|
|
544
|
-
|
|
545
|
-
**Conclusion:** This audit recommends only additive changes. All existing code will continue to work unchanged.
|
|
546
|
-
|
|
547
|
-
> [!NOTE]
|
|
548
|
-
> If we later decide to **remove** verbose forms like `bar_chart_bar` or `bar_chart_bar_group`, that would be a breaking change requiring a major version bump. This audit explicitly recommends **keeping** them (DWIM philosophy).
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
---
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
# dwim_dx
|
|
556
|
-
## dwim_dx
|
|
557
|
-
#### Problem Statement
|
|
558
|
-
|
|
559
|
-
Ruby's philosophy of "Do What I Mean" (DWIM) and human-centric design should extend to ratatui_ruby's API. Currently, app developers encounter friction points that force them to remember non-obvious conventions, use overly verbose code, or pattern-match when simple predicates would suffice.
|
|
560
|
-
|
|
561
|
-
This proposal identifies DX issues across the widget API and suggests improvements that maintain backward compatibility while providing ergonomic alternatives.
|
|
562
|
-
|
|
563
|
-
#### DX Issues Identified
|
|
564
|
-
|
|
565
|
-
##### 1. Confusing Event Method Names
|
|
566
|
-
|
|
567
|
-
**Current problem**: `event.char` doesn't exist, but `event.code` returns things like `"enter"`, `"ctrl"`, not just characters.
|
|
568
|
-
|
|
569
|
-
**What users expect**:
|
|
570
|
-
- `event.char` should return the printable character (matching the name)
|
|
571
|
-
- `event.ctrl_c?`, `event.enter?`, etc. should work for all key combinations
|
|
572
|
-
- `event.key?`, `event.mouse?` predicates exist but only for broad categories
|
|
573
|
-
|
|
574
|
-
**Solution implemented**: Added `char` method and dynamic predicates via `method_missing`. See `lib/ratatui_ruby/event/key.rb`.
|
|
575
|
-
|
|
576
|
-
##### 2. Dual Parameter APIs Without Predicates
|
|
577
|
-
|
|
578
|
-
**Current problem**: Widgets accept both forms but no convenience methods to query the state:
|
|
579
|
-
|
|
580
|
-
```ruby
|
|
581
|
-
### Both work, but which one does the widget store?
|
|
582
|
-
gauge1 = Gauge.new(ratio: 0.75)
|
|
583
|
-
gauge2 = Gauge.new(percent: 75)
|
|
584
|
-
gauge1.ratio # Works
|
|
585
|
-
gauge1.percent # Does NOT exist
|
|
586
|
-
```
|
|
587
|
-
|
|
588
|
-
Similarly with List and Table:
|
|
589
|
-
```ruby
|
|
590
|
-
list.selected_index = 2 # Works
|
|
591
|
-
list.selected? # Does NOT exist
|
|
592
|
-
list.is_selected? # Does NOT exist
|
|
593
|
-
```
|
|
594
|
-
|
|
595
|
-
**Affected widgets**:
|
|
596
|
-
- `Gauge` (ratio vs percent)
|
|
597
|
-
- `LineGauge` (ratio vs percent)
|
|
598
|
-
- `List` (selected_index with no query methods)
|
|
599
|
-
- `Table` (selected_row and selected_column with no query methods)
|
|
600
|
-
|
|
601
|
-
**Suggested solutions**:
|
|
602
|
-
|
|
603
|
-
For `Gauge` and `LineGauge`:
|
|
604
|
-
```ruby
|
|
605
|
-
### Add convenience predicates
|
|
606
|
-
gauge.percent # => 75 (coerced from ratio internally)
|
|
607
|
-
gauge.percent = 50 # => Updates ratio to 0.5
|
|
608
|
-
|
|
609
|
-
### Or provide explicit accessors
|
|
610
|
-
gauge.as_percent # => 75
|
|
611
|
-
gauge.as_ratio # => 0.75
|
|
612
|
-
```
|
|
613
|
-
|
|
614
|
-
For `List` and `Table`:
|
|
615
|
-
```ruby
|
|
616
|
-
list.selected? # => true if selected_index is not nil
|
|
617
|
-
list.selection # => 2 (alias for selected_index)
|
|
618
|
-
list.selected_item # => "Item 3"
|
|
619
|
-
|
|
620
|
-
table.selected_row? # => true if selected_row is not nil
|
|
621
|
-
table.selected_cell? # => true if both row and column selected
|
|
622
|
-
```
|
|
623
|
-
|
|
624
|
-
##### 4. Inconsistent Style APIs
|
|
625
|
-
|
|
626
|
-
**Current problem**: Different widgets accept styles differently:
|
|
627
|
-
|
|
628
|
-
```ruby
|
|
629
|
-
### Table accepts both
|
|
630
|
-
table = Table.new(style: Style.new(fg: :blue))
|
|
631
|
-
table = Table.new(style: { fg: :blue }) # Hash shorthand
|
|
632
|
-
|
|
633
|
-
### But Paragraph doesn't
|
|
634
|
-
paragraph = Paragraph.new(text: "hi", style: Style.new(fg: :blue))
|
|
635
|
-
paragraph = Paragraph.new(text: "hi", style: { fg: :blue }) # Works but undocumented
|
|
636
|
-
|
|
637
|
-
### And Gauge has separate properties
|
|
638
|
-
gauge = Gauge.new(style: Style.new(fg: :blue), gauge_style: Style.new(fg: :green))
|
|
639
|
-
```
|
|
640
|
-
|
|
641
|
-
**Suggested solution**: Standardize style handling across all widgets:
|
|
642
|
-
|
|
643
|
-
1. All widgets should accept `Style` objects and `Hash` shorthand
|
|
644
|
-
2. Document this clearly in each widget
|
|
645
|
-
3. Add a convenience constructor:
|
|
646
|
-
|
|
647
|
-
```ruby
|
|
648
|
-
class Style
|
|
649
|
-
def self.with(fg: nil, bg: nil, modifiers: [])
|
|
650
|
-
Style.new(fg: fg, bg: bg, modifiers: modifiers)
|
|
651
|
-
end
|
|
652
|
-
end
|
|
653
|
-
|
|
654
|
-
### Cleaner than always spelling out keyword args
|
|
655
|
-
paragraph = Paragraph.new(text: "hi", style: Style.with(fg: :blue))
|
|
656
|
-
```
|
|
657
|
-
|
|
658
|
-
##### 6. Magic Numeric Coercions
|
|
659
|
-
|
|
660
|
-
**Current problem**: Widgets accept `Numeric` but silently coerce:
|
|
661
|
-
|
|
662
|
-
```ruby
|
|
663
|
-
### These all work, but behavior is undocumented
|
|
664
|
-
list = List.new(selected_index: "2") # Coerced to 2
|
|
665
|
-
list = List.new(selected_index: 2.7) # Coerced to 2
|
|
666
|
-
list = List.new(selected_index: 2.0) # Coerced to 2
|
|
667
|
-
|
|
668
|
-
gauge = Gauge.new(percent: 150) # Should clamp?
|
|
669
|
-
gauge = Gauge.new(ratio: 1.5) # Should clamp?
|
|
670
|
-
```
|
|
671
|
-
|
|
672
|
-
**Suggested solution**:
|
|
673
|
-
|
|
674
|
-
1. Document coercion rules explicitly in RDoc
|
|
675
|
-
2. Add validation and raise on invalid inputs:
|
|
676
|
-
|
|
677
|
-
```ruby
|
|
678
|
-
def initialize(percent: nil, ...)
|
|
679
|
-
if percent
|
|
680
|
-
raise ArgumentError, "percent must be 0..100, got #{percent}" unless percent.between?(0, 100)
|
|
681
|
-
ratio = Float(percent) / 100.0
|
|
682
|
-
end
|
|
683
|
-
end
|
|
684
|
-
```
|
|
685
|
-
|
|
686
|
-
3. Provide clear error messages:
|
|
687
|
-
```ruby
|
|
688
|
-
gauge = Gauge.new(percent: 150)
|
|
689
|
-
### => ArgumentError: percent must be between 0 and 100 (got 150)
|
|
690
|
-
```
|
|
691
|
-
|
|
692
|
-
#### Implementation Strategy
|
|
693
|
-
|
|
694
|
-
##### Phase 3: Style Consistency
|
|
695
|
-
- [ ] Standardize `Hash` shorthand support across all widgets
|
|
696
|
-
- [ ] Add `Style.with(fg:, bg:, modifiers:)` convenience constructor
|
|
697
|
-
- [ ] Update `.rbs` files to reflect HashStyle support
|
|
698
|
-
- [ ] Document in style guide
|
|
699
|
-
|
|
700
|
-
##### Phase 4: Numeric Coercion Validation
|
|
701
|
-
- [ ] Add validation to `Gauge`, `LineGauge`, `List`, `Table`
|
|
702
|
-
- [ ] Raise `ArgumentError` on out-of-range values
|
|
703
|
-
- [ ] Provide clear error messages
|
|
704
|
-
- [ ] Update tests
|
|
705
|
-
|
|
706
|
-
##### Phase 5: Convenience Accessors
|
|
707
|
-
- [ ] Add `percent` to `Gauge` and `LineGauge`
|
|
708
|
-
- [ ] Add `selection` alias to `List` and `Table`
|
|
709
|
-
- [ ] Add `selected_item` to `List`
|
|
710
|
-
- [ ] Tests and documentation
|
|
711
|
-
|
|
712
|
-
#### Example: Before and After
|
|
713
|
-
|
|
714
|
-
##### Before (Confusing)
|
|
715
|
-
```ruby
|
|
716
|
-
class GameApp
|
|
717
|
-
def initialize
|
|
718
|
-
@menu = List.new(
|
|
719
|
-
items: ["Start Game", "Load Game", "Options", "Quit"],
|
|
720
|
-
selected_index: 0,
|
|
721
|
-
highlight_spacing: :when_selected, # What's valid here?
|
|
722
|
-
direction: :top_to_bottom
|
|
723
|
-
)
|
|
724
|
-
end
|
|
725
|
-
|
|
726
|
-
def handle_input(event)
|
|
727
|
-
case event
|
|
728
|
-
when :ctrl_c
|
|
729
|
-
exit
|
|
730
|
-
when :up
|
|
731
|
-
if @menu.selected_index && @menu.selected_index > 0
|
|
732
|
-
@menu = @menu.with(selected_index: @menu.selected_index - 1)
|
|
733
|
-
end
|
|
734
|
-
end
|
|
735
|
-
end
|
|
736
|
-
|
|
737
|
-
def render(tui)
|
|
738
|
-
tui.draw(@menu)
|
|
739
|
-
end
|
|
740
|
-
end
|
|
741
|
-
```
|
|
742
|
-
|
|
743
|
-
##### After (DWIM)
|
|
744
|
-
```ruby
|
|
745
|
-
class GameApp
|
|
746
|
-
def initialize
|
|
747
|
-
@menu = List.new(
|
|
748
|
-
items: ["Start Game", "Load Game", "Options", "Quit"],
|
|
749
|
-
selected_index: 0,
|
|
750
|
-
highlight_spacing: List::HIGHLIGHT_WHEN_SELECTED, # IDE autocomplete!
|
|
751
|
-
direction: List::DIRECTION_TOP_TO_BOTTOM
|
|
752
|
-
)
|
|
753
|
-
end
|
|
754
|
-
|
|
755
|
-
def handle_input(event)
|
|
756
|
-
return if event.ctrl_c? # Dynamic predicate!
|
|
757
|
-
|
|
758
|
-
if event.up?
|
|
759
|
-
move_menu_up if @menu.selected? # State predicate!
|
|
760
|
-
end
|
|
761
|
-
end
|
|
762
|
-
|
|
763
|
-
def move_menu_up
|
|
764
|
-
index = @menu.selected_index
|
|
765
|
-
return if index == 0
|
|
766
|
-
@menu = @menu.with(selected_index: index - 1)
|
|
767
|
-
end
|
|
768
|
-
|
|
769
|
-
def render(tui)
|
|
770
|
-
tui.draw(@menu)
|
|
771
|
-
end
|
|
772
|
-
end
|
|
773
|
-
```
|
|
774
|
-
|
|
775
|
-
#### Migration Path
|
|
776
|
-
|
|
777
|
-
All changes are backward compatible (additive):
|
|
778
|
-
- Existing code using symbols continues to work
|
|
779
|
-
- New constants coexist with symbols
|
|
780
|
-
- New predicates don't change existing behavior
|
|
781
|
-
- New methods are additions, not replacements
|
|
782
|
-
|
|
783
|
-
Apps can migrate at their own pace:
|
|
784
|
-
```ruby
|
|
785
|
-
### Old style still works
|
|
786
|
-
list = List.new(highlight_spacing: :when_selected)
|
|
787
|
-
|
|
788
|
-
### New style also works
|
|
789
|
-
list = List.new(highlight_spacing: List::HIGHLIGHT_WHEN_SELECTED)
|
|
790
|
-
|
|
791
|
-
### Mix and match
|
|
792
|
-
if list.selected? # New predicate
|
|
793
|
-
puts list.selected_index # Old accessor
|
|
794
|
-
end
|
|
795
|
-
```
|
|
796
|
-
|
|
797
|
-
#### Metrics for Success
|
|
798
|
-
|
|
799
|
-
1. **Discoverability**: New developers can find valid options via IDE autocomplete
|
|
800
|
-
2. **Clarity**: Code self-documents valid states and modes
|
|
801
|
-
3. **Type safety**: Constants and predicates provide type checking
|
|
802
|
-
4. **Error feedback**: Invalid inputs raise with helpful messages
|
|
803
|
-
5. **Backward compatibility**: Zero breaking changes, all existing code works
|
|
804
|
-
|
|
805
|
-
#### Related Issues
|
|
806
|
-
|
|
807
|
-
- AGENTS.md requirement: All examples must have tests verifying behavior
|
|
808
|
-
- Example improvements: Apply constants and predicates to all example code
|
|
809
|
-
- Documentation: Update style guide with DWIM principles
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
---
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
# examples_audit
|
|
816
|
-
## examples_audit
|
|
817
|
-
##### [P1: Moderate (Quality)](#p2_moderate)
|
|
818
|
-
|
|
819
|
-
1. **[Add RDoc Cross-Links](#1-add-rdoc-cross-links-examples--aliases)** (Documentation discoverability)
|
|
820
|
-
- Link library classes/methods to examples
|
|
821
|
-
- Link DWIM/TIMTOWTDI aliases
|
|
822
|
-
- Create consistent pattern across public APIs
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
---
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
### p2_moderate
|
|
829
|
-
#### Priority 2: Moderate (Quality Gates)
|
|
830
|
-
|
|
831
|
-
These are v1.0.0 quality improvements that refine the example suite after P0 is complete. Not blocking, but recommended for maintainability and API consistency.
|
|
832
|
-
|
|
833
|
-
---
|
|
834
|
-
|
|
835
|
-
##### 1. Add RDoc Cross-Links (Examples & Aliases)
|
|
836
|
-
|
|
837
|
-
**Status:** Important for API discoverability — Documentation should link library and examples
|
|
838
|
-
|
|
839
|
-
RDoc should cross-link between:
|
|
840
|
-
- **Library classes/methods** ↔ **Examples that use them** (See also: examples/widget_foo)
|
|
841
|
-
- **Primary methods** ↔ **DWIM/TIMTOWTDI aliases** (See also: tui.foo_bar as alias for tui.foo(:bar))
|
|
842
|
-
|
|
843
|
-
###### Current Practice
|
|
844
|
-
|
|
845
|
-
Done for:
|
|
846
|
-
- `RatatuiRuby::Frame#set_cursor_position` ↔ `RatatuiRuby::Cursor` (cross-linking)
|
|
847
|
-
- Limited elsewhere
|
|
848
|
-
|
|
849
|
-
###### Gaps
|
|
850
|
-
|
|
851
|
-
- Most widget classes have no "See also: example_foo_demo" links
|
|
852
|
-
- Aliases/TIMTOWTDI variants are not documented as such
|
|
853
|
-
- Users can't easily find examples for a given class/method
|
|
854
|
-
|
|
855
|
-
###### Action
|
|
856
|
-
|
|
857
|
-
1. Add `# See also: examples/widget_foo/app.rb` to class/method RDoc
|
|
858
|
-
2. Link DWIM methods to TIMTOWTDI variants: `# Also available as: tui.constraint_length (DWIM) vs tui.constraint(:length) (TIMTOWTDI)`
|
|
859
|
-
3. Create consistent pattern across all public APIs in `lib/ratatui_ruby/`
|
|
860
|
-
|
|
861
|
-
###### Example Pattern
|
|
862
|
-
|
|
863
|
-
```ruby
|
|
864
|
-
#### Renders text with styling.
|
|
865
|
-
#
|
|
866
|
-
#### See also: examples/widget_paragraph/app.rb (basic paragraph rendering)
|
|
867
|
-
class Paragraph < Data.define(...)
|
|
868
|
-
# ...
|
|
869
|
-
end
|
|
870
|
-
|
|
871
|
-
#### DWIM version of constraint creation
|
|
872
|
-
#### Also available as: constraint(type, value) for explicit control
|
|
873
|
-
def constraint_length(length)
|
|
874
|
-
constraint(:length, length)
|
|
875
|
-
end
|
|
876
|
-
```
|