Overview
Prompter provides a clean interface for gathering user input in CLI applications. Built on top of AlecAivazis/survey , it supports single selection, multi-selection, text input, and yes/no confirmations.
Interface
The Prompter interface defines methods for interactive user input.
type Prompter interface {
Select ( message , defaultValue string , options [] string ) ( int , error )
MultiSelect ( message , defaultValue string , options [] string ) ([] int , error )
Input ( message , defaultValue string ) ( string , error )
Confirm ( message string , defaultValue bool ) ( bool , error )
}
Functions
New
Creates a new Prompter instance.
A new Prompter instance ready for user interaction
Example:
prompter := prompter . New ()
Methods
Select
Prompts the user to select one option from a list.
func ( p * Prompter ) Select ( message , defaultValue string , options [] string ) ( int , error )
The prompt message to display to the user
The default selected option (must match one of the options)
List of options to display (page size: 20)
Zero-based index of the selected option
Error if the prompt fails or user cancels (Ctrl+C)
Example:
prompter := prompter . New ()
options := [] string { "Development" , "Staging" , "Production" }
index , err := prompter . Select (
"Select environment:" ,
"Development" ,
options ,
)
if err != nil {
log . Fatal ( err )
}
selected := options [ index ]
fmt . Printf ( "Deploying to %s \n " , selected )
Output:
? Select environment: [Use arrows to move, type to filter]
> Development
Staging
Production
MultiSelect
Prompts the user to select multiple options from a list.
func ( p * Prompter ) MultiSelect ( message , defaultValue string , options [] string ) ([] int , error )
The prompt message to display to the user
Comma-separated default values (must match options)
List of options to display (page size: 20)
Slice of zero-based indices of selected options
Error if the prompt fails or user cancels (Ctrl+C)
Example:
prompter := prompter . New ()
services := [] string { "api" , "web" , "worker" , "scheduler" }
indices , err := prompter . MultiSelect (
"Select services to restart:" ,
"" ,
services ,
)
if err != nil {
log . Fatal ( err )
}
if len ( indices ) == 0 {
fmt . Println ( "No services selected" )
return
}
fmt . Println ( "Restarting services:" )
for _ , idx := range indices {
fmt . Printf ( " - %s \n " , services [ idx ])
}
Output:
? Select services to restart: [Use arrows to move, space to select, type to filter]
[ ] api
[x] web
[x] worker
[ ] scheduler
Prompts the user for text input.
func ( p * Prompter ) Input ( message , defaultValue string ) ( string , error )
The prompt message to display to the user
Default value shown in the input field
Error if the prompt fails or user cancels (Ctrl+C)
Example:
prompter := prompter . New ()
name , err := prompter . Input (
"Enter project name:" ,
"my-project" ,
)
if err != nil {
log . Fatal ( err )
}
fmt . Printf ( "Creating project: %s \n " , name )
Output:
? Enter project name: my-project
Confirm
Prompts the user for a yes/no confirmation.
func ( p * Prompter ) Confirm ( message string , defaultValue bool ) ( bool , error )
The confirmation question to display
Default answer (true for yes, false for no)
True if user confirmed (yes), false otherwise (no)
Error if the prompt fails or user cancels (Ctrl+C)
Example:
prompter := prompter . New ()
confirmed , err := prompter . Confirm (
"Delete all data?" ,
false ,
)
if err != nil {
log . Fatal ( err )
}
if confirmed {
fmt . Println ( "Deleting data..." )
} else {
fmt . Println ( "Cancelled" )
}
Output:
Error Handling
All methods return an error if:
User cancels the prompt (Ctrl+C)
Terminal doesn’t support interactive input
Internal survey error occurs
Example:
index , err := prompter . Select ( "Choose option:" , "" , options )
if err != nil {
if err . Error () == "interrupt" {
fmt . Println ( " \n Operation cancelled" )
os . Exit ( 0 )
}
log . Fatal ( err )
}
Best Practices
Provide Sensible Defaults
Always provide default values to improve user experience: // Good: User can just press Enter
env , err := prompter . Select (
"Select environment:" ,
"Development" , // Default
[] string { "Development" , "Staging" , "Production" },
)
// Avoid: No default, user must navigate
env , err := prompter . Select (
"Select environment:" ,
"" , // No default
[] string { "Development" , "Staging" , "Production" },
)
Handle Cancellation Gracefully
Check for interrupt errors and exit cleanly: result , err := prompter . Input ( "Enter value:" , "" )
if err != nil {
if strings . Contains ( err . Error (), "interrupt" ) {
fmt . Println ( " \n Cancelled" )
return nil
}
return err
}
Confirm Destructive Operations
Always confirm before destructive actions: confirmed , err := prompter . Confirm (
"This will delete all data. Continue?" ,
false , // Default to No
)
if err != nil || ! confirmed {
fmt . Println ( "Operation cancelled" )
return
}
Complete Example
package main
import (
" fmt "
" log "
" strings "
" github.com/raystack/salt/cli/prompter "
" github.com/raystack/salt/cli/printer "
)
func main () {
p := prompter . New ()
// Get project name
projectName , err := p . Input (
"Enter project name:" ,
"my-app" ,
)
if err != nil {
handleError ( err )
return
}
// Select environment
environments := [] string { "Development" , "Staging" , "Production" }
envIdx , err := p . Select (
"Select deployment environment:" ,
"Development" ,
environments ,
)
if err != nil {
handleError ( err )
return
}
environment := environments [ envIdx ]
// Select services
services := [] string { "api" , "web" , "worker" , "scheduler" }
serviceIndices , err := p . MultiSelect (
"Select services to deploy:" ,
"" ,
services ,
)
if err != nil {
handleError ( err )
return
}
if len ( serviceIndices ) == 0 {
printer . Warningln ( "No services selected" )
return
}
// Show summary
fmt . Println ( " \n Deployment Configuration:" )
fmt . Printf ( " Project: %s \n " , projectName )
fmt . Printf ( " Environment: %s \n " , environment )
fmt . Printf ( " Services: " )
for i , idx := range serviceIndices {
if i > 0 {
fmt . Print ( ", " )
}
fmt . Print ( services [ idx ])
}
fmt . Println ()
// Confirm deployment
confirmed , err := p . Confirm (
" \n Proceed with deployment?" ,
true ,
)
if err != nil {
handleError ( err )
return
}
if ! confirmed {
printer . Infoln ( "Deployment cancelled" )
return
}
// Proceed with deployment
printer . Successln ( "Starting deployment..." )
}
func handleError ( err error ) {
if strings . Contains ( err . Error (), "interrupt" ) {
fmt . Println ( " \n Operation cancelled" )
return
}
log . Fatal ( err )
}