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  }