ratatui_ruby 1.0.0 → 1.1.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 (88) 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 +3 -2
  7. data/CHANGELOG.md +33 -7
  8. data/Steepfile +1 -0
  9. data/doc/concepts/application_testing.md +5 -5
  10. data/doc/concepts/event_handling.md +1 -1
  11. data/doc/contributors/design/ruby_frontend.md +40 -12
  12. data/doc/contributors/design/rust_backend.md +13 -1
  13. data/doc/contributors/releasing.md +215 -0
  14. data/doc/contributors/todo/align/api_completeness_audit-finished.md +6 -0
  15. data/doc/contributors/todo/align/api_completeness_audit-unfinished.md +1 -7
  16. data/doc/contributors/todo/align/term.md +351 -0
  17. data/doc/contributors/upstream_requests/paragraph_span_rects.md +259 -0
  18. data/doc/getting_started/quickstart.md +1 -1
  19. data/doc/getting_started/why.md +3 -3
  20. data/doc/images/app_external_editor.gif +0 -0
  21. data/doc/index.md +1 -6
  22. data/examples/app_external_editor/README.md +62 -0
  23. data/examples/app_external_editor/app.rb +344 -0
  24. data/examples/widget_list/app.rb +2 -4
  25. data/examples/widget_table/app.rb +8 -2
  26. data/ext/ratatui_ruby/Cargo.lock +1 -1
  27. data/ext/ratatui_ruby/Cargo.toml +1 -1
  28. data/ext/ratatui_ruby/src/events.rs +171 -203
  29. data/ext/ratatui_ruby/src/lib.rs +36 -0
  30. data/ext/ratatui_ruby/src/lib_header.rs +11 -0
  31. data/ext/ratatui_ruby/src/terminal/capabilities.rs +46 -0
  32. data/ext/ratatui_ruby/src/terminal/init.rs +92 -0
  33. data/ext/ratatui_ruby/src/terminal/mod.rs +12 -3
  34. data/ext/ratatui_ruby/src/terminal/queries.rs +15 -0
  35. data/ext/ratatui_ruby/src/terminal/query.rs +64 -2
  36. data/lib/ratatui_ruby/backend/window_size.rb +50 -0
  37. data/lib/ratatui_ruby/backend.rb +59 -0
  38. data/lib/ratatui_ruby/event/key/navigation.rb +10 -1
  39. data/lib/ratatui_ruby/event/key.rb +84 -0
  40. data/lib/ratatui_ruby/event/mouse.rb +95 -3
  41. data/lib/ratatui_ruby/event/resize.rb +45 -3
  42. data/lib/ratatui_ruby/layout/alignment.rb +91 -0
  43. data/lib/ratatui_ruby/layout/layout.rb +1 -2
  44. data/lib/ratatui_ruby/layout/size.rb +10 -3
  45. data/lib/ratatui_ruby/layout.rb +4 -0
  46. data/lib/ratatui_ruby/terminal/capabilities.rb +316 -0
  47. data/lib/ratatui_ruby/terminal/viewport.rb +1 -1
  48. data/lib/ratatui_ruby/terminal.rb +66 -0
  49. data/lib/ratatui_ruby/test_helper/global_state.rb +111 -0
  50. data/lib/ratatui_ruby/test_helper.rb +3 -0
  51. data/lib/ratatui_ruby/version.rb +1 -1
  52. data/lib/ratatui_ruby/widgets/table.rb +2 -2
  53. data/lib/ratatui_ruby.rb +25 -4
  54. data/sig/examples/app_external_editor/app.rbs +12 -0
  55. data/sig/generated/event_key_predicates.rbs +1348 -0
  56. data/sig/ratatui_ruby/backend/window_size.rbs +17 -0
  57. data/sig/ratatui_ruby/backend.rbs +12 -0
  58. data/sig/ratatui_ruby/event.rbs +7 -0
  59. data/sig/ratatui_ruby/layout/alignment.rbs +26 -0
  60. data/sig/ratatui_ruby/ratatui_ruby.rbs +2 -0
  61. data/sig/ratatui_ruby/terminal/capabilities.rbs +38 -0
  62. data/sig/ratatui_ruby/terminal/viewport.rbs +15 -1
  63. data/tasks/bump/bump_workflow.rb +49 -0
  64. data/tasks/bump/changelog.rb +57 -0
  65. data/tasks/bump/patch_release.rb +19 -0
  66. data/tasks/bump/release_branch.rb +17 -0
  67. data/tasks/bump/release_from_trunk.rb +49 -0
  68. data/tasks/bump/repository.rb +54 -0
  69. data/tasks/bump/ruby_gem.rb +6 -26
  70. data/tasks/bump/sem_ver.rb +4 -0
  71. data/tasks/bump/unreleased_section.rb +17 -0
  72. data/tasks/bump.rake +21 -11
  73. data/tasks/doc/documentation.rb +59 -0
  74. data/tasks/doc/link/file_url.rb +30 -0
  75. data/tasks/doc/link/relative_path.rb +61 -0
  76. data/tasks/doc/link/web_url.rb +55 -0
  77. data/tasks/doc/link.rb +52 -0
  78. data/tasks/doc/link_audit.rb +116 -0
  79. data/tasks/doc/problem.rb +40 -0
  80. data/tasks/doc/source_file.rb +93 -0
  81. data/tasks/doc.rake +18 -0
  82. data/tasks/rbs_predicates/predicate_catalog.rb +52 -0
  83. data/tasks/rbs_predicates/predicate_tests.rb +124 -0
  84. data/tasks/rbs_predicates/rbs_signature.rb +63 -0
  85. data/tasks/rbs_predicates.rake +31 -0
  86. data/tasks/test.rake +3 -0
  87. data/tasks/website/version.rb +23 -28
  88. metadata +38 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c8ee9b7928a67c0f332a1fdfd2870972ba9f37c6219879d427a5225f71a24b54
