internal/lsp: refactor generate code lens code

This change moves the "generic" go generate code lens code into
progress.go. Fix up a few generate-specific things in the progress
writers.

The remaining generate code isn't much, and is moved into command.go.

Change-Id: I2b7b6279da2442c0b92758b9b3e259f25787fabc
Reviewed-on: https://go-review.googlesource.com/c/tools/+/242919
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
diff --git a/internal/lsp/command.go b/internal/lsp/command.go
index f10b69a..18eee18 100644
--- a/internal/lsp/command.go
+++ b/internal/lsp/command.go
@@ -10,6 +10,8 @@
 	"io"
 	"strings"
 
+	"golang.org/x/tools/internal/event"
+	"golang.org/x/tools/internal/lsp/debug/tag"
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/source"
 	"golang.org/x/tools/internal/span"
@@ -57,7 +59,7 @@
 		if err != nil {
 			return nil, err
 		}
-		go s.runGenerate(xcontext.Detach(ctx), dir, recursive)
+		go s.runGoGenerate(xcontext.Detach(ctx), dir, recursive)
 	case source.CommandRegenerateCgo:
 		mod := source.FileModification{
 			URI:    protocol.DocumentURI(params.Arguments[0].(string)).SpanURI(),
@@ -104,7 +106,8 @@
 	defer cancel()
 
 	ew := &eventWriter{ctx: ctx, operation: "test"}
-	wc := s.newProgressWriter(ctx, "test", "running "+funcName, cancel)
+	msg := fmt.Sprintf("testing %s", funcName)
+	wc := s.newProgressWriter(ctx, "test", msg, msg, cancel)
 	defer wc.Close()
 
 	messageType := protocol.Info
@@ -124,6 +127,42 @@
 	})
 }
 
