mirror of
https://git.sr.ht/~rjarry/aerc
synced 2025-02-22 23:23:57 +01:00

It's useful to have some indicator of whether or not aerc is in visual mark mode. Add such an indicator to the TrayInfo available in the status line. Changelog-changed: The `TrayInfo` template variable now includes a visual mark mode indicator. Signed-off-by: Jason Cox <me@jasoncarloscox.com> Acked-by: Robin Jarry <robin@jarry.cc>
165 lines
4 KiB
Go
165 lines
4 KiB
Go
package app
|
|
|
|
import (
|
|
"bytes"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/mattn/go-runewidth"
|
|
|
|
"git.sr.ht/~rjarry/aerc/config"
|
|
"git.sr.ht/~rjarry/aerc/lib/log"
|
|
"git.sr.ht/~rjarry/aerc/lib/state"
|
|
"git.sr.ht/~rjarry/aerc/lib/templates"
|
|
"git.sr.ht/~rjarry/aerc/lib/ui"
|
|
"git.sr.ht/~rockorager/vaxis"
|
|
)
|
|
|
|
type StatusLine struct {
|
|
sync.Mutex
|
|
stack []*StatusMessage
|
|
acct *AccountView
|
|
err string
|
|
}
|
|
|
|
type StatusMessage struct {
|
|
style vaxis.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.acct != nil:
|
|
data := state.NewDataSetter()
|
|
data.SetPendingKeys(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)
|
|
data.SetRUE(status.acct.dirlist.List(), status.acct.dirlist.GetRUECount)
|
|
if store := status.acct.Store(); store != nil {
|
|
data.SetVisual(store.Marker().IsVisualMark())
|
|
}
|
|
table := ui.NewTable(
|
|
ctx.Height(),
|
|
config.Statusline.StatusColumns,
|
|
config.Statusline.ColumnSeparator,
|
|
nil,
|
|
func(*ui.Table, int) vaxis.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 SelectedAccountUiConfig()
|
|
}
|
|
|
|
func (msg *StatusMessage) Color(style vaxis.Style) {
|
|
msg.style = style
|
|
}
|