Skip to content

Multi-line DefaultValue, comments and attributes lose their indent after the first line: a nested field's [\n\t1,\n] initialiser drops to column 1 #132

Open

Description

@matt-edmondson

What happens

TemplateBase.WriteDefaultValueTo (CodeBlocker/Templates/TemplateBase.cs:96), AddComments (:157), and AddAttributes (:184) all pass the caller's string straight to CodeBlocker.Write / WriteLine. IndentedTextWriter adds the indent only after its own WriteLine. It does not add it after a line break embedded in the text. The first line of a multi-line value is indented, and every later line starts at the indent the caller happened to type, usually none.

Repro (class C nested in Outer, so members sit at two tabs):

new FieldTemplate { Type = "int[]", Name = "xs", DefaultValue = "[\n\t1,\n\t2,\n]" }
new FieldTemplate { Type = "int", Name = "y", Comments = { "// line a\n// line b" } }

Observed (→ = tab):

→→int[] xs = [
→1,
→2,
];

→→// line a
// line b
→→int y;

If DefaultValue contains CRLF and the writer uses LF, or the other way round, the output also mixes line endings. That breaks the byte-identical output #81 established, along the same lines as #123 does for bodies.

Why it matters

The templates exist so callers do not have to manage indentation. The most common multi-line DefaultValue is a collection or object initialiser, and it comes out misaligned whenever the member is nested or sits under a namespace scope. A generator that commits its output then shows formatting churn, or a formatter has to clean up after it. The output still compiles, so this is a layout defect, not a correctness one.

#112 fixed this same problem for expression bodies only (WriteExpressionBody). The three paths above were left out.

Suggested fix

Acceptance criteria

  • A nested field with DefaultValue = "[\n\t1,\n\t2,\n]" renders each continuation line at the field's indent plus the value's own relative indent.
  • A multi-line comment string and a multi-line attribute render every line at the member's indent.
  • CRLF inside any of the three values produces only the writer's NewLine in the output.
  • Tests cover all three paths, both nested and at top level.

Related, but none of them covers these paths: #112 (closed, expression bodies), #123 (body line endings), #121 (verbatim strings in bodies), #126 (blank line after Write("")).

Activity

  1. matt-edmondson commented on Oct 7, 2026

    @matt-edmondson
    ContributorAuthor

    Triage


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions