brigodier

package module
Version: v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 19, 2021 License: Apache-2.0 Imports: 10 Imported by: 4

README

brigodier

GitHub release (latest SemVer) Doc GitHub go.mod Go version Go Report Card test Discord

Brigodier is a command parser & dispatcher, designed and developed to provide a simple and flexible command framework.

It can be used in many command-line environments such as for chat commands in the Minecraft Java Edition.

It is completely ported to Go from Mojang's Brigadier (written in Java), including all features and tests.

Installation

For use in your projects go get it with:

go get -u go.minekube.com/brigodier

Usage

At the heart of Brigodier, you need a Dispatcher.

A command dispatcher holds a "command tree", which is a series of CommandNodes that represent the various possible syntax options that form a valid command.

Registering a new command

Before we can start parsing and dispatching commands, we need to build up our command tree. Every registration is an append operation, so you can freely extend existing commands in a project without needing access to the source code that created them.

Command registration also encourages the use of a builder pattern to keep code cruft to a minimum.

A "command" is a fairly loose term, but typically it means an exit point of the command tree. Every node can have an Executes function attached to it, which signifies that if the input stops here then this function will be called with the context so far.

Consider the following example:

var d Dispatcher

d.Register(
	Literal("foo").Then(
		Argument("bar", Int).
			Executes(CommandFunc(func(c *CommandContext) error {
				fmt.Println("Bar is", c.Int("bar"))
				return nil
			})),
	).Executes(CommandFunc(func(c *CommandContext) error {
		fmt.Println("Called foo with no arguments")
		return nil
	})),
)

This snippet registers two "commands": foo and foo <bar>. It is also common to refer to the <bar> as a "subcommand" of foo, as it's a child node.

At the start of the tree is a "root node", and it must have LiteralCommandNodes as children. Here, we register one command under the root: Literal("foo"), which means "the user must type the literal string 'foo'".

Under that is two extra definitions: a child node for possible further evaluation, or an executes block if the user input stops here.

The child node works exactly the same way, but is no longer limited to literals. The other type of node that is now allowed is an ArgumentCommandNode, which takes in a name, and an argument type.

Arguments can be anything, and you are encouraged to build your own for seamless integration into your own product. There are some builtin ArgumentTypes included, such as Int or String.

Argument types will be asked to parse input as much as they can, and then store the "result" of that argument however they see fit or throw a relevant error if they can't parse.

For example, an integer argument would parse "123" and store it as 123 (int), but throw an error if the input were onetwothree.

When a command function runs, it can access these arguments in the context provided to the registered function.

Parsing user input

So, we've registered some commands, and now we're ready to take in user input. If you're in a rush, you can just call dispatcher.Execute(ctx, "foo 123") and call it a day.

Go's context.Context can be used to track users/players/etc and will be provided to the command to give context on what's happening (e.g., who has run the command).

If the command failed or could not parse, some form of CommandSyntaxError will be returned, or the error that the Command returned.

If you wish to have more control over the parsing & executing of commands, or wish to cache the parse results, so you can execute it multiple times, you can split it up into two steps:

parse := dispatcher.Parse(ctx, "foo 123")
err := dispatcher.Execute(parse)

This is highly recommended as the parse step is the most expensive, and may be easily cached depending on your application.

You can also use this to do further introspection on a command, before (or without) actually running it.

The convenient method to parse and execute a command is:

err := dispatcher.Do(ctx, "foo 123")
Inspecting a command

If you Parse some input, you can find out what it will perform (if anything) and provide hints to the user safely and immediately.

The parse will never fail, and the ParseResults it returns will contain a possible context that a command may be called with (and from that, you can inspect which nodes the user entered, complete with start/end positions in the input string). It also contains a map of parse exceptions for each command node it encountered. If it couldn't build a valid context, then the reason is inside this exception map.

Displaying usage info

There are two forms of "usage strings" provided by this library, both require a target node.

  • dispatcher.AllUsage(ctx, node, restricted) will return a list of all possible commands (executable end-points) under the target node and their human-readable path. If restricted, it will ignore commands that ctx does not have access to. This will look like [foo, foo <bar>].

  • dispatcher.SmartUsage(ctx, node) will return a map of the child nodes to their "smart usage" human-readable path. This tries to squash future-nodes together and show optional & typed information, and can look like foo (<bar>).

Documentation

Index

Examples

Constants

View Source
const (
	// UsageArgumentOpen is the open rune for ArgumentCommandNode.UsageText.
	UsageArgumentOpen rune = '['
	// UsageArgumentClose is the close rune for ArgumentCommandNode.UsageText.
	UsageArgumentClose rune = ']'
)
View Source
const (
	// SyntaxDoubleQuote is a double quote.
	SyntaxDoubleQuote rune = '"'
	// SyntaxSingleQuote is a single quote.
	SyntaxSingleQuote rune = '\''
	// SyntaxEscape is an escape.
	SyntaxEscape rune = '\\'
)
View Source
const (
	MinInt32   = math.MinInt32
	MaxInt32   = math.MaxInt32
	MinInt64   = math.MinInt32
	MaxInt64   = math.MaxInt64
	MinFloat32 = -math.MaxFloat32
	MaxFloat32 = math.MaxFloat32
	MinFloat64 = -math.MaxFloat64
	MaxFloat64 = math.MaxFloat64
)

Default minimums and maximums of builtin numeric ArgumentType values.

View Source
const (
	// UsageOptionalOpen is the open rune for an optional argument.
	UsageOptionalOpen rune = '['
	// UsageOptionalClose is the close rune for an optional argument.
	UsageOptionalClose rune = ']'
	// UsageRequiredOpen is the open rune for a required argument.
	UsageRequiredOpen rune = '('
	// UsageRequiredClose is the close rune for a required argument.
	UsageRequiredClose rune = ')'
	// UsageOr is the or rune splitting multiple argument options.
	UsageOr rune = '|'
)
View Source
const ArgumentSeparator rune = ' '

