Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve alignment of -h Help output #880

Closed
kaushalmodi opened this issue May 23, 2017 · 14 comments
Closed

Improve alignment of -h Help output #880

kaushalmodi opened this issue May 23, 2017 · 14 comments

Comments

@kaushalmodi
Copy link

Hi,

I was trying out the diff2html-cli utility. That uses yargs.

When I type diff2html -h, I see:
image

I find the lack of column-based alignment make the output difficult to read. Compare to other CLI utility help outputs like grep --help:
image


I asked the dev to fix that. But it turns out that the output format of the Help depends on yargs. Can you please suggest how to make the help output look well-aligned like that of grep --help?

@zypA13510
Copy link
Contributor

Coming from #1403.

Current yargs behavior

source code
const {argv} = require('yargs')
  .options({
    output: {
      alias: ['O', 'dest', 'destination', 'foo', 'bar'],
      describe: 'Write output to <file> instead of stdout',
      normalize: true,
    },
    quiet: {
      alias: 'q',
      conflicts: 'verbose',
      describe: 'Suppress all normal output',
      type: 'boolean',
    },
    verbose: {
      alias: 'v',
      conflicts: 'quiet',
      describe: 'Output additional debugging information',
      type: 'boolean',
    },
  })
  .alias('help', 'h')
help output
$ node index.js --help
Options:
  --help, -h                                Show help                  [boolean]
  --version                                 Show version number        [boolean]
  --output, -O, --dest, --destination,      Write output to <file> instead of
  --foo, --bar                              stdout                      [string]
  --quiet, -q                               Suppress all normal output [boolean]
  --verbose, -v                             Output additional debugging
                                            information                [boolean]

Generally, there seems to be a limit on the maximum width of args/aliases column, and if exceeded, will expand into the second row. But the limit seems too big and it makes the output ugly (personal opinion).

The description will always start at the same line as the args/aliases.

Output from GNU coreutils help

Note: all output below are from CentOS 7, other distros may be different. Also, only the command-line arguments part is shown.

chmod
$ chmod --help
  -c, --changes          like verbose but report only when a change is made
  -f, --silent, --quiet  suppress most error messages
  -v, --verbose          output a diagnostic for every file processed
      --no-preserve-root  do not treat '/' specially (the default)
      --preserve-root    fail to operate recursively on '/'
      --reference=RFILE  use RFILE's mode instead of MODE values
  -R, --recursive        change files and directories recursively
      --help     display this help and exit
      --version  output version information and exit
cp
$ cp --help
  -a, --archive                same as -dR --preserve=all
      --attributes-only        don't copy the file data, just the attributes
      --backup[=CONTROL]       make a backup of each existing destination file
  -b                           like --backup but does not accept an argument
      --copy-contents          copy contents of special files when recursive
  -d                           same as --no-dereference --preserve=links
  -f, --force                  if an existing destination file cannot be
                                 opened, remove it and try again (this option
                                 is ignored when the -n option is also used)
  -i, --interactive            prompt before overwrite (overrides a previous -n
                                  option)
  -H                           follow command-line symbolic links in SOURCE
  -l, --link                   hard link files instead of copying
  -L, --dereference            always follow symbolic links in SOURCE
  -n, --no-clobber             do not overwrite an existing file (overrides
                                 a previous -i option)
  -P, --no-dereference         never follow symbolic links in SOURCE
  -p                           same as --preserve=mode,ownership,timestamps
      --preserve[=ATTR_LIST]   preserve the specified attributes (default:
                                 mode,ownership,timestamps), if possible
                                 additional attributes: context, links, xattr,
                                 all
  -c                           deprecated, same as --preserve=context
      --no-preserve=ATTR_LIST  don't preserve the specified attributes
      --parents                use full source file name under DIRECTORY
  -R, -r, --recursive          copy directories recursively
      --reflink[=WHEN]         control clone/CoW copies. See below
      --remove-destination     remove each existing destination file before
                                 attempting to open it (contrast with --force)
      --sparse=WHEN            control creation of sparse files. See below
      --strip-trailing-slashes  remove any trailing slashes from each SOURCE
                                 argument
  -s, --symbolic-link          make symbolic links instead of copying
  -S, --suffix=SUFFIX          override the usual backup suffix
  -t, --target-directory=DIRECTORY  copy all SOURCE arguments into DIRECTORY
  -T, --no-target-directory    treat DEST as a normal file
  -u, --update                 copy only when the SOURCE file is newer
                                 than the destination file or when the
                                 destination file is missing
  -v, --verbose                explain what is being done
  -x, --one-file-system        stay on this file system
  -Z                           set SELinux security context of destination
                                 file to default type
      --context[=CTX]          like -Z, or if CTX is specified then set the
                                 SELinux or SMACK security context to CTX
      --help     display this help and exit
      --version  output version information and exit
