commander.js icon indicating copy to clipboard operation
commander.js copied to clipboard

Add color support for help option

Open hcodes opened this issue 11 years ago • 13 comments

hcodes avatar Dec 08 '14 09:12 hcodes

As example: cli_color

hcodes avatar Dec 08 '14 09:12 hcodes

+1

tenorok avatar Dec 08 '14 09:12 tenorok

:+1:

arikon avatar Dec 08 '14 09:12 arikon

+1

jd327 avatar Nov 04 '16 21:11 jd327

Still open after 3+ years? Anyhow commander can be extended using class myconsole extends Command and override, but also can be direct prototype which I did here: https://gist.github.com/kevyworks/653b40af20dc9a2509f865cd7fca1ef0 -- This issue should be closed already.

kevyworks avatar Feb 05 '19 16:02 kevyworks

This has gathered a few likes over the years, so not closing quite yet. I have some problems with choosing colors:

  • color choice is quite personal
  • color support in some Windows shells is poor
  • light and dark themed shells makes color choice harder

I suspect it is too much trouble to build in directly, but perhaps commander can make it easier for people to customise the help output.

shadowspawn avatar Mar 16 '19 08:03 shadowspawn

This issue has not had any activity in over six months (other than a comment suggesting it be closed). It isn't likely to get acted on due to this report.

Feel free to open a new issue if it comes up again, with new information and renewed interest.

Thank you for your contributions.

shadowspawn avatar Apr 20 '19 11:04 shadowspawn

Sywac isn't well documented, but it has a way to specify colors like this:

// See http://sywac.io
const cli = require('sywac')

cli
  .string('-c, --cloudEnv <env>', {
    description: `The cloud env to use.`,
    required: true,
  })
  .version('-v, --version')
  .help('-h, --help')
  .showHelpByDefault()
  // Add colors to the help output!
  .style({
    usagePrefix: str => chalk().yellow(str.slice(0, 6)) + ' ' + chalk().bold(str.slice(7)),
    usageCommandPlaceholder: str => chalk().bold(str),
    usagePositionals: str => chalk().bold(str),
    usageArgsPlaceholder: str => chalk().bold(str),
    usageOptionsPlaceholder: str => chalk().bold(str),
    group: str => chalk().yellow(str),
    flags: str => chalk().bold(str),
    desc: str => chalk().cyan(str),
    hints: str => chalk().gray.dim(str),
    groupError: str => chalk().red.bold(str),
    flagsError: str => chalk().red.bold(str),
    descError: str => chalk().red.bold(str),
    hintsError: str => chalk().red(str),
    messages: str => chalk().red.bold(str), // these are error messages
  })
  .parseAndExit()
  .then(main)
  .catch(e => {
    console.error(e)
    process.exit(1)
  })

let c
function chalk() {
  // lazily load chalk, only used if help text displayed
  if (!c) c = require('chalk')
  return c
}

async function main(opts) {
  const {cloudEnv} = opts
  console.log(cloudEnv)
}

Example output with color:

color

It'd be neat to have some sort of color configurability for Commander.

trusktr avatar Apr 15 '20 14:04 trusktr

It would still be nice to have a more simple api to change colors & styles

ivands avatar Nov 30 '20 21:11 ivands

#1365 is a major refactor of how the help is generated including user customisation, but not specifically about adding color support.

shadowspawn avatar Dec 01 '20 01:12 shadowspawn

IMO, color support is crucial for a CLI tool. I understand the "no dependency" policy. commander should not do it itself, but at least provide a legal & easy way for the user.

// user code:
import { Command } from 'commander';
import c from 'chalk';

const formatter = {
  helpWidth: 120,
  indent: 2,
  titles: str => c.yellow.bold(str),
  usage: str => c.gray(str),
  option: flags => c.green(flags),
  command: (name, args) => c.green(name) + '  ' + c.gray(args),
  description: desc => c.white(desc),
  default: val => `[default: ${c.gray(val)}}`
};

const program = new Command();
program
  .name('colorful-cli')
  .usage('<command> [options]')
  .version(pkg.version)
  .format(formatter)            // <—— pass formatter object to commander
  .option('--debug', 'output extra logs')
  // ... more commands & options...

Pls re-open this issue.

onury avatar Aug 09 '24 14:08 onury

For future reference to check ongoing interest:

  • the opening comment currently has 12 👍
  • the comment with the Sywac example has 4 👍