ArgumentSeparator separates individual arguments in a command input string.

Variables

View Source
var (
	// ErrDispatcherUnknownCommand indicates that an input command was not found.
	ErrDispatcherUnknownCommand = errors.New("dispatcher: unknown command")
	// ErrDispatcherUnknownArgument indicates that the argument of an input command was not found.
	ErrDispatcherUnknownArgument = errors.New("dispatcher: unknown argument")
)
View Source
var (
	// ErrReaderInvalidEscape indicates an invalid escape error.
	ErrReaderInvalidEscape = errors.New("read invalid escape character")
	// ErrReaderExpectedStartOfQuote occurs when a start quote is missing.
	ErrReaderExpectedStartOfQuote = errors.New("reader expected start of quote")
	// ErrReaderExpectedEndOfQuote occurs when an end quote is missing.
	ErrReaderExpectedEndOfQuote = errors.New("reader expected end of quote")
)
View Source
var (
	// ErrReaderExpectedBool occurs when the reader expected a bool.
	ErrReaderExpectedBool = errors.New("reader expected bool")
	// ErrReaderExpectedFloat occurs when the reader expected a float.
	ErrReaderExpectedFloat = errors.New("reader expected float")
	// ErrReaderExpectedInt occurs when the reader expected a int.
	ErrReaderExpectedInt = errors.New("reader expected int")

	// ErrReaderInvalidInt occurs when the reader read an invalid int value.
	ErrReaderInvalidInt = errors.New("read invalid int")
	// ErrReaderInvalidFloat occurs when the reader read an invalid int float.
	ErrReaderInvalidFloat = errors.New("read invalid float")
)
View Source
var (
	// ErrArgumentIntegerTooHigh occurs when the found integer is higher than the specified maximum.
	ErrArgumentIntegerTooHigh = errors.New("integer too high")
	// ErrArgumentIntegerTooLow occurs when the found integer is lower than the specified minimum.
	ErrArgumentIntegerTooLow = errors.New("integer too low")

	// ErrArgumentFloatTooHigh occurs when the found float is higher than the specified maximum.
	ErrArgumentFloatTooHigh = errors.New("float too high")
	// ErrArgumentFloatTooLow occurs when the found float is lower than the specified minimum.
	ErrArgumentFloatTooLow = errors.New("float too low")
)
View Source
var ErrDispatcherExpectedArgumentSeparator = errors.New("dispatcher: expected argument separator")

ErrDispatcherExpectedArgumentSeparator occurs when the dispatcher expected an ArgumentSeparator.

View Source
var ErrNoNodeBeforeCursor = errors.New("can't find node before cursor")

ErrNoNodeBeforeCursor indicates that CommandContext.FindSuggestionContext could not find a matching node before the specified cursor.

Functions

func CanProvideSuggestions

func CanProvideSuggestions(i interface{}) bool

CanProvideSuggestions tests whether i implements SuggestionProvider.

func IsAllowedInUnquotedString

func IsAllowedInUnquotedString(c rune) bool

IsAllowedInUnquotedString indicated whether c is an allowed rune in an unquoted string.

func IsAllowedNumber

func IsAllowedNumber(c rune) bool

IsAllowedNumber indicated whether c is an allowed number rune.

func IsQuotedStringStart

func IsQuotedStringStart(c rune) bool

IsQuotedStringStart indicated whether c is the start of a quoted string.

Types

type ArgumentBuilder

type ArgumentBuilder struct {
	Arguments   RootCommandNode
	Command     Command
	Requirement RequireFn
	Target      CommandNode
	Modifier    RedirectModifier
	Forks       bool
}

ArgumentBuilder has the common builder fields and is wrapped by LiteralArgumentBuilder and RequiredArgumentBuilder

func (*ArgumentBuilder) Executes

func (b *ArgumentBuilder) Executes(command Command) *ArgumentBuilder

Executes defines the Command of the resulting CommandNode.

func (*ArgumentBuilder) Fork

func (b *ArgumentBuilder) Fork(target CommandNode, modifier RedirectModifier) *ArgumentBuilder

Fork defines the fork of the resulting CommandNode.

func (*ArgumentBuilder) Forward

func (b *ArgumentBuilder) Forward(target CommandNode, modifier RedirectModifier, fork bool) *ArgumentBuilder

func (*ArgumentBuilder) Redirect

func (b *ArgumentBuilder) Redirect(target CommandNode) *ArgumentBuilder

Redirect defines the redirect node of the resulting CommandNode.

func (*ArgumentBuilder) RedirectWithModifier

func (b *ArgumentBuilder) RedirectWithModifier(target CommandNode, modifier RedirectModifier) *ArgumentBuilder

RedirectWithModifier defines the redirect modifier of the resulting CommandNode.

func (*ArgumentBuilder) Requires

func (b *ArgumentBuilder) Requires(fn RequireFn) *ArgumentBuilder

Requires defines the RequireFn of the resulting CommandNode.

type ArgumentCommandNode

type ArgumentCommandNode struct {
	Node
	// contains filtered or unexported fields
}

ArgumentCommandNode is an argument command node storing the argument type, name and optional custom suggestions.

Use Argument(name, type) to build it.

func (*ArgumentCommandNode) Build

func (a *ArgumentCommandNode) Build() CommandNode

func (*ArgumentCommandNode) CreateArgumentBuilder

func (a *ArgumentCommandNode) CreateArgumentBuilder() ArgumentNodeBuilder

func (*ArgumentCommandNode) CreateBuilder

func (a *ArgumentCommandNode) CreateBuilder() NodeBuilder

func (*ArgumentCommandNode) CustomSuggestions

func (a *ArgumentCommandNode) CustomSuggestions() SuggestionProvider

func (*ArgumentCommandNode) Name

