AI.Tools.File.Edit.WhitespaceFitter (fnord v0.8.83)
View SourceDeterministic, language-agnostic whitespace fitting for file hunks.
This module is intentionally not wired into AI.Tools.File.Edit yet.
It exists as a proof-of-concept for how we might:
- Infer indentation style (tabs vs spaces, indent width) from local context
- Re-base a replacement hunk's indentation to match the original region
- Prepare
new_hunk_fittedthat can be spliced in literally
The goal is to make fuzzy / whitespace-tolerant matching safer by ensuring that once we have found the right region, we can adjust the replacement's indentation to dovetail with the surrounding code without relying on language-specific formatters or additional LLM calls.
Summary
Functions
Fit a replacement hunk's indentation to match local context.
Infer indentation style (tabs vs spaces, and space width) from a list of lines.
Types
@type indent_style() :: %{type: :spaces | :tabs, width: pos_integer()}
@type line_info() :: %{ indent_cols: non_neg_integer(), content: String.t(), raw: String.t() }
Functions
Fit a replacement hunk's indentation to match local context.
Inputs:
context_before- lines before the original hunk (nearest first preferred)orig_hunk- the original lines in the region being replacedcontext_after- lines after the original hunknew_hunk_raw- the proposed replacement text (may have arbitrary indentation)
Output:
- A single string containing
new_hunk_rawwith indentation adjusted to match the inferred style and depth of the original region.
Behavior (high level):
- Infer indentation style from
context_before ++ orig_hunk ++ context_after. - Determine the target base indentation for the region using the original hunk, falling back to neighbors if needed.
- Compute relative indentation within
new_hunk_rawand re-base it at the target depth, preserving the replacement's internal structure.
This function is deliberately conservative: it only changes leading whitespace and leaves the rest of each line untouched.
@spec infer_indent_style([String.t()]) :: indent_style()
Infer indentation style (tabs vs spaces, and space width) from a list of lines.
This looks only at leading whitespace on non-empty lines. If it sees any leading tabs and no spaced indentation, it assumes a tab-indented style. Otherwise, it looks at the distribution of leading space counts and picks a representative width (e.g., 2 or 4).
If there is not enough information, it falls back to %{type: :spaces, width: 2}.