aerc

Working clone of aerc-mail.org
git clone git://git.danielmoch.com/aerc.git
Log | Files | Refs | README | LICENSE

commit 77a0f68758905faa74407499ff92c90929e27989
parent db1b2cd53f5dc7bfbfb6ee54ad0bb0882ea2cc03
Author: Drew DeVault <sir@cmpwn.com>
Date:   Wed, 10 Jan 2018 22:41:15 -0500

Make termbox event loop async

Diffstat:
Mcmd/aerc/main.go | 11++++++-----
Aui/account.go | 41+++++++++++++++++++++++++++++++++++++++++
Aui/helpers.go | 21+++++++++++++++++++++
Mui/render.go | 53++++++++++++++++++++++++++++++++++++++++++++---------
Mui/types.go | 18++++++++++++++----
5 files changed, 126 insertions(+), 18 deletions(-)

diff --git a/cmd/aerc/main.go b/cmd/aerc/main.go @@ -14,6 +14,11 @@ func main() { if err != nil { panic(err) } + _ui, err := ui.Initialize(conf) + if err != nil { + panic(err) + } + defer _ui.Close() var workers []worker.Worker for _, account := range conf.Accounts { work, err := worker.NewWorker(account.Source) @@ -23,12 +28,8 @@ func main() { go work.Run() work.PostAction(types.Configure{Config: account}) workers = append(workers, work) + _ui.AddTab(ui.NewAccountTab(&account, &work)) } - _ui, err := ui.Initialize(conf) - if err != nil { - panic(err) - } - defer _ui.Close() for !_ui.Exit { activity := false for _, worker := range workers { diff --git a/ui/account.go b/ui/account.go @@ -0,0 +1,41 @@ +package ui + +import ( + tb "github.com/nsf/termbox-go" + + "git.sr.ht/~sircmpwn/aerc2/config" + "git.sr.ht/~sircmpwn/aerc2/worker" +) + +type AccountTab struct { + Config *config.AccountConfig + Worker *worker.Worker + Parent *UIState +} + +func NewAccountTab(conf *config.AccountConfig, work *worker.Worker) *AccountTab { + return &AccountTab{ + Config: conf, + Worker: work, + } +} + +func (acc *AccountTab) Name() string { + return acc.Config.Name +} + +func (acc *AccountTab) Invalid() bool { + return false +} + +func (acc *AccountTab) SetParent(parent *UIState) { + acc.Parent = parent +} + +func (acc *AccountTab) Render(at Geometry) { + cell := tb.Cell{ + Fg: tb.ColorDefault, + Bg: tb.ColorDefault, + } + TPrintf(&at, cell, "%s", acc.Name()) +} diff --git a/ui/helpers.go b/ui/helpers.go @@ -0,0 +1,21 @@ +package ui + +import ( + "fmt" + + tb "github.com/nsf/termbox-go" +) + +func TPrintf(geo *Geometry, ref tb.Cell, format string, a ...interface{}) { + str := fmt.Sprintf(format, a...) + _geo := *geo + for _, ch := range str { + tb.SetCell(geo.Col, geo.Row, ch, ref.Fg, ref.Bg) + geo.Col++ + if geo.Col == _geo.Col+geo.Width { + // TODO: Abort when out of room? + geo.Col = _geo.Col + geo.Row++ + } + } +} diff --git a/ui/render.go b/ui/render.go @@ -8,15 +8,21 @@ import ( func Initialize(conf *config.AercConfig) (*UIState, error) { state := UIState{ + Config: conf, InvalidPanes: InvalidateAll, - Tabs: make([]AercTab, len(conf.Accounts)), + + tbEvents: make(chan tb.Event, 10), } - // TODO: Initialize each tab to a mailbox tab if err := tb.Init(); err != nil { return nil, err } tb.SetInputMode(tb.InputEsc | tb.InputMouse) tb.SetOutputMode(tb.Output256) + go (func() { + for !state.Exit { + state.tbEvents <- tb.PollEvent() + } + })() return &state, nil } @@ -24,21 +30,50 @@ func (state *UIState) Close() { tb.Close() } +func (state *UIState) AddTab(tab AercTab) { + state.Tabs = append(state.Tabs, tab) +} + func (state *UIState) Invalidate(what uint) { state.InvalidPanes |= what } +func (state *UIState) calcGeometries() { + width, height := tb.Size() + // TODO: more + state.Panes.TabView = Geometry{ + Row: 0, + Col: 0, + Width: width, + Height: height, + } +} + func (state *UIState) Tick() bool { - switch e := tb.PollEvent(); e.Type { - case tb.EventKey: - if e.Key == tb.KeyEsc { - state.Exit = true + select { + case event := <-state.tbEvents: + switch event.Type { + case tb.EventKey: + if event.Key == tb.KeyEsc { + state.Exit = true + } + case tb.EventResize: + state.Invalidate(InvalidateAll) } - case tb.EventResize: - state.Invalidate(InvalidateAll) + default: + // no-op + break } if state.InvalidPanes != 0 { - // TODO: re-render + if state.InvalidPanes&InvalidateAll == InvalidateAll { + tb.Clear(tb.ColorDefault, tb.ColorDefault) + state.calcGeometries() + } + if state.InvalidPanes&InvalidateTabs != 0 { + tab := state.Tabs[state.SelectedTab] + tab.Render(state.Panes.TabView) + } + tb.Flush() state.InvalidPanes = 0 } return true diff --git a/ui/types.go b/ui/types.go @@ -1,5 +1,11 @@ package ui +import ( + tb "github.com/nsf/termbox-go" + + "git.sr.ht/~sircmpwn/aerc2/config" +) + const ( Valid = 0 InvalidateTabs = 1 << iota @@ -12,19 +18,21 @@ const ( ) type Geometry struct { - row int - col int - width int - height int + Row int + Col int + Width int + Height int } type AercTab interface { Name() string Invalid() bool Render(at Geometry) + SetParent(parent *UIState) } type UIState struct { + Config *config.AercConfig Exit bool InvalidPanes uint @@ -44,4 +52,6 @@ type UIState struct { Index int Scroll int } + + tbEvents chan tb.Event }