diff --git a/argument.go b/argument.go new file mode 100644 index 0000000..d3672e7 --- /dev/null +++ b/argument.go @@ -0,0 +1,6 @@ +package cmd + +type Argument struct { + Name string + Required bool +} diff --git a/command.go b/command.go new file mode 100644 index 0000000..65178fb --- /dev/null +++ b/command.go @@ -0,0 +1,66 @@ +package cmd + +import "go.fifitido.net/cmd/flags" + +type Command struct { + Name string + ShortDescription string + LongDescription string + Aliases []string + Arguments []*Argument + Flags []flags.Flag + Subcommands []*Command + Run func(args []string) + RunE func(args []string) error + isRoot bool +} + +func NewRoot(options ...Option) *Command { + cmd := &Command{isRoot: true} + cmd.ApplyOptions(options...) + return cmd +} + +func New(name string, options ...Option) *Command { + cmd := &Command{Name: name} + cmd.ApplyOptions(options...) + return cmd +} + +func (c *Command) ApplyOptions(options ...Option) { + for _, option := range options { + option(c) + } +} + +func (c *Command) Execute(args []string) { + if len(args) == 0 { + return + } + + for _, subcommand := range c.Subcommands { + if subcommand.Name == args[0] { + subcommand.Execute(args[1:]) + return + } + + for _, alias := range subcommand.Aliases { + if alias == args[0] { + subcommand.Execute(args[1:]) + return + } + } + } + + if c.Run != nil { + c.Run(args) + return + } + + if c.RunE != nil { + if err := c.RunE(args); err != nil { + panic(err) + } + return + } +} diff --git a/flags/flag.go b/flags/flag.go new file mode 100644 index 0000000..8eb843b --- /dev/null +++ b/flags/flag.go @@ -0,0 +1,8 @@ +package flags + +type Flag interface { + Name() string + ShortName() string + Description() string + Parse(raw string) (any, error) +} diff --git a/flags/string.go b/flags/string.go new file mode 100644 index 0000000..ebc14ea --- /dev/null +++ b/flags/string.go @@ -0,0 +1,50 @@ +package flags + +type StringFlag struct { + name string + shortName string + description string + value string +} + +var _ Flag = (*StringFlag)(nil) + +func NewStringFlag(name, shortName, description, defaultValue string) *StringFlag { + return &StringFlag{ + name: name, + shortName: shortName, + description: description, + value: defaultValue, + } +} + +// Description implements Flag. +func (f *StringFlag) Description() string { + return f.description +} + +// Name implements Flag. +func (f *StringFlag) Name() string { + return f.name +} + +// ShortName implements Flag. +func (f *StringFlag) ShortName() string { + return f.shortName + +} + +// Value implements Flag. +func (f *StringFlag) Parse(raw string) (any, error) { + if raw == "" { + return f.value, nil + } + + f.value = raw + + return raw, nil +} + +func (f *StringFlag) Value() string { + return f.value +} diff --git a/option.go b/option.go new file mode 100644 index 0000000..89783d5 --- /dev/null +++ b/option.go @@ -0,0 +1,41 @@ +package cmd + +import "go.fifitido.net/cmd/flags" + +type Option func(*Command) + +func WithArgument(name string, required bool) Option { + return func(c *Command) { + c.Arguments = append(c.Arguments, &Argument{name, required}) + } +} + +func WithArguments(args []*Argument) Option { + return func(c *Command) { + c.Arguments = append(c.Arguments, args...) + } +} + +func WithFlag(f flags.Flag) Option { + return func(c *Command) { + c.Flags = append(c.Flags, f) + } +} + +func WithFlags(fs []flags.Flag) Option { + return func(c *Command) { + c.Flags = append(c.Flags, fs...) + } +} + +func WithSubcommand(s *Command) Option { + return func(c *Command) { + c.Subcommands = append(c.Subcommands, s) + } +} + +func WithSubcommands(ss []*Command) Option { + return func(c *Command) { + c.Subcommands = append(c.Subcommands, ss...) + } +}