// Copyright 2019 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" "golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/lsp/source" "golang.org/x/tools/internal/lsp/telemetry" "golang.org/x/tools/internal/span" "golang.org/x/tools/internal/telemetry/log" ) func (s *Server) didChangeWatchedFiles(ctx context.Context, params *protocol.DidChangeWatchedFilesParams) error { for _, change := range params.Changes { uri := span.NewURI(change.URI) ctx := telemetry.File.With(ctx, uri) for _, view := range s.session.Views() { if !view.Options().WatchFileChanges { continue } action := toFileAction(change.Type) switch action { case source.Change, source.Create: // If client has this file open, don't do anything. // The client's contents must remain the source of truth. if s.session.IsOpen(uri) { break } if s.session.DidChangeOutOfBand(ctx, uri, action) { // If we had been tracking the given file, // recompute diagnostics to reflect updated file contents. go s.diagnostics(view, uri) } case source.Delete: f := view.FindFile(ctx, uri) // If we have never seen this file before, there is nothing to do. if f == nil { continue } _, cphs, err := view.CheckPackageHandles(ctx, f) if err != nil { log.Error(ctx, "didChangeWatchedFiles: CheckPackageHandles", err, telemetry.File) continue } cph, err := source.WidestCheckPackageHandle(cphs) if err != nil { log.Error(ctx, "didChangeWatchedFiles: WidestCheckPackageHandle", err, telemetry.File) continue } // Find a different file in the same package we can use to trigger diagnostics. // TODO(rstambler): Allow diagnostics to be called per-package to avoid this. var otherFile source.File for _, ph := range cph.CompiledGoFiles() { if ph.File().Identity().URI == f.URI() { continue } if f := view.FindFile(ctx, ph.File().Identity().URI); f != nil && s.session.IsOpen(f.URI()) { otherFile = f break } } // Notify the view of the deletion of the file. s.session.DidChangeOutOfBand(ctx, uri, action) // If this was the only file in the package, clear its diagnostics. if otherFile == nil { if err := s.publishDiagnostics(ctx, uri, []source.Diagnostic{}); err != nil { log.Error(ctx, "failed to clear diagnostics", err, telemetry.URI.Of(uri)) } return nil } // Refresh diagnostics for the package the file belonged to. go s.diagnostics(view, otherFile.URI()) } } } return nil } func toFileAction(ct protocol.FileChangeType) source.FileAction { switch ct { case protocol.Changed: return source.Change case protocol.Created: return source.Create case protocol.Deleted: return source.Delete } return source.UnknownFileAction }