Skip to content

Removing long help strings from the source code #2816

@tertsdiepraam

Description

@tertsdiepraam

Some utils have long strings that are passed to the "long help" section of Clap (or "after help").

Take for instance this bit from test:

const USAGE: &str = "test EXPRESSION
or:  test
or:  [ EXPRESSION ]
or:  [ ]
or:  [ OPTION"; // unrelated, but is this a typo?

const AFTER_HELP: &str = "
Exit with the status determined by EXPRESSION.

An omitted EXPRESSION defaults to false.  Otherwise,
EXPRESSION is true or false and sets exit status.  It is one of:

  ( EXPRESSION )               EXPRESSION is true
  ! EXPRESSION                 EXPRESSION is false
  EXPRESSION1 -a EXPRESSION2   both EXPRESSION1 and EXPRESSION2 are true
  EXPRESSION1 -o EXPRESSION2   either EXPRESSION1 or EXPRESSION2 is true

  -n STRING            the length of STRING is nonzero
  STRING               equivalent to -n STRING
  -z STRING            the length of STRING is zero
  STRING1 = STRING2    the strings are equal
  STRING1 != STRING2   the strings are not equal

<and it goes on like this for a while>";

I think does not really belong in the source code because

  1. You have to scroll past it to get to the actual implementation.
  2. It requires weird formatting tricks.
  3. Writing it this way makes it hard to spot errors and does not really encourage looking at it and revising it.

The solution that I would like to propose is a new macro: help_section!. It reads the contents from a file called help.md at the crate root which can contain several sections delimited by # (like Markdown). Here is an example for numfmt:

help.md

# about
Convert numbers from/to human-readable strings

# usage
[OPTION]... [NUMBER]...

# long help
UNIT options:
   none   no auto-scaling is done; suffixes will trigger an error

   auto   accept optional single/two letter suffix:

          1K = 1000, 1Ki = 1024, 1M = 1000000, 1Mi = 1048576,

<and more>

numfmt.rs

static ABOUT: &str = help_section!("about");
static LONG_HELP: &str = help_section!("long help");

fn usage() -> String {
    format!("{} {}", uucore::execution_phrase(), help_section!("usage"))
}

I have an implementation that is (at least should be) ready for use, except for some error handling, but I wanted to discuss whether this is desirable first. There are a couple of downsides to this approach that I can think of:

  • The markdown-like syntax may be confusing as only single # are supported.
  • Some utils use dynamic strings, for instance to indicate that certain features are unsupported on a given platform. They could keep using that. The text in help.md can also be used as a string literal for a format! call. Nevertheless, it could still be weird.
  • It introduces another barrier of entry to new contributors who already have to learn about main!, gen_uumain!, show!, crash! etc..
  • The names of help.md and help_section! are also open to discussion. Maybe it should be help.txt, or the macro should take the file its reading from as an argument (like include_str!), so it would be include_section("help.md", "about") or something like that.
  • The proc macro might have a negative effect on compilation time.

What do you think?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions