Building powerful interactive prompts in Go, inspired by python-prompt-toolkit.

Overview

go-prompt

Go Report Card Software License GoDoc tests

A library for building powerful interactive prompts inspired by python-prompt-toolkit, making it easier to build cross-platform command line tools using Go.

package main

import (
	"fmt"
	"github.com/c-bata/go-prompt"
)

func completer(d prompt.Document) []prompt.Suggest {
	s := []prompt.Suggest{
		{Text: "users", Description: "Store the username and age"},
		{Text: "articles", Description: "Store the article text posted by user"},
		{Text: "comments", Description: "Store the text commented to articles"},
	}
	return prompt.FilterHasPrefix(s, d.GetWordBeforeCursor(), true)
}

func main() {
	fmt.Println("Please select table.")
	t := prompt.Input("> ", completer)
	fmt.Println("You selected " + t)
}

Projects using go-prompt

Features

Powerful auto-completion

demo

(This is a GIF animation of kube-prompt.)

Flexible options

go-prompt provides many options. Please check option section of GoDoc for more details.

options

Keyboard Shortcuts

Emacs-like keyboard shortcuts are available by default (these also are the default shortcuts in Bash shell). You can customize and expand these shortcuts.

keyboard shortcuts

Key Binding Description
Ctrl + A Go to the beginning of the line (Home)
Ctrl + E Go to the end of the line (End)
Ctrl + P Previous command (Up arrow)
Ctrl + N Next command (Down arrow)
Ctrl + F Forward one character
Ctrl + B Backward one character
Ctrl + D Delete character under the cursor
Ctrl + H Delete character before the cursor (Backspace)
Ctrl + W Cut the word before the cursor to the clipboard
Ctrl + K Cut the line after the cursor to the clipboard
Ctrl + U Cut the line before the cursor to the clipboard
Ctrl + L Clear the screen

History

You can use Up arrow and Down arrow to walk through the history of commands executed.

History

Multiple platform support

We have confirmed go-prompt works fine in the following terminals:

  • iTerm2 (macOS)
  • Terminal.app (macOS)
  • Command Prompt (Windows)
  • gnome-terminal (Ubuntu)

Links

Author

Masashi Shibata

License

This software is licensed under the MIT license, see LICENSE for more information.

