ratatui_ruby 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) 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 +48 -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/async.md +160 -0
  12. data/doc/contributors/architectural_overhaul/chat_conversations.md +4952 -0
  13. data/doc/contributors/architectural_overhaul/implementation_plan.md +60 -0
  14. data/doc/contributors/architectural_overhaul/task.md +37 -0
  15. data/doc/contributors/design/ruby_frontend.md +277 -81
  16. data/doc/contributors/design/rust_backend.md +349 -55
  17. data/doc/contributors/developing_examples.md +5 -5
  18. data/doc/contributors/index.md +7 -5
  19. data/doc/contributors/v1.0.0_blockers.md +1729 -0
  20. data/doc/debugging.md +71 -0
  21. data/doc/index.md +11 -6
  22. data/doc/interactive_design.md +2 -2
  23. data/doc/quickstart.md +66 -97
  24. data/doc/v0.7.0_migration.md +236 -0
  25. data/doc/why.md +93 -0
  26. data/examples/app_all_events/README.md +6 -4
  27. data/examples/app_all_events/app.rb +1 -1
  28. data/examples/app_all_events/model/app_model.rb +1 -1
  29. data/examples/app_all_events/model/msg.rb +1 -1
  30. data/examples/app_all_events/update.rb +1 -1
  31. data/examples/app_all_events/view/app_view.rb +1 -1
  32. data/examples/app_all_events/view/controls_view.rb +1 -1
  33. data/examples/app_all_events/view/counts_view.rb +1 -1
  34. data/examples/app_all_events/view/live_view.rb +1 -1
  35. data/examples/app_all_events/view/log_view.rb +1 -1
  36. data/examples/app_color_picker/README.md +7 -5
  37. data/examples/app_color_picker/app.rb +1 -1
  38. data/examples/app_login_form/README.md +2 -0
  39. data/examples/app_stateful_interaction/README.md +2 -0
  40. data/examples/app_stateful_interaction/app.rb +1 -1
  41. data/examples/verify_quickstart_dsl/README.md +4 -3
  42. data/examples/verify_quickstart_dsl/app.rb +1 -1
  43. data/examples/verify_quickstart_layout/README.md +1 -1
  44. data/examples/verify_quickstart_lifecycle/README.md +3 -3
  45. data/examples/verify_quickstart_lifecycle/app.rb +2 -2
  46. data/examples/verify_readme_usage/README.md +1 -1
  47. data/examples/widget_barchart_demo/README.md +2 -1
  48. data/examples/widget_block_demo/README.md +2 -0
  49. data/examples/widget_box_demo/README.md +3 -3
  50. data/examples/widget_calendar_demo/README.md +3 -3
  51. data/examples/widget_calendar_demo/app.rb +5 -1
  52. data/examples/widget_canvas_demo/README.md +3 -3
  53. data/examples/widget_cell_demo/README.md +3 -3
  54. data/examples/widget_center_demo/README.md +3 -3
  55. data/examples/widget_chart_demo/README.md +3 -3
  56. data/examples/widget_gauge_demo/README.md +3 -3
  57. data/examples/widget_layout_split/README.md +3 -3
  58. data/examples/widget_line_gauge_demo/README.md +3 -3
  59. data/examples/widget_list_demo/README.md +3 -3
  60. data/examples/widget_map_demo/README.md +3 -3
  61. data/examples/widget_map_demo/app.rb +2 -2
  62. data/examples/widget_overlay_demo/README.md +36 -0
  63. data/examples/widget_popup_demo/README.md +3 -3
  64. data/examples/widget_ratatui_logo_demo/README.md +3 -3
  65. data/examples/widget_ratatui_logo_demo/app.rb +1 -1
  66. data/examples/widget_ratatui_mascot_demo/README.md +3 -3
  67. data/examples/widget_rect/README.md +3 -3
  68. data/examples/widget_render/README.md +3 -3
  69. data/examples/widget_render/app.rb +3 -3
  70. data/examples/widget_rich_text/README.md +3 -3
  71. data/examples/widget_scroll_text/README.md +3 -3
  72. data/examples/widget_scrollbar_demo/README.md +3 -3
  73. data/examples/widget_sparkline_demo/README.md +3 -3
  74. data/examples/widget_style_colors/README.md +3 -3
  75. data/examples/widget_table_demo/README.md +3 -3
  76. data/examples/widget_table_demo/app.rb +19 -4
  77. data/examples/widget_tabs_demo/README.md +3 -3
  78. data/examples/widget_text_width/README.md +3 -3
  79. data/examples/widget_text_width/app.rb +8 -1
  80. data/ext/ratatui_ruby/Cargo.lock +1 -1
  81. data/ext/ratatui_ruby/Cargo.toml +1 -1
  82. data/ext/ratatui_ruby/src/frame.rs +6 -5
  83. data/ext/ratatui_ruby/src/lib.rs +3 -2
  84. data/ext/ratatui_ruby/src/rendering.rs +22 -21
  85. data/ext/ratatui_ruby/src/style.rs +25 -9
  86. data/ext/ratatui_ruby/src/text.rs +12 -3
  87. data/ext/ratatui_ruby/src/widgets/canvas.rs +5 -5
  88. data/ext/ratatui_ruby/src/widgets/table.rs +81 -36
  89. data/lib/ratatui_ruby/buffer/cell.rb +168 -0
  90. data/lib/ratatui_ruby/buffer.rb +15 -0
  91. data/lib/ratatui_ruby/frame.rb +8 -8
  92. data/lib/ratatui_ruby/layout/constraint.rb +95 -0
  93. data/lib/ratatui_ruby/layout/layout.rb +106 -0
  94. data/lib/ratatui_ruby/layout/rect.rb +118 -0
  95. data/lib/ratatui_ruby/layout.rb +19 -0
  96. data/lib/ratatui_ruby/list_state.rb +2 -2
  97. data/lib/ratatui_ruby/schema/layout.rb +1 -1
  98. data/lib/ratatui_ruby/schema/row.rb +66 -0
  99. data/lib/ratatui_ruby/schema/table.rb +10 -10
  100. data/lib/ratatui_ruby/schema/text.rb +27 -2
  101. data/lib/ratatui_ruby/style/style.rb +81 -0
  102. data/lib/ratatui_ruby/style.rb +15 -0
  103. data/lib/ratatui_ruby/table_state.rb +1 -1
  104. data/lib/ratatui_ruby/test_helper/snapshot.rb +24 -0
  105. data/lib/ratatui_ruby/test_helper/style_assertions.rb +1 -1
  106. data/lib/ratatui_ruby/tui/buffer_factories.rb +20 -0
  107. data/lib/ratatui_ruby/tui/canvas_factories.rb +44 -0
  108. data/lib/ratatui_ruby/tui/core.rb +38 -0
  109. data/lib/ratatui_ruby/tui/layout_factories.rb +74 -0
  110. data/lib/ratatui_ruby/tui/state_factories.rb +33 -0
  111. data/lib/ratatui_ruby/tui/style_factories.rb +20 -0
  112. data/lib/ratatui_ruby/tui/text_factories.rb +44 -0
  113. data/lib/ratatui_ruby/tui/widget_factories.rb +195 -0
  114. data/lib/ratatui_ruby/tui.rb +75 -0
  115. data/lib/ratatui_ruby/version.rb +1 -1
  116. data/lib/ratatui_ruby/widgets/bar_chart/bar.rb +47 -0
  117. data/lib/ratatui_ruby/widgets/bar_chart/bar_group.rb +25 -0
  118. data/lib/ratatui_ruby/widgets/bar_chart.rb +239 -0
  119. data/lib/ratatui_ruby/widgets/block.rb +192 -0
  120. data/lib/ratatui_ruby/widgets/calendar.rb +84 -0
  121. data/lib/ratatui_ruby/widgets/canvas.rb +231 -0
  122. data/lib/ratatui_ruby/widgets/cell.rb +47 -0
  123. data/lib/ratatui_ruby/widgets/center.rb +59 -0
  124. data/lib/ratatui_ruby/widgets/chart.rb +185 -0
  125. data/lib/ratatui_ruby/widgets/clear.rb +54 -0
  126. data/lib/ratatui_ruby/widgets/cursor.rb +42 -0
  127. data/lib/ratatui_ruby/widgets/gauge.rb +72 -0
  128. data/lib/ratatui_ruby/widgets/line_gauge.rb +80 -0
  129. data/lib/ratatui_ruby/widgets/list.rb +127 -0
  130. data/lib/ratatui_ruby/widgets/list_item.rb +43 -0
  131. data/lib/ratatui_ruby/widgets/overlay.rb +43 -0
  132. data/lib/ratatui_ruby/widgets/paragraph.rb +99 -0
  133. data/lib/ratatui_ruby/widgets/ratatui_logo.rb +31 -0
  134. data/lib/ratatui_ruby/widgets/ratatui_mascot.rb +36 -0
  135. data/lib/ratatui_ruby/widgets/row.rb +68 -0
  136. data/lib/ratatui_ruby/widgets/scrollbar.rb +143 -0
  137. data/lib/ratatui_ruby/widgets/shape/label.rb +68 -0
  138. data/lib/ratatui_ruby/widgets/sparkline.rb +134 -0
  139. data/lib/ratatui_ruby/widgets/table.rb +141 -0
  140. data/lib/ratatui_ruby/widgets/tabs.rb +85 -0
  141. data/lib/ratatui_ruby/widgets.rb +40 -0
  142. data/lib/ratatui_ruby.rb +23 -39
  143. data/sig/examples/app_all_events/view.rbs +1 -1
  144. data/sig/examples/app_all_events/view_state.rbs +1 -1
  145. data/sig/ratatui_ruby/schema/row.rbs +22 -0
  146. data/sig/ratatui_ruby/schema/table.rbs +1 -1
  147. data/sig/ratatui_ruby/schema/text.rbs +1 -0
  148. data/sig/ratatui_ruby/session.rbs +29 -49
  149. data/sig/ratatui_ruby/tui/buffer_factories.rbs +10 -0
  150. data/sig/ratatui_ruby/tui/canvas_factories.rbs +14 -0
  151. data/sig/ratatui_ruby/tui/core.rbs +14 -0
  152. data/sig/ratatui_ruby/tui/layout_factories.rbs +19 -0
  153. data/sig/ratatui_ruby/tui/state_factories.rbs +12 -0
  154. data/sig/ratatui_ruby/tui/style_factories.rbs +10 -0
  155. data/sig/ratatui_ruby/tui/text_factories.rbs +14 -0
  156. data/sig/ratatui_ruby/tui/widget_factories.rbs +39 -0
  157. data/sig/ratatui_ruby/tui.rbs +19 -0
  158. data/tasks/autodoc.rake +1 -35
  159. data/tasks/bump/changelog.rb +8 -0
  160. data/tasks/bump/ruby_gem.rb +12 -0
  161. data/tasks/bump/unreleased_section.rb +16 -0
  162. data/tasks/sourcehut.rake +4 -1
  163. metadata +64 -15
  164. data/doc/contributors/dwim_dx.md +0 -366
  165. data/doc/contributors/examples_audit/p1_high.md +0 -21
  166. data/doc/contributors/examples_audit/p2_moderate.md +0 -81
  167. data/doc/contributors/examples_audit.md +0 -41
  168. data/doc/images/app_analytics.png +0 -0
  169. data/doc/images/app_custom_widget.png +0 -0
  170. data/doc/images/app_mouse_events.png +0 -0
  171. data/doc/images/widget_table_flex.png +0 -0
  172. data/lib/ratatui_ruby/session/autodoc.rb +0 -482
  173. data/lib/ratatui_ruby/session.rb +0 -178
  174. data/tasks/autodoc/inventory.rb +0 -63
  175. data/tasks/autodoc/notice.rb +0 -26
  176. data/tasks/autodoc/rbs.rb +0 -38
  177. data/tasks/autodoc/rdoc.rb +0 -45
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c8e3aed93d74250af44d1b7169dcf7d31575b8b6a24c65d40b4067edb1cf46ea
4
- data.tar.gz: e5f3d70e418bc9af98a1926838030aa934b13f64d617ed5c5a1809e91d17d72a
3
+ metadata.gz: 4fc5e88c5e6146ec1aeae7816aeb8bea73926aaf90d5b2df75fa58d5c6490ab0
4
+ data.tar.gz: 90ec60b887d797c1cd8b8f06ca41506dbf8a463abc554c20b7caab8ec537b496
5
5
  SHA512:
