use std::fmt::Write;
use facet_diff_core::{
AnsiBackend, BuildOptions, Diff, PlainBackend, RenderOptions, XmlFlavor, build_layout, render,
render_to_string,
};
pub use facet_diff_core::{DiffSymbols, DiffTheme};
use facet_reflect::Peek;
#[derive(Debug, Clone)]
pub struct DiffSerializeOptions {
pub symbols: DiffSymbols,
pub theme: DiffTheme,
pub colors: bool,
pub indent: &'static str,
pub max_line_width: usize,
pub max_unchanged_fields: usize,
pub collapse_threshold: usize,
}
impl Default for DiffSerializeOptions {
fn default() -> Self {
Self {
symbols: DiffSymbols::default(),
theme: DiffTheme::default(),
colors: true,
indent: " ",
max_line_width: 80,
max_unchanged_fields: 5,
collapse_threshold: 3,
}
}
}
impl DiffSerializeOptions {
pub fn new() -> Self {
Self::default()
}
pub const fn no_colors(mut self) -> Self {
self.colors = false;
self
}
pub const fn indent(mut self, indent: &'static str) -> Self {
self.indent = indent;
self
}
pub const fn max_line_width(mut self, width: usize) -> Self {
self.max_line_width = width;
self
}
pub const fn max_unchanged_fields(mut self, count: usize) -> Self {
self.max_unchanged_fields = count;
self
}
pub const fn collapse_threshold(mut self, threshold: usize) -> Self {
self.collapse_threshold = threshold;
self
}
}
pub fn diff_to_string<'mem, 'facet>(
from: &'mem impl facet_core::Facet<'facet>,
to: &'mem impl facet_core::Facet<'facet>,
diff: &Diff<'mem, 'facet>,
) -> String {
diff_to_string_with_options(from, to, diff, &DiffSerializeOptions::default())
}
pub fn diff_to_string_with_options<'mem, 'facet>(
from: &'mem impl facet_core::Facet<'facet>,
to: &'mem impl facet_core::Facet<'facet>,
diff: &Diff<'mem, 'facet>,
options: &DiffSerializeOptions,
) -> String {
let from_peek = Peek::new(from);
let to_peek = Peek::new(to);
let build_opts = BuildOptions {
max_line_width: options.max_line_width,
max_unchanged_fields: options.max_unchanged_fields,
collapse_threshold: options.collapse_threshold,
float_precision: None,
};
let flavor = XmlFlavor;
let layout = build_layout(diff, from_peek, to_peek, &build_opts, &flavor);
if options.colors {
let render_opts = RenderOptions {
indent: options.indent,
symbols: options.symbols.clone(),
backend: AnsiBackend::new(options.theme.clone()),
};
render_to_string(&layout, &render_opts, &flavor)
} else {
let render_opts = RenderOptions {
indent: options.indent,
symbols: options.symbols.clone(),
backend: PlainBackend,
};
render_to_string(&layout, &render_opts, &flavor)
}
}
pub fn diff_to_writer<'mem, 'facet, W: Write>(
from: &'mem impl facet_core::Facet<'facet>,
to: &'mem impl facet_core::Facet<'facet>,
diff: &Diff<'mem, 'facet>,
writer: &mut W,
) -> std::fmt::Result {
diff_to_writer_with_options(from, to, diff, writer, &DiffSerializeOptions::default())
}
pub fn diff_to_writer_with_options<'mem, 'facet, W: Write>(
from: &'mem impl facet_core::Facet<'facet>,
to: &'mem impl facet_core::Facet<'facet>,
diff: &Diff<'mem, 'facet>,
writer: &mut W,
options: &DiffSerializeOptions,
) -> std::fmt::Result {
let from_peek = Peek::new(from);
let to_peek = Peek::new(to);
let build_opts = BuildOptions {
max_line_width: options.max_line_width,
max_unchanged_fields: options.max_unchanged_fields,
collapse_threshold: options.collapse_threshold,
float_precision: None,
};
let flavor = XmlFlavor;
let layout = build_layout(diff, from_peek, to_peek, &build_opts, &flavor);
if options.colors {
let render_opts = RenderOptions {
indent: options.indent,
symbols: options.symbols.clone(),
backend: AnsiBackend::new(options.theme.clone()),
};
render(&layout, writer, &render_opts, &flavor)
} else {
let render_opts = RenderOptions {
indent: options.indent,
symbols: options.symbols.clone(),
backend: PlainBackend,
};
render(&layout, writer, &render_opts, &flavor)
}
}