~sircmpwn/aerc

Add display of unread messages in dirlist v5 PROPOSED

Jeffas: 1
 Add display of unread messages in dirlist

 5 files changed, 131 insertions(+), 4 deletions(-)
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/patches/8096/mbox | git am -3
Learn more about email & git
View this thread in the archives

[PATCH v5] 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 | 16 +++++++
 lib/msgstore.go       |  8 ++++
 widgets/dirlist.go    | 99 ++++++++++++++++++++++++++++++++++++++++++-
 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()
	})
}
--
2.23.0
Thanks!

To git.sr.ht:~sircmpwn/aerc
   572d9ff..618a500  master -> master