go-arg
go-arg copied to clipboard
Custom help text?
Is it possible to add custom help text? I'm using a custom type with a pointer receiver UnmarshalText
function which takes "columns" as inputs, which is a series of columns(in the sense of a table) and validates these according to the iota
.
This works fine and my validation does correct work. However, the help text isn't really helpful. Imagine if --columns
took a series of columns, like --columns A,B
. Which then in my "enum"
type Column int
const (
A = iota
B
)
type Config struct {
Columns []column `help:"${someCoolWayToGetStringsJoinedWithCommaAsDelimiter}`
}
Hey @Lilja- thank you for posting this. What would you like the help text to be in this case? Which strings would you like to join together?
I think it all boils down to the question:
What values can I supply to this flag?
I'll try to share my problem with some of the context of what I'm trying to build. I'm building a SSH config parser, which read the ~/.ssh/config
file and prints these out with a tool like FZF, and on enter you can ssh to it. Here is a screenshot from my python implementation. The related bit of my script to this project is to customize what columns to show in the FZF menu/filter.
In my case I have a couple of columns:
type Column int
const (
Host = iota
Username
Port
)
And for my custom validation
// A helper to show translate strings into this "iota type" (new to go, sorry if I call things incorrectly)
var columnKeys = map[Column]string {
"Host": Host,
"Username": Username,
"Port": Port,
}
type Columns = []Column
type Config struct {
// Help message not ideal, doesn't show what values are accepted.
Columns Columns `Help:"The columns to show"`
}
// and my proper validation goes something like this:
func (columns *Columns) UnmarshalText(b []byte) error {
// Behind the scenes some split by comma and then a for loop for each element. Like --column Host,Username
v, safe := columnKeys[string(b)]
if !safe {
return errors.New("Invalid value")
}
*columns = append(*columns, v)
return nil
}
Now what if --columns
is supplied --columns Nope
, the usage string will print out that it's an invalid value(as per my error in the custom validation). All right, I'll run the program with -h
and try to see what is accepted here. In this case it says --columns: The columns to show
. That isn't really helpful. Now as a potential user I would ask what can I supply to this flag?
I could start adding these into the string:
type Config struct {
Columns Columns `Help:"The columns to show. Possible value: Host,Username,Port"`
}
But that isn't very maintainable as it splits the source of truth into two places. Now if I want to add an entry into the Column type I have to add it twice.
It would be sweet if I could supply some kind of function here:
type Config struct {
// Bear in mind my Javascript syntax here. I'm more familiar with Javascript.
Columns Columns `Help:"The columns to show, possible values: Object.keys(columnKeys)"`
}
Or maybe some kind of custom help-message function?
I see. Thank you for explaining this, @Lilja. I understand your need. It seems reasonable to me. One way we could do it is with a convention where you can put a function on your struct to customize the help text for any given struct field. For example:
type Config struct {
Columns Columns
}
func (c *Config) HelpTextForColumns() string {
// do some computation here
}
Under this approach we would just make it a convention that for a field named X, you name your function HelpTextForX.
Another way would be to specify the function to call as a struct tag:
type Config struct {
Columns Columns `helpfunc:MyCustomHelpText`
}
func (c *Config) MyCustomHelpText() string {
// do some computation here
}
The main advantage of this approach that I see is that it would make it more obvious to people reading the code that this field does in fact have help text and that it is generated programmatically by a function.
A third approach is that you could use go:generate to slot the help text into the struct tag at "go generate" time.
A fourth approach is that you could just keep the tag updated manually, as you mention.
I will think about this some more. Thanks for taking the time to write this issue.
For what it's worth I like this approach:
type Config struct {
Columns Columns `helpfunc:MyCustomHelpText`
}
func (c *Config) MyCustomHelpText() string {
// do some computation here
}
Hello, We have been waiting for this for a long time! This is a must-have feature for where you want to translate your app. e.g using https://github.com/nicksnyder/go-i18n package.
Unfortunately, couldn't find any other alternatives that support this. However, i like this approach:
type Config struct {
Columns Columns
}
func (c *Config) HelpTextForColumns() string {
localizer := i18n.NewLocalizer(bundle, "en")
result, _ := localizer.Localize(
&i18n.LocalizeConfig{
DefaultMessage: &i18n.Message{
ID: "HelpText",
Other: "Nick has 2 cats.",
},
},
)
return result
}