aboutsummaryrefslogtreecommitdiffstats
path: root/crates/atuin-ai/src/tui/spinner.rs
diff options
context:
space:
mode:
authorMichelle Tilley <michelle@michelletilley.net>2026-03-26 19:19:47 -0700
committerGitHub <noreply@github.com>2026-03-27 02:19:47 +0000
commitb649a7ab8de6488c1341e94c37d032c07d5b3f13 (patch)
treeca9aadc1175b8439dd85de135f3804681b755776 /crates/atuin-ai/src/tui/spinner.rs
parentfix: set WorkingDirectory in PowerShell Invoke-AtuinSearch (#3351) (diff)
downloadatuin-b649a7ab8de6488c1341e94c37d032c07d5b3f13.zip
feat: Use eye-declare for more performant and flexible AI TUI (#3343)
This PR replaces the mess of custom rendering code in Atuin AI with [eye-declare](https://github.com/BinaryMuse/eye-declare), and updates the TUI to feel more terminal-native: output appears inline and persists in scrollback, so you can scroll up and look at previous conversations for reference. The "review" state — which used to exist between the LLM generating a response and the user either executing or following up — has been removed; just start typing to follow up with the LLM, or press `enter` at the empty input box to execute the suggested command. <img width="1203" height="633" alt="image" src="https://github.com/user-attachments/assets/159ee447-9a2a-4edd-b56e-a79bf1aaaa94" />
Diffstat (limited to 'crates/atuin-ai/src/tui/spinner.rs')
-rw-r--r--crates/atuin-ai/src/tui/spinner.rs99
1 files changed, 0 insertions, 99 deletions
diff --git a/crates/atuin-ai/src/tui/spinner.rs b/crates/atuin-ai/src/tui/spinner.rs
deleted file mode 100644
index 138e0269..00000000
--- a/crates/atuin-ai/src/tui/spinner.rs
+++ /dev/null
@@ -1,99 +0,0 @@
-//! Spinner styles and configuration for TUI animations
-//!
-//! To experiment with different spinners, change `ACTIVE_SPINNER` below.
-
-use std::time::Duration;
-
-/// Active spinner style - change this to experiment with different styles
-pub const ACTIVE_SPINNER: SpinnerStyle = SpinnerStyle::Dots;
-
-/// Spinner style definitions
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum SpinnerStyle {
- /// Classic ASCII line spinner: / - \ |
- Line,
- /// Braille dots pattern
- Dots,
- /// Growing/shrinking dots
- Pulse,
- /// Simple arrow rotation
- Arrow,
- /// Block building
- Block,
-}
-
-impl SpinnerStyle {
- /// Get the frames for this spinner style
- pub const fn frames(&self) -> &'static [&'static str] {
- match self {
- SpinnerStyle::Line => &["/", "-", "\\", "|"],
- SpinnerStyle::Dots => &["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"],
- SpinnerStyle::Pulse => &["·", "•", "●", "•"],
- SpinnerStyle::Arrow => &["←", "↖", "↑", "↗", "→", "↘", "↓", "↙"],
- SpinnerStyle::Block => &[
- "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█", "▉", "▊", "▋", "▌", "▍", "▎", "▏",
- ],
- }
- }
-
- /// Get the recommended tick interval for this spinner style
- /// Faster spinners need shorter intervals to look smooth
- pub const fn tick_interval(&self) -> Duration {
- match self {
- SpinnerStyle::Line => Duration::from_millis(150),
- SpinnerStyle::Dots => Duration::from_millis(80),
- SpinnerStyle::Pulse => Duration::from_millis(200),
- SpinnerStyle::Arrow => Duration::from_millis(100),
- SpinnerStyle::Block => Duration::from_millis(80),
- }
- }
-
- /// Get the frame at the given index (wraps around)
- pub fn frame_at(&self, index: usize) -> &'static str {
- let frames = self.frames();
- frames[index % frames.len()]
- }
-
- /// Get the number of frames in this spinner
- pub fn frame_count(&self) -> usize {
- self.frames().len()
- }
-}
-
-/// Get the active spinner's frame at the given index
-pub fn active_frame(index: usize) -> &'static str {
- ACTIVE_SPINNER.frame_at(index)
-}
-
-/// Get the active spinner's tick interval
-pub fn active_tick_interval() -> Duration {
- ACTIVE_SPINNER.tick_interval()
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn test_frame_wrapping() {
- let style = SpinnerStyle::Line;
- assert_eq!(style.frame_at(0), "/");
- assert_eq!(style.frame_at(4), "/"); // wraps
- assert_eq!(style.frame_at(5), "-");
- }
-
- #[test]
- fn test_all_styles_have_frames() {
- let styles = [
- SpinnerStyle::Line,
- SpinnerStyle::Dots,
- SpinnerStyle::Pulse,
- SpinnerStyle::Arrow,
- SpinnerStyle::Block,
- ];
- for style in styles {
- assert!(!style.frames().is_empty());
- assert!(style.tick_interval().as_millis() > 0);
- }
- }
-}