An easy to use menu structure for cli applications that prompts users to make choices.

Overview

WMenuBuild Status codecov

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 with concurrency by default. wmenu allows you to change the color of the different parts of the menu. This package also creates it's own error structure so you can type assert if you need to. wmenu will validate all responses before calling any function. It will also figure out which function should be called so you don't have to.

Watch example

Import

Post Go1.11

import "github.com/dixonwille/wmenu/v5"

Pre Go1.11

I try and keep up with my tags. To use the version and stable it is recommended to use govendor or another vendoring tool that allows you to build your project for specific tags.

govendor fetch github.com/dixonwille/[email protected]

The above will grab the latest v4 at that time and mark it. It will then be stable for you to use.

I will try to support as many versions as possable but please be patient.

V1.0.0 - Major Release Go Report Card GoDoc

V2.0.0 - Allowing an interface to be passed in for options Go Report Card GoDoc

V3.0.0 - Pass in the option to that option's function Go Report Card GoDoc

V4.0.0 - Now have an Action that supports multiple options Go Report Card GoDoc

v5.0.0 - Support Go Mods

https://pkg.go.dev/github.com/dixonwille/wmenu/v5

Features

  • Force single selection
  • Allow multiple selection
  • Change the delimiter
  • Change the color of different parts of the menu
  • Easily see which option(s) are default
  • Change the symbol used for default option(s)
  • Ask simple yes and no questions
  • Validate all responses before calling any functions
  • With yes and no can accept:
    • yes, Yes, YES, y, Y
    • no, No, NO, n, N
  • Figure out which Action should be called (Options, Default, or Multiple Action)
  • Re-ask question if invalid response up to a certain number of times
  • Can change max number of times to ask before failing output
  • Change reader and writer
  • Clear the screen whenever the menu is brought up
  • Has its own error structure so you can type assert menu errors

V2 - Adds these Features

  • Allowing any interface to be passed through for the options.

V3 - Adds these Features

  • Pass the option chosen to that options function

V4 - Adds these Features

  • Have one function for both single and multiple select. Allowing the user to an easier way of handeling the request.

v5 - Support Go Mods

  • No other change except you should import with the following now
import "github.com/dixonwille/wmenu/v5"

Usage

This is a simple use of the package. (NOTE: THIS IS A V4 SAMPLE)

menu := wmenu.NewMenu("What is your favorite food?")
menu.Action(func (opts []wmenu.Opt) error {fmt.Printf(opts[0].Text + " is your favorite food."); return nil})
menu.Option("Pizza", nil, true, nil)
menu.Option("Ice Cream", nil, false, nil)
menu.Option("Tacos", nil, false, func(opt wmenu.Opt) error {
  fmt.Printf("Tacos are great")
  return nil
})
err := menu.Run()
if err != nil{
  log.Fatal(err)
}

The output would look like this:

1) *Pizza
2) Ice Cream
3) Tacos
What is your favorite food?

If the user just presses [Enter] then the option(s) with the * will be selected. This indicates that it is a default function. If they choose 1 then they would see Ice Cream is your favorite food.. This used the Action's function because the option selected didn't have a function along with it. But if they choose 2 they would see Tacos are great. That option did have a function with it which take precedence over Action.

You can you also use:

menu.AllowMultiple()

This will allow the user to select multiple options. The default delimiter is a [space], but can be changed by using:

menu.SetSeperator("some string")

Another feature is the ability to ask yes or no questions.

menu.IsYesNo(0)

This will remove any options previously added options and hide the ones used for the menu. It will simply just ask yes or no. Menu will parse and validate the response for you. This option will always call the Action's function and pass in the option that was selected.

V3+ - Release

Allows the user to pass anything for the value so it can be retrieved later in the function. The following is to show case the power of this.

The following was written in V3 but the concept holds for V4. V4 just changed actFunc to be func([]wmenu.Opt) error instead.

type NameEntity struct {
  FirstName string
  LastName  string
}

optFunc := func(opt wmenu.Opt) error {
  fmt.Println("Option 1 was chosen.")
  return nil
}
actFunc := func(opt wmenu.Opt) error {
  name, ok := opt.Value.(NameEntity)
  if !ok {
    log.Fatal("Could not cast option's value to NameEntity")
  }
  fmt.Printf("%s has an id of %d.\n", opt.Text, opt.ID)
  fmt.Printf("Hello, %s %s.\n", name.FirstName, name.LastName)
  return nil
}
menu := NewMenu("Choose an option.")
menu.ChangeReaderWriter(reader, os.Stdout, os.Stderr)
menu.Action(actFunc)
menu.Option("Option 1", NameEntity{"Bill", "Bob"}, true, optFunc)
menu.Option("Option 2", NameEntity{"John", "Doe"}, false, nil)
menu.Option("Option 3", NameEntity{"Jane", "Doe"}, false, nil)
err := menu.Run()
if err != nil {
  log.Fatal(err)
}

The immediate output would be:

Output:
1) *Option 1
2) Option 2
3) Option 3
Choose an option.

