mirror of
https://github.com/peco/peco.git
synced 2026-09-10 07:16:29 -04:00
74 lines
2 KiB
Go
74 lines
2 KiB
Go
package peco
|
|
|
|
import "github.com/nsf/termbox-go"
|
|
|
|
// Screen hides termbox from tne consuming code so that
|
|
// it can be swapped out for testing
|
|
type Screen interface {
|
|
Flush() error
|
|
PollEvent() chan termbox.Event
|
|
SetCell(int, int, rune, termbox.Attribute, termbox.Attribute)
|
|
Size() (int, int)
|
|
SendEvent(termbox.Event)
|
|
}
|
|
|
|
// Termbox just hands out the processing to the termbox library
|
|
type Termbox struct{}
|
|
|
|
// termbox always gives us some sort of warning when we run
|
|
// go run -race cmd/peco/peco.go
|
|
var termboxMutex = newMutex()
|
|
|
|
// SendEvent is used to allow programmers generate random
|
|
// events, but it's only useful for testing purposes.
|
|
// When interactiving with termbox-go, this method is a noop
|
|
func (t Termbox) SendEvent(_ termbox.Event) {
|
|
// no op
|
|
}
|
|
|
|
// Flush calls termbox.Flush
|
|
func (t Termbox) Flush() error {
|
|
termboxMutex.Lock()
|
|
defer termboxMutex.Unlock()
|
|
return termbox.Flush()
|
|
}
|
|
|
|
// PollEvent returns a channel that you can listen to for
|
|
// termbox's events. The actual polling is done in a
|
|
// separate gouroutine
|
|
func (t Termbox) PollEvent() chan termbox.Event {
|
|
// XXX termbox.PollEvent() can get stuck on unexpected signal
|
|
// handling cases. We still would like to wait until the user
|
|
// (termbox) has some event for us to process, but we don't
|
|
// want to allow termbox to control/block our input loop.
|
|
//
|
|
// Solution: put termbox polling in a separate goroutine,
|
|
// and we just watch for a channel. The loop can now
|
|
// safely be implemented in terms of select {} which is
|
|
// safe from being stuck.
|
|
evCh := make(chan termbox.Event)
|
|
go func() {
|
|
defer func() { recover() }()
|
|
defer func() { close(evCh) }()
|
|
for {
|
|
evCh <- termbox.PollEvent()
|
|
}
|
|
}()
|
|
return evCh
|
|
|
|
}
|
|
|
|
// SetCell writes to the terminal
|
|
func (t Termbox) SetCell(x, y int, ch rune, fg, bg termbox.Attribute) {
|
|
termboxMutex.Lock()
|
|
defer termboxMutex.Unlock()
|
|
termbox.SetCell(x, y, ch, fg, bg)
|
|
}
|
|
|
|
// Size returns the dimensions of the current terminal
|
|
func (t Termbox) Size() (int, int) {
|
|
termboxMutex.Lock()
|
|
defer termboxMutex.Unlock()
|
|
return termbox.Size()
|
|
}
|