Comments
  • Fix test on macOS

    Fix test on macOS

    Characters in Добрый день are actually double-width on macOS terminals (confirmed on Terminal.app and iTerm2.app).

    2018-10-18 19 47 34

    It caused test failure and I fixed it by modifying expected value. (I'm not sure updated expected value is actually what you expect, tho...)

    opened by rhysd 12
  • Update pkg/term module to latest and use unix.Termios

    Update pkg/term module to latest and use unix.Termios

    Updating pkg/term is necessary to fix #190

    For more background, latest version of pkg/term has a change in argument type of function termios.Tcsetattr. See https://github.com/pkg/term/pull/51 for more details.

    Anyone using go prompt with explicit dependency of pkg/term to latest would encounter with issue #190

    opened by pgollangi 10
  • Problem with key bindings

    Problem with key bindings

    I have some problems adding key bindings in go-prompt. I took the 'echo' example, and tried to add a simple print for the 'Home', 'End' and 'PageUp' keys, but only the 'Home' key bind worked:

    package main
    
    import (
    	"fmt"
    	"github.com/c-bata/go-prompt"
    )
    
    func executor(in string) {
    	fmt.Println("Your input: " + in)
    }
    
    func completer(in prompt.Document) []prompt.Suggest {
    	s := []prompt.Suggest{
    		{Text: "users", Description: "Store the username and age"},
    		{Text: "articles", Description: "Store the article text posted by user"},
    		{Text: "comments", Description: "Store the text commented to articles"},
    		{Text: "groups", Description: "Combine users with specific rules"},
    	}
    	return prompt.FilterHasPrefix(s, in.GetWordBeforeCursor(), true)
    }
    
    func main() {
    	p := prompt.New(
    		executor,
    		completer,
    		prompt.OptionPrefix(">>> "),
    		prompt.OptionTitle("sql-prompt"),
    		prompt.OptionAddKeyBind(prompt.KeyBind{
    			Key: prompt.Home,
    			Fn: func(buf *prompt.Buffer) {
    				fmt.Println("HOME")
    			}}),
    		prompt.OptionAddKeyBind(prompt.KeyBind{
    			Key: prompt.End,
    			Fn: func(buf *prompt.Buffer) {
    				fmt.Println("END")
    			}}),
    		prompt.OptionAddKeyBind(prompt.KeyBind{
    			Key: prompt.PageUp,
    			Fn: func(buf *prompt.Buffer) {
    				fmt.Println("Up")
    			}}),
    	)
    	p.Run()
    }
    

    What's wrong with my code?

    Thanks for your help.

    PS: by the way, the default behaviour of the 'Home' key doesn't take into account the length of the Prefix (here, the ">>>").

    bug 
    opened by SebastienBoisard 7
  • Added OptionBreakLineCallback, to run a callback every time there's a line break

    Added OptionBreakLineCallback, to run a callback every time there's a line break

    It's sometimes useful to run a function everytime there's a line break -- Enter as well as, for example, ControlC.

    With this PR, a new option is added to assign a callback that gets called every time renderer.BreakLine() is called.

    Added a test that makes sure the renderer doesn't break if the callback is not specified, as well as to check that it runs ok when the callback executes.

    Just to give a bit more of context: in ABS we are trying to implement ControlR (reverse search), and need to clear the search selection every time the user "clears" the console, either by pressing enter or by clearing the current line (eg. ControlC).

    opened by odino 6
  • How to bind ctrl+c to terminate current running command?

    How to bind ctrl+c to terminate current running command?

    Hi, I've been using this lib building a dynamodb prompt, it's all good until I try to kill a query running too long. Ctrl+c seems can't kill what is running in that executor function, so I looked up in the docs, but can't find any useful tips.

    Can someone help me with this, thanks~~

    opened by FrontMage 6
  • [Bug] Errors on installing go-prompt via go get in Ubuntu 18

    [Bug] Errors on installing go-prompt via go get in Ubuntu 18

    Bug reports

    Got the errors in the system terminal on installing the go-prompt package via command go get github.com/c-bata/go-prompt in Ubuntu 18.

    Expected Behavior

    Package has been downloaded and installed, can be used for program build (i.e. via go run, go build).

    Current Behavior and Steps to Reproduce

    On installing via the command go get github.com/c-bata/go-prompt in Ubuntu 18 (and in docker with images golang:1.13 or golang:1.14) got the errors

    ../../c-bata/go-prompt/internal/term/raw.go:27:75: cannot use (*syscall.Termios)(&n) (type *syscall.Termios) as type *unix.Termios in argument to termios.Tcsetattr ../../c-bata/go-prompt/internal/term/term.go:22:40: cannot use &saveTermios (type *syscall.Termios) as type *unix.Termios in argument to termios.Tcgetattr ../../c-bata/go-prompt/internal/term/term.go:33:68: cannot use &o (type *syscall.Termios) as type *unix.Termios in argument to termios.Tcsetattr

    Tried to use go modules, and install a particular release (tag), alike go get -v github.com/c-bata/[email protected] but none of them helps (tried all 6 releases) - no changes, the same errors.

    At the same time, in the Windows WSL with Ubuntu 18 the package is being installed w/o errors and can be used as expected.

    Context

    • Operating System: Ubuntu 18 (Linux 5.0.0-38-generic #41-Ubuntu SMP Tue Dec 3 00:27:35 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux); docker images golang:1.13 or golang:1.14
    • Go version: on Ubuntu 18 - where errors occur: 1.14.1; on Windows WSL / Ubuntu 18: 1.14
    • Terminal Emulator: none (fails on installing step)
    • tag: any release

    Thanks for your help!

    bug 
    opened by oborshchak 5
  • Detect exit request with CTRL-D in Input

    Detect exit request with CTRL-D in Input

    Feature Request

    Feature Request

    Hi, thank you for the lovely library. I am using it in a project here https://github.com/fortify500/stepsman Would appreciate if you can add me to the list. Currently I am using Input and not Run because I have no apparent way to enter the OptionInitialBufferText on every input (which i need). However, the biggest problem is that in Input I don't know if a CTRL-D was pressed to exit. I tried serval tricks like KeyBind (which is not triggered for some reason) but to no avail.

    Would appreciate it if it was possible to somehow either detect CTRL-D after the Input finished like an err returned in addition to the string or a callback or simply enter "exit" string.

    Thanks!

    enhancement 
    opened by TzahiFadida 5
  • Update pkg/term to 1.2.0

    Update pkg/term to 1.2.0

    This fixes build errors on FreeBSD. Ran go mod tidy to clean up unused dependencies.

    Term package has fixed FreeBSD build errors recently https://github.com/pkg/term/pull/61

    opened by zaynetro 4
  • [Bug] Usage of Ctrl+C binding corrupt STTY settings

    [Bug] Usage of Ctrl+C binding corrupt STTY settings

    Bug reports

    Expected Behavior

    After my program is finished with ControlC binding, I expect that Ctrl+C combination will work in the terminal as it did before the program launch.

    Current Behavior and Steps to Reproduce

    After finished my program by ControlC binding and Ctrl+C combination do nothing.

    p := prompt.New(
    	// ... other options
    	prompt.OptionAddKeyBind(prompt.KeyBind{
    		Key: prompt.ControlC,
    		Fn: func(b *prompt.Buffer) { os.Exit(0) }
    	}),
    )
    
    p.Run()
    

    If I send text command to executor for exit it calls os.Exit(0) too and program finished correctly.

    Program exit if I press Ctrl+C in opened prompt and stty settings is corrupted.

    I got settings before run program with stty -a > stty.before and after finish program by CTRL+C with stty -a > stty.after.

    --- stty.before	2020-05-26 15:30:40.827199004 +0300
    +++ stty.after	2020-05-26 15:30:47.212105711 +0300
    @@ -3,8 +3,8 @@
     eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
     werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
     -parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
    --ignbrk brkint ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
    +-ignbrk -brkint ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff
     -iuclc -ixany imaxbel iutf8
     opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
    -isig icanon -iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
    +-isig icanon -iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
     echoctl echoke -flusho -extproc
    

    Disabled this options: -brkint -icrnl -ixon -isig

    Option isig enable interrupt, quit, and suspend special characters.

    More info about stty https://linux.die.net/man/1/stty

    For restore initial behavior need use command reset.

    Context

    • Operating System: Fedora Linux, CentOS
    • Terminal Emulator: gnome-terminal
    • commit revision: d043be07639872dd59e161726523dcf4687959cc
    bug 
    opened by sattellite 4
  • Trigger ExitChecker on pressed keys

    Trigger ExitChecker on pressed keys

    #161 allows to exit go-prompt (not the all Go program like an os.Exit(), but just go-prompt) when the user type <return> and select an entry matching a criteria.

    This PR adds the same exit-go-prompt option to each key typed.

    The general goal is to allow for an early exit as soon as a character (or sequence of characters) has been typed, without having to type <enter>.

    Example use-case: a go-prompt with three choices 'yes', 'no', 'cancel'.

    The following example would allow a user to select yes or no, just by typing 'y' or 'n' (no need to type <return>), or 'cancel' by typing ESC. That would not call os.Exit, just exit the go-prompt Run() loop, without executor.

    type choice struct {
    	isCancel bool
    	isYes    bool
    }
    
    func (c *choice) cancel(_ *prompt.Buffer) {
    	c.isCancel = true
    }
    
    func (c *choice) checkIfExit(in string) bool {
    	c.isYes = (in == "y")
    	return in == "y" || in == "n" || c.isCancel
    }
    
    func main() {
    	c := &choice{}
    	exitOnEscape := prompt.KeyBind{
    		Key: prompt.Escape,
    		Fn:  c.cancel,
    	}
    	p := prompt.New(
    		executor,
    		completer,
    		prompt.OptionPrefix(">>> "),
    		prompt.OptionSetExitCheckerOnInput(c.checkIfExit),
    		prompt.OptionCompletionOnDown(),
    		prompt.OptionAddKeyBind(exitOnEscape),
    	)
    	p.Run()
    	fmt.Println("All done")
    	fmt.Printf("Choice '%t', cancelled: '%t'\n", c.isYes, c.isCancel)
    }
    
    opened by VonC 4
  • Fix runtime error: index out of range in GetSelectedSuggestion

    Fix runtime error: index out of range in GetSelectedSuggestion

    When I enter [tab] many times, will panic like below: panic: runtime error: index out of range [0] with length 0

    goroutine 1 [running]: github.com/c-bata/go-prompt.(*CompletionManager).GetSelectedSuggestion(0xc0004320f0, 0xc000424c40, 0xc0004320f0, 0x17, 0x6f00000063, 0x6500000072) /root/go/pkg/mod/github.com/c-bata/[email protected]/completion.go:51 +0x13f github.com/c-bata/go-prompt.(*Render).Render(0xc000430f70, 0xc000424c40, 0xc0004320f0) /root/go/pkg/mod/github.com/c-bata/[email protected]/render.go:209 +0x3dd github.com/c-bata/go-prompt.(*Prompt).Run(0xc00044f700) /root/go/pkg/mod/github.com/c-bata/[email protected]/prompt.go:96 +0x6f9 github.com/shipengqi/hawk-eye/app/hectl/cmd.promptCommand.func1(0xc0001faf00, 0x1d61f80, 0x0, 0x0) /root/hawk-eye/app/hectl/cmd/prompt.go:38 +0x39f github.com/spf13/cobra.(*Command).execute(0xc0001faf00, 0x1d61f80, 0x0, 0x0, 0xc0001faf00, 0x1d61f80) /root/go/pkg/mod/github.com/spf13/[email protected]/command.go:830 +0x2aa github.com/spf13/cobra.(*Command).ExecuteC(0xc0001fac80, 0x0, 0x111c640, 0xc000096058) /root/go/pkg/mod/github.com/spf13/[email protected]/command.go:914 +0x2fb github.com/spf13/cobra.(*Command).Execute(...) /root/go/pkg/mod/github.com/spf13/[email protected]/command.go:864 main.main() /root/hawk-eye/app/hectl/main.go:7 +0x28

    opened by shipengqi 4
  • support meta-{backspace,left,right} key.

    support meta-{backspace,left,right} key.

    Added Alt+ and Alt+ processing to the contents of this pull request.

    For MacOS terminal emulators, Option + delete does not work with the default settings. Therefore, it is necessary to enable the setting to use the Options key as the Meta key in each terminal. This seems to be the same with zsh etc.

    opened by blacknon 0
  • [Bug] Unexpected behavior of log output

    [Bug] Unexpected behavior of log output

    Bug reports

    [tsh][listeners] >>> start default-http2-listener
    [2022-05-06 20:33:28][INFO] Starting listener default-http2-listener
    [tsh][listeners] >>> [2022-05-06 20:33:28][ERROR] HTTP2Listener default-http2-listener start error: listen tcp 0.0.0.0:8989: bind: address already in use
    

    As the above output shows, the log output coincides with the current command line, is there a way to fix this?

    Expected Behavior

    Logs are automatically output above the command line instead of peers

    Current Behavior and Steps to Reproduce

    The log output is the same as the current command line

    • Operating System: Macos
    • Terminal Emulator: iTerm2
    • tag of go-prompt or commit revision: v0.2.6
    bug 
    opened by tlmn-local 1
  • Fix file descriptor leak

    Fix file descriptor leak

    Fixes file descriptor leak as described in #253

    Reproduced by modifying _example/simple-echo/main.go, looping the body of the main function in order to observe multiple calls to prompt.Input(). "Exit" added for convenience:

    diff --git a/_example/simple-echo/main.go b/_example/simple-echo/main.go
    index 12b1bb4..b02199f 100644
    --- a/_example/simple-echo/main.go
    +++ b/_example/simple-echo/main.go
    @@ -12,17 +12,23 @@ func completer(in prompt.Document) []prompt.Suggest {
     		{Text: "articles", Description: "Store the article text posted by user"},
     		{Text: "comments", Description: "Store the text commented to articles"},
     		{Text: "groups", Description: "Combine users with specific rules"},
    +		{Text: "exit", Description: "Stop the loop"},
     	}
     	return prompt.FilterHasPrefix(s, in.GetWordBeforeCursor(), true)
     }
     
     func main() {
    -	in := prompt.Input(">>> ", completer,
    -		prompt.OptionTitle("sql-prompt"),
    -		prompt.OptionHistory([]string{"SELECT * FROM users;"}),
    -		prompt.OptionPrefixTextColor(prompt.Yellow),
    -		prompt.OptionPreviewSuggestionTextColor(prompt.Blue),
    -		prompt.OptionSelectedSuggestionBGColor(prompt.LightGray),
    -		prompt.OptionSuggestionBGColor(prompt.DarkGray))
    -	fmt.Println("Your input: " + in)
    +	for {
    +		in := prompt.Input(">>> ", completer,
    +			prompt.OptionTitle("sql-prompt"),
    +			prompt.OptionHistory([]string{"SELECT * FROM users;"}),
    +			prompt.OptionPrefixTextColor(prompt.Yellow),
    +			prompt.OptionPreviewSuggestionTextColor(prompt.Blue),
    +			prompt.OptionSelectedSuggestionBGColor(prompt.LightGray),
    +			prompt.OptionSuggestionBGColor(prompt.DarkGray))
    +		if in == "exit" {
    +			break
    +		}
    +		fmt.Println("Your input: " + in)
    +	}
     }
    

    Each call to Input will leak another file descriptor, seen with lsof -p <GO PID> | grep 'dev\/tty' | wc -l:

    Here you can see the count of /dev/tty file descriptors increasing: Screen Shot 2022-04-28 at 21 53 46

    Calling syscall.Close(t.fd) prevents this leak. After this fix the count of file descriptors is constant: Screen Shot 2022-04-28 at 21 56 20

    opened by AspenJames 0
  • [Question] Force prompt.Input() redraw during goroutine

    [Question] Force prompt.Input() redraw during goroutine

    Question

    I'm working on an application where users are able to execute commands on a server, for this I decided to use this project (great work by the way!), some of these commands are asynchronous jobs which I run using goroutines. I'd like to write the output in the same terminal, however calling things like fmt.Println() breaks the current render.

    If there a way I could do this? Eg using a method like InsertLineAboveInput() or something? Or maybe forcibly re-drawing the output? This is the example code I'm working with:

    
    
    func pollOutput() {
    	for {
    		time.Sleep(time.Second))
    		fmt.Println("Example line")  // This breaks the output
    		prompt.InsertLineAboveInput("Example line")  // Something like this, force redraw, etc
    	}
    }
    
    func main() {
    	go pollOutput()  // Example, real implementation is more complex
    
    	term := prompt.New(
    		executor,
    		completer,
    		prompt.OptionLivePrefix(func() (string, bool) {
    			if context == "" {
    				return "shell>", true
    			} else {
    				return fmt.Sprintf("shell(%s)> ", context), true
    			}
    		}),
    	)
    
    	term.Run()
    }
    

    Thanks a bunch for the reply!

    enhancement 
    opened by Paradoxis 0