Now if the user pushes [ENTER] the output would be Options 0 was chosen.. But now if either option 1 or 2 were chosen it would cast the options value to a NameEntity allowing the function to be able to gather both the first name and last name of the NameEntity. If you want though you can just pass in nil as the value or even a string ("hello") since both of these implement the empty interface required by value. Just make sure to cast the values so you can use them appropriately.

Further Reading

This whole package has been documented and has a few examples in:

You should read the docs to find all functions and structures at your finger tips.

Comments
  • Add Opt.Value to allow separate menu.Option display text vs. value

    Add Opt.Value to allow separate menu.Option display text vs. value

    This is a breaking change. So completely understand if you reject.

    Just wanted to inform you I forked your package, and added a Value string to the Opt struct, updated the various functions, etc.

    This allows creation of menus with "user friendly" display text (Opt.Text) but underlying long or complicated values (Opt.Value)

    0) NOC
    1) NetOps
    2) Security
    3) SysOps
    ....
    
    // where underlying values could be anything else, for example:
    Opt.ID == 0
    Opt.Text == "NOC"
    Opt.Value == "ou=NOC,ou=People,ou=ACME,dc=example,dc=com"
    

    My specific case I wanted to prompt the user for LDAP information, but I wanted a "friendlier" Opt.Text, but be able to pass specific value. Probably could have done this with func() call, but I was unable to make that work with a loop iteration to dynamically build my menus

    I have not added specific test cases for Opt.Value, but did updated menu_test to ensure everything passes with new function parameter (value)

    enhancement 
    opened by jamesboswell 7
  • how to pass answer from one menu to another

    how to pass answer from one menu to another

    i have a wizard with multiple questions and therefore multiple menus. i want subsequent menus to depend on data from previous menus. how could i achieve this?

    question 
    opened by phamdt 4
  • allow setting initial index

    allow setting initial index

    In #20, the code was changed to start Option IDs at 0. This broke existing workflows, as it changed the returned ID to no longer align with indexes on source lists.

    This PR attempts to reconcile both worlds. It sets display index as an option of the menu, and resets backend accounting to use zero-indexing. So, for example, if I take a slice of entries and turn them into options, and the user selects the first entry, it will always have ID 0, to align w/ the index I started with. But if I want the display to start at 0 or 1 or any other integer, I can control that. I set it to default to 1, to align with the current display behavior.

    opened by akerl-unpriv 3
  • add optinoal padding for optionID

    add optinoal padding for optionID

    add the ability to pad the ID of the options so the printed text is aligned.

    before

    9) worker1 - 1.2.3.4
    10) worker2 - 5.6.7.8
    

    after

     9) worker1 - 1.2.3.4
    10) worker2 - 5.6.7.8
    
    opened by jmcampanini 3
  • Convenient Action Handler

    Convenient Action Handler

    Looks like if you are working with a list where It's possible to have multiple selections, you have to provide both handlers - Action and MultipleAction. I had to spend some time to comprehend it.

    Why not just create an action handler, where if a single option is selected it will be a slice with one element only?

    enhancement question 
    opened by NicolasSiver 3
  • Trailing delimiter

    Trailing delimiter

    Looks like a trailing delimiter considered as an invalid response. For example, if space is a delimiter, such response will not be accepted:

    0_1_
    // where underscore _ is a space for clarity
    
    bug 
    opened by NicolasSiver 2
  • Error strings should not be capitalized

    Error strings should not be capitalized

    var (
    	//ErrInvalid is returned if a response from user was an invalid option
    	ErrInvalid = errors.New("Invalid response")
    
    	//ErrTooMany is returned if multiSelect is false and a user tries to select multiple options
    	ErrTooMany = errors.New("Too many responses")
    
    	//ErrNoResponse is returned if there were no responses and no action to call
    	ErrNoResponse = errors.New("No response")
    
    	//ErrDuplicate is returned is a user selects an option twice
    	ErrDuplicate = errors.New("Duplicated response")
    )
    
    opened by voidint 1
  • Screenshot / asciinema?

    Screenshot / asciinema?

    It would be great to show off what this library actually looks like in a terminal :).

    asciinema would be a good choice I think because you can show the full user flow there.

    enhancement 
    opened by jojomi 1
  • Fix clear screen function on windows

    Fix clear screen function on windows

    See http://stackoverflow.com/questions/19209425/how-can-i-clear-the-console-with-golang-in-windows#comment29035981_19290028 for more information on why this is needed

    opened by jamesbirtles 1
  • GoVendor for Packages

    GoVendor for Packages

    Govendor is not the best solution for packages as the root project does not pull the proper files. Include the vendor repositories in hope that it will help.

    bug 
    opened by dixonwille 1
  • Refactor the README to not include godoc as file

    Refactor the README to not include godoc as file

    Currently the README is godoc. This needs to be refactored to not include godoc and instead explain the usage of this package (See if there is a badge I can add for gowalk).

    opened by dixonwille 1
