1
0
Fork 0
mirror of https://git.sr.ht/~rjarry/aerc synced 2025-02-22 23:23:57 +01:00
aerc/worker/notmuch/search.go
Robin Jarry 3c9ad93801 completion: display descriptions next to choices
Use go-opt v2 new completion API which returns items descriptions along
with their text values.

Display the descriptions after the items separated by two spaces. Wrap
the descriptions in parentheses to better indicate that they are not
part of the completion choices. Limit the description length to 80
characters to avoid display issues.

Add a new style object completion_description in stylesets. By default,
the object will be rendered with a dimmed terminal attribute. Update all
stylesets and documentation accordingly.

Implements: https://todo.sr.ht/~rjarry/aerc/271
Link: https://git.sr.ht/~rjarry/go-opt/commit/ebeb82538395a
Changelog-added: Command completion now displays descriptions next
 to completion items.
Changelog-added: New `completion_description` style object in style
 sets used for rendering completion item descriptions.
Signed-off-by: Robin Jarry <robin@jarry.cc>
Tested-by: Bojan Gabric <bojan@bojangabric.com>
Tested-by: Jason Cox <me@jasoncarloscox.com>
Acked-by: Tim Culverhouse <tim@timculverhouse.com>
2024-10-23 10:22:51 +02:00

111 lines
1.9 KiB
Go

//go:build notmuch
// +build notmuch
package notmuch
import (
"fmt"
"strings"
"git.sr.ht/~rjarry/aerc/models"
"git.sr.ht/~rjarry/aerc/worker/types"
"git.sr.ht/~rjarry/go-opt/v2"
)
type queryBuilder struct {
s string
}
func (q *queryBuilder) and(s string) {
if len(s) == 0 {
return
}
if len(q.s) != 0 {
q.s += " and "
}
q.s += "(" + s + ")"
}
func (q *queryBuilder) or(s string) {
if len(s) == 0 {
return
}
if len(q.s) != 0 {
q.s += " or "
}
q.s += "(" + s + ")"
}
func translate(crit *types.SearchCriteria) string {
if crit == nil {
return ""
}
var base queryBuilder
// recipients
var from queryBuilder
for _, f := range crit.From {
from.or("from:" + opt.QuoteArg(f))
}
if from.s != "" {
base.and(from.s)
}
var to queryBuilder
for _, t := range crit.To {
to.or("to:" + opt.QuoteArg(t))
}
if to.s != "" {
base.and(to.s)
}
var cc queryBuilder
for _, c := range crit.Cc {
cc.or("cc:" + opt.QuoteArg(c))
}
if cc.s != "" {
base.and(cc.s)
}
// flags
for f := range flagToTag {
if crit.WithFlags.Has(f) {
base.and(getParsedFlag(f, false))
}
if crit.WithoutFlags.Has(f) {
base.and(getParsedFlag(f, true))
}
}
// dates
switch {
case !crit.StartDate.IsZero() && !crit.EndDate.IsZero():
base.and(fmt.Sprintf("date:@%d..@%d",
crit.StartDate.Unix(), crit.EndDate.Unix()))
case !crit.StartDate.IsZero():
base.and(fmt.Sprintf("date:@%d..", crit.StartDate.Unix()))
case !crit.EndDate.IsZero():
base.and(fmt.Sprintf("date:..@%d", crit.EndDate.Unix()))
}
// other terms
if len(crit.Terms) > 0 {
if crit.SearchBody {
base.and("body:" + opt.QuoteArg(strings.Join(crit.Terms, " ")))
} else {
for _, term := range crit.Terms {
base.and(term)
}
}
}
return base.s
}
func getParsedFlag(flag models.Flags, inverse bool) string {
name := "tag:" + flagToTag[flag]
if flagToInvert[flag] {
name = "not " + name
}
return name
}