msgstore: add marking functionality

This commit is contained in:
Reto Brunner 2019-12-18 06:33:59 +01:00 committed by Drew DeVault
parent 3e535f49b3
commit cf43066d5b
1 changed files with 127 additions and 4 deletions

View File

@ -21,6 +21,11 @@ type MessageStore struct {
bodyCallbacks map[uint32][]func(io.Reader) bodyCallbacks map[uint32][]func(io.Reader)
headerCallbacks map[uint32][]func(*types.MessageInfo) headerCallbacks map[uint32][]func(*types.MessageInfo)
//marking
marked map[uint32]struct{}
visualStartUid uint32
visualMarkMode bool
// Search/filter results // Search/filter results
results []uint32 results []uint32
resultIndex int resultIndex int
@ -51,6 +56,7 @@ func NewMessageStore(worker *types.Worker,
Messages: make(map[uint32]*models.MessageInfo), Messages: make(map[uint32]*models.MessageInfo),
selected: 0, selected: 0,
marked: make(map[uint32]struct{}),
bodyCallbacks: make(map[uint32][]func(io.Reader)), bodyCallbacks: make(map[uint32][]func(io.Reader)),
headerCallbacks: make(map[uint32][]func(*types.MessageInfo)), headerCallbacks: make(map[uint32][]func(*types.MessageInfo)),
@ -223,6 +229,7 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {
toDelete[uid] = nil toDelete[uid] = nil
delete(store.Messages, uid) delete(store.Messages, uid)
delete(store.Deleted, uid) delete(store.Deleted, uid)
delete(store.marked, uid)
} }
uids := make([]uint32, len(store.uids)-len(msg.Uids)) uids := make([]uint32, len(store.uids)-len(msg.Uids))
j := 0 j := 0
@ -345,12 +352,114 @@ func (store *MessageStore) SelectedIndex() int {
func (store *MessageStore) Select(index int) { func (store *MessageStore) Select(index int) {
uids := store.Uids() uids := store.Uids()
store.selected = index store.selected = index
for ; store.selected < 0; store.selected = len(uids) + store.selected { if store.selected < 0 {
/* This space deliberately left blank */ store.selected = len(uids) - 1
} } else if store.selected > len(uids) {
if store.selected > len(uids) {
store.selected = len(uids) store.selected = len(uids)
} }
store.updateVisual()
}
// Mark sets the marked state on a MessageInfo
func (store *MessageStore) Mark(uid uint32) {
if store.visualMarkMode {
// visual mode has override, bogus input from user
return
}
store.marked[uid] = struct{}{}
}
// Unmark removes the marked state on a MessageInfo
func (store *MessageStore) Unmark(uid uint32) {
if store.visualMarkMode {
// user probably wanted to clear the visual marking
store.ClearVisualMark()
return
}
delete(store.marked, uid)
}
// ToggleMark toggles the marked state on a MessageInfo
func (store *MessageStore) ToggleMark(uid uint32) {
if store.visualMarkMode {
// visual mode has override, bogus input from user
return
}
if store.IsMarked(uid) {
store.Unmark(uid)
} else {
store.Mark(uid)
}
}
// resetMark removes the marking from all messages
func (store *MessageStore) resetMark() {
store.marked = make(map[uint32]struct{})
}
//IsMarked checks whether a MessageInfo has been marked
func (store *MessageStore) IsMarked(uid uint32) bool {
_, marked := store.marked[uid]
return marked
}
//ToggleVisualMark enters or leaves the visual marking mode
func (store *MessageStore) ToggleVisualMark() {
store.visualMarkMode = !store.visualMarkMode
switch store.visualMarkMode {
case true:
// just entered visual mode, reset whatever marking was already done
store.resetMark()
store.visualStartUid = store.Selected().Uid
store.marked[store.visualStartUid] = struct{}{}
case false:
// visual mode ended, nothing to do
return
}
}
//ClearVisualMark leaves the visual marking mode and resets any marking
func (store *MessageStore) ClearVisualMark() {
store.resetMark()
store.visualMarkMode = false
store.visualStartUid = 0
}
// Marked returns the uids of all marked messages
func (store *MessageStore) Marked() []uint32 {
marked := make([]uint32, len(store.marked))
i := 0
for uid := range store.marked {
marked[i] = uid
i++
}
return marked
}
func (store *MessageStore) updateVisual() {
if !store.visualMarkMode {
// nothing to do
return
}
startIdx := store.visualStartIdx()
if startIdx < 0 {
// something deleted the startuid, abort the marking process
store.ClearVisualMark()
return
}
uidLen := len(store.Uids())
// store.selected is the inverted form of the actual array
selectedIdx := uidLen - store.selected - 1
var visUids []uint32
if selectedIdx > startIdx {
visUids = store.Uids()[startIdx : selectedIdx+1]
} else {
visUids = store.Uids()[selectedIdx : startIdx+1]
}
store.resetMark()
for _, uid := range visUids {
store.marked[uid] = struct{}{}
}
} }
func (store *MessageStore) NextPrev(delta int) { func (store *MessageStore) NextPrev(delta int) {
@ -365,6 +474,7 @@ func (store *MessageStore) NextPrev(delta int) {
if store.selected >= len(uids) { if store.selected >= len(uids) {
store.selected = len(uids) - 1 store.selected = len(uids) - 1
} }
store.updateVisual()
nextResultIndex := len(store.results) - store.resultIndex - 2*delta nextResultIndex := len(store.results) - store.resultIndex - 2*delta
if nextResultIndex < 0 || nextResultIndex >= len(store.results) { if nextResultIndex < 0 || nextResultIndex >= len(store.results) {
return return
@ -406,6 +516,9 @@ func (store *MessageStore) ApplyFilter(results []uint32) {
store.results = results store.results = results
store.filter = true store.filter = true
store.update() store.update()
// any marking is now invalid
// TODO: could save that probably
store.ClearVisualMark()
} }
func (store *MessageStore) ApplyClear() { func (store *MessageStore) ApplyClear() {
@ -457,3 +570,13 @@ func (store *MessageStore) Sort(criteria []*types.SortCriterion, cb func()) {
cb() cb()
}) })
} }
// returns the index of needle in haystack or -1 if not found
func (store *MessageStore) visualStartIdx() int {
for idx, u := range store.Uids() {
if u == store.visualStartUid {
return idx
}
}
return -1
}