Owner
Masashi Shibata
Creator of go-prompt and kube-prompt. Optuna committer. Kubeflow/Katib reviewer.
Masashi Shibata
git-glimpse is a command-line tool that is aimed at generating a git prompt like the one from zsh-vcs-prompt.

Git GoGlimpse git-glimpse is a command-line tool that is aimed at generating a git prompt like the one from zsh-vcs-prompt. The particularity of this

Corentin de Boisset 0 Jan 27, 2022
Interactive prompt for command-line applications

promptui Interactive prompt for command-line applications. We built Promptui because we wanted to make it easy and fun to explore cloud services with

Manifold 5.1k Sep 29, 2022
Interactive prompt to set and push a semver tag

cutver For when you know what version to tag, and you want to cut a release in the annotated tag format. Installation go install github.com/roryq/cutv

Rory Quinn 7 Oct 11, 2021
A simple CLI based rock-paper-scissors game created in GO with interactive shell prompt.

rock-paper-scissors A simple CLI (Command Line Interface) based rock-paper-scissors game with interactive shell prompt. Language Download Grab a binar

Saif Shahriar 0 Jul 17, 2022
An easy to use menu structure for cli applications that prompts users to make choices.

WMenu Package wmenu creates menus for cli programs. It uses wlog for its interface with the command line. It uses os.Stdin, os.Stdout, and os.Stderr w

