golang.org/x/tools/gopls@v0.15.3/internal/protocol/command/gen/gen.go (about)

     1  // Copyright 2021 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package gen is used to generate command bindings from the gopls command
     6  // interface.
     7  package gen
     8  
     9  import (
    10  	"bytes"
    11  	"fmt"
    12  	"go/types"
    13  	"text/template"
    14  
    15  	"golang.org/x/tools/gopls/internal/protocol/command/commandmeta"
    16  	"golang.org/x/tools/internal/imports"
    17  )
    18  
    19  const src = `// Copyright 2021 The Go Authors. All rights reserved.
    20  // Use of this source code is governed by a BSD-style
    21  // license that can be found in the LICENSE file.
    22  
    23  // Don't include this file during code generation, or it will break the build
    24  // if existing interface methods have been modified.
    25  //go:build !generate
    26  // +build !generate
    27  
    28  // Code generated by gen.go. DO NOT EDIT.
    29  
    30  package command
    31  
    32  import (
    33  	{{range $k, $v := .Imports -}}
    34  	"{{$k}}"
    35  	{{end}}
    36  )
    37  
    38  // Symbolic names for gopls commands, excluding "gopls." prefix.
    39  // These commands may be requested by ExecuteCommand, CodeLens,
    40  // CodeAction, and other LSP requests.
    41  const (
    42  {{- range .Commands}}
    43  	{{.MethodName}} Command = "{{.Name}}"
    44  {{- end}}
    45  )
    46  
    47  var Commands = []Command {
    48  {{- range .Commands}}
    49  	{{.MethodName}},
    50  {{- end}}
    51  }
    52  
    53  func Dispatch(ctx context.Context, params *protocol.ExecuteCommandParams, s Interface) (interface{}, error) {
    54  	switch params.Command {
    55  	{{- range .Commands}}
    56  	case "{{.ID}}":
    57  		{{- if .Args -}}
    58  			{{- range $i, $v := .Args}}
    59  		var a{{$i}} {{typeString $v.Type}}
    60  			{{- end}}
    61  		if err := UnmarshalArgs(params.Arguments{{range $i, $v := .Args}}, &a{{$i}}{{end}}); err != nil {
    62  			return nil, err
    63  		}
    64  		{{end -}}
    65  		return {{if not .Result}}nil, {{end}}s.{{.MethodName}}(ctx{{range $i, $v := .Args}}, a{{$i}}{{end}})
    66  	{{- end}}
    67  	}
    68  	return nil, fmt.Errorf("unsupported command %q", params.Command)
    69  }
    70  {{- range .Commands}}
    71  
    72  func New{{.MethodName}}Command(title string, {{range $i, $v := .Args}}{{if $i}}, {{end}}a{{$i}} {{typeString $v.Type}}{{end}}) (protocol.Command, error) {
    73  	args, err := MarshalArgs({{range $i, $v := .Args}}{{if $i}}, {{end}}a{{$i}}{{end}})
    74  	if err != nil {
    75  		return protocol.Command{}, err
    76  	}
    77  	return protocol.Command{
    78  		Title: title,
    79  		Command: "{{.ID}}",
    80  		Arguments: args,
    81  	}, nil
    82  }
    83  {{end}}
    84  `
    85  
    86  type data struct {
    87  	Imports  map[string]bool
    88  	Commands []*commandmeta.Command
    89  }
    90  
    91  func Generate() ([]byte, error) {
    92  	pkg, cmds, err := commandmeta.Load()
    93  	if err != nil {
    94  		return nil, fmt.Errorf("loading command data: %v", err)
    95  	}
    96  	qf := func(p *types.Package) string {
    97  		if p == pkg.Types {
    98  			return ""
    99  		}
   100  		return p.Name()
   101  	}
   102  	tmpl, err := template.New("").Funcs(template.FuncMap{
   103  		"typeString": func(t types.Type) string {
   104  			return types.TypeString(t, qf)
   105  		},
   106  	}).Parse(src)
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  	d := data{
   111  		Commands: cmds,
   112  		Imports: map[string]bool{
   113  			"context": true,
   114  			"fmt":     true,
   115  			"golang.org/x/tools/gopls/internal/protocol": true,
   116  		},
   117  	}
   118  	const thispkg = "golang.org/x/tools/gopls/internal/protocol/command"
   119  	for _, c := range d.Commands {
   120  		for _, arg := range c.Args {
   121  			pth := pkgPath(arg.Type)
   122  			if pth != "" && pth != thispkg {
   123  				d.Imports[pth] = true
   124  			}
   125  		}
   126  		if c.Result != nil {
   127  			pth := pkgPath(c.Result.Type)
   128  			if pth != "" && pth != thispkg {
   129  				d.Imports[pth] = true
   130  			}
   131  		}
   132  	}
   133  
   134  	var buf bytes.Buffer
   135  	if err := tmpl.Execute(&buf, d); err != nil {
   136  		return nil, fmt.Errorf("executing: %v", err)
   137  	}
   138  
   139  	opts := &imports.Options{
   140  		AllErrors:  true,
   141  		FormatOnly: true,
   142  		Comments:   true,
   143  	}
   144  	content, err := imports.Process("", buf.Bytes(), opts)
   145  	if err != nil {
   146  		return nil, fmt.Errorf("goimports: %v", err)
   147  	}
   148  	return content, nil
   149  }
   150  
   151  func pkgPath(t types.Type) string {
   152  	if n, ok := t.(*types.Named); ok {
   153  		if pkg := n.Obj().Pkg(); pkg != nil {
   154  			return pkg.Path()
   155  		}
   156  	}
   157  	return ""
   158  }