4
- data.tar.gz: 42ef63b4ca0dafb3220034af83a1d5d0acab49123378e0c5909b21c9baf60f52
3
+ metadata.gz: e4af7cd6e9b1850a0abe3099f29c1dbf4d9e4f01cd1782196b0948c8591d9ba3
4
+ data.tar.gz: 7e68a66603d410baaad20d9267b3da083bff66a1a9c7d3dd9d0142a4b89fca9f
5
5
  SHA512:
6
- metadata.gz: 68ec1dcf33fa00b9bb53852d5cc4c92c680f10924b13594854c34bc3e597db6214603c1513427cad35e31895d08cc7dd59e2ac1166dcd44f525043588b23407d
7
- data.tar.gz: c9cfbe2d111ca45cfe003fc28dea7d23f12dac8c14424701a8532d964d905e80d2fbdd2fdb2a749a291a23ef4e168e2ab0fac14c55ef874b5e1b357d75f4b66f
6
+ metadata.gz: b3790091fe5de4276ff383caffc753012efc7d8646eb7d2d5a2467e73518dbd8584c692ffec368a374d6cf9a11981be6af0d3d51a1421e48f4afe1e528547618
7
+ data.tar.gz: f63f2bbb7abf4462be09d17aabc8bdf7737853b79e4ff5d55425a2246687a23c47e5a04c19bd41405171f0e14f94749ba70e5fe07578ffcb5ffec1e248f43246
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-1.0.0.gem
19
+ - ratatui_ruby/pkg/ratatui_ruby-1.1.0.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-1.0.0.gem
19
+ - ratatui_ruby/pkg/ratatui_ruby-1.1.0.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-1.0.0.gem
19
+ - ratatui_ruby/pkg/ratatui_ruby-1.1.0.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-1.0.0.gem
19
+ - ratatui_ruby/pkg/ratatui_ruby-1.1.0.gem
20
20
  sources:
21
21
  - https://git.sr.ht/~kerrick/ratatui_ruby
22
22
  tasks:
data/AGENTS.md CHANGED
@@ -27,6 +27,7 @@ Architecture:
27
27
 
28
28
  ### STRICT REQUIREMENTS
29
29
 
30
+ - **Check Before Implementing:** FIRST check tests for existing coverage. If it works, say so and point to the test.
30
31
  - Every file MUST begin with an SPDX-compliant header. Use `AGPL-3.0-or-later` for code; `CC-BY-SA-4.0` for documentation. `reuse annotate` can help you generate the header. **For Ruby files**, wrap SPDX comments in `#--` / `#++` to hide them from RDoc output.
31
32
  - Every line of Ruby MUST be covered by tests that would stand up to mutation testing.
32
33
  - Tests must be meaningful and verify specific behavior or rendering output; simply verifying that code "doesn't crash" is insufficient and unacceptable.
@@ -62,14 +63,14 @@ Architecture:
62
63
  - Every public Ruby class/method must be documented for humans in RDoc (preferred)--**not** YARD--or markdown files (fallback), and must have `*.rbs` types defined.
63
64
  - Every significant architectural and design decision must be documented for contributors in markdown files. Mermaid is allowed.
64
65
  - **Rust-backed methods:** For methods implemented in Rust (magnus bindings), use RDoc directives instead of empty method bodies. Use `##` followed by `:method:`, `:call-seq:`, and prose. End with `(Native method implemented in Rust)`. See `lib/ratatui_ruby.rb` for examples.
65
- - Refer to [docs/contributors/design/ruby_frontend.md](docs/contributors/design/ruby_frontend.md) for detailed design philosophy regarding the Immediate Mode paradigm including Data-Driven UI and Frames.
66
+ - Refer to [doc/contributors/design/ruby_frontend.md](doc/contributors/design/ruby_frontend.md) for detailed design philosophy regarding the Immediate Mode paradigm including Data-Driven UI and Frames.
66
67
 
67
68
  ### Rust Standards
68
69
 
69
70
  - **Crate Type:** `cdylib`.
