Improve readability of help text
Checklist
- [x] Are you running the latest v3 release? The list of releases is here.
- [x] Did you check the manual for your release? The v3 manual is here.
- [x] Did you perform a search about this feature? Here's the GitHub guide about searching.
What problem does this solve?
Currently help text for flags is not very readable and looks all over the place, even when defining a custom Printer with a custom wrapAt
ex:
GLOBAL OPTIONS:
--listen value, --address value address on which the router will be listening on, ie: "localhost:11434"
(default: "localhost:11434") [$GOLLAMAS_LISTEN, $LISTEN]
--level value, --error-level value error level, can be any of panic|fatal|error|warning|info|debug|trace
(default: "error") [$GOLLAMAS_LEVEL, $LEVEL]
--proxy value [ --proxy value ] assigns a destination for a model, can be a url or a connection id ex: --proxy
'llama3.2-vision=http://server:11434'] ex: --proxy 'llama3.2-vision=c1 --connection c1=http://server:11434'
--proxies value assigns destinations for the models, in the list of model=destination pairs ex: --proxies
'llama3.2-vision=http://server:11434,deepseek-r1:14b=http://server2:11434' [$GOLLAMAS_PROXIES, $PROXIES]
--connection value [ --connection value ] assigns an identifier to a connection which can be reffered to by
proxy declarations ex: --connection c1=http://server:11434 --proxy llama=c1
GLOBAL OPTIONS:
--listen value, --address value address on which the router will be listening
on, ie: "localhost:11434"
(default: "localhost:11434") [$GOLLAMAS_LISTEN, $LISTEN]
--level value, --error-level value error level, can be any of
panic|fatal|error|warning|info|debug|trace
(default: "error") [$GOLLAMAS_LEVEL, $LEVEL]
--proxy value [ --proxy value ] assigns a destination for a model, can be a url
or a connection id ex: --proxy 'llama3.2-vision=http://server:11434'] ex:
--proxy 'llama3.2-vision=c1 --connection c1=http://server:11434'
--proxies value assigns destinations for the models, in the list of
model=destination pairs ex: --proxies
'llama3.2-vision=http://server:11434,deepseek-r1:14b=http://server2:11434'
[$GOLLAMAS_PROXIES, $PROXIES]
--connection value [ --connection value ] assigns an identifier to a connection
which can be reffered to by proxy declarations ex: --connection
c1=http://server:11434 --proxy llama=c1
--connections value provides a list of connections which can be reffered to by
id ex: --connections c1=http://server:11434,c2=http://server2:11434
[$GOLLAMAS_CONNECTIONS, $CONNECTIONS]
Notice when a default is declared the line for default indents further and is more readable.
Solution description
The lines which have been wrapped should also be indented to the same level as the (default: ... ) text or simply to the start of the description column like in the docker documentation:
Global Options:
--config string Location of client config files (default
"/home/vscode/.docker")
-c, --context string Name of the context to use to connect to the daemon
(overrides DOCKER_HOST env var and default context
set with "docker context use")
-D, --debug Enable debug mode
-H, --host list Daemon socket to connect to
-l, --log-level string Set the logging level ("debug", "info", "warn",
"error", "fatal") (default "info")
--tls Use TLS; implied by --tlsverify
currently I use this function to wrap the lines in the helper:
cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) {
funcMap := map[string]interface{}{
"wrapAt": func() int {
w := 10000
tid := int(os.Stdout.Fd())
if term.IsTerminal(tid) {
width, _, err := term.GetSize(tid)
println("width", width)
if err == nil {
w = width - 1
}
}
return w
},
}
cli.HelpPrinterCustom(w, templ, data, funcMap)
}
I would like the behavior to be:
- wrapped lines start at the beginning of the description column
- if there is not enough space they display like the default line
- if necessary I would like to pass a function to override that behavior with something like
"wrapTo":func(int)or"indentBy":func(int)
Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.
Or maybe, to save on horizontal screen real estate:
GLOBAL OPTIONS:
--listen value
--address value
address on which the router will be listening on, ie: "localhost:11434"
(default: "localhost:11434") [$GOLLAMAS_LISTEN, $LISTEN]
--level value
--error-level value
error level, can be any of panic|fatal|error|warning|info|debug|trace
(default: "error") [$GOLLAMAS_LEVEL, $LEVEL]
--proxy value [ --proxy value ]
assigns a destination for a model, can be a url or a connection id ex:
--proxy 'llama3.2-vision=http://server:11434'] ex: --proxy 'llama3.
2-vision=c1 --connection c1=http://server:11434'
--proxies value
assigns destinations for the models, in the list of model=destination
pairs ex: --proxies
'llama3.2-vision=http://server:11434,deepseek-r1:14b=http://server2:11434'
[$GOLLAMAS_PROXIES, $PROXIES]
--connection value [ --connection value ]
assigns an identifier to a connection which can be reffered to by proxy
declarations ex: --connection c1=http://server:11434 --proxy llama=c1
--connections value
provides a list of connections which can be reffered to by id ex: --connections
c1=http://server:11434,c2=http://server2:11434
[$GOLLAMAS_CONNECTIONS, $CONNECTIONS]
@Skeeve it does look neater, but wrapping the flags can lead to confusion. For example the 2 first lines don't make it obvious it is the same options. My current case is not the nicest for real estate as I have multiple flags for the same thing currently due exploring and renaming features before a proper release.
Maybe this way?
GLOBAL OPTIONS:
--listen value OR
--address value
address on which the router will be listening on, ie: "localhost:11434"
(default: "localhost:11434") [$GOLLAMAS_LISTEN, $LISTEN]
--level value OR
--error-level value
error level, can be any of panic|fatal|error|warning|info|debug|trace
(default: "error") [$GOLLAMAS_LEVEL, $LEVEL]
--proxy value [ --proxy value ]
assigns a destination for a model, can be a url or a connection id ex:
--proxy 'llama3.2-vision=http://server:11434'] ex: --proxy 'llama3.
2-vision=c1 --connection c1=http://server:11434'
--proxies value
assigns destinations for the models, in the list of model=destination
pairs ex: --proxies
'llama3.2-vision=http://server:11434,deepseek-r1:14b=http://server2:11434'
[$GOLLAMAS_PROXIES, $PROXIES]
--connection value [ --connection value ]
assigns an identifier to a connection which can be reffered to by proxy
declarations ex: --connection c1=http://server:11434 --proxy llama=c1
--connections value
provides a list of connections which can be reffered to by id ex: --connections
c1=http://server:11434,c2=http://server2:11434
[$GOLLAMAS_CONNECTIONS, $CONNECTIONS]
Alternatively, options without a help text could get an empty line. So let's assume the first two are different options where --listen doesn't have a help text:
GLOBAL OPTIONS:
--listen value
--address value
address on which the router will be listening on, ie: "localhost:11434"
(default: "localhost:11434") [$GOLLAMAS_LISTEN, $LISTEN]
--level value
--error-level value
error level, can be any of panic|fatal|error|warning|info|debug|trace
(default: "error") [$GOLLAMAS_LEVEL, $LEVEL]
Doesn't look nice, but on the other hand: What good is an option you do not explain?
Or, instead of empty:
GLOBAL OPTIONS:
--listen value
/no help available/
--address value
address on which the router will be listening on, ie: "localhost:11434"
(default: "localhost:11434") [$GOLLAMAS_LISTEN, $LISTEN]
--level value
--error-level value
error level, can be any of panic|fatal|error|warning|info|debug|trace
(default: "error") [$GOLLAMAS_LEVEL, $LEVEL]
Or maybe something like this
GLOBAL OPTIONS:
--listen value/
--address value
address on which the router will be listening on, ie: "localhost:11434"
(default: "localhost:11434") [$GOLLAMAS_LISTEN, $LISTEN]
....
T.b.h. A "/" would confuse me.
Personally I would prefer a hint that there is no help for that option. As I said before: What good is an option you don't explain? With that hint the author might be tempted to add at least something.
So any options on consecutive lines are the alternatives.
If we really want a visual hint that they are alternatives, I guess the "OR" would be good. Maybe, to not confuse it with any flag-related values, indent it by a few blanks?
GLOBAL OPTIONS:
--listen value OR
--address value
address on which the router will be listening on, ie: "localhost:11434"
(default: "localhost:11434") [$GOLLAMAS_LISTEN, $LISTEN]
....
I just checked a few man pages (ls, curl, git). All of them go the "Comma-way" and "Option on its own line"
-H, --header <header/@file>
(HTTP IMAP SMTP) Extra header to include in information sent. When used within an HTTP request, it is
added to the regular request headers.
Except when the option is short:
-B Force printing of non-printable characters (as defined by ctype(3) and current locale settings) in
file names as \xxx, where xxx is the numeric value of the character in octal. This option is not
defined in IEEE Std 1003.1-2008 (“POSIX.1”).
-C Force multi-column output; this is the default when output is to a terminal.
-D format
When printing in the long (-l) format, use format to format the date and time output. The argument
format is a string used by strftime(3). Depending on the choice of format string, this may result in
a different number of columns in the output. This option overrides the -T option. This option is not
defined in IEEE Std 1003.1-2008 (“POSIX.1”).
-F Display a slash (‘/’) immediately after each pathname that is a directory, an asterisk (‘*’) after
And they always have an empty line between options.
@Skeeve I like the idea of going with a more standardized output.
Although curl help looks like this and doesn't wrap
curl --help
Usage: curl [options...] <url>
-d, --data <data> HTTP POST data
-f, --fail Fail fast with no output on HTTP errors
-h, --help <category> Get help for commands
-i, --include Include response headers in output
-o, --output <file> Write to file instead of stdout
-O, --remote-name Write output to file named as remote file
-s, --silent Silent mode
-T, --upload-file <file> Transfer local FILE to destination
-u, --user <user:password> Server user and password
-A, --user-agent <name> Send User-Agent <name> to server
-v, --verbose Make the operation more talkative
-V, --version Show version number and quit
@dearchap would it be acceptable for the project to include a few different standardized output printer as an option?
@Skeeve I like the idea of going with a more standardized output.
Although curl help looks like this and doesn't wrap
curl --help Usage: curl [options...] <url> -d, --data <data> HTTP POST data -f, --fail Fail fast with no output on HTTP errors -h, --help <category> Get help for commands -i, --include Include response headers in output -o, --output <file> Write to file instead of stdout -O, --remote-name Write output to file named as remote file -s, --silent Silent mode -T, --upload-file <file> Transfer local FILE to destination -u, --user <user:password> Server user and password -A, --user-agent <name> Send User-Agent <name> to server -v, --verbose Make the operation more talkative -V, --version Show version number and quit@dearchap would it be acceptable for the project to include a few different standardized output printer as an option?
Yes. That's the help page. I looked ad the man page. Usually they are different, as we can see here. Otoh: There is no man page option in cli, or is it? So the help is more or less also the man page. At least for me that is. And if you look at a standard help output of cli programs, the similarities to man pages are there, don't you think?
Yes I've been dreaming up the idea of a "help personality". User can set the "help personality" to say ls or git style and the help output will match that of those commands. !!!!
Maybe take a look at what Pod::Usage in perl does. Okay… It extracts man and help text from "Plain Old Documentation", but maybe there is something which inspires you?
Depending on what you pass to pod2usage, it shows different sections of the usage text. Maybe that's something to consider. So you could call any cli --help to get just the options displayed, or cli --man to get a full man-page.
I had a look at the template system and I roughly understand how it works.
I have a question, I assume HelpPrinter existed first and HelpPrinterCustom was added afterwards and now there are 2 functions due to backwards compatibility. For a full release would it not make sense to keep only one and avoid the issue of having 2 functions which are used in 2 different scenarios?
If it's OK to break compatibility before release would you consider something along these lines:
type HelpPrinterConfig struct {
Template string
CustomFuncs map[string]interface{}
}
// printHelpCustom is the default implementation of HelpPrinterCustom.
//
// The customFuncs map will be combined with a default template.FuncMap to
// allow using arbitrary functions in template rendering.
func printHelpCustom(out io.Writer, templ HelpPrinterConfig, data interface{}) {
...
I propose making the formatting style easier to configure, with options such as:
- Two columns with aligned and properly wrapped descriptions, similar to the "Solution description" example or
curl --help. This behavior already exists for subcommands via theoffsetCommandsfunction. - Descriptions placed on the next line, as shown here.
If this can only be done through templates, please provide constants with these implementations so users don't have to write the templates themselves. Ideally, it should be possible to simply set a variable (or, even better, specify an argument or field) to choose one of these formatting styles.