From c7281459f9097b4456216ecf945796fa707bc4fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Baasch=20de=20Souza?= Date: Thu, 31 Jan 2019 16:31:02 -0200 Subject: [PATCH] Group file changes and rebuild book only once --- src/cmd/serve.rs | 4 ++-- src/cmd/watch.rs | 42 ++++++++++++++++++++++++++++-------------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/cmd/serve.rs b/src/cmd/serve.rs index 9659d820..ac6acbdd 100644 --- a/src/cmd/serve.rs +++ b/src/cmd/serve.rs @@ -115,8 +115,8 @@ pub fn execute(args: &ArgMatches) -> Result<()> { } #[cfg(feature = "watch")] - watch::trigger_on_change(&book, move |path, book_dir| { - info!("File changed: {:?}", path); + watch::trigger_on_change(&book, move |paths, book_dir| { + info!("Files changed: {:?}", paths); info!("Building book..."); // FIXME: This area is really ugly because we need to re-set livereload :( diff --git a/src/cmd/watch.rs b/src/cmd/watch.rs index d800ae7d..e19a5581 100644 --- a/src/cmd/watch.rs +++ b/src/cmd/watch.rs @@ -5,9 +5,10 @@ use clap::{App, ArgMatches, SubCommand}; use mdbook::errors::Result; use mdbook::utils; use mdbook::MDBook; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::sync::mpsc::channel; use std::time::Duration; +use std::thread::sleep; use {get_book_dir, open}; // Create clap subcommand arguments @@ -18,10 +19,12 @@ pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> { "-d, --dest-dir=[dest-dir] 'Output directory for the book{n}\ Relative paths are interpreted relative to the book's root directory.{n}\ If omitted, mdBook uses build.build-dir from book.toml or defaults to `./book`.'", - ).arg_from_usage( + ) + .arg_from_usage( "[dir] 'Root directory for the book{n}\ (Defaults to the Current Directory when omitted)'", - ).arg_from_usage("-o, --open 'Open the compiled book in a web browser'") + ) + .arg_from_usage("-o, --open 'Open the compiled book in a web browser'") } // Watch command implementation @@ -34,8 +37,8 @@ pub fn execute(args: &ArgMatches) -> Result<()> { open(book.build_dir_for("html").join("index.html")); } - trigger_on_change(&book, |path, book_dir| { - info!("File changed: {:?}\nBuilding book...\n", path); + trigger_on_change(&book, |paths, book_dir| { + info!("Files changed: {:?}\nBuilding book...\n", paths); let result = MDBook::load(&book_dir).and_then(|b| b.build()); if let Err(e) = result { @@ -50,7 +53,7 @@ pub fn execute(args: &ArgMatches) -> Result<()> { /// Calls the closure when a book source file is changed, blocking indefinitely. pub fn trigger_on_change(book: &MDBook, closure: F) where - F: Fn(&Path, &Path), + F: Fn(Vec, &Path), { use self::notify::DebouncedEvent::*; use self::notify::RecursiveMode::*; @@ -79,13 +82,24 @@ where info!("Listening for changes..."); - for event in rx.iter() { - debug!("Received filesystem event: {:?}", event); - match event { - Create(path) | Write(path) | Remove(path) | Rename(_, path) => { - closure(&path, &book.root); - } - _ => {} - } + loop { + let first_event = rx.recv().unwrap(); + sleep(Duration::from_millis(50)); + let other_events = rx.try_iter(); + + let all_events = std::iter::once(first_event).chain(other_events); + + let paths = all_events + .filter_map(|event| { + debug!("Received filesystem event: {:?}", event); + + match event { + Create(path) | Write(path) | Remove(path) | Rename(_, path) => Some(path), + _ => None, + } + }) + .collect(); + + closure(paths, &book.root); } }