Documentation ¶
Overview ¶
Package commandinput provides an implementation of the input.Input interface. It should be used to build interactive CLI applications.
Example ¶
package main import ( "fmt" "os" "strconv" prompt "github.com/aschey/bubbleprompt" "github.com/aschey/bubbleprompt/completer" "github.com/aschey/bubbleprompt/executor" "github.com/aschey/bubbleprompt/input/commandinput" "github.com/aschey/bubbleprompt/suggestion" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" ) type secretMsg string type cmdMetadata = commandinput.CommandMetadata[any] type model struct { suggestions []suggestion.Suggestion[cmdMetadata] textInput *commandinput.Model[any] secret string executorValueStyle lipgloss.Style filterer completer.RecursiveFilterer[cmdMetadata] } func (m model) Complete( promptModel prompt.Model[cmdMetadata], ) ([]suggestion.Suggestion[cmdMetadata], error) { parsed := m.textInput.ParsedValue() completed := m.textInput.CompletedArgsBeforeCursor() if len(completed) == 1 && parsed.Command.Value == "get" && parsed.Args[0].Value == "weather" { flags := []commandinput.FlagInput{ { Short: "d", Long: "days", ArgPlaceholder: m.textInput.NewFlagPlaceholder("<int>"), Description: "Forecast days", }, } return m.textInput.FlagSuggestions( m.textInput.CurrentTokenBeforeCursor().Value, flags, nil, ), nil } return m.filterer.GetRecursiveSuggestions( m.textInput.Tokens(), m.textInput.CursorIndex(), m.suggestions, ), nil } func (m model) Execute(input string, promptModel *prompt.Model[cmdMetadata]) (tea.Model, error) { parsed := m.textInput.ParsedValue() args := parsed.Args flags := parsed.Flags if len(args) == 0 { return nil, fmt.Errorf("1 argument required") } arg := args[0] switch parsed.Command.Value { case "get": switch arg.Value { case "weather": days := "1" if len(flags) > 0 { flag := flags[0] if flag.Name.Value == "-d" || flag.Name.Value == "--days" { if flag.Value == nil { return nil, fmt.Errorf("flag value required") } _, err := strconv.ParseInt(flag.Value.Value, 10, 64) if err != nil { return nil, fmt.Errorf("flag value must be a valid int") } days = flag.Value.Value } } days = m.executorValueStyle.Render(days) value := m.executorValueStyle.Render("cloudy with a chance of meatballs") return executor.NewStringModel( fmt.Sprintf("weather for the next %s day(s) is: %s", days, value), ), nil case "secret": return executor.NewStringModel( "the secret is: " + m.executorValueStyle.Render(m.secret), ), nil } case "set": switch arg.Value { case "secret": if len(args) < 2 { return nil, fmt.Errorf("secret value required") } secretVal := args[1] return executor.NewCmdModel("Secret updated", func() tea.Msg { return secretMsg(secretVal.Unquote()) }), nil } } return nil, fmt.Errorf("Invalid input") } func (m model) Init() tea.Cmd { return nil } func (m model) Update(msg tea.Msg) (prompt.InputHandler[cmdMetadata], tea.Cmd) { if msg, ok := msg.(secretMsg); ok { m.secret = string(msg) } return m, nil } func main() { textInput := commandinput.New[any]() secretArgs := textInput.NewPositionalArgs("<secret value>") secretArgs[0].ArgStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("6")) suggestions := []suggestion.Suggestion[cmdMetadata]{ { Text: "get", Description: "retrieve things", Metadata: cmdMetadata{ PositionalArgs: textInput.NewPositionalArgs("<command"), Children: []suggestion.Suggestion[cmdMetadata]{ { Text: "secret", Description: "get the secret", }, { Text: "weather", Description: "get the weather", Metadata: cmdMetadata{ ShowFlagPlaceholder: true, }, }, }, }, }, { Text: "set", Description: "update things", Metadata: cmdMetadata{ Children: []suggestion.Suggestion[cmdMetadata]{ { Text: "secret", Description: "update the secret", Metadata: cmdMetadata{ PositionalArgs: secretArgs, }, }, }, }, }, } model := model{ suggestions: suggestions, textInput: textInput, secret: "hunter2", executorValueStyle: lipgloss.NewStyle().Foreground(lipgloss.Color("13")), filterer: completer.NewRecursiveFilterer[cmdMetadata](), } promptModel := prompt.New[cmdMetadata]( model, textInput, ) if _, err := tea.NewProgram(promptModel, tea.WithFilter(prompt.MsgFilter)).Run(); err != nil { fmt.Printf("Could not start program\n%v\n", err) os.Exit(1) } }
Output:
Index ¶
- Variables
- type Arg
- type CommandMetadata
- type Flag
- type FlagArgPlaceholder
- type FlagFormatter
- type FlagInput
- type FlagValueFormatter
- type Formatters
- type Model
- func (m *Model[T]) ArgsBeforeCursor() []string
- func (m *Model[T]) Blur()
- func (m Model[T]) CommandBeforeCursor() string
- func (m Model[T]) CommandCompleted() bool
- func (m *Model[T]) CompletedArgsBeforeCursor() []string
- func (m Model[T]) CurrentToken() input.Token
- func (m Model[T]) CurrentTokenBeforeCursor() input.Token
- func (m Model[T]) CurrentTokenBeforeCursorRoundDown() input.Token
- func (m Model[T]) CurrentTokenRoundDown() input.Token
- func (m Model[T]) CursorIndex() int
- func (m Model[T]) CursorOffset() int
- func (m *Model[T]) FlagSuggestions(inputStr string, flags []FlagInput, ...) []suggestion.Suggestion[CommandMetadata[T]]
- func (m *Model[T]) Focus() tea.Cmd
- func (m Model[T]) Focused() bool
- func (m Model[T]) Formatters() Formatters
- func (m Model[T]) HasArgs() bool
- func (m Model[T]) LastArg() *input.Token
- func (m *Model[T]) NewFlagPlaceholder(placeholder string) FlagArgPlaceholder
- func (m *Model[T]) NewPositionalArg(placeholder string) PositionalArg
- func (m *Model[T]) NewPositionalArgs(placeholders ...string) []PositionalArg
- func (m *Model[T]) OnExecutorFinished()
- func (m *Model[T]) OnSuggestionChanged(suggestion suggestion.Suggestion[CommandMetadata[T]])
- func (m *Model[T]) OnSuggestionUnselected()
- func (m *Model[T]) OnUpdateFinish(msg tea.Msg, suggestion *suggestion.Suggestion[CommandMetadata[T]], ...) tea.Cmd
- func (m *Model[T]) OnUpdateStart(msg tea.Msg) tea.Cmd
- func (m *Model[T]) ParseUsage(placeholders string) ([]PositionalArg, error)
- func (m Model[T]) ParsedValue() Statement
- func (m *Model[T]) Prompt() string
- func (m *Model[T]) ResetValue()
- func (m Model[T]) Runes() []rune
- func (m *Model[T]) SetCursor(pos int)
- func (m *Model[T]) SetCursorMode(cursorMode cursor.Mode) tea.Cmd
- func (m *Model[T]) SetFormatters(formatters Formatters)
- func (m *Model[T]) SetPrompt(prompt string)
- func (m *Model[T]) SetValue(s string)
- func (m *Model[T]) ShouldClearSuggestions(prevText []rune, msg tea.KeyMsg) bool
- func (m *Model[T]) ShouldSelectSuggestion(suggestion suggestion.Suggestion[CommandMetadata[T]]) bool
- func (m *Model[T]) ShouldUnselectSuggestion(prevRunes []rune, msg tea.KeyMsg) bool
- func (m Model[T]) SuggestionRunes(runes []rune) []rune
- func (m Model[T]) Tokens() []input.Token
- func (m Model[T]) TokensBeforeCursor() []input.Token
- func (m Model[T]) Value() string
- func (m Model[T]) Values() []string
- func (m Model[T]) ValuesBeforeCursor() []string
- func (m Model[T]) View(viewMode input.ViewMode) string
- type Option
- type PositionalArg
- type PositionalArgFormatter
- type Statement
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( DefaultPlaceholderForeground = "14" DefaultCurrentPlaceholderSuggestion = "240" DefaultSelectedTextColor = "10" DefaultFlagForeground = "245" DefaultFlagPlaceholderForeground = "14" DefaultBoolFlagForeground = "13" DefaultNumberFlagForeground = "5" )
Functions ¶
This section is empty.
Types ¶
type CommandMetadata ¶
type CommandMetadata[T any] struct { // PositionalArgs is the list of positional args that this suggestion accepts. PositionalArgs []PositionalArg // ShowFlagPlaceholder is whether or not the input should display a placeholder // indicating that this command has flags available. ShowFlagPlaceholder bool // FlagArgPlaceholder is the placeholder FlagArgPlaceholder FlagArgPlaceholder PreservePlaceholder bool Variadic bool Children []suggestion.Suggestion[CommandMetadata[T]] Extra T }
CommandMetadata defines the metadata that the Model uses to get information about the supplied suggestion.Suggestion. You can extend this struct to provide additional metadata.
func MetadataFromPositionalArgs ¶
func MetadataFromPositionalArgs[T any](positionalArgs ...PositionalArg) CommandMetadata[T]
MetadataFromPositionalArgs is a convenience function for creating a CommandMetadata from one or more PositionalArg.
Example ¶
package main import ( "fmt" "github.com/aschey/bubbleprompt/input/commandinput" "github.com/aschey/bubbleprompt/suggestion" ) func main() { textInput := commandinput.New[commandinput.CommandMetadata[any]]() commandMetadata := commandinput.MetadataFromPositionalArgs[any](textInput.NewPositionalArg("<arg1>")) suggestions := []suggestion.Suggestion[commandinput.CommandMetadata[any]]{ {Text: "test", Metadata: commandMetadata}, } fmt.Println(suggestions[0].Metadata.PositionalArgs[0].Placeholder()) }
Output: <arg1>
func (CommandMetadata[T]) GetChildren ¶
func (c CommandMetadata[T]) GetChildren() []suggestion.Suggestion[CommandMetadata[T]]
type FlagArgPlaceholder ¶
FlagArgPlaceholder is a flag placeholder for completions.
func (FlagArgPlaceholder) Text ¶
func (p FlagArgPlaceholder) Text() string
Text returns the placeholder text.
type FlagFormatter ¶
type FlagFormatter struct { // Flag handles styling for the flag itself. Flag lipgloss.Style // Placeholder handles styling for the placeholder that appears before the flag's argument is supplied (if applicable). Placeholder lipgloss.Style }
FlagFormatter handles styling for flags.
type FlagInput ¶
type FlagInput struct { // Short is a short (single letter) flag with a single dash. // The leading dash can be optionally included. Short string // Long is a long (multi-letter) flag with multiple dashes. // The leading dashes can optionally be included. Long string // ArgPlaceholder is the placeholder for the flag argument (if applicable). ArgPlaceholder FlagArgPlaceholder // Description is the flag description. Description string }
FlagInput is used to generate a list of flag suggestions.
func (FlagInput) LongFlag ¶
ShortFlag returns the Long property formatted as a flag with the leading dashes.
func (FlagInput) RequiresArg ¶
RequiresArg returns whether or not the input has an argument placeholder. If no placeholder is supplied, then it is assumed that the FlagInput does not require an argument.
type FlagValueFormatter ¶
type FlagValueFormatter struct { // String handles styling for string values. String lipgloss.Style // Bool handles styling for boolean values. Bool lipgloss.Style // Number handles styling for numeric values. Number lipgloss.Style }
FlagValueFormatter handles styling for different flag value data types.
type Formatters ¶
type Formatters struct { // PositionalArg handles styling for positional arguments. PositionalArg PositionalArgFormatter // Flag handles styling for flags. Flag FlagFormatter // FlagValue handles styling for a flag's value (if applicable). FlagValue FlagValueFormatter // Placeholder handles styling for placeholder that's shown as the user types the current argument. Placeholder lipgloss.Style // Prompt handles styling for the prompt that's shown before the user input. Prompt lipgloss.Style // Command handles styling for the command. Command lipgloss.Style // SelectedText handles styling for the text that's selected by the suggestion manager. SelectedText lipgloss.Style // Cursor handles styling for the cursor. Cursor lipgloss.Style }
Formatters handles styling for the command input.
func DefaultFormatters ¶
func DefaultFormatters() Formatters
DefaultFormatters initializes the Formatters with sensible defaults. You can modify any settings that you wish after calling this function.
Example ¶
package main import ( "fmt" "github.com/aschey/bubbleprompt/input/commandinput" "github.com/charmbracelet/lipgloss" ) func main() { defaultFormatters := commandinput.DefaultFormatters() defaultFormatters.Cursor = lipgloss.NewStyle().Foreground(lipgloss.Color("128")) fmt.Println(defaultFormatters.Cursor.GetForeground()) }
Output: 128
type Model ¶
type Model[T any] struct { // contains filtered or unexported fields }
A Model is an input for handling CLI-style inputs. It provides advanced features such as placeholders and context-aware suggestions.
func (*Model[T]) ArgsBeforeCursor ¶
ArgsBeforeCursor returns the positional arguments before the cursor position.
func (Model[T]) CommandBeforeCursor ¶
CommandBeforeCursor returns the portion of the command (first input token) before the cursor position.
func (Model[T]) CommandCompleted ¶
CommandCompleted returns whether the user finished typing the entire command (first token).
func (*Model[T]) CompletedArgsBeforeCursor ¶
CompletedArgsBeforeCursor returns the positional arguments before the cursor that have already been completed. In other words, there needs to be a delimiter after the argument to indicate that the user has finished entering in that argument.
func (Model[T]) CurrentToken ¶
CurrentToken returns the token under the cursor. If the cursor is between two tokens, it will take the token after the cursor.
func (Model[T]) CurrentTokenBeforeCursor ¶
CurrentTokenBeforeCursor returns the portion of the current token before the cursor. If the cursor is between two tokens, it will take the token after the cursor.
func (Model[T]) CurrentTokenBeforeCursorRoundDown ¶
CurrentTokenBeforeCursorRoundDown returns the portion of the current token before the cursor. If the cursor is between two tokens, it will take the token before the cursor.
func (Model[T]) CurrentTokenRoundDown ¶
CurrentTokenRoundDown returns the token under the cursor. If the cursor is between two tokens, it will take the token before the cursor.
func (Model[T]) CursorIndex ¶
CursorIndex returns the cursor index in terms of number of unicode characters. Use this to calculate input lengths in terms of number of characters entered.
func (Model[T]) CursorOffset ¶
CursorOffset returns the visual offset of the cursor in terms of number of terminal cells. Use this for calculating visual dimensions such as input width/height.
func (*Model[T]) FlagSuggestions ¶
func (m *Model[T]) FlagSuggestions( inputStr string, flags []FlagInput, suggestionFunc func(FlagInput) CommandMetadata[T], ) []suggestion.Suggestion[CommandMetadata[T]]
FlagSuggestions generates a list of suggestion.Suggestion based on the input string and the list of FlagInput supplied. The last parameter can be used to customize the metadata for the returned suggestions.
Example ¶
package main import ( "fmt" "github.com/aschey/bubbleprompt/input/commandinput" ) func main() { textInput := commandinput.New[any]() flags := []commandinput.FlagInput{ { Short: "i", Long: "interval", Description: "refresh interval", ArgPlaceholder: textInput.NewFlagPlaceholder("<value>"), }, } suggestions := textInput.FlagSuggestions("", flags, nil) fmt.Printf("Text: %s, Description: %s\n", suggestions[0].Text, suggestions[0].Description) suggestions = textInput.FlagSuggestions("--", flags, nil) fmt.Printf("Text: %s, Description: %s\n", suggestions[0].Text, suggestions[0].Description) suggestions = textInput.FlagSuggestions("", flags, func(flagInput commandinput.FlagInput) commandinput.CommandMetadata[any] { return commandinput.CommandMetadata[any]{ FlagArgPlaceholder: flagInput.ArgPlaceholder, PreservePlaceholder: true, } }) fmt.Printf( "Text: %s, Description: %s, Preserve Placeholder: %t\n", suggestions[0].Text, suggestions[0].Description, suggestions[0].Metadata.PreservePlaceholder, ) }
Output: Text: -i, Description: refresh interval Text: --interval, Description: refresh interval Text: -i, Description: refresh interval, Preserve Placeholder: true
func (Model[T]) Formatters ¶
func (m Model[T]) Formatters() Formatters
Formatters returns the formatters used by the input.
func (Model[T]) LastArg ¶
LastArg returns the last positional argument in the input. If there are no arguments, it returns nil.
func (*Model[T]) NewFlagPlaceholder ¶
func (m *Model[T]) NewFlagPlaceholder(placeholder string) FlagArgPlaceholder
NewFlagPlaceholder creates a flag placeholder for completions.
Example ¶
package main import ( "fmt" "github.com/aschey/bubbleprompt/input/commandinput" ) func main() { textInput := commandinput.New[commandinput.CommandMetadata[any]]() flags := []commandinput.FlagInput{ { Short: "d", Long: "days", ArgPlaceholder: textInput.NewFlagPlaceholder("<number of days>"), Description: "Forecast days", }, } fmt.Println(flags[0].ArgPlaceholder.Text()) }
Output: <number of days>
func (*Model[T]) NewPositionalArg ¶
func (m *Model[T]) NewPositionalArg(placeholder string) PositionalArg
NewPositionalArg creates a positional arg placeholder for completions.
Example ¶
package main import ( "fmt" "github.com/aschey/bubbleprompt/input/commandinput" "github.com/aschey/bubbleprompt/suggestion" ) func main() { textInput := commandinput.New[commandinput.CommandMetadata[any]]() commandMetadata := commandinput.CommandMetadata[any]{ PositionalArgs: []commandinput.PositionalArg{textInput.NewPositionalArg("<arg1>")}, } suggestions := []suggestion.Suggestion[commandinput.CommandMetadata[any]]{ {Text: "test", Metadata: commandMetadata}, } fmt.Println(suggestions[0].Metadata.PositionalArgs[0].Placeholder()) }
Output: <arg1>
func (*Model[T]) NewPositionalArgs ¶
func (m *Model[T]) NewPositionalArgs(placeholders ...string) []PositionalArg
NewPositionalArgs creates multiple positional arg placeholders for completions.
Example ¶
package main import ( "fmt" "github.com/aschey/bubbleprompt/input/commandinput" "github.com/aschey/bubbleprompt/suggestion" ) func main() { textInput := commandinput.New[commandinput.CommandMetadata[any]]() commandMetadata := commandinput.CommandMetadata[any]{ PositionalArgs: textInput.NewPositionalArgs("<arg1>", "<arg2>"), } suggestions := []suggestion.Suggestion[commandinput.CommandMetadata[any]]{ {Text: "test", Metadata: commandMetadata}, } fmt.Println(suggestions[0].Metadata.PositionalArgs[0].Placeholder()) fmt.Println(suggestions[0].Metadata.PositionalArgs[1].Placeholder()) }
Output: <arg1> <arg2>
func (*Model[T]) OnExecutorFinished ¶
func (m *Model[T]) OnExecutorFinished()
OnExecutorFinished is part of the input.Input interface. It should not be invoked by users of this library.
func (*Model[T]) OnSuggestionChanged ¶
func (m *Model[T]) OnSuggestionChanged(suggestion suggestion.Suggestion[CommandMetadata[T]])
OnSuggestionChanged is part of the input.Input interface. It should not be invoked by users of this library.
func (*Model[T]) OnSuggestionUnselected ¶
func (m *Model[T]) OnSuggestionUnselected()
OnSuggestionUnselected is part of the input.Input interface. It should not be invoked by users of this library.
func (*Model[T]) OnUpdateFinish ¶
func (m *Model[T]) OnUpdateFinish( msg tea.Msg, suggestion *suggestion.Suggestion[CommandMetadata[T]], isSelected bool, ) tea.Cmd
OnUpdateFinish is part of the input.Input interface. It should not be invoked by users of this library.
func (*Model[T]) OnUpdateStart ¶
OnUpdateStart is part of the input.Input interface. It should not be invoked by users of this library.
func (*Model[T]) ParseUsage ¶
func (m *Model[T]) ParseUsage(placeholders string) ([]PositionalArg, error)
ParseUsage generates a list of PositionalArg from a usage string.
Example ¶
package main import ( "fmt" "github.com/aschey/bubbleprompt/input/commandinput" ) func main() { textInput := commandinput.New[commandinput.CommandMetadata[any]]() usage := `<mandatory arg> [optional arg] 'quoted arg' "double quoted arg" normal-arg` args, err := textInput.ParseUsage(usage) if err != nil { panic(err) } fmt.Printf("%s\n%s\n%s\n%s\n%s", args[0].Placeholder(), args[1].Placeholder(), args[2].Placeholder(), args[3].Placeholder(), args[4].Placeholder()) }
Output: <mandatory arg> [optional arg] 'quoted arg' "double quoted arg" normal-arg
func (Model[T]) ParsedValue ¶
ParsedValue returns the input parsed into a Statement.
func (Model[T]) Runes ¶
Runes returns the raw text entered by the user as a list of runes. This is useful for indexing and length checks because doing these operations on strings does not work well with some unicode characters.
func (*Model[T]) SetCursorMode ¶
SetCursorMode sets the mode of the cursor.
func (*Model[T]) SetFormatters ¶
func (m *Model[T]) SetFormatters(formatters Formatters)
SetFormatters sets the formatters used by the input.
func (*Model[T]) ShouldClearSuggestions ¶
ShouldClearSuggestions is part of the input.Input interface. It should not be invoked by users of this library.
func (*Model[T]) ShouldSelectSuggestion ¶
func (m *Model[T]) ShouldSelectSuggestion(suggestion suggestion.Suggestion[CommandMetadata[T]]) bool
ShouldSelectSuggestion is part of the input.Input interface. It should not be invoked by users of this library.
func (*Model[T]) ShouldUnselectSuggestion ¶
ShouldUnselectSuggestion is part of the input.Input interface. It should not be invoked by users of this library.
func (Model[T]) SuggestionRunes ¶
SuggestionRunes is part of the input.Input interface. It should not be invoked by users of this library.
func (Model[T]) Tokens ¶
Tokens returns the entire input as a list of input.Token.
func (Model[T]) TokensBeforeCursor ¶
TokensBeforeCursor returns the tokenized input before the cursor position.
func (Model[T]) ValuesBeforeCursor ¶
ValuesBeforeCursor returns the token values of the entire input before the cursor position.
type Option ¶
func WithDefaultDelimiter ¶
func WithFormatters ¶
func WithFormatters[T any](formatters Formatters) Option[T]
func WithPrompt ¶
type PositionalArg ¶
type PositionalArg struct { PlaceholderStyle lipgloss.Style ArgStyle lipgloss.Style // contains filtered or unexported fields }
PositionalArg is a positional arg placeholder for completions.
func (PositionalArg) Placeholder ¶
func (p PositionalArg) Placeholder() string
Placeholder returns the text value of the placeholder text.
type PositionalArgFormatter ¶
type PositionalArgFormatter struct { // Placeholder handles styling for the placeholder that appears before the argument is supplied. Placeholder lipgloss.Style // Arg handles styling for the argument that is supplied. Arg lipgloss.Style }
PositionalArgFormatter handles styling for positional arguments.