Skip to main content

API

commandinput

import "github.com/aschey/bubbleprompt/input/commandinput"

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​

var (
DefaultPlaceholderForeground = "14"
DefaultCurrentPlaceholderSuggestion = "240"
DefaultSelectedTextColor = "10"
DefaultFlagForeground = "245"
DefaultFlagPlaceholderForeground = "14"
DefaultBoolFlagForeground = "13"
DefaultNumberFlagForeground = "5"
)

type Arg​

type Arg struct {
Start int
Value string
}

type CommandMetadata​

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.

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
}

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 Flag​

type Flag struct {
Name input.Token
Value *input.Token
}

type FlagArgPlaceholder​

FlagArgPlaceholder is a flag placeholder for completions.

type FlagArgPlaceholder struct {
Style lipgloss.Style
// contains filtered or unexported fields
}

func (FlagArgPlaceholder) Text​

func (p FlagArgPlaceholder) Text() string

Text returns the placeholder text.

type FlagFormatter​

FlagFormatter handles styling for flags.

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
}

type FlagInput​

FlagInput is used to generate a list of flag suggestions.

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
}

func (FlagInput) LongFlag​

func (f FlagInput) LongFlag() string

ShortFlag returns the Long property formatted as a flag with the leading dashes.

func (FlagInput) RequiresArg​

func (f FlagInput) RequiresArg() bool

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.

func (FlagInput) ShortFlag​

func (f FlagInput) ShortFlag() string

ShortFlag returns the Short property formatted as a flag with a leading dash.

type FlagValueFormatter​

FlagValueFormatter handles styling for different flag value data types.

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
}

type Formatters​

Formatters handles styling for the command input.

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
}

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​

A Model is an input for handling CLI-style inputs. It provides advanced features such as placeholders and context-aware suggestions.

type Model[T any] struct {
// contains filtered or unexported fields
}

func New​

func New[T any](opts ...Option[T]) *Model[T]

New creates a new model.

func (*Model[T]) ArgsBeforeCursor​

func (m *Model[T]) ArgsBeforeCursor() []string

ArgsBeforeCursor returns the positional arguments before the cursor position.

func (*Model[T]) Blur​

func (m *Model[T]) Blur()

Blur removes the focus from the input.

func (Model[T]) CommandBeforeCursor​

func (m Model[T]) CommandBeforeCursor() string

CommandBeforeCursor returns the portion of the command (first input token) before the cursor position.

func (Model[T]) CommandCompleted​

func (m Model[T]) CommandCompleted() bool

CommandCompleted returns whether the user finished typing the entire command (first token).

func (*Model[T]) CompletedArgsBeforeCursor​

func (m *Model[T]) CompletedArgsBeforeCursor() []string

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​

func (m Model[T]) CurrentToken() input.Token

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​

func (m Model[T]) CurrentTokenBeforeCursor() input.Token

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​

func (m Model[T]) CurrentTokenBeforeCursorRoundDown() input.Token

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​

func (m Model[T]) CurrentTokenRoundDown() input.Token

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​

func (m Model[T]) CursorIndex() int

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​

func (m Model[T]) CursorOffset() int

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]) Focus​

func (m *Model[T]) Focus() tea.Cmd

Focus sets the keyboard focus on the editor so the user can enter text.

func (Model[T]) Focused​

func (m Model[T]) Focused() bool

Focused returns whether the keyboard is focused on the input.

func (Model[T]) Formatters​

func (m Model[T]) Formatters() Formatters

Formatters returns the formatters used by the input.

func (Model[T]) HasArgs​

func (m Model[T]) HasArgs() bool

HasArgs returns whether the input has any positional arguments.

func (Model[T]) LastArg​

func (m Model[T]) LastArg() *input.Token

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​

func (m *Model[T]) OnUpdateStart(msg tea.Msg) tea.Cmd

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​

func (m Model[T]) ParsedValue() Statement

ParsedValue returns the input parsed into a Statement.

func (*Model[T]) Prompt​

func (m *Model[T]) Prompt() string

Prompt returns the terminal prompt.

func (*Model[T]) ResetValue​

func (m *Model[T]) ResetValue()

ResetValue clears the entire input.

func (Model[T]) Runes​

func (m Model[T]) Runes() []rune

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]) SetCursor​

func (m *Model[T]) SetCursor(pos int)

SetCursor sets the cursor position.

func (*Model[T]) SetCursorMode​

func (m *Model[T]) SetCursorMode(cursorMode cursor.Mode) tea.Cmd

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]) SetPrompt​

func (m *Model[T]) SetPrompt(prompt string)

SetPrompt sets the terminal prompt.

func (*Model[T]) SetValue​

func (m *Model[T]) SetValue(s string)

SetValue overwrites the entire input with the given string.

func (*Model[T]) ShouldClearSuggestions​

func (m *Model[T]) ShouldClearSuggestions(prevText []rune, msg tea.KeyMsg) bool

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​

func (m *Model[T]) ShouldUnselectSuggestion(prevRunes []rune, msg tea.KeyMsg) bool

ShouldUnselectSuggestion is part of the input.Input interface. It should not be invoked by users of this library.

func (Model[T]) SuggestionRunes​

func (m Model[T]) SuggestionRunes(runes []rune) []rune

SuggestionRunes is part of the input.Input interface. It should not be invoked by users of this library.

func (Model[T]) Tokens​

func (m Model[T]) Tokens() []input.Token

Tokens returns the entire input as a list of input.Token.

func (Model[T]) TokensBeforeCursor​

func (m Model[T]) TokensBeforeCursor() []input.Token

TokensBeforeCursor returns the tokenized input before the cursor position.

func (Model[T]) Value​

func (m Model[T]) Value() string

Value returns the raw text entered by the user.

func (Model[T]) Values​

func (m Model[T]) Values() []string

Values returns the tokenized input values.

func (Model[T]) ValuesBeforeCursor​

func (m Model[T]) ValuesBeforeCursor() []string

ValuesBeforeCursor returns the token values of the entire input before the cursor position.

func (Model[T]) View​

func (m Model[T]) View(viewMode input.ViewMode) string

View is part of the input.Input interface. It should not be invoked by users of this library.

type Option​

type Option[T any] func(model *Model[T])

func WithCursorMode​

func WithCursorMode[T any](cursorMode cursor.Mode) Option[T]

func WithDefaultDelimiter​

func WithDefaultDelimiter[T any](defaultDelimiter string) Option[T]

func WithFormatters​

func WithFormatters[T any](formatters Formatters) Option[T]

func WithPrompt​

func WithPrompt[T any](prompt string) Option[T]

type PositionalArg​

PositionalArg is a positional arg placeholder for completions.

type PositionalArg struct {
PlaceholderStyle lipgloss.Style
ArgStyle lipgloss.Style
// contains filtered or unexported fields
}

func (PositionalArg) Placeholder​

func (p PositionalArg) Placeholder() string

Placeholder returns the text value of the placeholder text.

type PositionalArgFormatter​

PositionalArgFormatter handles styling for positional arguments.

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
}

type Statement​

type Statement struct {
Command input.Token
Args []input.Token
Flags []Flag
}

Generated by gomarkdoc