Will Dixon 173 Sep 15, 2022
Prompts users to enter values for required flags in Cobra CLI applications

Cobra Flag Prompt Cobra Flag Prompt prompts users to enter values for required flags. It is an extension of Cobra, and requires that you use Cobra to

null 1 Nov 13, 2021
Strumt is a library to create prompt chain

Strumt Strumt is a library to create prompt chain. It provides multiline prompt, input validation, retry on error, ability to create typesafe prompt,

Anthony HAMON 48 Sep 6, 2022
Shelby is a fast ⚡️ , lightweight ☁️ , minimal✨, shell prompt written in Go.

Shelby is a fast ⚡️ ,lightweight ☁️ ,minimal ✨ , shell prompt written in Pure Go. Installation Follow the steps below(Linux and macOS), and Post Insta

Athul Cyriac Ajay 165 Sep 16, 2022
Pure Go command line prompt with history, kill-ring, and tab completion

Prompt Prompt is a command line prompt editor with history, kill-ring, and tab completion. It was inspired by linenoise and derivatives which eschew u

Peter Mattis 1 Nov 20, 2021
The extremely customizable and themeable shell prompt.

kitch-prompt Kitch-prompt is a cross-platform tool for displaying a shell prompt, which can be extensively customized both in terms of what is shown,

