ishell

package module
v2.0.0+incompatible Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 7, 2018 License: MIT Imports: 20 Imported by: 273

README

ishell

ishell is an interactive shell library for creating interactive cli applications.

Documentation Go Report Card

Older version

The current master is not backward compatible with older version. Kindly change your import path to gopkg.in/abiosoft/ishell.v1.

Older version of this library is still available at https://gopkg.in/abiosoft/ishell.v1.

However, you are advised to upgrade to v2 https://gopkg.in/abiosoft/ishell.v2.

Usage

import "strings"
import "github.com/abiosoft/ishell"

func main(){
    // create new shell.
    // by default, new shell includes 'exit', 'help' and 'clear' commands.
    shell := ishell.New()

    // display welcome info.
    shell.Println("Sample Interactive Shell")

    // register a function for "greet" command.
    shell.AddCmd(&ishell.Cmd{
        Name: "greet",
        Help: "greet user",
        Func: func(c *ishell.Context) {
            c.Println("Hello", strings.Join(c.Args, " "))
        },
    })

    // run shell
    shell.Run()
}

Execution

Sample Interactive Shell
>>> help

Commands:
  clear      clear the screen
  greet      greet user
  exit       exit the program
  help       display help

>>> greet Someone Somewhere
Hello Someone Somewhere
>>> exit
$
Reading input
// simulate an authentication
shell.AddCmd(&ishell.Cmd{
    Name: "login",
    Help: "simulate a login",
    Func: func(c *ishell.Context) {
        // disable the '>>>' for cleaner same line input.
        c.ShowPrompt(false)
        defer c.ShowPrompt(true) // yes, revert after login.

        // get username
        c.Print("Username: ")
        username := c.ReadLine()

        // get password.
        c.Print("Password: ")
        password := c.ReadPassword()

        ... // do something with username and password

        c.Println("Authentication Successful.")
    },
})

Execution

>>> login
Username: someusername
Password:
Authentication Successful.
Multiline input

Builtin support for multiple lines.

>>> This is \
... multi line

>>> Cool that << EOF
... everything here goes
... as a single argument.
... EOF

User defined

shell.AddCmd(&ishell.Cmd{
    Name: "multi",
    Help: "input in multiple lines",
    Func: func(c *ishell.Context) {
        c.Println("Input multiple lines and end with semicolon ';'.")
        lines := c.ReadMultiLines(";")
        c.Println("Done reading. You wrote:")
        c.Println(lines)
    },
})

Execution

>>> multi
Input multiple lines and end with semicolon ';'.
>>> this is user defined
... multiline input;
You wrote:
this is user defined
multiline input;
Keyboard interrupt

Builtin interrupt handler.

>>> ^C
Input Ctrl-C once more to exit
>>> ^C
Interrupted
exit status 1

Custom

shell.Interrupt(func(count int, c *ishell.Context) { ... })
Multiple Choice
func(c *ishell.Context) {
    choice := c.MultiChoice([]string{
        "Golangers",
        "Go programmers",
        "Gophers",
        "Goers",
    }, "What are Go programmers called ?")
    if choice == 2 {
        c.Println("You got it!")
    } else {
        c.Println("Sorry, you're wrong.")
    }
},

Output

What are Go programmers called ?
  Golangers
  Go programmers
> Gophers
  Goers

You got it!
Checklist
func(c *ishell.Context) {
    languages := []string{"Python", "Go", "Haskell", "Rust"}
    choices := c.Checklist(languages,
        "What are your favourite programming languages ?", nil)
    out := func() []string { ... } // convert index to language
    c.Println("Your choices are", strings.Join(out(), ", "))
}

Output

What are your favourite programming languages ?
    Python
  ✓ Go
    Haskell
 >✓ Rust

Your choices are Go, Rust
Progress Bar

Determinate

func(c *ishell.Context) {
    c.ProgressBar().Start()
    for i := 0; i < 101; i++ {
        c.ProgressBar().Suffix(fmt.Sprint(" ", i, "%"))
        c.ProgressBar().Progress(i)
        ... // some background computation
    }
    c.ProgressBar().Stop()
}

Output

[==========>         ] 50%

Indeterminate


func(c *ishell.Context) {
    c.ProgressBar().Indeterminate(true)
    c.ProgressBar().Start()
    ... // some background computation
    c.ProgressBar().Stop()
}

Output

