Skip to content

Commit

Permalink
Merge pull request #181 from rsteube/fix-nonposix
Browse files Browse the repository at this point in the history
fix nonposix
  • Loading branch information
rsteube authored Jul 21, 2023
2 parents cea7829 + 1eab222 commit 6ae4a6a
Show file tree
Hide file tree
Showing 9 changed files with 355 additions and 145 deletions.
2 changes: 1 addition & 1 deletion example/nonposix.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: nonposix
description:
flags:
-opt, -optarg?: both nonposix
-styled=: nonpoxis shorthand
-styled=: nonposix shorthand
-mx, --mixed*: mixed repeatable
completion:
flag:
Expand Down
12 changes: 12 additions & 0 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (

"github.com/rsteube/carapace"
"github.com/rsteube/carapace/pkg/sandbox"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
)

//go:embed example/runnable.yaml
Expand All @@ -26,3 +28,13 @@ func TestRunnable(t *testing.T) {
Tag("commands"))
})
}

func sandboxSpec(t *testing.T, spec string) (f func(func(s *sandbox.Sandbox))) {
var command Command
if err := yaml.Unmarshal([]byte(spec), &command); err != nil {
panic(err.Error())
}
return sandbox.Command(t, func() *cobra.Command {
return command.ToCobra()
})
}
64 changes: 32 additions & 32 deletions flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ import (
)

type flag struct {
longhand string
shorthand string
usage string
slice bool
optarg bool
value bool
nonposix bool
hidden bool
required bool
longhand string
shorthand string
usage string
slice bool
optarg bool
value bool
nameAsShorthand bool
hidden bool
required bool
}

