Skip to content

Commit 0613f84

Browse files
committed
positionals wip
1 parent efb9d2f commit 0613f84

File tree

3 files changed

+55
-13
lines changed

3 files changed

+55
-13
lines changed

demo.citty.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ const devCommand = defineCommand({
2424
host: { type: "string", description: "Specify hostname" },
2525
port: { type: "string", description: "Specify port" },
2626
},
27-
run({ args }) { },
27+
run(ctx) {
28+
console.log('dev', ctx)
29+
},
2830
});
2931

3032
devCommand.subCommands = {
@@ -37,13 +39,39 @@ devCommand.subCommands = {
3739
})
3840
}
3941

42+
const lintCommand = defineCommand({
43+
meta: {
44+
name: "lint",
45+
description: "Lint project",
46+
},
47+
args: {
48+
files: { type: "positional", description: "Files to lint" },
49+
},
50+
run(ctx) {
51+
console.log('lint', ctx.cmd.args)
52+
},
53+
});
54+
4055
main.subCommands = {
41-
dev: devCommand
56+
dev: devCommand,
57+
lint: lintCommand
58+
4259
} as Record<string, CommandDef<any>>;
4360

4461
const completion = await tab(main)
4562

4663
for (const command of completion.commands.values()) {
64+
console.log(command)
65+
66+
if (command.name === 'lint') {
67+
console.log('lint')
68+
command.handler = () => {
69+
return [
70+
{ value: "main.ts", description: "Main file" },
71+
{ value: "index.ts", description: "Index file" },
72+
]
73+
}
74+
}
4775

4876
for (const [o, config] of command.options.entries()) {
4977
if (o === "--port") {

src/citty.ts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import * as bash from "./bash";
44
import * as fish from "./fish";
55
import * as powershell from "./powershell";
66
import { Completion } from ".";
7-
import type { ArgsDef, CommandDef, PositionalArgDef } from "citty";
7+
import type { ArgsDef, CommandDef, PositionalArgDef, SubCommandsDef } from "citty";
88

99
function quoteIfNeeded(path) {
1010
return path.includes(" ") ? `'${path}'` : path;
@@ -17,32 +17,40 @@ const quotedProcessArgs = processArgs.map(quoteIfNeeded);
1717
const quotedProcessExecArgs = process.execArgv.map(quoteIfNeeded);
1818
const x = `${quotedExecPath} ${quotedProcessExecArgs.join(" ")} ${quotedProcessArgs[0]}`;
1919

20-
async function handleSubCommands(
20+
function isConfigPositional<T extends ArgsDef>(config: CommandDef<T>) {
21+
return config.args && Object.values(config.args).some(arg => arg.type === 'positional')
22+
}
23+
24+
async function handleSubCommands<T extends ArgsDef = ArgsDef>(
2125
completion: Completion,
22-
subCommands: Record<string, any>,
26+
subCommands: SubCommandsDef,
2327
parentCmd?: string
2428
) {
2529
for (const [cmd, resolvableConfig] of Object.entries(subCommands)) {
2630
const config = await resolve(resolvableConfig);
2731
const meta = await resolve(config.meta);
32+
const subCommands = await resolve(config.subCommands)
2833

2934
if (!meta || typeof meta?.description !== "string") {
3035
throw new Error("Invalid meta or missing description.");
3136
}
32-
33-
const name = completion.addCommand(cmd, meta.description, async (previousArgs, toComplete, endsWithSpace) => {
37+
const isPositional = isConfigPositional(config)
38+
const name = completion.addCommand(cmd, meta.description, isPositional ? [false] : [], async (previousArgs, toComplete, endsWithSpace) => {
3439
return []
3540
}, parentCmd);
3641

3742
// Handle nested subcommands recursively
38-
if (config.subCommands) {
39-
await handleSubCommands(completion, config.subCommands, name);
43+
if (subCommands) {
44+
await handleSubCommands(completion, subCommands, name);
4045
}
4146

4247
// Handle arguments
4348
if (config.args) {
4449
for (const [argName, argConfig] of Object.entries(config.args)) {
4550
const conf = argConfig as ArgDef;
51+
if (conf.type === 'positional') {
52+
continue
53+
}
4654
completion.addOption(
4755
name,
4856
`--${argName}`,
@@ -75,7 +83,8 @@ export default async function tab<T extends ArgsDef = ArgsDef>(instance: Command
7583
}
7684

7785
const root = ''
78-
completion.addCommand(root, meta?.description ?? "", async (previousArgs, toComplete, endsWithSpace) => {
86+
const isPositional = isConfigPositional(instance)
87+
completion.addCommand(root, meta?.description ?? "", isPositional ? [false] : [], async (previousArgs, toComplete, endsWithSpace) => {
7988
return []
8089
});
8190

src/index.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ type Option = {
7575
}
7676

7777
type Command = {
78+
name: string;
7879
description: string;
7980
handler: Handler;
8081
options: Map<string, Option>;
@@ -84,9 +85,12 @@ type Command = {
8485
export class Completion {
8586
commands = new Map<string, Command>();
8687

87-
addCommand(name: string, description: string, handler: Handler, parent?: string) {
88+
// vite <entry> <another> [...files]
89+
// args: [false, false, true], only the last argument can be variadic
90+
addCommand(name: string, description: string, args: boolean[], handler: Handler, parent?: string) {
8891
const key = parent ? `${parent} ${name}` : name;
8992
this.commands.set(key, {
93+
name: key,
9094
description,
9195
handler,
9296
options: new Map(),
@@ -95,6 +99,7 @@ export class Completion {
9599
return key;
96100
}
97101

102+
// --port
98103
addOption(command: string, option: string, description: string, handler: Handler) {
99104
const cmd = this.commands.get(command);
100105
if (!cmd) {
@@ -215,7 +220,6 @@ export class Completion {
215220
}
216221
}
217222
}
218-
completions.push({ value: 'dhere1', description: '' })
219223

220224
directive = ShellCompDirective.ShellCompDirectiveNoFileComp;
221225
}
@@ -227,7 +231,8 @@ export class Completion {
227231
// TODO: prettier (plus check in ci)
228232
// TODO: ci type check
229233

230-
// TODO: positionals (tomorrow night)
234+
// TODO: positionals (tomorrow night), this is nearly there!
235+
231236
// TODO: cac (tomorrow night)
232237
// TODO: check behaviour of the tests (tomorrow night)
233238

0 commit comments

Comments
 (0)