Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / internal / lsp / cache / imports.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/internal/lsp/cache/imports.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/internal/lsp/cache/imports.go
new file mode 100644 (file)
index 0000000..5039eac
--- /dev/null
@@ -0,0 +1,199 @@
+package cache
+
+import (
+       "context"
+       "fmt"
+       "reflect"
+       "sync"
+       "time"
+
+       "golang.org/x/tools/internal/event"
+       "golang.org/x/tools/internal/event/keys"
+       "golang.org/x/tools/internal/imports"
+       "golang.org/x/tools/internal/lsp/source"
+       "golang.org/x/tools/internal/span"
+)
+
+type importsState struct {
+       ctx context.Context
+
+       mu                      sync.Mutex
+       processEnv              *imports.ProcessEnv
+       cleanupProcessEnv       func()
+       cacheRefreshDuration    time.Duration
+       cacheRefreshTimer       *time.Timer
+       cachedModFileIdentifier string
+       cachedBuildFlags        []string
+}
+
+func (s *importsState) runProcessEnvFunc(ctx context.Context, snapshot *snapshot, fn func(*imports.Options) error) error {
+       s.mu.Lock()
+       defer s.mu.Unlock()
+
+       // Use temporary go.mod files, but always go to disk for the contents.
+       // Rebuilding the cache is expensive, and we don't want to do it for
+       // transient changes.
+       var modFH, sumFH source.FileHandle
+       var modFileIdentifier string
+       var err error
+       // TODO(heschik): Change the goimports logic to use a persistent workspace
+       // module for workspace module mode.
+       //
+       // Get the go.mod file that corresponds to this view's root URI. This is
+       // broken because it assumes that the view's root is a module, but this is
+       // not more broken than the previous state--it is a temporary hack that
+       // should be removed ASAP.
+       var match *moduleRoot
+       for _, m := range snapshot.modules {
+               if m.rootURI == snapshot.view.rootURI {
+                       match = m
+               }
+       }
+       if match != nil {
+               modFH, err = snapshot.GetFile(ctx, match.modURI)
+               if err != nil {
+                       return err
+               }
+               modFileIdentifier = modFH.FileIdentity().Hash
+               if match.sumURI != "" {
+                       sumFH, err = snapshot.GetFile(ctx, match.sumURI)
+                       if err != nil {
+                               return err
+                       }
+               }
+       }
+       // v.goEnv is immutable -- changes make a new view. Options can change.
+       // We can't compare build flags directly because we may add -modfile.
+       snapshot.view.optionsMu.Lock()
+       localPrefix := snapshot.view.options.Local
+       currentBuildFlags := snapshot.view.options.BuildFlags
+       changed := !reflect.DeepEqual(currentBuildFlags, s.cachedBuildFlags) ||
+               snapshot.view.options.VerboseOutput != (s.processEnv.Logf != nil) ||
+               modFileIdentifier != s.cachedModFileIdentifier
+       snapshot.view.optionsMu.Unlock()
+
+       // If anything relevant to imports has changed, clear caches and
+       // update the processEnv. Clearing caches blocks on any background
+       // scans.
+       if changed {
+               // As a special case, skip cleanup the first time -- we haven't fully
+               // initialized the environment yet and calling GetResolver will do
+               // unnecessary work and potentially mess up the go.mod file.
+               if s.cleanupProcessEnv != nil {
+                       if resolver, err := s.processEnv.GetResolver(); err == nil {
+                               resolver.(*imports.ModuleResolver).ClearForNewMod()
+                       }
+                       s.cleanupProcessEnv()
+               }
+               s.cachedModFileIdentifier = modFileIdentifier
+               s.cachedBuildFlags = currentBuildFlags
+               s.cleanupProcessEnv, err = s.populateProcessEnv(ctx, snapshot, modFH, sumFH)
+               if err != nil {
+                       return err
+               }
+       }
+
+       // Run the user function.
+       opts := &imports.Options{
+               // Defaults.
+               AllErrors:   true,
+               Comments:    true,
+               Fragment:    true,
+               FormatOnly:  false,
+               TabIndent:   true,
+               TabWidth:    8,
+               Env:         s.processEnv,
+               LocalPrefix: localPrefix,
+       }
+
+       if err := fn(opts); err != nil {
+               return err
+       }
+
+       if s.cacheRefreshTimer == nil {
+               // Don't refresh more than twice per minute.
+               delay := 30 * time.Second
+               // Don't spend more than a couple percent of the time refreshing.
+               if adaptive := 50 * s.cacheRefreshDuration; adaptive > delay {
+                       delay = adaptive
+               }
+               s.cacheRefreshTimer = time.AfterFunc(delay, s.refreshProcessEnv)
+       }
+
+       return nil
+}
+
+// populateProcessEnv sets the dynamically configurable fields for the view's
+// process environment. Assumes that the caller is holding the s.view.importsMu.
+func (s *importsState) populateProcessEnv(ctx context.Context, snapshot *snapshot, modFH, sumFH source.FileHandle) (cleanup func(), err error) {
+       cleanup = func() {}
+       pe := s.processEnv
+
+       snapshot.view.optionsMu.Lock()
+       pe.BuildFlags = append([]string(nil), snapshot.view.options.BuildFlags...)
+       if snapshot.view.options.VerboseOutput {
+               pe.Logf = func(format string, args ...interface{}) {
+                       event.Log(ctx, fmt.Sprintf(format, args...))
+               }
+       } else {
+               pe.Logf = nil
+       }
+       snapshot.view.optionsMu.Unlock()
+
+       pe.Env = map[string]string{}
+       for k, v := range snapshot.view.goEnv {
+               pe.Env[k] = v
+       }
+       pe.Env["GO111MODULE"] = snapshot.view.go111module
+
+       var modURI span.URI
+       var modContent []byte
+       if modFH != nil {
+               modURI = modFH.URI()
+               modContent, err = modFH.Read()
+               if err != nil {
+                       return nil, err
+               }
+       }
+       modmod, err := snapshot.needsModEqualsMod(ctx, modURI, modContent)
+       if err != nil {
+               return cleanup, err
+       }
+       if modmod {
+               pe.ModFlag = "mod"
+       }
+
+       // Add -modfile to the build flags, if we are using it.
+       if snapshot.workspaceMode()&tempModfile != 0 && modFH != nil {
+               var tmpURI span.URI
+               tmpURI, cleanup, err = tempModFile(modFH, sumFH)
+               if err != nil {
+                       return nil, err
+               }
+               pe.ModFile = tmpURI.Filename()
+       }
+
+       return cleanup, nil
+}
+
+func (s *importsState) refreshProcessEnv() {
+       start := time.Now()
+
+       s.mu.Lock()
+       env := s.processEnv
+       if resolver, err := s.processEnv.GetResolver(); err == nil {
+               resolver.ClearForNewScan()
+       }
+       s.mu.Unlock()
+
+       event.Log(s.ctx, "background imports cache refresh starting")
+       if err := imports.PrimeCache(context.Background(), env); err == nil {
+               event.Log(s.ctx, fmt.Sprintf("background refresh finished after %v", time.Since(start)))
+       } else {
+               event.Log(s.ctx, fmt.Sprintf("background refresh finished after %v", time.Since(start)), keys.Err.Of(err))
+       }
+       s.mu.Lock()
+       s.cacheRefreshDuration = time.Since(start)
+       s.cacheRefreshTimer = nil
+       s.mu.Unlock()
+}