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
80
81
82
83
84
85
86
87
88
89
90
91
|
use std::fs;
use std::path::PathBuf;
use std::sync::mpsc;
use std::time::Duration;
use log::{debug, error};
use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
use alacritty_terminal::thread;
use crate::event::{Event, EventProxy};
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
const DEBOUNCE_DELAY: Duration = Duration::from_millis(10);
#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
const DEBOUNCE_DELAY: Duration = Duration::from_millis(1000);
pub fn watch(mut paths: Vec<PathBuf>, event_proxy: EventProxy) {
// Canonicalize all paths, filtering out the ones that do not exist.
paths = paths
.drain(..)
.filter_map(|path| match fs::canonicalize(&path) {
Ok(path) => Some(path),
Err(err) => {
error!("Unable to canonicalize config path {:?}: {}", path, err);
None
},
})
.collect();
// Don't monitor config if there is no path to watch.
if paths.is_empty() {
return;
}
// The Duration argument is a debouncing period.
let (tx, rx) = mpsc::channel();
let mut watcher = match watcher(tx, DEBOUNCE_DELAY) {
Ok(watcher) => watcher,
Err(err) => {
error!("Unable to watch config file: {}", err);
return;
},
};
thread::spawn_named("config watcher", move || {
// Get all unique parent directories.
let mut parents = paths
.iter()
.map(|path| {
let mut path = path.clone();
path.pop();
path
})
.collect::<Vec<PathBuf>>();
parents.sort_unstable();
parents.dedup();
// Watch all configuration file directories.
for parent in &parents {
if let Err(err) = watcher.watch(&parent, RecursiveMode::NonRecursive) {
debug!("Unable to watch config directory {:?}: {}", parent, err);
}
}
loop {
let event = match rx.recv() {
Ok(event) => event,
Err(err) => {
debug!("Config watcher channel dropped unexpectedly: {}", err);
break;
},
};
match event {
DebouncedEvent::Rename(..) => continue,
DebouncedEvent::Write(path)
| DebouncedEvent::Create(path)
| DebouncedEvent::Chmod(path) => {
if !paths.contains(&path) {
continue;
}
// Always reload the primary configuration file.
event_proxy.send_event(Event::ConfigReload(paths[0].clone()));
},
_ => {},
}
}
});
}
|