From 905d4fb04747db91c201b537915191c7e3f0c10a Mon Sep 17 00:00:00 2001 From: "Philip K. Warren" Date: Fri, 25 Sep 2026 11:03:50 -0500 Subject: [PATCH 1/2] Update LSP to support additional generate templates Update the LSP to support `buf.gen*.yaml` and `buf*.gen.yaml` as generation templates. This pattern is often used to run multiple generation jobs and is documented as a pattern in the docs: https://buf.build/docs/migration-guides/migrate-from-protoc/. --- CHANGELOG.md | 2 ++ private/buf/buflsp/buf_gen_yaml.go | 25 ++++++++++++++---- private/buf/buflsp/buf_gen_yaml_lsp_test.go | 8 ++++++ private/buf/buflsp/buf_yaml_test.go | 26 +++++++++++++++++++ .../named_template/buf.go.gen.yaml | 11 ++++++++ 5 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 private/buf/buflsp/testdata/buf_gen_yaml/named_template/buf.go.gen.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index 15d63c3eb2..e48b4c6100 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ `ignore: [!foo/bar.proto]`. Previously they parsed as empty strings, now they rejected with an error. - Fix lint comment ignores on proto2 `group` fields being ignored. +- Update the LSP to support named generation templates such as `buf.go.gen.yaml` and + `buf.gen.go.yaml`. - Improve the `buf curl` error message for methods that accept a single request message. - Deduplicate remote input fetches within a single command invocation, so that multiple `inputs` in a `buf.gen.yaml` that resolve to the same archive, git repository, or image diff --git a/private/buf/buflsp/buf_gen_yaml.go b/private/buf/buflsp/buf_gen_yaml.go index d0b09b9cb1..7f77bd4445 100644 --- a/private/buf/buflsp/buf_gen_yaml.go +++ b/private/buf/buflsp/buf_gen_yaml.go @@ -21,6 +21,7 @@ import ( "log/slog" "os" "path/filepath" + "strings" "sync" "buf.build/go/standard/xos/xexec" @@ -38,9 +39,13 @@ const CommandRunGenerate = "buf.generate.run" // plugins in a buf.gen.yaml file and publish informational diagnostics for any that are outdated. const CommandCheckPluginUpdates = "buf.generate.checkPluginUpdates" -// isBufGenYAMLURI reports whether uri refers to a buf.gen.yaml file. +// isBufGenYAMLURI reports whether uri refers to a buf.gen.yaml file. Named +// templates such as buf.go.gen.yaml and buf.gen.go.yaml are also matched, since +// they are commonly passed to buf generate with --template. func isBufGenYAMLURI(uri protocol.URI) bool { - return filepath.Base(uri.Filename()) == bufconfig.DefaultBufGenYAMLFileName + name := filepath.Base(uri.Filename()) + return (strings.HasPrefix(name, "buf") && strings.HasSuffix(name, ".gen.yaml")) || + (strings.HasPrefix(name, "buf.gen") && strings.HasSuffix(name, ".yaml")) } // bufGenYAMLManager tracks open buf.gen.yaml files in the LSP session. @@ -213,8 +218,9 @@ func (m *bufGenYAMLManager) GetCodeLenses(uri protocol.URI) []protocol.CodeLens return lenses } -// ExecuteRunGenerate runs buf generate in the directory containing the given -// buf.gen.yaml URI. Results are reported to the user via ShowMessage. +// ExecuteRunGenerate runs buf generate with the given buf.gen.yaml URI as the +// template, from the directory containing it. Results are reported to the user +// via ShowMessage. func (m *bufGenYAMLManager) ExecuteRunGenerate(ctx context.Context, uri protocol.URI) error { dirPath := filepath.Dir(uri.Filename()) executable, err := os.Executable() @@ -225,7 +231,7 @@ func (m *bufGenYAMLManager) ExecuteRunGenerate(ctx context.Context, uri protocol msg := "buf generate completed successfully" var outBuf bytes.Buffer if err := xexec.Run(ctx, executable, - xexec.WithArgs("generate"), + xexec.WithArgs(bufGenerateArgs(uri)...), xexec.WithDir(dirPath), xexec.WithStdout(&outBuf), xexec.WithStderr(&outBuf), @@ -240,6 +246,15 @@ func (m *bufGenYAMLManager) ExecuteRunGenerate(ctx context.Context, uri protocol return nil } +// bufGenerateArgs returns the buf generate arguments for the template at uri. +func bufGenerateArgs(uri protocol.URI) []string { + name := filepath.Base(uri.Filename()) + if name == bufconfig.DefaultBufGenYAMLFileName { + return []string{"generate"} + } + return []string{"generate", "--template", name} +} + // ExecuteCheckPluginUpdates queries the BSR for the latest version of each // versioned remote plugin in the buf.gen.yaml file and publishes an // informational diagnostic on any plugin line where a newer version is diff --git a/private/buf/buflsp/buf_gen_yaml_lsp_test.go b/private/buf/buflsp/buf_gen_yaml_lsp_test.go index fd86e6290f..208a47adcf 100644 --- a/private/buf/buflsp/buf_gen_yaml_lsp_test.go +++ b/private/buf/buflsp/buf_gen_yaml_lsp_test.go @@ -631,6 +631,14 @@ func TestBufGenYAMLCodeLens(t *testing.T) { wantRunLensLine: 0, wantCheckLensLine: 1, // plugins: key is on line 1 }, + { + name: "named_template", + fixture: "testdata/buf_gen_yaml/named_template/buf.go.gen.yaml", + wantCount: 2, + wantTitles: []string{"Run buf generate", "Check for plugin updates"}, + wantRunLensLine: 0, + wantCheckLensLine: 1, + }, } for _, tc := range tests { diff --git a/private/buf/buflsp/buf_yaml_test.go b/private/buf/buflsp/buf_yaml_test.go index a4a39777ee..9f15991355 100644 --- a/private/buf/buflsp/buf_yaml_test.go +++ b/private/buf/buflsp/buf_yaml_test.go @@ -133,8 +133,15 @@ func TestIsBufGenYAMLURI(t *testing.T) { expected bool }{ {"file:///home/user/project/buf.gen.yaml", true}, + {"file:///home/user/project/buf.go.gen.yaml", true}, + {"file:///home/user/project/buf.connect-go.gen.yaml", true}, + {"file:///home/user/project/buf.gen.go.yaml", true}, + {"file:///home/user/project/buf.gen-private.yaml", true}, {"file:///home/user/project/buf.yaml", false}, + {"file:///home/user/project/buf.work.yaml", false}, + {"file:///home/user/project/buf.policy.yaml", false}, {"file:///home/user/project/buf.gen.yaml.bak", false}, + {"file:///home/user/project/mybuf.gen.yaml", false}, {"file:///home/user/project/foo.proto", false}, } @@ -146,6 +153,25 @@ func TestIsBufGenYAMLURI(t *testing.T) { } } +func TestBufGenerateArgs(t *testing.T) { + t.Parallel() + + tests := []struct { + uri protocol.URI + expected []string + }{ + {"file:///home/user/project/buf.gen.yaml", []string{"generate"}}, + {"file:///home/user/project/buf.go.gen.yaml", []string{"generate", "--template", "buf.go.gen.yaml"}}, + } + + for _, tt := range tests { + t.Run(string(tt.uri), func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.expected, bufGenerateArgs(tt.uri)) + }) + } +} + func TestIsBufPolicyYAMLURI(t *testing.T) { t.Parallel() diff --git a/private/buf/buflsp/testdata/buf_gen_yaml/named_template/buf.go.gen.yaml b/private/buf/buflsp/testdata/buf_gen_yaml/named_template/buf.go.gen.yaml new file mode 100644 index 0000000000..c2e1b52320 --- /dev/null +++ b/private/buf/buflsp/testdata/buf_gen_yaml/named_template/buf.go.gen.yaml @@ -0,0 +1,11 @@ +version: v2 +plugins: + - remote: buf.build/protocolbuffers/go + out: gen/go + - remote: buf.build/bufbuild/es:v2.2.2 + out: gen/es + - local: protoc-gen-custom + out: gen/custom +inputs: + - module: buf.build/acme/petapis + - directory: proto From 570f9b3918b20a4331655185bdfc14d6abfe67a3 Mon Sep 17 00:00:00 2001 From: "Philip K. Warren" Date: Fri, 25 Sep 2026 14:15:43 -0500 Subject: [PATCH 2/2] Use a stricter match --- private/buf/buflsp/buf_gen_yaml.go | 4 ++-- private/buf/buflsp/buf_yaml_test.go | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/private/buf/buflsp/buf_gen_yaml.go b/private/buf/buflsp/buf_gen_yaml.go index 7f77bd4445..ecf6e48333 100644 --- a/private/buf/buflsp/buf_gen_yaml.go +++ b/private/buf/buflsp/buf_gen_yaml.go @@ -44,8 +44,8 @@ const CommandCheckPluginUpdates = "buf.generate.checkPluginUpdates" // they are commonly passed to buf generate with --template. func isBufGenYAMLURI(uri protocol.URI) bool { name := filepath.Base(uri.Filename()) - return (strings.HasPrefix(name, "buf") && strings.HasSuffix(name, ".gen.yaml")) || - (strings.HasPrefix(name, "buf.gen") && strings.HasSuffix(name, ".yaml")) + return (strings.HasPrefix(name, "buf.") && strings.HasSuffix(name, ".gen.yaml")) || + (strings.HasPrefix(name, "buf.gen.") && strings.HasSuffix(name, ".yaml")) } // bufGenYAMLManager tracks open buf.gen.yaml files in the LSP session. diff --git a/private/buf/buflsp/buf_yaml_test.go b/private/buf/buflsp/buf_yaml_test.go index 9f15991355..5a27c08209 100644 --- a/private/buf/buflsp/buf_yaml_test.go +++ b/private/buf/buflsp/buf_yaml_test.go @@ -136,7 +136,10 @@ func TestIsBufGenYAMLURI(t *testing.T) { {"file:///home/user/project/buf.go.gen.yaml", true}, {"file:///home/user/project/buf.connect-go.gen.yaml", true}, {"file:///home/user/project/buf.gen.go.yaml", true}, - {"file:///home/user/project/buf.gen-private.yaml", true}, + {"file:///home/user/project/buf.gen-private.yaml", false}, + {"file:///home/user/project/buf-go.gen.yaml", false}, + {"file:///home/user/project/bufgo.gen.yaml", false}, + {"file:///home/user/project/buf.generated.yaml", false}, {"file:///home/user/project/buf.yaml", false}, {"file:///home/user/project/buf.work.yaml", false}, {"file:///home/user/project/buf.policy.yaml", false},