~sircmpwn/aerc

de364846ccaba3b93c383add3846443048f1c2c9 — Drew DeVault 2 years ago 11f0a72
Display message subjects in message list
4 files changed, 71 insertions(+), 4 deletions(-)

M widgets/msglist.go
M widgets/spinner.go
A worker/imap/fetch.go
M worker/imap/worker.go
M widgets/msglist.go => widgets/msglist.go +22 -3
@@ 14,6 14,8 @@ import (
type MessageStore struct {
	DirInfo  types.DirectoryInfo
	Messages map[uint32]*types.MessageInfo
	// Ordered list of known UIDs
	Uids []uint32
	// Map of uids we've asked the worker to fetch
	onUpdate       func(store *MessageStore)
	pendingBodies  map[uint32]interface{}


@@ 67,9 69,11 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {
			}
		}
		store.Messages = newMap
		store.Uids = msg.Uids
		update = true
		break
	case *types.MessageInfo:
		// TODO: merge message info into existing record, if applicable
		store.Messages[msg.Uid] = msg
		if _, ok := store.pendingHeaders[msg.Uid]; msg.Envelope != nil && ok {
			delete(store.pendingHeaders, msg.Uid)


@@ 90,6 94,7 @@ type MessageList struct {
	conf         *config.AercConfig
	logger       *log.Logger
	onInvalidate func(d ui.Drawable)
	selected     int
	spinner      *Spinner
	store        *MessageStore
}


@@ 97,8 102,9 @@ type MessageList struct {
// TODO: fish in config
func NewMessageList(logger *log.Logger) *MessageList {
	ml := &MessageList{
		logger:  logger,
		spinner: NewSpinner(),
		logger:   logger,
		selected: 0,
		spinner:  NewSpinner(),
	}
	ml.spinner.OnInvalidate(func(_ ui.Drawable) {
		ml.Invalidate()


@@ 131,7 137,10 @@ func (ml *MessageList) Draw(ctx *ui.Context) {
		row          int = 0
	)

	for uid, msg := range ml.store.Messages {
	for i := len(ml.store.Uids) - 1; i >= 0; i-- {
		uid := ml.store.Uids[i]
		msg := ml.store.Messages[uid]

		if row >= ctx.Height() {
			break
		}


@@ 139,7 148,17 @@ func (ml *MessageList) Draw(ctx *ui.Context) {
		if msg == nil {
			needsHeaders = append(needsHeaders, uid)
			ml.spinner.Draw(ctx.Subcontext(0, row, ctx.Width(), 1))
			row += 1
			continue
		}

		style := tcell.StyleDefault
		if row == ml.selected {
			style = style.Background(tcell.ColorWhite).
				Foreground(tcell.ColorBlack)
		}
		ctx.Fill(0, row, ctx.Width(), 1, ' ', style)
		ctx.Printf(0, row, style, "%s", msg.Envelope.Subject)

		row += 1
	}

M widgets/spinner.go => widgets/spinner.go +1 -1
@@ 73,7 73,7 @@ func (s *Spinner) IsRunning() bool {

func (s *Spinner) Draw(ctx *ui.Context) {
	if !s.IsRunning() {
		return
		s.Start()
	}

	ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault)

A worker/imap/fetch.go => worker/imap/fetch.go +46 -0
@@ 0,0 1,46 @@
package imap

import (
	"github.com/emersion/go-imap"

	"git.sr.ht/~sircmpwn/aerc2/worker/types"
)

func (imapw *IMAPWorker) handleFetchMessageHeaders(
	msg *types.FetchMessageHeaders) {

	imapw.worker.Logger.Printf("Fetching message headers")

	go func() {
		messages := make(chan *imap.Message)
		done := make(chan error, 1)
		items := []imap.FetchItem{
			imap.FetchEnvelope,
			imap.FetchInternalDate,
			imap.FetchFlags,
			imap.FetchUid,
		}
		go func() {
			done <- imapw.client.UidFetch(&msg.Uids, items, messages)
		}()
		go func() {
			for msg := range messages {
				imapw.worker.PostMessage(&types.MessageInfo{
					Envelope:     msg.Envelope,
					Flags:        msg.Flags,
					InternalDate: msg.InternalDate,
					Uid:          msg.Uid,
				}, nil)
			}
			if err := <-done; err != nil {
				imapw.worker.PostMessage(&types.Error{
					Message: types.RespondTo(msg),
					Error:   err,
				}, nil)
			} else {
				imapw.worker.PostMessage(
					&types.Done{types.RespondTo(msg)}, nil)
			}
		}()
	}()
}

M worker/imap/worker.go => worker/imap/worker.go +2 -0
@@ 154,6 154,8 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error {
		w.handleOpenDirectory(msg)
	case *types.FetchDirectoryContents:
		w.handleFetchDirectoryContents(msg)
	case *types.FetchMessageHeaders:
		w.handleFetchMessageHeaders(msg)
	default:
		return errUnsupported
	}