Open mikeerickson opened 5 years ago
@mikeerickson Hm, good question. Right now, no, but that's something we should add.
Something like:
$ movie imdb --help
... should display help for all commands under ./src/commands/imdb/
.
For now, you can check it in your root command:
import { GluegunToolbox } from 'gluegun'
const HELP_MESSAGE = `
movie api
Run \`movie api reset\` to reset your IMDB token.
`
module.exports = {
name: 'api',
run: async (toolbox: GluegunToolbox) => {
const {
meta: { commandInfo },
print,
parameters: { options }
} = toolbox
if (options.help || options.h) {
print.info(HELP_MESSAGE)
return
}
// do other things
}
}
There is already a built-in capability to do this here:
However, it's not exposed with the full interface:
If we updated toolbox.meta.commandInfo()
to take an argument and pass that on as the second argument, then it would be easy to implement this:
const { meta, print } = toolbox
print.info(meta.commandInfo(['api']))
We should also make it so this is essentially what happens when you do mycli foo bar --help
by default, especially if you added the .help()
call to the CLI builder.
I definitely want to do this.
Being able to print what arguments a command expects would be nice too. Should I make that a separate ticket?
I think these two Items go hand in hand, definitely something that should be supported together. Same ticket, or separate but both should be supported.
@RichiCoder1 @jamonholmgren
Back from holiday, figured I would chime in some more on this topic.
I have created CLIs internally using some homegrown libraries and one of the important features is the ability to show command specific help, including support for command attributes
This is how command specific help appears:
The content for command help is read from the command file
module.exports = {
init: function(cli) {
cli.arguments.commitlint = cli.arguments.c = cli.arguments.commitlint || cli.arguments.c || true;
},
name: "husky",
disabled: false,
description: "Install and configure husky module",
flags: {
"--commitlint, -c": "configures commitlint"
},
run: function(cli) {
cli.arguments = cli.setDefaultFlags(cli, this.flags);
this.hasOwnProperty("init") ? this.init(cli) : null;
cli.print.info(`⚙️ Execute ${this.name} command`);
cli.print.info(cli.strings.stringify(cli.arguments));
}
};
And for completeness sake, here is what the default help looks like (I am thinking of creating a plugin for gluegun to show this as default as opposed to current help) Or, I could just create a simple function for help interface to use
I really love that @mikeerickson. Any help you can provide is greatly appreciated, as I'm focusing on some other aspects of Gluegun at the moment.
I will surely add the necessary code to provide this functionality. Would you like me to implement similar UI to what I have shown above.
I was going to create a new plugin for personal use, but if you are keen to having this UI in core, I would prefer to do it there as well.
I like the UI you created. It's clean, elegant, and impressive. I'd like to have it in core.
(Hint: It may require fixing a few tests that depend on the exact help message. What I would do is use the shouldContain
matcher to be less dependent on exact output.)
@jamonholmgren sounds good, I have already started the "Getting to know the source" process. I will do the primary help interface, then move onto the command help.
I am reviewing the cli.integration.ts tests right now.
Feel free to join the #gluegun channel in http://community.infinite.red Slack to chat about this in realtime, Mike.
@jamonholmgren I have already joined :-)
I have cross-posted questions about the Plugin API there, so no need to reply :-)
@jamonholmgren OK, first pass is done (prettify the main cli help) I have not fixed the tests yet, but wanted to share this with you. There will be a few more tweaks (ie adding the Usage section, not sure how that is going to be implemented just yet)
Looks awesome! Bit late, but let me know if yah need any help.
@RichiCoder1 So far, so good. Getting up to speed with the source code is the longest part, but that is going swimmingly.
One question, do you have place where you store application wide constants? I am sure I could track it down, but since you are here :-)
I'm as a novice to the code base as you :). But from what I've seen so far, constants have been kept close to the most relevant place they're used. So colors
in print-tools
, plugin defaults with plugin-loader
, etc. Correct @jamonholmgren?
Fair enough, that is where I have put it (unless told otherwise)
@jamonholmgren Here are my proposed changes to the command object. I have only added flags
property to the command object (if it is not supplied, it will operate as normal). Let me know if there are any other properites you might need on the flags
property
module.exports = {
name: 'prompty',
description: 'Get user information',
flags: {
age: {
alias: ['a', 'age'],
description: 'Supply age',
},
shoe: {
alias: ['s', 'shoe'],
description: 'What shoes are you wearing',
choices: ['Clown', 'Adidas', 'Nike'],
initial: 'Adidas',
},
},
run: async function(toolbox) {
const { print } = toolbox
print.info('Welcome to your CLI')
let choices = this.flags.shoe.choices || ['Other']
// let choices = this.flags.shoe.choices
// text input
const askAge = { type: 'input', name: 'age', message: 'How old are you?' }
// multiple choice
const askShoe = {
type: 'list',
name: 'shoe',
message: 'What shoes are you wearing?',
choices,
}
// ask a series of questions
const questions = [askAge, askShoe]
const { age, shoe } = await toolbox.prompt.ask(questions)
console.log(age, shoe)
},
}
It looks awesome.
Minor nit: would you need to put shoe
in the alias
list if it's already the name of the flag? Perhaps just any aliases that aren't the name of the flag.
Also, you may want dashed: true|false
as an option, since some flags might be --shoe=Adidas
or -s Adidas
(accessible in toolbox.parameters.options['shoe'] || toolbox.parameters.options['s']
).
@jamonholmgren makes good sense on the alias
property. As far as the dashed
property is concerned, I didnt realize that is how it works :-)
In my current CLI tool, the params are parsed using yargs-parser
so that is not an issue to solve. But, I can see now how it is configured in gluegun. I will make these changes as well.
@jamonholmgren Are the CLI arguments available on the toolbox
object anywhere? Just thinking ahead as to how the user will access these arguments, or will I need to add code for that as well.
@mikeerickson Apologies, I've been out of town. I'm not sure what you're asking, to be honest -- there is toolbox.parameters, is that what you're looking for?
Is this dead? Is there any way to auto-document toolbox.parameters.options
?
@danawoodman Currently I don't have plans to add it (we haven't needed it for our CLIs yet), but if you have any ideas, I'm happy to review!
@jamonholmgren I don't mind the proposals discussed here. Some way of passing in a definition of the options/flags that the given command supports then those are automatically documented/validated before hand. I find I'm writing a LOT of extra code to do this instead of Gluegun doing which I would hope.
Thinking out-loud:
options: [
{ option: '-y, --yes', type: boolean, default: true },
{ option: '-c, --config', type: string, required: true },
]
I like this. We could possibly use yargs
for this. It's currently only a devDependency, though -- we're using yargs-parser
in production which has some of this capability but not all.
yargs has a pretty full featured capability:
https://github.com/yargs/yargs/blob/HEAD/docs/api.md
Perhaps see if we want to bring in all of yargs
(if it's worth the extra kbs)?
@jamonholmgren yeah, to me a few kb is fine esp since my CLI has to bundle the whole of Node so it already is bloated haha
Maybe the support is optional? Might be confusing though.
A way to be able to define typed options and have the CLI output help for them would be killer
I managed to get a "auto-generated" help command to work without modifying Gluegun or adding yargs
. I will say though, it is quite basic and doesn't support typed options. Another thing is, you have to run a function at the start of each command in order to capture the --help, -h
flag.
I have created a gist (using TypeScript) with how I achieved it. Feel free to use it as a starting point. Again, very basic implementation and only displays the command, your description and available flags. If you use the files in the gist, when you run <brand> some command --help
, you should get.
+1 interested to see how this develops! :)
I realize this is an old issue, and not much progress has happened, but I do intend to work on it eventually. Perhaps a good option for hacking on my Twitch stream.
Does any interface exist to display command specific help?