70
71
  - **Bindings:** Use [magnus](https://github.com/matsadler/magnus).
71
72
  - **Platform:** Support macOS (Apple Silicon), Linux, and Windows.
72
- - Refer to [docs/contributors/design/rust_backend.md](docs/contributors/design/rust_backend.md) for detailed implementation guidelines, module structure, and rendering logic.
73
+ - Refer to [doc/contributors/design/rust_backend.md](doc/contributors/design/rust_backend.md) for detailed implementation guidelines, module structure, and rendering logic.
73
74
 
74
75
  ## 2. Directory Structure Convention
75
76
 
data/CHANGELOG.md CHANGED
@@ -18,15 +18,41 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
18
18
 
19
19
  ### Removed
20
20
 
21
+ ## [1.1.0] - 2026-01-25
22
+
23
+ ### Added
24
+
25
+ - **Terminal Capability Detection**: New class methods on `RatatuiRuby::Terminal` for environment-based capability detection before initializing TUI mode:
26
+ - `Terminal.tty?` — checks if stdout is connected to a terminal
27
+ - `Terminal.dumb?` — checks if TERM is explicitly set to "dumb"
28
+ - `Terminal.no_color?` — checks if NO_COLOR environment variable is set (respects the [NO_COLOR standard](https://no-color.org/))
29
+ - `Terminal.force_color?` — checks if FORCE_COLOR environment variable is set
30
+ - `Terminal.interactive?` — returns true only when tty? and not dumb?
31
+ - `Terminal.available_color_count` — returns color support level (8, 256, or 65535) via crossterm detection
32
+ - `Terminal.color_support` — convenience method returning `:none`, `:basic`, `:ansi256`, or `:truecolor`
33
+ - `Terminal.supports_keyboard_enhancement?` — checks for Kitty keyboard protocol support
34
+ - `Backend.window_size` — returns terminal dimensions as `Backend::WindowSize` with both character grid (`columns_rows`) and pixel (`pixels`) sizes as `Layout::Size` instances; mirrors upstream Ratatui's `backend::WindowSize` struct
35
+ - `Terminal.force_color_output(enable)` — globally overrides NO_COLOR detection for `--color=always` flags
36
+ - **Alignment Constants**: New `RatatuiRuby::Layout::HorizontalAlignment` and `RatatuiRuby::Layout::VerticalAlignment` modules with discoverable constants (`LEFT`, `CENTER`, `RIGHT`, `TOP`, `BOTTOM`). `Layout::Alignment` is an alias for `HorizontalAlignment`. Use the constants for IDE discoverability, or continue passing symbols (`:left`, `:center`, etc.) directly—both work.
37
+ - **Frame Count Query**: `RatatuiRuby.frame_count` returns the number of frames drawn since terminal initialization. The count starts at 0 when the terminal is created, increments by 1 after each draw, and resets when the terminal is restored and re-initialized.
38
+ - **Mouse and Resize Symbol Comparison**: `Event::Mouse` and `Event::Resize` now support symbol comparison via `to_sym` and `==`, matching `Event::Key`. Use `event == :mouse_left_down`, `event == :scroll_up`, or `event == :resize` for cleaner event handling.
39
+ - **Key Event DWIM Predicates**: `Event::Key` now supports alternate predicate forms for disambiguation and case handling. Arrow key aliases (`arrow_up?`, `up_arrow?`) distinguish keyboard input from `Mouse#up?`/`Mouse#down?`. The `key_` prefix and `_key` suffix (`key_up?`, `q_key?`) provide explicit key event matching in mixed event contexts. Capital letters match their shifted form naturally (`G?` matches `code="G"` with shift), and uppercase in predicates implies shift (`alt_B?` matches `alt_shift_B`).
40
+ - **Generated RBS Predicate Declarations**: New `rake rbs:predicates` task generates RBS type declarations for all 1,328 `Event::Key` predicate methods (base keys, modifiers, characters, function keys, and all modifier combinations). Predicates are derived from a single source of truth in Rust FFI.
41
+
42
+ ### Changed
43
+
44
+ ### Fixed
45
+
46
+ ### Removed
47
+
21
48
  ## [1.0.0] - 2026-01-25
22
- This release is functionally equivalent to v0.10.3, with additional bug fixes.
23
- The version bump signals the beginning of the 1.0 release series.
24
49
 
25
50
  ### Added
26
51
 
27
52
  ### Changed
28
53
 
29
54
  ### Fixed
55
+
30
56
  - **back_tab? DWIM**: `back_tab?` and `backtab?` predicates now match events with code "back_tab" regardless of whether the shift modifier is explicitly present, since back_tab semantically implies shift.
31
57
  - **Terminal Queries During Draw (Deadlock)**: Calling `viewport_area`, `terminal_size`, `get_cell_at`, `poll_event`, `get_cursor_position`, or `get_viewport_type` from inside a `draw()` block previously caused the application to freeze forever. The thread blocked on a Mutex. Ruby's `Timeout` could not interrupt it. The only recovery was `kill -9`. These reads now work via a snapshot captured before rendering.
32
58
  - **Terminal Mutations During Draw (Deadlock)**: Calling `insert_before`, `set_cursor_position`, or `resize_terminal` from inside a `draw()` block previously caused the same silent freeze. These writes now raise `Error::Invariant` with a clear message.
@@ -34,6 +60,8 @@ The version bump signals the beginning of the 1.0 release series.
34
60
  - **Event Injection During Draw (Deadlock)**: Calling `inject_test_event` from inside a `draw()` block previously froze the application. Event injection now works correctly during draw.
35
61
  - **TableState Row Navigation Methods**: Added missing row navigation methods (`select_next`, `select_previous`, `select_first`, `select_last`) that should have been included alongside the column navigation methods added in v0.10.0. These methods match `ListState`'s navigation API and are used in the `app_stateful_interaction` example.
36
62
 
63
+ ### Removed
64
+
37
65
  ## [0.10.3] - 2026-01-16
38
66
 
39
67
  ### Added
@@ -348,7 +376,7 @@ The version bump signals the beginning of the 1.0 release series.
348
376
  ## [0.7.0] - 2026-01-03
349
377
 
350
378
  > [!WARNING]
351
- > v0.7.0 contains significant breaking changes. See the [Migration Guide](doc/v0.7.0_migration.md) for upgrade instructions.
379
+ > v0.7.0 contains significant breaking changes. See the [Migration Guide](https://man.sr.ht/~kerrick/ratatui_ruby/history/migrations/v0_7_0.md) for upgrade instructions.
352
380
 
353
381
  ### Added
354
382
 
@@ -360,7 +388,7 @@ The version bump signals the beginning of the 1.0 release series.
360
388
 
361
389
  ### Changed
362
390
 
363
- - **Namespace Restructure (Breaking)**: Classes reorganized to match Ratatui's module hierarchy. See [Migration Guide](doc/v0.7.0_migration.md) for details:
391
+ - **Namespace Restructure (Breaking)**: Classes reorganized to match Ratatui's module hierarchy. See [Migration Guide](https://man.sr.ht/~kerrick/ratatui_ruby/history/migrations/v0_7_0.md) for details:
364
392
  - `RatatuiRuby::Rect` → `RatatuiRuby::Layout::Rect`
365
393
  - `RatatuiRuby::Constraint` → `RatatuiRuby::Layout::Constraint`
366
394
  - `RatatuiRuby::Layout` → `RatatuiRuby::Layout::Layout`
@@ -683,10 +711,8 @@ The version bump signals the beginning of the 1.0 release series.
683
711
  - **Testing Support**: Included `RatatuiRuby::TestHelper` and RSpec integration to make testing your TUI applications possible.
684
712
 
685
713
  [Unreleased]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/HEAD
714
+ [1.1.0]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v1.1.0
686
715
  [1.0.0]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v1.0.0
687
- [1.0.0-beta.3]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v1.0.0-beta.3
688
- [1.0.0-beta.2]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v1.0.0-beta.2
689
- [1.0.0-beta.1]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v1.0.0-beta.1
690
716
  [0.10.3]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v0.10.3
691
717
  [0.10.2]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v0.10.2
692
718
  [0.10.1]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v0.10.1
data/Steepfile CHANGED
@@ -46,4 +46,5 @@ target :lib do
46
46
  library "fileutils"
47
47
  library "minitest"
48
48
  library "date"
49
+ library "timeout"
49
50
  end
@@ -76,7 +76,7 @@ end
76
76
  ```
77
77
  <!-- SPDX-SnippetEnd -->
78
78
 
79
- For the full API list, including `buffer_content` and `cursor_position`, see [RatatuiRuby::TestHelper::Terminal](../lib/ratatui_ruby/test_helper/terminal.rb).
79
+ For the full API list, including `buffer_content` and `cursor_position`, see [RatatuiRuby::TestHelper::Terminal](../../lib/ratatui_ruby/test_helper/terminal.rb).
80
80
 
81
81
  ## Verifying Styles
82
82
 
@@ -99,7 +99,7 @@ assert_area_style({ x: 0, y: 0, w: 10, h: 1 }, bg: :blue)
99
99
  ```
100
100
  <!-- SPDX-SnippetEnd -->
101
101
 
102
- See [RatatuiRuby::TestHelper::StyleAssertions](../lib/ratatui_ruby/test_helper/style_assertions.rb) for the comprehensive list of style helpers.
102
+ See [RatatuiRuby::TestHelper::StyleAssertions](../../lib/ratatui_ruby/test_helper/style_assertions.rb) for the comprehensive list of style helpers.
103
103
 
104
104
  ## Simulating Input
105
105
 
@@ -127,7 +127,7 @@ end
127
127
  ```
128
128
  <!-- SPDX-SnippetEnd -->
129
129
 
130
- See [RatatuiRuby::TestHelper::EventInjection](../lib/ratatui_ruby/test_helper/event_injection.rb) for helper methods like `inject_keys` and `inject_click`.
130
+ See [RatatuiRuby::TestHelper::EventInjection](../../lib/ratatui_ruby/test_helper/event_injection.rb) for helper methods like `inject_keys` and `inject_click`.
131
131
 
132
132
  ## Snapshot Testing
133
133
 
@@ -158,7 +158,7 @@ To prevent this:
158
158
  1. **Seed Randomness:** Use a fixed seed for any RNG.
159
159
  2. **Stub Time:** Force the application to use a static time.
160
160
 
161
- For detailed strategies and code examples, see [RatatuiRuby::TestHelper::Snapshot](../lib/ratatui_ruby/test_helper/snapshot.rb).
161
+ For detailed strategies and code examples, see [RatatuiRuby::TestHelper::Snapshot](../../lib/ratatui_ruby/test_helper/snapshot.rb).
162
162
 
163
163
  ## Isolated View Testing
164
164
 
@@ -186,7 +186,7 @@ end
186
186
  ```
187
187
  <!-- SPDX-SnippetEnd -->
188
188
 
189
- See [RatatuiRuby::TestHelper::TestDoubles](../lib/ratatui_ruby/test_helper/test_doubles.rb).
189
+ See [RatatuiRuby::TestHelper::TestDoubles](../../lib/ratatui_ruby/test_helper/test_doubles.rb).
190
190
 
191
191
  ## Example
192
192
 
@@ -27,7 +27,7 @@ For simple key events, `RatatuiRuby::Event::Key` objects can be compared directl
27
27
  > [!NOTE]
28
28
  > On macOS, the **Option** key is mapped to `alt`. The **Command** key is typically intercepted by the terminal emulator and may not be sent to the application, or it may be mapped to Meta/Alt depending on your terminal settings.
29
29
 
30
- For a complete list of supported keys, modifiers, and event types, please refer to the [API Documentation for RatatuiRuby::Event](file:///Users/kerrick/Developer/ratatui_ruby/lib/ratatui_ruby/event.rb).
30
+ For a complete list of supported keys, modifiers, and event types, please refer to the [API Documentation for RatatuiRuby::Event](../../lib/ratatui_ruby/event.rb).
31
31
 
32
32
  <!-- SPDX-SnippetBegin -->
33
33
  <!--
@@ -9,25 +9,53 @@ This document describes the architectural design and guiding principles of the R
9
9
 
10
10
  ## Guiding Design Principles
11
11
 
12
- ### 1. Ratatui Alignment
12
+ ### 1. Three-Tier Namespace Architecture
13
13
 
14
- The Ruby namespace structure mirrors Ratatui's Rust module hierarchy exactly. This is a deliberate architectural choice with specific benefits:
14
+ The gem provides three distinct namespaces, each with a specific purpose:
15
15
 
16
- - **Documentation Mapping**: A contributor reading Ratatui's docs for `ratatui::widgets::Table` immediately knows to look at `RatatuiRuby::Widgets::Table`.
17
- - **Predictability**: No mental translation required between Rust and Ruby codebases.
18
- - **Scalability**: As Ratatui adds new types, the Ruby placement is deterministic.
16
+ **Tier 1: `Ratatui::` Upstream Alignment**
19
17
 
20
- **Module Mapping:**
18
+ Pure upstream Ratatui types with 1:1 API correspondence. If it exists in Rust Ratatui, it has the same name and location here.
21
19
 
22
20
  | Rust Module | Ruby Module | Purpose |
23
21
  |-------------|-------------|---------|
24
- | `ratatui::layout` | `RatatuiRuby::Layout` | Rect, Constraint, Layout |
25
- | `ratatui::widgets` | `RatatuiRuby::Widgets` | All widgets (Table, List, Paragraph, Block, etc.) |
26
- | `ratatui::style` | `RatatuiRuby::Style` | Style, Color |
27
- | `ratatui::text` | `RatatuiRuby::Text` | Span, Line |
28
- | `ratatui::buffer` | `RatatuiRuby::Buffer` | Cell (for buffer inspection) |
22
+ | `ratatui::layout` | `Ratatui::Layout` | Rect, Constraint, Layout, Position, Size |
23
+ | `ratatui::widgets` | `Ratatui::Widgets` | All widgets (Table, List, Paragraph, Block, etc.) |
24
+ | `ratatui::style` | `Ratatui::Style` | Style, Color |
25
+ | `ratatui::text` | `Ratatui::Text` | Span, Line |
26
+ | `ratatui::buffer` | `Ratatui::Buffer` | Cell (for buffer inspection) |
27
+ | `ratatui::backend` | `Ratatui::Backend` | WindowSize |
28
+ | `ratatui::Terminal` | `Ratatui::Terminal` | Terminal lifecycle (draw, size, cursor) |
29
+ | `ratatui::Frame` | `Ratatui::Frame` | Frame object for render callbacks |
29
30
 
30
- This structure resolves name collisions that would otherwise require arbitrary prefixes. For example, `Buffer::Cell` (terminal cell inspection) vs `Widgets::Cell` (table cell construction) are clearly distinct.
31
+ **Tier 2: `Crossterm::` Backend Alignment**
32
+
33
+ Direct exposure of crossterm functionality. These are terminal I/O primitives that Ratatui builds upon.
34
+
35
+ | Rust Module | Ruby Module | Purpose |
36
+ |-------------|-------------|---------|
37
+ | `crossterm::terminal` | `Crossterm::Terminal` | `supports_keyboard_enhancement?`, `window_size` |
38
+ | `crossterm::style` | `Crossterm::Style` | `available_color_count`, `force_color_output` |
39
+
40
+ **Tier 3: `RatatuiRuby::` — Ruby Convenience Layer**
41
+
42
+ Ruby-specific conveniences, the main entry point, and the TUI DSL facade. This is where Ruby idioms live.
43
+
44
+ - `RatatuiRuby.run { |tui| ... }` — Main entry point with setup/teardown
45
+ - `RatatuiRuby.tty?`, `RatatuiRuby.dumb?`, `RatatuiRuby.interactive?` — Environment detection (Ruby-specific)
46
+ - `RatatuiRuby::TUI` — DSL facade with shorthand factory methods
47
+ - `RatatuiRuby::TestHelper` — Testing utilities
48
+ - `RatatuiRuby::Error` — Exception hierarchy
49
+
50
+ **Why Three Tiers?**
51
+
52
+ 1. **Upstream Purity**: Users who want exact Ratatui API parity use `Ratatui::` and `Crossterm::` namespaces.
53
+ 2. **Ruby Idioms**: Users who want convenience use `RatatuiRuby.run`, the TUI facade, and helper methods.
54
+ 3. **Documentation Mapping**: A contributor reading Ratatui's Rust docs immediately knows where to find the Ruby equivalent.
55
+ 4. **Predictability**: As upstream adds types, their Ruby placement is deterministic.
56
+
57
+ > [!NOTE]
58
+ > This three-tier architecture will be rolled out incrementally as 1.x releases. The `Ratatui::` and `Crossterm::` namespaces are additive—`RatatuiRuby::` will continue to work by delegating to them. No breaking changes required.
31
59
 
32
60
  ### 2. Two-Layer Architecture
33
61
 
@@ -166,11 +166,20 @@ Defines the Ruby module hierarchy using `magnus` and exports public functions (`
166
166
 
167
167
  Manages the global `TERMINAL` singleton (mutex-wrapped `CrosstermBackend<Stdout>`).
168
168
 
169
- Key functions:
169
+ **Lifecycle Functions:**
170
170
  - `init()` — Enter raw mode, enable mouse capture, switch to alternate screen
171
171
  - `restore()` — Disable raw mode, restore main screen
172
172
  - `get_cell_at(x, y)` — Return buffer cell as Ruby `Buffer::Cell` object
173
173
 
174
+ **Crossterm Capability Queries:**
175
+
176
+ These functions expose crossterm's terminal capability detection to Ruby. In the three-tier architecture, they'll be surfaced via the `Crossterm::` namespace:
177
+
178
+ - `terminal_window_size()` — Returns `(columns, rows, pixel_width, pixel_height)` via `crossterm::terminal::window_size()`
179
+ - `available_color_count()` — Returns color depth (8/256/65535) via crossterm's `COLORTERM`/`TERM` detection
180
+ - `supports_keyboard_enhancement()` — Queries Kitty keyboard protocol support
181
+ - `force_color_output(enable)` — Overrides `NO_COLOR` detection via `crossterm::style::force_color_output()`
182
+
174
183
  **Safety Note:** The terminal is a global mutable resource. All access goes through a mutex. Holding the lock across Ruby calls risks deadlock—release the lock before calling back into Ruby.
175
184
 
176
185
  ### `frame.rs` — Frame Wrapper
@@ -230,6 +239,9 @@ pub fn render_widget(frame: &mut Frame, area: Rect, node: Value) -> Result<(), E
230
239
 
231
240
  **Namespace Pattern:** All built-in widgets use the `RatatuiRuby::Widgets::*` namespace. The dispatcher matches on full class names, not prefixes.
232
241
 
242
+ > [!NOTE]
243
+ > The dispatcher will be updated to also match `Ratatui::Widgets::*` class names when the three-tier namespace architecture rolls out. This is additive—existing `RatatuiRuby::` names will continue to work. See [Ruby Frontend Design](./ruby_frontend.md) for details.
244
+
233
245
  ### `widgets/*.rs` — Widget Renderers
234
246
 
235
247
  Each widget has its own module with a standard interface:
@@ -0,0 +1,215 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
+ SPDX-License-Identifier: CC-BY-SA-4.0
4
+ -->
5
+
6
+ # Releasing
7
+
8
+ This guide documents RatatuiRuby's release workflow. We use
9
+ [trunk-based development](https://trunkbaseddevelopment.com/committing-straight-to-the-trunk/)
10
+ with [release branches](https://trunkbaseddevelopment.com/branch-for-release/).
11
+
12
+ ## Overview
13
+
14
+ - **`trunk`** — Active development. Features land here first.
15
+ - **`release/X.Y`** — Release series branches (e.g., `release/1.0`).
16
+ - **`stable`** — Always points to the latest stable release.
17
+
18
+ <!-- SPDX-SnippetBegin -->
19
+ <!--
20
+ SPDX-FileCopyrightText: 2026 Kerrick Long
21
+ SPDX-License-Identifier: MIT-0
22
+ -->
23
+ ```
24
+ trunk ──●──●──●──●──●──●──●──●──●── (future work)
25
+ \ \
26
+ release/1.0 ───●──●──● \ (1.0.0, 1.0.1, ...)
27
+ \
28
+ release/1.1 ●──●──●── (1.1.0, 1.1.1, ...)
29
+ ```
30
+ <!-- SPDX-SnippetEnd -->
31
+
32
+ ## Versioning Philosophy
33
+
34
+ We follow strict SemVer without ceremony:
35
+
36
+ - **Breaking change?** → Bump major
37
+ - **New feature?** → Bump minor
38
+ - **Bug fix?** → Bump patch
39
+
40
+ Version numbers are technical artifacts, not marketing. If we end up at v50 by
41
+ year's end, so be it.
42
+
43
+ ## Changelog Management
44
+
45
+ Trunk maintains the canonical project history. Each release branch maintains
46
+ its own changelog during development, then syncs back to trunk.
47
+
48
+ ### During Beta/RC Cycles
49
+
50
+ The release branch (`release/1.0`) tracks granular changes:
51
+
52
+ <!-- SPDX-SnippetBegin -->
53
+ <!--
54
+ SPDX-FileCopyrightText: 2026 Kerrick Long
55
+ SPDX-License-Identifier: MIT-0
56
+ -->
57
+ ```markdown
58
+ ## [Unreleased]
59
+
60
+ ## [1.0.0-beta.2] - 2026-01-20
61
+ ### Fixed
62
+ - TableState row navigation methods
63
+
64
+ ## [1.0.0-beta.1] - 2026-01-20
65
+ - Initial 1.0 beta release
66
+ ```
67
+ <!-- SPDX-SnippetEnd -->
68
+
69
+ Trunk's `[Unreleased]` section accumulates features for the next minor:
70
+
71
+ <!-- SPDX-SnippetBegin -->
72
+ <!--
73
+ SPDX-FileCopyrightText: 2026 Kerrick Long
74
+ SPDX-License-Identifier: MIT-0
75
+ -->
76
+ ```markdown
77
+ ## [Unreleased]
78
+ ### Added
79
+ - Terminal Capability Detection
80
+
81
+ ### Fixed
82
+ - TableState row navigation methods
83
+ ```
84
+ <!-- SPDX-SnippetEnd -->
85
+
86
+ The fix appears in both places. This is correct — both branches contain it.
87
+
88
+ ### When Final Ships
89
+
90
+ When `1.0.0` final releases, **consolidate** all beta entries into one section
91
+ on both branches:
92
+
93
+ **release/1.0:**
94
+ <!-- SPDX-SnippetBegin -->
95
+ <!--
96
+ SPDX-FileCopyrightText: 2026 Kerrick Long
97
+ SPDX-License-Identifier: MIT-0
98
+ -->
99
+ ```markdown
100
+ ## [1.0.0] - 2026-xx-xx
101
+ ### Fixed
102
+ - TableState row navigation methods
103
+
104
+ ## [0.10.3] - 2026-01-16
105
+ ...
106
+ ```
107
+ <!-- SPDX-SnippetEnd -->
108
+
109
+ **trunk (synced):**
110
+ <!-- SPDX-SnippetBegin -->
111
+ <!--
112
+ SPDX-FileCopyrightText: 2026 Kerrick Long
113
+ SPDX-License-Identifier: MIT-0
114
+ -->
115
+ ```markdown
116
+ ## [Unreleased]
117
+ ### Added
118
+ - Terminal Capability Detection
119
+
120
+ ## [1.0.0] - 2026-xx-xx
121
+ ### Fixed
122
+ - TableState row navigation methods
123
+
124
+ ## [0.10.3] - 2026-01-16
125
+ ...
126
+ ```
127
+ <!-- SPDX-SnippetEnd -->
128
+
129
+ The beta granularity served its purpose during testing. Git tags preserve the
130
+ detailed history.
131
+
132
+ ## Release Workflows
133
+
134
+ ### Bugfix (Patch) Release
135
+
136
+ For bugs affecting a released version:
137
+
138
+ 1. **Fix on trunk first** — All bugs get fixed on trunk.
139
+ 2. **Cherry-pick to release branch** with provenance:
140
+ ```bash
141
+ git checkout release/1.0
142
+ git cherry-pick -x <commit> # -x adds "cherry picked from" trailer
143
+ ```
144
+ 3. **Update the changelog** on the release branch.
145
+ 4. **Bump and release:**
146
+ ```bash
147
+ bundle exec rake bump:patch
148
+ bundle exec rake release
149
+ ```
150
+
151
+ ### New Version (Major/Minor)
152
+
153
+ When trunk is ready for a new release series:
154
+
155
+ 1. **Decide version** based on changes:
156
+ - Breaking changes → Major (2.0.0)
157
+ - New features only → Minor (1.1.0)
158
+
159
+ 2. **Create release branch:**
160
+ ```bash
161
+ git checkout trunk
162
+ git checkout -b release/1.1 # or release/2.0
163
+ ```
164
+
165
+ 3. **Release from the branch:**
166
+ ```bash
167
+ bundle exec rake bump:exact[1.1.0-beta.1]
168
+ bundle exec rake release
169
+ ```
170
+
171
+ 4. **Bump trunk** to the next dev version if desired.
172
+
173
+ 5. **Iterate** through betas/RCs as needed, then ship final.
174
+
175
+ 6. **Sync changelog** — When final ships, add the consolidated section to trunk.
176
+
177
+ ### Prerelease Notes
178
+
179
+ RubyGems normalizes prerelease versions. Our `rake release` task automatically:
180
+
181
+ 1. Lets Bundler create the normalized tag (e.g., `v1.0.0.pre.beta.1`)
182
+ 2. Deletes it locally and remotely
183
+ 3. Creates the SemVer tag (e.g., `v1.0.0-beta.1`) and pushes it
184
+
185
+ This keeps our Git tags strictly SemVer-compliant.
186
+
187
+ ## Commands Reference
188
+
189
+ <!-- SPDX-SnippetBegin -->
190
+ <!--
191
+ SPDX-FileCopyrightText: 2026 Kerrick Long
192
+ SPDX-License-Identifier: MIT-0
193
+ -->
194
+ ```bash
195
+ # Bump version
196
+ bundle exec rake bump:patch # 1.0.0 → 1.0.1
197
+ bundle exec rake bump:minor # 1.0.0 → 1.1.0
198
+ bundle exec rake bump:major # 1.0.0 → 2.0.0
199
+ bundle exec rake bump:exact[1.0.0-beta.1]
200
+
201
+ # Release (builds, tags, pushes gem, updates stable branch)
202
+ bundle exec rake release
203
+
204
+ # Watch builds
205
+ bin/hbs # Wait for SourceHut builds
206
+ bin/hbs && bundle exec rake release # Release only if builds pass
207
+ ```
208
+ <!-- SPDX-SnippetEnd -->
209
+
210
+ ## Further Reading
211
+
212
+ - [Trunk-Based Development](https://trunkbaseddevelopment.com/)
213
+ - [Branch for Release](https://trunkbaseddevelopment.com/branch-for-release/)
214
+ - [SemVer Specification](https://semver.org/)
215
+ - [Keep a Changelog](https://keepachangelog.com/)
@@ -62,6 +62,12 @@ These documents catalog EVERY public feature, method, function, enum variant, an
62
62
  | Direction::Vertical | ratatui-core/src/layout/direction.rs:20 | ✅ |
63
63
  | Position struct | ratatui-core/src/layout/position.rs:57 | ✅ |
64
64
  | Size struct | ratatui-core/src/layout/size.rs:46 | ✅ |
65
+ | HorizontalAlignment::Left | ratatui-core/src/layout/alignment.rs:25 | ✅ |
66
+ | HorizontalAlignment::Center | ratatui-core/src/layout/alignment.rs:26 | ✅ |
67
+ | HorizontalAlignment::Right | ratatui-core/src/layout/alignment.rs:27 | ✅ |
68
+ | VerticalAlignment::Top | ratatui-core/src/layout/alignment.rs:40 | ✅ |
69
+ | VerticalAlignment::Center | ratatui-core/src/layout/alignment.rs:41 | ✅ |
70
+ | VerticalAlignment::Bottom | ratatui-core/src/layout/alignment.rs:42 | ✅ |
65
71
  | Rect struct | ratatui-core/src/layout/rect.rs:134 | ✅ |
66
72
  | Rect::new | ratatui-core/src/layout/rect.rs:166 | ✅ |
67
73
  | Rect::area | ratatui-core/src/layout/rect.rs:190 | ✅ |
@@ -29,19 +29,13 @@ These documents catalog EVERY public feature, method, function, enum variant, an
29
29
 
30
30
  **Notes:**
31
31
  - **Terminal struct**: No direct Terminal object; abstracted behind `RatatuiRuby` module methods
32
- - **Terminal::get_cursor_position/set_cursor_position**: Only available via [Frame](file:///Users/kerrick/Developer/ratatui_ruby/lib/ratatui_ruby/frame.rb#72-257) during draw, not on Terminal
32
+ - **Terminal::get_cursor_position/set_cursor_position**: Only available via [Frame](../../../../lib/ratatui_ruby/frame.rb#72-257) during draw, not on Terminal
33
33
 
34
34
  ## Layout Features
35
35
 
36
36
  | Feature Name | File/Line | Status |
37
37
  |--------------|-----------|--------|
38
38
  | Spacing enum | ratatui-core/src/layout/layout.rs:80 | ❌ |
39
- | HorizontalAlignment::Left | ratatui-core/src/layout/alignment.rs:25 | ❌ |
40
- | HorizontalAlignment::Center | ratatui-core/src/layout/alignment.rs:26 | ❌ |
41
- | HorizontalAlignment::Right | ratatui-core/src/layout/alignment.rs:27 | ❌ |
42
- | VerticalAlignment::Top | ratatui-core/src/layout/alignment.rs:40 | ❌ |
43
- | VerticalAlignment::Center | ratatui-core/src/layout/alignment.rs:41 | ❌ |
44
- | VerticalAlignment::Bottom | ratatui-core/src/layout/alignment.rs:42 | ❌ |
45
39
  | Offset struct | ratatui-core/src/layout/offset.rs:10 | ❌ |
46
40
  | Margin struct | ratatui-core/src/layout/margin.rs:38 | ❌ |
47
41