diff --git a/guide/src/format/configuration/general.md b/guide/src/format/configuration/general.md index a00247ec..af9d532e 100644 --- a/guide/src/format/configuration/general.md +++ b/guide/src/format/configuration/general.md @@ -87,6 +87,7 @@ This controls the build process of your book. build-dir = "book" # the directory where the output is placed create-missing = true # whether or not to create missing pages use-default-preprocessors = true # use the default preprocessors +extra-watch-dirs = [] # directories to watch for triggering builds ``` - **build-dir:** The directory to put the rendered book in. By default this is @@ -108,3 +109,6 @@ use-default-preprocessors = true # use the default preprocessors default preprocessors from running. - Adding `[preprocessor.links]`, for example, will ensure, regardless of `use-default-preprocessors` that `links` it will run. +- **extra-watch-dirs**: A list of paths to directories that will be watched in + the `watch` and `serve` commands. Changes to files under these directories will + trigger rebuilds. Useful if your book depends on files outside its `src` directory. \ No newline at end of file diff --git a/src/cmd/watch.rs b/src/cmd/watch.rs index 9336af77..68921810 100644 --- a/src/cmd/watch.rs +++ b/src/cmd/watch.rs @@ -146,6 +146,17 @@ where // Add the book.toml file to the watcher if it exists let _ = watcher.watch(book.root.join("book.toml"), NonRecursive); + for dir in &book.config.build.extra_watch_dirs { + let path = dir.canonicalize().unwrap(); + if let Err(e) = watcher.watch(&path, Recursive) { + error!( + "Error while watching extra directory {:?}:\n {:?}", + path, e + ); + std::process::exit(1); + } + } + info!("Listening for changes..."); loop { @@ -166,7 +177,11 @@ where }) .collect::>(); - let paths = remove_ignored_files(&book.root, &paths[..]); + // If we are watching files outside the current repository (via extra-watch-dirs), then they are definitionally + // ignored by gitignore. So we handle this case by including such files into the watched paths list. + let any_external_paths = paths.iter().filter(|p| !p.starts_with(&book.root)).cloned(); + let mut paths = remove_ignored_files(&book.root, &paths[..]); + paths.extend(any_external_paths); if !paths.is_empty() { closure(paths, &book.root); diff --git a/src/config.rs b/src/config.rs index 6b8f1414..d9696ea5 100644 --- a/src/config.rs +++ b/src/config.rs @@ -438,6 +438,8 @@ pub struct BuildConfig { /// Should the default preprocessors always be used when they are /// compatible with the renderer? pub use_default_preprocessors: bool, + /// Extra directories to trigger rebuild when watching/serving + pub extra_watch_dirs: Vec, } impl Default for BuildConfig { @@ -446,6 +448,7 @@ impl Default for BuildConfig { build_dir: PathBuf::from("book"), create_missing: true, use_default_preprocessors: true, + extra_watch_dirs: Vec::new(), } } } @@ -772,6 +775,7 @@ mod tests { build_dir: PathBuf::from("outputs"), create_missing: false, use_default_preprocessors: true, + extra_watch_dirs: Vec::new(), }; let rust_should_be = RustConfig { edition: None }; let playground_should_be = Playground { @@ -982,6 +986,7 @@ mod tests { build_dir: PathBuf::from("my-book"), create_missing: true, use_default_preprocessors: true, + extra_watch_dirs: Vec::new(), }; let html_should_be = HtmlConfig { diff --git a/tests/init.rs b/tests/init.rs index 4deb8401..1c3b962b 100644 --- a/tests/init.rs +++ b/tests/init.rs @@ -95,7 +95,7 @@ fn run_mdbook_init_with_custom_book_and_src_locations() { let contents = fs::read_to_string(temp.path().join("book.toml")).unwrap(); assert_eq!( contents, - "[book]\nauthors = []\nlanguage = \"en\"\nmultilingual = false\nsrc = \"in\"\n\n[build]\nbuild-dir = \"out\"\ncreate-missing = true\nuse-default-preprocessors = true\n" + "[book]\nauthors = []\nlanguage = \"en\"\nmultilingual = false\nsrc = \"in\"\n\n[build]\nbuild-dir = \"out\"\ncreate-missing = true\nextra-watch-dirs = []\nuse-default-preprocessors = true\n" ); }