~rjarry/aerc-devel

aerc: search: add flag to select immediate next result v1 NEEDS REVISION

Koni Marti: 1
 search: add flag to select immediate next result

 3 files changed, 42 insertions(+), 48 deletions(-)
#1310091 alpine-edge.yml success
#1310092 openbsd.yml success
Hi Jason
Next
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/~rjarry/aerc-devel/patches/54661/mbox | git am -3
Learn more about email & git

[PATCH aerc] search: add flag to select immediate next result Export this patch

Add a -n flag to :search to select the immediate next search result from
the current position in the messsage list. If not set, the (current)
default behavior for :search is to jump to the very first search result.
The following example will select the immediate next unread message:

	:search -nu

Fixes: https://todo.sr.ht/~rjarry/aerc/168
Signed-off-by: Koni Marti <koni.marti@gmail.com>
---
 commands/account/search.go |  3 +-
 doc/aerc-search.1.scd      |  3 ++
 lib/msgstore.go            | 84 +++++++++++++++++---------------------
 3 files changed, 42 insertions(+), 48 deletions(-)

diff --git a/commands/account/search.go b/commands/account/search.go
index 5c2eaec7..dee52f06 100644
--- a/commands/account/search.go
+++ b/commands/account/search.go
@@ -24,6 +24,7 @@ type SearchFilter struct {
	Body         bool                 `opt:"-b"`
	All          bool                 `opt:"-a"`
	UseExtension bool                 `opt:"-e"`
	NextResult   bool                 `opt:"-n"`
	Headers      textproto.MIMEHeader `opt:"-H" action:"ParseHeader" metavar:"<header>:<value>"`
	WithFlags    models.Flags         `opt:"-x" action:"ParseFlag" complete:"CompleteFlag"`
	WithoutFlags models.Flags         `opt:"-X" action:"ParseNotFlag" complete:"CompleteFlag"`
@@ -194,7 +195,7 @@ func (s SearchFilter) Execute(args []string) error {
		cb := func(uids []uint32) {
			acct.SetStatus(state.Search(strings.Join(args, " ")))
			log.Tracef("Search results: %v", uids)
			store.ApplySearch(uids)
			store.ApplySearch(uids, s.NextResult)
			// TODO: Remove when stores have multiple OnUpdate handlers
			ui.Invalidate()
		}
diff --git a/doc/aerc-search.1.scd b/doc/aerc-search.1.scd
index 6ec4e53d..b2d83772 100644
--- a/doc/aerc-search.1.scd
+++ b/doc/aerc-search.1.scd
@@ -53,6 +53,9 @@ This syntax is common to all backends.
		(such as the X-GM-EXT if available). Search terms are expected
		in _<terms>_; other flags will be ignored.

	*-n*: Select the immediate next search result from the current position
		in the messsage list (only for *:search*).

	*-f* _<from>_: Search for messages from _<from>_

	*-t* _<to>_: Search for messages to _<to>_
diff --git a/lib/msgstore.go b/lib/msgstore.go
index 5c8b3ef1..6212bb31 100644
--- a/lib/msgstore.go
+++ b/lib/msgstore.go
@@ -44,9 +44,8 @@ type MessageStore struct {
	marker marker.Marker

	// Search/filter results
	results     []uint32
	resultIndex int
	filter      *types.SearchCriteria
	results map[uint32]struct{}
	filter  *types.SearchCriteria

	sortCriteria []*types.SortCriterion
	sortDefault  []*types.SortCriterion
@@ -125,6 +124,7 @@ func NewMessageStore(worker *types.Worker, name string,
		triggerFlagChanged:     triggerFlagChanged,

		onSelect: onSelect,
		results:  make(map[uint32]struct{}),
	}
}

@@ -356,6 +356,7 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {
			toDelete[uid] = nil
			delete(store.Messages, uid)
			delete(store.Deleted, uid)
			delete(store.results, uid)
		}
		uids := make([]uint32, 0, len(store.uids)-len(msg.Uids))
		for _, uid := range store.uids {
@@ -369,14 +370,6 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {
			store.Select(MagicUid)
		}

		var newResults []uint32
		for _, res := range store.results {
			if _, deleted := toDelete[res]; !deleted {
				newResults = append(newResults, res)
			}
		}
		store.results = newResults

		for uid := range toDelete {
			thread, err := store.Thread(uid)
			if err != nil {
@@ -833,7 +826,6 @@ func (store *MessageStore) NextPrev(delta int) {
	if store.marker != nil {
		store.marker.UpdateVisualMark()
	}
	store.updateResults()
}

func (store *MessageStore) Next() {
@@ -866,20 +858,31 @@ func (store *MessageStore) Search(terms *types.SearchCriteria, cb func([]uint32)
	})
}

func (store *MessageStore) ApplySearch(results []uint32) {
	store.results = results
	store.resultIndex = -1
	store.NextResult()
func (store *MessageStore) ApplySearch(results []uint32, nextResult bool) {
	if len(results) == 0 {
		return
	}
	store.results = make(map[uint32]struct{}, len(results))
	for _, u := range results {
		store.results[u] = struct{}{}
	}
	if nextResult {
		store.NextResult()
	} else if len(results) > 0 {
		it := store.iterFactory.NewIterator(results)
		idx := it.StartIndex()
		if store.ui().SelectLast {
			idx = it.EndIndex()
		}
		store.Select(results[idx])
		store.update(false)
	}
}

// IsResult returns true if uid is a search result
func (store *MessageStore) IsResult(uid uint32) bool {
	for _, hit := range store.results {
		if hit == uid {
			return true
		}
	}
	return false
	_, ok := store.results[uid]
	return ok
}

func (store *MessageStore) SetFilter(terms *types.SearchCriteria) {
@@ -895,36 +898,23 @@ func (store *MessageStore) ApplyClear() {
	store.Sort(store.sortDefault, nil)
}

func (store *MessageStore) updateResults() {
	if len(store.results) == 0 || store.resultIndex < 0 {
		return
	}
	uid := store.SelectedUid()
	for i, u := range store.results {
		if uid == u {
			store.resultIndex = i
			break
		}
	}
}

func (store *MessageStore) nextPrevResult(delta int) {
	if len(store.results) == 0 {
		return
	}
	iter := store.iterFactory.NewIterator(store.results)
	if store.resultIndex < 0 {
		store.resultIndex = iter.StartIndex()
	} else {
		store.resultIndex = iterator.MoveIndex(
			store.resultIndex,
			delta,
			iter,
			iterator.WrapBounds,
		)
	uids := store.Uids()
	iter := store.iterFactory.NewIterator(uids)
	nextIndex := store.SelectedIndex()
	for i := 0; i < len(uids); i++ {
		nextIndex = iterator.MoveIndex(nextIndex, delta, iter,
			iterator.WrapBounds)
		u := uids[nextIndex]
		if _, ok := store.results[u]; ok {
			store.Select(u)
			store.update(false)
			return
		}
	}
	store.Select(store.results[store.resultIndex])
	store.update(false)
}

func (store *MessageStore) NextResult() {
-- 
2.45.2
aerc/patches: SUCCESS in 1m55s

[search: add flag to select immediate next result][0] from [Koni Marti][1]

[0]: https://lists.sr.ht/~rjarry/aerc-devel/patches/54661
[1]: mailto:koni.marti@gmail.com

✓ #1310092 SUCCESS aerc/patches/openbsd.yml     https://builds.sr.ht/~rjarry/job/1310092
✓ #1310091 SUCCESS aerc/patches/alpine-edge.yml https://builds.sr.ht/~rjarry/job/1310091
Hi Koni,