Merge pull request #228 from nickwei84/master

Completion on short option names allows for exploration of short and long option names
diff --git a/completion.go b/completion.go
index cca12a7..7a7a08b 100644
--- a/completion.go
+++ b/completion.go
@@ -136,6 +136,9 @@
 }
 
 func (c *completion) completeValue(value reflect.Value, prefix string, match string) []Completion {
+	if value.Kind() == reflect.Slice {
+		value = reflect.New(value.Type().Elem())
+	}
 	i := value.Interface()
 
 	var ret []Completion
@@ -155,16 +158,6 @@
 	return ret
 }
 
-func (c *completion) completeArg(arg *Arg, prefix string, match string) []Completion {
-	if arg.isRemaining() {
-		// For remaining positional args (that are parsed into a slice), complete
-		// based on the element type.
-		return c.completeValue(reflect.New(arg.value.Type().Elem()), prefix, match)
-	}
-
-	return c.completeValue(arg.value, prefix, match)
-}
-
 func (c *completion) complete(args []string) []Completion {
 	if len(args) == 0 {
 		args = []string{""}
@@ -279,7 +272,7 @@
 		}
 	} else if len(s.positional) > 0 {
 		// Complete for positional argument
-		ret = c.completeArg(s.positional[0], "", lastarg)
+		ret = c.completeValue(s.positional[0].value, "", lastarg)
 	} else if len(s.command.commands) > 0 {
 		// Complete for command
 		ret = c.completeCommands(s, lastarg)
diff --git a/completion_test.go b/completion_test.go
index 3a1a2ce..26f70e4 100644
--- a/completion_test.go
+++ b/completion_test.go
@@ -53,8 +53,13 @@
 		Positional struct {
 			Filename []Filename
 		} `positional-args:"yes"`
+		Extra []Filename `short:"f"`
 	} `command:"add-multi" description:"add multiple items"`
 
+	AddMultiCommandFlag struct {
+		Files []Filename `short:"f"`
+	} `command:"add-multi-flag" description:"add multiple items via flags"`
+
 	RemoveCommand struct {
 		Other bool     `short:"o"`
 		File  Filename `short:"f" long:"filename"`
@@ -130,7 +135,7 @@
 		{
 			// Commands
 			[]string{""},
-			[]string{"add", "add-multi", "rename", "rm"},
+			[]string{"add", "add-multi", "add-multi-flag", "rename", "rm"},
 			false,
 		},
 
@@ -138,10 +143,11 @@
 			// Commands with descriptions
 			[]string{""},
 			[]string{
-				"add        # add an item",
-				"add-multi  # add multiple items",
-				"rename     # rename an item",
-				"rm         # remove an item",
+				"add             # add an item",
+				"add-multi       # add multiple items",
+				"add-multi-flag  # add multiple items via flags",
+				"rename          # rename an item",
+				"rm              # remove an item",
 			},
 			true,
 		},
@@ -227,6 +233,12 @@
 			[]string{"hello universe"},
 			false,
 		},
+		{
+			// Multiple flag filename
+			[]string{"add-multi-flag", "-f", filepath.Join(completionTestSourcedir, "completion")},
+			completionTestFilename,
+			false,
+		},
 	}
 }
 
diff --git a/group.go b/group.go
index 51b4704..6133a71 100644
--- a/group.go
+++ b/group.go
@@ -174,6 +174,10 @@
 	}
 }
 
