Skip to content

Commit 138663a

Browse files
committed
unify repl command registry
1 parent edb9fb0 commit 138663a

9 files changed

Lines changed: 984 additions & 731 deletions

File tree

internal/repl/completion.go

Lines changed: 40 additions & 175 deletions
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,7 @@ type flagSpec struct {
1616
const CompletionEnvVar = "CLOUDCANAL_INTERNAL_COMPLETE"
1717

1818
var (
19-
visibleTopLevelCommands = []string{
20-
"help",
21-
"jobs",
22-
"datasources",
23-
"clusters",
24-
"workers",
25-
"consolejobs",
26-
"job-config",
27-
"schemas",
28-
"config",
29-
}
3019
visibleReplOnlyCommands = []string{"exit"}
31-
visibleHelpTopics = []string{
32-
"jobs",
33-
"datasources",
34-
"clusters",
35-
"workers",
36-
"consolejobs",
37-
"job-config",
38-
"schemas",
39-
"config",
40-
}
41-
boolValues = []string{"true", "false"}
42-
outputValues = []string{"text", "json"}
4320
)
4421

4522
func RenderCompletionScript(args []string) (string, error) {
@@ -79,12 +56,29 @@ func (s *Shell) completeLine(line string) []string {
7956
}
8057

8158
func (s *Shell) handleCompletion(tokens []string) error {
59+
return s.dispatchRegisteredCommand(tokens)
60+
}
61+
62+
func (s *Shell) runCompletionZsh(tokens []string) error {
63+
return s.runCompletionShell(tokens, "zsh")
64+
}
65+
66+
func (s *Shell) runCompletionBash(tokens []string) error {
67+
return s.runCompletionShell(tokens, "bash")
68+
}
69+
70+
func (s *Shell) runCompletionShell(tokens []string, shellName string) error {
8271
if len(tokens) < 2 || len(tokens) > 3 {
8372
s.io.Println(s.usageCompletion())
8473
return nil
8574
}
8675

87-
script, err := RenderCompletionScript(tokens[1:])
76+
args := []string{shellName}
77+
if len(tokens) == 3 {
78+
args = append(args, tokens[2])
79+
}
80+
81+
script, err := RenderCompletionScript(args)
8882
if err != nil {
8983
return err
9084
}
@@ -103,7 +97,7 @@ func completeContext(context []string, prefix string, replMode bool) []string {
10397
if name, valuePrefix, ok := splitInlineFlag(prefix); ok && name == "--output" {
10498
return prependInlineFlag(name, matchCandidates(outputValues, valuePrefix))
10599
}
106-
candidates := append([]string{}, visibleTopLevelCommands...)
100+
candidates := append([]string{}, visibleTopLevelCommands()...)
107101
if replMode {
108102
candidates = append(candidates, visibleReplOnlyCommands...)
109103
}
@@ -113,162 +107,33 @@ func completeContext(context []string, prefix string, replMode bool) []string {
113107
return matchCandidates(candidates, prefix)
114108
}
115109

116-
root := strings.ToLower(context[0])
117-
switch root {
118-
case "help":
119-
return matchCandidates(visibleHelpTopics, prefix)
120-
case "completion":
121-
if len(context) == 1 {
122-
return matchCandidates(append(append([]string{}, completionSubcommands...), "--help"), prefix)
123-
}
124-
return nil
125-
case "lang", "language":
126-
if len(context) == 1 {
127-
return matchCandidates(append(append([]string{}, langSubcommands...), "--help"), prefix)
128-
}
129-
if strings.EqualFold(context[1], "set") {
130-
return matchCandidates([]string{"en", "zh"}, prefix)
131-
}
132-
return nil
133-
case "config":
134-
if len(context) == 1 {
135-
return matchCandidates(append(append([]string{}, configSubcommands...), "--help"), prefix)
136-
}
137-
if strings.EqualFold(context[1], "lang") {
138-
if len(context) == 2 {
139-
return matchCandidates(append(append([]string{}, langSubcommands...), "--help"), prefix)
140-
}
141-
if len(context) == 3 && strings.EqualFold(context[2], "set") {
142-
return matchCandidates([]string{"en", "zh"}, prefix)
143-
}
144-
}
145-
return nil
146-
case "jobs":
147-
if len(context) == 1 {
148-
return matchCandidates(append(append([]string{}, jobsSubcommands...), "--help"), prefix)
149-
}
150-
switch strings.ToLower(context[1]) {
151-
case "list":
152-
return completeFlags(context[2:], prefix, withGlobalFlags([]flagSpec{
153-
{name: "--name"},
154-
{name: "--type"},
155-
{name: "--desc"},
156-
{name: "--source-id"},
157-
{name: "--target-id"},
158-
}))
159-
case "create", "update-incre-pos":
160-
return completeFlags(context[2:], prefix, withGlobalFlags([]flagSpec{
161-
{name: "--body"},
162-
{name: "--body-file"},
163-
}))
164-
case "replay":
165-
return completeFlags(context[2:], prefix, withGlobalFlags([]flagSpec{
166-
{name: "--auto-start", values: boolValues},
167-
{name: "--reset-to-created", values: boolValues},
168-
}))
169-
}
170-
return nil
171-
case "datasources":
172-
if len(context) == 1 {
173-
return matchCandidates(append(append([]string{}, dataSourceSubcommands...), "--help"), prefix)
174-
}
175-
if strings.EqualFold(context[1], "list") {
176-
return completeFlags(context[2:], prefix, withGlobalFlags([]flagSpec{
177-
{name: "--id"},
178-
{name: "--type"},
179-
{name: "--deploy-type"},
180-
{name: "--host-type"},
181-
{name: "--lifecycle"},
182-
}))
183-
}
184-
if strings.EqualFold(context[1], "add") {
185-
return completeFlags(context[2:], prefix, withGlobalFlags([]flagSpec{
186-
{name: "--body"},
187-
{name: "--body-file"},
188-
{name: "--security-file"},
189-
{name: "--secret-file"},
190-
}))
191-
}
192-
return nil
193-
case "clusters":
194-
if len(context) == 1 {
195-
return matchCandidates(append(append([]string{}, clusterSubcommands...), "--help"), prefix)
196-
}
197-
if strings.EqualFold(context[1], "list") {
198-
return completeFlags(context[2:], prefix, withGlobalFlags([]flagSpec{
199-
{name: "--name"},
200-
{name: "--desc"},
201-
{name: "--cloud"},
202-
{name: "--region"},
203-
}))
204-
}
205-
return nil
206-
case "workers":
207-
if len(context) == 1 {
208-
return matchCandidates(append(append([]string{}, workerSubcommands...), "--help"), prefix)
209-
}
210-
if strings.EqualFold(context[1], "list") {
211-
return completeFlags(context[2:], prefix, withGlobalFlags([]flagSpec{
212-
{name: "--cluster-id"},
213-
{name: "--source-id"},
214-
{name: "--target-id"},
215-
}))
216-
}
217-
if strings.EqualFold(context[1], "modify-mem-oversold") {
218-
return completeFlags(context[2:], prefix, withGlobalFlags([]flagSpec{
219-
{name: "--percent"},
220-
}))
221-
}
222-
if strings.EqualFold(context[1], "update-alert") {
223-
return completeFlags(context[2:], prefix, withGlobalFlags([]flagSpec{
224-
{name: "--phone", values: boolValues},
225-
{name: "--email", values: boolValues},
226-
{name: "--im", values: boolValues},
227-
{name: "--sms", values: boolValues},
228-
}))
229-
}
230-
return nil
231-
case "consolejobs":
232-
if len(context) == 1 {
233-
return matchCandidates(append(append([]string{}, consoleJobSubcommands...), "--help"), prefix)
234-
}
110+
if strings.EqualFold(context[0], "help") {
111+
return matchCandidates(visibleHelpTopics(), prefix)
112+
}
113+
114+
spec, consumed := findCommandPath(context)
115+
if spec == nil {
235116
return nil
236-
case "job-config", "jobconfig":
237-
if len(context) == 1 {
238-
return matchCandidates(append(append([]string{}, jobConfigSubcommands...), "--help"), prefix)
239-
}
240-
if strings.EqualFold(context[1], "specs") {
241-
return completeFlags(context[2:], prefix, withGlobalFlags([]flagSpec{
242-
{name: "--type"},
243-
{name: "--initial-sync", values: boolValues},
244-
{name: "--short-term-sync", values: boolValues},
245-
}))
117+
}
118+
119+
if consumed == len(context) {
120+
if len(spec.children) > 0 {
121+
candidates := append(append([]string{}, visibleCommandNames(spec.children)...), "--help")
122+
return matchCandidates(candidates, prefix)
246123
}
247-
if strings.EqualFold(context[1], "transform-job-type") {
248-
return completeFlags(context[2:], prefix, withGlobalFlags([]flagSpec{
249-
{name: "--source-type"},
250-
{name: "--target-type"},
251-
}))
124+
if len(spec.nextArgs) > 0 && !strings.HasPrefix(prefix, "--") {
125+
return matchCandidates(spec.nextArgs, prefix)
252126
}
253-
return nil
254-
case "schemas", "schema":
255-
if len(context) == 1 {
256-
return matchCandidates(append(append([]string{}, schemaSubcommands...), "--help"), prefix)
127+
if len(spec.flags) == 0 {
128+
return nil
257129
}
258-
if strings.EqualFold(context[1], "list-trans-objs-by-meta") {
259-
return completeFlags(context[2:], prefix, withGlobalFlags([]flagSpec{
260-
{name: "--src-db"},
261-
{name: "--src-schema"},
262-
{name: "--src-trans-obj"},
263-
{name: "--dst-db"},
264-
{name: "--dst-schema"},
265-
{name: "--dst-tran-obj"},
266-
}))
267-
}
268-
return nil
269-
default:
130+
return completeFlags(nil, prefix, withGlobalFlags(spec.flags))
131+
}
132+
133+
if len(spec.flags) == 0 {
270134
return nil
271135
}
136+
return completeFlags(context[consumed:], prefix, withGlobalFlags(spec.flags))
272137
}
273138

274139
func completeFlags(args []string, prefix string, specs []flagSpec) []string {

internal/repl/help.go

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,35 +19,18 @@ func RenderHelp(args []string) string {
1919
func (s *Shell) renderHelp(args []string) string {
2020
topic := ""
2121
if len(args) > 0 {
22-
topic = strings.ToLower(args[0])
22+
topic = strings.ToLower(strings.TrimSpace(args[0]))
2323
}
2424

25-
switch topic {
26-
case "", "overview":
25+
if topic == "" || topic == "overview" {
2726
return s.helpOverview()
28-
case "jobs":
29-
return s.helpJobs()
30-
case "datasources":
31-
return s.helpDataSources()
32-
case "clusters":
33-
return s.helpClusters()
34-
case "workers":
35-
return s.helpWorkers()
36-
case "consolejobs":
37-
return s.helpConsoleJobs()
38-
case "job-config", "jobconfig":
39-
return s.helpJobConfig()
40-
case "schemas", "schema":
41-
return s.helpSchemas()
42-
case "config":
43-
return s.helpConfig()
44-
case "lang", "language":
45-
return s.helpLanguage()
46-
case "completion":
47-
return s.helpCompletion()
48-
default:
49-
return s.unknownHelpText(topic)
5027
}
28+
29+
if spec := findRootCommand(topic); canRenderHelp(spec) {
30+
return commandHelpText(s, spec)
31+
}
32+
33+
return s.unknownHelpText(topic)
5134
}
5235

5336
func (s *Shell) helpOverview() string {

0 commit comments

Comments
 (0)