func (a *ArgumentCommandNode) Name() string

func (*ArgumentCommandNode) Parse

Parse parses the argument from an input reader.

func (*ArgumentCommandNode) String

func (a *ArgumentCommandNode) String() string

func (*ArgumentCommandNode) Suggestions

func (a *ArgumentCommandNode) Suggestions(ctx *CommandContext, builder *SuggestionsBuilder) *Suggestions

Suggestions implements SuggestionProvider.

func (*ArgumentCommandNode) Type

func (*ArgumentCommandNode) UsageText

func (a *ArgumentCommandNode) UsageText() string

type ArgumentNodeBuilder

type ArgumentNodeBuilder interface {
	Builder
	BuildArgument() *ArgumentCommandNode
	NodeBuilder() NodeBuilder // Convert to NodeBuilder
	Then(arguments ...Builder) ArgumentNodeBuilder

	Suggests(provider SuggestionProvider) ArgumentNodeBuilder
	Executes(command Command) ArgumentNodeBuilder
	Requires(fn RequireFn) ArgumentNodeBuilder
	Redirect(target CommandNode) ArgumentNodeBuilder
	RedirectWithModifier(target CommandNode, modifier RedirectModifier) ArgumentNodeBuilder
	Fork(target CommandNode, modifier RedirectModifier) ArgumentNodeBuilder
	Forward(target CommandNode, modifier RedirectModifier, fork bool) ArgumentNodeBuilder
}

ArgumentNodeBuilder is an ArgumentCommandNode builder.

type ArgumentType

type ArgumentType interface {
	// Parse parses the argument from the given reader input.
	Parse(rd *StringReader) (interface{}, error)
	String() string // String returns the name of the type.
}

ArgumentType is a parsable argument type.

var (
	// String argument type is quoted or unquoted.
	String ArgumentType = QuotablePhase
	// StringWord argument type is a single word.
	StringWord ArgumentType = SingleWord
	// StringPhrase argument type is phrase.
	StringPhrase ArgumentType = GreedyPhrase
	// Bool argument type.
	Bool ArgumentType = &BoolArgumentType{}

	// Int32 argument type.
	Int32 ArgumentType = &Int32ArgumentType{
		Min: MinInt32,
		Max: MaxInt32,
	}
	// Int64 argument type.
	Int64 ArgumentType = &Int64ArgumentType{
		Min: MinInt64,
		Max: MaxInt64,
	}
	// Int is an alias of Int32.
	Int = Int32

	// Float32 argument type.
	Float32 ArgumentType = &Float32ArgumentType{
		Min: MinFloat32,
		Max: MaxFloat32,
	}
	// Float64 argument type.
	Float64 ArgumentType = &Float64ArgumentType{
		Min: MinFloat64,
		Max: MaxFloat64,
	}
)

Builtin argument types.

type ArgumentTypeFuncs

type ArgumentTypeFuncs struct {
	Name    string                                      // The name of the argument type returned by ArgumentType.String.
	ParseFn func(rd *StringReader) (interface{}, error) // ArgumentType.Parse
	// Optional suggestions for use with Dispatcher.CompletionSuggestions (ProvideSuggestions).
	SuggestionsFn func(ctx *CommandContext, builder *SuggestionsBuilder) *Suggestions
}

ArgumentTypeFuncs is a convenient struct implementing ArgumentType.

func (*ArgumentTypeFuncs) Parse

func (t *ArgumentTypeFuncs) Parse(rd *StringReader) (interface{}, error)

func (*ArgumentTypeFuncs) String

func (t *ArgumentTypeFuncs) String() string

func (*ArgumentTypeFuncs) Suggestions

func (t *ArgumentTypeFuncs) Suggestions(ctx *CommandContext, builder *SuggestionsBuilder) *Suggestions

Suggestions implements SuggestionProvider.

type BoolArgumentType

type BoolArgumentType struct{}

func (*BoolArgumentType) Parse

func (t *BoolArgumentType) Parse(rd *StringReader) (interface{}, error)

func (*BoolArgumentType) String

func (t *BoolArgumentType) String() string

func (*BoolArgumentType) Suggestions

func (t *BoolArgumentType) Suggestions(_ *CommandContext, builder *SuggestionsBuilder) *Suggestions

type Builder

type Builder interface{ Build() CommandNode }

Builder is a CommandNode builder.

type Command

type Command interface {
	Run(c *CommandContext) error
}

Command is the command run by Dispatcher.Execute for a matching input.

type CommandContext

type CommandContext struct {
	context.Context
	Arguments map[string]*ParsedArgument
	RootNode  CommandNode
	Child     *CommandContext
	Command   Command
	Nodes     []*ParsedCommandNode
	Range     StringRange
	Modifier  RedirectModifier
	Forks     bool
	Input     string
	// contains filtered or unexported fields
}

CommandContext is the context for executing a command.

func (*CommandContext) Bool

func (c *CommandContext) Bool(argumentName string) bool

Bool returns the parsed bool argument from the command context. It returns the zero-value if not found.

func (*CommandContext) Copy

func (c *CommandContext) Copy() *CommandContext

Copy copies the CommandContext.

func (*CommandContext) CopyFor

func (c *CommandContext) CopyFor(ctx context.Context) *CommandContext

CopyFor copies the CommandContext if ctx is not equal to CommandContext.Context and sets CommandContext.Context to ctx.

func (*CommandContext) FindSuggestionContext

func (c *CommandContext) FindSuggestionContext(cursor int) (*SuggestionContext, error)

FindSuggestionContext tries to calculate the SuggestionContext starting at cursor or returns ErrNoNodeBeforeCursor if no node could be found before the specified cursor.

func (*CommandContext) Float32

func (c *CommandContext) Float32(argumentName string) float32

Float32 returns the parsed float32 argument from the command context. It returns the zero-value if not found.

