~sircmpwn/aerc

94b9d557dee0fd13853b1883cc2730c5cbdbcd3f — Reto Brunner 1 year, 4 months ago ac99d9e
extract search criteria parsing into the backends
M Makefile => Makefile +2 -0
@@ 28,6 28,7 @@ aerc.conf: config/aerc.conf.in

DOCS := \
	aerc.1 \
	aerc-search.1 \
	aerc-config.5 \
	aerc-imap.5 \
	aerc-maildir.5 \


@@ 60,6 61,7 @@ install: all
		$(SHAREDIR) $(SHAREDIR)/filters
	install -m755 aerc $(BINDIR)/aerc
	install -m644 aerc.1 $(MANDIR)/man1/aerc.1
	install -m644 aerc-search.1 $(MANDIR)/man1/aerc-search.1
	install -m644 aerc-config.5 $(MANDIR)/man5/aerc-config.5
	install -m644 aerc-imap.5 $(MANDIR)/man5/aerc-imap.5
	install -m644 aerc-maildir.5 $(MANDIR)/man5/aerc-maildir.5

M commands/account/search.go => commands/account/search.go +1 -26
@@ 3,9 3,6 @@ package account
import (
	"errors"

	"git.sr.ht/~sircmpwn/getopt"
	"github.com/emersion/go-imap"

	"git.sr.ht/~sircmpwn/aerc/widgets"
)



@@ 24,28 21,6 @@ func (_ SearchFilter) Complete(aerc *widgets.Aerc, args []string) []string {
}

func (_ SearchFilter) Execute(aerc *widgets.Aerc, args []string) error {
	var (
		criteria *imap.SearchCriteria = imap.NewSearchCriteria()
	)

	opts, optind, err := getopt.Getopts(args, "ruH:")
	if err != nil {
		return err
	}
	for _, opt := range opts {
		switch opt.Option {
		case 'r':
			criteria.WithFlags = append(criteria.WithFlags, imap.SeenFlag)
		case 'u':
			criteria.WithoutFlags = append(criteria.WithoutFlags, imap.SeenFlag)
		case 'H':
			// TODO
		}
	}
	for _, arg := range args[optind:] {
		criteria.Header.Add("Subject", arg)
	}

	acct := aerc.SelectedAccount()
	if acct == nil {
		return errors.New("No account selected")


@@ 73,6 48,6 @@ func (_ SearchFilter) Execute(aerc *widgets.Aerc, args []string) error {
			acct.Messages().Scroll()
		}
	}
	store.Search(criteria, cb)
	store.Search(args, cb)
	return nil
}

A doc/aerc-search.1.scd => doc/aerc-search.1.scd +11 -0
@@ 0,0 1,11 @@
aerc-search(1)

# IMAP

*search* [-ru] <terms...>
	Searches the current folder for <terms>. Each separate term is searched
	case-insensitively among subject lines.

	*-r*: Search for read messages

	*-u*: Search for unread messages

M doc/aerc.1.scd => doc/aerc.1.scd +4 -7
@@ 175,13 175,10 @@ message list, the message in the message viewer, etc).
*next-result*, *prev-result*
	Selects the next or previous search result.

*search* [-ru] <terms...>
	Searches the current folder for <terms>. Each separate term is searched
	case-insensitively among subject lines.

	*-r*: Search for read messages

	*-u*: Search for unread messages
*search*
	Searches the current folder.
	The search syntax is dependant on the underlying backend.
	Refer to *aerc-search*(1) for details

*select* <n>
	Selects the nth message in the message list (and scrolls it into view if

M lib/msgstore.go => lib/msgstore.go +2 -4
@@ 4,8 4,6 @@ import (
	"io"
	"time"

	"github.com/emersion/go-imap"

	"git.sr.ht/~sircmpwn/aerc/models"
	"git.sr.ht/~sircmpwn/aerc/worker/types"
)


@@ 368,9 366,9 @@ func (store *MessageStore) Prev() {
	store.NextPrev(-1)
}

func (store *MessageStore) Search(c *imap.SearchCriteria, cb func([]uint32)) {
func (store *MessageStore) Search(args []string, cb func([]uint32)) {
	store.worker.PostAction(&types.SearchDirectory{
		Criteria: c,
		Argv: args,
	}, func(msg types.WorkerMessage) {
		switch msg := msg.(type) {
		case *types.SearchResults:

M worker/imap/list.go => worker/imap/list.go +20 -8
@@ 52,17 52,29 @@ func canOpen(mbox *imap.MailboxInfo) bool {
}

func (imapw *IMAPWorker) handleSearchDirectory(msg *types.SearchDirectory) {
	imapw.worker.Logger.Println("Executing search")

	if uids, err := imapw.client.UidSearch(msg.Criteria); err != nil {
	emitError := func(err error) {
		imapw.worker.PostMessage(&types.Error{
			Message: types.RespondTo(msg),
			Error:   err,
		}, nil)
	} else {
		imapw.worker.PostMessage(&types.SearchResults{
			Message: types.RespondTo(msg),
			Uids:    uids,
		}, nil)
	}

	imapw.worker.Logger.Println("Executing search")
	criteria, err := parseSearch(msg.Argv)
	if err != nil {
		emitError(err)
		return
	}

	uids, err := imapw.client.UidSearch(criteria)
	if err != nil {
		emitError(err)
		return
	}

	imapw.worker.PostMessage(&types.SearchResults{
		Message: types.RespondTo(msg),
		Uids:    uids,
	}, nil)

}

A worker/imap/search.go => worker/imap/search.go +29 -0
@@ 0,0 1,29 @@
package imap

import (
	"git.sr.ht/~sircmpwn/getopt"
	"github.com/emersion/go-imap"
)

func parseSearch(args []string) (*imap.SearchCriteria, error) {
	criteria := imap.NewSearchCriteria()

	opts, optind, err := getopt.Getopts(args, "ruH:")
	if err != nil {
		return nil, err
	}
	for _, opt := range opts {
		switch opt.Option {
		case 'r':
			criteria.WithFlags = append(criteria.WithFlags, imap.SeenFlag)
		case 'u':
			criteria.WithoutFlags = append(criteria.WithoutFlags, imap.SeenFlag)
		case 'H':
			// TODO
		}
	}
	for _, arg := range args[optind:] {
		criteria.Header.Add("Subject", arg)
	}
	return criteria, nil
}

M worker/types/messages.go => worker/types/messages.go +1 -3
@@ 4,8 4,6 @@ import (
	"io"
	"time"

	"github.com/emersion/go-imap"

	"git.sr.ht/~sircmpwn/aerc/config"
	"git.sr.ht/~sircmpwn/aerc/models"
)


@@ 84,7 82,7 @@ type FetchDirectoryContents struct {

type SearchDirectory struct {
	Message
	Criteria *imap.SearchCriteria
	Argv []string
}

type CreateDirectory struct {