[ ====               ]

Custom display using briandowns/spinner.

display := ishell.ProgressDisplayCharSet(spinner.CharSets[11])
func(c *Context) { c.ProgressBar().Display(display) ... }

// or set it globally
ishell.ProgressBar().Display(display)
Durable history
// Read and write history to $HOME/.ishell_history
shell.SetHomeHistoryPath(".ishell_history")
Non-interactive execution

In some situations it is desired to exit the program directly after executing a single command.

// when started with "exit" as first argument, assume non-interactive execution
if len(os.Args) > 1 && os.Args[1] == "exit" {
    shell.Process(os.Args[2:]...)
} else {
    // start shell
    shell.Run()
}
# Run normally - interactive mode:
$ go run main.go
>>> |

# Run non-interactivelly
$ go run main.go exit greet Someusername
Hello Someusername
Output with Color

You can use fatih/color.

func(c *ishell.Context) {
    yellow := color.New(color.FgYellow).SprintFunc()
    c.Println(yellow("This line is yellow"))
}

Execution

>>> color
This line is yellow
Example

Available here.

go run example/main.go

Supported Platforms

  • Linux
  • OSX
  • Windows [Not tested but should work]

Note

ishell is in active development and can still change significantly.

Roadmap (in no particular order)

  • Multiline inputs
  • Command history
  • Customizable tab completion
  • Handle ^C interrupts
  • Subcommands and help texts
  • Scrollable paged output
  • Progress bar
  • Multiple choice prompt
  • Checklist prompt
  • Support for command aliases
  • Multiple line progress bars
  • Testing, testing, testing

Contribution

  1. Create an issue to discuss it.
  2. Send in Pull Request.

License

MIT

Credits

Library Use
github.com/flynn-archive/go-shlex splitting input into command and args.
github.com/chzyer/readline readline capabilities.

Donate

bitcoin: 1GTHYEDiy2C7RzXn5nY4wVRaEN2GvLjwZN
paypal: a@abiosoft.com

Documentation

Overview

Package ishell implements an interactive shell.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Actions

type Actions interface {
	// ReadLine reads a line from standard input.
	ReadLine() string
	// ReadLineErr is ReadLine but returns error as well
	ReadLineErr() (string, error)
	// ReadPassword reads password from standard input without echoing the characters.
	// Note that this only works as expected when the standard input is a terminal.
	ReadPassword() string
	// ReadPasswordErr is ReadPassword but returns error as well
	ReadPasswordErr() (string, error)
	// ReadMultiLinesFunc reads multiple lines from standard input. It passes each read line to
	// f and stops reading when f returns false.
	ReadMultiLinesFunc(f func(string) bool) string
	// ReadMultiLines reads multiple lines from standard input. It stops reading when terminator
	// is encountered at the end of the line. It returns the lines read including terminator.
	// For more control, use ReadMultiLinesFunc.
	ReadMultiLines(terminator string) string
	// Println prints to output and ends with newline character.
	Println(val ...interface{})
	// Print prints to output.
	Print(val ...interface{})
	// Printf prints to output using string format.
	Printf(format string, val ...interface{})
	// ShowPaged shows a paged text that is scrollable.
	// This leverages on "less" for unix and "more" for windows.
	ShowPaged(text string) error
	// MultiChoice presents options to the user.
	// returns the index of the selection or -1 if nothing is
	// selected.
	// text is displayed before the options.
	MultiChoice(options []string, text string) int
	// Checklist is similar to MultiChoice but user can choose multiple variants using Space.
	// init is initially selected options.
	Checklist(options []string, text string, init []int) []int
	// SetPrompt sets the prompt string. The string to be displayed before the cursor.
	SetPrompt(prompt string)
	// SetMultiPrompt sets the prompt string used for multiple lines. The string to be displayed before
	// the cursor; starting from the second line of input.
	SetMultiPrompt(prompt string)
	// ShowPrompt sets whether prompt should show when requesting input for ReadLine and ReadPassword.
	// Defaults to true.
	ShowPrompt(show bool)
	// Cmds returns all the commands added to the shell.
	Cmds() []*Cmd
	// HelpText returns the computed help of top level commands.
	HelpText() string
	// ClearScreen clears the screen. Same behaviour as running 'clear' in unix terminal or 'cls' in windows cmd.
	ClearScreen() error
	// Stop stops the shell. This will stop the shell from auto reading inputs and calling
	// registered functions. A stopped shell is only inactive but totally functional.
	// Its functions can still be called and can be restarted.
	Stop()
}