6
- metadata.gz: c1742d63643a1ebef6063097e3755e819da39354b631d70ba72ead21d48d8a9199a5421184698fb41a56ee0991a7411adfbcf125f6ec9e18aa980eeb6d4e03fe
7
- data.tar.gz: 995f166470814f6ec2a0e073bc658eb52b5a5381a5c19539d4b6ef575e601eb3ac8c3b000a23b4c226b6708a5387024b71a84c43cd69a5240f538aca261a815b
6
+ metadata.gz: 3d6fdbb5c4c2970210f70cb0f16c0f40eca871afd6cc115cc5e744e9b85aed01b2c7209baabbb4b2e7129f6ddf460f1add31a6612070a8ef239fbb1e5e2893bd
7
+ data.tar.gz: ffef16474856ead4d0754dcd6f26104b795a6c2d8aac962df73d7f6c468d4fc6ad7c769a68bb97c1ad3fecc487973afbb50764c555f0a8385addf14864d5c22c
data/.builds/ruby-3.2.yml CHANGED
@@ -16,7 +16,7 @@ packages:
16
16
  - clang
17
17
  - git
18
18
  artifacts:
19
- - ratatui_ruby/pkg/ratatui_ruby-0.6.0.gem
19
+ - ratatui_ruby/pkg/ratatui_ruby-0.7.1.gem
20
20
  sources:
