diff --git a/context.go b/context.go index 4d24161..9ca3f35 100644 --- a/context.go +++ b/context.go @@ -579,6 +579,9 @@ func (c *Context) getValue(value *Value) reflect.Value { } c.values[value] = v } + if value.Flag != nil && value.Flag.Negated { + v.SetBool(false) + } return v } @@ -639,15 +642,19 @@ func (c *Context) parseFlag(flags []*Flag, match string) (err error) { for _, flag := range flags { long := "--" + flag.Name short := "-" + string(flag.Short) + neg := "--no-" + flag.Name candidates = append(candidates, long) if flag.Short != 0 { candidates = append(candidates, short) } - if short != match && long != match { + if short != match && long != match && neg != match { continue } // Found a matching flag. c.scan.Pop() + if flag.Value.IsBool() && match == neg { + flag.Negated = true + } err := flag.Parse(c.scan, c.getValue(flag.Value)) if err != nil { if e, ok := errors.Cause(err).(*expectedError); ok && e.token.InferredType().IsAny(FlagToken, ShortFlagToken) { diff --git a/kong_test.go b/kong_test.go index 03ff1d6..e9316fe 100644 --- a/kong_test.go +++ b/kong_test.go @@ -356,6 +356,19 @@ func TestTraceErrorPartiallySucceeds(t *testing.T) { require.Equal(t, "one", ctx.Command()) } +func TestNegatedBooleanFlag(t *testing.T) { + var cli struct { + Cmd struct { + Flag bool `kong:"default='true'"` + } `kong:"cmd"` + } + + p := mustNew(t, &cli) + _, err := p.Parse([]string{"cmd", "--no-flag"}) + require.NoError(t, err) + require.Equal(t, false, cli.Cmd.Flag) +} + type hookContext struct { cmd bool values []string diff --git a/model.go b/model.go index c64cab3..8b90acc 100644 --- a/model.go +++ b/model.go @@ -227,6 +227,7 @@ type Value struct { Tag *Tag Target reflect.Value Required bool + Negated bool Set bool // Set to true when this value is set through some mechanism. Format string // Formatting directive, if applicable. Position int // Position (for positional arguments).