fetter-io / fetter-rs

System-wide Python package discovery, validation, and allow-listing
2 stars 0 forks source link

Implement terminal spinner for long searches #40

Closed flexatone closed 3 weeks ago

flexatone commented 1 month ago

Sample implementation:

use std::io::{stdout, Write};
use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
use std::thread;
use std::time::Duration;
use crossterm::{
    ExecutableCommand,
    cursor,
    terminal::{self, Clear, ClearType},
};

fn start_delayed_spinner(is_searching: Arc<AtomicBool>, delay: Duration) {
    let spinner_frames = vec!["|", "/", "-", "\\"];
    let mut stdout = stdout();
    let mut frame_idx = 0;

    thread::spawn(move || {
        // Sleep for the delay duration before starting the spinner
        thread::sleep(delay);

        // Only start the spinner if the search is still ongoing
        if is_searching.load(Ordering::Relaxed) {
            stdout.execute(Clear(ClearType::CurrentLine)).unwrap();
            while is_searching.load(Ordering::Relaxed) {
                // Move the cursor to the beginning of the line
                stdout.execute(cursor::MoveToColumn(0)).unwrap();

                // Print the spinner frame
                let frame = spinner_frames[frame_idx % spinner_frames.len()];
                print!("Searching... {}", frame);
                stdout.flush().unwrap();

                // Sleep for a short while to create the animation effect
                thread::sleep(Duration::from_millis(100));

                // Advance to the next frame
                frame_idx += 1;
            }

            // Clear spinner when done
            stdout.execute(Clear(ClearType::CurrentLine)).unwrap();
            println!("Search complete!");
        }
    });
}

fn main() {
    let is_searching = Arc::new(AtomicBool::new(true));
    let delay = Duration::from_secs(1); // Delay before showing spinner

    // Start the delayed spinner animation
    let spinner_handle = {
        let is_searching = Arc::clone(&is_searching);
        start_delayed_spinner(is_searching, delay);
    };

    // Simulate a search routine (you can replace this with your actual search code)
    thread::sleep(Duration::from_secs(3)); // Simulating a 3-second search

    // Stop the spinner
    is_searching.store(false, Ordering::Relaxed);

    // Allow the spinner thread to finish
    thread::sleep(Duration::from_millis(500)); // Give time for spinner to clear line
}