internal/jsonrpc2: cleanup the jsonrpc2 callbacks
We merge them into a single interface and support multiple of them rather than just one. This will allow us to stack handlers with different responsabilities and extract some core logic (like tracing) out to a handler where it belongs. Change-Id: I6aab92138550c5062fcb1bed86171e0850d1eb38 Reviewed-on: https://go-review.googlesource.com/c/tools/+/185879 Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
f4b4e63240
commit
b32ec66a23
|
@ -0,0 +1,89 @@
|
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package jsonrpc2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Handler is the interface used to hook into the mesage handling of an rpc
|
||||
// connection.
|
||||
type Handler interface {
|
||||
// Deliver is invoked to handle incoming requests.
|
||||
// If the request returns false from IsNotify then the Handler must eventually
|
||||
// call Reply on the Conn with the supplied request.
|
||||
// Handlers are called synchronously, they should pass the work off to a go
|
||||
// routine if they are going to take a long time.
|
||||
// If Deliver returns true all subsequent handlers will be invoked with
|
||||
// delivered set to true, and should not attempt to deliver the message.
|
||||
Deliver(ctx context.Context, r *Request, delivered bool) bool
|
||||
|
||||
// Cancel is invoked for cancelled outgoing requests.
|
||||
// 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
|
||||
// instead.
|
||||
// If Cancel returns true all subsequent handlers will be invoked with
|
||||
// cancelled set to true, and should not attempt to cancel the message.
|
||||
Cancel(ctx context.Context, conn *Conn, id ID, cancelled bool) bool
|
||||
|
||||
// Log is invoked for all messages flowing through a Conn.
|
||||
// direction indicates if the message being received or sent
|
||||
// id is the message id, if not set it was a notification
|
||||
// elapsed is the time between a call being seen and the response, and is
|
||||
// negative for anything that is not a response.
|
||||
// method is the method name specified in the message
|
||||
// payload is the parameters for a call or notification, and the result for a
|
||||
// response
|
||||
Log(direction Direction, id *ID, elapsed time.Duration, method string, payload *json.RawMessage, err *Error)
|
||||
}
|
||||
|
||||
// Direction is used to indicate to a logger whether the logged message was being
|
||||
// sent or received.
|
||||
type Direction bool
|
||||
|
||||
const (
|
||||
// Send indicates the message is outgoing.
|
||||
Send = Direction(true)
|
||||
// Receive indicates the message is incoming.
|
||||
Receive = Direction(false)
|
||||
)
|
||||
|
||||
func (d Direction) String() string {
|
||||
switch d {
|
||||
case Send:
|
||||
return "send"
|
||||
case Receive:
|
||||
return "receive"
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
|
||||
type EmptyHandler struct{}
|
||||
|
||||
func (EmptyHandler) Deliver(ctx context.Context, r *Request, delivered bool) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (EmptyHandler) Cancel(ctx context.Context, conn *Conn, id ID, cancelled bool) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (EmptyHandler) Log(direction Direction, id *ID, elapsed time.Duration, method string, payload *json.RawMessage, err *Error) {
|
||||
}
|
||||
|
||||
type defaultHandler struct{ EmptyHandler }
|
||||
|
||||
func (defaultHandler) Deliver(ctx context.Context, r *Request, delivered bool) bool {
|
||||
if delivered {
|
||||
return false
|
||||
}
|
||||
if !r.IsNotify() {
|
||||
r.Reply(ctx, nil, NewErrorf(CodeMethodNotFound, "method %q not found", r.Method))
|
||||
}
|
||||
return true
|
||||
}
|
|
@ -23,18 +23,14 @@ import (
|
|||
// Conn is a JSON RPC 2 client server connection.
|
||||
// Conn is bidirectional; it does not have a designated server or client end.
|
||||
type Conn struct {
|
||||
seq int64 // must only be accessed using atomic operations
|
||||
Handler Handler
|
||||
Canceler Canceler
|
||||
Logger Logger
|
||||
Capacity int
|
||||
RejectIfOverloaded bool
|
||||
stream Stream
|
||||
err error
|
||||
pendingMu sync.Mutex // protects the pending map
|
||||
pending map[ID]chan *wireResponse
|
||||
handlingMu sync.Mutex // protects the handling map
|
||||
handling map[ID]*Request
|
||||
seq int64 // must only be accessed using atomic operations
|
||||
handlers []Handler
|
||||
stream Stream
|
||||
err error
|
||||
pendingMu sync.Mutex // protects the pending map
|
||||
pending map[ID]chan *wireResponse
|
||||
handlingMu sync.Mutex // protects the handling map
|
||||
handling map[ID]*Request
|
||||
}
|
||||
|
||||
type requestState int
|
||||
|
@ -65,20 +61,6 @@ type Request struct {
|
|||
ID *ID
|
||||
}
|
||||
|
||||
// Handler is an option you can pass to NewConn to handle incoming requests.
|
||||
// If the request returns false from IsNotify then the Handler must eventually
|
||||
// call Reply on the Conn with the supplied request.
|
||||
// Handlers are called synchronously, they should pass the work off to a go
|
||||
// routine if they are going to take a long time.
|
||||
type Handler func(context.Context, *Request)
|
||||
|
||||
// Canceler is an option you can pass to NewConn which is invoked for
|
||||
// cancelled outgoing requests.
|
||||
// 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
|
||||
// instead.
|
||||
type Canceler func(context.Context, *Conn, ID)
|
||||
|
||||
type rpcStats struct {
|
||||
server bool
|
||||
method string
|
||||
|
@ -133,23 +115,23 @@ func NewErrorf(code int64, format string, args ...interface{}) *Error {
|
|||
// You must call Run for the connection to be active.
|
||||
func NewConn(s Stream) *Conn {
|
||||
conn := &Conn{
|
||||
handlers: []Handler{defaultHandler{}},
|
||||
stream: s,
|
||||
pending: make(map[ID]chan *wireResponse),
|
||||
handling: make(map[ID]*Request),
|
||||
}
|
||||
// the default handler reports a method error
|
||||
conn.Handler = func(ctx context.Context, r *Request) {
|
||||
if !r.IsNotify() {
|
||||
r.Reply(ctx, nil, NewErrorf(CodeMethodNotFound, "method %q not found", r.Method))
|
||||
}
|
||||
}
|
||||
// the default canceler does nothing
|
||||
conn.Canceler = func(context.Context, *Conn, ID) {}
|
||||
// the default logger does nothing
|
||||
conn.Logger = func(Direction, *ID, time.Duration, string, *json.RawMessage, *Error) {}
|
||||
return conn
|
||||
}
|
||||
|
||||
// AddHandler adds a new handler to the set the connection will invoke.
|
||||
// Handlers are invoked in the reverse order of how they were added, this
|
||||
// allows the most recent addition to be the first one to attempt to handle a
|
||||
// message.
|
||||
func (c *Conn) AddHandler(handler Handler) {
|
||||
// prepend the new handlers so we use them first
|
||||
c.handlers = append([]Handler{handler}, c.handlers...)
|
||||
}
|
||||
|
||||
// Cancel cancels a pending Call on the server side.
|
||||
// The call is identified by its id.
|
||||
// JSON RPC 2 does not specify a cancel message, so cancellation support is not
|
||||
|
@ -183,7 +165,9 @@ func (c *Conn) Notify(ctx context.Context, method string, params interface{}) (e
|
|||
if err != nil {
|
||||
return fmt.Errorf("marshalling notify request: %v", err)
|
||||
}
|
||||
c.Logger(Send, nil, -1, request.Method, request.Params, nil)
|
||||
for _, h := range c.handlers {
|
||||
h.Log(Send, nil, -1, request.Method, request.Params, nil)
|
||||
}
|
||||
n, err := c.stream.Write(ctx, data)
|
||||
telemetry.SentBytes.Record(ctx, n)
|
||||
return err
|
||||
|
@ -225,7 +209,9 @@ func (c *Conn) Call(ctx context.Context, method string, params, result interface
|
|||
}()
|
||||
// now we are ready to send
|
||||
before := time.Now()
|
||||
c.Logger(Send, request.ID, -1, request.Method, request.Params, nil)
|
||||
for _, h := range c.handlers {
|
||||
h.Log(Send, request.ID, -1, request.Method, request.Params, nil)
|
||||
}
|
||||
n, err := c.stream.Write(ctx, data)
|
||||
telemetry.SentBytes.Record(ctx, n)
|
||||
if err != nil {
|
||||
|
@ -236,7 +222,9 @@ func (c *Conn) Call(ctx context.Context, method string, params, result interface
|
|||
select {
|
||||
case response := <-rchan:
|
||||
elapsed := time.Since(before)
|
||||
c.Logger(Receive, response.ID, elapsed, request.Method, response.Result, response.Error)
|
||||
for _, h := range c.handlers {
|
||||
h.Log(Receive, response.ID, elapsed, request.Method, response.Result, response.Error)
|
||||
}
|
||||
// is it an error response?
|
||||
if response.Error != nil {
|
||||
return response.Error
|
||||
|
@ -250,7 +238,12 @@ func (c *Conn) Call(ctx context.Context, method string, params, result interface
|
|||
return nil
|
||||
case <-ctx.Done():
|
||||
// allow the handler to propagate the cancel
|
||||
c.Canceler(ctx, c, id)
|
||||
cancelled := false
|
||||
for _, h := range c.handlers {
|
||||
if h.Cancel(ctx, c, id, cancelled) {
|
||||
cancelled = true
|
||||
}
|
||||
}
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
|
@ -320,7 +313,9 @@ func (r *Request) Reply(ctx context.Context, result interface{}, err error) erro
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.conn.Logger(Send, response.ID, elapsed, r.Method, response.Result, response.Error)
|
||||
for _, h := range r.conn.handlers {
|
||||
h.Log(Send, response.ID, elapsed, r.Method, response.Result, response.Error)
|
||||
}
|
||||
n, err := r.conn.stream.Write(ctx, data)
|
||||
telemetry.SentBytes.Record(ctx, n)
|
||||
|
||||
|
@ -378,7 +373,9 @@ func (c *Conn) Run(ctx context.Context) error {
|
|||
if err := json.Unmarshal(data, msg); err != nil {
|
||||
// a badly formed message arrived, log it and continue
|
||||
// we trust the stream to have isolated the error to just this message
|
||||
c.Logger(Receive, nil, -1, "", nil, NewErrorf(0, "unmarshal failed: %v", err))
|
||||
for _, h := range c.handlers {
|
||||
h.Log(Receive, nil, -1, "", nil, NewErrorf(0, "unmarshal failed: %v", err))
|
||||
}
|
||||
continue
|
||||
}
|
||||
// work out which kind of message we have
|
||||
|
@ -412,8 +409,13 @@ func (c *Conn) Run(ctx context.Context) error {
|
|||
rpcStats.end(reqCtx, nil)
|
||||
cancelReq()
|
||||
}()
|
||||
c.Logger(Receive, req.ID, -1, req.Method, req.Params, nil)
|
||||
c.Handler(reqCtx, req)
|
||||
delivered := false
|
||||
for _, h := range c.handlers {
|
||||
h.Log(Receive, req.ID, -1, req.Method, req.Params, nil)
|
||||
if h.Deliver(reqCtx, req, delivered) {
|
||||
delivered = true
|
||||
}
|
||||
}
|
||||
}()
|
||||
case msg.ID != nil:
|
||||
// we have a response, get the pending entry from the map
|
||||
|
@ -432,7 +434,9 @@ func (c *Conn) Run(ctx context.Context) error {
|
|||
rchan <- response
|
||||
close(rchan)
|
||||
default:
|
||||
c.Logger(Receive, nil, -1, "", nil, NewErrorf(0, "message not a call, notify or response, ignoring"))
|
||||
for _, h := range c.handlers {
|
||||
h.Log(Receive, nil, -1, "", nil, NewErrorf(0, "message not a call, notify or response, ignoring"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,11 @@ import (
|
|||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"path"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/tools/internal/jsonrpc2"
|
||||
)
|
||||
|
@ -106,10 +108,7 @@ func run(ctx context.Context, t *testing.T, withHeaders bool, r io.ReadCloser, w
|
|||
stream = jsonrpc2.NewStream(r, w)
|
||||
}
|
||||
conn := jsonrpc2.NewConn(stream)
|
||||
conn.Handler = handle
|
||||
if *logRPC {
|
||||
conn.Logger = jsonrpc2.Log
|
||||
}
|
||||
conn.AddHandler(handle{})
|
||||
go func() {
|
||||
defer func() {
|
||||
r.Close()
|
||||
|
@ -122,36 +121,55 @@ func run(ctx context.Context, t *testing.T, withHeaders bool, r io.ReadCloser, w
|
|||
return conn
|
||||
}
|
||||
|
||||
func handle(ctx context.Context, r *jsonrpc2.Request) {
|
||||
type handle struct{ jsonrpc2.EmptyHandler }
|
||||
|
||||
func (handle) Deliver(ctx context.Context, r *jsonrpc2.Request, delivered bool) bool {
|
||||
switch r.Method {
|
||||
case "no_args":
|
||||
if r.Params != nil {
|
||||
r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
|
||||
return
|
||||
return true
|
||||
}
|
||||
r.Reply(ctx, true, nil)
|
||||
case "one_string":
|
||||
var v string
|
||||
if err := json.Unmarshal(*r.Params, &v); err != nil {
|
||||
r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err.Error()))
|
||||
return
|
||||
return true
|
||||
}
|
||||
r.Reply(ctx, "got:"+v, nil)
|
||||
case "one_number":
|
||||
var v int
|
||||
if err := json.Unmarshal(*r.Params, &v); err != nil {
|
||||
r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err.Error()))
|
||||
return
|
||||
return true
|
||||
}
|
||||
r.Reply(ctx, fmt.Sprintf("got:%d", v), nil)
|
||||
case "join":
|
||||
var v []string
|
||||
if err := json.Unmarshal(*r.Params, &v); err != nil {
|
||||
r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err.Error()))
|
||||
return
|
||||
return true
|
||||
}
|
||||
r.Reply(ctx, path.Join(v...), nil)
|
||||
default:
|
||||
r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not found", r.Method))
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (handle) Log(direction jsonrpc2.Direction, id *jsonrpc2.ID, elapsed time.Duration, method string, payload *json.RawMessage, err *jsonrpc2.Error) {
|
||||
if !*logRPC {
|
||||
return
|
||||
}
|
||||
switch {
|
||||
case err != nil:
|
||||
log.Printf("%v failure [%v] %s %v", direction, id, method, err)
|
||||
case id == nil:
|
||||
log.Printf("%v notification %s %s", direction, method, *payload)
|
||||
case elapsed >= 0:
|
||||
log.Printf("%v response in %v [%v] %s %s", direction, elapsed, id, method, *payload)
|
||||
default:
|
||||
log.Printf("%v call [%v] %s %s", direction, id, method, *payload)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package jsonrpc2
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Logger is an option you can pass to NewConn which is invoked for
|
||||
// all messages flowing through a Conn.
|
||||
// direction indicates if the message being recieved or sent
|
||||
// id is the message id, if not set it was a notification
|
||||
// elapsed is the time between a call being seen and the response, and is
|
||||
// negative for anything that is not a response.
|
||||
// method is the method name specified in the message
|
||||
// payload is the parameters for a call or notification, and the result for a
|
||||
// response
|
||||
type Logger = func(direction Direction, id *ID, elapsed time.Duration, method string, payload *json.RawMessage, err *Error)
|
||||
|
||||
// Direction is used to indicate to a logger whether the logged message was being
|
||||
// sent or received.
|
||||
type Direction bool
|
||||
|
||||
const (
|
||||
// Send indicates the message is outgoing.
|
||||
Send = Direction(true)
|
||||
// Receive indicates the message is incoming.
|
||||
Receive = Direction(false)
|
||||
)
|
||||
|
||||
func (d Direction) String() string {
|
||||
switch d {
|
||||
case Send:
|
||||
return "send"
|
||||
case Receive:
|
||||
return "receive"
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
|
||||
// Log is an implementation of Logger that outputs using log.Print
|
||||
// It is not used by default, but is provided for easy logging in users code.
|
||||
func Log(direction Direction, id *ID, elapsed time.Duration, method string, payload *json.RawMessage, err *Error) {
|
||||
switch {
|
||||
case err != nil:
|
||||
log.Printf("%v failure [%v] %s %v", direction, id, method, err)
|
||||
case id == nil:
|
||||
log.Printf("%v notification %s %s", direction, method, *payload)
|
||||
case elapsed >= 0:
|
||||
log.Printf("%v response in %v [%v] %s %s", direction, elapsed, id, method, *payload)
|
||||
default:
|
||||
log.Printf("%v call [%v] %s %s", direction, id, method, *payload)
|
||||
}
|
||||
}
|
|
@ -80,7 +80,7 @@ func (s *Serve) Run(ctx context.Context, args ...string) error {
|
|||
|
||||
// For debugging purposes only.
|
||||
run := func(srv *lsp.Server) {
|
||||
srv.Conn.Logger = logger(s.Trace, out)
|
||||
srv.Conn.AddHandler(&handler{trace: s.Trace, out: out})
|
||||
go srv.Run(ctx)
|
||||
}
|
||||
if s.Address != "" {
|
||||
|
@ -91,7 +91,7 @@ func (s *Serve) Run(ctx context.Context, args ...string) error {
|
|||
}
|
||||
stream := jsonrpc2.NewHeaderStream(os.Stdin, os.Stdout)
|
||||
srv := lsp.NewServer(s.app.cache, stream)
|
||||
srv.Conn.Logger = logger(s.Trace, out)
|
||||
srv.Conn.AddHandler(&handler{trace: s.Trace, out: out})
|
||||
return srv.Run(ctx)
|
||||
}
|
||||
|
||||
|
@ -115,55 +115,66 @@ func (s *Serve) forward() error {
|
|||
return <-errc
|
||||
}
|
||||
|
||||
func logger(trace bool, out io.Writer) jsonrpc2.Logger {
|
||||
return func(direction jsonrpc2.Direction, id *jsonrpc2.ID, elapsed time.Duration, method string, payload *json.RawMessage, err *jsonrpc2.Error) {
|
||||
if !trace {
|
||||
return
|
||||
}
|
||||
const eol = "\r\n\r\n\r\n"
|
||||
if err != nil {
|
||||
fmt.Fprintf(out, "[Error - %v] %s %s%s %v%s", time.Now().Format("3:04:05 PM"),
|
||||
direction, method, id, err, eol)
|
||||
return
|
||||
}
|
||||
outx := new(strings.Builder)
|
||||
fmt.Fprintf(outx, "[Trace - %v] ", time.Now().Format("3:04:05 PM"))
|
||||
switch direction {
|
||||
case jsonrpc2.Send:
|
||||
fmt.Fprint(outx, "Received ")
|
||||
case jsonrpc2.Receive:
|
||||
fmt.Fprint(outx, "Sending ")
|
||||
}
|
||||
switch {
|
||||
case id == nil:
|
||||
fmt.Fprint(outx, "notification ")
|
||||
case elapsed >= 0:
|
||||
fmt.Fprint(outx, "response ")
|
||||
default:
|
||||
fmt.Fprint(outx, "request ")
|
||||
}
|
||||
fmt.Fprintf(outx, "'%s", method)
|
||||
switch {
|
||||
case id == nil:
|
||||
// do nothing
|
||||
case id.Name != "":
|
||||
fmt.Fprintf(outx, " - (%s)", id.Name)
|
||||
default:
|
||||
fmt.Fprintf(outx, " - (%d)", id.Number)
|
||||
}
|
||||
fmt.Fprint(outx, "'")
|
||||
if elapsed >= 0 {
|
||||
msec := int(elapsed.Round(time.Millisecond) / time.Millisecond)
|
||||
fmt.Fprintf(outx, " in %dms", msec)
|
||||
}
|
||||
params := "null"
|
||||
if payload != nil {
|
||||
params = string(*payload)
|
||||
}
|
||||
if params == "null" {
|
||||
params = "{}"
|
||||
}
|
||||
fmt.Fprintf(outx, ".\r\nParams: %s%s", params, eol)
|
||||
fmt.Fprintf(out, "%s", outx.String())
|
||||
}
|
||||
type handler struct {
|
||||
trace bool
|
||||
out io.Writer
|
||||
}
|
||||
|
||||
func (h *handler) Deliver(ctx context.Context, r *jsonrpc2.Request, delivered bool) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (h *handler) Cancel(ctx context.Context, conn *jsonrpc2.Conn, id jsonrpc2.ID, cancelled bool) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (h *handler) Log(direction jsonrpc2.Direction, id *jsonrpc2.ID, elapsed time.Duration, method string, payload *json.RawMessage, err *jsonrpc2.Error) {
|
||||
if !h.trace {
|
||||
return
|
||||
}
|
||||
const eol = "\r\n\r\n\r\n"
|
||||
if err != nil {
|
||||
fmt.Fprintf(h.out, "[Error - %v] %s %s%s %v%s", time.Now().Format("3:04:05 PM"),
|
||||
direction, method, id, err, eol)
|
||||
return
|
||||
}
|
||||
outx := new(strings.Builder)
|
||||
fmt.Fprintf(outx, "[Trace - %v] ", time.Now().Format("3:04:05 PM"))
|
||||
switch direction {
|
||||
case jsonrpc2.Send:
|
||||
fmt.Fprint(outx, "Received ")
|
||||
case jsonrpc2.Receive:
|
||||
fmt.Fprint(outx, "Sending ")
|
||||
}
|
||||
switch {
|
||||
case id == nil:
|
||||
fmt.Fprint(outx, "notification ")
|
||||
case elapsed >= 0:
|
||||
fmt.Fprint(outx, "response ")
|
||||
default:
|
||||
fmt.Fprint(outx, "request ")
|
||||
}
|
||||
fmt.Fprintf(outx, "'%s", method)
|
||||
switch {
|
||||
case id == nil:
|
||||
// do nothing
|
||||
case id.Name != "":
|
||||
fmt.Fprintf(outx, " - (%s)", id.Name)
|
||||
default:
|
||||
fmt.Fprintf(outx, " - (%d)", id.Number)
|
||||
}
|
||||
fmt.Fprint(outx, "'")
|
||||
if elapsed >= 0 {
|
||||
msec := int(elapsed.Round(time.Millisecond) / time.Millisecond)
|
||||
fmt.Fprintf(outx, " in %dms", msec)
|
||||
}
|
||||
params := "null"
|
||||
if payload != nil {
|
||||
params = string(*payload)
|
||||
}
|
||||
if params == "null" {
|
||||
params = "{}"
|
||||
}
|
||||
fmt.Fprintf(outx, ".\r\nParams: %s%s", params, eol)
|
||||
fmt.Fprintf(h.out, "%s", outx.String())
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ package protocol
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"golang.org/x/tools/internal/jsonrpc2"
|
||||
"golang.org/x/tools/internal/lsp/telemetry/trace"
|
||||
|
@ -15,23 +17,38 @@ import (
|
|||
|
||||
type DocumentUri = string
|
||||
|
||||
const defaultMessageBufferSize = 20
|
||||
const defaultRejectIfOverloaded = false
|
||||
type canceller struct{}
|
||||
|
||||
func canceller(ctx context.Context, conn *jsonrpc2.Conn, id jsonrpc2.ID) {
|
||||
type clientHandler struct {
|
||||
canceller
|
||||
log xlog.Logger
|
||||
client Client
|
||||
}
|
||||
|
||||
type serverHandler struct {
|
||||
canceller
|
||||
log xlog.Logger
|
||||
server Server
|
||||
}
|
||||
|
||||
func (canceller) Cancel(ctx context.Context, conn *jsonrpc2.Conn, id jsonrpc2.ID, cancelled bool) bool {
|
||||
if cancelled {
|
||||
return false
|
||||
}
|
||||
ctx = xcontext.Detach(ctx)
|
||||
ctx, done := trace.StartSpan(ctx, "protocol.canceller")
|
||||
defer done()
|
||||
conn.Notify(ctx, "$/cancelRequest", &CancelParams{ID: id})
|
||||
return true
|
||||
}
|
||||
|
||||
func (canceller) Log(direction jsonrpc2.Direction, id *jsonrpc2.ID, elapsed time.Duration, method string, payload *json.RawMessage, err *jsonrpc2.Error) {
|
||||
}
|
||||
|
||||
func NewClient(stream jsonrpc2.Stream, client Client) (*jsonrpc2.Conn, Server, xlog.Logger) {
|
||||
log := xlog.New(NewLogger(client))
|
||||
conn := jsonrpc2.NewConn(stream)
|
||||
conn.Capacity = defaultMessageBufferSize
|
||||
conn.RejectIfOverloaded = defaultRejectIfOverloaded
|
||||
conn.Handler = clientHandler(log, client)
|
||||
conn.Canceler = jsonrpc2.Canceler(canceller)
|
||||
conn.AddHandler(&clientHandler{log: log, client: client})
|
||||
return conn, &serverDispatcher{Conn: conn}, log
|
||||
}
|
||||
|
||||
|
@ -39,10 +56,7 @@ func NewServer(stream jsonrpc2.Stream, server Server) (*jsonrpc2.Conn, Client, x
|
|||
conn := jsonrpc2.NewConn(stream)
|
||||
client := &clientDispatcher{Conn: conn}
|
||||
log := xlog.New(NewLogger(client))
|
||||
conn.Capacity = defaultMessageBufferSize
|
||||
conn.RejectIfOverloaded = defaultRejectIfOverloaded
|
||||
conn.Handler = serverHandler(log, server)
|
||||
conn.Canceler = jsonrpc2.Canceler(canceller)
|
||||
conn.AddHandler(&serverHandler{log: log, server: server})
|
||||
return conn, client, log
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"encoding/json"
|
||||
|
||||
"golang.org/x/tools/internal/jsonrpc2"
|
||||
"golang.org/x/tools/internal/lsp/xlog"
|
||||
)
|
||||
|
||||
type Client interface {
|
||||
|
@ -23,117 +22,127 @@ type Client interface {
|
|||
ApplyEdit(context.Context, *ApplyWorkspaceEditParams) (*ApplyWorkspaceEditResponse, error)
|
||||
}
|
||||
|
||||
func clientHandler(log xlog.Logger, client Client) jsonrpc2.Handler {
|
||||
return func(ctx context.Context, r *jsonrpc2.Request) {
|
||||
switch r.Method {
|
||||
case "$/cancelRequest":
|
||||
var params CancelParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
r.Conn().Cancel(params.ID)
|
||||
case "window/showMessage": // notif
|
||||
var params ShowMessageParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
if err := client.ShowMessage(ctx, ¶ms); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "window/logMessage": // notif
|
||||
var params LogMessageParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
if err := client.LogMessage(ctx, ¶ms); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "telemetry/event": // notif
|
||||
var params interface{}
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
if err := client.Event(ctx, ¶ms); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/publishDiagnostics": // notif
|
||||
var params PublishDiagnosticsParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
if err := client.PublishDiagnostics(ctx, ¶ms); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "workspace/workspaceFolders": // req
|
||||
if r.Params != nil {
|
||||
r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
|
||||
return
|
||||
}
|
||||
resp, err := client.WorkspaceFolders(ctx)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "workspace/configuration": // req
|
||||
var params ConfigurationParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := client.Configuration(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "client/registerCapability": // req
|
||||
var params RegistrationParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
err := client.RegisterCapability(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, nil, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "client/unregisterCapability": // req
|
||||
var params UnregistrationParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
err := client.UnregisterCapability(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, nil, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "window/showMessageRequest": // req
|
||||
var params ShowMessageRequestParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := client.ShowMessageRequest(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "workspace/applyEdit": // req
|
||||
var params ApplyWorkspaceEditParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := client.ApplyEdit(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
|
||||
default:
|
||||
if r.IsNotify() {
|
||||
r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not found", r.Method))
|
||||
}
|
||||
func (h clientHandler) Deliver(ctx context.Context, r *jsonrpc2.Request, delivered bool) bool {
|
||||
if delivered {
|
||||
return false
|
||||
}
|
||||
switch r.Method {
|
||||
case "$/cancelRequest":
|
||||
var params CancelParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
r.Conn().Cancel(params.ID)
|
||||
return true
|
||||
case "window/showMessage": // notif
|
||||
var params ShowMessageParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
if err := h.client.ShowMessage(ctx, ¶ms); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "window/logMessage": // notif
|
||||
var params LogMessageParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
if err := h.client.LogMessage(ctx, ¶ms); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "telemetry/event": // notif
|
||||
var params interface{}
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
if err := h.client.Event(ctx, ¶ms); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/publishDiagnostics": // notif
|
||||
var params PublishDiagnosticsParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
if err := h.client.PublishDiagnostics(ctx, ¶ms); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "workspace/workspaceFolders": // req
|
||||
if r.Params != nil {
|
||||
r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
|
||||
return true
|
||||
}
|
||||
resp, err := h.client.WorkspaceFolders(ctx)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "workspace/configuration": // req
|
||||
var params ConfigurationParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.client.Configuration(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "client/registerCapability": // req
|
||||
var params RegistrationParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
err := h.client.RegisterCapability(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, nil, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "client/unregisterCapability": // req
|
||||
var params UnregistrationParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
err := h.client.UnregisterCapability(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, nil, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "window/showMessageRequest": // req
|
||||
var params ShowMessageRequestParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.client.ShowMessageRequest(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "workspace/applyEdit": // req
|
||||
var params ApplyWorkspaceEditParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.client.ApplyEdit(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"encoding/json"
|
||||
|
||||
"golang.org/x/tools/internal/jsonrpc2"
|
||||
"golang.org/x/tools/internal/lsp/xlog"
|
||||
)
|
||||
|
||||
type Server interface {
|
||||
|
@ -55,424 +54,466 @@ type Server interface {
|
|||
ExecuteCommand(context.Context, *ExecuteCommandParams) (interface{}, error)
|
||||
}
|
||||
|
||||
func serverHandler(log xlog.Logger, server Server) jsonrpc2.Handler {
|
||||
return func(ctx context.Context, r *jsonrpc2.Request) {
|
||||
switch r.Method {
|
||||
case "$/cancelRequest":
|
||||
var params CancelParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
r.Conn().Cancel(params.ID)
|
||||
case "workspace/didChangeWorkspaceFolders": // notif
|
||||
var params DidChangeWorkspaceFoldersParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
if err := server.DidChangeWorkspaceFolders(ctx, ¶ms); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "initialized": // notif
|
||||
var params InitializedParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
if err := server.Initialized(ctx, ¶ms); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "exit": // notif
|
||||
if err := server.Exit(ctx); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "workspace/didChangeConfiguration": // notif
|
||||
var params DidChangeConfigurationParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
if err := server.DidChangeConfiguration(ctx, ¶ms); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/didOpen": // notif
|
||||
var params DidOpenTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
if err := server.DidOpen(ctx, ¶ms); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/didChange": // notif
|
||||
var params DidChangeTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
if err := server.DidChange(ctx, ¶ms); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/didClose": // notif
|
||||
var params DidCloseTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
if err := server.DidClose(ctx, ¶ms); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/didSave": // notif
|
||||
var params DidSaveTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
if err := server.DidSave(ctx, ¶ms); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/willSave": // notif
|
||||
var params WillSaveTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
if err := server.WillSave(ctx, ¶ms); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "workspace/didChangeWatchedFiles": // notif
|
||||
var params DidChangeWatchedFilesParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
if err := server.DidChangeWatchedFiles(ctx, ¶ms); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "$/setTraceNotification": // notif
|
||||
var params SetTraceParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
if err := server.SetTraceNotification(ctx, ¶ms); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "$/logTraceNotification": // notif
|
||||
var params LogTraceParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
if err := server.LogTraceNotification(ctx, ¶ms); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/implementation": // req
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Implementation(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/typeDefinition": // req
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.TypeDefinition(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/documentColor": // req
|
||||
var params DocumentColorParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.DocumentColor(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/colorPresentation": // req
|
||||
var params ColorPresentationParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.ColorPresentation(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/foldingRange": // req
|
||||
var params FoldingRangeParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.FoldingRange(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/declaration": // req
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Declaration(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/selectionRange": // req
|
||||
var params SelectionRangeParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.SelectionRange(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "initialize": // req
|
||||
var params InitializeParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Initialize(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "shutdown": // req
|
||||
if r.Params != nil {
|
||||
r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
|
||||
return
|
||||
}
|
||||
err := server.Shutdown(ctx)
|
||||
if err := r.Reply(ctx, nil, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/willSaveWaitUntil": // req
|
||||
var params WillSaveTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.WillSaveWaitUntil(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/completion": // req
|
||||
var params CompletionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Completion(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "completionItem/resolve": // req
|
||||
var params CompletionItem
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Resolve(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/hover": // req
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Hover(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/signatureHelp": // req
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.SignatureHelp(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/definition": // req
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Definition(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/references": // req
|
||||
var params ReferenceParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.References(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/documentHighlight": // req
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.DocumentHighlight(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/documentSymbol": // req
|
||||
var params DocumentSymbolParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.DocumentSymbol(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "workspace/symbol": // req
|
||||
var params WorkspaceSymbolParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Symbol(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/codeAction": // req
|
||||
var params CodeActionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.CodeAction(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/codeLens": // req
|
||||
var params CodeLensParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.CodeLens(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "codeLens/resolve": // req
|
||||
var params CodeLens
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.ResolveCodeLens(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/formatting": // req
|
||||
var params DocumentFormattingParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Formatting(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/rangeFormatting": // req
|
||||
var params DocumentRangeFormattingParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.RangeFormatting(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/onTypeFormatting": // req
|
||||
var params DocumentOnTypeFormattingParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.OnTypeFormatting(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/rename": // req
|
||||
var params RenameParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Rename(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/prepareRename": // req
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.PrepareRename(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "textDocument/documentLink": // req
|
||||
var params DocumentLinkParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.DocumentLink(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "documentLink/resolve": // req
|
||||
var params DocumentLink
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.ResolveDocumentLink(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
case "workspace/executeCommand": // req
|
||||
var params ExecuteCommandParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.ExecuteCommand(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
|
||||
default:
|
||||
if r.IsNotify() {
|
||||
r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not found", r.Method))
|
||||
}
|
||||
func (h serverHandler) Deliver(ctx context.Context, r *jsonrpc2.Request, delivered bool) bool {
|
||||
if delivered {
|
||||
return false
|
||||
}
|
||||
switch r.Method {
|
||||
case "$/cancelRequest":
|
||||
var params CancelParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
r.Conn().Cancel(params.ID)
|
||||
return true
|
||||
case "workspace/didChangeWorkspaceFolders": // notif
|
||||
var params DidChangeWorkspaceFoldersParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
if err := h.server.DidChangeWorkspaceFolders(ctx, ¶ms); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "initialized": // notif
|
||||
var params InitializedParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
if err := h.server.Initialized(ctx, ¶ms); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "exit": // notif
|
||||
if err := h.server.Exit(ctx); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "workspace/didChangeConfiguration": // notif
|
||||
var params DidChangeConfigurationParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
if err := h.server.DidChangeConfiguration(ctx, ¶ms); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/didOpen": // notif
|
||||
var params DidOpenTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
if err := h.server.DidOpen(ctx, ¶ms); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/didChange": // notif
|
||||
var params DidChangeTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
if err := h.server.DidChange(ctx, ¶ms); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/didClose": // notif
|
||||
var params DidCloseTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
if err := h.server.DidClose(ctx, ¶ms); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/didSave": // notif
|
||||
var params DidSaveTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
if err := h.server.DidSave(ctx, ¶ms); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/willSave": // notif
|
||||
var params WillSaveTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
if err := h.server.WillSave(ctx, ¶ms); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "workspace/didChangeWatchedFiles": // notif
|
||||
var params DidChangeWatchedFilesParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
if err := h.server.DidChangeWatchedFiles(ctx, ¶ms); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "$/setTraceNotification": // notif
|
||||
var params SetTraceParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
if err := h.server.SetTraceNotification(ctx, ¶ms); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "$/logTraceNotification": // notif
|
||||
var params LogTraceParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
if err := h.server.LogTraceNotification(ctx, ¶ms); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/implementation": // req
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.Implementation(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/typeDefinition": // req
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.TypeDefinition(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/documentColor": // req
|
||||
var params DocumentColorParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.DocumentColor(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/colorPresentation": // req
|
||||
var params ColorPresentationParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.ColorPresentation(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/foldingRange": // req
|
||||
var params FoldingRangeParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.FoldingRange(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/declaration": // req
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.Declaration(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/selectionRange": // req
|
||||
var params SelectionRangeParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.SelectionRange(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "initialize": // req
|
||||
var params InitializeParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.Initialize(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "shutdown": // req
|
||||
if r.Params != nil {
|
||||
r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
|
||||
return true
|
||||
}
|
||||
err := h.server.Shutdown(ctx)
|
||||
if err := r.Reply(ctx, nil, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/willSaveWaitUntil": // req
|
||||
var params WillSaveTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.WillSaveWaitUntil(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/completion": // req
|
||||
var params CompletionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.Completion(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "completionItem/resolve": // req
|
||||
var params CompletionItem
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.Resolve(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/hover": // req
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.Hover(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/signatureHelp": // req
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.SignatureHelp(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/definition": // req
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.Definition(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/references": // req
|
||||
var params ReferenceParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.References(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/documentHighlight": // req
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.DocumentHighlight(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/documentSymbol": // req
|
||||
var params DocumentSymbolParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.DocumentSymbol(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "workspace/symbol": // req
|
||||
var params WorkspaceSymbolParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.Symbol(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/codeAction": // req
|
||||
var params CodeActionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.CodeAction(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/codeLens": // req
|
||||
var params CodeLensParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.CodeLens(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "codeLens/resolve": // req
|
||||
var params CodeLens
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.ResolveCodeLens(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/formatting": // req
|
||||
var params DocumentFormattingParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.Formatting(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/rangeFormatting": // req
|
||||
var params DocumentRangeFormattingParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.RangeFormatting(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/onTypeFormatting": // req
|
||||
var params DocumentOnTypeFormattingParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.OnTypeFormatting(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/rename": // req
|
||||
var params RenameParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.Rename(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/prepareRename": // req
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.PrepareRename(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "textDocument/documentLink": // req
|
||||
var params DocumentLinkParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.DocumentLink(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "documentLink/resolve": // req
|
||||
var params DocumentLink
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.ResolveDocumentLink(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
case "workspace/executeCommand": // req
|
||||
var params ExecuteCommandParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
resp, err := h.server.ExecuteCommand(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ function generate(files: string[], options: ts.CompilerOptions): void {
|
|||
setReceives(); // distinguish client and server
|
||||
// for each of Client and Server there are 3 parts to the output:
|
||||
// 1. type X interface {methods}
|
||||
// 2. serverHandler(...) { return func(...) { switch r.method}}
|
||||
// 2. func (h *serverHandler) Deliver(...) { switch r.method }
|
||||
// 3. func (x *xDispatcher) Method(ctx, parm)
|
||||
not.forEach(
|
||||
(v, k) => {
|
||||
|
@ -99,7 +99,7 @@ function sig(nm: string, a: string, b: string, names?: boolean): string {
|
|||
|
||||
const notNil = `if r.Params != nil {
|
||||
r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
|
||||
return
|
||||
return true
|
||||
}`;
|
||||
// Go code for notifications. Side is client or server, m is the request method
|
||||
function goNot(side: side, m: string) {
|
||||
|
@ -113,16 +113,18 @@ function goNot(side: side, m: string) {
|
|||
if (a != '') {
|
||||
case1 = `var params ${a}
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
if err := ${side.name}.${nm}(ctx, ¶ms); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}`;
|
||||
if err := h.${side.name}.${nm}(ctx, ¶ms); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true`;
|
||||
} else {
|
||||
case1 = `if err := ${side.name}.${nm}(ctx); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}`;
|
||||
case1 = `if err := h.${side.name}.${nm}(ctx); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true`;
|
||||
}
|
||||
side.cases.push(`${caseHdr}\n${case1}`);
|
||||
|
||||
|
@ -152,24 +154,26 @@ function goReq(side: side, m: string) {
|
|||
if (a != '') {
|
||||
case1 = `var params ${a}
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}`;
|
||||
}
|
||||
const arg2 = a == '' ? '' : ', ¶ms';
|
||||
let case2 = `if err := ${side.name}.${nm}(ctx${arg2}); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
let case2 = `if err := h.${side.name}.${nm}(ctx${arg2}); err != nil {
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}`;
|
||||
if (b != '') {
|
||||
case2 = `resp, err := ${side.name}.${nm}(ctx${arg2})
|
||||
case2 = `resp, err := h.${side.name}.${nm}(ctx${arg2})
|
||||
if err := r.Reply(ctx, resp, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}`;
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true`;
|
||||
} else { // response is nil
|
||||
case2 = `err := ${side.name}.${nm}(ctx${arg2})
|
||||
case2 = `err := h.${side.name}.${nm}(ctx${arg2})
|
||||
if err := r.Reply(ctx, nil, err); err != nil {
|
||||
log.Errorf(ctx, "%v", err)
|
||||
}`
|
||||
h.log.Errorf(ctx, "%v", err)
|
||||
}
|
||||
return true`
|
||||
}
|
||||
|
||||
side.cases.push(`${caseHdr}\n${case1}\n${case2}`);
|
||||
|
@ -222,32 +226,30 @@ function output(side: side) {
|
|||
"encoding/json"
|
||||
|
||||
"golang.org/x/tools/internal/jsonrpc2"
|
||||
"golang.org/x/tools/internal/lsp/xlog"
|
||||
)
|
||||
`);
|
||||
const a = side.name[0].toUpperCase() + side.name.substring(1)
|
||||
f(`type ${a} interface {`);
|
||||
side.methods.forEach((v) => { f(v) });
|
||||
f('}\n');
|
||||
f(`func ${side.name}Handler(log xlog.Logger, ${side.name} ${
|
||||
side.goName}) jsonrpc2.Handler {
|
||||
return func(ctx context.Context, r *jsonrpc2.Request) {
|
||||
f(`func (h ${side.name}Handler) Deliver(ctx context.Context, r *jsonrpc2.Request, delivered bool) bool {
|
||||
if delivered {
|
||||
return false
|
||||
}
|
||||
switch r.Method {
|
||||
case "$/cancelRequest":
|
||||
var params CancelParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, log, r, err)
|
||||
return
|
||||
sendParseError(ctx, h.log, r, err)
|
||||
return true
|
||||
}
|
||||
r.Conn().Cancel(params.ID)`);
|
||||
r.Conn().Cancel(params.ID)
|
||||
return true`);
|
||||
side.cases.forEach((v) => { f(v) });
|
||||
f(`
|
||||
default:
|
||||
if r.IsNotify() {
|
||||
r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not found", r.Method))
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}`);
|
||||
f(`
|
||||
type ${side.name}Dispatcher struct {
|
||||
|
|
Loading…
Reference in New Issue