.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools / gopls@v0.6.9 / integration / replay / main.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools/gopls@v0.6.9/integration/replay/main.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools/gopls@v0.6.9/integration/replay/main.go
new file mode 100644 (file)
index 0000000..35cd1d5
--- /dev/null
@@ -0,0 +1,292 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Replay logs. See README.md
+package main
+
+import (
+       "bufio"
+       "context"
+       "flag"
+       "fmt"
+       exec "golang.org/x/sys/execabs"
+       "log"
+       "os"
+       "sort"
+       "strconv"
+       "strings"
+
+       "golang.org/x/tools/gopls/integration/parse"
+       "golang.org/x/tools/internal/fakenet"
+       "golang.org/x/tools/internal/jsonrpc2"
+       p "golang.org/x/tools/internal/lsp/protocol"
+)
+
+var (
+       command = flag.String("cmd", "", "location of server to send to, looks for gopls")
+       cmp     = flag.Bool("cmp", false, "only compare log and /tmp/seen")
+       logrdr  *bufio.Scanner
+       msgs    []*parse.Logmsg
+       // requests and responses/errors, by id
+       clreq  = make(map[string]*parse.Logmsg)
+       clresp = make(map[string]*parse.Logmsg)
+       svreq  = make(map[string]*parse.Logmsg)
+       svresp = make(map[string]*parse.Logmsg)
+)
+
+func main() {
+       log.SetFlags(log.Lshortfile)
+       flag.Usage = func() {
+               fmt.Fprintln(flag.CommandLine.Output(), "replay [options] <logfile>")
+               flag.PrintDefaults()
+       }
+       flag.Parse()
+       if flag.NArg() != 1 {
+               flag.Usage()
+               os.Exit(2)
+       }
+       logf := flag.Arg(0)
+
+       orig, err := parse.ToRlog(logf)
+       if err != nil {
+               log.Fatalf("error parsing logfile %q: %v", logf, err)
+       }
+       ctx := context.Background()
+       msgs = orig.Logs
+       log.Printf("old %d, hist:%s", len(msgs), orig.Histogram)
+
+       if !*cmp {
+               log.Print("calling mimic")
+               mimic(ctx)
+       }
+       seen, err := parse.ToRlog("/tmp/seen")
+       if err != nil {
+               log.Fatal(err)
+       }
+       newMsgs := seen.Logs
+       log.Printf("new %d, hist:%s", len(newMsgs), seen.Histogram)
+
+       ok := make(map[string]int)
+       f := func(x []*parse.Logmsg, label string, diags map[p.DocumentURI][]p.Diagnostic) {
+               counts := make(map[parse.MsgType]int)
+               for _, l := range x {
+                       if l.Method == "window/logMessage" {
+                               // don't care
+                               //continue
+                       }
+                       if l.Method == "textDocument/publishDiagnostics" {
+                               v, ok := l.Body.(*p.PublishDiagnosticsParams)
+                               if !ok {
+                                       log.Fatalf("got %T expected PublishDiagnosticsParams", l.Body)
+                               }
+                               diags[v.URI] = v.Diagnostics
+                       }
+                       counts[l.Type]++
+                       // notifications only
+                       if l.Type != parse.ToServer && l.Type != parse.ToClient {
+                               continue
+                       }
+                       s := fmt.Sprintf("%s %s %s", strings.Replace(l.Hdr, "\r", "", -1), label, l.Type)
+                       if i := strings.Index(s, "notification"); i != -1 {
+                               s = s[i+12:]
+                       }
+                       if len(s) > 120 {
+                               s = s[:120]
+                       }
+                       ok[s]++
+               }
+               msg := ""
+               for i := parse.ClRequest; i <= parse.ReportErr; i++ {
+                       msg += fmt.Sprintf("%s:%d ", i, counts[i])
+               }
+               log.Printf("%s: %s", label, msg)
+       }
+       mdiags := make(map[p.DocumentURI][]p.Diagnostic)
+       f(msgs, "old", mdiags)
+       vdiags := make(map[p.DocumentURI][]p.Diagnostic)
+       f(newMsgs, "new", vdiags)
+       buf := []string{}
+       for k := range ok {
+               buf = append(buf, fmt.Sprintf("%s %d", k, ok[k]))
+       }
+       if len(buf) > 0 {
+               log.Printf("counts of notifications")
+               sort.Strings(buf)
+               for _, k := range buf {
+                       log.Print(k)
+               }
+       }
+       buf = buf[0:0]
+       for k, v := range mdiags {
+               va := vdiags[k]
+               if len(v) != len(va) {
+                       buf = append(buf, fmt.Sprintf("new has %d, old has %d for %s",
+                               len(va), len(v), k))
+               }
+       }
+       for ka := range vdiags {
+               if _, ok := mdiags[ka]; !ok {
+                       buf = append(buf, fmt.Sprintf("new diagnostics, but no old ones, for %s",
+                               ka))
+               }
+       }
+       if len(buf) > 0 {
+               log.Print("diagnostics differ:")
+               for _, s := range buf {
+                       log.Print(s)
+               }
+       }
+}
+
+func send(ctx context.Context, l *parse.Logmsg, stream jsonrpc2.Stream, id *jsonrpc2.ID) {
+       if id == nil {
+               // need to use the number version of ID
+               n, err := strconv.Atoi(l.ID)
+               if err != nil {
+                       n = 0
+               }
+               nid := jsonrpc2.NewIntID(int64(n))
+               id = &nid
+       }
+       var msg jsonrpc2.Message
+       var err error
+       switch l.Type {
+       case parse.ClRequest:
+               msg, err = jsonrpc2.NewCall(*id, l.Method, l.Body)
+       case parse.SvResponse:
+               msg, err = jsonrpc2.NewResponse(*id, l.Body, nil)
+       case parse.ToServer:
+               msg, err = jsonrpc2.NewNotification(l.Method, l.Body)
+       default:
+               log.Fatalf("sending %s", l.Type)
+       }
+       if err != nil {
+               log.Fatal(err)
+       }
+       stream.Write(ctx, msg)
+}
+
+func respond(ctx context.Context, c *jsonrpc2.Call, stream jsonrpc2.Stream) {
+       // c is a server request
+       // pick out the id, and look for the response in msgs
+       id := c.ID()
+       idstr := fmt.Sprint(id)
+       for _, l := range msgs {
+               if l.ID == idstr && l.Type == parse.SvResponse {
+                       // check that the methods match?
+                       // need to send back the same ID we got.
+                       send(ctx, l, stream, &id)
+                       return
+               }
+       }
+       log.Fatalf("no response found %q %+v %+v", c.Method(), c.ID(), c)
+}
+
+func findgopls() string {
+       totry := [][]string{{"GOBIN", "/gopls"}, {"GOPATH", "/bin/gopls"}, {"HOME", "/go/bin/gopls"}}
+       // looks in the places go install would install:
+       // GOBIN, else GOPATH/bin, else HOME/go/bin
+       ok := func(s string) bool {
+               fd, err := os.Open(s)
+               if err != nil {
+                       return false
+               }
+               fi, err := fd.Stat()
+               if err != nil {
+                       return false
+               }
+               return fi.Mode()&0111 != 0
+       }
+       for _, t := range totry {
+               g := os.Getenv(t[0])
+               if g != "" && ok(g+t[1]) {
+                       gopls := g + t[1]
+                       log.Printf("using gopls at %s", gopls)
+                       return gopls
+               }
+       }
+       log.Fatal("could not find gopls")
+       return ""
+}
+
+func mimic(ctx context.Context) {
+       log.Printf("mimic %d", len(msgs))
+       if *command == "" {
+               *command = findgopls()
+       }
+       cmd := exec.Command(*command, "-logfile", "/tmp/seen", "-rpc.trace")
+       toServer, err := cmd.StdinPipe()
+       if err != nil {
+               log.Fatal(err)
+       }
+       fromServer, err := cmd.StdoutPipe()
+       if err != nil {
+               log.Fatal(err)
+       }
+       err = cmd.Start()
+       if err != nil {
+               log.Fatal(err)
+       }
+       conn := fakenet.NewConn("stdio", fromServer, toServer)
+       stream := jsonrpc2.NewHeaderStream(conn)
+       rchan := make(chan jsonrpc2.Message, 10) // do we need buffering?
+       rdr := func() {
+               for {
+                       msg, _, err := stream.Read(ctx)
+                       if err != nil {
+                               rchan <- nil // close it instead?
+                               return
+                       }
+                       rchan <- msg
+               }
+       }
+       go rdr()
+       // send as many as possible: all clrequests and toservers up to a clresponse
+       // and loop
+       seenids := make(map[string]bool) // id's that have been responded to:
+big:
+       for _, l := range msgs {
+               switch l.Type {
+               case parse.ToServer: // just send these as we get to them
+                       send(ctx, l, stream, nil)
+               case parse.ClRequest:
+                       send(ctx, l, stream, nil) // for now, wait for a response, to make sure code is ok
+                       fallthrough
+               case parse.ClResponse, parse.ReportErr: // don't go past these until they're received
+                       if seenids[l.ID] {
+                               break // onward, as it has been received already
+                       }
+               done:
+                       for {
+                               msg := <-rchan
+                               if msg == nil {
+                                       break big
+                               }
+                               // if it's svrequest, do something
+                               // if it's clresponse or reporterr, add to seenids, and if it
+                               // is l.id, break out of the loop, and continue the outer loop
+
+                               switch msg := msg.(type) {
+                               case *jsonrpc2.Call:
+                                       if parse.FromServer(msg.Method()) {
+                                               respond(ctx, msg, stream)
+                                               continue done // still waiting
+                                       }
+                               case *jsonrpc2.Response:
+                                       id := fmt.Sprint(msg.ID())
+                                       seenids[id] = true
+                                       if id == l.ID {
+                                               break done
+                                       }
+                               }
+                       }
+               case parse.SvRequest: // not ours to send
+                       continue
+               case parse.SvResponse: // sent by us, if the request arrives
+                       continue
+               case parse.ToClient: // we don't send these
+                       continue
+               }
+       }
+}