21
21
  - https://git.sr.ht/~kerrick/ratatui_ruby
22
22
  tasks:
data/.builds/ruby-3.3.yml CHANGED
@@ -16,7 +16,7 @@ packages:
16
16
  - clang
17
17
  - git
18
18
  artifacts:
19
- - ratatui_ruby/pkg/ratatui_ruby-0.6.0.gem
19
+ - ratatui_ruby/pkg/ratatui_ruby-0.7.1.gem
20
20
  sources:
21
21
  - https://git.sr.ht/~kerrick/ratatui_ruby
22
22
  tasks:
data/.builds/ruby-3.4.yml CHANGED
@@ -16,7 +16,7 @@ packages:
16
16
  - clang
17
17
  - git
18
18
  artifacts:
19
- - ratatui_ruby/pkg/ratatui_ruby-0.6.0.gem
19
+ - ratatui_ruby/pkg/ratatui_ruby-0.7.1.gem
20
20
  sources:
21
21
  - https://git.sr.ht/~kerrick/ratatui_ruby
22
22
  tasks:
@@ -16,7 +16,7 @@ packages:
16
16
  - clang
17
17
  - git
18
18
  artifacts:
19
- - ratatui_ruby/pkg/ratatui_ruby-0.6.0.gem
19
+ - ratatui_ruby/pkg/ratatui_ruby-0.7.1.gem
20
20
  sources:
