internal/jsonrpc2: refactor to enable a more advanced request

This separates hides the wire structures, and then exposes a new Request
type to allow for it to carry advanced features.
It also embeds the connection into the request and changes the signature of the
handler to no longer require a separate Conn argument.

Change-Id: I20b54f146285f7a9cb5f279c6ebdf0f286f4b829
Reviewed-on: https://go-review.googlesource.com/c/tools/+/183717
Run-TryBot: Ian Cottrell <iancottrell@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
Ian Cottrell 2019-06-24 09:18:31 -04:00
parent a6ef77d3cb
commit 619de4ed67
6 changed files with 162 additions and 147 deletions

View File

@ -33,14 +33,27 @@ type Conn struct {
stream Stream stream Stream
err error err error
pendingMu sync.Mutex // protects the pending map pendingMu sync.Mutex // protects the pending map
pending map[ID]chan *Response pending map[ID]chan *wireResponse
handlingMu sync.Mutex // protects the handling map handlingMu sync.Mutex // protects the handling map
handling map[ID]handling handling map[ID]handling
} }
// Request is sent to a server to represent a Call or Notify operaton.
type Request struct {
conn *Conn
// Method is a string containing the method name to invoke.
Method string
// Params is either a struct or an array with the parameters of the method.
Params *json.RawMessage
// The id of this request, used to tie the response back to the request.
// Will be either a string or a number. If not set, the request is a notify,
// and no response is possible.
ID *ID
}
type queueEntry struct { type queueEntry struct {
ctx context.Context ctx context.Context
c *Conn
r *Request r *Request
size int64 size int64
} }
@ -50,16 +63,14 @@ type queueEntry struct {
// call Reply on the Conn with the supplied request. // call Reply on the Conn with the supplied request.
// Handlers are called synchronously, they should pass the work off to a go // Handlers are called synchronously, they should pass the work off to a go
// routine if they are going to take a long time. // routine if they are going to take a long time.
type Handler func(context.Context, *Conn, *Request) type Handler func(context.Context, *Request)
// Canceler is an option you can pass to NewConn which is invoked for // Canceler is an option you can pass to NewConn which is invoked for
// cancelled outgoing requests. // cancelled outgoing requests.
// The request will have the ID filled in, which can be used to propagate the
// cancel to the other process if needed.
// It is okay to use the connection to send notifications, but the context will // It is okay to use the connection to send notifications, but the context will
// be in the cancelled state, so you must do it with the background context // be in the cancelled state, so you must do it with the background context
// instead. // instead.
type Canceler func(context.Context, *Conn, *Request) type Canceler func(context.Context, *Conn, ID)
type rpcStats struct { type rpcStats struct {
server bool server bool
@ -133,17 +144,17 @@ func NewErrorf(code int64, format string, args ...interface{}) *Error {
func NewConn(s Stream) *Conn { func NewConn(s Stream) *Conn {
conn := &Conn{ conn := &Conn{
stream: s, stream: s,
pending: make(map[ID]chan *Response), pending: make(map[ID]chan *wireResponse),
handling: make(map[ID]handling), handling: make(map[ID]handling),
} }
// the default handler reports a method error // the default handler reports a method error
conn.Handler = func(ctx context.Context, c *Conn, r *Request) { conn.Handler = func(ctx context.Context, r *Request) {
if r.IsNotify() { if r.IsNotify() {
c.Reply(ctx, r, nil, NewErrorf(CodeMethodNotFound, "method %q not found", r.Method)) r.Reply(ctx, nil, NewErrorf(CodeMethodNotFound, "method %q not found", r.Method))
} }
} }
// the default canceller does nothing // the default canceler does nothing
conn.Canceler = func(context.Context, *Conn, *Request) {} conn.Canceler = func(context.Context, *Conn, ID) {}
// the default logger does nothing // the default logger does nothing
conn.Logger = func(Direction, *ID, time.Duration, string, *json.RawMessage, *Error) {} conn.Logger = func(Direction, *ID, time.Duration, string, *json.RawMessage, *Error) {}
return conn return conn
@ -174,7 +185,7 @@ func (c *Conn) Notify(ctx context.Context, method string, params interface{}) (e
if err != nil { if err != nil {
return fmt.Errorf("marshalling notify parameters: %v", err) return fmt.Errorf("marshalling notify parameters: %v", err)
} }
request := &Request{ request := &wireRequest{
Method: method, Method: method,
Params: jsonParams, Params: jsonParams,
} }
@ -200,7 +211,7 @@ func (c *Conn) Call(ctx context.Context, method string, params, result interface
if err != nil { if err != nil {
return fmt.Errorf("marshalling call parameters: %v", err) return fmt.Errorf("marshalling call parameters: %v", err)
} }
request := &Request{ request := &wireRequest{
ID: &id, ID: &id,
Method: method, Method: method,
Params: jsonParams, Params: jsonParams,
@ -212,7 +223,7 @@ func (c *Conn) Call(ctx context.Context, method string, params, result interface
} }
// we have to add ourselves to the pending map before we send, otherwise we // we have to add ourselves to the pending map before we send, otherwise we
// are racing the response // are racing the response
rchan := make(chan *Response) rchan := make(chan *wireResponse)
c.pendingMu.Lock() c.pendingMu.Lock()
c.pending[id] = rchan c.pending[id] = rchan
c.pendingMu.Unlock() c.pendingMu.Unlock()
@ -249,30 +260,38 @@ func (c *Conn) Call(ctx context.Context, method string, params, result interface
return nil return nil
case <-ctx.Done(): case <-ctx.Done():
// allow the handler to propagate the cancel // allow the handler to propagate the cancel
c.Canceler(ctx, c, request) c.Canceler(ctx, c, id)
return ctx.Err() return ctx.Err()
} }
} }
// Conn returns the connection that created this request.
func (r *Request) Conn() *Conn { return r.conn }
// IsNotify returns true if this request is a notification.
func (r *Request) IsNotify() bool {
return r.ID == nil
}
// Reply sends a reply to the given request. // Reply sends a reply to the given request.
// It is an error to call this if request was not a call. // It is an error to call this if request was not a call.
// You must call this exactly once for any given request. // You must call this exactly once for any given request.
// If err is set then result will be ignored. // If err is set then result will be ignored.
func (c *Conn) Reply(ctx context.Context, req *Request, result interface{}, err error) error { func (r *Request) Reply(ctx context.Context, result interface{}, err error) error {
ctx, st := trace.StartSpan(ctx, req.Method+":reply", trace.WithSpanKind(trace.SpanKindClient)) ctx, st := trace.StartSpan(ctx, r.Method+":reply", trace.WithSpanKind(trace.SpanKindClient))
defer st.End() defer st.End()
if req.IsNotify() { if r.IsNotify() {
return fmt.Errorf("reply not invoked with a valid call") return fmt.Errorf("reply not invoked with a valid call")
} }
c.handlingMu.Lock() r.conn.handlingMu.Lock()
handling, found := c.handling[*req.ID] handling, found := r.conn.handling[*r.ID]
if found { if found {
delete(c.handling, *req.ID) delete(r.conn.handling, *r.ID)
} }
c.handlingMu.Unlock() r.conn.handlingMu.Unlock()
if !found { if !found {
return fmt.Errorf("not a call in progress: %v", req.ID) return fmt.Errorf("not a call in progress: %v", r.ID)
} }
elapsed := time.Since(handling.start) elapsed := time.Since(handling.start)
@ -280,9 +299,9 @@ func (c *Conn) Reply(ctx context.Context, req *Request, result interface{}, err
if err == nil { if err == nil {
raw, err = marshalToRaw(result) raw, err = marshalToRaw(result)
} }
response := &Response{ response := &wireResponse{
Result: raw, Result: raw,
ID: req.ID, ID: r.ID,
} }
if err != nil { if err != nil {
if callErr, ok := err.(*Error); ok { if callErr, ok := err.(*Error); ok {
@ -295,8 +314,8 @@ func (c *Conn) Reply(ctx context.Context, req *Request, result interface{}, err
if err != nil { if err != nil {
return err return err
} }
c.Logger(Send, response.ID, elapsed, req.Method, response.Result, response.Error) r.conn.Logger(Send, response.ID, elapsed, r.Method, response.Result, response.Error)
n, err := c.stream.Write(ctx, data) n, err := r.conn.stream.Write(ctx, data)
v := ctx.Value(rpcStatsKey) v := ctx.Value(rpcStatsKey)
if v != nil { if v != nil {
@ -332,7 +351,7 @@ type combined struct {
} }
func (c *Conn) deliver(ctx context.Context, q chan queueEntry, request *Request, size int64) bool { func (c *Conn) deliver(ctx context.Context, q chan queueEntry, request *Request, size int64) bool {
e := queueEntry{ctx: ctx, c: c, r: request, size: size} e := queueEntry{ctx: ctx, r: request, size: size}
if !c.RejectIfOverloaded { if !c.RejectIfOverloaded {
q <- e q <- e
return true return true
@ -361,7 +380,7 @@ func (c *Conn) Run(ctx context.Context) error {
} }
ctx, rpcStats := start(ctx, true, e.r.Method, e.r.ID) ctx, rpcStats := start(ctx, true, e.r.Method, e.r.ID)
rpcStats.received += e.size rpcStats.received += e.size
c.Handler(ctx, e.c, e.r) c.Handler(ctx, e.r)
rpcStats.end(ctx, nil) rpcStats.end(ctx, nil)
} }
}() }()
@ -385,6 +404,7 @@ func (c *Conn) Run(ctx context.Context) error {
case msg.Method != "": case msg.Method != "":
// if method is set it must be a request // if method is set it must be a request
request := &Request{ request := &Request{
conn: c,
Method: msg.Method, Method: msg.Method,
Params: msg.Params, Params: msg.Params,
ID: msg.ID, ID: msg.ID,
@ -407,7 +427,7 @@ func (c *Conn) Run(ctx context.Context) error {
c.Logger(Receive, request.ID, -1, request.Method, request.Params, nil) c.Logger(Receive, request.ID, -1, request.Method, request.Params, nil)
if !c.deliver(reqCtx, q, request, n) { if !c.deliver(reqCtx, q, request, n) {
// queue is full, reject the message by directly replying // queue is full, reject the message by directly replying
c.Reply(ctx, request, nil, NewErrorf(CodeServerOverloaded, "no room in queue")) request.Reply(ctx, nil, NewErrorf(CodeServerOverloaded, "no room in queue"))
} }
} }
case msg.ID != nil: case msg.ID != nil:
@ -419,7 +439,7 @@ func (c *Conn) Run(ctx context.Context) error {
} }
c.pendingMu.Unlock() c.pendingMu.Unlock()
// and send the reply to the channel // and send the reply to the channel
response := &Response{ response := &wireResponse{
Result: msg.Result, Result: msg.Result,
Error: msg.Error, Error: msg.Error,
ID: msg.ID, ID: msg.ID,

View File

@ -122,36 +122,36 @@ func run(ctx context.Context, t *testing.T, withHeaders bool, r io.ReadCloser, w
return conn return conn
} }
func handle(ctx context.Context, c *jsonrpc2.Conn, r *jsonrpc2.Request) { func handle(ctx context.Context, r *jsonrpc2.Request) {
switch r.Method { switch r.Method {
case "no_args": case "no_args":
if r.Params != nil { if r.Params != nil {
c.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params")) r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
return return
} }
c.Reply(ctx, r, true, nil) r.Reply(ctx, true, nil)
case "one_string": case "one_string":
var v string var v string
if err := json.Unmarshal(*r.Params, &v); err != nil { if err := json.Unmarshal(*r.Params, &v); err != nil {
c.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err.Error())) r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err.Error()))
return return
} }
c.Reply(ctx, r, "got:"+v, nil) r.Reply(ctx, "got:"+v, nil)
case "one_number": case "one_number":
var v int var v int
if err := json.Unmarshal(*r.Params, &v); err != nil { if err := json.Unmarshal(*r.Params, &v); err != nil {
c.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err.Error())) r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err.Error()))
return return
} }
c.Reply(ctx, r, fmt.Sprintf("got:%d", v), nil) r.Reply(ctx, fmt.Sprintf("got:%d", v), nil)
case "join": case "join":
var v []string var v []string
if err := json.Unmarshal(*r.Params, &v); err != nil { if err := json.Unmarshal(*r.Params, &v); err != nil {
c.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err.Error())) r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err.Error()))
return return
} }
c.Reply(ctx, r, path.Join(v...), nil) r.Reply(ctx, path.Join(v...), nil)
default: default:
c.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not found", r.Method)) r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not found", r.Method))
} }
} }

View File

@ -34,8 +34,8 @@ const (
CodeServerOverloaded = -32000 CodeServerOverloaded = -32000
) )
// Request is sent to a server to represent a Call or Notify operaton. // wireRequest is sent to a server to represent a Call or Notify operaton.
type Request struct { type wireRequest struct {
// VersionTag is always encoded as the string "2.0" // VersionTag is always encoded as the string "2.0"
VersionTag VersionTag `json:"jsonrpc"` VersionTag VersionTag `json:"jsonrpc"`
// Method is a string containing the method name to invoke. // Method is a string containing the method name to invoke.
@ -48,11 +48,11 @@ type Request struct {
ID *ID `json:"id,omitempty"` ID *ID `json:"id,omitempty"`
} }
// Response is a reply to a Request. // wireResponse is a reply to a Request.
// It will always have the ID field set to tie it back to a request, and will // It will always have the ID field set to tie it back to a request, and will
// have either the Result or Error fields set depending on whether it is a // have either the Result or Error fields set depending on whether it is a
// success or failure response. // success or failure response.
type Response struct { type wireResponse struct {
// VersionTag is always encoded as the string "2.0" // VersionTag is always encoded as the string "2.0"
VersionTag VersionTag `json:"jsonrpc"` VersionTag VersionTag `json:"jsonrpc"`
// Result is the response value, and is required on success. // Result is the response value, and is required on success.
@ -87,11 +87,6 @@ type ID struct {
Number int64 Number int64
} }
// IsNotify returns true if this request is a notification.
func (r *Request) IsNotify() bool {
return r.ID == nil
}
func (err *Error) Error() string { func (err *Error) Error() string {
if err == nil { if err == nil {
return "" return ""

View File

@ -14,8 +14,8 @@ import (
const defaultMessageBufferSize = 20 const defaultMessageBufferSize = 20
const defaultRejectIfOverloaded = false const defaultRejectIfOverloaded = false
func canceller(ctx context.Context, conn *jsonrpc2.Conn, req *jsonrpc2.Request) { func canceller(ctx context.Context, conn *jsonrpc2.Conn, id jsonrpc2.ID) {
conn.Notify(context.Background(), "$/cancelRequest", &CancelParams{ID: *req.ID}) conn.Notify(context.Background(), "$/cancelRequest", &CancelParams{ID: id})
} }
func NewClient(stream jsonrpc2.Stream, client Client) (*jsonrpc2.Conn, Server, xlog.Logger) { func NewClient(stream jsonrpc2.Stream, client Client) (*jsonrpc2.Conn, Server, xlog.Logger) {
@ -39,11 +39,11 @@ func NewServer(stream jsonrpc2.Stream, server Server) (*jsonrpc2.Conn, Client, x
return conn, client, log return conn, client, log
} }
func sendParseError(ctx context.Context, log xlog.Logger, conn *jsonrpc2.Conn, req *jsonrpc2.Request, err error) { func sendParseError(ctx context.Context, log xlog.Logger, req *jsonrpc2.Request, err error) {
if _, ok := err.(*jsonrpc2.Error); !ok { if _, ok := err.(*jsonrpc2.Error); !ok {
err = jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) err = jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
} }
if err := conn.Reply(ctx, req, nil, err); err != nil { if err := req.Reply(ctx, nil, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
} }

View File

@ -24,19 +24,19 @@ type Client interface {
} }
func clientHandler(log xlog.Logger, client Client) jsonrpc2.Handler { func clientHandler(log xlog.Logger, client Client) jsonrpc2.Handler {
return func(ctx context.Context, conn *jsonrpc2.Conn, r *jsonrpc2.Request) { return func(ctx context.Context, r *jsonrpc2.Request) {
switch r.Method { switch r.Method {
case "$/cancelRequest": case "$/cancelRequest":
var params CancelParams var params CancelParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
conn.Cancel(params.ID) r.Conn().Cancel(params.ID)
case "window/showMessage": // notif case "window/showMessage": // notif
var params ShowMessageParams var params ShowMessageParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
if err := client.ShowMessage(ctx, &params); err != nil { if err := client.ShowMessage(ctx, &params); err != nil {
@ -45,7 +45,7 @@ func clientHandler(log xlog.Logger, client Client) jsonrpc2.Handler {
case "window/logMessage": // notif case "window/logMessage": // notif
var params LogMessageParams var params LogMessageParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
if err := client.LogMessage(ctx, &params); err != nil { if err := client.LogMessage(ctx, &params); err != nil {
@ -54,7 +54,7 @@ func clientHandler(log xlog.Logger, client Client) jsonrpc2.Handler {
case "telemetry/event": // notif case "telemetry/event": // notif
var params interface{} var params interface{}
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
if err := client.Event(ctx, &params); err != nil { if err := client.Event(ctx, &params); err != nil {
@ -63,7 +63,7 @@ func clientHandler(log xlog.Logger, client Client) jsonrpc2.Handler {
case "textDocument/publishDiagnostics": // notif case "textDocument/publishDiagnostics": // notif
var params PublishDiagnosticsParams var params PublishDiagnosticsParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
if err := client.PublishDiagnostics(ctx, &params); err != nil { if err := client.PublishDiagnostics(ctx, &params); err != nil {
@ -71,67 +71,67 @@ func clientHandler(log xlog.Logger, client Client) jsonrpc2.Handler {
} }
case "workspace/workspaceFolders": // req case "workspace/workspaceFolders": // req
if r.Params != nil { if r.Params != nil {
conn.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params")) r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
return return
} }
resp, err := client.WorkspaceFolders(ctx) resp, err := client.WorkspaceFolders(ctx)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "workspace/configuration": // req case "workspace/configuration": // req
var params ConfigurationParams var params ConfigurationParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := client.Configuration(ctx, &params) resp, err := client.Configuration(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "client/registerCapability": // req case "client/registerCapability": // req
var params RegistrationParams var params RegistrationParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
err := client.RegisterCapability(ctx, &params) err := client.RegisterCapability(ctx, &params)
if err := conn.Reply(ctx, r, nil, err); err != nil { if err := r.Reply(ctx, nil, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "client/unregisterCapability": // req case "client/unregisterCapability": // req
var params UnregistrationParams var params UnregistrationParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
err := client.UnregisterCapability(ctx, &params) err := client.UnregisterCapability(ctx, &params)
if err := conn.Reply(ctx, r, nil, err); err != nil { if err := r.Reply(ctx, nil, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "window/showMessageRequest": // req case "window/showMessageRequest": // req
var params ShowMessageRequestParams var params ShowMessageRequestParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := client.ShowMessageRequest(ctx, &params) resp, err := client.ShowMessageRequest(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "workspace/applyEdit": // req case "workspace/applyEdit": // req
var params ApplyWorkspaceEditParams var params ApplyWorkspaceEditParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := client.ApplyEdit(ctx, &params) resp, err := client.ApplyEdit(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
default: default:
if r.IsNotify() { if r.IsNotify() {
conn.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not found", r.Method)) r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not found", r.Method))
} }
} }
} }

View File

@ -55,19 +55,19 @@ type Server interface {
} }
func serverHandler(log xlog.Logger, server Server) jsonrpc2.Handler { func serverHandler(log xlog.Logger, server Server) jsonrpc2.Handler {
return func(ctx context.Context, conn *jsonrpc2.Conn, r *jsonrpc2.Request) { return func(ctx context.Context, r *jsonrpc2.Request) {
switch r.Method { switch r.Method {
case "$/cancelRequest": case "$/cancelRequest":
var params CancelParams var params CancelParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
conn.Cancel(params.ID) r.Conn().Cancel(params.ID)
case "workspace/didChangeWorkspaceFolders": // notif case "workspace/didChangeWorkspaceFolders": // notif
var params DidChangeWorkspaceFoldersParams var params DidChangeWorkspaceFoldersParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
if err := server.DidChangeWorkspaceFolders(ctx, &params); err != nil { if err := server.DidChangeWorkspaceFolders(ctx, &params); err != nil {
@ -76,7 +76,7 @@ func serverHandler(log xlog.Logger, server Server) jsonrpc2.Handler {
case "initialized": // notif case "initialized": // notif
var params InitializedParams var params InitializedParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
if err := server.Initialized(ctx, &params); err != nil { if err := server.Initialized(ctx, &params); err != nil {
@ -89,7 +89,7 @@ func serverHandler(log xlog.Logger, server Server) jsonrpc2.Handler {
case "workspace/didChangeConfiguration": // notif case "workspace/didChangeConfiguration": // notif
var params DidChangeConfigurationParams var params DidChangeConfigurationParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
if err := server.DidChangeConfiguration(ctx, &params); err != nil { if err := server.DidChangeConfiguration(ctx, &params); err != nil {
@ -98,7 +98,7 @@ func serverHandler(log xlog.Logger, server Server) jsonrpc2.Handler {
case "textDocument/didOpen": // notif case "textDocument/didOpen": // notif
var params DidOpenTextDocumentParams var params DidOpenTextDocumentParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
if err := server.DidOpen(ctx, &params); err != nil { if err := server.DidOpen(ctx, &params); err != nil {
@ -107,7 +107,7 @@ func serverHandler(log xlog.Logger, server Server) jsonrpc2.Handler {
case "textDocument/didChange": // notif case "textDocument/didChange": // notif
var params DidChangeTextDocumentParams var params DidChangeTextDocumentParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
if err := server.DidChange(ctx, &params); err != nil { if err := server.DidChange(ctx, &params); err != nil {
@ -116,7 +116,7 @@ func serverHandler(log xlog.Logger, server Server) jsonrpc2.Handler {
case "textDocument/didClose": // notif case "textDocument/didClose": // notif
var params DidCloseTextDocumentParams var params DidCloseTextDocumentParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
if err := server.DidClose(ctx, &params); err != nil { if err := server.DidClose(ctx, &params); err != nil {
@ -125,7 +125,7 @@ func serverHandler(log xlog.Logger, server Server) jsonrpc2.Handler {
case "textDocument/didSave": // notif case "textDocument/didSave": // notif
var params DidSaveTextDocumentParams var params DidSaveTextDocumentParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
if err := server.DidSave(ctx, &params); err != nil { if err := server.DidSave(ctx, &params); err != nil {
@ -134,7 +134,7 @@ func serverHandler(log xlog.Logger, server Server) jsonrpc2.Handler {
case "textDocument/willSave": // notif case "textDocument/willSave": // notif
var params WillSaveTextDocumentParams var params WillSaveTextDocumentParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
if err := server.WillSave(ctx, &params); err != nil { if err := server.WillSave(ctx, &params); err != nil {
@ -143,7 +143,7 @@ func serverHandler(log xlog.Logger, server Server) jsonrpc2.Handler {
case "workspace/didChangeWatchedFiles": // notif case "workspace/didChangeWatchedFiles": // notif
var params DidChangeWatchedFilesParams var params DidChangeWatchedFilesParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
if err := server.DidChangeWatchedFiles(ctx, &params); err != nil { if err := server.DidChangeWatchedFiles(ctx, &params); err != nil {
@ -152,7 +152,7 @@ func serverHandler(log xlog.Logger, server Server) jsonrpc2.Handler {
case "$/setTraceNotification": // notif case "$/setTraceNotification": // notif
var params SetTraceParams var params SetTraceParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
if err := server.SetTraceNotification(ctx, &params); err != nil { if err := server.SetTraceNotification(ctx, &params); err != nil {
@ -161,7 +161,7 @@ func serverHandler(log xlog.Logger, server Server) jsonrpc2.Handler {
case "$/logTraceNotification": // notif case "$/logTraceNotification": // notif
var params LogTraceParams var params LogTraceParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
if err := server.LogTraceNotification(ctx, &params); err != nil { if err := server.LogTraceNotification(ctx, &params); err != nil {
@ -170,296 +170,296 @@ func serverHandler(log xlog.Logger, server Server) jsonrpc2.Handler {
case "textDocument/implementation": // req case "textDocument/implementation": // req
var params TextDocumentPositionParams var params TextDocumentPositionParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.Implementation(ctx, &params) resp, err := server.Implementation(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "textDocument/typeDefinition": // req case "textDocument/typeDefinition": // req
var params TextDocumentPositionParams var params TextDocumentPositionParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.TypeDefinition(ctx, &params) resp, err := server.TypeDefinition(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "textDocument/documentColor": // req case "textDocument/documentColor": // req
var params DocumentColorParams var params DocumentColorParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.DocumentColor(ctx, &params) resp, err := server.DocumentColor(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "textDocument/colorPresentation": // req case "textDocument/colorPresentation": // req
var params ColorPresentationParams var params ColorPresentationParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.ColorPresentation(ctx, &params) resp, err := server.ColorPresentation(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "textDocument/foldingRange": // req case "textDocument/foldingRange": // req
var params FoldingRangeParams var params FoldingRangeParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.FoldingRange(ctx, &params) resp, err := server.FoldingRange(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "textDocument/declaration": // req case "textDocument/declaration": // req
var params TextDocumentPositionParams var params TextDocumentPositionParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.Declaration(ctx, &params) resp, err := server.Declaration(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "initialize": // req case "initialize": // req
var params InitializeParams var params InitializeParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.Initialize(ctx, &params) resp, err := server.Initialize(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "shutdown": // req case "shutdown": // req
if r.Params != nil { if r.Params != nil {
conn.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params")) r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
return return
} }
err := server.Shutdown(ctx) err := server.Shutdown(ctx)
if err := conn.Reply(ctx, r, nil, err); err != nil { if err := r.Reply(ctx, nil, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "textDocument/willSaveWaitUntil": // req case "textDocument/willSaveWaitUntil": // req
var params WillSaveTextDocumentParams var params WillSaveTextDocumentParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.WillSaveWaitUntil(ctx, &params) resp, err := server.WillSaveWaitUntil(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "textDocument/completion": // req case "textDocument/completion": // req
var params CompletionParams var params CompletionParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.Completion(ctx, &params) resp, err := server.Completion(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "completionItem/resolve": // req case "completionItem/resolve": // req
var params CompletionItem var params CompletionItem
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.Resolve(ctx, &params) resp, err := server.Resolve(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "textDocument/hover": // req case "textDocument/hover": // req
var params TextDocumentPositionParams var params TextDocumentPositionParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.Hover(ctx, &params) resp, err := server.Hover(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "textDocument/signatureHelp": // req case "textDocument/signatureHelp": // req
var params TextDocumentPositionParams var params TextDocumentPositionParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.SignatureHelp(ctx, &params) resp, err := server.SignatureHelp(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "textDocument/definition": // req case "textDocument/definition": // req
var params TextDocumentPositionParams var params TextDocumentPositionParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.Definition(ctx, &params) resp, err := server.Definition(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "textDocument/references": // req case "textDocument/references": // req
var params ReferenceParams var params ReferenceParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.References(ctx, &params) resp, err := server.References(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "textDocument/documentHighlight": // req case "textDocument/documentHighlight": // req
var params TextDocumentPositionParams var params TextDocumentPositionParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.DocumentHighlight(ctx, &params) resp, err := server.DocumentHighlight(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "textDocument/documentSymbol": // req case "textDocument/documentSymbol": // req
var params DocumentSymbolParams var params DocumentSymbolParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.DocumentSymbol(ctx, &params) resp, err := server.DocumentSymbol(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "workspace/symbol": // req case "workspace/symbol": // req
var params WorkspaceSymbolParams var params WorkspaceSymbolParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.Symbol(ctx, &params) resp, err := server.Symbol(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "textDocument/codeAction": // req case "textDocument/codeAction": // req
var params CodeActionParams var params CodeActionParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.CodeAction(ctx, &params) resp, err := server.CodeAction(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "textDocument/codeLens": // req case "textDocument/codeLens": // req
var params CodeLensParams var params CodeLensParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.CodeLens(ctx, &params) resp, err := server.CodeLens(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "codeLens/resolve": // req case "codeLens/resolve": // req
var params CodeLens var params CodeLens
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.ResolveCodeLens(ctx, &params) resp, err := server.ResolveCodeLens(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "textDocument/formatting": // req case "textDocument/formatting": // req
var params DocumentFormattingParams var params DocumentFormattingParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.Formatting(ctx, &params) resp, err := server.Formatting(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "textDocument/rangeFormatting": // req case "textDocument/rangeFormatting": // req
var params DocumentRangeFormattingParams var params DocumentRangeFormattingParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.RangeFormatting(ctx, &params) resp, err := server.RangeFormatting(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "textDocument/onTypeFormatting": // req case "textDocument/onTypeFormatting": // req
var params DocumentOnTypeFormattingParams var params DocumentOnTypeFormattingParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.OnTypeFormatting(ctx, &params) resp, err := server.OnTypeFormatting(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "textDocument/rename": // req case "textDocument/rename": // req
var params RenameParams var params RenameParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.Rename(ctx, &params) resp, err := server.Rename(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "textDocument/prepareRename": // req case "textDocument/prepareRename": // req
var params TextDocumentPositionParams var params TextDocumentPositionParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.PrepareRename(ctx, &params) resp, err := server.PrepareRename(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "textDocument/documentLink": // req case "textDocument/documentLink": // req
var params DocumentLinkParams var params DocumentLinkParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.DocumentLink(ctx, &params) resp, err := server.DocumentLink(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "documentLink/resolve": // req case "documentLink/resolve": // req
var params DocumentLink var params DocumentLink
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.ResolveDocumentLink(ctx, &params) resp, err := server.ResolveDocumentLink(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
case "workspace/executeCommand": // req case "workspace/executeCommand": // req
var params ExecuteCommandParams var params ExecuteCommandParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
resp, err := server.ExecuteCommand(ctx, &params) resp, err := server.ExecuteCommand(ctx, &params)
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
} }
default: default:
if r.IsNotify() { if r.IsNotify() {
conn.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not found", r.Method)) r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not found", r.Method))
} }
} }
} }