~rjarry/aerc

e7c26e02bb326f08c071e9f37ebf80952a0cca97 — Koni Marti 2 months ago 05874f8
filter: allow workers to combine filter terms

Allow the backend workers to combine the filter terms. Currently, the
consecutive filters are joined in the message store with a space (" ").
This works well for most backends, but makes the filter combination for
notmuch confusing.

Example:

Issuing two consecutive filter commands in notmuch

	:filter not tag:list
	:filter tag:list

would create the following filter query

	'not tag:list tag:list'

This is not what users would expect; they expect:

	'(not tag:list) and (tag:list)'

Note that the notmuch backend works correctly for the given query, but
produced a query that does not match the user's expectation. This patch
fixes this.

The combination of filter terms in other backends remains the same.

Reported-by: Ángel Castañeda <angel@acsq.me>
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Tested-by: Inwit <inwit@sindominio.net>
Acked-by: Robin Jarry <robin@jarry.cc>
M commands/account/search.go => commands/account/search.go +1 -1
@@ 154,7 154,7 @@ func (s SearchFilter) Execute(args []string) error {
		EndDate:      s.EndDate,
		SearchBody:   s.Body,
		SearchAll:    s.All,
		Terms:        s.Terms,
		Terms:        []string{s.Terms},
	}

	if args[0] == "filter" {

M worker/imap/search.go => worker/imap/search.go +3 -1
@@ 1,6 1,8 @@
package imap

import (
	"strings"

	"github.com/emersion/go-imap"

	"git.sr.ht/~rjarry/aerc/worker/types"


@@ 33,7 35,7 @@ func translateSearch(c *types.SearchCriteria) *imap.SearchCriteria {
	for _, c := range c.Cc {
		criteria.Header.Add("Cc", c)
	}
	terms := opt.LexArgs(c.Terms)
	terms := opt.LexArgs(strings.Join(c.Terms, " "))
	if terms.Count() > 0 {
		switch {
		case c.SearchAll:

M worker/jmap/search.go => worker/jmap/search.go +6 -3
@@ 1,6 1,8 @@
package jmap

import (
	"strings"

	"git.sr.ht/~rjarry/aerc/worker/types"
	"git.sr.ht/~rockorager/go-jmap"
	"git.sr.ht/~rockorager/go-jmap/mail/email"


@@ 38,13 40,14 @@ func (w *JMAPWorker) translateSearch(
	}

	// general search terms
	terms := strings.Join(criteria.Terms, " ")
	switch {
	case criteria.SearchAll:
		cond.Text = criteria.Terms
		cond.Text = terms
	case criteria.SearchBody:
		cond.Body = criteria.Terms
		cond.Body = terms
	default:
		cond.Subject = criteria.Terms
		cond.Subject = terms
	}

	filter := &email.FilterOperator{Operator: jmap.OperatorAND}

M worker/lib/search.go => worker/lib/search.go +1 -1
@@ 108,7 108,7 @@ func SearchMessage(message rfc822.RawMessage, criteria *types.SearchCriteria,
		}
	}

	args := opt.LexArgs(criteria.Terms)
	args := opt.LexArgs(strings.Join(criteria.Terms, " "))
	for _, searchTerm := range args.Args() {
		if !containsSmartCase(text, searchTerm) {
			return false, nil

M worker/notmuch/search.go => worker/notmuch/search.go +6 -3
@@ 5,6 5,7 @@ package notmuch

import (
	"fmt"
	"strings"

	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/worker/types"


@@ 88,11 89,13 @@ func translate(crit *types.SearchCriteria) string {
	}

	// other terms
	if crit.Terms != "" {
	if len(crit.Terms) > 0 {
		if crit.SearchBody {
			base.and("body:" + opt.QuoteArg(crit.Terms))
			base.and("body:" + opt.QuoteArg(strings.Join(crit.Terms, " ")))
		} else {
			base.and(crit.Terms)
			for _, term := range crit.Terms {
				base.and(term)
			}
		}
	}


M worker/types/search.go => worker/types/search.go +2 -3
@@ 2,7 2,6 @@ package types

import (
	"net/textproto"
	"strings"
	"time"

	"git.sr.ht/~rjarry/aerc/models"


@@ 19,7 18,7 @@ type SearchCriteria struct {
	EndDate      time.Time
	SearchBody   bool
	SearchAll    bool
	Terms        string
	Terms        []string
}

func (c *SearchCriteria) PrepareHeader() {


@@ 79,6 78,6 @@ func (c *SearchCriteria) Combine(other *SearchCriteria) *SearchCriteria {
		EndDate:      end,
		SearchBody:   c.SearchBody || other.SearchBody,
		SearchAll:    c.SearchAll || other.SearchAll,
		Terms:        strings.Join([]string{c.Terms, other.Terms}, " "),
		Terms:        append(c.Terms, other.Terms...),
	}
}