+// GenerateWorkDoneTitle is the title used in progress reporting for go
+// generate commands. It is exported for testing purposes.
+const GenerateWorkDoneTitle = "generate"
+
+func (s *Server) runGoGenerate(ctx context.Context, dir string, recursive bool) error {
+	ctx, cancel := context.WithCancel(ctx)
+	defer cancel()
+
+	er := &eventWriter{ctx: ctx, operation: "generate"}
+	wc := s.newProgressWriter(ctx, GenerateWorkDoneTitle, "running go generate", "started go generate, check logs for progress", cancel)
+	defer wc.Close()
+	args := []string{"-x"}
+	if recursive {
+		args = append(args, "./...")
+	}
+
+	stderr := io.MultiWriter(er, wc)
+	uri := span.URIFromPath(dir)
+	view, err := s.session.ViewOf(uri)
+	if err != nil {
+		return err
+	}
+	snapshot := view.Snapshot()
+	if err := snapshot.RunGoCommandPiped(ctx, "generate", args, er, stderr); err != nil {
+		if errors.Is(err, context.Canceled) {
+			return nil
+		}
+		event.Error(ctx, "generate: command error", err, tag.Directory.Of(uri.Filename()))
+		return s.client.ShowMessage(ctx, &protocol.ShowMessageParams{
+			Type:    protocol.Error,
+			Message: "go generate exited with an error, check gopls logs",
+		})
+	}
+	return nil
+}
+
 func getRunTestArguments(args []interface{}) (string, span.URI, error) {
 	if len(args) != 2 {
 		return "", "", errors.Errorf("expected one test func name and one file path, got %v", args)
diff --git a/internal/lsp/generate.go b/internal/lsp/generate.go
deleted file mode 100644
index d850dec..0000000
--- a/internal/lsp/generate.go
+++ /dev/null
@@ -1,138 +0,0 @@
-// 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 lsp
-
-import (
-	"context"
-	"io"
-
-	"golang.org/x/tools/internal/event"
-	"golang.org/x/tools/internal/lsp/debug/tag"
-	"golang.org/x/tools/internal/lsp/protocol"
-	"golang.org/x/tools/internal/span"
-	errors "golang.org/x/xerrors"
-)
-
-// GenerateWorkDoneTitle is the title used in progress reporting for go
-// generate commands. It is exported for testing purposes.
-const GenerateWorkDoneTitle = "generate"
-
-func (s *Server) runGenerate(ctx context.Context, dir string, recursive bool) error {
-	ctx, cancel := context.WithCancel(ctx)
-	defer cancel()
-
-	er := &eventWriter{ctx: ctx, operation: "generate"}
-	wc := s.newProgressWriter(ctx, GenerateWorkDoneTitle, "running go generate", cancel)
-	defer wc.Close()
-	args := []string{"-x"}
-	if recursive {
-		args = append(args, "./...")
-	}
-
-	stderr := io.MultiWriter(er, wc)
-	uri := span.URIFromPath(dir)
-	view, err := s.session.ViewOf(uri)
-	if err != nil {
-		return err
-	}
-	snapshot := view.Snapshot()
-	if err := snapshot.RunGoCommandPiped(ctx, "generate", args, er, stderr); err != nil {
-		if errors.Is(err, context.Canceled) {
-			return nil
-		}
-		event.Error(ctx, "generate: command error", err, tag.Directory.Of(dir))
-		return s.client.ShowMessage(ctx, &protocol.ShowMessageParams{
-			Type:    protocol.Error,
-			Message: "go generate exited with an error, check gopls logs",
-		})
-	}
-	return nil
-}
-
-// eventWriter writes every incoming []byte to
-// event.Print with the operation=generate tag
-// to distinguish its logs from others.
-type eventWriter struct {
-	ctx       context.Context
-	operation string
-}
-
-func (ew *eventWriter) Write(p []byte) (n int, err error) {
-	event.Log(ew.ctx, string(p), tag.Operation.Of(ew.operation))
-	return len(p), nil
-}
-
-// newProgressWriter returns an io.WriterCloser that can be used
-// to report progress on a command based on the client capabilities.
-func (s *Server) newProgressWriter(ctx context.Context, title, message string, cancel func()) io.WriteCloser {
-	if s.supportsWorkDoneProgress {
-		wd := s.StartWork(ctx, title, message, cancel)
-		return &workDoneWriter{ctx, wd}
-	}
-	mw := &messageWriter{ctx, cancel, s.client}
-	mw.start()
-	return mw
-}
-
-// messageWriter implements progressWriter
-// and only tells the user that "go generate"
-// has started through window/showMessage but does not
-// report anything afterwards. This is because each
-// log shows up as a separate window and therefore
-// would be obnoxious to show every incoming line.
-// Request cancellation happens synchronously through
-// the ShowMessageRequest response.
-type messageWriter struct {
-	ctx    context.Context
-	cancel func()
-	client protocol.Client
-}
-
-func (lw *messageWriter) Write(p []byte) (n int, err error) {
-	return len(p), nil
-}
-
-func (lw *messageWriter) start() {
-	go func() {
-		msg, err := lw.client.ShowMessageRequest(lw.ctx, &protocol.ShowMessageRequestParams{
-			Type:    protocol.Log,
-			Message: "go generate has started, check logs for progress",
-			Actions: []protocol.MessageActionItem{{
-				Title: "Cancel",
-			}},
-		})
-		if err != nil {
-			event.Error(lw.ctx, "error sending initial generate msg", err)
-			return
-		}
-		if msg != nil && msg.Title == "Cancel" {
-			lw.cancel()
-		}
-	}()
-}
-
-func (lw *messageWriter) Close() error {
-	return lw.client.ShowMessage(lw.ctx, &protocol.ShowMessageParams{
-		Type:    protocol.Info,
-		Message: "go generate has finished",
-	})
-}
-
-// workDoneWriter implements progressWriter by sending $/progress notifications
-// to the client. Request cancellations happens separately through the
-// window/workDoneProgress/cancel request, in which case the given context will
-// be rendered done.
-type workDoneWriter struct {
-	ctx context.Context
-	wd  *WorkDone
-}
-
-func (wdw *workDoneWriter) Write(p []byte) (n int, err error) {
-	return len(p), wdw.wd.Progress(wdw.ctx, string(p), 0)
-}
-
-func (wdw *workDoneWriter) Close() error {
-	return wdw.wd.End(wdw.ctx, "finished")
-}
diff --git a/internal/lsp/progress.go b/internal/lsp/progress.go
index c5e70cf..c5431f9 100644
--- a/internal/lsp/progress.go
+++ b/internal/lsp/progress.go
@@ -7,10 +7,12 @@
 import (
 	"context"
 	"errors"
+	"io"
 	"math/rand"
 	"strconv"
 
 	"golang.org/x/tools/internal/event"
+	"golang.org/x/tools/internal/lsp/debug/tag"
 	"golang.org/x/tools/internal/lsp/protocol"
 )
 
@@ -121,3 +123,90 @@
 	}
 	return err
 }
