Evaluating GoLang CLI Packages
Comparing survey
, promptui
, and go-prompt
Building effective command-line interfaces (such as chifra and khedra) requires choosing the right tools. While Go’s standard library provides basic support for CLIs, it lacks the advanced features necessary for modern, user-friendly CLIs.
This article examines three widely used Go libraries — survey
, promptui
, and go-prompt
—to help you make the best choice for your project. We considered looking at another package called Bubble Tea, which is fantastic, but we felt that it might be overkill for our purposes.
The Packages
We evaluated four “packages.” Go’s standard library, a package called survey
, another called promptui
, and a third called go-prompt
.
The Go standard library allows for basic input handling using packages such as bufio
and os.Stdin
; however, the standard library lacks features like validation, tab completion, or aesthetic customization. We stopped looking pretty early.
Third-party libraries such as survey
, promptui
, and go-prompt
address these gaps, each offering distinct strengths and weaknesses. We used ChatGPT, which is excellent for wading through all the various options, to help us evaluate. We thought we’d share in the hopes it may help you’all.
In the end, we chose go-prompt
for various reasons. Mainly because it has REPL-style capabilities and a more modern feel, which was one of our requirements. Your mileage may vary.
In this article, we briefly describe each package and show examples of how to use them. We then compare each package’s capabilities.
Survey:
https://github.com/AlecAivazis/survey
The first package we evaluated is called survey
.
Survey
provides an easy-to-use API with built-in validation, multi-select prompts, and several pre-designed input types. It’s an excellent choice for quick and user-friendly CLIs. In the end, we discovered its GitHub repo has recently been archived, which excluded it from further consideration.
Here’s an example of how to code with it.
package main
import (
"fmt"
"github.com/AlecAivazis/survey/v2"
)
func main() {
var name string
prompt := &survey.Input{
Message: "What is your name?",
}
survey.AskOne(prompt, &name)
fmt.Printf("Hello, %s!\n", name)
}
As you can see, survey
is straightforward, which is why Chat thought it was suitable for quick and dirty command line tools. It has a lot of options, including pre-canned input types (passwords, radio selection, email input, input validation, etc.) According to Chat, it’s also very well documented. We chose not to use it because it’s been archived.
Promptui:
https://github.com/manifoldco/promptui
promptui
excels at creating polished CLIs with customizable templates. While it lacks advanced features like tab completion, it is good at creating visually appealing CLIs. Again, this is a solid library, given its ease of programming, good documentation, community engagement, and features. It can support REPL-style interaction, but one must write custom code. Ultimately, this was the deciding factor against the package for us.
package main
import (
"fmt"
"github.com/manifoldco/promptui"
)
func main() {
prompt := promptui.Prompt{
Label: "What is your name?",
Validate: func(input string) error {
if len(input) == 0 {
return fmt.Errorf("Name cannot be empty")
}
return nil
},
}
name, err := prompt.Run()
if err != nil {
fmt.Printf("Prompt failed %v\n", err)
return
}
fmt.Printf("Hello, %s!\n", name)
}
Go-prompt
https://github.com/c-bata/go-prompt
For REPL-style interactivity, go-prompt
offers advanced features such as tab completion, dynamic suggestions, and better rendering control. This is the library we ultimately selected because of its REPL-style interaction. (REPL means “Read-Eval-Print-Loop.”) We need REPL-style behavior to build a “wizard” interface that walks users through several steps. The library has its benefits and weak points — summarized below.
package mainimport (
"fmt"
"github.com/c-bata/go-prompt"
)func completer(d prompt.Document) []prompt.Suggest {
suggestions := []prompt.Suggest{
{Text: "apple", Description: "A fruit"},
{Text: "banana", Description: "Another fruit"},
}
return prompt.FilterHasPrefix(suggestions, d.GetWordBeforeCursor(), true)
}func main() {
fmt.Println("Please select a fruit:")
t := prompt.Input("> ", completer)
fmt.Printf("You selected %s\n", t)
}
Comparisons
In the following sections, we compare the packages. First, we show where each package excels and then where each could improve.
Where the Packages Excel
Here’s a list of the various capabilities and where each package excels. (Thanks Chat!)
This shows two points that ended up being part of our final consideration: REPL support and Interactive Multi-Line Input. (We need to build a wizard and allow users to copy a list of Ethereum addresses — one per line — into the wizard.) The lack of built-in validation concerns us, but the code must “handle” the user’s response anyway —so maybe that’s not a big deal.
survey
: Multi-select support, built-in validation, simplicity.
prompt-ui
: Polished templates, customizable prompts, and spinners for long-running tasks.
go-prompt
: Tab completion, dynamic suggestions, advanced interactivity for REPLs.
Where the Packages are Weakest
The following table shows where the packages are weaker than they could be. (Again, thanks Chat!)
promptui
has a lot of red Xs. So does survey
(and it’s also archived).
Three features stood out to us (all showing favor to go-prompt
): Custom Rendering, REPL support, and Tab Completion — I don’t know about you, but tab completion is essential — at least to my mind.
survey
: No tab completion, limited advanced features like REPL support.
prompt-ui
: No multi-select support, lacks tab completion, limited for advanced CLIs.
go-prompt
: No built-in validation, lacks multi-select, complex setup for simple CLIs.
Other Considerations
Here’s a final table comparing the three packages along less technical lines. Long-term support, community engagement, good documentation, etc., are also important when selecting a package.
(Again, we thank Chat. Thanks Chat!)
There’s not much to see here. All three packages are pretty equal on these terms; however, I think Chat made a mistake (Bad Chat!) The survey
package recently announced that the repo would be archived. Other than that, they all have a lot of stars, a lot of forks, and active communities.
UpShot
In the end, our decision was rather simple. We chose go-prompt
. Go-prompt
met particular requirements that the other packages didn’t meet (REPL, customizability). This sealed the deal for us. Plus, we’ve used go-prompt
before, so it’s familiar.
Thanks for reading. As always, the above works for us. Your mileage may vary. Have fun, and do check out Bubble Tea. It actually looks amaze-ballz.
Your Support is Welcome
TrueBlocks is funded from personal funds and grants from The Ethereum Foundation (2018, 2022, 2024), Optimism Retro PGF (2022, 2023), Moloch DAO (2021), Filecoin/IPFS (2021), Consensys (2019), and our lovely GitCoin donors.
If you like this article and wish to support our work, please donate to our GitCoin grant using ETH or any token. If you’re an Optimism badge holder, vote for our project in future Retro rounds. Or send us a tip directly at trueblocks.eth or 0xf503017d7baf7fbc0fff7492b751025c6a78179b.