aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/config.rs68
-rw-r--r--src/main.rs44
-rw-r--r--src/renderer/mod.rs61
3 files changed, 111 insertions, 62 deletions
diff --git a/src/config.rs b/src/config.rs
index 27fcf3ca..f3e68dca 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -7,11 +7,13 @@ use std::env;
use std::fs;
use std::io::{self, Read};
use std::path::{Path, PathBuf};
+use std::sync::mpsc;
use ::Rgb;
use font::Size;
use serde_yaml;
use serde::{self, Error as SerdeError};
+use notify::{Watcher as WatcherApi, RecommendedWatcher as FileWatcher, op};
/// Top-level config type
#[derive(Debug, Deserialize, Default)]
@@ -232,7 +234,7 @@ impl Config {
///
/// 1. `$HOME/.config/alacritty.yml`
/// 2. `$HOME/.alacritty.yml`
- pub fn load() -> Result<Config> {
+ pub fn load() -> Result<(Config, PathBuf)> {
let home = env::var("HOME")?;
// First path
@@ -240,15 +242,17 @@ impl Config {
path.push(".config");
path.push("alacritty.yml");
- // Fallback path
- let mut alt_path = PathBuf::from(&home);
- alt_path.push(".alacritty.yml");
-
- match Config::load_from(&path) {
+ match Config::load_from(path) {
Ok(c) => Ok(c),
Err(e) => {
match e {
- Error::NotFound => Config::load_from(&alt_path),
+ Error::NotFound => {
+ // Fallback path
+ let mut alt_path = PathBuf::from(&home);
+ alt_path.push(".alacritty.yml");
+
+ Config::load_from(alt_path)
+ },
_ => Err(e),
}
}
@@ -315,9 +319,10 @@ impl Config {
self.render_timer
}
- fn load_from<P: AsRef<Path>>(path: P) -> Result<Config> {
- let raw = Config::read_file(path)?;
- Ok(serde_yaml::from_str(&raw[..])?)
+ fn load_from<P: Into<PathBuf>>(path: P) -> Result<(Config, PathBuf)> {
+ let path = path.into();
+ let raw = Config::read_file(path.as_path())?;
+ Ok((serde_yaml::from_str(&raw[..])?, path))
}
fn read_file<P: AsRef<Path>>(path: P) -> Result<String> {
@@ -525,3 +530,46 @@ impl Default for Font {
}
}
}
+
+pub struct Watcher(::std::thread::JoinHandle<()>);
+
+pub trait OnConfigReload {
+ fn on_config_reload(&mut self, Config);
+}
+
+impl Watcher {
+ pub fn new<H: OnConfigReload + Send + 'static>(path: PathBuf, mut handler: H) -> Watcher {
+ Watcher(::util::thread::spawn_named("config watcher", move || {
+ let (tx, rx) = mpsc::channel();
+ let mut watcher = FileWatcher::new(tx).unwrap();
+ watcher.watch(&path).expect("watch alacritty yml");
+
+ let config_path = path.as_path();
+
+ loop {
+ let event = rx.recv().expect("watcher event");
+ let ::notify::Event { path, op } = event;
+
+ if let Ok(op) = op {
+ if op.contains(op::RENAME) {
+ continue;
+ }
+
+ if op.contains(op::IGNORED) {
+ if let Some(path) = path.as_ref() {
+ if let Err(err) = watcher.watch(&path) {
+ err_println!("failed to establish watch on {:?}: {:?}", path, err);
+ }
+
+ if path == config_path {
+ if let Ok((config, _)) = Config::load() {
+ handler.on_config_reload(config);
+ };
+ }
+ }
+ }
+ }
+ }
+ }))
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 01c5f511..8a2159e8 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -118,14 +118,14 @@ mod gl {
fn main() {
// Load configuration
- let config = match Config::load() {
+ let (config, config_path) = match Config::load() {
Err(err) => match err {
// Use default config when not found
- config::Error::NotFound => Config::default(),
+ config::Error::NotFound => (Config::default(), None),
// Exit when there's a problem with it
_ => die!("{}", err),
},
- Ok(config) => config,
+ Ok((config, path)) => (config, Some(path)),
};
let font = config.font();
@@ -225,11 +225,25 @@ fn main() {
tx
);
+ let (config_tx, config_rx) = mpsc::channel();
+
+ // create a config watcher when config is loaded from disk
+ let _config_reloader = config_path.map(|config_path| {
+ config::Watcher::new(config_path, ConfigHandler {
+ tx: config_tx,
+ window: window.create_window_proxy(),
+ })
+ });
+
// Main loop
loop {
// Wait for something to happen
processor.process_events(&window);
+ if let Ok(config) = config_rx.try_recv() {
+ display.update_config(&config);
+ }
+
// Maybe draw the terminal
let terminal = terminal.lock();
signal_flag.set(false);
@@ -242,11 +256,31 @@ fn main() {
}
}
+ // FIXME need file watcher to work with custom delegates before
+ // joining config reloader is possible
+ // config_reloader.join().ok();
+
// shutdown
event_loop_handle.join().ok();
println!("Goodbye");
}
+struct ConfigHandler {
+ tx: mpsc::Sender<config::Config>,
+ window: ::glutin::WindowProxy,
+}
+
+impl config::OnConfigReload for ConfigHandler {
+ fn on_config_reload(&mut self, config: Config) {
+ if let Err(..) = self.tx.send(config) {
+ err_println!("Failed to notify of new config");
+ return;
+ }
+
+ self.window.wakeup_event_loop();
+ }
+}
+
struct Display {
window: Arc<glutin::Window>,
renderer: QuadRenderer,
@@ -257,6 +291,10 @@ struct Display {
}
impl Display {
+ pub fn update_config(&mut self, config: &Config) {
+ self.renderer.update_config(config);
+ }
+
pub fn new(window: Arc<glutin::Window>,
renderer: QuadRenderer,
glyph_cache: GlyphCache,
diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs
index eccbb8af..bbd07fe5 100644
--- a/src/renderer/mod.rs
+++ b/src/renderer/mod.rs
@@ -42,37 +42,9 @@ pub trait LoadGlyph {
}
enum Msg {
- ConfigReload(Config),
ShaderReload,
}
-/// Colors!
-///
-/// FIXME this is obviously bad; need static for reload logic for now. Hacking something in with
-/// minimal effort and will improve later.
-///
-/// Only renderer is allowed to access this to prevent race conditions
-static mut COLORS: [Rgb; 18] = [
- Rgb { r: 0, g: 0, b: 0 },
- Rgb { r: 0, g: 0, b: 0 },
- Rgb { r: 0, g: 0, b: 0 },
- Rgb { r: 0, g: 0, b: 0 },
- Rgb { r: 0, g: 0, b: 0 },
- Rgb { r: 0, g: 0, b: 0 },
- Rgb { r: 0, g: 0, b: 0 },
- Rgb { r: 0, g: 0, b: 0 },
- Rgb { r: 0, g: 0, b: 0 },
- Rgb { r: 0, g: 0, b: 0 },
- Rgb { r: 0, g: 0, b: 0 },
- Rgb { r: 0, g: 0, b: 0 },
- Rgb { r: 0, g: 0, b: 0 },
- Rgb { r: 0, g: 0, b: 0 },
- Rgb { r: 0, g: 0, b: 0 },
- Rgb { r: 0, g: 0, b: 0 },
- Rgb { r: 0, g: 0, b: 0 },
- Rgb { r: 0, g: 0, b: 0 },
-];
-
/// Text drawing program
///
/// Uniforms are prefixed with "u", and vertex attributes are prefixed with "a".
@@ -278,6 +250,7 @@ pub struct RenderApi<'a> {
batch: &'a mut Batch,
atlas: &'a mut Vec<Atlas>,
program: &'a mut ShaderProgram,
+ colors: &'a [Rgb; 18],
}
#[derive(Debug)]
@@ -500,7 +473,6 @@ impl QuadRenderer {
let mut watcher = Watcher::new(tx).unwrap();
watcher.watch(TEXT_SHADER_F_PATH).expect("watch fragment shader");
watcher.watch(TEXT_SHADER_V_PATH).expect("watch vertex shader");
- watcher.watch("/home/jwilm/.alacritty.yml").expect("watch alacritty yml");
loop {
let event = rx.recv().expect("watcher event");
@@ -517,15 +489,8 @@ impl QuadRenderer {
println!("failed to establish watch on {:?}: {:?}", path, err);
}
- if path == ::std::path::Path::new("/home/jwilm/.alacritty.yml") {
- if let Ok(config) = Config::load() {
- msg_tx.send(Msg::ConfigReload(config))
- .expect("msg send ok");
- };
- } else {
- msg_tx.send(Msg::ShaderReload)
- .expect("msg send ok");
- }
+ msg_tx.send(Msg::ShaderReload)
+ .expect("msg send ok");
}
}
}
@@ -545,27 +510,24 @@ impl QuadRenderer {
rx: msg_rx,
};
- unsafe {
- COLORS = config.color_list();
- }
-
let atlas = Atlas::new(ATLAS_SIZE);
renderer.atlas.push(atlas);
renderer
}
+ pub fn update_config(&mut self, config: &Config) {
+ self.colors = config.color_list();
+ self.program.activate();
+ self.program.set_color_uniforms(&self.colors);
+ self.program.deactivate();
+ }
+
pub fn with_api<F, T>(&mut self, props: &term::SizeInfo, func: F) -> T
where F: FnOnce(RenderApi) -> T
{
while let Ok(msg) = self.rx.try_recv() {
match msg {
- Msg::ConfigReload(config) => {
- self.colors = config.color_list();
- self.program.activate();
- self.program.set_color_uniforms(&self.colors);
- self.program.deactivate();
- },
Msg::ShaderReload => {
self.reload_shaders(props.width as u32, props.height as u32);
}
@@ -587,6 +549,7 @@ impl QuadRenderer {
batch: &mut self.batch,
atlas: &mut self.atlas,
program: &mut self.program,
+ colors: &self.colors,
});
unsafe {
@@ -732,7 +695,7 @@ impl<'a> RenderApi<'a> {
glyph_cache: &mut GlyphCache
) {
// TODO should be built into renderer
- let color = unsafe { COLORS[::ansi::Color::Background as usize] };
+ let color = self.colors[::ansi::Color::Background as usize];
unsafe {
gl::ClearColor(
color.r as f32 / 255.0,