diff --git a/mapper.go b/mapper.go index e6c6ad7..244dcb3 100644 --- a/mapper.go +++ b/mapper.go @@ -159,7 +159,8 @@ func (r *Registry) RegisterDefaults() *Registry { RegisterKind(reflect.Float32, floatDecoder(32)). RegisterKind(reflect.Float64, floatDecoder(64)). RegisterKind(reflect.String, MapperFunc(func(ctx *DecodeContext, target reflect.Value) error { - target.SetString(ctx.Scan.PopValue("string")) + token := ctx.Scan.PopValue("string") + target.SetString(token) return nil })). RegisterKind(reflect.Bool, boolMapper{}). @@ -294,7 +295,7 @@ func sliceDecoder(r *Registry) MapperFunc { childScanner = Scan(SplitEscaped(ctx.Scan.PopValue("list"), sep)...) } else { tokens := ctx.Scan.PopWhile(func(t Token) bool { return t.IsValue() }) - childScanner = Scan(tokens...) + childScanner = ScanFromTokens(tokens...) } childDecoder := r.ForNamedType(ctx.Value.Tag.Type, el) if childDecoder == nil { diff --git a/mapper_test.go b/mapper_test.go index 66fc679..12e982f 100644 --- a/mapper_test.go +++ b/mapper_test.go @@ -110,3 +110,13 @@ func TestURLMapper(t *testing.T) { _, err = p.Parse([]string{":foo"}) require.Error(t, err) } + +func TestSliceConsumesRemainingPositionalArgs(t *testing.T) { + var cli struct { + Remainder []string `arg:""` + } + p := mustNew(t, &cli) + _, err := p.Parse([]string{"--", "ls", "-lart"}) + require.NoError(t, err) + require.Equal(t, []string{"ls", "-lart"}, cli.Remainder) +} diff --git a/scanner.go b/scanner.go index 765f3b3..acab5e3 100644 --- a/scanner.go +++ b/scanner.go @@ -87,6 +87,11 @@ func Scan(args ...string) *Scanner { return s } +// ScanFromTokens creates a new Scanner from a slice of tokens. +func ScanFromTokens(tokens ...Token) *Scanner { + return &Scanner{args: tokens} +} + // Len returns the number of input arguments. func (s *Scanner) Len() int { return len(s.args) @@ -114,17 +119,17 @@ func (s *Scanner) PopValue(context string) string { } // PopWhile predicate returns true. -func (s *Scanner) PopWhile(predicate func(Token) bool) (values []string) { +func (s *Scanner) PopWhile(predicate func(Token) bool) (values []Token) { for predicate(s.Peek()) { - values = append(values, s.Pop().Value) + values = append(values, s.Pop()) } return } // PopUntil predicate returns true. -func (s *Scanner) PopUntil(predicate func(Token) bool) (values []string) { +func (s *Scanner) PopUntil(predicate func(Token) bool) (values []Token) { for !predicate(s.Peek()) { - values = append(values, s.Pop().Value) + values = append(values, s.Pop()) } return }