diff options
Diffstat (limited to 'gopls/internal/lsp/debounce.go')
-rw-r--r-- | gopls/internal/lsp/debounce.go | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/gopls/internal/lsp/debounce.go b/gopls/internal/lsp/debounce.go new file mode 100644 index 000000000..06f411471 --- /dev/null +++ b/gopls/internal/lsp/debounce.go @@ -0,0 +1,71 @@ +// 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 ( + "sync" + "time" +) + +type debounceEvent struct { + order uint64 + done chan struct{} +} + +type debouncer struct { + mu sync.Mutex + events map[string]*debounceEvent +} + +func newDebouncer() *debouncer { + return &debouncer{ + events: make(map[string]*debounceEvent), + } +} + +// debounce returns a channel that receives a boolean reporting whether, +// by the time the delay channel receives a value, this call is (or will be) +// the most recent call with the highest order number for its key. +func (d *debouncer) debounce(key string, order uint64, delay <-chan time.Time) <-chan bool { + okc := make(chan bool, 1) + + d.mu.Lock() + if prev, ok := d.events[key]; ok { + if prev.order > order { + // If we have a logical ordering of events (as is the case for snapshots), + // don't overwrite a later event with an earlier event. + d.mu.Unlock() + okc <- false + return okc + } + close(prev.done) + } + done := make(chan struct{}) + next := &debounceEvent{ + order: order, + done: done, + } + d.events[key] = next + d.mu.Unlock() + + go func() { + ok := false + select { + case <-delay: + d.mu.Lock() + if d.events[key] == next { + ok = true + delete(d.events, key) + } else { + // The event was superseded before we acquired d.mu. + } + d.mu.Unlock() + case <-done: + } + okc <- ok + }() + + return okc +} |