store: keep current message selected

Keep current message selected when clearing or changing filters and when
toggling threads.

Add -s flag to the clear command to also clear the selected message and
set cursor to the top of the message list.

Implements: https://todo.sr.ht/~rjarry/aerc/36
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
This commit is contained in:
Koni Marti 2022-04-16 00:22:20 +02:00 committed by Robin Jarry
parent a34be9eb36
commit cb887a2d9d
4 changed files with 55 additions and 2 deletions

View File

@ -5,6 +5,7 @@ import (
"git.sr.ht/~rjarry/aerc/lib/statusline" "git.sr.ht/~rjarry/aerc/lib/statusline"
"git.sr.ht/~rjarry/aerc/widgets" "git.sr.ht/~rjarry/aerc/widgets"
"git.sr.ht/~sircmpwn/getopt"
) )
type Clear struct{} type Clear struct{}
@ -30,6 +31,30 @@ func (Clear) Execute(aerc *widgets.Aerc, args []string) error {
if store == nil { if store == nil {
return errors.New("Cannot perform action. Messages still loading") return errors.New("Cannot perform action. Messages still loading")
} }
clearSelected := false
opts, optind, err := getopt.Getopts(args, "s")
if err != nil {
return err
}
for _, opt := range opts {
switch opt.Option {
case 's':
clearSelected = true
}
}
if len(args) != optind {
return errors.New("Usage: clear [-s]")
}
if clearSelected {
defer store.Select(0)
} else {
defer store.Reselect(store.Selected())
}
store.ApplyClear() store.ApplyClear()
acct.SetStatus(statusline.SearchFilterClear()) acct.SetStatus(statusline.SearchFilterClear())

View File

@ -34,6 +34,7 @@ func (ToggleThreads) Execute(aerc *widgets.Aerc, args []string) error {
if err != nil { if err != nil {
return err return err
} }
defer store.Reselect(store.Selected())
store.SetBuildThreads(!store.BuildThreads()) store.SetBuildThreads(!store.BuildThreads())
acct.SetStatus(statusline.Threading(store.BuildThreads())) acct.SetStatus(statusline.Threading(store.BuildThreads()))
acct.Messages().Invalidate() acct.Messages().Invalidate()

View File

@ -216,9 +216,15 @@ message list, the message in the message viewer, etc).
## MESSAGE LIST COMMANDS ## MESSAGE LIST COMMANDS
*clear* *clear* [-s]
Clears the current search or filter criteria. Clears the current search or filter criteria.
By default, the selected message will be kept. To clear the selected
message and move cursor to the top of the message list, use the -s flag.
*-s*
Selects the message at the top of the message list after clearing.
*cf* <folder> *cf* <folder>
Change the folder shown in the message list. Change the folder shown in the message list.

View File

@ -472,7 +472,12 @@ func (store *MessageStore) Uids() []uint32 {
} }
func (store *MessageStore) Selected() *models.MessageInfo { func (store *MessageStore) Selected() *models.MessageInfo {
return store.Messages[store.Uids()[len(store.Uids())-store.selected-1]] uids := store.Uids()
idx := len(uids) - store.selected - 1
if len(uids) == 0 || idx < 0 || idx >= len(uids) {
return nil
}
return store.Messages[uids[idx]]
} }
func (store *MessageStore) SelectedIndex() int { func (store *MessageStore) SelectedIndex() int {
@ -490,6 +495,21 @@ func (store *MessageStore) Select(index int) {
store.updateVisual() store.updateVisual()
} }
func (store *MessageStore) Reselect(info *models.MessageInfo) {
if info == nil {
return
}
uid := info.Uid
newIdx := 0
for idx, uidStore := range store.Uids() {
if uidStore == uid {
newIdx = len(store.Uids()) - idx - 1
break
}
}
store.Select(newIdx)
}
// Mark sets the marked state on a MessageInfo // Mark sets the marked state on a MessageInfo
func (store *MessageStore) Mark(uid uint32) { func (store *MessageStore) Mark(uid uint32) {
if store.visualMarkMode { if store.visualMarkMode {
@ -660,6 +680,7 @@ func (store *MessageStore) ApplySearch(results []uint32) {
} }
func (store *MessageStore) ApplyFilter(results []uint32) { func (store *MessageStore) ApplyFilter(results []uint32) {
defer store.Reselect(store.Selected())
store.results = nil store.results = nil
store.filtered = results store.filtered = results
store.filter = true store.filter = true