/
keyboard_widget.go
167 lines (134 loc) · 4.56 KB
/
keyboard_widget.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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
package view
import (
"fmt"
"github.com/gdamore/tcell/v2"
"github.com/wtfutil/wtf/cfg"
"github.com/wtfutil/wtf/utils"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)
const helpKeyChar = "/"
const refreshKeyChar = "r"
type helpItem struct {
Key string
Text string
}
// KeyboardWidget manages keyboard control for a widget
type KeyboardWidget struct {
settings *cfg.Common
charMap map[string]func()
keyMap map[tcell.Key]func()
charHelp []helpItem
keyHelp []helpItem
maxKey int
}
// NewKeyboardWidget creates and returns a new instance of KeyboardWidget
// func NewKeyboardWidget(tviewApp *tview.Application, pages *tview.Pages, settings *cfg.Common) *KeyboardWidget {
func NewKeyboardWidget(settings *cfg.Common) *KeyboardWidget {
keyWidget := &KeyboardWidget{
settings: settings,
charMap: make(map[string]func()),
keyMap: make(map[tcell.Key]func()),
charHelp: []helpItem{},
keyHelp: []helpItem{},
}
keyWidget.initializeCommonKeyboardControls()
return keyWidget
}
/* -------------------- Exported Functions --------------------- */
// AssignedChars returns a list of all the text characters assigned to an operation
func (widget *KeyboardWidget) AssignedChars() []string {
chars := []string{}
for char := range widget.charMap {
chars = append(chars, char)
}
return chars
}
// HelpText returns the help text and keyboard command info for this widget
func (widget *KeyboardWidget) HelpText() string {
c := cases.Title(language.English)
str := " [green::b]Keyboard commands for " + c.String(widget.settings.Module.Type) + "[white]\n\n"
for _, item := range widget.charHelp {
str += fmt.Sprintf(" %s\t%s\n", item.Key, item.Text)
}
str += "\n\n"
for _, item := range widget.keyHelp {
str += fmt.Sprintf(" %-*s\t%s\n", widget.maxKey, item.Key, item.Text)
}
return str
}
// InitializeHelpTextKeyboardControl assigns the function that displays help text to the
// common help text key value
func (widget *KeyboardWidget) InitializeHelpTextKeyboardControl(helpFunc func()) {
if helpFunc != nil {
widget.SetKeyboardChar(helpKeyChar, helpFunc, "Show/hide this help prompt")
}
}
// InitializeRefreshKeyboardControl assigns the module's explicit refresh function to
// the commom refresh key value
func (widget *KeyboardWidget) InitializeRefreshKeyboardControl(refreshFunc func()) {
if refreshFunc != nil {
widget.SetKeyboardChar(refreshKeyChar, refreshFunc, "Refresh widget")
}
}
// InputCapture is the function passed to tview's SetInputCapture() function
// This is done during the main widget's creation process using the following code:
//
// widget.View.SetInputCapture(widget.InputCapture)
func (widget *KeyboardWidget) InputCapture(event *tcell.EventKey) *tcell.EventKey {
if event == nil {
return nil
}
fn := widget.charMap[string(event.Rune())]
if fn != nil {
fn()
return nil
}
fn = widget.keyMap[event.Key()]
if fn != nil {
fn()
return nil
}
return event
}
// LaunchDocumentation opens the module docs in a browser
func (widget *KeyboardWidget) LaunchDocumentation() {
path := widget.settings.DocPath
if path == "" {
path = widget.settings.Type
}
url := "https://wtfutil.com/modules/" + path
utils.OpenFile(url)
}
// SetKeyboardChar sets a character/function combination that responds to key presses
// Example:
//
// widget.SetKeyboardChar("d", widget.deleteSelectedItem)
func (widget *KeyboardWidget) SetKeyboardChar(char string, fn func(), helpText string) {
if char == "" {
return
}
// Check to ensure that the key trying to be used isn't already being used for something
if _, ok := widget.charMap[char]; ok {
panic(fmt.Sprintf("Key is already mapped to a keyboard command: %s\n", char))
}
widget.charMap[char] = fn
widget.charHelp = append(widget.charHelp, helpItem{char, helpText})
}
// SetKeyboardKey sets a tcell.Key/function combination that responds to key presses
// Example:
//
// widget.SetKeyboardKey(tcell.KeyCtrlD, widget.deleteSelectedItem)
func (widget *KeyboardWidget) SetKeyboardKey(key tcell.Key, fn func(), helpText string) {
widget.keyMap[key] = fn
widget.keyHelp = append(widget.keyHelp, helpItem{tcell.KeyNames[key], helpText})
if len(tcell.KeyNames[key]) > widget.maxKey {
widget.maxKey = len(tcell.KeyNames[key])
}
}
/* -------------------- Unexported Functions -------------------- */
// initializeCommonKeyboardControls sets up the keyboard controls that are common to
// all widgets that accept keyboard input
func (widget *KeyboardWidget) initializeCommonKeyboardControls() {
widget.SetKeyboardChar("\\", widget.LaunchDocumentation, "Open the documentation for this module in a browser")
}