commander

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Sep 29, 2024 License: MIT Imports: 11 Imported by: 0

README

commander

commander is an interactive command processor, similar to python's CMD2, but written for golang. it is not a golang REPL, but rather an interactive shell environment which allows the user to define and implement rich commands, which can then be executed with amenities such as:

  • full tab completion
  • contextual help
  • stdout piping and redirection

demo

a brief screen recording showcasing some of commander's capabilities demo

example

please explore the working example in the /example directory

go run ./example/*.go

Documentation

Index

Constants

View Source
const (
	PatternArg     string = "pattern"
	InsensitiveArg string = "insensitive"
)
View Source
const (
	COMMAND_PADDING = 30
)

Variables

View Source
var (
	C_RESET = "\x1b[0m"
	C_RED   = FgColor(255, 0, 0)
	C_GREEN = FgColor(0, 255, 0)
	C_BOLD  = "\x1b[1m"
)
View Source
var (
	FLOW_CONTROL_UNSPECIFIED byte = ' '
	FLOW_CONTROL_PIPE        byte = '|'
	FLOW_CONTROL_REDIRECT    byte = '>'
)
View Source
var ClearCommand = &Command{
	Name:        "clear",
	Description: "clear the terminal",
	OnExecute: func(c *Command, args ArgMap, capturedInput []byte) error {
		termutils.ClearTerminal()
		termutils.SetCursorPos(1, 1)
		return nil
	},
}
View Source
var ControlCharacters = map[byte]struct{}{
	FLOW_CONTROL_PIPE:     {},
	FLOW_CONTROL_REDIRECT: {},
}
View Source
var ExitCommand = &Command{
	Name:        "exit",
	Description: "exit the shell",
	OnExecute: func(c *Command, args ArgMap, capturedInput []byte) error {
		return ns.ErrEof
	},
}
View Source
var GrepCommand = &Command{
	Name:        "grep",
	Description: "filter and pattern match input",
	Arguments: []*Argument{
		{
			Name:        PatternArg,
			Description: "search pattern",
			ArgType:     ArgTypeString,
		},
	},
	Flags: []*Flag{
		{
			Name:         InsensitiveArg,
			ShortName:    "i",
			Description:  "case insensitive matching",
			ArgType:      ArgTypeBool,
			DefaultValue: false,
		},
	},
	OnExecute: func(c *Command, args ArgMap, capturedInput []byte) error {
		pattern := args.GetString(PatternArg)
		insensitive := args.GetBool(InsensitiveArg)
		lowerPattern := strings.ToLower(pattern)

		if len(capturedInput) > 0 {
			ci := string(capturedInput)
			lines := strings.Split(ci, "\n")
			for _, line := range lines {
				if insensitive {
					if !strings.Contains(strings.ToLower(line), lowerPattern) {
						continue
					}
				} else if !strings.Contains(line, pattern) {
					continue
				}

				fmt.Println(line)
			}
		}

		return nil
	},
}
View Source
var HelpCommand = &Command{
	Name:        "help",
	Description: "display contextual command help",
	OnExecute: func(c *Command, args ArgMap, capturedInput []byte) error {
		fmt.Println("Command list:")

		commandList := []string{}
		for _, cmd := range c.Commander.commandMap {
			commandList = append(commandList, cmd.Name)
		}
		sort.Slice(commandList, func(i, j int) bool {
			return commandList[i] < commandList[j]
		})

		for _, cmdName := range commandList {
			cmd := c.Commander.commandMap[cmdName]
			fmt.Printf("  %s%s\n", PadRight(cmd.Name, COMMAND_PADDING), cmd.Description)
		}

		return nil
	},
}

Functions

func Errorln

func Errorln(text ...string)

func FgColor

func FgColor(red int, green int, blue int) string

func GetValueFromString

func GetValueFromString(argType ArgType, value string) (any, error)

func MatchesOneOf

func MatchesOneOf(oneOf []any, sample any) bool

func PadRight

func PadRight(text string, width int) string

func Println

func Println(text ...string)

func Sprintf

func Sprintf(text ...string) string

Types

type ArgMap added in v0.2.0

type ArgMap map[string]any

func (ArgMap) GetBool added in v0.2.0

func (m ArgMap) GetBool(argName string) bool

func (ArgMap) GetFloat added in v0.2.0

func (m ArgMap) GetFloat(argName string) float64

func (ArgMap) GetFloatArray added in v0.2.0

func (m ArgMap) GetFloatArray(argName string) []float64

func (ArgMap) GetInt added in v0.2.0

func (m ArgMap) GetInt(argName string) int

func (ArgMap) GetIntArray added in v0.2.0

func (m ArgMap) GetIntArray(argName string) []int

func (ArgMap) GetString added in v0.2.0

func (m ArgMap) GetString(argName string) string

func (ArgMap) GetStringArray added in v0.2.0

func (m ArgMap) GetStringArray(argName string) []string

type ArgType

type ArgType string
const (
	ArgTypeUnspecified ArgType = ""
	ArgTypeInt         ArgType = "INT"
	ArgTypeFloat       ArgType = "FLOAT"
	ArgTypeString      ArgType = "STRING"
	ArgTypeBool        ArgType = "BOOL"
)

func InferArgType

func InferArgType(value any) ArgType

InferArgType infers the ArgType based on the variable type, or returns ArgTypeUnspecified if the variable type does not match one of the known values.

type Argument

type Argument struct {
	Name          string
	Description   string
	ArgType       ArgType
	AllowMultiple bool  // if enabled, will be returned as an array of ArgType
	OneOf         []any // if specified, value must belong to collection
	Completer     Completer
}

an argument represents a positional argument. it is non-defaultable

func (*Argument) GetValueFromString

func (a *Argument) GetValueFromString(value string) (any, error)

GetValueFromString parses the provided value according to the argument's underlying data type and returns that parsed value, or an error

func (*Argument) PopulateMap

func (a *Argument) PopulateMap(value string, target map[string]any) error

func (*Argument) SuggestValues

func (a *Argument) SuggestValues(prefix string) *ns.Suggestions

func (*Argument) Validate

func (a *Argument) Validate() error

Validate returns an error if any part of the argument is invalid

type BoundExec

type BoundExec struct {
	IsCapturingOutput bool
	Command           *Command
	ArgMap            map[string]any
}

type Capture

type Capture struct {
	Buffer bytes.Buffer
	Error  error
}

type Command

type Command struct {
	Name        string
	Description string
	Flags       []*Flag
	Arguments   []*Argument
	SubCommands []*Command
	OnExecute   func(c *Command, args ArgMap, capturedInput []byte) error

	Commander *Commander
	// contains filtered or unexported fields
}

func (*Command) ClassifyTokens

func (c *Command) ClassifyTokens(tokens []string, parentFlags []*Flag) (map[string]any, error)

ClassifyTokens attempts to classify the token array using the defined flags and arguments, in order to populate a name to value mapping

func (*Command) GetHelpString

func (c *Command) GetHelpString(parentFlags []*Flag) string

func (*Command) Suggest

func (c *Command) Suggest(tokens []string, parentFlags []*Flag) *ns.Suggestions

func (*Command) Validate

func (c *Command) Validate(parentFlags map[string]struct{}) error

Validate ensures that the command is valid, returning a descriptive error if it is not. Also, performs any run-time optimization. This should only be called by the Commander.

type Commander

type Commander struct {
	Config Config
	// contains filtered or unexported fields
}

func NewCommander

func NewCommander(config Config) (*Commander, error)

NewCommander returns a new Commander instance

func (*Commander) LocateCommand

func (c *Commander) LocateCommand(tokens []string) (*Command, []*Flag, []string)

LocateCommand will attempt to locate a command from a series of tokens presented as arguments to the Commander. The method will match up to either the final subcommand, returning the remaining arguments, or to the final matching subcommand, returning whatever unmatched is left.

func (*Commander) Run

func (c *Commander) Run() error

type Completer

type Completer func(search string) *ns.Suggestions

Completer is a type of function which returns a list of strings based on a search string

type Config

type Config struct {
	PromptFunc func() string
	Commands   []*Command
	DumpFile   string // For debugging purposes, all input will be sent to this file, if set
}

type Flag

type Flag struct {
	Name          string
	ShortName     string
	Description   string
	ArgType       ArgType
	AllowMultiple bool // if enabled, will be returned as an array of ArgType
	DefaultValue  any
	OneOf         []any // if specified, value must belong to collection
	Completer     Completer
	IsRequired    bool
}

func (*Flag) GetInvocation

func (f *Flag) GetInvocation() string

func (*Flag) GetPaddedInvocation

func (f *Flag) GetPaddedInvocation() string

func (*Flag) GetValueFromString

func (f *Flag) GetValueFromString(value string) (any, error)

GetValueFromString parses the provided value according to the flag's underlying data type and returns that parsed value, or an error

func (*Flag) PopulateDefault

func (f *Flag) PopulateDefault(target map[string]any) error

func (*Flag) PopulateMap

func (f *Flag) PopulateMap(value string, target map[string]any) error

func (*Flag) SuggestValues

func (f *Flag) SuggestValues(prefix string) *ns.Suggestions

func (*Flag) Validate

func (f *Flag) Validate() error

Validate returns an error if any part of the flag is invalid

type TokenGroup

type TokenGroup struct {
	Tokens      []string
	FlowControl byte
}

func Tokenize

func Tokenize(line string) []*TokenGroup

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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