func parseFlag(s, usage string) (*flag, error) {
Expand All @@ -30,8 +30,8 @@ func parseFlag(s, usage string) (*flag, error) {

f := &flag{}
f.longhand = strings.TrimLeft(matches["longhand"], "-")
f.nonposix = matches["longhand"] != "" && !strings.HasPrefix(matches["longhand"], "--")
f.shorthand = strings.TrimPrefix(matches["shorthand"], "-")
f.nameAsShorthand = (matches["longhand"] != "" && !strings.HasPrefix(matches["longhand"], "--"))
f.usage = usage
f.slice = strings.Contains(matches["modifier"], "*")
f.optarg = strings.Contains(matches["modifier"], "?")
Expand All @@ -57,57 +57,57 @@ func (f flag) addTo(fset *pflag.FlagSet) error {
if f.longhand != "" && f.shorthand != "" {
if f.value {
if f.slice {
if !f.nonposix {
fs.StringSliceP(f.longhand, f.shorthand, []string{}, f.usage)
} else {
if f.nameAsShorthand {
fs.StringSliceN(f.longhand, f.shorthand, []string{}, f.usage)
} else {
fs.StringSliceP(f.longhand, f.shorthand, []string{}, f.usage)
}
} else {
if !f.nonposix {
fs.StringP(f.longhand, f.shorthand, "", f.usage)
} else {
if f.nameAsShorthand {
fs.StringN(f.longhand, f.shorthand, "", f.usage)
} else {
fs.StringP(f.longhand, f.shorthand, "", f.usage)
}
}
} else {
if f.slice {
if !f.nonposix {
fs.CountP(f.longhand, f.shorthand, f.usage)
} else {
if f.nameAsShorthand {
fs.CountN(f.longhand, f.shorthand, f.usage)
} else {
fs.CountP(f.longhand, f.shorthand, f.usage)
}
} else {
if !f.nonposix {
fs.BoolP(f.longhand, f.shorthand, false, f.usage)
} else {
if f.nameAsShorthand {
fs.BoolN(f.longhand, f.shorthand, false, f.usage)
} else {
fs.BoolP(f.longhand, f.shorthand, false, f.usage)
}
}
}
} else if f.longhand != "" {
if f.value {
if f.slice {
if !f.nonposix {
fs.StringSlice(f.longhand, []string{}, f.usage)
} else {
if f.nameAsShorthand {
fs.StringSliceS(f.longhand, f.longhand, []string{}, f.usage)
} else {
fs.StringSlice(f.longhand, []string{}, f.usage)
}
} else {
if !f.nonposix {
fs.String(f.longhand, "", f.usage)
} else {
if f.nameAsShorthand {
fs.StringS(f.longhand, f.longhand, "", f.usage)
} else {
fs.String(f.longhand, "", f.usage)
}
}
} else {
if f.slice {
if !f.nonposix {
fs.Count(f.longhand, f.usage)
} else {
if f.nameAsShorthand {
fs.CountS(f.longhand, f.longhand, f.usage)
} else {
fs.Count(f.longhand, f.usage)
}
} else {
if !f.nonposix {
if !f.nameAsShorthand {
fs.Bool(f.longhand, false, f.usage)
} else {
fs.BoolS(f.longhand, f.longhand, false, f.usage)
Expand Down
14 changes: 7 additions & 7 deletions flag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,15 @@ func TestParseFlag(t *testing.T) {
})

test("nonposix both", "-short, -long*", &flag{
shorthand: "short",
longhand: "long",
slice: true,
nonposix: true,
shorthand: "short",
longhand: "long",
slice: true,
nameAsShorthand: true,
})

test("nonposix mixed", "-short, --long", &flag{
shorthand: "short",
longhand: "long",
nonposix: false,
shorthand: "short",
longhand: "long",
nameAsShorthand: false,
})
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.18

require (
github.com/invopop/jsonschema v0.7.0
github.com/rsteube/carapace v0.39.1
github.com/rsteube/carapace v0.39.2
github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5
gopkg.in/yaml.v3 v3.0.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ github.com/invopop/jsonschema v0.7.0 h1:2vgQcBz1n256N+FpX3Jq7Y17AjYt46Ig3zIWyy77
github.com/invopop/jsonschema v0.7.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rsteube/carapace v0.39.1 h1:ZEBhfRn5BvRyZkR8tdwvXP2/35ZMj6rZ/K2anCPbSFU=
github.com/rsteube/carapace v0.39.1/go.mod h1:jkLt41Ne2TD2xPuMdX/2O05Smhy8vMgG7O2TYvC0yOc=
github.com/rsteube/carapace v0.39.2 h1:Fy577GqW96r3l/mfcSJf022Ed3SUsn9gNRFu86KLO6Q=
github.com/rsteube/carapace v0.39.2/go.mod h1:jkLt41Ne2TD2xPuMdX/2O05Smhy8vMgG7O2TYvC0yOc=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
Expand Down
176 changes: 176 additions & 0 deletions internal/pflagfork/flag.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
package pflagfork

import (
"fmt"
"reflect"
"strings"

"github.com/rsteube/carapace/pkg/style"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)

// mode defines how flags are represented.
type mode int

const (
Default mode = iota // default behaviour
ShorthandOnly // only the shorthand should be used
NameAsShorthand // non-posix mode where the name is also added as shorthand (single `-` prefix)
)

type Flag struct {
*pflag.Flag
}

func (f Flag) Nargs() int {
if field := reflect.ValueOf(f.Flag).Elem().FieldByName("Nargs"); field.IsValid() && field.Kind() == reflect.Int {
return int(field.Int())
}
return 0
}

func (f Flag) Mode() mode {
if field := reflect.ValueOf(f.Flag).Elem().FieldByName("Mode"); field.IsValid() && field.Kind() == reflect.Int {
return mode(field.Int())
}
return Default
}

func (f Flag) OptargDelimiter() rune {
if field := reflect.ValueOf(f.Flag).Elem().FieldByName("OptargDelimiter"); field.IsValid() && field.Kind() == reflect.Int32 {
return (rune(field.Int()))
}
return '='
}

func (f Flag) IsRepeatable() bool {
if strings.Contains(f.Value.Type(), "Slice") ||
strings.Contains(f.Value.Type(), "Array") ||
f.Value.Type() == "count" {
return true
}
return false
}

func (f Flag) Split(arg string) (prefix, optarg string) {
delimiter := string(f.OptargDelimiter())
splitted := strings.SplitN(arg, delimiter, 2)
return splitted[0] + delimiter, splitted[1]
}

func (f Flag) Matches(arg string, posix bool) bool {
if !strings.HasPrefix(arg, "-") { // not a flag
return false
}

switch {

case strings.HasPrefix(arg, "--"):
name := strings.TrimPrefix(arg, "--")
name = strings.SplitN(name, string(f.OptargDelimiter()), 2)[0]

switch f.Mode() {
case ShorthandOnly, NameAsShorthand:
return false
default:
return name == f.Name
}

case !posix:
name := strings.TrimPrefix(arg, "-")
name = strings.SplitN(name, string(f.OptargDelimiter()), 2)[0]

if name == "" {
return false
}

switch f.Mode() {
case ShorthandOnly:
return name == f.Shorthand
default:
return name == f.Name || name == f.Shorthand
}

default:
if f.Shorthand != "" {
return strings.HasSuffix(arg, f.Shorthand)
}
return false
}
}

func (f Flag) TakesValue() bool {
switch f.Value.Type() {
case "bool", "boolSlice", "count":
return false
default:
return true
}
}

func (f Flag) IsOptarg() bool {
return f.NoOptDefVal != ""
}

func (f Flag) Style() string {
switch {
case !f.TakesValue():
return style.Carapace.FlagNoArg
case f.IsOptarg():
return style.Carapace.FlagOptArg
case f.Nargs() != 0:
return style.Carapace.FlagMultiArg
default:
return style.Carapace.FlagArg
}
}

func (f Flag) Required() bool {
if annotation := f.Annotations[cobra.BashCompOneRequiredFlag]; len(annotation) == 1 && annotation[0] == "true" {
return true
}
return false
}

func (f Flag) Definition() string {
var definition string
switch f.Mode() {
case ShorthandOnly:
definition = fmt.Sprintf("-%v", f.Shorthand)
case NameAsShorthand:
definition = fmt.Sprintf("-%v, -%v", f.Shorthand, f.Name)
default:
switch f.Shorthand {
case "":
definition = fmt.Sprintf("--%v", f.Name)
default:
definition = fmt.Sprintf("-%v, --%v", f.Shorthand, f.Name)
}
}

if f.Hidden {
definition += "&"
}

if f.Required() {
definition += "!"
}

if f.IsRepeatable() {
definition += "*"
}

switch {
case f.IsOptarg():
switch f.Value.Type() {
case "bool", "boolSlice", "count":
default:
definition += "?"
}
case f.TakesValue():
definition += "="
}

return definition
}
Loading

0 comments on commit 6ae4a6a

Please sign in to comment.