shadowspawn avatar Aug 10 '24 05:08 shadowspawn

This old issue has been getting recent upvotes, and I have started looking at what is needed to make it easier for authors to provide custom colours in the help. I'll reopen at least while I am working on it.

shadowspawn avatar Sep 17 '24 01:09 shadowspawn

I have a prototype of Commander with support for padding and wrapping correctly when colours are included in the Help. It uses the existing Help customisation, and effectively requires a subclass to get access to the underlying implementation (i.e. super). styleTitle is a new Help style hook.

Is this enough to be useful?

import { styleText } from 'node:util'; // from node v20.12.0
import { Command, Help } from 'commander';

class MyHelp extends Help {
  commandUsage(command) {
    return `${command.name()} ${styleText('green', '[options]')} ${styleText('yellow', '[command]')}`;
  }
  commandDescription(command) {
    return styleText('magenta', super.commandDescription(command));
  }
  optionTerm(option) {
    return styleText('green', super.optionTerm(option));
  }
  optionDescription(option) {
    return styleText('italic', super.optionDescription(option));
  }
  subcommandTerm(command) {
    return styleText('yellow', super.subcommandTerm(command));
  }
  styleTitle(title) {
    return styleText('bold', title);
  }
}

class MyCommand extends Command {
  createCommand(name) {
    return new MyCommand(name);
  }
  createHelp() {
    return Object.assign(new MyHelp(), this.configureHelp());
  }
}

const program = new MyCommand();

program.description('d '.repeat(100));
program
  .option('-s', 'short flag')
  .option('-f, --flag', 'short and long flag')
  .option('--long', 'l '.repeat(100));

program
  .command('sub1', 'sssss '.repeat(33))
  .command('sub2', 'subcommand 2 description')
  .command('sub3', 'subcommand 3 description');

program.parse();
colour example

shadowspawn avatar Sep 29 '24 08:09 shadowspawn

Open draft PR in #2251. Added a style layer of simple hooks so don't need to subclass to add colour:

program.configureHelp({
  styleTitle: (str) => styleText('bold', str),
  styleCommandText: (str) => styleText('cyan', str),
  styleCommandDescription: (str) => styleText('magenta', str),
  styleItemDescription: (str) => styleText('italic', str),
  styleOptionText: (str) => styleText('green', str),
  styleArgumentText: (str) => styleText('yellow', str),
  styleSubcommandText: (str) => styleText('blue', str),
});
Screenshot 2024-10-12 at 14 33 20

shadowspawn avatar Oct 08 '24 09:10 shadowspawn

A prerelease is available for v13. The release is tagged as next and can be installed with:

npm install commander@next

shadowspawn avatar Dec 06 '24 23:12 shadowspawn

Version 13.0.0 has been released

shadowspawn avatar Dec 30 '24 05:12 shadowspawn

What a pleasant surprise! Building my first CLI with Commander and wanted to pretty up the outputs a bit, just tried this out now and it's working great.

For anyone stumbling upon this, here is a picocolors equivalent to @shadowspawn's styleText version https://github.com/tj/commander.js/issues/301#issuecomment-2399287580:

import pc from "picocolors";

program.configureHelp({
  styleTitle: (str) => pc.bold(str),
  styleCommandText: (str) => pc.cyan(str),
  styleCommandDescription: (str) => pc.magenta(str),
  styleDescriptionText: (str) => pc.italic(str),
  styleOptionText: (str) => pc.green(str),
  styleArgumentText: (str) => pc.yellow(str),
  styleSubcommandText: (str) => pc.blue(str),
});

dir avatar Dec 31 '24 19:12 dir

What a pleasant surprise! Building my first CLI with Commander and wanted to pretty up the outputs a bit, just tried this out now and it's working great.

For anyone stumbling upon this, here is a picocolors equivalent to @shadowspawn's styleText version #301 (comment):

import pc from "picocolors";

program.configureHelp({ styleTitle: (str) => pc.bold(str), styleCommandText: (str) => pc.cyan(str), styleCommandDescription: (str) => pc.magenta(str), styleDescriptionText: (str) => pc.italic(str), styleOptionText: (str) => pc.green(str), styleArgumentText: (str) => pc.yellow(str), styleSubcommandText: (str) => pc.blue(str), });

thanks!

psulek avatar Mar 31 '25 11:03 psulek