func (*CommandContext) Float64

func (c *CommandContext) Float64(argumentName string) float64

Float64 returns the parsed float64 argument from the command context. It returns the zero-value if not found.

func (*CommandContext) HasNodes

func (c *CommandContext) HasNodes() bool

HasNodes indicates whether the command context has at least one ParsedCommandNode.

func (*CommandContext) Int

func (c *CommandContext) Int(argumentName string) int

Int is the same as CommandContext.Int32.

func (*CommandContext) Int32

func (c *CommandContext) Int32(argumentName string) int32

Int32 returns the parsed int32 argument from the command context. It returns the zero-value if not found.

func (*CommandContext) Int64

func (c *CommandContext) Int64(argumentName string) int64

Int64 returns the parsed int64 argument from the command context. It returns the zero-value if not found.

func (*CommandContext) String

func (c *CommandContext) String(argumentName string) string

String returns the parsed string argument from the command context. It returns the zero-value if not found.

type CommandFunc

type CommandFunc func(c *CommandContext) error

CommandFunc is a convenient function type implementing the Command interface.

func (CommandFunc) Run

func (cf CommandFunc) Run(c *CommandContext) error

Run implements Command.

type CommandNode

type CommandNode interface {
	// Arguments returns the nodes's arguments.
	Arguments() map[string]*ArgumentCommandNode
	// Literals returns the node's literals.
	Literals() map[string]*LiteralCommandNode
	// CanUse tests whether the node can be used with the given context.Context.
	// It can be used for restricting Dispatcher.Parse/Execute and Dispatcher.AllUsage
	// for certain subjects, e.g. whether the entity seeing/executing a command is allowed.
	CanUse(ctx context.Context) bool
	// RelevantNodes returns the relevant nodes of a Node for an input.
	RelevantNodes(input *StringReader) []CommandNode
	// Parse parses the given reader input.
	Parse(ctx *CommandContext, rd *StringReader) error
	// Redirect is the optional redirect node.
	// May return nil.
	Redirect() CommandNode
	// Command returns the command of the node.
	// May return nil since not all nodes must be executable.
	Command() Command

	// Requirement is the optional condition used to run CanUse.
	Requirement() RequireFn
	// RedirectModifier is the optional redirect modifier.
	// May return nil.
	RedirectModifier() RedirectModifier
	// IsFork indicated whether the node is a fork.
	IsFork() bool
	// Name returns the name of the node.
	Name() string
	// Children returns the node's children.
	// Use ChildrenOrdered if register order matters.
	Children() map[string]CommandNode
	// ChildrenOrdered returns the node's children in the same order as registered.
	ChildrenOrdered() StringCommandNodeMap
	// AddChild adds node children to the node.
	// Passing nil is valid and is ignored.
	AddChild(nodes ...CommandNode)
	// RemoveChild removes child nodes from the node
	RemoveChild(names ...string)
	// UsageText returns the usage text of the node.
	UsageText() string
	// CreateBuilder creates a new builder without children from the node.
	//
	// Note that a RootCommandNode returns a no-operation builder where Build() returns nil.
	// Passing such a no-Op builder to Dispatcher.Register is always valid and has no effect.
	CreateBuilder() NodeBuilder
	// contains filtered or unexported methods
}

CommandNode is a command node in a tree.

type CommandNodeStringMap

type CommandNodeStringMap interface {
	// Put inserts key-value pair into the map.
	Put(key CommandNode, value string)
	// Get searches the element in the map by key and returns its value or nil if key is not found in tree.
	// Second return parameter is true if key was found, otherwise false.
	Get(key CommandNode) (value string, found bool)
	// Remove removes the element from the map by key.
	Remove(key CommandNode)
	// Keys returns all keys in-order
	Keys() []CommandNode
	// Values returns all values in-order based on the key.
	Values() []string

	// Range calls the given function once for each element
	// until f returns false, passing that element's key and value.
	Range(f func(key CommandNode, value string) bool)

	Container
}

CommandNodeStringMap holds the elements in a regular hash table, and uses doubly-linked list to store key ordering.

func NewCommandNodeStringMap

func NewCommandNodeStringMap() CommandNodeStringMap

NewCommandNodeStringMap returns a new CommandNodeStringMap.

type CommandSyntaxError

type CommandSyntaxError struct{ Err error }

CommandSyntaxError is a syntax error returned on parse error.

func (*CommandSyntaxError) Error

func (e *CommandSyntaxError) Error() string

func (*CommandSyntaxError) Unwrap

func (e *CommandSyntaxError) Unwrap() error

Unwrap implements errors.Unwrap.

type Container

type Container interface {
	// Empty returns true if map does not contain any elements
	Empty() bool
	// Size returns number of elements in the map.
	Size() int
	// Clear removes all elements from the map.
	Clear()
}

Container is base interface that container structures implement.

type Dispatcher

type Dispatcher struct {
	// The root of this command tree.
	// This is often useful as a target of an
	// ArgumentBuilder.Redirect, AllUsage or SmartUsage.
	Root RootCommandNode
}

Dispatcher is the command dispatcher, for registering, parsing, and executing commands.

func (*Dispatcher) AllUsage

func (d *Dispatcher) AllUsage(ctx context.Context, node CommandNode, restricted bool) []string

AllUsage gets all possible executable commands following the given node.

You may use Dispatcher.Root as a target to get all usage data for the entire command tree.

The returned syntax will be in "simple" form: <param> and literal. "Optional" nodes will be listed as multiple entries: the parent node, and the child nodes. For example, a required literal "foo" followed by an optional param "int" will be two nodes:

foo
foo <int>

The path to the specified node will NOT be prepended to the output, as there can theoretically be many ways to reach a given node. It will only give you paths relative to the specified node, not absolute from root.

func (*Dispatcher) CompletionSuggestions

func (d *Dispatcher) CompletionSuggestions(parse *ParseResults) (*Suggestions, error)