+func isStringFalsy(s string) bool {
+	return s == "" || s == "false" || s == "no" || s == "0"
+}
+
 func (g *Group) scanStruct(realval reflect.Value, sfield *reflect.StructField, handler scanHandler) error {
 	stype := realval.Type()
 
@@ -255,10 +259,10 @@
 		valueName := mtag.Get("value-name")
 		defaultMask := mtag.Get("default-mask")
 
-		optional := (mtag.Get("optional") != "")
-		required := (mtag.Get("required") != "")
+		optional := !isStringFalsy(mtag.Get("optional"))
+		required := !isStringFalsy(mtag.Get("required"))
 		choices := mtag.GetMany("choice")
-		hidden := (mtag.Get("hidden") != "")
+		hidden := !isStringFalsy(mtag.Get("hidden"))
 
 		option := &Option{
 			Description:      description,
diff --git a/help.go b/help.go
index 9167847..d380305 100644
--- a/help.go
+++ b/help.go
@@ -216,8 +216,10 @@
 
 		var def string
 
-		if len(option.DefaultMask) != 0 && option.DefaultMask != "-" {
-			def = option.DefaultMask
+		if len(option.DefaultMask) != 0 {
+			if option.DefaultMask != "-" {
+				def = option.DefaultMask
+			}
 		} else {
 			def = option.defaultLiteral
 		}
diff --git a/help_test.go b/help_test.go
index 01942a2..bb76640 100644
--- a/help_test.go
+++ b/help_test.go
@@ -1,10 +1,12 @@
 package flags
 
 import (
+	"bufio"
 	"bytes"
 	"fmt"
 	"os"
 	"runtime"
+	"strings"
 	"testing"
 	"time"
 )
@@ -36,8 +38,9 @@
 	} `group:"Hidden group" hidden:"yes"`
 
 	Group struct {
-		Opt               string `long:"opt" description:"This is a subgroup option"`
-		HiddenInsideGroup string `long:"hidden-inside-group" description:"Hidden inside group" hidden:"yes"`
+		Opt                  string `long:"opt" description:"This is a subgroup option"`
+		HiddenInsideGroup    string `long:"hidden-inside-group" description:"Hidden inside group" hidden:"yes"`
+		NotHiddenInsideGroup string `long:"not-hidden-inside-group" description:"Not hidden inside group" hidden:"false"`
 
 		Group struct {
 			Opt string `long:"opt" description:"This is a subsubgroup option"`
@@ -113,6 +116,7 @@
 
 Subgroup:
       /sip.opt:                             This is a subgroup option
+      /sip.not-hidden-inside-group:         Not hidden inside group
 
 Subsubgroup:
       /sip.sap.opt:                         This is a subsubgroup option
@@ -159,6 +163,7 @@
 
 Subgroup:
       --sip.opt=                            This is a subgroup option
+      --sip.not-hidden-inside-group=        Not hidden inside group
 
 Subsubgroup:
       --sip.sap.opt=                        This is a subsubgroup option
@@ -261,6 +266,9 @@
 .TP
 \fB\fB\-\-sip.opt\fR\fP
 This is a subgroup option
+.TP
+\fB\fB\-\-sip.not-hidden-inside-group\fR\fP
+Not hidden inside group
 .SS Subsubgroup
 .TP
 \fB\fB\-\-sip.sap.opt\fR\fP
@@ -466,3 +474,65 @@
 
 	assertDiff(t, got, expected, "wrapped paragraph")
 }
+
+func TestHelpDefaultMask(t *testing.T) {
+	var tests = []struct {
+		opts    interface{}
+		present string
+	}{
+		{
+			opts: &struct {
+				Value string `short:"v" default:"123" description:"V"`
+			}{},
+			present: "V (default: 123)\n",
+		},
+		{
+			opts: &struct {
+				Value string `short:"v" default:"123" default-mask:"abc" description:"V"`
+			}{},
+			present: "V (default: abc)\n",
+		},
+		{
+			opts: &struct {
+				Value string `short:"v" default:"123" default-mask:"-" description:"V"`
+			}{},
+			present: "V\n",
+		},
+		{
+			opts: &struct {
+				Value string `short:"v" description:"V"`
+			}{Value: "123"},
+			present: "V (default: 123)\n",
+		},
+		{
+			opts: &struct {
+				Value string `short:"v" default-mask:"abc" description:"V"`
+			}{Value: "123"},
+			present: "V (default: abc)\n",
+		},
+		{
+			opts: &struct {
+				Value string `short:"v" default-mask:"-" description:"V"`
+			}{Value: "123"},
+			present: "V\n",
+		},
+	}
+
+	for _, test := range tests {
+		p := NewParser(test.opts, HelpFlag)
+		_, err := p.ParseArgs([]string{"-h"})
+		if flagsErr, ok := err.(*Error); ok && flagsErr.Type == ErrHelp {
+			err = nil
+		}
+		if err != nil {
+			t.Fatalf("Unexpected error: %v", err)
+		}
+		h := &bytes.Buffer{}
+		w := bufio.NewWriter(h)
+		p.writeHelpOption(w, p.FindOptionByShortName('v'), p.getAlignmentInfo())
+		w.Flush()
+		if strings.Index(h.String(), test.present) < 0 {
+			t.Errorf("Not present %q\n%s", test.present, h.String())
+		}
+	}
+}
diff --git a/ini_test.go b/ini_test.go
index e1f22ce..ad4852e 100644
--- a/ini_test.go
+++ b/ini_test.go
@@ -93,6 +93,9 @@
 ; This is a subgroup option
 Opt =
 
+; Not hidden inside group
+NotHiddenInsideGroup =
+
 [Subsubgroup]
 ; This is a subsubgroup option
 Opt =
@@ -153,6 +156,9 @@
 ; This is a subgroup option
 ; Opt =
 
+; Not hidden inside group
+; NotHiddenInsideGroup =
+
 [Subsubgroup]
 ; This is a subsubgroup option
 ; Opt =
@@ -211,6 +217,9 @@
 ; This is a subgroup option
 ; Opt =
 
+; Not hidden inside group
+; NotHiddenInsideGroup =
+
 [Subsubgroup]
 ; This is a subsubgroup option
 ; Opt =
diff --git a/option.go b/option.go
index 8270a22..ea09fb4 100644
--- a/option.go
+++ b/option.go
@@ -179,7 +179,7 @@
 	return option.isSet
 }
 
-// IsSet returns true if option has been set via the default option tag
+// IsSetDefault returns true if option has been set via the default option tag
 func (option *Option) IsSetDefault() bool {
 	return option.isSetDefault
 }
diff --git a/parser.go b/parser.go
index fd2fd5f..0a7922a 100644
--- a/parser.go
+++ b/parser.go
@@ -479,7 +479,7 @@
 			msg = fmt.Sprintf("%s. You should use the %s command",
 				msg,
 				cmdnames[0])
-		} else {
+		} else if len(cmdnames) > 1 {
 			msg = fmt.Sprintf("%s. Please specify one command of: %s or %s",
 				msg,
 				strings.Join(cmdnames[:len(cmdnames)-1], ", "),
@@ -490,7 +490,7 @@
 
 		if len(cmdnames) == 1 {
 			msg = fmt.Sprintf("Please specify the %s command", cmdnames[0])
-		} else {
+		} else if len(cmdnames) > 1 {
 			msg = fmt.Sprintf("Please specify one command of: %s or %s",
 				strings.Join(cmdnames[:len(cmdnames)-1], ", "),
 				cmdnames[len(cmdnames)-1])
diff --git a/short_test.go b/short_test.go
index 95712c1..5f4106b 100644
--- a/short_test.go
+++ b/short_test.go
@@ -35,6 +35,22 @@
 	assertParseFail(t, ErrRequired, fmt.Sprintf("the required flag `%cv' was not specified", defaultShortOptDelimiter), &opts)
 }
 
+func TestShortRequiredFalsy1(t *testing.T) {
+	var opts = struct {
+		Value bool `short:"v" required:"false"`
+	}{}
+
+	assertParseSuccess(t, &opts)
+}
+
+func TestShortRequiredFalsy2(t *testing.T) {
+	var opts = struct {
+		Value bool `short:"v" required:"no"`
+	}{}
+
+	assertParseSuccess(t, &opts)
+}
+
 func TestShortMultiConcat(t *testing.T) {
 	var opts = struct {
 		V bool `short:"v"`
@@ -192,3 +208,27 @@
 	assertStringArray(t, ret, []string{"f"})
 	assertString(t, opts.Value, "value")
 }
+
+func TestShortOptionalFalsy1(t *testing.T) {
+	var opts = struct {
+		F     []bool `short:"f"`
+		Value string `short:"v" optional:"false" optional-value:"value"`
+	}{}
+
+	ret := assertParseSuccess(t, &opts, "-fv", "f")
+
+	assertStringArray(t, ret, []string{})
+	assertString(t, opts.Value, "f")
+}
+
+func TestShortOptionalFalsy2(t *testing.T) {
+	var opts = struct {
+		F     []bool `short:"f"`
+		Value string `short:"v" optional:"no" optional-value:"value"`
+	}{}
+
+	ret := assertParseSuccess(t, &opts, "-fv", "f")
+
+	assertStringArray(t, ret, []string{})
+	assertString(t, opts.Value, "f")
+}