tinka alpha

Prompts

This guide covers prompts. You will learn how to:

Overview

A prompt asks a person for something the command line didn't give, such as a title or which database to use. Every prompt is answered by a flag the Command declares, which makes the same answer something you can always pass instead:

Prompts take the context Run received, so Ctrl+C ends a prompt and the Command exits with status 130.

Ask for text

c.Input asks for a line of text, answered by the flag you name. The flag's default is the default answer, which the person accepts by pressing Enter:

go
		Flags: func(f *cli.FlagSet) {
			f.StringVar(&title, "title", "", "The post's title")
		},
		Run: func(ctx context.Context, c *cli.Call) (cli.Result, error) {
			title, err := c.Input(ctx, "title", "What is the post's title?", cli.Required())
			if err != nil {
				return nil, err
			}
			…
		},
Output
? What is the post's title? Hello, world

Validate answers

cli.Required() refuses an empty answer, and cli.Validate checks each answer with your function. A person sees the error and is asked again; a flag that fails the check is a usage error:

go
			title, err := c.Input(ctx, "title", "What is the post's title?", cli.Required(), cli.Validate(func(s string) error {
				if len(s) > 80 {
					return errors.New("keep it under 80 characters")
				}
				return nil
			}))

The answer is parsed as the flag's type, so a prompt for an int flag refuses an answer that isn't a number, and the variable bound to the flag holds the number.

Ask for a password

c.Password asks for a secret without showing what the person types. Give its flag an environment variable with Env, so scripts pass the secret without putting it on the command line, where other users of the machine can see it:

go
			f.StringVar(&token, "token", "", "The API token")
			f.Env("token", "API_TOKEN")
go
			token, err := c.Password(ctx, "token", "Your API token?", cli.Required())

Errors never include the secret.

Offer choices

c.Select asks the person to choose one of a list, with the arrow keys and Enter. The flag's default is selected first, and a value passed on the command line must be one of the choices:

go
			f.StringVar(&db, "db", "sqlite", "The database")
go
			db, err := c.Select(ctx, "db", "Which database?", []string{"sqlite", "postgres", "mysql"})
Output
? Which database? (↑/↓ and Enter)
❯ sqlite
  postgres
  mysql

In a terminal that can't move the cursor (TERM=dumb), the choices are numbered and the person types a number.

Ask for confirmation

c.Confirm asks a yes or no question, answered by a bool flag. When nobody can answer, it returns the flag's default, which is false unless you declare otherwise, so nothing is confirmed without a person or the flag:

go
			f.BoolVar(&force, "force", false, "Overwrite an existing file")
go
			if _, err := os.Stat(path); err == nil {
				ok, err := c.Confirm(ctx, "force", "Overwrite "+path+"?")
				if err != nil {
					return nil, err
				}
				if !ok {
					return nil, &cli.Error{Code: "exists", Message: path + " already exists", Fix: "Pass --force to overwrite it"}
				}
			}
Output
? Overwrite app/controllers/posts.go? (y/N)

Run with nobody to answer

In Agent mode, with --no-interaction, or without a terminal, a prompt answers itself from its flag, and a required prompt with no value fails with exit status 2 and the flag to pass:

Output
$ act make:controller posts --no-interaction
Error: --title is required.
  No one can answer the prompt "What is the post's title?" here
  Fix: Pass --title=<value>

Agents get the same error as JSON, with the code missing_flag, and retry with the flag.

Ask follow-up questions only when they help

c.Given() reports whether the person passed any flag, and c.Interactive() whether a person can answer at all. Ask optional follow-up questions only when both say so: someone who passed flags has shown what they want, and a script has nobody to ask:

go
			if !c.Given() && c.Interactive() {
				if _, err := c.Confirm(ctx, "resource", "Add the resource actions?"); err != nil {
					return nil, err
				}
			}

See also: Flags, Testing Commands, Agent mode