add prune and remove unused packages
This commit is contained in:
239
vendor/golang.org/x/tools/internal/fastwalk/fastwalk_test.go
generated
vendored
239
vendor/golang.org/x/tools/internal/fastwalk/fastwalk_test.go
generated
vendored
@@ -1,239 +0,0 @@
|
||||
// Copyright 2016 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 fastwalk_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/tools/internal/fastwalk"
|
||||
)
|
||||
|
||||
func formatFileModes(m map[string]os.FileMode) string {
|
||||
var keys []string
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
var buf bytes.Buffer
|
||||
for _, k := range keys {
|
||||
fmt.Fprintf(&buf, "%-20s: %v\n", k, m[k])
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func testFastWalk(t *testing.T, files map[string]string, callback func(path string, typ os.FileMode) error, want map[string]os.FileMode) {
|
||||
tempdir, err := ioutil.TempDir("", "test-fast-walk")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tempdir)
|
||||
for path, contents := range files {
|
||||
file := filepath.Join(tempdir, "/src", path)
|
||||
if err := os.MkdirAll(filepath.Dir(file), 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var err error
|
||||
if strings.HasPrefix(contents, "LINK:") {
|
||||
err = os.Symlink(strings.TrimPrefix(contents, "LINK:"), file)
|
||||
} else {
|
||||
err = ioutil.WriteFile(file, []byte(contents), 0644)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
got := map[string]os.FileMode{}
|
||||
var mu sync.Mutex
|
||||
if err := fastwalk.Walk(tempdir, func(path string, typ os.FileMode) error {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
if !strings.HasPrefix(path, tempdir) {
|
||||
t.Fatalf("bogus prefix on %q, expect %q", path, tempdir)
|
||||
}
|
||||
key := filepath.ToSlash(strings.TrimPrefix(path, tempdir))
|
||||
if old, dup := got[key]; dup {
|
||||
t.Fatalf("callback called twice for key %q: %v -> %v", key, old, typ)
|
||||
}
|
||||
got[key] = typ
|
||||
return callback(path, typ)
|
||||
}); err != nil {
|
||||
t.Fatalf("callback returned: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("walk mismatch.\n got:\n%v\nwant:\n%v", formatFileModes(got), formatFileModes(want))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFastWalk_Basic(t *testing.T) {
|
||||
testFastWalk(t, map[string]string{
|
||||
"foo/foo.go": "one",
|
||||
"bar/bar.go": "two",
|
||||
"skip/skip.go": "skip",
|
||||
},
|
||||
func(path string, typ os.FileMode) error {
|
||||
return nil
|
||||
},
|
||||
map[string]os.FileMode{
|
||||
"": os.ModeDir,
|
||||
"/src": os.ModeDir,
|
||||
"/src/bar": os.ModeDir,
|
||||
"/src/bar/bar.go": 0,
|
||||
"/src/foo": os.ModeDir,
|
||||
"/src/foo/foo.go": 0,
|
||||
"/src/skip": os.ModeDir,
|
||||
"/src/skip/skip.go": 0,
|
||||
})
|
||||
}
|
||||
|
||||
func TestFastWalk_LongFileName(t *testing.T) {
|
||||
longFileName := strings.Repeat("x", 255)
|
||||
|
||||
testFastWalk(t, map[string]string{
|
||||
longFileName: "one",
|
||||
},
|
||||
func(path string, typ os.FileMode) error {
|
||||
return nil
|
||||
},
|
||||
map[string]os.FileMode{
|
||||
"": os.ModeDir,
|
||||
"/src": os.ModeDir,
|
||||
"/src/" + longFileName: 0,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestFastWalk_Symlink(t *testing.T) {
|
||||
switch runtime.GOOS {
|
||||
case "windows", "plan9":
|
||||
t.Skipf("skipping on %s", runtime.GOOS)
|
||||
}
|
||||
testFastWalk(t, map[string]string{
|
||||
"foo/foo.go": "one",
|
||||
"bar/bar.go": "LINK:../foo.go",
|
||||
"symdir": "LINK:foo",
|
||||
},
|
||||
func(path string, typ os.FileMode) error {
|
||||
return nil
|
||||
},
|
||||
map[string]os.FileMode{
|
||||
"": os.ModeDir,
|
||||
"/src": os.ModeDir,
|
||||
"/src/bar": os.ModeDir,
|
||||
"/src/bar/bar.go": os.ModeSymlink,
|
||||
"/src/foo": os.ModeDir,
|
||||
"/src/foo/foo.go": 0,
|
||||
"/src/symdir": os.ModeSymlink,
|
||||
})
|
||||
}
|
||||
|
||||
func TestFastWalk_SkipDir(t *testing.T) {
|
||||
testFastWalk(t, map[string]string{
|
||||
"foo/foo.go": "one",
|
||||
"bar/bar.go": "two",
|
||||
"skip/skip.go": "skip",
|
||||
},
|
||||
func(path string, typ os.FileMode) error {
|
||||
if typ == os.ModeDir && strings.HasSuffix(path, "skip") {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
},
|
||||
map[string]os.FileMode{
|
||||
"": os.ModeDir,
|
||||
"/src": os.ModeDir,
|
||||
"/src/bar": os.ModeDir,
|
||||
"/src/bar/bar.go": 0,
|
||||
"/src/foo": os.ModeDir,
|
||||
"/src/foo/foo.go": 0,
|
||||
"/src/skip": os.ModeDir,
|
||||
})
|
||||
}
|
||||
|
||||
func TestFastWalk_SkipFiles(t *testing.T) {
|
||||
// Directory iteration order is undefined, so there's no way to know
|
||||
// which file to expect until the walk happens. Rather than mess
|
||||
// with the test infrastructure, just mutate want.
|
||||
var mu sync.Mutex
|
||||
want := map[string]os.FileMode{
|
||||
"": os.ModeDir,
|
||||
"/src": os.ModeDir,
|
||||
"/src/zzz": os.ModeDir,
|
||||
"/src/zzz/c.go": 0,
|
||||
}
|
||||
|
||||
testFastWalk(t, map[string]string{
|
||||
"a_skipfiles.go": "a",
|
||||
"b_skipfiles.go": "b",
|
||||
"zzz/c.go": "c",
|
||||
},
|
||||
func(path string, typ os.FileMode) error {
|
||||
if strings.HasSuffix(path, "_skipfiles.go") {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
want["/src/"+filepath.Base(path)] = 0
|
||||
return fastwalk.SkipFiles
|
||||
}
|
||||
return nil
|
||||
},
|
||||
want)
|
||||
if len(want) != 5 {
|
||||
t.Errorf("saw too many files: wanted 5, got %v (%v)", len(want), want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFastWalk_TraverseSymlink(t *testing.T) {
|
||||
switch runtime.GOOS {
|
||||
case "windows", "plan9":
|
||||
t.Skipf("skipping on %s", runtime.GOOS)
|
||||
}
|
||||
|
||||
testFastWalk(t, map[string]string{
|
||||
"foo/foo.go": "one",
|
||||
"bar/bar.go": "two",
|
||||
"skip/skip.go": "skip",
|
||||
"symdir": "LINK:foo",
|
||||
},
|
||||
func(path string, typ os.FileMode) error {
|
||||
if typ == os.ModeSymlink {
|
||||
return fastwalk.TraverseLink
|
||||
}
|
||||
return nil
|
||||
},
|
||||
map[string]os.FileMode{
|
||||
"": os.ModeDir,
|
||||
"/src": os.ModeDir,
|
||||
"/src/bar": os.ModeDir,
|
||||
"/src/bar/bar.go": 0,
|
||||
"/src/foo": os.ModeDir,
|
||||
"/src/foo/foo.go": 0,
|
||||
"/src/skip": os.ModeDir,
|
||||
"/src/skip/skip.go": 0,
|
||||
"/src/symdir": os.ModeSymlink,
|
||||
"/src/symdir/foo.go": 0,
|
||||
})
|
||||
}
|
||||
|
||||
var benchDir = flag.String("benchdir", runtime.GOROOT(), "The directory to scan for BenchmarkFastWalk")
|
||||
|
||||
func BenchmarkFastWalk(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
err := fastwalk.Walk(*benchDir, func(path string, typ os.FileMode) error { return nil })
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
135
vendor/golang.org/x/tools/internal/gopathwalk/walk_test.go
generated
vendored
135
vendor/golang.org/x/tools/internal/gopathwalk/walk_test.go
generated
vendored
@@ -1,135 +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 gopathwalk
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestShouldTraverse(t *testing.T) {
|
||||
switch runtime.GOOS {
|
||||
case "windows", "plan9":
|
||||
t.Skipf("skipping symlink-requiring test on %s", runtime.GOOS)
|
||||
}
|
||||
|
||||
dir, err := ioutil.TempDir("", "goimports-")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
// Note: mapToDir prepends "src" to each element, since
|
||||
// mapToDir was made for creating GOPATHs.
|
||||
if err := mapToDir(dir, map[string]string{
|
||||
"foo/foo2/file.txt": "",
|
||||
"foo/foo2/link-to-src": "LINK:../../",
|
||||
"foo/foo2/link-to-src-foo": "LINK:../../foo",
|
||||
"foo/foo2/link-to-dot": "LINK:.",
|
||||
"bar/bar2/file.txt": "",
|
||||
"bar/bar2/link-to-src-foo": "LINK:../../foo",
|
||||
|
||||
"a/b/c": "LINK:../../a/d",
|
||||
"a/d/e": "LINK:../../a/b",
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tests := []struct {
|
||||
dir string
|
||||
file string
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
dir: "src/foo/foo2",
|
||||
file: "link-to-src-foo",
|
||||
want: false, // loop
|
||||
},
|
||||
{
|
||||
dir: "src/foo/foo2",
|
||||
file: "link-to-src",
|
||||
want: false, // loop
|
||||
},
|
||||
{
|
||||
dir: "src/foo/foo2",
|
||||
file: "link-to-dot",
|
||||
want: false, // loop
|
||||
},
|
||||
{
|
||||
dir: "src/bar/bar2",
|
||||
file: "link-to-src-foo",
|
||||
want: true, // not a loop
|
||||
},
|
||||
{
|
||||
dir: "src/a/b/c",
|
||||
file: "e",
|
||||
want: false, // loop: "e" is the same as "b".
|
||||
},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
fi, err := os.Stat(filepath.Join(dir, tt.dir, tt.file))
|
||||
if err != nil {
|
||||
t.Errorf("%d. Stat = %v", i, err)
|
||||
continue
|
||||
}
|
||||
var w walker
|
||||
got := w.shouldTraverse(filepath.Join(dir, tt.dir), fi)
|
||||
if got != tt.want {
|
||||
t.Errorf("%d. shouldTraverse(%q, %q) = %v; want %v", i, tt.dir, tt.file, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestSkip tests that various goimports rules are followed in non-modules mode.
|
||||
func TestSkip(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "goimports-")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
if err := mapToDir(dir, map[string]string{
|
||||
"ignoreme/f.go": "package ignoreme", // ignored by .goimportsignore
|
||||
"node_modules/f.go": "package nodemodules;", // ignored by hardcoded node_modules filter
|
||||
"v/f.go": "package v;", // ignored by hardcoded vgo cache rule
|
||||
"mod/f.go": "package mod;", // ignored by hardcoded vgo cache rule
|
||||
"shouldfind/f.go": "package shouldfind;", // not ignored
|
||||
|
||||
".goimportsignore": "ignoreme\n",
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var found []string
|
||||
walkDir(Root{filepath.Join(dir, "src"), RootGOPATH}, func(root Root, dir string) {
|
||||
found = append(found, dir[len(root.Path)+1:])
|
||||
}, Options{ModulesEnabled: false, Debug: true})
|
||||
if want := []string{"shouldfind"}; !reflect.DeepEqual(found, want) {
|
||||
t.Errorf("expected to find only %v, got %v", want, found)
|
||||
}
|
||||
}
|
||||
|
||||
func mapToDir(destDir string, files map[string]string) error {
|
||||
for path, contents := range files {
|
||||
file := filepath.Join(destDir, "src", path)
|
||||
if err := os.MkdirAll(filepath.Dir(file), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
var err error
|
||||
if strings.HasPrefix(contents, "LINK:") {
|
||||
err = os.Symlink(strings.TrimPrefix(contents, "LINK:"), file)
|
||||
} else {
|
||||
err = ioutil.WriteFile(file, []byte(contents), 0644)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
358
vendor/golang.org/x/tools/internal/jsonrpc2/jsonrpc2.go
generated
vendored
358
vendor/golang.org/x/tools/internal/jsonrpc2/jsonrpc2.go
generated
vendored
@@ -1,358 +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 is a minimal implementation of the JSON RPC 2 spec.
|
||||
// https://www.jsonrpc.org/specification
|
||||
// It is intended to be compatible with other implementations at the wire level.
|
||||
package jsonrpc2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
handle Handler
|
||||
cancel Canceler
|
||||
log Logger
|
||||
stream Stream
|
||||
done chan struct{}
|
||||
err error
|
||||
seq int64 // must only be accessed using atomic operations
|
||||
pendingMu sync.Mutex // protects the pending map
|
||||
pending map[ID]chan *Response
|
||||
handlingMu sync.Mutex // protects the handling map
|
||||
handling map[ID]handling
|
||||
}
|
||||
|
||||
// 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, *Conn, *Request)
|
||||
|
||||
// Canceler is an option you can pass to NewConn which is invoked for
|
||||
// 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
|
||||
// be in the cancelled state, so you must do it with the background context
|
||||
// instead.
|
||||
type Canceler func(context.Context, *Conn, *Request)
|
||||
|
||||
// NewErrorf builds a Error struct for the suppied message and code.
|
||||
// If args is not empty, message and args will be passed to Sprintf.
|
||||
func NewErrorf(code int64, format string, args ...interface{}) *Error {
|
||||
return &Error{
|
||||
Code: code,
|
||||
Message: fmt.Sprintf(format, args...),
|
||||
}
|
||||
}
|
||||
|
||||
// NewConn creates a new connection object that reads and writes messages from
|
||||
// the supplied stream and dispatches incoming messages to the supplied handler.
|
||||
func NewConn(ctx context.Context, s Stream, options ...interface{}) *Conn {
|
||||
conn := &Conn{
|
||||
stream: s,
|
||||
done: make(chan struct{}),
|
||||
pending: make(map[ID]chan *Response),
|
||||
handling: make(map[ID]handling),
|
||||
}
|
||||
for _, opt := range options {
|
||||
switch opt := opt.(type) {
|
||||
case Handler:
|
||||
if conn.handle != nil {
|
||||
panic("Duplicate Handler function in options list")
|
||||
}
|
||||
conn.handle = opt
|
||||
case Canceler:
|
||||
if conn.cancel != nil {
|
||||
panic("Duplicate Canceler function in options list")
|
||||
}
|
||||
conn.cancel = opt
|
||||
case Logger:
|
||||
if conn.log != nil {
|
||||
panic("Duplicate Logger function in options list")
|
||||
}
|
||||
conn.log = opt
|
||||
default:
|
||||
panic(fmt.Errorf("Unknown option type %T in options list", opt))
|
||||
}
|
||||
}
|
||||
if conn.handle == nil {
|
||||
// the default handler reports a method error
|
||||
conn.handle = func(ctx context.Context, c *Conn, r *Request) {
|
||||
if r.IsNotify() {
|
||||
c.Reply(ctx, r, nil, NewErrorf(CodeMethodNotFound, "method %q not found", r.Method))
|
||||
}
|
||||
}
|
||||
}
|
||||
if conn.cancel == nil {
|
||||
// the default canceller does nothing
|
||||
conn.cancel = func(context.Context, *Conn, *Request) {}
|
||||
}
|
||||
if conn.log == nil {
|
||||
// the default logger does nothing
|
||||
conn.log = func(Direction, *ID, time.Duration, string, *json.RawMessage, *Error) {}
|
||||
}
|
||||
go func() {
|
||||
conn.err = conn.run(ctx)
|
||||
close(conn.done)
|
||||
}()
|
||||
return conn
|
||||
}
|
||||
|
||||
// Wait blocks until the connection is terminated, and returns any error that
|
||||
// cause the termination.
|
||||
func (c *Conn) Wait(ctx context.Context) error {
|
||||
select {
|
||||
case <-c.done:
|
||||
return c.err
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// directly wired in. This method allows a higher level protocol to choose how
|
||||
// to propagate the cancel.
|
||||
func (c *Conn) Cancel(id ID) {
|
||||
c.handlingMu.Lock()
|
||||
handling, found := c.handling[id]
|
||||
c.handlingMu.Unlock()
|
||||
if found {
|
||||
handling.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
// Notify is called to send a notification request over the connection.
|
||||
// It will return as soon as the notification has been sent, as no response is
|
||||
// possible.
|
||||
func (c *Conn) Notify(ctx context.Context, method string, params interface{}) error {
|
||||
jsonParams, err := marshalToRaw(params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshalling notify parameters: %v", err)
|
||||
}
|
||||
request := &Request{
|
||||
Method: method,
|
||||
Params: jsonParams,
|
||||
}
|
||||
data, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshalling notify request: %v", err)
|
||||
}
|
||||
c.log(Send, nil, -1, request.Method, request.Params, nil)
|
||||
return c.stream.Write(ctx, data)
|
||||
}
|
||||
|
||||
// Call sends a request over the connection and then waits for a response.
|
||||
// If the response is not an error, it will be decoded into result.
|
||||
// result must be of a type you an pass to json.Unmarshal.
|
||||
func (c *Conn) Call(ctx context.Context, method string, params, result interface{}) error {
|
||||
jsonParams, err := marshalToRaw(params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshalling call parameters: %v", err)
|
||||
}
|
||||
// generate a new request identifier
|
||||
id := ID{Number: atomic.AddInt64(&c.seq, 1)}
|
||||
request := &Request{
|
||||
ID: &id,
|
||||
Method: method,
|
||||
Params: jsonParams,
|
||||
}
|
||||
// marshal the request now it is complete
|
||||
data, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshalling call request: %v", err)
|
||||
}
|
||||
// we have to add ourselves to the pending map before we send, otherwise we
|
||||
// are racing the response
|
||||
rchan := make(chan *Response)
|
||||
c.pendingMu.Lock()
|
||||
c.pending[id] = rchan
|
||||
c.pendingMu.Unlock()
|
||||
defer func() {
|
||||
// clean up the pending response handler on the way out
|
||||
c.pendingMu.Lock()
|
||||
delete(c.pending, id)
|
||||
c.pendingMu.Unlock()
|
||||
}()
|
||||
// now we are ready to send
|
||||
before := time.Now()
|
||||
c.log(Send, request.ID, -1, request.Method, request.Params, nil)
|
||||
if err := c.stream.Write(ctx, data); err != nil {
|
||||
// sending failed, we will never get a response, so don't leave it pending
|
||||
return err
|
||||
}
|
||||
// now wait for the response
|
||||
select {
|
||||
case response := <-rchan:
|
||||
elapsed := time.Since(before)
|
||||
c.log(Send, response.ID, elapsed, request.Method, response.Result, response.Error)
|
||||
// is it an error response?
|
||||
if response.Error != nil {
|
||||
return response.Error
|
||||
}
|
||||
if result == nil || response.Result == nil {
|
||||
return nil
|
||||
}
|
||||
if err := json.Unmarshal(*response.Result, result); err != nil {
|
||||
return fmt.Errorf("unmarshalling result: %v", err)
|
||||
}
|
||||
return nil
|
||||
case <-ctx.Done():
|
||||
// allow the handler to propagate the cancel
|
||||
c.cancel(ctx, c, request)
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
// Reply sends a reply to the given request.
|
||||
// It is an error to call this if request was not a call.
|
||||
// You must call this exactly once for any given request.
|
||||
// If err is set then result will be ignored.
|
||||
func (c *Conn) Reply(ctx context.Context, req *Request, result interface{}, err error) error {
|
||||
if req.IsNotify() {
|
||||
return fmt.Errorf("reply not invoked with a valid call")
|
||||
}
|
||||
c.handlingMu.Lock()
|
||||
handling, found := c.handling[*req.ID]
|
||||
if found {
|
||||
delete(c.handling, *req.ID)
|
||||
}
|
||||
c.handlingMu.Unlock()
|
||||
if !found {
|
||||
return fmt.Errorf("not a call in progress: %v", req.ID)
|
||||
}
|
||||
|
||||
elapsed := time.Since(handling.start)
|
||||
var raw *json.RawMessage
|
||||
if err == nil {
|
||||
raw, err = marshalToRaw(result)
|
||||
}
|
||||
response := &Response{
|
||||
Result: raw,
|
||||
ID: req.ID,
|
||||
}
|
||||
if err != nil {
|
||||
if callErr, ok := err.(*Error); ok {
|
||||
response.Error = callErr
|
||||
} else {
|
||||
response.Error = NewErrorf(0, "%s", err)
|
||||
}
|
||||
}
|
||||
data, err := json.Marshal(response)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.log(Send, response.ID, elapsed, req.Method, response.Result, response.Error)
|
||||
if err = c.stream.Write(ctx, data); err != nil {
|
||||
// TODO(iancottrell): if a stream write fails, we really need to shut down
|
||||
// the whole stream
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type handling struct {
|
||||
request *Request
|
||||
cancel context.CancelFunc
|
||||
start time.Time
|
||||
}
|
||||
|
||||
// combined has all the fields of both Request and Response.
|
||||
// We can decode this and then work out which it is.
|
||||
type combined struct {
|
||||
VersionTag VersionTag `json:"jsonrpc"`
|
||||
ID *ID `json:"id,omitempty"`
|
||||
Method string `json:"method"`
|
||||
Params *json.RawMessage `json:"params,omitempty"`
|
||||
Result *json.RawMessage `json:"result,omitempty"`
|
||||
Error *Error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// Run starts a read loop on the supplied reader.
|
||||
// It must be called exactly once for each Conn.
|
||||
// It returns only when the reader is closed or there is an error in the stream.
|
||||
func (c *Conn) run(ctx context.Context) error {
|
||||
for {
|
||||
// get the data for a message
|
||||
data, err := c.stream.Read(ctx)
|
||||
if err != nil {
|
||||
// the stream failed, we cannot continue
|
||||
return err
|
||||
}
|
||||
// read a combined message
|
||||
msg := &combined{}
|
||||
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.log(Receive, nil, -1, "", nil, NewErrorf(0, "unmarshal failed: %v", err))
|
||||
continue
|
||||
}
|
||||
// work out which kind of message we have
|
||||
switch {
|
||||
case msg.Method != "":
|
||||
// if method is set it must be a request
|
||||
request := &Request{
|
||||
Method: msg.Method,
|
||||
Params: msg.Params,
|
||||
ID: msg.ID,
|
||||
}
|
||||
if request.IsNotify() {
|
||||
c.log(Receive, request.ID, -1, request.Method, request.Params, nil)
|
||||
// we have a Notify, forward to the handler in a go routine
|
||||
c.handle(ctx, c, request)
|
||||
} else {
|
||||
// we have a Call, forward to the handler in another go routine
|
||||
reqCtx, cancelReq := context.WithCancel(ctx)
|
||||
c.handlingMu.Lock()
|
||||
c.handling[*request.ID] = handling{
|
||||
request: request,
|
||||
cancel: cancelReq,
|
||||
start: time.Now(),
|
||||
}
|
||||
c.handlingMu.Unlock()
|
||||
c.log(Receive, request.ID, -1, request.Method, request.Params, nil)
|
||||
c.handle(reqCtx, c, request)
|
||||
}
|
||||
case msg.ID != nil:
|
||||
// we have a response, get the pending entry from the map
|
||||
c.pendingMu.Lock()
|
||||
rchan := c.pending[*msg.ID]
|
||||
if rchan != nil {
|
||||
delete(c.pending, *msg.ID)
|
||||
}
|
||||
c.pendingMu.Unlock()
|
||||
// and send the reply to the channel
|
||||
response := &Response{
|
||||
Result: msg.Result,
|
||||
Error: msg.Error,
|
||||
ID: msg.ID,
|
||||
}
|
||||
rchan <- response
|
||||
close(rchan)
|
||||
default:
|
||||
c.log(Receive, nil, -1, "", nil, NewErrorf(0, "message not a call, notify or response, ignoring"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func marshalToRaw(obj interface{}) (*json.RawMessage, error) {
|
||||
data, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
raw := json.RawMessage(data)
|
||||
return &raw, nil
|
||||
}
|
163
vendor/golang.org/x/tools/internal/jsonrpc2/jsonrpc2_test.go
generated
vendored
163
vendor/golang.org/x/tools/internal/jsonrpc2/jsonrpc2_test.go
generated
vendored
@@ -1,163 +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_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/tools/internal/jsonrpc2"
|
||||
)
|
||||
|
||||
var logRPC = flag.Bool("logrpc", false, "Enable jsonrpc2 communication logging")
|
||||
|
||||
type callTest struct {
|
||||
method string
|
||||
params interface{}
|
||||
expect interface{}
|
||||
}
|
||||
|
||||
var callTests = []callTest{
|
||||
{"no_args", nil, true},
|
||||
{"one_string", "fish", "got:fish"},
|
||||
{"one_number", 10, "got:10"},
|
||||
{"join", []string{"a", "b", "c"}, "a/b/c"},
|
||||
//TODO: expand the test cases
|
||||
}
|
||||
|
||||
func (test *callTest) newResults() interface{} {
|
||||
switch e := test.expect.(type) {
|
||||
case []interface{}:
|
||||
var r []interface{}
|
||||
for _, v := range e {
|
||||
r = append(r, reflect.New(reflect.TypeOf(v)).Interface())
|
||||
}
|
||||
return r
|
||||
case nil:
|
||||
return nil
|
||||
default:
|
||||
return reflect.New(reflect.TypeOf(test.expect)).Interface()
|
||||
}
|
||||
}
|
||||
|
||||
func (test *callTest) verifyResults(t *testing.T, results interface{}) {
|
||||
if results == nil {
|
||||
return
|
||||
}
|
||||
val := reflect.Indirect(reflect.ValueOf(results)).Interface()
|
||||
if !reflect.DeepEqual(val, test.expect) {
|
||||
t.Errorf("%v:Results are incorrect, got %+v expect %+v", test.method, val, test.expect)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlainCall(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
a, b := prepare(ctx, t, false)
|
||||
for _, test := range callTests {
|
||||
results := test.newResults()
|
||||
if err := a.Call(ctx, test.method, test.params, results); err != nil {
|
||||
t.Fatalf("%v:Call failed: %v", test.method, err)
|
||||
}
|
||||
test.verifyResults(t, results)
|
||||
if err := b.Call(ctx, test.method, test.params, results); err != nil {
|
||||
t.Fatalf("%v:Call failed: %v", test.method, err)
|
||||
}
|
||||
test.verifyResults(t, results)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHeaderCall(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
a, b := prepare(ctx, t, true)
|
||||
for _, test := range callTests {
|
||||
results := test.newResults()
|
||||
if err := a.Call(ctx, test.method, test.params, results); err != nil {
|
||||
t.Fatalf("%v:Call failed: %v", test.method, err)
|
||||
}
|
||||
test.verifyResults(t, results)
|
||||
if err := b.Call(ctx, test.method, test.params, results); err != nil {
|
||||
t.Fatalf("%v:Call failed: %v", test.method, err)
|
||||
}
|
||||
test.verifyResults(t, results)
|
||||
}
|
||||
}
|
||||
|
||||
func prepare(ctx context.Context, t *testing.T, withHeaders bool) (*testHandler, *testHandler) {
|
||||
a := &testHandler{t: t}
|
||||
b := &testHandler{t: t}
|
||||
a.reader, b.writer = io.Pipe()
|
||||
b.reader, a.writer = io.Pipe()
|
||||
for _, h := range []*testHandler{a, b} {
|
||||
h := h
|
||||
if withHeaders {
|
||||
h.stream = jsonrpc2.NewHeaderStream(h.reader, h.writer)
|
||||
} else {
|
||||
h.stream = jsonrpc2.NewStream(h.reader, h.writer)
|
||||
}
|
||||
args := []interface{}{jsonrpc2.Handler(handle)}
|
||||
if *logRPC {
|
||||
args = append(args, jsonrpc2.Log)
|
||||
}
|
||||
h.Conn = jsonrpc2.NewConn(ctx, h.stream, args...)
|
||||
go func() {
|
||||
defer func() {
|
||||
h.reader.Close()
|
||||
h.writer.Close()
|
||||
}()
|
||||
if err := h.Conn.Wait(ctx); err != nil {
|
||||
t.Fatalf("Stream failed: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
return a, b
|
||||
}
|
||||
|
||||
type testHandler struct {
|
||||
t *testing.T
|
||||
reader *io.PipeReader
|
||||
writer *io.PipeWriter
|
||||
stream jsonrpc2.Stream
|
||||
*jsonrpc2.Conn
|
||||
}
|
||||
|
||||
func handle(ctx context.Context, c *jsonrpc2.Conn, r *jsonrpc2.Request) {
|
||||
switch r.Method {
|
||||
case "no_args":
|
||||
if r.Params != nil {
|
||||
c.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
|
||||
return
|
||||
}
|
||||
c.Reply(ctx, r, true, nil)
|
||||
case "one_string":
|
||||
var v string
|
||||
if err := json.Unmarshal(*r.Params, &v); err != nil {
|
||||
c.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err.Error()))
|
||||
return
|
||||
}
|
||||
c.Reply(ctx, r, "got:"+v, nil)
|
||||
case "one_number":
|
||||
var v int
|
||||
if err := json.Unmarshal(*r.Params, &v); err != nil {
|
||||
c.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err.Error()))
|
||||
return
|
||||
}
|
||||
c.Reply(ctx, r, fmt.Sprintf("got:%d", v), nil)
|
||||
case "join":
|
||||
var v []string
|
||||
if err := json.Unmarshal(*r.Params, &v); err != nil {
|
||||
c.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err.Error()))
|
||||
return
|
||||
}
|
||||
c.Reply(ctx, r, path.Join(v...), nil)
|
||||
default:
|
||||
c.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not found", r.Method))
|
||||
}
|
||||
}
|
59
vendor/golang.org/x/tools/internal/jsonrpc2/log.go
generated
vendored
59
vendor/golang.org/x/tools/internal/jsonrpc2/log.go
generated
vendored
@@ -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)
|
||||
}
|
||||
}
|
146
vendor/golang.org/x/tools/internal/jsonrpc2/stream.go
generated
vendored
146
vendor/golang.org/x/tools/internal/jsonrpc2/stream.go
generated
vendored
@@ -1,146 +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 (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Stream abstracts the transport mechanics from the JSON RPC protocol.
|
||||
// A Conn reads and writes messages using the stream it was provided on
|
||||
// construction, and assumes that each call to Read or Write fully transfers
|
||||
// a single message, or returns an error.
|
||||
type Stream interface {
|
||||
// Read gets the next message from the stream.
|
||||
// It is never called concurrently.
|
||||
Read(context.Context) ([]byte, error)
|
||||
// Write sends a message to the stream.
|
||||
// It must be safe for concurrent use.
|
||||
Write(context.Context, []byte) error
|
||||
}
|
||||
|
||||
// NewStream returns a Stream built on top of an io.Reader and io.Writer
|
||||
// The messages are sent with no wrapping, and rely on json decode consistency
|
||||
// to determine message boundaries.
|
||||
func NewStream(in io.Reader, out io.Writer) Stream {
|
||||
return &plainStream{
|
||||
in: json.NewDecoder(in),
|
||||
out: out,
|
||||
}
|
||||
}
|
||||
|
||||
type plainStream struct {
|
||||
in *json.Decoder
|
||||
outMu sync.Mutex
|
||||
out io.Writer
|
||||
}
|
||||
|
||||
func (s *plainStream) Read(ctx context.Context) ([]byte, error) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
}
|
||||
var raw json.RawMessage
|
||||
if err := s.in.Decode(&raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
func (s *plainStream) Write(ctx context.Context, data []byte) error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
s.outMu.Lock()
|
||||
_, err := s.out.Write(data)
|
||||
s.outMu.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
// NewHeaderStream returns a Stream built on top of an io.Reader and io.Writer
|
||||
// The messages are sent with HTTP content length and MIME type headers.
|
||||
// This is the format used by LSP and others.
|
||||
func NewHeaderStream(in io.Reader, out io.Writer) Stream {
|
||||
return &headerStream{
|
||||
in: bufio.NewReader(in),
|
||||
out: out,
|
||||
}
|
||||
}
|
||||
|
||||
type headerStream struct {
|
||||
in *bufio.Reader
|
||||
outMu sync.Mutex
|
||||
out io.Writer
|
||||
}
|
||||
|
||||
func (s *headerStream) Read(ctx context.Context) ([]byte, error) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
}
|
||||
var length int64
|
||||
// read the header, stop on the first empty line
|
||||
for {
|
||||
line, err := s.in.ReadString('\n')
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed reading header line %q", err)
|
||||
}
|
||||
line = strings.TrimSpace(line)
|
||||
// check we have a header line
|
||||
if line == "" {
|
||||
break
|
||||
}
|
||||
colon := strings.IndexRune(line, ':')
|
||||
if colon < 0 {
|
||||
return nil, fmt.Errorf("invalid header line %q", line)
|
||||
}
|
||||
name, value := line[:colon], strings.TrimSpace(line[colon+1:])
|
||||
switch name {
|
||||
case "Content-Length":
|
||||
if length, err = strconv.ParseInt(value, 10, 32); err != nil {
|
||||
return nil, fmt.Errorf("failed parsing Content-Length: %v", value)
|
||||
}
|
||||
if length <= 0 {
|
||||
return nil, fmt.Errorf("invalid Content-Length: %v", length)
|
||||
}
|
||||
default:
|
||||
// ignoring unknown headers
|
||||
}
|
||||
}
|
||||
if length == 0 {
|
||||
return nil, fmt.Errorf("missing Content-Length header")
|
||||
}
|
||||
data := make([]byte, length)
|
||||
if _, err := io.ReadFull(s.in, data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (s *headerStream) Write(ctx context.Context, data []byte) error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
s.outMu.Lock()
|
||||
_, err := fmt.Fprintf(s.out, "Content-Length: %v\r\n\r\n", len(data))
|
||||
if err == nil {
|
||||
_, err = s.out.Write(data)
|
||||
}
|
||||
s.outMu.Unlock()
|
||||
return err
|
||||
}
|
139
vendor/golang.org/x/tools/internal/jsonrpc2/wire.go
generated
vendored
139
vendor/golang.org/x/tools/internal/jsonrpc2/wire.go
generated
vendored
@@ -1,139 +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"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// this file contains the go forms of the wire specification
|
||||
// see http://www.jsonrpc.org/specification for details
|
||||
|
||||
const (
|
||||
// CodeUnknownError should be used for all non coded errors.
|
||||
CodeUnknownError = -32001
|
||||
// CodeParseError is used when invalid JSON was received by the server.
|
||||
CodeParseError = -32700
|
||||
//CodeInvalidRequest is used when the JSON sent is not a valid Request object.
|
||||
CodeInvalidRequest = -32600
|
||||
// CodeMethodNotFound should be returned by the handler when the method does
|
||||
// not exist / is not available.
|
||||
CodeMethodNotFound = -32601
|
||||
// CodeInvalidParams should be returned by the handler when method
|
||||
// parameter(s) were invalid.
|
||||
CodeInvalidParams = -32602
|
||||
// CodeInternalError is not currently returned but defined for completeness.
|
||||
CodeInternalError = -32603
|
||||
)
|
||||
|
||||
// Request is sent to a server to represent a Call or Notify operaton.
|
||||
type Request struct {
|
||||
// VersionTag is always encoded as the string "2.0"
|
||||
VersionTag VersionTag `json:"jsonrpc"`
|
||||
// Method is a string containing the method name to invoke.
|
||||
Method string `json:"method"`
|
||||
// Params is either a struct or an array with the parameters of the method.
|
||||
Params *json.RawMessage `json:"params,omitempty"`
|
||||
// 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 `json:"id,omitempty"`
|
||||
}
|
||||
|
||||
// Response is a reply to a Request.
|
||||
// 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
|
||||
// success or failure response.
|
||||
type Response struct {
|
||||
// VersionTag is always encoded as the string "2.0"
|
||||
VersionTag VersionTag `json:"jsonrpc"`
|
||||
// Result is the response value, and is required on success.
|
||||
Result *json.RawMessage `json:"result,omitempty"`
|
||||
// Error is a structured error response if the call fails.
|
||||
Error *Error `json:"error,omitempty"`
|
||||
// ID must be set and is the identifier of the Request this is a response to.
|
||||
ID *ID `json:"id,omitempty"`
|
||||
}
|
||||
|
||||
// Error represents a structured error in a Response.
|
||||
type Error struct {
|
||||
// Code is an error code indicating the type of failure.
|
||||
Code int64 `json:"code"`
|
||||
// Message is a short description of the error.
|
||||
Message string `json:"message"`
|
||||
// Data is optional structured data containing additional information about the error.
|
||||
Data *json.RawMessage `json:"data"`
|
||||
}
|
||||
|
||||
// VersionTag is a special 0 sized struct that encodes as the jsonrpc version
|
||||
// tag.
|
||||
// It will fail during decode if it is not the correct version tag in the
|
||||
// stream.
|
||||
type VersionTag struct{}
|
||||
|
||||
// ID is a Request identifier.
|
||||
// Only one of either the Name or Number members will be set, using the
|
||||
// number form if the Name is the empty string.
|
||||
type ID struct {
|
||||
Name string
|
||||
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 {
|
||||
if err == nil {
|
||||
return ""
|
||||
}
|
||||
return err.Message
|
||||
}
|
||||
|
||||
func (VersionTag) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal("2.0")
|
||||
}
|
||||
|
||||
func (VersionTag) UnmarshalJSON(data []byte) error {
|
||||
version := ""
|
||||
if err := json.Unmarshal(data, &version); err != nil {
|
||||
return err
|
||||
}
|
||||
if version != "2.0" {
|
||||
return fmt.Errorf("Invalid RPC version %v", version)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns a string representation of the ID.
|
||||
// The representation is non ambiguous, string forms are quoted, number forms
|
||||
// are preceded by a #
|
||||
func (id *ID) String() string {
|
||||
if id == nil {
|
||||
return ""
|
||||
}
|
||||
if id.Name != "" {
|
||||
return strconv.Quote(id.Name)
|
||||
}
|
||||
return "#" + strconv.FormatInt(id.Number, 10)
|
||||
}
|
||||
|
||||
func (id *ID) MarshalJSON() ([]byte, error) {
|
||||
if id.Name != "" {
|
||||
return json.Marshal(id.Name)
|
||||
}
|
||||
return json.Marshal(id.Number)
|
||||
}
|
||||
|
||||
func (id *ID) UnmarshalJSON(data []byte) error {
|
||||
*id = ID{}
|
||||
if err := json.Unmarshal(data, &id.Number); err == nil {
|
||||
return nil
|
||||
}
|
||||
return json.Unmarshal(data, &id.Name)
|
||||
}
|
53
vendor/golang.org/x/tools/internal/lsp/completion.go
generated
vendored
53
vendor/golang.org/x/tools/internal/lsp/completion.go
generated
vendored
@@ -1,53 +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 lsp
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"golang.org/x/tools/internal/lsp/protocol"
|
||||
"golang.org/x/tools/internal/lsp/source"
|
||||
)
|
||||
|
||||
func toProtocolCompletionItems(items []source.CompletionItem) []protocol.CompletionItem {
|
||||
var results []protocol.CompletionItem
|
||||
sort.Slice(items, func(i, j int) bool {
|
||||
return items[i].Score > items[j].Score
|
||||
})
|
||||
for _, item := range items {
|
||||
results = append(results, protocol.CompletionItem{
|
||||
Label: item.Label,
|
||||
Detail: item.Detail,
|
||||
Kind: float64(toProtocolCompletionItemKind(item.Kind)),
|
||||
})
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func toProtocolCompletionItemKind(kind source.CompletionItemKind) protocol.CompletionItemKind {
|
||||
switch kind {
|
||||
case source.InterfaceCompletionItem:
|
||||
return protocol.InterfaceCompletion
|
||||
case source.StructCompletionItem:
|
||||
return protocol.StructCompletion
|
||||
case source.TypeCompletionItem:
|
||||
return protocol.TypeParameterCompletion // ??
|
||||
case source.ConstantCompletionItem:
|
||||
return protocol.ConstantCompletion
|
||||
case source.FieldCompletionItem:
|
||||
return protocol.FieldCompletion
|
||||
case source.ParameterCompletionItem, source.VariableCompletionItem:
|
||||
return protocol.VariableCompletion
|
||||
case source.FunctionCompletionItem:
|
||||
return protocol.FunctionCompletion
|
||||
case source.MethodCompletionItem:
|
||||
return protocol.MethodCompletion
|
||||
case source.PackageCompletionItem:
|
||||
return protocol.ModuleCompletion // ??
|
||||
default:
|
||||
return protocol.TextCompletion
|
||||
}
|
||||
|
||||
}
|
38
vendor/golang.org/x/tools/internal/lsp/diagnostics.go
generated
vendored
38
vendor/golang.org/x/tools/internal/lsp/diagnostics.go
generated
vendored
@@ -1,38 +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 lsp
|
||||
|
||||
import (
|
||||
"golang.org/x/tools/internal/lsp/protocol"
|
||||
"golang.org/x/tools/internal/lsp/source"
|
||||
)
|
||||
|
||||
func toProtocolDiagnostics(v *source.View, diagnostics []source.Diagnostic) []protocol.Diagnostic {
|
||||
reports := []protocol.Diagnostic{}
|
||||
for _, diag := range diagnostics {
|
||||
tok := v.Config.Fset.File(diag.Range.Start)
|
||||
reports = append(reports, protocol.Diagnostic{
|
||||
Message: diag.Message,
|
||||
Range: toProtocolRange(tok, diag.Range),
|
||||
Severity: toProtocolSeverity(diag.Severity),
|
||||
Source: "LSP",
|
||||
})
|
||||
}
|
||||
return reports
|
||||
}
|
||||
|
||||
func toProtocolSeverity(severity source.DiagnosticSeverity) protocol.DiagnosticSeverity {
|
||||
switch severity {
|
||||
case source.SeverityError:
|
||||
return protocol.SeverityError
|
||||
case source.SeverityWarning:
|
||||
return protocol.SeverityWarning
|
||||
case source.SeverityHint:
|
||||
return protocol.SeverityHint
|
||||
case source.SeverityInformation:
|
||||
return protocol.SeverityInformation
|
||||
}
|
||||
return protocol.SeverityError // default
|
||||
}
|
314
vendor/golang.org/x/tools/internal/lsp/lsp_test.go
generated
vendored
314
vendor/golang.org/x/tools/internal/lsp/lsp_test.go
generated
vendored
@@ -1,314 +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 lsp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"go/token"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/tools/go/packages"
|
||||
"golang.org/x/tools/go/packages/packagestest"
|
||||
"golang.org/x/tools/internal/lsp/protocol"
|
||||
"golang.org/x/tools/internal/lsp/source"
|
||||
)
|
||||
|
||||
func TestLSP(t *testing.T) {
|
||||
packagestest.TestAll(t, testLSP)
|
||||
}
|
||||
|
||||
func testLSP(t *testing.T, exporter packagestest.Exporter) {
|
||||
const dir = "testdata"
|
||||
const expectedCompletionsCount = 4
|
||||
const expectedDiagnosticsCount = 9
|
||||
const expectedFormatCount = 3
|
||||
const expectedDefinitionsCount = 16
|
||||
|
||||
files := packagestest.MustCopyFileTree(dir)
|
||||
for fragment, operation := range files {
|
||||
if trimmed := strings.TrimSuffix(fragment, ".in"); trimmed != fragment {
|
||||
delete(files, fragment)
|
||||
files[trimmed] = operation
|
||||
}
|
||||
}
|
||||
modules := []packagestest.Module{
|
||||
{
|
||||
Name: "golang.org/x/tools/internal/lsp",
|
||||
Files: files,
|
||||
},
|
||||
}
|
||||
exported := packagestest.Export(t, exporter, modules)
|
||||
defer exported.Cleanup()
|
||||
|
||||
dirs := make(map[string]bool)
|
||||
|
||||
// collect results for certain tests
|
||||
expectedDiagnostics := make(diagnostics)
|
||||
completionItems := make(completionItems)
|
||||
expectedCompletions := make(completions)
|
||||
expectedFormat := make(formats)
|
||||
expectedDefinitions := make(definitions)
|
||||
|
||||
s := &server{
|
||||
view: source.NewView(),
|
||||
}
|
||||
// merge the config objects
|
||||
cfg := *exported.Config
|
||||
cfg.Fset = s.view.Config.Fset
|
||||
cfg.Mode = packages.LoadSyntax
|
||||
s.view.Config = &cfg
|
||||
|
||||
for _, module := range modules {
|
||||
for fragment := range module.Files {
|
||||
if !strings.HasSuffix(fragment, ".go") {
|
||||
continue
|
||||
}
|
||||
filename := exporter.Filename(exported, module.Name, fragment)
|
||||
expectedDiagnostics[filename] = []protocol.Diagnostic{}
|
||||
dirs[filepath.Dir(filename)] = true
|
||||
}
|
||||
}
|
||||
// Do a first pass to collect special markers
|
||||
if err := exported.Expect(map[string]interface{}{
|
||||
"item": func(name string, r packagestest.Range, _, _ string) {
|
||||
exported.Mark(name, r)
|
||||
},
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Collect any data that needs to be used by subsequent tests.
|
||||
if err := exported.Expect(map[string]interface{}{
|
||||
"diag": expectedDiagnostics.collect,
|
||||
"item": completionItems.collect,
|
||||
"complete": expectedCompletions.collect,
|
||||
"format": expectedFormat.collect,
|
||||
"godef": expectedDefinitions.collect,
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Run("Completion", func(t *testing.T) {
|
||||
t.Helper()
|
||||
if len(expectedCompletions) != expectedCompletionsCount {
|
||||
t.Errorf("got %v completions expected %v", len(expectedCompletions), expectedCompletionsCount)
|
||||
}
|
||||
expectedCompletions.test(t, exported, s, completionItems)
|
||||
})
|
||||
|
||||
t.Run("Diagnostics", func(t *testing.T) {
|
||||
t.Helper()
|
||||
diagnosticsCount := expectedDiagnostics.test(t, exported, s.view, dirs)
|
||||
if diagnosticsCount != expectedDiagnosticsCount {
|
||||
t.Errorf("got %v diagnostics expected %v", diagnosticsCount, expectedDiagnosticsCount)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Format", func(t *testing.T) {
|
||||
t.Helper()
|
||||
if len(expectedFormat) != expectedFormatCount {
|
||||
t.Errorf("got %v formats expected %v", len(expectedFormat), expectedFormatCount)
|
||||
}
|
||||
expectedFormat.test(t, s)
|
||||
})
|
||||
|
||||
t.Run("Definitions", func(t *testing.T) {
|
||||
t.Helper()
|
||||
if len(expectedDefinitions) != expectedDefinitionsCount {
|
||||
t.Errorf("got %v definitions expected %v", len(expectedDefinitions), expectedDefinitionsCount)
|
||||
}
|
||||
expectedDefinitions.test(t, s)
|
||||
})
|
||||
}
|
||||
|
||||
type diagnostics map[string][]protocol.Diagnostic
|
||||
type completionItems map[token.Pos]*protocol.CompletionItem
|
||||
type completions map[token.Position][]token.Pos
|
||||
type formats map[string]string
|
||||
type definitions map[protocol.Location]protocol.Location
|
||||
|
||||
func (c completions) test(t *testing.T, exported *packagestest.Exported, s *server, items completionItems) {
|
||||
for src, itemList := range c {
|
||||
var want []protocol.CompletionItem
|
||||
for _, pos := range itemList {
|
||||
want = append(want, *items[pos])
|
||||
}
|
||||
list, err := s.Completion(context.Background(), &protocol.CompletionParams{
|
||||
TextDocumentPositionParams: protocol.TextDocumentPositionParams{
|
||||
TextDocument: protocol.TextDocumentIdentifier{
|
||||
URI: protocol.DocumentURI(source.ToURI(src.Filename)),
|
||||
},
|
||||
Position: protocol.Position{
|
||||
Line: float64(src.Line - 1),
|
||||
Character: float64(src.Column - 1),
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got := list.Items
|
||||
if equal := reflect.DeepEqual(want, got); !equal {
|
||||
t.Errorf("completion failed for %s:%v:%v: (expected: %v), (got: %v)", filepath.Base(src.Filename), src.Line, src.Column, want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c completions) collect(src token.Position, expected []token.Pos) {
|
||||
c[src] = expected
|
||||
}
|
||||
|
||||
func (i completionItems) collect(pos token.Pos, label, detail, kind string) {
|
||||
var k protocol.CompletionItemKind
|
||||
switch kind {
|
||||
case "struct":
|
||||
k = protocol.StructCompletion
|
||||
case "func":
|
||||
k = protocol.FunctionCompletion
|
||||
case "var":
|
||||
k = protocol.VariableCompletion
|
||||
case "type":
|
||||
k = protocol.TypeParameterCompletion
|
||||
case "field":
|
||||
k = protocol.FieldCompletion
|
||||
case "interface":
|
||||
k = protocol.InterfaceCompletion
|
||||
case "const":
|
||||
k = protocol.ConstantCompletion
|
||||
case "method":
|
||||
k = protocol.MethodCompletion
|
||||
}
|
||||
i[pos] = &protocol.CompletionItem{
|
||||
Label: label,
|
||||
Detail: detail,
|
||||
Kind: float64(k),
|
||||
}
|
||||
}
|
||||
|
||||
func (d diagnostics) test(t *testing.T, exported *packagestest.Exported, v *source.View, dirs map[string]bool) int {
|
||||
// first trigger a load to get the diagnostics
|
||||
var dirList []string
|
||||
for dir := range dirs {
|
||||
dirList = append(dirList, dir)
|
||||
}
|
||||
exported.Config.Mode = packages.LoadFiles
|
||||
pkgs, err := packages.Load(exported.Config, dirList...)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// and now see if they match the expected ones
|
||||
count := 0
|
||||
for _, pkg := range pkgs {
|
||||
for _, filename := range pkg.GoFiles {
|
||||
f := v.GetFile(source.ToURI(filename))
|
||||
diagnostics, err := source.Diagnostics(context.Background(), v, f)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got := toProtocolDiagnostics(v, diagnostics[filename])
|
||||
sort.Slice(got, func(i int, j int) bool {
|
||||
return got[i].Range.Start.Line < got[j].Range.Start.Line
|
||||
})
|
||||
want := d[filename]
|
||||
if equal := reflect.DeepEqual(want, got); !equal {
|
||||
msg := &bytes.Buffer{}
|
||||
fmt.Fprintf(msg, "diagnostics failed for %s: expected:\n", filepath.Base(filename))
|
||||
for _, d := range want {
|
||||
fmt.Fprintf(msg, " %v\n", d)
|
||||
}
|
||||
fmt.Fprintf(msg, "got:\n")
|
||||
for _, d := range got {
|
||||
fmt.Fprintf(msg, " %v\n", d)
|
||||
}
|
||||
t.Error(msg.String())
|
||||
}
|
||||
count += len(want)
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func (d diagnostics) collect(pos token.Position, msg string) {
|
||||
line := float64(pos.Line - 1)
|
||||
col := float64(pos.Column - 1)
|
||||
want := protocol.Diagnostic{
|
||||
Range: protocol.Range{
|
||||
Start: protocol.Position{
|
||||
Line: line,
|
||||
Character: col,
|
||||
},
|
||||
End: protocol.Position{
|
||||
Line: line,
|
||||
Character: col,
|
||||
},
|
||||
},
|
||||
Severity: protocol.SeverityError,
|
||||
Source: "LSP",
|
||||
Message: msg,
|
||||
}
|
||||
d[pos.Filename] = append(d[pos.Filename], want)
|
||||
}
|
||||
|
||||
func (f formats) test(t *testing.T, s *server) {
|
||||
for filename, gofmted := range f {
|
||||
edits, err := s.Formatting(context.Background(), &protocol.DocumentFormattingParams{
|
||||
TextDocument: protocol.TextDocumentIdentifier{
|
||||
URI: protocol.DocumentURI(source.ToURI(filename)),
|
||||
},
|
||||
})
|
||||
if err != nil || len(edits) == 0 {
|
||||
if gofmted != "" {
|
||||
t.Error(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
edit := edits[0]
|
||||
if edit.NewText != gofmted {
|
||||
t.Errorf("formatting failed: (got: %s), (expected: %s)", edit.NewText, gofmted)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f formats) collect(pos token.Position) {
|
||||
cmd := exec.Command("gofmt", pos.Filename)
|
||||
stdout := bytes.NewBuffer(nil)
|
||||
cmd.Stdout = stdout
|
||||
cmd.Run() // ignore error, sometimes we have intentionally ungofmt-able files
|
||||
f[pos.Filename] = stdout.String()
|
||||
}
|
||||
|
||||
func (d definitions) test(t *testing.T, s *server) {
|
||||
for src, target := range d {
|
||||
locs, err := s.Definition(context.Background(), &protocol.TextDocumentPositionParams{
|
||||
TextDocument: protocol.TextDocumentIdentifier{
|
||||
URI: src.URI,
|
||||
},
|
||||
Position: src.Range.Start,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(locs) != 1 {
|
||||
t.Errorf("got %d locations for definition, expected 1", len(locs))
|
||||
}
|
||||
if locs[0] != target {
|
||||
t.Errorf("for %v got %v want %v", src, locs[0], target)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d definitions) collect(fset *token.FileSet, src, target packagestest.Range) {
|
||||
sRange := source.Range{Start: src.Start, End: src.End}
|
||||
sLoc := toProtocolLocation(fset, sRange)
|
||||
tRange := source.Range{Start: target.Start, End: target.End}
|
||||
tLoc := toProtocolLocation(fset, tRange)
|
||||
d[sLoc] = tLoc
|
||||
}
|
114
vendor/golang.org/x/tools/internal/lsp/position.go
generated
vendored
114
vendor/golang.org/x/tools/internal/lsp/position.go
generated
vendored
@@ -1,114 +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 lsp
|
||||
|
||||
import (
|
||||
"go/token"
|
||||
|
||||
"golang.org/x/tools/internal/lsp/protocol"
|
||||
"golang.org/x/tools/internal/lsp/source"
|
||||
)
|
||||
|
||||
// fromProtocolLocation converts from a protocol location to a source range.
|
||||
// It will return an error if the file of the location was not valid.
|
||||
// It uses fromProtocolRange to convert the start and end positions.
|
||||
func fromProtocolLocation(v *source.View, loc protocol.Location) (source.Range, error) {
|
||||
f := v.GetFile(source.URI(loc.URI))
|
||||
tok, err := f.GetToken()
|
||||
if err != nil {
|
||||
return source.Range{}, err
|
||||
}
|
||||
return fromProtocolRange(tok, loc.Range), nil
|
||||
}
|
||||
|
||||
// toProtocolLocation converts from a source range back to a protocol location.
|
||||
func toProtocolLocation(fset *token.FileSet, r source.Range) protocol.Location {
|
||||
tokFile := fset.File(r.Start)
|
||||
uri := source.ToURI(tokFile.Name())
|
||||
return protocol.Location{
|
||||
URI: protocol.DocumentURI(uri),
|
||||
Range: toProtocolRange(tokFile, r),
|
||||
}
|
||||
}
|
||||
|
||||
// fromProtocolRange converts a protocol range to a source range.
|
||||
// It uses fromProtocolPosition to convert the start and end positions, which
|
||||
// requires the token file the positions belongs to.
|
||||
func fromProtocolRange(f *token.File, r protocol.Range) source.Range {
|
||||
start := fromProtocolPosition(f, r.Start)
|
||||
var end token.Pos
|
||||
switch {
|
||||
case r.End == r.Start:
|
||||
end = start
|
||||
case r.End.Line < 0:
|
||||
end = token.NoPos
|
||||
default:
|
||||
end = fromProtocolPosition(f, r.End)
|
||||
}
|
||||
return source.Range{
|
||||
Start: start,
|
||||
End: end,
|
||||
}
|
||||
}
|
||||
|
||||
// toProtocolRange converts from a source range back to a protocol range.
|
||||
func toProtocolRange(f *token.File, r source.Range) protocol.Range {
|
||||
return protocol.Range{
|
||||
Start: toProtocolPosition(f, r.Start),
|
||||
End: toProtocolPosition(f, r.End),
|
||||
}
|
||||
}
|
||||
|
||||
// fromProtocolPosition converts a protocol position (0-based line and column
|
||||
// number) to a token.Pos (byte offset value).
|
||||
// It requires the token file the pos belongs to in order to do this.
|
||||
func fromProtocolPosition(f *token.File, pos protocol.Position) token.Pos {
|
||||
line := lineStart(f, int(pos.Line)+1)
|
||||
return line + token.Pos(pos.Character) // TODO: this is wrong, bytes not characters
|
||||
}
|
||||
|
||||
// toProtocolPosition converts from a token pos (byte offset) to a protocol
|
||||
// position (0-based line and column number)
|
||||
// It requires the token file the pos belongs to in order to do this.
|
||||
func toProtocolPosition(f *token.File, pos token.Pos) protocol.Position {
|
||||
if !pos.IsValid() {
|
||||
return protocol.Position{Line: -1.0, Character: -1.0}
|
||||
}
|
||||
p := f.Position(pos)
|
||||
return protocol.Position{
|
||||
Line: float64(p.Line - 1),
|
||||
Character: float64(p.Column - 1),
|
||||
}
|
||||
}
|
||||
|
||||
// this functionality was borrowed from the analysisutil package
|
||||
func lineStart(f *token.File, line int) token.Pos {
|
||||
// Use binary search to find the start offset of this line.
|
||||
//
|
||||
// TODO(adonovan): eventually replace this function with the
|
||||
// simpler and more efficient (*go/token.File).LineStart, added
|
||||
// in go1.12.
|
||||
|
||||
min := 0 // inclusive
|
||||
max := f.Size() // exclusive
|
||||
for {
|
||||
offset := (min + max) / 2
|
||||
pos := f.Pos(offset)
|
||||
posn := f.Position(pos)
|
||||
if posn.Line == line {
|
||||
return pos - (token.Pos(posn.Column) - 1)
|
||||
}
|
||||
|
||||
if min+1 >= max {
|
||||
return token.NoPos
|
||||
}
|
||||
|
||||
if posn.Line < line {
|
||||
min = offset
|
||||
} else {
|
||||
max = offset
|
||||
}
|
||||
}
|
||||
}
|
362
vendor/golang.org/x/tools/internal/lsp/protocol/basic.go
generated
vendored
362
vendor/golang.org/x/tools/internal/lsp/protocol/basic.go
generated
vendored
@@ -1,362 +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.
|
||||
|
||||
// This file contains the corresponding structures to the
|
||||
// "Basic JSON Structures" part of the LSP specification.
|
||||
|
||||
package protocol
|
||||
|
||||
const (
|
||||
// CodeRequestCancelled is the error code that is returned when a request is
|
||||
// cancelled early.
|
||||
CodeRequestCancelled = -32800
|
||||
)
|
||||
|
||||
// DocumentURI represents the URI of a document.
|
||||
// Many of the interfaces contain fields that correspond to the URI of a document.
|
||||
// For clarity, the type of such a field is declared as a DocumentURI.
|
||||
// Over the wire, it will still be transferred as a string, but this guarantees
|
||||
// that the contents of that string can be parsed as a valid URI.
|
||||
type DocumentURI string
|
||||
|
||||
// Position in a text document expressed as zero-based line and zero-based character offset.
|
||||
// A position is between two characters like an ‘insert’ cursor in a editor.
|
||||
type Position struct {
|
||||
/**
|
||||
* Line position in a document (zero-based).
|
||||
*/
|
||||
Line float64 `json:"line"`
|
||||
|
||||
/**
|
||||
* Character offset on a line in a document (zero-based). Assuming that the line is
|
||||
* represented as a string, the `character` value represents the gap between the
|
||||
* `character` and `character + 1`.
|
||||
*
|
||||
* If the character value is greater than the line length it defaults back to the
|
||||
* line length.
|
||||
*/
|
||||
Character float64 `json:"character"`
|
||||
}
|
||||
|
||||
// Range in a text document expressed as (zero-based) start and end positions.
|
||||
// A range is comparable to a selection in an editor.
|
||||
// Therefore the end position is exclusive.
|
||||
// If you want to specify a range that contains a line including the line
|
||||
// ending character(s) then use an end position denoting the start of the next
|
||||
// line.
|
||||
type Range struct {
|
||||
/**
|
||||
* The range's start position.
|
||||
*/
|
||||
Start Position `json:"start"`
|
||||
|
||||
/**
|
||||
* The range's end position.
|
||||
*/
|
||||
End Position `json:"end"`
|
||||
}
|
||||
|
||||
// Location represents a location inside a resource, such as a line inside a text file.
|
||||
type Location struct {
|
||||
URI DocumentURI `json:"uri"`
|
||||
Range Range `json:"range"`
|
||||
}
|
||||
|
||||
// Diagnostic represents a diagnostic, such as a compiler error or warning.
|
||||
// Diagnostic objects are only valid in the scope of a resource.
|
||||
type Diagnostic struct {
|
||||
/**
|
||||
* The range at which the message applies.
|
||||
*/
|
||||
Range Range `json:"range"`
|
||||
|
||||
/**
|
||||
* The diagnostic's severity. Can be omitted. If omitted it is up to the
|
||||
* client to interpret diagnostics as error, warning, info or hint.
|
||||
*/
|
||||
Severity DiagnosticSeverity `json:"severity,omitempty"`
|
||||
|
||||
/**
|
||||
* The diagnostic's code, which might appear in the user interface.
|
||||
*/
|
||||
Code string `json:"code,omitempty"` // number | string
|
||||
|
||||
/**
|
||||
* A human-readable string describing the source of this
|
||||
* diagnostic, e.g. 'typescript' or 'super lint'.
|
||||
*/
|
||||
Source string `json:"source,omitempty"`
|
||||
|
||||
/**
|
||||
* The diagnostic's message.
|
||||
*/
|
||||
Message string `json:"message"`
|
||||
|
||||
/**
|
||||
* An array of related diagnostic information, e.g. when symbol-names within
|
||||
* a scope collide all definitions can be marked via this property.
|
||||
*/
|
||||
Related []DiagnosticRelatedInformation `json:"relatedInformation,omitempty"`
|
||||
}
|
||||
|
||||
// DiagnosticSeverity indicates the severity of a Diagnostic message.
|
||||
type DiagnosticSeverity float64
|
||||
|
||||
const (
|
||||
/**
|
||||
* Reports an error.
|
||||
*/
|
||||
SeverityError DiagnosticSeverity = 1
|
||||
/**
|
||||
* Reports a warning.
|
||||
*/
|
||||
SeverityWarning DiagnosticSeverity = 2
|
||||
/**
|
||||
* Reports an information.
|
||||
*/
|
||||
SeverityInformation DiagnosticSeverity = 3
|
||||
/**
|
||||
* Reports a hint.
|
||||
*/
|
||||
SeverityHint DiagnosticSeverity = 4
|
||||
)
|
||||
|
||||
// DiagnosticRelatedInformation represents a related message and source code
|
||||
// location for a diagnostic.
|
||||
// This should be used to point to code locations that cause or related to a
|
||||
// diagnostics, e.g when duplicating a symbol in a scope.
|
||||
type DiagnosticRelatedInformation struct {
|
||||
/**
|
||||
* The location of this related diagnostic information.
|
||||
*/
|
||||
Location Location `json:"location"`
|
||||
|
||||
/**
|
||||
* The message of this related diagnostic information.
|
||||
*/
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// Command represents a reference to a command.
|
||||
// Provides a title which will be used to represent a command in the UI.
|
||||
// Commands are identified by a string identifier.
|
||||
// The protocol currently doesn’t specify a set of well-known commands.
|
||||
// So executing a command requires some tool extension code.
|
||||
type Command struct {
|
||||
/**
|
||||
* Title of the command, like `save`.
|
||||
*/
|
||||
Title string `json:"title"`
|
||||
|
||||
/**
|
||||
* The identifier of the actual command handler.
|
||||
*/
|
||||
Command string `json:"command"`
|
||||
|
||||
/**
|
||||
* Arguments that the command handler should be
|
||||
* invoked with.
|
||||
*/
|
||||
Arguments []interface{} `json:"arguments,omitempty"`
|
||||
}
|
||||
|
||||
// TextEdit is a textual edit applicable to a text document.
|
||||
type TextEdit struct {
|
||||
/**
|
||||
* The range of the text document to be manipulated. To insert
|
||||
* text into a document create a range where start === end.
|
||||
*/
|
||||
Range Range `json:"range"`
|
||||
|
||||
/**
|
||||
* The string to be inserted. For delete operations use an
|
||||
* empty string.
|
||||
*/
|
||||
NewText string `json:"newText"`
|
||||
}
|
||||
|
||||
// TextDocumentEdit describes textual changes on a single text document.
|
||||
// The text document is referred to as a VersionedTextDocumentIdentifier to
|
||||
// allow clients to check the text document version before an edit is applied.
|
||||
// A TextDocumentEdit describes all changes on a version Si and after they are
|
||||
// applied move the document to version Si+1.
|
||||
// So the creator of a TextDocumentEdit doesn’t need to sort the array or do
|
||||
// any kind of ordering.
|
||||
// However the edits must be non overlapping.
|
||||
type TextDocumentEdit struct {
|
||||
/**
|
||||
* The text document to change.
|
||||
*/
|
||||
TextDocument VersionedTextDocumentIdentifier `json:"textDocument"`
|
||||
|
||||
/**
|
||||
* The edits to be applied.
|
||||
*/
|
||||
Edits []TextEdit `json:"edits"`
|
||||
}
|
||||
|
||||
// WorkspaceEdit represents changes to many resources managed in the workspace.
|
||||
// The edit should either provide Changes or DocumentChanges.
|
||||
// If the client can handle versioned document edits and if DocumentChanges are
|
||||
// present, the latter are preferred over Changes.
|
||||
type WorkspaceEdit struct {
|
||||
/**
|
||||
* Holds changes to existing resources.
|
||||
*/
|
||||
Changes map[DocumentURI][]TextEdit `json:"changes,omitempty"`
|
||||
|
||||
/**
|
||||
* An array of `TextDocumentEdit`s to express changes to n different text documents
|
||||
* where each text document edit addresses a specific version of a text document.
|
||||
* Whether a client supports versioned document edits is expressed via
|
||||
* `WorkspaceClientCapabilities.workspaceEdit.documentChanges`.
|
||||
*/
|
||||
DocumentChanges []TextDocumentEdit `json:"documentChanges,omitempty"`
|
||||
}
|
||||
|
||||
// TextDocumentIdentifier identifies a document using a URI.
|
||||
// On the protocol level, URIs are passed as strings.
|
||||
// The corresponding JSON structure looks like this.
|
||||
type TextDocumentIdentifier struct {
|
||||
/**
|
||||
* The text document's URI.
|
||||
*/
|
||||
URI DocumentURI `json:"uri"`
|
||||
}
|
||||
|
||||
// TextDocumentItem is an item to transfer a text document from the client to
|
||||
// the server.
|
||||
type TextDocumentItem struct {
|
||||
/**
|
||||
* The text document's URI.
|
||||
*/
|
||||
URI DocumentURI `json:"uri"`
|
||||
|
||||
/**
|
||||
* The text document's language identifier.
|
||||
*/
|
||||
LanguageID string `json:"languageId"`
|
||||
|
||||
/**
|
||||
* The version number of this document (it will increase after each
|
||||
* change, including undo/redo).
|
||||
*/
|
||||
Version float64 `json:"version"`
|
||||
|
||||
/**
|
||||
* The content of the opened text document.
|
||||
*/
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
// VersionedTextDocumentIdentifier is an identifier to denote a specific version of a text document.
|
||||
type VersionedTextDocumentIdentifier struct {
|
||||
TextDocumentIdentifier
|
||||
|
||||
/**
|
||||
* The version number of this document. If a versioned text document identifier
|
||||
* is sent from the server to the client and the file is not open in the editor
|
||||
* (the server has not received an open notification before) the server can send
|
||||
* `null` to indicate that the version is known and the content on disk is the
|
||||
* truth (as speced with document content ownership)
|
||||
*/
|
||||
Version *uint64 `json:"version"`
|
||||
}
|
||||
|
||||
// TextDocumentPositionParams is a parameter literal used in requests to pass
|
||||
// a text document and a position inside that document.
|
||||
type TextDocumentPositionParams struct {
|
||||
/**
|
||||
* The text document.
|
||||
*/
|
||||
TextDocument TextDocumentIdentifier `json:"textDocument"`
|
||||
|
||||
/**
|
||||
* The position inside the text document.
|
||||
*/
|
||||
Position Position `json:"position"`
|
||||
}
|
||||
|
||||
// DocumentFilter is a document filter denotes a document through properties
|
||||
// like language, scheme or pattern.
|
||||
// An example is a filter that applies to TypeScript files on disk.
|
||||
// Another example is a filter the applies to JSON files with name package.json:
|
||||
// { language: 'typescript', scheme: 'file' }
|
||||
// { language: 'json', pattern: '**/package.json' }
|
||||
type DocumentFilter struct {
|
||||
/**
|
||||
* A language id, like `typescript`.
|
||||
*/
|
||||
Language string `json:"language,omitempty"`
|
||||
|
||||
/**
|
||||
* A URI [scheme](#URI.scheme), like `file` or `untitled`.
|
||||
*/
|
||||
Scheme string `json:"scheme,omitempty"`
|
||||
|
||||
/**
|
||||
* A glob pattern, like `*.{ts,js}`.
|
||||
*/
|
||||
Pattern string `json:"pattern,omitempty"`
|
||||
}
|
||||
|
||||
// A document selector is the combination of one or more document filters.
|
||||
type DocumentSelector []DocumentFilter
|
||||
|
||||
/**
|
||||
* Describes the content type that a client supports in various
|
||||
* result literals like `Hover`, `ParameterInfo` or `CompletionItem`.
|
||||
*
|
||||
* Please note that `MarkupKinds` must not start with a `$`. This kinds
|
||||
* are reserved for internal usage.
|
||||
*/
|
||||
type MarkupKind string
|
||||
|
||||
const (
|
||||
/**
|
||||
* Plain text is supported as a content format
|
||||
*/
|
||||
PlainText MarkupKind = "plaintext"
|
||||
|
||||
/**
|
||||
* Markdown is supported as a content format
|
||||
*/
|
||||
Markdown MarkupKind = "markdown"
|
||||
)
|
||||
|
||||
/**
|
||||
* A `MarkupContent` literal represents a string value which content is interpreted base on its
|
||||
* kind flag. Currently the protocol supports `plaintext` and `markdown` as markup kinds.
|
||||
*
|
||||
* If the kind is `markdown` then the value can contain fenced code blocks like in GitHub issues.
|
||||
* See https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting
|
||||
*
|
||||
* Here is an example how such a string can be constructed using JavaScript / TypeScript:
|
||||
* ```ts
|
||||
* let markdown: MarkdownContent = {
|
||||
* kind: MarkupKind.Markdown,
|
||||
* value: [
|
||||
* '# Header',
|
||||
* 'Some text',
|
||||
* '```typescript',
|
||||
* 'someCode();',
|
||||
* '```'
|
||||
* ].join('\n')
|
||||
* };
|
||||
* ```
|
||||
*
|
||||
* *Please Note* that clients might sanitize the return markdown. A client could decide to
|
||||
* remove HTML from the markdown to avoid script execution.
|
||||
*/
|
||||
type MarkupContent struct {
|
||||
/**
|
||||
* The type of the Markup
|
||||
*/
|
||||
Kind MarkupKind `json:"kind"`
|
||||
|
||||
/**
|
||||
* The content itself
|
||||
*/
|
||||
Value string `json:"value"`
|
||||
}
|
187
vendor/golang.org/x/tools/internal/lsp/protocol/client.go
generated
vendored
187
vendor/golang.org/x/tools/internal/lsp/protocol/client.go
generated
vendored
@@ -1,187 +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 protocol
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"golang.org/x/tools/internal/jsonrpc2"
|
||||
)
|
||||
|
||||
type Client interface {
|
||||
ShowMessage(context.Context, *ShowMessageParams) error
|
||||
ShowMessageRequest(context.Context, *ShowMessageRequestParams) (*MessageActionItem, error)
|
||||
LogMessage(context.Context, *LogMessageParams) error
|
||||
Telemetry(context.Context, interface{}) error
|
||||
RegisterCapability(context.Context, *RegistrationParams) error
|
||||
UnregisterCapability(context.Context, *UnregistrationParams) error
|
||||
WorkspaceFolders(context.Context) ([]WorkspaceFolder, error)
|
||||
Configuration(context.Context, *ConfigurationParams) ([]interface{}, error)
|
||||
ApplyEdit(context.Context, *ApplyWorkspaceEditParams) (bool, error)
|
||||
PublishDiagnostics(context.Context, *PublishDiagnosticsParams) error
|
||||
}
|
||||
|
||||
func clientHandler(client Client) jsonrpc2.Handler {
|
||||
return func(ctx context.Context, conn *jsonrpc2.Conn, r *jsonrpc2.Request) {
|
||||
switch r.Method {
|
||||
case "$/cancelRequest":
|
||||
var params CancelParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
conn.Cancel(params.ID)
|
||||
|
||||
case "window/showMessage":
|
||||
var params ShowMessageParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
unhandledError(client.ShowMessage(ctx, ¶ms))
|
||||
|
||||
case "window/showMessageRequest":
|
||||
var params ShowMessageRequestParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := client.ShowMessageRequest(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "window/logMessage":
|
||||
var params LogMessageParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
unhandledError(client.LogMessage(ctx, ¶ms))
|
||||
|
||||
case "telemetry/event":
|
||||
var params interface{}
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
unhandledError(client.Telemetry(ctx, ¶ms))
|
||||
|
||||
case "client/registerCapability":
|
||||
var params RegistrationParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
unhandledError(client.RegisterCapability(ctx, ¶ms))
|
||||
|
||||
case "client/unregisterCapability":
|
||||
var params UnregistrationParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
unhandledError(client.UnregisterCapability(ctx, ¶ms))
|
||||
|
||||
case "workspace/workspaceFolders":
|
||||
if r.Params != nil {
|
||||
conn.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
|
||||
return
|
||||
}
|
||||
resp, err := client.WorkspaceFolders(ctx)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "workspace/configuration":
|
||||
var params ConfigurationParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := client.Configuration(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "workspace/applyEdit":
|
||||
var params ApplyWorkspaceEditParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := client.ApplyEdit(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/publishDiagnostics":
|
||||
var params PublishDiagnosticsParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
unhandledError(client.PublishDiagnostics(ctx, ¶ms))
|
||||
|
||||
default:
|
||||
if r.IsNotify() {
|
||||
conn.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not found", r.Method))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type clientDispatcher struct {
|
||||
*jsonrpc2.Conn
|
||||
}
|
||||
|
||||
func (c *clientDispatcher) ShowMessage(ctx context.Context, params *ShowMessageParams) error {
|
||||
return c.Conn.Notify(ctx, "window/showMessage", params)
|
||||
}
|
||||
|
||||
func (c *clientDispatcher) ShowMessageRequest(ctx context.Context, params *ShowMessageRequestParams) (*MessageActionItem, error) {
|
||||
var result MessageActionItem
|
||||
if err := c.Conn.Call(ctx, "window/showMessageRequest", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (c *clientDispatcher) LogMessage(ctx context.Context, params *LogMessageParams) error {
|
||||
return c.Conn.Notify(ctx, "window/logMessage", params)
|
||||
}
|
||||
|
||||
func (c *clientDispatcher) Telemetry(ctx context.Context, params interface{}) error {
|
||||
return c.Conn.Notify(ctx, "telemetry/event", params)
|
||||
}
|
||||
|
||||
func (c *clientDispatcher) RegisterCapability(ctx context.Context, params *RegistrationParams) error {
|
||||
return c.Conn.Notify(ctx, "client/registerCapability", params)
|
||||
}
|
||||
|
||||
func (c *clientDispatcher) UnregisterCapability(ctx context.Context, params *UnregistrationParams) error {
|
||||
return c.Conn.Notify(ctx, "client/unregisterCapability", params)
|
||||
}
|
||||
|
||||
func (c *clientDispatcher) WorkspaceFolders(ctx context.Context) ([]WorkspaceFolder, error) {
|
||||
var result []WorkspaceFolder
|
||||
if err := c.Conn.Call(ctx, "workspace/workspaceFolders", nil, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *clientDispatcher) Configuration(ctx context.Context, params *ConfigurationParams) ([]interface{}, error) {
|
||||
var result []interface{}
|
||||
if err := c.Conn.Call(ctx, "workspace/configuration", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *clientDispatcher) ApplyEdit(ctx context.Context, params *ApplyWorkspaceEditParams) (bool, error) {
|
||||
var result bool
|
||||
if err := c.Conn.Call(ctx, "workspace/applyEdit", params, &result); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *clientDispatcher) PublishDiagnostics(ctx context.Context, params *PublishDiagnosticsParams) error {
|
||||
return c.Conn.Notify(ctx, "textDocument/publishDiagnostics", params)
|
||||
}
|
20
vendor/golang.org/x/tools/internal/lsp/protocol/diagnostics.go
generated
vendored
20
vendor/golang.org/x/tools/internal/lsp/protocol/diagnostics.go
generated
vendored
@@ -1,20 +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.
|
||||
|
||||
// This file contains the corresponding structures to the
|
||||
// "Diagnostics" part of the LSP specification.
|
||||
|
||||
package protocol
|
||||
|
||||
type PublishDiagnosticsParams struct {
|
||||
/**
|
||||
* The URI for which diagnostic information is reported.
|
||||
*/
|
||||
URI DocumentURI `json:"uri"`
|
||||
|
||||
/**
|
||||
* An array of diagnostic information items.
|
||||
*/
|
||||
Diagnostics []Diagnostic `json:"diagnostics"`
|
||||
}
|
16
vendor/golang.org/x/tools/internal/lsp/protocol/doc.go
generated
vendored
16
vendor/golang.org/x/tools/internal/lsp/protocol/doc.go
generated
vendored
@@ -1,16 +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 protocol contains the structs that map directly to the wire format
|
||||
// of the "Language Server Protocol".
|
||||
//
|
||||
// It is a literal transcription, with unmodified comments, and only the changes
|
||||
// required to make it go code.
|
||||
// Names are uppercased to export them.
|
||||
// All fields have JSON tags added to correct the names.
|
||||
// Fields marked with a ? are also marked as "omitempty"
|
||||
// Fields that are "|| null" are made pointers
|
||||
// Fields that are string or number are left as string
|
||||
// Fields that are type "number" are made float64
|
||||
package protocol
|
849
vendor/golang.org/x/tools/internal/lsp/protocol/general.go
generated
vendored
849
vendor/golang.org/x/tools/internal/lsp/protocol/general.go
generated
vendored
@@ -1,849 +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.
|
||||
|
||||
// This file contains the corresponding structures to the
|
||||
// "General" messages part of the LSP specification.
|
||||
|
||||
package protocol
|
||||
|
||||
import "golang.org/x/tools/internal/jsonrpc2"
|
||||
|
||||
type CancelParams struct {
|
||||
/**
|
||||
* The request id to cancel.
|
||||
*/
|
||||
ID jsonrpc2.ID `json:"id"`
|
||||
}
|
||||
|
||||
type InitializeParams struct {
|
||||
/**
|
||||
* The process Id of the parent process that started
|
||||
* the server. Is null if the process has not been started by another process.
|
||||
* If the parent process is not alive then the server should exit (see exit notification) its process.
|
||||
*/
|
||||
ProcessID *float64 `json:"processId"`
|
||||
|
||||
/**
|
||||
* The rootPath of the workspace. Is null
|
||||
* if no folder is open.
|
||||
*
|
||||
* @deprecated in favour of rootURI.
|
||||
*/
|
||||
RootPath *string `json:"rootPath"`
|
||||
|
||||
/**
|
||||
* The rootURI of the workspace. Is null if no
|
||||
* folder is open. If both `rootPath` and `rootURI` are set
|
||||
* `rootURI` wins.
|
||||
*/
|
||||
RootURI *DocumentURI `json:"rootURI"`
|
||||
|
||||
/**
|
||||
* User provided initialization options.
|
||||
*/
|
||||
InitializationOptions interface{} `json:"initializationOptions"`
|
||||
|
||||
/**
|
||||
* The capabilities provided by the client (editor or tool)
|
||||
*/
|
||||
Capabilities ClientCapabilities `json:"capabilities"`
|
||||
|
||||
/**
|
||||
* The initial trace setting. If omitted trace is disabled ('off').
|
||||
*/
|
||||
Trace string `json:"trace"` // 'off' | 'messages' | 'verbose'
|
||||
|
||||
/**
|
||||
* The workspace folders configured in the client when the server starts.
|
||||
* This property is only available if the client supports workspace folders.
|
||||
* It can be `null` if the client supports workspace folders but none are
|
||||
* configured.
|
||||
*
|
||||
* Since 3.6.0
|
||||
*/
|
||||
WorkspaceFolders []WorkspaceFolder `json:"workspaceFolders,omitempty"`
|
||||
}
|
||||
|
||||
/**
|
||||
* Workspace specific client capabilities.
|
||||
*/
|
||||
type WorkspaceClientCapabilities struct {
|
||||
/**
|
||||
* The client supports applying batch edits to the workspace by supporting
|
||||
* the request 'workspace/applyEdit'
|
||||
*/
|
||||
ApplyEdit bool `json:"applyEdit,omitempty"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to `WorkspaceEdit`s
|
||||
*/
|
||||
WorkspaceEdit struct {
|
||||
/**
|
||||
* The client supports versioned document changes in `WorkspaceEdit`s
|
||||
*/
|
||||
DocumentChanges bool `json:"documentChanges,omitempty"`
|
||||
} `json:"workspaceEdit,omitempty"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to the `workspace/didChangeConfiguration` notification.
|
||||
*/
|
||||
DidChangeConfiguration struct {
|
||||
/**
|
||||
* Did change configuration notification supports dynamic registration.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
} `json:"didChangeConfiguration,omitempty"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to the `workspace/didChangeWatchedFiles` notification.
|
||||
*/
|
||||
DidChangeWatchedFiles struct {
|
||||
/**
|
||||
* Did change watched files notification supports dynamic registration.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
} `json:"didChangeWatchedFiles,omitempty"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to the `workspace/symbol` request.
|
||||
*/
|
||||
Symbol struct {
|
||||
/**
|
||||
* Symbol request supports dynamic registration.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
|
||||
/**
|
||||
* Specific capabilities for the `SymbolKind` in the `workspace/symbol` request.
|
||||
*/
|
||||
SymbolKind struct {
|
||||
/**
|
||||
* The symbol kind values the client supports. When this
|
||||
* property exists the client also guarantees that it will
|
||||
* handle values outside its set gracefully and falls back
|
||||
* to a default value when unknown.
|
||||
*
|
||||
* If this property is not present the client only supports
|
||||
* the symbol kinds from `File` to `Array` as defined in
|
||||
* the initial version of the protocol.
|
||||
*/
|
||||
ValueSet []SymbolKind `json:"valueSet,omitempty"`
|
||||
} `json:"symbolKind,omitempty"`
|
||||
} `json:"symbol,omitempty"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to the `workspace/executeCommand` request.
|
||||
*/
|
||||
ExecuteCommand struct {
|
||||
/**
|
||||
* Execute command supports dynamic registration.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
} `json:"executeCommand,omitempty"`
|
||||
|
||||
/**
|
||||
* The client has support for workspace folders.
|
||||
*
|
||||
* Since 3.6.0
|
||||
*/
|
||||
WorkspaceFolders bool `json:"workspaceFolders,omitempty"`
|
||||
|
||||
/**
|
||||
* The client supports `workspace/configuration` requests.
|
||||
*
|
||||
* Since 3.6.0
|
||||
*/
|
||||
Configuration bool `json:"configuration,omitempty"`
|
||||
}
|
||||
|
||||
/**
|
||||
* Text document specific client capabilities.
|
||||
*/
|
||||
type TextDocumentClientCapabilities struct {
|
||||
Synchronization struct {
|
||||
/**
|
||||
* Whether text document synchronization supports dynamic registration.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
|
||||
/**
|
||||
* The client supports sending will save notifications.
|
||||
*/
|
||||
WillSave bool `json:"willSave,omitempty"`
|
||||
|
||||
/**
|
||||
* The client supports sending a will save request and
|
||||
* waits for a response providing text edits which will
|
||||
* be applied to the document before it is saved.
|
||||
*/
|
||||
WillSaveWaitUntil bool `json:"willSaveWaitUntil,omitempty"`
|
||||
|
||||
/**
|
||||
* The client supports did save notifications.
|
||||
*/
|
||||
DidSave bool `json:"didSave,omitempty"`
|
||||
} `json:"synchronization,omitempty"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to the `textDocument/completion`
|
||||
*/
|
||||
Completion struct {
|
||||
/**
|
||||
* Whether completion supports dynamic registration.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
|
||||
/**
|
||||
* The client supports the following `CompletionItem` specific
|
||||
* capabilities.
|
||||
*/
|
||||
CompletionItem struct {
|
||||
/**
|
||||
* Client supports snippets as insert text.
|
||||
*
|
||||
* A snippet can define tab stops and placeholders with `$1`, `$2`
|
||||
* and `${3:foo}`. `$0` defines the final tab stop, it defaults to
|
||||
* the end of the snippet. Placeholders with equal identifiers are linked,
|
||||
* that is typing in one will update others too.
|
||||
*/
|
||||
SnippetSupport bool `json:"snippetSupport,omitempty"`
|
||||
|
||||
/**
|
||||
* Client supports commit characters on a completion item.
|
||||
*/
|
||||
CommitCharactersSupport bool `json:"commitCharactersSupport,omitempty"`
|
||||
|
||||
/**
|
||||
* Client supports the follow content formats for the documentation
|
||||
* property. The order describes the preferred format of the client.
|
||||
*/
|
||||
DocumentationFormat []MarkupKind `json:"documentationFormat,omitempty"`
|
||||
|
||||
/**
|
||||
* Client supports the deprecated property on a completion item.
|
||||
*/
|
||||
DeprecatedSupport bool `json:"deprecatedSupport,omitempty"`
|
||||
|
||||
/**
|
||||
* Client supports the preselect property on a completion item.
|
||||
*/
|
||||
PreselectSupport bool `json:"preselectSupport,omitempty"`
|
||||
} `json:"completionItem,omitempty"`
|
||||
|
||||
CompletionItemKind struct {
|
||||
/**
|
||||
* The completion item kind values the client supports. When this
|
||||
* property exists the client also guarantees that it will
|
||||
* handle values outside its set gracefully and falls back
|
||||
* to a default value when unknown.
|
||||
*
|
||||
* If this property is not present the client only supports
|
||||
* the completion items kinds from `Text` to `Reference` as defined in
|
||||
* the initial version of the protocol.
|
||||
*/
|
||||
ValueSet []CompletionItemKind `json:"valueSet,omitempty"`
|
||||
} `json:"completionItemKind,omitempty"`
|
||||
|
||||
/**
|
||||
* The client supports to send additional context information for a
|
||||
* `textDocument/completion` request.
|
||||
*/
|
||||
ContextSupport bool `json:"contextSupport,omitempty"`
|
||||
} `json:"completion"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to the `textDocument/hover`
|
||||
*/
|
||||
Hover struct {
|
||||
/**
|
||||
* Whether hover supports dynamic registration.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
|
||||
/**
|
||||
* Client supports the follow content formats for the content
|
||||
* property. The order describes the preferred format of the client.
|
||||
*/
|
||||
ContentFormat []MarkupKind `json:"contentFormat,omitempty"`
|
||||
} `json:"hover,omitempty"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to the `textDocument/signatureHelp`
|
||||
*/
|
||||
SignatureHelp struct {
|
||||
/**
|
||||
* Whether signature help supports dynamic registration.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
|
||||
/**
|
||||
* The client supports the following `SignatureInformation`
|
||||
* specific properties.
|
||||
*/
|
||||
SignatureInformation struct {
|
||||
/**
|
||||
* Client supports the follow content formats for the documentation
|
||||
* property. The order describes the preferred format of the client.
|
||||
*/
|
||||
DocumentationFormat []MarkupKind `json:"documentationFormat,omitempty"`
|
||||
} `json:"signatureInformation,omitempty"`
|
||||
} `json:"signatureHelp,omitempty"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to the `textDocument/references`
|
||||
*/
|
||||
References struct {
|
||||
/**
|
||||
* Whether references supports dynamic registration.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
} `json:"references,omitempty"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to the `textDocument/documentHighlight`
|
||||
*/
|
||||
DocumentHighlight struct {
|
||||
/**
|
||||
* Whether document highlight supports dynamic registration.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
} `json:"documentHighlight,omitempty"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to the `textDocument/documentSymbol`
|
||||
*/
|
||||
DocumentSymbol struct {
|
||||
/**
|
||||
* Whether document symbol supports dynamic registration.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
|
||||
/**
|
||||
* Specific capabilities for the `SymbolKind`.
|
||||
*/
|
||||
SymbolKind struct {
|
||||
/**
|
||||
* The symbol kind values the client supports. When this
|
||||
* property exists the client also guarantees that it will
|
||||
* handle values outside its set gracefully and falls back
|
||||
* to a default value when unknown.
|
||||
*
|
||||
* If this property is not present the client only supports
|
||||
* the symbol kinds from `File` to `Array` as defined in
|
||||
* the initial version of the protocol.
|
||||
*/
|
||||
ValueSet []SymbolKind `json:"valueSet,omitempty"`
|
||||
} `json:"symbolKind,omitempty"`
|
||||
|
||||
/**
|
||||
* The client support hierarchical document symbols.
|
||||
*/
|
||||
HierarchicalDocumentSymbolSupport bool `json:"hierarchicalDocumentSymbolSupport,omitempty"`
|
||||
} `json:"documentSymbol,omitempty"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to the `textDocument/formatting`
|
||||
*/
|
||||
Formatting struct {
|
||||
/**
|
||||
* Whether formatting supports dynamic registration.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
} `json:"formatting,omitempty"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to the `textDocument/rangeFormatting`
|
||||
*/
|
||||
RangeFormatting struct {
|
||||
/**
|
||||
* Whether range formatting supports dynamic registration.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
} `json:"rangeFormatting,omitempty"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to the `textDocument/onTypeFormatting`
|
||||
*/
|
||||
OnTypeFormatting struct {
|
||||
/**
|
||||
* Whether on type formatting supports dynamic registration.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
} `json:"onTypeFormatting,omitempty"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to the `textDocument/definition`
|
||||
*/
|
||||
Definition struct {
|
||||
/**
|
||||
* Whether definition supports dynamic registration.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
} `json:"definition,omitempty"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to the `textDocument/typeDefinition`
|
||||
*
|
||||
* Since 3.6.0
|
||||
*/
|
||||
TypeDefinition struct {
|
||||
/**
|
||||
* Whether typeDefinition supports dynamic registration. If this is set to `true`
|
||||
* the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
|
||||
* return value for the corresponding server capability as well.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
} `json:"typeDefinition,omitempty"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to the `textDocument/implementation`.
|
||||
*
|
||||
* Since 3.6.0
|
||||
*/
|
||||
Implementation struct {
|
||||
/**
|
||||
* Whether implementation supports dynamic registration. If this is set to `true`
|
||||
* the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
|
||||
* return value for the corresponding server capability as well.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
} `json:"implementation,omitempty"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to the `textDocument/codeAction`
|
||||
*/
|
||||
CodeAction struct {
|
||||
/**
|
||||
* Whether code action supports dynamic registration.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
/**
|
||||
* The client support code action literals as a valid
|
||||
* response of the `textDocument/codeAction` request.
|
||||
*
|
||||
* Since 3.8.0
|
||||
*/
|
||||
CodeActionLiteralSupport struct {
|
||||
/**
|
||||
* The code action kind is support with the following value
|
||||
* set.
|
||||
*/
|
||||
CodeActionKind struct {
|
||||
|
||||
/**
|
||||
* The code action kind values the client supports. When this
|
||||
* property exists the client also guarantees that it will
|
||||
* handle values outside its set gracefully and falls back
|
||||
* to a default value when unknown.
|
||||
*/
|
||||
ValueSet []CodeActionKind `json:"valueSet"`
|
||||
} `json:"codeActionKind"`
|
||||
} `json:"codeActionLiteralSupport,omitempty"`
|
||||
} `json:"codeAction,omitempty"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to the `textDocument/codeLens`
|
||||
*/
|
||||
CodeLens struct {
|
||||
/**
|
||||
* Whether code lens supports dynamic registration.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
} `json:"codeLens,omitempty"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to the `textDocument/documentLink`
|
||||
*/
|
||||
DocumentLink struct {
|
||||
/**
|
||||
* Whether document link supports dynamic registration.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
} `json:"documentLink,omitempty"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to the `textDocument/documentColor` and the
|
||||
* `textDocument/colorPresentation` request.
|
||||
*
|
||||
* Since 3.6.0
|
||||
*/
|
||||
ColorProvider struct {
|
||||
/**
|
||||
* Whether colorProvider supports dynamic registration. If this is set to `true`
|
||||
* the client supports the new `(ColorProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)`
|
||||
* return value for the corresponding server capability as well.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
} `json:"colorProvider,omitempty"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to the `textDocument/rename`
|
||||
*/
|
||||
Rename struct {
|
||||
/**
|
||||
* Whether rename supports dynamic registration.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
} `json:"rename,omitempty"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to `textDocument/publishDiagnostics`.
|
||||
*/
|
||||
PublishDiagnostics struct {
|
||||
/**
|
||||
* Whether the clients accepts diagnostics with related information.
|
||||
*/
|
||||
RelatedInformation bool `json:"relatedInformation,omitempty"`
|
||||
} `json:"publishDiagnostics,omitempty"`
|
||||
|
||||
/**
|
||||
* Capabilities specific to `textDocument/foldingRange` requests.
|
||||
*
|
||||
* Since 3.10.0
|
||||
*/
|
||||
FoldingRange struct {
|
||||
/**
|
||||
* Whether implementation supports dynamic registration for folding range providers. If this is set to `true`
|
||||
* the client supports the new `(FoldingRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)`
|
||||
* return value for the corresponding server capability as well.
|
||||
*/
|
||||
DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
|
||||
/**
|
||||
* The maximum number of folding ranges that the client prefers to receive per document. The value serves as a
|
||||
* hint, servers are free to follow the limit.
|
||||
*/
|
||||
RangeLimit float64 `json:"rangeLimit,omitempty"`
|
||||
/**
|
||||
* If set, the client signals that it only supports folding complete lines. If set, client will
|
||||
* ignore specified `startCharacter` and `endCharacter` properties in a FoldingRange.
|
||||
*/
|
||||
LineFoldingOnly bool `json:"lineFoldingOnly,omitempty"`
|
||||
}
|
||||
}
|
||||
|
||||
// ClientCapabilities now define capabilities for dynamic registration, workspace
|
||||
// and text document features the client supports. The experimental can be used to
|
||||
// pass experimental capabilities under development. For future compatibility a
|
||||
// ClientCapabilities object literal can have more properties set than currently
|
||||
// defined. Servers receiving a ClientCapabilities object literal with unknown
|
||||
// properties should ignore these properties. A missing property should be
|
||||
// interpreted as an absence of the capability. If a property is missing that
|
||||
// defines sub properties all sub properties should be interpreted as an absence
|
||||
// of the capability.
|
||||
//
|
||||
// Client capabilities got introduced with version 3.0 of the protocol. They
|
||||
// therefore only describe capabilities that got introduced in 3.x or later.
|
||||
// Capabilities that existed in the 2.x version of the protocol are still
|
||||
// mandatory for clients. Clients cannot opt out of providing them. So even if a
|
||||
// client omits the ClientCapabilities.textDocument.synchronization it is still
|
||||
// required that the client provides text document synchronization (e.g. open,
|
||||
// changed and close notifications).
|
||||
type ClientCapabilities struct {
|
||||
/**
|
||||
* Workspace specific client capabilities.
|
||||
*/
|
||||
Workspace WorkspaceClientCapabilities `json:"workspace,omitempty"`
|
||||
|
||||
/**
|
||||
* Text document specific client capabilities.
|
||||
*/
|
||||
TextDocument TextDocumentClientCapabilities `json:"textDocument,omitempty"`
|
||||
|
||||
/**
|
||||
* Experimental client capabilities.
|
||||
*/
|
||||
Experimental interface{} `json:"experimental,omitempty"`
|
||||
}
|
||||
|
||||
type InitializeResult struct {
|
||||
/**
|
||||
* The capabilities the language server provides.
|
||||
*/
|
||||
Capabilities ServerCapabilities `json:"capabilities"`
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines how the host (editor) should sync document changes to the language server.
|
||||
*/
|
||||
type TextDocumentSyncKind float64
|
||||
|
||||
const (
|
||||
/**
|
||||
* Documents should not be synced at all.
|
||||
*/
|
||||
None TextDocumentSyncKind = 0
|
||||
|
||||
/**
|
||||
* Documents are synced by always sending the full content
|
||||
* of the document.
|
||||
*/
|
||||
Full TextDocumentSyncKind = 1
|
||||
|
||||
/**
|
||||
* Documents are synced by sending the full content on open.
|
||||
* After that only incremental updates to the document are
|
||||
* send.
|
||||
*/
|
||||
Incremental TextDocumentSyncKind = 2
|
||||
)
|
||||
|
||||
/**
|
||||
* Completion options.
|
||||
*/
|
||||
type CompletionOptions struct {
|
||||
/**
|
||||
* The server provides support to resolve additional
|
||||
* information for a completion item.
|
||||
*/
|
||||
ResolveProvider bool `json:"resolveProvider,omitempty"`
|
||||
|
||||
/**
|
||||
* The characters that trigger completion automatically.
|
||||
*/
|
||||
TriggerCharacters []string `json:"triggerCharacters,omitempty"`
|
||||
}
|
||||
|
||||
/**
|
||||
* Signature help options.
|
||||
*/
|
||||
type SignatureHelpOptions struct {
|
||||
/**
|
||||
* The characters that trigger signature help
|
||||
* automatically.
|
||||
*/
|
||||
TriggerCharacters []string `json:"triggerCharacters,omitempty"`
|
||||
}
|
||||
|
||||
/**
|
||||
* Code Lens options.
|
||||
*/
|
||||
type CodeLensOptions struct {
|
||||
/**
|
||||
* Code lens has a resolve provider as well.
|
||||
*/
|
||||
ResolveProvider bool `json:"resolveProvider,omitempty"`
|
||||
}
|
||||
|
||||
/**
|
||||
* Format document on type options.
|
||||
*/
|
||||
type DocumentOnTypeFormattingOptions struct {
|
||||
/**
|
||||
* A character on which formatting should be triggered, like `}`.
|
||||
*/
|
||||
FirstTriggerCharacter string `json:"firstTriggerCharacter"`
|
||||
|
||||
/**
|
||||
* More trigger characters.
|
||||
*/
|
||||
MoreTriggerCharacter []string `json:"moreTriggerCharacter,omitempty"`
|
||||
}
|
||||
|
||||
/**
|
||||
* Document link options.
|
||||
*/
|
||||
type DocumentLinkOptions struct {
|
||||
/**
|
||||
* Document links have a resolve provider as well.
|
||||
*/
|
||||
ResolveProvider bool `json:"resolveProvider,omitempty"`
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute command options.
|
||||
*/
|
||||
type ExecuteCommandOptions struct {
|
||||
/**
|
||||
* The commands to be executed on the server
|
||||
*/
|
||||
Commands []string `json:"commands"`
|
||||
}
|
||||
|
||||
/**
|
||||
* Save options.
|
||||
*/
|
||||
type SaveOptions struct {
|
||||
/**
|
||||
* The client is supposed to include the content on save.
|
||||
*/
|
||||
IncludeText bool `json:"includeText,omitempty"`
|
||||
}
|
||||
|
||||
/**
|
||||
* Color provider options.
|
||||
*/
|
||||
type ColorProviderOptions struct {
|
||||
}
|
||||
|
||||
/**
|
||||
* Folding range provider options.
|
||||
*/
|
||||
type FoldingRangeProviderOptions struct {
|
||||
}
|
||||
|
||||
type TextDocumentSyncOptions struct {
|
||||
/**
|
||||
* Open and close notifications are sent to the server.
|
||||
*/
|
||||
OpenClose bool `json:"openClose,omitempty"`
|
||||
/**
|
||||
* Change notifications are sent to the server. See TextDocumentSyncKind.None, TextDocumentSyncKind.Full
|
||||
* and TextDocumentSyncKind.Incremental. If omitted it defaults to TextDocumentSyncKind.None.
|
||||
*/
|
||||
Change float64 `json:"change,omitempty"`
|
||||
/**
|
||||
* Will save notifications are sent to the server.
|
||||
*/
|
||||
WillSave bool `json:"willSave,omitempty"`
|
||||
/**
|
||||
* Will save wait until requests are sent to the server.
|
||||
*/
|
||||
WillSaveWaitUntil bool `json:"willSaveWaitUntil,omitempty"`
|
||||
/**
|
||||
* Save notifications are sent to the server.
|
||||
*/
|
||||
Save SaveOptions `json:"save,omitempty"`
|
||||
}
|
||||
|
||||
/**
|
||||
* Static registration options to be returned in the initialize request.
|
||||
*/
|
||||
type StaticRegistrationOptions struct {
|
||||
/**
|
||||
* The id used to register the request. The id can be used to deregister
|
||||
* the request again. See also Registration#id.
|
||||
*/
|
||||
ID string `json:"id,omitempty"`
|
||||
}
|
||||
|
||||
type ServerCapabilities struct {
|
||||
/**
|
||||
* Defines how text documents are synced. Is either a detailed structure defining each notification or
|
||||
* for backwards compatibility the TextDocumentSyncKind number. If omitted it defaults to `TextDocumentSyncKind.None`.
|
||||
*/
|
||||
TextDocumentSync interface{} `json:"textDocumentSync,omitempty"` // TextDocumentSyncOptions | number
|
||||
/**
|
||||
* The server provides hover support.
|
||||
*/
|
||||
HoverProvider bool `json:"hoverProvider,omitempty"`
|
||||
/**
|
||||
* The server provides completion support.
|
||||
*/
|
||||
CompletionProvider CompletionOptions `json:"completionProvider,omitempty"`
|
||||
/**
|
||||
* The server provides signature help support.
|
||||
*/
|
||||
SignatureHelpProvider SignatureHelpOptions `json:"signatureHelpProvider,omitempty"`
|
||||
/**
|
||||
* The server provides goto definition support.
|
||||
*/
|
||||
DefinitionProvider bool `json:"definitionProvider,omitempty"`
|
||||
/**
|
||||
* The server provides Goto Type Definition support.
|
||||
*
|
||||
* Since 3.6.0
|
||||
*/
|
||||
TypeDefinitionProvider interface{} `json:"typeDefinitionProvider,omitempty"` // boolean | (TextDocumentRegistrationOptions & StaticRegistrationOptions)
|
||||
/**
|
||||
* The server provides Goto Implementation support.
|
||||
*
|
||||
* Since 3.6.0
|
||||
*/
|
||||
ImplementationProvider interface{} `json:"implementationProvider,omitempty"` // boolean | (TextDocumentRegistrationOptions & StaticRegistrationOptions)
|
||||
/**
|
||||
* The server provides find references support.
|
||||
*/
|
||||
ReferencesProvider bool `json:"referencesProvider,omitempty"`
|
||||
/**
|
||||
* The server provides document highlight support.
|
||||
*/
|
||||
DocumentHighlightProvider bool `json:"documentHighlightProvider,omitempty"`
|
||||
/**
|
||||
* The server provides document symbol support.
|
||||
*/
|
||||
DocumentSymbolProvider bool `json:"documentSymbolProvider,omitempty"`
|
||||
/**
|
||||
* The server provides workspace symbol support.
|
||||
*/
|
||||
WorkspaceSymbolProvider bool `json:"workspaceSymbolProvider,omitempty"`
|
||||
/**
|
||||
* The server provides code actions.
|
||||
*/
|
||||
CodeActionProvider bool `json:"codeActionProvider,omitempty"`
|
||||
/**
|
||||
* The server provides code lens.
|
||||
*/
|
||||
CodeLensProvider CodeLensOptions `json:"codeLensProvider,omitempty"`
|
||||
/**
|
||||
* The server provides document formatting.
|
||||
*/
|
||||
DocumentFormattingProvider bool `json:"documentFormattingProvider,omitempty"`
|
||||
/**
|
||||
* The server provides document range formatting.
|
||||
*/
|
||||
DocumentRangeFormattingProvider bool `json:"documentRangeFormattingProvider,omitempty"`
|
||||
/**
|
||||
* The server provides document formatting on typing.
|
||||
*/
|
||||
DocumentOnTypeFormattingProvider DocumentOnTypeFormattingOptions `json:"documentOnTypeFormattingProvider,omitempty"`
|
||||
/**
|
||||
* The server provides rename support.
|
||||
*/
|
||||
RenameProvider bool `json:"renameProvider,omitempty"`
|
||||
/**
|
||||
* The server provides document link support.
|
||||
*/
|
||||
DocumentLinkProvider DocumentLinkOptions `json:"documentLinkProvider,omitempty"`
|
||||
/**
|
||||
* The server provides color provider support.
|
||||
*
|
||||
* Since 3.6.0
|
||||
*/
|
||||
//TODO: complex union type to decode here
|
||||
ColorProvider interface{} `json:"colorProvider,omitempty"` // boolean | ColorProviderOptions | (ColorProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)
|
||||
/**
|
||||
* The server provides folding provider support.
|
||||
*
|
||||
* Since 3.10.0
|
||||
*/
|
||||
//TODO: complex union type to decode here
|
||||
FoldingRangeProvider interface{} `json:"foldingRangeProvider,omitempty"` // boolean | FoldingRangeProviderOptions | (FoldingRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)
|
||||
/**
|
||||
* The server provides execute command support.
|
||||
*/
|
||||
ExecuteCommandProvider ExecuteCommandOptions `json:"executeCommandProvider,omitempty"`
|
||||
/**
|
||||
* Workspace specific server capabilities
|
||||
*/
|
||||
Workspace struct {
|
||||
/**
|
||||
* The server supports workspace folder.
|
||||
*
|
||||
* Since 3.6.0
|
||||
*/
|
||||
WorkspaceFolders struct {
|
||||
/**
|
||||
* The server has support for workspace folders
|
||||
*/
|
||||
Supported bool `json:"supported,omitempty"`
|
||||
/**
|
||||
* Whether the server wants to receive workspace folder
|
||||
* change notifications.
|
||||
*
|
||||
* If a strings is provided the string is treated as a ID
|
||||
* under which the notification is registered on the client
|
||||
* side. The ID can be used to unregister for these events
|
||||
* using the `client/unregisterCapability` request.
|
||||
*/
|
||||
ChangeNotifications interface{} `json:"changeNotifications,omitempty"` // string | boolean
|
||||
} `json:"workspaceFolders,omitempty"`
|
||||
} `json:"workspace,omitempty"`
|
||||
/**
|
||||
* Experimental server capabilities.
|
||||
*/
|
||||
Experimental interface{} `json:"experimental,omitempty"`
|
||||
}
|
||||
|
||||
type InitializedParams struct {
|
||||
}
|
1020
vendor/golang.org/x/tools/internal/lsp/protocol/language.go
generated
vendored
1020
vendor/golang.org/x/tools/internal/lsp/protocol/language.go
generated
vendored
File diff suppressed because it is too large
Load Diff
56
vendor/golang.org/x/tools/internal/lsp/protocol/printers.go
generated
vendored
56
vendor/golang.org/x/tools/internal/lsp/protocol/printers.go
generated
vendored
@@ -1,56 +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.
|
||||
|
||||
// This file contains formatting functions for types that
|
||||
// are commonly printed in debugging information.
|
||||
// They are separated from their types and gathered here as
|
||||
// they are hand written and not generated from the spec.
|
||||
// They should not be relied on for programmatic use (their
|
||||
// results should never be parsed for instance) but are meant
|
||||
// for temporary debugging and error messages.
|
||||
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func (p Position) Format(f fmt.State, c rune) {
|
||||
fmt.Fprintf(f, "%d", int(p.Line)+1)
|
||||
if p.Character >= 0 {
|
||||
fmt.Fprintf(f, ":%d", int(p.Character)+1)
|
||||
}
|
||||
}
|
||||
|
||||
func (r Range) Format(f fmt.State, c rune) {
|
||||
switch {
|
||||
case r.Start == r.End || r.End.Line < 0:
|
||||
fmt.Fprintf(f, "%v", r.Start)
|
||||
case r.End.Line == r.Start.Line:
|
||||
fmt.Fprintf(f, "%v¦%d", r.Start, int(r.End.Character)+1)
|
||||
default:
|
||||
fmt.Fprintf(f, "%v¦%v", r.Start, r.End)
|
||||
}
|
||||
}
|
||||
|
||||
func (l Location) Format(f fmt.State, c rune) {
|
||||
fmt.Fprintf(f, "%s:%v", l.URI, l.Range)
|
||||
}
|
||||
|
||||
func (s DiagnosticSeverity) Format(f fmt.State, c rune) {
|
||||
switch s {
|
||||
case SeverityError:
|
||||
fmt.Fprint(f, "Error")
|
||||
case SeverityWarning:
|
||||
fmt.Fprint(f, "Warning")
|
||||
case SeverityInformation:
|
||||
fmt.Fprint(f, "Information")
|
||||
case SeverityHint:
|
||||
fmt.Fprint(f, "Hint")
|
||||
}
|
||||
}
|
||||
|
||||
func (d Diagnostic) Format(f fmt.State, c rune) {
|
||||
fmt.Fprintf(f, "%v:%v from %v at %v: %v", d.Severity, d.Code, d.Source, d.Range, d.Message)
|
||||
}
|
49
vendor/golang.org/x/tools/internal/lsp/protocol/protocol.go
generated
vendored
49
vendor/golang.org/x/tools/internal/lsp/protocol/protocol.go
generated
vendored
@@ -1,49 +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 protocol
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"golang.org/x/tools/internal/jsonrpc2"
|
||||
)
|
||||
|
||||
func canceller(ctx context.Context, conn *jsonrpc2.Conn, req *jsonrpc2.Request) {
|
||||
conn.Notify(context.Background(), "$/cancelRequest", &CancelParams{ID: *req.ID})
|
||||
}
|
||||
|
||||
func RunClient(ctx context.Context, stream jsonrpc2.Stream, client Client, opts ...interface{}) (*jsonrpc2.Conn, Server) {
|
||||
opts = append([]interface{}{clientHandler(client), jsonrpc2.Canceler(canceller)}, opts...)
|
||||
conn := jsonrpc2.NewConn(ctx, stream, opts...)
|
||||
return conn, &serverDispatcher{Conn: conn}
|
||||
}
|
||||
|
||||
func RunServer(ctx context.Context, stream jsonrpc2.Stream, server Server, opts ...interface{}) (*jsonrpc2.Conn, Client) {
|
||||
opts = append([]interface{}{serverHandler(server), jsonrpc2.Canceler(canceller)}, opts...)
|
||||
conn := jsonrpc2.NewConn(ctx, stream, opts...)
|
||||
return conn, &clientDispatcher{Conn: conn}
|
||||
}
|
||||
|
||||
func sendParseError(ctx context.Context, conn *jsonrpc2.Conn, req *jsonrpc2.Request, err error) {
|
||||
if _, ok := err.(*jsonrpc2.Error); !ok {
|
||||
err = jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err)
|
||||
}
|
||||
unhandledError(conn.Reply(ctx, req, nil, err))
|
||||
}
|
||||
|
||||
// unhandledError is used in places where an error may occur that cannot be handled.
|
||||
// This occurs in things like rpc handlers that are a notify, where we cannot
|
||||
// reply to the caller, or in a call when we are actually attempting to reply.
|
||||
// In these cases, there is nothing we can do with the error except log it, so
|
||||
// we do that in this function, and the presence of this function acts as a
|
||||
// useful reminder of why we are effectively dropping the error and also a
|
||||
// good place to hook in when debugging those kinds of errors.
|
||||
func unhandledError(err error) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
log.Printf("%v", err)
|
||||
}
|
61
vendor/golang.org/x/tools/internal/lsp/protocol/registration.go
generated
vendored
61
vendor/golang.org/x/tools/internal/lsp/protocol/registration.go
generated
vendored
@@ -1,61 +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.
|
||||
|
||||
// This file contains the corresponding structures to the
|
||||
// "Client" part of the LSP specification.
|
||||
|
||||
package protocol
|
||||
|
||||
/**
|
||||
* General parameters to register for a capability.
|
||||
*/
|
||||
type Registration struct {
|
||||
/**
|
||||
* The id used to register the request. The id can be used to deregister
|
||||
* the request again.
|
||||
*/
|
||||
ID string `json:"id"`
|
||||
|
||||
/**
|
||||
* The method / capability to register for.
|
||||
*/
|
||||
Method string `json:"method"`
|
||||
|
||||
/**
|
||||
* Options necessary for the registration.
|
||||
*/
|
||||
RegisterOptions interface{} `json:"registerOptions,omitempty"`
|
||||
}
|
||||
|
||||
type RegistrationParams struct {
|
||||
Registrations []Registration `json:"registrations"`
|
||||
}
|
||||
|
||||
type TextDocumentRegistrationOptions struct {
|
||||
/**
|
||||
* A document selector to identify the scope of the registration. If set to null
|
||||
* the document selector provided on the client side will be used.
|
||||
*/
|
||||
DocumentSelector *DocumentSelector `json:"documentSelector"`
|
||||
}
|
||||
|
||||
/**
|
||||
* General parameters to unregister a capability.
|
||||
*/
|
||||
type Unregistration struct {
|
||||
/**
|
||||
* The id used to unregister the request or notification. Usually an id
|
||||
* provided during the register request.
|
||||
*/
|
||||
ID string `json:"id"`
|
||||
|
||||
/**
|
||||
* The method / capability to unregister for.
|
||||
*/
|
||||
Method string `json:"method"`
|
||||
}
|
||||
|
||||
type UnregistrationParams struct {
|
||||
Unregisterations []Unregistration `json:"unregisterations"`
|
||||
}
|
646
vendor/golang.org/x/tools/internal/lsp/protocol/server.go
generated
vendored
646
vendor/golang.org/x/tools/internal/lsp/protocol/server.go
generated
vendored
@@ -1,646 +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 protocol
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"golang.org/x/tools/internal/jsonrpc2"
|
||||
)
|
||||
|
||||
type Server interface {
|
||||
Initialize(context.Context, *InitializeParams) (*InitializeResult, error)
|
||||
Initialized(context.Context, *InitializedParams) error
|
||||
Shutdown(context.Context) error
|
||||
Exit(context.Context) error
|
||||
DidChangeWorkspaceFolders(context.Context, *DidChangeWorkspaceFoldersParams) error
|
||||
DidChangeConfiguration(context.Context, *DidChangeConfigurationParams) error
|
||||
DidChangeWatchedFiles(context.Context, *DidChangeWatchedFilesParams) error
|
||||
Symbols(context.Context, *WorkspaceSymbolParams) ([]SymbolInformation, error)
|
||||
ExecuteCommand(context.Context, *ExecuteCommandParams) (interface{}, error)
|
||||
DidOpen(context.Context, *DidOpenTextDocumentParams) error
|
||||
DidChange(context.Context, *DidChangeTextDocumentParams) error
|
||||
WillSave(context.Context, *WillSaveTextDocumentParams) error
|
||||
WillSaveWaitUntil(context.Context, *WillSaveTextDocumentParams) ([]TextEdit, error)
|
||||
DidSave(context.Context, *DidSaveTextDocumentParams) error
|
||||
DidClose(context.Context, *DidCloseTextDocumentParams) error
|
||||
Completion(context.Context, *CompletionParams) (*CompletionList, error)
|
||||
CompletionResolve(context.Context, *CompletionItem) (*CompletionItem, error)
|
||||
Hover(context.Context, *TextDocumentPositionParams) (*Hover, error)
|
||||
SignatureHelp(context.Context, *TextDocumentPositionParams) (*SignatureHelp, error)
|
||||
Definition(context.Context, *TextDocumentPositionParams) ([]Location, error)
|
||||
TypeDefinition(context.Context, *TextDocumentPositionParams) ([]Location, error)
|
||||
Implementation(context.Context, *TextDocumentPositionParams) ([]Location, error)
|
||||
References(context.Context, *ReferenceParams) ([]Location, error)
|
||||
DocumentHighlight(context.Context, *TextDocumentPositionParams) ([]DocumentHighlight, error)
|
||||
DocumentSymbol(context.Context, *DocumentSymbolParams) ([]DocumentSymbol, error)
|
||||
CodeAction(context.Context, *CodeActionParams) ([]CodeAction, error)
|
||||
CodeLens(context.Context, *CodeLensParams) ([]CodeLens, error)
|
||||
CodeLensResolve(context.Context, *CodeLens) (*CodeLens, error)
|
||||
DocumentLink(context.Context, *DocumentLinkParams) ([]DocumentLink, error)
|
||||
DocumentLinkResolve(context.Context, *DocumentLink) (*DocumentLink, error)
|
||||
DocumentColor(context.Context, *DocumentColorParams) ([]ColorInformation, error)
|
||||
ColorPresentation(context.Context, *ColorPresentationParams) ([]ColorPresentation, error)
|
||||
Formatting(context.Context, *DocumentFormattingParams) ([]TextEdit, error)
|
||||
RangeFormatting(context.Context, *DocumentRangeFormattingParams) ([]TextEdit, error)
|
||||
OnTypeFormatting(context.Context, *DocumentOnTypeFormattingParams) ([]TextEdit, error)
|
||||
Rename(context.Context, *RenameParams) ([]WorkspaceEdit, error)
|
||||
FoldingRanges(context.Context, *FoldingRangeRequestParam) ([]FoldingRange, error)
|
||||
}
|
||||
|
||||
func serverHandler(server Server) jsonrpc2.Handler {
|
||||
return func(ctx context.Context, conn *jsonrpc2.Conn, r *jsonrpc2.Request) {
|
||||
switch r.Method {
|
||||
case "initialize":
|
||||
var params InitializeParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Initialize(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "initialized":
|
||||
var params InitializedParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
unhandledError(server.Initialized(ctx, ¶ms))
|
||||
|
||||
case "shutdown":
|
||||
if r.Params != nil {
|
||||
conn.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
|
||||
return
|
||||
}
|
||||
unhandledError(server.Shutdown(ctx))
|
||||
|
||||
case "exit":
|
||||
if r.Params != nil {
|
||||
conn.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
|
||||
return
|
||||
}
|
||||
unhandledError(server.Exit(ctx))
|
||||
|
||||
case "$/cancelRequest":
|
||||
var params CancelParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
conn.Cancel(params.ID)
|
||||
|
||||
case "workspace/didChangeWorkspaceFolders":
|
||||
var params DidChangeWorkspaceFoldersParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
unhandledError(server.DidChangeWorkspaceFolders(ctx, ¶ms))
|
||||
|
||||
case "workspace/didChangeConfiguration":
|
||||
var params DidChangeConfigurationParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
unhandledError(server.DidChangeConfiguration(ctx, ¶ms))
|
||||
|
||||
case "workspace/didChangeWatchedFiles":
|
||||
var params DidChangeWatchedFilesParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
unhandledError(server.DidChangeWatchedFiles(ctx, ¶ms))
|
||||
|
||||
case "workspace/symbol":
|
||||
var params WorkspaceSymbolParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Symbols(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "workspace/executeCommand":
|
||||
var params ExecuteCommandParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.ExecuteCommand(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/didOpen":
|
||||
var params DidOpenTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
unhandledError(server.DidOpen(ctx, ¶ms))
|
||||
|
||||
case "textDocument/didChange":
|
||||
var params DidChangeTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
unhandledError(server.DidChange(ctx, ¶ms))
|
||||
|
||||
case "textDocument/willSave":
|
||||
var params WillSaveTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
unhandledError(server.WillSave(ctx, ¶ms))
|
||||
|
||||
case "textDocument/willSaveWaitUntil":
|
||||
var params WillSaveTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.WillSaveWaitUntil(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/didSave":
|
||||
var params DidSaveTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
unhandledError(server.DidSave(ctx, ¶ms))
|
||||
|
||||
case "textDocument/didClose":
|
||||
var params DidCloseTextDocumentParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
unhandledError(server.DidClose(ctx, ¶ms))
|
||||
|
||||
case "textDocument/completion":
|
||||
var params CompletionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Completion(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "completionItem/resolve":
|
||||
var params CompletionItem
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.CompletionResolve(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/hover":
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Hover(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/signatureHelp":
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.SignatureHelp(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/definition":
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Definition(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/typeDefinition":
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.TypeDefinition(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/implementation":
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Implementation(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/references":
|
||||
var params ReferenceParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.References(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/documentHighlight":
|
||||
var params TextDocumentPositionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.DocumentHighlight(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/documentSymbol":
|
||||
var params DocumentSymbolParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.DocumentSymbol(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/codeAction":
|
||||
var params CodeActionParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.CodeAction(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/codeLens":
|
||||
var params CodeLensParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.CodeLens(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "codeLens/resolve":
|
||||
var params CodeLens
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.CodeLensResolve(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/documentLink":
|
||||
var params DocumentLinkParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.DocumentLink(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "documentLink/resolve":
|
||||
var params DocumentLink
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.DocumentLinkResolve(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/documentColor":
|
||||
var params DocumentColorParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.DocumentColor(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/colorPresentation":
|
||||
var params ColorPresentationParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.ColorPresentation(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/formatting":
|
||||
var params DocumentFormattingParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Formatting(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/rangeFormatting":
|
||||
var params DocumentRangeFormattingParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.RangeFormatting(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/onTypeFormatting":
|
||||
var params DocumentOnTypeFormattingParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.OnTypeFormatting(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/rename":
|
||||
var params RenameParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.Rename(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
|
||||
case "textDocument/foldingRanges":
|
||||
var params FoldingRangeRequestParam
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, conn, r, err)
|
||||
return
|
||||
}
|
||||
resp, err := server.FoldingRanges(ctx, ¶ms)
|
||||
unhandledError(conn.Reply(ctx, r, resp, err))
|
||||
default:
|
||||
if r.IsNotify() {
|
||||
conn.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not found", r.Method))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type serverDispatcher struct {
|
||||
*jsonrpc2.Conn
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) Initialize(ctx context.Context, params *InitializeParams) (*InitializeResult, error) {
|
||||
var result InitializeResult
|
||||
if err := s.Conn.Call(ctx, "initialize", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) Initialized(ctx context.Context, params *InitializedParams) error {
|
||||
return s.Conn.Notify(ctx, "initialized", params)
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) Shutdown(ctx context.Context) error {
|
||||
return s.Conn.Call(ctx, "shutdown", nil, nil)
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) Exit(ctx context.Context) error {
|
||||
return s.Conn.Notify(ctx, "exit", nil)
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) DidChangeWorkspaceFolders(ctx context.Context, params *DidChangeWorkspaceFoldersParams) error {
|
||||
return s.Conn.Notify(ctx, "workspace/didChangeWorkspaceFolders", params)
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) DidChangeConfiguration(ctx context.Context, params *DidChangeConfigurationParams) error {
|
||||
return s.Conn.Notify(ctx, "workspace/didChangeConfiguration", params)
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) DidChangeWatchedFiles(ctx context.Context, params *DidChangeWatchedFilesParams) error {
|
||||
return s.Conn.Notify(ctx, "workspace/didChangeWatchedFiles", params)
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) Symbols(ctx context.Context, params *WorkspaceSymbolParams) ([]SymbolInformation, error) {
|
||||
var result []SymbolInformation
|
||||
if err := s.Conn.Call(ctx, "workspace/symbol", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) ExecuteCommand(ctx context.Context, params *ExecuteCommandParams) (interface{}, error) {
|
||||
var result interface{}
|
||||
if err := s.Conn.Call(ctx, "workspace/executeCommand", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) DidOpen(ctx context.Context, params *DidOpenTextDocumentParams) error {
|
||||
return s.Conn.Notify(ctx, "textDocument/didOpen", params)
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) DidChange(ctx context.Context, params *DidChangeTextDocumentParams) error {
|
||||
return s.Conn.Notify(ctx, "textDocument/didChange", params)
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) WillSave(ctx context.Context, params *WillSaveTextDocumentParams) error {
|
||||
return s.Conn.Notify(ctx, "textDocument/willSave", params)
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) WillSaveWaitUntil(ctx context.Context, params *WillSaveTextDocumentParams) ([]TextEdit, error) {
|
||||
var result []TextEdit
|
||||
if err := s.Conn.Call(ctx, "textDocument/willSaveWaitUntil", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) DidSave(ctx context.Context, params *DidSaveTextDocumentParams) error {
|
||||
return s.Conn.Notify(ctx, "textDocument/didSave", params)
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) DidClose(ctx context.Context, params *DidCloseTextDocumentParams) error {
|
||||
return s.Conn.Notify(ctx, "textDocument/didClose", params)
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) Completion(ctx context.Context, params *CompletionParams) (*CompletionList, error) {
|
||||
var result CompletionList
|
||||
if err := s.Conn.Call(ctx, "textDocument/completion", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) CompletionResolve(ctx context.Context, params *CompletionItem) (*CompletionItem, error) {
|
||||
var result CompletionItem
|
||||
if err := s.Conn.Call(ctx, "completionItem/resolve", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) Hover(ctx context.Context, params *TextDocumentPositionParams) (*Hover, error) {
|
||||
var result Hover
|
||||
if err := s.Conn.Call(ctx, "textDocument/hover", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) SignatureHelp(ctx context.Context, params *TextDocumentPositionParams) (*SignatureHelp, error) {
|
||||
var result SignatureHelp
|
||||
if err := s.Conn.Call(ctx, "textDocument/signatureHelp", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) Definition(ctx context.Context, params *TextDocumentPositionParams) ([]Location, error) {
|
||||
var result []Location
|
||||
if err := s.Conn.Call(ctx, "textDocument/definition", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) TypeDefinition(ctx context.Context, params *TextDocumentPositionParams) ([]Location, error) {
|
||||
var result []Location
|
||||
if err := s.Conn.Call(ctx, "textDocument/typeDefinition", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) Implementation(ctx context.Context, params *TextDocumentPositionParams) ([]Location, error) {
|
||||
var result []Location
|
||||
if err := s.Conn.Call(ctx, "textDocument/implementation", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) References(ctx context.Context, params *ReferenceParams) ([]Location, error) {
|
||||
var result []Location
|
||||
if err := s.Conn.Call(ctx, "textDocument/references", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) DocumentHighlight(ctx context.Context, params *TextDocumentPositionParams) ([]DocumentHighlight, error) {
|
||||
var result []DocumentHighlight
|
||||
if err := s.Conn.Call(ctx, "textDocument/documentHighlight", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) DocumentSymbol(ctx context.Context, params *DocumentSymbolParams) ([]DocumentSymbol, error) {
|
||||
var result []DocumentSymbol
|
||||
if err := s.Conn.Call(ctx, "textDocument/documentSymbol", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) CodeAction(ctx context.Context, params *CodeActionParams) ([]CodeAction, error) {
|
||||
var result []CodeAction
|
||||
if err := s.Conn.Call(ctx, "textDocument/codeAction", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) CodeLens(ctx context.Context, params *CodeLensParams) ([]CodeLens, error) {
|
||||
var result []CodeLens
|
||||
if err := s.Conn.Call(ctx, "textDocument/codeLens", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) CodeLensResolve(ctx context.Context, params *CodeLens) (*CodeLens, error) {
|
||||
var result CodeLens
|
||||
if err := s.Conn.Call(ctx, "codeLens/resolve", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) DocumentLink(ctx context.Context, params *DocumentLinkParams) ([]DocumentLink, error) {
|
||||
var result []DocumentLink
|
||||
if err := s.Conn.Call(ctx, "textDocument/documentLink", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) DocumentLinkResolve(ctx context.Context, params *DocumentLink) (*DocumentLink, error) {
|
||||
var result DocumentLink
|
||||
if err := s.Conn.Call(ctx, "documentLink/resolve", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) DocumentColor(ctx context.Context, params *DocumentColorParams) ([]ColorInformation, error) {
|
||||
var result []ColorInformation
|
||||
if err := s.Conn.Call(ctx, "textDocument/documentColor", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) ColorPresentation(ctx context.Context, params *ColorPresentationParams) ([]ColorPresentation, error) {
|
||||
var result []ColorPresentation
|
||||
if err := s.Conn.Call(ctx, "textDocument/colorPresentation", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) Formatting(ctx context.Context, params *DocumentFormattingParams) ([]TextEdit, error) {
|
||||
var result []TextEdit
|
||||
if err := s.Conn.Call(ctx, "textDocument/formatting", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) RangeFormatting(ctx context.Context, params *DocumentRangeFormattingParams) ([]TextEdit, error) {
|
||||
var result []TextEdit
|
||||
if err := s.Conn.Call(ctx, "textDocument/rangeFormatting", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) OnTypeFormatting(ctx context.Context, params *DocumentOnTypeFormattingParams) ([]TextEdit, error) {
|
||||
var result []TextEdit
|
||||
if err := s.Conn.Call(ctx, "textDocument/onTypeFormatting", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) Rename(ctx context.Context, params *RenameParams) ([]WorkspaceEdit, error) {
|
||||
var result []WorkspaceEdit
|
||||
if err := s.Conn.Call(ctx, "textDocument/rename", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) FoldingRanges(ctx context.Context, params *FoldingRangeRequestParam) ([]FoldingRange, error) {
|
||||
var result []FoldingRange
|
||||
if err := s.Conn.Call(ctx, "textDocument/foldingRanges", params, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
130
vendor/golang.org/x/tools/internal/lsp/protocol/text.go
generated
vendored
130
vendor/golang.org/x/tools/internal/lsp/protocol/text.go
generated
vendored
@@ -1,130 +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.
|
||||
|
||||
// This file contains the corresponding structures to the
|
||||
// "Text Synchronization" part of the LSP specification.
|
||||
|
||||
package protocol
|
||||
|
||||
type DidOpenTextDocumentParams struct {
|
||||
/**
|
||||
* The document that was opened.
|
||||
*/
|
||||
TextDocument TextDocumentItem `json:"textDocument"`
|
||||
}
|
||||
|
||||
type DidChangeTextDocumentParams struct {
|
||||
/**
|
||||
* The document that did change. The version number points
|
||||
* to the version after all provided content changes have
|
||||
* been applied.
|
||||
*/
|
||||
TextDocument VersionedTextDocumentIdentifier `json:"textDocument"`
|
||||
|
||||
/**
|
||||
* The actual content changes. The content changes describe single state changes
|
||||
* to the document. So if there are two content changes c1 and c2 for a document
|
||||
* in state S10 then c1 move the document to S11 and c2 to S12.
|
||||
*/
|
||||
ContentChanges []TextDocumentContentChangeEvent `json:"contentChanges"`
|
||||
}
|
||||
|
||||
/**
|
||||
* An event describing a change to a text document. If range and rangeLength are omitted
|
||||
* the new text is considered to be the full content of the document.
|
||||
*/
|
||||
type TextDocumentContentChangeEvent struct {
|
||||
/**
|
||||
* The range of the document that changed.
|
||||
*/
|
||||
Range Range `json:"range,omitempty"`
|
||||
|
||||
/**
|
||||
* The length of the range that got replaced.
|
||||
*/
|
||||
RangeLength float64 `json:"rangeLength,omitempty"`
|
||||
|
||||
/**
|
||||
* The new text of the range/document.
|
||||
*/
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe options to be used when registering for text document change events.
|
||||
*/
|
||||
type TextDocumentChangeRegistrationOptions struct {
|
||||
TextDocumentRegistrationOptions
|
||||
/**
|
||||
* How documents are synced to the server. See TextDocumentSyncKind.Full
|
||||
* and TextDocumentSyncKind.Incremental.
|
||||
*/
|
||||
SyncKind float64 `json:"syncKind"`
|
||||
}
|
||||
|
||||
/**
|
||||
* The parameters send in a will save text document notification.
|
||||
*/
|
||||
type WillSaveTextDocumentParams struct {
|
||||
/**
|
||||
* The document that will be saved.
|
||||
*/
|
||||
TextDocument TextDocumentIdentifier `json:"textDocument"`
|
||||
|
||||
/**
|
||||
* The 'TextDocumentSaveReason'.
|
||||
*/
|
||||
Reason TextDocumentSaveReason `json:"reason"`
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents reasons why a text document is saved.
|
||||
*/
|
||||
type TextDocumentSaveReason float64
|
||||
|
||||
const (
|
||||
/**
|
||||
* Manually triggered, e.g. by the user pressing save, by starting debugging,
|
||||
* or by an API call.
|
||||
*/
|
||||
Manual TextDocumentSaveReason = 1
|
||||
|
||||
/**
|
||||
* Automatic after a delay.
|
||||
*/
|
||||
AfterDelay TextDocumentSaveReason = 2
|
||||
|
||||
/**
|
||||
* When the editor lost focus.
|
||||
*/
|
||||
FocusOut TextDocumentSaveReason = 3
|
||||
)
|
||||
|
||||
type DidSaveTextDocumentParams struct {
|
||||
/**
|
||||
* The document that was saved.
|
||||
*/
|
||||
TextDocument TextDocumentIdentifier `json:"textDocument"`
|
||||
|
||||
/**
|
||||
* Optional the content when saved. Depends on the includeText value
|
||||
* when the save notification was requested.
|
||||
*/
|
||||
Text string `json:"text,omitempty"`
|
||||
}
|
||||
|
||||
type TextDocumentSaveRegistrationOptions struct {
|
||||
TextDocumentRegistrationOptions
|
||||
/**
|
||||
* The client is supposed to include the content on save.
|
||||
*/
|
||||
IncludeText bool `json:"includeText,omitempty"`
|
||||
}
|
||||
|
||||
type DidCloseTextDocumentParams struct {
|
||||
/**
|
||||
* The document that was closed.
|
||||
*/
|
||||
TextDocument TextDocumentIdentifier `json:"textDocument"`
|
||||
}
|
77
vendor/golang.org/x/tools/internal/lsp/protocol/window.go
generated
vendored
77
vendor/golang.org/x/tools/internal/lsp/protocol/window.go
generated
vendored
@@ -1,77 +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.
|
||||
|
||||
// This file contains the corresponding structures to the
|
||||
// "Window" messages part of the LSP specification.
|
||||
|
||||
package protocol
|
||||
|
||||
type ShowMessageParams struct {
|
||||
/**
|
||||
* The message type. See {@link MessageType}.
|
||||
*/
|
||||
Type MessageType `json:"type"`
|
||||
|
||||
/**
|
||||
* The actual message.
|
||||
*/
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type MessageType float64
|
||||
|
||||
const (
|
||||
/**
|
||||
* An error message.
|
||||
*/
|
||||
Error MessageType = 1
|
||||
/**
|
||||
* A warning message.
|
||||
*/
|
||||
Warning MessageType = 2
|
||||
/**
|
||||
* An information message.
|
||||
*/
|
||||
Info MessageType = 3
|
||||
/**
|
||||
* A log message.
|
||||
*/
|
||||
Log MessageType = 4
|
||||
)
|
||||
|
||||
type ShowMessageRequestParams struct {
|
||||
/**
|
||||
* The message type. See {@link MessageType}.
|
||||
*/
|
||||
Type MessageType `json:"type"`
|
||||
|
||||
/**
|
||||
* The actual message.
|
||||
*/
|
||||
Message string `json:"message"`
|
||||
|
||||
/**
|
||||
* The message action items to present.
|
||||
*/
|
||||
Actions []MessageActionItem `json:"actions,omitempty"`
|
||||
}
|
||||
|
||||
type MessageActionItem struct {
|
||||
/**
|
||||
* A short title like 'Retry', 'Open Log' etc.
|
||||
*/
|
||||
Title string
|
||||
}
|
||||
|
||||
type LogMessageParams struct {
|
||||
/**
|
||||
* The message type. See {@link MessageType}.
|
||||
*/
|
||||
Type MessageType `json:"type"`
|
||||
|
||||
/**
|
||||
* The actual message.
|
||||
*/
|
||||
Message string `json:"message"`
|
||||
}
|
203
vendor/golang.org/x/tools/internal/lsp/protocol/workspace.go
generated
vendored
203
vendor/golang.org/x/tools/internal/lsp/protocol/workspace.go
generated
vendored
@@ -1,203 +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.
|
||||
|
||||
// This file contains the corresponding structures to the
|
||||
// "Workspace" part of the LSP specification.
|
||||
|
||||
package protocol
|
||||
|
||||
type WorkspaceFolder struct {
|
||||
/**
|
||||
* The associated URI for this workspace folder.
|
||||
*/
|
||||
URI string `json:"uri"`
|
||||
|
||||
/**
|
||||
* The name of the workspace folder. Defaults to the
|
||||
* uri's basename.
|
||||
*/
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type DidChangeWorkspaceFoldersParams struct {
|
||||
/**
|
||||
* The actual workspace folder change event.
|
||||
*/
|
||||
Event WorkspaceFoldersChangeEvent `json:"event"`
|
||||
}
|
||||
|
||||
/**
|
||||
* The workspace folder change event.
|
||||
*/
|
||||
type WorkspaceFoldersChangeEvent struct {
|
||||
/**
|
||||
* The array of added workspace folders
|
||||
*/
|
||||
Added []WorkspaceFolder `json:"added"`
|
||||
|
||||
/**
|
||||
* The array of the removed workspace folders
|
||||
*/
|
||||
Removed []WorkspaceFolder `json:"removed"`
|
||||
}
|
||||
|
||||
type DidChangeConfigurationParams struct {
|
||||
/**
|
||||
* The actual changed settings
|
||||
*/
|
||||
Settings interface{} `json:"settings"`
|
||||
}
|
||||
|
||||
type ConfigurationParams struct {
|
||||
Items []ConfigurationItem `json:"items"`
|
||||
}
|
||||
|
||||
type ConfigurationItem struct {
|
||||
/**
|
||||
* The scope to get the configuration section for.
|
||||
*/
|
||||
ScopeURI string `json:"scopeURI,omitempty"`
|
||||
|
||||
/**
|
||||
* The configuration section asked for.
|
||||
*/
|
||||
Section string `json:"section,omitempty"`
|
||||
}
|
||||
|
||||
type DidChangeWatchedFilesParams struct {
|
||||
/**
|
||||
* The actual file events.
|
||||
*/
|
||||
Changes []FileEvent `json:"changes"`
|
||||
}
|
||||
|
||||
/**
|
||||
* An event describing a file change.
|
||||
*/
|
||||
type FileEvent struct {
|
||||
/**
|
||||
* The file's URI.
|
||||
*/
|
||||
URI DocumentURI `json:"uri"`
|
||||
/**
|
||||
* The change type.
|
||||
*/
|
||||
Type float64 `json:"type"`
|
||||
}
|
||||
|
||||
/**
|
||||
* The file event type.
|
||||
*/
|
||||
type FileChangeType float64
|
||||
|
||||
const (
|
||||
/**
|
||||
* The file got created.
|
||||
*/
|
||||
Created FileChangeType = 1
|
||||
/**
|
||||
* The file got changed.
|
||||
*/
|
||||
Changed FileChangeType = 2
|
||||
/**
|
||||
* The file got deleted.
|
||||
*/
|
||||
Deleted FileChangeType = 3
|
||||
)
|
||||
|
||||
/**
|
||||
* Describe options to be used when registering for text document change events.
|
||||
*/
|
||||
type DidChangeWatchedFilesRegistrationOptions struct {
|
||||
/**
|
||||
* The watchers to register.
|
||||
*/
|
||||
Watchers []FileSystemWatcher `json:"watchers"`
|
||||
}
|
||||
|
||||
type FileSystemWatcher struct {
|
||||
/**
|
||||
* The glob pattern to watch
|
||||
*/
|
||||
GlobPattern string `json:"globPattern"`
|
||||
|
||||
/**
|
||||
* The kind of events of interest. If omitted it defaults
|
||||
* to WatchKind.Create | WatchKind.Change | WatchKind.Delete
|
||||
* which is 7.
|
||||
*/
|
||||
Kind float64 `json:"kind,omitempty"`
|
||||
}
|
||||
|
||||
type WatchKind float64
|
||||
|
||||
const (
|
||||
/**
|
||||
* Interested in create events.
|
||||
*/
|
||||
Create WatchKind = 1
|
||||
|
||||
/**
|
||||
* Interested in change events
|
||||
*/
|
||||
Change WatchKind = 2
|
||||
|
||||
/**
|
||||
* Interested in delete events
|
||||
*/
|
||||
Delete WatchKind = 4
|
||||
)
|
||||
|
||||
/**
|
||||
* The parameters of a Workspace Symbol Request.
|
||||
*/
|
||||
type WorkspaceSymbolParams struct {
|
||||
/**
|
||||
* A non-empty query string
|
||||
*/
|
||||
Query string `json:"query"`
|
||||
}
|
||||
|
||||
type ExecuteCommandParams struct {
|
||||
|
||||
/**
|
||||
* The identifier of the actual command handler.
|
||||
*/
|
||||
Command string `json:"command"`
|
||||
/**
|
||||
* Arguments that the command should be invoked with.
|
||||
*/
|
||||
Arguments []interface{} `json:"arguments,omitempty"`
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute command registration options.
|
||||
*/
|
||||
type ExecuteCommandRegistrationOptions struct {
|
||||
/**
|
||||
* The commands to be executed on the server
|
||||
*/
|
||||
Commands []string `json:"commands"`
|
||||
}
|
||||
|
||||
type ApplyWorkspaceEditParams struct {
|
||||
/**
|
||||
* An optional label of the workspace edit. This label is
|
||||
* presented in the user interface for example on an undo
|
||||
* stack to undo the workspace edit.
|
||||
*/
|
||||
Label string `json:"label,omitempty"`
|
||||
|
||||
/**
|
||||
* The edits to apply.
|
||||
*/
|
||||
Edit WorkspaceEdit `json:"edit"`
|
||||
}
|
||||
|
||||
type ApplyWorkspaceEditResponse struct {
|
||||
/**
|
||||
* Indicates whether the edit was applied or not.
|
||||
*/
|
||||
Applied bool `json:"applied"`
|
||||
}
|
315
vendor/golang.org/x/tools/internal/lsp/server.go
generated
vendored
315
vendor/golang.org/x/tools/internal/lsp/server.go
generated
vendored
@@ -1,315 +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 lsp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"go/token"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/tools/internal/jsonrpc2"
|
||||
"golang.org/x/tools/internal/lsp/protocol"
|
||||
"golang.org/x/tools/internal/lsp/source"
|
||||
)
|
||||
|
||||
// RunServer starts an LSP server on the supplied stream, and waits until the
|
||||
// stream is closed.
|
||||
func RunServer(ctx context.Context, stream jsonrpc2.Stream, opts ...interface{}) error {
|
||||
s := &server{}
|
||||
conn, client := protocol.RunServer(ctx, stream, s, opts...)
|
||||
s.client = client
|
||||
return conn.Wait(ctx)
|
||||
}
|
||||
|
||||
type server struct {
|
||||
client protocol.Client
|
||||
|
||||
initializedMu sync.Mutex
|
||||
initialized bool // set once the server has received "initialize" request
|
||||
|
||||
view *source.View
|
||||
}
|
||||
|
||||
func (s *server) Initialize(ctx context.Context, params *protocol.InitializeParams) (*protocol.InitializeResult, error) {
|
||||
s.initializedMu.Lock()
|
||||
defer s.initializedMu.Unlock()
|
||||
if s.initialized {
|
||||
return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidRequest, "server already initialized")
|
||||
}
|
||||
s.view = source.NewView()
|
||||
s.initialized = true
|
||||
return &protocol.InitializeResult{
|
||||
Capabilities: protocol.ServerCapabilities{
|
||||
CompletionProvider: protocol.CompletionOptions{
|
||||
TriggerCharacters: []string{"."},
|
||||
},
|
||||
DefinitionProvider: true,
|
||||
DocumentFormattingProvider: true,
|
||||
DocumentRangeFormattingProvider: true,
|
||||
SignatureHelpProvider: protocol.SignatureHelpOptions{
|
||||
TriggerCharacters: []string{"("},
|
||||
},
|
||||
TextDocumentSync: protocol.TextDocumentSyncOptions{
|
||||
Change: float64(protocol.Full), // full contents of file sent on each update
|
||||
OpenClose: true,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *server) Initialized(context.Context, *protocol.InitializedParams) error {
|
||||
return nil // ignore
|
||||
}
|
||||
|
||||
func (s *server) Shutdown(context.Context) error {
|
||||
s.initializedMu.Lock()
|
||||
defer s.initializedMu.Unlock()
|
||||
if !s.initialized {
|
||||
return jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidRequest, "server not initialized")
|
||||
}
|
||||
s.initialized = false
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *server) Exit(ctx context.Context) error {
|
||||
if s.initialized {
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Exit(0)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *server) DidChangeWorkspaceFolders(context.Context, *protocol.DidChangeWorkspaceFoldersParams) error {
|
||||
return notImplemented("DidChangeWorkspaceFolders")
|
||||
}
|
||||
|
||||
func (s *server) DidChangeConfiguration(context.Context, *protocol.DidChangeConfigurationParams) error {
|
||||
return notImplemented("DidChangeConfiguration")
|
||||
}
|
||||
|
||||
func (s *server) DidChangeWatchedFiles(context.Context, *protocol.DidChangeWatchedFilesParams) error {
|
||||
return notImplemented("DidChangeWatchedFiles")
|
||||
}
|
||||
|
||||
func (s *server) Symbols(context.Context, *protocol.WorkspaceSymbolParams) ([]protocol.SymbolInformation, error) {
|
||||
return nil, notImplemented("Symbols")
|
||||
}
|
||||
|
||||
func (s *server) ExecuteCommand(context.Context, *protocol.ExecuteCommandParams) (interface{}, error) {
|
||||
return nil, notImplemented("ExecuteCommand")
|
||||
}
|
||||
|
||||
func (s *server) DidOpen(ctx context.Context, params *protocol.DidOpenTextDocumentParams) error {
|
||||
s.cacheAndDiagnoseFile(ctx, params.TextDocument.URI, params.TextDocument.Text)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *server) DidChange(ctx context.Context, params *protocol.DidChangeTextDocumentParams) error {
|
||||
if len(params.ContentChanges) < 1 {
|
||||
return jsonrpc2.NewErrorf(jsonrpc2.CodeInternalError, "no content changes provided")
|
||||
}
|
||||
// We expect the full content of file, i.e. a single change with no range.
|
||||
if change := params.ContentChanges[0]; change.RangeLength == 0 {
|
||||
s.cacheAndDiagnoseFile(ctx, params.TextDocument.URI, change.Text)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *server) cacheAndDiagnoseFile(ctx context.Context, uri protocol.DocumentURI, text string) {
|
||||
f := s.view.GetFile(source.URI(uri))
|
||||
f.SetContent([]byte(text))
|
||||
go func() {
|
||||
f := s.view.GetFile(source.URI(uri))
|
||||
reports, err := source.Diagnostics(ctx, s.view, f)
|
||||
if err != nil {
|
||||
return // handle error?
|
||||
}
|
||||
for filename, diagnostics := range reports {
|
||||
s.client.PublishDiagnostics(ctx, &protocol.PublishDiagnosticsParams{
|
||||
URI: protocol.DocumentURI(source.ToURI(filename)),
|
||||
Diagnostics: toProtocolDiagnostics(s.view, diagnostics),
|
||||
})
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (s *server) WillSave(context.Context, *protocol.WillSaveTextDocumentParams) error {
|
||||
return notImplemented("WillSave")
|
||||
}
|
||||
|
||||
func (s *server) WillSaveWaitUntil(context.Context, *protocol.WillSaveTextDocumentParams) ([]protocol.TextEdit, error) {
|
||||
return nil, notImplemented("WillSaveWaitUntil")
|
||||
}
|
||||
|
||||
func (s *server) DidSave(context.Context, *protocol.DidSaveTextDocumentParams) error {
|
||||
// TODO(rstambler): Should we clear the cache here?
|
||||
return nil // ignore
|
||||
}
|
||||
|
||||
func (s *server) DidClose(ctx context.Context, params *protocol.DidCloseTextDocumentParams) error {
|
||||
s.view.GetFile(source.URI(params.TextDocument.URI)).SetContent(nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *server) Completion(ctx context.Context, params *protocol.CompletionParams) (*protocol.CompletionList, error) {
|
||||
f := s.view.GetFile(source.URI(params.TextDocument.URI))
|
||||
tok, err := f.GetToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pos := fromProtocolPosition(tok, params.Position)
|
||||
items, err := source.Completion(ctx, f, pos)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &protocol.CompletionList{
|
||||
IsIncomplete: false,
|
||||
Items: toProtocolCompletionItems(items),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *server) CompletionResolve(context.Context, *protocol.CompletionItem) (*protocol.CompletionItem, error) {
|
||||
return nil, notImplemented("CompletionResolve")
|
||||
}
|
||||
|
||||
func (s *server) Hover(context.Context, *protocol.TextDocumentPositionParams) (*protocol.Hover, error) {
|
||||
return nil, notImplemented("Hover")
|
||||
}
|
||||
|
||||
func (s *server) SignatureHelp(ctx context.Context, params *protocol.TextDocumentPositionParams) (*protocol.SignatureHelp, error) {
|
||||
f := s.view.GetFile(source.URI(params.TextDocument.URI))
|
||||
tok, err := f.GetToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pos := fromProtocolPosition(tok, params.Position)
|
||||
info, err := source.SignatureHelp(ctx, f, pos)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return toProtocolSignatureHelp(info), nil
|
||||
}
|
||||
|
||||
func (s *server) Definition(ctx context.Context, params *protocol.TextDocumentPositionParams) ([]protocol.Location, error) {
|
||||
f := s.view.GetFile(source.URI(params.TextDocument.URI))
|
||||
tok, err := f.GetToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pos := fromProtocolPosition(tok, params.Position)
|
||||
r, err := source.Definition(ctx, f, pos)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []protocol.Location{toProtocolLocation(s.view.Config.Fset, r)}, nil
|
||||
}
|
||||
|
||||
func (s *server) TypeDefinition(context.Context, *protocol.TextDocumentPositionParams) ([]protocol.Location, error) {
|
||||
return nil, notImplemented("TypeDefinition")
|
||||
}
|
||||
|
||||
func (s *server) Implementation(context.Context, *protocol.TextDocumentPositionParams) ([]protocol.Location, error) {
|
||||
return nil, notImplemented("Implementation")
|
||||
}
|
||||
|
||||
func (s *server) References(context.Context, *protocol.ReferenceParams) ([]protocol.Location, error) {
|
||||
return nil, notImplemented("References")
|
||||
}
|
||||
|
||||
func (s *server) DocumentHighlight(context.Context, *protocol.TextDocumentPositionParams) ([]protocol.DocumentHighlight, error) {
|
||||
return nil, notImplemented("DocumentHighlight")
|
||||
}
|
||||
|
||||
func (s *server) DocumentSymbol(context.Context, *protocol.DocumentSymbolParams) ([]protocol.DocumentSymbol, error) {
|
||||
return nil, notImplemented("DocumentSymbol")
|
||||
}
|
||||
|
||||
func (s *server) CodeAction(context.Context, *protocol.CodeActionParams) ([]protocol.CodeAction, error) {
|
||||
return nil, notImplemented("CodeAction")
|
||||
}
|
||||
|
||||
func (s *server) CodeLens(context.Context, *protocol.CodeLensParams) ([]protocol.CodeLens, error) {
|
||||
return nil, nil // ignore
|
||||
}
|
||||
|
||||
func (s *server) CodeLensResolve(context.Context, *protocol.CodeLens) (*protocol.CodeLens, error) {
|
||||
return nil, notImplemented("CodeLensResolve")
|
||||
}
|
||||
|
||||
func (s *server) DocumentLink(context.Context, *protocol.DocumentLinkParams) ([]protocol.DocumentLink, error) {
|
||||
return nil, nil // ignore
|
||||
}
|
||||
|
||||
func (s *server) DocumentLinkResolve(context.Context, *protocol.DocumentLink) (*protocol.DocumentLink, error) {
|
||||
return nil, notImplemented("DocumentLinkResolve")
|
||||
}
|
||||
|
||||
func (s *server) DocumentColor(context.Context, *protocol.DocumentColorParams) ([]protocol.ColorInformation, error) {
|
||||
return nil, notImplemented("DocumentColor")
|
||||
}
|
||||
|
||||
func (s *server) ColorPresentation(context.Context, *protocol.ColorPresentationParams) ([]protocol.ColorPresentation, error) {
|
||||
return nil, notImplemented("ColorPresentation")
|
||||
}
|
||||
|
||||
func (s *server) Formatting(ctx context.Context, params *protocol.DocumentFormattingParams) ([]protocol.TextEdit, error) {
|
||||
return formatRange(ctx, s.view, params.TextDocument.URI, nil)
|
||||
}
|
||||
|
||||
func (s *server) RangeFormatting(ctx context.Context, params *protocol.DocumentRangeFormattingParams) ([]protocol.TextEdit, error) {
|
||||
return formatRange(ctx, s.view, params.TextDocument.URI, ¶ms.Range)
|
||||
}
|
||||
|
||||
// formatRange formats a document with a given range.
|
||||
func formatRange(ctx context.Context, v *source.View, uri protocol.DocumentURI, rng *protocol.Range) ([]protocol.TextEdit, error) {
|
||||
f := v.GetFile(source.URI(uri))
|
||||
tok, err := f.GetToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var r source.Range
|
||||
if rng == nil {
|
||||
r.Start = tok.Pos(0)
|
||||
r.End = tok.Pos(tok.Size())
|
||||
} else {
|
||||
r = fromProtocolRange(tok, *rng)
|
||||
}
|
||||
edits, err := source.Format(ctx, f, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return toProtocolEdits(tok, edits), nil
|
||||
}
|
||||
|
||||
func toProtocolEdits(f *token.File, edits []source.TextEdit) []protocol.TextEdit {
|
||||
if edits == nil {
|
||||
return nil
|
||||
}
|
||||
result := make([]protocol.TextEdit, len(edits))
|
||||
for i, edit := range edits {
|
||||
result[i] = protocol.TextEdit{
|
||||
Range: toProtocolRange(f, edit.Range),
|
||||
NewText: edit.NewText,
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (s *server) OnTypeFormatting(context.Context, *protocol.DocumentOnTypeFormattingParams) ([]protocol.TextEdit, error) {
|
||||
return nil, notImplemented("OnTypeFormatting")
|
||||
}
|
||||
|
||||
func (s *server) Rename(context.Context, *protocol.RenameParams) ([]protocol.WorkspaceEdit, error) {
|
||||
return nil, notImplemented("Rename")
|
||||
}
|
||||
|
||||
func (s *server) FoldingRanges(context.Context, *protocol.FoldingRangeRequestParam) ([]protocol.FoldingRange, error) {
|
||||
return nil, notImplemented("FoldingRanges")
|
||||
}
|
||||
|
||||
func notImplemented(method string) *jsonrpc2.Error {
|
||||
return jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not yet implemented", method)
|
||||
}
|
33
vendor/golang.org/x/tools/internal/lsp/signature_help.go
generated
vendored
33
vendor/golang.org/x/tools/internal/lsp/signature_help.go
generated
vendored
@@ -1,33 +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 lsp
|
||||
|
||||
import (
|
||||
"golang.org/x/tools/internal/lsp/protocol"
|
||||
"golang.org/x/tools/internal/lsp/source"
|
||||
)
|
||||
|
||||
func toProtocolSignatureHelp(info *source.SignatureInformation) *protocol.SignatureHelp {
|
||||
return &protocol.SignatureHelp{
|
||||
ActiveParameter: float64(info.ActiveParameter),
|
||||
ActiveSignature: 0, // there is only ever one possible signature
|
||||
Signatures: []protocol.SignatureInformation{
|
||||
{
|
||||
Label: info.Label,
|
||||
Parameters: toProtocolParameterInformation(info.Parameters),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func toProtocolParameterInformation(info []source.ParameterInformation) []protocol.ParameterInformation {
|
||||
var result []protocol.ParameterInformation
|
||||
for _, p := range info {
|
||||
result = append(result, protocol.ParameterInformation{
|
||||
Label: p.Label,
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
734
vendor/golang.org/x/tools/internal/lsp/source/completion.go
generated
vendored
734
vendor/golang.org/x/tools/internal/lsp/source/completion.go
generated
vendored
@@ -1,734 +0,0 @@
|
||||
package source
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/ast/astutil"
|
||||
)
|
||||
|
||||
type CompletionItem struct {
|
||||
Label, Detail string
|
||||
Kind CompletionItemKind
|
||||
Score int
|
||||
}
|
||||
|
||||
type CompletionItemKind int
|
||||
|
||||
const (
|
||||
Unknown CompletionItemKind = iota
|
||||
InterfaceCompletionItem
|
||||
StructCompletionItem
|
||||
TypeCompletionItem
|
||||
ConstantCompletionItem
|
||||
FieldCompletionItem
|
||||
ParameterCompletionItem
|
||||
VariableCompletionItem
|
||||
FunctionCompletionItem
|
||||
MethodCompletionItem
|
||||
PackageCompletionItem
|
||||
)
|
||||
|
||||
func Completion(ctx context.Context, f *File, pos token.Pos) ([]CompletionItem, error) {
|
||||
file, err := f.GetAST()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pkg, err := f.GetPackage()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items, _, err := completions(file, pos, pkg.Fset, pkg.Types, pkg.TypesInfo)
|
||||
return items, err
|
||||
}
|
||||
|
||||
type finder func(types.Object, float64, []CompletionItem) []CompletionItem
|
||||
|
||||
// completions returns the map of possible candidates for completion, given a
|
||||
// position, a file AST, and type information. The prefix is computed based on
|
||||
// the preceding identifier and can be used by the client to score the quality
|
||||
// of the completion. For instance, some clients may tolerate imperfect matches
|
||||
// as valid completion results, since users may make typos.
|
||||
func completions(file *ast.File, pos token.Pos, fset *token.FileSet, pkg *types.Package, info *types.Info) (items []CompletionItem, prefix string, err error) {
|
||||
path, _ := astutil.PathEnclosingInterval(file, pos, pos)
|
||||
if path == nil {
|
||||
return nil, "", fmt.Errorf("cannot find node enclosing position")
|
||||
}
|
||||
// If the position is not an identifier but immediately follows
|
||||
// an identifier or selector period (as is common when
|
||||
// requesting a completion), use the path to the preceding node.
|
||||
if _, ok := path[0].(*ast.Ident); !ok {
|
||||
if p, _ := astutil.PathEnclosingInterval(file, pos-1, pos-1); p != nil {
|
||||
switch p[0].(type) {
|
||||
case *ast.Ident, *ast.SelectorExpr:
|
||||
path = p // use preceding ident/selector
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save certain facts about the query position, including the expected type
|
||||
// of the completion result, the signature of the function enclosing the
|
||||
// position.
|
||||
typ := expectedType(path, pos, info)
|
||||
sig := enclosingFunction(path, pos, info)
|
||||
pkgStringer := qualifier(file, pkg, info)
|
||||
|
||||
seen := make(map[types.Object]bool)
|
||||
|
||||
// found adds a candidate completion.
|
||||
// Only the first candidate of a given name is considered.
|
||||
found := func(obj types.Object, weight float64, items []CompletionItem) []CompletionItem {
|
||||
if obj.Pkg() != nil && obj.Pkg() != pkg && !obj.Exported() {
|
||||
return items // inaccessible
|
||||
}
|
||||
if !seen[obj] {
|
||||
seen[obj] = true
|
||||
if typ != nil && matchingTypes(typ, obj.Type()) {
|
||||
weight *= 10
|
||||
}
|
||||
if !strings.HasPrefix(obj.Name(), prefix) {
|
||||
return items
|
||||
}
|
||||
item := formatCompletion(obj, pkgStringer, weight, func(v *types.Var) bool {
|
||||
return isParameter(sig, v)
|
||||
})
|
||||
items = append(items, item)
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
// The position is within a composite literal.
|
||||
if items, ok := complit(path, pos, pkg, info, found); ok {
|
||||
return items, "", nil
|
||||
}
|
||||
switch n := path[0].(type) {
|
||||
case *ast.Ident:
|
||||
// Set the filter prefix.
|
||||
prefix = n.Name[:pos-n.Pos()]
|
||||
|
||||
// Is this the Sel part of a selector?
|
||||
if sel, ok := path[1].(*ast.SelectorExpr); ok && sel.Sel == n {
|
||||
return selector(sel, info, found)
|
||||
}
|
||||
// reject defining identifiers
|
||||
if obj, ok := info.Defs[n]; ok {
|
||||
if v, ok := obj.(*types.Var); ok && v.IsField() {
|
||||
// An anonymous field is also a reference to a type.
|
||||
} else {
|
||||
of := ""
|
||||
if obj != nil {
|
||||
qual := types.RelativeTo(pkg)
|
||||
of += ", of " + types.ObjectString(obj, qual)
|
||||
}
|
||||
return nil, "", fmt.Errorf("this is a definition%s", of)
|
||||
}
|
||||
}
|
||||
|
||||
items = append(items, lexical(path, pos, pkg, info, found)...)
|
||||
|
||||
// The function name hasn't been typed yet, but the parens are there:
|
||||
// recv.‸(arg)
|
||||
case *ast.TypeAssertExpr:
|
||||
// Create a fake selector expression.
|
||||
return selector(&ast.SelectorExpr{X: n.X}, info, found)
|
||||
|
||||
case *ast.SelectorExpr:
|
||||
return selector(n, info, found)
|
||||
|
||||
default:
|
||||
// fallback to lexical completions
|
||||
return lexical(path, pos, pkg, info, found), "", nil
|
||||
}
|
||||
|
||||
return items, prefix, nil
|
||||
}
|
||||
|
||||
// selector finds completions for
|
||||
// the specified selector expression.
|
||||
// TODO(rstambler): Set the prefix filter correctly for selectors.
|
||||
func selector(sel *ast.SelectorExpr, info *types.Info, found finder) (items []CompletionItem, prefix string, err error) {
|
||||
// Is sel a qualified identifier?
|
||||
if id, ok := sel.X.(*ast.Ident); ok {
|
||||
if pkgname, ok := info.Uses[id].(*types.PkgName); ok {
|
||||
// Enumerate package members.
|
||||
// TODO(adonovan): can Imported() be nil?
|
||||
scope := pkgname.Imported().Scope()
|
||||
// TODO testcase: bad import
|
||||
for _, name := range scope.Names() {
|
||||
items = found(scope.Lookup(name), 1, items)
|
||||
}
|
||||
return items, prefix, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Inv: sel is a true selector.
|
||||
tv, ok := info.Types[sel.X]
|
||||
if !ok {
|
||||
return nil, "", fmt.Errorf("cannot resolve %s", sel.X)
|
||||
}
|
||||
|
||||
// methods of T
|
||||
mset := types.NewMethodSet(tv.Type)
|
||||
for i := 0; i < mset.Len(); i++ {
|
||||
items = found(mset.At(i).Obj(), 1, items)
|
||||
}
|
||||
|
||||
// methods of *T
|
||||
if tv.Addressable() && !types.IsInterface(tv.Type) && !isPointer(tv.Type) {
|
||||
mset := types.NewMethodSet(types.NewPointer(tv.Type))
|
||||
for i := 0; i < mset.Len(); i++ {
|
||||
items = found(mset.At(i).Obj(), 1, items)
|
||||
}
|
||||
}
|
||||
|
||||
// fields of T
|
||||
for _, f := range fieldSelections(tv.Type) {
|
||||
items = found(f, 1, items)
|
||||
}
|
||||
|
||||
return items, prefix, nil
|
||||
}
|
||||
|
||||
// lexical finds completions in the lexical environment.
|
||||
func lexical(path []ast.Node, pos token.Pos, pkg *types.Package, info *types.Info, found finder) (items []CompletionItem) {
|
||||
var scopes []*types.Scope // scopes[i], where i<len(path), is the possibly nil Scope of path[i].
|
||||
for _, n := range path {
|
||||
switch node := n.(type) {
|
||||
case *ast.FuncDecl:
|
||||
n = node.Type
|
||||
case *ast.FuncLit:
|
||||
n = node.Type
|
||||
}
|
||||
scopes = append(scopes, info.Scopes[n])
|
||||
}
|
||||
scopes = append(scopes, pkg.Scope())
|
||||
|
||||
// Process scopes innermost first.
|
||||
for i, scope := range scopes {
|
||||
if scope == nil {
|
||||
continue
|
||||
}
|
||||
for _, name := range scope.Names() {
|
||||
declScope, obj := scope.LookupParent(name, pos)
|
||||
if declScope != scope {
|
||||
continue // Name was declared in some enclosing scope, or not at all.
|
||||
}
|
||||
// If obj's type is invalid, find the AST node that defines the lexical block
|
||||
// containing the declaration of obj. Don't resolve types for packages.
|
||||
if _, ok := obj.(*types.PkgName); !ok && obj.Type() == types.Typ[types.Invalid] {
|
||||
// Match the scope to its ast.Node. If the scope is the package scope,
|
||||
// use the *ast.File as the starting node.
|
||||
var node ast.Node
|
||||
if i < len(path) {
|
||||
node = path[i]
|
||||
} else if i == len(path) { // use the *ast.File for package scope
|
||||
node = path[i-1]
|
||||
}
|
||||
if node != nil {
|
||||
if resolved := resolveInvalid(obj, node, info); resolved != nil {
|
||||
obj = resolved
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
score := 1.0
|
||||
// Rank builtins significantly lower than other results.
|
||||
if scope == types.Universe {
|
||||
score *= 0.1
|
||||
}
|
||||
items = found(obj, score, items)
|
||||
}
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
// complit finds completions for field names inside a composite literal.
|
||||
// It reports whether the node was handled as part of a composite literal.
|
||||
func complit(path []ast.Node, pos token.Pos, pkg *types.Package, info *types.Info, found finder) (items []CompletionItem, ok bool) {
|
||||
var lit *ast.CompositeLit
|
||||
|
||||
// First, determine if the pos is within a composite literal.
|
||||
switch n := path[0].(type) {
|
||||
case *ast.CompositeLit:
|
||||
// The enclosing node will be a composite literal if the user has just
|
||||
// opened the curly brace (e.g. &x{<>) or the completion request is triggered
|
||||
// from an already completed composite literal expression (e.g. &x{foo: 1, <>})
|
||||
//
|
||||
// If the cursor position is within a key-value expression inside the composite
|
||||
// literal, we try to determine if it is before or after the colon. If it is before
|
||||
// the colon, we return field completions. If the cursor does not belong to any
|
||||
// expression within the composite literal, we show composite literal completions.
|
||||
var expr ast.Expr
|
||||
for _, e := range n.Elts {
|
||||
if e.Pos() <= pos && pos < e.End() {
|
||||
expr = e
|
||||
break
|
||||
}
|
||||
}
|
||||
lit = n
|
||||
// If the position belongs to a key-value expression and is after the colon,
|
||||
// don't show composite literal completions.
|
||||
if kv, ok := expr.(*ast.KeyValueExpr); ok && pos > kv.Colon {
|
||||
lit = nil
|
||||
}
|
||||
case *ast.KeyValueExpr:
|
||||
// If the enclosing node is a key-value expression (e.g. &x{foo: <>}),
|
||||
// we show composite literal completions if the cursor position is before the colon.
|
||||
if len(path) > 1 && pos < n.Colon {
|
||||
if l, ok := path[1].(*ast.CompositeLit); ok {
|
||||
lit = l
|
||||
}
|
||||
}
|
||||
case *ast.Ident:
|
||||
// If the enclosing node is an identifier, it can either be an identifier that is
|
||||
// part of a composite literal (e.g. &x{fo<>}), or it can be an identifier that is
|
||||
// part of a key-value expression, which is part of a composite literal (e.g. &x{foo: ba<>).
|
||||
// We handle both of these cases, showing composite literal completions only if
|
||||
// the cursor position for the key-value expression is before the colon.
|
||||
if len(path) > 1 {
|
||||
if l, ok := path[1].(*ast.CompositeLit); ok {
|
||||
lit = l
|
||||
} else if len(path) > 2 {
|
||||
if l, ok := path[2].(*ast.CompositeLit); ok {
|
||||
// Confirm that cursor position is inside curly braces.
|
||||
if l.Lbrace <= pos && pos <= l.Rbrace {
|
||||
lit = l
|
||||
if kv, ok := path[1].(*ast.KeyValueExpr); ok {
|
||||
if pos > kv.Colon {
|
||||
lit = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// We are not in a composite literal.
|
||||
if lit == nil {
|
||||
return nil, false
|
||||
}
|
||||
// Mark fields of the composite literal that have already been set,
|
||||
// except for the current field.
|
||||
hasKeys := false // true if the composite literal already has key-value pairs
|
||||
addedFields := make(map[*types.Var]bool)
|
||||
for _, el := range lit.Elts {
|
||||
if kv, ok := el.(*ast.KeyValueExpr); ok {
|
||||
hasKeys = true
|
||||
if kv.Pos() <= pos && pos <= kv.End() {
|
||||
continue
|
||||
}
|
||||
if key, ok := kv.Key.(*ast.Ident); ok {
|
||||
if used, ok := info.Uses[key]; ok {
|
||||
if usedVar, ok := used.(*types.Var); ok {
|
||||
addedFields[usedVar] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the underlying type of the composite literal is a struct,
|
||||
// collect completions for the fields of this struct.
|
||||
if tv, ok := info.Types[lit]; ok {
|
||||
var structPkg *types.Package // package containing the struct type declaration
|
||||
if s, ok := tv.Type.Underlying().(*types.Struct); ok {
|
||||
for i := 0; i < s.NumFields(); i++ {
|
||||
field := s.Field(i)
|
||||
if i == 0 {
|
||||
structPkg = field.Pkg()
|
||||
}
|
||||
if !addedFields[field] {
|
||||
items = found(field, 10, items)
|
||||
}
|
||||
}
|
||||
// Add lexical completions if the user hasn't typed a key value expression
|
||||
// and if the struct fields are defined in the same package as the user is in.
|
||||
if !hasKeys && structPkg == pkg {
|
||||
items = append(items, lexical(path, pos, pkg, info, found)...)
|
||||
}
|
||||
return items, true
|
||||
}
|
||||
}
|
||||
return items, false
|
||||
}
|
||||
|
||||
// formatCompletion creates a completion item for a given types.Object.
|
||||
func formatCompletion(obj types.Object, qualifier types.Qualifier, score float64, isParam func(*types.Var) bool) CompletionItem {
|
||||
label := obj.Name()
|
||||
detail := types.TypeString(obj.Type(), qualifier)
|
||||
var kind CompletionItemKind
|
||||
|
||||
switch o := obj.(type) {
|
||||
case *types.TypeName:
|
||||
detail, kind = formatType(o.Type(), qualifier)
|
||||
if obj.Parent() == types.Universe {
|
||||
detail = ""
|
||||
}
|
||||
case *types.Const:
|
||||
if obj.Parent() == types.Universe {
|
||||
detail = ""
|
||||
} else {
|
||||
val := o.Val().ExactString()
|
||||
if !strings.Contains(val, "\\n") { // skip any multiline constants
|
||||
label += " = " + o.Val().ExactString()
|
||||
}
|
||||
}
|
||||
kind = ConstantCompletionItem
|
||||
case *types.Var:
|
||||
if _, ok := o.Type().(*types.Struct); ok {
|
||||
detail = "struct{...}" // for anonymous structs
|
||||
}
|
||||
if o.IsField() {
|
||||
kind = FieldCompletionItem
|
||||
} else if isParam(o) {
|
||||
kind = ParameterCompletionItem
|
||||
} else {
|
||||
kind = VariableCompletionItem
|
||||
}
|
||||
case *types.Func:
|
||||
if sig, ok := o.Type().(*types.Signature); ok {
|
||||
label += formatParams(sig.Params(), sig.Variadic(), qualifier)
|
||||
detail = strings.Trim(types.TypeString(sig.Results(), qualifier), "()")
|
||||
kind = FunctionCompletionItem
|
||||
if sig.Recv() != nil {
|
||||
kind = MethodCompletionItem
|
||||
}
|
||||
}
|
||||
case *types.Builtin:
|
||||
item, ok := builtinDetails[obj.Name()]
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
label, detail = item.label, item.detail
|
||||
kind = FunctionCompletionItem
|
||||
case *types.PkgName:
|
||||
kind = PackageCompletionItem
|
||||
detail = fmt.Sprintf("\"%s\"", o.Imported().Path())
|
||||
case *types.Nil:
|
||||
kind = VariableCompletionItem
|
||||
detail = ""
|
||||
}
|
||||
detail = strings.TrimPrefix(detail, "untyped ")
|
||||
|
||||
return CompletionItem{
|
||||
Label: label,
|
||||
Detail: detail,
|
||||
Kind: kind,
|
||||
}
|
||||
}
|
||||
|
||||
// formatType returns the detail and kind for an object of type *types.TypeName.
|
||||
func formatType(typ types.Type, qualifier types.Qualifier) (detail string, kind CompletionItemKind) {
|
||||
if types.IsInterface(typ) {
|
||||
detail = "interface{...}"
|
||||
kind = InterfaceCompletionItem
|
||||
} else if _, ok := typ.(*types.Struct); ok {
|
||||
detail = "struct{...}"
|
||||
kind = StructCompletionItem
|
||||
} else if typ != typ.Underlying() {
|
||||
detail, kind = formatType(typ.Underlying(), qualifier)
|
||||
} else {
|
||||
detail = types.TypeString(typ, qualifier)
|
||||
kind = TypeCompletionItem
|
||||
}
|
||||
return detail, kind
|
||||
}
|
||||
|
||||
// formatParams correctly format the parameters of a function.
|
||||
func formatParams(t *types.Tuple, variadic bool, qualifier types.Qualifier) string {
|
||||
var b bytes.Buffer
|
||||
b.WriteByte('(')
|
||||
for i := 0; i < t.Len(); i++ {
|
||||
if i > 0 {
|
||||
b.WriteString(", ")
|
||||
}
|
||||
el := t.At(i)
|
||||
typ := types.TypeString(el.Type(), qualifier)
|
||||
// Handle a variadic parameter (can only be the final parameter).
|
||||
if variadic && i == t.Len()-1 {
|
||||
typ = strings.Replace(typ, "[]", "...", 1)
|
||||
}
|
||||
fmt.Fprintf(&b, "%v %v", el.Name(), typ)
|
||||
}
|
||||
b.WriteByte(')')
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// isParameter returns true if the given *types.Var is a parameter to the given
|
||||
// *types.Signature.
|
||||
func isParameter(sig *types.Signature, v *types.Var) bool {
|
||||
if sig == nil {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < sig.Params().Len(); i++ {
|
||||
if sig.Params().At(i) == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// qualifier returns a function that appropriately formats a types.PkgName
|
||||
// appearing in a *ast.File.
|
||||
func qualifier(f *ast.File, pkg *types.Package, info *types.Info) types.Qualifier {
|
||||
// Construct mapping of import paths to their defined or implicit names.
|
||||
imports := make(map[*types.Package]string)
|
||||
for _, imp := range f.Imports {
|
||||
var obj types.Object
|
||||
if imp.Name != nil {
|
||||
obj = info.Defs[imp.Name]
|
||||
} else {
|
||||
obj = info.Implicits[imp]
|
||||
}
|
||||
if pkgname, ok := obj.(*types.PkgName); ok {
|
||||
imports[pkgname.Imported()] = pkgname.Name()
|
||||
}
|
||||
}
|
||||
// Define qualifier to replace full package paths with names of the imports.
|
||||
return func(pkg *types.Package) string {
|
||||
if pkg == pkg {
|
||||
return ""
|
||||
}
|
||||
if name, ok := imports[pkg]; ok {
|
||||
return name
|
||||
}
|
||||
return pkg.Name()
|
||||
}
|
||||
}
|
||||
|
||||
// enclosingFunction returns the signature of the function enclosing the given
|
||||
// position.
|
||||
func enclosingFunction(path []ast.Node, pos token.Pos, info *types.Info) *types.Signature {
|
||||
for _, node := range path {
|
||||
switch t := node.(type) {
|
||||
case *ast.FuncDecl:
|
||||
if obj, ok := info.Defs[t.Name]; ok {
|
||||
return obj.Type().(*types.Signature)
|
||||
}
|
||||
case *ast.FuncLit:
|
||||
if typ, ok := info.Types[t]; ok {
|
||||
return typ.Type.(*types.Signature)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// expectedType returns the expected type for an expression at the query position.
|
||||
func expectedType(path []ast.Node, pos token.Pos, info *types.Info) types.Type {
|
||||
for i, node := range path {
|
||||
if i == 2 {
|
||||
break
|
||||
}
|
||||
switch expr := node.(type) {
|
||||
case *ast.BinaryExpr:
|
||||
// Determine if query position comes from left or right of op.
|
||||
e := expr.X
|
||||
if pos < expr.OpPos {
|
||||
e = expr.Y
|
||||
}
|
||||
if tv, ok := info.Types[e]; ok {
|
||||
return tv.Type
|
||||
}
|
||||
case *ast.AssignStmt:
|
||||
// Only rank completions if you are on the right side of the token.
|
||||
if pos <= expr.TokPos {
|
||||
break
|
||||
}
|
||||
i := exprAtPos(pos, expr.Rhs)
|
||||
if i >= len(expr.Lhs) {
|
||||
i = len(expr.Lhs) - 1
|
||||
}
|
||||
if tv, ok := info.Types[expr.Lhs[i]]; ok {
|
||||
return tv.Type
|
||||
}
|
||||
case *ast.CallExpr:
|
||||
if tv, ok := info.Types[expr.Fun]; ok {
|
||||
if sig, ok := tv.Type.(*types.Signature); ok {
|
||||
if sig.Params().Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
i := exprAtPos(pos, expr.Args)
|
||||
// Make sure not to run past the end of expected parameters.
|
||||
if i >= sig.Params().Len() {
|
||||
i = sig.Params().Len() - 1
|
||||
}
|
||||
return sig.Params().At(i).Type()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// matchingTypes reports whether actual is a good candidate type
|
||||
// for a completion in a context of the expected type.
|
||||
func matchingTypes(expected, actual types.Type) bool {
|
||||
// Use a function's return type as its type.
|
||||
if sig, ok := actual.(*types.Signature); ok {
|
||||
if sig.Results().Len() == 1 {
|
||||
actual = sig.Results().At(0).Type()
|
||||
}
|
||||
}
|
||||
return types.Identical(types.Default(expected), types.Default(actual))
|
||||
}
|
||||
|
||||
// exprAtPos returns the index of the expression containing pos.
|
||||
func exprAtPos(pos token.Pos, args []ast.Expr) int {
|
||||
for i, expr := range args {
|
||||
if expr.Pos() <= pos && pos <= expr.End() {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return len(args)
|
||||
}
|
||||
|
||||
// fieldSelections returns the set of fields that can
|
||||
// be selected from a value of type T.
|
||||
func fieldSelections(T types.Type) (fields []*types.Var) {
|
||||
// TODO(adonovan): this algorithm doesn't exclude ambiguous
|
||||
// selections that match more than one field/method.
|
||||
// types.NewSelectionSet should do that for us.
|
||||
|
||||
seen := make(map[types.Type]bool) // for termination on recursive types
|
||||
var visit func(T types.Type)
|
||||
visit = func(T types.Type) {
|
||||
if !seen[T] {
|
||||
seen[T] = true
|
||||
if T, ok := deref(T).Underlying().(*types.Struct); ok {
|
||||
for i := 0; i < T.NumFields(); i++ {
|
||||
f := T.Field(i)
|
||||
fields = append(fields, f)
|
||||
if f.Anonymous() {
|
||||
visit(f.Type())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
visit(T)
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
func isPointer(T types.Type) bool {
|
||||
_, ok := T.(*types.Pointer)
|
||||
return ok
|
||||
}
|
||||
|
||||
// deref returns a pointer's element type; otherwise it returns typ.
|
||||
func deref(typ types.Type) types.Type {
|
||||
if p, ok := typ.Underlying().(*types.Pointer); ok {
|
||||
return p.Elem()
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
// resolveInvalid traverses the node of the AST that defines the scope
|
||||
// containing the declaration of obj, and attempts to find a user-friendly
|
||||
// name for its invalid type. The resulting Object and its Type are fake.
|
||||
func resolveInvalid(obj types.Object, node ast.Node, info *types.Info) types.Object {
|
||||
// Construct a fake type for the object and return a fake object with this type.
|
||||
formatResult := func(expr ast.Expr) types.Object {
|
||||
var typename string
|
||||
switch t := expr.(type) {
|
||||
case *ast.SelectorExpr:
|
||||
typename = fmt.Sprintf("%s.%s", t.X, t.Sel)
|
||||
case *ast.Ident:
|
||||
typename = t.String()
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
typ := types.NewNamed(types.NewTypeName(token.NoPos, obj.Pkg(), typename, nil), nil, nil)
|
||||
return types.NewVar(obj.Pos(), obj.Pkg(), obj.Name(), typ)
|
||||
}
|
||||
var resultExpr ast.Expr
|
||||
ast.Inspect(node, func(node ast.Node) bool {
|
||||
switch n := node.(type) {
|
||||
case *ast.ValueSpec:
|
||||
for _, name := range n.Names {
|
||||
if info.Defs[name] == obj {
|
||||
resultExpr = n.Type
|
||||
}
|
||||
}
|
||||
return false
|
||||
case *ast.Field: // This case handles parameters and results of a FuncDecl or FuncLit.
|
||||
for _, name := range n.Names {
|
||||
if info.Defs[name] == obj {
|
||||
resultExpr = n.Type
|
||||
}
|
||||
}
|
||||
return false
|
||||
// TODO(rstambler): Handle range statements.
|
||||
default:
|
||||
return true
|
||||
}
|
||||
})
|
||||
return formatResult(resultExpr)
|
||||
}
|
||||
|
||||
type itemDetails struct {
|
||||
label, detail string
|
||||
}
|
||||
|
||||
var builtinDetails = map[string]itemDetails{
|
||||
"append": { // append(slice []T, elems ...T)
|
||||
label: "append(slice []T, elems ...T)",
|
||||
detail: "[]T",
|
||||
},
|
||||
"cap": { // cap(v []T) int
|
||||
label: "cap(v []T)",
|
||||
detail: "int",
|
||||
},
|
||||
"close": { // close(c chan<- T)
|
||||
label: "close(c chan<- T)",
|
||||
},
|
||||
"complex": { // complex(r, i float64) complex128
|
||||
label: "complex(real, imag float64)",
|
||||
detail: "complex128",
|
||||
},
|
||||
"copy": { // copy(dst, src []T) int
|
||||
label: "copy(dst, src []T)",
|
||||
detail: "int",
|
||||
},
|
||||
"delete": { // delete(m map[T]T1, key T)
|
||||
label: "delete(m map[K]V, key K)",
|
||||
},
|
||||
"imag": { // imag(c complex128) float64
|
||||
label: "imag(complex128)",
|
||||
detail: "float64",
|
||||
},
|
||||
"len": { // len(v T) int
|
||||
label: "len(T)",
|
||||
detail: "int",
|
||||
},
|
||||
"make": { // make(t T, size ...int) T
|
||||
label: "make(t T, size ...int)",
|
||||
detail: "T",
|
||||
},
|
||||
"new": { // new(T) *T
|
||||
label: "new(T)",
|
||||
detail: "*T",
|
||||
},
|
||||
"panic": { // panic(v interface{})
|
||||
label: "panic(interface{})",
|
||||
},
|
||||
"print": { // print(args ...T)
|
||||
label: "print(args ...T)",
|
||||
},
|
||||
"println": { // println(args ...T)
|
||||
label: "println(args ...T)",
|
||||
},
|
||||
"real": { // real(c complex128) float64
|
||||
label: "real(complex128)",
|
||||
detail: "float64",
|
||||
},
|
||||
"recover": { // recover() interface{}
|
||||
label: "recover()",
|
||||
detail: "interface{}",
|
||||
},
|
||||
}
|
121
vendor/golang.org/x/tools/internal/lsp/source/definition.go
generated
vendored
121
vendor/golang.org/x/tools/internal/lsp/source/definition.go
generated
vendored
@@ -1,121 +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 source
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"io/ioutil"
|
||||
|
||||
"golang.org/x/tools/go/ast/astutil"
|
||||
)
|
||||
|
||||
func Definition(ctx context.Context, f *File, pos token.Pos) (Range, error) {
|
||||
fAST, err := f.GetAST()
|
||||
if err != nil {
|
||||
return Range{}, err
|
||||
}
|
||||
pkg, err := f.GetPackage()
|
||||
if err != nil {
|
||||
return Range{}, err
|
||||
}
|
||||
i, err := findIdentifier(fAST, pos)
|
||||
if err != nil {
|
||||
return Range{}, err
|
||||
}
|
||||
if i.ident == nil {
|
||||
return Range{}, fmt.Errorf("definition was not a valid identifier")
|
||||
}
|
||||
obj := pkg.TypesInfo.ObjectOf(i.ident)
|
||||
if obj == nil {
|
||||
return Range{}, fmt.Errorf("no object")
|
||||
}
|
||||
if i.wasEmbeddedField {
|
||||
// the original position was on the embedded field declaration
|
||||
// so we try to dig out the type and jump to that instead
|
||||
if v, ok := obj.(*types.Var); ok {
|
||||
if n, ok := v.Type().(*types.Named); ok {
|
||||
obj = n.Obj()
|
||||
}
|
||||
}
|
||||
}
|
||||
return objToRange(f.view.Config.Fset, obj), nil
|
||||
}
|
||||
|
||||
// ident returns the ident plus any extra information needed
|
||||
type ident struct {
|
||||
ident *ast.Ident
|
||||
wasEmbeddedField bool
|
||||
}
|
||||
|
||||
// findIdentifier returns the ast.Ident for a position
|
||||
// in a file, accounting for a potentially incomplete selector.
|
||||
func findIdentifier(f *ast.File, pos token.Pos) (ident, error) {
|
||||
m, err := checkIdentifier(f, pos)
|
||||
if err != nil {
|
||||
return ident{}, err
|
||||
}
|
||||
if m.ident != nil {
|
||||
return m, nil
|
||||
}
|
||||
// If the position is not an identifier but immediately follows
|
||||
// an identifier or selector period (as is common when
|
||||
// requesting a completion), use the path to the preceding node.
|
||||
return checkIdentifier(f, pos-1)
|
||||
}
|
||||
|
||||
// checkIdentifier checks a single position for a potential identifier.
|
||||
func checkIdentifier(f *ast.File, pos token.Pos) (ident, error) {
|
||||
path, _ := astutil.PathEnclosingInterval(f, pos, pos)
|
||||
result := ident{}
|
||||
if path == nil {
|
||||
return result, fmt.Errorf("can't find node enclosing position")
|
||||
}
|
||||
switch node := path[0].(type) {
|
||||
case *ast.Ident:
|
||||
result.ident = node
|
||||
case *ast.SelectorExpr:
|
||||
result.ident = node.Sel
|
||||
}
|
||||
if result.ident != nil {
|
||||
for _, n := range path[1:] {
|
||||
if field, ok := n.(*ast.Field); ok {
|
||||
result.wasEmbeddedField = len(field.Names) == 0
|
||||
}
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func objToRange(fSet *token.FileSet, obj types.Object) Range {
|
||||
p := obj.Pos()
|
||||
f := fSet.File(p)
|
||||
pos := f.Position(p)
|
||||
if pos.Column == 1 {
|
||||
// Column is 1, so we probably do not have full position information
|
||||
// Currently exportdata does not store the column.
|
||||
// For now we attempt to read the original source and find the identifier
|
||||
// within the line. If we find it we patch the column to match its offset.
|
||||
// TODO: we have probably already added the full data for the file to the
|
||||
// fileset, we ought to track it rather than adding it over and over again
|
||||
// TODO: if we parse from source, we will never need this hack
|
||||
if src, err := ioutil.ReadFile(pos.Filename); err == nil {
|
||||
newF := fSet.AddFile(pos.Filename, -1, len(src))
|
||||
newF.SetLinesForContent(src)
|
||||
lineStart := lineStart(newF, pos.Line)
|
||||
offset := newF.Offset(lineStart)
|
||||
col := bytes.Index(src[offset:], []byte(obj.Name()))
|
||||
p = newF.Pos(offset + col)
|
||||
}
|
||||
}
|
||||
return Range{
|
||||
Start: p,
|
||||
End: p + token.Pos(len([]byte(obj.Name()))), // TODO: use real range of obj
|
||||
}
|
||||
}
|
148
vendor/golang.org/x/tools/internal/lsp/source/diagnostics.go
generated
vendored
148
vendor/golang.org/x/tools/internal/lsp/source/diagnostics.go
generated
vendored
@@ -1,148 +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 source
|
||||
|
||||
import (
|
||||
"context"
|
||||
"go/token"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/packages"
|
||||
)
|
||||
|
||||
type Diagnostic struct {
|
||||
Range Range
|
||||
Severity DiagnosticSeverity
|
||||
Message string
|
||||
}
|
||||
|
||||
type DiagnosticSeverity int
|
||||
|
||||
const (
|
||||
SeverityError DiagnosticSeverity = iota
|
||||
SeverityWarning
|
||||
SeverityHint
|
||||
SeverityInformation
|
||||
)
|
||||
|
||||
func Diagnostics(ctx context.Context, v *View, f *File) (map[string][]Diagnostic, error) {
|
||||
pkg, err := f.GetPackage()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Prepare the reports we will send for this package.
|
||||
reports := make(map[string][]Diagnostic)
|
||||
for _, filename := range pkg.GoFiles {
|
||||
reports[filename] = []Diagnostic{}
|
||||
}
|
||||
var parseErrors, typeErrors []packages.Error
|
||||
for _, err := range pkg.Errors {
|
||||
switch err.Kind {
|
||||
case packages.ParseError:
|
||||
parseErrors = append(parseErrors, err)
|
||||
case packages.TypeError:
|
||||
typeErrors = append(typeErrors, err)
|
||||
default:
|
||||
// ignore other types of errors
|
||||
continue
|
||||
}
|
||||
}
|
||||
// Don't report type errors if there are parse errors.
|
||||
diags := typeErrors
|
||||
if len(parseErrors) > 0 {
|
||||
diags = parseErrors
|
||||
}
|
||||
for _, diag := range diags {
|
||||
filename, start := v.errorPos(diag)
|
||||
// TODO(rstambler): Add support for diagnostic ranges.
|
||||
end := start
|
||||
diagnostic := Diagnostic{
|
||||
Range: Range{
|
||||
Start: start,
|
||||
End: end,
|
||||
},
|
||||
Message: diag.Msg,
|
||||
Severity: SeverityError,
|
||||
}
|
||||
if _, ok := reports[filename]; ok {
|
||||
reports[filename] = append(reports[filename], diagnostic)
|
||||
}
|
||||
}
|
||||
return reports, nil
|
||||
}
|
||||
|
||||
func (v *View) errorPos(pkgErr packages.Error) (string, token.Pos) {
|
||||
remainder1, first, hasLine := chop(pkgErr.Pos)
|
||||
remainder2, second, hasColumn := chop(remainder1)
|
||||
var pos token.Position
|
||||
if hasLine && hasColumn {
|
||||
pos.Filename = remainder2
|
||||
pos.Line = second
|
||||
pos.Column = first
|
||||
} else if hasLine {
|
||||
pos.Filename = remainder1
|
||||
pos.Line = first
|
||||
}
|
||||
f := v.GetFile(ToURI(pos.Filename))
|
||||
if f == nil {
|
||||
return "", token.NoPos
|
||||
}
|
||||
tok, err := f.GetToken()
|
||||
if err != nil {
|
||||
return "", token.NoPos
|
||||
}
|
||||
return pos.Filename, fromTokenPosition(tok, pos)
|
||||
}
|
||||
|
||||
func chop(text string) (remainder string, value int, ok bool) {
|
||||
i := strings.LastIndex(text, ":")
|
||||
if i < 0 {
|
||||
return text, 0, false
|
||||
}
|
||||
v, err := strconv.ParseInt(text[i+1:], 10, 64)
|
||||
if err != nil {
|
||||
return text, 0, false
|
||||
}
|
||||
return text[:i], int(v), true
|
||||
}
|
||||
|
||||
// fromTokenPosition converts a token.Position (1-based line and column
|
||||
// number) to a token.Pos (byte offset value).
|
||||
// It requires the token file the pos belongs to in order to do this.
|
||||
func fromTokenPosition(f *token.File, pos token.Position) token.Pos {
|
||||
line := lineStart(f, pos.Line)
|
||||
return line + token.Pos(pos.Column-1) // TODO: this is wrong, bytes not characters
|
||||
}
|
||||
|
||||
// this functionality was borrowed from the analysisutil package
|
||||
func lineStart(f *token.File, line int) token.Pos {
|
||||
// Use binary search to find the start offset of this line.
|
||||
//
|
||||
// TODO(adonovan): eventually replace this function with the
|
||||
// simpler and more efficient (*go/token.File).LineStart, added
|
||||
// in go1.12.
|
||||
|
||||
min := 0 // inclusive
|
||||
max := f.Size() // exclusive
|
||||
for {
|
||||
offset := (min + max) / 2
|
||||
pos := f.Pos(offset)
|
||||
posn := f.Position(pos)
|
||||
if posn.Line == line {
|
||||
return pos - (token.Pos(posn.Column) - 1)
|
||||
}
|
||||
|
||||
if min+1 >= max {
|
||||
return token.NoPos
|
||||
}
|
||||
|
||||
if posn.Line < line {
|
||||
min = offset
|
||||
} else {
|
||||
max = offset
|
||||
}
|
||||
}
|
||||
}
|
131
vendor/golang.org/x/tools/internal/lsp/source/file.go
generated
vendored
131
vendor/golang.org/x/tools/internal/lsp/source/file.go
generated
vendored
@@ -1,131 +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 source
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"io/ioutil"
|
||||
|
||||
"golang.org/x/tools/go/packages"
|
||||
)
|
||||
|
||||
// File holds all the information we know about a file.
|
||||
type File struct {
|
||||
URI URI
|
||||
view *View
|
||||
active bool
|
||||
content []byte
|
||||
ast *ast.File
|
||||
token *token.File
|
||||
pkg *packages.Package
|
||||
}
|
||||
|
||||
// Range represents a start and end position.
|
||||
// Because Range is based purely on two token.Pos entries, it is not self
|
||||
// contained. You need access to a token.FileSet to regain the file
|
||||
// information.
|
||||
type Range struct {
|
||||
Start token.Pos
|
||||
End token.Pos
|
||||
}
|
||||
|
||||
// TextEdit represents a change to a section of a document.
|
||||
// The text within the specified range should be replaced by the supplied new text.
|
||||
type TextEdit struct {
|
||||
Range Range
|
||||
NewText string
|
||||
}
|
||||
|
||||
// SetContent sets the overlay contents for a file.
|
||||
// Setting it to nil will revert it to the on disk contents, and remove it
|
||||
// from the active set.
|
||||
func (f *File) SetContent(content []byte) {
|
||||
f.view.mu.Lock()
|
||||
defer f.view.mu.Unlock()
|
||||
f.content = content
|
||||
// the ast and token fields are invalid
|
||||
f.ast = nil
|
||||
f.token = nil
|
||||
f.pkg = nil
|
||||
// and we might need to update the overlay
|
||||
switch {
|
||||
case f.active && content == nil:
|
||||
// we were active, and want to forget the content
|
||||
f.active = false
|
||||
if filename, err := f.URI.Filename(); err == nil {
|
||||
delete(f.view.Config.Overlay, filename)
|
||||
}
|
||||
f.content = nil
|
||||
case content != nil:
|
||||
// an active overlay, update the map
|
||||
f.active = true
|
||||
if filename, err := f.URI.Filename(); err == nil {
|
||||
f.view.Config.Overlay[filename] = f.content
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read returns the contents of the file, reading it from file system if needed.
|
||||
func (f *File) Read() ([]byte, error) {
|
||||
f.view.mu.Lock()
|
||||
defer f.view.mu.Unlock()
|
||||
return f.read()
|
||||
}
|
||||
|
||||
func (f *File) GetToken() (*token.File, error) {
|
||||
f.view.mu.Lock()
|
||||
defer f.view.mu.Unlock()
|
||||
if f.token == nil {
|
||||
if err := f.view.parse(f.URI); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if f.token == nil {
|
||||
return nil, fmt.Errorf("failed to find or parse %v", f.URI)
|
||||
}
|
||||
}
|
||||
return f.token, nil
|
||||
}
|
||||
|
||||
func (f *File) GetAST() (*ast.File, error) {
|
||||
f.view.mu.Lock()
|
||||
defer f.view.mu.Unlock()
|
||||
if f.ast == nil {
|
||||
if err := f.view.parse(f.URI); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return f.ast, nil
|
||||
}
|
||||
|
||||
func (f *File) GetPackage() (*packages.Package, error) {
|
||||
f.view.mu.Lock()
|
||||
defer f.view.mu.Unlock()
|
||||
if f.pkg == nil {
|
||||
if err := f.view.parse(f.URI); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return f.pkg, nil
|
||||
}
|
||||
|
||||
// read is the internal part of Read that presumes the lock is already held
|
||||
func (f *File) read() ([]byte, error) {
|
||||
if f.content != nil {
|
||||
return f.content, nil
|
||||
}
|
||||
// we don't know the content yet, so read it
|
||||
filename, err := f.URI.Filename()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
content, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.content = content
|
||||
return f.content, nil
|
||||
}
|
59
vendor/golang.org/x/tools/internal/lsp/source/format.go
generated
vendored
59
vendor/golang.org/x/tools/internal/lsp/source/format.go
generated
vendored
@@ -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 source
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/format"
|
||||
|
||||
"golang.org/x/tools/go/ast/astutil"
|
||||
)
|
||||
|
||||
// Format formats a document with a given range.
|
||||
func Format(ctx context.Context, f *File, rng Range) ([]TextEdit, error) {
|
||||
fAST, err := f.GetAST()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
path, exact := astutil.PathEnclosingInterval(fAST, rng.Start, rng.End)
|
||||
if !exact || len(path) == 0 {
|
||||
return nil, fmt.Errorf("no exact AST node matching the specified range")
|
||||
}
|
||||
node := path[0]
|
||||
// format.Node can fail when the AST contains a bad expression or
|
||||
// statement. For now, we preemptively check for one.
|
||||
// TODO(rstambler): This should really return an error from format.Node.
|
||||
var isBad bool
|
||||
ast.Inspect(node, func(n ast.Node) bool {
|
||||
switch n.(type) {
|
||||
case *ast.BadDecl, *ast.BadExpr, *ast.BadStmt:
|
||||
isBad = true
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
})
|
||||
if isBad {
|
||||
return nil, fmt.Errorf("unable to format file due to a badly formatted AST")
|
||||
}
|
||||
// format.Node changes slightly from one release to another, so the version
|
||||
// of Go used to build the LSP server will determine how it formats code.
|
||||
// This should be acceptable for all users, who likely be prompted to rebuild
|
||||
// the LSP server on each Go release.
|
||||
buf := &bytes.Buffer{}
|
||||
if err := format.Node(buf, f.view.Config.Fset, node); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// TODO(rstambler): Compute text edits instead of replacing whole file.
|
||||
return []TextEdit{
|
||||
{
|
||||
Range: rng,
|
||||
NewText: buf.String(),
|
||||
},
|
||||
}, nil
|
||||
}
|
118
vendor/golang.org/x/tools/internal/lsp/source/signature_help.go
generated
vendored
118
vendor/golang.org/x/tools/internal/lsp/source/signature_help.go
generated
vendored
@@ -1,118 +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 source
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/go/ast/astutil"
|
||||
)
|
||||
|
||||
type SignatureInformation struct {
|
||||
Label string
|
||||
Parameters []ParameterInformation
|
||||
ActiveParameter int
|
||||
}
|
||||
|
||||
type ParameterInformation struct {
|
||||
Label string
|
||||
}
|
||||
|
||||
func SignatureHelp(ctx context.Context, f *File, pos token.Pos) (*SignatureInformation, error) {
|
||||
fAST, err := f.GetAST()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pkg, err := f.GetPackage()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Find a call expression surrounding the query position.
|
||||
var callExpr *ast.CallExpr
|
||||
path, _ := astutil.PathEnclosingInterval(fAST, pos, pos)
|
||||
if path == nil {
|
||||
return nil, fmt.Errorf("cannot find node enclosing position")
|
||||
}
|
||||
for _, node := range path {
|
||||
if c, ok := node.(*ast.CallExpr); ok {
|
||||
callExpr = c
|
||||
break
|
||||
}
|
||||
}
|
||||
if callExpr == nil || callExpr.Fun == nil {
|
||||
return nil, fmt.Errorf("cannot find an enclosing function")
|
||||
}
|
||||
|
||||
// Get the type information for the function corresponding to the call expression.
|
||||
var obj types.Object
|
||||
switch t := callExpr.Fun.(type) {
|
||||
case *ast.Ident:
|
||||
obj = pkg.TypesInfo.ObjectOf(t)
|
||||
case *ast.SelectorExpr:
|
||||
obj = pkg.TypesInfo.ObjectOf(t.Sel)
|
||||
default:
|
||||
return nil, fmt.Errorf("the enclosing function is malformed")
|
||||
}
|
||||
if obj == nil {
|
||||
return nil, fmt.Errorf("cannot resolve %s", callExpr.Fun)
|
||||
}
|
||||
// Find the signature corresponding to the object.
|
||||
var sig *types.Signature
|
||||
switch obj.(type) {
|
||||
case *types.Var:
|
||||
if underlying, ok := obj.Type().Underlying().(*types.Signature); ok {
|
||||
sig = underlying
|
||||
}
|
||||
case *types.Func:
|
||||
sig = obj.Type().(*types.Signature)
|
||||
}
|
||||
if sig == nil {
|
||||
return nil, fmt.Errorf("no function signatures found for %s", obj.Name())
|
||||
}
|
||||
pkgStringer := qualifier(fAST, pkg.Types, pkg.TypesInfo)
|
||||
var paramInfo []ParameterInformation
|
||||
for i := 0; i < sig.Params().Len(); i++ {
|
||||
param := sig.Params().At(i)
|
||||
label := types.TypeString(param.Type(), pkgStringer)
|
||||
if param.Name() != "" {
|
||||
label = fmt.Sprintf("%s %s", param.Name(), label)
|
||||
}
|
||||
paramInfo = append(paramInfo, ParameterInformation{
|
||||
Label: label,
|
||||
})
|
||||
}
|
||||
// Determine the query position relative to the number of parameters in the function.
|
||||
var activeParam int
|
||||
var start, end token.Pos
|
||||
for i, expr := range callExpr.Args {
|
||||
if start == token.NoPos {
|
||||
start = expr.Pos()
|
||||
}
|
||||
end = expr.End()
|
||||
if i < len(callExpr.Args)-1 {
|
||||
end = callExpr.Args[i+1].Pos() - 1 // comma
|
||||
}
|
||||
if start <= pos && pos <= end {
|
||||
break
|
||||
}
|
||||
activeParam++
|
||||
start = expr.Pos() + 1 // to account for commas
|
||||
}
|
||||
// Label for function, qualified by package name.
|
||||
label := obj.Name()
|
||||
if pkg := pkgStringer(obj.Pkg()); pkg != "" {
|
||||
label = pkg + "." + label
|
||||
}
|
||||
return &SignatureInformation{
|
||||
Label: label + formatParams(sig.Params(), sig.Variadic(), pkgStringer),
|
||||
Parameters: paramInfo,
|
||||
ActiveParameter: activeParam,
|
||||
}, nil
|
||||
}
|
47
vendor/golang.org/x/tools/internal/lsp/source/uri.go
generated
vendored
47
vendor/golang.org/x/tools/internal/lsp/source/uri.go
generated
vendored
@@ -1,47 +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 source
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const fileSchemePrefix = "file://"
|
||||
|
||||
// URI represents the full uri for a file.
|
||||
type URI string
|
||||
|
||||
// Filename gets the file path for the URI.
|
||||
// It will return an error if the uri is not valid, or if the URI was not
|
||||
// a file URI
|
||||
func (uri URI) Filename() (string, error) {
|
||||
s := string(uri)
|
||||
if !strings.HasPrefix(s, fileSchemePrefix) {
|
||||
return "", fmt.Errorf("only file URI's are supported, got %v", uri)
|
||||
}
|
||||
s = s[len(fileSchemePrefix):]
|
||||
s, err := url.PathUnescape(s)
|
||||
if err != nil {
|
||||
return s, err
|
||||
}
|
||||
s = filepath.FromSlash(s)
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// ToURI returns a protocol URI for the supplied path.
|
||||
// It will always have the file scheme.
|
||||
func ToURI(path string) URI {
|
||||
const prefix = "$GOROOT"
|
||||
if strings.EqualFold(prefix, path[:len(prefix)]) {
|
||||
suffix := path[len(prefix):]
|
||||
//TODO: we need a better way to get the GOROOT that uses the packages api
|
||||
path = runtime.GOROOT() + suffix
|
||||
}
|
||||
return URI(fileSchemePrefix + filepath.ToSlash(path))
|
||||
}
|
82
vendor/golang.org/x/tools/internal/lsp/source/view.go
generated
vendored
82
vendor/golang.org/x/tools/internal/lsp/source/view.go
generated
vendored
@@ -1,82 +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 source
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/token"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/tools/go/packages"
|
||||
)
|
||||
|
||||
type View struct {
|
||||
mu sync.Mutex // protects all mutable state of the view
|
||||
|
||||
Config *packages.Config
|
||||
|
||||
files map[URI]*File
|
||||
}
|
||||
|
||||
func NewView() *View {
|
||||
return &View{
|
||||
Config: &packages.Config{
|
||||
Mode: packages.LoadSyntax,
|
||||
Fset: token.NewFileSet(),
|
||||
Tests: true,
|
||||
Overlay: make(map[string][]byte),
|
||||
},
|
||||
files: make(map[URI]*File),
|
||||
}
|
||||
}
|
||||
|
||||
// GetFile returns a File for the given uri.
|
||||
// It will always succeed, adding the file to the managed set if needed.
|
||||
func (v *View) GetFile(uri URI) *File {
|
||||
v.mu.Lock()
|
||||
f := v.getFile(uri)
|
||||
v.mu.Unlock()
|
||||
return f
|
||||
}
|
||||
|
||||
// getFile is the unlocked internal implementation of GetFile.
|
||||
func (v *View) getFile(uri URI) *File {
|
||||
f, found := v.files[uri]
|
||||
if !found {
|
||||
f = &File{
|
||||
URI: uri,
|
||||
view: v,
|
||||
}
|
||||
v.files[f.URI] = f
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
func (v *View) parse(uri URI) error {
|
||||
path, err := uri.Filename()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pkgs, err := packages.Load(v.Config, fmt.Sprintf("file=%s", path))
|
||||
if len(pkgs) == 0 {
|
||||
if err == nil {
|
||||
err = fmt.Errorf("no packages found for %s", path)
|
||||
}
|
||||
return err
|
||||
}
|
||||
for _, pkg := range pkgs {
|
||||
// add everything we find to the files cache
|
||||
for _, fAST := range pkg.Syntax {
|
||||
// if a file was in multiple packages, which token/ast/pkg do we store
|
||||
fToken := v.Config.Fset.File(fAST.Pos())
|
||||
fURI := ToURI(fToken.Name())
|
||||
f := v.getFile(fURI)
|
||||
f.token = fToken
|
||||
f.ast = fAST
|
||||
f.pkg = pkg
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
18
vendor/golang.org/x/tools/internal/lsp/testdata/bad/bad.go
generated
vendored
18
vendor/golang.org/x/tools/internal/lsp/testdata/bad/bad.go
generated
vendored
@@ -1,18 +0,0 @@
|
||||
package bad
|
||||
|
||||
func stuff() {
|
||||
x := "heeeeyyyy"
|
||||
random2(x) //@diag("x", "cannot use x (variable of type string) as int value in argument to random2")
|
||||
random2(1)
|
||||
y := 3 //@diag("y", "y declared but not used")
|
||||
}
|
||||
|
||||
type bob struct {
|
||||
x int
|
||||
}
|
||||
|
||||
func _() {
|
||||
_ = &bob{
|
||||
f: 0, //@diag("f", "unknown field f in struct literal")
|
||||
}
|
||||
}
|
6
vendor/golang.org/x/tools/internal/lsp/testdata/bad/bad_util.go
generated
vendored
6
vendor/golang.org/x/tools/internal/lsp/testdata/bad/bad_util.go
generated
vendored
@@ -1,6 +0,0 @@
|
||||
package bad
|
||||
|
||||
func random2(y int) int {
|
||||
x := 6 //@diag("x", "x declared but not used")
|
||||
return y
|
||||
}
|
7
vendor/golang.org/x/tools/internal/lsp/testdata/bar/bar.go
generated
vendored
7
vendor/golang.org/x/tools/internal/lsp/testdata/bar/bar.go
generated
vendored
@@ -1,7 +0,0 @@
|
||||
package bar
|
||||
|
||||
import "golang.org/x/tools/internal/lsp/foo"
|
||||
|
||||
func Bar() {
|
||||
foo.Foo()
|
||||
}
|
7
vendor/golang.org/x/tools/internal/lsp/testdata/baz/baz.go
generated
vendored
7
vendor/golang.org/x/tools/internal/lsp/testdata/baz/baz.go
generated
vendored
@@ -1,7 +0,0 @@
|
||||
package baz
|
||||
|
||||
import "golang.org/x/tools/internal/lsp/bar"
|
||||
|
||||
func Baz() {
|
||||
bar.Bar()
|
||||
}
|
23
vendor/golang.org/x/tools/internal/lsp/testdata/foo/foo.go
generated
vendored
23
vendor/golang.org/x/tools/internal/lsp/testdata/foo/foo.go
generated
vendored
@@ -1,23 +0,0 @@
|
||||
package foo
|
||||
|
||||
type StructFoo struct { //@item(StructFoo, "StructFoo", "struct{...}", "struct")
|
||||
Value int //@item(Value, "Value", "int", "field")
|
||||
}
|
||||
|
||||
// TODO(rstambler): Create pre-set builtins?
|
||||
/* Error() */ //@item(Error, "Error()", "string", "method")
|
||||
|
||||
func Foo() { //@item(Foo, "Foo()", "", "func")
|
||||
var err error
|
||||
err.Error() //@complete("E", Error)
|
||||
}
|
||||
|
||||
func _() {
|
||||
var sFoo StructFoo //@complete("t", StructFoo)
|
||||
if x := sFoo; x.Value == 1 { //@complete("V", Value)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
//@complete("", Foo, IntFoo, StructFoo)
|
||||
type IntFoo int //@item(IntFoo, "IntFoo", "int", "type")
|
21
vendor/golang.org/x/tools/internal/lsp/testdata/format/bad_format.go
generated
vendored
21
vendor/golang.org/x/tools/internal/lsp/testdata/format/bad_format.go
generated
vendored
@@ -1,21 +0,0 @@
|
||||
package format //@format("package")
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"log"
|
||||
)
|
||||
|
||||
func hello() {
|
||||
|
||||
var x int //@diag("x", "x declared but not used")
|
||||
}
|
||||
|
||||
func hi() {
|
||||
|
||||
runtime.GOROOT()
|
||||
fmt.Printf("")
|
||||
|
||||
log.Printf("")
|
||||
}
|
9
vendor/golang.org/x/tools/internal/lsp/testdata/format/good_format.go
generated
vendored
9
vendor/golang.org/x/tools/internal/lsp/testdata/format/good_format.go
generated
vendored
@@ -1,9 +0,0 @@
|
||||
package format //@format("package")
|
||||
|
||||
import (
|
||||
"log"
|
||||
)
|
||||
|
||||
func goodbye() {
|
||||
log.Printf("byeeeee")
|
||||
}
|
11
vendor/golang.org/x/tools/internal/lsp/testdata/godef/a/a.go
generated
vendored
11
vendor/golang.org/x/tools/internal/lsp/testdata/godef/a/a.go
generated
vendored
@@ -1,11 +0,0 @@
|
||||
// A comment just to push the positions out
|
||||
|
||||
package a
|
||||
|
||||
type A string //@A
|
||||
|
||||
func Stuff() { //@Stuff
|
||||
x := 5
|
||||
Random2(x) //@godef("dom2", Random2)
|
||||
Random() //@godef("()", Random)
|
||||
}
|
23
vendor/golang.org/x/tools/internal/lsp/testdata/godef/a/random.go
generated
vendored
23
vendor/golang.org/x/tools/internal/lsp/testdata/godef/a/random.go
generated
vendored
@@ -1,23 +0,0 @@
|
||||
package a
|
||||
|
||||
func Random() int { //@Random
|
||||
y := 6 + 7
|
||||
return y
|
||||
}
|
||||
|
||||
func Random2(y int) int { //@Random2,mark(RandomParamY, "y")
|
||||
return y //@godef("y", RandomParamY)
|
||||
}
|
||||
|
||||
type Pos struct {
|
||||
x, y int //@mark(PosX, "x"),mark(PosY, "y")
|
||||
}
|
||||
|
||||
func (p *Pos) Sum() int { //@mark(PosSum, "Sum")
|
||||
return p.x + p.y //@godef("x", PosX)
|
||||
}
|
||||
|
||||
func _() {
|
||||
var p Pos
|
||||
_ = p.Sum() //@godef("()", PosSum)
|
||||
}
|
23
vendor/golang.org/x/tools/internal/lsp/testdata/godef/b/b.go
generated
vendored
23
vendor/golang.org/x/tools/internal/lsp/testdata/godef/b/b.go
generated
vendored
@@ -1,23 +0,0 @@
|
||||
package b
|
||||
|
||||
import "golang.org/x/tools/internal/lsp/godef/a"
|
||||
|
||||
type S1 struct { //@S1
|
||||
F1 int //@mark(S1F1, "F1")
|
||||
S2 //@godef("S2", S2), mark(S1S2, "S2")
|
||||
a.A //@godef("A", A)
|
||||
}
|
||||
|
||||
type S2 struct { //@S2
|
||||
F1 string //@mark(S2F1, "F1")
|
||||
F2 int //@mark(S2F2, "F2")
|
||||
}
|
||||
|
||||
func Bar() {
|
||||
a.Stuff() //@godef("Stuff", Stuff)
|
||||
var x S1 //@godef("S1", S1)
|
||||
_ = x.S2 //@godef("S2", S1S2)
|
||||
_ = x.F1 //@godef("F1", S1F1)
|
||||
_ = x.F2 //@godef("F2", S2F2)
|
||||
_ = x.S2.F1 //@godef("F1", S2F1)
|
||||
}
|
8
vendor/golang.org/x/tools/internal/lsp/testdata/godef/b/c.go
generated
vendored
8
vendor/golang.org/x/tools/internal/lsp/testdata/godef/b/c.go
generated
vendored
@@ -1,8 +0,0 @@
|
||||
package b
|
||||
|
||||
// This is the in-editor version of the file.
|
||||
// The on-disk version is in c.go.saved.
|
||||
|
||||
var _ = S1{ //@godef("S1", S1)
|
||||
F1: 99, //@godef("F1", S1F1)
|
||||
}
|
7
vendor/golang.org/x/tools/internal/lsp/testdata/godef/b/c.go.saved
generated
vendored
7
vendor/golang.org/x/tools/internal/lsp/testdata/godef/b/c.go.saved
generated
vendored
@@ -1,7 +0,0 @@
|
||||
package b
|
||||
|
||||
// This is the on-disk version of c.go, which represents
|
||||
// the in-editor version of the file.
|
||||
|
||||
}
|
||||
|
11
vendor/golang.org/x/tools/internal/lsp/testdata/godef/broken/unclosedIf.go.in
generated
vendored
11
vendor/golang.org/x/tools/internal/lsp/testdata/godef/broken/unclosedIf.go.in
generated
vendored
@@ -1,11 +0,0 @@
|
||||
package broken
|
||||
|
||||
import "fmt"
|
||||
|
||||
func unclosedIf() {
|
||||
if false {
|
||||
var myUnclosedIf string //@myUnclosedIf
|
||||
fmt.Printf("s = %v\n", myUnclosedIf) //@godef("my", myUnclosedIf)
|
||||
}
|
||||
//@diag(EOF, "expected ';', found 'EOF'")
|
||||
//@diag(EOF, "expected '}', found 'EOF'")
|
6
vendor/golang.org/x/tools/internal/lsp/testdata/good/good.go
generated
vendored
6
vendor/golang.org/x/tools/internal/lsp/testdata/good/good.go
generated
vendored
@@ -1,6 +0,0 @@
|
||||
package good
|
||||
|
||||
func stuff() {
|
||||
x := 5
|
||||
random2(x)
|
||||
}
|
10
vendor/golang.org/x/tools/internal/lsp/testdata/good/good_util.go
generated
vendored
10
vendor/golang.org/x/tools/internal/lsp/testdata/good/good_util.go
generated
vendored
@@ -1,10 +0,0 @@
|
||||
package good
|
||||
|
||||
func random() int {
|
||||
y := 6 + 7
|
||||
return y
|
||||
}
|
||||
|
||||
func random2(y int) int {
|
||||
return y
|
||||
}
|
11
vendor/golang.org/x/tools/internal/lsp/testdata/noparse/noparse.go.in
generated
vendored
11
vendor/golang.org/x/tools/internal/lsp/testdata/noparse/noparse.go.in
generated
vendored
@@ -1,11 +0,0 @@
|
||||
package noparse
|
||||
|
||||
func bye(x int) {
|
||||
hi()
|
||||
}
|
||||
|
||||
func stuff() {
|
||||
x := 5
|
||||
}
|
||||
|
||||
func .() {} //@diag(".", "expected 'IDENT', found '.'")
|
11
vendor/golang.org/x/tools/internal/lsp/testdata/noparse_format/noparse_format.1_10.go.in
generated
vendored
11
vendor/golang.org/x/tools/internal/lsp/testdata/noparse_format/noparse_format.1_10.go.in
generated
vendored
@@ -1,11 +0,0 @@
|
||||
// +build !go1.11
|
||||
|
||||
// This file does not actually test anything
|
||||
// on 1.10 the errors are different
|
||||
package noparse_format
|
||||
|
||||
func what() {
|
||||
// we need a diagnostic below so we have the same count as the main file
|
||||
var b int //@diag("b", "b declared but not used")
|
||||
if true {}
|
||||
}
|
9
vendor/golang.org/x/tools/internal/lsp/testdata/noparse_format/noparse_format.go.in
generated
vendored
9
vendor/golang.org/x/tools/internal/lsp/testdata/noparse_format/noparse_format.go.in
generated
vendored
@@ -1,9 +0,0 @@
|
||||
// +build go1.11
|
||||
|
||||
package noparse_format //@format("package")
|
||||
|
||||
func what() {
|
||||
var b int
|
||||
if { hi() //@diag("{", "missing condition in if statement")
|
||||
}
|
||||
}
|
159
vendor/golang.org/x/tools/internal/memcache/memcache.go
generated
vendored
159
vendor/golang.org/x/tools/internal/memcache/memcache.go
generated
vendored
@@ -1,159 +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.
|
||||
|
||||
// +build golangorg
|
||||
|
||||
// Package memcache provides a minimally compatible interface for
|
||||
// google.golang.org/appengine/memcache
|
||||
// and stores the data in Redis (e.g., via Cloud Memorystore).
|
||||
package memcache
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/gomodule/redigo/redis"
|
||||
)
|
||||
|
||||
var ErrCacheMiss = errors.New("memcache: cache miss")
|
||||
|
||||
func New(addr string) *Client {
|
||||
const maxConns = 20
|
||||
|
||||
pool := redis.NewPool(func() (redis.Conn, error) {
|
||||
return redis.Dial("tcp", addr)
|
||||
}, maxConns)
|
||||
|
||||
return &Client{
|
||||
pool: pool,
|
||||
}
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
pool *redis.Pool
|
||||
}
|
||||
|
||||
type CodecClient struct {
|
||||
client *Client
|
||||
codec Codec
|
||||
}
|
||||
|
||||
type Item struct {
|
||||
Key string
|
||||
Value []byte
|
||||
Object interface{} // Used with Codec.
|
||||
Expiration time.Duration // Read-only.
|
||||
}
|
||||
|
||||
func (c *Client) WithCodec(codec Codec) *CodecClient {
|
||||
return &CodecClient{
|
||||
c, codec,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) Delete(ctx context.Context, key string) error {
|
||||
conn, err := c.pool.GetContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
_, err = conn.Do("DEL", key)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *CodecClient) Delete(ctx context.Context, key string) error {
|
||||
return c.client.Delete(ctx, key)
|
||||
}
|
||||
|
||||
func (c *Client) Set(ctx context.Context, item *Item) error {
|
||||
if item.Value == nil {
|
||||
return errors.New("nil item value")
|
||||
}
|
||||
return c.set(ctx, item.Key, item.Value, item.Expiration)
|
||||
}
|
||||
|
||||
func (c *CodecClient) Set(ctx context.Context, item *Item) error {
|
||||
if item.Object == nil {
|
||||
return errors.New("nil object value")
|
||||
}
|
||||
b, err := c.codec.Marshal(item.Object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.client.set(ctx, item.Key, b, item.Expiration)
|
||||
}
|
||||
|
||||
func (c *Client) set(ctx context.Context, key string, value []byte, expiration time.Duration) error {
|
||||
conn, err := c.pool.GetContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
if expiration == 0 {
|
||||
_, err := conn.Do("SET", key, value)
|
||||
return err
|
||||
}
|
||||
|
||||
// NOTE(cbro): redis does not support expiry in units more granular than a second.
|
||||
exp := int64(expiration.Seconds())
|
||||
if exp == 0 {
|
||||
// Redis doesn't allow a zero expiration, delete the key instead.
|
||||
_, err := conn.Do("DEL", key)
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = conn.Do("SETEX", key, exp, value)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get gets the item.
|
||||
func (c *Client) Get(ctx context.Context, key string) ([]byte, error) {
|
||||
conn, err := c.pool.GetContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
b, err := redis.Bytes(conn.Do("GET", key))
|
||||
if err == redis.ErrNil {
|
||||
err = ErrCacheMiss
|
||||
}
|
||||
return b, err
|
||||
}
|
||||
|
||||
func (c *CodecClient) Get(ctx context.Context, key string, v interface{}) error {
|
||||
b, err := c.client.Get(ctx, key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.codec.Unmarshal(b, v)
|
||||
}
|
||||
|
||||
var (
|
||||
Gob = Codec{gobMarshal, gobUnmarshal}
|
||||
JSON = Codec{json.Marshal, json.Unmarshal}
|
||||
)
|
||||
|
||||
type Codec struct {
|
||||
Marshal func(interface{}) ([]byte, error)
|
||||
Unmarshal func([]byte, interface{}) error
|
||||
}
|
||||
|
||||
func gobMarshal(v interface{}) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
if err := gob.NewEncoder(&buf).Encode(v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func gobUnmarshal(data []byte, v interface{}) error {
|
||||
return gob.NewDecoder(bytes.NewBuffer(data)).Decode(v)
|
||||
}
|
85
vendor/golang.org/x/tools/internal/memcache/memcache_test.go
generated
vendored
85
vendor/golang.org/x/tools/internal/memcache/memcache_test.go
generated
vendored
@@ -1,85 +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.
|
||||
|
||||
// +build golangorg
|
||||
|
||||
package memcache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func getClient(t *testing.T) *Client {
|
||||
t.Helper()
|
||||
|
||||
addr := os.Getenv("GOLANG_REDIS_ADDR")
|
||||
if addr == "" {
|
||||
t.Skip("skipping because GOLANG_REDIS_ADDR is unset")
|
||||
}
|
||||
|
||||
return New(addr)
|
||||
}
|
||||
|
||||
func TestCacheMiss(t *testing.T) {
|
||||
c := getClient(t)
|
||||
ctx := context.Background()
|
||||
|
||||
if _, err := c.Get(ctx, "doesnotexist"); err != ErrCacheMiss {
|
||||
t.Errorf("got %v; want ErrCacheMiss", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpiry(t *testing.T) {
|
||||
c := getClient(t).WithCodec(Gob)
|
||||
ctx := context.Background()
|
||||
|
||||
key := "testexpiry"
|
||||
|
||||
firstTime := time.Now()
|
||||
err := c.Set(ctx, &Item{
|
||||
Key: key,
|
||||
Object: firstTime,
|
||||
Expiration: 3500 * time.Millisecond, // NOTE: check that non-rounded expiries work.
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Set: %v", err)
|
||||
}
|
||||
|
||||
var newTime time.Time
|
||||
if err := c.Get(ctx, key, &newTime); err != nil {
|
||||
t.Fatalf("Get: %v", err)
|
||||
}
|
||||
if !firstTime.Equal(newTime) {
|
||||
t.Errorf("Get: got value %v, want %v", newTime, firstTime)
|
||||
}
|
||||
|
||||
time.Sleep(4 * time.Second)
|
||||
|
||||
if err := c.Get(ctx, key, &newTime); err != ErrCacheMiss {
|
||||
t.Errorf("Get: got %v, want ErrCacheMiss", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShortExpiry(t *testing.T) {
|
||||
c := getClient(t).WithCodec(Gob)
|
||||
ctx := context.Background()
|
||||
|
||||
key := "testshortexpiry"
|
||||
|
||||
err := c.Set(ctx, &Item{
|
||||
Key: key,
|
||||
Value: []byte("ok"),
|
||||
Expiration: time.Millisecond,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Set: %v", err)
|
||||
}
|
||||
|
||||
if err := c.Get(ctx, key, nil); err != ErrCacheMiss {
|
||||
t.Errorf("GetBytes: got %v, want ErrCacheMiss", err)
|
||||
}
|
||||
}
|
388
vendor/golang.org/x/tools/internal/semver/semver.go
generated
vendored
388
vendor/golang.org/x/tools/internal/semver/semver.go
generated
vendored
@@ -1,388 +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 semver implements comparison of semantic version strings.
|
||||
// In this package, semantic version strings must begin with a leading "v",
|
||||
// as in "v1.0.0".
|
||||
//
|
||||
// The general form of a semantic version string accepted by this package is
|
||||
//
|
||||
// vMAJOR[.MINOR[.PATCH[-PRERELEASE][+BUILD]]]
|
||||
//
|
||||
// where square brackets indicate optional parts of the syntax;
|
||||
// MAJOR, MINOR, and PATCH are decimal integers without extra leading zeros;
|
||||
// PRERELEASE and BUILD are each a series of non-empty dot-separated identifiers
|
||||
// using only alphanumeric characters and hyphens; and
|
||||
// all-numeric PRERELEASE identifiers must not have leading zeros.
|
||||
//
|
||||
// This package follows Semantic Versioning 2.0.0 (see semver.org)
|
||||
// with two exceptions. First, it requires the "v" prefix. Second, it recognizes
|
||||
// vMAJOR and vMAJOR.MINOR (with no prerelease or build suffixes)
|
||||
// as shorthands for vMAJOR.0.0 and vMAJOR.MINOR.0.
|
||||
package semver
|
||||
|
||||
// parsed returns the parsed form of a semantic version string.
|
||||
type parsed struct {
|
||||
major string
|
||||
minor string
|
||||
patch string
|
||||
short string
|
||||
prerelease string
|
||||
build string
|
||||
err string
|
||||
}
|
||||
|
||||
// IsValid reports whether v is a valid semantic version string.
|
||||
func IsValid(v string) bool {
|
||||
_, ok := parse(v)
|
||||
return ok
|
||||
}
|
||||
|
||||
// Canonical returns the canonical formatting of the semantic version v.
|
||||
// It fills in any missing .MINOR or .PATCH and discards build metadata.
|
||||
// Two semantic versions compare equal only if their canonical formattings
|
||||
// are identical strings.
|
||||
// The canonical invalid semantic version is the empty string.
|
||||
func Canonical(v string) string {
|
||||
p, ok := parse(v)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
if p.build != "" {
|
||||
return v[:len(v)-len(p.build)]
|
||||
}
|
||||
if p.short != "" {
|
||||
return v + p.short
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Major returns the major version prefix of the semantic version v.
|
||||
// For example, Major("v2.1.0") == "v2".
|
||||
// If v is an invalid semantic version string, Major returns the empty string.
|
||||
func Major(v string) string {
|
||||
pv, ok := parse(v)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return v[:1+len(pv.major)]
|
||||
}
|
||||
|
||||
// MajorMinor returns the major.minor version prefix of the semantic version v.
|
||||
// For example, MajorMinor("v2.1.0") == "v2.1".
|
||||
// If v is an invalid semantic version string, MajorMinor returns the empty string.
|
||||
func MajorMinor(v string) string {
|
||||
pv, ok := parse(v)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
i := 1 + len(pv.major)
|
||||
if j := i + 1 + len(pv.minor); j <= len(v) && v[i] == '.' && v[i+1:j] == pv.minor {
|
||||
return v[:j]
|
||||
}
|
||||
return v[:i] + "." + pv.minor
|
||||
}
|
||||
|
||||
// Prerelease returns the prerelease suffix of the semantic version v.
|
||||
// For example, Prerelease("v2.1.0-pre+meta") == "-pre".
|
||||
// If v is an invalid semantic version string, Prerelease returns the empty string.
|
||||
func Prerelease(v string) string {
|
||||
pv, ok := parse(v)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return pv.prerelease
|
||||
}
|
||||
|
||||
// Build returns the build suffix of the semantic version v.
|
||||
// For example, Build("v2.1.0+meta") == "+meta".
|
||||
// If v is an invalid semantic version string, Build returns the empty string.
|
||||
func Build(v string) string {
|
||||
pv, ok := parse(v)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return pv.build
|
||||
}
|
||||
|
||||
// Compare returns an integer comparing two versions according to
|
||||
// according to semantic version precedence.
|
||||
// The result will be 0 if v == w, -1 if v < w, or +1 if v > w.
|
||||
//
|
||||
// An invalid semantic version string is considered less than a valid one.
|
||||
// All invalid semantic version strings compare equal to each other.
|
||||
func Compare(v, w string) int {
|
||||
pv, ok1 := parse(v)
|
||||
pw, ok2 := parse(w)
|
||||
if !ok1 && !ok2 {
|
||||
return 0
|
||||
}
|
||||
if !ok1 {
|
||||
return -1
|
||||
}
|
||||
if !ok2 {
|
||||
return +1
|
||||
}
|
||||
if c := compareInt(pv.major, pw.major); c != 0 {
|
||||
return c
|
||||
}
|
||||
if c := compareInt(pv.minor, pw.minor); c != 0 {
|
||||
return c
|
||||
}
|
||||
if c := compareInt(pv.patch, pw.patch); c != 0 {
|
||||
return c
|
||||
}
|
||||
return comparePrerelease(pv.prerelease, pw.prerelease)
|
||||
}
|
||||
|
||||
// Max canonicalizes its arguments and then returns the version string
|
||||
// that compares greater.
|
||||
func Max(v, w string) string {
|
||||
v = Canonical(v)
|
||||
w = Canonical(w)
|
||||
if Compare(v, w) > 0 {
|
||||
return v
|
||||
}
|
||||
return w
|
||||
}
|
||||
|
||||
func parse(v string) (p parsed, ok bool) {
|
||||
if v == "" || v[0] != 'v' {
|
||||
p.err = "missing v prefix"
|
||||
return
|
||||
}
|
||||
p.major, v, ok = parseInt(v[1:])
|
||||
if !ok {
|
||||
p.err = "bad major version"
|
||||
return
|
||||
}
|
||||
if v == "" {
|
||||
p.minor = "0"
|
||||
p.patch = "0"
|
||||
p.short = ".0.0"
|
||||
return
|
||||
}
|
||||
if v[0] != '.' {
|
||||
p.err = "bad minor prefix"
|
||||
ok = false
|
||||
return
|
||||
}
|
||||
p.minor, v, ok = parseInt(v[1:])
|
||||
if !ok {
|
||||
p.err = "bad minor version"
|
||||
return
|
||||
}
|
||||
if v == "" {
|
||||
p.patch = "0"
|
||||
p.short = ".0"
|
||||
return
|
||||
}
|
||||
if v[0] != '.' {
|
||||
p.err = "bad patch prefix"
|
||||
ok = false
|
||||
return
|
||||
}
|
||||
p.patch, v, ok = parseInt(v[1:])
|
||||
if !ok {
|
||||
p.err = "bad patch version"
|
||||
return
|
||||
}
|
||||
if len(v) > 0 && v[0] == '-' {
|
||||
p.prerelease, v, ok = parsePrerelease(v)
|
||||
if !ok {
|
||||
p.err = "bad prerelease"
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(v) > 0 && v[0] == '+' {
|
||||
p.build, v, ok = parseBuild(v)
|
||||
if !ok {
|
||||
p.err = "bad build"
|
||||
return
|
||||
}
|
||||
}
|
||||
if v != "" {
|
||||
p.err = "junk on end"
|
||||
ok = false
|
||||
return
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
func parseInt(v string) (t, rest string, ok bool) {
|
||||
if v == "" {
|
||||
return
|
||||
}
|
||||
if v[0] < '0' || '9' < v[0] {
|
||||
return
|
||||
}
|
||||
i := 1
|
||||
for i < len(v) && '0' <= v[i] && v[i] <= '9' {
|
||||
i++
|
||||
}
|
||||
if v[0] == '0' && i != 1 {
|
||||
return
|
||||
}
|
||||
return v[:i], v[i:], true
|
||||
}
|
||||
|
||||
func parsePrerelease(v string) (t, rest string, ok bool) {
|
||||
// "A pre-release version MAY be denoted by appending a hyphen and
|
||||
// a series of dot separated identifiers immediately following the patch version.
|
||||
// Identifiers MUST comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-].
|
||||
// Identifiers MUST NOT be empty. Numeric identifiers MUST NOT include leading zeroes."
|
||||
if v == "" || v[0] != '-' {
|
||||
return
|
||||
}
|
||||
i := 1
|
||||
start := 1
|
||||
for i < len(v) && v[i] != '+' {
|
||||
if !isIdentChar(v[i]) && v[i] != '.' {
|
||||
return
|
||||
}
|
||||
if v[i] == '.' {
|
||||
if start == i || isBadNum(v[start:i]) {
|
||||
return
|
||||
}
|
||||
start = i + 1
|
||||
}
|
||||
i++
|
||||
}
|
||||
if start == i || isBadNum(v[start:i]) {
|
||||
return
|
||||
}
|
||||
return v[:i], v[i:], true
|
||||
}
|
||||
|
||||
func parseBuild(v string) (t, rest string, ok bool) {
|
||||
if v == "" || v[0] != '+' {
|
||||
return
|
||||
}
|
||||
i := 1
|
||||
start := 1
|
||||
for i < len(v) {
|
||||
if !isIdentChar(v[i]) {
|
||||
return
|
||||
}
|
||||
if v[i] == '.' {
|
||||
if start == i {
|
||||
return
|
||||
}
|
||||
start = i + 1
|
||||
}
|
||||
i++
|
||||
}
|
||||
if start == i {
|
||||
return
|
||||
}
|
||||
return v[:i], v[i:], true
|
||||
}
|
||||
|
||||
func isIdentChar(c byte) bool {
|
||||
return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '-'
|
||||
}
|
||||
|
||||
func isBadNum(v string) bool {
|
||||
i := 0
|
||||
for i < len(v) && '0' <= v[i] && v[i] <= '9' {
|
||||
i++
|
||||
}
|
||||
return i == len(v) && i > 1 && v[0] == '0'
|
||||
}
|
||||
|
||||
func isNum(v string) bool {
|
||||
i := 0
|
||||
for i < len(v) && '0' <= v[i] && v[i] <= '9' {
|
||||
i++
|
||||
}
|
||||
return i == len(v)
|
||||
}
|
||||
|
||||
func compareInt(x, y string) int {
|
||||
if x == y {
|
||||
return 0
|
||||
}
|
||||
if len(x) < len(y) {
|
||||
return -1
|
||||
}
|
||||
if len(x) > len(y) {
|
||||
return +1
|
||||
}
|
||||
if x < y {
|
||||
return -1
|
||||
} else {
|
||||
return +1
|
||||
}
|
||||
}
|
||||
|
||||
func comparePrerelease(x, y string) int {
|
||||
// "When major, minor, and patch are equal, a pre-release version has
|
||||
// lower precedence than a normal version.
|
||||
// Example: 1.0.0-alpha < 1.0.0.
|
||||
// Precedence for two pre-release versions with the same major, minor,
|
||||
// and patch version MUST be determined by comparing each dot separated
|
||||
// identifier from left to right until a difference is found as follows:
|
||||
// identifiers consisting of only digits are compared numerically and
|
||||
// identifiers with letters or hyphens are compared lexically in ASCII
|
||||
// sort order. Numeric identifiers always have lower precedence than
|
||||
// non-numeric identifiers. A larger set of pre-release fields has a
|
||||
// higher precedence than a smaller set, if all of the preceding
|
||||
// identifiers are equal.
|
||||
// Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta <
|
||||
// 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0."
|
||||
if x == y {
|
||||
return 0
|
||||
}
|
||||
if x == "" {
|
||||
return +1
|
||||
}
|
||||
if y == "" {
|
||||
return -1
|
||||
}
|
||||
for x != "" && y != "" {
|
||||
x = x[1:] // skip - or .
|
||||
y = y[1:] // skip - or .
|
||||
var dx, dy string
|
||||
dx, x = nextIdent(x)
|
||||
dy, y = nextIdent(y)
|
||||
if dx != dy {
|
||||
ix := isNum(dx)
|
||||
iy := isNum(dy)
|
||||
if ix != iy {
|
||||
if ix {
|
||||
return -1
|
||||
} else {
|
||||
return +1
|
||||
}
|
||||
}
|
||||
if ix {
|
||||
if len(dx) < len(dy) {
|
||||
return -1
|
||||
}
|
||||
if len(dx) > len(dy) {
|
||||
return +1
|
||||
}
|
||||
}
|
||||
if dx < dy {
|
||||
return -1
|
||||
} else {
|
||||
return +1
|
||||
}
|
||||
}
|
||||
}
|
||||
if x == "" {
|
||||
return -1
|
||||
} else {
|
||||
return +1
|
||||
}
|
||||
}
|
||||
|
||||
func nextIdent(x string) (dx, rest string) {
|
||||
i := 0
|
||||
for i < len(x) && x[i] != '.' {
|
||||
i++
|
||||
}
|
||||
return x[:i], x[i:]
|
||||
}
|
182
vendor/golang.org/x/tools/internal/semver/semver_test.go
generated
vendored
182
vendor/golang.org/x/tools/internal/semver/semver_test.go
generated
vendored
@@ -1,182 +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 semver
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var tests = []struct {
|
||||
in string
|
||||
out string
|
||||
}{
|
||||
{"bad", ""},
|
||||
{"v1-alpha.beta.gamma", ""},
|
||||
{"v1-pre", ""},
|
||||
{"v1+meta", ""},
|
||||
{"v1-pre+meta", ""},
|
||||
{"v1.2-pre", ""},
|
||||
{"v1.2+meta", ""},
|
||||
{"v1.2-pre+meta", ""},
|
||||
{"v1.0.0-alpha", "v1.0.0-alpha"},
|
||||
{"v1.0.0-alpha.1", "v1.0.0-alpha.1"},
|
||||
{"v1.0.0-alpha.beta", "v1.0.0-alpha.beta"},
|
||||
{"v1.0.0-beta", "v1.0.0-beta"},
|
||||
{"v1.0.0-beta.2", "v1.0.0-beta.2"},
|
||||
{"v1.0.0-beta.11", "v1.0.0-beta.11"},
|
||||
{"v1.0.0-rc.1", "v1.0.0-rc.1"},
|
||||
{"v1", "v1.0.0"},
|
||||
{"v1.0", "v1.0.0"},
|
||||
{"v1.0.0", "v1.0.0"},
|
||||
{"v1.2", "v1.2.0"},
|
||||
{"v1.2.0", "v1.2.0"},
|
||||
{"v1.2.3-456", "v1.2.3-456"},
|
||||
{"v1.2.3-456.789", "v1.2.3-456.789"},
|
||||
{"v1.2.3-456-789", "v1.2.3-456-789"},
|
||||
{"v1.2.3-456a", "v1.2.3-456a"},
|
||||
{"v1.2.3-pre", "v1.2.3-pre"},
|
||||
{"v1.2.3-pre+meta", "v1.2.3-pre"},
|
||||
{"v1.2.3-pre.1", "v1.2.3-pre.1"},
|
||||
{"v1.2.3-zzz", "v1.2.3-zzz"},
|
||||
{"v1.2.3", "v1.2.3"},
|
||||
{"v1.2.3+meta", "v1.2.3"},
|
||||
{"v1.2.3+meta-pre", "v1.2.3"},
|
||||
}
|
||||
|
||||
func TestIsValid(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
ok := IsValid(tt.in)
|
||||
if ok != (tt.out != "") {
|
||||
t.Errorf("IsValid(%q) = %v, want %v", tt.in, ok, !ok)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanonical(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
out := Canonical(tt.in)
|
||||
if out != tt.out {
|
||||
t.Errorf("Canonical(%q) = %q, want %q", tt.in, out, tt.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMajor(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
out := Major(tt.in)
|
||||
want := ""
|
||||
if i := strings.Index(tt.out, "."); i >= 0 {
|
||||
want = tt.out[:i]
|
||||
}
|
||||
if out != want {
|
||||
t.Errorf("Major(%q) = %q, want %q", tt.in, out, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMajorMinor(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
out := MajorMinor(tt.in)
|
||||
var want string
|
||||
if tt.out != "" {
|
||||
want = tt.in
|
||||
if i := strings.Index(want, "+"); i >= 0 {
|
||||
want = want[:i]
|
||||
}
|
||||
if i := strings.Index(want, "-"); i >= 0 {
|
||||
want = want[:i]
|
||||
}
|
||||
switch strings.Count(want, ".") {
|
||||
case 0:
|
||||
want += ".0"
|
||||
case 1:
|
||||
// ok
|
||||
case 2:
|
||||
want = want[:strings.LastIndex(want, ".")]
|
||||
}
|
||||
}
|
||||
if out != want {
|
||||
t.Errorf("MajorMinor(%q) = %q, want %q", tt.in, out, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrerelease(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
pre := Prerelease(tt.in)
|
||||
var want string
|
||||
if tt.out != "" {
|
||||
if i := strings.Index(tt.out, "-"); i >= 0 {
|
||||
want = tt.out[i:]
|
||||
}
|
||||
}
|
||||
if pre != want {
|
||||
t.Errorf("Prerelease(%q) = %q, want %q", tt.in, pre, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuild(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
build := Build(tt.in)
|
||||
var want string
|
||||
if tt.out != "" {
|
||||
if i := strings.Index(tt.in, "+"); i >= 0 {
|
||||
want = tt.in[i:]
|
||||
}
|
||||
}
|
||||
if build != want {
|
||||
t.Errorf("Build(%q) = %q, want %q", tt.in, build, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompare(t *testing.T) {
|
||||
for i, ti := range tests {
|
||||
for j, tj := range tests {
|
||||
cmp := Compare(ti.in, tj.in)
|
||||
var want int
|
||||
if ti.out == tj.out {
|
||||
want = 0
|
||||
} else if i < j {
|
||||
want = -1
|
||||
} else {
|
||||
want = +1
|
||||
}
|
||||
if cmp != want {
|
||||
t.Errorf("Compare(%q, %q) = %d, want %d", ti.in, tj.in, cmp, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMax(t *testing.T) {
|
||||
for i, ti := range tests {
|
||||
for j, tj := range tests {
|
||||
max := Max(ti.in, tj.in)
|
||||
want := Canonical(ti.in)
|
||||
if i < j {
|
||||
want = Canonical(tj.in)
|
||||
}
|
||||
if max != want {
|
||||
t.Errorf("Max(%q, %q) = %q, want %q", ti.in, tj.in, max, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
v1 = "v1.0.0+metadata-dash"
|
||||
v2 = "v1.0.0+metadata-dash1"
|
||||
)
|
||||
|
||||
func BenchmarkCompare(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
if Compare(v1, v2) != 0 {
|
||||
b.Fatalf("bad compare")
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user