ratatui_ruby 1.1.1 → 1.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 410fcf24b7399d5e9cdab0c6819555fe91e277484d7c772587c9811860bdd372
4
- data.tar.gz: 67cd5478a880a29ec4fa1f5500892fc854af285b90c9505dec8c14c22a027161
3
+ metadata.gz: aa64c94e2dded3a4de71ebdff888860a1528f42a4b9a1ed0200361d3a811e715
4
+ data.tar.gz: aa98fe686ef20f10e310b3a0bc87b60412279d85d1d60befa31c60c3eef5bf01
5
5
  SHA512:
6
- metadata.gz: ee74b8f1092d5dd4ea0348363230acd1edb198a87eeb4f0a6bc7052e5f5e49f9c3fb02ea8c2690e7e3e91ab07d703fe4ff6de91b6db50a72f98040ff1d98c62f
7
- data.tar.gz: '08e7944efa53c1a78ed90c889ef9f7eed9b192beb0a39d0b3c4615cc1dfb08659f10bdacc03f626c526344e204e29dfe0bc14c2a7ba4c831e508cebee571538c'
6
+ metadata.gz: fab99ab43c386a115027ea204ec578c7d20c1b4bd7ddfeee43d384825f536ed49162ca8957e1c46b994809cbd20137d16857f39c792330148a5b1eb3d69957a3
7
+ data.tar.gz: c6b42590b5f920d19062e99fef14a92dfffe2a5482a9b3295fc5b73df095336a99c33b782e1ae14fd17027593253f545957919cf8603936842e121e166dd54b7
@@ -1059,7 +1059,7 @@ dependencies = [
1059
1059
 
1060
1060
  [[package]]
1061
1061
  name = "ratatui_ruby"
1062
- version = "1.1.1"
1062
+ version = "1.2.1"
1063
1063
  dependencies = [
1064
1064
  "bumpalo",
1065
1065
  "lazy_static",
@@ -3,7 +3,7 @@
3
3
 
4
4
  [package]
5
5
  name = "ratatui_ruby"
6
- version = "1.1.1"
6
+ version = "1.2.1"
7
7
  edition = "2021"
8
8
 
9
9
  [lib]
@@ -4,8 +4,15 @@
4
4
  use magnus::{Error, IntoValue, TryConvert, Value};
5
5
  use std::cell::RefCell;
6
6
 
7
+ /// Wrapper enum for test events - includes crossterm events and our Sync event.
8
+ #[derive(Debug, Clone)]
9
+ enum TestEvent {
10
+ Crossterm(ratatui::crossterm::event::Event),
11
+ Sync,
12
+ }
13
+
7
14
  thread_local! {
8
- static EVENT_QUEUE: RefCell<Vec<ratatui::crossterm::event::Event>> = const { RefCell::new(Vec::new()) };
15
+ static EVENT_QUEUE: RefCell<Vec<TestEvent>> = const { RefCell::new(Vec::new()) };
9
16
  }
10
17
 
11
18
  use ratatui::crossterm::event::{KeyCode, KeyModifiers, MediaKeyCode, ModifierKeyCode};
@@ -107,12 +114,13 @@ pub fn all_key_codes() -> magnus::RHash {
107
114
  pub fn inject_test_event(event_type: String, data: magnus::RHash) -> Result<(), Error> {
108
115
  let ruby = magnus::Ruby::get().unwrap();
109
116
  let event = match event_type.as_str() {
110
- "key" => parse_key_event(data, &ruby)?,
111
- "mouse" => parse_mouse_event(data, &ruby)?,
112
- "resize" => parse_resize_event(data, &ruby)?,
113
- "paste" => parse_paste_event(data, &ruby)?,
114
- "focus_gained" => ratatui::crossterm::event::Event::FocusGained,
115
- "focus_lost" => ratatui::crossterm::event::Event::FocusLost,
117
+ "key" => TestEvent::Crossterm(parse_key_event(data, &ruby)?),
118
+ "mouse" => TestEvent::Crossterm(parse_mouse_event(data, &ruby)?),
119
+ "resize" => TestEvent::Crossterm(parse_resize_event(data, &ruby)?),
120
+ "paste" => TestEvent::Crossterm(parse_paste_event(data, &ruby)?),
121
+ "focus_gained" => TestEvent::Crossterm(ratatui::crossterm::event::Event::FocusGained),
122
+ "focus_lost" => TestEvent::Crossterm(ratatui::crossterm::event::Event::FocusLost),
123
+ "sync" => TestEvent::Sync,
116
124
  _ => {
117
125
  return Err(Error::new(
118
126
  ruby.exception_arg_error(),
@@ -317,7 +325,7 @@ pub fn poll_event(ruby: &magnus::Ruby, timeout_val: Option<f64>) -> Result<Value
317
325
  });
318
326
 
319
327
  if let Some(e) = event {
320
- return handle_event(e);
328
+ return handle_test_event(e);
321
329
  }
322
330
 
323
331
  let is_test_mode = crate::terminal::with_query(|q| q.is_test_mode()).unwrap_or(false);
@@ -334,7 +342,7 @@ pub fn poll_event(ruby: &magnus::Ruby, timeout_val: Option<f64>) -> Result<Value
334
342
  {
335
343
  let event = ratatui::crossterm::event::read()
336
344
  .map_err(|e| Error::new(ruby.exception_runtime_error(), e.to_string()))?;
337
- handle_event(event)
345
+ handle_crossterm_event(event)
338
346
  } else {
339
347
  Ok(ruby.qnil().into_value_with(ruby))
340
348
  }
@@ -342,11 +350,18 @@ pub fn poll_event(ruby: &magnus::Ruby, timeout_val: Option<f64>) -> Result<Value
342
350
  // Blocking: wait indefinitely for an event
343
351
  let event = ratatui::crossterm::event::read()
344
352
  .map_err(|e| Error::new(ruby.exception_runtime_error(), e.to_string()))?;
345
- handle_event(event)
353
+ handle_crossterm_event(event)
354
+ }
355
+ }
356
+
357
+ fn handle_test_event(event: TestEvent) -> Result<Value, Error> {
358
+ match event {
359
+ TestEvent::Crossterm(e) => handle_crossterm_event(e),
360
+ TestEvent::Sync => handle_sync_event(),
346
361
  }
347
362
  }
348
363
 
349
- fn handle_event(event: ratatui::crossterm::event::Event) -> Result<Value, Error> {
364
+ fn handle_crossterm_event(event: ratatui::crossterm::event::Event) -> Result<Value, Error> {
350
365
  match event {
351
366
  ratatui::crossterm::event::Event::Key(key) => handle_key_event(key),
352
367
  ratatui::crossterm::event::Event::Mouse(event) => handle_mouse_event(event),
@@ -357,6 +372,13 @@ fn handle_event(event: ratatui::crossterm::event::Event) -> Result<Value, Error>
357
372
  }
358
373
  }
359
374
 
375
+ fn handle_sync_event() -> Result<Value, Error> {
376
+ let ruby = magnus::Ruby::get().unwrap();
377
+ let hash = ruby.hash_new();
378
+ hash.aset(ruby.to_symbol("type"), ruby.to_symbol("sync"))?;
379
+ Ok(hash.into_value_with(&ruby))
380
+ }
381
+
360
382
  fn media_key_to_string(m: MediaKeyCode) -> &'static str {
361
383
  MEDIA_KEY_MAPPINGS
362
384
  .iter()
@@ -48,8 +48,28 @@ module RatatuiRuby
48
48
  module SyntheticEvents
49
49
  @queue = [] #: Array[Event]
50
50
  @mutex = Mutex.new
51
+ @inline_sync = false #: bool
51
52
 
52
53
  class << self
54
+ ##
55
+ # Enables inline sync mode for deterministic event ordering.
56
+ #
57
+ # Call once at startup. Cannot be disabled.
58
+ #
59
+ # When enabled, +inject_sync+ routes through the native event queue
60
+ # and +poll_event+ returns +Event::Sync+ like any other event.
61
+ # This ensures sync events are processed in sequence with key events.
62
+ #
63
+ # Runtimes that need ordering guarantees (like Rooibos) should call
64
+ # this before entering their event loop.
65
+ def inline_sync!
66
+ @inline_sync = true
67
+ end
68
+
69
+ def inline_sync? # :nodoc:
70
+ @inline_sync
71
+ end
72
+
53
73
  ##
54
74
  # Pushes an event to the synthetic queue.
55
75
  #
@@ -89,8 +89,13 @@ module RatatuiRuby
89
89
  when RatatuiRuby::Event::FocusLost
90
90
  RatatuiRuby.inject_test_event("focus_lost", {})
91
91
  when RatatuiRuby::Event::Sync
92
- # Sync events use the engine-level synthetic queue
93
- RatatuiRuby::SyntheticEvents.push(event)
92
+ if RatatuiRuby::SyntheticEvents.inline_sync?
93
+ # Route through native queue for deterministic ordering with key events
94
+ RatatuiRuby.inject_test_event("sync", {})
95
+ else
96
+ # Default 1.0 behavior: use the engine-level synthetic queue
97
+ RatatuiRuby::SyntheticEvents.push(event)
98
+ end
94
99
  else
95
100
  raise ArgumentError, "Unknown event type: #{event.class}"
96
101
  end
@@ -8,5 +8,5 @@
8
8
  module RatatuiRuby
9
9
  # The version of the ratatui_ruby gem.
10
10
  # See https://semver.org/spec/v2.0.0.html
11
- VERSION = "1.1.1"
11
+ VERSION = "1.2.1"
12
12
  end
data/lib/ratatui_ruby.rb CHANGED
@@ -409,6 +409,8 @@ module RatatuiRuby
409
409
  Event::FocusGained.new.freeze
410
410
  when :focus_lost
411
411
  Event::FocusLost.new.freeze
412
+ when :sync
413
+ Event::Sync.new.freeze
412
414
  else
413
415
  # Return None for unknown event types
414
416
  Event::None.new.freeze
@@ -12,7 +12,10 @@ module RatatuiRuby
12
12
  # Used primarily for testing and the andThen-like integration pattern.
13
13
  module SyntheticEvents
14
14
  @queue: Array[Event]
15
+ @inline_sync: bool
15
16
 
17
+ def self.inline_sync!: () -> void
18
+ def self.inline_sync?: () -> bool
16
19
  def self.push: (Event event) -> void
17
20
  def self.pop: () -> Event?
18
21
  def self.clear: () -> void
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: 1.1.1
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kerrick Long