+
+// eventWriter writes every incoming []byte to
+// event.Print with the operation=generate tag
+// to distinguish its logs from others.
+type eventWriter struct {
+	ctx       context.Context
+	operation string
+}
+
+func (ew *eventWriter) Write(p []byte) (n int, err error) {
+	event.Log(ew.ctx, string(p), tag.Operation.Of(ew.operation))
+	return len(p), nil
+}
+
+// newProgressWriter returns an io.WriterCloser that can be used
+// to report progress on a command based on the client capabilities.
+func (s *Server) newProgressWriter(ctx context.Context, title, beginMsg, msg string, cancel func()) io.WriteCloser {
+	if s.supportsWorkDoneProgress {
+		wd := s.StartWork(ctx, title, beginMsg, cancel)
+		return &workDoneWriter{ctx, wd}
+	}
+	mw := &messageWriter{ctx, cancel, s.client}
+	mw.start(msg)
+	return mw
+}
+
+// messageWriter implements progressWriter
+// and only tells the user that "go generate"
+// has started through window/showMessage but does not
+// report anything afterwards. This is because each
+// log shows up as a separate window and therefore
+// would be obnoxious to show every incoming line.
+// Request cancellation happens synchronously through
+// the ShowMessageRequest response.
+type messageWriter struct {
+	ctx    context.Context
+	cancel func()
+	client protocol.Client
+}
+
+func (lw *messageWriter) Write(p []byte) (n int, err error) {
+	return len(p), nil
+}
+
+func (lw *messageWriter) start(msg string) {
+	go func() {
+		const cancel = "Cancel"
+		item, err := lw.client.ShowMessageRequest(lw.ctx, &protocol.ShowMessageRequestParams{
+			Type:    protocol.Log,
+			Message: msg,
+			Actions: []protocol.MessageActionItem{{
+				Title: "Cancel",
+			}},
+		})
+		if err != nil {
+			event.Error(lw.ctx, "error sending message request", err)
+			return
+		}
+		if item != nil && item.Title == "Cancel" {
+			lw.cancel()
+		}
+	}()
+}
+
+func (lw *messageWriter) Close() error {
+	return lw.client.ShowMessage(lw.ctx, &protocol.ShowMessageParams{
+		Type:    protocol.Info,
+		Message: "go generate has finished",
+	})
+}
+
+// workDoneWriter implements progressWriter by sending $/progress notifications
+// to the client. Request cancellations happens separately through the
+// window/workDoneProgress/cancel request, in which case the given context will
+// be rendered done.
+type workDoneWriter struct {
+	ctx context.Context
+	wd  *WorkDone
+}
+
+func (wdw *workDoneWriter) Write(p []byte) (n int, err error) {
+	return len(p), wdw.wd.Progress(wdw.ctx, string(p), 0)
+}
+
+func (wdw *workDoneWriter) Close() error {
+	return wdw.wd.End(wdw.ctx, "finished")
+}