-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathgoquery.go
150 lines (130 loc) · 4.08 KB
/
goquery.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
package goquery
import (
"fmt"
"sort"
"strings"
"github.com/AbGuthrie/goquery/v2/commands"
"github.com/AbGuthrie/goquery/v2/config"
"github.com/AbGuthrie/goquery/v2/hosts"
"github.com/AbGuthrie/goquery/v2/models"
"github.com/AbGuthrie/goquery/v2/utils"
prompt "github.com/c-bata/go-prompt"
)
var apiInstance models.GoQueryAPI
var options config.Config
// Run is the entry point for a file impporting the goquery library to start the prompt REPL
func RunWithExternalCommands(api models.GoQueryAPI, _config config.Config, _externalCommandMap map[string]commands.GoQueryCommand) {
for k, v := range _externalCommandMap {
commands.CommandMap[k] = v
}
Run(api, _config)
}
// Run is the entry point for a file impporting the goquery library to start the prompt REPL
func Run(api models.GoQueryAPI, _config config.Config) {
// Print errors/warnings with provided aliases, and print state of debug flags
_config.Validate()
// Set globals for executor function closure
options = _config
apiInstance = api
history, err := utils.LoadHistoryFile()
if err != nil {
fmt.Printf("Unable to load history file %s\n", err)
}
p := prompt.New(
executor,
completer,
prompt.OptionPrefix("goquery> "),
prompt.OptionLivePrefix(refreshLivePrefix),
prompt.OptionTitle("goquery"),
prompt.OptionHistory(history),
)
p.Run()
}
func refreshLivePrefix() (string, bool) {
// Prototype for showing current connected host state in
// input line prefix
subPrefix := ""
currentHost, err := hosts.GetCurrentHost()
if err == nil {
subPrefix = " | " + currentHost.ComputerName + ":" + currentHost.CurrentDirectory
}
return fmt.Sprintf("goquery%s> ", subPrefix), true
}
func executor(input string) {
writeHistory := true
defer func() {
if !writeHistory {
return
}
// Write history entry
if err := utils.UpdateHistoryFile(input); err != nil {
fmt.Printf("Failed to write history file: %s\n", err)
}
}()
// Separate command and arguments
input = strings.TrimSpace(input)
args := strings.Split(input, " ")
if len(args) == 0 {
return
}
// Lookup and run command in command map
if command, ok := commands.CommandMap[args[0]]; ok {
err := command.Execute(apiInstance, &options, input)
if err != nil {
fmt.Printf("%s: %s\n", args[0], err.Error())
}
return
}
// Command not found, was this command aliased?
alias, found := options.Aliases[args[0]]
if !found {
fmt.Printf("No such command: %s\n", args[0])
return
}
realizedCommand, err := utils.InterpolateArguments(input, alias.Command)
if err != nil {
fmt.Printf("Alias error: %s\n", err)
return
}
// Run the parsed and interpolated alias through executor again
writeHistory = false
executor(realizedCommand)
}
func completer(in prompt.Document) []prompt.Suggest {
command := strings.Split(in.CurrentLine(), " ")[0]
// Nothing has been typed at the prompt
if command == "" {
return []prompt.Suggest{}
}
// Suggest any top level command
if _, ok := commands.CommandMap[command]; !ok {
prompts := []prompt.Suggest{}
// We also need to sort the final array because go traverses maps non
// deterministically
suggestions := make([]string, 0)
// Add all command suggestions
for name := range commands.CommandMap {
suggestions = append(suggestions, name)
}
// Add all alias suggestions
for name := range options.Aliases {
suggestions = append(suggestions, name)
}
sort.Strings(suggestions)
for _, suggestion := range suggestions {
if alias, ok := options.Aliases[suggestion]; ok {
description := alias.Description
if len(description) == 0 {
description = alias.Command
}
prompts = append(prompts, prompt.Suggest{Text: suggestion, Description: description})
} else if command, ok := commands.CommandMap[suggestion]; ok {
prompts = append(prompts, prompt.Suggest{Text: suggestion, Description: command.Help()})
}
}
return prompt.FilterHasPrefix(prompts, command, true)
}
// Call into the command to ask for further suggestions
commandStruct := commands.CommandMap[command]
return prompt.FilterHasPrefix(commandStruct.Suggestions(in.CurrentLine()), in.GetWordBeforeCursor(), true)
}