From a873d468711e14fc291b69f23f50b6769f9e6dab Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" <193874+carols10cents@users.noreply.github.com> Date: Fri, 30 Aug 2019 06:20:53 -0400 Subject: [PATCH] Implement a markdown renderer (#1018) Use case: when trying to `mdbook test` a file that has many `include` directives, and a test fails, the line numbers in the `rustdoc` output don't match the line numbers in the original markdown file. Turning on the markdown renderer implemented here lets you see what is being passed to `rustdoc` by saving the markdown after the preprocessors have run. This renderer could be helpful for debugging many preprocessors, but it's probably not useful in the general case, so it's turned off by default. --- README.md | 3 ++ book-example/src/format/config.md | 20 ++++++++++++++ src/book/mod.rs | 4 ++- src/renderer/markdown_renderer.rs | 46 +++++++++++++++++++++++++++++++ src/renderer/mod.rs | 2 ++ 5 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/renderer/markdown_renderer.rs diff --git a/README.md b/README.md index 97633599..cd98cbda 100644 --- a/README.md +++ b/README.md @@ -169,6 +169,9 @@ format, however there's nothing stopping a renderer from doing static analysis of a book in order to validate links or run tests. Some existing renderers are: - `html` - the built-in renderer which will generate a HTML version of the book +- `markdown` - the built-in renderer (disabled by default) which will run + preprocessors then output the resulting Markdown. Useful for debugging + preprocessors. - [`linkcheck`] - a backend which will check that all links are valid - [`epub`] - an experimental EPUB generator diff --git a/book-example/src/format/config.md b/book-example/src/format/config.md index 6f2bf9be..d443911f 100644 --- a/book-example/src/format/config.md +++ b/book-example/src/format/config.md @@ -242,6 +242,26 @@ heading-split-level = 3 copy-js = true ``` +### Markdown Renderer + +The Markdown renderer will run preprocessors and then output the resulting +Markdown. This is mostly useful for debugging preprocessors, especially in +conjunction with `mdbook test` to see the Markdown that `mdbook` is passing +to `rustdoc`. + +The Markdown renderer is included with `mdbook` but disabled by default. +Enable it by adding an emtpy table to your `book.toml` as follows: + +```toml +[output.markdown] +``` + +There are no configuration options for the Markdown renderer at this time; +only whether it is enabled or disabled. + +See [the preprocessors documentation](#configuring-preprocessors) for how to +specify which preprocessors should run before the Markdown renderer. + ### Custom Renderers A custom renderer can be enabled by adding a `[output.foo]` table to your diff --git a/src/book/mod.rs b/src/book/mod.rs index f464b496..923673c8 100644 --- a/src/book/mod.rs +++ b/src/book/mod.rs @@ -24,7 +24,7 @@ use crate::errors::*; use crate::preprocess::{ CmdPreprocessor, IndexPreprocessor, LinkPreprocessor, Preprocessor, PreprocessorContext, }; -use crate::renderer::{CmdRenderer, HtmlHandlebars, RenderContext, Renderer}; +use crate::renderer::{CmdRenderer, HtmlHandlebars, MarkdownRenderer, RenderContext, Renderer}; use crate::utils; use crate::config::Config; @@ -336,6 +336,8 @@ fn determine_renderers(config: &Config) -> Vec> { renderers.extend(output_table.iter().map(|(key, table)| { if key == "html" { Box::new(HtmlHandlebars::new()) as Box + } else if key == "markdown" { + Box::new(MarkdownRenderer::new()) as Box } else { interpret_custom_renderer(key, table) } diff --git a/src/renderer/markdown_renderer.rs b/src/renderer/markdown_renderer.rs new file mode 100644 index 00000000..e59436e7 --- /dev/null +++ b/src/renderer/markdown_renderer.rs @@ -0,0 +1,46 @@ +use crate::book::BookItem; +use crate::errors::*; +use crate::renderer::{RenderContext, Renderer}; +use crate::utils; + +use std::fs; + +#[derive(Default)] +/// A renderer to output the Markdown after the preprocessors have run. Mostly useful +/// when debugging preprocessors. +pub struct MarkdownRenderer; + +impl MarkdownRenderer { + /// Create a new `MarkdownRenderer` instance. + pub fn new() -> Self { + MarkdownRenderer + } +} + +impl Renderer for MarkdownRenderer { + fn name(&self) -> &str { + "markdown" + } + + fn render(&self, ctx: &RenderContext) -> Result<()> { + let destination = &ctx.destination; + let book = &ctx.book; + + if destination.exists() { + utils::fs::remove_dir_content(destination) + .chain_err(|| "Unable to remove stale Markdown output")?; + } + + trace!("markdown render"); + for item in book.iter() { + if let BookItem::Chapter(ref ch) = *item { + utils::fs::write_file(&ctx.destination, &ch.path, ch.content.as_bytes())?; + } + } + + fs::create_dir_all(&destination) + .chain_err(|| "Unexpected error when constructing destination path")?; + + Ok(()) + } +} diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index d4243332..3dcfaaa4 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -12,8 +12,10 @@ //! [RenderContext]: struct.RenderContext.html pub use self::html_handlebars::HtmlHandlebars; +pub use self::markdown_renderer::MarkdownRenderer; mod html_handlebars; +mod markdown_renderer; use shlex::Shlex; use std::fs;