Switching termdash to EDS.

This commit is contained in:
Jakub Sobon 2019-02-20 01:18:44 -05:00
parent adb11e8358
commit b79c3fef2d
No known key found for this signature in database
GPG Key ID: F2451A77FB05D3B7
4 changed files with 47 additions and 31 deletions

View File

@ -31,6 +31,7 @@ import (
"time" "time"
"github.com/mum4k/termdash/container" "github.com/mum4k/termdash/container"
"github.com/mum4k/termdash/event"
"github.com/mum4k/termdash/terminalapi" "github.com/mum4k/termdash/terminalapi"
) )
@ -157,6 +158,9 @@ type termdash struct {
// container maintains terminal splits and places widgets. // container maintains terminal splits and places widgets.
container *container.Container container *container.Container
// eds distributes input events to subscribers.
eds *event.DistributionSystem
// closeCh gets closed when Stop() is called, which tells the event // closeCh gets closed when Stop() is called, which tells the event
// collecting goroutine to exit. // collecting goroutine to exit.
closeCh chan struct{} closeCh chan struct{}
@ -182,6 +186,7 @@ func newTermdash(t terminalapi.Terminal, c *container.Container, opts ...Option)
td := &termdash{ td := &termdash{
term: t, term: t,
container: c, container: c,
eds: event.NewDistributionSystem(),
closeCh: make(chan struct{}), closeCh: make(chan struct{}),
exitCh: make(chan struct{}), exitCh: make(chan struct{}),
redrawInterval: DefaultRedrawInterval, redrawInterval: DefaultRedrawInterval,
@ -190,9 +195,45 @@ func newTermdash(t terminalapi.Terminal, c *container.Container, opts ...Option)
for _, opt := range opts { for _, opt := range opts {
opt.set(td) opt.set(td)
} }
td.subscribers()
return td return td
} }
// subscribers subscribes event receivers that live in this package to EDS.
func (td *termdash) subscribers() {
// Handler for all errors that occur during input event processing.
td.eds.Subscribe([]terminalapi.Event{terminalapi.NewError("")}, func(ev terminalapi.Event) {
td.handleError(ev.(*terminalapi.Error).Error())
})
// Handles terminal resize events.
td.eds.Subscribe([]terminalapi.Event{&terminalapi.Resize{}}, func(terminalapi.Event) {
td.setClearNeeded()
})
// Redraws the screen on Keyboard and Mouse events.
// These events very likely change the content of the widgets (e.g. zooming
// a LineChart) so a redraw is needed to make that visible.
td.eds.Subscribe([]terminalapi.Event{&terminalapi.Keyboard{}}, func(ev terminalapi.Event) {
td.keyEvRedraw(ev.(*terminalapi.Keyboard))
})
td.eds.Subscribe([]terminalapi.Event{&terminalapi.Mouse{}}, func(ev terminalapi.Event) {
td.mouseEvRedraw(ev.(*terminalapi.Mouse))
})
// Keyboard and Mouse subscribers specified via options.
if td.keyboardSubscriber != nil {
td.eds.Subscribe([]terminalapi.Event{&terminalapi.Keyboard{}}, func(ev terminalapi.Event) {
td.keyboardSubscriber(ev.(*terminalapi.Keyboard))
})
}
if td.mouseSubscriber != nil {
td.eds.Subscribe([]terminalapi.Event{&terminalapi.Mouse{}}, func(ev terminalapi.Event) {
td.mouseSubscriber(ev.(*terminalapi.Mouse))
})
}
}
// handleError forwards the error to the error handler if one was // handleError forwards the error to the error handler if one was
// provided or panics. // provided or panics.
func (td *termdash) handleError(err error) { func (td *termdash) handleError(err error) {
@ -240,9 +281,6 @@ func (td *termdash) keyEvRedraw(ev *terminalapi.Keyboard) error {
if err := td.container.Keyboard(ev); err != nil { if err := td.container.Keyboard(ev); err != nil {
return err return err
} }
if td.keyboardSubscriber != nil {
td.keyboardSubscriber(ev)
}
return td.redraw() return td.redraw()
} }
@ -255,9 +293,6 @@ func (td *termdash) mouseEvRedraw(ev *terminalapi.Mouse) error {
if err := td.container.Mouse(ev); err != nil { if err := td.container.Mouse(ev); err != nil {
return err return err
} }
if td.mouseSubscriber != nil {
td.mouseSubscriber(ev)
}
return td.redraw() return td.redraw()
} }
@ -274,29 +309,9 @@ func (td *termdash) processEvents(ctx context.Context) {
defer close(td.exitCh) defer close(td.exitCh)
for { for {
event := td.term.Event(ctx) ev := td.term.Event(ctx)
switch ev := event.(type) { if ev != nil {
case *terminalapi.Keyboard: td.eds.Event(ev)
if err := td.keyEvRedraw(ev); err != nil {
td.handleError(err)
}
case *terminalapi.Mouse:
if err := td.mouseEvRedraw(ev); err != nil {
td.handleError(err)
}
case *terminalapi.Resize:
td.setClearNeeded()
case *terminalapi.Error:
// Don't forward the error if the context is closed.
// It just says that the context expired.
select {
case <-ctx.Done():
default:
td.handleError(ev.Error())
}
} }
select { select {

View File

@ -197,7 +197,7 @@ func (t *Terminal) Event(ctx context.Context) terminalapi.Event {
ev := t.events.Pull(ctx) ev := t.events.Pull(ctx)
if ev == nil { if ev == nil {
return terminalapi.NewError("unable to pull the next event") return nil
} }
if res, ok := ev.(*terminalapi.Resize); ok { if res, ok := ev.(*terminalapi.Resize); ok {

View File

@ -150,7 +150,7 @@ func (t *Terminal) pollEvents() {
func (t *Terminal) Event(ctx context.Context) terminalapi.Event { func (t *Terminal) Event(ctx context.Context) terminalapi.Event {
ev := t.events.Pull(ctx) ev := t.events.Pull(ctx)
if ev == nil { if ev == nil {
return terminalapi.NewError("unable to pull the next event") return nil
} }
return ev return ev
} }

View File

@ -47,5 +47,6 @@ type Terminal interface {
// Event waits for the next event and returns it. // Event waits for the next event and returns it.
// This call blocks until the next event or cancellation of the context. // This call blocks until the next event or cancellation of the context.
// Returns nil when the context gets canceled.
Event(ctx context.Context) Event Event(ctx context.Context) Event
} }