~sircmpwn/aerc

Add display of unread messages in dirlist v3 PROPOSED

Hi Jeffas,
This patch doesn't apply.

Greetings,
Reto
Nicolai Dagestad
It applied fine for me.

Sent with this patch applied and this sentence as a signature
Nicolai Dagestad
Sorry, I looked at the wrong patch...
This patch looks good, but does not apply.
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~sircmpwn/aerc/%3C20190907165326.17749-1-dev%40jeffas.io%3E/mbox | git am -3
Learn more about email & git

[PATCH v3] Add display of unread messages in dirlist Export this patch

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.
---
 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 33119dd..6337862 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++
 	}
 }
@@ -204,4 +298,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
Hi Jeffas,
This patch doesn't apply.

Greetings,
Reto
This patch looks good, but does not apply.
View this thread in the archives