+++ /dev/null
-package mod
-
-import (
- "context"
- "fmt"
- "os"
- "path/filepath"
-
- "golang.org/x/mod/modfile"
- "golang.org/x/tools/internal/lsp/protocol"
- "golang.org/x/tools/internal/lsp/source"
- "golang.org/x/tools/internal/span"
-)
-
-// LensFuncs returns the supported lensFuncs for go.mod files.
-func LensFuncs() map[string]source.LensFunc {
- return map[string]source.LensFunc{
- source.CommandUpgradeDependency.Name: upgradeLens,
- source.CommandTidy.Name: tidyLens,
- source.CommandVendor.Name: vendorLens,
- }
-}
-
-func upgradeLens(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]protocol.CodeLens, error) {
- pm, err := snapshot.ParseMod(ctx, fh)
- if err != nil {
- return nil, err
- }
- module := pm.File.Module
- if module == nil || module.Syntax == nil {
- return nil, nil
- }
- upgrades, err := snapshot.ModUpgrade(ctx, fh)
- if err != nil {
- return nil, err
- }
- var (
- codelenses []protocol.CodeLens
- allUpgrades []string
- )
- for _, req := range pm.File.Require {
- dep := req.Mod.Path
- latest, ok := upgrades[dep]
- if !ok {
- continue
- }
- if req.Syntax == nil {
- continue
- }
- // Get the range of the require directive.
- rng, err := positionsToRange(fh.URI(), pm.Mapper, req.Syntax.Start, req.Syntax.End)
- if err != nil {
- return nil, err
- }
- upgradeDepArgs, err := source.MarshalArgs(fh.URI(), false, []string{dep})
- if err != nil {
- return nil, err
- }
- codelenses = append(codelenses, protocol.CodeLens{
- Range: rng,
- Command: protocol.Command{
- Title: fmt.Sprintf("Upgrade dependency to %s", latest),
- Command: source.CommandUpgradeDependency.ID(),
- Arguments: upgradeDepArgs,
- },
- })
- allUpgrades = append(allUpgrades, dep)
- }
- // If there is at least 1 upgrade, add "Upgrade all dependencies" to
- // the module statement.
- if len(allUpgrades) > 0 {
- upgradeDepArgs, err := source.MarshalArgs(fh.URI(), false, append([]string{"-u"}, allUpgrades...))
- if err != nil {
- return nil, err
- }
- // Get the range of the module directive.
- moduleRng, err := positionsToRange(pm.Mapper.URI, pm.Mapper, module.Syntax.Start, module.Syntax.End)
- if err != nil {
- return nil, err
- }
- codelenses = append(codelenses, protocol.CodeLens{
- Range: moduleRng,
- Command: protocol.Command{
- Title: "Upgrade all dependencies",
- Command: source.CommandUpgradeDependency.ID(),
- Arguments: upgradeDepArgs,
- },
- })
- }
- return codelenses, err
-}
-
-func tidyLens(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]protocol.CodeLens, error) {
- goModArgs, err := source.MarshalArgs(fh.URI())
- if err != nil {
- return nil, err
- }
- tidied, err := snapshot.ModTidy(ctx, fh)
- if err != nil {
- return nil, err
- }
- if len(tidied.Errors) == 0 {
- return nil, nil
- }
- pm, err := snapshot.ParseMod(ctx, fh)
- if err != nil {
- return nil, err
- }
- if pm.File == nil || pm.File.Module == nil || pm.File.Module.Syntax == nil {
- return nil, fmt.Errorf("no parsed go.mod for %s", fh.URI())
- }
- rng, err := positionsToRange(pm.Mapper.URI, pm.Mapper, pm.File.Module.Syntax.Start, pm.File.Module.Syntax.End)
- if err != nil {
- return nil, err
- }
- return []protocol.CodeLens{{
- Range: rng,
- Command: protocol.Command{
- Title: source.CommandTidy.Title,
- Command: source.CommandTidy.ID(),
- Arguments: goModArgs,
- },
- }}, err
-}
-
-func vendorLens(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]protocol.CodeLens, error) {
- goModArgs, err := source.MarshalArgs(fh.URI())
- if err != nil {
- return nil, err
- }
- pm, err := snapshot.ParseMod(ctx, fh)
- if err != nil {
- return nil, err
- }
- if pm.File == nil || pm.File.Module == nil || pm.File.Module.Syntax == nil {
- return nil, fmt.Errorf("no parsed go.mod for %s", fh.URI())
- }
- rng, err := positionsToRange(pm.Mapper.URI, pm.Mapper, pm.File.Module.Syntax.Start, pm.File.Module.Syntax.End)
- if err != nil {
- return nil, err
- }
- // Change the message depending on whether or not the module already has a
- // vendor directory.
- title := "Create vendor directory"
- vendorDir := filepath.Join(filepath.Dir(fh.URI().Filename()), "vendor")
- if info, _ := os.Stat(vendorDir); info != nil && info.IsDir() {
- title = "Sync vendor directory"
- }
- return []protocol.CodeLens{{
- Range: rng,
- Command: protocol.Command{
- Title: title,
- Command: source.CommandVendor.ID(),
- Arguments: goModArgs,
- },
- }}, nil
-}
-
-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
-}