aboutsummaryrefslogtreecommitdiffstats
path: root/app/status.go
diff options
context:
space:
mode:
Diffstat (limited to 'app/status.go')
-rw-r--r--app/status.go166
1 files changed, 166 insertions, 0 deletions
diff --git a/app/status.go b/app/status.go
new file mode 100644
index 00000000..f6919e29
--- /dev/null
+++ b/app/status.go
@@ -0,0 +1,166 @@
+package app
+
+import (
+ "bytes"
+ "sync"
+ "time"
+
+ "github.com/gdamore/tcell/v2"
+ "github.com/mattn/go-runewidth"
+
+ "git.sr.ht/~rjarry/aerc/config"
+ "git.sr.ht/~rjarry/aerc/lib/state"
+ "git.sr.ht/~rjarry/aerc/lib/templates"
+ "git.sr.ht/~rjarry/aerc/lib/ui"
+ "git.sr.ht/~rjarry/aerc/log"
+)
+
+type StatusLine struct {
+ sync.Mutex
+ stack []*StatusMessage
+ aerc *Aerc
+ acct *AccountView
+ err string
+}
+
+type StatusMessage struct {
+ style tcell.Style
+ message string
+}
+
+func (status *StatusLine) Invalidate() {
+ ui.Invalidate()
+}
+
+func (status *StatusLine) Draw(ctx *ui.Context) {
+ status.Lock()
+ defer status.Unlock()
+ style := status.uiConfig().GetStyle(config.STYLE_STATUSLINE_DEFAULT)
+ ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', style)
+ switch {
+ case len(status.stack) != 0:
+ line := status.stack[len(status.stack)-1]
+ msg := runewidth.Truncate(line.message, ctx.Width(), "")
+ msg = runewidth.FillRight(msg, ctx.Width())
+ ctx.Printf(0, 0, line.style, "%s", msg)
+ case status.err != "":
+ msg := runewidth.Truncate(status.err, ctx.Width(), "")
+ msg = runewidth.FillRight(msg, ctx.Width())
+ style := status.uiConfig().GetStyle(config.STYLE_STATUSLINE_ERROR)
+ ctx.Printf(0, 0, style, "%s", msg)
+ case status.aerc != nil && status.acct != nil:
+ data := state.NewDataSetter()
+ data.SetPendingKeys(status.aerc.pendingKeys)
+ data.SetState(&status.acct.state)
+ data.SetAccount(status.acct.acct)
+ data.SetFolder(status.acct.Directories().SelectedDirectory())
+ msg, _ := status.acct.SelectedMessage()
+ data.SetInfo(msg, 0, false)
+ table := ui.NewTable(
+ ctx.Height(),
+ config.Statusline.StatusColumns,
+ config.Statusline.ColumnSeparator,
+ nil,
+ func(*ui.Table, int) tcell.Style { return style },
+ )
+ var buf bytes.Buffer
+ cells := make([]string, len(table.Columns))
+ for c, col := range table.Columns {
+ err := templates.Render(col.Def.Template, &buf,
+ data.Data())
+ if err != nil {
+ log.Errorf("%s", err)
+ cells[c] = err.Error()
+ } else {
+ cells[c] = buf.String()
+ }
+ buf.Reset()
+ }
+ table.AddRow(cells, nil)
+ table.Draw(ctx)
+ }
+}
+
+func (status *StatusLine) Update(acct *AccountView) {
+ status.acct = acct
+ status.Invalidate()
+}
+
+func (status *StatusLine) SetError(err string) {
+ prev := status.err
+ status.err = err
+ if prev != status.err {
+ status.Invalidate()
+ }
+}
+
+func (status *StatusLine) Clear() {
+ status.SetError("")
+ status.acct = nil
+}
+
+func (status *StatusLine) Push(text string, expiry time.Duration) *StatusMessage {
+ status.Lock()
+ defer status.Unlock()
+ log.Debugf(text)
+ msg := &StatusMessage{
+ style: status.uiConfig().GetStyle(config.STYLE_STATUSLINE_DEFAULT),
+ message: text,
+ }
+ status.stack = append(status.stack, msg)
+ go (func() {
+ defer log.PanicHandler()
+
+ time.Sleep(expiry)
+ status.Lock()
+ defer status.Unlock()
+ for i, m := range status.stack {
+ if m == msg {
+ status.stack = append(status.stack[:i], status.stack[i+1:]...)
+ break
+ }
+ }
+ status.Invalidate()
+ })()
+ status.Invalidate()
+ return msg
+}
+
+func (status *StatusLine) PushError(text string) *StatusMessage {
+ log.Errorf(text)
+ msg := status.Push(text, 10*time.Second)
+ msg.Color(status.uiConfig().GetStyle(config.STYLE_STATUSLINE_ERROR))
+ return msg
+}
+
+func (status *StatusLine) PushWarning(text string) *StatusMessage {
+ log.Warnf(text)
+ msg := status.Push(text, 10*time.Second)
+ msg.Color(status.uiConfig().GetStyle(config.STYLE_STATUSLINE_WARNING))
+ return msg
+}
+
+func (status *StatusLine) PushSuccess(text string) *StatusMessage {
+ log.Tracef(text)
+ msg := status.Push(text, 10*time.Second)
+ msg.Color(status.uiConfig().GetStyle(config.STYLE_STATUSLINE_SUCCESS))
+ return msg
+}
+
+func (status *StatusLine) Expire() {
+ status.Lock()
+ defer status.Unlock()
+ status.stack = nil
+}
+
+func (status *StatusLine) uiConfig() *config.UIConfig {
+ return status.aerc.SelectedAccountUiConfig()
+}
+
+func (status *StatusLine) SetAerc(aerc *Aerc) {
+ status.aerc = aerc
+}
+
+func (msg *StatusMessage) Color(style tcell.Style) {
+ msg.style = style
+}