CompletionSuggestions gets suggestions for a parsed input string on what comes next.

As it is ultimately up to custom argument types to provide suggestions.

The suggestions provided will be in the context of the end of the parsed input string, but may suggest new or replacement strings for earlier in the input string. For example, if the end of the string was foobar but an argument preferred it to be minecraft:foobar, it will suggest a replacement for that whole segment of the input.

func (*Dispatcher) CompletionSuggestionsCursor

func (d *Dispatcher) CompletionSuggestionsCursor(parse *ParseResults, cursor int) (*Suggestions, error)

CompletionSuggestionsCursor gets suggestions for a parsed input string on what comes next with a cursor to begin suggesting at. See CompletionSuggestions for details.

func (*Dispatcher) Do

func (d *Dispatcher) Do(ctx context.Context, command string) error

Do parses and then executes the specified command and returns the execution error, if any.

Example
var d Dispatcher

d.Register(
	Literal("foo").Then(
		Argument("bar", Int).
			Executes(CommandFunc(func(c *CommandContext) error {
				fmt.Println("Bar is", c.Int("bar"))
				return nil
			})),
	).Executes(CommandFunc(func(c *CommandContext) error {
		fmt.Println("Called foo with no arguments")
		return nil
	})),
)
Output:

func (*Dispatcher) Execute

func (d *Dispatcher) Execute(parse *ParseResults) error

Execute executes a given pre-parsed command.

If this command returns a nil error, then it successfully executed something. If the execution was a failure, then an error. Most errors will be of type CommandSyntaxError wrapping another error struct for details or an unknown error returned by a Command execution. The meaning behind the returned result is arbitrary, and will depend entirely on what command was performed.

If the command passes through a node that is CommandNode.IsFork then it will be 'forked'. A forked command will not return a CommandSyntaxError.

TODO After each and any command is ran, a registered callback given to #setConsumer(ResultConsumer)} will be notified of the result and success of the command. You can use that method to gather more meaningful results than this method will return, especially when a command forks.

func (*Dispatcher) FindNode

func (d *Dispatcher) FindNode(path ...string) CommandNode

FindNode finds a node by its path.

Paths may be generated with Path(CommandNode), and are guaranteed (for the same tree, and the same version of this library) to always produce the same valid node by this method.

If a node could not be found at the specified path, nil will be returned.

func (*Dispatcher) Parse

func (d *Dispatcher) Parse(ctx context.Context, command string) *ParseResults

Parse parses a given command.

The result of this method can be cached, and it is advised to do so where appropriate. Parsing is often the most expensive step, and this allows you to essentially "precompile" a command if it will be ran often.

If the command passes through a node that is CommandNode.IsFork then the resulting context will be marked as 'forked'. Forked contexts may contain child contexts, which may be modified by the RedirectModifier attached to the fork.

Parsing a command can never fail, you will always be provided with a new ParseResults. However, that does not mean that it will always parse into a valid command. You should inspect the returned results to check for validity. If its ParseResults.Reader StringReader.CanRead then it did not finish parsing successfully. You can use that position as an indicator to the user where the command stopped being valid. You may inspect ParseResults.Errs if you know the parse failed, as it will explain why it could not find any valid commands. It may contain multiple errors, one for each "potential node" that it could have visited, explaining why it did not go down that node.

When you eventually call Execute(ParseResults) with the result of this method, the above error checking will occur. You only need to inspect it yourself if you wish to handle that yourself.

func (*Dispatcher) ParseReader

func (d *Dispatcher) ParseReader(ctx context.Context, command *StringReader) *ParseResults

ParseReader parses a given command within a reader and optional StringReader.Cursor offset.

See Parse for more details.

func (*Dispatcher) Path

func (d *Dispatcher) Path(target CommandNode) []string

Path finds a valid path to a given node on the command tree.

There may theoretically be multiple paths to a node on the tree, especially with the use of forking or redirecting. As such, this method makes no guarantees about which path it finds. It will not look at forks or redirects, and find the first instance of the target node on the tree.

The only guarantee made is that for the same command tree and the same version of this library, the result of this method will ALWAYS be a valid input for FindNode, which should return the same node as provided to this method.

func (*Dispatcher) Register

func (d *Dispatcher) Register(command LiteralNodeBuilder) *LiteralCommandNode

Register registers new commands. This is a shortcut for calling Dispatcher.Root.AddChild after building the provided command.

As RootCommandNode can only hold literals, this method will only allow literal arguments.

func (*Dispatcher) SmartUsage

func (d *Dispatcher) SmartUsage(ctx context.Context, node CommandNode) CommandNodeStringMap

SmartUsage gets the possible executable commands from a specified node.

You may use Dispatcher.Root as a target to get usage data for the entire command tree.

The returned syntax will be in "smart" form: <param>, literal, [optional] and (either|or). These forms may be mixed and matched to provide as much information about the child nodes as it can, without being too verbose. For example, a required literal "foo" followed by an optional param "int" can be compressed into one string:

foo [<int>]

The path to the specified node will NOT be prepended to the output, as there can theoretically be many ways to reach a given node. It will only give you paths relative to the specified node, not absolute from root.

The returned usage will be restricted to only commands that the provided context.Context can use.

type Float32ArgumentType

type Float32ArgumentType struct{ Min, Max float32 }

func (*Float32ArgumentType) Parse

func (t *Float32ArgumentType) Parse(rd *StringReader) (interface{}, error)

func (*Float32ArgumentType) String

func (t *Float32ArgumentType) String() string

type Float64ArgumentType

type Float64ArgumentType struct{ Min, Max float64 }

func (*Float64ArgumentType) Parse

func (t *Float64ArgumentType) Parse(rd *StringReader) (interface{}, error)

func (*Float64ArgumentType) String

func (t *Float64ArgumentType) String() string

