mark: allow multiple visual selections

When entering visual selection mode, the current selection is deleted.
This patch extends the visual mode behavior to select multiple blocks of
messages.

Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
This commit is contained in:
Koni Marti 2022-08-08 22:21:44 +02:00 committed by Robin Jarry
parent 16dbb94221
commit b12dd9f926
4 changed files with 23 additions and 7 deletions

View file

@ -32,19 +32,23 @@ func (Mark) Execute(aerc *widgets.Aerc, args []string) error {
return err return err
} }
marker := store.Marker() marker := store.Marker()
opts, _, err := getopt.Getopts(args, "atv") opts, _, err := getopt.Getopts(args, "atvV")
if err != nil { if err != nil {
return err return err
} }
var all bool var all bool
var toggle bool var toggle bool
var visual bool var visual bool
var clearVisual bool
for _, opt := range opts { for _, opt := range opts {
switch opt.Option { switch opt.Option {
case 'a': case 'a':
all = true all = true
case 'v': case 'v':
visual = true visual = true
clearVisual = true
case 'V':
visual = true
case 't': case 't':
toggle = true toggle = true
} }
@ -70,7 +74,7 @@ func (Mark) Execute(aerc *widgets.Aerc, args []string) error {
} }
return nil return nil
case visual: case visual:
marker.ToggleVisualMark() marker.ToggleVisualMark(clearVisual)
return nil return nil
default: default:
modFunc(selected.Uid) modFunc(selected.Uid)

View file

@ -412,6 +412,8 @@ message list, the message in the message viewer, etc).
*-v*: Enter / leave visual mark mode *-v*: Enter / leave visual mark mode
*-V*: Same as -v but does not clear existing selection
*unmark* [-at] *unmark* [-at]
Unmarks messages. The flags below can be combined as needed. Unmarks messages. The flags below can be combined as needed.

View file

@ -8,7 +8,7 @@ type Marker interface {
Remark() Remark()
Marked() []uint32 Marked() []uint32
IsMarked(uint32) bool IsMarked(uint32) bool
ToggleVisualMark() ToggleVisualMark(bool)
UpdateVisualMark() UpdateVisualMark()
ClearVisualMark() ClearVisualMark()
} }
@ -25,6 +25,7 @@ type controller struct {
lastMarked map[uint32]struct{} lastMarked map[uint32]struct{}
visualStartUID uint32 visualStartUID uint32
visualMarkMode bool visualMarkMode bool
visualBase map[uint32]struct{}
} }
// New returns a new Marker // New returns a new Marker
@ -114,15 +115,21 @@ func (mc *controller) Marked() []uint32 {
} }
// ToggleVisualMark enters or leaves the visual marking mode // ToggleVisualMark enters or leaves the visual marking mode
func (mc *controller) ToggleVisualMark() { func (mc *controller) ToggleVisualMark(clear bool) {
mc.visualMarkMode = !mc.visualMarkMode mc.visualMarkMode = !mc.visualMarkMode
if mc.visualMarkMode { if mc.visualMarkMode {
// just entered visual mode, reset whatever marking was already done // just entered visual mode, reset whatever marking was already done
mc.resetMark() if clear {
mc.resetMark()
}
uids := mc.uidProvider.Uids() uids := mc.uidProvider.Uids()
if idx := mc.uidProvider.SelectedIndex(); idx >= 0 && idx < len(uids) { if idx := mc.uidProvider.SelectedIndex(); idx >= 0 && idx < len(uids) {
mc.visualStartUID = uids[idx] mc.visualStartUID = uids[idx]
mc.marked[mc.visualStartUID] = struct{}{} mc.marked[mc.visualStartUID] = struct{}{}
mc.visualBase = make(map[uint32]struct{})
for key, value := range mc.marked {
mc.visualBase[key] = value
}
} }
} }
} }
@ -160,7 +167,10 @@ func (mc *controller) UpdateVisualMark() {
} else { } else {
visUids = uids[selectedIdx : startIdx+1] visUids = uids[selectedIdx : startIdx+1]
} }
mc.resetMark() mc.marked = make(map[uint32]struct{})
for uid := range mc.visualBase {
mc.marked[uid] = struct{}{}
}
for _, uid := range visUids { for _, uid := range visUids {
mc.marked[uid] = struct{}{} mc.marked[uid] = struct{}{}
} }

View file

@ -90,7 +90,7 @@ func TestMarker_VisualMode(t *testing.T) {
m, up := createMarker() m, up := createMarker()
// activate visual mode // activate visual mode
m.ToggleVisualMark() m.ToggleVisualMark(false)
// marking should now fail silently because we're in visual mode // marking should now fail silently because we're in visual mode
m.Mark(1) m.Mark(1)