aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config/aerc.conf.in5
-rw-r--r--config/config.go7
-rw-r--r--doc/aerc-config.5.scd16
-rw-r--r--lib/msgstore.go8
-rw-r--r--widgets/dirlist.go99
5 files changed, 131 insertions, 4 deletions
diff --git a/config/aerc.conf.in b/config/aerc.conf.in
index 4d0f9fd..c50b7b9 100644
--- a/config/aerc.conf.in
+++ b/config/aerc.conf.in
@@ -43,6 +43,11 @@ mouse-enabled=false
# Default: yes
new-message-bell=true
+# Describes the format string to use for the directory list
+#
+# Default: %n %>r
+dirlist-format=%n %>r
+
[viewer]
#
# Specifies the pager to use when displaying emails. Note that some filters
diff --git a/config/config.go b/config/config.go
index 06caec1..738fd1d 100644
--- a/config/config.go
+++ b/config/config.go
@@ -35,6 +35,7 @@ type UIConfig struct {
NewMessageBell bool `ini:"new-message-bell"`
Spinner string `ini:"spinner"`
SpinnerDelimiter string `ini:"spinner-delimiter"`
+ DirListFormat string `ini:"dirlist-format"`
}
const (
@@ -349,9 +350,9 @@ func LoadConfigFromFile(root *string, sharedir string) (*AercConfig, error) {
EmptyDirlist: "(no folders)",
MouseEnabled: false,
NewMessageBell: true,
- Spinner:
- "[..] , [..] , [..] , [..] , [..], [..] , [..] , [..] ",
- SpinnerDelimiter: ",",
+ Spinner: "[..] , [..] , [..] , [..] , [..], [..] , [..] , [..] ",
+ SpinnerDelimiter: ",",
+ DirListFormat: "%n %>r",
},
Viewer: ViewerConfig{
diff --git a/doc/aerc-config.5.scd b/doc/aerc-config.5.scd
index 9257bde..d422e5d 100644
--- a/doc/aerc-config.5.scd
+++ b/doc/aerc-config.5.scd
@@ -125,6 +125,22 @@ These options are configured in the *[ui]* section of aerc.conf.
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
These options are configured in the *[viewer]* section of aerc.conf.
diff --git a/lib/msgstore.go b/lib/msgstore.go
index bbdfa57..2733288 100644
--- a/lib/msgstore.go
+++ b/lib/msgstore.go
@@ -27,6 +27,7 @@ type MessageStore struct {
// Map of uids we've asked the worker to fetch
onUpdate func(store *MessageStore) // TODO: multiple onUpdate handlers
+ onUpdateDirs func()
pendingBodies map[uint32]interface{}
pendingHeaders map[uint32]interface{}
worker *types.Worker
@@ -234,10 +235,17 @@ func (store *MessageStore) OnUpdate(fn func(store *MessageStore)) {
store.onUpdate = fn
}
+func (store *MessageStore) OnUpdateDirs(fn func()) {
+ store.onUpdateDirs = fn
+}
+
func (store *MessageStore) update() {
if store.onUpdate != nil {
store.onUpdate(store)
}
+ if store.onUpdateDirs != nil {
+ store.onUpdateDirs()
+ }
}
func (store *MessageStore) Delete(uids []uint32,
diff --git a/widgets/dirlist.go b/widgets/dirlist.go
index ec73082..ef2dd1e 100644
--- a/widgets/dirlist.go
+++ b/widgets/dirlist.go
@@ -1,15 +1,18 @@
package widgets
import (
+ "fmt"
"log"
"regexp"
"sort"
"github.com/gdamore/tcell"
+ "github.com/mattn/go-runewidth"
"git.sr.ht/~sircmpwn/aerc/config"
"git.sr.ht/~sircmpwn/aerc/lib"
"git.sr.ht/~sircmpwn/aerc/lib/ui"
+ "git.sr.ht/~sircmpwn/aerc/models"
"git.sr.ht/~sircmpwn/aerc/worker/types"
)
@@ -105,6 +108,92 @@ func (dirlist *DirectoryList) Invalidate() {
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) {
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)
}
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++
}
}
@@ -233,4 +327,7 @@ func (dirlist *DirectoryList) MsgStore(name string) (*lib.MessageStore, bool) {
func (dirlist *DirectoryList) SetMsgStore(name string, msgStore *lib.MessageStore) {
dirlist.store.SetMessageStore(name, msgStore)
+ msgStore.OnUpdateDirs(func() {
+ dirlist.Invalidate()
+ })
}