From 6572de03e2a1305ac0e861ecad3804616e9b1d21 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Wed, 2 Sep 2026 11:42:16 +0200 Subject: [PATCH] fix(toml_edit): reformat dotted keyed-items in TableLike::fmt `TableLike::fmt` only reset the decor of value items, leaving dotted keyed-items untouched. They are stored as dotted tables and dotted inline tables, so recurse into them to reformat their key segments and nested values as well. Fixes #262 --- crates/toml_edit/src/inline_table.rs | 25 ++++++++++------ crates/toml_edit/src/table.rs | 25 ++++++++++------ crates/toml_edit/tests/testsuite/edit.rs | 38 ++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 18 deletions(-) diff --git a/crates/toml_edit/src/inline_table.rs b/crates/toml_edit/src/inline_table.rs index 10e7ffe..039baef 100644 --- a/crates/toml_edit/src/inline_table.rs +++ b/crates/toml_edit/src/inline_table.rs @@ -512,15 +512,22 @@ impl<'s> IntoIterator for &'s InlineTable { fn decorate_inline_table(table: &mut InlineTable) { use indexmap::map::MutableKeys; - for (mut key, value) in table - .items - .iter_mut2() - .filter(|(_, value)| value.is_value()) - .map(|(key, value)| (key.as_mut(), value.as_value_mut().unwrap())) - { - key.leaf_decor_mut().clear(); - key.dotted_decor_mut().clear(); - value.decor_mut().clear(); + for (key, value) in table.items.iter_mut2() { + match value { + // Dotted keyed-items are stored as dotted inline tables, so reformat the + // key segment and recurse to cover any values nested beneath it. + Item::Value(Value::InlineTable(dotted)) if dotted.is_dotted() => { + key.leaf_decor_mut().clear(); + key.dotted_decor_mut().clear(); + decorate_inline_table(dotted); + } + Item::Value(value) => { + key.leaf_decor_mut().clear(); + key.dotted_decor_mut().clear(); + value.decor_mut().clear(); + } + _ => {} + } } } diff --git a/crates/toml_edit/src/table.rs b/crates/toml_edit/src/table.rs index c9c1f2c..50f873b 100644 --- a/crates/toml_edit/src/table.rs +++ b/crates/toml_edit/src/table.rs @@ -540,15 +540,22 @@ pub(crate) type KeyValuePairs = IndexMap; fn decorate_table(table: &mut Table) { use indexmap::map::MutableKeys; - for (mut key, value) in table - .items - .iter_mut2() - .filter(|(_, value)| value.is_value()) - .map(|(key, value)| (key.as_mut(), value.as_value_mut().unwrap())) - { - key.leaf_decor_mut().clear(); - key.dotted_decor_mut().clear(); - value.decor_mut().clear(); + for (key, value) in table.items.iter_mut2() { + match value { + Item::Value(value) => { + key.leaf_decor_mut().clear(); + key.dotted_decor_mut().clear(); + value.decor_mut().clear(); + } + // Dotted keyed-items are stored as dotted tables, so reformat the key + // segment and recurse to cover any values nested beneath it. + Item::Table(dotted) if dotted.is_dotted() => { + key.leaf_decor_mut().clear(); + key.dotted_decor_mut().clear(); + decorate_table(dotted); + } + _ => {} + } } } diff --git a/crates/toml_edit/tests/testsuite/edit.rs b/crates/toml_edit/tests/testsuite/edit.rs index 4d7d1de..a45c8bf 100644 --- a/crates/toml_edit/tests/testsuite/edit.rs +++ b/crates/toml_edit/tests/testsuite/edit.rs @@ -1238,6 +1238,44 @@ fn test_format_array() { "#]]); } +#[test] +fn test_format_dotted_keys() { + given( + r#" + a . b = 1 + c = 2 + d . e . f = 3 + "#, + ) + .running(|root| { + root.fmt(); + }) + .produces_display(str![[r#" +a.b = 1 +c = 2 +d.e.f = 3 + +"#]]); +} + +#[test] +fn test_format_dotted_keys_in_inline_table() { + given( + r#" + a = { b . c = 1, d = 2 } + "#, + ) + .running(|root| { + let a = root.get_mut("a").unwrap().as_inline_table_mut().unwrap(); + a.fmt(); + }) + .produces_display(str![[r#" + + a = { b.c = 1, d = 2 } + +"#]]); +} + macro_rules! as_inline_table { ($entry:ident) => {{ assert!($entry.is_value());