mirror of
https://github.com/foomo/posh.git
synced 2025-10-16 12:45:38 +00:00
109 lines
2.8 KiB
Go
109 lines
2.8 KiB
Go
package tree
|
|
|
|
import (
|
|
"context"
|
|
"sort"
|
|
|
|
"github.com/c-bata/go-prompt"
|
|
"github.com/foomo/posh/pkg/readline"
|
|
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
type Root struct {
|
|
Name string
|
|
Nodes []*Node
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ~ Public methods
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
func (p *Root) Execute(ctx context.Context, r *readline.Readline) error {
|
|
if r.Args().LenIs(0) {
|
|
return errors.New("missing [command] argument")
|
|
} else if cmd, i := p.find(p.Nodes, r, 0); cmd == nil {
|
|
return errors.New("invalid [command] argument")
|
|
} else if err := cmd.setFlags(r, true); err != nil {
|
|
return err
|
|
} else if err := cmd.execute(ctx, r, i); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (p *Root) Complete(ctx context.Context, r *readline.Readline) (suggests []prompt.Suggest) {
|
|
switch r.Mode() {
|
|
case readline.ModeArgs:
|
|
if r.Args().LenLte(1) {
|
|
for _, command := range p.Nodes {
|
|
suggests = append(suggests, prompt.Suggest{Text: command.Name, Description: command.Description})
|
|
}
|
|
} else if cmd, i := p.find(p.Nodes, r, 0); cmd == nil {
|
|
return nil
|
|
} else if err := cmd.setFlags(r, false); err != nil {
|
|
return nil
|
|
} else {
|
|
suggests = cmd.completeArguments(ctx, p, r, i+1)
|
|
}
|
|
sort.Slice(suggests, func(i, j int) bool {
|
|
return suggests[i].Text < suggests[j].Text
|
|
})
|
|
case readline.ModeFlags:
|
|
if cmd, _ := p.find(p.Nodes, r, 0); cmd == nil {
|
|
return nil
|
|
} else if err := cmd.setFlags(r, false); err != nil {
|
|
return nil
|
|
} else {
|
|
suggests = cmd.completeFlags(r)
|
|
}
|
|
sort.Slice(suggests, func(i, j int) bool {
|
|
return suggests[i].Text < suggests[j].Text
|
|
})
|
|
case readline.ModePassThroughArgs:
|
|
// TODO
|
|
case readline.ModePassThroughFlags:
|
|
if cmd, _ := p.find(p.Nodes, r, 0); cmd == nil {
|
|
return nil
|
|
} else if err := cmd.setFlags(r, false); err != nil {
|
|
return nil
|
|
} else {
|
|
suggests = cmd.completePassThroughFlags(r)
|
|
}
|
|
sort.Slice(suggests, func(i, j int) bool {
|
|
return suggests[i].Text < suggests[j].Text
|
|
})
|
|
}
|
|
return suggests
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ~ Private methods
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
func (p *Root) find(cmds []*Node, r *readline.Readline, i int) (*Node, int) {
|
|
if r.Args().LenLt(i + 1) {
|
|
return nil, i
|
|
}
|
|
arg := r.Args().At(i)
|
|
for _, cmd := range cmds {
|
|
if cmd.Name == arg {
|
|
if subCmd, j := p.find(cmd.Commands, r, i+1); subCmd != nil {
|
|
return subCmd, j
|
|
}
|
|
return cmd, i
|
|
}
|
|
if cmd.Names != nil {
|
|
for _, name := range cmd.Names() {
|
|
if name == arg {
|
|
if subCmd, j := p.find(cmd.Commands, r, i+1); subCmd != nil {
|
|
return subCmd, j
|
|
}
|
|
}
|
|
return cmd, i
|
|
}
|
|
}
|
|
}
|
|
return nil, i
|
|
}
|