Skip to content

Commit d500877

Browse files
doriableemcfarlane
andauthored
Use new protocompile/experimental for LSP and implement textDocument/References (#4026)
Co-authored-by: Edward McFarlane <[email protected]>
1 parent ae89d7f commit d500877

File tree

14 files changed

+1193
-1454
lines changed

14 files changed

+1193
-1454
lines changed

.golangci.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,11 @@ linters:
158158
# G115 checks for use of truncating conversions.
159159
path: private/buf/buflsp/file.go
160160
text: 'G115:'
161+
- linters:
162+
- gosec
163+
# G115 checks for use of truncating conversions.
164+
path: private/buf/buflsp/diagnostic.go
165+
text: 'G115:'
161166
- linters:
162167
- gosec
163168
# G115 checks for use of truncating conversions.

cmd/buf/buf.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import (
3434
"github.com/bufbuild/buf/cmd/buf/internal/command/beta/bufpluginv1"
3535
"github.com/bufbuild/buf/cmd/buf/internal/command/beta/bufpluginv1beta1"
3636
"github.com/bufbuild/buf/cmd/buf/internal/command/beta/bufpluginv2"
37-
"github.com/bufbuild/buf/cmd/buf/internal/command/beta/lsp"
3837
"github.com/bufbuild/buf/cmd/buf/internal/command/beta/price"
3938
betaplugindelete "github.com/bufbuild/buf/cmd/buf/internal/command/beta/registry/plugin/plugindelete"
4039
betapluginpush "github.com/bufbuild/buf/cmd/buf/internal/command/beta/registry/plugin/pluginpush"
@@ -59,6 +58,7 @@ import (
5958
"github.com/bufbuild/buf/cmd/buf/internal/command/generate"
6059
"github.com/bufbuild/buf/cmd/buf/internal/command/lint"
6160
"github.com/bufbuild/buf/cmd/buf/internal/command/lsfiles"
61+
"github.com/bufbuild/buf/cmd/buf/internal/command/lsp/lspserve"
6262
"github.com/bufbuild/buf/cmd/buf/internal/command/mod/modlsbreakingrules"
6363
"github.com/bufbuild/buf/cmd/buf/internal/command/mod/modlslintrules"
6464
"github.com/bufbuild/buf/cmd/buf/internal/command/mod/modopen"
@@ -177,6 +177,13 @@ func newRootCommand(name string) *appcmd.Command {
177177
configlsmodules.NewCommand("ls-modules", builder),
178178
},
179179
},
180+
{
181+
Use: "lsp",
182+
Short: "Work with Buf Language Server",
183+
SubCommands: []*appcmd.Command{
184+
lspserve.NewCommand("serve", builder, ``, false, false),
185+
},
186+
},
180187
{
181188
Use: "mod",
182189
Short: `Manage Buf modules, all commands are deprecated and have moved to the "buf config", "buf dep", or "buf registry" subcommands.`,
@@ -386,7 +393,7 @@ func newRootCommand(name string) *appcmd.Command {
386393
Use: "beta",
387394
Short: "Beta commands. Unstable and likely to change",
388395
SubCommands: []*appcmd.Command{
389-
lsp.NewCommand("lsp", builder),
396+
lspserve.NewCommand("lsp", builder, deprecatedMessage("buf lsp serve", "buf beta lsp"), true, true),
390397
price.NewCommand("price", builder),
391398
bufpluginv1beta1.NewCommand("buf-plugin-v1beta1", builder),
392399
bufpluginv1.NewCommand("buf-plugin-v1", builder),

cmd/buf/internal/command/beta/lsp/lsp.go renamed to cmd/buf/internal/command/lsp/lspserve/lspserve.go

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
// Package lsp defines the entry-point for the Buf LSP within the CLI.
15+
// Package lspserve defines the entry-point for the Buf LSP within the CLI.
1616
//
1717
// The actual implementation of the LSP lives under private/buf/buflsp
18-
package lsp
18+
package lspserve
1919

2020
import (
2121
"context"
@@ -29,6 +29,7 @@ import (
2929
"buf.build/go/standard/xio"
3030
"github.com/bufbuild/buf/private/buf/bufcli"
3131
"github.com/bufbuild/buf/private/buf/buflsp"
32+
"github.com/bufbuild/protocompile/experimental/incremental"
3233
"github.com/spf13/pflag"
3334
"go.lsp.dev/jsonrpc2"
3435
)
@@ -39,14 +40,25 @@ const (
3940
)
4041

4142
// NewCommand constructs the CLI command for executing the LSP.
42-
func NewCommand(name string, builder appext.Builder) *appcmd.Command {
43+
func NewCommand(
44+
name string,
45+
builder appext.Builder,
46+
deprecated string,
47+
hidden bool,
48+
beta bool,
49+
) *appcmd.Command {
4350
flags := newFlags()
4451
return &appcmd.Command{
45-
Use: name,
46-
Short: "Start the language server",
47-
Args: appcmd.NoArgs,
52+
Use: name,
53+
Short: "Start the language server",
54+
Args: appcmd.NoArgs,
55+
Deprecated: deprecated,
56+
Hidden: hidden,
4857
Run: builder.NewRunFunc(
4958
func(ctx context.Context, container appext.Container) error {
59+
if beta {
60+
bufcli.WarnBetaCommand(ctx, container)
61+
}
5062
return run(ctx, container, flags)
5163
},
5264
),
@@ -79,8 +91,6 @@ func run(
7991
container appext.Container,
8092
flags *flags,
8193
) (retErr error) {
82-
bufcli.WarnBetaCommand(ctx, container)
83-
8494
transport, err := dial(container, flags)
8595
if err != nil {
8696
return err
@@ -108,7 +118,15 @@ func run(
108118
retErr = errors.Join(retErr, wasmRuntime.Close(ctx))
109119
}()
110120

111-
conn, err := buflsp.Serve(ctx, wktBucket, container, controller, wasmRuntime, jsonrpc2.NewStream(transport))
121+
conn, err := buflsp.Serve(
122+
ctx,
123+
wktBucket,
124+
container,
125+
controller,
126+
wasmRuntime,
127+
jsonrpc2.NewStream(transport),
128+
incremental.New(),
129+
)
112130
if err != nil {
113131
return err
114132
}

go.mod

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ require (
1616
buf.build/go/standard v0.1.0
1717
connectrpc.com/connect v1.19.1
1818
connectrpc.com/otelconnect v0.8.0
19-
github.com/bufbuild/protocompile v0.14.1
19+
github.com/bufbuild/protocompile v0.14.2-0.20251014195937-e47b8c2d39fe
2020
github.com/bufbuild/protoplugin v0.0.0-20250218205857-750e09ce93e1
2121
github.com/docker/docker v28.5.1+incompatible
2222
github.com/go-chi/chi/v5 v5.2.3
@@ -52,6 +52,7 @@ require (
5252
)
5353

5454
require (
55+
buf.build/gen/go/bufbuild/protodescriptor/protocolbuffers/go v1.36.10-20250109164928-1da0de137947.1 // indirect
5556
buf.build/gen/go/pluginrpc/pluginrpc/protocolbuffers/go v1.36.10-20241007202033-cf42259fcbfc.1 // indirect
5657
buf.build/go/interrupt v1.1.0 // indirect
5758
cel.dev/expr v0.24.0 // indirect
@@ -82,14 +83,17 @@ require (
8283
github.com/morikuni/aec v1.0.0 // indirect
8384
github.com/opencontainers/go-digest v1.0.0 // indirect
8485
github.com/opencontainers/image-spec v1.1.1 // indirect
86+
github.com/petermattis/goid v0.0.0-20250904145737-900bdf8bb490 // indirect
8587
github.com/pkg/errors v0.9.1 // indirect
8688
github.com/pmezard/go-difflib v1.0.0 // indirect
8789
github.com/quic-go/qpack v0.5.1 // indirect
90+
github.com/rivo/uniseg v0.4.7 // indirect
8891
github.com/russross/blackfriday/v2 v2.1.0 // indirect
8992
github.com/segmentio/asm v1.2.1 // indirect
9093
github.com/segmentio/encoding v0.5.3 // indirect
9194
github.com/sirupsen/logrus v1.9.3 // indirect
9295
github.com/stoewer/go-strcase v1.3.1 // indirect
96+
github.com/tidwall/btree v1.8.1 // indirect
9397
github.com/vbatts/tar-split v0.12.1 // indirect
9498
go.lsp.dev/pkg v0.0.0-20210717090340-384b27a52fb2 // indirect
9599
go.opentelemetry.io/auto/sdk v1.2.1 // indirect

go.sum

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
buf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.36.10-20250718181942-e35f9b667443.1 h1:FzJGrb8r7vir+P3zJ5Ebey8p54LYTYtQsrM/U35YO9Q=
22
buf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.36.10-20250718181942-e35f9b667443.1/go.mod h1:E6HwqUm4Ag7bXtg/tX7jHWO7CgpknbmeACgDax0icV0=
3+
buf.build/gen/go/bufbuild/protodescriptor/protocolbuffers/go v1.36.10-20250109164928-1da0de137947.1 h1:9hkMnVoImDlY7rTlAWIWXdkGUKOjf3YlyZeSbYT29uA=
4+
buf.build/gen/go/bufbuild/protodescriptor/protocolbuffers/go v1.36.10-20250109164928-1da0de137947.1/go.mod h1:/AouMCAeQ+kB7+RRFpdUlZe3503p18VoUNcU2AFqZXM=
35
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.10-20250912141014-52f32327d4b0.1 h1:31on4W/yPcV4nZHL4+UCiCvLPsMqe/vJcNg8Rci0scc=
46
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.10-20250912141014-52f32327d4b0.1/go.mod h1:fUl8CEN/6ZAMk6bP8ahBJPUJw7rbp+j4x+wCcYi2IG4=
57
buf.build/gen/go/bufbuild/registry/connectrpc/go v1.19.1-20250924144421-cb55f06efbd2.2 h1:hLW3Bta/Nplz6v//utPUmIqAWIIXFOMH0hWXJv9cWLQ=
@@ -36,8 +38,10 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo
3638
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
3739
github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
3840
github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
39-
github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw=
40-
github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c=
41+
github.com/bmatcuk/doublestar/v4 v4.9.1 h1:X8jg9rRZmJd4yRy7ZeNDRnM+T3ZfHv15JiBJ/avrEXE=
42+
github.com/bmatcuk/doublestar/v4 v4.9.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
43+
github.com/bufbuild/protocompile v0.14.2-0.20251014195937-e47b8c2d39fe h1:MnsgPmILvj7ItlAtkF7oeJEIq1fPkCuxqTOkPWoEmDo=
44+
github.com/bufbuild/protocompile v0.14.2-0.20251014195937-e47b8c2d39fe/go.mod h1:HKN246DRQwavs64sr2xYmSL+RFOFxmLti+WGCZ2jh9U=
4145
github.com/bufbuild/protoplugin v0.0.0-20250218205857-750e09ce93e1 h1:V1xulAoqLqVg44rY97xOR+mQpD2N+GzhMHVwJ030WEU=
4246
github.com/bufbuild/protoplugin v0.0.0-20250218205857-750e09ce93e1/go.mod h1:c5D8gWRIZ2HLWO3gXYTtUfw/hbJyD8xikv2ooPxnklQ=
4347
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
@@ -128,16 +132,22 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
128132
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
129133
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
130134
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
135+
github.com/petermattis/goid v0.0.0-20250904145737-900bdf8bb490 h1:QTvNkZ5ylY0PGgA+Lih+GdboMLY/G9SEGLMEGVjTVA4=
136+
github.com/petermattis/goid v0.0.0-20250904145737-900bdf8bb490/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
131137
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
132138
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
133139
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
134140
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
135141
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
136142
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
143+
github.com/protocolbuffers/protoscope v0.0.0-20221109213918-8e7a6aafa2c9 h1:arwj11zP0yJIxIRiDn22E0H8PxfF7TsTrc2wIPFIsf4=
144+
github.com/protocolbuffers/protoscope v0.0.0-20221109213918-8e7a6aafa2c9/go.mod h1:SKZx6stCn03JN3BOWTwvVIO2ajMkb/zQdTceXYhKw/4=
137145
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
138146
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
139147
github.com/quic-go/quic-go v0.55.0 h1:zccPQIqYCXDt5NmcEabyYvOnomjs8Tlwl7tISjJh9Mk=
140148
github.com/quic-go/quic-go v0.55.0/go.mod h1:DR51ilwU1uE164KuWXhinFcKWGlEjzys2l8zUl5Ss1U=
149+
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
150+
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
141151
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
142152
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
143153
github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
@@ -168,6 +178,8 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
168178
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
169179
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
170180
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
181+
github.com/tidwall/btree v1.8.1 h1:27ehoXvm5AG/g+1VxLS1SD3vRhp/H7LuEfwNvddEdmA=
182+
github.com/tidwall/btree v1.8.1/go.mod h1:jBbTdUWhSZClZWoDg54VnvV7/54modSOzDN7VXftj1A=
171183
github.com/vbatts/tar-split v0.12.1 h1:CqKoORW7BUWBe7UL/iqTVvkTBOF8UvOMKOIZykxnnbo=
172184
github.com/vbatts/tar-split v0.12.1/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA=
173185
go.lsp.dev/jsonrpc2 v0.10.0 h1:Pr/YcXJoEOTMc/b6OTmcR1DPJ3mSWl/SWiU1Cct6VmI=

private/buf/buflsp/buflsp.go

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ import (
2828
"buf.build/go/standard/xlog/xslog"
2929
"github.com/bufbuild/buf/private/buf/bufctl"
3030
"github.com/bufbuild/buf/private/pkg/storage"
31-
"github.com/bufbuild/buf/private/pkg/storage/storageos"
3231
"github.com/bufbuild/buf/private/pkg/wasm"
32+
"github.com/bufbuild/protocompile/experimental/incremental"
3333
"go.lsp.dev/jsonrpc2"
3434
"go.lsp.dev/protocol"
3535
"go.uber.org/zap"
@@ -45,32 +45,21 @@ func Serve(
4545
controller bufctl.Controller,
4646
wasmRuntime wasm.Runtime,
4747
stream jsonrpc2.Stream,
48+
queryExecutor *incremental.Executor,
4849
) (jsonrpc2.Conn, error) {
49-
// The LSP protocol deals with absolute filesystem paths. This requires us to
50-
// bypass the bucket API completely, so we create a bucket pointing at the filesystem
51-
// root.
52-
bucketProvider := storageos.NewProvider(storageos.ProviderWithSymlinks())
53-
bucket, err := bucketProvider.NewReadWriteBucket(
54-
"/", // TODO: This is not correct for Windows.
55-
storageos.ReadWriteBucketWithSymlinksIfSupported(),
56-
)
57-
if err != nil {
58-
return nil, err
59-
}
60-
6150
conn := jsonrpc2.NewConn(stream)
6251
lsp := &lsp{
6352
conn: conn,
6453
client: protocol.ClientDispatcher(
6554
&connWrapper{Conn: conn, logger: container.Logger()},
6655
zap.NewNop(), // The logging from protocol itself isn't very good, we've replaced it with connAdapter here.
6756
),
68-
container: container,
69-
logger: container.Logger(),
70-
controller: controller,
71-
wasmRuntime: wasmRuntime,
72-
rootBucket: bucket,
73-
wktBucket: wktBucket,
57+
container: container,
58+
logger: container.Logger(),
59+
controller: controller,
60+
wasmRuntime: wasmRuntime,
61+
wktBucket: wktBucket,
62+
queryExecutor: queryExecutor,
7463
}
7564
lsp.fileManager = newFileManager(lsp)
7665
off := protocol.TraceOff
@@ -94,13 +83,13 @@ type lsp struct {
9483
client protocol.Client
9584
container appext.Container
9685

97-
logger *slog.Logger
98-
controller bufctl.Controller
99-
wasmRuntime wasm.Runtime
100-
rootBucket storage.ReadBucket
101-
fileManager *fileManager
102-
103-
wktBucket storage.ReadBucket
86+
logger *slog.Logger
87+
controller bufctl.Controller
88+
wasmRuntime wasm.Runtime
89+
fileManager *fileManager
90+
queryExecutor *incremental.Executor
91+
wktBucket storage.ReadBucket
92+
shutdown bool
10493

10594
lock sync.Mutex
10695

private/buf/buflsp/diagnostic.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Copyright 2020-2025 Buf Technologies, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// This file provides helpers for bridging protocompile and LSP diagnostics.
16+
17+
package buflsp
18+
19+
import (
20+
"encoding/json"
21+
"strings"
22+
23+
"github.com/bufbuild/protocompile/experimental/report"
24+
"go.lsp.dev/protocol"
25+
)
26+
27+
// UTF-16 is the default per LSP spec. Position encoding negotiation is not yet
28+
// supported by the go.lsp.dev/protocol library.
29+
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#position
30+
const positionalEncoding = report.UTF16Length
31+
32+
// diagnosticData is a structure to hold the [report.Diagnostic] notes, help, and debug
33+
// messages, to marshal into JSON for the [protocol.Diagnostic].Data field.
34+
type diagnosticData struct {
35+
Notes string `json:"notes,omitempty"`
36+
Help string `json:"help,omitempty"`
37+
Debug string `json:"debug,omitempty"`
38+
}
39+
40+
// reportLevelToDiagnosticSeverity is a mapping of [report.Level] to [protocol.DiagnosticSeverity].
41+
var reportLevelToDiagnosticSeverity = map[report.Level]protocol.DiagnosticSeverity{
42+
report.ICE: protocol.DiagnosticSeverityError,
43+
report.Error: protocol.DiagnosticSeverityError,
44+
report.Warning: protocol.DiagnosticSeverityWarning,
45+
report.Remark: protocol.DiagnosticSeverityInformation,
46+
}
47+
48+
// reportDiagnosticToProtocolDiagnostic takes a [report.Diagnostic] and returns the
49+
// corresponding [protocol.Diagnostic].
50+
func reportDiagnosticToProtocolDiagnostic(
51+
reportDiagnostic report.Diagnostic,
52+
) (protocol.Diagnostic, error) {
53+
diagnostic := protocol.Diagnostic{
54+
Source: serverName,
55+
Severity: reportLevelToDiagnosticSeverity[reportDiagnostic.Level()],
56+
Message: reportDiagnostic.Message(),
57+
}
58+
if primary := reportDiagnostic.Primary(); !primary.IsZero() {
59+
startLocation := primary.Location(primary.Start, positionalEncoding)
60+
endLocation := primary.Location(primary.End, positionalEncoding)
61+
diagnostic.Range = protocol.Range{
62+
Start: protocol.Position{
63+
Line: uint32(startLocation.Line - 1),
64+
Character: uint32(startLocation.Column - 1),
65+
},
66+
End: protocol.Position{
67+
Line: uint32(endLocation.Line - 1),
68+
Character: uint32(endLocation.Column - 1),
69+
},
70+
}
71+
}
72+
data := diagnosticData{
73+
Notes: strings.Join(reportDiagnostic.Notes(), "\n"),
74+
Help: strings.Join(reportDiagnostic.Help(), "\n"),
75+
Debug: strings.Join(reportDiagnostic.Debug(), "\n"),
76+
}
77+
bytes, err := json.Marshal(data)
78+
if err != nil {
79+
return protocol.Diagnostic{}, err
80+
}
81+
if bytes != nil {
82+
// We serialize the bytes into a string before providing the structure to diagnostic.Data
83+
// because diagnostic.Data is an interface{}, which is treated as a JSON "any", which
84+
// will not cleanly deserialize.
85+
diagnostic.Data = string(bytes)
86+
}
87+
return diagnostic, nil
88+
}

0 commit comments

Comments
 (0)