21
21
  - https://git.sr.ht/~kerrick/ratatui_ruby
22
22
  tasks:
data/AGENTS.md CHANGED
@@ -19,9 +19,9 @@ Architecture:
19
19
  ## Stability & Compatibility
20
20
 
21
21
  - **Project Status:** Pre-1.0.
22
- - **User Base:** 0 users (internal/experimental).
23
- - **Breaking Changes:** Backward compatibility is **NOT** a priority at this stage. Since there are no external users, you are encouraged to refactor APIs for better ergonomics and performance even if it breaks existing code.
24
- - **Requirement:** All breaking changes **MUST** be explicitly documented in the [CHANGELOG.md](CHANGELOG.md)'s **Unreleased** section to ensure transparency as the project evolves toward 1.0.
22
+ - **User Base:** First external users (as of 2026-01-03).
23
+ - **Breaking Changes:** Backward compatibility is **NOT YET** a priority. Since there are few external users, you are encouraged to refactor APIs for better ergonomics and performance even if it breaks existing code. This will when we ship v1.0.0.
24
+ - **Requirement:** All breaking changes **MUST** be explicitly documented in the [CHANGELOG.md](CHANGELOG.md)'s **Unreleased** section to ensure transparency as the project evolves toward 1.0. Migration guides **MUST** be included in `doc/` when we release a new minor version.
25
25
 
26
26
  ## 1. Standards
27
27
 
@@ -91,7 +91,7 @@ The project follows a standard Gem layout with an `ext/` directory for Rust code
91
91
 
92
92
  ## 4. Committing
93
93
 
94
- - Who commits: DON'T stage (DON'T `git add`). DON'T commit. DO suggest a commit message.
94
+ - Who commits: DON'T stage (DON'T `git add`) unless explicitly instructed. DON'T commit unless explicitly instructed. DO suggest a commit message when you finish, even if not instructed..
95
95
  - When: Before reporting the task as complete to the user, suggest the commit message.
96
96
  - What: Consider not what you remember, but EVERYTHING in the `git diff` and `git diff --cached`.
97
97
  - **Format:**
data/CHANGELOG.md CHANGED
@@ -18,6 +18,52 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
18
18
 
19
19
  ### Removed
20
20
 
