Files
commandkit/completion_context.go

79 lines
2.7 KiB
Go

package commandkit
import (
"strings"
internalcobra "gitea.maximumdirect.net/eric/CommandKit/internal/cobra"
commandmeta "gitea.maximumdirect.net/eric/CommandKit/internal/commandmeta"
"gitea.maximumdirect.net/eric/CommandKit/internal/commandpath"
)
type completionContext struct {
route routeResult
command *commandmeta.Command
aliases []commandmeta.FlagAlias
completed []string
tail []string
current string
commandPosition bool
}
func resolveCompletionContext(snapshot *routingSnapshot, completed []string, current string) completionContext {
context := completionContext{completed: append([]string(nil), completed...), current: current}
if snapshot == nil {
return context
}
context.route = resolveEnteredRoute(completed, snapshot)
switch context.route.kind {
case routeCanonical:
context.command = completionCommand(snapshot, context.route.canonicalPath)
if context.command == nil || len(context.route.args) < len(context.route.canonicalPath) {
context.command = nil
return context
}
context.tail = append([]string(nil), context.route.args[len(context.route.canonicalPath):]...)
context.aliases = snapshot.flagAliases[context.route.canonicalPath.Key()].lookupRecords()
context.commandPosition = len(context.tail) == 0
case routeDiscovery:
context.command = &commandmeta.Command{CoreFlags: commandmeta.ReportingFlags()}
context.tail = append([]string(nil), context.route.args...)
context.aliases = snapshot.discoveryFlags[context.route.discoveryPath.Key()].lookupRecords()
}
return context
}
func completionCommand(snapshot *routingSnapshot, path commandpath.Path) *commandmeta.Command {
if len(path) == 0 {
return snapshot.metadata
}
children := snapshot.canonical
var node *canonicalNode
for _, name := range path {
node = children[name]
if node == nil {
return nil
}
children = node.children
}
return node.metadata
}
func completionChildren(snapshot *routingSnapshot, context completionContext) []commandmeta.CompletionChoice {
if snapshot == nil || context.command == nil || !context.commandPosition {
return nil
}
var choices []commandmeta.CompletionChoice
for _, child := range context.command.Children {
if !strings.HasPrefix(child.Name, context.current) || (len(context.route.canonicalPath) == 0 && child.Name == internalcobra.CompletionQueryToken) {
continue
}
entered := append(append([]string(nil), context.completed...), child.Name)
route := resolveEnteredRoute(entered, snapshot)
intended := append(context.route.canonicalPath.Clone(), child.Name)
if route.kind == routeCanonical && route.canonicalPath.Equal(intended) {
choices = append(choices, commandmeta.CompletionChoice{Value: child.Name, Description: child.Summary})
}
}
return choices
}