~gpanders/ijq

ea4a58f2fe6d03e3a8bc249f3e22a4ee8aaefdaf — Gregory Anders 14 days ago b4e9a4d
Debounce filter input

Entering input too quickly (e.g. holding a single key) causes array
indexing errors in the tview library. This is most likely a concurrency
issue caused by a race condition on the `outputWriter` in the filter
input's asynchronous `ChangedFunc`.

My solution to this problem is to debounce the filter input so that the
filter is only executed at most every millisecond. This causes a
noticeable amount of input latency when a single key is held down, but
it's better than the program crashing.
1 files changed, 27 insertions(+), 12 deletions(-)

M main.go
M main.go => main.go +27 -12
@@ 10,6 10,7 @@ import (
	"os"
	"os/exec"
	"strings"
	"time"

	"github.com/gdamore/tcell"
	"github.com/rivo/tview"


@@ 189,24 190,14 @@ func main() {
		fmt.Fprint(outputWriter, out)
	}()

	inputChan := make(chan string)
	filterInput := tview.NewInputField()
	filterInput.
		SetText(filter).
		SetFieldBackgroundColor(0).
		SetFieldTextColor(7).
		SetChangedFunc(func(text string) {
			go func() {
				out, err := doc.Filter(text)
				if err != nil {
					filterInput.SetFieldTextColor(1)
					return
				}

				filterInput.SetFieldTextColor(7)
				outputView.Clear()
				fmt.Fprint(outputWriter, out)
				outputView.ScrollToBeginning()
			}()
			inputChan <- text
		}).
		SetDoneFunc(func(key tcell.Key) {
			switch key {


@@ 219,6 210,30 @@ func main() {

	filterInput.SetTitle("Filter").SetBorder(true)

	// Debounce filter input to avoid problems with input being entered too quickly
	go func() {
		var text string
		interval := time.Millisecond
		timer := time.NewTimer(interval)
		for {
			select {
			case text = <-inputChan:
				timer.Reset(interval)
			case <-timer.C:
				out, err := doc.Filter(text)
				if err != nil {
					filterInput.SetFieldTextColor(1)
					continue
				}

				filterInput.SetFieldTextColor(7)
				outputView.Clear()
				fmt.Fprint(outputWriter, out)
				outputView.ScrollToBeginning()
			}
		}
	}()

	grid := tview.NewGrid().
		SetRows(0, 3).
		SetColumns(0).