use super::Formatter;
use crate::{Change, Diff, FormatError};
#[derive(Debug)]
pub struct MarkdownFormatter {
max_value_length: usize,
}
impl MarkdownFormatter {
pub fn new() -> Self {
Self {
max_value_length: 100,
}
}
pub fn max_value_length(mut self, length: usize) -> Self {
self.max_value_length = length;
self
}
fn truncate(&self, s: String) -> String {
if s.len() > self.max_value_length {
format!("{}...", &s[..self.max_value_length])
} else {
s
}
}
}
impl Default for MarkdownFormatter {
fn default() -> Self {
Self::new()
}
}
impl Formatter for MarkdownFormatter {
fn format(&self, diff: &Diff) -> Result<String, FormatError> {
if diff.is_empty() {
return Ok(String::from("No changes"));
}
let mut output = String::new();
output.push_str("| Path | Change | Old Value | New Value |\n");
output.push_str("|------|--------|-----------|-----------|");
output.push('\n');
for (path, change) in diff.changes() {
match change {
Change::Added(val) => {
let val_str = self.truncate(format!("{:?}", val));
output.push_str(&format!("| {} | Added | - | {} |\n", path, val_str));
}
Change::Removed(val) => {
let val_str = self.truncate(format!("{:?}", val));
output.push_str(&format!("| {} | Removed | {} | - |\n", path, val_str));
}
Change::Modified { from, to } => {
let from_str = self.truncate(format!("{:?}", from));
let to_str = self.truncate(format!("{:?}", to));
output.push_str(&format!(
"| {} | Modified | {} | {} |\n",
path, from_str, to_str
));
}
Change::Elided { reason, count } => {
output.push_str(&format!(
"| {} | Elided | {} ({} items) | - |\n",
path, reason, count
));
}
}
}
Ok(output)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Path;
use serde_value::Value;
#[test]
fn test_markdown_format() {
let mut diff = Diff::new();
diff.insert(Path::root().field("x"), Change::Added(Value::I64(42)));
let formatter = MarkdownFormatter::new();
let output = formatter.format(&diff).unwrap();
assert!(output.contains("| Path | Change |"));
assert!(output.contains("| x | Added |"));
}
}