diff options
-rw-r--r-- | lib/msgstore.go | 131 |
1 files changed, 127 insertions, 4 deletions
diff --git a/lib/msgstore.go b/lib/msgstore.go index 2a9ea86..9075a26 100644 --- a/lib/msgstore.go +++ b/lib/msgstore.go @@ -21,6 +21,11 @@ type MessageStore struct { bodyCallbacks map[uint32][]func(io.Reader) headerCallbacks map[uint32][]func(*types.MessageInfo) + //marking + marked map[uint32]struct{} + visualStartUid uint32 + visualMarkMode bool + // Search/filter results results []uint32 resultIndex int @@ -51,6 +56,7 @@ func NewMessageStore(worker *types.Worker, Messages: make(map[uint32]*models.MessageInfo), selected: 0, + marked: make(map[uint32]struct{}), bodyCallbacks: make(map[uint32][]func(io.Reader)), headerCallbacks: make(map[uint32][]func(*types.MessageInfo)), @@ -223,6 +229,7 @@ func (store *MessageStore) Update(msg types.WorkerMessage) { toDelete[uid] = nil delete(store.Messages, uid) delete(store.Deleted, uid) + delete(store.marked, uid) } uids := make([]uint32, len(store.uids)-len(msg.Uids)) j := 0 @@ -345,12 +352,114 @@ func (store *MessageStore) SelectedIndex() int { func (store *MessageStore) Select(index int) { uids := store.Uids() store.selected = index - for ; store.selected < 0; store.selected = len(uids) + store.selected { - /* This space deliberately left blank */ - } - if store.selected > len(uids) { + if store.selected < 0 { + store.selected = len(uids) - 1 + } else if 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) { @@ -365,6 +474,7 @@ func (store *MessageStore) NextPrev(delta int) { if store.selected >= len(uids) { store.selected = len(uids) - 1 } + store.updateVisual() nextResultIndex := len(store.results) - store.resultIndex - 2*delta if nextResultIndex < 0 || nextResultIndex >= len(store.results) { return @@ -406,6 +516,9 @@ func (store *MessageStore) ApplyFilter(results []uint32) { store.results = results store.filter = true store.update() + // any marking is now invalid + // TODO: could save that probably + store.ClearVisualMark() } func (store *MessageStore) ApplyClear() { @@ -457,3 +570,13 @@ func (store *MessageStore) Sort(criteria []*types.SortCriterion, cb func()) { 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 +} |