type IncorrectLiteralError

type IncorrectLiteralError struct {
	Literal string // The incorrect literal value.
}

IncorrectLiteralError is used to indicate an incorrect literal parse error.

func (*IncorrectLiteralError) Error

func (e *IncorrectLiteralError) Error() string

type Int32ArgumentType

type Int32ArgumentType struct{ Min, Max int32 }

func (*Int32ArgumentType) Parse

func (t *Int32ArgumentType) Parse(rd *StringReader) (interface{}, error)

func (*Int32ArgumentType) String

func (t *Int32ArgumentType) String() string

type Int64ArgumentType

type Int64ArgumentType struct{ Min, Max int64 }

func (*Int64ArgumentType) Parse

func (t *Int64ArgumentType) Parse(rd *StringReader) (interface{}, error)

func (*Int64ArgumentType) String

func (t *Int64ArgumentType) String() string

type LiteralArgumentBuilder

type LiteralArgumentBuilder struct {
	Literal string
	ArgumentBuilder
}

LiteralArgumentBuilder builds a LiteralCommandNode.

func Literal

func Literal(literal string) *LiteralArgumentBuilder

Literal returns a new literal node builder.

func (*LiteralArgumentBuilder) Build

func (*LiteralArgumentBuilder) BuildLiteral

func (b *LiteralArgumentBuilder) BuildLiteral() *LiteralCommandNode

func (*LiteralArgumentBuilder) Executes

func (b *LiteralArgumentBuilder) Executes(command Command) LiteralNodeBuilder

Executes defines the Command of the resulting LiteralCommandNode.

func (*LiteralArgumentBuilder) Fork

Fork defines the fork of the resulting LiteralCommandNode.

func (*LiteralArgumentBuilder) Forward

func (b *LiteralArgumentBuilder) Forward(target CommandNode, modifier RedirectModifier, fork bool) LiteralNodeBuilder

Forward defines the forward of the resulting ArgumentCommandNode.

func (*LiteralArgumentBuilder) NodeBuilder

func (b *LiteralArgumentBuilder) NodeBuilder() NodeBuilder

func (*LiteralArgumentBuilder) Redirect

Redirect defines the redirect node of the resulting LiteralCommandNode.

func (*LiteralArgumentBuilder) RedirectWithModifier

func (b *LiteralArgumentBuilder) RedirectWithModifier(target CommandNode, modifier RedirectModifier) LiteralNodeBuilder

RedirectWithModifier defines the redirect modifier of the resulting LiteralCommandNode.

func (*LiteralArgumentBuilder) Requires

Requires defines the RequireFn of the resulting LiteralCommandNode.

func (*LiteralArgumentBuilder) Then

func (b *LiteralArgumentBuilder) Then(arguments ...Builder) LiteralNodeBuilder

Then adds arguments to the resulting LiteralCommandNode.

type LiteralCommandNode

type LiteralCommandNode struct {
	Node
	Literal string
	// contains filtered or unexported fields
}

LiteralCommandNode is a command node storing a fixed literal.

Use Literal(name) to build it.

func (*LiteralCommandNode) Build

func (n *LiteralCommandNode) Build() CommandNode

func (*LiteralCommandNode) CreateBuilder

func (n *LiteralCommandNode) CreateBuilder() NodeBuilder

func (*LiteralCommandNode) CreateLiteralBuilder

func (n *LiteralCommandNode) CreateLiteralBuilder() LiteralNodeBuilder

func (*LiteralCommandNode) Name

func (n *LiteralCommandNode) Name() string

func (*LiteralCommandNode) Parse

Parse parses the literal from an input reader.

func (*LiteralCommandNode) String

func (n *LiteralCommandNode) String() string

func (*LiteralCommandNode) Suggestions

func (n *LiteralCommandNode) Suggestions(_ *CommandContext, builder *SuggestionsBuilder) *Suggestions

Suggestions implements SuggestionProvider.

func (*LiteralCommandNode) UsageText

func (n *LiteralCommandNode) UsageText() string

type LiteralNodeBuilder

type LiteralNodeBuilder interface {
	Builder
	BuildLiteral() *LiteralCommandNode
	NodeBuilder() NodeBuilder // Convert to NodeBuilder
	Then(arguments ...Builder) LiteralNodeBuilder

	Executes(command Command) LiteralNodeBuilder
	Requires(fn RequireFn) LiteralNodeBuilder
	Redirect(target CommandNode) LiteralNodeBuilder
	RedirectWithModifier(target CommandNode, modifier RedirectModifier) LiteralNodeBuilder
	Fork(target CommandNode, modifier RedirectModifier) LiteralNodeBuilder
	Forward(target CommandNode, modifier RedirectModifier, fork bool) LiteralNodeBuilder
}

LiteralNodeBuilder is a LiteralCommandNode builder.

type ModifierFunc

type ModifierFunc func(c *CommandContext) (context.Context, error)

ModifierFunc is a convenient function type implementing the RedirectModifier interface.

func (ModifierFunc) Apply

Apply implements RedirectModifier.

type Node

type Node struct {
	// contains filtered or unexported fields
}

Node is a node with the common fields and wrapped by RootCommandNode, LiteralCommandNode and ArgumentCommandNode.

func (*Node) AddChild

func (n *Node) AddChild(nodes ...CommandNode)

AddChild adds a CommandNode to the Node's children. Most often times one should use Dispatcher.Register instead.

func (*Node) Arguments

func (n *Node) Arguments() map[string]*ArgumentCommandNode

func (*Node) CanUse

func (n *Node) CanUse(ctx context.Context) bool

func (*Node) Children

func (n *Node) Children() map[string]CommandNode

func (*Node) ChildrenOrdered

func (n *Node) ChildrenOrdered() StringCommandNodeMap

func (*Node) Command

func (n *Node) Command() Command

func (*Node) IsFork