Jason Walton 10 Sep 22, 2022
A command line tool to prompt for a value to be included in another command line.

readval is a command line tool which is designed for one specific purpose—to prompt for a value to be included in another command line. readval prints

Venky 0 Dec 22, 2021
a python command-line tool which draws basic graphs in the terminal

Termgraph A command-line tool that draws basic graphs in the terminal, written in Python. Graph types supported: Bar Graphs Color charts Multi-variabl

Marcus Kazmierczak 2.9k Sep 22, 2022
convert curl commands to Python, JavaScript, Go, PHP, R, Dart, Java, MATLAB, Rust, Elixir and more

curlconverter curlconverter transpiles curl commands into programs in other programming languages. $ curlconverter --data "Hello, world!" example.com

null 5.9k Sep 26, 2022
Abacus is a simple interactive calculator CLI

Abacus is a simple interactive calculator CLI with support for variables, comparison checks, and math functions abacus -

Viktor Danov 33 Sep 15, 2022
🔥 [WIP] Interactive Jira Command Line

JiraCLI Interactive Jira CLI ?? This project is still a work in progress ?? This tool mostly focuses on issue search and navigation at the moment. How

Ankit Pokhrel 2.1k Sep 30, 2022
Simplistic interactive filtering tool

peco Simplistic interactive filtering tool NOTE: If you are viewing this on GitHub, this document refers to the state of peco in whatever current bran

null 7.1k Oct 2, 2022
Terminal UI library with rich, interactive widgets — written in Golang

Rich Interactive Widgets for Terminal UIs This Go package provides commonly needed components for terminal based user interfaces. Among these componen

rivo 7.5k Oct 2, 2022
Build an interactive CLI application with Go, Cobra and promptui. Video tutorial available on the Div Rhino YouTube channel.

Build an interactive CLI app with Go, Cobra and promptui Text tutorial: https://divrhino.com/articles/build-interactive-cli-app-with-go-cobra-promptui

Div Rhino Dev 15 Sep 17, 2022
Interactive CLI helper for creating git branches with JIRA Links and some text

bb (better-branch) Interactive CLI helper for creating git branches with JIRA Links and some text Still in development? Yes How it works? This tiny ut

Eugene Uvarov 3 Aug 18, 2022