diff --git a/internal/spec/command.go b/internal/spec/command.go deleted file mode 100644 index f3db47b38..000000000 --- a/internal/spec/command.go +++ /dev/null @@ -1,20 +0,0 @@ -package spec - -type Command struct { - Name string `yaml:"name"` - Aliases []string `yaml:"aliases,omitempty"` - Description string `yaml:"description,omitempty"` - Group string `yaml:"group,omitempty"` - Hidden bool `yaml:"hidden,omitempty"` - ExclusiveFlags [][]string `yaml:"exclusiveflags,omitempty"` - Flags map[string]string `yaml:"flags,omitempty"` - PersistentFlags map[string]string `yaml:"persistentflags,omitempty"` - Completion struct { - Flag map[string][]string `yaml:"flag,omitempty"` - Positional [][]string `yaml:"positional,omitempty"` - PositionalAny []string `yaml:"positionalany,omitempty"` - Dash [][]string `yaml:"dash,omitempty"` - DashAny []string `yaml:"dashany,omitempty"` - } `yaml:"completion,omitempty"` - Commands []Command `yaml:"commands,omitempty"` -} diff --git a/internal/spec/command/command.go b/internal/spec/command/command.go new file mode 100644 index 000000000..fe96ea222 --- /dev/null +++ b/internal/spec/command/command.go @@ -0,0 +1,49 @@ +package command + +type Command struct { + Name string `yaml:"name" json:"name" jsonschema_description:"Name of the command"` + Aliases []string `yaml:"aliases,omitempty" json:"aliases,omitempty" jsonschema_description:"Aliases of the command"` + Description string `yaml:"description,omitempty" json:"description,omitempty" jsonschema_description:"Description of the command"` + Group string `yaml:"group,omitempty" json:"group,omitempty" jsonschema_description:"Group of the command"` + Hidden bool `yaml:"hidden,omitempty" json:"hidden,omitempty" jsonschema_description:"Hidden state of the command"` + Parsing Parsing `yaml:"parsing,omitempty" json:"parsing,omitempty" jsonschema_description:"Flag parsing mode of the command" jsonschema:"enum=interspersed,enum=non-interspersed,enum=disabled"` + + Flags map[string]string `yaml:"flags,omitempty" json:"flags,omitempty" jsonschema_description:"Flags of the command with their description"` + PersistentFlags map[string]string `yaml:"persistentflags,omitempty" json:"persistentflags,omitempty" jsonschema_description:"Persistent flags of the command with their description"` + ExclusiveFlags [][]string `yaml:"exclusiveflags,omitempty" json:"exclusiveflags,omitempty" jsonschema_description:"Flags that are mutually exclusive"` + Run string `yaml:"run,omitempty" json:"run,omitempty" jsonschema_description:"Command or script to execute in runnable mode"` + Completion struct { + Flag map[string][]string `yaml:"flag,omitempty" json:"flag,omitempty" jsonschema_description:"Flag completion"` + Positional [][]string `yaml:"positional,omitempty" json:"positional,omitempty" jsonschema_description:"Positional completion"` + PositionalAny []string `yaml:"positionalany,omitempty" json:"positionalany,omitempty" jsonschema_description:"Positional completion for every other position"` + Dash [][]string `yaml:"dash,omitempty" json:"dash,omitempty" jsonschema_description:"Dash completion"` + DashAny []string `yaml:"dashany,omitempty" json:"dashany,omitempty" jsonschema_description:"Dash completion of every other position"` + } `yaml:"completion,omitempty" json:"completion,omitempty" jsonschema_description:"Completion definition"` + Commands []Command `yaml:"commands,omitempty" json:"commands,omitempty" jsonschema_description:"Subcommands of the command"` + + Documentation struct { + Command string `yaml:"command,omitempty" json:"command,omitempty" jsonschema_description:"Documentation of the command"` + Flag map[string]string `yaml:"flag,omitempty" json:"flag,omitempty" jsonschema_description:"Documentation of flags"` + Positional []string `yaml:"positional,omitempty" json:"positional,omitempty" jsonschema_description:"Documentation of positional arguments"` + PositionalAny string `yaml:"positionalany,omitempty" json:"positionalany,omitempty" jsonschema_description:"Documentation of other positional arguments"` + Dash []string `yaml:"dash,omitempty" json:"dash,omitempty" jsonschema_description:"Documentation of dash arguments"` + DashAny string `yaml:"dashany,omitempty" json:"dashany,omitempty" jsonschema_description:"Documentation of other dash arguments"` + } `yaml:"documentation,omitempty" json:"documentation,omitempty" jsonschema_description:"Documentation"` + Examples map[string]string `yaml:"examples,omitempty" json:"examples,omitempty" jsonschema_description:"Examples"` +} + +func (c *Command) AddFlag(f Flag) { + switch { + case f.Persistent: + if c.PersistentFlags == nil { + c.PersistentFlags = make(map[string]string) + } + c.PersistentFlags[f.format()] = f.Usage + + default: + if c.Flags == nil { + c.Flags = make(map[string]string) + } + c.Flags[f.format()] = f.Usage + } +} diff --git a/internal/spec/command/flag.go b/internal/spec/command/flag.go new file mode 100644 index 000000000..e66fe7790 --- /dev/null +++ b/internal/spec/command/flag.go @@ -0,0 +1,49 @@ +package command + +type Flag struct { + Longhand string + Shorthand string + Usage string + Repeatable bool + Optarg bool + Value bool + Hidden bool + Required bool + Persistent bool +} + +func (f Flag) format() string { + var s string + + if f.Shorthand != "" { + s += f.Shorthand + if f.Longhand != "" { + s += ", " + } + } + + if f.Longhand != "" { + s += f.Longhand + } + + switch { + case f.Optarg: + s += "?" + case f.Value: + s += "=" + } + + if f.Repeatable { + s += "*" + } + + if f.Required { + s += "!" + } + + if f.Hidden { + s += "&" + } + + return s +} diff --git a/internal/spec/command/parsing.go b/internal/spec/command/parsing.go new file mode 100644 index 000000000..264a92c24 --- /dev/null +++ b/internal/spec/command/parsing.go @@ -0,0 +1,10 @@ +package command + +type Parsing string + +const ( + DEFAULT Parsing = "" // INTERSPERSED but allows implicit changes + INTERSPERSED Parsing = "interspersed" // mixed flags and positional arguments + NON_INTERSPERSED Parsing = "non-interspersed" // flag parsing stopped after first positional argument + DISABLED Parsing = "disabled" // flag parsing disabled +) diff --git a/internal/spec/spec.go b/internal/spec/spec.go index a5cb978df..5238b5568 100644 --- a/internal/spec/spec.go +++ b/internal/spec/spec.go @@ -3,6 +3,7 @@ package spec import ( "github.com/rsteube/carapace/internal/pflagfork" + "github.com/rsteube/carapace/internal/spec/command" "github.com/spf13/cobra" "github.com/spf13/pflag" "gopkg.in/yaml.v3" @@ -10,12 +11,12 @@ import ( // Spec generates the spec file. func Spec(cmd *cobra.Command) string { - m, _ := yaml.Marshal(command(cmd)) + m, _ := yaml.Marshal(genCommand(cmd)) return "# yaml-language-server: $schema=https://carapace.sh/schemas/command.json\n" + string(m) } -func command(cmd *cobra.Command) Command { - c := Command{ +func genCommand(cmd *cobra.Command) command.Command { + c := command.Command{ Name: cmd.Use, Description: cmd.Short, Aliases: cmd.Aliases, @@ -23,7 +24,7 @@ func command(cmd *cobra.Command) Command { Hidden: cmd.Hidden, Flags: make(map[string]string), PersistentFlags: make(map[string]string), - Commands: make([]Command, 0), + Commands: make([]command.Command, 0), } // TODO mutually exclusive flags @@ -46,9 +47,11 @@ func command(cmd *cobra.Command) Command { for _, subcmd := range cmd.Commands() { if subcmd.Name() != "_carapace" && subcmd.Deprecated == "" { - c.Commands = append(c.Commands, command(subcmd)) + c.Commands = append(c.Commands, genCommand(subcmd)) } } + c.Documentation.Command = cmd.Long + return c }