aboutsummaryrefslogtreecommitdiff
path: root/gopls/internal/lsp/debounce.go
diff options
context:
space:
mode:
Diffstat (limited to 'gopls/internal/lsp/debounce.go')
-rw-r--r--gopls/internal/lsp/debounce.go71
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
+}