use std::sync::mpsc;
use std::thread;
use std::time::Duration;
use std::marker::Send;
use dirs::home_dir;
use log::{debug, error, warn};
use notify::{Watcher, RecursiveMode, DebouncedEvent, watcher};
use crate::ui;
use crate::markdown;
pub trait Sender {
fn send(&mut self, event: ui::Event) -> Result<(), mpsc::SendError<ui::Event>>;
}
impl Sender for glib::Sender<ui::Event> {
fn send(&mut self, event: ui::Event) -> Result<(), mpsc::SendError<ui::Event>> {
glib::Sender::<ui::Event>::send(self, event)
}
}
impl Sender for mpsc::Sender<ui::Event> {
fn send(&mut self, event: ui::Event) -> Result<(), mpsc::SendError<ui::Event>> {
mpsc::Sender::<ui::Event>::send(self, event)
}
}
pub fn init_update_loop<S>(renderer: markdown::Renderer, mut ui_sender: S)
where S: Sender + Send + 'static
{
thread::spawn(move || {
let (watcher_sender, watcher_receiver) = mpsc::channel();
let mut watcher = match watcher(watcher_sender, Duration::from_millis(200)) {
Ok(w) => w,
Err(e) => {
warn!("Couldn't initialize watcher: {}", e);
return;
}
};
let main_watch_path = renderer.canonical_md_path.parent().
unwrap_or_else(|| &renderer.canonical_md_path).
to_owned();
if let Err(e) = watcher.watch(&main_watch_path, RecursiveMode::NonRecursive) {
warn!("Couldn't initialize watcher: {}", e);
return;
}
let mut extra_watch_paths = vec![];
if let Some(home) = home_dir() {
let config_path = home.join(".quickmd.css");
if watcher.watch(&config_path, RecursiveMode::NonRecursive).is_ok() {
debug!("Watching {}", config_path.display());
extra_watch_paths.push(config_path);
}
let config_path = home.join(".config/quickmd.css");
if watcher.watch(&config_path, RecursiveMode::NonRecursive).is_ok() {
debug!("Watching {}", config_path.display());
extra_watch_paths.push(config_path);
}
}
loop {
match watcher_receiver.recv() {
Ok(DebouncedEvent::Write(file)) => {
debug!("File updated: {}", file.display());
if file == renderer.canonical_md_path {
match renderer.run() {
Ok(html) => {
let _ = ui_sender.send(ui::Event::LoadHtml(html));
},
Err(e) => {
error! {
"Error rendering markdown ({}): {:?}",
renderer.canonical_md_path.display(), e
};
}
}
} else if extra_watch_paths.contains(&file) {
let _ = ui_sender.send(ui::Event::Reload);
} else {
debug!("Ignored file update event: {:?}", file)
}
},
Ok(event) => debug!("Ignored watcher event: {:?}", event),
Err(e) => error!("Error watching file for changes: {:?}", e),
}
}
});
}