ishellLibrary for creating interactive cli applications.

联合创作 · 2023-09-30 06:54

ishell


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


Go Reference Go Report Card


Usage



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

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

浏览 21
点赞
评论
收藏
分享

手机扫一扫分享

编辑 分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

编辑 分享
举报