github.com/jd-ly/tools@v0.5.7/internal/lsp/mod/code_lens.go (about) 1 package mod 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "path/filepath" 8 9 "github.com/jd-ly/tools/internal/lsp/protocol" 10 "github.com/jd-ly/tools/internal/lsp/source" 11 "github.com/jd-ly/tools/internal/span" 12 ) 13 14 // LensFuncs returns the supported lensFuncs for go.mod files. 15 func LensFuncs() map[string]source.LensFunc { 16 return map[string]source.LensFunc{ 17 source.CommandUpgradeDependency.Name: upgradeLens, 18 source.CommandTidy.Name: tidyLens, 19 source.CommandVendor.Name: vendorLens, 20 } 21 } 22 23 func upgradeLens(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]protocol.CodeLens, error) { 24 pm, err := snapshot.ParseMod(ctx, fh) 25 if err != nil || pm.File == nil { 26 return nil, err 27 } 28 if len(pm.File.Require) == 0 { 29 // Nothing to upgrade. 30 return nil, nil 31 } 32 upgradeDepArgs, err := source.MarshalArgs(fh.URI(), false, []string{"-u", "all"}) 33 if err != nil { 34 return nil, err 35 } 36 rng, err := moduleStmtRange(fh, pm) 37 if err != nil { 38 return nil, err 39 } 40 return []protocol.CodeLens{{ 41 Range: rng, 42 Command: protocol.Command{ 43 Title: "Upgrade all dependencies", 44 Command: source.CommandUpgradeDependency.ID(), 45 Arguments: upgradeDepArgs, 46 }, 47 }}, nil 48 49 } 50 51 func tidyLens(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]protocol.CodeLens, error) { 52 pm, err := snapshot.ParseMod(ctx, fh) 53 if err != nil || pm.File == nil { 54 return nil, err 55 } 56 if len(pm.File.Require) == 0 { 57 // Nothing to vendor. 58 return nil, nil 59 } 60 goModArgs, err := source.MarshalArgs(fh.URI()) 61 if err != nil { 62 return nil, err 63 } 64 rng, err := moduleStmtRange(fh, pm) 65 if err != nil { 66 return nil, err 67 } 68 return []protocol.CodeLens{{ 69 Range: rng, 70 Command: protocol.Command{ 71 Title: source.CommandTidy.Title, 72 Command: source.CommandTidy.ID(), 73 Arguments: goModArgs, 74 }, 75 }}, nil 76 } 77 78 func vendorLens(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]protocol.CodeLens, error) { 79 pm, err := snapshot.ParseMod(ctx, fh) 80 if err != nil || pm.File == nil { 81 return nil, err 82 } 83 rng, err := moduleStmtRange(fh, pm) 84 if err != nil { 85 return nil, err 86 } 87 goModArgs, err := source.MarshalArgs(fh.URI()) 88 if err != nil { 89 return nil, err 90 } 91 // Change the message depending on whether or not the module already has a 92 // vendor directory. 93 title := "Create vendor directory" 94 vendorDir := filepath.Join(filepath.Dir(fh.URI().Filename()), "vendor") 95 if info, _ := os.Stat(vendorDir); info != nil && info.IsDir() { 96 title = "Sync vendor directory" 97 } 98 return []protocol.CodeLens{{ 99 Range: rng, 100 Command: protocol.Command{ 101 Title: title, 102 Command: source.CommandVendor.ID(), 103 Arguments: goModArgs, 104 }, 105 }}, nil 106 } 107 108 func moduleStmtRange(fh source.FileHandle, pm *source.ParsedModule) (protocol.Range, error) { 109 if pm.File == nil || pm.File.Module == nil || pm.File.Module.Syntax == nil { 110 return protocol.Range{}, fmt.Errorf("no module statement in %s", fh.URI()) 111 } 112 syntax := pm.File.Module.Syntax 113 line, col, err := pm.Mapper.Converter.ToPosition(syntax.Start.Byte) 114 if err != nil { 115 return protocol.Range{}, err 116 } 117 start := span.NewPoint(line, col, syntax.Start.Byte) 118 line, col, err = pm.Mapper.Converter.ToPosition(syntax.End.Byte) 119 if err != nil { 120 return protocol.Range{}, err 121 } 122 end := span.NewPoint(line, col, syntax.End.Byte) 123 rng, err := pm.Mapper.Range(span.New(fh.URI(), start, end)) 124 if err != nil { 125 return protocol.Range{}, err 126 } 127 return rng, err 128 }