[&mut] [Context]
, giving access to rendering
+/// options, plugins, and output appending.
+/// * `output`: `context` cast to [&mut] dyn [Write]
when you don't
+/// need the whole thing.
+/// * `node`: the [&][&][AstNode]
being formatted, when the
+/// [`NodeValue`]'s contents aren't enough.
+/// * `entering`: [`true`] when the node is being first descended into,
+/// [`false`] when being exited.
+/// * `suppress_children`: a [&mut] [bool]
; set to [`true`] when
+/// `entering` to cause this node's children not to be recursed into by the
+/// formatter.
+///
+/// ```
+/// # use comrak::{create_formatter, parse_document, Arena, Options, nodes::NodeValue};
+/// create_formatter!(CustomFormatter, {
+/// NodeValue::Emph => |output, entering| {
+/// if entering {
+/// output.write_all(b"")?;
+/// } else {
+/// output.write_all(b"")?;
+/// }
+/// },
+/// NodeValue::Strong => |context, entering| {
+/// use std::io::Write;
+/// context.write_all(if entering { b"" } else { b"" })?;
+/// },
+/// NodeValue::Image(ref nl) => |output, node, entering, suppress_children| {
+/// assert!(node.data.borrow().sourcepos == (3, 1, 3, 18).into());
+/// if entering {
+/// output.write_all(nl.url.to_uppercase().as_bytes())?;
+/// *suppress_children = true;
+/// }
+/// },
+/// });
+///
+/// let options = Options::default();
+/// let arena = Arena::new();
+/// let doc = parse_document(
+/// &arena,
+/// "_Hello_, **world**.\n\n",
+/// &options,
+/// );
+///
+/// let mut buf: VecHello, world.
\n/IMG.PNG
\n" +/// ); +/// ``` #[macro_export] macro_rules! create_formatter { - // No overrides (i.e. as used to create comrak::html::HtmlFormatter). - ($name:ident) => { - $crate::create_formatter!($name, {}); - }; - // Permit lack of trailing comma by adding one. ($name:ident, { $( $pat:pat => | $( $capture:ident ),* | $case:tt ),* }) => { $crate::create_formatter!($name, { $( $pat => | $( $capture ),* | $case ),*, }); @@ -81,7 +146,13 @@ macro_rules! create_formatter { options: &$crate::Options, output: &mut dyn ::std::io::Write, ) -> ::std::io::Result<()> { - Self::format_document_with_plugins(root, options, output, &$crate::Plugins::default()) + $crate::html::format_document_with_formatter( + root, + options, + output, + &$crate::Plugins::default(), + Self::formatter, + ) } /// Formats an AST as HTML, modified by the given options. Accepts custom plugins. @@ -92,7 +163,13 @@ macro_rules! create_formatter { output: &'o mut dyn ::std::io::Write, plugins: &'o $crate::Plugins<'o>, ) -> ::std::io::Result<()> { - $crate::html::format_document_with_formatter(root, options, output, plugins, Self::formatter) + $crate::html::format_document_with_formatter( + root, + options, + output, + plugins, + Self::formatter, + ) } fn formatter<'a>( @@ -113,14 +190,16 @@ macro_rules! create_formatter { } } ),* - _ => $crate::html::format_node_default(context, node, entering).map(::std::option::Option::Some), + _ => $crate::html::format_node_default(context, node, entering), } } } }; } -/// TODO +/// This must be exported so its uses in [`create_formatter!`] can be expanded, +/// but it's not intended for direct use. +#[doc(hidden)] #[macro_export] macro_rules! formatter_captures { (($context:ident, $node:ident, $entering:ident, $suppress_children:ident), context, $bind:ident) => { @@ -150,13 +229,23 @@ macro_rules! formatter_captures { }; } -/// TODO +/// Formats the given AST with all options and formatter function specified. +/// +/// The default formatter as used by [`format_document`] is +/// [`format_node_default`]. It is given the [`Context`], [`AstNode`], and a +/// boolean indicating whether the node is being entered into or exited. It +/// should return[Some]\([RenderMode::HTML])
, or [`None`] if the
+/// node's children should not be recursed into automatically.
pub fn format_document_with_formatter<'a, 'o, 'c: 'o>(
root: &'a AstNode<'a>,
options: &'o Options<'c>,
output: &'o mut dyn Write,
plugins: &'o Plugins<'o>,
- formatter: fn(&mut Context, &'a AstNode<'a>, bool) -> io::Result