Skip to content

Add fsharp_keep_single_case_union_multiline setting#3377

Open
philipcraig wants to merge 2 commits into
fsprojects:mainfrom
philipcraig:feature/keep-single-case-union-multiline
Open

Add fsharp_keep_single_case_union_multiline setting#3377
philipcraig wants to merge 2 commits into
fsprojects:mainfrom
philipcraig:feature/keep-single-case-union-multiline

Conversation

@philipcraig

@philipcraig philipcraig commented Jul 11, 2026

Copy link
Copy Markdown

What

Adds an opt-in setting fsharp_keep_single_case_union_multiline (default false, so existing output is unchanged). When enabled, a single-case discriminated union declaration is kept on its own line instead of being collapsed onto the type name when it fits:

// default (false) — unchanged
type MyDU = Short of int

// fsharp_keep_single_case_union_multiline = true
type MyDU =
    | Short of int

Why

The goal is to let users uphold the G-Research F# formatting conventions, which list the multiline layout as the Preferred form for a single-case DU:

// Preferred
type Foo =
    | Foo of int

Today Fantomas collapses a short single-case DU onto one line — even with fsharp_bar_before_discriminated_union_declaration = true it produces type Foo = | Foo of int — so that Preferred multiline form only appears once the declaration is long enough to wrap. This setting lets people following those conventions get the Preferred shape consistently, and (independently) gives teams the uniform "one case per line regardless of case count" style, which also keeps diffs smaller when a second case is later added.

It is opt-in and off by default, so nothing changes for anyone who doesn't set it. Related prior discussion: fsharp/fslang-design#762.

How

  • FormatConfig: new field KeepSingleCaseUnionMultiline (+ default). The editorconfig key is derived by reflection, so parsing/serialization are automatic.
  • CodePrinter: in the single-case branch of genTypeDefn (TypeDefn.Union), use the existing multiline layout when the flag is set instead of expressionFitsOnRestOfLine. Signature files share this path.
  • Docs section + CHANGELOG entry.

Tested

  • New KeepSingleCaseUnionMultilineTests.fs (8 tests: fields / no-field / access modifier / bar-combination / multi-case unaffected / member case / signature file / idempotency).
  • Full Fantomas.Core.Tests green (2849 passed); changed files pass fantomas --check.

Happy to bikeshed the setting name.

philipcraig and others added 2 commits July 11, 2026 15:39
Add a new boolean configuration option that, when enabled, keeps a
single-case discriminated union declaration on its own line instead of
collapsing it onto the same line as the type name when it is short
enough to fit.

The option defaults to false, preserving the existing behaviour. It is
wired through the FormatConfig record (and is therefore picked up
automatically by the .editorconfig reflection-based parser/serializer)
and applied in the single-case union branch of genTypeDefn in
CodePrinter. Signature files share the same code path.

Includes documentation and regression/idempotency tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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