Actions are actions that can be performed by a shell.

type Cmd

type Cmd struct {
	// Command name.
	Name string
	// Command name aliases.
	Aliases []string
	// Function to execute for the command.
	Func func(c *Context)
	// One liner help message for the command.
	Help string
	// More descriptive help message for the command.
	LongHelp string

	// Completer is custom autocomplete for command.
	// It takes in command arguments and returns
	// autocomplete options.
	// By default all commands get autocomplete of
	// subcommands.
	// A non-nil Completer overrides the default behaviour.
	Completer func(args []string) []string
	// contains filtered or unexported fields
}

Cmd is a shell command handler.

func (*Cmd) AddCmd

func (c *Cmd) AddCmd(cmd *Cmd)

AddCmd adds cmd as a subcommand.

func (*Cmd) Children

func (c *Cmd) Children() []*Cmd

Children returns the subcommands of c.

func (*Cmd) DeleteCmd

func (c *Cmd) DeleteCmd(name string)

DeleteCmd deletes cmd from subcommands.

func (Cmd) FindCmd

func (c Cmd) FindCmd(args []string) (*Cmd, []string)

FindCmd finds the matching Cmd for args. It returns the Cmd and the remaining args.

func (Cmd) HelpText

func (c Cmd) HelpText() string

HelpText returns the computed help of the command and its subcommands.

type Context

type Context struct {

	// Args is command arguments.
	Args []string

	// RawArgs is unprocessed command arguments.
	RawArgs []string

	// Cmd is the currently executing command. This is empty for NotFound and Interrupt.
	Cmd Cmd

	Actions
	// contains filtered or unexported fields
}

Context is an ishell context. It embeds ishell.Actions.

func (Context) Del

func (c Context) Del(key string)

Del deletes key and its value in this context.

func (*Context) Err

func (c *Context) Err(err error)

Err informs ishell that an error occurred in the current function.

func (Context) Get

func (c Context) Get(key string) interface{}

Get returns the value associated with this context for key, or nil if no value is associated with key. Successive calls to Get with the same key returns the same result.

func (Context) Keys

func (c Context) Keys() (keys []string)

Keys returns all keys in the context.

func (*Context) ProgressBar

func (c *Context) ProgressBar() ProgressBar

ProgressBar returns the progress bar for the current shell context.

func (*Context) Set

func (c *Context) Set(key string, value interface{})

Set sets the key in this context to value.

type ProgressBar

type ProgressBar interface {
	// Display sets the display of the progress bar.
	Display(ProgressDisplay)
	// Indeterminate sets the progress bar type
	// to indeterminate if true or determinate otherwise.
	Indeterminate(bool)
	// Interval sets the time between transitions for indeterminate
	// progress bar.
	Interval(time.Duration)
	// SetProgress sets the progress stage of the progress bar.
	// percent is from between 1 and 100.
	Progress(percent int)
	// Prefix sets the prefix for the output. The text to place before
	// the display.
	Prefix(string)
	// Suffix sets the suffix for the output. The text to place after
	// the display.
	Suffix(string)
	// Final sets the string to show after the progress bar is done.
	Final(string)
	// Start starts the progress bar.
	Start()
	// Stop stops the progress bar.
	Stop()
}

ProgressBar is an ishell progress bar.

type ProgressDisplay

type ProgressDisplay interface {
	// Determinate returns the strings to display
	// for percents 0 to 100.
	Determinate() [101]string
	// Indeterminate returns the strings to display
	// at interval.
	Indeterminate() []string
}

ProgressDisplay handles the display string for a progress bar.

type ProgressDisplayCharSet

type ProgressDisplayCharSet []string

ProgressDisplayCharSet is the character set for a progress bar.

func (ProgressDisplayCharSet) Determinate

func (p ProgressDisplayCharSet) Determinate() [101]string

Determinate satisfies ProgressDisplay interface.

func (ProgressDisplayCharSet) Indeterminate

func (p ProgressDisplayCharSet) Indeterminate() []string

Indeterminate satisfies ProgressDisplay interface.

type ProgressDisplayFunc

type ProgressDisplayFunc func(percent int) string