df
$ df --help
  -a, --all             include pseudo, duplicate, inaccessible file systems
  -B, --block-size=SIZE  scale sizes by SIZE before printing them; e.g.,
                           '-BM' prints sizes in units of 1,048,576 bytes;
                           see SIZE format below
      --direct          show statistics for a file instead of mount point
      --total           produce a grand total
  -h, --human-readable  print sizes in human readable format (e.g., 1K 234M 2G)
  -H, --si              likewise, but use powers of 1000 not 1024
  -i, --inodes          list inode information instead of block usage
  -k                    like --block-size=1K
  -l, --local           limit listing to local file systems
      --no-sync         do not invoke sync before getting usage info (default)
      --output[=FIELD_LIST]  use the output format defined by FIELD_LIST,
                               or print all fields if FIELD_LIST is omitted.
  -P, --portability     use the POSIX output format
      --sync            invoke sync before getting usage info
  -t, --type=TYPE       limit listing to file systems of type TYPE
  -T, --print-type      print file system type
  -x, --exclude-type=TYPE   limit listing to file systems not of type TYPE
  -v                    (ignored)
      --help     display this help and exit
      --version  output version information and exit
ls
$ ls --help
  -a, --all                  do not ignore entries starting with .
  -A, --almost-all           do not list implied . and ..
      --author               with -l, print the author of each file
  -b, --escape               print C-style escapes for nongraphic characters
      --block-size=SIZE      scale sizes by SIZE before printing them; e.g.,
                               '--block-size=M' prints sizes in units of
                               1,048,576 bytes; see SIZE format below
  -B, --ignore-backups       do not list implied entries ending with ~
  -c                         with -lt: sort by, and show, ctime (time of last
                               modification of file status information);
                               with -l: show ctime and sort by name;
                               otherwise: sort by ctime, newest first
  -C                         list entries by columns
      --color[=WHEN]         colorize the output; WHEN can be 'never', 'auto',
                               or 'always' (the default); more info below
  -d, --directory            list directories themselves, not their contents
  -D, --dired                generate output designed for Emacs' dired mode
  -f                         do not sort, enable -aU, disable -ls --color
  -F, --classify             append indicator (one of */=>@|) to entries
      --file-type            likewise, except do not append '*'
      --format=WORD          across -x, commas -m, horizontal -x, long -l,
                               single-column -1, verbose -l, vertical -C
      --full-time            like -l --time-style=full-iso
  -g                         like -l, but do not list owner
      --group-directories-first
                             group directories before files;
                               can be augmented with a --sort option, but any
                               use of --sort=none (-U) disables grouping
  -G, --no-group             in a long listing, don't print group names
  -h, --human-readable       with -l, print sizes in human readable format
                               (e.g., 1K 234M 2G)
      --si                   likewise, but use powers of 1000 not 1024
  -H, --dereference-command-line
                             follow symbolic links listed on the command line
      --dereference-command-line-symlink-to-dir
                             follow each command line symbolic link
                               that points to a directory
      --hide=PATTERN         do not list implied entries matching shell PATTERN
                               (overridden by -a or -A)
      --indicator-style=WORD  append indicator with style WORD to entry names:
                               none (default), slash (-p),
                               file-type (--file-type), classify (-F)
  -i, --inode                print the index number of each file
  -I, --ignore=PATTERN       do not list implied entries matching shell PATTERN
  -k, --kibibytes            default to 1024-byte blocks for disk usage
  -l                         use a long listing format
  -L, --dereference          when showing file information for a symbolic
                               link, show information for the file the link
                               references rather than for the link itself
  -m                         fill width with a comma separated list of entries
  -n, --numeric-uid-gid      like -l, but list numeric user and group IDs
  -N, --literal              print raw entry names (don't treat e.g. control
                               characters specially)
  -o                         like -l, but do not list group information
  -p, --indicator-style=slash
                             append / indicator to directories
  -q, --hide-control-chars   print ? instead of nongraphic characters
      --show-control-chars   show nongraphic characters as-is (the default,
                               unless program is 'ls' and output is a terminal)
  -Q, --quote-name           enclose entry names in double quotes
      --quoting-style=WORD   use quoting style WORD for entry names:
                               literal, locale, shell, shell-always, c, escape
  -r, --reverse              reverse order while sorting
  -R, --recursive            list subdirectories recursively
  -s, --size                 print the allocated size of each file, in blocks
  -S                         sort by file size
      --sort=WORD            sort by WORD instead of name: none (-U), size (-S),
                               time (-t), version (-v), extension (-X)
      --time=WORD            with -l, show time as WORD instead of default
                               modification time: atime or access or use (-u)
                               ctime or status (-c); also use specified time
                               as sort key if --sort=time
      --time-style=STYLE     with -l, show times using style STYLE:
                               full-iso, long-iso, iso, locale, or +FORMAT;
                               FORMAT is interpreted like in 'date'; if FORMAT
                               is FORMAT1<newline>FORMAT2, then FORMAT1 applies
                               to non-recent files and FORMAT2 to recent files;
                               if STYLE is prefixed with 'posix-', STYLE
                               takes effect only outside the POSIX locale
  -t                         sort by modification time, newest first
  -T, --tabsize=COLS         assume tab stops at each COLS instead of 8
  -u                         with -lt: sort by, and show, access time;
                               with -l: show access time and sort by name;
                               otherwise: sort by access time
  -U                         do not sort; list entries in directory order
  -v                         natural sort of (version) numbers within text
  -w, --width=COLS           assume screen width instead of current value
  -x                         list entries by lines instead of by columns
  -X                         sort alphabetically by entry extension
  -1                         list one file per line

