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)
}
}
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.