Skip to content

Commit 116feae

Browse files
committed
internal/lsp: move the progress tracker to the session
Sometimes, we may want to report progress from functions inside of the cache package, so move the progress tracker to the session to allow for that. Change-Id: I15409577a7a5080e7f0224a95d159de42856ffa7 Reviewed-on: https://go-review.googlesource.com/c/tools/+/319330 Trust: Rebecca Stambler <rstambler@golang.org> Run-TryBot: Rebecca Stambler <rstambler@golang.org> gopls-CI: kokoro <noreply+kokoro@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
1 parent 3f7c326 commit 116feae

File tree

12 files changed

+107
-63
lines changed

12 files changed

+107
-63
lines changed

internal/lsp/cache/load.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,15 @@ type metadata struct {
5555
// load calls packages.Load for the given scopes, updating package metadata,
5656
// import graph, and mapped files with the result.
5757
func (s *snapshot) load(ctx context.Context, allowNetwork bool, scopes ...interface{}) error {
58+
if s.view.Options().VerboseWorkDoneProgress {
59+
work := s.view.session.progress.Start(ctx, "Load", fmt.Sprintf("Loading scopes %s", scopes), nil, nil)
60+
defer func() {
61+
go func() {
62+
work.End("Done.")
63+
}()
64+
}()
65+
}
66+
5867
var query []string
5968
var containsDir bool // for logging
6069
for _, scope := range scopes {

internal/lsp/cache/session.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"golang.org/x/tools/internal/event"
1515
"golang.org/x/tools/internal/gocommand"
1616
"golang.org/x/tools/internal/imports"
17+
"golang.org/x/tools/internal/lsp/progress"
1718
"golang.org/x/tools/internal/lsp/source"
1819
"golang.org/x/tools/internal/span"
1920
"golang.org/x/tools/internal/xcontext"
@@ -36,6 +37,8 @@ type Session struct {
3637

3738
// gocmdRunner guards go command calls from concurrency errors.
3839
gocmdRunner *gocommand.Runner
40+
41+
progress *progress.Tracker
3942
}
4043

4144
type overlay struct {
@@ -131,6 +134,11 @@ func (s *Session) SetOptions(options *source.Options) {
131134
s.options = options
132135
}
133136

137+
func (s *Session) SetProgressTracker(tracker *progress.Tracker) {
138+
// The progress tracker should be set before any view is initialized.
139+
s.progress = tracker
140+
}
141+
134142
func (s *Session) Shutdown(ctx context.Context) {
135143
s.viewMu.Lock()
136144
defer s.viewMu.Unlock()

internal/lsp/cmd/info.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,6 @@ func (l *licenses) Run(ctx context.Context, args ...string) error {
178178
} else {
179179
txt += opts.LicensesText
180180
}
181-
fmt.Fprintf(os.Stdout, txt)
181+
fmt.Fprint(os.Stdout, txt)
182182
return nil
183183
}

internal/lsp/command.go

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"golang.org/x/tools/internal/gocommand"
2121
"golang.org/x/tools/internal/lsp/command"
2222
"golang.org/x/tools/internal/lsp/debug"
23+
"golang.org/x/tools/internal/lsp/progress"
2324
"golang.org/x/tools/internal/lsp/protocol"
2425
"golang.org/x/tools/internal/lsp/source"
2526
"golang.org/x/tools/internal/span"
@@ -65,7 +66,7 @@ type commandConfig struct {
6566
type commandDeps struct {
6667
snapshot source.Snapshot // present if cfg.forURI was set
6768
fh source.VersionedFileHandle // present if cfg.forURI was set
68-
work *workDone // present cfg.progress was set
69+
work *progress.WorkDone // present cfg.progress was set
6970
}
7071

7172
type commandFunc func(context.Context, commandDeps) error
@@ -90,19 +91,21 @@ func (c *commandHandler) run(ctx context.Context, cfg commandConfig, run command
9091
}
9192
ctx, cancel := context.WithCancel(xcontext.Detach(ctx))
9293
if cfg.progress != "" {
93-
deps.work = c.s.progress.start(ctx, cfg.progress, "Running...", c.params.WorkDoneToken, cancel)
94+
deps.work = c.s.progress.Start(ctx, cfg.progress, "Running...", c.params.WorkDoneToken, cancel)
9495
}
9596
runcmd := func() error {
9697
defer cancel()
9798
err := run(ctx, deps)
98-
switch {
99-
case errors.Is(err, context.Canceled):
100-
deps.work.end("canceled")
101-
case err != nil:
102-
event.Error(ctx, "command error", err)
103-
deps.work.end("failed")
104-
default:
105-
deps.work.end("completed")
99+
if deps.work != nil {
100+
switch {
101+
case errors.Is(err, context.Canceled):
102+
deps.work.End("canceled")
103+
case err != nil:
104+
event.Error(ctx, "command error", err)
105+
deps.work.End("failed")
106+
default:
107+
deps.work.End("completed")
108+
}
106109
}
107110
return err
108111
}
@@ -349,7 +352,7 @@ func (c *commandHandler) RunTests(ctx context.Context, args command.RunTestsArgs
349352
})
350353
}
351354

352-
func (c *commandHandler) runTests(ctx context.Context, snapshot source.Snapshot, work *workDone, uri protocol.DocumentURI, tests, benchmarks []string) error {
355+
func (c *commandHandler) runTests(ctx context.Context, snapshot source.Snapshot, work *progress.WorkDone, uri protocol.DocumentURI, tests, benchmarks []string) error {
353356
// TODO: fix the error reporting when this runs async.
354357
pkgs, err := snapshot.PackagesForFile(ctx, uri.SpanURI(), source.TypecheckWorkspace)
355358
if err != nil {
@@ -362,8 +365,8 @@ func (c *commandHandler) runTests(ctx context.Context, snapshot source.Snapshot,
362365

363366
// create output
364367
buf := &bytes.Buffer{}
365-
ew := &eventWriter{ctx: ctx, operation: "test"}
366-
out := io.MultiWriter(ew, workDoneWriter{work}, buf)
368+
ew := progress.NewEventWriter(ctx, "test")
369+
out := io.MultiWriter(ew, progress.NewWorkDoneWriter(work), buf)
367370

368371
// Run `go test -run Func` on each test.
369372
var failedTests int
@@ -435,7 +438,7 @@ func (c *commandHandler) Generate(ctx context.Context, args command.GenerateArgs
435438
progress: title,
436439
forURI: args.Dir,
437440
}, func(ctx context.Context, deps commandDeps) error {
438-
er := &eventWriter{ctx: ctx, operation: "generate"}
441+
er := progress.NewEventWriter(ctx, "generate")
439442

440443
pattern := "."
441444
if args.Recursive {
@@ -446,7 +449,7 @@ func (c *commandHandler) Generate(ctx context.Context, args command.GenerateArgs
446449
Args: []string{"-x", pattern},
447450
WorkingDir: args.Dir.SpanURI().Filename(),
448451
}
449-
stderr := io.MultiWriter(er, workDoneWriter{deps.work})
452+
stderr := io.MultiWriter(er, progress.NewWorkDoneWriter(deps.work))
450453
if err := deps.snapshot.RunGoCommandPiped(ctx, source.Normal, inv, er, stderr); err != nil {
451454
return err
452455
}

internal/lsp/diagnostics.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -384,18 +384,18 @@ func (s *Server) showCriticalErrorStatus(ctx context.Context, snapshot source.Sn
384384

385385
if s.criticalErrorStatus == nil {
386386
if errMsg != "" {
387-
s.criticalErrorStatus = s.progress.start(ctx, WorkspaceLoadFailure, errMsg, nil, nil)
387+
s.criticalErrorStatus = s.progress.Start(ctx, WorkspaceLoadFailure, errMsg, nil, nil)
388388
}
389389
return
390390
}
391391

392392
// If an error is already shown to the user, update it or mark it as
393393
// resolved.
394394
if errMsg == "" {
395-
s.criticalErrorStatus.end("Done.")
395+
s.criticalErrorStatus.End("Done.")
396396
s.criticalErrorStatus = nil
397397
} else {
398-
s.criticalErrorStatus.report(errMsg, 0)
398+
s.criticalErrorStatus.Report(errMsg, 0)
399399
}
400400
}
401401

internal/lsp/general.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func (s *Server) initialize(ctx context.Context, params *protocol.ParamInitializ
4646
event.Error(ctx, "creating temp dir", err)
4747
s.tempDir = ""
4848
}
49-
s.progress.supportsWorkDoneProgress = params.Capabilities.Window.WorkDoneProgress
49+
s.progress.SetSupportsWorkDoneProgress(params.Capabilities.Window.WorkDoneProgress)
5050

5151
options := s.session.Options()
5252
defer func() { s.session.SetOptions(options) }()
@@ -217,11 +217,11 @@ func (s *Server) addFolders(ctx context.Context, folders []protocol.WorkspaceFol
217217

218218
var wg sync.WaitGroup
219219
if s.session.Options().VerboseWorkDoneProgress {
220-
work := s.progress.start(ctx, DiagnosticWorkTitle(FromInitialWorkspaceLoad), "Calculating diagnostics for initial workspace load...", nil, nil)
220+
work := s.progress.Start(ctx, DiagnosticWorkTitle(FromInitialWorkspaceLoad), "Calculating diagnostics for initial workspace load...", nil, nil)
221221
defer func() {
222222
go func() {
223223
wg.Wait()
224-
work.end("Done.")
224+
work.End("Done.")
225225
}()
226226
}()
227227
}
@@ -233,11 +233,11 @@ func (s *Server) addFolders(ctx context.Context, folders []protocol.WorkspaceFol
233233
if !uri.IsFile() {
234234
continue
235235
}
236-
work := s.progress.start(ctx, "Setting up workspace", "Loading packages...", nil, nil)
236+
work := s.progress.Start(ctx, "Setting up workspace", "Loading packages...", nil, nil)
237237
snapshot, release, err := s.addView(ctx, folder.Name, uri)
238238
if err != nil {
239239
viewErrors[uri] = err
240-
work.end(fmt.Sprintf("Error loading packages: %s", err))
240+
work.End(fmt.Sprintf("Error loading packages: %s", err))
241241
continue
242242
}
243243
var swg sync.WaitGroup
@@ -247,7 +247,7 @@ func (s *Server) addFolders(ctx context.Context, folders []protocol.WorkspaceFol
247247
defer swg.Done()
248248
defer allFoldersWg.Done()
249249
snapshot.AwaitInitialized(ctx)
250-
work.end("Finished loading packages.")
250+
work.End("Finished loading packages.")
251251
}()
252252

253253
// Print each view's environment.

internal/lsp/lsp_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ func testLSP(t *testing.T, datum *tests.Data) {
9292
normalizers: tests.CollectNormalizers(datum.Exported),
9393
editRecv: make(chan map[span.URI]string, 1),
9494
}
95+
9596
r.server = NewServer(session, testClient{runner: r})
9697
tests.Run(t, r, datum)
9798
}

internal/lsp/progress.go renamed to internal/lsp/progress/progress.go

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
package lsp
5+
package progress
66

77
import (
88
"context"
@@ -18,22 +18,26 @@ import (
1818
errors "golang.org/x/xerrors"
1919
)
2020

21-
type progressTracker struct {
21+
type Tracker struct {
2222
client protocol.Client
2323
supportsWorkDoneProgress bool
2424

2525
mu sync.Mutex
26-
inProgress map[protocol.ProgressToken]*workDone
26+
inProgress map[protocol.ProgressToken]*WorkDone
2727
}
2828

29-
func newProgressTracker(client protocol.Client) *progressTracker {
30-
return &progressTracker{
29+
func NewTracker(client protocol.Client) *Tracker {
30+
return &Tracker{
3131
client: client,
32-
inProgress: make(map[protocol.ProgressToken]*workDone),
32+
inProgress: make(map[protocol.ProgressToken]*WorkDone),
3333
}
3434
}
3535

36-
// start notifies the client of work being done on the server. It uses either
36+
func (tracker *Tracker) SetSupportsWorkDoneProgress(b bool) {
37+
tracker.supportsWorkDoneProgress = b
38+
}
39+
40+
// Start notifies the client of work being done on the server. It uses either
3741
// ShowMessage RPCs or $/progress messages, depending on the capabilities of
3842
// the client. The returned WorkDone handle may be used to report incremental
3943
// progress, and to report work completion. In particular, it is an error to
@@ -59,8 +63,8 @@ func newProgressTracker(client protocol.Client) *progressTracker {
5963
// // Do the work...
6064
// }
6165
//
62-
func (t *progressTracker) start(ctx context.Context, title, message string, token protocol.ProgressToken, cancel func()) *workDone {
63-
wd := &workDone{
66+
func (t *Tracker) Start(ctx context.Context, title, message string, token protocol.ProgressToken, cancel func()) *WorkDone {
67+
wd := &WorkDone{
6468
ctx: xcontext.Detach(ctx),
6569
client: t.client,
6670
token: token,
@@ -119,7 +123,7 @@ func (t *progressTracker) start(ctx context.Context, title, message string, toke
119123
return wd
120124
}
121125

122-
func (t *progressTracker) cancel(ctx context.Context, token protocol.ProgressToken) error {
126+
func (t *Tracker) Cancel(ctx context.Context, token protocol.ProgressToken) error {
123127
t.mu.Lock()
124128
defer t.mu.Unlock()
125129
wd, ok := t.inProgress[token]
@@ -133,9 +137,9 @@ func (t *progressTracker) cancel(ctx context.Context, token protocol.ProgressTok
133137
return nil
134138
}
135139

136-
// workDone represents a unit of work that is reported to the client via the
140+
// WorkDone represents a unit of work that is reported to the client via the
137141
// progress API.
138-
type workDone struct {
142+
type WorkDone struct {
139143
// ctx is detached, for sending $/progress updates.
140144
ctx context.Context
141145
client protocol.Client
@@ -153,7 +157,11 @@ type workDone struct {
153157
cleanup func()
154158
}
155159

156-
func (wd *workDone) doCancel() {
160+
func (wd *WorkDone) Token() protocol.ProgressToken {
161+
return wd.token
162+
}
163+
164+
func (wd *WorkDone) doCancel() {
157165
wd.cancelMu.Lock()
158166
defer wd.cancelMu.Unlock()
159167
if !wd.cancelled {
@@ -162,7 +170,7 @@ func (wd *workDone) doCancel() {
162170
}
163171

164172
// report reports an update on WorkDone report back to the client.
165-
func (wd *workDone) report(message string, percentage float64) {
173+
func (wd *WorkDone) Report(message string, percentage float64) {
166174
if wd == nil {
167175
return
168176
}
@@ -196,7 +204,7 @@ func (wd *workDone) report(message string, percentage float64) {
196204
}
197205

198206
// end reports a workdone completion back to the client.
199-
func (wd *workDone) end(message string) {
207+
func (wd *WorkDone) End(message string) {
200208
if wd == nil {
201209
return
202210
}
@@ -227,27 +235,35 @@ func (wd *workDone) end(message string) {
227235
}
228236
}
229237

230-
// eventWriter writes every incoming []byte to
238+
// EventWriter writes every incoming []byte to
231239
// event.Print with the operation=generate tag
232240
// to distinguish its logs from others.
233-
type eventWriter struct {
241+
type EventWriter struct {
234242
ctx context.Context
235243
operation string
236244
}
237245

238-
func (ew *eventWriter) Write(p []byte) (n int, err error) {
246+
func NewEventWriter(ctx context.Context, operation string) *EventWriter {
247+
return &EventWriter{ctx: ctx, operation: operation}
248+
}
249+
250+
func (ew *EventWriter) Write(p []byte) (n int, err error) {
239251
event.Log(ew.ctx, string(p), tag.Operation.Of(ew.operation))
240252
return len(p), nil
241253
}
242254

243-
// workDoneWriter wraps a workDone handle to provide a Writer interface,
255+
// WorkDoneWriter wraps a workDone handle to provide a Writer interface,
244256
// so that workDone reporting can more easily be hooked into commands.
245-
type workDoneWriter struct {
246-
wd *workDone
257+
type WorkDoneWriter struct {
258+
wd *WorkDone
259+
}
260+
261+
func NewWorkDoneWriter(wd *WorkDone) *WorkDoneWriter {
262+
return &WorkDoneWriter{wd: wd}
247263
}
248264

249-
func (wdw workDoneWriter) Write(p []byte) (n int, err error) {
250-
wdw.wd.report(string(p), 0)
265+
func (wdw WorkDoneWriter) Write(p []byte) (n int, err error) {
266+
wdw.wd.Report(string(p), 0)
251267
// Don't fail just because of a failure to report progress.
252268
return len(p), nil
253269
}

0 commit comments

Comments
 (0)