mirror of
https://github.com/foomo/posh.git
synced 2025-10-16 12:45:38 +00:00
139 lines
3.3 KiB
Go
139 lines
3.3 KiB
Go
package tree
|
|
|
|
import (
|
|
"context"
|
|
"sort"
|
|
|
|
"github.com/foomo/posh/pkg/prompt/goprompt"
|
|
"github.com/foomo/posh/pkg/readline"
|
|
)
|
|
|
|
type Root interface {
|
|
Node() *Node
|
|
Complete(ctx context.Context, r *readline.Readline) []goprompt.Suggest
|
|
Execute(ctx context.Context, r *readline.Readline) error
|
|
Help(ctx context.Context, r *readline.Readline) string
|
|
}
|
|
|
|
type root struct {
|
|
node *Node
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ~ Constructor
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
func New(node *Node) Root {
|
|
return &root{
|
|
node: node,
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ~ Public methods
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
func (t *root) Node() *Node {
|
|
return t.node
|
|
}
|
|
|
|
func (t *root) Complete(ctx context.Context, r *readline.Readline) []goprompt.Suggest {
|
|
var suggests []goprompt.Suggest
|
|
switch r.Mode() {
|
|
case readline.ModeArgs:
|
|
if r.Args().LenLte(1) && len(t.node.Nodes) > 0 {
|
|
for _, command := range t.node.Nodes {
|
|
if command.Values != nil {
|
|
suggests = command.Values(ctx, r)
|
|
} else {
|
|
suggests = append(suggests, goprompt.Suggest{Text: command.Name, Description: command.Description})
|
|
}
|
|
}
|
|
} else if cmd, i := t.node.find(ctx, r, 0); cmd == nil && t.node != nil {
|
|
if err := t.node.setFlags(ctx, r, false); err != nil {
|
|
return nil
|
|
} else {
|
|
suggests = t.node.completeArguments(ctx, t, r, 0)
|
|
}
|
|
} else if cmd == nil {
|
|
return nil
|
|
} else if err := cmd.setFlags(ctx, r, false); err != nil {
|
|
return nil
|
|
} else {
|
|
suggests = cmd.completeArguments(ctx, t, r, i+1)
|
|
}
|
|
case readline.ModeFlags:
|
|
if cmd, _ := t.node.find(ctx, r, 0); cmd == nil && t.node != nil {
|
|
if err := t.node.setFlags(ctx, r, false); err != nil {
|
|
return nil
|
|
} else {
|
|
suggests = t.node.completeFlags(r)
|
|
}
|
|
} else if cmd == nil {
|
|
return nil
|
|
} else if err := cmd.setFlags(ctx, r, false); err != nil {
|
|
return nil
|
|
} else {
|
|
suggests = cmd.completeFlags(r)
|
|
}
|
|
case readline.ModeAdditionalArgs:
|
|
// do nothing
|
|
}
|
|
sort.Slice(suggests, func(i, j int) bool {
|
|
return suggests[i].Text < suggests[j].Text
|
|
})
|
|
return suggests
|
|
}
|
|
|
|
func (t *root) Execute(ctx context.Context, r *readline.Readline) error {
|
|
var (
|
|
cmd *Node
|
|
index int
|
|
)
|
|
|
|
switch {
|
|
case t.node == nil && t.node.Execute == nil && len(t.node.Nodes) == 0:
|
|
return ErrNoop
|
|
case r.Args().LenIs(1) && t.node == nil:
|
|
return ErrMissingCommand
|
|
}
|
|
|
|
if r.Args().LenIs(0) {
|
|
cmd = t.node
|
|
} else if found, i := t.node.find(ctx, r, 0); found != nil {
|
|
cmd = found
|
|
index = i
|
|
} else if t.node == nil {
|
|
return ErrInvalidCommand
|
|
} else {
|
|
cmd = t.node
|
|
}
|
|
|
|
if err := cmd.setFlags(ctx, r, true); err != nil {
|
|
return err
|
|
} else if err := cmd.execute(ctx, r, index); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (t *root) Help(ctx context.Context, r *readline.Readline) string {
|
|
var (
|
|
cmd *Node
|
|
)
|
|
|
|
if t.node == nil {
|
|
return "command not found"
|
|
} else if r.Args().LenIs(1) {
|
|
cmd = t.node
|
|
} else if len(t.node.Nodes) == 0 {
|
|
return "command not found"
|
|
} else if found, _ := t.node.find(ctx, r, 1); found != nil {
|
|
cmd = found
|
|
} else {
|
|
cmd = t.node
|
|
}
|
|
|
|
return cmd.help(ctx, r)
|
|
}
|