ratatui_ruby 0.9.0 → 0.9.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.
- 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/CHANGELOG.md +24 -0
- data/doc/contributors/v1.0.0_blockers.md +4 -10
- data/examples/widget_layout_split/app.rb +6 -0
- data/ext/ratatui_ruby/Cargo.lock +1 -1
- data/ext/ratatui_ruby/Cargo.toml +1 -1
- data/ext/ratatui_ruby/src/events.rs +1 -0
- data/lib/ratatui_ruby/event/sync.rb +52 -0
- data/lib/ratatui_ruby/event.rb +6 -0
- data/lib/ratatui_ruby/layout/constraint.rb +135 -0
- data/lib/ratatui_ruby/synthetic_events.rb +86 -0
- data/lib/ratatui_ruby/test_helper/event_injection.rb +28 -0
- data/lib/ratatui_ruby/version.rb +1 -1
- data/lib/ratatui_ruby.rb +11 -7
- data/sig/ratatui_ruby/schema/constraint.rbs +8 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c543e8590fa79c457dac22abc8c39fc2264026079196ff7d0afc1d083c9cf013
|
|
4
|
+
data.tar.gz: 8c044e43009f8ede9c66274809aacae1c7e66a503157afc6756c4890b50d899c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dfd4c34a23e0af4dcb47c9520bae94db94cb7587f37b11662668e8f6f7e7a3148aeb0fb66ed66cb47f51898fc42da496ce50cec46ea1b286c3bcfcbe5dc43e41
|
|
7
|
+
data.tar.gz: 19871c4b3ec78afc30fc004f019b6b0ff246654ffbbe6dafb7e92cd5d1b3c4b1294ed3e836c47b70fb094dad3f5aa7927dd2b23a6cf458d571f5248fa5b0b934
|
data/.builds/ruby-3.2.yml
CHANGED
data/.builds/ruby-3.3.yml
CHANGED
data/.builds/ruby-3.4.yml
CHANGED
data/.builds/ruby-4.0.0.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -18,6 +18,29 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
18
18
|
|
|
19
19
|
### Removed
|
|
20
20
|
|
|
21
|
+
## [0.9.1] - 2026-01-08
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- **Constraint Batch Constructors**: `Constraint` now provides batch factory methods matching upstream Ratatui for creating constraint arrays in a single call:
|
|
26
|
+
- `from_lengths([10, 20, 10])` — create multiple Length constraints
|
|
27
|
+
- `from_percentages([25, 50, 25])` — create multiple Percentage constraints
|
|
28
|
+
- `from_mins([5, 10, 5])` — create multiple Min constraints
|
|
29
|
+
- `from_maxes([20, 30, 40])` — create multiple Max constraints
|
|
30
|
+
- `from_fills([1, 2, 1])` — create multiple Fill constraints
|
|
31
|
+
- `from_ratios([[1, 4], [2, 4], [1, 4]])` — create multiple Ratio constraints
|
|
32
|
+
|
|
33
|
+
- **Async Synchronization**: New `Event::Sync` event and `SyntheticEvents` module enable deterministic testing of async behavior:
|
|
34
|
+
- `Event::Sync` — synthetic event that signals runtimes (Tea, Kit) to wait for pending async operations before continuing
|
|
35
|
+
- `RatatuiRuby::SyntheticEvents` — thread-safe Ruby-only queue for synthetic events; runtimes check this alongside native events
|
|
36
|
+
- `inject_sync` test helper — injects a Sync event for deterministic async testing
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
### Removed
|
|
43
|
+
|
|
21
44
|
## [0.9.0] - 2026-01-08
|
|
22
45
|
|
|
23
46
|
### Added
|
|
@@ -492,6 +515,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
492
515
|
- **Testing Support**: Included `RatatuiRuby::TestHelper` and RSpec integration to make testing your TUI applications possible.
|
|
493
516
|
|
|
494
517
|
[Unreleased]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/HEAD
|
|
518
|
+
[0.9.1]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v0.9.1
|
|
495
519
|
[0.9.0]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v0.9.0
|
|
496
520
|
[0.8.0]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v0.8.0
|
|
497
521
|
[0.7.4]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v0.7.4
|
|
@@ -14,7 +14,7 @@ SPDX-License-Identifier: CC-BY-SA-4.0
|
|
|
14
14
|
- Symbol Sets
|
|
15
15
|
- line::Set, block::Set, scrollbar::Set
|
|
16
16
|
- Layout
|
|
17
|
-
- Constraint batch constructors (6)
|
|
17
|
+
- ~~Constraint batch constructors (6)~~ ✅ DONE
|
|
18
18
|
- Layout margin, spacing (2)
|
|
19
19
|
- Style
|
|
20
20
|
- sub_modifier, underline_color (2)
|
|
@@ -34,16 +34,10 @@ This document audits alignment between RatatuiRuby v0.7.0 and the upstream Ratat
|
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
###### `Layout::Constraint` —
|
|
37
|
+
###### `Layout::Constraint` — Batch Constructors ✅ DONE
|
|
38
38
|
|
|
39
|
-
|
|
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]` |
|
|
39
|
+
All 6 batch constructors implemented in v0.8.0:
|
|
40
|
+
- `from_lengths`, `from_percentages`, `from_mins`, `from_maxes`, `from_fills`, `from_ratios`
|
|
47
41
|
|
|
48
42
|
---
|
|
49
43
|
|
data/ext/ratatui_ruby/Cargo.lock
CHANGED
data/ext/ratatui_ruby/Cargo.toml
CHANGED
|
@@ -383,6 +383,7 @@ fn handle_key_event(key: ratatui::crossterm::event::KeyEvent) -> Result<Value, E
|
|
|
383
383
|
if key.kind != ratatui::crossterm::event::KeyEventKind::Press {
|
|
384
384
|
return Ok(ruby.qnil().into_value_with(&ruby));
|
|
385
385
|
}
|
|
386
|
+
|
|
386
387
|
let hash = ruby.hash_new();
|
|
387
388
|
hash.aset(ruby.to_symbol("type"), ruby.to_symbol("key"))?;
|
|
388
389
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#--
|
|
4
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
6
|
+
#++
|
|
7
|
+
|
|
8
|
+
module RatatuiRuby
|
|
9
|
+
class Event
|
|
10
|
+
# Synthetic event for synchronizing async operations in tests.
|
|
11
|
+
#
|
|
12
|
+
# Testing async behavior is tricky. You inject an event, but results arrive
|
|
13
|
+
# later. By the time you assert, the async work may not have completed.
|
|
14
|
+
#
|
|
15
|
+
# When a runtime (Tea, Kit) encounters this event, it should wait for all
|
|
16
|
+
# pending async operations to complete before processing the next event.
|
|
17
|
+
# This enables deterministic testing without changing production code paths.
|
|
18
|
+
#
|
|
19
|
+
# Inject this event between user actions and assertions to ensure async
|
|
20
|
+
# results have been processed:
|
|
21
|
+
#
|
|
22
|
+
# === Example
|
|
23
|
+
#
|
|
24
|
+
#--
|
|
25
|
+
# SPDX-SnippetBegin
|
|
26
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
27
|
+
# SPDX-License-Identifier: MIT-0
|
|
28
|
+
#++
|
|
29
|
+
# inject_key("s") # Triggers async command
|
|
30
|
+
# inject_sync # Wait for command to complete
|
|
31
|
+
# inject_key(:q) # Quit after seeing results
|
|
32
|
+
# Tea.run(...)
|
|
33
|
+
# assert_snapshots("after_s_with_results")
|
|
34
|
+
#
|
|
35
|
+
#--
|
|
36
|
+
# SPDX-SnippetEnd
|
|
37
|
+
#++
|
|
38
|
+
# This is not "test mode"—it's a real event that runtimes handle.
|
|
39
|
+
# Production apps could use it too (e.g., "ensure saves complete before quit").
|
|
40
|
+
class Sync < Event
|
|
41
|
+
# Returns true for Sync events.
|
|
42
|
+
def sync?
|
|
43
|
+
true
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Deconstructs the event for pattern matching.
|
|
47
|
+
def deconstruct_keys(keys)
|
|
48
|
+
{ type: :sync }
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
data/lib/ratatui_ruby/event.rb
CHANGED
|
@@ -111,6 +111,11 @@ module RatatuiRuby
|
|
|
111
111
|
false
|
|
112
112
|
end
|
|
113
113
|
|
|
114
|
+
# Returns true if this is a Sync event.
|
|
115
|
+
def sync?
|
|
116
|
+
false
|
|
117
|
+
end
|
|
118
|
+
|
|
114
119
|
# Responds to dynamic predicate methods for key checks.
|
|
115
120
|
# All non-Key events return false for any key predicate.
|
|
116
121
|
def method_missing(name, *args, &block)
|
|
@@ -155,3 +160,4 @@ require_relative "event/resize"
|
|
|
155
160
|
require_relative "event/paste"
|
|
156
161
|
require_relative "event/focus_gained"
|
|
157
162
|
require_relative "event/focus_lost"
|
|
163
|
+
require_relative "event/sync"
|
|
@@ -148,6 +148,141 @@ module RatatuiRuby
|
|
|
148
148
|
def self.ratio(numerator, denominator)
|
|
149
149
|
new(type: :ratio, value: [Integer(numerator), Integer(denominator)])
|
|
150
150
|
end
|
|
151
|
+
|
|
152
|
+
# Converts an array of lengths into an array of Length constraints.
|
|
153
|
+
#
|
|
154
|
+
# Complex layouts often use multiple fixed-size sections. Manually creating each constraint
|
|
155
|
+
# clutters the code.
|
|
156
|
+
#
|
|
157
|
+
# This method maps over the input, returning a constraint array in one call.
|
|
158
|
+
#
|
|
159
|
+
# === Example
|
|
160
|
+
#
|
|
161
|
+
#--
|
|
162
|
+
# SPDX-SnippetBegin
|
|
163
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
164
|
+
# SPDX-License-Identifier: MIT-0
|
|
165
|
+
#++
|
|
166
|
+
# Constraint.from_lengths([10, 20, 10])
|
|
167
|
+
# # => [Constraint.length(10), Constraint.length(20), Constraint.length(10)]
|
|
168
|
+
#
|
|
169
|
+
#--
|
|
170
|
+
# SPDX-SnippetEnd
|
|
171
|
+
#++
|
|
172
|
+
# [values] Enumerable of Integers.
|
|
173
|
+
def self.from_lengths(values)
|
|
174
|
+
values.map { |v| length(v) }
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Converts an array of percentages into an array of Percentage constraints.
|
|
178
|
+
#
|
|
179
|
+
# Percentage-based layouts distribute space proportionally. This method batches the creation.
|
|
180
|
+
#
|
|
181
|
+
# === Example
|
|
182
|
+
#
|
|
183
|
+
#--
|
|
184
|
+
# SPDX-SnippetBegin
|
|
185
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
186
|
+
# SPDX-License-Identifier: MIT-0
|
|
187
|
+
#++
|
|
188
|
+
# Constraint.from_percentages([25, 50, 25])
|
|
189
|
+
# # => [Constraint.percentage(25), Constraint.percentage(50), Constraint.percentage(25)]
|
|
190
|
+
#
|
|
191
|
+
#--
|
|
192
|
+
# SPDX-SnippetEnd
|
|
193
|
+
#++
|
|
194
|
+
# [values] Enumerable of Integers (0-100).
|
|
195
|
+
def self.from_percentages(values)
|
|
196
|
+
values.map { |v| percentage(v) }
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Converts an array of minimums into an array of Min constraints.
|
|
200
|
+
#
|
|
201
|
+
# Minimum constraints ensure sections never shrink below a threshold. Batch them here.
|
|
202
|
+
#
|
|
203
|
+
# === Example
|
|
204
|
+
#
|
|
205
|
+
#--
|
|
206
|
+
# SPDX-SnippetBegin
|
|
207
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
208
|
+
# SPDX-License-Identifier: MIT-0
|
|
209
|
+
#++
|
|
210
|
+
# Constraint.from_mins([5, 10, 5])
|
|
211
|
+
# # => [Constraint.min(5), Constraint.min(10), Constraint.min(5)]
|
|
212
|
+
#
|
|
213
|
+
#--
|
|
214
|
+
# SPDX-SnippetEnd
|
|
215
|
+
#++
|
|
216
|
+
# [values] Enumerable of Integers.
|
|
217
|
+
def self.from_mins(values)
|
|
218
|
+
values.map { |v| min(v) }
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# Converts an array of maximums into an array of Max constraints.
|
|
222
|
+
#
|
|
223
|
+
# Maximum constraints cap section sizes. Batch them here.
|
|
224
|
+
#
|
|
225
|
+
# === Example
|
|
226
|
+
#
|
|
227
|
+
#--
|
|
228
|
+
# SPDX-SnippetBegin
|
|
229
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
230
|
+
# SPDX-License-Identifier: MIT-0
|
|
231
|
+
#++
|
|
232
|
+
# Constraint.from_maxes([20, 30, 40])
|
|
233
|
+
# # => [Constraint.max(20), Constraint.max(30), Constraint.max(40)]
|
|
234
|
+
#
|
|
235
|
+
#--
|
|
236
|
+
# SPDX-SnippetEnd
|
|
237
|
+
#++
|
|
238
|
+
# [values] Enumerable of Integers.
|
|
239
|
+
def self.from_maxes(values)
|
|
240
|
+
values.map { |v| max(v) }
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# Converts an array of weights into an array of Fill constraints.
|
|
244
|
+
#
|
|
245
|
+
# Fill constraints distribute remaining space by weight. Batch them here.
|
|
246
|
+
#
|
|
247
|
+
# === Example
|
|
248
|
+
#
|
|
249
|
+
#--
|
|
250
|
+
# SPDX-SnippetBegin
|
|
251
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
252
|
+
# SPDX-License-Identifier: MIT-0
|
|
253
|
+
#++
|
|
254
|
+
# Constraint.from_fills([1, 2, 1])
|
|
255
|
+
# # => [Constraint.fill(1), Constraint.fill(2), Constraint.fill(1)]
|
|
256
|
+
#
|
|
257
|
+
#--
|
|
258
|
+
# SPDX-SnippetEnd
|
|
259
|
+
#++
|
|
260
|
+
# [values] Enumerable of Integers.
|
|
261
|
+
def self.from_fills(values)
|
|
262
|
+
values.map { |v| fill(v) }
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# Converts an array of ratio pairs into an array of Ratio constraints.
|
|
266
|
+
#
|
|
267
|
+
# Ratio constraints define exact fractions of space. Batch them here.
|
|
268
|
+
#
|
|
269
|
+
# === Example
|
|
270
|
+
#
|
|
271
|
+
#--
|
|
272
|
+
# SPDX-SnippetBegin
|
|
273
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
274
|
+
# SPDX-License-Identifier: MIT-0
|
|
275
|
+
#++
|
|
276
|
+
# Constraint.from_ratios([[1, 4], [2, 4], [1, 4]])
|
|
277
|
+
# # => [Constraint.ratio(1, 4), Constraint.ratio(2, 4), Constraint.ratio(1, 4)]
|
|
278
|
+
#
|
|
279
|
+
#--
|
|
280
|
+
# SPDX-SnippetEnd
|
|
281
|
+
#++
|
|
282
|
+
# [pairs] Enumerable of <tt>[numerator, denominator]</tt> arrays.
|
|
283
|
+
def self.from_ratios(pairs)
|
|
284
|
+
pairs.map { |n, d| ratio(n, d) }
|
|
285
|
+
end
|
|
151
286
|
end
|
|
152
287
|
end
|
|
153
288
|
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#--
|
|
4
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
6
|
+
#++
|
|
7
|
+
|
|
8
|
+
module RatatuiRuby
|
|
9
|
+
##
|
|
10
|
+
# Ruby-only event queue for synthetic events.
|
|
11
|
+
#
|
|
12
|
+
# Native events flow through the Rust backend. Synthetic events bypass it.
|
|
13
|
+
# Runtimes (Tea, Kit) check this queue and handle events like
|
|
14
|
+
# <tt>Event::Sync</tt> specially.
|
|
15
|
+
#
|
|
16
|
+
# *For runtime authors:* Check <tt>pending?</tt> each loop iteration after
|
|
17
|
+
# polling native events. When true, pop the event and handle it. For
|
|
18
|
+
# <tt>Event::Sync</tt>, wait for pending threads and process background
|
|
19
|
+
# results before continuing.
|
|
20
|
+
#
|
|
21
|
+
# *For app developers:* Push <tt>Event::Sync</tt> when you need async
|
|
22
|
+
# results before continuing. The runtime will block until all pending
|
|
23
|
+
# work completes. Use this for "ensure saves complete before quit."
|
|
24
|
+
#
|
|
25
|
+
# *For test authors:* Use <tt>inject_sync</tt> between events to create
|
|
26
|
+
# synchronization points. This enables deterministic testing of async
|
|
27
|
+
# behavior.
|
|
28
|
+
#
|
|
29
|
+
# === Example
|
|
30
|
+
#
|
|
31
|
+
#--
|
|
32
|
+
# SPDX-SnippetBegin
|
|
33
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
34
|
+
# SPDX-License-Identifier: MIT-0
|
|
35
|
+
#++
|
|
36
|
+
# # Production: ensure async saves finish before exiting
|
|
37
|
+
# RatatuiRuby::SyntheticEvents.push(RatatuiRuby::Event::Sync.new)
|
|
38
|
+
#
|
|
39
|
+
# # Runtime authors: check in your event loop
|
|
40
|
+
# if RatatuiRuby::SyntheticEvents.pending?
|
|
41
|
+
# event = RatatuiRuby::SyntheticEvents.pop
|
|
42
|
+
# handle_sync if event.sync?
|
|
43
|
+
# end
|
|
44
|
+
#
|
|
45
|
+
#--
|
|
46
|
+
# SPDX-SnippetEnd
|
|
47
|
+
#++
|
|
48
|
+
module SyntheticEvents
|
|
49
|
+
@queue = []
|
|
50
|
+
@mutex = Mutex.new
|
|
51
|
+
|
|
52
|
+
class << self
|
|
53
|
+
##
|
|
54
|
+
# Pushes an event to the synthetic queue.
|
|
55
|
+
#
|
|
56
|
+
# [event] An <tt>Event</tt> object (typically <tt>Event::Sync</tt>).
|
|
57
|
+
def push(event)
|
|
58
|
+
@mutex.synchronize { @queue << event }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
##
|
|
62
|
+
# Pops an event from the synthetic queue.
|
|
63
|
+
#
|
|
64
|
+
# Returns the oldest pending event, or <tt>nil</tt> if empty.
|
|
65
|
+
def pop
|
|
66
|
+
@mutex.synchronize { @queue.shift }
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
##
|
|
70
|
+
# Clears all pending synthetic events.
|
|
71
|
+
#
|
|
72
|
+
# Test helpers call this during teardown to reset state between tests.
|
|
73
|
+
def clear
|
|
74
|
+
@mutex.synchronize { @queue.clear }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
##
|
|
78
|
+
# Checks for pending synthetic events.
|
|
79
|
+
#
|
|
80
|
+
# Returns <tt>true</tt> if the queue has events waiting.
|
|
81
|
+
def pending?
|
|
82
|
+
@mutex.synchronize { !@queue.empty? }
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -88,6 +88,9 @@ module RatatuiRuby
|
|
|
88
88
|
RatatuiRuby.inject_test_event("focus_gained", {})
|
|
89
89
|
when RatatuiRuby::Event::FocusLost
|
|
90
90
|
RatatuiRuby.inject_test_event("focus_lost", {})
|
|
91
|
+
when RatatuiRuby::Event::Sync
|
|
92
|
+
# Sync events use the engine-level synthetic queue
|
|
93
|
+
RatatuiRuby::SyntheticEvents.push(event)
|
|
91
94
|
else
|
|
92
95
|
raise ArgumentError, "Unknown event type: #{event.class}"
|
|
93
96
|
end
|
|
@@ -198,6 +201,31 @@ module RatatuiRuby
|
|
|
198
201
|
end
|
|
199
202
|
end
|
|
200
203
|
alias inject_key inject_keys
|
|
204
|
+
|
|
205
|
+
##
|
|
206
|
+
# Injects a Sync event.
|
|
207
|
+
#
|
|
208
|
+
# When a runtime (Tea, Kit) encounters this event, it should wait for all
|
|
209
|
+
# pending async operations to complete before processing the next event.
|
|
210
|
+
# This enables deterministic testing of async behavior.
|
|
211
|
+
#
|
|
212
|
+
# === Example
|
|
213
|
+
#
|
|
214
|
+
#--
|
|
215
|
+
# SPDX-SnippetBegin
|
|
216
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
217
|
+
# SPDX-License-Identifier: MIT-0
|
|
218
|
+
#++
|
|
219
|
+
# inject_key("s") # Triggers async command
|
|
220
|
+
# inject_sync # Wait for command to complete
|
|
221
|
+
# inject_key(:q) # Quit after seeing results
|
|
222
|
+
#
|
|
223
|
+
#--
|
|
224
|
+
# SPDX-SnippetEnd
|
|
225
|
+
#++
|
|
226
|
+
def inject_sync
|
|
227
|
+
inject_event(RatatuiRuby::Event::Sync.new)
|
|
228
|
+
end
|
|
201
229
|
end
|
|
202
230
|
end
|
|
203
231
|
end
|
data/lib/ratatui_ruby/version.rb
CHANGED
data/lib/ratatui_ruby.rb
CHANGED
|
@@ -31,6 +31,9 @@ require_relative "ratatui_ruby/terminal_lifecycle"
|
|
|
31
31
|
# TUI facade (for external instantiation and caching)
|
|
32
32
|
require_relative "ratatui_ruby/tui"
|
|
33
33
|
|
|
34
|
+
# Synthetic events queue (for async synchronization)
|
|
35
|
+
require_relative "ratatui_ruby/synthetic_events"
|
|
36
|
+
|
|
34
37
|
begin
|
|
35
38
|
require "ratatui_ruby/ratatui_ruby"
|
|
36
39
|
rescue LoadError
|
|
@@ -120,16 +123,17 @@ module RatatuiRuby
|
|
|
120
123
|
#++
|
|
121
124
|
class Safety < Error; end
|
|
122
125
|
|
|
123
|
-
#
|
|
126
|
+
# Invariant violation.
|
|
124
127
|
#
|
|
125
|
-
# The library
|
|
126
|
-
#
|
|
128
|
+
# The library enforces rules about valid states and contracts.
|
|
129
|
+
# Breaking these rules raises this error.
|
|
127
130
|
#
|
|
128
|
-
#
|
|
129
|
-
#
|
|
131
|
+
# Common causes:
|
|
132
|
+
# - Calling methods in the wrong order (e.g., \`init_terminal\` twice)
|
|
133
|
+
# - Callable return type mismatch (e.g., view returns \`nil\` instead of a widget)
|
|
130
134
|
#
|
|
131
|
-
# To resolve, check
|
|
132
|
-
#
|
|
135
|
+
# To resolve, check the method's documented contract. Ensure
|
|
136
|
+
# state preconditions are met and return types are correct.
|
|
133
137
|
#
|
|
134
138
|
# === Example
|
|
135
139
|
#
|
|
@@ -18,5 +18,13 @@ module RatatuiRuby
|
|
|
18
18
|
def self.fill: (?Numeric) -> Constraint
|
|
19
19
|
def self.ratio: (Numeric, Numeric) -> Constraint
|
|
20
20
|
def self.new: (type: Symbol, value: (Integer | Array[Integer])) -> Constraint
|
|
21
|
+
|
|
22
|
+
# Batch constructors
|
|
23
|
+
def self.from_lengths: (Enumerable[Numeric]) -> Array[Constraint]
|
|
24
|
+
def self.from_percentages: (Enumerable[Numeric]) -> Array[Constraint]
|
|
25
|
+
def self.from_mins: (Enumerable[Numeric]) -> Array[Constraint]
|
|
26
|
+
def self.from_maxes: (Enumerable[Numeric]) -> Array[Constraint]
|
|
27
|
+
def self.from_fills: (Enumerable[Numeric]) -> Array[Constraint]
|
|
28
|
+
def self.from_ratios: (Enumerable[[Numeric, Numeric]]) -> Array[Constraint]
|
|
21
29
|
end
|
|
22
30
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ratatui_ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.9.
|
|
4
|
+
version: 0.9.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kerrick Long
|
|
@@ -315,6 +315,7 @@ files:
|
|
|
315
315
|
- lib/ratatui_ruby/event/none.rb
|
|
316
316
|
- lib/ratatui_ruby/event/paste.rb
|
|
317
317
|
- lib/ratatui_ruby/event/resize.rb
|
|
318
|
+
- lib/ratatui_ruby/event/sync.rb
|
|
318
319
|
- lib/ratatui_ruby/frame.rb
|
|
319
320
|
- lib/ratatui_ruby/layout.rb
|
|
320
321
|
- lib/ratatui_ruby/layout/constraint.rb
|
|
@@ -355,6 +356,7 @@ files:
|
|
|
355
356
|
- lib/ratatui_ruby/scrollbar_state.rb
|
|
356
357
|
- lib/ratatui_ruby/style.rb
|
|
357
358
|
- lib/ratatui_ruby/style/style.rb
|
|
359
|
+
- lib/ratatui_ruby/synthetic_events.rb
|
|
358
360
|
- lib/ratatui_ruby/table_state.rb
|
|
359
361
|
- lib/ratatui_ruby/terminal_lifecycle.rb
|
|
360
362
|
- lib/ratatui_ruby/test_helper.rb
|