summaryrefslogtreecommitdiff
path: root/alacritty_terminal/src/config/monitor.rs
blob: 6d2ab41aee8c9d617b51615296910a95be639ecb (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
67
68
69
70
71
72
73
74
75
76
77
78
79
use std::path::PathBuf;
use std::sync::mpsc;
use std::time::Duration;

use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};

pub struct Monitor {
    _thread: ::std::thread::JoinHandle<()>,
    rx: mpsc::Receiver<PathBuf>,
}

pub trait OnConfigReload {
    fn on_config_reload(&mut self);
}

impl OnConfigReload for crate::display::Notifier {
    fn on_config_reload(&mut self) {
        self.notify();
    }
}

impl Monitor {
    /// Get pending config changes
    pub fn pending(&self) -> Option<PathBuf> {
        let mut config = None;
        while let Ok(new) = self.rx.try_recv() {
            config = Some(new);
        }

        config
    }

    pub fn new<H, P>(path: P, mut handler: H) -> Monitor
    where
        H: OnConfigReload + Send + 'static,
        P: Into<PathBuf>,
    {
        let path = path.into();

        let (config_tx, config_rx) = mpsc::channel();

        Monitor {
            _thread: crate::util::thread::spawn_named("config watcher", move || {
                let (tx, rx) = mpsc::channel();
                // The Duration argument is a debouncing period.
                let mut watcher =
                    watcher(tx, Duration::from_millis(10)).expect("Unable to spawn file watcher");
                let config_path = ::std::fs::canonicalize(path).expect("canonicalize config path");

                // Get directory of config
                let mut parent = config_path.clone();
                parent.pop();

                // Watch directory
                watcher
                    .watch(&parent, RecursiveMode::NonRecursive)
                    .expect("watch alacritty.yml dir");

                loop {
                    match rx.recv().expect("watcher event") {
                        DebouncedEvent::Rename(..) => continue,
                        DebouncedEvent::Write(path)
                        | DebouncedEvent::Create(path)
                        | DebouncedEvent::Chmod(path) => {
                            if path != config_path {
                                continue;
                            }

                            let _ = config_tx.send(path);
                            handler.on_config_reload();
                        },
                        _ => {},
                    }
                }
            }),
            rx: config_rx,
        }
    }
}