Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / internal / lsp / mod / code_lens.go
1 package mod
2
3 import (
4         "context"
5         "fmt"
6         "os"
7         "path/filepath"
8
9         "golang.org/x/mod/modfile"
10         "golang.org/x/tools/internal/lsp/protocol"
11         "golang.org/x/tools/internal/lsp/source"
12         "golang.org/x/tools/internal/span"
13 )
14
15 // LensFuncs returns the supported lensFuncs for go.mod files.
16 func LensFuncs() map[string]source.LensFunc {
17         return map[string]source.LensFunc{
18                 source.CommandUpgradeDependency.Name: upgradeLens,
19                 source.CommandTidy.Name:              tidyLens,
20                 source.CommandVendor.Name:            vendorLens,
21         }
22 }
23
24 func upgradeLens(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]protocol.CodeLens, error) {
25         pm, err := snapshot.ParseMod(ctx, fh)
26         if err != nil {
27                 return nil, err
28         }
29         module := pm.File.Module
30         if module == nil || module.Syntax == nil {
31                 return nil, nil
32         }
33         upgrades, err := snapshot.ModUpgrade(ctx, fh)
34         if err != nil {
35                 return nil, err
36         }
37         var (
38                 codelenses  []protocol.CodeLens
39                 allUpgrades []string
40         )
41         for _, req := range pm.File.Require {
42                 dep := req.Mod.Path
43                 latest, ok := upgrades[dep]
44                 if !ok {
45                         continue
46                 }
47                 if req.Syntax == nil {
48                         continue
49                 }
50                 // Get the range of the require directive.
51                 rng, err := positionsToRange(fh.URI(), pm.Mapper, req.Syntax.Start, req.Syntax.End)
52                 if err != nil {
53                         return nil, err
54                 }
55                 upgradeDepArgs, err := source.MarshalArgs(fh.URI(), false, []string{dep})
56                 if err != nil {
57                         return nil, err
58                 }
59                 codelenses = append(codelenses, protocol.CodeLens{
60                         Range: rng,
61                         Command: protocol.Command{
62                                 Title:     fmt.Sprintf("Upgrade dependency to %s", latest),
63                                 Command:   source.CommandUpgradeDependency.ID(),
64                                 Arguments: upgradeDepArgs,
65                         },
66                 })
67                 allUpgrades = append(allUpgrades, dep)
68         }
69         // If there is at least 1 upgrade, add "Upgrade all dependencies" to
70         // the module statement.
71         if len(allUpgrades) > 0 {
72                 upgradeDepArgs, err := source.MarshalArgs(fh.URI(), false, append([]string{"-u"}, allUpgrades...))
73                 if err != nil {
74                         return nil, err
75                 }
76                 // Get the range of the module directive.
77                 moduleRng, err := positionsToRange(pm.Mapper.URI, pm.Mapper, module.Syntax.Start, module.Syntax.End)
78                 if err != nil {
79                         return nil, err
80                 }
81                 codelenses = append(codelenses, protocol.CodeLens{
82                         Range: moduleRng,
83                         Command: protocol.Command{
84                                 Title:     "Upgrade all dependencies",
85                                 Command:   source.CommandUpgradeDependency.ID(),
86                                 Arguments: upgradeDepArgs,
87                         },
88                 })
89         }
90         return codelenses, err
91 }
92
93 func tidyLens(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]protocol.CodeLens, error) {
94         goModArgs, err := source.MarshalArgs(fh.URI())
95         if err != nil {
96                 return nil, err
97         }
98         tidied, err := snapshot.ModTidy(ctx, fh)
99         if err != nil {
100                 return nil, err
101         }
102         if len(tidied.Errors) == 0 {
103                 return nil, nil
104         }
105         pm, err := snapshot.ParseMod(ctx, fh)
106         if err != nil {
107                 return nil, err
108         }
109         if pm.File == nil || pm.File.Module == nil || pm.File.Module.Syntax == nil {
110                 return nil, fmt.Errorf("no parsed go.mod for %s", fh.URI())
111         }
112         rng, err := positionsToRange(pm.Mapper.URI, pm.Mapper, pm.File.Module.Syntax.Start, pm.File.Module.Syntax.End)
113         if err != nil {
114                 return nil, err
115         }
116         return []protocol.CodeLens{{
117                 Range: rng,
118                 Command: protocol.Command{
119                         Title:     source.CommandTidy.Title,
120                         Command:   source.CommandTidy.ID(),
121                         Arguments: goModArgs,
122                 },
123         }}, err
124 }
125
126 func vendorLens(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]protocol.CodeLens, error) {
127         goModArgs, err := source.MarshalArgs(fh.URI())
128         if err != nil {
129                 return nil, err
130         }
131         pm, err := snapshot.ParseMod(ctx, fh)
132         if err != nil {
133                 return nil, err
134         }
135         if pm.File == nil || pm.File.Module == nil || pm.File.Module.Syntax == nil {
136                 return nil, fmt.Errorf("no parsed go.mod for %s", fh.URI())
137         }
138         rng, err := positionsToRange(pm.Mapper.URI, pm.Mapper, pm.File.Module.Syntax.Start, pm.File.Module.Syntax.End)
139         if err != nil {
140                 return nil, err
141         }
142         // Change the message depending on whether or not the module already has a
143         // vendor directory.
144         title := "Create vendor directory"
145         vendorDir := filepath.Join(filepath.Dir(fh.URI().Filename()), "vendor")
146         if info, _ := os.Stat(vendorDir); info != nil && info.IsDir() {
147                 title = "Sync vendor directory"
148         }
149         return []protocol.CodeLens{{
150                 Range: rng,
151                 Command: protocol.Command{
152                         Title:     title,
153                         Command:   source.CommandVendor.ID(),
154                         Arguments: goModArgs,
155                 },
156         }}, nil
157 }
158
159 func positionsToRange(uri span.URI, m *protocol.ColumnMapper, s, e modfile.Position) (protocol.Range, error) {
160         line, col, err := m.Converter.ToPosition(s.Byte)
161         if err != nil {
162                 return protocol.Range{}, err
163         }
164         start := span.NewPoint(line, col, s.Byte)
165         line, col, err = m.Converter.ToPosition(e.Byte)
166         if err != nil {
167                 return protocol.Range{}, err
168         }
169         end := span.NewPoint(line, col, e.Byte)
170         rng, err := m.Range(span.New(uri, start, end))
171         if err != nil {
172                 return protocol.Range{}, err
173         }
174         return rng, err
175 }