diff --git a/src/toml.rs b/src/toml.rs index 03ea1f8..3b2f7c2 100644 --- a/src/toml.rs +++ b/src/toml.rs @@ -80,6 +80,7 @@ impl Default for FormatOptions { /// ## Required! This value must be specified.\n\ /// ##color =\n\ /// \n\ +/// \n\ /// [log]\n\ /// ## If set to `true`, the app will log to stdout.\n\ /// ##\n\ @@ -127,48 +128,59 @@ fn format_impl( }}; } - if !path.is_empty() { - add_empty_line(s); - emit!("[{}]", path.join(".")); - } - - let leaf_fields = meta.fields.iter().filter(|f| matches!(&f.kind, FieldKind::Leaf { .. })); - let nested_fields = meta.fields.iter().filter(|f| matches!(&f.kind, FieldKind::Nested { .. })); - - for field in leaf_fields.chain(nested_fields) { + // Output all leaf fields first + let leaf_fields = meta.fields.iter().filter_map(|f| match &f.kind { + FieldKind::Leaf { kind, env } => Some((f, kind, env)), + _ => None, + }); + for (field, kind, _env) in leaf_fields { if options.comments { field.doc.iter().for_each(|doc| emit!("#{}", doc)); } - match &field.kind { - FieldKind::Leaf { kind: LeafKind::Required { default }, .. } => { - // Emit comment about default value or the value being required - if options.comments { - if !field.doc.is_empty() { - emit!("#"); - } - emit!("# {}", DefaultValueComment(default.as_ref().map(PrintExpr))); - } - - // Emit the actual line with the name and optional value - match default { - Some(v) => emit!("#{} = {}", field.name, PrintExpr(v)), - None => emit!("#{} =", field.name), + if let LeafKind::Required { default } = kind { + // Emit comment about default value or the value being required + if options.comments { + if !field.doc.is_empty() { + emit!("#"); } + emit!("# {}", DefaultValueComment(default.as_ref().map(PrintExpr))); } - FieldKind::Leaf { kind: LeafKind::Optional, .. } => emit!("#{} =", field.name), - - FieldKind::Nested { meta } => { - let child_path = path.iter().copied().chain([field.name]).collect(); - format_impl(s, meta, child_path, options); + // Emit the actual line with the name and optional value + match default { + Some(v) => emit!("#{} = {}", field.name, PrintExpr(v)), + None => emit!("#{} =", field.name), } + } else { + emit!("#{} =", field.name); } if options.comments { add_empty_line(s); } } + + // Then all nested fields recursively + let nested_fields = meta.fields.iter().filter_map(|f| match &f.kind { + FieldKind::Nested { meta } => Some((f, meta)), + _ => None, + }); + for (field, meta) in nested_fields { + emit!(""); + // add_empty_line(s); + if options.comments { + field.doc.iter().for_each(|doc| emit!("#{}", doc)); + } + + let child_path = path.iter().copied().chain([field.name]).collect::>(); + emit!("[{}]", child_path.join(".")); + format_impl(s, meta, child_path, options); + + if options.comments { + add_empty_line(s); + } + } } /// Helper to emit `meta::Expr` into TOML. diff --git a/tests/format-output/1-default.toml b/tests/format-output/1-default.toml index 5ce4692..92bc8d9 100644 --- a/tests/format-output/1-default.toml +++ b/tests/format-output/1-default.toml @@ -5,8 +5,8 @@ # Required! This value must be specified. #site_name = -# Configurations related to the HTTP communication. +# Configurations related to the HTTP communication. [http] # The port the server will listen on. # @@ -19,6 +19,7 @@ # Default value: "127.0.0.1" #bind = "127.0.0.1" + [http.headers] # The header in which the reverse proxy specifies the username. # @@ -30,8 +31,8 @@ # Default value: "x-display-name" #display_name = "x-display-name" -# Configuring the logging. +# Configuring the logging. [log] # If set to `true`, the app will log to stdout. #