summaryrefslogtreecommitdiffstats
path: root/src/refresher.rs
blob: 790a76f224dae4f75bdadeccd870aabd2990ecf5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
use std::sync::mpsc::{self, TryRecvError};
use std::sync::Arc;
use std::thread;
use std::time::Duration;

use anyhow::Result;

use crate::keybindings::REFRESH_EVENT;

/// Allows refresh if the current path has been modified externally.
pub struct Refresher {
    /// Sender of messages, used to terminate the thread properly
    tx: mpsc::Sender<()>,
    /// Handle to the `term::Event` sender thread.
    handle: thread::JoinHandle<()>,
}

impl Refresher {
    /// Between 2 refreshed
    const TEN_SECONDS_IN_DECISECONDS: u8 = 10 * 10;

    /// Event sent to Fm event poller which is interpreted
    /// as a request for refresh.
    /// This key can't be bound to anything (who would use that ?).

    /// Spawn a thread which sends events to the terminal.
    /// Those events are interpreted as refresh requests.
    /// It also listen to a receiver for quit messages.
    ///
    /// This will send periodically an `Key::AltPageUp` event to the terminal which requires a refresh.
    /// This keybind is reserved and can't be bound to anything.
    ///
    /// Using Event::User(()) conflicts with skim internal which interpret this
    /// event as a signal(1) and hangs the terminal.
    pub fn new(term: Arc<tuikit::term::Term>) -> Self {
        let (tx, rx) = mpsc::channel();
        let mut counter: u8 = 0;
        let handle = thread::spawn(move || loop {
            match rx.try_recv() {
                Ok(_) | Err(TryRecvError::Disconnected) => {
                    log::info!("terminating refresher");
                    let _ = term.show_cursor(true);
                    return;
                }
                Err(TryRecvError::Empty) => {}
            }
            counter += 1;
            thread::sleep(Duration::from_millis(100));
            if counter >= Self::TEN_SECONDS_IN_DECISECONDS {
                counter = 0;
                if term.send_event(REFRESH_EVENT).is_err() {
                    break;
                }
            }
        });
        Self { tx, handle }
    }

    /// Send a quit message to the receiver, signaling it to quit.
    /// Join the refreshing thread which should be terminated.
    pub fn quit(self) -> Result<()> {
        self.tx.send(())?;
        let _ = self.handle.join();
        Ok(())
    }
}