Skip to content

Feature: optionally preserve blank lines between struct fields - #1657

Open
giuinktse7 wants to merge 6 commits into
DanielGavin:masterfrom
giuinktse7:feat/preserve-struct-blank-lines
Open

Feature: optionally preserve blank lines between struct fields#1657
giuinktse7 wants to merge 6 commits into
DanielGavin:masterfrom
giuinktse7:feat/preserve-struct-blank-lines

Conversation

@giuinktse7

@giuinktse7 giuinktse7 commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Motivation

odinfmt currently collapses blank lines between struct fields, but I often want to separate fields visually into logical groups.

For example, this:

Settings :: struct {
	window_width:  int,
	window_height: int,
	target_fps:    int,

	fullscreen:    bool,
	vertical_sync: bool,
}

becomes:

Settings :: struct {
	window_width:  int,
	window_height: int,
	target_fps:    int,
	fullscreen:    bool,
	vertical_sync: bool,
}

It is possible to preserve the visual separation by adding a comment, but a comment should not be necessary solely for formatting:

Settings :: struct {
	window_width:  int,
	window_height: int,
	target_fps:    int,

	// Display options
	fullscreen:    bool,
	vertical_sync: bool,
}

Proposed Solution

This PR adds an opt-in preserve_struct_blank_lines setting:

{
	"preserve_struct_blank_lines": true
}

When enabled, the formatter preserves blank lines between struct fields while respecting the existing newline_limit
setting.

Each blank-line-separated section is also aligned independently, similar to gofmt. A long field name in one logical
section therefore does not add padding to fields in another section. This applies to both align_struct_fields and
align_struct_declarations.

Comments attached to fields are treated as part of those fields when identifying section boundaries. Blank lines inside multiline block comments do not create sections, while an actual blank line between a field and the next field or its documentation does.

When newline_limit is zero, blank lines are removed and alignment continues across the whole struct because no visible section boundary remains.

The option defaults to false, so existing formatting behavior remains unchanged.

Example

Fields previously aligned across the entire struct:

Fields :: struct {
      short:            int,
      medium_name:      int,

      much_longer_name: int,
      x:                int,
}

With preserve_struct_blank_lines enabled, each blank-line-separated section now has its own alignment width:

Fields :: struct {
      short:       int,
      medium_name: int,

      much_longer_name: int,
      x:                int,
}

Alignment Improvements

This PR also fixes an inconsistency where #subtype was included in declaration alignment widths but omitted from field-type alignment widths. For example, with align_struct_fields enabled:

  Fields :: struct {
        #subtype embedded: Embedded,
        regular: int,
  }

Previously, #subtype was omitted when calculating the maximum width, producing:

  Fields :: struct {
        #subtype embedded: Embedded,
        regular:  int,
  }

After including #subtype in the shared width calculation:

  Fields :: struct {
        #subtype embedded: Embedded,
        regular:           int,
  }

Verification

Added snapshot coverage for:

  • Preserving blank lines between field groups
  • Aligning each field group independently
  • Section alignment with both align_struct_fields and align_struct_declarations
  • Leading, trailing, line, and multiline block comments around section boundaries
  • Ignoring blank lines contained within multiline block comments
  • Accounting for #subtype prefixes during alignment
  • Limiting excessive blank lines according to newline_limit
  • Using whole-struct alignment when newline_limit is zero
  • Retaining the existing collapsing behavior when the option is disabled

The odinfmt snapshot suite passes.

Settings :: struct {
window_width: int,
window_height: int,
target_fps: int,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I wonder with this if we should align each section separately? Similarly to how gofmt handles it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ah, I agree! That behavior is better.

I've updated the PR (& PR body) to use the gofmt style, see:

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.

2 participants