Add display of unread messages in dirlist

Add an onUpdateDirs handler. This is used to invalidate the dirlist and
redraw with the correct number of recent/unread/total messages is shown.

A config option and formatting options are provided.
This commit is contained in:
Jeffas 2019-09-11 17:37:21 +01:00 committed by Drew DeVault
parent 572d9ff728
commit 618a500341
5 changed files with 131 additions and 4 deletions

View File

@ -43,6 +43,11 @@ mouse-enabled=false
# Default: yes # Default: yes
new-message-bell=true new-message-bell=true
# Describes the format string to use for the directory list
#
# Default: %n %>r
dirlist-format=%n %>r
[viewer] [viewer]
# #
# Specifies the pager to use when displaying emails. Note that some filters # Specifies the pager to use when displaying emails. Note that some filters

View File

@ -35,6 +35,7 @@ type UIConfig struct {
NewMessageBell bool `ini:"new-message-bell"` NewMessageBell bool `ini:"new-message-bell"`
Spinner string `ini:"spinner"` Spinner string `ini:"spinner"`
SpinnerDelimiter string `ini:"spinner-delimiter"` SpinnerDelimiter string `ini:"spinner-delimiter"`
DirListFormat string `ini:"dirlist-format"`
} }
const ( const (
@ -349,9 +350,9 @@ func LoadConfigFromFile(root *string, sharedir string) (*AercConfig, error) {
EmptyDirlist: "(no folders)", EmptyDirlist: "(no folders)",
MouseEnabled: false, MouseEnabled: false,
NewMessageBell: true, NewMessageBell: true,
Spinner: Spinner: "[..] , [..] , [..] , [..] , [..], [..] , [..] , [..] ",
"[..] , [..] , [..] , [..] , [..], [..] , [..] , [..] ", SpinnerDelimiter: ",",
SpinnerDelimiter: ",", DirListFormat: "%n %>r",
}, },
Viewer: ViewerConfig{ Viewer: ViewerConfig{

View File

@ -125,6 +125,22 @@ These options are configured in the *[ui]* section of aerc.conf.
Default: "," Default: ","
*dirlist-format*
Describes the format string to use for the directory list
Default: %n %>r
[- *Format specifier*
:[ *Description*
| %%
: literal %
| %n
: directory name
| %r
: recent/unseen/total message count
| %>X
: make format specifier 'X' be right justified
## VIEWER ## VIEWER
These options are configured in the *[viewer]* section of aerc.conf. These options are configured in the *[viewer]* section of aerc.conf.

View File

@ -27,6 +27,7 @@ type MessageStore struct {
// Map of uids we've asked the worker to fetch // Map of uids we've asked the worker to fetch
onUpdate func(store *MessageStore) // TODO: multiple onUpdate handlers onUpdate func(store *MessageStore) // TODO: multiple onUpdate handlers
onUpdateDirs func()
pendingBodies map[uint32]interface{} pendingBodies map[uint32]interface{}
pendingHeaders map[uint32]interface{} pendingHeaders map[uint32]interface{}
worker *types.Worker worker *types.Worker
@ -234,10 +235,17 @@ func (store *MessageStore) OnUpdate(fn func(store *MessageStore)) {
store.onUpdate = fn store.onUpdate = fn
} }
func (store *MessageStore) OnUpdateDirs(fn func()) {
store.onUpdateDirs = fn
}
func (store *MessageStore) update() { func (store *MessageStore) update() {
if store.onUpdate != nil { if store.onUpdate != nil {
store.onUpdate(store) store.onUpdate(store)
} }
if store.onUpdateDirs != nil {
store.onUpdateDirs()
}
} }
func (store *MessageStore) Delete(uids []uint32, func (store *MessageStore) Delete(uids []uint32,

View File

@ -1,15 +1,18 @@
package widgets package widgets
import ( import (
"fmt"
"log" "log"
"regexp" "regexp"
"sort" "sort"
"github.com/gdamore/tcell" "github.com/gdamore/tcell"
"github.com/mattn/go-runewidth"
"git.sr.ht/~sircmpwn/aerc/config" "git.sr.ht/~sircmpwn/aerc/config"
"git.sr.ht/~sircmpwn/aerc/lib" "git.sr.ht/~sircmpwn/aerc/lib"
"git.sr.ht/~sircmpwn/aerc/lib/ui" "git.sr.ht/~sircmpwn/aerc/lib/ui"
"git.sr.ht/~sircmpwn/aerc/models"
"git.sr.ht/~sircmpwn/aerc/worker/types" "git.sr.ht/~sircmpwn/aerc/worker/types"
) )
@ -105,6 +108,92 @@ func (dirlist *DirectoryList) Invalidate() {
dirlist.DoInvalidate(dirlist) dirlist.DoInvalidate(dirlist)
} }
func (dirlist *DirectoryList) getDirString(name string, width int, recentUnseen func() string) string {
percent := false
rightJustify := false
formatted := ""
doRightJustify := func(s string) {
formatted = runewidth.FillRight(formatted, width-len(s))
formatted = runewidth.Truncate(formatted, width-len(s), "…")
}
for _, char := range dirlist.uiConf.DirListFormat {
switch char {
case '%':
if percent {
formatted += string(char)
percent = false
} else {
percent = true
}
case '>':
if percent {
rightJustify = true
}
case 'n':
if percent {
if rightJustify {
doRightJustify(name)
rightJustify = false
}
formatted += name
percent = false
}
case 'r':
if percent {
rString := recentUnseen()
if rightJustify {
doRightJustify(rString)
rightJustify = false
}
formatted += rString
percent = false
}
default:
formatted += string(char)
}
}
return formatted
}
func (dirlist *DirectoryList) getRUEString(name string) string {
totalUnseen := 0
totalRecent := 0
totalExists := 0
if msgStore, ok := dirlist.MsgStore(name); ok {
for _, msg := range msgStore.Messages {
if msg == nil {
continue
}
seen := false
recent := false
for _, flag := range msg.Flags {
if flag == models.SeenFlag {
seen = true
} else if flag == models.RecentFlag {
recent = true
}
}
if !seen {
if recent {
totalRecent++
} else {
totalUnseen++
}
}
}
totalExists = msgStore.DirInfo.Exists
}
rueString := ""
if totalRecent > 0 {
rueString = fmt.Sprintf("%d/%d/%d", totalRecent, totalUnseen, totalExists)
} else if totalUnseen > 0 {
rueString = fmt.Sprintf("%d/%d", totalUnseen, totalExists)
} else if totalExists > 0 {
rueString = fmt.Sprintf("%d", totalExists)
}
return rueString
}
func (dirlist *DirectoryList) Draw(ctx *ui.Context) { func (dirlist *DirectoryList) Draw(ctx *ui.Context) {
ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault) ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault)
@ -132,7 +221,12 @@ func (dirlist *DirectoryList) Draw(ctx *ui.Context) {
style = style.Foreground(tcell.ColorGray) style = style.Foreground(tcell.ColorGray)
} }
ctx.Fill(0, row, ctx.Width(), 1, ' ', style) ctx.Fill(0, row, ctx.Width(), 1, ' ', style)
ctx.Printf(0, row, style, "%s", name)
dirString := dirlist.getDirString(name, ctx.Width(), func() string {
return dirlist.getRUEString(name)
})
ctx.Printf(0, row, style, dirString)
row++ row++
} }
} }
@ -233,4 +327,7 @@ func (dirlist *DirectoryList) MsgStore(name string) (*lib.MessageStore, bool) {
func (dirlist *DirectoryList) SetMsgStore(name string, msgStore *lib.MessageStore) { func (dirlist *DirectoryList) SetMsgStore(name string, msgStore *lib.MessageStore) {
dirlist.store.SetMessageStore(name, msgStore) dirlist.store.SetMessageStore(name, msgStore)
msgStore.OnUpdateDirs(func() {
dirlist.Invalidate()
})
} }