21
+ ## [0.7.1] - 2026-01-03
22
+
23
+ ### Added
24
+
25
+ ### Changed
26
+
27
+ ### Fixed
28
+
29
+ - **Block Title Styling**: `Block` title `content` now correctly renders `Text::Line` objects with styled spans. Previously, passing a styled `Line` as title content displayed its Ruby inspect representation (e.g., `#<data RatatuiRuby::Text::Line...>`) instead of the styled text.
30
+
31
+ ### Removed
32
+
33
+ ## [0.7.0] - 2026-01-03
34
+
35
+ > [!WARNING]
36
+ > v0.7.0 contains significant breaking changes. See the [Migration Guide](doc/v0.7.0_migration.md) for upgrade instructions.
37
+
38
+ ### Added
39
+
40
+ - **Rich Text in Table Cells**: `Table` cells (rows, header, footer) now accept `Text::Span` and `Text::Line` objects for per-character styling, matching List widget capabilities.
41
+ - **Row Wrapper**: New `Widgets::Row` class allows applying row-level styling (background color, style) and layout properties (height, top_margin, bottom_margin) to Table rows. Table rows can now be plain arrays or `Widgets::Row` objects.
42
+ - **Cell Wrapper**: New `Widgets::Cell` class wraps table cell content with optional cell-level styling. Distinct from `Buffer::Cell` which is for buffer inspection.
43
+ - **Line#width Method**: `Text::Line` now has a `width` instance method that calculates the display width in terminal cells using unicode-aware measurement. Useful for layout calculations with rich text.
44
+ - **render_rich_buffer**: New `TestHelper::Snapshot#render_rich_buffer` method returns the terminal buffer as an ANSI-encoded string with escape codes for colors and modifiers. Useful for debugging, custom assertions, or programmatic inspection beyond `assert_rich_snapshot`.
45
+
46
+ ### Changed
47
+
48
+ - **Namespace Restructure (Breaking)**: Classes reorganized to match Ratatui's module hierarchy. See [Migration Guide](doc/v0.7.0_migration.md) for details:
49
+ - `RatatuiRuby::Rect` → `RatatuiRuby::Layout::Rect`
50
+ - `RatatuiRuby::Constraint` → `RatatuiRuby::Layout::Constraint`
51
+ - `RatatuiRuby::Layout` → `RatatuiRuby::Layout::Layout`
52
+ - `RatatuiRuby::Style` → `RatatuiRuby::Style::Style`
53
+ - `RatatuiRuby::Paragraph` → `RatatuiRuby::Widgets::Paragraph`
54
+ - `RatatuiRuby::Block` → `RatatuiRuby::Widgets::Block`
55
+ - `RatatuiRuby::Table` → `RatatuiRuby::Widgets::Table`
56
+ - `RatatuiRuby::List` → `RatatuiRuby::Widgets::List`
57
+ - *(and all other widgets)*
58
+ - **Session → TUI Rename (Breaking)**: `RatatuiRuby::Session` renamed to `RatatuiRuby::TUI` to better reflect its role as a facade/DSL. The `TUI` class now uses explicit factory methods (no metaprogramming) for improved IDE autocomplete support.
59
+ - **Buffer::Cell vs Widgets::Cell (Breaking)**: `RatatuiRuby::Cell` (buffer inspection) renamed to `RatatuiRuby::Buffer::Cell`. New `RatatuiRuby::Widgets::Cell` added for table cell construction.
60
+ - **Text::Line style field (Breaking)**: `Text::Line` now accepts a `style:` parameter for line-level styling, matching Ratatui's `Line` struct which has `style`, `alignment`, and `spans` fields.
61
+ - **Table highlight_style → row_highlight_style (Breaking)**: `Table` parameter `highlight_style:` renamed to `row_highlight_style:` to match Ratatui's API naming convention.
62
+
63
+ ### Fixed
64
+
65
+ ### Removed
66
+
21
67
  ## [0.6.0] - 2026-01-03
22
68
 
23
69
  ### Added
@@ -322,6 +368,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
322
368
  - **Testing Support**: Included `RatatuiRuby::TestHelper` and RSpec integration to make testing your TUI applications possible.
323
369
 
324
370
  [Unreleased]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/HEAD
371
+ [0.7.1]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v0.7.1
372
+ [0.7.0]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v0.7.0
325
373
  [0.6.0]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v0.6.0
326
374
  [0.5.0]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v0.5.0
327
375
  [0.4.0]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v0.4.0
