@catladder/cli 0.0.0-new-cli-a65ec262 → 0.0.0-new-cli-52525b58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundles/catenv/index.js +1 -1
- package/dist/bundles/cli/index.js +35 -20
- package/dist/cli/src/completion.js +34 -19
- package/dist/cli/src/completion.js.map +1 -1
- package/dist/pipeline/src/constants.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/completion.ts +32 -19
package/package.json
CHANGED
package/src/completion.ts
CHANGED
|
@@ -16,27 +16,25 @@ export async function getCompletions(
|
|
|
16
16
|
words: string[],
|
|
17
17
|
cursorWord: string,
|
|
18
18
|
): Promise<string[]> {
|
|
19
|
-
// Try to
|
|
20
|
-
//
|
|
21
|
-
//
|
|
19
|
+
// Try to find a command by matching the longest prefix of words.
|
|
20
|
+
// E.g., for words ["project", "cloudsql", "restore-db", "--source"],
|
|
21
|
+
// we match "project cloudsql restore-db" and treat ["--source"] as args.
|
|
22
|
+
const matched = findCommand(allCommands, words);
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
if (matched) {
|
|
25
|
+
const { command, argsAfterCommand } = matched;
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
const exactCommand = allCommands.find((c) => c.name === typed);
|
|
28
|
-
if (exactCommand) {
|
|
29
|
-
// Check if cursor is a --flag
|
|
27
|
+
// Check if cursor is a --flag name
|
|
30
28
|
if (cursorWord.startsWith("--")) {
|
|
31
|
-
return getFlagCompletions(
|
|
29
|
+
return getFlagCompletions(command, cursorWord);
|
|
32
30
|
}
|
|
33
31
|
|
|
34
32
|
// Check if previous word was a --flag (complete its value)
|
|
35
|
-
const prevWord =
|
|
33
|
+
const prevWord = argsAfterCommand[argsAfterCommand.length - 1];
|
|
36
34
|
if (prevWord?.startsWith("--")) {
|
|
37
35
|
const flagName = prevWord.replace(/^--/, "");
|
|
38
36
|
const inputName = flagNameToInputName(flagName);
|
|
39
|
-
const inputDef =
|
|
37
|
+
const inputDef = command.inputs[inputName];
|
|
40
38
|
if (inputDef && "choices" in inputDef && inputDef.choices) {
|
|
41
39
|
return resolveChoicesForCompletion(inputDef, cursorWord);
|
|
42
40
|
}
|
|
@@ -44,9 +42,7 @@ export async function getCompletions(
|
|
|
44
42
|
}
|
|
45
43
|
|
|
46
44
|
// Complete positional inputs
|
|
47
|
-
const positionalInputs = getPositionalInputs(
|
|
48
|
-
// Count non-flag args after the command name
|
|
49
|
-
const argsAfterCommand = words.slice(exactCommand.name.split(" ").length);
|
|
45
|
+
const positionalInputs = getPositionalInputs(command);
|
|
50
46
|
const positionalArgs = argsAfterCommand.filter((w) => !w.startsWith("--"));
|
|
51
47
|
const positionalIndex = positionalArgs.length;
|
|
52
48
|
const targetInput = positionalInputs[positionalIndex];
|
|
@@ -60,15 +56,13 @@ export async function getCompletions(
|
|
|
60
56
|
return [];
|
|
61
57
|
}
|
|
62
58
|
|
|
63
|
-
// No
|
|
64
|
-
|
|
59
|
+
// No command matched. Complete subcommand names at the current level.
|
|
60
|
+
const typed = words.join(" ");
|
|
65
61
|
const prefix = typed ? typed + " " : "";
|
|
66
62
|
|
|
67
|
-
// Find unique next-level subcommand names
|
|
68
63
|
const nextParts = new Set<string>();
|
|
69
64
|
for (const cmd of allCommands) {
|
|
70
65
|
if (cmd.name.startsWith(prefix)) {
|
|
71
|
-
// Get the next word after the prefix
|
|
72
66
|
const rest = cmd.name.slice(prefix.length);
|
|
73
67
|
const nextPart = rest.split(" ")[0];
|
|
74
68
|
if (nextPart && nextPart.startsWith(cursorWord)) {
|
|
@@ -80,6 +74,25 @@ export async function getCompletions(
|
|
|
80
74
|
return [...nextParts].sort();
|
|
81
75
|
}
|
|
82
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Find a command by matching the longest prefix of words against command names.
|
|
79
|
+
* Returns the matched command and the remaining words (args/flags after the command name).
|
|
80
|
+
*/
|
|
81
|
+
function findCommand(
|
|
82
|
+
allCommands: CommandDef[],
|
|
83
|
+
words: string[],
|
|
84
|
+
): { command: CommandDef; argsAfterCommand: string[] } | null {
|
|
85
|
+
// Try longest match first
|
|
86
|
+
for (let i = words.length; i >= 1; i--) {
|
|
87
|
+
const candidate = words.slice(0, i).join(" ");
|
|
88
|
+
const command = allCommands.find((c) => c.name === candidate);
|
|
89
|
+
if (command) {
|
|
90
|
+
return { command, argsAfterCommand: words.slice(i) };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
|
|
83
96
|
function getPositionalInputs(command: CommandDef): [string, InputDef][] {
|
|
84
97
|
return Object.entries(command.inputs).filter(([, def]) => def.positional);
|
|
85
98
|
}
|