aboutsummaryrefslogtreecommitdiff
path: root/alacritty/src/config/monitor.rs
diff options
context:
space:
mode:
authorChristian Duerr <contact@christianduerr.com>2020-08-21 15:48:48 +0000
committerGitHub <noreply@github.com>2020-08-21 18:48:48 +0300
commit3c3e6870dedad56b270f5b65ea57d5a6e46b1de6 (patch)
tree84a4e306a1c198f1bb81a090cb41f7b062e3f736 /alacritty/src/config/monitor.rs
parent3a7130086a8b5fa95c46a15d5b09a220be57708c (diff)
downloadr-alacritty-3c3e6870dedad56b270f5b65ea57d5a6e46b1de6.tar.gz
r-alacritty-3c3e6870dedad56b270f5b65ea57d5a6e46b1de6.tar.bz2
r-alacritty-3c3e6870dedad56b270f5b65ea57d5a6e46b1de6.zip
Add configuration file imports
This adds the ability for users to have multiple configuration files which all inherit from each other. The order of imports is chronological, branching out to the deepest children first and overriding every field with that of the configuration files that are loaded at a later point in time. Live config reload watches the directories of all configuration files, allowing edits in any of them to update Alacritty immediately. While the imports are live reloaded, a new configuration file watcher will only be spawned once Alacritty is restarted. Since this might cause loops which would be very difficult to detect, a maximum depth is set to limit the recursion possible with nested configuration files. Fixes #779.
Diffstat (limited to 'alacritty/src/config/monitor.rs')
-rw-r--r--alacritty/src/config/monitor.rs115
1 files changed, 72 insertions, 43 deletions
diff --git a/alacritty/src/config/monitor.rs b/alacritty/src/config/monitor.rs
index 2ed0c426..5d388182 100644
--- a/alacritty/src/config/monitor.rs
+++ b/alacritty/src/config/monitor.rs
@@ -1,57 +1,86 @@
+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};
-pub struct Monitor {
- _thread: ::std::thread::JoinHandle<()>,
-}
+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, Duration::from_millis(10)) {
+ 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();
-impl Monitor {
- pub fn new<P>(path: P, event_proxy: EventProxy) -> Monitor
- where
- P: Into<PathBuf>,
- {
- let path = path.into();
-
- Monitor {
- _thread: 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;
- }
-
- event_proxy.send_event(Event::ConfigReload(path));
- },
- _ => {},
+ // 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()));
+ },
+ _ => {},
+ }
}
- }
+ });
}