Skip to content

Commit

Permalink
feat(fmt): Add clear_fmt_recursive method (#45)
Browse files Browse the repository at this point in the history
Fixes #46

When comparing two different `KdlNode` or `KdlDocument`, it's useful to
have a "canonical" representation where formatting differences do not
matter.

`clear_fmt` removes all formatting from a `KdlNode`, but does not apply
recursively, as a result, it doesn't create a canonical representation.
`clear_fmt_recursive` solves this by applying `clear_fmt` recursively to
the contents of the node.
  • Loading branch information
nicopap authored and zkat committed Jun 11, 2022
1 parent b3ea4a8 commit cd2d6e4
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 0 deletions.
41 changes: 41 additions & 0 deletions src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,11 +180,22 @@ impl KdlDocument {

/// Clears leading and trailing text (whitespace, comments). `KdlNode`s in
/// this document will be unaffected.
///
/// If you need to clear the `KdlNode`s, use [`Self::clear_fmt_recursive`].
pub fn clear_fmt(&mut self) {
self.leading = None;
self.trailing = None;
}

/// Clears leading and trailing text (whitespace, comments), also clearing
/// all the `KdlNode`s in the document.
pub fn clear_fmt_recursive(&mut self) {
self.clear_fmt();
for node in self.nodes.iter_mut() {
node.clear_fmt_recursive();
}
}

/// Auto-formats this Document, making everything nice while preserving
/// comments.
pub fn fmt(&mut self) {
Expand Down Expand Up @@ -265,6 +276,36 @@ mod test {

use super::*;

#[test]
fn canonical_clear_fmt() -> miette::Result<()> {
let left_src = r#"
// There is a node here
first_node /*with cool comments, too */ param=1.03e2 /-"commented" "argument" {
// With nested nodes too
nested 1 2 3
nested_2 "hi" "world" // this one is cool
}
second_node param=153 { nested one=1 two=2; }"#;
let right_src = r#"
first_node param=103.0 "argument" {
// Different indentation, because
// Why not
nested 1 2 3
nested_2 "hi" /* actually, "hello" */ "world"
}
// There is a node here
second_node /* This time, the comment is here */ param=153 {
nested one=1 two=2
}"#;
let mut left_doc: KdlDocument = left_src.parse()?;
let mut right_doc: KdlDocument = right_src.parse()?;
assert_ne!(left_doc, right_doc);
left_doc.clear_fmt_recursive();
right_doc.clear_fmt_recursive();
assert_eq!(left_doc, right_doc);
Ok(())
}

#[test]
fn parsing() -> miette::Result<()> {
let src = "
Expand Down
18 changes: 18 additions & 0 deletions src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ impl KdlEntry {
pub fn clear_fmt(&mut self) {
self.leading = None;
self.trailing = None;
self.value_repr = None;
if let Some(ty) = &mut self.ty {
ty.clear_fmt();
}
if let Some(name) = &mut self.name {
name.clear_fmt();
}
}

/// Gets the custom string representation for this KdlEntry's [`KdlValue`].
Expand Down Expand Up @@ -188,6 +195,17 @@ impl FromStr for KdlEntry {
mod test {
use super::*;

#[test]
fn reset_value_repr() -> miette::Result<()> {
let mut left_entry: KdlEntry = " name=1.03e2".parse()?;
let mut right_entry: KdlEntry = " name=103.0".parse()?;
assert_ne!(left_entry, right_entry);
left_entry.clear_fmt();
right_entry.clear_fmt();
assert_eq!(left_entry, right_entry);
Ok(())
}

#[test]
fn new() {
let entry = KdlEntry::new(42);
Expand Down
32 changes: 32 additions & 0 deletions src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,29 @@ impl KdlNode {
/// Clears leading and trailing text (whitespace, comments), as well as
/// the space before the children block, if any. Individual entries and
/// their formatting will be preserved.
///
/// If you want to clear formatting on all children and entries as well,
/// use [`Self::clear_fmt_recursive`].
pub fn clear_fmt(&mut self) {
self.leading = None;
self.trailing = None;
self.before_children = None;
}

/// Clears leading and trailing text (whitespace, comments), as well as
/// the space before the children block, if any. Individual entries and
/// children formatting will also be cleared.
pub fn clear_fmt_recursive(&mut self) {
self.clear_fmt();
self.name.clear_fmt();
if let Some(children) = &mut self.children {
children.clear_fmt_recursive();
}
for entry in self.entries.iter_mut() {
entry.clear_fmt();
}
}

/// Fetches an entry by key. Number keys will look up arguments, strings
/// will look up properties.
pub fn get(&self, key: impl Into<NodeKey>) -> Option<&KdlEntry> {
Expand Down Expand Up @@ -509,6 +526,21 @@ impl KdlNode {
mod test {
use super::*;

#[test]
fn canonical_clear_fmt() -> miette::Result<()> {
let mut left_node: KdlNode = r#"node /-"commented" param_name=103.000 {
// This is a nested node
nested 1 2 3
}"#
.parse()?;
let mut right_node: KdlNode = "node param_name=103.0 { nested 1 2 3; }".parse()?;
assert_ne!(left_node, right_node);
left_node.clear_fmt_recursive();
right_node.clear_fmt_recursive();
assert_eq!(left_node, right_node);
Ok(())
}

#[test]
fn parsing() -> miette::Result<()> {
let node: KdlNode = "\n\t (\"ty\")\"node\" 0xDEADbeef;\n".parse()?;
Expand Down

0 comments on commit cd2d6e4

Please sign in to comment.