mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-22 00:08:04 +02:00
More work on completions
This commit is contained in:
@@ -35,6 +35,8 @@ func init() {
|
||||
output_serializers["json"] = json_output_serializer
|
||||
}
|
||||
|
||||
var registered_exes = make(map[string]func(root *Command))
|
||||
|
||||
func main(args []string) error {
|
||||
output_type := "json"
|
||||
if len(args) > 0 {
|
||||
@@ -62,7 +64,12 @@ func main(args []string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
completions := GetCompletions(argv)
|
||||
var root = Command{Options: make([]*Option, 0), Groups: make([]*CommandGroup, 0, 8)}
|
||||
for _, re := range registered_exes {
|
||||
re(&root)
|
||||
}
|
||||
|
||||
completions := root.GetCompletions(argv)
|
||||
output, err := output_serializer(completions, shell_state)
|
||||
if err == nil {
|
||||
_, err = os.Stdout.Write(output)
|
||||
|
||||
@@ -70,7 +70,7 @@ func complete_word(word string, completions *Completions, only_args_allowed bool
|
||||
cmd := completions.current_cmd
|
||||
if expecting_arg_for != nil {
|
||||
if expecting_arg_for.Completion_for_arg != nil {
|
||||
expecting_arg_for.Completion_for_arg(completions, word)
|
||||
expecting_arg_for.Completion_for_arg(completions, word, arg_num)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -81,7 +81,7 @@ func complete_word(word string, completions *Completions, only_args_allowed bool
|
||||
if option != nil {
|
||||
if option.Completion_for_arg != nil {
|
||||
completions.WordPrefix = word[:idx+1]
|
||||
option.Completion_for_arg(completions, word[idx+1:])
|
||||
option.Completion_for_arg(completions, word[idx+1:], arg_num)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -89,18 +89,19 @@ func complete_word(word string, completions *Completions, only_args_allowed bool
|
||||
}
|
||||
return
|
||||
}
|
||||
if arg_num == 1 && len(cmd.Subcommands) > 0 {
|
||||
for _, sc := range cmd.Subcommands {
|
||||
if strings.HasPrefix(sc.Name, word) {
|
||||
title := cmd.Subcommands_title
|
||||
if title == "" {
|
||||
title = "Sub-commands"
|
||||
}
|
||||
group := MatchGroup{Title: title}
|
||||
group.Matches = make([]*Match, 0, len(cmd.Subcommands))
|
||||
if arg_num == 1 && cmd.has_subcommands() {
|
||||
for _, cg := range cmd.Groups {
|
||||
group := MatchGroup{Title: cg.Title}
|
||||
if group.Title == "" {
|
||||
group.Title = "Sub-commands"
|
||||
}
|
||||
group.Matches = make([]*Match, 0, len(cg.Commands))
|
||||
for _, sc := range cg.Commands {
|
||||
if strings.HasPrefix(sc.Name, word) {
|
||||
group.Matches = append(group.Matches, &Match{Word: sc.Name, Description: sc.Description})
|
||||
}
|
||||
}
|
||||
if len(group.Matches) > 0 {
|
||||
completions.add_group(&group)
|
||||
}
|
||||
}
|
||||
@@ -108,20 +109,11 @@ func complete_word(word string, completions *Completions, only_args_allowed bool
|
||||
}
|
||||
|
||||
if cmd.Completion_for_arg != nil {
|
||||
cmd.Completion_for_arg(completions, word)
|
||||
cmd.Completion_for_arg(completions, word, arg_num)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (self *Command) find_subcommand(name string) *Command {
|
||||
for _, sc := range self.Subcommands {
|
||||
if sc.Name == name {
|
||||
return sc
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cmd *Command) parse_args(words []string, completions *Completions) {
|
||||
completions.current_cmd = cmd
|
||||
if len(words) == 0 {
|
||||
@@ -156,13 +148,13 @@ func (cmd *Command) parse_args(words []string, completions *Completions) {
|
||||
continue
|
||||
}
|
||||
option := cmd.find_option(word[:idx])
|
||||
if option != nil {
|
||||
if option != nil && option.Has_following_arg {
|
||||
expecting_arg_for = option
|
||||
}
|
||||
continue
|
||||
}
|
||||
if len(cmd.Subcommands) > 0 && arg_num == 1 {
|
||||
sc := cmd.find_subcommand(word)
|
||||
if cmd.has_subcommands() && arg_num == 1 {
|
||||
sc := cmd.find_subcommand_with_name(word)
|
||||
if sc == nil {
|
||||
only_args_allowed = true
|
||||
continue
|
||||
|
||||
@@ -23,7 +23,7 @@ type Completions struct {
|
||||
current_cmd *Command
|
||||
}
|
||||
|
||||
type completion_func func(completions *Completions, partial_word string)
|
||||
type completion_func func(completions *Completions, partial_word string, arg_num int)
|
||||
|
||||
type Option struct {
|
||||
Name string
|
||||
@@ -33,29 +33,58 @@ type Option struct {
|
||||
Completion_for_arg completion_func
|
||||
}
|
||||
|
||||
type CommandGroup struct {
|
||||
Title string
|
||||
Commands []*Command
|
||||
}
|
||||
|
||||
type Command struct {
|
||||
Name string
|
||||
Description string
|
||||
|
||||
// List of options for this command
|
||||
Options []*Option
|
||||
|
||||
// List of subcommands
|
||||
Subcommands []*Command
|
||||
// Optional title used as a header when displaying the list of matching sub-commands for a completion
|
||||
Subcommands_title string
|
||||
Groups []*CommandGroup
|
||||
|
||||
Completion_for_arg completion_func
|
||||
Stop_processing_at_arg int
|
||||
}
|
||||
|
||||
var Root = Command{Options: make([]*Option, 0), Subcommands: make([]*Command, 0, 32)}
|
||||
func (self *Command) add_command(name string) *Command {
|
||||
ans := Command{Name: name}
|
||||
ans.Options = make([]*Option, 0, 8)
|
||||
ans.Groups = make([]*CommandGroup, 0, 2)
|
||||
return &ans
|
||||
}
|
||||
|
||||
func GetCompletions(argv []string) *Completions {
|
||||
func (self *Command) find_subcommand(is_ok func(cmd *Command) bool) *Command {
|
||||
for _, g := range self.Groups {
|
||||
for _, q := range g.Commands {
|
||||
if is_ok(q) {
|
||||
return q
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *Command) find_subcommand_with_name(name string) *Command {
|
||||
return self.find_subcommand(func(cmd *Command) bool { return cmd.Name == name })
|
||||
}
|
||||
|
||||
func (self *Command) has_subcommands() bool {
|
||||
for _, g := range self.Groups {
|
||||
if len(g.Commands) > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *Command) GetCompletions(argv []string) *Completions {
|
||||
ans := Completions{Groups: make([]*MatchGroup, 0, 4)}
|
||||
if len(argv) > 0 {
|
||||
exe := argv[0]
|
||||
cmd := Root.find_subcommand(exe)
|
||||
cmd := self.find_subcommand_with_name(exe)
|
||||
if cmd != nil {
|
||||
cmd.parse_args(argv[1:], &ans)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user