data/README.md CHANGED
@@ -23,6 +23,8 @@ Mailing List: Announcements](https://img.shields.io/badge/mailing_list-announcem
23
23
  > [!WARNING]
24
24
  > **ratatui_ruby** is currently in **BETA**. The API may change between minor versions.
25
25
 
26
+ **[Why RatatuiRuby?](./doc/why.md)** — Native Rust performance, zero runtime overhead, and Ruby's expressiveness. [See how we compare](./doc/why.md) to CharmRuby, raw Rust, and Go.
27
+
26
28
  Please join the **announce** mailing list at https://lists.sr.ht/~kerrick/ratatui_ruby-announce to stay up-to-date on new releases and announcements. See the [`trunk` branch](https://git.sr.ht/~kerrick/ratatui_ruby/tree/trunk) for pre-release updates.
27
29
 
28
30
 
@@ -92,12 +94,35 @@ end
92
94
  ```
93
95
  <!-- SYNC:END -->
94
96
 
97
+ ![Hello Ratatui](./doc/images/verify_readme_usage.png)
98
+
95
99
  For a full tutorial, see [the Quickstart](./doc/quickstart.md). For an explanation of the application architecture, see [Application Architecture](./doc/application_architecture.md).
96
100
 
97
101
 
102
+ ## Features
103
+
104
+ **ratatui_ruby** gives you 20+ widgets out of the box:
105
+
106
+ | Category | Widgets |
107
+ |----------|---------|
108
+ | **Data Display** | Table, List, Chart, Bar Chart, Sparkline, Calendar |
109
+ | **Layout** | Block, Tabs, Scrollbar, Center, Overlay, Clear |
110
+ | **Input** | Gauge, Line Gauge |
111
+ | **Text** | Paragraph, Rich Text (Spans + Lines), Cursor |
112
+ | **Canvas** | Shapes (Line, Circle, Rectangle, Map), Custom Drawing |
113
+
114
+ Plus: flexible layouts with constraints, full keyboard/mouse/paste/resize events, snapshot testing, and hex/RGB/256-color support.
115
+
116
+
98
117
  ## Documentation
99
118
 
100
- For the full documentation on how to use **ratatui_ruby**, see the [documentation](./doc/index.md). For other information, see the [wiki](https://man.sr.ht/~kerrick/ratatui_ruby).
119
+ | Resource | Description |
120
+ |----------|-------------|
121
+ | [Quickstart](./doc/quickstart.md) | Get running in 5 minutes |
122
+ | [Widget Gallery](./doc/quickstart.md#widget-demos) | Every widget with examples |
123
+ | [Application Architecture](./doc/application_architecture.md) | Patterns for scaling your app |
124
+ | [API Reference](./doc/index.md) | Full RDoc documentation |
125
+ | [Wiki](https://man.sr.ht/~kerrick/ratatui_ruby) | Guides and community resources |
101
126
 
102
127
 
103
128
  ## Contributing
@@ -44,7 +44,7 @@ Need granular control? You can initialize and restore the terminal yourself. Use
44
44
  RatatuiRuby.init_terminal
45
45
  begin
46
46
  RatatuiRuby.draw do |frame|
47
- frame.render_widget(RatatuiRuby::Paragraph.new(text: "Hello"), frame.area)
47
+ frame.render_widget(RatatuiRuby::Widgets::Paragraph.new(text: "Hello"), frame.area)
48
48
  end
49
49
  ensure
50
50
  RatatuiRuby.restore_terminal
@@ -91,9 +91,9 @@ end
91
91
 
92
92
  Writing UI trees involves nesting many widgets.
93
93
 
94
- **The Problem:** Explicitly namespacing `RatatuiRuby::` for every widget (e.g., `RatatuiRuby::Paragraph.new`) is tedious. It creates visual noise that hides your layout structure.
94
+ **The Problem:** Explicitly namespacing `RatatuiRuby::` for every widget (e.g., `RatatuiRuby::Widgets::Paragraph.new`) is tedious. It creates visual noise that hides your layout structure.
95
95
 
96
- **The Solution:** The Session API (`tui`) provides shorthand factories for every widget. It yields a session object to your block.
96
+ **The Solution:** The TUI API (`tui`) provides shorthand factories for every widget. It yields a TUI object to your block.
97
97
 
98
98
  ```ruby
99
99
  RatatuiRuby.run do |tui|
@@ -147,31 +147,31 @@ RatatuiRuby.run do
147
147
  loop do
148
148
  RatatuiRuby.draw do |frame|
149
149
  # Manual split
150
- rects = RatatuiRuby::Layout.split(
150
+ rects = RatatuiRuby::Layout::Layout.split(
151
151
  frame.area,
152
152
  direction: :horizontal,
153
153
  constraints: [
154
- RatatuiRuby::Constraint.length(20),
155
- RatatuiRuby::Constraint.min(0)
154
+ RatatuiRuby::Layout::Constraint.length(20),
155
+ RatatuiRuby::Layout::Constraint.min(0)
156
156
  ]
157
157
  )
158
158
 
159
159
  frame.render_widget(
160
- RatatuiRuby::Paragraph.new(
160
+ RatatuiRuby::Widgets::Paragraph.new(
161
161
  text: RatatuiRuby::Text::Line.new(spans: [
162
- RatatuiRuby::Text::Span.new(content: "Side", style: RatatuiRuby::Style.new(fg: :blue)),
162
+ RatatuiRuby::Text::Span.new(content: "Side", style: RatatuiRuby::Style::Style.new(fg: :blue)),
163
163
  RatatuiRuby::Text::Span.new(content: "bar")
164
164
  ]),
165
- block: RatatuiRuby::Block.new(borders: [:all], title: "Nav")
165
+ block: RatatuiRuby::Widgets::Block.new(borders: [:all], title: "Nav")
166
166
  ),
167
167
  rects[0]
168
168
  )
169
169
 
170
170
  frame.render_widget(
171
- RatatuiRuby::Paragraph.new(
171
+ RatatuiRuby::Widgets::Paragraph.new(
172
172
  text: "Main Content",
173
- style: RatatuiRuby::Style.new(fg: :green),
174
- block: RatatuiRuby::Block.new(borders: [:all], title: "Content")
173
+ style: RatatuiRuby::Style::Style.new(fg: :green),
174
+ block: RatatuiRuby::Widgets::Block.new(borders: [:all], title: "Content")
175
175
  ),
176
176
  rects[1]
177
177
  )
@@ -189,7 +189,7 @@ Building for Ruby 4.0's parallel future? Know which objects can travel between R
189
189
 
190
190
  ### Data Objects (Shareable)
191
191
 
192
- These are deeply frozen and `Ractor.shareable?`. Include them in TEA Models/Messages freely:
192
+ These are deeply frozen and `Ractor.shareable?`. Include them in immutable Models/Messages freely:
193
193
 
194
194
  | Object | Source |
195
195
  |--------|--------|
@@ -203,7 +203,7 @@ These have side effects and are intentionally not shareable:
203
203
 
204
204
  | Object | Valid Usage |
205
205
  |--------|-------------|
206
- | `Session` | Cache in `@tui` during run loop. Don't include in Models. |
206
+ | `TUI` | Cache in `@tui` during run loop. Don't include in Models. |
207
207
  | `Frame` | Pass to helpers during draw block. Invalid after block returns. |
208
208
 
209
209
  ```ruby
@@ -224,7 +224,7 @@ Simple scripts work well with valid linear code. Complex apps need structure.
224
224
 
225
225
  We provide these reference architectures to inspire you:
226
226
 
227
- ### Proto-TEA (Model-View-Update)
227
+ ### Model-View-Update
228
228
 
229
229
  **Source:** [examples/app_all_events](../examples/app_all_events/README.md)
230
230
 
@@ -236,7 +236,7 @@ This pattern implements unidirectional data flow inspired by The Elm Architectur
236
236
 
237
237
  Use this when you want predictable state management and easy-to-test logic.
238
238
 
239
- ### Proto-Kit (Component-Based)
239
+ ### Component-Based
240
240
 
241
241
  **Source:** [examples/app_color_picker](../examples/app_color_picker/README.md)
242
242
 
@@ -45,7 +45,7 @@ def test_rendering
45
45
  # Uses default 80x24 terminal
46
46
  with_test_terminal do
47
47
  # 1. Instantiate your widget
48
- widget = RatatuiRuby::Paragraph.new(text: "Hello World")
48
+ widget = RatatuiRuby::Widgets::Paragraph.new(text: "Hello World")
49
49
 
50
50
  # 2. Render it using the Frame API
51
51
  RatatuiRuby.draw do |frame|
data/doc/async.md ADDED
@@ -0,0 +1,160 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
3
+ SPDX-License-Identifier: AGPL-3.0-or-later
4
+ -->
5
+
6
+ # Async Operations in TUI Applications
7
+
8
+ TUI applications fetch data from APIs, run shell commands, and query databases. These operations take time. Blocking the render loop freezes the interface.
9
+
10
+ You want responsive UIs. The checklist shows "Loading..." while data arrives. The interface never hangs.
11
+
12
+ This guide explains async patterns that work with raw terminal mode.
13
+
14
+ ## The Raw Terminal Problem
15
+
16
+ `RatatuiRuby.run` enters raw terminal mode:
17
+
18
+ - stdin reconfigures for character-by-character input
19
+ - stdout carries terminal escape sequences
20
+ - External commands expecting normal terminal I/O fail
21
+
22
+ ### What Breaks
23
+
24
+ ```ruby
25
+ # These fail inside a Thread during raw mode:
26
+ `git ls-remote --tags origin` # Returns empty or hangs
27
+ IO.popen(["git", "ls-remote", ...]) # Same
28
+ Open3.capture2("git", "ls-remote", ...) # Same
29
+ ```
30
+
31
+ The commands succeed synchronously. They fail asynchronously. The difference: thread context inherits the parent's raw terminal state.
32
+
33
+ ### Why Threads Fail
34
+
35
+ Ruby's GIL releases during I/O. But:
36
+
37
+ 1. Subprocesses inherit the parent's terminal state.
38
+ 2. Git/SSH try to read credentials from raw-mode stdin.
39
+ 3. The read blocks forever. Or returns empty.
40
+
41
+ `GIT_TERMINAL_PROMPT=0` prevents prompts. Auth fails silently instead of hanging.
42
+
43
+ ## Solutions
44
+
45
+ ### Pre-Check Before Raw Mode
46
+
47
+ Run slow operations before entering the TUI:
48
+
49
+ ```ruby
50
+ def initialize
51
+ @data = fetch_data # Runs before RatatuiRuby.run
52
+ end
53
+ ```
54
+
55
+ **Trade-off**: Delays startup.
56
+
57
+ ### Process.spawn with File Output
58
+
59
+ Spawn a separate process before entering raw mode. Write results to a temp file. Poll for completion:
60
+
61
+ ```ruby
62
+ class AsyncChecker
63
+ CACHE_FILE = File.join(Dir.tmpdir, "my_check_result.txt")
64
+
65
+ def initialize
66
+ @loading = true
67
+ @result = nil
68
+ @pid = Process.spawn("my-command > #{CACHE_FILE}")
69
+ end
70
+
71
+ def loading?
72
+ return false unless @loading
73
+
74
+ # Non-blocking poll
75
+ _pid, status = Process.waitpid2(@pid, Process::WNOHANG)
76
+ if status
77
+ @result = File.read(CACHE_FILE).strip
78
+ @loading = false
79
+ end
80
+ @loading
81
+ end
82
+ end
83
+ ```
84
+
85
+ **Key points**:
86
+
87
+ - `Process.spawn` returns immediately.
88
+ - The command runs in a separate process, not a thread.
89
+ - Results pass through a temp file. Avoids pipe/terminal issues.
90
+ - `Process::WNOHANG` polls without blocking.
91
+
92
+ ### Thread for CPU-Bound Work
93
+
94
+ Ruby threads work for pure computation:
95
+
96
+ ```ruby
97
+ Thread.new { @result = expensive_calculation }
98
+ ```
99
+
100
+ Avoid threads for shell commands.
101
+
102
+ ## Ractors
103
+
104
+ Ractors provide true parallelism. Trade-offs:
105
+
106
+ - No mutable shared state.
107
+ - Limited to Ractor-safe values.
108
+ - Terminal I/O issues remain.
109
+
110
+ For TUI async, `Process.spawn` solves the problem cleanly.
111
+
112
+ ## Pattern Summary
113
+
114
+ | Approach | Use Case | Raw Mode Safe? |
115
+ |----------|----------|----------------|
116
+ | Sync before TUI | Fast checks (<100ms) | Yes |
117
+ | Process.spawn + file | Shell commands, network | Yes |
118
+ | Thread | CPU-bound Ruby code | Yes |
119
+ | Thread + shell | Shell commands | **No** |
120
+
121
+ ## Real Example: Git Tag Check
122
+
123
+ Check if a tag exists on the remote:
124
+
125
+ ```ruby
126
+ class GitRepo
127
+ CACHE_FILE = File.join(Dir.tmpdir, "git_tag_pushed.txt")
128
+
129
+ def initialize
130
+ @version = `git describe --tags --abbrev=0`.strip
131
+ @tag_pushed = nil
132
+ @loading = true
133
+ @pid = Process.spawn(
134
+ "git ls-remote --tags origin | grep -q '#{@version}' " \
135
+ "&& echo true > #{CACHE_FILE} || echo false > #{CACHE_FILE}"
136
+ )
137
+ end
138
+
139
+ def loading?
140
+ return false unless @loading
141
+
142
+ _pid, status = Process.waitpid2(@pid, Process::WNOHANG)
143
+ if status
144
+ @tag_pushed = File.read(CACHE_FILE).strip == "true"
145
+ @loading = false
146
+ end
147
+ @loading
148
+ end
149
+
150
+ def refresh
151
+ # Sync version for manual refresh (user presses 'r')
152
+ @loading = true
153
+ remote_tags = `git ls-remote --tags origin`.strip
154
+ @tag_pushed = remote_tags.include?(@version)
155
+ @loading = false
156
+ end
157
+ end
158
+ ```
159
+
160
+ The TUI starts instantly. The tag check runs in the background. The checklist updates when the result arrives.