Skip to content

Commit dc558c3

Browse files
committed
Implemented multiple choice for ListSelect dialog. You can now select multiple entry tags
1 parent 1c2727e commit dc558c3

File tree

2 files changed

+77
-23
lines changed

2 files changed

+77
-23
lines changed

dialog/list_select.go

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ const (
1212
listSelectViewName = "listSelectViewName"
1313
)
1414

15-
func ListSelect(gui *gocui.Gui, title string, slice interface{}) (
16-
<-chan int, CleanUpFunc, error,
15+
// Displays a list created from given slice / array.
16+
// If allowMultipleSelection is set, you can select multiple entries with space.
17+
func ListSelect(gui *gocui.Gui, title string, slice interface{}, allowMultipleSelection bool) (
18+
<-chan []int, CleanUpFunc, error,
1719
) {
1820
value := reflect.ValueOf(slice)
1921
if k := value.Kind(); k != reflect.Slice && k != reflect.Array {
@@ -27,7 +29,7 @@ func ListSelect(gui *gocui.Gui, title string, slice interface{}) (
2729
idxLen, _ := buf.WriteString(strconv.Itoa(i))
2830
buf.WriteByte('.')
2931
strBytes := []byte(fmt.Sprint(value.Index(i).Interface()))
30-
if bLen := len(strBytes) + idxLen + 1; bLen > listW {
32+
if bLen := len(strBytes) + idxLen + 2; bLen > listW {
3133
listW = bLen
3234
}
3335
buf.Write(strBytes)
@@ -36,14 +38,16 @@ func ListSelect(gui *gocui.Gui, title string, slice interface{}) (
3638
listW += 2
3739

3840
cleanUp := cleanUpFunc(gui, listSelectViewName)
39-
selectedIdx, v, err := listSelect(gui, title, listW, listH)
41+
selectedIdxes, v, err := listSelect(gui, title, listW, listH, allowMultipleSelection)
4042
if v != nil {
4143
buf.WriteTo(v)
4244
}
43-
return selectedIdx, cleanUp, err
45+
return selectedIdxes, cleanUp, err
4446
}
4547

46-
func listSelect(gui *gocui.Gui, title string, listW, listH int) (chan int, *gocui.View, error) {
48+
func listSelect(gui *gocui.Gui, title string, listW, listH int, multiSel bool) (
49+
chan []int, *gocui.View, error,
50+
) {
4751
w, h := gui.Size()
4852

4953
//TODO wrap list if list is too wide (handle moving up & down correctly)
@@ -68,9 +72,10 @@ func listSelect(gui *gocui.Gui, title string, listW, listH int) (chan int, *gocu
6872
v.Highlight = true
6973
v.Editable = true
7074

71-
selectedIdx := make(chan int)
75+
selectedIdxes := make(chan []int)
7276
chanClosed := false
7377

78+
idxs := make([]int, 0, listH)
7479
v.Editor = gocui.EditorFunc(func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
7580
switch {
7681
case key == gocui.KeyArrowDown || ch == 'j':
@@ -82,23 +87,55 @@ func listSelect(gui *gocui.Gui, title string, listW, listH int) (chan int, *gocu
8287
}
8388
case key == gocui.KeyArrowUp || ch == 'k':
8489
v.MoveCursor(0, -1, false)
85-
case key == gocui.KeyEnter:
86-
//TODO mutliple selection (color / highlight selected row) (buffered channels?)
90+
case key == gocui.KeySpace:
91+
if !multiSel {
92+
return
93+
}
8794
_, oy := v.Origin()
8895
_, y := v.Cursor()
8996
y += oy
97+
idxsIdx := -1
98+
for i, v := range idxs {
99+
if v == y {
100+
idxsIdx = i
101+
break
102+
}
103+
}
104+
v.SetCursor(0, y-oy)
105+
if idxsIdx != -1 {
106+
idxs = append(idxs[:idxsIdx], idxs[idxsIdx+1:]...)
107+
v.EditDelete(false)
108+
} else {
109+
idxs = append(idxs, y)
110+
v.EditWrite('*')
111+
}
112+
case key == gocui.KeyEnter:
90113
if !chanClosed {
91-
selectedIdx <- y
92-
close(selectedIdx)
114+
_, oy := v.Origin()
115+
_, y := v.Cursor()
116+
y += oy
117+
contains := false
118+
for _, v := range idxs {
119+
if v == y {
120+
contains = true
121+
break
122+
}
123+
}
124+
if !contains {
125+
idxs = append(idxs, y)
126+
}
127+
128+
selectedIdxes <- idxs
129+
close(selectedIdxes)
93130
chanClosed = true
94131
}
95132
case key == gocui.KeyCtrlQ || key == gocui.KeyEsc || ch == 'q':
96133
if !chanClosed {
97-
close(selectedIdx)
134+
close(selectedIdxes)
98135
chanClosed = true
99136
}
100137
}
101138
})
102139

103-
return selectedIdx, v, err
140+
return selectedIdxes, v, err
104141
}

nyaa_cui.go

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -345,30 +345,30 @@ func (nc *nyaaCui) LoadNextPage() {
345345
}
346346

347347
func (nc *nyaaCui) ChangeCategory() {
348-
selIdxChan, cleanUp, err := dialog.ListSelect(nc.Gui, "Select category", ns.Categories)
348+
selIdxChan, cleanUp, err := dialog.ListSelect(nc.Gui, "Select category", ns.Categories, false)
349349
if err != nil {
350350
gocuiReturnError(nc.Gui, err)
351351
}
352352
go func() {
353-
idx, ok := <-selIdxChan
353+
idxs, ok := <-selIdxChan
354354
nc.Gui.Update(cleanUp)
355355
if ok {
356-
nc.Category = ns.Categories[idx]
356+
nc.Category = ns.Categories[idxs[0]]
357357
nc.Reload()
358358
}
359359
}()
360360
}
361361

362362
func (nc *nyaaCui) ChangeFilter() {
363-
selIdxChan, cleanUp, err := dialog.ListSelect(nc.Gui, "Select filter", ns.Filters)
363+
selIdxChan, cleanUp, err := dialog.ListSelect(nc.Gui, "Select filter", ns.Filters, false)
364364
if err != nil {
365365
gocuiReturnError(nc.Gui, err)
366366
}
367367
go func() {
368-
idx, ok := <-selIdxChan
368+
idxs, ok := <-selIdxChan
369369
nc.Gui.Update(cleanUp)
370370
if ok {
371-
nc.Filter = ns.Filters[idx]
371+
nc.Filter = ns.Filters[idxs[0]]
372372
nc.Reload()
373373
}
374374
}()
@@ -391,18 +391,35 @@ func (nc *nyaaCui) FilterByTag() {
391391
sort.Strings(tags)
392392
tags[0] = "None"
393393

394-
selIdxChan, cleanUp, err := dialog.ListSelect(nc.Gui, "Select title filter", tags)
394+
selIdxChan, cleanUp, err := dialog.ListSelect(nc.Gui, "Select title filter", tags, true)
395395
if err != nil {
396396
gocuiReturnError(nc.Gui, err)
397397
}
398398
go func() {
399-
idx, ok := <-selIdxChan
399+
idxs, ok := <-selIdxChan
400400
nc.Gui.Update(cleanUp)
401401
if ok {
402-
if idx == 0 {
402+
containsNone := false
403+
for _, v := range idxs {
404+
if v == 0 {
405+
containsNone = true
406+
break
407+
}
408+
}
409+
if len(idxs) == 0 || containsNone {
403410
nc.TitleFilter = nil
404411
} else {
405-
regex, err := regexp.Compile("\\[" + regexp.QuoteMeta(tags[idx]) + "\\]")
412+
tagBuffer := strings.Builder{}
413+
for i, v := range idxs {
414+
tagBuffer.WriteString("\\[")
415+
tagBuffer.WriteString(regexp.QuoteMeta(tags[v]))
416+
tagBuffer.WriteString("\\]")
417+
if i < len(idxs)-1 {
418+
tagBuffer.WriteString("|")
419+
}
420+
}
421+
422+
regex, err := regexp.Compile(tagBuffer.String())
406423
if err != nil {
407424
gocuiReturnError(nc.Gui, err)
408425
}

0 commit comments

Comments
 (0)