Skip to content

Apply curb formatting to entire codebase - #3905

Open
Mpdreamz wants to merge 2 commits into
feature/move-to-curbfrom
feature/curb-format-codebase
Open

Apply curb formatting to entire codebase#3905
Mpdreamz wants to merge 2 commits into
feature/move-to-curbfrom
feature/curb-format-codebase

Conversation

@Mpdreamz

@Mpdreamz Mpdreamz commented Aug 20, 2026

Copy link
Copy Markdown
Member

Stacked on #3904 — merge that first.

What is curb?

curb is a new C# formatting tool built by nullean. It reads your existing .editorconfig — both standard .NET keys (dotnet_*, IDE0055) and ReSharper keys (resharper_*) — and formats your code without loading the MSBuild workspace. No project restore, no Roslyn workspace hydration, just the formatter.

Speed comparison on this repo (1 201 files):

Cold (no cache) Warm (cache hit)
dotnet curb format . 414ms ~200ms
dotnet curb check . 429ms 306ms
dotnet format whitespace ~3.5s ~3.5s (no cache)
dotnet format (full) ~46s ~46s (no cache)

The pre-commit hook warmup cost is effectively zero in practice — by the time you commit, dotnet build has already run curb in Debug mode and cached the result. The check pass on commit is burning through the cache, not re-reading the world.

How it works

Instead of a tool you run, think of it as a formatter that already ran. When you dotnet build in Debug mode, curb reformats any file that's out of style before the compiler ever sees it. By the time compilation happens, style is already applied. The only thing left for you to think about is logic.

In Release/CI mode it flips to read-only: instead of rewriting, it errors with CURB0001 if any file would change. That's the signal CI uses. The lint job just runs dotnet curb check . — no workspace load, no project restore.

curb cleanup is worth knowing about: after a build that failed on standard diagnostics (unused usings, redundant modifiers, etc.) curb can apply those fixes in ~15ms by reading the SARIF output the last build already wrote, without loading the workspace at all. Add --forward to pass the remainder to dotnet format style.

This PR

Three commits on top of #3904:

  1. dotnet curb format . — 886 of 1 201 files reformatted with the new .editorconfig settings from Migrate formatting toolchain from dotnet format to curb #3904 (line length 160→140, chained method/binary expression wrapping, binary operators lead lines)
  2. Fix import ordering in one test file where curb and dotnet format differ on sort order for _-prefixed namespaces
  3. Add end_of_line = lf for *.cs — without this, Windows git autocrlf converts LF→CRLF on checkout and curb's Release-mode check flags every file

Pure mechanical reformat, no logic changes. Best reviewed with whitespace hidden (?w=1 in the URL).

Test plan

  • ./build.sh lint passes with 0 violations on all platforms
  • ./build.sh unit-test green
  • Windows CI build passes (the LF fix is the key)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Without end_of_line = lf, git autocrlf on Windows converts LF→CRLF
on checkout, causing curb to flag files as unformatted in Release mode.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Approved — no actionable issues found.


What is this? | From workflow: PR Review

Give us feedback! React with 🚀 if perfect, 👍 if helpful, 👎 if not.

Mpdreamz added a commit to nullean/curb that referenced this pull request Aug 20, 2026
…oreCase (#53)

## Summary

- `elastic/docs-builder#3905` found that Curb and `dotnet format`
disagree on using-directive sort order for a namespace with an
underscore-prefixed segment (`Elastic.ApiExplorer._Partials.Layout`),
and had to fix the ordering by hand in one test file after running
`dotnet curb format .`.
- Root cause: `UsingOrganiser.Compare` case-folded names via
`StringComparison.OrdinalIgnoreCase`, which folds to **upper** case
internally. That leaves `_` (0x5F) above every letter, so `_Partials`
sorts after `Infrastructure`. `dotnet format`'s own sort folds to
**lower** case, where `_` (0x5F) sits below `i` (0x69), so it sorts
`_Partials` before `Infrastructure` — the opposite order.
- Verified directly: `string.Compare("_Partials", "Infrastructure",
StringComparison.OrdinalIgnoreCase)` returns positive (wrong direction);
lower-casing both first and comparing ordinally returns negative
(matches `dotnet format`).
- Fix: fold with `.ToLowerInvariant()` + `string.CompareOrdinal` instead
of `StringComparison.OrdinalIgnoreCase`. The existing case-sensitive
ordinal tie-break is unchanged, and the fix preserves the original
motivating case (`Microsoft.CodeAnalysis.CSharp.CodeStyle` sorting after
`Microsoft.CodeAnalysis.CodeStyle` — verified by hand with the same test
harness).

## Test plan

- [x] Added
`An_underscore_prefixed_segment_sorts_before_a_capitalised_one` to
`UsingOrderTests.cs`, reproducing the exact docs-builder namespace
shape.
- [x] Full test suite (`dotnet run --project tests/Nullean.Curb.Tests -c
Release`): 1134 succeeded, 0 failed, 5 pre-existing skips.
- [x] `./build.sh conformance --corpus <elastic/docs-builder checkout>`:
1201/1201 files (100.00%) — confirms the fix, applied to the actual
repository that surfaced this, needs no further manual correction.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_015byCT9ghPLnCK3QZf5wNPD

Co-authored-by: mpdreamz <mpdreamz@cosmolino.home>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants