Skip to content

Add parse::format whitespace formatter to gix-config (#2594)#2636

Open
Amey Pawar (ameyypawar) wants to merge 1 commit into
GitoxideLabs:mainfrom
ameyypawar:gix-config-formatter
Open

Add parse::format whitespace formatter to gix-config (#2594)#2636
Amey Pawar (ameyypawar) wants to merge 1 commit into
GitoxideLabs:mainfrom
ameyypawar:gix-config-formatter

Conversation

@ameyypawar

Copy link
Copy Markdown
Contributor

feat(gix-config): add a flat whitespace formatter (parse::format)

Implements the library half of #2594 — a config-file formatter that re-emits a single file
with normalized whitespace, without resolving include/includeIf.

What

A new module gix_config::parse::format with:

pub fn normalize(input: &[u8], options: &Options) -> Result<BString, parse::Error>

plus Options, Indentation (Tab | Spaces(usize) | None) and Newline (Detect | Lf | CrLf).

It works on the public parse::Events stream, so it is flat by construction — parsing at that
layer never resolves includes (only File does), which is exactly what Eir Nym (@eirnym) needed. Values,
comments and section headers are re-emitted verbatim; only insignificant whitespace, the =
separator, and newlines are rewritten.

Defaults (from the discussion on #2594)

  • 2-space indentation (configurable: tabs or None for no indentation, per 93578237)
  • a single space around =
  • newline style detected from the input (overridable to LF / CRLF)
  • ensure a single trailing newline
  • blank lines left as-is (opt-in to collapse runs of them)
  • trailing whitespace always removed (never significant)

Why this shape

parse::Events already separates whitespace into its own events and round-trips losslessly via
Event::write_to, so the formatter only substitutes the whitespace/separator/newline bytes and
passes everything else through unchanged. Line continuations (\) carry their leading whitespace
inside the value chunk, so the whole ValueNotDone … ValueDone span is emitted verbatim and stays
byte-identical — covered by a dedicated test.

Scope

Library API only. The CLI is intentionally left out — Eir Nym (@eirnym) offered to build it on top once the
API lands.

Tests

Added gix-config/tests/config/parse/format.rs (16 tests): default policy, semantic-equivalence
(re-parse and compare section/key/value triples), line continuation untouched, trailing backslash at
EOF, implicit boolean keys (no injected =), comments preserved, quoted subsection/value verbatim,
newline detect + forced LF/CRLF, tab / 2-space / no-indent, blank-line preserve + opt-in collapse,
separator toggle, and idempotency.

Verified locally against main with:

cargo fmt -p gix-config --check
cargo clippy -p gix-config --all-targets -- -D warnings
cargo test -p gix-config

All pass (94 unit + 224 integration + 32 doctests, 0 failures).

Files changed

  • gix-config/src/parse/format.rs (new)
  • gix-config/src/parse/mod.rs (pub mod format;)
  • gix-config/tests/config/parse/format.rs (new)
  • gix-config/tests/config/parse/mod.rs (mod format;)

Part of #2594 — this is the library API; the CLI will follow (per Eir Nym (@eirnym)'s offer). Intentionally
not using a Closes keyword so the issue stays open for the CLI work.


Disclosure: developed with AI assistance, reviewed and tested by me.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3af56a3f15

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "Codex (@codex) review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "Codex (@codex) address that feedback".

Comment on lines +186 to +187
while out.last() == Some(&b'\n') || out.last() == Some(&b'\r') {
out.pop();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve trailing blank lines when collapse is disabled

With the default max_consecutive_blank_lines: None, callers are told blank lines are left exactly as-is, but this loop strips every trailing \r/\n that was already emitted and then appends a single newline. For an input like [a]\nx = 1\n\n, normalization silently removes the final blank line even though blank-line collapsing was not requested; ensure_trailing_newline should add a newline only when one is missing, or otherwise honor the collapse option explicitly.

Useful? React with 👍 / 👎.

…deLabs#2594)

Adds `gix_config::parse::format::normalize(input, &Options)`, which re-emits a
single config file with sanitized whitespace without resolving includes. Values,
comments and section headers are preserved verbatim; only insignificant
whitespace, the `=` separator and newlines are rewritten.

`Options` controls indentation (two spaces by default; tabs or none also
available), spacing around `=`, the newline sequence (detect/LF/CRLF), the
trailing newline, and optional blank-line collapsing.

This is the library portion; the CLI will follow separately.

Co-authored-by: Claude <ai-agent@example.invalid>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant