diff --git a/src/cmd/build.rs b/src/cmd/build.rs index 0091d482..c0a28ec0 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -1,7 +1,8 @@ -use crate::{get_book_dir, open}; +use crate::{first_chapter, get_book_dir, open}; use clap::{arg, App, Arg, ArgMatches}; use mdbook::errors::Result; use mdbook::MDBook; +use std::path::Path; // Create clap subcommand arguments pub fn make_subcommand<'help>() -> App<'help> { @@ -38,7 +39,15 @@ pub fn execute(args: &ArgMatches) -> Result<()> { if args.is_present("open") { // FIXME: What's the right behaviour if we don't use the HTML renderer? - open(book.build_dir_for("html").join("index.html")); + match first_chapter(&book) + .map(|path| book.build_dir_for("html").join(path).with_extension("html")) + { + Some(path) if Path::new(&path).exists() => open(path), + _ => { + error!("No chapter available to open"); + std::process::exit(1) + } + } } Ok(()) diff --git a/src/cmd/serve.rs b/src/cmd/serve.rs index bafbfd52..04ee556c 100644 --- a/src/cmd/serve.rs +++ b/src/cmd/serve.rs @@ -1,6 +1,6 @@ #[cfg(feature = "watch")] use super::watch; -use crate::{get_book_dir, open}; +use crate::{first_chapter, get_book_dir, open}; use clap::{arg, App, Arg, ArgMatches}; use futures_util::sink::SinkExt; use futures_util::StreamExt; @@ -102,10 +102,12 @@ pub fn execute(args: &ArgMatches) -> Result<()> { serve(build_dir, sockaddr, reload_tx, &file_404); }); - let serving_url = format!("http://{}", address); - info!("Serving on: {}", serving_url); - if open_browser { + let serving_url = match first_chapter(&book).map(|path| path.with_extension("html")) { + Some(path) => format!("http://{}/{}", address, path.display()), + _ => format!("http://{}", address), + }; + info!("Serving on: {}", serving_url); open(serving_url); } diff --git a/src/cmd/watch.rs b/src/cmd/watch.rs index 78ae1968..2effd29f 100644 --- a/src/cmd/watch.rs +++ b/src/cmd/watch.rs @@ -1,3 +1,4 @@ +use crate::first_chapter; use crate::{get_book_dir, open}; use clap::{arg, App, Arg, ArgMatches}; use mdbook::errors::Result; @@ -45,7 +46,12 @@ pub fn execute(args: &ArgMatches) -> Result<()> { if args.is_present("open") { book.build()?; - open(book.build_dir_for("html").join("index.html")); + match first_chapter(&book) + .map(|path| book.build_dir_for("html").join(path).with_extension("html")) + { + Some(path) if Path::new(&path).exists() => open(path), + _ => warn!("No chapter available to open"), + } } trigger_on_change(&book, |paths, book_dir| { diff --git a/src/main.rs b/src/main.rs index 35562e64..f993d475 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,10 @@ use clap::{App, AppSettings, Arg, ArgMatches}; use clap_complete::Shell; use env_logger::Builder; use log::LevelFilter; +use mdbook::book::Chapter; use mdbook::utils; +use mdbook::BookItem; +use mdbook::MDBook; use std::env; use std::ffi::OsStr; use std::io::Write; @@ -137,6 +140,17 @@ fn get_book_dir(args: &ArgMatches) -> PathBuf { } } +// Return the first displayable chapter of the given book, or None if no displayable +// chapter is found (i.e. only drafts). +fn first_chapter(book: &MDBook) -> Option<&PathBuf> { + book.iter().find_map(|item| match item { + BookItem::Chapter(Chapter { + path: Some(path), .. + }) => Some(path), + _ => None, + }) +} + fn open>(path: P) { info!("Opening web browser"); if let Err(e) = opener::open(path) {