mirror of https://github.com/golang/go.git
internal/lsp: add a command to generate the gopls.mod file
Wire up a command to generate a gopls.mod file for a multi-module workspace. In the future, this can actually be used to manage the workspace, but for now the file is just generated, not actually used. For golang/go#32394 Change-Id: I8a53da8ac9337bde132c7d8ca8557467f368fc24 Reviewed-on: https://go-review.googlesource.com/c/tools/+/256042 Run-TryBot: Robert Findley <rfindley@google.com> gopls-CI: kokoro <noreply+kokoro@google.com> TryBot-Result: Go Bot <gobot@golang.org> Trust: Robert Findley <rfindley@google.com> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
03f0cc1caa
commit
463111b698
|
|
@ -1374,7 +1374,7 @@ func (s *snapshot) getWorkspaceModuleHandle(ctx context.Context) (*workspaceModu
|
|||
h := s.generation.Bind(key, func(ctx context.Context, arg memoize.Arg) interface{} {
|
||||
s := arg.(*snapshot)
|
||||
data := &workspaceModuleData{}
|
||||
data.file, data.err = s.buildWorkspaceModule(ctx)
|
||||
data.file, data.err = s.BuildWorkspaceModFile(ctx)
|
||||
return data
|
||||
})
|
||||
wsModule = &workspaceModuleHandle{
|
||||
|
|
@ -1386,9 +1386,9 @@ func (s *snapshot) getWorkspaceModuleHandle(ctx context.Context) (*workspaceModu
|
|||
return s.workspaceModuleHandle, nil
|
||||
}
|
||||
|
||||
// buildWorkspaceModule generates a workspace module given the modules in the
|
||||
// BuildWorkspaceModFile generates a workspace module given the modules in the
|
||||
// the workspace.
|
||||
func (s *snapshot) buildWorkspaceModule(ctx context.Context) (*modfile.File, error) {
|
||||
func (s *snapshot) BuildWorkspaceModFile(ctx context.Context) (*modfile.File, error) {
|
||||
file := &modfile.File{}
|
||||
file.AddModuleStmt("gopls-workspace")
|
||||
|
||||
|
|
|
|||
|
|
@ -192,6 +192,7 @@ func (app *Application) featureCommands() []tool.Application {
|
|||
&signature{app: app},
|
||||
&suggestedFix{app: app},
|
||||
&symbols{app: app},
|
||||
&workspace{app: app},
|
||||
&workspaceSymbol{app: app},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,90 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/tools/internal/lsp/protocol"
|
||||
"golang.org/x/tools/internal/lsp/source"
|
||||
"golang.org/x/tools/internal/tool"
|
||||
)
|
||||
|
||||
// workspace is a top-level command for working with the gopls workspace. This
|
||||
// is experimental and subject to change. The idea is that subcommands could be
|
||||
// used for manipulating the workspace mod file, rather than editing it
|
||||
// manually.
|
||||
type workspace struct {
|
||||
app *Application
|
||||
}
|
||||
|
||||
func (w *workspace) subCommands() []tool.Application {
|
||||
return []tool.Application{
|
||||
&generateWorkspaceMod{app: w.app},
|
||||
}
|
||||
}
|
||||
|
||||
func (w *workspace) Name() string { return "workspace" }
|
||||
func (w *workspace) Usage() string { return "<subcommand> [args...]" }
|
||||
func (w *workspace) ShortHelp() string {
|
||||
return "manage the gopls workspace (experimental: under development)"
|
||||
}
|
||||
|
||||
func (w *workspace) DetailedHelp(f *flag.FlagSet) {
|
||||
fmt.Fprint(f.Output(), "\nsubcommands:\n")
|
||||
for _, c := range w.subCommands() {
|
||||
fmt.Fprintf(f.Output(), " %s: %s\n", c.Name(), c.ShortHelp())
|
||||
}
|
||||
f.PrintDefaults()
|
||||
}
|
||||
|
||||
func (w *workspace) Run(ctx context.Context, args ...string) error {
|
||||
if len(args) == 0 {
|
||||
return tool.CommandLineErrorf("must provide subcommand to %q", w.Name())
|
||||
}
|
||||
command, args := args[0], args[1:]
|
||||
for _, c := range w.subCommands() {
|
||||
if c.Name() == command {
|
||||
return tool.Run(ctx, c, args)
|
||||
}
|
||||
}
|
||||
return tool.CommandLineErrorf("unknown command %v", command)
|
||||
}
|
||||
|
||||
// generateWorkspaceMod (re)generates the gopls.mod file for the current
|
||||
// workspace.
|
||||
type generateWorkspaceMod struct {
|
||||
app *Application
|
||||
}
|
||||
|
||||
func (c *generateWorkspaceMod) Name() string { return "generate" }
|
||||
func (c *generateWorkspaceMod) Usage() string { return "" }
|
||||
func (c *generateWorkspaceMod) ShortHelp() string {
|
||||
return "generate a gopls.mod file for a workspace"
|
||||
}
|
||||
|
||||
func (c *generateWorkspaceMod) DetailedHelp(f *flag.FlagSet) {
|
||||
f.PrintDefaults()
|
||||
}
|
||||
|
||||
func (c *generateWorkspaceMod) Run(ctx context.Context, args ...string) error {
|
||||
origOptions := c.app.options
|
||||
c.app.options = func(opts *source.Options) {
|
||||
origOptions(opts)
|
||||
opts.ExperimentalWorkspaceModule = true
|
||||
}
|
||||
conn, err := c.app.connect(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.terminate(ctx)
|
||||
params := &protocol.ExecuteCommandParams{Command: source.CommandGenerateGoplsMod.Name}
|
||||
if _, err := conn.ExecuteCommand(ctx, params); err != nil {
|
||||
return fmt.Errorf("executing server command: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -10,8 +10,10 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/tools/internal/event"
|
||||
"golang.org/x/tools/internal/lsp/protocol"
|
||||
|
|
@ -79,6 +81,9 @@ func (s *Server) executeCommand(ctx context.Context, params *protocol.ExecuteCom
|
|||
// matters for regtests, where having a continuous thread of work is
|
||||
// convenient for assertions.
|
||||
work := s.progress.start(ctx, title, "Running...", params.WorkDoneToken, cancel)
|
||||
if command.Synchronous {
|
||||
return nil, s.runCommand(ctx, work, command, params.Arguments)
|
||||
}
|
||||
go func() {
|
||||
defer cancel()
|
||||
err := s.runCommand(ctx, work, command, params.Arguments)
|
||||
|
|
@ -217,6 +222,39 @@ func (s *Server) runCommand(ctx context.Context, work *workDone, command *source
|
|||
snapshot, release := sv.Snapshot(ctx)
|
||||
defer release()
|
||||
s.diagnoseSnapshot(snapshot)
|
||||
case source.CommandGenerateGoplsMod:
|
||||
var v source.View
|
||||
if len(args) == 0 {
|
||||
views := s.session.Views()
|
||||
if len(views) != 1 {
|
||||
return fmt.Errorf("cannot resolve view: have %d views", len(views))
|
||||
}
|
||||
v = views[0]
|
||||
} else {
|
||||
var uri protocol.DocumentURI
|
||||
if err := source.UnmarshalArgs(args, &uri); err != nil {
|
||||
return err
|
||||
}
|
||||
var err error
|
||||
v, err = s.session.ViewOf(uri.SpanURI())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
snapshot, release := v.Snapshot(ctx)
|
||||
defer release()
|
||||
modFile, err := snapshot.BuildWorkspaceModFile(ctx)
|
||||
if err != nil {
|
||||
return errors.Errorf("getting workspace mod file: %w", err)
|
||||
}
|
||||
content, err := modFile.Format()
|
||||
if err != nil {
|
||||
return errors.Errorf("formatting mod file: %w", err)
|
||||
}
|
||||
filename := filepath.Join(v.Folder().Filename(), "gopls.mod")
|
||||
if err := ioutil.WriteFile(filename, content, 0644); err != nil {
|
||||
return errors.Errorf("writing mod file: %w", err)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unsupported command: %s", command.Name)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@ import (
|
|||
type Command struct {
|
||||
Name, Title string
|
||||
|
||||
// Synchronous controls whether the command executes synchronously within the
|
||||
// ExecuteCommand request (applying suggested fixes is always synchronous).
|
||||
Synchronous bool
|
||||
|
||||
// appliesFn is an optional field to indicate whether or not a command can
|
||||
// be applied to the given inputs. If it returns false, we should not
|
||||
// suggest this command for these inputs.
|
||||
|
|
@ -55,6 +59,7 @@ var Commands = []*Command{
|
|||
CommandExtractVariable,
|
||||
CommandExtractFunction,
|
||||
CommandToggleDetails,
|
||||
CommandGenerateGoplsMod,
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
@ -135,6 +140,13 @@ var (
|
|||
return ok
|
||||
},
|
||||
}
|
||||
|
||||
// CommandGenerateGoplsMod (re)generates the gopls.mod file.
|
||||
CommandGenerateGoplsMod = &Command{
|
||||
Name: "generate_gopls_mod",
|
||||
Title: "Generate gopls.mod",
|
||||
Synchronous: true,
|
||||
}
|
||||
)
|
||||
|
||||
// Applies reports whether the command c implements a suggested fix that is
|
||||
|
|
|
|||
|
|
@ -94,6 +94,10 @@ type Snapshot interface {
|
|||
// the given go.mod file.
|
||||
ModTidy(ctx context.Context, fh FileHandle) (*TidiedModule, error)
|
||||
|
||||
// BuildWorkspaceModFile builds the contents of mod file to be used for
|
||||
// multi-module workspace.
|
||||
BuildWorkspaceModFile(ctx context.Context) (*modfile.File, error)
|
||||
|
||||
// BuiltinPackage returns information about the special builtin package.
|
||||
BuiltinPackage(ctx context.Context) (*BuiltinPackage, error)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue