X-Git-Url: https://git.josue.xyz/?a=blobdiff_plain;f=.config%2Fcoc%2Fextensions%2Fcoc-go-data%2Ftools%2Fpkg%2Fmod%2Fgolang.org%2Fx%2Ftools%40v0.0.0-20201028153306-37f0764111ff%2Finternal%2Flsp%2Fhelper%2Fhelper.go;fp=.config%2Fcoc%2Fextensions%2Fcoc-go-data%2Ftools%2Fpkg%2Fmod%2Fgolang.org%2Fx%2Ftools%40v0.0.0-20201028153306-37f0764111ff%2Finternal%2Flsp%2Fhelper%2Fhelper.go;h=06b24571997451e313bef124af8853dd36c94d36;hb=4d07c77cf4d78cab8639e13ddc3c22495e585b0b;hp=0000000000000000000000000000000000000000;hpb=b3950616b54221c40a7dab9099bda675007e5b6e;p=dotfiles%2F.git diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/internal/lsp/helper/helper.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/internal/lsp/helper/helper.go new file mode 100644 index 00000000..06b24571 --- /dev/null +++ b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/internal/lsp/helper/helper.go @@ -0,0 +1,244 @@ +// Invoke with //go:generate helper/helper -t Server -d protocol/tsserver.go -u lsp -o server_gen.go +// invoke in internal/lsp +package main + +import ( + "bytes" + "flag" + "fmt" + "go/ast" + "go/format" + "go/parser" + "go/token" + "log" + "os" + "sort" + "strings" + "text/template" +) + +var ( + typ = flag.String("t", "Server", "generate code for this type") + def = flag.String("d", "", "the file the type is defined in") // this relies on punning + use = flag.String("u", "", "look for uses in this package") + out = flag.String("o", "", "where to write the generated file") +) + +func main() { + log.SetFlags(log.Lshortfile) + flag.Parse() + if *typ == "" || *def == "" || *use == "" || *out == "" { + flag.PrintDefaults() + return + } + // read the type definition and see what methods we're looking for + doTypes() + + // parse the package and see which methods are defined + doUses() + + output() +} + +// replace "\\\n" with nothing before using +var tmpl = ` +package lsp + +// code generated by helper. DO NOT EDIT. + +import ( + "context" + + "golang.org/x/tools/internal/lsp/protocol" +) + +{{range $key, $v := .Stuff}} +func (s *{{$.Type}}) {{$v.Name}}({{.Param}}) {{.Result}} { + {{if ne .Found ""}} return s.{{.Internal}}({{.Invoke}})\ + {{else}}return {{if lt 1 (len .Results)}}nil, {{end}}notImplemented("{{.Name}}"){{end}} +} +{{end}} +` + +func output() { + // put in empty param names as needed + for _, t := range types { + if t.paramnames == nil { + t.paramnames = make([]string, len(t.paramtypes)) + } + for i, p := range t.paramtypes { + cm := "" + if i > 0 { + cm = ", " + } + t.Param += fmt.Sprintf("%s%s %s", cm, t.paramnames[i], p) + t.Invoke += fmt.Sprintf("%s%s", cm, t.paramnames[i]) + } + if len(t.Results) > 1 { + t.Result = "(" + } + for i, r := range t.Results { + cm := "" + if i > 0 { + cm = ", " + } + t.Result += fmt.Sprintf("%s%s", cm, r) + } + if len(t.Results) > 1 { + t.Result += ")" + } + } + + fd, err := os.Create(*out) + if err != nil { + log.Fatal(err) + } + t, err := template.New("foo").Parse(tmpl) + if err != nil { + log.Fatal(err) + } + type par struct { + Type string + Stuff []*Function + } + p := par{*typ, types} + if false { // debugging the template + t.Execute(os.Stderr, &p) + } + buf := bytes.NewBuffer(nil) + err = t.Execute(buf, &p) + if err != nil { + log.Fatal(err) + } + ans, err := format.Source(bytes.Replace(buf.Bytes(), []byte("\\\n"), []byte{}, -1)) + if err != nil { + log.Fatal(err) + } + fd.Write(ans) +} + +func doUses() { + fset := token.NewFileSet() + pkgs, err := parser.ParseDir(fset, *use, nil, 0) + if err != nil { + log.Fatalf("%q:%v", *use, err) + } + pkg := pkgs["lsp"] // CHECK + files := pkg.Files + for fname, f := range files { + for _, d := range f.Decls { + fd, ok := d.(*ast.FuncDecl) + if !ok { + continue + } + nm := fd.Name.String() + if ast.IsExported(nm) { + // we're looking for things like didChange + continue + } + if fx, ok := byname[nm]; ok { + if fx.Found != "" { + log.Fatalf("found %s in %s and %s", fx.Internal, fx.Found, fname) + } + fx.Found = fname + // and the Paramnames + ft := fd.Type + for _, f := range ft.Params.List { + nm := "" + if len(f.Names) > 0 { + nm = f.Names[0].String() + } + fx.paramnames = append(fx.paramnames, nm) + } + } + } + } + if false { + for i, f := range types { + log.Printf("%d %s %s", i, f.Internal, f.Found) + } + } +} + +type Function struct { + Name string + Internal string // first letter lower case + paramtypes []string + paramnames []string + Results []string + Param string + Result string // do it in code, easier than in a template + Invoke string + Found string // file it was found in +} + +var types []*Function +var byname = map[string]*Function{} // internal names + +func doTypes() { + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, *def, nil, 0) + if err != nil { + log.Fatal(err) + } + fd, err := os.Create("/tmp/ast") + if err != nil { + log.Fatal(err) + } + ast.Fprint(fd, fset, f, ast.NotNilFilter) + ast.Inspect(f, inter) + sort.Slice(types, func(i, j int) bool { return types[i].Name < types[j].Name }) + if false { + for i, f := range types { + log.Printf("%d %s(%v) %v", i, f.Name, f.paramtypes, f.Results) + } + } +} + +func inter(n ast.Node) bool { + x, ok := n.(*ast.TypeSpec) + if !ok || x.Name.Name != *typ { + return true + } + m := x.Type.(*ast.InterfaceType).Methods.List + for _, fld := range m { + fn := fld.Type.(*ast.FuncType) + p := fn.Params.List + r := fn.Results.List + fx := &Function{ + Name: fld.Names[0].String(), + } + fx.Internal = strings.ToLower(fx.Name[:1]) + fx.Name[1:] + for _, f := range p { + fx.paramtypes = append(fx.paramtypes, whatis(f.Type)) + } + for _, f := range r { + fx.Results = append(fx.Results, whatis(f.Type)) + } + types = append(types, fx) + byname[fx.Internal] = fx + } + return false +} + +func whatis(x ast.Expr) string { + switch n := x.(type) { + case *ast.SelectorExpr: + return whatis(n.X) + "." + n.Sel.String() + case *ast.StarExpr: + return "*" + whatis(n.X) + case *ast.Ident: + if ast.IsExported(n.Name) { + // these are from package protocol + return "protocol." + n.Name + } + return n.Name + case *ast.ArrayType: + return "[]" + whatis(n.Elt) + case *ast.InterfaceType: + return "interface{}" + default: + log.Fatalf("Fatal %T", x) + return fmt.Sprintf("%T", x) + } +}