aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichelle Tilley <michelle@michelletilley.net>2026-03-27 10:45:04 -0700
committerGitHub <noreply@github.com>2026-03-27 10:45:04 -0700
commitbc9e62e8e24f5e218acd471404455ef57bc7d752 (patch)
treeac647dcadac9c1ddf3b0ec3e21e5e3bd9bb33993
parentfeat: Use eye-declare for more performant and flexible AI TUI (#3343) (diff)
downloadatuin-bc9e62e8e24f5e218acd471404455ef57bc7d752.zip
chore(deps): Update to eye-declare v0.2.0 (#3355)
eye-declare v0.2.0 includes two relevant changes: * "Capture-phase" event handling lets us remove the special-case event handling in `InputBox` that allowed global keyboard binds to work; the `AtuinAi` component now handles this directly. * `Tracked::read()` allows reading fields in tracked state without triggering the dirty-tracking from the `DerefMut` implementation, allowing us to send messages on the app event bus without marking the containing state as dirty.
Diffstat (limited to '')
-rw-r--r--Cargo.lock8
-rw-r--r--crates/atuin-ai/Cargo.toml2
-rw-r--r--crates/atuin-ai/src/tui/components/atuin_ai.rs6
-rw-r--r--crates/atuin-ai/src/tui/components/input_box.rs24
4 files changed, 15 insertions, 25 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 03e78c09..1fa8ebca 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1498,9 +1498,9 @@ dependencies = [
[[package]]
name = "eye_declare"
-version = "0.1.4"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29f7a306e9da6182b45de1c5e29ca9d469f6aa4cd0bdd6ff0da4bdaf67bec4ff"
+checksum = "4d025f4c5954a5797f81cdde3871f301a3e5bca02e3110848de0f2c348a05573"
dependencies = [
"crossterm",
"eye_declare_macros",
@@ -1513,9 +1513,9 @@ dependencies = [
[[package]]
name = "eye_declare_macros"
-version = "0.1.3"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c552b6cb631a6826de9c793d7f1b620e4007c6f8ee584f2bc428d193c14b3381"
+checksum = "7ad7509865efe5f9cd4b05db4e50605e06c6425b7ef1a579526bebb3bd4bfa1a"
dependencies = [
"proc-macro2",
"quote",
diff --git a/crates/atuin-ai/Cargo.toml b/crates/atuin-ai/Cargo.toml
index a62e3274..f4d6e8f2 100644
--- a/crates/atuin-ai/Cargo.toml
+++ b/crates/atuin-ai/Cargo.toml
@@ -39,7 +39,7 @@ async-stream = "0.3"
uuid = { workspace = true }
tui-textarea-2 = "0.10.2"
unicode-width = "0.2"
-eye_declare = "0.1"
+eye_declare = "0.2"
ratatui-core = "0.1"
ratatui-widgets = "0.3"
diff --git a/crates/atuin-ai/src/tui/components/atuin_ai.rs b/crates/atuin-ai/src/tui/components/atuin_ai.rs
index 680b93ed..b2239a70 100644
--- a/crates/atuin-ai/src/tui/components/atuin_ai.rs
+++ b/crates/atuin-ai/src/tui/components/atuin_ai.rs
@@ -7,7 +7,7 @@
use std::sync::mpsc;
use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers};
-use eye_declare::{Component, EventResult, Hooks, impl_slot_children};
+use eye_declare::{Component, EventResult, Hooks, Tracked, impl_slot_children};
use crate::tui::events::AiTuiEvent;
use crate::tui::state::AppMode;
@@ -67,7 +67,9 @@ impl Component for AtuinAi {
0
}
- fn handle_event(&self, event: &Event, state: &mut Self::State) -> EventResult {
+ fn handle_event_capture(&self, event: &Event, state: &mut Tracked<Self::State>) -> EventResult {
+ let state = state.read();
+
let Event::Key(KeyEvent {
code,
kind: KeyEventKind::Press,
diff --git a/crates/atuin-ai/src/tui/components/input_box.rs b/crates/atuin-ai/src/tui/components/input_box.rs
index fd8132f4..3167ecc1 100644
--- a/crates/atuin-ai/src/tui/components/input_box.rs
+++ b/crates/atuin-ai/src/tui/components/input_box.rs
@@ -9,7 +9,7 @@
use std::sync::{Mutex, mpsc};
use crossterm::event::KeyModifiers;
-use eye_declare::{Component, EventResult, Hooks};
+use eye_declare::{Component, EventResult, Hooks, Tracked};
use ratatui::widgets::{Block, Borders, Padding};
use ratatui_core::{
buffer::Buffer,
@@ -153,8 +153,10 @@ impl Component for InputBox {
fn handle_event(
&self,
event: &crossterm::event::Event,
- state: &mut Self::State,
+ state: &mut Tracked<Self::State>,
) -> EventResult {
+ let state = state.read();
+
if !self.active {
return EventResult::Ignored;
}
@@ -170,13 +172,6 @@ impl Component for InputBox {
return EventResult::Ignored;
}
- // Let Ctrl+C bubble up to AtuinAi for exit handling
- if key.modifiers.contains(KeyModifiers::CONTROL)
- && key.code == crossterm::event::KeyCode::Char('c')
- {
- return EventResult::Ignored;
- }
-
let mut textarea = state.textarea.lock().unwrap();
match key.code {
@@ -192,25 +187,18 @@ impl Component for InputBox {
return EventResult::Consumed;
} else {
let text = textarea.lines().join("\n");
- textarea.clear();
-
if text.trim().is_empty() {
return EventResult::Ignored;
}
+ textarea.clear();
+
if let Some(ref tx) = state.tx {
let _ = tx.send(AiTuiEvent::SubmitInput(text));
}
return EventResult::Consumed;
}
}
- crossterm::event::KeyCode::Tab => {
- return EventResult::Ignored;
- }
- // Esc: bubble up to app
- crossterm::event::KeyCode::Esc => {
- return EventResult::Ignored;
- }
_ => {}
}