Releases(v4.0.2)
  • v4.0.2(Jan 5, 2018)

  • v3.0.1(Feb 22, 2017)

  • v2.0.0(Jun 6, 2016)

    Allow the user to pass anything through the given options to a function that they can use later. This allows the user to not rely on the string name but instead they can pass a whole model through if they want. A simple string or even nil works as well.

    This is a breaking change Option now requires one more parameter in it that is the value interface. Easy change but is breaking.

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Jun 6, 2016)

    Completely stable and have test to back that. It is in my best interest to break the API. I will come out with a versioning schema in the future just in case I do need to version this API out.

    Source code(tar.gz)
    Source code(zip)
Owner
Will Dixon
Will Dixon
CLI for SendGrid, which helps in managing SSO users, can install and update users from yaml config

Sendgrid API This script is needed to add new users to SendGrid as SSO teammates. Previously, all users were manually added and manually migrating the

ANNA 4 Jul 20, 2022
Building powerful interactive prompts in Go, inspired by python-prompt-toolkit.

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

Masashi Shibata 4.6k Sep 26, 2022
A golang library for building interactive prompts with full support for windows and posix terminals.

Survey A library for building interactive prompts on terminals supporting ANSI escape sequences. package main import ( "fmt" "github.com/Alec

Alec Aivazis 3.3k Oct 1, 2022
A go lib based on tcell which builds a simple menu UI in your terminal.

MenuScreen A simple go lib based on github.com/gdamore/tcell/v2,which helps you build a simple menu UI in your terminal. Install go get -u github.com/

SCU-SJL 0 Nov 11, 2021
A CLI tool for leveraging IDP signing keys to impersonate users and groups

Imperson8 Disclaimer This is a security testing tool. Only use this on systems you have explicit authorization to test. This isn't an exploit and won'

null 17 Jul 23, 2022
Scrappy is a cli tool that allows multiple web scrappers to monitor periodically for a basic ruleset coverage and inform users when the criteria have been met.

Scrappy - A multi-type web scrapper with alerting Scrappy is a cli tool that allows multiple web scrappers to monitor periodically for a basic ruleset

Michalis Zampetakis 0 Nov 7, 2021
Gobby-cli - CLI application to debug gobby applications

go(bby) Interactive debugging tool for gobby applications Usage Coming soon™ Ins

Qwiri 0 Feb 8, 2022
This package to make it easy to work with env

Go Env This package to make it easy to work with env Example usage package main

Sergey A. 3 Jan 30, 2022
An easy-to-use cli tool for downloading manga

mangodl Download and search manga right from the terminal! Report Bug || Request Feature Table of Contents About the Project Built With Getting Starte

null 142 Sep 11, 2022
Easy to use CLI for cryptography

EDH (Encryption, Decryption, Hashing) Utility that aims to improve efficiency of encryption, decryption and hashing by making a simple to use CLI Writ

null 2 Nov 4, 2021
Easy to use library and CLI utility to generate Go struct from CSV files.

csv2struct Easy to use library and CLI utility to generate Go struct from CSV files. As a benefit, it's fully compatible with csvutil. So, structs gen

Ivan Maliovaniy 11 Aug 19, 2022
Simple, lightweight, and easy to use gopacket wrapper cli

gniffer Simple, lightweight, and easy to use gopacket wrapper cli Explore the docs » View Demo · Report Bug · Request Feature Table of Contents About

StrixEye 4 Dec 25, 2021
Make Highly Customized Boxes for your CLI

Box CLI Maker ?? Box CLI Maker is a Highly Customized Terminal Box Creator. Features Make Terminal Box in 8️⃣ inbuilt different styles 16 Inbuilt Colo

Swastik Baranwal 236 Sep 20, 2022
An attempt to make a cli for dev.to in Go

Devto a cli for dev.to This is a work in progress so don't a expect a full support for Dev API(beta). Table of contents Devto a cli for dev.to Table o

Gealber Morales 5 Mar 13, 2022
Minutes is a CLI tool for synchronizing work logs between multiple time trackers, invoicing, and bookkeeping software to make entrepreneurs' daily work easier.

Minutes is a CLI tool for synchronizing work logs between multiple time trackers, invoicing, and bookkeeping software to make entrepreneurs' daily work easier.

Gábor Boros 21 Aug 8, 2022
Go-file-downloader-ftctl - A file downloader cli built using golang. Makes use of cobra for building the cli and go concurrent feature to download files.

ftctl This is a file downloader cli written in Golang which uses the concurrent feature of go to download files. The cli is built using cobra. How to

Dipto Chakrabarty 2 Jan 2, 2022
create boilerplate structure for neovim plugins

boilit Boil yourself a sweet plugin Installation • Usage Ain't nobody got time to create plugin directories: boilit yourself! boilit creates boilerpla

Gennaro Tedesco 50 Sep 15, 2022
A command line utility for generating language-specific project structure.

hydra hydra is a command line utility for generating language-specific project structures. ⏬ ✨ Features Build project templates with just one command

Shravan 18 Oct 8, 2021