diff --git a/private/buf/bufformat/formatter.go b/private/buf/bufformat/formatter.go index 396cebb437..1cb9d97ffa 100644 --- a/private/buf/bufformat/formatter.go +++ b/private/buf/bufformat/formatter.go @@ -2408,10 +2408,32 @@ func (f *formatter) writeComment(comment string) { } } else { f.Indent(nil) + // Normalize comment spacing: ensure single-line comments have a space after // + if strings.HasPrefix(comment, "//") { + comment = normalizeCommentSpacing(comment) + } f.WriteString(strings.TrimSpace(comment)) } } +// normalizeCommentSpacing ensures that single-line comments have a space +// after the // delimiter. Comments like //TODO: or //no-space are transformed +// to // TODO: and // no-space respectively. +func normalizeCommentSpacing(comment string) string { + lines := strings.Split(comment, "\n") + for i, line := range lines { + if strings.HasPrefix(line, "//") { + after := strings.TrimPrefix(line, "//") + // If the content after // is non-empty and doesn't start with a space, + // add a single space. + if len(after) > 0 && after[0] != ' ' && after[0] != '\t' { + lines[i] = "// " + after + } + } + } + return strings.Join(lines, "\n") +} + func isCommentPrefix(ch byte) bool { r := rune(ch) // A multi-line comment prefix is *usually* an asterisk, like in the following diff --git a/private/buf/bufformat/formatter_test.go b/private/buf/bufformat/formatter_test.go index 6e43d9e4f1..c582039d7c 100644 --- a/private/buf/bufformat/formatter_test.go +++ b/private/buf/bufformat/formatter_test.go @@ -61,6 +61,7 @@ func testFormatProto2(t *testing.T) { func testFormatProto3(t *testing.T) { testFormatNoDiff(t, "testdata/proto3/all/v1") testFormatNoDiff(t, "testdata/proto3/block/v1") + testFormatNoDiff(t, "testdata/proto3/comment_spacing") testFormatNoDiff(t, "testdata/proto3/file/v1") testFormatNoDiff(t, "testdata/proto3/header/v1") testFormatNoDiff(t, "testdata/proto3/literal/v1") diff --git a/private/buf/bufformat/testdata/proto3/comment_spacing/comment_spacing.golden b/private/buf/bufformat/testdata/proto3/comment_spacing/comment_spacing.golden new file mode 100644 index 0000000000..69b79494c7 --- /dev/null +++ b/private/buf/bufformat/testdata/proto3/comment_spacing/comment_spacing.golden @@ -0,0 +1,16 @@ +syntax = "proto3"; + +package test.v1; + +// no space (should become "// no space") +// one space (already correct) +// multiple spaces (should remain as-is per issue expectation) +// TODO: should become "// TODO:" +// FIXME: another common marker +// indented content (should remain as-is) + +message TestMessage { + // field comment without space + // field comment with one space + string name = 1; +} \ No newline at end of file diff --git a/private/buf/bufformat/testdata/proto3/comment_spacing/comment_spacing.proto b/private/buf/bufformat/testdata/proto3/comment_spacing/comment_spacing.proto new file mode 100644 index 0000000000..18f315b22e --- /dev/null +++ b/private/buf/bufformat/testdata/proto3/comment_spacing/comment_spacing.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; + +package test.v1; + +//no space (should become "// no space") +// one space (already correct) +// multiple spaces (should remain as-is per issue expectation) +//TODO: should become "// TODO:" +//FIXME: another common marker +// indented content (should remain as-is) + +message TestMessage { + //field comment without space + // field comment with one space + string name = 1; +} \ No newline at end of file