func (n *Node) IsFork() bool

func (*Node) Literals

func (n *Node) Literals() map[string]*LiteralCommandNode

func (*Node) Redirect

func (n *Node) Redirect() CommandNode

func (*Node) RedirectModifier

func (n *Node) RedirectModifier() RedirectModifier

func (*Node) RelevantNodes

func (n *Node) RelevantNodes(input *StringReader) []CommandNode

func (*Node) RemoveChild

func (n *Node) RemoveChild(names ...string)

func (*Node) Requirement

func (n *Node) Requirement() RequireFn

type NodeBuilder

type NodeBuilder interface {
	Builder
	Then(arguments ...Builder) NodeBuilder

	Executes(command Command) NodeBuilder
	Requires(fn RequireFn) NodeBuilder
	Redirect(target CommandNode) NodeBuilder
	RedirectWithModifier(target CommandNode, modifier RedirectModifier) NodeBuilder
	Fork(target CommandNode, modifier RedirectModifier) NodeBuilder
	Forward(target CommandNode, modifier RedirectModifier, fork bool) NodeBuilder
}

NodeBuilder is a Builder with build-methods.

type ParseResults

type ParseResults struct {
	Context *CommandContext
	Reader  *StringReader
	Errs    map[CommandNode]error
}

ParseResults stores the parse results returned by Dispatcher.Parse.

type ParsedArgument

type ParsedArgument struct {
	Range  *StringRange // The string range of the argument in the command input.
	Result interface{}  // The parsed result value.
}

ParsedArgument is a parsed argument.

type ParsedCommandNode

type ParsedCommandNode struct {
	Node  CommandNode
	Range *StringRange
}

ParsedCommandNode is a parsed command node.

type ReaderError

type ReaderError struct {
	Err    error
	Reader *StringReader
}

ReaderError indicates a StringReader error.

func (*ReaderError) Error

func (e *ReaderError) Error() string

func (*ReaderError) Unwrap

func (e *ReaderError) Unwrap() error

Unwrap implements errors.Unwrap.

type ReaderInvalidValueError

type ReaderInvalidValueError struct {
	Type  ArgumentType // The expected value type
	Value string

	Err error // Optional underlying error
}

ReaderInvalidValueError indicates an invalid value error.

func (*ReaderInvalidValueError) Error

func (e *ReaderInvalidValueError) Error() string

Error implements error.

func (*ReaderInvalidValueError) Unwrap

func (e *ReaderInvalidValueError) Unwrap() error

Unwrap implements errors.Unwrap.

type RedirectModifier

type RedirectModifier interface {
	Apply(ctx *CommandContext) (context.Context, error)
}

RedirectModifier modifies

type RequireFn

type RequireFn func(context.Context) bool

RequireFn is the function used for CommandNode.CanUse.

type RequiredArgumentBuilder

type RequiredArgumentBuilder struct {
	Name                string
	Type                ArgumentType
	SuggestionsProvider SuggestionProvider // Optional
	ArgumentBuilder
}

RequiredArgumentBuilder builds an ArgumentCommandNode.

func Argument

func Argument(name string, argType ArgumentType) *RequiredArgumentBuilder

Argument returns a new argument node builder.

func (*RequiredArgumentBuilder) Build

func (*RequiredArgumentBuilder) BuildArgument

func (b *RequiredArgumentBuilder) BuildArgument() *ArgumentCommandNode

func (*RequiredArgumentBuilder) Executes

Executes defines the Command of the resulting ArgumentCommandNode.

func (*RequiredArgumentBuilder) Fork

Fork defines the fork of the resulting ArgumentCommandNode.

func (*RequiredArgumentBuilder) Forward

Forward defines the forward of the resulting ArgumentCommandNode.

func (*RequiredArgumentBuilder) NodeBuilder

func (b *RequiredArgumentBuilder) NodeBuilder() NodeBuilder

func (*RequiredArgumentBuilder) Redirect

Redirect defines the redirect node of the resulting ArgumentCommandNode.

func (*RequiredArgumentBuilder) RedirectWithModifier

func (b *RequiredArgumentBuilder) RedirectWithModifier(target CommandNode, modifier RedirectModifier) ArgumentNodeBuilder

RedirectWithModifier defines the redirect modifier of the resulting ArgumentCommandNode.

func (*RequiredArgumentBuilder) Requires

Requires defines the RequireFn of the resulting ArgumentCommandNode.

func (*RequiredArgumentBuilder) Suggests

Suggests defines the SuggestionProvider of the resulting ArgumentCommandNode.

func (*RequiredArgumentBuilder) Then

func (b *RequiredArgumentBuilder) Then(arguments ...Builder) ArgumentNodeBuilder

Then adds arguments to the resulting ArgumentCommandNode.

type RootCommandNode

type RootCommandNode struct {
	Node // The starting root node.
}

RootCommandNode is the root of a command node tree.

func (*RootCommandNode) CreateBuilder

func (r *RootCommandNode) CreateBuilder() NodeBuilder

CreateBuilder cannot create a builder from root node and returns a nop-builder!

func (*RootCommandNode) Name

func (r *RootCommandNode) Name() string

func (*RootCommandNode) Parse

func (*RootCommandNode) String

func (r *RootCommandNode) String() string

func (*RootCommandNode) UsageText

func (r *RootCommandNode) UsageText() string

type StringCommandNodeMap

type StringCommandNodeMap interface {
	// Put inserts key-value pair into the map.
	Put(key string, value CommandNode)
	// Get searches the element in the map by key and returns its value or nil if key is not found in tree.
	// Second return parameter is true if key was found, otherwise false.
	Get(key string) (value CommandNode, found bool)
	// Remove removes the element from the map by key.
	Remove(key string)
	// Keys returns all keys in-order
	Keys() []string
	// Values returns all values in-order based on the key.
	Values() []CommandNode

	// Range calls the given function once for each element
	// until f returns false, passing that element's key and value.
	Range(f func(key string, value CommandNode) bool)

	Container
}

