diff --git a/packages/core/package.json b/packages/core/package.json index 951970a7..3d335712 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -145,6 +145,7 @@ "read-yaml-file": "^2.1.0", "socket.io": "^4.8.0", "svgo": "catalog:", + "tab": "https://pkg.pr.new/bombshell-dev/tab@4595b27", "typescript": "catalog:", "validate-npm-package-name": "^5.0.0", "vite": "catalog:", diff --git a/packages/core/src/cli/cli-executable.ts b/packages/core/src/cli/cli-executable.ts index 764131ea..4dc4df97 100644 --- a/packages/core/src/cli/cli-executable.ts +++ b/packages/core/src/cli/cli-executable.ts @@ -11,6 +11,7 @@ const cliExecId = new Date().toISOString(); import * as _ from 'lodash-es'; import Debug from 'debug'; import { DmnoCommand } from './lib/dmno-command'; +// import {Completion, script} from "tab"; import { addDocsCommand } from './lib/cli-schema-generation'; import { customizeHelp } from './lib/help-customizations'; @@ -26,6 +27,7 @@ import { PluginCommand } from './commands/plugin.command'; import { InitCommand } from './commands/init.command'; import { ClearCacheCommand } from './commands/clear-cache.command'; import { PrintEnvCommand } from './commands/printenv.command'; +import { CompleteCommand } from './commands/complete.command'; const debug = Debug('dmno:cli'); @@ -33,6 +35,8 @@ const program = new DmnoCommand('dmno') .description('dmnno cli - https://dmno.dev') .version('0.0.1'); +program.enablePositionalOptions(); + program.addCommand(ResolveCommand); program.addCommand(RunCommand); program.addCommand(DevCommand); @@ -40,6 +44,7 @@ program.addCommand(InitCommand); program.addCommand(ClearCacheCommand); program.addCommand(PluginCommand); program.addCommand(PrintEnvCommand); +program.addCommand(CompleteCommand); // have to pass through the root program for this one so we can access all the subcommands addDocsCommand(program); diff --git a/packages/core/src/cli/commands/complete.command.ts b/packages/core/src/cli/commands/complete.command.ts new file mode 100644 index 00000000..b60712fc --- /dev/null +++ b/packages/core/src/cli/commands/complete.command.ts @@ -0,0 +1,72 @@ +import { DmnoCommand } from '../lib/dmno-command'; +import { Completion } from 'tab'; + +//TODO: this must be set to hidden. +const completeCmd = new DmnoCommand('complete') + .summary('Autocompletion') + .description('Internal command for shell autocompletion (do not use directly).') + .argument('', 'Tokens for autocompletion') + .example('dmno complete resolve --f', 'Provide suggestions for the "resolve" command when typing "--f"') + .passThroughOptions(); + +completeCmd.action(async (tokens: string[]): Promise => { + + const completion = new Completion(); + + // we get the root command to access all the registered commands. + const parent = completeCmd.parent; + if (parent && parent.commands) { + // in this step, we add each command + for (const cmd of parent.commands) { + const cmdName = cmd.name(); + const cmdDescription = cmd.description() || ''; + + completion.addCommand( + cmdName, + '', + [], // here we can define positional args to return. + async () => { + return []; + } + ); + } + + // here, for each command we add all its options. + for (const cmd of parent.commands) { + const cmdName = cmd.name(); + if (Array.isArray(cmd.options)) { + for (const option of cmd.options) { + // console.log('HERE', cmdName, option.long); + completion.addOption( + cmdName, + option.long, + "", + async (previousArgs, toComplete, endsWithSpace) => { + // here we can define suggestions to return. + if (option.long === '--format') { + return [ + { value: 'json', description: 'Output as JSON' }, + { value: 'env', description: 'Output as ENV file' } + ]; + } + if (option.long === '--watch') { + return [ + { value: 'true', description: 'Enable watch mode' }, + { value: 'false', description: 'Disable watch mode' } + ]; + } + return [] + } + ); + } + } + } + } + + const tokenStrings = tokens.map(token => token.toString()); + await completion.parse(tokenStrings); + process.exit(0); +}); + +export default completeCmd; +export { completeCmd as CompleteCommand }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bd2ebfe5..1fd98153 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -231,6 +231,9 @@ importers: svgo: specifier: 'catalog:' version: 3.3.2 + tab: + specifier: https://pkg.pr.new/bombshell-dev/tab@4595b27 + version: https://pkg.pr.new/bombshell-dev/tab@4595b27 typescript: specifier: 'catalog:' version: 5.7.2 @@ -11075,6 +11078,10 @@ packages: resolution: {integrity: sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==} engines: {node: '>=18'} + tab@https://pkg.pr.new/bombshell-dev/tab@4595b27: + resolution: {tarball: https://pkg.pr.new/bombshell-dev/tab@4595b27} + version: 0.0.0 + tabtab@3.0.2: resolution: {integrity: sha512-jANKmUe0sIQc/zTALTBy186PoM/k6aPrh3A7p6AaAfF6WPSbTx1JYeGIGH162btpH+mmVEXln+UxwViZHO2Jhg==} @@ -14480,7 +14487,7 @@ snapshots: dependencies: '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.14.12 + '@types/node': 22.10.4 '@types/yargs': 16.0.9 chalk: 4.1.2 @@ -15889,7 +15896,7 @@ snapshots: '@types/concat-stream@2.0.3': dependencies: - '@types/node': 20.14.12 + '@types/node': 22.10.4 '@types/cookie@0.4.1': {} @@ -25226,6 +25233,10 @@ snapshots: system-architecture@0.1.0: {} + tab@https://pkg.pr.new/bombshell-dev/tab@4595b27: + dependencies: + mri: 1.2.0 + tabtab@3.0.2: dependencies: debug: 4.3.7