~sircmpwn/aerc

Mailing list for aerc development.

1

[PATCH v4] Add display of unread messages in dirlist

Details
Message ID
<20190911163049.15090-1-dev@jeffas.io>
DKIM signature
missing
Download raw message
Patch: +149 -22
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.
---

Rebased. Hopefully this applies now.

 config/aerc.conf.in   |  5 +++
 config/config.go      |  7 +--
 doc/aerc-config.5.scd | 52 +++++++++++++++--------
 lib/msgstore.go       |  8 ++++
 widgets/dirlist.go    | 99 ++++++++++++++++++++++++++++++++++++++++++-
 5 files changed, 149 insertions(+), 22 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..f7bf530 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.
@@ -328,7 +344,7 @@ each binding context:
 *$ex*
 	This can be set to a keystroke which will bring up the command input in this
 	context.
-
+
 	Default: <semicolon>

 In addition to letters, special keys may be specified in <angle brackets>. The
@@ -341,39 +357,39 @@ following special keys are supported:
 |  semicolon
 :  ;
 |  tab
-:
+:
 |  enter
-:
+:
 |  up
-:
+:
 |  down
-:
+:
 |  right
-:
+:
 |  left
-:
+:
 |  pgup
-:
+:
 |  pgdn
-:
+:
 |  home
-:
+:
 |  end
-:
+:
 |  insert
-:
+:
 |  delete
-:
+:
 |  exit
-:
+:
 |  cancel
-:
+:
 |  print
-:
+:
 |  pause
-:
+:
 |  backtab
-:
+:
 |  c-space
 :  Ctrl+Space
 |  c-a
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()
+	})
 }
--
2.23.0
Details
Message ID
<BWXBF8LOA851.MQVC8CW8HMU7@homura>
In-Reply-To
<20190911163049.15090-1-dev@jeffas.io> (view parent)
DKIM signature
pass
Download raw message
No dice. Are you doing anything weird (e.g. not using git-send-email)
when preparing the patch?