internal/lsp: add go get quick fix on failing imports

With -mod=readonly set, we no longer automatically add new requires to
go.mod, even the temporary one. We have the go mod tidy code lens, but
that only works on saved files, even in 1.16 due to golang/go#42491.
Plus we may remove the code lens's network access in the future.

Add a simple quick fix for import errors that runs (the moral equivalent
of) go get on the missing import.

Change-Id: Id5764a37ce7db0dce5370da9d648462aefa2042b
Reviewed-on: https://go-review.googlesource.com/c/tools/+/274121
Trust: Heschi Kreinick <heschi@google.com>
Run-TryBot: Heschi Kreinick <heschi@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
diff --git a/internal/lsp/command.go b/internal/lsp/command.go
index 6044d13..fddb718 100644
--- a/internal/lsp/command.go
+++ b/internal/lsp/command.go
@@ -12,6 +12,7 @@
 	"io"
 	"io/ioutil"
 	"path/filepath"
+	"strings"
 
 	"golang.org/x/tools/internal/event"
 	"golang.org/x/tools/internal/gocommand"
@@ -228,6 +229,19 @@
 			return err
 		}
 		return s.runGoGetModule(ctx, snapshot, uri.SpanURI(), addRequire, goCmdArgs)
+	case source.CommandGoGetPackage:
+		var uri protocol.DocumentURI
+		var pkg string
+		if err := source.UnmarshalArgs(args, &uri, &pkg); err != nil {
+			return err
+		}
+		snapshot, _, ok, release, err := s.beginFileRequest(ctx, uri, source.UnknownKind)
+		defer release()
+		if !ok {
+			return err
+		}
+		return s.runGoGetPackage(ctx, snapshot, uri.SpanURI(), pkg)
+
 	case source.CommandToggleDetails:
 		var fileURI protocol.DocumentURI
 		if err := source.UnmarshalArgs(args, &fileURI); err != nil {
@@ -387,6 +401,19 @@
 	return nil
 }
 
+func (s *Server) runGoGetPackage(ctx context.Context, snapshot source.Snapshot, uri span.URI, pkg string) error {
+	stdout, err := snapshot.RunGoCommandDirect(ctx, source.WriteTemporaryModFile|source.AllowNetwork, &gocommand.Invocation{
+		Verb:       "list",
+		Args:       []string{"-f", "{{.Module.Path}}@{{.Module.Version}}", pkg},
+		WorkingDir: filepath.Dir(uri.Filename()),
+	})
+	if err != nil {
+		return err
+	}
+	ver := strings.TrimSpace(stdout.String())
+	return s.runGoGetModule(ctx, snapshot, uri, true, []string{ver})
+}
+
 func (s *Server) runGoGetModule(ctx context.Context, snapshot source.Snapshot, uri span.URI, addRequire bool, args []string) error {
 	if addRequire {
 		// Using go get to create a new dependency results in an