2020-02-06 12:50:26 -07:00
|
|
|
package mod
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
|
2020-02-26 12:11:30 -07:00
|
|
|
"golang.org/x/mod/modfile"
|
2020-04-17 07:32:56 -06:00
|
|
|
"golang.org/x/tools/internal/event"
|
2020-03-10 21:09:39 -06:00
|
|
|
"golang.org/x/tools/internal/lsp/debug/tag"
|
2020-02-06 12:50:26 -07:00
|
|
|
"golang.org/x/tools/internal/lsp/protocol"
|
|
|
|
"golang.org/x/tools/internal/lsp/source"
|
|
|
|
"golang.org/x/tools/internal/span"
|
|
|
|
)
|
|
|
|
|
2020-05-06 20:54:50 -06:00
|
|
|
// CodeLens computes code lens for a go.mod file.
|
2020-02-06 12:50:26 -07:00
|
|
|
func CodeLens(ctx context.Context, snapshot source.Snapshot, uri span.URI) ([]protocol.CodeLens, error) {
|
2020-07-23 21:24:36 -06:00
|
|
|
if !snapshot.View().Options().EnabledCodeLens[source.CommandUpgradeDependency.Name] {
|
2020-05-06 20:54:50 -06:00
|
|
|
return nil, nil
|
|
|
|
}
|
2020-06-10 23:11:52 -06:00
|
|
|
ctx, done := event.Start(ctx, "mod.CodeLens", tag.URI.Of(uri))
|
2020-02-06 12:50:26 -07:00
|
|
|
defer done()
|
|
|
|
|
2020-06-19 17:07:57 -06:00
|
|
|
// Only show go.mod code lenses in module mode, for the view's go.mod.
|
|
|
|
if modURI := snapshot.View().ModFile(); modURI == "" || modURI != uri {
|
2020-06-10 23:11:52 -06:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
fh, err := snapshot.GetFile(ctx, uri)
|
2020-02-06 12:50:26 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-07-24 11:39:58 -06:00
|
|
|
pm, err := snapshot.ParseMod(ctx, fh)
|
2020-06-10 14:13:25 -06:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-07-24 11:39:58 -06:00
|
|
|
upgrades, err := snapshot.ModUpgrade(ctx)
|
2020-06-19 17:07:57 -06:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
var (
|
|
|
|
codelens []protocol.CodeLens
|
|
|
|
allUpgrades []string
|
|
|
|
)
|
2020-07-24 11:39:58 -06:00
|
|
|
for _, req := range pm.File.Require {
|
2020-02-06 12:50:26 -07:00
|
|
|
dep := req.Mod.Path
|
|
|
|
latest, ok := upgrades[dep]
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
// Get the range of the require directive.
|
2020-07-24 11:39:58 -06:00
|
|
|
rng, err := positionsToRange(uri, pm.Mapper, req.Syntax.Start, req.Syntax.End)
|
2020-02-06 12:50:26 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-07-27 14:47:26 -06:00
|
|
|
jsonArgs, err := source.MarshalArgs(uri, []string{dep})
|
2020-07-14 18:40:38 -06:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-02-26 12:11:30 -07:00
|
|
|
codelens = append(codelens, protocol.CodeLens{
|
|
|
|
Range: rng,
|
|
|
|
Command: protocol.Command{
|
|
|
|
Title: fmt.Sprintf("Upgrade dependency to %s", latest),
|
2020-07-23 21:24:36 -06:00
|
|
|
Command: source.CommandUpgradeDependency.Name,
|
2020-07-14 18:40:38 -06:00
|
|
|
Arguments: jsonArgs,
|
2020-02-26 12:11:30 -07:00
|
|
|
},
|
|
|
|
})
|
|
|
|
allUpgrades = append(allUpgrades, dep)
|
|
|
|
}
|
|
|
|
// If there is at least 1 upgrade, add an "Upgrade all dependencies" to the module statement.
|
2020-07-24 11:39:58 -06:00
|
|
|
if module := pm.File.Module; len(allUpgrades) > 0 && module != nil && module.Syntax != nil {
|
2020-02-26 12:11:30 -07:00
|
|
|
// Get the range of the module directive.
|
2020-07-24 11:39:58 -06:00
|
|
|
rng, err := positionsToRange(uri, pm.Mapper, module.Syntax.Start, module.Syntax.End)
|
2020-02-06 12:50:26 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-07-23 21:24:36 -06:00
|
|
|
jsonArgs, err := source.MarshalArgs(uri, append([]string{"-u"}, allUpgrades...))
|
2020-07-14 18:40:38 -06:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-02-06 12:50:26 -07:00
|
|
|
codelens = append(codelens, protocol.CodeLens{
|
|
|
|
Range: rng,
|
|
|
|
Command: protocol.Command{
|
2020-02-26 12:11:30 -07:00
|
|
|
Title: "Upgrade all dependencies",
|
2020-07-23 21:24:36 -06:00
|
|
|
Command: source.CommandUpgradeDependency.Name,
|
2020-07-14 18:40:38 -06:00
|
|
|
Arguments: jsonArgs,
|
2020-02-06 12:50:26 -07:00
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return codelens, err
|
|
|
|
}
|
2020-02-26 12:11:30 -07:00
|
|
|
|
|
|
|
func positionsToRange(uri span.URI, m *protocol.ColumnMapper, s, e modfile.Position) (protocol.Range, error) {
|
|
|
|
line, col, err := m.Converter.ToPosition(s.Byte)
|
|
|
|
if err != nil {
|
|
|
|
return protocol.Range{}, err
|
|
|
|
}
|
|
|
|
start := span.NewPoint(line, col, s.Byte)
|
|
|
|
line, col, err = m.Converter.ToPosition(e.Byte)
|
|
|
|
if err != nil {
|
|
|
|
return protocol.Range{}, err
|
|
|
|
}
|
|
|
|
end := span.NewPoint(line, col, e.Byte)
|
|
|
|
rng, err := m.Range(span.New(uri, start, end))
|
|
|
|
if err != nil {
|
|
|
|
return protocol.Range{}, err
|
|
|
|
}
|
|
|
|
return rng, err
|
|
|
|
}
|