github.com/v2fly/tools@v0.100.0/internal/lsp/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  	"github.com/v2fly/tools/internal/imports"
    16  	"github.com/v2fly/tools/internal/lsp/command/commandmeta"
    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  package command
    29  
    30  // Code generated by generate.go. DO NOT EDIT.
    31  
    32  import (
    33  	{{range $k, $v := .Imports -}}
    34  	"{{$k}}"
    35  	{{end}}
    36  )
    37  
    38  const (
    39  {{- range .Commands}}
    40  	{{.MethodName}} Command = "{{.Name}}"
    41  {{- end}}
    42  )
    43  
    44  var Commands = []Command {
    45  {{- range .Commands}}
    46  	{{.MethodName}},
    47  {{- end}}
    48  }
    49  
    50  func Dispatch(ctx context.Context, params *protocol.ExecuteCommandParams, s Interface) (interface{}, error) {
    51  	switch params.Command {
    52  	{{- range .Commands}}
    53  	case "{{.ID}}":
    54  		{{- if .Args -}}
    55  			{{- range $i, $v := .Args}}
    56  		var a{{$i}} {{typeString $v.Type}}
    57  			{{- end}}
    58  		if err := UnmarshalArgs(params.Arguments{{range $i, $v := .Args}}, &a{{$i}}{{end}}); err != nil {
    59  			return nil, err
    60  		}
    61  		{{end -}}
    62  		return {{if not .Result}}nil, {{end}}s.{{.MethodName}}(ctx{{range $i, $v := .Args}}, a{{$i}}{{end}})
    63  	{{- end}}
    64  	}
    65  	return nil, fmt.Errorf("unsupported command %q", params.Command)
    66  }
    67  {{- range .Commands}}
    68  
    69  func New{{.MethodName}}Command(title string, {{range $i, $v := .Args}}{{if $i}}, {{end}}a{{$i}} {{typeString $v.Type}}{{end}}) (protocol.Command, error) {
    70  	args, err := MarshalArgs({{range $i, $v := .Args}}{{if $i}}, {{end}}a{{$i}}{{end}})
    71  	if err != nil {
    72  		return protocol.Command{}, err
    73  	}
    74  	return protocol.Command{
    75  		Title: title,
    76  		Command: "{{.ID}}",
    77  		Arguments: args,
    78  	}, nil
    79  }
    80  {{end}}
    81  `
    82  
    83  type data struct {
    84  	Imports  map[string]bool
    85  	Commands []*commandmeta.Command
    86  }
    87  
    88  func Generate() ([]byte, error) {
    89  	pkg, cmds, err := commandmeta.Load()
    90  	if err != nil {
    91  		return nil, fmt.Errorf("loading command data: %v", err)
    92  	}
    93  	qf := func(p *types.Package) string {
    94  		if p == pkg.Types {
    95  			return ""
    96  		}
    97  		return p.Name()
    98  	}
    99  	tmpl, err := template.New("").Funcs(template.FuncMap{
   100  		"typeString": func(t types.Type) string {
   101  			return types.TypeString(t, qf)
   102  		},
   103  	}).Parse(src)
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  	d := data{
   108  		Commands: cmds,
   109  		Imports: map[string]bool{
   110  			"context": true,
   111  			"fmt":     true,
   112  			"github.com/v2fly/tools/internal/lsp/protocol": true,
   113  		},
   114  	}
   115  	const thispkg = "github.com/v2fly/tools/internal/lsp/command"
   116  	for _, c := range d.Commands {
   117  		for _, arg := range c.Args {
   118  			pth := pkgPath(arg.Type)
   119  			if pth != "" && pth != thispkg {
   120  				d.Imports[pth] = true
   121  			}
   122  		}
   123  		pth := pkgPath(c.Result)
   124  		if pth != "" && pth != thispkg {
   125  			d.Imports[pth] = true
   126  		}
   127  	}
   128  
   129  	var buf bytes.Buffer
   130  	if err := tmpl.Execute(&buf, d); err != nil {
   131  		return nil, fmt.Errorf("executing: %v", err)
   132  	}
   133  
   134  	opts := &imports.Options{
   135  		AllErrors:  true,
   136  		FormatOnly: true,
   137  		Comments:   true,
   138  	}
   139  	content, err := imports.Process("", buf.Bytes(), opts)
   140  	if err != nil {
   141  		return nil, fmt.Errorf("goimports: %v", err)
   142  	}
   143  	return content, nil
   144  }
   145  
   146  func pkgPath(t types.Type) string {
   147  	if n, ok := t.(*types.Named); ok {
   148  		if pkg := n.Obj().Pkg(); pkg != nil {
   149  			return pkg.Path()
   150  		}
   151  	}
   152  	return ""
   153  }