StringCommandNodeMap holds the elements in a regular hash table, and uses doubly-linked list to store key ordering.

func NewStringCommandNodeMap

func NewStringCommandNodeMap() StringCommandNodeMap

NewStringCommandNodeMap returns a new StringCommandNodeMap.

type StringRange

type StringRange struct{ Start, End int }

StringRange stores a range indicating the start and end of a string

func EncompassingRange

func EncompassingRange(r1, r2 *StringRange) *StringRange

EncompassingRange returns the min and max StringRange of two ranges.

func (StringRange) Copy

func (r StringRange) Copy() StringRange

Copy copies the StringRange.

func (*StringRange) Get

func (r *StringRange) Get(s string) string

Get returns the substring of s from Start to End.

func (*StringRange) IsEmpty

func (r *StringRange) IsEmpty() bool

IsEmpty indicated whether Start and End is equal.

type StringReader

type StringReader struct {
	Cursor int
	String string
}

StringReader is a string reader used for input parsing.

func (*StringReader) CanRead

func (r *StringReader) CanRead() bool

CanRead indicates whether a next rune can be read to a call to Read.

func (*StringReader) CanReadLen

func (r *StringReader) CanReadLen(length int) bool

CanReadLen indicates whether the next length runes can be read.

func (*StringReader) Peek

func (r *StringReader) Peek() rune

Peek returns the next rune without incrementing the Cursor.

func (*StringReader) Read

func (r *StringReader) Read() rune

Read returns the next rune.

func (*StringReader) ReadBool

func (r *StringReader) ReadBool() (bool, error)

ReadBool tries to read a bool.

func (*StringReader) ReadFloat32

func (r *StringReader) ReadFloat32() (float32, error)

ReadFloat32 tries to read a float32.

func (*StringReader) ReadFloat64

func (r *StringReader) ReadFloat64() (float64, error)

ReadFloat64 tries to read a float64.

func (*StringReader) ReadInt

func (r *StringReader) ReadInt() (int, error)

ReadInt tries to read an int32.

func (*StringReader) ReadInt32

func (r *StringReader) ReadInt32() (int32, error)

ReadInt32 tries to read an int32.

func (*StringReader) ReadInt64

func (r *StringReader) ReadInt64() (int64, error)

ReadInt64 tries to read an int64.

func (*StringReader) ReadQuotedString

func (r *StringReader) ReadQuotedString() (string, error)

ReadQuotedString reads a quoted string.

func (*StringReader) ReadString

func (r *StringReader) ReadString() (string, error)

ReadString returns the next quoted or unquoted string.

func (*StringReader) ReadStringUntil

func (r *StringReader) ReadStringUntil(terminator rune) (string, error)

ReadStringUntil reads a string until the terminator rune.

func (*StringReader) ReadUnquotedString

func (r *StringReader) ReadUnquotedString() string

ReadUnquotedString reads an unquoted string.

func (*StringReader) Remaining

func (r *StringReader) Remaining() string

Remaining returns the remaining string beginning at the current Cursor

func (*StringReader) RemainingLen

func (r *StringReader) RemainingLen() int

RemainingLen returns the remaining string length beginning at the current Cursor

func (*StringReader) Skip

func (r *StringReader) Skip()

Skip increments the Cursor.

type StringType

type StringType uint8

StringType is a string ArgumentType.

const (
	SingleWord    StringType = iota // A single-word string.
	QuotablePhase                   // A quotable phrase string.
	GreedyPhrase                    // A "greedy" string phrase.
)

Builtin string argument types.

func (StringType) Parse

func (t StringType) Parse(rd *StringReader) (interface{}, error)

func (StringType) String

func (t StringType) String() string

type Suggestion

type Suggestion struct {
	Range   StringRange
	Text    string
	Tooltip fmt.Stringer
}

Suggestion is a command suggestion.

func (*Suggestion) Expand

func (s *Suggestion) Expand(command string, strRange *StringRange) *Suggestion

Expand expands a command suggestion if appropriate.

type SuggestionContext

type SuggestionContext struct {
	Parent CommandNode
	Start  int
}

SuggestionContext is a command suggestion context.

type SuggestionProvider

type SuggestionProvider interface {
	Suggestions(*CommandContext, *SuggestionsBuilder) *Suggestions
}

SuggestionProvider provides Suggestions and can optionally be implemented by a CommandNode to add suggestions support to an command argument type.

type Suggestions

type Suggestions struct {
	Range       StringRange
	Suggestions []*Suggestion
}

Suggestions are command suggestions within a string range.

func CreateSuggestion

func CreateSuggestion(command string, suggestions []*Suggestion) *Suggestions

CreateSuggestion creates a Suggestions from multiple Suggestion.

func MergeSuggestions

func MergeSuggestions(command string, input []*Suggestions) *Suggestions

MergeSuggestions merges multiple Suggestions into one.

func ProvideSuggestions

func ProvideSuggestions(i interface{}, ctx *CommandContext, builder *SuggestionsBuilder) *Suggestions

ProvideSuggestions returns the Suggestions if i implements SuggestionProvider or returns empty Suggestions if it doesn't.

type SuggestionsBuilder

type SuggestionsBuilder struct {
	Input              string
	InputLowerCase     string
	Start              int
	Remaining          string
	RemainingLowerCase string
	Result             []*Suggestion
}

SuggestionsBuilder is a convenient struct for building Suggestions.

func (*SuggestionsBuilder) Build

func (b *SuggestionsBuilder) Build() *Suggestions

Build returns a Suggestions build from the builder.

func (*SuggestionsBuilder) Suggest

func (b *SuggestionsBuilder) Suggest(text string) *SuggestionsBuilder

Suggest adds a suggestion to the builder.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL