-
Notifications
You must be signed in to change notification settings - Fork 5
/
menu.go
97 lines (89 loc) · 1.89 KB
/
menu.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package activekit
import (
"bufio"
"fmt"
"os"
"sync"
"strings"
)
type Menu struct {
Title string
Promt string
History []string
Items MenuItems
CustomOptionHandler func(string) error
once sync.Once
}
type MenuItem struct {
Label string
Action func() error
}
func (item *MenuItem) String() string {
return item.Label
}
func (menu *Menu) init() {
menu.once.Do(func() {
if menu.History == nil {
menu.History = make([]string, 0, 16)
}
if menu.Title == "" {
menu.Title = "What's next?"
}
if menu.Promt == "" {
menu.Promt = "Choose wisely: "
}
menu.Items = menu.Items.NotNil()
})
}
func (menu *Menu) scanLine() (string, error) {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
if err := scanner.Err(); err != nil {
return "", err
}
if scanner.Text() == "" {
continue
}
return scanner.Text(), nil
}
return "", nil
}
func (menu *Menu) Run() (*MenuItem, error) {
menu.init()
optionSet := map[string]int{}
for i, item := range menu.Items {
optionSet[item.Label] = i
}
for {
fmt.Printf("%s\n", menu.Title)
for i, item := range menu.Items {
fmt.Printf("%d) %s\n", i+1, item.String())
}
fmt.Printf("%s", menu.Promt)
input, err := menu.scanLine()
if err != nil {
return nil, err
}
input = strings.TrimSpace(input)
if ind, ok := optionSet[input]; ok {
item := menu.Items[ind]
if item.Action == nil {
return item, nil
}
return item, item.Action()
}
ind := 0
if _, err = fmt.Sscan(input, &ind); err == nil && (ind > 0 && ind <= len(menu.Items)) {
item := menu.Items[ind-1] // -1 is very important, do not change!
if item.Action == nil {
return item, nil
}
return item, item.Action()
}
if menu.CustomOptionHandler == nil {
fmt.Printf("Option %q not found\n", input)
} else {
return nil, menu.CustomOptionHandler(input)
}
}
}