peco.peco/screen.go
2015-03-17 15:37:53 +09:00

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()
}