-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhelp.go
179 lines (147 loc) · 4.97 KB
/
help.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
168
169
170
171
172
173
174
175
176
177
178
179
package main
import (
"bytes"
"fmt"
"log"
"regexp"
"slices"
"strings"
"text/template"
"github.com/rivo/tview"
)
// merges the default keybindings with the user's customized keybindings.
//
// Example: "Ctrl+S": ["save"]
//
// Do not use outside of the context of documentation, because this will also
// modify things like Rune[x] to render properly within a dynamically colored
// textview. For example, Rune[x] will transform to Rune[x[].
func GetCombinedKeybindings(kb map[string][]string, def map[string]string) map[string][]string {
r := make(map[string][]string)
reg := regexp.MustCompile(`^Rune\[.\]$`)
for k, v := range def {
if reg.MatchString(k) {
r[strings.Replace(k, "]", "[]", 1)] = []string{v}
continue
}
r[k] = []string{v}
}
for k, v := range kb {
if reg.MatchString(k) {
r[strings.Replace(k, "]", "[]", 1)] = v
continue
}
// delete the old keybinding and reformat it to show that it's customized
formattedKeybinding := fmt.Sprintf("[gold::b]%v[-:-:-:-]", k)
delete(r, k)
r[formattedKeybinding] = v
}
return r
}
// merges the default keybindings with the user's customized keybindings, except
// unlike GetCombinedKeybindings, this will list every Action as the primary map
// key, and the keybindings are the map values. There may be multiple
// keybindings for a single action. In the event that there is a chained
// keybinding, such as Ctrl+X mapping to save+quit, the keybinding will be
// rendered lightgreen instead of gold (which is the norm for custom
// keybindings).
//
// Example: "save": []string{"[lightgreen]Ctrl+X[-]", "Ctrl+S"}
//
// Keybindings are inserted in order of priority - custom keybindings will be at
// the 0-based index of the slice, so that various UI elements can quickly
// render the last-defined keybinding (not all UI elements have the space to
// show every keybinding. Plus, the help file shows all defined keybindings).
//
// Do not use outside of the context of documentation, because this will also
// modify things like Rune[x] to render properly within a dynamically colored
// textview. For example, Rune[x] will transform to Rune[x[].
func GetAllBoundActions(kb map[string][]string, def map[string]string) map[string][]string {
r := make(map[string][]string)
reg := regexp.MustCompile(`^Rune\[.\]$`)
// handle default actions first
for binding, action := range def {
fixedBinding := binding
if reg.MatchString(fixedBinding) {
fixedBinding = strings.Replace(fixedBinding, "]", "[]", 1)
}
r[action] = []string{fixedBinding}
}
// higlight custom key bindings next
for binding, actions := range kb {
color := "gold"
if len(actions) > 1 {
color = "#aaffee"
}
fixedBinding := binding
if reg.MatchString(fixedBinding) {
fixedBinding = strings.Replace(fixedBinding, "]", "[]", 1)
}
formattedBinding := fmt.Sprintf("[%v::b]%v[-:-:-:-]", color, fixedBinding)
for _, action := range actions {
r[action] = slices.Insert(r[action], 0, formattedBinding)
}
}
return r
}
func getHelpText(conf Config, combinedKeybindings, combinedActions map[string][]string) string {
type tmplDataShape struct {
Conf Config
AllActions []string
DefaultKeybindings map[string]string
CombinedKeybindings map[string][]string
CombinedActions map[string][]string
Explanations map[string]string
}
tmplData := tmplDataShape{
Conf: conf,
AllActions: AllActions,
DefaultKeybindings: DefaultMappings,
CombinedKeybindings: combinedKeybindings,
CombinedActions: combinedActions,
Explanations: ActionExplanations,
}
tmpl, err := template.New("help").Parse(FP.T["HelpTextTemplate"])
if err != nil {
log.Fatalf("failed to parse help text template: %v", err.Error())
}
var b bytes.Buffer
err = tmpl.Execute(&b, tmplData)
if err != nil {
log.Fatalf("failed to render help text: %v", err.Error())
}
return b.String()
}
func getHelpModal() {
FP.HelpTextView = tview.NewTextView()
FP.HelpTextView.SetBorder(true)
FP.HelpTextView.SetText(getHelpText(FP.Config, FP.KeyBindings, FP.ActionBindings)).SetDynamicColors(true)
}
// returns the first configured keybinding for the provided action. returns
// "n/a" if none defined.
func getBinding(action string) string {
bindings, ok := FP.ActionBindings[action]
if !ok || len(bindings) < 1 {
return ""
}
return bindings[0]
}
// setBottomPageNavText renders something like "F1 help F2 profiles F3 results"
// at the bottom of the terminal.
func setBottomPageNavText() {
p, _ := FP.Pages.GetFrontPage()
pgs := [][]string{
{PageHelp, FP.T["BottomPageNavTextHelp"], getBinding(ActionGlobalHelp)},
{PageProfiles, FP.T["BottomPageNavTextProfiles"], getBinding(ActionProfiles)},
{PageResults, FP.T["BottomPageNavTextResults"], getBinding(ActionResults)},
}
var sb strings.Builder
for _, v := range pgs {
color := "[gray]"
if p == v[0] {
color = "[gold]"
}
sb.WriteString(fmt.Sprintf("%v%v%v %v %v", v[2], Reset, color, v[1], Reset))
}
FP.BottomPageNavText.SetText(sb.String())
}