ProgressDisplayFunc is a convenience function to create a ProgressDisplay. percent is -1 for indeterminate and 0-100 for determinate.

func (ProgressDisplayFunc) Determinate

func (p ProgressDisplayFunc) Determinate() [101]string

Determinate satisfies ProgressDisplay interface.

func (ProgressDisplayFunc) Indeterminate

func (p ProgressDisplayFunc) Indeterminate() []string

Indeterminate satisfies ProgressDisplay interface.

type Shell

type Shell struct {
	Actions
	// contains filtered or unexported fields
}

Shell is an interactive cli shell.

func New

func New() *Shell

New creates a new shell with default settings. Uses standard output and default prompt ">> ".

func NewWithConfig

func NewWithConfig(conf *readline.Config) *Shell

NewWithConfig creates a new shell with custom readline config.

func (*Shell) Active

func (s *Shell) Active() bool

Active tells if the shell is active. i.e. Start is previously called.

func (*Shell) AddCmd

func (s *Shell) AddCmd(cmd *Cmd)

AddCmd adds a new command handler. This only adds top level commands.

func (*Shell) AutoHelp

func (s *Shell) AutoHelp(enable bool)

AutoHelp sets if ishell should trigger help message if a command's arg is "help". Defaults to true.

This can be set to false for more control on how help is displayed.

func (*Shell) Close

func (s *Shell) Close()

Close stops the shell (if required) and closes the shell's input. This should be called when done with reading inputs. Unlike `Stop`, a closed shell cannot be restarted.

func (*Shell) CustomCompleter

func (s *Shell) CustomCompleter(completer readline.AutoCompleter)

CustomCompleter allows use of custom implementation of readline.Autocompleter.

func (Shell) Del

func (c Shell) Del(key string)

Del deletes key and its value in this context.

func (*Shell) DeleteCmd

func (s *Shell) DeleteCmd(name string)

DeleteCmd deletes a top level command.

func (*Shell) EOF

func (s *Shell) EOF(f func(c *Context))

EOF adds a function to handle End of File input (Ctrl-d). This overrides the default behaviour which terminates the shell.

func (Shell) Get

func (c Shell) Get(key string) interface{}

Get returns the value associated with this context for key, or nil if no value is associated with key. Successive calls to Get with the same key returns the same result.

func (*Shell) IgnoreCase

func (s *Shell) IgnoreCase(ignore bool)

IgnoreCase specifies whether commands should not be case sensitive. Defaults to false i.e. commands are case sensitive. If true, commands must be registered in lower cases.

func (*Shell) Interrupt

func (s *Shell) Interrupt(f func(c *Context, count int, input string))

Interrupt adds a function to handle keyboard interrupt (Ctrl-c). count is the number of consecutive times that Ctrl-c has been pressed. i.e. any input apart from Ctrl-c resets count to 0.

func (Shell) Keys

func (c Shell) Keys() (keys []string)

Keys returns all keys in the context.

func (*Shell) NotFound

func (s *Shell) NotFound(f func(*Context))

NotFound adds a generic function for all inputs. It is called if the shell input could not be handled by any of the added commands.

func (*Shell) Process

func (s *Shell) Process(args ...string) error

Process runs shell using args in a non-interactive mode.

func (*Shell) ProgressBar

func (s *Shell) ProgressBar() ProgressBar

ProgressBar returns the progress bar for the shell.

func (*Shell) Run

func (s *Shell) Run()

Run starts the shell and waits for it to stop.

func (*Shell) Set

func (c *Shell) Set(key string, value interface{})

Set sets the key in this context to value.

func (*Shell) SetHistoryPath

func (s *Shell) SetHistoryPath(path string)

SetHistoryPath sets where readlines history file location. Use an empty string to disable history file. It is empty by default.

func (*Shell) SetHomeHistoryPath

func (s *Shell) SetHomeHistoryPath(path string)

SetHomeHistoryPath is a convenience method that sets the history path in user's home directory.

func (*Shell) SetOut

func (s *Shell) SetOut(writer io.Writer)

SetOut sets the writer to write outputs to.

func (*Shell) SetPager

func (s *Shell) SetPager(pager string, args []string)

SetPager sets the pager and its arguments for paged output

func (*Shell) Start

func (s *Shell) Start()

Start starts the shell but does not wait for it to stop.

func (*Shell) Wait

func (s *Shell) Wait()

Wait waits for the shell to stop.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL