aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--alacritty/src/config/monitor.rs37
-rw-r--r--alacritty/src/event.rs29
-rw-r--r--alacritty/src/main.rs14
4 files changed, 66 insertions, 15 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 203624fe..20df64f0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -36,6 +36,7 @@ Notable changes to the `alacritty_terminal` crate are documented in its
- Config emitting errors for nonexistent import paths
- Kitty keyboard protocol reporting shifted key codes
- Broken search with words broken across line boundary on the first character
+- Config import changes not being live reloaded
## 0.13.2
diff --git a/alacritty/src/config/monitor.rs b/alacritty/src/config/monitor.rs
index 53cff1c9..3f73f120 100644
--- a/alacritty/src/config/monitor.rs
+++ b/alacritty/src/config/monitor.rs
@@ -1,3 +1,5 @@
+use std::collections::hash_map::DefaultHasher;
+use std::hash::{Hash, Hasher};
use std::path::PathBuf;
use std::sync::mpsc::{self, RecvTimeoutError, Sender};
use std::thread::JoinHandle;
@@ -23,6 +25,7 @@ const FALLBACK_POLLING_TIMEOUT: Duration = Duration::from_secs(1);
pub struct ConfigMonitor {
thread: JoinHandle<()>,
shutdown_tx: Sender<Result<NotifyEvent, NotifyError>>,
+ watched_hash: Option<u64>,
}
impl ConfigMonitor {
@@ -32,6 +35,9 @@ impl ConfigMonitor {
return None;
}
+ // Calculate the hash for the unmodified list of paths.
+ let watched_hash = Self::hash_paths(&paths);
+
// Exclude char devices like `/dev/null`, sockets, and so on, by checking that file type is
// a regular file.
paths.retain(|path| {
@@ -139,7 +145,7 @@ impl ConfigMonitor {
}
});
- Some(Self { thread: join_handle, shutdown_tx: tx })
+ Some(Self { watched_hash, thread: join_handle, shutdown_tx: tx })
}
/// Synchronously shut down the monitor.
@@ -154,4 +160,33 @@ impl ConfigMonitor {
warn!("config monitor shutdown failed: {err:?}");
}
}
+
+ /// Check if the config monitor needs to be restarted.
+ ///
+ /// This checks the supplied list of files against the monitored files to determine if a
+ /// restart is necessary.
+ pub fn needs_restart(&self, files: &[PathBuf]) -> bool {
+ Self::hash_paths(files).map_or(true, |hash| Some(hash) == self.watched_hash)
+ }
+
+ /// Generate the hash for a list of paths.
+ fn hash_paths(files: &[PathBuf]) -> Option<u64> {
+ // Use file count limit to avoid allocations.
+ const MAX_PATHS: usize = 1024;
+ if files.len() > MAX_PATHS {
+ return None;
+ }
+
+ // Sort files to avoid restart on order change.
+ let mut sorted_files = [None; MAX_PATHS];
+ for (i, file) in files.iter().enumerate() {
+ sorted_files[i] = Some(file);
+ }
+ sorted_files.sort_unstable();
+
+ // Calculate hash for the paths, regardless of order.
+ let mut hasher = DefaultHasher::new();
+ Hash::hash_slice(&sorted_files, &mut hasher);
+ Some(hasher.finish())
+ }
}
diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs
index 8da758df..72009d88 100644
--- a/alacritty/src/event.rs
+++ b/alacritty/src/event.rs
@@ -1,5 +1,6 @@
//! Process window events.
+use crate::ConfigMonitor;
use std::borrow::Cow;
use std::cmp::min;
use std::collections::{HashMap, HashSet, VecDeque};
@@ -70,6 +71,8 @@ const TOUCH_ZOOM_FACTOR: f32 = 0.01;
/// Stores some state from received events and dispatches actions when they are
/// triggered.
pub struct Processor {
+ pub config_monitor: Option<ConfigMonitor>,
+
clipboard: Clipboard,
scheduler: Scheduler,
initial_window_options: Option<WindowOptions>,
@@ -101,6 +104,16 @@ impl Processor {
// which is done in `loop_exiting`.
let clipboard = unsafe { Clipboard::new(event_loop.display_handle().unwrap().as_raw()) };
+ // Create a config monitor.
+ //
+ // The monitor watches the config file for changes and reloads it. Pending
+ // config changes are processed in the main loop.
+ let mut config_monitor = None;
+ if config.live_config_reload {
+ config_monitor =
+ ConfigMonitor::new(config.config_paths.clone(), event_loop.create_proxy());
+ }
+
Processor {
initial_window_options,
initial_window_error: None,
@@ -113,6 +126,7 @@ impl Processor {
windows: Default::default(),
#[cfg(unix)]
global_ipc_options: Default::default(),
+ config_monitor,
}
}
@@ -160,8 +174,8 @@ impl Processor {
/// Run the event loop.
///
/// The result is exit code generate from the loop.
- pub fn run(mut self, event_loop: EventLoop<Event>) -> Result<(), Box<dyn Error>> {
- let result = event_loop.run_app(&mut self);
+ pub fn run(&mut self, event_loop: EventLoop<Event>) -> Result<(), Box<dyn Error>> {
+ let result = event_loop.run_app(self);
if let Some(initial_window_error) = self.initial_window_error.take() {
Err(initial_window_error)
} else {
@@ -297,6 +311,17 @@ impl ApplicationHandler<Event> for Processor {
if let Ok(config) = config::reload(path, &mut self.cli_options) {
self.config = Rc::new(config);
+ // Restart config monitor if imports changed.
+ if let Some(monitor) = self.config_monitor.take() {
+ let paths = &self.config.config_paths;
+ self.config_monitor = if monitor.needs_restart(paths) {
+ monitor.shutdown();
+ ConfigMonitor::new(paths.clone(), self.proxy.clone())
+ } else {
+ Some(monitor)
+ };
+ }
+
for window_context in self.windows.values_mut() {
window_context.update_config(self.config.clone());
}
diff --git a/alacritty/src/main.rs b/alacritty/src/main.rs
index 6219dd78..da50c3e4 100644
--- a/alacritty/src/main.rs
+++ b/alacritty/src/main.rs
@@ -172,16 +172,6 @@ fn alacritty(mut options: Options) -> Result<(), Box<dyn Error>> {
#[cfg(target_os = "macos")]
locale::set_locale_environment();
- // Create a config monitor when config was loaded from path.
- //
- // The monitor watches the config file for changes and reloads it. Pending
- // config changes are processed in the main loop.
- let mut config_monitor = None;
- if config.live_config_reload {
- config_monitor =
- ConfigMonitor::new(config.config_paths.clone(), window_event_loop.create_proxy());
- }
-
// Create the IPC socket listener.
#[cfg(unix)]
let socket_path = if config.ipc_socket {
@@ -199,7 +189,7 @@ fn alacritty(mut options: Options) -> Result<(), Box<dyn Error>> {
};
// Event processor.
- let processor = Processor::new(config, options, &window_event_loop);
+ let mut processor = Processor::new(config, options, &window_event_loop);
// Start event loop and block until shutdown.
let result = processor.run(window_event_loop);
@@ -219,7 +209,7 @@ fn alacritty(mut options: Options) -> Result<(), Box<dyn Error>> {
// FIXME: Change PTY API to enforce the correct drop order with the typesystem.
// Terminate the config monitor.
- if let Some(config_monitor) = config_monitor.take() {
+ if let Some(config_monitor) = processor.config_monitor.take() {
config_monitor.shutdown();
}