SELinux options:

  --lcontext                 Display security context.   Enable -l. Lines
                             will probably be too wide for most displays.
  -Z, --context              Display security context so it fits on most
                             displays.  Displays only mode, user, group,
                             security context and file name.
  --scontext                 Display only security context and file name.
      --help     display this help and exit
      --version  output version information and exit

Summary

long args/aliases column

From what I see, there isn't a consensus on how to handle extremely long args/aliases column, some of them (chmod, cp and df) push the description on the same line further to the right, whereas others (ls) move the entire description to the next line.

If they decide to push the description to the right, two spaces are added between the two columns. Also, if they do, the 2nd line of description (and all following lines) are also padded for the same amount.

The args/aliases column width is inconsistent, the maximum being 31 characters from cp.

long description

They all add two more spaces before the second line of description.

different console width

All the programs above did not try to detect console width, they will spill over to the 2nd line if console width is smaller than 80 characters.

how grouping affects the output

Note that in all cases, --help and --version always have a different column width. This is similar to the grouping in yargs.

Proposal

My proposal is:

  1. Decrease the limit of the args/aliases column to either 32-chars or 40%, depending on whether yargs tries to detect console width.
  2. If the limit is exceeded, move the description to the 2nd line (or the next line if list of aliases is so long it takes 2 lines to display). I choose this ls-like behavior because aliases in yargs are defined by downstream users, you can't prevent users from having 20 aliases and the other option simply won't work in this scenario.
  3. Add two more spaces before the second line and all following lines of description.
  4. Provide an option to hide default and type ([Feature Request] Hide default value and flag type #1145).

@mleguen
Copy link
Member

mleguen commented Aug 28, 2019

I agree both with the feeling that yargs generated help can sometimes look messy, and with @zypA13510's proposal of improving that in a way consistent with standard cli tools.

I thing this should be adressed in the same PR as #1403.

@mrmckeb
Copy link

mrmckeb commented Feb 29, 2020

OK, I was looking into this @mleguen and I can see that there are a number of changes needed, and I propose we start with the first column.

This is my proposal for this:

  • Implement a sensible max-width, as suggested by @zypA13510.
  • Add a new method to usage.js that calculates the column width based on everything that would be in that column, across all groups.

This covers the most basic case, as below:

Before:

abcd <command> [args]

Commands:
  abcd branch [name]  Create a new branch
  abcd check <type>   Perform a check in the current repository
  abcd pr             Create a new pull request on GitHub

Options:
  -h, --help     Show help                                             [boolean]
  -v, --version  Show version number                                   [boolean]

After:

abcd <command> [args]

Commands:
  abcd branch [name]  Create a new branch
  abcd check <type>   Perform a check in the current repository
  abcd pr             Create a new pull request on GitHub

Options:
  -h, --help          Show help                                        [boolean]
  -v, --version       Show version number                              [boolean]

But if you think this needs to be fixed in one hit, I feel it needs a detailed and agreed upon proposal.

Otherwise, I can probably get this out over the next week or so.

@mleguen
Copy link
Member

mleguen commented Mar 4, 2020

@mrmckeb Sounds great to me!

I do no longer think it better to be "fixed in one hit", as you say. Splitting this into several PR will make it more reviewable, so let's go.

@mleguen
Copy link
Member

mleguen commented Mar 4, 2020

@mrmckeb By the way, I submitted #1574 to fix #1403

@mrmckeb
Copy link

mrmckeb commented Mar 9, 2020

Thanks for the update @mleguen, I'll wait for #1574 to merge to avoid conflicts.

@wdanilo
Copy link

wdanilo commented Mar 16, 2020

Allowing to hide default and type info would be such an amazing thing. Currently this is the biggest pain for me as it just breaks the help into a nonreadable mess :(

@mleguen
Copy link
Member

mleguen commented Mar 17, 2020

it just breaks the help into a nonreadable mess

@wdanilo well, another solution could be to think about a way to display it without turning the help into a non-readable mess...

@mleguen
Copy link
Member

mleguen commented Mar 17, 2020

@wdanilo could you please open another issue to deal with this?

@zypA13510
Copy link
Contributor

@mleguen I think #1145 is exactly what @wdanilo wants. There is no need for another issue.

@bcoe
Copy link
Member

bcoe commented Sep 24, 2020

@zypA13510 if you feel like making a PR for some of your suggestions, would happily accept them.

@zypA13510
Copy link
Contributor

@bcoe Sorry, I was busy with other things last year. No promise but I'll take a look.

@bcoe
Copy link
Member

bcoe commented Apr 3, 2021

In #1574 @mleguen makes a significant improvement to the alignment of help output:

Usage: diff2html [options] -- [diff args]

Options:
  -s, --style                          Output style
                                     [choices: "line", "side"] [default: "line"]
      --synchronisedScroll, --sc       Synchronised horizontal scroll
                                                       [boolean] [default: true]
      --highlightCode, --hc            Highlight Code  [boolean] [default: true]
      --summary, --su                  Show files summary
                       [choices: "closed", "open", "hidden"] [default: "closed"]
  -d, --diffStyle                      Diff style
                                     [choices: "word", "char"] [default: "word"]
      --matching, --lm                 Diff line matching type
                           [choices: "lines", "words", "none"] [default: "none"]

And diff2html's output looks much better to me 😄 If there are additional fixes we'd like to make, let's open specific pull requests or issues, for each suggestion.

@bcoe bcoe closed this as completed Apr 3, 2021
@sorenlouv
Copy link

Linking to this related issue for visibility: #1145

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants